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