diff options
author | Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com> | 2016-12-02 15:01:56 +0200 |
---|---|---|
committer | Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com> | 2017-01-19 11:51:21 +0200 |
commit | 53fda2bb933694c9bdb1bbf1f5583e39673b74b2 (patch) | |
tree | 46b3802c23d3e88b557449476e3aa53d3474f209 /src/resolve/resolved-dns-scope.c | |
parent | 3b991089c389d8ac969ce77f2606f996f3f411d0 (diff) |
resolved: implement mDNS probing and announcement
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Diffstat (limited to 'src/resolve/resolved-dns-scope.c')
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 98 |
1 files changed, 91 insertions, 7 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"); + } +} |