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