summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-scope.c
diff options
context:
space:
mode:
authorDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>2016-12-02 15:01:56 +0200
committerDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>2017-01-19 11:51:21 +0200
commit53fda2bb933694c9bdb1bbf1f5583e39673b74b2 (patch)
tree46b3802c23d3e88b557449476e3aa53d3474f209 /src/resolve/resolved-dns-scope.c
parent3b991089c389d8ac969ce77f2606f996f3f411d0 (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.c98
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");
+ }
+}