]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-scope.c
resolved: implement full LLMNR conflict detection logic
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/tcp.h>
23
24 #include "missing.h"
25 #include "strv.h"
26 #include "socket-util.h"
27 #include "af-list.h"
28 #include "resolved-dns-domain.h"
29 #include "resolved-dns-scope.h"
30
31 #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
32 #define MULTICAST_RATELIMIT_BURST 1000
33
34 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
35 DnsScope *s;
36
37 assert(m);
38 assert(ret);
39
40 s = new0(DnsScope, 1);
41 if (!s)
42 return -ENOMEM;
43
44 s->manager = m;
45 s->link = l;
46 s->protocol = protocol;
47 s->family = family;
48
49 LIST_PREPEND(scopes, m->dns_scopes, s);
50
51 dns_scope_llmnr_membership(s, true);
52
53 log_debug("New scope on link %s, protocol %s, family %s", l ? l->name : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
54
55 /* Enforce ratelimiting for the multicast protocols */
56 RATELIMIT_INIT(s->ratelimit, MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST);
57
58 *ret = s;
59 return 0;
60 }
61
62 DnsScope* dns_scope_free(DnsScope *s) {
63 DnsTransaction *t;
64 DnsResourceRecord *rr;
65
66 if (!s)
67 return NULL;
68
69 log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
70
71 dns_scope_llmnr_membership(s, false);
72
73 while ((t = s->transactions)) {
74
75 /* Abort the transaction, but make sure it is not
76 * freed while we still look at it */
77
78 t->block_gc++;
79 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
80 t->block_gc--;
81
82 dns_transaction_free(t);
83 }
84
85 while ((rr = hashmap_steal_first(s->conflict_queue)))
86 dns_resource_record_unref(rr);
87
88 hashmap_free(s->conflict_queue);
89 sd_event_source_unref(s->conflict_event_source);
90
91 dns_cache_flush(&s->cache);
92 dns_zone_flush(&s->zone);
93
94 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
95 strv_free(s->domains);
96 free(s);
97
98 return NULL;
99 }
100
101 DnsServer *dns_scope_get_dns_server(DnsScope *s) {
102 assert(s);
103
104 if (s->protocol != DNS_PROTOCOL_DNS)
105 return NULL;
106
107 if (s->link)
108 return link_get_dns_server(s->link);
109 else
110 return manager_get_dns_server(s->manager);
111 }
112
113 void dns_scope_next_dns_server(DnsScope *s) {
114 assert(s);
115
116 if (s->protocol != DNS_PROTOCOL_DNS)
117 return;
118
119 if (s->link)
120 link_next_dns_server(s->link);
121 else
122 manager_next_dns_server(s->manager);
123 }
124
125 int dns_scope_emit(DnsScope *s, DnsPacket *p) {
126 union in_addr_union addr;
127 int ifindex = 0, r;
128 int family;
129 uint16_t port;
130 uint32_t mtu;
131 int fd;
132
133 assert(s);
134 assert(p);
135 assert(p->protocol == s->protocol);
136
137 if (s->link) {
138 mtu = s->link->mtu;
139 ifindex = s->link->ifindex;
140 } else
141 mtu = manager_find_mtu(s->manager);
142
143 if (s->protocol == DNS_PROTOCOL_DNS) {
144 DnsServer *srv;
145
146 if (DNS_PACKET_QDCOUNT(p) > 1)
147 return -ENOTSUP;
148
149 srv = dns_scope_get_dns_server(s);
150 if (!srv)
151 return -ESRCH;
152
153 family = srv->family;
154 addr = srv->address;
155 port = 53;
156
157 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
158 return -EMSGSIZE;
159
160 if (p->size > mtu)
161 return -EMSGSIZE;
162
163 if (family == AF_INET)
164 fd = manager_dns_ipv4_fd(s->manager);
165 else if (family == AF_INET6)
166 fd = manager_dns_ipv6_fd(s->manager);
167 else
168 return -EAFNOSUPPORT;
169 if (fd < 0)
170 return fd;
171
172 } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
173
174 if (DNS_PACKET_QDCOUNT(p) > 1)
175 return -ENOTSUP;
176
177 if (!ratelimit_test(&s->ratelimit))
178 return -EBUSY;
179
180 family = s->family;
181 port = 5355;
182
183 if (family == AF_INET) {
184 addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
185 fd = manager_llmnr_ipv4_udp_fd(s->manager);
186 } else if (family == AF_INET6) {
187 addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
188 fd = manager_llmnr_ipv6_udp_fd(s->manager);
189 } else
190 return -EAFNOSUPPORT;
191 if (fd < 0)
192 return fd;
193 } else
194 return -EAFNOSUPPORT;
195
196 r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
197 if (r < 0)
198 return r;
199
200 return 1;
201 }
202
203 int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
204 _cleanup_close_ int fd = -1;
205 union sockaddr_union sa = {};
206 socklen_t salen;
207 static const int one = 1;
208 int ret, r;
209
210 assert(s);
211 assert((family == AF_UNSPEC) == !address);
212
213 if (family == AF_UNSPEC) {
214 DnsServer *srv;
215
216 srv = dns_scope_get_dns_server(s);
217 if (!srv)
218 return -ESRCH;
219
220 sa.sa.sa_family = srv->family;
221 if (srv->family == AF_INET) {
222 sa.in.sin_port = htobe16(port);
223 sa.in.sin_addr = srv->address.in;
224 salen = sizeof(sa.in);
225 } else if (srv->family == AF_INET6) {
226 sa.in6.sin6_port = htobe16(port);
227 sa.in6.sin6_addr = srv->address.in6;
228 sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
229 salen = sizeof(sa.in6);
230 } else
231 return -EAFNOSUPPORT;
232 } else {
233 sa.sa.sa_family = family;
234
235 if (family == AF_INET) {
236 sa.in.sin_port = htobe16(port);
237 sa.in.sin_addr = address->in;
238 salen = sizeof(sa.in);
239 } else if (family == AF_INET6) {
240 sa.in6.sin6_port = htobe16(port);
241 sa.in6.sin6_addr = address->in6;
242 sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
243 salen = sizeof(sa.in6);
244 } else
245 return -EAFNOSUPPORT;
246 }
247
248 fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
249 if (fd < 0)
250 return -errno;
251
252 r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
253 if (r < 0)
254 return -errno;
255
256 if (s->link) {
257 uint32_t ifindex = htobe32(s->link->ifindex);
258
259 if (sa.sa.sa_family == AF_INET) {
260 r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
261 if (r < 0)
262 return -errno;
263 } else if (sa.sa.sa_family == AF_INET6) {
264 r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
265 if (r < 0)
266 return -errno;
267 }
268 }
269
270 if (s->protocol == DNS_PROTOCOL_LLMNR) {
271 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
272
273 if (sa.sa.sa_family == AF_INET) {
274 r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
275 if (r < 0)
276 return -errno;
277 } else if (sa.sa.sa_family == AF_INET6) {
278 r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
279 if (r < 0)
280 return -errno;
281 }
282 }
283
284 r = connect(fd, &sa.sa, salen);
285 if (r < 0 && errno != EINPROGRESS)
286 return -errno;
287
288 ret = fd;
289 fd = -1;
290
291 return ret;
292 }
293
294 DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
295 char **i;
296
297 assert(s);
298 assert(domain);
299
300 STRV_FOREACH(i, s->domains)
301 if (dns_name_endswith(domain, *i) > 0)
302 return DNS_SCOPE_YES;
303
304 if (dns_name_root(domain) != 0)
305 return DNS_SCOPE_NO;
306
307 if (is_localhost(domain))
308 return DNS_SCOPE_NO;
309
310 if (s->protocol == DNS_PROTOCOL_DNS) {
311 if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
312 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
313 dns_name_single_label(domain) == 0)
314 return DNS_SCOPE_MAYBE;
315
316 return DNS_SCOPE_NO;
317 }
318
319 if (s->protocol == DNS_PROTOCOL_MDNS) {
320 if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
321 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
322 (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
323 return DNS_SCOPE_MAYBE;
324
325 return DNS_SCOPE_NO;
326 }
327
328 if (s->protocol == DNS_PROTOCOL_LLMNR) {
329 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
330 dns_name_endswith(domain, "ip6.arpa") > 0 ||
331 dns_name_single_label(domain) > 0)
332 return DNS_SCOPE_MAYBE;
333
334 return DNS_SCOPE_NO;
335 }
336
337 assert_not_reached("Unknown scope protocol");
338 }
339
340 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
341 assert(s);
342 assert(key);
343
344 if (s->protocol == DNS_PROTOCOL_DNS)
345 return true;
346
347 /* On mDNS and LLMNR, send A and AAAA queries only on the
348 * respective scopes */
349
350 if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
351 return false;
352
353 if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
354 return false;
355
356 return true;
357 }
358
359 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
360 int fd;
361
362 if (s->family == AF_INET) {
363 struct ip_mreqn mreqn = {
364 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
365 .imr_ifindex = s->link->ifindex,
366 };
367
368 fd = manager_llmnr_ipv4_udp_fd(s->manager);
369 if (fd < 0)
370 return fd;
371
372 /* Always first try to drop membership before we add
373 * one. This is necessary on some devices, such as
374 * veth. */
375 if (b)
376 setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
377
378 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
379 return -errno;
380
381 } else if (s->family == AF_INET6) {
382 struct ipv6_mreq mreq = {
383 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
384 .ipv6mr_interface = s->link->ifindex,
385 };
386
387 fd = manager_llmnr_ipv6_udp_fd(s->manager);
388 if (fd < 0)
389 return fd;
390
391 if (b)
392 setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
393
394 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
395 return -errno;
396 } else
397 return -EAFNOSUPPORT;
398
399 return 0;
400 }
401
402 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
403 assert(s);
404 assert(address);
405
406 if (s->protocol != DNS_PROTOCOL_DNS)
407 return 1;
408
409 if (s->link)
410 return !!link_find_dns_server(s->link, family, address);
411 else
412 return !!manager_find_dns_server(s->manager, family, address);
413 }
414
415 static int dns_scope_make_reply_packet(
416 DnsScope *s,
417 uint16_t id,
418 int rcode,
419 DnsQuestion *q,
420 DnsAnswer *answer,
421 DnsAnswer *soa,
422 bool tentative,
423 DnsPacket **ret) {
424
425 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
426 unsigned i;
427 int r;
428
429 assert(s);
430 assert(ret);
431
432 if ((!q || q->n_keys <= 0)
433 && (!answer || answer->n_rrs <= 0)
434 && (!soa || soa->n_rrs <= 0))
435 return -EINVAL;
436
437 r = dns_packet_new(&p, s->protocol, 0);
438 if (r < 0)
439 return r;
440
441 DNS_PACKET_HEADER(p)->id = id;
442 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
443 1 /* qr */,
444 0 /* opcode */,
445 0 /* c */,
446 0 /* tc */,
447 tentative,
448 0 /* (ra) */,
449 0 /* (ad) */,
450 0 /* (cd) */,
451 rcode));
452
453 if (q) {
454 for (i = 0; i < q->n_keys; i++) {
455 r = dns_packet_append_key(p, q->keys[i], NULL);
456 if (r < 0)
457 return r;
458 }
459
460 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
461 }
462
463 if (answer) {
464 for (i = 0; i < answer->n_rrs; i++) {
465 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
466 if (r < 0)
467 return r;
468 }
469
470 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
471 }
472
473 if (soa) {
474 for (i = 0; i < soa->n_rrs; i++) {
475 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
476 if (r < 0)
477 return r;
478 }
479
480 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
481 }
482
483 *ret = p;
484 p = NULL;
485
486 return 0;
487 }
488
489 static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
490 unsigned n;
491
492 assert(s);
493 assert(p);
494
495 if (p->question)
496 for (n = 0; n < p->question->n_keys; n++)
497 dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
498 if (p->answer)
499 for (n = 0; n < p->answer->n_rrs; n++)
500 dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
501 }
502
503 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
504 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
505 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
506 bool tentative = false;
507 int r, fd;
508
509 assert(s);
510 assert(p);
511
512 if (p->protocol != DNS_PROTOCOL_LLMNR)
513 return;
514
515 if (p->ipproto == IPPROTO_UDP) {
516 /* Don't accept UDP queries directed to anything but
517 * the LLMNR multicast addresses. See RFC 4795,
518 * section 2.5.*/
519
520 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
521 return;
522
523 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
524 return;
525 }
526
527 r = dns_packet_extract(p);
528 if (r < 0) {
529 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
530 return;
531 }
532
533 if (DNS_PACKET_C(p)) {
534 /* Somebody notified us about a possible conflict */
535 dns_scope_verify_conflicts(s, p);
536 return;
537 }
538
539 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
540 if (r < 0) {
541 log_debug("Failed to lookup key: %s", strerror(-r));
542 return;
543 }
544 if (r == 0)
545 return;
546
547 if (answer)
548 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
549
550 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
551 if (r < 0) {
552 log_debug("Failed to build reply packet: %s", strerror(-r));
553 return;
554 }
555
556 if (stream)
557 r = dns_stream_write_packet(stream, reply);
558 else {
559 if (!ratelimit_test(&s->ratelimit))
560 return;
561
562 if (p->family == AF_INET)
563 fd = manager_llmnr_ipv4_udp_fd(s->manager);
564 else if (p->family == AF_INET6)
565 fd = manager_llmnr_ipv6_udp_fd(s->manager);
566 else {
567 log_debug("Unknown protocol");
568 return;
569 }
570 if (fd < 0) {
571 log_debug("Failed to get reply socket: %s", strerror(-fd));
572 return;
573 }
574
575 /* Note that we always immediately reply to all LLMNR
576 * requests, and do not wait any time, since we
577 * verified uniqueness for all records. Also see RFC
578 * 4795, Section 2.7 */
579
580 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
581 }
582
583 if (r < 0) {
584 log_debug("Failed to send reply packet: %s", strerror(-r));
585 return;
586 }
587 }
588
589 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
590 DnsTransaction *t;
591
592 assert(scope);
593 assert(question);
594
595 /* Try to find an ongoing transaction that is a equal or a
596 * superset of the specified question */
597
598 LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
599
600 /* Refuse reusing transactions that completed based on
601 * cached data instead of a real packet, if that's
602 * requested. */
603 if (!cache_ok &&
604 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
605 !t->received)
606 continue;
607
608 if (dns_question_is_superset(t->question, question) > 0)
609 return t;
610 }
611
612 return NULL;
613 }
614
615 static int dns_scope_make_conflict_packet(
616 DnsScope *s,
617 DnsResourceRecord *rr,
618 DnsPacket **ret) {
619
620 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
621 int r;
622
623 assert(s);
624 assert(rr);
625 assert(ret);
626
627 r = dns_packet_new(&p, s->protocol, 0);
628 if (r < 0)
629 return r;
630
631 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
632 0 /* qr */,
633 0 /* opcode */,
634 1 /* conflict */,
635 0 /* tc */,
636 0 /* t */,
637 0 /* (ra) */,
638 0 /* (ad) */,
639 0 /* (cd) */,
640 0));
641 random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
642 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
643 DNS_PACKET_HEADER(p)->arcount = htobe16(1);
644
645 r = dns_packet_append_key(p, rr->key, NULL);
646 if (r < 0)
647 return r;
648
649 r = dns_packet_append_rr(p, rr, NULL);
650 if (r < 0)
651 return r;
652
653 *ret = p;
654 p = NULL;
655
656 return 0;
657 }
658
659 static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
660 DnsScope *scope = userdata;
661 int r;
662
663 assert(es);
664 assert(scope);
665
666 scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
667
668 for (;;) {
669 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
670 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
671
672 rr = hashmap_steal_first(scope->conflict_queue);
673 if (!rr)
674 break;
675
676 r = dns_scope_make_conflict_packet(scope, rr, &p);
677 if (r < 0) {
678 log_error("Failed to make conflict packet: %s", strerror(-r));
679 return 0;
680 }
681
682 r = dns_scope_emit(scope, p);
683 if (r < 0)
684 log_debug("Failed to send conflict packet: %s", strerror(-r));
685 }
686
687 return 0;
688 }
689
690 int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
691 usec_t jitter;
692 int r;
693
694 assert(scope);
695 assert(rr);
696
697 /* We don't send these queries immediately. Instead, we queue
698 * them, and send them after some jitter delay. */
699 r = hashmap_ensure_allocated(&scope->conflict_queue, dns_resource_key_hash_func, dns_resource_key_compare_func);
700 if (r < 0) {
701 log_oom();
702 return r;
703 }
704
705 /* We only place one RR per key in the conflict
706 * messages, not all of them. That should be enough to
707 * indicate where there might be a conflict */
708 r = hashmap_put(scope->conflict_queue, rr->key, rr);
709 if (r == -EEXIST || r == 0)
710 return 0;
711 if (r < 0) {
712 log_debug("Failed to queue conflicting RR: %s", strerror(-r));
713 return r;
714 }
715
716 dns_resource_record_ref(rr);
717
718 if (scope->conflict_event_source)
719 return 0;
720
721 random_bytes(&jitter, sizeof(jitter));
722 jitter %= LLMNR_JITTER_INTERVAL_USEC;
723
724 r = sd_event_add_time(scope->manager->event,
725 &scope->conflict_event_source,
726 clock_boottime_or_monotonic(),
727 now(clock_boottime_or_monotonic()) + jitter,
728 LLMNR_JITTER_INTERVAL_USEC,
729 on_conflict_dispatch, scope);
730 if (r < 0) {
731 log_debug("Failed to add conflict dispatch event: %s", strerror(-r));
732 return r;
733 }
734
735 return 0;
736 }
737
738 void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
739 unsigned i;
740 int r;
741
742 assert(scope);
743 assert(p);
744
745 if (p->protocol != DNS_PROTOCOL_LLMNR)
746 return;
747
748 if (DNS_PACKET_RRCOUNT(p) <= 0)
749 return;
750
751 if (DNS_PACKET_C(p) != 0)
752 return;
753
754 if (DNS_PACKET_T(p) != 0)
755 return;
756
757 if (manager_our_packet(scope->manager, p))
758 return;
759
760 r = dns_packet_extract(p);
761 if (r < 0) {
762 log_debug("Failed to extract packet: %s", strerror(-r));
763 return;
764 }
765
766 log_debug("Checking for conflicts...");
767
768 for (i = 0; i < p->answer->n_rrs; i++) {
769
770 /* Check for conflicts against the local zone. If we
771 * found one, we won't check any further */
772 r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
773 if (r != 0)
774 continue;
775
776 /* Check for conflicts against the local cache. If so,
777 * send out an advisory query, to inform everybody */
778 r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
779 if (r <= 0)
780 continue;
781
782 dns_scope_notify_conflict(scope, p->answer->rrs[i]);
783 }
784 }