diff options
41 files changed, 668 insertions, 174 deletions
@@ -30,6 +30,11 @@ CHANGES WITH 233 in spe during startup. If no such message is sent, the service now fails, even if the main process exited with a successful exit code. + * The option MulticastDNS= of network configuration files has got + actual implementation. With MulticastDNS=yes a host can resolve + names of remote hosts and to reply to mDNS's A and AAAA requests + from the hosts. + CHANGES WITH 232: * The new RemoveIPC= option can be used to remove IPC objects owned by diff --git a/man/busctl.xml b/man/busctl.xml index 052a33097f..f63d0d5bab 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -291,11 +291,11 @@ <listitem><para>Similar to <command>monitor</command> but writes the output in pcap format (for details, see the <ulink - url="http://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap - File Format</ulink> description. Make sure to redirect the - output to STDOUT to a file. Tools like + url="https://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap + File Format</ulink> description). Make sure to redirect + standard output to a file. Tools like <citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry> - may be used to dissect and view the generated + may be used to dissect and view the resulting files.</para></listitem> </varlistentry> diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index b52f946fa5..50da971b07 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -182,7 +182,9 @@ (i.e. classic unicast DNS), <literal>llmnr</literal> (<ulink url="https://tools.ietf.org/html/rfc4795">Link-Local Multicast Name Resolution</ulink>), <literal>llmnr-ipv4</literal>, <literal>llmnr-ipv6</literal> (LLMNR via the indicated underlying IP - protocols). By default the lookup is done via all protocols suitable for the lookup. If used, limits the set of + protocols), <literal>mdns</literal> (<ulink url="https://www.ietf.org/rfc/rfc6762.txt">Multicast DNS</ulink>), + <literal>mdns-ipv4</literal>, <literal>mdns-ipv6</literal> (MDNS via the indicated underlying IP protocols). + By default the lookup is done via all protocols suitable for the lookup. If used, limits the set of protocols that may be used. Use this option multiple times to enable resolving via multiple protocols at the same time. The setting <literal>llmnr</literal> is identical to specifying this switch once with <literal>llmnr-ipv4</literal> and once via <literal>llmnr-ipv6</literal>. Note that this option does not force diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 51d881c5fb..a9402fdb28 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -461,6 +461,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { "org.freedesktop.hostname1", "/org/freedesktop/hostname1", hostname_map, + &error, host); if (r < 0) log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r)); @@ -469,6 +470,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { "org.freedesktop.systemd1", "/org/freedesktop/systemd1", manager_map, + &error, host); if (r < 0) return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r)); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 27f948cbdd..f87b52a266 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1338,7 +1338,7 @@ static int verify_run_space(const char *message, sd_bus_error *error) { } int verify_run_space_and_log(const char *message) { - sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; r = verify_run_space(message, &error); diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 07c57fb567..f5a9de94a6 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -137,10 +137,8 @@ static int show_one_name(sd_bus *bus, const char* attr) { "org.freedesktop.hostname1", attr, &error, &reply, "s"); - if (r < 0) { - log_error("Could not get property: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Could not get property: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &s); if (r < 0) @@ -151,7 +149,7 @@ static int show_one_name(sd_bus *bus, const char* attr) { return 0; } -static int show_all_names(sd_bus *bus) { +static int show_all_names(sd_bus *bus, sd_bus_error *error) { StatusInfo info = {}; static const struct bus_properties_map hostname_map[] = { @@ -181,6 +179,7 @@ static int show_all_names(sd_bus *bus) { "org.freedesktop.hostname1", "/org/freedesktop/hostname1", hostname_map, + error, &info); if (r < 0) goto fail; @@ -189,6 +188,7 @@ static int show_all_names(sd_bus *bus) { "org.freedesktop.systemd1", "/org/freedesktop/systemd1", manager_map, + error, &info); print_status_info(&info); @@ -212,6 +212,8 @@ fail: } static int show_status(sd_bus *bus, char **args, unsigned n) { + int r; + assert(args); if (arg_pretty || arg_static || arg_transient) { @@ -226,8 +228,15 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { arg_static ? "StaticHostname" : "Hostname"; return show_one_name(bus, attr); - } else - return show_all_names(bus); + } else { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + + r = show_all_names(bus, &error); + if (r < 0) + return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r)); + + return 0; + } } static int set_simple_string(sd_bus *bus, const char *method, const char *value) { diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 81afb4909f..0bd18a5c0b 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -166,6 +166,8 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { { "Locale", "as", NULL, offsetof(StatusInfo, locale) }, {} }; + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -174,9 +176,10 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { "org.freedesktop.locale1", "/org/freedesktop/locale1", map, + &error, &info); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); print_overridden_variables(); print_status_info(&info); diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 1aac7ae979..7dea5c0859 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -482,14 +482,15 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; char since2[FORMAT_TIMESTAMP_MAX], *s2; _cleanup_(session_status_info_clear) SessionStatusInfo i = {}; int r; - r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i); + r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); if (*new_line) printf("\n"); @@ -611,14 +612,15 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; char since2[FORMAT_TIMESTAMP_MAX], *s2; _cleanup_(user_status_info_clear) UserStatusInfo i = {}; int r; - r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i); + r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); if (*new_line) printf("\n"); @@ -685,12 +687,13 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(seat_status_info_clear) SeatStatusInfo i = {}; int r; - r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i); + r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); if (*new_line) printf("\n"); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4f5f659c7c..fe4f1b7726 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -772,6 +772,7 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(machine_status_info_clear) MachineStatusInfo info = {}; int r; @@ -784,9 +785,10 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo "org.freedesktop.machine1", path, map, + &error, &info); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); if (*new_line) printf("\n"); @@ -962,6 +964,7 @@ static int show_image_info(sd_bus *bus, const char *path, bool *new_line) { {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(image_status_info_clear) ImageStatusInfo info = {}; int r; @@ -973,9 +976,10 @@ static int show_image_info(sd_bus *bus, const char *path, bool *new_line) { "org.freedesktop.machine1", path, map, + &error, &info); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); if (*new_line) printf("\n"); @@ -1029,6 +1033,8 @@ static int show_pool_info(sd_bus *bus) { .usage = (uint64_t) -1, .limit = (uint64_t) -1, }; + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1037,9 +1043,10 @@ static int show_pool_info(sd_bus *bus) { "org.freedesktop.machine1", "/org/freedesktop/machine1", map, + &error, &info); if (r < 0) - return log_error_errno(r, "Could not get properties: %m"); + return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r)); print_pool_status_info(bus, &info); diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 11c27575c0..326672cab5 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -55,7 +55,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( _cleanup_free_ struct local_address *addresses = NULL; _cleanup_free_ char *hn = NULL; const char *canonical = NULL; - int n_addresses = 0, lo_ifi; + int n_addresses = 0; uint32_t local_address_ipv4; struct local_address *a; size_t l, idx, ms; @@ -111,9 +111,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r( local_address_ipv4 = LOCALADDRESS_IPV4; } - /* If this call fails we fill in 0 as scope. Which is fine */ - lo_ifi = n_addresses <= 0 ? LOOPBACK_IFINDEX : 0; - l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2); if (buflen < ms) { @@ -135,7 +132,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( r_tuple->name = r_name; r_tuple->family = AF_INET6; memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16); - r_tuple->scopeid = (uint32_t) lo_ifi; + r_tuple->scopeid = 0; idx += ALIGN(sizeof(struct gaih_addrtuple)); r_tuple_prev = r_tuple; @@ -146,7 +143,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( r_tuple->name = r_name; r_tuple->family = AF_INET; *(uint32_t*) r_tuple->addr = local_address_ipv4; - r_tuple->scopeid = (uint32_t) lo_ifi; + r_tuple->scopeid = 0; idx += ALIGN(sizeof(struct gaih_addrtuple)); r_tuple_prev = r_tuple; @@ -158,7 +155,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( r_tuple->next = r_tuple_prev; r_tuple->name = r_name; r_tuple->family = a->family; - r_tuple->scopeid = a->ifindex; + r_tuple->scopeid = a->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&a->address.in6) ? a->ifindex : 0; memcpy(r_tuple->addr, &a->address, 16); idx += ALIGN(sizeof(struct gaih_addrtuple)); diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index d46a3afe91..ce8d59d390 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -110,6 +110,20 @@ static int count_addresses(sd_bus_message *m, int af, const char **canonical) { return c; } +static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) { + struct in6_addr in6; + + if (family != AF_INET6) + return 0; + + /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */ + + assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET)); + memcpy(&in6, a, sizeof(struct in6_addr)); + + return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0; +} + enum nss_status _nss_resolve_gethostbyname4_r( const char *name, struct gaih_addrtuple **pat, @@ -245,7 +259,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple))); r_tuple->name = r_name; r_tuple->family = family; - r_tuple->scopeid = ifindex; + r_tuple->scopeid = ifindex_to_scopeid(family, a, ifindex); memcpy(r_tuple->addr, a, sz); idx += ALIGN(sizeof(struct gaih_addrtuple)); diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 07d9582ccb..3cec36817a 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -1186,6 +1186,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *ifi = NULL, *p = NULL; char ifname[IF_NAMESIZE] = ""; char **i; @@ -1213,9 +1214,10 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt "org.freedesktop.resolve1", p, property_map, + &error, &link_info); if (r < 0) { - log_error_errno(r, "Failed to get link data for %i: %m", ifindex); + log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r)); goto finish; } @@ -1405,6 +1407,7 @@ static int status_global(sd_bus *bus, bool *empty_line) { {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char **i; int r; @@ -1415,9 +1418,10 @@ static int status_global(sd_bus *bus, bool *empty_line) { "org.freedesktop.resolve1", "/org/freedesktop/resolve1", property_map, + &error, &global_info); if (r < 0) { - log_error_errno(r, "Failed to get global data: %m"); + log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r)); goto finish; } @@ -1524,7 +1528,7 @@ static int status_all(sd_bus *bus) { static void help_protocol_types(void) { if (arg_legend) puts("Known protocol types:"); - puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6"); + puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6\nmdns\nmnds-ipv4\nmdns-ipv6"); } static void help_dns_types(void) { @@ -1722,6 +1726,12 @@ static int parse_argv(int argc, char *argv[]) { arg_flags |= SD_RESOLVED_LLMNR_IPV4; else if (streq(optarg, "llmnr-ipv6")) arg_flags |= SD_RESOLVED_LLMNR_IPV6; + else if (streq(optarg, "mdns")) + arg_flags |= SD_RESOLVED_MDNS; + else if (streq(optarg, "mdns-ipv4")) + arg_flags |= SD_RESOLVED_MDNS_IPV4; + else if (streq(optarg, "mdns-ipv6")) + arg_flags |= SD_RESOLVED_MDNS_IPV6; else { log_error("Unknown protocol specifier: %s", optarg); return -EINVAL; diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 2ca65e6953..2c50109388 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -211,7 +211,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { r = sd_bus_message_append( reply, "st", normalized, - SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); + SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); if (r < 0) goto finish; @@ -439,7 +439,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); + r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); if (r < 0) goto finish; @@ -605,7 +605,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); + r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); if (r < 0) goto finish; @@ -979,7 +979,7 @@ static void resolve_service_all_complete(DnsQuery *q) { reply, "ssst", name, type, domain, - SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); + SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); if (r < 0) goto finish; diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 4a92bd1150..11d2e25eeb 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -33,9 +33,11 @@ typedef struct DnsAnswerItem DnsAnswerItem; * Note that we usually encode the empty DnsAnswer object as a simple NULL. */ typedef enum DnsAnswerFlags { - DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */ - DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */ - DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */ + DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */ + DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */ + DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */ + DNS_ANSWER_CACHE_FLUSH = 8, /* For mDNS: sets cache-flush bit in the rrclass of response records */ + DNS_ANSWER_GOODBYE = 16, /* For mDNS: item is subject to disappear */ } DnsAnswerFlags; struct DnsAnswerItem { diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 9233fb0ac1..c43a7865dc 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -980,7 +980,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { if (!j->shared_owner) continue; - r = dns_packet_append_rr(p, j->rr, NULL, NULL); + r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL); if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) { /* For mDNS, if we're unable to stuff all known answers into the given packet, * allocate a new one, push the RR into that one and link it to the current one. @@ -995,7 +995,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { /* continue with new packet */ p = p->more; - r = dns_packet_append_rr(p, j->rr, NULL, NULL); + r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL); } if (r < 0) diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 337a8c473f..652970284e 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -569,8 +569,9 @@ fail: return r; } -int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) { +int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, const DnsAnswerFlags flags, size_t *start) { size_t saved_size; + uint16_t class; int r; assert(p); @@ -586,7 +587,8 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) if (r < 0) goto fail; - r = dns_packet_append_uint16(p, k->class, NULL); + class = flags & DNS_ANSWER_CACHE_FLUSH ? k->class | MDNS_RR_CACHE_FLUSH : k->class; + r = dns_packet_append_uint16(p, class, NULL); if (r < 0) goto fail; @@ -791,9 +793,10 @@ int dns_packet_truncate_opt(DnsPacket *p) { return 1; } -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) { +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start) { size_t saved_size, rdlength_offset, end, rdlength, rds; + uint32_t ttl; int r; assert(p); @@ -801,11 +804,12 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star saved_size = p->size; - r = dns_packet_append_key(p, rr->key, NULL); + r = dns_packet_append_key(p, rr->key, flags, NULL); if (r < 0) goto fail; - r = dns_packet_append_uint32(p, rr->ttl, NULL); + ttl = flags & DNS_ANSWER_GOODBYE ? 0 : rr->ttl; + r = dns_packet_append_uint32(p, ttl, NULL); if (r < 0) goto fail; @@ -1143,7 +1147,7 @@ int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) { assert(p); DNS_QUESTION_FOREACH(key, q) { - r = dns_packet_append_key(p, key, NULL); + r = dns_packet_append_key(p, key, 0, NULL); if (r < 0) return r; } @@ -1153,12 +1157,13 @@ int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) { int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) { DnsResourceRecord *rr; + DnsAnswerFlags flags; int r; assert(p); - DNS_ANSWER_FOREACH(rr, a) { - r = dns_packet_append_rr(p, rr, NULL, NULL); + DNS_ANSWER_FOREACH_FLAGS(rr, flags, a) { + r = dns_packet_append_rr(p, rr, flags, NULL, NULL); if (r < 0) return r; } diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 054dc88a85..2c92392e4d 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -209,8 +209,8 @@ int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start); int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start); int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonical_candidate, size_t *start); int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start); -int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start); +int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnswerFlags flags, size_t *start); +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start); int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start); int dns_packet_append_question(DnsPacket *p, DnsQuestion *q); int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index e03db4d003..c58845c3b6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -403,6 +403,7 @@ DnsQuery *dns_query_free(DnsQuery *q) { sd_bus_track_unref(q->bus_track); dns_packet_unref(q->request_dns_packet); + dns_packet_unref(q->reply_dns_packet); if (q->request_dns_stream) { /* Detach the stream from our query, in case something else keeps a reference to it. */ @@ -1028,6 +1029,9 @@ int dns_query_process_cname(DnsQuery *q) { if (q->flags & SD_RESOLVED_NO_CNAME) return -ELOOP; + if (!q->answer_authenticated) + q->previous_redirect_unauthenticated = true; + /* OK, let's actually follow the CNAME */ r = dns_query_cname_redirect(q, cname); if (r < 0) @@ -1115,3 +1119,9 @@ const char *dns_query_string(DnsQuery *q) { return dns_question_first_name(q->question_idna); } + +bool dns_query_fully_authenticated(DnsQuery *q) { + assert(q); + + return q->answer_authenticated && !q->previous_redirect_unauthenticated; +} diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 49a35b846b..b8ea48f6af 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -71,7 +71,6 @@ struct DnsQuery { * family */ bool suppress_unroutable_family; - /* If true, the RR TTLs of the answer will be clamped by their current left validity in the cache */ bool clamp_ttl; @@ -90,6 +89,7 @@ struct DnsQuery { int answer_family; DnsSearchDomain *answer_search_domain; int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ + bool previous_redirect_unauthenticated; /* Bus client information */ sd_bus_message *request; @@ -102,6 +102,7 @@ struct DnsQuery { /* DNS stub information */ DnsPacket *request_dns_packet; DnsStream *request_dns_stream; + DnsPacket *reply_dns_packet; /* Completion callback */ void (*complete)(DnsQuery* q); @@ -139,3 +140,5 @@ DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol); const char *dns_query_string(DnsQuery *q); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free); + +bool dns_query_fully_authenticated(DnsQuery *q); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 209d565033..e8c05ed0da 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1262,7 +1262,7 @@ int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { if (rr->wire_format && rr->wire_format_canonical == canonical) return 0; - r = dns_packet_append_rr(&packet, rr, &start, &rds); + r = dns_packet_append_rr(&packet, rr, 0, &start, &rds); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 8dbc7f623b..750409eebf 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -124,6 +124,8 @@ DnsScope* dns_scope_free(DnsScope *s) { ordered_hashmap_free(s->conflict_queue); sd_event_source_unref(s->conflict_event_source); + sd_event_source_unref(s->announce_event_source); + dns_cache_flush(&s->cache); dns_zone_flush(&s->zone); @@ -549,7 +551,11 @@ static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in .imr_ifindex = s->link->ifindex, }; - fd = manager_llmnr_ipv4_udp_fd(s->manager); + if (s->protocol == DNS_PROTOCOL_LLMNR) + fd = manager_llmnr_ipv4_udp_fd(s->manager); + else + fd = manager_mdns_ipv4_fd(s->manager); + if (fd < 0) return fd; @@ -568,7 +574,11 @@ static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in .ipv6mr_interface = s->link->ifindex, }; - fd = manager_llmnr_ipv6_udp_fd(s->manager); + if (s->protocol == DNS_PROTOCOL_LLMNR) + fd = manager_llmnr_ipv6_udp_fd(s->manager); + else + fd = manager_mdns_ipv6_fd(s->manager); + if (fd < 0) return fd; @@ -601,7 +611,7 @@ int dns_scope_mdns_membership(DnsScope *s, bool b) { return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS); } -static int dns_scope_make_reply_packet( +int dns_scope_make_reply_packet( DnsScope *s, uint16_t id, int rcode, @@ -783,8 +793,15 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, /* Try to find an ongoing transaction that is a equal to the * specified question */ t = hashmap_get(scope->transactions_by_key, key); - if (!t) - return NULL; + if (!t) { + DnsResourceKey *key_any; + + key_any = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_ANY, dns_resource_key_name(key)); + t = hashmap_get(scope->transactions_by_key, key_any); + key_any = dns_resource_key_unref(key_any); + if (!t) + return NULL; + } /* Refuse reusing transactions that completed based on cached * data instead of a real packet, if that's requested. */ @@ -830,11 +847,11 @@ static int dns_scope_make_conflict_packet( DNS_PACKET_HEADER(p)->qdcount = htobe16(1); DNS_PACKET_HEADER(p)->arcount = htobe16(1); - r = dns_packet_append_key(p, rr->key, NULL); + r = dns_packet_append_key(p, rr->key, 0, NULL); if (r < 0) return r; - r = dns_packet_append_rr(p, rr, NULL, NULL); + r = dns_packet_append_rr(p, rr, 0, NULL, NULL); if (r < 0) return r; @@ -928,17 +945,19 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) { assert(scope); assert(p); - if (p->protocol != DNS_PROTOCOL_LLMNR) + if (!IN_SET(p->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) return; if (DNS_PACKET_RRCOUNT(p) <= 0) return; - if (DNS_PACKET_LLMNR_C(p) != 0) - return; + if (p->protocol == DNS_PROTOCOL_LLMNR) { + if (DNS_PACKET_LLMNR_C(p) != 0) + return; - if (DNS_PACKET_LLMNR_T(p) != 0) - return; + if (DNS_PACKET_LLMNR_T(p) != 0) + return; + } if (manager_our_packet(scope->manager, p)) return; @@ -1041,3 +1060,76 @@ int dns_scope_ifindex(DnsScope *s) { return 0; } + +static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userdata) { + DnsScope *scope = userdata; + + assert(s); + + scope->announce_event_source = sd_event_source_unref(scope->announce_event_source); + + dns_scope_announce(scope, false); + return 0; +} + +void dns_scope_announce(DnsScope *scope, bool goodbye) { + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + LinkAddress *a; + int r; + + if (!scope) + return; + + if (scope->protocol != DNS_PROTOCOL_MDNS) + return; + + answer = dns_answer_new(4); + LIST_FOREACH(addresses, a, scope->link->addresses) { + r = dns_answer_add(answer, a->mdns_address_rr, 0, goodbye ? DNS_ANSWER_GOODBYE : DNS_ANSWER_CACHE_FLUSH); + if (r < 0) { + log_debug_errno(r, "Failed to add address RR to answer: %m"); + return; + } + r = dns_answer_add(answer, a->mdns_ptr_rr, 0, goodbye ? DNS_ANSWER_GOODBYE : DNS_ANSWER_CACHE_FLUSH); + if (r < 0) { + log_debug_errno(r, "Failed to add PTR RR to answer: %m"); + return; + } + } + + if (dns_answer_isempty(answer)) + return; + + r = dns_scope_make_reply_packet(scope, 0, DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &p); + if (r < 0) { + log_debug_errno(r, "Failed to build reply packet: %m"); + return; + } + r = dns_scope_emit_udp(scope, -1, p); + if (r < 0) { + log_debug_errno(r, "Failed to send reply packet: %m"); + return; + } + + /* In section 8.3 of RFC6762: "The Multicast DNS responder MUST send at least two unsolicited + * responses, one second apart." */ + if (!scope->announced) { + usec_t ts; + + scope->announced = true; + + assert_se(sd_event_now(scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); + ts += MDNS_ANNOUNCE_DELAY; + + r = sd_event_add_time( + scope->manager->event, + &scope->announce_event_source, + clock_boottime_or_monotonic(), + ts, + MDNS_JITTER_RANGE_USEC, + on_announcement_timeout, scope); + if (r < 0) + log_debug_errno(r, "Failed to schedule second announcement: %m"); + } +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 01a83a76b2..360d86bc25 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -56,6 +56,9 @@ struct DnsScope { OrderedHashmap *conflict_queue; sd_event_source *conflict_event_source; + bool announced:1; + sd_event_source *announce_event_source; + RateLimit ratelimit; usec_t resend_timeout; @@ -96,6 +99,7 @@ void dns_scope_next_dns_server(DnsScope *s); int dns_scope_llmnr_membership(DnsScope *s, bool b); int dns_scope_mdns_membership(DnsScope *s, bool b); +int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *answer, DnsAnswer *soa, bool tentative, DnsPacket **ret); void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p); DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok); @@ -112,3 +116,5 @@ bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); bool dns_scope_network_good(DnsScope *s); int dns_scope_ifindex(DnsScope *s); + +void dns_scope_announce(DnsScope *scope, bool goodbye); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 22c64e8491..10562d03ec 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -451,18 +451,22 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_EDNS0; } else if (s->n_failed_udp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && - s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_UDP) { + s->possible_feature_level >= (dns_server_get_dnssec_mode(s) == DNSSEC_YES ? DNS_SERVER_FEATURE_LEVEL_LARGE : DNS_SERVER_FEATURE_LEVEL_UDP)) { /* We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If the * packets are lost, maybe the server cannot parse them, hence downgrading sounds like a good - * idea. We might downgrade all the way down to TCP this way. */ + * idea. We might downgrade all the way down to TCP this way. + * + * If strict DNSSEC mode is used we won't downgrade below DO level however, as packet loss + * might have many reasons, a broken DNSSEC implementation being only one reason. And if the + * user is strict on DNSSEC, then let's assume that DNSSEC is not the fault here. */ log_debug("Lost too many UDP packets, downgrading feature level..."); s->possible_feature_level--; } else if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && s->packet_truncated && - s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) { + s->possible_feature_level > (dns_server_get_dnssec_mode(s) == DNSSEC_YES ? DNS_SERVER_FEATURE_LEVEL_LARGE : DNS_SERVER_FEATURE_LEVEL_UDP)) { /* We got too many TCP connection failures in a row, we had at least one truncated packet, and * are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or EDNS0 @@ -779,6 +783,15 @@ bool dns_server_address_valid(int family, const union in_addr_union *sa) { return true; } +DnssecMode dns_server_get_dnssec_mode(DnsServer *s) { + assert(s); + + if (s->link) + return link_get_dnssec_mode(s->link); + + return manager_get_dnssec_mode(s->manager); +} + static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = { [DNS_SERVER_SYSTEM] = "system", [DNS_SERVER_FALLBACK] = "fallback", diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 83e288a202..406282d864 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -144,6 +144,8 @@ void manager_next_dns_server(Manager *m); bool dns_server_address_valid(int family, const union in_addr_union *sa); +DnssecMode dns_server_get_dnssec_mode(DnsServer *s); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref); extern const struct hash_ops dns_server_hash_ops; diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 4a3c5f612f..7d43825960 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -29,49 +29,33 @@ static int manager_dns_stub_udp_fd(Manager *m); static int manager_dns_stub_tcp_fd(Manager *m); static int dns_stub_make_reply_packet( - uint16_t id, - int rcode, + DnsPacket **p, DnsQuestion *q, - DnsAnswer *answer, - bool add_opt, /* add an OPT RR to this packet */ - bool edns0_do, /* set the EDNS0 DNSSEC OK bit */ - bool ad, /* set the DNSSEC authenticated data bit */ - DnsPacket **ret) { + DnsAnswer *answer) { - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; DnsResourceRecord *rr; unsigned c = 0; int r; + assert(p); + /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence * roundtrips aren't expensive. */ - r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); - if (r < 0) - return r; - - /* If the client didn't do EDNS, clamp the rcode to 4 bit */ - if (!add_opt && rcode > 0xF) - rcode = DNS_RCODE_SERVFAIL; + if (!*p) { + r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0); + if (r < 0) + return r; - DNS_PACKET_HEADER(p)->id = id; - DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS( - 1 /* qr */, - 0 /* opcode */, - 0 /* aa */, - 0 /* tc */, - 1 /* rd */, - 1 /* ra */, - ad /* ad */, - 0 /* cd */, - rcode)); + r = dns_packet_append_question(*p, q); + if (r < 0) + return r; - r = dns_packet_append_question(p, q); - if (r < 0) - return r; - DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q)); + DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q)); + } DNS_ANSWER_FOREACH(rr, answer) { + r = dns_question_matches_rr(q, rr, NULL); if (r < 0) return r; @@ -86,13 +70,46 @@ static int dns_stub_make_reply_packet( continue; add: - r = dns_packet_append_rr(p, rr, NULL, NULL); + r = dns_packet_append_rr(*p, rr, 0, NULL, NULL); if (r < 0) return r; c++; } - DNS_PACKET_HEADER(p)->ancount = htobe16(c); + + DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c); + + return 0; +} + +static int dns_stub_finish_reply_packet( + DnsPacket *p, + uint16_t id, + int rcode, + bool add_opt, /* add an OPT RR to this packet? */ + bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */ + bool ad) { /* set the DNSSEC authenticated data bit? */ + + int r; + + assert(p); + + /* If the client didn't do EDNS, clamp the rcode to 4 bit */ + if (!add_opt && rcode > 0xF) + rcode = DNS_RCODE_SERVFAIL; + + DNS_PACKET_HEADER(p)->id = id; + + DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS( + 1 /* qr */, + 0 /* opcode */, + 0 /* aa */, + 0 /* tc */, + 1 /* rd */, + 1 /* ra */, + ad /* ad */, + 0 /* cd */, + rcode)); if (add_opt) { r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL); @@ -100,9 +117,6 @@ static int dns_stub_make_reply_packet( return r; } - *ret = p; - p = NULL; - return 0; } @@ -155,7 +169,11 @@ static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rco assert(m); assert(p); - r = dns_stub_make_reply_packet(DNS_PACKET_ID(p), rcode, p->question, NULL, !!p->opt, DNS_PACKET_DO(p), false, &reply); + r = dns_stub_make_reply_packet(&reply, p->question, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to make failure packet: %m"); + + r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, !!p->opt, DNS_PACKET_DO(p), false); if (r < 0) return log_debug_errno(r, "Failed to build failure packet: %m"); @@ -170,26 +188,40 @@ static void dns_stub_query_complete(DnsQuery *q) { switch (q->state) { - case DNS_TRANSACTION_SUCCESS: { - _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + case DNS_TRANSACTION_SUCCESS: + + r = dns_stub_make_reply_packet(&q->reply_dns_packet, q->question_idna, q->answer); + if (r < 0) { + log_debug_errno(r, "Failed to build reply packet: %m"); + break; + } + + r = dns_query_process_cname(q); + if (r == -ELOOP) { + (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL); + break; + } + if (r < 0) { + log_debug_errno(r, "Failed to process CNAME: %m"); + break; + } + if (r == DNS_QUERY_RESTARTED) + return; - r = dns_stub_make_reply_packet( + r = dns_stub_finish_reply_packet( + q->reply_dns_packet, DNS_PACKET_ID(q->request_dns_packet), q->answer_rcode, - q->question_idna, - q->answer, !!q->request_dns_packet->opt, DNS_PACKET_DO(q->request_dns_packet), - DNS_PACKET_DO(q->request_dns_packet) && q->answer_authenticated, - &reply); + DNS_PACKET_DO(q->request_dns_packet) && dns_query_fully_authenticated(q)); if (r < 0) { - log_debug_errno(r, "Failed to build reply packet: %m"); + log_debug_errno(r, "Failed to finish reply packet: %m"); break; } - (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, reply); + (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet); break; - } case DNS_TRANSACTION_RCODE_FAILURE: (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode); @@ -301,7 +333,7 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) { goto fail; } - r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_NO_CNAME); + r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH); if (r < 0) { log_error_errno(r, "Failed to generate query object: %m"); dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 2fce44ec8b..0c7a8867fb 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -363,6 +363,8 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items) dns_zone_item_notify(z); SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done); + if (t->probing) + dns_scope_announce(t->scope, false); SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions) dns_transaction_notify(d, t); @@ -924,7 +926,16 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { dns_transaction_retry(t, false /* use the same server */); return; - } else if (DNS_PACKET_TC(p)) + } + + if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) { + /* This server refused our request? If so, try again, use a different server */ + log_debug("Server returned REFUSED, switching servers, and retrying."); + dns_transaction_retry(t, true /* pick a new server */); + return; + } + + if (DNS_PACKET_TC(p)) dns_server_packet_truncated(t->server, t->current_feature_level); break; @@ -1003,15 +1014,20 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { if (r > 0) /* Transaction got restarted... */ return; - if (IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) { + if (IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) { - /* Only consider responses with equivalent query section to the request */ - r = dns_packet_is_reply_for(p, t->key); - if (r < 0) - goto fail; - if (r == 0) { - dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); - return; + /* When dealing with protocols other than mDNS only consider responses with + * equivalent query section to the request. For mDNS this check doesn't make + * sense, because the section 6 of RFC6762 states that "Multicast DNS responses MUST NOT + * contain any questions in the Question Section". */ + if (t->scope->protocol != DNS_PROTOCOL_MDNS) { + r = dns_packet_is_reply_for(p, t->key); + if (r < 0) + goto fail; + if (r == 0) { + dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + return; + } } /* Install the answer as answer to the transaction */ @@ -1204,7 +1220,10 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) { case DNS_PROTOCOL_MDNS: assert(t->n_attempts > 0); - return (1 << (t->n_attempts - 1)) * USEC_PER_SEC; + if (t->probing) + return MDNS_PROBING_INTERVAL_USEC; + else + return (1 << (t->n_attempts - 1)) * USEC_PER_SEC; case DNS_PROTOCOL_LLMNR: return t->scope->resend_timeout; @@ -1358,7 +1377,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { if (r < 0) return r; - r = dns_packet_append_key(p, t->key, NULL); + r = dns_packet_append_key(p, t->key, 0, NULL); if (r < 0) return r; @@ -1390,7 +1409,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { if (qdcount >= UINT16_MAX) break; - r = dns_packet_append_key(p, other->key, NULL); + r = dns_packet_append_key(p, other->key, 0, NULL); /* * If we can't stuff more questions into the packet, just give up. @@ -1417,7 +1436,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { if (r < 0) return r; - (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout"); + (void) sd_event_source_set_description(other->timeout_event_source, "dns-transaction-timeout"); other->state = DNS_TRANSACTION_PENDING; other->next_attempt_after = ts; @@ -1459,7 +1478,7 @@ static int dns_transaction_make_packet(DnsTransaction *t) { if (r < 0) return r; - r = dns_packet_append_key(p, t->key, NULL); + r = dns_packet_append_key(p, t->key, 0, NULL); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 5a1df70422..c4fb51958d 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -78,6 +78,8 @@ struct DnsTransaction { bool clamp_ttl:1; + bool probing:1; + DnsPacket *sent, *received; DnsAnswer *answer; @@ -172,10 +174,20 @@ DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_; #define MDNS_JITTER_MIN_USEC (20 * USEC_PER_MSEC) #define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC) +/* mDNS probing interval, see RFC 6762 Section 8.1 */ +#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC) + /* Maximum attempts to send DNS requests, across all DNS servers */ #define DNS_TRANSACTION_ATTEMPTS_MAX 16 /* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */ #define LLMNR_TRANSACTION_ATTEMPTS_MAX 3 -#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX) +/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */ +#define MDNS_TRANSACTION_ATTEMPTS_MAX 3 + +#define TRANSACTION_ATTEMPTS_MAX(p) (((p) == DNS_PROTOCOL_LLMNR) ? \ + LLMNR_TRANSACTION_ATTEMPTS_MAX : \ + (((p) == DNS_PROTOCOL_MDNS) ? \ + MDNS_TRANSACTION_ATTEMPTS_MAX : \ + DNS_TRANSACTION_ATTEMPTS_MAX)) diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 746a979f47..ad024b54f5 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -196,6 +196,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { goto gc; i->probe_transaction = t; + t->probing = true; if (t->state == DNS_TRANSACTION_NULL) { diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h index a41df37e6b..545ec958fb 100644 --- a/src/resolve/resolved-dns-zone.h +++ b/src/resolve/resolved-dns-zone.h @@ -37,6 +37,9 @@ typedef enum DnsZoneItemState DnsZoneItemState; /* RFC 4795 Section 2.8. suggests a TTL of 30s by default */ #define LLMNR_DEFAULT_TTL (30) +/* RFC 6762 Section 10. suggests a TTL of 120s by default */ +#define MDNS_DEFAULT_TTL (120) + enum DnsZoneItemState { DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index e7e5c5f5a7..7b6e4f8398 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -85,6 +85,10 @@ Link *link_free(Link *l) { if (!l) return NULL; + /* Send goodbye messages. */ + dns_scope_announce(l->mdns_ipv4_scope, true); + dns_scope_announce(l->mdns_ipv6_scope, true); + link_flush_settings(l); while (l->addresses) @@ -692,10 +696,26 @@ LinkAddress *link_address_free(LinkAddress *a) { else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope) dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr); } + + if (a->mdns_address_rr) { + if (a->family == AF_INET && a->link->mdns_ipv4_scope) + dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_address_rr); + else if (a->family == AF_INET6 && a->link->mdns_ipv6_scope) + dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_address_rr); + } + + if (a->mdns_ptr_rr) { + if (a->family == AF_INET && a->link->mdns_ipv4_scope) + dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_ptr_rr); + else if (a->family == AF_INET6 && a->link->mdns_ipv6_scope) + dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_ptr_rr); + } } dns_resource_record_unref(a->llmnr_address_rr); dns_resource_record_unref(a->llmnr_ptr_rr); + dns_resource_record_unref(a->mdns_address_rr); + dns_resource_record_unref(a->mdns_ptr_rr); return mfree(a); } @@ -746,7 +766,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false); if (r < 0) - log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m"); + log_warning_errno(r, "Failed to add IPv4 PTR record to LLMNR zone: %m"); } else { if (a->llmnr_address_rr) { if (a->link->llmnr_ipv4_scope) @@ -760,6 +780,59 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr); } } + + if (!force_remove && + link_address_relevant(a, true) && + a->link->mdns_ipv4_scope && + a->link->mdns_support == RESOLVE_SUPPORT_YES && + a->link->manager->mdns_support == RESOLVE_SUPPORT_YES) { + if (!a->link->manager->mdns_host_ipv4_key) { + a->link->manager->mdns_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->mdns_hostname); + if (!a->link->manager->mdns_host_ipv4_key) { + r = -ENOMEM; + goto fail; + } + } + + if (!a->mdns_address_rr) { + a->mdns_address_rr = dns_resource_record_new(a->link->manager->mdns_host_ipv4_key); + if (!a->mdns_address_rr) { + r = -ENOMEM; + goto fail; + } + + a->mdns_address_rr->a.in_addr = a->in_addr.in; + a->mdns_address_rr->ttl = MDNS_DEFAULT_TTL; + } + + if (!a->mdns_ptr_rr) { + r = dns_resource_record_new_reverse(&a->mdns_ptr_rr, a->family, &a->in_addr, a->link->manager->mdns_hostname); + if (r < 0) + goto fail; + + a->mdns_ptr_rr->ttl = MDNS_DEFAULT_TTL; + } + + r = dns_zone_put(&a->link->mdns_ipv4_scope->zone, a->link->mdns_ipv4_scope, a->mdns_address_rr, true); + if (r < 0) + log_warning_errno(r, "Failed to add A record to MDNS zone: %m"); + + r = dns_zone_put(&a->link->mdns_ipv4_scope->zone, a->link->mdns_ipv4_scope, a->mdns_ptr_rr, false); + if (r < 0) + log_warning_errno(r, "Failed to add IPv4 PTR record to MDNS zone: %m"); + } else { + if (a->mdns_address_rr) { + if (a->link->mdns_ipv4_scope) + dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_address_rr); + a->mdns_address_rr = dns_resource_record_unref(a->mdns_address_rr); + } + + if (a->mdns_ptr_rr) { + if (a->link->mdns_ipv4_scope) + dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_ptr_rr); + a->mdns_ptr_rr = dns_resource_record_unref(a->mdns_ptr_rr); + } + } } if (a->family == AF_INET6) { @@ -817,6 +890,60 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr); } } + + if (!force_remove && + link_address_relevant(a, true) && + a->link->mdns_ipv6_scope && + a->link->mdns_support == RESOLVE_SUPPORT_YES && + a->link->manager->mdns_support == RESOLVE_SUPPORT_YES) { + + if (!a->link->manager->mdns_host_ipv6_key) { + a->link->manager->mdns_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->mdns_hostname); + if (!a->link->manager->mdns_host_ipv6_key) { + r = -ENOMEM; + goto fail; + } + } + + if (!a->mdns_address_rr) { + a->mdns_address_rr = dns_resource_record_new(a->link->manager->mdns_host_ipv6_key); + if (!a->mdns_address_rr) { + r = -ENOMEM; + goto fail; + } + + a->mdns_address_rr->aaaa.in6_addr = a->in_addr.in6; + a->mdns_address_rr->ttl = MDNS_DEFAULT_TTL; + } + + if (!a->mdns_ptr_rr) { + r = dns_resource_record_new_reverse(&a->mdns_ptr_rr, a->family, &a->in_addr, a->link->manager->mdns_hostname); + if (r < 0) + goto fail; + + a->mdns_ptr_rr->ttl = MDNS_DEFAULT_TTL; + } + + r = dns_zone_put(&a->link->mdns_ipv6_scope->zone, a->link->mdns_ipv6_scope, a->mdns_address_rr, true); + if (r < 0) + log_warning_errno(r, "Failed to add AAAA record to MDNS zone: %m"); + + r = dns_zone_put(&a->link->mdns_ipv6_scope->zone, a->link->mdns_ipv6_scope, a->mdns_ptr_rr, false); + if (r < 0) + log_warning_errno(r, "Failed to add IPv6 PTR record to MDNS zone: %m"); + } else { + if (a->mdns_address_rr) { + if (a->link->mdns_ipv6_scope) + dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_address_rr); + a->mdns_address_rr = dns_resource_record_unref(a->mdns_address_rr); + } + + if (a->mdns_ptr_rr) { + if (a->link->mdns_ipv6_scope) + dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_ptr_rr); + a->mdns_ptr_rr = dns_resource_record_unref(a->mdns_ptr_rr); + } + } } return; diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index c9b2a58c34..1e9be8ae84 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -47,6 +47,8 @@ struct LinkAddress { DnsResourceRecord *llmnr_address_rr; DnsResourceRecord *llmnr_ptr_rr; + DnsResourceRecord *mdns_address_rr; + DnsResourceRecord *mdns_ptr_rr; LIST_FIELDS(LinkAddress, addresses); }; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 667774b906..791c125613 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -322,12 +322,13 @@ static int manager_network_monitor_listen(Manager *m) { return 0; } -static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) { +static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) { _cleanup_free_ char *h = NULL, *n = NULL; char label[DNS_LABEL_MAX]; const char *p; int r, k; + assert(full_hostname); assert(llmnr_hostname); assert(mdns_hostname); @@ -374,32 +375,33 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) { *llmnr_hostname = n; n = NULL; + *full_hostname = h; + h = NULL; + return 0; } static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) { - _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL; + _cleanup_free_ char *full_hostname = NULL, *llmnr_hostname = NULL, *mdns_hostname = NULL; Manager *m = userdata; int r; assert(m); - r = determine_hostname(&llmnr_hostname, &mdns_hostname); + r = determine_hostname(&full_hostname, &llmnr_hostname, &mdns_hostname); if (r < 0) return 0; /* ignore invalid hostnames */ - if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname)) + if (streq(full_hostname, m->full_hostname) && + streq(llmnr_hostname, m->llmnr_hostname) && + streq(mdns_hostname, m->mdns_hostname)) return 0; - log_info("System hostname changed to '%s'.", llmnr_hostname); - - free(m->llmnr_hostname); - free(m->mdns_hostname); + log_info("System hostname changed to '%s'.", full_hostname); - m->llmnr_hostname = llmnr_hostname; - m->mdns_hostname = mdns_hostname; - - llmnr_hostname = mdns_hostname = NULL; + free_and_replace(m->full_hostname, full_hostname); + free_and_replace(m->llmnr_hostname, llmnr_hostname); + free_and_replace(m->mdns_hostname, mdns_hostname); manager_refresh_rrs(m); @@ -428,9 +430,14 @@ static int manager_watch_hostname(Manager *m) { (void) sd_event_source_set_description(m->hostname_event_source, "hostname"); - r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname); + r = determine_hostname(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { log_info("Defaulting to hostname 'linux'."); + + m->full_hostname = strdup("linux"); + if (!m->full_hostname) + return log_oom(); + m->llmnr_hostname = strdup("linux"); if (!m->llmnr_hostname) return log_oom(); @@ -439,7 +446,7 @@ static int manager_watch_hostname(Manager *m) { if (!m->mdns_hostname) return log_oom(); } else - log_info("Using system hostname '%s'.", m->llmnr_hostname); + log_info("Using system hostname '%s'.", m->full_hostname); return 0; } @@ -498,7 +505,7 @@ int manager_new(Manager **ret) { m->hostname_fd = -1; m->llmnr_support = RESOLVE_SUPPORT_YES; - m->mdns_support = RESOLVE_SUPPORT_NO; + m->mdns_support = RESOLVE_SUPPORT_YES; m->dnssec_mode = DEFAULT_DNSSEC_MODE; m->enable_cache = true; m->dns_stub_listener_mode = DNS_STUB_LISTENER_UDP; @@ -621,9 +628,13 @@ Manager *manager_free(Manager *m) { dns_resource_key_unref(m->llmnr_host_ipv4_key); dns_resource_key_unref(m->llmnr_host_ipv6_key); + dns_resource_key_unref(m->mdns_host_ipv4_key); + dns_resource_key_unref(m->mdns_host_ipv6_key); sd_event_source_unref(m->hostname_event_source); safe_close(m->hostname_fd); + + free(m->full_hostname); free(m->llmnr_hostname); free(m->mdns_hostname); @@ -1007,6 +1018,8 @@ void manager_refresh_rrs(Manager *m) { m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key); m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key); + m->mdns_host_ipv4_key = dns_resource_key_unref(m->mdns_host_ipv4_key); + m->mdns_host_ipv6_key = dns_resource_key_unref(m->mdns_host_ipv6_key); HASHMAP_FOREACH(l, m->links, i) { link_add_rrs(l, true); @@ -1146,8 +1159,14 @@ int manager_is_own_hostname(Manager *m, const char *name) { return r; } - if (m->mdns_hostname) - return dns_name_equal(name, m->mdns_hostname); + if (m->mdns_hostname) { + r = dns_name_equal(name, m->mdns_hostname); + if (r != 0) + return r; + } + + if (m->full_hostname) + return dns_name_equal(name, m->full_hostname); return 0; } diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 6b2208ed94..97c52b7729 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -109,10 +109,13 @@ struct Manager { sd_event_source *bus_retry_event_source; /* The hostname we publish on LLMNR and mDNS */ + char *full_hostname; char *llmnr_hostname; char *mdns_hostname; DnsResourceKey *llmnr_host_ipv4_key; DnsResourceKey *llmnr_host_ipv6_key; + DnsResourceKey *mdns_host_ipv4_key; + DnsResourceKey *mdns_host_ipv6_key; /* Watch the system hostname */ int hostname_fd; diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index b13b1d0144..f5cae6f682 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -67,6 +67,52 @@ eaddrinuse: return 0; } +static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) { + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; + _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + DnsResourceKey *key = NULL; + bool tentative = false; + int r; + + assert(s); + assert(p); + + r = dns_packet_extract(p); + if (r < 0) { + log_debug_errno(r, "Failed to extract resource records from incoming packet: %m"); + return r; + } + + /* TODO: there might be more than one question in mDNS queries. */ + assert_return((dns_question_size(p->question) > 0), -EINVAL); + key = p->question->keys[0]; + + r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative); + if (r < 0) { + log_debug_errno(r, "Failed to lookup key: %m"); + return r; + } + if (r == 0) + return 0; + + r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &reply); + if (r < 0) { + log_debug_errno(r, "Failed to build reply packet: %m"); + return r; + } + + if (!ratelimit_test(&s->ratelimit)) + return 0; + + r = dns_scope_emit_udp(s, -1, reply); + if (r < 0) { + log_debug_errno(r, "Failed to send reply packet: %m"); + return r; + } + + return 0; +} + static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; Manager *m = userdata; @@ -77,6 +123,9 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us if (r <= 0) return r; + if (manager_our_packet(m, p)) + return 0; + scope = manager_find_scope(m, p); if (!scope) { log_warning("Got mDNS UDP packet on unknown scope. Ignoring."); @@ -115,6 +164,12 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us dns_name_endswith(name, "local") > 0)) return 0; + if (rr->ttl == 0) { + log_debug("Got a goodbye packet"); + /* See the section 10.1 of RFC6762 */ + rr->ttl = 1; + } + t = dns_scope_find_transaction(scope, rr->key, false); if (t) dns_transaction_process_reply(t, p); @@ -125,7 +180,11 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us } else if (dns_packet_validate_query(p) > 0) { log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p)); - dns_scope_process_query(scope, NULL, p); + r = mdns_scope_process_query(scope, p); + if (r < 0) { + log_debug("mDNS query processing failed."); + return 0; + } } else log_debug("Invalid mDNS UDP packet."); diff --git a/src/resolve/resolved-mdns.h b/src/resolve/resolved-mdns.h index 5d274648f4..06bd3296be 100644 --- a/src/resolve/resolved-mdns.h +++ b/src/resolve/resolved-mdns.h @@ -22,6 +22,7 @@ #include "resolved-manager.h" #define MDNS_PORT 5353 +#define MDNS_ANNOUNCE_DELAY (1 * USEC_PER_SEC) int manager_mdns_ipv4_fd(Manager *m); int manager_mdns_ipv6_fd(Manager *m); diff --git a/src/run/run.c b/src/run/run.c index 08f7e12336..f8257abc93 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -818,16 +818,18 @@ static int run_context_update(RunContext *c, const char *path) { {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; r = bus_map_all_properties(c->bus, "org.freedesktop.systemd1", path, map, + &error, c); if (r < 0) { sd_event_exit(c->event, EXIT_FAILURE); - return log_error_errno(r, "Failed to query unit state: %m"); + return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r)); } run_context_check_done(c); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 6aebe18fc0..8ddfb584ea 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1116,9 +1116,9 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_ int bus_message_map_all_properties( sd_bus_message *m, const struct bus_properties_map *map, + sd_bus_error *error, void *userdata) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(m); @@ -1156,9 +1156,9 @@ int bus_message_map_all_properties( v = (uint8_t *)userdata + prop->offset; if (map[i].set) - r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v); + r = prop->set(sd_bus_message_get_bus(m), member, m, error, v); else - r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v); + r = map_basic(sd_bus_message_get_bus(m), member, m, error, v); if (r < 0) return r; @@ -1184,6 +1184,7 @@ int bus_message_map_all_properties( int bus_message_map_properties_changed( sd_bus_message *m, const struct bus_properties_map *map, + sd_bus_error *error, void *userdata) { const char *member; @@ -1192,7 +1193,7 @@ int bus_message_map_properties_changed( assert(m); assert(map); - r = bus_message_map_all_properties(m, map, userdata); + r = bus_message_map_all_properties(m, map, error, userdata); if (r < 0) return r; @@ -1222,10 +1223,10 @@ int bus_map_all_properties( const char *destination, const char *path, const struct bus_properties_map *map, + sd_bus_error *error, void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1239,13 +1240,13 @@ int bus_map_all_properties( path, "org.freedesktop.DBus.Properties", "GetAll", - &error, + error, &m, "s", ""); if (r < 0) return r; - return bus_message_map_all_properties(m, map, userdata); + return bus_message_map_all_properties(m, map, error, userdata); } int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) { diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index af5f133912..d9ce4263bb 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -50,9 +50,9 @@ struct bus_properties_map { int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata); -int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map, void *userdata); -int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, void *userdata); -int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map, void *userdata); +int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map, sd_bus_error *error, void *userdata); +int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, sd_bus_error *error, void *userdata); +int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map, sd_bus_error *error, void *userdata); int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 451669d9d5..84964f750f 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -948,17 +948,42 @@ int seccomp_protect_sysctl(void) { } int seccomp_restrict_address_families(Set *address_families, bool whitelist) { - -#if !SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN uint32_t arch; int r; SECCOMP_FOREACH_LOCAL_ARCH(arch) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; + bool supported; Iterator i; log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + switch (arch) { + + case SCMP_ARCH_X86_64: + case SCMP_ARCH_X32: + case SCMP_ARCH_ARM: + case SCMP_ARCH_AARCH64: + /* These we know we support (i.e. are the ones that do not use socketcall()) */ + supported = true; + break; + + case SCMP_ARCH_X86: + case SCMP_ARCH_S390: + case SCMP_ARCH_S390X: + case SCMP_ARCH_PPC: + case SCMP_ARCH_PPC64: + case SCMP_ARCH_PPC64LE: + default: + /* These we either know we don't support (i.e. are the ones that do use socketcall()), or we + * don't know */ + supported = false; + break; + } + + if (!supported) + continue; + r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW); if (r < 0) return r; @@ -1078,7 +1103,6 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) { if (r < 0) log_debug_errno(r, "Failed to install socket family rules for architecture %s, skipping: %m", seccomp_arch_to_string(arch)); } -#endif return 0; } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 2809dece50..2336ae34f4 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1922,7 +1922,7 @@ static int get_machine_properties(sd_bus *bus, struct machine_info *mi) { bus = container; } - r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, mi); + r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, NULL, mi); if (r < 0) return r; @@ -1957,7 +1957,7 @@ static int get_machine_list( machine_infos[c].name = hn; hn = NULL; - get_machine_properties(bus, &machine_infos[c]); + (void) get_machine_properties(bus, &machine_infos[c]); c++; } @@ -1987,7 +1987,7 @@ static int get_machine_list( return log_oom(); } - get_machine_properties(NULL, &machine_infos[c]); + (void) get_machine_properties(NULL, &machine_infos[c]); c++; } @@ -4953,7 +4953,7 @@ static int show_one( return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r)); if (unit) { - r = bus_message_map_all_properties(reply, property_map, &info); + r = bus_message_map_all_properties(reply, property_map, &error, &info); if (r < 0) return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); @@ -5125,8 +5125,9 @@ static int show_all( static int show_system_status(sd_bus *bus) { char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX]; - _cleanup_free_ char *hn = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(machine_info_clear) struct machine_info mi = {}; + _cleanup_free_ char *hn = NULL; const char *on, *off; int r; @@ -5134,9 +5135,9 @@ static int show_system_status(sd_bus *bus) { if (!hn) return log_oom(); - r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi); + r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &error, &mi); if (r < 0) - return log_error_errno(r, "Failed to read server status: %m"); + return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r)); if (streq_ptr(mi.state, "degraded")) { on = ansi_highlight_red(); @@ -6028,7 +6029,7 @@ static int unit_exists(const char *unit) { if (r < 0) return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r)); - r = bus_message_map_all_properties(reply, property_map, &info); + r = bus_message_map_all_properties(reply, property_map, &error, &info); if (r < 0) return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 553ef67011..281b1534a3 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -165,6 +165,8 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { { "RTCTimeUSec", "t", NULL, offsetof(StatusInfo, rtc_time) }, {} }; + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -173,9 +175,10 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { "org.freedesktop.timedate1", "/org/freedesktop/timedate1", map, + &error, &info); if (r < 0) - return log_error_errno(r, "Failed to query server: %m"); + return log_error_errno(r, "Failed to query server: %s", bus_error_message(&error, r)); print_status_info(&info); |