Merge pull request #16353 from yuwata/network-dns-sni

resolve, network: more SNI and port number support
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-07-21 08:06:17 +02:00 committed by GitHub
commit 739b9a4354
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1121 additions and 431 deletions

View File

@ -145,15 +145,20 @@
settings for network interfaces. These commands may be used to inform
<command>systemd-resolved</command> or <command>systemd-networkd</command> about per-interface DNS
configuration determined through external means. The <command>dns</command> command expects IPv4 or
IPv6 address specifications of DNS servers to use. The <command>domain</command> command expects
valid DNS domains, possibly prefixed with <literal>~</literal>, and configures a per-interface
search or route-only domain. The <command>default-route</command> command expects a boolean
parameter, and configures whether the link may be used as default route for DNS lookups, i.e. if it
is suitable for lookups on domains no other link explicitly is configured for. The
<command>llmnr</command>, <command>mdns</command>, <command>dnssec</command> and
<command>dnsovertls</command> commands may be used to configure the per-interface LLMNR,
MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, <command>nta</command> command may be used
to configure additional per-interface DNSSEC NTA domains.</para>
IPv6 address specifications of DNS servers to use. Each address can optionally take a port number
separated with <literal>:</literal>, a network interface name or index separated with
<literal>%</literal>, and a Server Name Indication (SNI) separated with <literal>#</literal>. When
IPv6 address is specified with a port number, then the address must be in the square brackets. That
is, the acceptable full formats are <literal>111.222.333.444:9953%ifname#example.com</literal> for
IPv4 and <literal>[1111:2222::3333]:9953%ifname#example.com</literal> for IPv6. The
<command>domain</command> command expects valid DNS domains, possibly prefixed with
<literal>~</literal>, and configures a per-interface search or route-only domain. The
<command>default-route</command> command expects a boolean parameter, and configures whether the
link may be used as default route for DNS lookups, i.e. if it is suitable for lookups on domains no
other link explicitly is configured for. The <command>llmnr</command>, <command>mdns</command>,
<command>dnssec</command> and <command>dnsovertls</command> commands may be used to configure the
per-interface LLMNR, MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, <command>nta</command>
command may be used to configure additional per-interface DNSSEC NTA domains.</para>
<para>Commands <command>dns</command>, <command>domain</command> and <command>nta</command> can take
a single empty string argument to clear their respective value lists.</para>

View File

@ -47,8 +47,13 @@
<varlistentry>
<term><varname>DNS=</varname></term>
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. DNS requests
are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. Each address can
optionally take a port number separated with <literal>:</literal>, a network interface name or index separated with
<literal>%</literal>, and a Server Name Indication (SNI) separated with <literal>#</literal>. When IPv6 address is
specified with a port number, then the address must be in the square brackets. That is, the acceptable full formats
are <literal>111.222.333.444:9953%ifname#example.com</literal> for IPv4 and
<literal>[1111:2222::3333]:9953%ifname#example.com</literal> for IPv6. DNS requests are sent to one of the listed
DNS servers in parallel to suitable per-link DNS servers acquired from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
set at runtime by external applications. For compatibility reasons, if this setting is not specified, the DNS
servers listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any servers
@ -57,8 +62,8 @@
<varlistentry>
<term><varname>FallbackDNS=</varname></term>
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Any
per-link DNS servers obtained from
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Please see
<varname>DNS=</varname> for acceptable format of adddresses. Any per-link DNS servers obtained from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
take precedence over this setting, as do any servers set via <varname>DNS=</varname> above or
<filename>/etc/resolv.conf</filename>. This setting is hence only used if no other DNS server information is

View File

@ -606,7 +606,15 @@
<para>A DNS server address, which must be in the format
described in
<citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This option may be specified more than once. This setting is read by
This option may be specified more than once. Each address can optionally take a port number
separated with <literal>:</literal>, a network interface name or index separated with
<literal>%</literal>, and a Server Name Indication (SNI) separated with <literal>#</literal>.
When IPv6 address is specified with a port number, then the address must be in the square
brackets. That is, the acceptable full formats are
<literal>111.222.333.444:9953%ifname#example.com</literal> for IPv4 and
<literal>[1111:2222::3333]:9953%ifname#example.com</literal> for IPv6. This setting can be
specified multiple times. If an empty string is assigned, then the all previous assignments
are cleared. This setting is read by
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>

View File

@ -14,6 +14,7 @@
#include "macro.h"
#include "parse-util.h"
#include "random-util.h"
#include "string-util.h"
#include "strxcpyx.h"
#include "util.h"
@ -445,6 +446,61 @@ fallback:
return in_addr_to_string(family, u, ret);
}
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) {
_cleanup_free_ char *ip_str = NULL, *x = NULL;
int r;
assert(IN_SET(family, AF_INET, AF_INET6));
assert(u);
assert(ret);
/* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
* handle IPv6 link-local addresses. */
r = in_addr_to_string(family, u, &ip_str);
if (r < 0)
return r;
if (family == AF_INET6) {
r = in_addr_is_link_local(family, u);
if (r < 0)
return r;
if (r == 0)
ifindex = 0;
} else
ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
if (port == 0 && ifindex == 0 && isempty(server_name)) {
*ret = TAKE_PTR(ip_str);
return 0;
}
const char *separator = isempty(server_name) ? "" : "#";
server_name = strempty(server_name);
if (port > 0) {
if (family == AF_INET6) {
if (ifindex > 0)
r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
else
r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
} else
r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
} else {
if (ifindex > 0)
r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
else {
x = strjoin(ip_str, separator, server_name);
r = x ? 0 : -ENOMEM;
}
}
if (r < 0)
return -ENOMEM;
*ret = TAKE_PTR(x);
return 0;
}
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
union in_addr_union buffer;
assert(s);

View File

@ -41,6 +41,7 @@ int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);

View File

@ -61,10 +61,10 @@ static int link_push_uplink_to_dhcp_server(
struct in_addr ia;
/* Only look for IPv4 addresses */
if (link->network->dns[i].family != AF_INET)
if (link->network->dns[i]->family != AF_INET)
continue;
ia = link->network->dns[i].address.in;
ia = link->network->dns[i]->address.in;
/* Never propagate obviously borked data */
if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))

View File

@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-message-util.h"
#include "bus-polkit.h"
#include "dns-domain.h"
#include "networkd-link-bus.h"
@ -14,6 +15,7 @@
#include "networkd-manager.h"
#include "parse-util.h"
#include "resolve-util.h"
#include "socket-netlink.h"
#include "strv.h"
#include "user-util.h"
@ -113,10 +115,10 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_
return sd_bus_reply_method_return(message, NULL);
}
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ struct in_addr_data *dns = NULL;
size_t allocated = 0, n = 0;
static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
struct in_addr_full **dns;
Link *l = userdata;
size_t n;
int r;
assert(message);
@ -126,52 +128,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
if (r < 0)
return r;
r = sd_bus_message_enter_container(message, 'a', "(iay)");
if (r < 0)
return r;
for (;;) {
int family;
size_t sz;
const void *d;
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_enter_container(message, 'r', "iay");
if (r < 0)
return r;
if (r == 0)
break;
r = sd_bus_message_read(message, "i", &family);
if (r < 0)
return r;
if (!IN_SET(family, AF_INET, AF_INET6))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
r = sd_bus_message_read_array(message, 'y', &d, &sz);
if (r < 0)
return r;
if (sz != FAMILY_ADDRESS_SIZE(family))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
if (!dns_server_address_valid(family, d))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!GREEDY_REALLOC(dns, allocated, n+1))
return -ENOMEM;
dns[n].family = family;
memcpy(&dns[n].address, d, sz);
n++;
}
r = sd_bus_message_exit_container(message);
r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
if (r < 0)
return r;
@ -180,9 +137,15 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
NULL, true, UID_INVALID,
&l->manager->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Polkit will call us back */
goto finalize;
if (r == 0) {
r = 1; /* Polkit will call us back */
goto finalize;
}
if (l->n_dns != (unsigned) -1)
for (unsigned i = 0; i < l->n_dns; i++)
in_addr_full_free(l->dns[i]);
free_and_replace(l->dns, dns);
l->n_dns = n;
@ -190,6 +153,21 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
(void) link_dirty(l);
return sd_bus_reply_method_return(message, NULL);
finalize:
for (size_t i = 0; i < n; i++)
in_addr_full_free(dns[i]);
free(dns);
return r;
}
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
}
int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
}
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@ -670,6 +648,7 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDNSEx", "a(iayqs)", NULL, bus_link_method_set_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@ -21,6 +21,7 @@ int property_get_address_state(sd_bus *bus, const char *path, const char *interf
int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);

View File

@ -666,6 +666,9 @@ void link_ntp_settings_clear(Link *link) {
}
void link_dns_settings_clear(Link *link) {
if (link->n_dns != (unsigned) -1)
for (unsigned i = 0; i < link->n_dns; i++)
in_addr_full_free(link->dns[i]);
link->dns = mfree(link->dns);
link->n_dns = (unsigned) -1;
@ -4108,20 +4111,20 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
fputc('\n', f);
}
static void link_save_dns(FILE *f, struct in_addr_data *dns, unsigned n_dns, bool *space) {
static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
for (unsigned j = 0; j < n_dns; j++) {
_cleanup_free_ char *b = NULL;
int r;
const char *str;
r = in_addr_to_string(dns[j].family, &dns[j].address, &b);
if (r < 0) {
log_debug_errno(r, "Failed to format address, ignoring: %m");
if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
continue;
str = in_addr_full_to_string(dns[j]);
if (!str)
continue;
}
if (*space)
fputc(' ', f);
fputs(b, f);
fputs(str, f);
*space = true;
}
}
@ -4251,9 +4254,9 @@ int link_save(Link *link) {
fputs("DNS=", f);
space = false;
if (link->n_dns != (unsigned) -1)
link_save_dns(f, link->dns, link->n_dns, &space);
link_save_dns(link, f, link->dns, link->n_dns, &space);
else
link_save_dns(f, link->network->dns, link->network->n_dns, &space);
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
serialize_addresses(f, NULL, &space,
NULL,

View File

@ -163,7 +163,7 @@ typedef struct Link {
bool stats_updated;
/* All kinds of DNS configuration the user configured via D-Bus */
struct in_addr_data *dns;
struct in_addr_full **dns;
unsigned n_dns;
OrderedSet *search_domains, *route_domains;

View File

@ -6,6 +6,7 @@
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-message-util.h"
#include "bus-polkit.h"
#include "networkd-link-bus.h"
#include "networkd-link.h"
@ -93,17 +94,16 @@ static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *path = NULL;
Manager *manager = userdata;
int32_t index;
int ifindex, r;
Link *link;
int r;
r = sd_bus_message_read(message, "i", &index);
r = bus_message_read_ifindex(message, error, &ifindex);
if (r < 0)
return r;
link = hashmap_get(manager->links, INT_TO_PTR((int) index));
link = hashmap_get(manager->links, INT_TO_PTR(ifindex));
if (!link)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %" PRIi32 " not known", index);
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
@ -128,14 +128,10 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_
assert(message);
assert(handler);
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(message, "i", &ifindex);
r = bus_message_read_ifindex(message, error, &ifindex);
if (r < 0)
return r;
if (ifindex <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
l = hashmap_get(m->links, INT_TO_PTR(ifindex));
if (!l)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
@ -151,6 +147,10 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda
return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
}
static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error);
}
static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return call_link_method(userdata, message, bus_link_method_set_domains, error);
}
@ -243,6 +243,7 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("GetLinkByIndex", "i", "so", method_get_link_by_index, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkNTP", "ias", NULL, bus_method_set_link_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNSEx", "ia(iayqs)", NULL, bus_method_set_link_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@ -1425,33 +1425,36 @@ static int manager_connect_rtnl(Manager *m) {
return 0;
}
static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
char *p;
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
const char *p;
int r;
assert(s);
assert(address);
assert(dns);
r = in_addr_to_string(address->family, &address->address, &p);
if (r < 0)
return r;
if (dns->ifindex != 0 && dns->ifindex != ifindex)
return 0;
r = ordered_set_consume(s, p);
p = in_addr_full_to_string(dns);
if (!p)
return 0;
r = ordered_set_put_strdup(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) {
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
int r, c = 0;
unsigned i;
assert(s);
assert(addresses || n == 0);
assert(dns || n == 0);
for (i = 0; i < n; i++) {
r = ordered_set_put_in_addr_data(s, addresses+i);
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
if (r < 0)
return r;
@ -1558,7 +1561,10 @@ static int manager_save(Manager *m) {
continue;
/* First add the static configured entries */
r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
if (link->n_dns != (unsigned) -1)
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
else
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
if (r < 0)
return r;

View File

@ -682,6 +682,8 @@ static Network *network_free(Network *network) {
sd_ipv4acd_unref(network->dhcp_acd);
strv_free(network->ntp);
for (unsigned i = 0; i < network->n_dns; i++)
in_addr_full_free(network->dns[i]);
free(network->dns);
ordered_set_free_free(network->search_domains);
ordered_set_free_free(network->route_domains);
@ -1194,16 +1196,17 @@ int config_parse_dns(
assert(rvalue);
if (isempty(rvalue)) {
for (unsigned i = 0; i < n->n_dns; i++)
in_addr_full_free(n->dns[i]);
n->dns = mfree(n->dns);
n->n_dns = 0;
return 0;
}
for (const char *p = rvalue;;) {
_cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
_cleanup_free_ char *w = NULL;
union in_addr_union a;
struct in_addr_data *m;
int family;
struct in_addr_full **m;
r = extract_first_word(&p, &w, NULL, 0);
if (r == -ENOMEM)
@ -1216,22 +1219,21 @@ int config_parse_dns(
if (r == 0)
return 0;
r = in_addr_from_string_auto(w, &family, &a);
r = in_addr_full_new_from_string(w, &dns);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse dns server address, ignoring: %s", w);
continue;
}
m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
if (IN_SET(dns->port, 53, 853))
dns->port = 0;
m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
if (!m)
return log_oom();
m[n->n_dns++] = (struct in_addr_data) {
.family = family,
.address = a,
};
m[n->n_dns++] = TAKE_PTR(dns);
n->dns = m;
}
}

View File

@ -32,6 +32,7 @@
#include "networkd-util.h"
#include "ordered-set.h"
#include "resolve-util.h"
#include "socket-netlink.h"
typedef enum IPv6PrivacyExtensions {
/* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
@ -316,7 +317,7 @@ struct Network {
OrderedHashmap *sr_iov_by_section;
/* All kinds of DNS configuration */
struct in_addr_data *dns;
struct in_addr_full **dns;
unsigned n_dns;
OrderedSet *search_domains, *route_domains;

View File

@ -463,10 +463,10 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
for (i = 0; i < network->n_dns; i++) {
union in_addr_union *addr;
if (network->dns[i].family != AF_INET6)
if (network->dns[i]->family != AF_INET6)
continue;
addr = &network->dns[i].address;
addr = &network->dns[i]->address;
if (in_addr_is_null(AF_INET6, addr) ||
in_addr_is_link_local(AF_INET6, addr) ||

View File

@ -13,6 +13,7 @@
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-map-properties.h"
#include "bus-message-util.h"
#include "dns-domain.h"
#include "escape.h"
#include "format-table.h"
@ -209,34 +210,29 @@ static int resolve_host(sd_bus *bus, const char *name) {
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
_cleanup_free_ char *pretty = NULL;
int ifindex, family, k;
const void *a;
size_t sz;
union in_addr_union a;
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(reply, "ii", &ifindex, &family);
r = sd_bus_message_read(reply, "i", &ifindex);
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);
sd_bus_error_free(&error);
r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&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");
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
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;
}
r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
if (r < 0)
return log_error_errno(r, "Failed to print address for %s: %m", name);
@ -740,33 +736,29 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
_cleanup_free_ char *pretty = NULL;
int ifindex, family, k;
const void *a;
union in_addr_union a;;
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(reply, "ii", &ifindex, &family);
r = sd_bus_message_read(reply, "i", &ifindex);
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);
sd_bus_error_free(&error);
r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&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");
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
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;
}
r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
if (r < 0)
return log_error_errno(r, "Failed to print address for %s: %m", name);
@ -1120,16 +1112,18 @@ static int reset_server_features(int argc, char **argv, void *userdata) {
return 0;
}
static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) {
static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extended, char **ret) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *pretty = NULL;
int ifindex, family, r;
const void *a;
size_t sz;
int ifindex, family, r, k;
union in_addr_union a;
const char *name = NULL;
uint16_t port = 0;
assert(m);
assert(ret);
r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay");
r = sd_bus_message_enter_container(m, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay"));
if (r <= 0)
return r;
@ -1139,39 +1133,37 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret)
return r;
}
r = sd_bus_message_read(m, "i", &family);
if (r < 0)
return r;
k = bus_message_read_in_addr_auto(m, &error, &family, &a);
if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
return k;
r = sd_bus_message_read_array(m, 'y', &a, &sz);
if (r < 0)
return r;
if (extended) {
r = sd_bus_message_read(m, "q", &port);
if (r < 0)
return r;
r = sd_bus_message_read(m, "s", &name);
if (r < 0)
return r;
}
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
if (k < 0) {
log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, k));
*ret = NULL;
return 1;
}
if (with_ifindex && ifindex != 0) {
/* only show the global ones here */
*ret = NULL;
return 1;
}
if (!IN_SET(family, AF_INET, AF_INET6)) {
log_debug("Unexpected family, ignoring: %i", family);
*ret = NULL;
return 1;
}
if (sz != FAMILY_ADDRESS_SIZE(family)) {
log_debug("Address size mismatch, ignoring.");
*ret = NULL;
return 1;
}
r = in_addr_to_string(family, a, &pretty);
r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty);
if (r < 0)
return r;
@ -1180,7 +1172,7 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret)
return 1;
}
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
char ***l = userdata;
int r;
@ -1189,14 +1181,14 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message
assert(m);
assert(l);
r = sd_bus_message_enter_container(m, 'a', "(iay)");
r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)");
if (r < 0)
return r;
for (;;) {
_cleanup_free_ char *pretty = NULL;
r = read_dns_server_one(m, false, &pretty);
r = read_dns_server_one(m, false, extended, &pretty);
if (r < 0)
return r;
if (r == 0)
@ -1217,11 +1209,26 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message
return 0;
}
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
return map_link_dns_servers_internal(bus, member, m, error, userdata, false);
}
static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
return map_link_dns_servers_internal(bus, member, m, error, userdata, true);
}
static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
assert(m);
assert(userdata);
return read_dns_server_one(m, false, userdata);
return read_dns_server_one(m, false, false, userdata);
}
static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
assert(m);
assert(userdata);
return read_dns_server_one(m, false, true, userdata);
}
static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
@ -1315,7 +1322,9 @@ struct link_info {
const char *dns_over_tls;
const char *dnssec;
char *current_dns;
char *current_dns_ex;
char **dns;
char **dns_ex;
char **domains;
char **ntas;
bool dnssec_supported;
@ -1324,7 +1333,9 @@ struct link_info {
static void link_info_clear(struct link_info *p) {
free(p->current_dns);
free(p->current_dns_ex);
strv_free(p->dns);
strv_free(p->dns_ex);
strv_free(p->domains);
strv_free(p->ntas);
}
@ -1346,17 +1357,19 @@ static int dump_list(Table *table, const char *prefix, char * const *l) {
static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
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) },
{ "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) },
{ "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) },
{ "DefaultRoute", "b", NULL, offsetof(struct link_info, default_route) },
{ "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
{ "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
{ "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) },
{ "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) },
{ "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) },
{ "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) },
{ "DNSEx", "a(iayqs)", map_link_dns_servers_ex, offsetof(struct link_info, dns_ex) },
{ "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) },
{ "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex, offsetof(struct link_info, current_dns_ex) },
{ "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) },
{ "DefaultRoute", "b", NULL, offsetof(struct link_info, default_route) },
{ "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
{ "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
{ "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) },
{ "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) },
{}
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -1396,7 +1409,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
(void) pager_open(arg_pager_flags);
if (mode == STATUS_DNS)
return status_print_strv_ifindex(ifindex, name, link_info.dns);
return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns);
if (mode == STATUS_DOMAIN)
return status_print_strv_ifindex(ifindex, name, link_info.domains);
@ -1504,12 +1517,12 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
if (link_info.current_dns) {
r = table_add_many(table,
TABLE_STRING, "Current DNS Server:",
TABLE_STRING, link_info.current_dns);
TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns);
if (r < 0)
return table_log_add_error(r);
}
r = dump_list(table, "DNS Servers:", link_info.dns);
r = dump_list(table, "DNS Servers:", link_info.dns_ex ?: link_info.dns);
if (r < 0)
return r;
@ -1527,7 +1540,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
return 0;
}
static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
static int map_global_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
char ***l = userdata;
int r;
@ -1536,14 +1549,14 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag
assert(m);
assert(l);
r = sd_bus_message_enter_container(m, 'a', "(iiay)");
r = sd_bus_message_enter_container(m, 'a', extended ? "(iiayqs)" : "(iiay)");
if (r < 0)
return r;
for (;;) {
_cleanup_free_ char *pretty = NULL;
r = read_dns_server_one(m, true, &pretty);
r = read_dns_server_one(m, true, extended, &pretty);
if (r < 0)
return r;
if (r == 0)
@ -1564,11 +1577,26 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag
return 0;
}
static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
return map_global_dns_servers_internal(bus, member, m, error, userdata, false);
}
static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
return map_global_dns_servers_internal(bus, member, m, error, userdata, true);
}
static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
assert(m);
assert(userdata);
return read_dns_server_one(m, true, userdata);
return read_dns_server_one(m, true, false, userdata);
}
static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
assert(m);
assert(userdata);
return read_dns_server_one(m, true, true, userdata);
}
static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
@ -1623,8 +1651,11 @@ static int status_print_strv_global(char **p) {
struct global_info {
char *current_dns;
char *current_dns_ex;
char **dns;
char **dns_ex;
char **fallback_dns;
char **fallback_dns_ex;
char **domains;
char **ntas;
const char *llmnr;
@ -1636,24 +1667,30 @@ struct global_info {
static void global_info_clear(struct global_info *p) {
free(p->current_dns);
free(p->current_dns_ex);
strv_free(p->dns);
strv_free(p->dns_ex);
strv_free(p->fallback_dns);
strv_free(p->fallback_dns_ex);
strv_free(p->domains);
strv_free(p->ntas);
}
static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
static const struct bus_properties_map property_map[] = {
{ "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) },
{ "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_dns) },
{ "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) },
{ "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) },
{ "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) },
{ "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) },
{ "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) },
{ "DNSOverTLS", "s", NULL, offsetof(struct global_info, dns_over_tls) },
{ "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) },
{ "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) },
{ "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) },
{ "DNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(struct global_info, dns_ex) },
{ "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_dns) },
{ "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(struct global_info, fallback_dns_ex) },
{ "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) },
{ "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex, offsetof(struct global_info, current_dns_ex) },
{ "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) },
{ "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) },
{ "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) },
{ "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) },
{ "DNSOverTLS", "s", NULL, offsetof(struct global_info, dns_over_tls) },
{ "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) },
{ "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) },
{}
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -1679,7 +1716,7 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
(void) pager_open(arg_pager_flags);
if (mode == STATUS_DNS)
return status_print_strv_global(global_info.dns);
return status_print_strv_global(global_info.dns_ex ?: global_info.dns);
if (mode == STATUS_DOMAIN)
return status_print_strv_global(global_info.domains);
@ -1741,16 +1778,16 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
if (global_info.current_dns) {
r = table_add_many(table,
TABLE_STRING, "Current DNS Server:",
TABLE_STRING, global_info.current_dns);
TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns);
if (r < 0)
return table_log_add_error(r);
}
r = dump_list(table, "DNS Servers:", global_info.dns);
r = dump_list(table, "DNS Servers:", global_info.dns_ex ?: global_info.dns);
if (r < 0)
return r;
r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns);
r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns_ex ?: global_info.fallback_dns);
if (r < 0)
return r;
@ -1867,12 +1904,12 @@ static int verb_status(int argc, char **argv, void *userdata) {
return r;
}
static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error) {
static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
char **p;
int r;
r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNS");
r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS");
if (r < 0)
return bus_log_create_error(r);
@ -1880,7 +1917,7 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(req, 'a', "(iay)");
r = sd_bus_message_open_container(req, 'a', extended ? "(iayqs)" : "(iay)");
if (r < 0)
return bus_log_create_error(r);
@ -1888,13 +1925,19 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
* empty list, which will clear the list of domains for an interface. */
if (!strv_equal(dns, STRV_MAKE("")))
STRV_FOREACH(p, dns) {
_cleanup_free_ char *name = NULL;
struct in_addr_data data;
uint16_t port;
int ifindex;
r = in_addr_from_string_auto(*p, &data.family, &data.address);
r = in_addr_port_ifindex_name_from_string_auto(*p, &data.family, &data.address, &port, &ifindex, &name);
if (r < 0)
return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
r = sd_bus_message_open_container(req, 'r', "iay");
if (ifindex != 0 && ifindex != arg_ifindex)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifindex: %i", ifindex);
r = sd_bus_message_open_container(req, 'r', extended ? "iayqs" : "iay");
if (r < 0)
return bus_log_create_error(r);
@ -1906,6 +1949,16 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
if (r < 0)
return bus_log_create_error(r);
if (extended) {
r = sd_bus_message_append(req, "q", port);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(req, "s", name);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_message_close_container(req);
if (r < 0)
return bus_log_create_error(r);
@ -1915,7 +1968,10 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
if (r < 0)
return bus_log_create_error(r);
return sd_bus_call(bus, req, 0, error, NULL);
r = sd_bus_call(bus, req, 0, error, NULL);
if (r < 0 && extended && sd_bus_error_has_name(error, SD_BUS_ERROR_UNKNOWN_METHOD))
return call_dns(bus, dns, locator, error, false);
return r;
}
static int verb_dns(int argc, char **argv, void *userdata) {
@ -1937,11 +1993,11 @@ static int verb_dns(int argc, char **argv, void *userdata) {
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
r = call_dns(bus, argv + 2, bus_resolve_mgr, &error);
r = call_dns(bus, argv + 2, bus_resolve_mgr, &error, true);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
r = call_dns(bus, argv + 2, bus_network_mgr, &error);
r = call_dns(bus, argv + 2, bus_network_mgr, &error, true);
}
if (r < 0) {
if (arg_ifindex_permissive &&

View File

@ -4,6 +4,7 @@
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
#include "bus-message-util.h"
#include "bus-polkit.h"
#include "dns-domain.h"
#include "memory-util.h"
@ -454,11 +455,10 @@ finish:
static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
Manager *m = userdata;
union in_addr_union a;
int family, ifindex;
uint64_t flags;
const void *d;
DnsQuery *q;
size_t sz;
int r;
assert(message);
@ -466,20 +466,14 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(message, "ii", &ifindex, &family);
r = sd_bus_message_read(message, "i", &ifindex);
if (r < 0)
return r;
if (!IN_SET(family, AF_INET, AF_INET6))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
r = sd_bus_message_read_array(message, 'y', &d, &sz);
r = bus_message_read_in_addr_auto(message, error, &family, &a);
if (r < 0)
return r;
if (sz != FAMILY_ADDRESS_SIZE(family))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
r = sd_bus_message_read(message, "t", &flags);
if (r < 0)
return r;
@ -488,7 +482,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
r = dns_question_new_reverse(&question, family, d);
r = dns_question_new_reverse(&question, family, &a);
if (r < 0)
return r;
@ -498,7 +492,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
q->request = sd_bus_message_ref(message);
q->request_family = family;
memcpy(&q->request_address, d, sz);
q->request_address = a;
q->complete = bus_method_resolve_address_complete;
r = dns_query_bus_track(q, message);
@ -1218,19 +1212,26 @@ fail:
return r;
}
int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) {
int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex, bool extended) {
int r;
assert(reply);
if (!s) {
if (with_ifindex)
return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0);
else
return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0);
if (with_ifindex) {
if (extended)
return sd_bus_message_append(reply, "(iiayqs)", 0, AF_UNSPEC, 0, 0, NULL);
else
return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0);
} else {
if (extended)
return sd_bus_message_append(reply, "(iayqs)", AF_UNSPEC, 0, 0, NULL);
else
return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0);
}
}
r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay");
r = sd_bus_message_open_container(reply, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay"));
if (r < 0)
return r;
@ -1248,6 +1249,55 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex
if (r < 0)
return r;
if (extended) {
r = sd_bus_message_append(reply, "q", s->port);
if (r < 0)
return r;
r = sd_bus_message_append(reply, "s", s->server_name);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int bus_property_get_dns_servers_internal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error,
bool extended) {
Manager *m = userdata;
DnsServer *s;
Iterator i;
Link *l;
int r;
assert(reply);
assert(m);
r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)");
if (r < 0)
return r;
LIST_FOREACH(servers, s, m->dns_servers) {
r = bus_dns_server_append(reply, s, true, extended);
if (r < 0)
return r;
}
HASHMAP_FOREACH(l, m->links, i)
LIST_FOREACH(servers, s, l->dns_servers) {
r = bus_dns_server_append(reply, s, true, extended);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
@ -1259,33 +1309,46 @@ static int bus_property_get_dns_servers(
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false);
}
Manager *m = userdata;
DnsServer *s;
Iterator i;
Link *l;
static int bus_property_get_dns_servers_ex(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true);
}
static int bus_property_get_fallback_dns_servers_internal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error,
bool extended) {
DnsServer *s, **f = userdata;
int r;
assert(reply);
assert(m);
assert(f);
r = sd_bus_message_open_container(reply, 'a', "(iiay)");
r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)");
if (r < 0)
return r;
LIST_FOREACH(servers, s, m->dns_servers) {
r = bus_dns_server_append(reply, s, true);
LIST_FOREACH(servers, s, *f) {
r = bus_dns_server_append(reply, s, true, extended);
if (r < 0)
return r;
}
HASHMAP_FOREACH(l, m->links, i)
LIST_FOREACH(servers, s, l->dns_servers) {
r = bus_dns_server_append(reply, s, true);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
@ -1297,24 +1360,38 @@ static int bus_property_get_fallback_dns_servers(
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false);
}
DnsServer *s, **f = userdata;
int r;
static int bus_property_get_fallback_dns_servers_ex(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true);
}
static int bus_property_get_current_dns_server_internal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error,
bool extended) {
DnsServer *s;
assert(reply);
assert(f);
assert(userdata);
r = sd_bus_message_open_container(reply, 'a', "(iiay)");
if (r < 0)
return r;
s = *(DnsServer **) userdata;
LIST_FOREACH(servers, s, *f) {
r = bus_dns_server_append(reply, s, true);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
return bus_dns_server_append(reply, s, true, extended);
}
static int bus_property_get_current_dns_server(
@ -1325,15 +1402,18 @@ static int bus_property_get_current_dns_server(
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
}
DnsServer *s;
assert(reply);
assert(userdata);
s = *(DnsServer **) userdata;
return bus_dns_server_append(reply, s, true);
static int bus_property_get_current_dns_server_ex(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
}
static int bus_property_get_domains(
@ -1497,9 +1577,6 @@ static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error
assert(m);
assert(ret);
if (ifindex <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
l = hashmap_get(m->links, INT_TO_PTR(ifindex));
if (!l)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
@ -1516,8 +1593,7 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_
assert(message);
assert(handler);
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(message, "i", &ifindex);
r = bus_message_read_ifindex(message, error, &ifindex);
if (r < 0)
return r;
@ -1532,6 +1608,10 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda
return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
}
static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error);
}
static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return call_link_method(userdata, message, bus_link_method_set_domains, error);
}
@ -1573,8 +1653,7 @@ static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_e
assert(message);
assert(m);
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(message, "i", &ifindex);
r = bus_message_read_ifindex(message, error, &ifindex);
if (r < 0)
return r;
@ -1844,8 +1923,11 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Manager, mdns_support), 0),
SD_BUS_PROPERTY("DNSOverTLS", "s", bus_property_get_dns_over_tls_mode, 0, 0),
SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("DNSEx", "a(iiayqs)", bus_property_get_dns_servers_ex, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("FallbackDNS", "a(iiay)", bus_property_get_fallback_dns_servers, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FallbackDNSEx", "a(iiayqs)", bus_property_get_fallback_dns_servers_ex, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CurrentDNSServer", "(iiay)", bus_property_get_current_dns_server, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CurrentDNSServerEx", "(iiayqs)", bus_property_get_current_dns_server_ex, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0),
SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
@ -1895,6 +1977,11 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_NO_RESULT,
bus_method_set_link_dns_servers,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("SetLinkDNSEx",
SD_BUS_ARGS("i", ifindex, "a(iayqs)", addresses),
SD_BUS_NO_RESULT,
bus_method_set_link_dns_servers_ex,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("SetLinkDomains",
SD_BUS_ARGS("i", ifindex, "a(sb)", domains),
SD_BUS_NO_RESULT,

View File

@ -9,7 +9,7 @@ extern const BusObjectImplementation manager_object;
int manager_connect_bus(Manager *m);
int _manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
#define manager_send_changed(manager, ...) _manager_send_changed(manager, __VA_ARGS__, NULL)
int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex);
int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex, bool extended);
int bus_property_get_resolve_support(sd_bus *bus, const char *path, const char *interface,
const char *property, sd_bus_message *reply,
void *userdata, sd_bus_error *error);

View File

@ -28,24 +28,33 @@ static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MA
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_stub_listener_mode, DnsStubListenerMode, DNS_STUB_LISTENER_YES);
static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
_cleanup_free_ char *server_name = NULL;
union in_addr_union address;
int family, r, ifindex = 0;
uint16_t port;
DnsServer *s;
_cleanup_free_ char *server_name = NULL;
assert(m);
assert(word);
r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name);
if (r < 0)
return r;
if (IN_SET(port, 53, 853))
port = 0;
/* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
if (!dns_server_address_valid(family, &address))
return 0;
/* By default, the port number is determined with the transaction feature level.
* See dns_transaction_port() and dns_server_port(). */
if (IN_SET(port, 53, 853))
port = 0;
/* Filter out duplicates */
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex);
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
if (s) {
/*
* Drop the marker. This is used to find the servers
@ -57,7 +66,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
return 0;
}
return dns_server_new(m, NULL, type, NULL, family, &address, ifindex, server_name);
return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name);
}
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {

View File

@ -447,8 +447,8 @@ static int dns_scope_socket(
return TAKE_FD(fd);
}
int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port) {
return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port, NULL);
int dns_scope_socket_udp(DnsScope *s, DnsServer *server) {
return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, dns_server_port(server), NULL);
}
int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address) {

View File

@ -75,7 +75,7 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec);
int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p);
int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address);
int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port);
int dns_scope_socket_udp(DnsScope *s, DnsServer *server);
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key);

View File

@ -26,6 +26,7 @@ int dns_server_new(
Link *l,
int family,
const union in_addr_union *in_addr,
uint16_t port,
int ifindex,
const char *server_name) {
@ -47,7 +48,7 @@ int dns_server_new(
return -E2BIG;
}
if (server_name) {
if (!isempty(server_name)) {
name = strdup(server_name);
if (!name)
return -ENOMEM;
@ -63,6 +64,7 @@ int dns_server_new(
.type = type,
.family = family,
.address = *in_addr,
.port = port,
.ifindex = ifindex,
.server_name = TAKE_PTR(name),
};
@ -117,6 +119,7 @@ static DnsServer* dns_server_free(DnsServer *s) {
#endif
free(s->server_string);
free(s->server_string_full);
free(s->server_name);
return mfree(s);
}
@ -223,7 +226,7 @@ static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) {
if (s->verified_feature_level != level) {
log_debug("Verified we get a response at feature level %s from DNS server %s.",
dns_server_feature_level_to_string(level),
dns_server_string(s));
strna(dns_server_string_full(s)));
s->verified_feature_level = level;
}
@ -360,7 +363,7 @@ void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level
dns_server_reset_counters(s);
}
log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", dns_server_string(s));
log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s)));
}
static bool dns_server_grace_period_expired(DnsServer *s) {
@ -414,7 +417,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
log_info("Grace period over, resuming full feature set (%s) for DNS server %s.",
dns_server_feature_level_to_string(s->possible_feature_level),
dns_server_string(s));
strna(dns_server_string_full(s)));
dns_server_flush_cache(s);
@ -500,7 +503,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
log_full(log_level, "Using degraded feature set %s instead of %s for DNS server %s.",
dns_server_feature_level_to_string(s->possible_feature_level),
dns_server_feature_level_to_string(p), dns_server_string(s));
dns_server_feature_level_to_string(p), strna(dns_server_string_full(s)));
}
}
@ -548,13 +551,37 @@ int dns_server_ifindex(const DnsServer *s) {
return 0;
}
uint16_t dns_server_port(const DnsServer *s) {
assert(s);
if (s->port > 0)
return s->port;
return 53;
}
const char *dns_server_string(DnsServer *server) {
assert(server);
if (!server->server_string)
(void) in_addr_ifindex_to_string(server->family, &server->address, dns_server_ifindex(server), &server->server_string);
return strna(server->server_string);
return server->server_string;
}
const char *dns_server_string_full(DnsServer *server) {
assert(server);
if (!server->server_string_full)
(void) in_addr_port_ifindex_name_to_string(
server->family,
&server->address,
server->port,
dns_server_ifindex(server),
server->server_name,
&server->server_string_full);
return server->server_string_full;
}
bool dns_server_dnssec_supported(DnsServer *server) {
@ -586,8 +613,8 @@ void dns_server_warn_downgrade(DnsServer *server) {
log_struct(LOG_NOTICE,
"MESSAGE_ID=" SD_MESSAGE_DNSSEC_DOWNGRADE_STR,
LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", dns_server_string(server)),
"DNS_SERVER=%s", dns_server_string(server),
LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", strna(dns_server_string_full(server))),
"DNS_SERVER=%s", strna(dns_server_string_full(server)),
"DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(server->possible_feature_level));
server->warned_downgrade = true;
@ -598,7 +625,10 @@ static void dns_server_hash_func(const DnsServer *s, struct siphash *state) {
siphash24_compress(&s->family, sizeof(s->family), state);
siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
siphash24_compress(&s->port, sizeof(s->port), state);
siphash24_compress(&s->ifindex, sizeof(s->ifindex), state);
if (s->server_name)
siphash24_compress(s->server_name, strlen(s->server_name), state);
}
static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) {
@ -612,11 +642,15 @@ static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) {
if (r != 0)
return r;
r = CMP(x->port, y->port);
if (r != 0)
return r;
r = CMP(x->ifindex, y->ifindex);
if (r != 0)
return r;
return 0;
return streq_ptr(x->server_name, y->server_name);
}
DEFINE_HASH_OPS(dns_server_hash_ops, DnsServer, dns_server_hash_func, dns_server_compare_func);
@ -655,11 +689,15 @@ void dns_server_mark_all(DnsServer *first) {
dns_server_mark_all(first->servers_next);
}
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex) {
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name) {
DnsServer *s;
LIST_FOREACH(servers, s, first)
if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0 && s->ifindex == ifindex)
if (s->family == family &&
in_addr_equal(family, &s->address, in_addr) > 0 &&
s->port == port &&
s->ifindex == ifindex &&
streq_ptr(s->server_name, name))
return s;
return NULL;
@ -690,7 +728,7 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
if (s)
log_debug("Switching to %s DNS server %s.",
dns_server_type_to_string(s->type),
dns_server_string(s));
strna(dns_server_string_full(s)));
dns_server_unref(m->current_dns_server);
m->current_dns_server = dns_server_ref(s);
@ -830,7 +868,7 @@ void dns_server_dump(DnsServer *s, FILE *f) {
f = stdout;
fputs("[Server ", f);
fputs(dns_server_string(s), f);
fputs(strna(dns_server_string_full(s)), f);
fputs(" type=", f);
fputs(dns_server_type_to_string(s->type), f);

View File

@ -56,10 +56,11 @@ struct DnsServer {
int family;
union in_addr_union address;
int ifindex; /* for IPv6 link-local DNS servers */
uint16_t port;
char *server_name;
char *server_string;
char *server_name;
char *server_string_full;
/* The long-lived stream towards this server. */
DnsStream *stream;
@ -102,6 +103,7 @@ int dns_server_new(
Link *link,
int family,
const union in_addr_union *address,
uint16_t port,
int ifindex,
const char *server_string);
@ -123,13 +125,15 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s);
int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level);
const char *dns_server_string(DnsServer *server);
const char *dns_server_string_full(DnsServer *server);
int dns_server_ifindex(const DnsServer *s);
uint16_t dns_server_port(const DnsServer *s);
bool dns_server_dnssec_supported(DnsServer *server);
void dns_server_warn_downgrade(DnsServer *server);
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex);
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name);
void dns_server_unlink_all(DnsServer *first);
void dns_server_unlink_marked(DnsServer *first);

View File

@ -314,7 +314,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
"DNS_TRANSACTION=%" PRIu16, t->id,
"DNS_QUESTION=%s", key_str,
"DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result),
"DNS_SERVER=%s", dns_server_string(t->server),
"DNS_SERVER=%s", strna(dns_server_string_full(t->server)),
"DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level));
}
@ -398,7 +398,7 @@ static int dns_transaction_pick_server(DnsTransaction *t) {
t->n_picked_servers ++;
log_debug("Using DNS server %s for transaction %u.", dns_server_string(t->server), t->id);
log_debug("Using DNS server %s for transaction %u.", strna(dns_server_string_full(t->server)), t->id);
return 1;
}
@ -544,8 +544,10 @@ static int on_stream_packet(DnsStream *s) {
return 0;
}
static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) {
return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53;
static uint16_t dns_transaction_port(DnsTransaction *t) {
if (t->server->port > 0)
return t->server->port;
return DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53;
}
static int dns_transaction_emit_tcp(DnsTransaction *t) {
@ -576,7 +578,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted))
s = dns_stream_ref(t->server->stream);
else
fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa);
fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_transaction_port(t), &sa);
type = DNS_STREAM_LOOKUP;
break;
@ -1243,7 +1245,7 @@ static int dns_transaction_emit_udp(DnsTransaction *t) {
dns_transaction_close_connection(t);
fd = dns_scope_socket_udp(t->scope, t->server, 53);
fd = dns_scope_socket_udp(t->scope, t->server);
if (fd < 0)
return fd;

View File

@ -7,12 +7,14 @@
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-message-util.h"
#include "bus-polkit.h"
#include "parse-util.h"
#include "resolve-util.h"
#include "resolved-bus.h"
#include "resolved-link-bus.h"
#include "resolved-resolv-conf.h"
#include "socket-netlink.h"
#include "stdio-util.h"
#include "strv.h"
#include "user-util.h"
@ -37,14 +39,15 @@ static int property_get_dns_over_tls_mode(
return sd_bus_message_append(reply, "s", dns_over_tls_mode_to_string(link_get_dns_over_tls_mode(l)));
}
static int property_get_dns(
static int property_get_dns_internal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
sd_bus_error *error,
bool extended) {
Link *l = userdata;
DnsServer *s;
@ -53,12 +56,12 @@ static int property_get_dns(
assert(reply);
assert(l);
r = sd_bus_message_open_container(reply, 'a', "(iay)");
r = sd_bus_message_open_container(reply, 'a', extended ? "(iayqs)" : "(iay)");
if (r < 0)
return r;
LIST_FOREACH(servers, s, l->dns_servers) {
r = bus_dns_server_append(reply, s, false);
r = bus_dns_server_append(reply, s, false, extended);
if (r < 0)
return r;
}
@ -66,6 +69,48 @@ static int property_get_dns(
return sd_bus_message_close_container(reply);
}
static int property_get_dns(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, false);
}
static int property_get_dns_ex(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, true);
}
static int property_get_current_dns_server_internal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error,
bool extended) {
DnsServer *s;
assert(reply);
assert(userdata);
s = *(DnsServer **) userdata;
return bus_dns_server_append(reply, s, false, extended);
}
static int property_get_current_dns_server(
sd_bus *bus,
const char *path,
@ -74,15 +119,18 @@ static int property_get_current_dns_server(
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
}
DnsServer *s;
assert(reply);
assert(userdata);
s = *(DnsServer **) userdata;
return bus_dns_server_append(reply, s, false);
static int property_get_current_dns_server_ex(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
}
static int property_get_domains(
@ -204,11 +252,10 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
return 0;
}
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ struct in_addr_data *dns = NULL;
size_t allocated = 0, n = 0;
static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
struct in_addr_full **dns;
Link *l = userdata;
unsigned i;
size_t n;
int r;
assert(message);
@ -218,52 +265,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
if (r < 0)
return r;
r = sd_bus_message_enter_container(message, 'a', "(iay)");
if (r < 0)
return r;
for (;;) {
int family;
size_t sz;
const void *d;
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_enter_container(message, 'r', "iay");
if (r < 0)
return r;
if (r == 0)
break;
r = sd_bus_message_read(message, "i", &family);
if (r < 0)
return r;
if (!IN_SET(family, AF_INET, AF_INET6))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
r = sd_bus_message_read_array(message, 'y', &d, &sz);
if (r < 0)
return r;
if (sz != FAMILY_ADDRESS_SIZE(family))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
if (!dns_server_address_valid(family, d))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!GREEDY_REALLOC(dns, allocated, n+1))
return -ENOMEM;
dns[n].family = family;
memcpy(&dns[n].address, d, sz);
n++;
}
r = sd_bus_message_exit_container(message);
r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
if (r < 0)
return r;
@ -272,22 +274,26 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
NULL, true, UID_INVALID,
&l->manager->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Polkit will call us back */
goto finalize;
if (r == 0) {
r = 1; /* Polkit will call us back */
goto finalize;
}
dns_server_mark_all(l->dns_servers);
for (i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
DnsServer *s;
s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
s = dns_server_find(l->dns_servers, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
if (s)
dns_server_move_back_and_unmark(s);
else {
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0, NULL);
if (r < 0)
goto clear;
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
if (r < 0) {
dns_server_unlink_all(l->dns_servers);
goto finalize;
}
}
}
@ -299,13 +305,24 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
(void) manager_write_resolv_conf(l->manager);
(void) manager_send_changed(l->manager, "DNS");
return sd_bus_reply_method_return(message, NULL);
r = sd_bus_reply_method_return(message, NULL);
finalize:
for (size_t i = 0; i < n; i++)
in_addr_full_free(dns[i]);
free(dns);
clear:
dns_server_unlink_all(l->dns_servers);
return r;
}
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
}
int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
}
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Link *l = userdata;
int r;
@ -762,7 +779,9 @@ static const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
SD_BUS_PROPERTY("DNSEx", "a(iayqs)", property_get_dns_ex, 0, 0),
SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex, offsetof(Link, current_dns_server), 0),
SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
@ -777,6 +796,11 @@ static const sd_bus_vtable link_vtable[] = {
SD_BUS_NO_RESULT,
bus_link_method_set_dns_servers,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("SetDNSEx",
SD_BUS_ARGS("a(iayqs)", addresses),
SD_BUS_NO_RESULT,
bus_link_method_set_dns_servers_ex,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("SetDomains",
SD_BUS_ARGS("a(sb)", domains),
SD_BUS_NO_RESULT,

View File

@ -11,6 +11,7 @@ extern const BusObjectImplementation link_object;
char *link_bus_path(const Link *link);
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);

View File

@ -15,6 +15,7 @@
#include "resolved-link.h"
#include "resolved-llmnr.h"
#include "resolved-mdns.h"
#include "socket-netlink.h"
#include "string-util.h"
#include "strv.h"
#include "tmpfile-util.h"
@ -251,25 +252,35 @@ int link_process_rtnl(Link *l, sd_netlink_message *m) {
return 0;
}
static int link_update_dns_server_one(Link *l, const char *name) {
static int link_update_dns_server_one(Link *l, const char *str) {
_cleanup_free_ char *name = NULL;
int family, ifindex, r;
union in_addr_union a;
DnsServer *s;
int family, r;
uint16_t port;
assert(l);
assert(name);
assert(str);
r = in_addr_from_string_auto(name, &family, &a);
r = in_addr_port_ifindex_name_from_string_auto(str, &family, &a, &port, &ifindex, &name);
if (r < 0)
return r;
s = dns_server_find(l->dns_servers, family, &a, 0);
if (ifindex != 0 && ifindex != l->ifindex)
return -EINVAL;
/* By default, the port number is determined with the transaction feature level.
* See dns_transaction_port() and dns_server_port(). */
if (IN_SET(port, 53, 853))
port = 0;
s = dns_server_find(l->dns_servers, family, &a, port, 0, name);
if (s) {
dns_server_move_back_and_unmark(s);
return 0;
}
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, NULL);
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name);
}
static int link_update_dns_servers(Link *l) {
@ -652,7 +663,9 @@ int link_update(Link *l) {
assert(l);
link_read_settings(l);
link_load_user(l);
r = link_load_user(l);
if (r < 0)
return r;
if (l->llmnr_support != RESOLVE_SUPPORT_NO) {
r = manager_llmnr_start(l->manager);
@ -730,7 +743,7 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
return s;
if (s)
log_debug("Switching to DNS server %s for interface %s.", dns_server_string(s), l->ifname);
log_debug("Switching to DNS server %s for interface %s.", strna(dns_server_string_full(s)), l->ifname);
dns_server_unref(l->current_dns_server);
l->current_dns_server = dns_server_ref(s);
@ -1207,7 +1220,7 @@ int link_save_user(Link *l) {
if (server != l->dns_servers)
fputc(' ', f);
v = dns_server_string(server);
v = dns_server_string_full(server);
if (!v) {
r = -ENOMEM;
goto fail;

View File

@ -3,8 +3,6 @@
#include "sd-bus.h"
#include "sd-bus.h"
#include "macro.h"
int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);

View File

@ -0,0 +1,182 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "bus-message-util.h"
#include "resolve-util.h"
int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret) {
int ifindex, r;
assert(message);
assert(ret);
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(message, "i", &ifindex);
if (r < 0)
return r;
if (ifindex <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
*ret = ifindex;
return 0;
}
int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret) {
int family, r;
assert(message);
assert(ret);
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(message, "i", &family);
if (r < 0)
return r;
if (!IN_SET(family, AF_INET, AF_INET6))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
*ret = family;
return 0;
}
int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr) {
int family, r;
const void *d;
size_t sz;
assert(message);
r = sd_bus_message_read(message, "i", &family);
if (r < 0)
return r;
r = sd_bus_message_read_array(message, 'y', &d, &sz);
if (r < 0)
return r;
if (!IN_SET(family, AF_INET, AF_INET6))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
if (sz != FAMILY_ADDRESS_SIZE(family))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
if (ret_family)
*ret_family = family;
if (ret_addr)
memcpy(ret_addr, d, sz);
return 0;
}
static int bus_message_read_dns_one(
sd_bus_message *message,
sd_bus_error *error,
bool extended,
int *ret_family,
union in_addr_union *ret_address,
uint16_t *ret_port,
const char **ret_server_name) {
const char *server_name = NULL;
union in_addr_union a;
uint16_t port = 0;
int family, r;
assert(message);
assert(ret_family);
assert(ret_address);
assert(ret_port);
assert(ret_server_name);
r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay");
if (r <= 0)
return r;
r = bus_message_read_in_addr_auto(message, error, &family, &a);
if (r < 0)
return r;
if (!dns_server_address_valid(family, &a))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
if (extended) {
r = sd_bus_message_read(message, "q", &port);
if (r < 0)
return r;
if (IN_SET(port, 53, 853))
port = 0;
r = sd_bus_message_read(message, "s", &server_name);
if (r < 0)
return r;
}
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
*ret_family = family;
*ret_address = a;
*ret_port = port;
*ret_server_name = server_name;
return 1;
}
int bus_message_read_dns_servers(
sd_bus_message *message,
sd_bus_error *error,
bool extended,
struct in_addr_full ***ret_dns,
size_t *ret_n_dns) {
struct in_addr_full **dns = NULL;
size_t n = 0, allocated = 0;
int r;
assert(message);
assert(ret_dns);
assert(ret_n_dns);
r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)");
if (r < 0)
return r;
for (;;) {
const char *server_name;
union in_addr_union a;
uint16_t port;
int family;
r = bus_message_read_dns_one(message, error, extended, &family, &a, &port, &server_name);
if (r < 0)
goto clear;
if (r == 0)
break;
if (!GREEDY_REALLOC(dns, allocated, n+1)) {
r = -ENOMEM;
goto clear;
}
r = in_addr_full_new(family, &a, port, 0, server_name, dns + n);
if (r < 0)
goto clear;
n++;
}
*ret_dns = TAKE_PTR(dns);
*ret_n_dns = n;
return 0;
clear:
for (size_t i = 0; i < n; i++)
in_addr_full_free(dns[i]);
free(dns);
return r;
}

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "sd-bus.h"
#include "in-addr-util.h"
#include "socket-netlink.h"
int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret);
int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret);
int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr);
int bus_message_read_dns_servers(
sd_bus_message *message,
sd_bus_error *error,
bool extended,
struct in_addr_full ***ret_dns,
size_t *ret_n_dns);

View File

@ -35,6 +35,8 @@ shared_sources = files('''
bus-log-control-api.h
bus-map-properties.c
bus-map-properties.h
bus-message-util.c
bus-message-util.h
bus-object.c
bus-object.h
bus-polkit.c

View File

@ -327,68 +327,197 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) {
return fd;
}
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret_addr, int *ret_ifindex) {
_cleanup_free_ char *buf = NULL;
const char *suffix;
int r, ifindex = 0;
int in_addr_port_ifindex_name_from_string_auto(
const char *s,
int *ret_family,
union in_addr_union *ret_address,
uint16_t *ret_port,
int *ret_ifindex,
char **ret_server_name) {
_cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL;
int family, ifindex = 0, r;
union in_addr_union a;
uint16_t port = 0;
const char *m;
assert(s);
assert(family);
assert(ret_addr);
/* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
* if one is found. */
/* This accepts the following:
* 192.168.0.1:53#example.com
* [2001:4860:4860::8888]:53%eth0#example.com */
/* if ret_port is NULL, then strings with port cannot be specified.
* Also, if ret_server_name is NULL, then server_name cannot be specified. */
m = strchr(s, '#');
if (m) {
if (!ret_server_name)
return -EINVAL;
if (isempty(m + 1))
return -EINVAL;
name = strdup(m + 1);
if (!name)
return -ENOMEM;
s = buf1 = strndup(s, m - s);
if (!buf1)
return -ENOMEM;
}
m = strchr(s, '%');
if (m) {
if (isempty(m + 1))
return -EINVAL;
suffix = strchr(s, '%');
if (suffix) {
if (ret_ifindex) {
/* If we shall return the interface index, try to parse it */
ifindex = resolve_interface(NULL, suffix + 1);
ifindex = resolve_interface(NULL, m + 1);
if (ifindex < 0)
return ifindex;
}
s = buf = strndup(s, suffix - s);
if (!buf)
s = buf2 = strndup(s, m - s);
if (!buf2)
return -ENOMEM;
}
r = in_addr_from_string_auto(s, family, ret_addr);
if (r < 0)
return r;
m = strrchr(s, ':');
if (m) {
if (*s == '[') {
_cleanup_free_ char *ip_str = NULL;
if (!ret_port)
return -EINVAL;
if (*(m - 1) != ']')
return -EINVAL;
family = AF_INET6;
r = parse_ip_port(m + 1, &port);
if (r < 0)
return r;
ip_str = strndup(s + 1, m - s - 2);
if (!ip_str)
return -ENOMEM;
r = in_addr_from_string(family, ip_str, &a);
if (r < 0)
return r;
} else {
/* First try to parse the string as IPv6 address without port number */
r = in_addr_from_string(AF_INET6, s, &a);
if (r < 0) {
/* Then the input should be IPv4 address with port number */
_cleanup_free_ char *ip_str = NULL;
if (!ret_port)
return -EINVAL;
family = AF_INET;
ip_str = strndup(s, m - s);
if (!ip_str)
return -ENOMEM;
r = in_addr_from_string(family, ip_str, &a);
if (r < 0)
return r;
r = parse_ip_port(m + 1, &port);
if (r < 0)
return r;
} else
family = AF_INET6;
}
} else {
family = AF_INET;
r = in_addr_from_string(family, s, &a);
if (r < 0)
return r;
}
if (ret_family)
*ret_family = family;
if (ret_address)
*ret_address = a;
if (ret_port)
*ret_port = port;
if (ret_ifindex)
*ret_ifindex = ifindex;
if (ret_server_name)
*ret_server_name = TAKE_PTR(name);
return r;
}
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
_cleanup_free_ char *buf = NULL, *name = NULL;
const char *m;
int r;
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
if (!a)
return NULL;
free(a->server_name);
free(a->cached_server_string);
return mfree(a);
}
int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret) {
_cleanup_free_ char *name = NULL;
struct in_addr_full *x;
assert(ret);
if (!isempty(server_name)) {
name = strdup(server_name);
if (!name)
return -ENOMEM;
}
x = new(struct in_addr_full, 1);
if (!x)
return -ENOMEM;
*x = (struct in_addr_full) {
.family = family,
.address = *a,
.port = port,
.ifindex = ifindex,
.server_name = TAKE_PTR(name),
};
*ret = x;
return 0;
}
int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) {
_cleanup_free_ char *server_name = NULL;
int family, ifindex, r;
union in_addr_union a;
uint16_t port;
assert(s);
m = strchr(s, '#');
if (m) {
name = strdup(m+1);
if (!name)
return -ENOMEM;
buf = strndup(s, m - s);
if (!buf)
return -ENOMEM;
s = buf;
}
r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name);
if (r < 0)
return r;
if (server_name)
*server_name = TAKE_PTR(name);
return r;
return in_addr_full_new(family, &a, port, ifindex, server_name, ret);
}
const char *in_addr_full_to_string(struct in_addr_full *a) {
assert(a);
if (!a->cached_server_string)
(void) in_addr_port_ifindex_name_to_string(
a->family,
&a->address,
a->port,
a->ifindex,
a->server_name,
&a->cached_server_string);
return a->cached_server_string;
}

View File

@ -20,5 +20,31 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s);
bool socket_address_is(const SocketAddress *a, const char *s, int type);
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
int in_addr_port_ifindex_name_from_string_auto(
const char *s,
int *ret_family,
union in_addr_union *ret_address,
uint16_t *ret_port,
int *ret_ifindex,
char **ret_server_name);
static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
return in_addr_port_ifindex_name_from_string_auto(s, family, ret, NULL, ifindex, server_name);
}
static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
}
struct in_addr_full {
int family;
union in_addr_union address;
uint16_t port;
int ifindex;
char *server_name;
char *cached_server_string; /* Should not be handled directly, but through in_addr_full_to_string(). */
};
struct in_addr_full *in_addr_full_free(struct in_addr_full *a);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct in_addr_full*, in_addr_full_free);
int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret);
int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret);
const char *in_addr_full_to_string(struct in_addr_full *a);

View File

@ -302,6 +302,38 @@ static void test_in_addr_ifindex_name_from_string_auto(void) {
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
}
static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) {
_cleanup_free_ char *name = NULL, *x = NULL;
union in_addr_union a;
uint16_t p;
int f, i;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) >= 0);
assert_se(family == f);
assert_se(port == p);
assert_se(ifindex == i);
assert_se(streq_ptr(server_name, name));
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
assert_se(streq(str, x));
}
static void test_in_addr_port_ifindex_name_from_string_auto(void) {
log_info("/* %s */", __func__);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com");
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com");
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com");
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com");
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com");
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com");
}
static void test_sockaddr_equal(void) {
union sockaddr_union a = {
.in.sin_family = AF_INET,
@ -735,6 +767,7 @@ int main(int argc, char *argv[]) {
test_in_addr_ifindex_to_string();
test_in_addr_ifindex_from_string_auto();
test_in_addr_ifindex_name_from_string_auto();
test_in_addr_port_ifindex_name_from_string_auto();
test_sockaddr_equal();

View File

@ -6,7 +6,7 @@ RequiredForOnline=routable
[Network]
IPv6AcceptRA=no
DNS=10.10.10.10 10.10.10.11
DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com
NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org
Domains=hogehoge ~foofoo
LLMNR=no

View File

@ -2601,7 +2601,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes')
self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
self.assertRegex(data, r'DNS=10.10.10.10 10.10.10.11')
self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
self.assertRegex(data, r'DOMAINS=hogehoge')
self.assertRegex(data, r'ROUTE_DOMAINS=foofoo')
@ -2610,7 +2610,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
self.assertRegex(data, r'DNSSEC=no')
self.assertRegex(data, r'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env=env)
check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env)
check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env)
check_output(*resolvectl_cmd, 'llmnr', 'dummy98', 'yes', env=env)
check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env)
@ -2620,7 +2620,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
with open(path) as f:
data = f.read()
self.assertRegex(data, r'DNS=10.10.10.12 10.10.10.13')
self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
self.assertRegex(data, r'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
self.assertRegex(data, r'DOMAINS=hogehogehoge')
self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo')
@ -2633,7 +2633,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
with open(path) as f:
data = f.read()
self.assertRegex(data, r'DNS=10.10.10.12 10.10.10.13')
self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
self.assertRegex(data, r'DOMAINS=hogehogehoge')
self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo')
@ -2646,7 +2646,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
with open(path) as f:
data = f.read()
self.assertRegex(data, r'DNS=10.10.10.10 10.10.10.11')
self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
self.assertRegex(data, r'DOMAINS=hogehoge')
self.assertRegex(data, r'ROUTE_DOMAINS=foofoo')