2017-11-18 17:09:20 +01:00
/* SPDX-License-Identifier: LGPL-2.1+ */
2014-07-16 22:55:23 +02:00
/***
This file is part of systemd .
Copyright 2014 Zbigniew Jędrzejewski - Szmek
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <getopt.h>
2015-11-16 22:09:36 +01:00
# include <net/if.h>
2014-07-16 22:55:23 +02:00
# include "sd-bus.h"
2016-06-15 21:43:36 +02:00
# include "sd-netlink.h"
2015-09-23 03:01:06 +02:00
# include "af-list.h"
2015-10-27 03:01:06 +01:00
# include "alloc-util.h"
2017-12-14 20:13:14 +01:00
# include "bus-common-errors.h"
2014-07-16 22:55:23 +02:00
# include "bus-error.h"
2015-09-23 03:01:06 +02:00
# include "bus-util.h"
2017-12-14 20:13:14 +01:00
# include "dns-domain.h"
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
# include "escape.h"
2016-01-29 00:24:27 +01:00
# include "gcrypt-util.h"
2016-06-15 21:43:36 +02:00
# include "in-addr-util.h"
# include "netlink-util.h"
# include "pager.h"
2015-10-26 16:18:16 +01:00
# include "parse-util.h"
2014-08-14 01:00:15 +02:00
# include "resolved-def.h"
2015-09-23 03:01:06 +02:00
# include "resolved-dns-packet.h"
2016-06-15 21:43:36 +02:00
# include "strv.h"
2015-12-23 19:06:36 +01:00
# include "terminal-util.h"
2014-07-30 19:23:27 +02:00
2014-07-16 22:55:23 +02:00
static int arg_family = AF_UNSPEC ;
static int arg_ifindex = 0 ;
2015-12-18 18:53:11 +01:00
static uint16_t arg_type = 0 ;
2014-07-30 19:23:27 +02:00
static uint16_t arg_class = 0 ;
2014-08-01 02:06:30 +02:00
static bool arg_legend = true ;
2014-08-14 01:00:15 +02:00
static uint64_t arg_flags = 0 ;
2016-06-15 21:43:36 +02:00
static bool arg_no_pager = false ;
2016-01-31 06:06:49 +01:00
2016-02-18 03:08:57 +01:00
typedef enum ServiceFamily {
SERVICE_FAMILY_TCP ,
SERVICE_FAMILY_UDP ,
SERVICE_FAMILY_SCTP ,
_SERVICE_FAMILY_INVALID = - 1 ,
} ServiceFamily ;
static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP ;
2016-01-31 06:06:49 +01:00
typedef enum RawType {
RAW_NONE ,
RAW_PAYLOAD ,
RAW_PACKET ,
} RawType ;
static RawType arg_raw = RAW_NONE ;
2015-12-23 19:06:36 +01:00
static enum {
MODE_RESOLVE_HOST ,
MODE_RESOLVE_RECORD ,
MODE_RESOLVE_SERVICE ,
2016-01-29 00:24:27 +01:00
MODE_RESOLVE_OPENPGP ,
2016-02-18 03:08:57 +01:00
MODE_RESOLVE_TLSA ,
2015-12-23 19:06:36 +01:00
MODE_STATISTICS ,
MODE_RESET_STATISTICS ,
2016-06-10 20:40:30 +02:00
MODE_FLUSH_CACHES ,
2017-09-29 21:19:54 +02:00
MODE_RESET_SERVER_FEATURES ,
2016-06-15 21:43:36 +02:00
MODE_STATUS ,
2017-12-14 20:13:14 +01:00
MODE_SET_LINK ,
MODE_REVERT_LINK ,
2015-12-23 19:06:36 +01:00
} arg_mode = MODE_RESOLVE_HOST ;
2014-08-14 01:00:15 +02:00
2017-12-14 20:13:14 +01:00
static struct in_addr_data * arg_set_dns = NULL ;
static size_t arg_n_set_dns = 0 ;
static char * * arg_set_domain = NULL ;
static char * arg_set_llmnr = NULL ;
static char * arg_set_mdns = NULL ;
static char * arg_set_dnssec = NULL ;
static char * * arg_set_nta = NULL ;
2016-02-18 03:08:57 +01:00
static ServiceFamily service_family_from_string ( const char * s ) {
2018-02-27 17:45:04 +01:00
if ( ! s | | streq ( s , " tcp " ) )
2016-02-18 03:08:57 +01:00
return SERVICE_FAMILY_TCP ;
if ( streq ( s , " udp " ) )
return SERVICE_FAMILY_UDP ;
if ( streq ( s , " sctp " ) )
return SERVICE_FAMILY_SCTP ;
return _SERVICE_FAMILY_INVALID ;
}
static const char * service_family_to_string ( ServiceFamily service ) {
switch ( service ) {
case SERVICE_FAMILY_TCP :
return " _tcp " ;
case SERVICE_FAMILY_UDP :
return " _udp " ;
case SERVICE_FAMILY_SCTP :
return " _sctp " ;
default :
assert_not_reached ( " invalid service " ) ;
}
}
2015-08-17 23:54:08 +02:00
static void print_source ( uint64_t flags , usec_t rtt ) {
2015-08-11 22:37:23 +02:00
char rtt_str [ FORMAT_TIMESTAMP_MAX ] ;
2014-08-14 01:00:15 +02:00
if ( ! arg_legend )
return ;
2015-08-17 23:54:08 +02:00
if ( flags = = 0 )
2014-08-14 01:00:15 +02:00
return ;
fputs ( " \n -- Information acquired via " , stdout ) ;
if ( flags ! = 0 )
2016-01-19 17:10:34 +01:00
printf ( " protocol%s%s%s%s%s " ,
2014-08-14 01:00:15 +02:00
flags & SD_RESOLVED_DNS ? " DNS " : " " ,
flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4 " : " " ,
2016-01-19 17:10:34 +01:00
flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6 " : " " ,
2017-03-13 01:12:03 +01:00
flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4 " : " " ,
flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6 " : " " ) ;
2014-08-14 01:00:15 +02:00
2015-08-11 22:37:23 +02:00
assert_se ( format_timespan ( rtt_str , sizeof ( rtt_str ) , rtt , 100 ) ) ;
printf ( " in %s " , rtt_str ) ;
2014-08-14 01:00:15 +02:00
fputc ( ' . ' , stdout ) ;
fputc ( ' \n ' , stdout ) ;
2015-12-03 21:04:52 +01:00
printf ( " -- Data is authenticated: %s \n " , yes_no ( flags & SD_RESOLVED_AUTHENTICATED ) ) ;
2014-08-14 01:00:15 +02:00
}
2014-07-16 22:55:23 +02:00
2014-07-30 17:52:21 +02:00
static int resolve_host ( sd_bus * bus , const char * name ) {
2014-07-16 22:55:23 +02:00
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2014-07-30 17:52:21 +02:00
const char * canonical = NULL ;
2015-08-17 23:54:08 +02:00
char ifname [ IF_NAMESIZE ] = " " ;
2014-07-16 22:55:23 +02:00
unsigned c = 0 ;
2015-08-17 23:54:08 +02:00
int r ;
2014-08-14 01:00:15 +02:00
uint64_t flags ;
2015-08-11 22:37:23 +02:00
usec_t ts ;
2014-07-16 22:55:23 +02:00
assert ( name ) ;
2015-08-17 23:54:08 +02:00
if ( arg_ifindex > 0 & & ! if_indextoname ( arg_ifindex , ifname ) )
return log_error_errno ( errno , " Failed to resolve interface name for index %i: %m " , arg_ifindex ) ;
log_debug ( " Resolving %s (family %s, interface %s). " , name , af_to_name ( arg_family ) ? : " * " , isempty ( ifname ) ? " * " : ifname ) ;
2014-07-16 22:55:23 +02:00
r = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" ResolveHostname " ) ;
2014-07-30 17:11:21 +02:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
2014-07-16 22:55:23 +02:00
2014-08-14 01:00:15 +02:00
r = sd_bus_message_append ( req , " isit " , arg_ifindex , name , arg_family , arg_flags ) ;
2014-07-30 17:11:21 +02:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
2014-07-16 22:55:23 +02:00
2015-08-11 22:37:23 +02:00
ts = now ( CLOCK_MONOTONIC ) ;
2018-01-23 01:53:31 +01:00
r = sd_bus_call ( bus , req , SD_RESOLVED_QUERY_TIMEOUT_USEC , & error , & reply ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
if ( r < 0 )
return log_error_errno ( r , " %s: resolve call failed: %s " , name , bus_error_message ( & error , r ) ) ;
2014-07-16 22:55:23 +02:00
2015-08-11 22:37:23 +02:00
ts = now ( CLOCK_MONOTONIC ) - ts ;
2015-08-17 23:54:08 +02:00
r = sd_bus_message_enter_container ( reply , ' a ' , " (iiay) " ) ;
2014-07-30 17:11:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-16 22:55:23 +02:00
2015-08-17 23:54:08 +02:00
while ( ( r = sd_bus_message_enter_container ( reply , ' r ' , " iiay " ) ) > 0 ) {
2014-07-16 22:55:23 +02:00
_cleanup_free_ char * pretty = NULL ;
2015-08-17 23:54:08 +02:00
int ifindex , family ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
const void * a ;
size_t sz ;
2015-08-17 23:54:08 +02:00
assert_cc ( sizeof ( int ) = = sizeof ( int32_t ) ) ;
2014-07-16 22:55:23 +02:00
2015-08-17 23:54:08 +02:00
r = sd_bus_message_read ( reply , " ii " , & ifindex , & family ) ;
2014-07-30 17:11:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-16 22:55:23 +02:00
r = sd_bus_message_read_array ( reply , ' y ' , & a , & sz ) ;
2014-07-30 17:11:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-16 22:55:23 +02:00
r = sd_bus_message_exit_container ( reply ) ;
2014-07-30 17:11:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-16 22:55:23 +02:00
2014-07-30 17:52:21 +02:00
if ( ! IN_SET ( family , AF_INET , AF_INET6 ) ) {
2014-08-03 09:39:30 +02:00
log_debug ( " %s: skipping entry with family %d (%s) " , name , family , af_to_name ( family ) ? : " unknown " ) ;
2014-07-16 22:55:23 +02:00
continue ;
}
if ( sz ! = FAMILY_ADDRESS_SIZE ( family ) ) {
2015-08-17 23:54:08 +02:00
log_error ( " %s: systemd-resolved returned address of invalid size %zu for family %s " , name , sz , af_to_name ( family ) ? : " unknown " ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
return - EINVAL ;
2014-07-16 22:55:23 +02:00
}
2015-08-17 23:54:08 +02:00
ifname [ 0 ] = 0 ;
if ( ifindex > 0 & & ! if_indextoname ( ifindex , ifname ) )
log_warning_errno ( errno , " Failed to resolve interface name for index %i: %m " , ifindex ) ;
2014-07-16 22:55:23 +02:00
2016-06-14 23:27:30 +02:00
r = in_addr_ifindex_to_string ( family , a , ifindex , & pretty ) ;
2015-08-17 23:54:08 +02:00
if ( r < 0 )
return log_error_errno ( r , " Failed to print address for %s: %m " , name ) ;
2014-07-16 22:55:23 +02:00
2014-07-30 17:52:21 +02:00
printf ( " %*s%s %s%s%s \n " ,
( int ) strlen ( name ) , c = = 0 ? name : " " , c = = 0 ? " : " : " " ,
pretty ,
isempty ( ifname ) ? " " : " % " , ifname ) ;
2014-07-16 22:55:23 +02:00
c + + ;
}
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-08-14 01:00:15 +02:00
r = sd_bus_message_read ( reply , " st " , & canonical , & flags ) ;
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2015-09-08 23:03:38 +02:00
if ( ! streq ( name , canonical ) )
2014-07-30 17:52:21 +02:00
printf ( " %*s%s (%s) \n " ,
( int ) strlen ( name ) , c = = 0 ? name : " " , c = = 0 ? " : " : " " ,
canonical ) ;
2014-07-16 22:55:23 +02:00
if ( c = = 0 ) {
log_error ( " %s: no addresses found " , name ) ;
2014-07-30 17:52:21 +02:00
return - ESRCH ;
}
2015-08-17 23:54:08 +02:00
print_source ( flags , ts ) ;
2014-08-14 01:00:15 +02:00
2014-07-30 17:52:21 +02:00
return 0 ;
}
static int resolve_address ( sd_bus * bus , int family , const union in_addr_union * address , int ifindex ) {
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2014-07-30 17:52:21 +02:00
_cleanup_free_ char * pretty = NULL ;
char ifname [ IF_NAMESIZE ] = " " ;
2014-08-14 01:00:15 +02:00
uint64_t flags ;
2014-07-30 17:52:21 +02:00
unsigned c = 0 ;
2015-08-11 22:37:23 +02:00
usec_t ts ;
2014-07-30 17:52:21 +02:00
int r ;
assert ( bus ) ;
assert ( IN_SET ( family , AF_INET , AF_INET6 ) ) ;
assert ( address ) ;
2015-08-17 23:54:08 +02:00
if ( ifindex < = 0 )
ifindex = arg_ifindex ;
2016-06-14 23:27:30 +02:00
r = in_addr_ifindex_to_string ( family , address , ifindex , & pretty ) ;
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return log_oom ( ) ;
2015-08-17 23:54:08 +02:00
if ( ifindex > 0 & & ! if_indextoname ( ifindex , ifname ) )
return log_error_errno ( errno , " Failed to resolve interface name for index %i: %m " , ifindex ) ;
2014-07-30 17:52:21 +02:00
log_debug ( " Resolving %s%s%s. " , pretty , isempty ( ifname ) ? " " : " % " , ifname ) ;
r = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" ResolveAddress " ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2014-08-14 01:00:15 +02:00
r = sd_bus_message_append ( req , " ii " , ifindex , family ) ;
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
r = sd_bus_message_append_array ( req , ' y ' , address , FAMILY_ADDRESS_SIZE ( family ) ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2014-08-14 01:00:15 +02:00
r = sd_bus_message_append ( req , " t " , arg_flags ) ;
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
2015-08-11 22:37:23 +02:00
ts = now ( CLOCK_MONOTONIC ) ;
2018-01-23 01:53:31 +01:00
r = sd_bus_call ( bus , req , SD_RESOLVED_QUERY_TIMEOUT_USEC , & error , & reply ) ;
2014-07-30 17:52:21 +02:00
if ( r < 0 ) {
log_error ( " %s: resolve call failed: %s " , pretty , bus_error_message ( & error , r ) ) ;
return r ;
}
2015-08-11 22:37:23 +02:00
ts = now ( CLOCK_MONOTONIC ) - ts ;
2015-08-17 23:54:08 +02:00
r = sd_bus_message_enter_container ( reply , ' a ' , " (is) " ) ;
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
2015-08-17 23:54:08 +02:00
while ( ( r = sd_bus_message_enter_container ( reply , ' r ' , " is " ) ) > 0 ) {
const char * n ;
assert_cc ( sizeof ( int ) = = sizeof ( int32_t ) ) ;
2014-07-30 17:52:21 +02:00
2015-08-17 23:54:08 +02:00
r = sd_bus_message_read ( reply , " is " , & ifindex , & n ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return r ;
ifname [ 0 ] = 0 ;
if ( ifindex > 0 & & ! if_indextoname ( ifindex , ifname ) )
log_warning_errno ( errno , " Failed to resolve interface name for index %i: %m " , ifindex ) ;
printf ( " %*s%*s%*s%s %s \n " ,
2014-07-30 17:52:21 +02:00
( int ) strlen ( pretty ) , c = = 0 ? pretty : " " ,
2015-08-17 23:54:08 +02:00
isempty ( ifname ) ? 0 : 1 , c > 0 | | isempty ( ifname ) ? " " : " % " ,
( int ) strlen ( ifname ) , c = = 0 ? ifname : " " ,
2014-07-30 17:52:21 +02:00
c = = 0 ? " : " : " " ,
n ) ;
c + + ;
2014-07-16 22:55:23 +02:00
}
2014-07-30 17:52:21 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-16 22:55:23 +02:00
2014-07-30 17:11:21 +02:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-08-14 01:00:15 +02:00
r = sd_bus_message_read ( reply , " t " , & flags ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-30 17:52:21 +02:00
if ( c = = 0 ) {
log_error ( " %s: no names found " , pretty ) ;
return - ESRCH ;
}
2015-08-17 23:54:08 +02:00
print_source ( flags , ts ) ;
2014-08-14 01:00:15 +02:00
2014-07-30 17:52:21 +02:00
return 0 ;
}
2016-01-31 06:06:49 +01:00
static int output_rr_packet ( const void * d , size_t l , int ifindex ) {
_cleanup_ ( dns_resource_record_unrefp ) DnsResourceRecord * rr = NULL ;
_cleanup_ ( dns_packet_unrefp ) DnsPacket * p = NULL ;
int r ;
char ifname [ IF_NAMESIZE ] = " " ;
2017-10-04 12:35:48 +02:00
r = dns_packet_new ( & p , DNS_PROTOCOL_DNS , 0 , DNS_PACKET_SIZE_MAX ) ;
2016-01-31 06:06:49 +01:00
if ( r < 0 )
return log_oom ( ) ;
p - > refuse_compression = true ;
r = dns_packet_append_blob ( p , d , l , NULL ) ;
if ( r < 0 )
return log_oom ( ) ;
r = dns_packet_read_rr ( p , & rr , NULL , NULL ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse RR: %m " ) ;
if ( arg_raw = = RAW_PAYLOAD ) {
void * data ;
ssize_t k ;
k = dns_resource_record_payload ( rr , & data ) ;
if ( k < 0 )
return log_error_errno ( k , " Cannot dump RR: %m " ) ;
fwrite ( data , 1 , k , stdout ) ;
} else {
const char * s ;
s = dns_resource_record_to_string ( rr ) ;
if ( ! s )
return log_oom ( ) ;
if ( ifindex > 0 & & ! if_indextoname ( ifindex , ifname ) )
log_warning_errno ( errno , " Failed to resolve interface name for index %i: %m " , ifindex ) ;
printf ( " %s%s%s \n " , s , isempty ( ifname ) ? " " : " # interface " , ifname ) ;
}
return 0 ;
}
2016-10-08 13:59:34 +02:00
static int resolve_record ( sd_bus * bus , const char * name , uint16_t class , uint16_t type , bool warn_missing ) {
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2015-08-17 23:54:08 +02:00
char ifname [ IF_NAMESIZE ] = " " ;
2014-07-30 19:23:27 +02:00
unsigned n = 0 ;
2014-08-14 01:00:15 +02:00
uint64_t flags ;
2015-08-17 23:54:08 +02:00
int r ;
2015-08-11 22:37:23 +02:00
usec_t ts ;
2016-02-15 21:25:33 +01:00
bool needs_authentication = false ;
2014-07-30 19:23:27 +02:00
assert ( name ) ;
2015-08-17 23:54:08 +02:00
if ( arg_ifindex > 0 & & ! if_indextoname ( arg_ifindex , ifname ) )
return log_error_errno ( errno , " Failed to resolve interface name for index %i: %m " , arg_ifindex ) ;
2016-01-03 12:58:26 +01:00
log_debug ( " Resolving %s %s %s (interface %s). " , name , dns_class_to_string ( class ) , dns_type_to_string ( type ) , isempty ( ifname ) ? " * " : ifname ) ;
2014-07-30 19:23:27 +02:00
r = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" ResolveRecord " ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2016-01-03 12:58:26 +01:00
r = sd_bus_message_append ( req , " isqqt " , arg_ifindex , name , class , type , arg_flags ) ;
2014-07-30 19:23:27 +02:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
2015-08-11 22:37:23 +02:00
ts = now ( CLOCK_MONOTONIC ) ;
2018-01-23 01:53:31 +01:00
r = sd_bus_call ( bus , req , SD_RESOLVED_QUERY_TIMEOUT_USEC , & error , & reply ) ;
2014-07-30 19:23:27 +02:00
if ( r < 0 ) {
2016-10-08 13:59:34 +02:00
if ( warn_missing | | r ! = - ENXIO )
log_error ( " %s: resolve call failed: %s " , name , bus_error_message ( & error , r ) ) ;
2014-07-30 19:23:27 +02:00
return r ;
}
2015-08-11 22:37:23 +02:00
ts = now ( CLOCK_MONOTONIC ) - ts ;
2015-08-17 23:54:08 +02:00
r = sd_bus_message_enter_container ( reply , ' a ' , " (iqqay) " ) ;
2014-08-14 01:00:15 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2015-08-17 23:54:08 +02:00
while ( ( r = sd_bus_message_enter_container ( reply , ' r ' , " iqqay " ) ) > 0 ) {
2014-07-30 19:23:27 +02:00
uint16_t c , t ;
2015-08-17 23:54:08 +02:00
int ifindex ;
2014-07-30 19:23:27 +02:00
const void * d ;
size_t l ;
2015-08-17 23:54:08 +02:00
assert_cc ( sizeof ( int ) = = sizeof ( int32_t ) ) ;
r = sd_bus_message_read ( reply , " iqq " , & ifindex , & c , & t ) ;
2014-07-30 19:23:27 +02:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_read_array ( reply , ' y ' , & d , & l ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2016-01-31 06:06:49 +01:00
if ( arg_raw = = RAW_PACKET ) {
uint64_t u64 = htole64 ( l ) ;
2014-07-30 19:23:27 +02:00
2016-01-31 06:06:49 +01:00
fwrite ( & u64 , sizeof ( u64 ) , 1 , stdout ) ;
fwrite ( d , 1 , l , stdout ) ;
2016-01-29 00:24:28 +01:00
} else {
2016-01-31 06:06:49 +01:00
r = output_rr_packet ( d , l , ifindex ) ;
if ( r < 0 )
return r ;
2016-01-29 00:24:28 +01:00
}
2015-08-17 23:54:08 +02:00
2016-02-15 21:25:33 +01:00
if ( dns_type_needs_authentication ( t ) )
needs_authentication = true ;
2014-07-30 19:23:27 +02:00
n + + ;
}
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-08-14 01:00:15 +02:00
r = sd_bus_message_read ( reply , " t " , & flags ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2014-07-30 19:23:27 +02:00
if ( n = = 0 ) {
2016-10-08 13:59:34 +02:00
if ( warn_missing )
log_error ( " %s: no records found " , name ) ;
2014-07-30 19:23:27 +02:00
return - ESRCH ;
}
2015-08-17 23:54:08 +02:00
print_source ( flags , ts ) ;
2014-08-14 01:00:15 +02:00
2016-02-15 21:25:33 +01:00
if ( ( flags & SD_RESOLVED_AUTHENTICATED ) = = 0 & & needs_authentication ) {
fflush ( stdout ) ;
fprintf ( stderr , " \n %s "
" WARNING: The resources shown contain cryptographic key data which could not be \n "
" authenticated. It is not suitable to authenticate any communication. \n "
" This is usually indication that DNSSEC authentication was not enabled \n "
" or is not available for the selected protocol or DNS servers.%s \n " ,
ansi_highlight_red ( ) ,
ansi_normal ( ) ) ;
}
2014-07-30 19:23:27 +02:00
return 0 ;
}
2016-01-03 12:58:26 +01:00
static int resolve_rfc4501 ( sd_bus * bus , const char * name ) {
uint16_t type = 0 , class = 0 ;
const char * p , * q , * n ;
int r ;
assert ( bus ) ;
assert ( name ) ;
assert ( startswith ( name , " dns: " ) ) ;
/* Parse RFC 4501 dns: URIs */
p = name + 4 ;
if ( p [ 0 ] = = ' / ' ) {
const char * e ;
if ( p [ 1 ] ! = ' / ' )
goto invalid ;
e = strchr ( p + 2 , ' / ' ) ;
if ( ! e )
goto invalid ;
if ( e ! = p + 2 )
log_warning ( " DNS authority specification not supported; ignoring specified authority. " ) ;
p = e + 1 ;
}
q = strchr ( p , ' ? ' ) ;
if ( q ) {
n = strndupa ( p , q - p ) ;
q + + ;
for ( ; ; ) {
const char * f ;
f = startswith_no_case ( q , " class= " ) ;
if ( f ) {
_cleanup_free_ char * t = NULL ;
const char * e ;
if ( class ! = 0 ) {
log_error ( " DNS class specified twice. " ) ;
return - EINVAL ;
}
e = strchrnul ( f , ' ; ' ) ;
t = strndup ( f , e - f ) ;
if ( ! t )
return log_oom ( ) ;
r = dns_class_from_string ( t ) ;
if ( r < 0 ) {
log_error ( " Unknown DNS class %s. " , t ) ;
return - EINVAL ;
}
class = r ;
if ( * e = = ' ; ' ) {
q = e + 1 ;
continue ;
}
break ;
}
f = startswith_no_case ( q , " type= " ) ;
if ( f ) {
_cleanup_free_ char * t = NULL ;
const char * e ;
if ( type ! = 0 ) {
log_error ( " DNS type specified twice. " ) ;
return - EINVAL ;
}
e = strchrnul ( f , ' ; ' ) ;
t = strndup ( f , e - f ) ;
if ( ! t )
return log_oom ( ) ;
r = dns_type_from_string ( t ) ;
if ( r < 0 ) {
log_error ( " Unknown DNS type %s. " , t ) ;
return - EINVAL ;
}
type = r ;
if ( * e = = ' ; ' ) {
q = e + 1 ;
continue ;
}
break ;
}
goto invalid ;
}
} else
n = p ;
if ( class = = 0 )
2016-01-29 00:24:27 +01:00
class = arg_class ? : DNS_CLASS_IN ;
if ( type = = 0 )
type = arg_type ? : DNS_TYPE_A ;
2016-01-03 12:58:26 +01:00
2016-10-08 13:59:34 +02:00
return resolve_record ( bus , n , class , type , true ) ;
2016-01-03 12:58:26 +01:00
invalid :
log_error ( " Invalid DNS URI: %s " , name ) ;
return - EINVAL ;
}
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
static int resolve_service ( sd_bus * bus , const char * name , const char * type , const char * domain ) {
const char * canonical_name , * canonical_type , * canonical_domain ;
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
char ifname [ IF_NAMESIZE ] = " " ;
size_t indent , sz ;
uint64_t flags ;
const char * p ;
unsigned c ;
usec_t ts ;
int r ;
assert ( bus ) ;
assert ( domain ) ;
2016-05-30 17:59:43 +02:00
name = empty_to_null ( name ) ;
type = empty_to_null ( type ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
if ( arg_ifindex > 0 & & ! if_indextoname ( arg_ifindex , ifname ) )
return log_error_errno ( errno , " Failed to resolve interface name for index %i: %m " , arg_ifindex ) ;
if ( name )
log_debug ( " Resolving service \" %s \" of type %s in %s (family %s, interface %s). " , name , type , domain , af_to_name ( arg_family ) ? : " * " , isempty ( ifname ) ? " * " : ifname ) ;
else if ( type )
log_debug ( " Resolving service type %s of %s (family %s, interface %s). " , type , domain , af_to_name ( arg_family ) ? : " * " , isempty ( ifname ) ? " * " : ifname ) ;
else
log_debug ( " Resolving service type %s (family %s, interface %s). " , domain , af_to_name ( arg_family ) ? : " * " , isempty ( ifname ) ? " * " : ifname ) ;
r = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" ResolveService " ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
r = sd_bus_message_append ( req , " isssit " , arg_ifindex , name , type , domain , arg_family , arg_flags ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
ts = now ( CLOCK_MONOTONIC ) ;
2018-01-23 01:53:31 +01:00
r = sd_bus_call ( bus , req , SD_RESOLVED_QUERY_TIMEOUT_USEC , & error , & reply ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
if ( r < 0 )
return log_error_errno ( r , " Resolve call failed: %s " , bus_error_message ( & error , r ) ) ;
ts = now ( CLOCK_MONOTONIC ) - ts ;
r = sd_bus_message_enter_container ( reply , ' a ' , " (qqqsa(iiay)s) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
indent =
( name ? strlen ( name ) + 1 : 0 ) +
( type ? strlen ( type ) + 1 : 0 ) +
strlen ( domain ) + 2 ;
c = 0 ;
while ( ( r = sd_bus_message_enter_container ( reply , ' r ' , " qqqsa(iiay)s " ) ) > 0 ) {
uint16_t priority , weight , port ;
const char * hostname , * canonical ;
r = sd_bus_message_read ( reply , " qqqs " , & priority , & weight , & port , & hostname ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
if ( name )
printf ( " %*s%s " , ( int ) strlen ( name ) , c = = 0 ? name : " " , c = = 0 ? " / " : " " ) ;
if ( type )
printf ( " %*s%s " , ( int ) strlen ( type ) , c = = 0 ? type : " " , c = = 0 ? " / " : " " ) ;
printf ( " %*s%s %s:%u [priority=%u, weight=%u] \n " ,
( int ) strlen ( domain ) , c = = 0 ? domain : " " ,
c = = 0 ? " : " : " " ,
hostname , port ,
priority , weight ) ;
r = sd_bus_message_enter_container ( reply , ' a ' , " (iiay) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
while ( ( r = sd_bus_message_enter_container ( reply , ' r ' , " iiay " ) ) > 0 ) {
_cleanup_free_ char * pretty = NULL ;
int ifindex , family ;
const void * a ;
assert_cc ( sizeof ( int ) = = sizeof ( int32_t ) ) ;
r = sd_bus_message_read ( reply , " ii " , & ifindex , & family ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_read_array ( reply , ' y ' , & a , & sz ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
if ( ! IN_SET ( family , AF_INET , AF_INET6 ) ) {
log_debug ( " %s: skipping entry with family %d (%s) " , name , family , af_to_name ( family ) ? : " unknown " ) ;
continue ;
}
if ( sz ! = FAMILY_ADDRESS_SIZE ( family ) ) {
log_error ( " %s: systemd-resolved returned address of invalid size %zu for family %s " , name , sz , af_to_name ( family ) ? : " unknown " ) ;
return - EINVAL ;
}
ifname [ 0 ] = 0 ;
if ( ifindex > 0 & & ! if_indextoname ( ifindex , ifname ) )
log_warning_errno ( errno , " Failed to resolve interface name for index %i: %m " , ifindex ) ;
r = in_addr_to_string ( family , a , & pretty ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to print address for %s: %m " , name ) ;
printf ( " %*s%s%s%s \n " , ( int ) indent , " " , pretty , isempty ( ifname ) ? " " : " %s " , ifname ) ;
}
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_read ( reply , " s " , & canonical ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
if ( ! streq ( hostname , canonical ) )
printf ( " %*s(%s) \n " , ( int ) indent , " " , canonical ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
c + + ;
}
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_enter_container ( reply , ' a ' , " ay " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
while ( ( r = sd_bus_message_read_array ( reply , ' y ' , ( const void * * ) & p , & sz ) ) > 0 ) {
_cleanup_free_ char * escaped = NULL ;
escaped = cescape_length ( p , sz ) ;
if ( ! escaped )
return log_oom ( ) ;
printf ( " %*s%s \n " , ( int ) indent , " " , escaped ) ;
}
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_read ( reply , " ssst " , & canonical_name , & canonical_type , & canonical_domain , & flags ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2016-05-30 17:59:43 +02:00
canonical_name = empty_to_null ( canonical_name ) ;
canonical_type = empty_to_null ( canonical_type ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
if ( ! streq_ptr ( name , canonical_name ) | |
! streq_ptr ( type , canonical_type ) | |
! streq_ptr ( domain , canonical_domain ) ) {
printf ( " %*s( " , ( int ) indent , " " ) ;
if ( canonical_name )
printf ( " %s/ " , canonical_name ) ;
if ( canonical_type )
printf ( " %s/ " , canonical_type ) ;
printf ( " %s) \n " , canonical_domain ) ;
}
print_source ( flags , ts ) ;
return 0 ;
}
2016-01-29 00:24:27 +01:00
static int resolve_openpgp ( sd_bus * bus , const char * address ) {
const char * domain , * full ;
int r ;
_cleanup_free_ char * hashed = NULL ;
assert ( bus ) ;
assert ( address ) ;
domain = strrchr ( address , ' @ ' ) ;
if ( ! domain ) {
log_error ( " Address does not contain '@': \" %s \" " , address ) ;
return - EINVAL ;
} else if ( domain = = address | | domain [ 1 ] = = ' \0 ' ) {
log_error ( " Address starts or ends with '@': \" %s \" " , address ) ;
return - EINVAL ;
}
domain + + ;
2016-10-08 13:59:34 +02:00
r = string_hashsum_sha256 ( address , domain - 1 - address , & hashed ) ;
2016-01-29 00:24:27 +01:00
if ( r < 0 )
return log_error_errno ( r , " Hashing failed: %m " ) ;
2016-10-08 13:59:34 +02:00
strshorten ( hashed , 56 ) ;
2016-01-29 00:24:27 +01:00
full = strjoina ( hashed , " ._openpgpkey. " , domain ) ;
log_debug ( " Looking up \" %s \" . " , full ) ;
2016-10-08 13:59:34 +02:00
r = resolve_record ( bus , full ,
arg_class ? : DNS_CLASS_IN ,
arg_type ? : DNS_TYPE_OPENPGPKEY , false ) ;
if ( IN_SET ( r , - ENXIO , - ESRCH ) ) { /* NXDOMAIN or NODATA? */
hashed = NULL ;
r = string_hashsum_sha224 ( address , domain - 1 - address , & hashed ) ;
if ( r < 0 )
return log_error_errno ( r , " Hashing failed: %m " ) ;
full = strjoina ( hashed , " ._openpgpkey. " , domain ) ;
log_debug ( " Looking up \" %s \" . " , full ) ;
return resolve_record ( bus , full ,
arg_class ? : DNS_CLASS_IN ,
arg_type ? : DNS_TYPE_OPENPGPKEY , true ) ;
}
return r ;
2016-01-29 00:24:27 +01:00
}
2016-02-18 03:08:57 +01:00
static int resolve_tlsa ( sd_bus * bus , const char * address ) {
const char * port ;
uint16_t port_num = 443 ;
_cleanup_free_ char * full = NULL ;
int r ;
assert ( bus ) ;
assert ( address ) ;
port = strrchr ( address , ' : ' ) ;
if ( port ) {
2016-12-06 12:21:45 +01:00
r = parse_ip_port ( port + 1 , & port_num ) ;
if ( r < 0 )
2016-02-18 03:08:57 +01:00
return log_error_errno ( r , " Invalid port \" %s \" . " , port + 1 ) ;
address = strndupa ( address , port - address ) ;
}
r = asprintf ( & full , " _%u.%s.%s " ,
port_num ,
service_family_to_string ( arg_service_family ) ,
address ) ;
if ( r < 0 )
return log_oom ( ) ;
log_debug ( " Looking up \" %s \" . " , full ) ;
return resolve_record ( bus , full ,
arg_class ? : DNS_CLASS_IN ,
2016-10-08 13:59:34 +02:00
arg_type ? : DNS_TYPE_TLSA , true ) ;
2016-02-18 03:08:57 +01:00
}
2015-12-23 19:06:36 +01:00
static int show_statistics ( sd_bus * bus ) {
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * reply = NULL ;
uint64_t n_current_transactions , n_total_transactions ,
cache_size , n_cache_hit , n_cache_miss ,
n_dnssec_secure , n_dnssec_insecure , n_dnssec_bogus , n_dnssec_indeterminate ;
2016-01-19 17:11:28 +01:00
int r , dnssec_supported ;
2015-12-23 19:06:36 +01:00
assert ( bus ) ;
2016-01-19 17:11:28 +01:00
r = sd_bus_get_property_trivial ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" DNSSECSupported " ,
& error ,
' b ' ,
& dnssec_supported ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to get DNSSEC supported state: %s " , bus_error_message ( & error , r ) ) ;
printf ( " DNSSEC supported by current servers: %s%s%s \n \n " ,
ansi_highlight ( ) ,
yes_no ( dnssec_supported ) ,
ansi_normal ( ) ) ;
2015-12-23 19:06:36 +01:00
r = sd_bus_get_property ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" TransactionStatistics " ,
& error ,
& reply ,
" (tt) " ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to get transaction statistics: %s " , bus_error_message ( & error , r ) ) ;
r = sd_bus_message_read ( reply , " (tt) " ,
& n_current_transactions ,
& n_total_transactions ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
printf ( " %sTransactions%s \n "
" Current Transactions: % " PRIu64 " \n "
" Total Transactions: % " PRIu64 " \n " ,
ansi_highlight ( ) ,
ansi_normal ( ) ,
n_current_transactions ,
n_total_transactions ) ;
reply = sd_bus_message_unref ( reply ) ;
r = sd_bus_get_property ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" CacheStatistics " ,
& error ,
& reply ,
" (ttt) " ) ;
2015-12-27 23:57:58 +01:00
if ( r < 0 )
return log_error_errno ( r , " Failed to get cache statistics: %s " , bus_error_message ( & error , r ) ) ;
2015-12-23 19:06:36 +01:00
r = sd_bus_message_read ( reply , " (ttt) " ,
& cache_size ,
& n_cache_hit ,
& n_cache_miss ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
printf ( " \n %sCache%s \n "
" Current Cache Size: % " PRIu64 " \n "
" Cache Hits: % " PRIu64 " \n "
" Cache Misses: % " PRIu64 " \n " ,
ansi_highlight ( ) ,
ansi_normal ( ) ,
cache_size ,
n_cache_hit ,
n_cache_miss ) ;
reply = sd_bus_message_unref ( reply ) ;
r = sd_bus_get_property ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" DNSSECStatistics " ,
& error ,
& reply ,
" (tttt) " ) ;
2015-12-27 23:57:58 +01:00
if ( r < 0 )
return log_error_errno ( r , " Failed to get DNSSEC statistics: %s " , bus_error_message ( & error , r ) ) ;
2015-12-23 19:06:36 +01:00
r = sd_bus_message_read ( reply , " (tttt) " ,
& n_dnssec_secure ,
& n_dnssec_insecure ,
& n_dnssec_bogus ,
& n_dnssec_indeterminate ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2016-01-21 02:27:44 +01:00
printf ( " \n %sDNSSEC Verdicts%s \n "
" Secure: % " PRIu64 " \n "
" Insecure: % " PRIu64 " \n "
" Bogus: % " PRIu64 " \n "
" Indeterminate: % " PRIu64 " \n " ,
2015-12-23 19:06:36 +01:00
ansi_highlight ( ) ,
ansi_normal ( ) ,
n_dnssec_secure ,
n_dnssec_insecure ,
n_dnssec_bogus ,
n_dnssec_indeterminate ) ;
return 0 ;
}
static int reset_statistics ( sd_bus * bus ) {
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
int r ;
r = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" ResetStatistics " ,
& error ,
NULL ,
NULL ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to reset statistics: %s " , bus_error_message ( & error , r ) ) ;
return 0 ;
}
2016-06-10 20:40:30 +02:00
static int flush_caches ( sd_bus * bus ) {
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
int r ;
r = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" FlushCaches " ,
& error ,
NULL ,
NULL ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to flush caches: %s " , bus_error_message ( & error , r ) ) ;
return 0 ;
}
2017-09-29 21:19:54 +02:00
static int reset_server_features ( sd_bus * bus ) {
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
int r ;
r = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" ResetServerFeatures " ,
& error ,
NULL ,
NULL ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to reset server features: %s " , bus_error_message ( & error , r ) ) ;
return 0 ;
}
2016-06-15 21:43:36 +02:00
static int map_link_dns_servers ( sd_bus * bus , const char * member , sd_bus_message * m , sd_bus_error * error , void * userdata ) {
char * * * l = userdata ;
int r ;
assert ( bus ) ;
assert ( member ) ;
assert ( m ) ;
assert ( l ) ;
r = sd_bus_message_enter_container ( m , ' a ' , " (iay) " ) ;
if ( r < 0 )
return r ;
for ( ; ; ) {
const void * a ;
char * pretty ;
int family ;
size_t sz ;
r = sd_bus_message_enter_container ( m , ' r ' , " iay " ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
r = sd_bus_message_read ( m , " i " , & family ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_read_array ( m , ' y ' , & a , & sz ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return r ;
if ( ! IN_SET ( family , AF_INET , AF_INET6 ) ) {
log_debug ( " Unexpected family, ignoring. " ) ;
continue ;
}
if ( sz ! = FAMILY_ADDRESS_SIZE ( family ) ) {
log_debug ( " Address size mismatch, ignoring. " ) ;
continue ;
}
r = in_addr_to_string ( family , a , & pretty ) ;
if ( r < 0 )
return r ;
r = strv_consume ( l , pretty ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return r ;
return 0 ;
}
static int map_link_domains ( sd_bus * bus , const char * member , sd_bus_message * m , sd_bus_error * error , void * userdata ) {
char * * * l = userdata ;
int r ;
assert ( bus ) ;
assert ( member ) ;
assert ( m ) ;
assert ( l ) ;
r = sd_bus_message_enter_container ( m , ' a ' , " (sb) " ) ;
if ( r < 0 )
return r ;
for ( ; ; ) {
const char * domain ;
int route_only ;
char * pretty ;
r = sd_bus_message_read ( m , " (sb) " , & domain , & route_only ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
if ( route_only )
pretty = strappend ( " ~ " , domain ) ;
else
pretty = strdup ( domain ) ;
if ( ! pretty )
return - ENOMEM ;
r = strv_consume ( l , pretty ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return r ;
return 0 ;
}
static int status_ifindex ( sd_bus * bus , int ifindex , const char * name , bool * empty_line ) {
struct link_info {
uint64_t scopes_mask ;
char * llmnr ;
char * mdns ;
char * dnssec ;
char * * dns ;
char * * domains ;
char * * ntas ;
int dnssec_supported ;
} link_info = { } ;
static const struct bus_properties_map property_map [ ] = {
{ " ScopesMask " , " t " , NULL , offsetof ( struct link_info , scopes_mask ) } ,
{ " DNS " , " a(iay) " , map_link_dns_servers , offsetof ( struct link_info , dns ) } ,
{ " Domains " , " a(sb) " , map_link_domains , offsetof ( struct link_info , domains ) } ,
{ " LLMNR " , " s " , NULL , offsetof ( struct link_info , llmnr ) } ,
{ " MulticastDNS " , " s " , NULL , offsetof ( struct link_info , mdns ) } ,
{ " DNSSEC " , " s " , NULL , offsetof ( struct link_info , dnssec ) } ,
{ " DNSSECNegativeTrustAnchors " , " as " , NULL , offsetof ( struct link_info , ntas ) } ,
{ " DNSSECSupported " , " b " , NULL , offsetof ( struct link_info , dnssec_supported ) } ,
{ }
} ;
2017-02-08 17:59:58 +01:00
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2016-06-15 21:43:36 +02:00
_cleanup_free_ char * ifi = NULL , * p = NULL ;
char ifname [ IF_NAMESIZE ] = " " ;
char * * i ;
int r ;
assert ( bus ) ;
assert ( ifindex > 0 ) ;
assert ( empty_line ) ;
if ( ! name ) {
if ( ! if_indextoname ( ifindex , ifname ) )
return log_error_errno ( errno , " Failed to resolve interface name for %i: %m " , ifindex ) ;
name = ifname ;
}
if ( asprintf ( & ifi , " %i " , ifindex ) < 0 )
return log_oom ( ) ;
r = sd_bus_path_encode ( " /org/freedesktop/resolve1/link " , ifi , & p ) ;
if ( r < 0 )
return log_oom ( ) ;
r = bus_map_all_properties ( bus ,
" org.freedesktop.resolve1 " ,
p ,
property_map ,
2017-02-08 17:59:58 +01:00
& error ,
2016-06-15 21:43:36 +02:00
& link_info ) ;
if ( r < 0 ) {
2017-02-08 17:59:58 +01:00
log_error_errno ( r , " Failed to get link data for %i: %s " , ifindex , bus_error_message ( & error , r ) ) ;
2016-06-15 21:43:36 +02:00
goto finish ;
}
pager_open ( arg_no_pager , false ) ;
if ( * empty_line )
fputc ( ' \n ' , stdout ) ;
printf ( " %sLink %i (%s)%s \n " ,
ansi_highlight ( ) , ifindex , name , ansi_normal ( ) ) ;
if ( link_info . scopes_mask = = 0 )
printf ( " Current Scopes: none \n " ) ;
else
printf ( " Current Scopes:%s%s%s%s%s \n " ,
link_info . scopes_mask & SD_RESOLVED_DNS ? " DNS " : " " ,
link_info . scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4 " : " " ,
link_info . scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6 " : " " ,
link_info . scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4 " : " " ,
link_info . scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6 " : " " ) ;
printf ( " LLMNR setting: %s \n "
" MulticastDNS setting: %s \n "
" DNSSEC setting: %s \n "
" DNSSEC supported: %s \n " ,
strna ( link_info . llmnr ) ,
strna ( link_info . mdns ) ,
strna ( link_info . dnssec ) ,
yes_no ( link_info . dnssec_supported ) ) ;
STRV_FOREACH ( i , link_info . dns ) {
2016-06-28 19:51:30 +02:00
printf ( " %s %s \n " ,
i = = link_info . dns ? " DNS Servers: " : " " ,
2016-06-15 21:43:36 +02:00
* i ) ;
}
STRV_FOREACH ( i , link_info . domains ) {
printf ( " %s %s \n " ,
i = = link_info . domains ? " DNS Domain: " : " " ,
* i ) ;
}
STRV_FOREACH ( i , link_info . ntas ) {
printf ( " %s %s \n " ,
i = = link_info . ntas ? " DNSSEC NTA: " : " " ,
* i ) ;
}
* empty_line = true ;
r = 0 ;
finish :
strv_free ( link_info . dns ) ;
strv_free ( link_info . domains ) ;
free ( link_info . llmnr ) ;
free ( link_info . mdns ) ;
free ( link_info . dnssec ) ;
strv_free ( link_info . ntas ) ;
return r ;
}
static int map_global_dns_servers ( sd_bus * bus , const char * member , sd_bus_message * m , sd_bus_error * error , void * userdata ) {
char * * * l = userdata ;
int r ;
assert ( bus ) ;
assert ( member ) ;
assert ( m ) ;
assert ( l ) ;
r = sd_bus_message_enter_container ( m , ' a ' , " (iiay) " ) ;
if ( r < 0 )
return r ;
for ( ; ; ) {
const void * a ;
char * pretty ;
int family , ifindex ;
size_t sz ;
r = sd_bus_message_enter_container ( m , ' r ' , " iiay " ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
r = sd_bus_message_read ( m , " ii " , & ifindex , & family ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_read_array ( m , ' y ' , & a , & sz ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return r ;
if ( ifindex ! = 0 ) /* only show the global ones here */
continue ;
if ( ! IN_SET ( family , AF_INET , AF_INET6 ) ) {
log_debug ( " Unexpected family, ignoring. " ) ;
continue ;
}
if ( sz ! = FAMILY_ADDRESS_SIZE ( family ) ) {
log_debug ( " Address size mismatch, ignoring. " ) ;
continue ;
}
r = in_addr_to_string ( family , a , & pretty ) ;
if ( r < 0 )
return r ;
r = strv_consume ( l , pretty ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return r ;
return 0 ;
}
static int map_global_domains ( sd_bus * bus , const char * member , sd_bus_message * m , sd_bus_error * error , void * userdata ) {
char * * * l = userdata ;
int r ;
assert ( bus ) ;
assert ( member ) ;
assert ( m ) ;
assert ( l ) ;
r = sd_bus_message_enter_container ( m , ' a ' , " (isb) " ) ;
if ( r < 0 )
return r ;
for ( ; ; ) {
const char * domain ;
int route_only , ifindex ;
char * pretty ;
r = sd_bus_message_read ( m , " (isb) " , & ifindex , & domain , & route_only ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
break ;
if ( ifindex ! = 0 ) /* only show the global ones here */
continue ;
if ( route_only )
pretty = strappend ( " ~ " , domain ) ;
else
pretty = strdup ( domain ) ;
if ( ! pretty )
return - ENOMEM ;
r = strv_consume ( l , pretty ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return r ;
return 0 ;
}
static int status_global ( sd_bus * bus , bool * empty_line ) {
struct global_info {
char * * dns ;
char * * domains ;
char * * ntas ;
} global_info = { } ;
static const struct bus_properties_map property_map [ ] = {
{ " DNS " , " a(iiay) " , map_global_dns_servers , offsetof ( struct global_info , dns ) } ,
{ " Domains " , " a(isb) " , map_global_domains , offsetof ( struct global_info , domains ) } ,
{ " DNSSECNegativeTrustAnchors " , " as " , NULL , offsetof ( struct global_info , ntas ) } ,
{ }
} ;
2017-02-08 17:59:58 +01:00
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2016-06-15 21:43:36 +02:00
char * * i ;
int r ;
assert ( bus ) ;
assert ( empty_line ) ;
r = bus_map_all_properties ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
property_map ,
2017-02-08 17:59:58 +01:00
& error ,
2016-06-15 21:43:36 +02:00
& global_info ) ;
if ( r < 0 ) {
2017-02-08 17:59:58 +01:00
log_error_errno ( r , " Failed to get global data: %s " , bus_error_message ( & error , r ) ) ;
2016-06-15 21:43:36 +02:00
goto finish ;
}
if ( strv_isempty ( global_info . dns ) & & strv_isempty ( global_info . domains ) & & strv_isempty ( global_info . ntas ) ) {
r = 0 ;
goto finish ;
}
pager_open ( arg_no_pager , false ) ;
printf ( " %sGlobal%s \n " , ansi_highlight ( ) , ansi_normal ( ) ) ;
STRV_FOREACH ( i , global_info . dns ) {
2016-06-28 19:51:30 +02:00
printf ( " %s %s \n " ,
i = = global_info . dns ? " DNS Servers: " : " " ,
2016-06-15 21:43:36 +02:00
* i ) ;
}
STRV_FOREACH ( i , global_info . domains ) {
printf ( " %s %s \n " ,
i = = global_info . domains ? " DNS Domain: " : " " ,
* i ) ;
}
strv_sort ( global_info . ntas ) ;
STRV_FOREACH ( i , global_info . ntas ) {
printf ( " %s %s \n " ,
i = = global_info . ntas ? " DNSSEC NTA: " : " " ,
* i ) ;
}
* empty_line = true ;
r = 0 ;
finish :
strv_free ( global_info . dns ) ;
strv_free ( global_info . domains ) ;
strv_free ( global_info . ntas ) ;
return r ;
}
static int status_all ( sd_bus * bus ) {
_cleanup_ ( sd_netlink_message_unrefp ) sd_netlink_message * req = NULL , * reply = NULL ;
_cleanup_ ( sd_netlink_unrefp ) sd_netlink * rtnl = NULL ;
sd_netlink_message * i ;
2016-06-28 19:55:58 +02:00
bool empty_line = false ;
2016-06-15 21:43:36 +02:00
int r ;
assert ( bus ) ;
r = status_global ( bus , & empty_line ) ;
if ( r < 0 )
return r ;
r = sd_netlink_open ( & rtnl ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to connect to netlink: %m " ) ;
r = sd_rtnl_message_new_link ( rtnl , & req , RTM_GETLINK , 0 ) ;
if ( r < 0 )
return rtnl_log_create_error ( r ) ;
r = sd_netlink_message_request_dump ( req , true ) ;
if ( r < 0 )
return rtnl_log_create_error ( r ) ;
r = sd_netlink_call ( rtnl , req , 0 , & reply ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to enumerate links: %m " ) ;
r = 0 ;
for ( i = reply ; i ; i = sd_netlink_message_next ( i ) ) {
const char * name ;
int ifindex , q ;
uint16_t type ;
q = sd_netlink_message_get_type ( i , & type ) ;
if ( q < 0 )
return rtnl_log_parse_error ( q ) ;
if ( type ! = RTM_NEWLINK )
continue ;
q = sd_rtnl_message_link_get_ifindex ( i , & ifindex ) ;
if ( q < 0 )
return rtnl_log_parse_error ( q ) ;
if ( ifindex = = LOOPBACK_IFINDEX )
continue ;
q = sd_netlink_message_read_string ( i , IFLA_IFNAME , & name ) ;
if ( q < 0 )
return rtnl_log_parse_error ( q ) ;
q = status_ifindex ( bus , ifindex , name , & empty_line ) ;
if ( q < 0 & & r > = 0 )
r = q ;
}
return r ;
}
2017-12-14 20:13:14 +01:00
static int set_link ( sd_bus * bus ) {
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
int r = 0 , q ;
assert ( bus ) ;
if ( arg_n_set_dns > 0 ) {
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL ;
size_t i ;
q = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" SetLinkDNS " ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_append ( req , " i " , arg_ifindex ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_open_container ( req , ' a ' , " (iay) " ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
for ( i = 0 ; i < arg_n_set_dns ; i + + ) {
q = sd_bus_message_open_container ( req , ' r ' , " iay " ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_append ( req , " i " , arg_set_dns [ i ] . family ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_append_array ( req , ' y ' , & arg_set_dns [ i ] . address , FAMILY_ADDRESS_SIZE ( arg_set_dns [ i ] . family ) ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_close_container ( req ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
}
q = sd_bus_message_close_container ( req ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_call ( bus , req , 0 , & error , NULL ) ;
if ( q < 0 ) {
if ( sd_bus_error_has_name ( & error , BUS_ERROR_LINK_BUSY ) )
goto is_managed ;
log_error_errno ( q , " Failed to set DNS configuration: %s " , bus_error_message ( & error , q ) ) ;
if ( r = = 0 )
r = q ;
}
}
if ( ! strv_isempty ( arg_set_domain ) ) {
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL ;
char * * p ;
q = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" SetLinkDomains " ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_append ( req , " i " , arg_ifindex ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_open_container ( req , ' a ' , " (sb) " ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
STRV_FOREACH ( p , arg_set_domain ) {
const char * n ;
n = * * p = = ' ~ ' ? * p + 1 : * p ;
q = sd_bus_message_append ( req , " (sb) " , n , * * p = = ' ~ ' ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
}
q = sd_bus_message_close_container ( req ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_call ( bus , req , 0 , & error , NULL ) ;
if ( q < 0 ) {
if ( sd_bus_error_has_name ( & error , BUS_ERROR_LINK_BUSY ) )
goto is_managed ;
log_error_errno ( q , " Failed to set domain configuration: %s " , bus_error_message ( & error , q ) ) ;
if ( r = = 0 )
r = q ;
}
}
if ( arg_set_llmnr ) {
q = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" SetLinkLLMNR " ,
& error ,
NULL ,
" is " , arg_ifindex , arg_set_llmnr ) ;
if ( q < 0 ) {
if ( sd_bus_error_has_name ( & error , BUS_ERROR_LINK_BUSY ) )
goto is_managed ;
log_error_errno ( q , " Failed to set LLMNR configuration: %s " , bus_error_message ( & error , q ) ) ;
if ( r = = 0 )
r = q ;
}
}
if ( arg_set_mdns ) {
q = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" SetLinkMulticastDNS " ,
& error ,
NULL ,
" is " , arg_ifindex , arg_set_mdns ) ;
if ( q < 0 ) {
if ( sd_bus_error_has_name ( & error , BUS_ERROR_LINK_BUSY ) )
goto is_managed ;
log_error_errno ( q , " Failed to set MulticastDNS configuration: %s " , bus_error_message ( & error , q ) ) ;
if ( r = = 0 )
r = q ;
}
}
if ( arg_set_dnssec ) {
q = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" SetLinkDNSSEC " ,
& error ,
NULL ,
" is " , arg_ifindex , arg_set_dnssec ) ;
if ( q < 0 ) {
if ( sd_bus_error_has_name ( & error , BUS_ERROR_LINK_BUSY ) )
goto is_managed ;
log_error_errno ( q , " Failed to set DNSSEC configuration: %s " , bus_error_message ( & error , q ) ) ;
if ( r = = 0 )
r = q ;
}
}
if ( ! strv_isempty ( arg_set_nta ) ) {
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * req = NULL ;
q = sd_bus_message_new_method_call (
bus ,
& req ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" SetLinkDNSSECNegativeTrustAnchors " ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_append ( req , " i " , arg_ifindex ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_message_append_strv ( req , arg_set_nta ) ;
if ( q < 0 )
return bus_log_create_error ( q ) ;
q = sd_bus_call ( bus , req , 0 , & error , NULL ) ;
if ( q < 0 ) {
if ( sd_bus_error_has_name ( & error , BUS_ERROR_LINK_BUSY ) )
goto is_managed ;
log_error_errno ( q , " Failed to set DNSSEC NTA configuration: %s " , bus_error_message ( & error , q ) ) ;
if ( r = = 0 )
r = q ;
}
}
return r ;
is_managed :
{
char ifname [ IFNAMSIZ ] ;
return log_error_errno ( q ,
" The specified interface %s is managed by systemd-networkd. Operation refused. \n "
" Please configure DNS settings for systemd-networkd managed interfaces directly in their .network files. " , strna ( if_indextoname ( arg_ifindex , ifname ) ) ) ;
}
}
static int revert_link ( sd_bus * bus ) {
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
int r ;
assert ( bus ) ;
r = sd_bus_call_method ( bus ,
" org.freedesktop.resolve1 " ,
" /org/freedesktop/resolve1 " ,
" org.freedesktop.resolve1.Manager " ,
" RevertLink " ,
& error ,
NULL ,
" i " , arg_ifindex ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to revert interface configuration: %s " , bus_error_message ( & error , r ) ) ;
return 0 ;
}
2015-02-05 03:06:36 +01:00
static void help_protocol_types ( void ) {
if ( arg_legend )
puts ( " Known protocol types: " ) ;
2017-11-23 13:12:00 +01:00
puts ( " dns \n llmnr \n llmnr-ipv4 \n llmnr-ipv6 \n mdns \n mdns-ipv4 \n mdns-ipv6 " ) ;
2015-02-05 03:06:36 +01:00
}
2014-08-01 02:06:30 +02:00
static void help_dns_types ( void ) {
const char * t ;
2016-06-15 21:43:36 +02:00
int i ;
2014-08-01 02:06:30 +02:00
if ( arg_legend )
2015-08-21 16:06:25 +02:00
puts ( " Known DNS RR types: " ) ;
2014-08-01 02:06:30 +02:00
for ( i = 0 ; i < _DNS_TYPE_MAX ; i + + ) {
t = dns_type_to_string ( i ) ;
if ( t )
puts ( t ) ;
}
}
static void help_dns_classes ( void ) {
const char * t ;
2016-06-15 21:43:36 +02:00
int i ;
2014-08-01 02:06:30 +02:00
if ( arg_legend )
2015-08-21 16:06:25 +02:00
puts ( " Known DNS RR classes: " ) ;
2014-08-01 02:06:30 +02:00
for ( i = 0 ; i < _DNS_CLASS_MAX ; i + + ) {
t = dns_class_to_string ( i ) ;
if ( t )
puts ( t ) ;
}
}
2014-07-16 22:55:23 +02:00
static void help ( void ) {
2016-02-15 19:15:23 +01:00
printf ( " %1$s [OPTIONS...] HOSTNAME|ADDRESS... \n "
" %1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN \n "
" %1$s [OPTIONS...] --openpgp EMAIL@DOMAIN... \n "
" %1$s [OPTIONS...] --statistics \n "
" %1$s [OPTIONS...] --reset-statistics \n "
" \n "
2016-08-04 02:05:37 +02:00
" Resolve domain names, IPv4 and IPv6 addresses, DNS records, and services. \n \n "
2016-02-15 19:15:23 +01:00
" -h --help Show this help \n "
" --version Show package version \n "
2016-06-15 21:43:36 +02:00
" --no-pager Do not pipe output into a pager \n "
2016-02-15 19:15:23 +01:00
" -4 Resolve IPv4 addresses \n "
" -6 Resolve IPv6 addresses \n "
" -i --interface=INTERFACE Look on interface \n "
" -p --protocol=PROTO|help Look via protocol \n "
" -t --type=TYPE|help Query RR with DNS type \n "
" -c --class=CLASS|help Query RR with DNS class \n "
" --service Resolve service (SRV) \n "
" --service-address=BOOL Resolve address for services (default: yes) \n "
" --service-txt=BOOL Resolve TXT records for services (default: yes) \n "
" --openpgp Query OpenPGP public key \n "
2016-02-18 03:08:57 +01:00
" --tlsa Query TLS public key \n "
2016-02-15 19:15:23 +01:00
" --cname=BOOL Follow CNAME redirects (default: yes) \n "
" --search=BOOL Use search domains for single-label names \n "
" (default: yes) \n "
2016-01-31 06:06:49 +01:00
" --raw[=payload|packet] Dump the answer as binary data \n "
2016-02-15 19:15:23 +01:00
" --legend=BOOL Print headers and additional info (default: yes) \n "
" --statistics Show resolver statistics \n "
" --reset-statistics Reset resolver statistics \n "
2016-06-15 21:43:36 +02:00
" --status Show link and server status \n "
2016-06-10 20:40:30 +02:00
" --flush-caches Flush all local DNS caches \n "
2017-09-29 21:19:54 +02:00
" --reset-server-features \n "
" Forget learnt DNS server feature levels \n "
2017-12-14 20:13:14 +01:00
" --set-dns=SERVER Set per-interface DNS server address \n "
" --set-domain=DOMAIN Set per-interface search domain \n "
" --set-llmnr=MODE Set per-interface LLMNR mode \n "
" --set-mdns=MODE Set per-interface MulticastDNS mode \n "
" --set-dnssec=MODE Set per-interface DNSSEC mode \n "
" --set-nta=DOMAIN Set per-interface DNSSEC NTA \n "
" --revert Revert per-interface configuration \n "
2016-02-15 19:15:23 +01:00
, program_invocation_short_name ) ;
2014-07-16 22:55:23 +02:00
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
2014-08-20 00:15:05 +02:00
ARG_LEGEND ,
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
ARG_SERVICE ,
ARG_CNAME ,
ARG_SERVICE_ADDRESS ,
ARG_SERVICE_TXT ,
2016-01-29 00:24:27 +01:00
ARG_OPENPGP ,
2016-02-18 03:08:57 +01:00
ARG_TLSA ,
2016-01-29 00:24:28 +01:00
ARG_RAW ,
2015-11-25 20:47:27 +01:00
ARG_SEARCH ,
2015-12-23 19:06:36 +01:00
ARG_STATISTICS ,
ARG_RESET_STATISTICS ,
2016-06-15 21:43:36 +02:00
ARG_STATUS ,
2016-06-10 20:40:30 +02:00
ARG_FLUSH_CACHES ,
2017-09-29 21:19:54 +02:00
ARG_RESET_SERVER_FEATURES ,
2016-06-15 21:43:36 +02:00
ARG_NO_PAGER ,
2017-12-14 20:13:14 +01:00
ARG_SET_DNS ,
ARG_SET_DOMAIN ,
ARG_SET_LLMNR ,
ARG_SET_MDNS ,
ARG_SET_DNSSEC ,
ARG_SET_NTA ,
ARG_REVERT_LINK ,
2014-07-16 22:55:23 +02:00
} ;
static const struct option options [ ] = {
2017-09-29 21:19:54 +02:00
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " type " , required_argument , NULL , ' t ' } ,
{ " class " , required_argument , NULL , ' c ' } ,
{ " legend " , required_argument , NULL , ARG_LEGEND } ,
{ " interface " , required_argument , NULL , ' i ' } ,
{ " protocol " , required_argument , NULL , ' p ' } ,
{ " cname " , required_argument , NULL , ARG_CNAME } ,
{ " service " , no_argument , NULL , ARG_SERVICE } ,
{ " service-address " , required_argument , NULL , ARG_SERVICE_ADDRESS } ,
{ " service-txt " , required_argument , NULL , ARG_SERVICE_TXT } ,
{ " openpgp " , no_argument , NULL , ARG_OPENPGP } ,
{ " tlsa " , optional_argument , NULL , ARG_TLSA } ,
{ " raw " , optional_argument , NULL , ARG_RAW } ,
{ " search " , required_argument , NULL , ARG_SEARCH } ,
{ " statistics " , no_argument , NULL , ARG_STATISTICS , } ,
{ " reset-statistics " , no_argument , NULL , ARG_RESET_STATISTICS } ,
{ " status " , no_argument , NULL , ARG_STATUS } ,
{ " flush-caches " , no_argument , NULL , ARG_FLUSH_CACHES } ,
{ " reset-server-features " , no_argument , NULL , ARG_RESET_SERVER_FEATURES } ,
{ " no-pager " , no_argument , NULL , ARG_NO_PAGER } ,
2017-12-14 20:13:14 +01:00
{ " set-dns " , required_argument , NULL , ARG_SET_DNS } ,
{ " set-domain " , required_argument , NULL , ARG_SET_DOMAIN } ,
{ " set-llmnr " , required_argument , NULL , ARG_SET_LLMNR } ,
{ " set-mdns " , required_argument , NULL , ARG_SET_MDNS } ,
{ " set-dnssec " , required_argument , NULL , ARG_SET_DNSSEC } ,
{ " set-nta " , required_argument , NULL , ARG_SET_NTA } ,
{ " revert " , no_argument , NULL , ARG_REVERT_LINK } ,
2014-07-16 22:55:23 +02:00
{ }
} ;
2014-07-30 19:23:27 +02:00
int c , r ;
2014-07-16 22:55:23 +02:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
2014-08-14 01:00:15 +02:00
while ( ( c = getopt_long ( argc , argv , " h46i:t:c:p: " , options , NULL ) ) > = 0 )
2014-07-16 22:55:23 +02:00
switch ( c ) {
case ' h ' :
help ( ) ;
return 0 ; /* done */ ;
case ARG_VERSION :
2015-09-23 03:01:06 +02:00
return version ( ) ;
2014-07-16 22:55:23 +02:00
case ' 4 ' :
arg_family = AF_INET ;
break ;
case ' 6 ' :
arg_family = AF_INET6 ;
break ;
2018-02-27 17:45:04 +01:00
case ' i ' :
if ( parse_ifindex ( optarg , & arg_ifindex ) < 0 ) {
int ifi ;
2015-08-24 23:46:24 +02:00
ifi = if_nametoindex ( optarg ) ;
if ( ifi < = 0 )
return log_error_errno ( errno , " Unknown interface %s: %m " , optarg ) ;
arg_ifindex = ifi ;
}
2014-07-30 19:23:27 +02:00
break ;
case ' t ' :
2014-08-01 02:06:30 +02:00
if ( streq ( optarg , " help " ) ) {
help_dns_types ( ) ;
return 0 ;
}
2015-12-18 18:53:11 +01:00
r = dns_type_from_string ( optarg ) ;
if ( r < 0 ) {
2014-07-30 19:23:27 +02:00
log_error ( " Failed to parse RR record type %s " , optarg ) ;
2015-12-18 18:53:11 +01:00
return r ;
2014-07-30 19:23:27 +02:00
}
2015-12-18 18:53:11 +01:00
arg_type = ( uint16_t ) r ;
assert ( ( int ) arg_type = = r ) ;
2014-08-01 02:06:30 +02:00
2015-12-23 19:06:36 +01:00
arg_mode = MODE_RESOLVE_RECORD ;
2014-07-30 19:23:27 +02:00
break ;
case ' c ' :
2014-08-01 02:06:30 +02:00
if ( streq ( optarg , " help " ) ) {
help_dns_classes ( ) ;
return 0 ;
}
2015-12-18 18:53:11 +01:00
r = dns_class_from_string ( optarg ) ;
2014-07-30 19:23:27 +02:00
if ( r < 0 ) {
log_error ( " Failed to parse RR record class %s " , optarg ) ;
return r ;
2014-07-16 22:55:23 +02:00
}
2015-12-18 18:53:11 +01:00
arg_class = ( uint16_t ) r ;
assert ( ( int ) arg_class = = r ) ;
2014-08-01 02:06:30 +02:00
break ;
2014-08-20 00:15:05 +02:00
case ARG_LEGEND :
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --legend= argument " ) ;
arg_legend = r ;
2014-07-16 22:55:23 +02:00
break ;
2014-08-14 01:00:15 +02:00
case ' p ' :
2015-02-05 03:06:36 +01:00
if ( streq ( optarg , " help " ) ) {
help_protocol_types ( ) ;
return 0 ;
} else if ( streq ( optarg , " dns " ) )
2014-08-14 01:00:15 +02:00
arg_flags | = SD_RESOLVED_DNS ;
else if ( streq ( optarg , " llmnr " ) )
arg_flags | = SD_RESOLVED_LLMNR ;
else if ( streq ( optarg , " llmnr-ipv4 " ) )
arg_flags | = SD_RESOLVED_LLMNR_IPV4 ;
else if ( streq ( optarg , " llmnr-ipv6 " ) )
arg_flags | = SD_RESOLVED_LLMNR_IPV6 ;
2017-01-19 10:47:51 +01:00
else if ( streq ( optarg , " mdns " ) )
arg_flags | = SD_RESOLVED_MDNS ;
else if ( streq ( optarg , " mdns-ipv4 " ) )
arg_flags | = SD_RESOLVED_MDNS_IPV4 ;
else if ( streq ( optarg , " mdns-ipv6 " ) )
arg_flags | = SD_RESOLVED_MDNS_IPV6 ;
2014-08-14 01:00:15 +02:00
else {
log_error ( " Unknown protocol specifier: %s " , optarg ) ;
return - EINVAL ;
}
break ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
case ARG_SERVICE :
2015-12-23 19:06:36 +01:00
arg_mode = MODE_RESOLVE_SERVICE ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
break ;
2016-01-29 00:24:27 +01:00
case ARG_OPENPGP :
arg_mode = MODE_RESOLVE_OPENPGP ;
break ;
2016-02-18 03:08:57 +01:00
case ARG_TLSA :
arg_mode = MODE_RESOLVE_TLSA ;
arg_service_family = service_family_from_string ( optarg ) ;
if ( arg_service_family < 0 ) {
log_error ( " Unknown service family \" %s \" . " , optarg ) ;
return - EINVAL ;
}
break ;
2016-01-29 00:24:28 +01:00
case ARG_RAW :
if ( on_tty ( ) ) {
log_error ( " Refusing to write binary data to tty. " ) ;
return - ENOTTY ;
}
2016-01-31 06:06:49 +01:00
if ( optarg = = NULL | | streq ( optarg , " payload " ) )
arg_raw = RAW_PAYLOAD ;
else if ( streq ( optarg , " packet " ) )
arg_raw = RAW_PACKET ;
else {
log_error ( " Unknown --raw specifier \" %s \" . " , optarg ) ;
return - EINVAL ;
}
2016-01-29 00:24:28 +01:00
arg_legend = false ;
break ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
case ARG_CNAME :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --cname= argument. " ) ;
2016-03-03 18:30:37 +01:00
SET_FLAG ( arg_flags , SD_RESOLVED_NO_CNAME , r = = 0 ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
break ;
case ARG_SERVICE_ADDRESS :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --service-address= argument. " ) ;
2016-03-03 18:30:37 +01:00
SET_FLAG ( arg_flags , SD_RESOLVED_NO_ADDRESS , r = = 0 ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
break ;
case ARG_SERVICE_TXT :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --service-txt= argument. " ) ;
2016-03-03 18:30:37 +01:00
SET_FLAG ( arg_flags , SD_RESOLVED_NO_TXT , r = = 0 ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
break ;
2015-11-25 20:47:27 +01:00
case ARG_SEARCH :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --search argument. " ) ;
2016-03-03 18:30:37 +01:00
SET_FLAG ( arg_flags , SD_RESOLVED_NO_SEARCH , r = = 0 ) ;
2015-11-25 20:47:27 +01:00
break ;
2015-12-23 19:06:36 +01:00
case ARG_STATISTICS :
arg_mode = MODE_STATISTICS ;
break ;
case ARG_RESET_STATISTICS :
arg_mode = MODE_RESET_STATISTICS ;
break ;
2016-06-10 20:40:30 +02:00
case ARG_FLUSH_CACHES :
arg_mode = MODE_FLUSH_CACHES ;
break ;
2017-09-29 21:19:54 +02:00
case ARG_RESET_SERVER_FEATURES :
arg_mode = MODE_RESET_SERVER_FEATURES ;
break ;
2016-06-15 21:43:36 +02:00
case ARG_STATUS :
arg_mode = MODE_STATUS ;
break ;
case ARG_NO_PAGER :
arg_no_pager = true ;
break ;
2017-12-14 20:13:14 +01:00
case ARG_SET_DNS : {
struct in_addr_data data , * n ;
r = in_addr_from_string_auto ( optarg , & data . family , & data . address ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse DNS server address: %s " , optarg ) ;
n = realloc ( arg_set_dns , sizeof ( struct in_addr_data ) * ( arg_n_set_dns + 1 ) ) ;
if ( ! n )
return log_oom ( ) ;
arg_set_dns = n ;
arg_set_dns [ arg_n_set_dns + + ] = data ;
arg_mode = MODE_SET_LINK ;
break ;
}
case ARG_SET_DOMAIN : {
const char * p ;
p = optarg [ 0 ] = = ' ~ ' ? optarg + 1 : optarg ;
r = dns_name_is_valid ( p ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to validate specified domain %s: %m " , p ) ;
2018-02-27 17:46:00 +01:00
if ( r = = 0 ) {
log_error ( " Domain not valid: %s " , p ) ;
return - EINVAL ;
}
2017-12-14 20:13:14 +01:00
r = strv_extend ( & arg_set_domain , optarg ) ;
if ( r < 0 )
return log_oom ( ) ;
arg_mode = MODE_SET_LINK ;
break ;
}
case ARG_SET_LLMNR :
r = free_and_strdup ( & arg_set_llmnr , optarg ) ;
if ( r < 0 )
return log_oom ( ) ;
arg_mode = MODE_SET_LINK ;
break ;
case ARG_SET_MDNS :
r = free_and_strdup ( & arg_set_mdns , optarg ) ;
if ( r < 0 )
return log_oom ( ) ;
arg_mode = MODE_SET_LINK ;
break ;
case ARG_SET_DNSSEC :
r = free_and_strdup ( & arg_set_dnssec , optarg ) ;
if ( r < 0 )
return log_oom ( ) ;
arg_mode = MODE_SET_LINK ;
break ;
case ARG_SET_NTA :
r = dns_name_is_valid ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to validate specified domain %s: %m " , optarg ) ;
2018-02-27 17:46:00 +01:00
if ( r = = 0 ) {
log_error ( " Domain not valid: %s " , optarg ) ;
return - EINVAL ;
}
2017-12-14 20:13:14 +01:00
r = strv_extend ( & arg_set_nta , optarg ) ;
if ( r < 0 )
return log_oom ( ) ;
arg_mode = MODE_SET_LINK ;
break ;
case ARG_REVERT_LINK :
arg_mode = MODE_REVERT_LINK ;
break ;
2014-07-16 22:55:23 +02:00
case ' ? ' :
return - EINVAL ;
default :
assert_not_reached ( " Unhandled option " ) ;
}
2014-07-30 19:23:27 +02:00
if ( arg_type = = 0 & & arg_class ! = 0 ) {
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
log_error ( " --class= may only be used in conjunction with --type=. " ) ;
return - EINVAL ;
}
2016-02-18 03:08:57 +01:00
if ( arg_type ! = 0 & & arg_mode = = MODE_RESOLVE_SERVICE ) {
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
log_error ( " --service and --type= may not be combined. " ) ;
2014-07-30 19:23:27 +02:00
return - EINVAL ;
}
if ( arg_type ! = 0 & & arg_class = = 0 )
arg_class = DNS_CLASS_IN ;
2016-01-03 12:58:26 +01:00
if ( arg_class ! = 0 & & arg_type = = 0 )
arg_type = DNS_TYPE_A ;
2017-12-14 20:13:14 +01:00
if ( IN_SET ( arg_mode , MODE_SET_LINK , MODE_REVERT_LINK ) ) {
if ( arg_ifindex < = 0 ) {
log_error ( " --set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnssec=, --set-nta= and --revert require --interface=. " ) ;
return - EINVAL ;
}
if ( arg_ifindex = = LOOPBACK_IFINDEX ) {
log_error ( " Interface can't be the loopback interface (lo). Sorry. " ) ;
return - EINVAL ;
}
}
2014-07-16 22:55:23 +02:00
return 1 /* work to do */ ;
}
int main ( int argc , char * * argv ) {
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_flush_close_unrefp ) sd_bus * bus = NULL ;
2014-07-16 22:55:23 +02:00
int r ;
log_parse_environment ( ) ;
log_open ( ) ;
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
2014-07-30 17:52:21 +02:00
goto finish ;
2014-07-16 22:55:23 +02:00
r = sd_bus_open_system ( & bus ) ;
if ( r < 0 ) {
2014-11-28 13:19:16 +01:00
log_error_errno ( r , " sd_bus_open_system: %m " ) ;
2014-07-30 17:52:21 +02:00
goto finish ;
2014-07-16 22:55:23 +02:00
}
2015-12-23 19:06:36 +01:00
switch ( arg_mode ) {
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
2015-12-23 19:06:36 +01:00
case MODE_RESOLVE_HOST :
if ( optind > = argc ) {
2016-01-21 00:05:37 +01:00
log_error ( " No arguments passed. " ) ;
2015-12-23 19:06:36 +01:00
r = - EINVAL ;
goto finish ;
}
while ( argv [ optind ] ) {
int family , ifindex , k ;
union in_addr_union a ;
2016-01-03 12:58:26 +01:00
if ( startswith ( argv [ optind ] , " dns: " ) )
k = resolve_rfc4501 ( bus , argv [ optind ] ) ;
else {
2016-06-14 23:27:30 +02:00
k = in_addr_ifindex_from_string_auto ( argv [ optind ] , & family , & a , & ifindex ) ;
2016-01-03 12:58:26 +01:00
if ( k > = 0 )
k = resolve_address ( bus , family , & a , ifindex ) ;
else
k = resolve_host ( bus , argv [ optind ] ) ;
}
2015-12-23 19:06:36 +01:00
if ( r = = 0 )
r = k ;
optind + + ;
}
break ;
case MODE_RESOLVE_RECORD :
if ( optind > = argc ) {
2016-01-21 00:05:37 +01:00
log_error ( " No arguments passed. " ) ;
2015-12-23 19:06:36 +01:00
r = - EINVAL ;
goto finish ;
}
while ( argv [ optind ] ) {
int k ;
2016-10-08 13:59:34 +02:00
k = resolve_record ( bus , argv [ optind ] , arg_class , arg_type , true ) ;
2015-12-23 19:06:36 +01:00
if ( r = = 0 )
r = k ;
optind + + ;
}
break ;
case MODE_RESOLVE_SERVICE :
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
if ( argc < optind + 1 ) {
log_error ( " Domain specification required. " ) ;
r = - EINVAL ;
goto finish ;
} else if ( argc = = optind + 1 )
r = resolve_service ( bus , NULL , NULL , argv [ optind ] ) ;
else if ( argc = = optind + 2 )
r = resolve_service ( bus , NULL , argv [ optind ] , argv [ optind + 1 ] ) ;
else if ( argc = = optind + 3 )
r = resolve_service ( bus , argv [ optind ] , argv [ optind + 1 ] , argv [ optind + 2 ] ) ;
else {
2016-01-21 00:05:37 +01:00
log_error ( " Too many arguments. " ) ;
resolved: add ResolveService() bus call for resolving SRV and DNS-SD services
This also adds client-side support for this to systemd-resolve-host.
Note that the ResolveService() API can deal both with DNS-SD service
(consisting of service name, type and domain), as well as classic SRV
services (consisting just of a type and a domain), all exposed in the
same call.
This patch also reworks CNAME handling in order to reuse it between
hostname, RR and service lookups.
In contrast to Avahi and Bonjour, this new API will actually reolve the
A/AAAA RRs the SRV RRs point to in one go (unless this is explicitly
disabled). This normally comes for free, as these RRs are sent along
the SRV responses anyway, hence let's make use of that. This makes the
API considerably easier to use, as a single ResolveService() invocation
will return all necessary data to pick a server and connect() to it.
Note that this only implements the DNS-SD resolving step, it does not
implement DNS-SD browsing, as that makes sense primarily on mDNS, due to
its continuous nature.
2015-11-23 21:25:40 +01:00
r = - EINVAL ;
goto finish ;
}
2015-12-23 19:06:36 +01:00
break ;
2014-07-30 17:52:21 +02:00
2016-01-29 00:24:27 +01:00
case MODE_RESOLVE_OPENPGP :
if ( argc < optind + 1 ) {
log_error ( " E-mail address required. " ) ;
r = - EINVAL ;
goto finish ;
}
r = 0 ;
while ( optind < argc ) {
int k ;
k = resolve_openpgp ( bus , argv [ optind + + ] ) ;
if ( k < 0 )
r = k ;
}
break ;
2016-02-18 03:08:57 +01:00
case MODE_RESOLVE_TLSA :
if ( argc < optind + 1 ) {
log_error ( " Domain name required. " ) ;
r = - EINVAL ;
goto finish ;
}
r = 0 ;
while ( optind < argc ) {
int k ;
k = resolve_tlsa ( bus , argv [ optind + + ] ) ;
if ( k < 0 )
r = k ;
}
break ;
2015-12-23 19:06:36 +01:00
case MODE_STATISTICS :
if ( argc > optind ) {
log_error ( " Too many arguments. " ) ;
r = - EINVAL ;
goto finish ;
2014-07-30 19:23:27 +02:00
}
2014-07-16 22:55:23 +02:00
2015-12-23 19:06:36 +01:00
r = show_statistics ( bus ) ;
break ;
case MODE_RESET_STATISTICS :
if ( argc > optind ) {
log_error ( " Too many arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
2014-07-30 17:52:21 +02:00
2015-12-23 19:06:36 +01:00
r = reset_statistics ( bus ) ;
break ;
2016-06-10 20:40:30 +02:00
case MODE_FLUSH_CACHES :
if ( argc > optind ) {
log_error ( " Too many arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
r = flush_caches ( bus ) ;
break ;
2016-06-15 21:43:36 +02:00
2017-09-29 21:19:54 +02:00
case MODE_RESET_SERVER_FEATURES :
if ( argc > optind ) {
log_error ( " Too many arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
r = reset_server_features ( bus ) ;
break ;
2016-06-15 21:43:36 +02:00
case MODE_STATUS :
if ( argc > optind ) {
char * * ifname ;
bool empty_line = false ;
r = 0 ;
STRV_FOREACH ( ifname , argv + optind ) {
int ifindex , q ;
q = parse_ifindex ( argv [ optind ] , & ifindex ) ;
if ( q < 0 ) {
ifindex = if_nametoindex ( argv [ optind ] ) ;
if ( ifindex < = 0 ) {
log_error_errno ( errno , " Failed to resolve interface name: %s " , argv [ optind ] ) ;
continue ;
}
}
q = status_ifindex ( bus , ifindex , NULL , & empty_line ) ;
if ( q < 0 & & r > = 0 )
r = q ;
}
} else
r = status_all ( bus ) ;
break ;
2017-12-14 20:13:14 +01:00
case MODE_SET_LINK :
if ( argc > optind ) {
log_error ( " Too many arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
r = set_link ( bus ) ;
break ;
case MODE_REVERT_LINK :
if ( argc > optind ) {
log_error ( " Too many arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
r = revert_link ( bus ) ;
break ;
2014-07-16 22:55:23 +02:00
}
2014-07-30 17:52:21 +02:00
finish :
2016-06-15 21:43:36 +02:00
pager_close ( ) ;
2017-12-14 20:13:14 +01:00
free ( arg_set_dns ) ;
strv_free ( arg_set_domain ) ;
free ( arg_set_llmnr ) ;
free ( arg_set_mdns ) ;
free ( arg_set_dnssec ) ;
strv_free ( arg_set_nta ) ;
2014-07-16 22:55:23 +02:00
return r = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}