]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-scope.c
treewide: auto-convert the simple cases to log_*_errno()
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
CommitLineData
74b2466e
LP
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
ad867662
LP
22#include <netinet/tcp.h>
23
623a4c97 24#include "missing.h"
74b2466e 25#include "strv.h"
ad867662 26#include "socket-util.h"
46f08bea 27#include "af-list.h"
74b2466e
LP
28#include "resolved-dns-domain.h"
29#include "resolved-dns-scope.h"
30
aea2429d
LP
31#define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
32#define MULTICAST_RATELIMIT_BURST 1000
33
0dd25fb9 34int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
74b2466e
LP
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;
1716f6dc
LP
45 s->link = l;
46 s->protocol = protocol;
47 s->family = family;
74b2466e
LP
48
49 LIST_PREPEND(scopes, m->dns_scopes, s);
50
1716f6dc
LP
51 dns_scope_llmnr_membership(s, true);
52
46f08bea 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));
1716f6dc 54
aea2429d
LP
55 /* Enforce ratelimiting for the multicast protocols */
56 RATELIMIT_INIT(s->ratelimit, MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST);
57
74b2466e
LP
58 *ret = s;
59 return 0;
60}
61
62DnsScope* dns_scope_free(DnsScope *s) {
ec2c5e43 63 DnsTransaction *t;
a4076574 64 DnsResourceRecord *rr;
faa133f3 65
74b2466e
LP
66 if (!s)
67 return NULL;
68
46f08bea 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));
1716f6dc
LP
70
71 dns_scope_llmnr_membership(s, false);
72
faa133f3
LP
73 while ((t = s->transactions)) {
74
75 /* Abort the transaction, but make sure it is not
76 * freed while we still look at it */
74b2466e 77
faa133f3 78 t->block_gc++;
ec2c5e43 79 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
faa133f3 80 t->block_gc--;
74b2466e 81
ec2c5e43 82 dns_transaction_free(t);
74b2466e
LP
83 }
84
1e43061b 85 while ((rr = ordered_hashmap_steal_first(s->conflict_queue)))
a4076574
LP
86 dns_resource_record_unref(rr);
87
1e43061b 88 ordered_hashmap_free(s->conflict_queue);
a4076574
LP
89 sd_event_source_unref(s->conflict_event_source);
90
322345fd 91 dns_cache_flush(&s->cache);
623a4c97 92 dns_zone_flush(&s->zone);
322345fd 93
74b2466e
LP
94 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
95 strv_free(s->domains);
96 free(s);
97
98 return NULL;
99}
100
2c27fbca 101DnsServer *dns_scope_get_dns_server(DnsScope *s) {
74b2466e
LP
102 assert(s);
103
1716f6dc
LP
104 if (s->protocol != DNS_PROTOCOL_DNS)
105 return NULL;
106
74b2466e
LP
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
1716f6dc
LP
116 if (s->protocol != DNS_PROTOCOL_DNS)
117 return;
118
74b2466e
LP
119 if (s->link)
120 link_next_dns_server(s->link);
121 else
122 manager_next_dns_server(s->manager);
123}
124
a4076574 125int dns_scope_emit(DnsScope *s, DnsPacket *p) {
1716f6dc
LP
126 union in_addr_union addr;
127 int ifindex = 0, r;
0dd25fb9 128 int family;
1716f6dc
LP
129 uint16_t port;
130 uint32_t mtu;
131 int fd;
74b2466e
LP
132
133 assert(s);
134 assert(p);
1716f6dc 135 assert(p->protocol == s->protocol);
ad867662
LP
136
137 if (s->link) {
1716f6dc 138 mtu = s->link->mtu;
74b2466e 139 ifindex = s->link->ifindex;
1716f6dc 140 } else
e1c95994 141 mtu = manager_find_mtu(s->manager);
74b2466e 142
1716f6dc
LP
143 if (s->protocol == DNS_PROTOCOL_DNS) {
144 DnsServer *srv;
e1c95994 145
623a4c97
LP
146 if (DNS_PACKET_QDCOUNT(p) > 1)
147 return -ENOTSUP;
148
2c27fbca 149 srv = dns_scope_get_dns_server(s);
1716f6dc
LP
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
aea2429d
LP
177 if (!ratelimit_test(&s->ratelimit))
178 return -EBUSY;
179
1716f6dc
LP
180 family = s->family;
181 port = 5355;
182
183 if (family == AF_INET) {
184 addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
1716f6dc
LP
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);
1716f6dc
LP
189 } else
190 return -EAFNOSUPPORT;
191 if (fd < 0)
192 return fd;
193 } else
74b2466e
LP
194 return -EAFNOSUPPORT;
195
1716f6dc 196 r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
74b2466e
LP
197 if (r < 0)
198 return r;
199
200 return 1;
201}
202
623a4c97 203int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
ad867662
LP
204 _cleanup_close_ int fd = -1;
205 union sockaddr_union sa = {};
206 socklen_t salen;
623a4c97
LP
207 static const int one = 1;
208 int ret, r;
ad867662
LP
209
210 assert(s);
623a4c97 211 assert((family == AF_UNSPEC) == !address);
ad867662 212
623a4c97
LP
213 if (family == AF_UNSPEC) {
214 DnsServer *srv;
215
2c27fbca 216 srv = dns_scope_get_dns_server(s);
623a4c97
LP
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 }
ad867662 247
623a4c97 248 fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
ad867662
LP
249 if (fd < 0)
250 return -errno;
251
623a4c97
LP
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) {
bf3f1271 271 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
623a4c97
LP
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 }
ad867662
LP
283
284 r = connect(fd, &sa.sa, salen);
285 if (r < 0 && errno != EINPROGRESS)
286 return -errno;
287
288 ret = fd;
289 fd = -1;
623a4c97 290
ad867662
LP
291 return ret;
292}
293
51323288 294DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
74b2466e
LP
295 char **i;
296
297 assert(s);
298 assert(domain);
299
51323288
LP
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
74b2466e 306 STRV_FOREACH(i, s->domains)
faa133f3 307 if (dns_name_endswith(domain, *i) > 0)
74b2466e
LP
308 return DNS_SCOPE_YES;
309
faa133f3 310 if (dns_name_root(domain) != 0)
74b2466e
LP
311 return DNS_SCOPE_NO;
312
faec72d5
LP
313 if (is_localhost(domain))
314 return DNS_SCOPE_NO;
315
1716f6dc 316 if (s->protocol == DNS_PROTOCOL_DNS) {
faa133f3
LP
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;
1716f6dc 321
faa133f3 322 return DNS_SCOPE_NO;
1716f6dc
LP
323 }
324
325 if (s->protocol == DNS_PROTOCOL_MDNS) {
faa133f3
LP
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))
74b2466e
LP
329 return DNS_SCOPE_MAYBE;
330
331 return DNS_SCOPE_NO;
332 }
333
1716f6dc 334 if (s->protocol == DNS_PROTOCOL_LLMNR) {
b914e211
LP
335 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
336 dns_name_endswith(domain, "ip6.arpa") > 0 ||
faa133f3 337 dns_name_single_label(domain) > 0)
1716f6dc 338 return DNS_SCOPE_MAYBE;
74b2466e 339
1716f6dc 340 return DNS_SCOPE_NO;
74b2466e
LP
341 }
342
1716f6dc
LP
343 assert_not_reached("Unknown scope protocol");
344}
345
346int 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
365int dns_scope_llmnr_membership(DnsScope *s, bool b) {
366 int fd;
367
5ba73e9b 368 assert(s);
4de120ee
LP
369
370 if (s->protocol != DNS_PROTOCOL_LLMNR)
371 return 0;
372
5ba73e9b
LP
373 assert(s->link);
374
1716f6dc
LP
375 if (s->family == AF_INET) {
376 struct ip_mreqn mreqn = {
377 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
378 .imr_ifindex = s->link->ifindex,
379 };
380
381 fd = manager_llmnr_ipv4_udp_fd(s->manager);
382 if (fd < 0)
383 return fd;
384
7b4c2ee7
LP
385 /* Always first try to drop membership before we add
386 * one. This is necessary on some devices, such as
387 * veth. */
388 if (b)
0c9eefb7 389 (void)setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
7b4c2ee7 390
1716f6dc
LP
391 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
392 return -errno;
393
394 } else if (s->family == AF_INET6) {
395 struct ipv6_mreq mreq = {
396 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
397 .ipv6mr_interface = s->link->ifindex,
398 };
399
400 fd = manager_llmnr_ipv6_udp_fd(s->manager);
401 if (fd < 0)
402 return fd;
403
7b4c2ee7 404 if (b)
0c9eefb7 405 (void)setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
7b4c2ee7 406
1716f6dc
LP
407 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
408 return -errno;
409 } else
410 return -EAFNOSUPPORT;
411
412 return 0;
74b2466e 413}
623a4c97
LP
414
415int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
416 assert(s);
417 assert(address);
418
419 if (s->protocol != DNS_PROTOCOL_DNS)
420 return 1;
421
422 if (s->link)
423 return !!link_find_dns_server(s->link, family, address);
424 else
2c27fbca 425 return !!manager_find_dns_server(s->manager, family, address);
623a4c97
LP
426}
427
ec2c5e43
LP
428static int dns_scope_make_reply_packet(
429 DnsScope *s,
430 uint16_t id,
431 int rcode,
432 DnsQuestion *q,
433 DnsAnswer *answer,
434 DnsAnswer *soa,
435 bool tentative,
436 DnsPacket **ret) {
437
623a4c97
LP
438 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
439 unsigned i;
440 int r;
441
442 assert(s);
a4076574 443 assert(ret);
623a4c97 444
75cd513e
TA
445 if ((!q || q->n_keys <= 0)
446 && (!answer || answer->n_rrs <= 0)
447 && (!soa || soa->n_rrs <= 0))
623a4c97
LP
448 return -EINVAL;
449
450 r = dns_packet_new(&p, s->protocol, 0);
451 if (r < 0)
452 return r;
453
454 DNS_PACKET_HEADER(p)->id = id;
ea917db9
LP
455 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
456 1 /* qr */,
457 0 /* opcode */,
458 0 /* c */,
459 0 /* tc */,
ec2c5e43 460 tentative,
ea917db9
LP
461 0 /* (ra) */,
462 0 /* (ad) */,
463 0 /* (cd) */,
464 rcode));
623a4c97
LP
465
466 if (q) {
467 for (i = 0; i < q->n_keys; i++) {
468 r = dns_packet_append_key(p, q->keys[i], NULL);
469 if (r < 0)
470 return r;
471 }
472
473 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
474 }
475
8bf52d3d
LP
476 if (answer) {
477 for (i = 0; i < answer->n_rrs; i++) {
478 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
623a4c97
LP
479 if (r < 0)
480 return r;
481 }
482
8bf52d3d
LP
483 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
484 }
485
486 if (soa) {
487 for (i = 0; i < soa->n_rrs; i++) {
488 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
489 if (r < 0)
490 return r;
491 }
492
493 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
623a4c97
LP
494 }
495
496 *ret = p;
497 p = NULL;
498
499 return 0;
500}
501
a4076574
LP
502static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
503 unsigned n;
504
505 assert(s);
506 assert(p);
507
508 if (p->question)
509 for (n = 0; n < p->question->n_keys; n++)
510 dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
511 if (p->answer)
512 for (n = 0; n < p->answer->n_rrs; n++)
513 dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
514}
515
623a4c97
LP
516void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
517 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
8bf52d3d 518 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
ec2c5e43 519 bool tentative = false;
623a4c97
LP
520 int r, fd;
521
522 assert(s);
523 assert(p);
524
525 if (p->protocol != DNS_PROTOCOL_LLMNR)
526 return;
527
2442b93d
LP
528 if (p->ipproto == IPPROTO_UDP) {
529 /* Don't accept UDP queries directed to anything but
530 * the LLMNR multicast addresses. See RFC 4795,
531 * section 2.5.*/
532
533 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
534 return;
535
536 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
537 return;
538 }
539
623a4c97
LP
540 r = dns_packet_extract(p);
541 if (r < 0) {
0a1beeb6 542 log_debug_errno(-r, "Failed to extract resources from incoming packet: %m");
623a4c97
LP
543 return;
544 }
545
ea917db9 546 if (DNS_PACKET_C(p)) {
a4076574
LP
547 /* Somebody notified us about a possible conflict */
548 dns_scope_verify_conflicts(s, p);
ea917db9
LP
549 return;
550 }
551
ec2c5e43 552 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
623a4c97 553 if (r < 0) {
0a1beeb6 554 log_debug_errno(-r, "Failed to lookup key: %m");
623a4c97
LP
555 return;
556 }
557 if (r == 0)
558 return;
559
fcf57f9c
LP
560 if (answer)
561 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
af93291c 562
ec2c5e43 563 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
623a4c97 564 if (r < 0) {
0a1beeb6 565 log_debug_errno(-r, "Failed to build reply packet: %m");
623a4c97
LP
566 return;
567 }
568
569 if (stream)
570 r = dns_stream_write_packet(stream, reply);
571 else {
aea2429d
LP
572 if (!ratelimit_test(&s->ratelimit))
573 return;
574
623a4c97
LP
575 if (p->family == AF_INET)
576 fd = manager_llmnr_ipv4_udp_fd(s->manager);
577 else if (p->family == AF_INET6)
578 fd = manager_llmnr_ipv6_udp_fd(s->manager);
579 else {
580 log_debug("Unknown protocol");
581 return;
582 }
583 if (fd < 0) {
0a1beeb6 584 log_debug_errno(-fd, "Failed to get reply socket: %m");
623a4c97
LP
585 return;
586 }
587
6e068472
LP
588 /* Note that we always immediately reply to all LLMNR
589 * requests, and do not wait any time, since we
590 * verified uniqueness for all records. Also see RFC
591 * 4795, Section 2.7 */
592
623a4c97
LP
593 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
594 }
595
596 if (r < 0) {
0a1beeb6 597 log_debug_errno(-r, "Failed to send reply packet: %m");
623a4c97
LP
598 return;
599 }
600}
ec2c5e43 601
dc4d47e2 602DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
ec2c5e43
LP
603 DnsTransaction *t;
604
605 assert(scope);
606 assert(question);
607
608 /* Try to find an ongoing transaction that is a equal or a
609 * superset of the specified question */
610
dc4d47e2
LP
611 LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
612
613 /* Refuse reusing transactions that completed based on
614 * cached data instead of a real packet, if that's
615 * requested. */
616 if (!cache_ok &&
617 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
618 !t->received)
619 continue;
620
ec2c5e43
LP
621 if (dns_question_is_superset(t->question, question) > 0)
622 return t;
dc4d47e2 623 }
ec2c5e43
LP
624
625 return NULL;
626}
a4076574
LP
627
628static int dns_scope_make_conflict_packet(
629 DnsScope *s,
630 DnsResourceRecord *rr,
631 DnsPacket **ret) {
632
633 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
634 int r;
635
636 assert(s);
637 assert(rr);
638 assert(ret);
639
640 r = dns_packet_new(&p, s->protocol, 0);
641 if (r < 0)
642 return r;
643
644 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
645 0 /* qr */,
646 0 /* opcode */,
647 1 /* conflict */,
648 0 /* tc */,
649 0 /* t */,
650 0 /* (ra) */,
651 0 /* (ad) */,
652 0 /* (cd) */,
653 0));
654 random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
655 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
656 DNS_PACKET_HEADER(p)->arcount = htobe16(1);
657
658 r = dns_packet_append_key(p, rr->key, NULL);
659 if (r < 0)
660 return r;
661
662 r = dns_packet_append_rr(p, rr, NULL);
663 if (r < 0)
664 return r;
665
666 *ret = p;
667 p = NULL;
668
669 return 0;
670}
671
672static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
673 DnsScope *scope = userdata;
674 int r;
675
676 assert(es);
677 assert(scope);
678
679 scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
680
681 for (;;) {
682 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
683 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
684
1e43061b 685 rr = ordered_hashmap_steal_first(scope->conflict_queue);
a4076574
LP
686 if (!rr)
687 break;
688
689 r = dns_scope_make_conflict_packet(scope, rr, &p);
690 if (r < 0) {
0a1beeb6 691 log_error_errno(-r, "Failed to make conflict packet: %m");
a4076574
LP
692 return 0;
693 }
694
695 r = dns_scope_emit(scope, p);
696 if (r < 0)
0a1beeb6 697 log_debug_errno(-r, "Failed to send conflict packet: %m");
a4076574
LP
698 }
699
700 return 0;
701}
702
703int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
704 usec_t jitter;
705 int r;
706
707 assert(scope);
708 assert(rr);
709
710 /* We don't send these queries immediately. Instead, we queue
711 * them, and send them after some jitter delay. */
1e43061b 712 r = ordered_hashmap_ensure_allocated(&scope->conflict_queue, &dns_resource_key_hash_ops);
a4076574
LP
713 if (r < 0) {
714 log_oom();
715 return r;
716 }
717
718 /* We only place one RR per key in the conflict
719 * messages, not all of them. That should be enough to
720 * indicate where there might be a conflict */
1e43061b 721 r = ordered_hashmap_put(scope->conflict_queue, rr->key, rr);
a4076574
LP
722 if (r == -EEXIST || r == 0)
723 return 0;
724 if (r < 0) {
0a1beeb6 725 log_debug_errno(-r, "Failed to queue conflicting RR: %m");
a4076574
LP
726 return r;
727 }
728
729 dns_resource_record_ref(rr);
730
731 if (scope->conflict_event_source)
732 return 0;
733
734 random_bytes(&jitter, sizeof(jitter));
735 jitter %= LLMNR_JITTER_INTERVAL_USEC;
736
737 r = sd_event_add_time(scope->manager->event,
738 &scope->conflict_event_source,
739 clock_boottime_or_monotonic(),
740 now(clock_boottime_or_monotonic()) + jitter,
741 LLMNR_JITTER_INTERVAL_USEC,
742 on_conflict_dispatch, scope);
743 if (r < 0) {
0a1beeb6 744 log_debug_errno(-r, "Failed to add conflict dispatch event: %m");
a4076574
LP
745 return r;
746 }
747
748 return 0;
749}
750
751void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
752 unsigned i;
753 int r;
754
755 assert(scope);
756 assert(p);
757
758 if (p->protocol != DNS_PROTOCOL_LLMNR)
759 return;
760
761 if (DNS_PACKET_RRCOUNT(p) <= 0)
762 return;
763
764 if (DNS_PACKET_C(p) != 0)
765 return;
766
767 if (DNS_PACKET_T(p) != 0)
768 return;
769
770 if (manager_our_packet(scope->manager, p))
771 return;
772
773 r = dns_packet_extract(p);
774 if (r < 0) {
0a1beeb6 775 log_debug_errno(-r, "Failed to extract packet: %m");
a4076574
LP
776 return;
777 }
778
779 log_debug("Checking for conflicts...");
780
781 for (i = 0; i < p->answer->n_rrs; i++) {
782
783 /* Check for conflicts against the local zone. If we
784 * found one, we won't check any further */
785 r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
786 if (r != 0)
787 continue;
788
789 /* Check for conflicts against the local cache. If so,
790 * send out an advisory query, to inform everybody */
791 r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
792 if (r <= 0)
793 continue;
794
795 dns_scope_notify_conflict(scope, p->answer->rrs[i]);
796 }
797}