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