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