]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-scope.c
resolved: allow passing on which protocol, family and interface to look something up
[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, int ifindex, uint64_t flags, const char *domain) {
295 char **i;
296
297 assert(s);
298 assert(domain);
299
300 if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex))
301 return DNS_SCOPE_NO;
302
303 if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0)
304 return DNS_SCOPE_NO;
305
306 STRV_FOREACH(i, s->domains)
307 if (dns_name_endswith(domain, *i) > 0)
308 return DNS_SCOPE_YES;
309
310 if (dns_name_root(domain) != 0)
311 return DNS_SCOPE_NO;
312
313 if (is_localhost(domain))
314 return DNS_SCOPE_NO;
315
316 if (s->protocol == DNS_PROTOCOL_DNS) {
317 if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
318 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
319 dns_name_single_label(domain) == 0)
320 return DNS_SCOPE_MAYBE;
321
322 return DNS_SCOPE_NO;
323 }
324
325 if (s->protocol == DNS_PROTOCOL_MDNS) {
326 if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
327 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
328 (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
329 return DNS_SCOPE_MAYBE;
330
331 return DNS_SCOPE_NO;
332 }
333
334 if (s->protocol == DNS_PROTOCOL_LLMNR) {
335 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
336 dns_name_endswith(domain, "ip6.arpa") > 0 ||
337 dns_name_single_label(domain) > 0)
338 return DNS_SCOPE_MAYBE;
339
340 return DNS_SCOPE_NO;
341 }
342
343 assert_not_reached("Unknown scope protocol");
344 }
345
346 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
347 assert(s);
348 assert(key);
349
350 if (s->protocol == DNS_PROTOCOL_DNS)
351 return true;
352
353 /* On mDNS and LLMNR, send A and AAAA queries only on the
354 * respective scopes */
355
356 if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
357 return false;
358
359 if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
360 return false;
361
362 return true;
363 }
364
365 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
366 int fd;
367
368 if (s->family == AF_INET) {
369 struct ip_mreqn mreqn = {
370 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
371 .imr_ifindex = s->link->ifindex,
372 };
373
374 fd = manager_llmnr_ipv4_udp_fd(s->manager);
375 if (fd < 0)
376 return fd;
377
378 /* Always first try to drop membership before we add
379 * one. This is necessary on some devices, such as
380 * veth. */
381 if (b)
382 setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
383
384 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
385 return -errno;
386
387 } else if (s->family == AF_INET6) {
388 struct ipv6_mreq mreq = {
389 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
390 .ipv6mr_interface = s->link->ifindex,
391 };
392
393 fd = manager_llmnr_ipv6_udp_fd(s->manager);
394 if (fd < 0)
395 return fd;
396
397 if (b)
398 setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
399
400 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
401 return -errno;
402 } else
403 return -EAFNOSUPPORT;
404
405 return 0;
406 }
407
408 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
409 assert(s);
410 assert(address);
411
412 if (s->protocol != DNS_PROTOCOL_DNS)
413 return 1;
414
415 if (s->link)
416 return !!link_find_dns_server(s->link, family, address);
417 else
418 return !!manager_find_dns_server(s->manager, family, address);
419 }
420
421 static int dns_scope_make_reply_packet(
422 DnsScope *s,
423 uint16_t id,
424 int rcode,
425 DnsQuestion *q,
426 DnsAnswer *answer,
427 DnsAnswer *soa,
428 bool tentative,
429 DnsPacket **ret) {
430
431 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
432 unsigned i;
433 int r;
434
435 assert(s);
436 assert(ret);
437
438 if ((!q || q->n_keys <= 0)
439 && (!answer || answer->n_rrs <= 0)
440 && (!soa || soa->n_rrs <= 0))
441 return -EINVAL;
442
443 r = dns_packet_new(&p, s->protocol, 0);
444 if (r < 0)
445 return r;
446
447 DNS_PACKET_HEADER(p)->id = id;
448 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
449 1 /* qr */,
450 0 /* opcode */,
451 0 /* c */,
452 0 /* tc */,
453 tentative,
454 0 /* (ra) */,
455 0 /* (ad) */,
456 0 /* (cd) */,
457 rcode));
458
459 if (q) {
460 for (i = 0; i < q->n_keys; i++) {
461 r = dns_packet_append_key(p, q->keys[i], NULL);
462 if (r < 0)
463 return r;
464 }
465
466 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
467 }
468
469 if (answer) {
470 for (i = 0; i < answer->n_rrs; i++) {
471 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
472 if (r < 0)
473 return r;
474 }
475
476 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
477 }
478
479 if (soa) {
480 for (i = 0; i < soa->n_rrs; i++) {
481 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
482 if (r < 0)
483 return r;
484 }
485
486 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
487 }
488
489 *ret = p;
490 p = NULL;
491
492 return 0;
493 }
494
495 static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
496 unsigned n;
497
498 assert(s);
499 assert(p);
500
501 if (p->question)
502 for (n = 0; n < p->question->n_keys; n++)
503 dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
504 if (p->answer)
505 for (n = 0; n < p->answer->n_rrs; n++)
506 dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
507 }
508
509 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
510 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
511 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
512 bool tentative = false;
513 int r, fd;
514
515 assert(s);
516 assert(p);
517
518 if (p->protocol != DNS_PROTOCOL_LLMNR)
519 return;
520
521 if (p->ipproto == IPPROTO_UDP) {
522 /* Don't accept UDP queries directed to anything but
523 * the LLMNR multicast addresses. See RFC 4795,
524 * section 2.5.*/
525
526 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
527 return;
528
529 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
530 return;
531 }
532
533 r = dns_packet_extract(p);
534 if (r < 0) {
535 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
536 return;
537 }
538
539 if (DNS_PACKET_C(p)) {
540 /* Somebody notified us about a possible conflict */
541 dns_scope_verify_conflicts(s, p);
542 return;
543 }
544
545 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
546 if (r < 0) {
547 log_debug("Failed to lookup key: %s", strerror(-r));
548 return;
549 }
550 if (r == 0)
551 return;
552
553 if (answer)
554 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
555
556 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
557 if (r < 0) {
558 log_debug("Failed to build reply packet: %s", strerror(-r));
559 return;
560 }
561
562 if (stream)
563 r = dns_stream_write_packet(stream, reply);
564 else {
565 if (!ratelimit_test(&s->ratelimit))
566 return;
567
568 if (p->family == AF_INET)
569 fd = manager_llmnr_ipv4_udp_fd(s->manager);
570 else if (p->family == AF_INET6)
571 fd = manager_llmnr_ipv6_udp_fd(s->manager);
572 else {
573 log_debug("Unknown protocol");
574 return;
575 }
576 if (fd < 0) {
577 log_debug("Failed to get reply socket: %s", strerror(-fd));
578 return;
579 }
580
581 /* Note that we always immediately reply to all LLMNR
582 * requests, and do not wait any time, since we
583 * verified uniqueness for all records. Also see RFC
584 * 4795, Section 2.7 */
585
586 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
587 }
588
589 if (r < 0) {
590 log_debug("Failed to send reply packet: %s", strerror(-r));
591 return;
592 }
593 }
594
595 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
596 DnsTransaction *t;
597
598 assert(scope);
599 assert(question);
600
601 /* Try to find an ongoing transaction that is a equal or a
602 * superset of the specified question */
603
604 LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
605
606 /* Refuse reusing transactions that completed based on
607 * cached data instead of a real packet, if that's
608 * requested. */
609 if (!cache_ok &&
610 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
611 !t->received)
612 continue;
613
614 if (dns_question_is_superset(t->question, question) > 0)
615 return t;
616 }
617
618 return NULL;
619 }
620
621 static int dns_scope_make_conflict_packet(
622 DnsScope *s,
623 DnsResourceRecord *rr,
624 DnsPacket **ret) {
625
626 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
627 int r;
628
629 assert(s);
630 assert(rr);
631 assert(ret);
632
633 r = dns_packet_new(&p, s->protocol, 0);
634 if (r < 0)
635 return r;
636
637 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
638 0 /* qr */,
639 0 /* opcode */,
640 1 /* conflict */,
641 0 /* tc */,
642 0 /* t */,
643 0 /* (ra) */,
644 0 /* (ad) */,
645 0 /* (cd) */,
646 0));
647 random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
648 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
649 DNS_PACKET_HEADER(p)->arcount = htobe16(1);
650
651 r = dns_packet_append_key(p, rr->key, NULL);
652 if (r < 0)
653 return r;
654
655 r = dns_packet_append_rr(p, rr, NULL);
656 if (r < 0)
657 return r;
658
659 *ret = p;
660 p = NULL;
661
662 return 0;
663 }
664
665 static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
666 DnsScope *scope = userdata;
667 int r;
668
669 assert(es);
670 assert(scope);
671
672 scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
673
674 for (;;) {
675 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
676 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
677
678 rr = hashmap_steal_first(scope->conflict_queue);
679 if (!rr)
680 break;
681
682 r = dns_scope_make_conflict_packet(scope, rr, &p);
683 if (r < 0) {
684 log_error("Failed to make conflict packet: %s", strerror(-r));
685 return 0;
686 }
687
688 r = dns_scope_emit(scope, p);
689 if (r < 0)
690 log_debug("Failed to send conflict packet: %s", strerror(-r));
691 }
692
693 return 0;
694 }
695
696 int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
697 usec_t jitter;
698 int r;
699
700 assert(scope);
701 assert(rr);
702
703 /* We don't send these queries immediately. Instead, we queue
704 * them, and send them after some jitter delay. */
705 r = hashmap_ensure_allocated(&scope->conflict_queue, dns_resource_key_hash_func, dns_resource_key_compare_func);
706 if (r < 0) {
707 log_oom();
708 return r;
709 }
710
711 /* We only place one RR per key in the conflict
712 * messages, not all of them. That should be enough to
713 * indicate where there might be a conflict */
714 r = hashmap_put(scope->conflict_queue, rr->key, rr);
715 if (r == -EEXIST || r == 0)
716 return 0;
717 if (r < 0) {
718 log_debug("Failed to queue conflicting RR: %s", strerror(-r));
719 return r;
720 }
721
722 dns_resource_record_ref(rr);
723
724 if (scope->conflict_event_source)
725 return 0;
726
727 random_bytes(&jitter, sizeof(jitter));
728 jitter %= LLMNR_JITTER_INTERVAL_USEC;
729
730 r = sd_event_add_time(scope->manager->event,
731 &scope->conflict_event_source,
732 clock_boottime_or_monotonic(),
733 now(clock_boottime_or_monotonic()) + jitter,
734 LLMNR_JITTER_INTERVAL_USEC,
735 on_conflict_dispatch, scope);
736 if (r < 0) {
737 log_debug("Failed to add conflict dispatch event: %s", strerror(-r));
738 return r;
739 }
740
741 return 0;
742 }
743
744 void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
745 unsigned i;
746 int r;
747
748 assert(scope);
749 assert(p);
750
751 if (p->protocol != DNS_PROTOCOL_LLMNR)
752 return;
753
754 if (DNS_PACKET_RRCOUNT(p) <= 0)
755 return;
756
757 if (DNS_PACKET_C(p) != 0)
758 return;
759
760 if (DNS_PACKET_T(p) != 0)
761 return;
762
763 if (manager_our_packet(scope->manager, p))
764 return;
765
766 r = dns_packet_extract(p);
767 if (r < 0) {
768 log_debug("Failed to extract packet: %s", strerror(-r));
769 return;
770 }
771
772 log_debug("Checking for conflicts...");
773
774 for (i = 0; i < p->answer->n_rrs; i++) {
775
776 /* Check for conflicts against the local zone. If we
777 * found one, we won't check any further */
778 r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
779 if (r != 0)
780 continue;
781
782 /* Check for conflicts against the local cache. If so,
783 * send out an advisory query, to inform everybody */
784 r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
785 if (r <= 0)
786 continue;
787
788 dns_scope_notify_conflict(scope, p->answer->rrs[i]);
789 }
790 }