2014-07-16 22:55:23 +02:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
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"
2015-09-23 03:01:06 +02:00
# include "af-list.h"
2015-10-27 03:01:06 +01:00
# include "alloc-util.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"
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"
2014-07-16 22:55:23 +02:00
# include "in-addr-util.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"
2014-07-30 19:23:27 +02:00
2014-07-16 22:55:23 +02:00
# define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
static int arg_family = AF_UNSPEC ;
static int arg_ifindex = 0 ;
2014-08-03 20:02:04 +02:00
static int 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 ;
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 bool arg_resolve_service = false ;
2014-08-14 01:00:15 +02:00
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 )
printf ( " protocol%s%s%s " ,
flags & SD_RESOLVED_DNS ? " DNS " : " " ,
flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4 " : " " ,
flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6 " : " " ) ;
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 ) ;
}
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
_cleanup_bus_message_unref_ sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_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 ) ;
2014-07-16 22:55:23 +02:00
r = sd_bus_call ( bus , req , DNS_CALL_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
r = in_addr_to_string ( family , a , & 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 ) {
_cleanup_bus_message_unref_ sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_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 ;
2014-07-30 17:52:21 +02:00
r = in_addr_to_string ( family , address , & pretty ) ;
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 ) ;
2014-07-30 17:52:21 +02:00
r = sd_bus_call ( bus , req , DNS_CALL_TIMEOUT_USEC , & error , & reply ) ;
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 ;
}
static int parse_address ( const char * s , int * family , union in_addr_union * address , int * ifindex ) {
const char * percent , * a ;
int ifi = 0 ;
int r ;
percent = strchr ( s , ' % ' ) ;
if ( percent ) {
2015-11-02 23:57:21 +01:00
if ( parse_ifindex ( percent + 1 , & ifi ) < 0 ) {
2014-07-30 17:52:21 +02:00
ifi = if_nametoindex ( percent + 1 ) ;
if ( ifi < = 0 )
return - EINVAL ;
}
a = strndupa ( s , percent - s ) ;
} else
a = s ;
r = in_addr_from_string_auto ( a , family , address ) ;
if ( r < 0 )
return r ;
* ifindex = ifi ;
2014-07-30 17:11:21 +02:00
return 0 ;
2014-07-16 22:55:23 +02:00
}
2014-07-30 19:23:27 +02:00
static int resolve_record ( sd_bus * bus , const char * name ) {
_cleanup_bus_message_unref_ sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_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 ;
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 ) ;
log_debug ( " Resolving %s %s %s (interface %s). " , name , dns_class_to_string ( arg_class ) , dns_type_to_string ( arg_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 ) ;
2014-08-03 20:02:04 +02:00
assert ( ( uint16_t ) arg_type = = arg_type ) ;
2014-08-14 01:00:15 +02:00
r = sd_bus_message_append ( req , " isqqt " , arg_ifindex , name , arg_class , arg_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 ) ;
2014-07-30 19:23:27 +02:00
r = sd_bus_call ( bus , req , DNS_CALL_TIMEOUT_USEC , & error , & reply ) ;
if ( r < 0 ) {
log_error ( " %s: resolve call failed: %s " , name , 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 ' , " (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
_cleanup_ ( dns_resource_record_unrefp ) DnsResourceRecord * rr = NULL ;
_cleanup_ ( dns_packet_unrefp ) DnsPacket * p = NULL ;
_cleanup_free_ char * s = NULL ;
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 ) ;
r = dns_packet_new ( & p , DNS_PROTOCOL_DNS , 0 ) ;
if ( r < 0 )
return log_oom ( ) ;
2015-08-21 16:04:59 +02:00
p - > refuse_compression = true ;
2014-07-30 19:23:27 +02:00
r = dns_packet_append_blob ( p , d , l , NULL ) ;
if ( r < 0 )
return log_oom ( ) ;
r = dns_packet_read_rr ( p , & rr , NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to parse RR. " ) ;
return r ;
}
r = dns_resource_record_to_string ( rr , & s ) ;
if ( r < 0 ) {
log_error ( " Failed to format RR. " ) ;
return r ;
}
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 ) ;
printf ( " %s%s%s \n " , s , isempty ( ifname ) ? " " : " # interface " , ifname ) ;
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 ) {
log_error ( " %s: no records found " , name ) ;
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 19:23:27 +02:00
return 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
static int resolve_service ( sd_bus * bus , const char * name , const char * type , const char * domain ) {
const char * canonical_name , * canonical_type , * canonical_domain ;
_cleanup_bus_message_unref_ sd_bus_message * req = NULL , * reply = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
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 ) ;
if ( isempty ( name ) )
name = NULL ;
if ( isempty ( type ) )
type = NULL ;
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 ) ;
r = sd_bus_call ( bus , req , DNS_CALL_TIMEOUT_USEC , & error , & reply ) ;
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 ) ;
c = 0 ;
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 ) ;
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_read ( reply , " ssst " , & canonical_name , & canonical_type , & canonical_domain , & flags ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
if ( isempty ( canonical_name ) )
canonical_name = NULL ;
if ( isempty ( canonical_type ) )
canonical_type = NULL ;
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 ;
}
2014-08-01 02:06:30 +02:00
static void help_dns_types ( void ) {
int i ;
const char * t ;
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 ) {
int i ;
const char * t ;
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 ) {
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
printf ( " %s [OPTIONS...] NAME... \n "
" %s [OPTIONS...] --service [[NAME] TYPE] DOMAIN \n \n "
" Resolve domain names, IPv4 or IPv6 addresses, resource records, and services. \n \n "
" -h --help Show this help \n "
" --version Show package version \n "
" -4 Resolve IPv4 addresses \n "
" -6 Resolve IPv6 addresses \n "
" -i INTERFACE Look on interface \n "
" -p --protocol=PROTOCOL Look via protocol \n "
" -t --type=TYPE Query RR with DNS type \n "
" -c --class=CLASS Query RR with DNS class \n "
" --service Resolve service (SRV) \n "
" --service-address=BOOL Do [not] resolve address for services \n "
" --service-txt=BOOL Do [not] resolve TXT records for services \n "
" --cname=BOOL Do [not] follow CNAME redirects \n "
" --legend=BOOL Do [not] print column headers \n "
, program_invocation_short_name , 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 ,
2014-07-16 22:55:23 +02:00
} ;
static const struct option options [ ] = {
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
{ " 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 } ,
{ " 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 } ,
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 ;
2015-08-24 23:46:24 +02:00
case ' i ' : {
int ifi ;
2015-11-02 23:57:21 +01:00
if ( parse_ifindex ( optarg , & ifi ) > = 0 )
2015-08-24 23:46:24 +02:00
arg_ifindex = ifi ;
else {
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 ;
2015-08-24 23:46:24 +02:00
}
2014-07-30 19:23:27 +02:00
case ' t ' :
2014-08-01 02:06:30 +02:00
if ( streq ( optarg , " help " ) ) {
help_dns_types ( ) ;
return 0 ;
}
2014-08-03 20:02:04 +02:00
arg_type = dns_type_from_string ( optarg ) ;
if ( arg_type < 0 ) {
2014-07-30 19:23:27 +02:00
log_error ( " Failed to parse RR record type %s " , optarg ) ;
2014-08-04 05:41:45 +02:00
return arg_type ;
2014-07-30 19:23:27 +02:00
}
2014-08-03 20:02:04 +02:00
assert ( arg_type > 0 & & ( uint16_t ) arg_type = = arg_type ) ;
2014-08-01 02:06:30 +02:00
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 ;
}
2014-07-30 19:23:27 +02:00
r = dns_class_from_string ( optarg , & arg_class ) ;
if ( r < 0 ) {
log_error ( " Failed to parse RR record class %s " , optarg ) ;
return r ;
2014-07-16 22:55:23 +02:00
}
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 ' :
if ( streq ( optarg , " dns " ) )
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 ;
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 :
arg_resolve_service = true ;
break ;
case ARG_CNAME :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --cname= argument. " ) ;
if ( r = = 0 )
arg_flags | = SD_RESOLVED_NO_CNAME ;
else
arg_flags & = ~ SD_RESOLVED_NO_CNAME ;
break ;
case ARG_SERVICE_ADDRESS :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --service-address= argument. " ) ;
if ( r = = 0 )
arg_flags | = SD_RESOLVED_NO_ADDRESS ;
else
arg_flags & = ~ SD_RESOLVED_NO_ADDRESS ;
break ;
case ARG_SERVICE_TXT :
r = parse_boolean ( optarg ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse --service-txt= argument. " ) ;
if ( r = = 0 )
arg_flags | = SD_RESOLVED_NO_TXT ;
else
arg_flags & = ~ SD_RESOLVED_NO_TXT ;
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 ;
}
if ( arg_type ! = 0 & & arg_resolve_service ) {
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 ;
2014-07-16 22:55:23 +02:00
return 1 /* work to do */ ;
}
int main ( int argc , char * * argv ) {
2015-07-03 19:49:03 +02:00
_cleanup_bus_flush_close_unref_ 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 ;
if ( optind > = argc ) {
log_error ( " No arguments passed " ) ;
r = - EINVAL ;
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
}
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_resolve_service ) {
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 {
log_error ( " Too many arguments " ) ;
r = - EINVAL ;
goto finish ;
}
goto finish ;
}
2014-07-16 22:55:23 +02:00
while ( argv [ optind ] ) {
2014-07-30 17:52:21 +02:00
int family , ifindex , k ;
union in_addr_union a ;
2014-07-30 19:23:27 +02:00
if ( arg_type ! = 0 )
k = resolve_record ( bus , argv [ optind ] ) ;
else {
k = parse_address ( argv [ optind ] , & family , & a , & ifindex ) ;
if ( k > = 0 )
k = resolve_address ( bus , family , & a , ifindex ) ;
else
k = resolve_host ( bus , argv [ optind ] ) ;
}
2014-07-16 22:55:23 +02:00
if ( r = = 0 )
r = k ;
2014-07-30 17:52:21 +02:00
optind + + ;
2014-07-16 22:55:23 +02:00
}
2014-07-30 17:52:21 +02:00
finish :
2014-07-16 22:55:23 +02:00
return r = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
}