mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #16353 from yuwata/network-dns-sni
resolve, network: more SNI and port number support
This commit is contained in:
commit
739b9a4354
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) ||
|
||||
|
@ -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 &&
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
182
src/shared/bus-message-util.c
Normal file
182
src/shared/bus-message-util.c
Normal 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;
|
||||
}
|
18
src/shared/bus-message-util.h
Normal file
18
src/shared/bus-message-util.h
Normal 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);
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user