From 8b4198373b976035e0dfc347f50b61eab40c8e00 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 13:54:02 +0200 Subject: [PATCH 01/14] resolved: install answers to mDNS transactions too Currently resolving mDNS requests doesn't work because in dns_transaction_process_reply() no answer gets installed into mDNS transactions. When receiving a mDNS reply we should not check for query section equivalence of the request and its corresponsing response. But still we need to install answers to mDNS transactions to make it possible to actually resolve mDNS requests. Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-transaction.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 2fce44ec8b..ba38e0af78 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1003,15 +1003,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 */ From e372a138b20ade9fedd845dfbfc72dfb42eaf16b Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 11:19:16 +0200 Subject: [PATCH 02/14] resolved: fix typo in warning message Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index e7e5c5f5a7..4e38e88815 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -746,7 +746,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) From cfb17f45932dc73bb08f52746ca089bb62ef6fcc Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 11:30:00 +0200 Subject: [PATCH 03/14] resolved: ignore mDNS multicast packets originated from our host By default all sent multicast packets are looped back to the sending host. And since the code that adds the mDNS socket to the mDNS multicast group is the same as for LLMNR I decided that for now it'd be safer to filter looped back packets in the application than to switch loopback off. Because I don't know what would be the implications for LLMNR with loopback switched off. I suspect that loopback can be disabled for LLMNR safely too and the function manager_our_packet() is not really needed. But I'd prefer to do it in another patchset. Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-mdns.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index b13b1d0144..2efaa55d8d 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -77,6 +77,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."); From 3755027c2cada70345c96787a9b5569994dd23ed Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 11:31:45 +0200 Subject: [PATCH 04/14] resolved: adhere to RFC when handling mDNS goodbye packets Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-mdns.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index 2efaa55d8d..48ec17f4b5 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -118,6 +118,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); From 400cb36ec67cf47c7f445c73c03a715405e8f601 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 11:58:00 +0200 Subject: [PATCH 05/14] resolved: populate mDNS scopes' zones with RRs for the host Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-zone.h | 3 + src/resolve/resolved-link.c | 123 ++++++++++++++++++++++++++++++++ src/resolve/resolved-link.h | 2 + src/resolve/resolved-manager.c | 4 ++ src/resolve/resolved-manager.h | 2 + 5 files changed, 134 insertions(+) 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 4e38e88815..4d7447b507 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -692,10 +692,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); } @@ -760,6 +776,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 +886,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 0954641c20..97c1c2389d 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -621,6 +621,8 @@ 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); @@ -1007,6 +1009,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); diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 6b2208ed94..0b52ca594a 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -113,6 +113,8 @@ struct Manager { 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; From ff537038a95f6bd1212310e890469448ff7ea54c Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 14:07:09 +0200 Subject: [PATCH 06/14] resolved: set description to correct event source Otherwise we fail an assertion down the path since t->timeout_event_source is NULL and it's the "other" transaction that's supposed to have the event source. Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index ba38e0af78..03d25dd984 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1422,7 +1422,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; From d37baf4016b92cf0aee7dcef77446f73a2ed47e9 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 14:17:15 +0200 Subject: [PATCH 07/14] resolved: set multicast membership for mDNS sockets Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-scope.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 8dbc7f623b..92171107df 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -549,7 +549,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 +572,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; From 3b991089c389d8ac969ce77f2606f996f3f411d0 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Mon, 5 Dec 2016 17:12:15 +0200 Subject: [PATCH 08/14] resolved: process mDNS queries This way other hosts can resolve our hostname to its address using mDNS. Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-scope.c | 2 +- src/resolve/resolved-dns-scope.h | 1 + src/resolve/resolved-mdns.c | 52 +++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 92171107df..2c23a0df77 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -609,7 +609,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, diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 01a83a76b2..d501835e45 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -96,6 +96,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); diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index 48ec17f4b5..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; @@ -134,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."); From 53fda2bb933694c9bdb1bbf1f5583e39673b74b2 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 15:01:56 +0200 Subject: [PATCH 09/14] resolved: implement mDNS probing and announcement Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-scope.c | 98 ++++++++++++++++++++++++-- src/resolve/resolved-dns-scope.h | 5 ++ src/resolve/resolved-dns-transaction.c | 8 ++- src/resolve/resolved-dns-transaction.h | 14 +++- src/resolve/resolved-dns-zone.c | 1 + src/resolve/resolved-mdns.h | 1 + 6 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 2c23a0df77..6616bc4e0e 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); @@ -791,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. */ @@ -936,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; @@ -1049,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); + return 0; +} + +void dns_scope_announce(DnsScope *scope) { + _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); + 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); + 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 d501835e45..65b61c56aa 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; @@ -113,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); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 03d25dd984..bd36e5e1a1 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -363,6 +363,9 @@ 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); + } SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions) dns_transaction_notify(d, t); @@ -1209,7 +1212,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; 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-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); From 58ab31d57fdc2b55ebe07be90aea492911b6bad5 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 15:28:14 +0200 Subject: [PATCH 10/14] resolved: add cache-flush bit to answers in mDNS announcements See the section 10.2 of RFC6762 for details. Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-answer.h | 1 + src/resolve/resolved-dns-cache.c | 4 ++-- src/resolve/resolved-dns-packet.c | 17 ++++++++++------- src/resolve/resolved-dns-packet.h | 4 ++-- src/resolve/resolved-dns-rr.c | 2 +- src/resolve/resolved-dns-scope.c | 8 ++++---- src/resolve/resolved-dns-stub.c | 2 +- src/resolve/resolved-dns-transaction.c | 6 +++--- 8 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 4a92bd1150..c0a819873a 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -36,6 +36,7 @@ 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_CACHE_FLUSH = 8, /* For mDNS: sets cache-flush bit in the rrclass of response records */ } 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..8231c21450 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,7 +793,7 @@ 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; int r; @@ -801,7 +803,7 @@ 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; @@ -1143,7 +1145,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 +1155,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-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 6616bc4e0e..b47cb79795 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -847,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; @@ -1086,12 +1086,12 @@ void dns_scope_announce(DnsScope *scope) { answer = dns_answer_new(4); LIST_FOREACH(addresses, a, scope->link->addresses) { - r = dns_answer_add(answer, a->mdns_address_rr, 0); + r = dns_answer_add(answer, a->mdns_address_rr, 0, 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); + r = dns_answer_add(answer, a->mdns_ptr_rr, 0, DNS_ANSWER_CACHE_FLUSH); if (r < 0) { log_debug_errno(r, "Failed to add PTR RR to answer: %m"); return; diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index e76de6c06a..932e5b58a2 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -86,7 +86,7 @@ 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; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index bd36e5e1a1..672f0e4cb2 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1369,7 +1369,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; @@ -1401,7 +1401,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. @@ -1470,7 +1470,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; From c3ae418821a26005955af8b0e7c7207283213f55 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Fri, 2 Dec 2016 15:56:27 +0200 Subject: [PATCH 11/14] resolved: implement sending goodbye mDNS packet resolved: remove unneeded braces Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-dns-answer.h | 9 +++++---- src/resolve/resolved-dns-packet.c | 4 +++- src/resolve/resolved-dns-scope.c | 8 ++++---- src/resolve/resolved-dns-scope.h | 2 +- src/resolve/resolved-dns-transaction.c | 5 ++--- src/resolve/resolved-link.c | 4 ++++ 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index c0a819873a..11d2e25eeb 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -33,10 +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_CACHE_FLUSH = 8, /* For mDNS: sets cache-flush bit in the rrclass of response records */ + 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-packet.c b/src/resolve/resolved-dns-packet.c index 8231c21450..652970284e 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -796,6 +796,7 @@ int dns_packet_truncate_opt(DnsPacket *p) { 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); @@ -807,7 +808,8 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAns 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; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index b47cb79795..750409eebf 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -1068,11 +1068,11 @@ static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userda scope->announce_event_source = sd_event_source_unref(scope->announce_event_source); - dns_scope_announce(scope); + dns_scope_announce(scope, false); return 0; } -void dns_scope_announce(DnsScope *scope) { +void dns_scope_announce(DnsScope *scope, bool goodbye) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; LinkAddress *a; @@ -1086,12 +1086,12 @@ void dns_scope_announce(DnsScope *scope) { answer = dns_answer_new(4); LIST_FOREACH(addresses, a, scope->link->addresses) { - r = dns_answer_add(answer, a->mdns_address_rr, 0, DNS_ANSWER_CACHE_FLUSH); + 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, DNS_ANSWER_CACHE_FLUSH); + 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; diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 65b61c56aa..360d86bc25 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -117,4 +117,4 @@ bool dns_scope_network_good(DnsScope *s); int dns_scope_ifindex(DnsScope *s); -void dns_scope_announce(DnsScope *scope); +void dns_scope_announce(DnsScope *scope, bool goodbye); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 672f0e4cb2..81131df91e 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -363,9 +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); - } + 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); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 4d7447b507..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) From 7bef8e8e546cbd494ea93f92394abdca0f3ed157 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Wed, 18 Jan 2017 15:35:18 +0200 Subject: [PATCH 12/14] resolved: actually enable mDNS support Signed-off-by: Dmitry Rozhkov --- src/resolve/resolved-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 97c1c2389d..f81d6f0a55 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -498,7 +498,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; From 062aabb92438cd91642ff64721ebb8a110ea5ea3 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Thu, 19 Jan 2017 11:47:51 +0200 Subject: [PATCH 13/14] resolve: Add support for mDNS to systemd-resolve utility Signed-off-by: Dmitry Rozhkov --- man/systemd-resolve.xml | 4 +++- src/resolve/resolve-tool.c | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index bfd5a68fd9..f3dbaec744 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -182,7 +182,9 @@ (i.e. classic unicast DNS), llmnr (Link-Local Multicast Name Resolution), llmnr-ipv4, llmnr-ipv6 (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), mdns (Multicast DNS), + mdns-ipv4, mdns-ipv6 (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 llmnr is identical to specifying this switch once with llmnr-ipv4 and once via llmnr-ipv6. Note that this option does not force diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 07d9582ccb..0c62e5b385 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -1524,7 +1524,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 +1722,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; From fa8b44999406ace5f44376c1be1c75edfdde5a03 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Wed, 18 Jan 2017 17:27:40 +0200 Subject: [PATCH 14/14] resolve: mention added mDNS support in NEWS Signed-off-by: Dmitry Rozhkov --- NEWS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 540f4231a1..ec50c0c403 100644 --- a/NEWS +++ b/NEWS @@ -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