]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-scope.c
resolved: allow passing on which protocol, family and interface to look something up
[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
a4076574
LP
85 while ((rr = hashmap_steal_first(s->conflict_queue)))
86 dns_resource_record_unref(rr);
87
88 hashmap_free(s->conflict_queue);
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
368 if (s->family == AF_INET) {
369 struct ip_mreqn mreqn = {
370 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
371 .imr_ifindex = s->link->ifindex,
372 };
373
374 fd = manager_llmnr_ipv4_udp_fd(s->manager);
375 if (fd < 0)
376 return fd;
377
7b4c2ee7
LP
378 /* Always first try to drop membership before we add
379 * one. This is necessary on some devices, such as
380 * veth. */
381 if (b)
382 setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
383
1716f6dc
LP
384 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
385 return -errno;
386
387 } else if (s->family == AF_INET6) {
388 struct ipv6_mreq mreq = {
389 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
390 .ipv6mr_interface = s->link->ifindex,
391 };
392
393 fd = manager_llmnr_ipv6_udp_fd(s->manager);
394 if (fd < 0)
395 return fd;
396
7b4c2ee7
LP
397 if (b)
398 setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
399
1716f6dc
LP
400 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
401 return -errno;
402 } else
403 return -EAFNOSUPPORT;
404
405 return 0;
74b2466e 406}
623a4c97
LP
407
408int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
409 assert(s);
410 assert(address);
411
412 if (s->protocol != DNS_PROTOCOL_DNS)
413 return 1;
414
415 if (s->link)
416 return !!link_find_dns_server(s->link, family, address);
417 else
2c27fbca 418 return !!manager_find_dns_server(s->manager, family, address);
623a4c97
LP
419}
420
ec2c5e43
LP
421static int dns_scope_make_reply_packet(
422 DnsScope *s,
423 uint16_t id,
424 int rcode,
425 DnsQuestion *q,
426 DnsAnswer *answer,
427 DnsAnswer *soa,
428 bool tentative,
429 DnsPacket **ret) {
430
623a4c97
LP
431 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
432 unsigned i;
433 int r;
434
435 assert(s);
a4076574 436 assert(ret);
623a4c97 437
75cd513e
TA
438 if ((!q || q->n_keys <= 0)
439 && (!answer || answer->n_rrs <= 0)
440 && (!soa || soa->n_rrs <= 0))
623a4c97
LP
441 return -EINVAL;
442
443 r = dns_packet_new(&p, s->protocol, 0);
444 if (r < 0)
445 return r;
446
447 DNS_PACKET_HEADER(p)->id = id;
ea917db9
LP
448 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
449 1 /* qr */,
450 0 /* opcode */,
451 0 /* c */,
452 0 /* tc */,
ec2c5e43 453 tentative,
ea917db9
LP
454 0 /* (ra) */,
455 0 /* (ad) */,
456 0 /* (cd) */,
457 rcode));
623a4c97
LP
458
459 if (q) {
460 for (i = 0; i < q->n_keys; i++) {
461 r = dns_packet_append_key(p, q->keys[i], NULL);
462 if (r < 0)
463 return r;
464 }
465
466 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
467 }
468
8bf52d3d
LP
469 if (answer) {
470 for (i = 0; i < answer->n_rrs; i++) {
471 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
623a4c97
LP
472 if (r < 0)
473 return r;
474 }
475
8bf52d3d
LP
476 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
477 }
478
479 if (soa) {
480 for (i = 0; i < soa->n_rrs; i++) {
481 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
482 if (r < 0)
483 return r;
484 }
485
486 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
623a4c97
LP
487 }
488
489 *ret = p;
490 p = NULL;
491
492 return 0;
493}
494
a4076574
LP
495static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
496 unsigned n;
497
498 assert(s);
499 assert(p);
500
501 if (p->question)
502 for (n = 0; n < p->question->n_keys; n++)
503 dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
504 if (p->answer)
505 for (n = 0; n < p->answer->n_rrs; n++)
506 dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
507}
508
623a4c97
LP
509void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
510 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
8bf52d3d 511 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
ec2c5e43 512 bool tentative = false;
623a4c97
LP
513 int r, fd;
514
515 assert(s);
516 assert(p);
517
518 if (p->protocol != DNS_PROTOCOL_LLMNR)
519 return;
520
2442b93d
LP
521 if (p->ipproto == IPPROTO_UDP) {
522 /* Don't accept UDP queries directed to anything but
523 * the LLMNR multicast addresses. See RFC 4795,
524 * section 2.5.*/
525
526 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
527 return;
528
529 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
530 return;
531 }
532
623a4c97
LP
533 r = dns_packet_extract(p);
534 if (r < 0) {
535 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
536 return;
537 }
538
ea917db9 539 if (DNS_PACKET_C(p)) {
a4076574
LP
540 /* Somebody notified us about a possible conflict */
541 dns_scope_verify_conflicts(s, p);
ea917db9
LP
542 return;
543 }
544
ec2c5e43 545 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
623a4c97
LP
546 if (r < 0) {
547 log_debug("Failed to lookup key: %s", strerror(-r));
548 return;
549 }
550 if (r == 0)
551 return;
552
fcf57f9c
LP
553 if (answer)
554 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
af93291c 555
ec2c5e43 556 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
623a4c97
LP
557 if (r < 0) {
558 log_debug("Failed to build reply packet: %s", strerror(-r));
559 return;
560 }
561
562 if (stream)
563 r = dns_stream_write_packet(stream, reply);
564 else {
aea2429d
LP
565 if (!ratelimit_test(&s->ratelimit))
566 return;
567
623a4c97
LP
568 if (p->family == AF_INET)
569 fd = manager_llmnr_ipv4_udp_fd(s->manager);
570 else if (p->family == AF_INET6)
571 fd = manager_llmnr_ipv6_udp_fd(s->manager);
572 else {
573 log_debug("Unknown protocol");
574 return;
575 }
576 if (fd < 0) {
577 log_debug("Failed to get reply socket: %s", strerror(-fd));
578 return;
579 }
580
6e068472
LP
581 /* Note that we always immediately reply to all LLMNR
582 * requests, and do not wait any time, since we
583 * verified uniqueness for all records. Also see RFC
584 * 4795, Section 2.7 */
585
623a4c97
LP
586 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
587 }
588
589 if (r < 0) {
590 log_debug("Failed to send reply packet: %s", strerror(-r));
591 return;
592 }
593}
ec2c5e43 594
dc4d47e2 595DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
ec2c5e43
LP
596 DnsTransaction *t;
597
598 assert(scope);
599 assert(question);
600
601 /* Try to find an ongoing transaction that is a equal or a
602 * superset of the specified question */
603
dc4d47e2
LP
604 LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
605
606 /* Refuse reusing transactions that completed based on
607 * cached data instead of a real packet, if that's
608 * requested. */
609 if (!cache_ok &&
610 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
611 !t->received)
612 continue;
613
ec2c5e43
LP
614 if (dns_question_is_superset(t->question, question) > 0)
615 return t;
dc4d47e2 616 }
ec2c5e43
LP
617
618 return NULL;
619}
a4076574
LP
620
621static int dns_scope_make_conflict_packet(
622 DnsScope *s,
623 DnsResourceRecord *rr,
624 DnsPacket **ret) {
625
626 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
627 int r;
628
629 assert(s);
630 assert(rr);
631 assert(ret);
632
633 r = dns_packet_new(&p, s->protocol, 0);
634 if (r < 0)
635 return r;
636
637 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
638 0 /* qr */,
639 0 /* opcode */,
640 1 /* conflict */,
641 0 /* tc */,
642 0 /* t */,
643 0 /* (ra) */,
644 0 /* (ad) */,
645 0 /* (cd) */,
646 0));
647 random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
648 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
649 DNS_PACKET_HEADER(p)->arcount = htobe16(1);
650
651 r = dns_packet_append_key(p, rr->key, NULL);
652 if (r < 0)
653 return r;
654
655 r = dns_packet_append_rr(p, rr, NULL);
656 if (r < 0)
657 return r;
658
659 *ret = p;
660 p = NULL;
661
662 return 0;
663}
664
665static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
666 DnsScope *scope = userdata;
667 int r;
668
669 assert(es);
670 assert(scope);
671
672 scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
673
674 for (;;) {
675 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
676 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
677
678 rr = hashmap_steal_first(scope->conflict_queue);
679 if (!rr)
680 break;
681
682 r = dns_scope_make_conflict_packet(scope, rr, &p);
683 if (r < 0) {
684 log_error("Failed to make conflict packet: %s", strerror(-r));
685 return 0;
686 }
687
688 r = dns_scope_emit(scope, p);
689 if (r < 0)
690 log_debug("Failed to send conflict packet: %s", strerror(-r));
691 }
692
693 return 0;
694}
695
696int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
697 usec_t jitter;
698 int r;
699
700 assert(scope);
701 assert(rr);
702
703 /* We don't send these queries immediately. Instead, we queue
704 * them, and send them after some jitter delay. */
705 r = hashmap_ensure_allocated(&scope->conflict_queue, dns_resource_key_hash_func, dns_resource_key_compare_func);
706 if (r < 0) {
707 log_oom();
708 return r;
709 }
710
711 /* We only place one RR per key in the conflict
712 * messages, not all of them. That should be enough to
713 * indicate where there might be a conflict */
714 r = hashmap_put(scope->conflict_queue, rr->key, rr);
715 if (r == -EEXIST || r == 0)
716 return 0;
717 if (r < 0) {
718 log_debug("Failed to queue conflicting RR: %s", strerror(-r));
719 return r;
720 }
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 log_debug("Failed to add conflict dispatch event: %s", strerror(-r));
738 return r;
739 }
740
741 return 0;
742}
743
744void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
745 unsigned i;
746 int r;
747
748 assert(scope);
749 assert(p);
750
751 if (p->protocol != DNS_PROTOCOL_LLMNR)
752 return;
753
754 if (DNS_PACKET_RRCOUNT(p) <= 0)
755 return;
756
757 if (DNS_PACKET_C(p) != 0)
758 return;
759
760 if (DNS_PACKET_T(p) != 0)
761 return;
762
763 if (manager_our_packet(scope->manager, p))
764 return;
765
766 r = dns_packet_extract(p);
767 if (r < 0) {
768 log_debug("Failed to extract packet: %s", strerror(-r));
769 return;
770 }
771
772 log_debug("Checking for conflicts...");
773
774 for (i = 0; i < p->answer->n_rrs; i++) {
775
776 /* Check for conflicts against the local zone. If we
777 * found one, we won't check any further */
778 r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
779 if (r != 0)
780 continue;
781
782 /* Check for conflicts against the local cache. If so,
783 * send out an advisory query, to inform everybody */
784 r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
785 if (r <= 0)
786 continue;
787
788 dns_scope_notify_conflict(scope, p->answer->rrs[i]);
789 }
790}