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