]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-scope.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
74b2466e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
ad867662
LP
21#include <netinet/tcp.h>
22
46f08bea 23#include "af-list.h"
b5efdb8a 24#include "alloc-util.h"
4ad7f276 25#include "dns-domain.h"
3ffd4af2
LP
26#include "fd-util.h"
27#include "hostname-util.h"
28#include "missing.h"
29#include "random-util.h"
6db6a464 30#include "resolved-dnssd.h"
74b2466e 31#include "resolved-dns-scope.h"
a2bf8a19 32#include "resolved-dns-zone.h"
3ffd4af2 33#include "resolved-llmnr.h"
b4f1862d 34#include "resolved-mdns.h"
3ffd4af2
LP
35#include "socket-util.h"
36#include "strv.h"
74b2466e 37
aea2429d
LP
38#define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
39#define MULTICAST_RATELIMIT_BURST 1000
40
9df3ba6c
TG
41/* After how much time to repeat LLMNR requests, see RFC 4795 Section 7 */
42#define MULTICAST_RESEND_TIMEOUT_MIN_USEC (100 * USEC_PER_MSEC)
43#define MULTICAST_RESEND_TIMEOUT_MAX_USEC (1 * USEC_PER_SEC)
44
0dd25fb9 45int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
74b2466e
LP
46 DnsScope *s;
47
48 assert(m);
49 assert(ret);
50
51 s = new0(DnsScope, 1);
52 if (!s)
53 return -ENOMEM;
54
55 s->manager = m;
1716f6dc
LP
56 s->link = l;
57 s->protocol = protocol;
58 s->family = family;
9df3ba6c 59 s->resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC;
74b2466e 60
ad6c0475
LP
61 if (protocol == DNS_PROTOCOL_DNS) {
62 /* Copy DNSSEC mode from the link if it is set there,
63 * otherwise take the manager's DNSSEC mode. Note that
64 * we copy this only at scope creation time, and do
65 * not update it from the on, even if the setting
66 * changes. */
67
68 if (l)
c69fa7e3
LP
69 s->dnssec_mode = link_get_dnssec_mode(l);
70 else
71 s->dnssec_mode = manager_get_dnssec_mode(m);
658f7f02
LP
72 } else
73 s->dnssec_mode = DNSSEC_NO;
ad6c0475 74
74b2466e
LP
75 LIST_PREPEND(scopes, m->dns_scopes, s);
76
1716f6dc 77 dns_scope_llmnr_membership(s, true);
0db4c90a 78 dns_scope_mdns_membership(s, true);
1716f6dc 79
46f08bea 80 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 81
aea2429d
LP
82 /* Enforce ratelimiting for the multicast protocols */
83 RATELIMIT_INIT(s->ratelimit, MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST);
84
74b2466e
LP
85 *ret = s;
86 return 0;
87}
88
801ad6a6 89static void dns_scope_abort_transactions(DnsScope *s) {
801ad6a6 90 assert(s);
1716f6dc 91
f9ebb22a
LP
92 while (s->transactions) {
93 DnsTransaction *t = s->transactions;
94
faa133f3
LP
95 /* Abort the transaction, but make sure it is not
96 * freed while we still look at it */
74b2466e 97
faa133f3 98 t->block_gc++;
f4e38037
LP
99 if (DNS_TRANSACTION_IS_LIVE(t->state))
100 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
faa133f3 101 t->block_gc--;
74b2466e 102
ec2c5e43 103 dns_transaction_free(t);
74b2466e 104 }
801ad6a6
LP
105}
106
107DnsScope* dns_scope_free(DnsScope *s) {
801ad6a6
LP
108 if (!s)
109 return NULL;
110
111 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));
112
113 dns_scope_llmnr_membership(s, false);
0db4c90a 114 dns_scope_mdns_membership(s, false);
801ad6a6
LP
115 dns_scope_abort_transactions(s);
116
117 while (s->query_candidates)
118 dns_query_candidate_free(s->query_candidates);
74b2466e 119
f9ebb22a 120 hashmap_free(s->transactions_by_key);
da0c630e 121
224b0e7a 122 ordered_hashmap_free_with_destructor(s->conflict_queue, dns_resource_record_unref);
a4076574
LP
123 sd_event_source_unref(s->conflict_event_source);
124
53fda2bb
DR
125 sd_event_source_unref(s->announce_event_source);
126
322345fd 127 dns_cache_flush(&s->cache);
623a4c97 128 dns_zone_flush(&s->zone);
322345fd 129
74b2466e 130 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
6b430fdb 131 return mfree(s);
74b2466e
LP
132}
133
2c27fbca 134DnsServer *dns_scope_get_dns_server(DnsScope *s) {
74b2466e
LP
135 assert(s);
136
1716f6dc
LP
137 if (s->protocol != DNS_PROTOCOL_DNS)
138 return NULL;
139
74b2466e
LP
140 if (s->link)
141 return link_get_dns_server(s->link);
142 else
143 return manager_get_dns_server(s->manager);
144}
145
44db02d0
LP
146unsigned dns_scope_get_n_dns_servers(DnsScope *s) {
147 unsigned n = 0;
148 DnsServer *i;
149
150 assert(s);
151
152 if (s->protocol != DNS_PROTOCOL_DNS)
153 return 0;
154
155 if (s->link)
156 i = s->link->dns_servers;
157 else
158 i = s->manager->dns_servers;
159
160 for (; i; i = i->servers_next)
161 n++;
162
163 return n;
164}
165
74b2466e
LP
166void dns_scope_next_dns_server(DnsScope *s) {
167 assert(s);
168
1716f6dc
LP
169 if (s->protocol != DNS_PROTOCOL_DNS)
170 return;
171
74b2466e
LP
172 if (s->link)
173 link_next_dns_server(s->link);
174 else
175 manager_next_dns_server(s->manager);
176}
177
9df3ba6c
TG
178void dns_scope_packet_received(DnsScope *s, usec_t rtt) {
179 assert(s);
180
84129d46
LP
181 if (rtt <= s->max_rtt)
182 return;
183
184 s->max_rtt = rtt;
185 s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2), MULTICAST_RESEND_TIMEOUT_MAX_USEC);
9df3ba6c
TG
186}
187
188void dns_scope_packet_lost(DnsScope *s, usec_t usec) {
189 assert(s);
190
191 if (s->resend_timeout <= usec)
192 s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC);
193}
194
519ef046 195static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) {
1716f6dc
LP
196 union in_addr_union addr;
197 int ifindex = 0, r;
0dd25fb9 198 int family;
1716f6dc 199 uint32_t mtu;
74b2466e
LP
200
201 assert(s);
202 assert(p);
1716f6dc 203 assert(p->protocol == s->protocol);
ad867662
LP
204
205 if (s->link) {
1716f6dc 206 mtu = s->link->mtu;
74b2466e 207 ifindex = s->link->ifindex;
1716f6dc 208 } else
e1c95994 209 mtu = manager_find_mtu(s->manager);
74b2466e 210
106784eb 211 switch (s->protocol) {
519ef046 212
106784eb 213 case DNS_PROTOCOL_DNS:
519ef046 214 assert(fd >= 0);
9c5e12a4 215
623a4c97 216 if (DNS_PACKET_QDCOUNT(p) > 1)
15411c0c 217 return -EOPNOTSUPP;
623a4c97 218
1716f6dc
LP
219 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
220 return -EMSGSIZE;
221
a0166609 222 if (p->size + UDP_PACKET_HEADER_SIZE > mtu)
1716f6dc
LP
223 return -EMSGSIZE;
224
72290734
TG
225 r = manager_write(s->manager, fd, p);
226 if (r < 0)
227 return r;
228
106784eb 229 break;
1716f6dc 230
106784eb 231 case DNS_PROTOCOL_LLMNR:
519ef046
LP
232 assert(fd < 0);
233
1716f6dc 234 if (DNS_PACKET_QDCOUNT(p) > 1)
15411c0c 235 return -EOPNOTSUPP;
1716f6dc 236
aea2429d
LP
237 if (!ratelimit_test(&s->ratelimit))
238 return -EBUSY;
239
1716f6dc 240 family = s->family;
1716f6dc
LP
241
242 if (family == AF_INET) {
243 addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
1716f6dc
LP
244 fd = manager_llmnr_ipv4_udp_fd(s->manager);
245 } else if (family == AF_INET6) {
246 addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
247 fd = manager_llmnr_ipv6_udp_fd(s->manager);
1716f6dc
LP
248 } else
249 return -EAFNOSUPPORT;
250 if (fd < 0)
251 return fd;
72290734 252
b30bf55d 253 r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, NULL, p);
b4f1862d
DM
254 if (r < 0)
255 return r;
256
257 break;
258
259 case DNS_PROTOCOL_MDNS:
519ef046
LP
260 assert(fd < 0);
261
b4f1862d
DM
262 if (!ratelimit_test(&s->ratelimit))
263 return -EBUSY;
264
265 family = s->family;
266
267 if (family == AF_INET) {
268 addr.in = MDNS_MULTICAST_IPV4_ADDRESS;
269 fd = manager_mdns_ipv4_fd(s->manager);
270 } else if (family == AF_INET6) {
271 addr.in6 = MDNS_MULTICAST_IPV6_ADDRESS;
272 fd = manager_mdns_ipv6_fd(s->manager);
273 } else
274 return -EAFNOSUPPORT;
275 if (fd < 0)
276 return fd;
277
b30bf55d 278 r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, NULL, p);
72290734
TG
279 if (r < 0)
280 return r;
106784eb
DM
281
282 break;
283
284 default:
74b2466e 285 return -EAFNOSUPPORT;
106784eb 286 }
74b2466e 287
74b2466e
LP
288 return 1;
289}
290
519ef046 291int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p) {
80a62095
DM
292 int r;
293
294 assert(s);
295 assert(p);
296 assert(p->protocol == s->protocol);
519ef046 297 assert((s->protocol == DNS_PROTOCOL_DNS) == (fd >= 0));
80a62095
DM
298
299 do {
300 /* If there are multiple linked packets, set the TC bit in all but the last of them */
301 if (p->more) {
302 assert(p->protocol == DNS_PROTOCOL_MDNS);
261f3673 303 dns_packet_set_flags(p, true, true);
80a62095
DM
304 }
305
519ef046 306 r = dns_scope_emit_one(s, fd, p);
80a62095
DM
307 if (r < 0)
308 return r;
309
310 p = p->more;
519ef046 311 } while (p);
80a62095
DM
312
313 return 0;
314}
315
519ef046
LP
316static int dns_scope_socket(
317 DnsScope *s,
318 int type,
319 int family,
320 const union in_addr_union *address,
321 DnsServer *server,
322 uint16_t port) {
323
ad867662
LP
324 _cleanup_close_ int fd = -1;
325 union sockaddr_union sa = {};
326 socklen_t salen;
623a4c97 327 static const int one = 1;
c10d6bdb 328 int r, ifindex;
ad867662
LP
329
330 assert(s);
be808ea0 331
519ef046
LP
332 if (server) {
333 assert(family == AF_UNSPEC);
334 assert(!address);
be808ea0 335
2817157b
LP
336 ifindex = dns_server_ifindex(server);
337
519ef046
LP
338 sa.sa.sa_family = server->family;
339 if (server->family == AF_INET) {
623a4c97 340 sa.in.sin_port = htobe16(port);
519ef046 341 sa.in.sin_addr = server->address.in;
623a4c97 342 salen = sizeof(sa.in);
519ef046 343 } else if (server->family == AF_INET6) {
623a4c97 344 sa.in6.sin6_port = htobe16(port);
519ef046 345 sa.in6.sin6_addr = server->address.in6;
2817157b 346 sa.in6.sin6_scope_id = ifindex;
623a4c97
LP
347 salen = sizeof(sa.in6);
348 } else
349 return -EAFNOSUPPORT;
350 } else {
519ef046
LP
351 assert(family != AF_UNSPEC);
352 assert(address);
353
623a4c97 354 sa.sa.sa_family = family;
2817157b 355 ifindex = s->link ? s->link->ifindex : 0;
623a4c97
LP
356
357 if (family == AF_INET) {
358 sa.in.sin_port = htobe16(port);
359 sa.in.sin_addr = address->in;
360 salen = sizeof(sa.in);
361 } else if (family == AF_INET6) {
362 sa.in6.sin6_port = htobe16(port);
363 sa.in6.sin6_addr = address->in6;
2817157b 364 sa.in6.sin6_scope_id = ifindex;
623a4c97
LP
365 salen = sizeof(sa.in6);
366 } else
367 return -EAFNOSUPPORT;
368 }
ad867662 369
0db64366 370 fd = socket(sa.sa.sa_family, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
ad867662
LP
371 if (fd < 0)
372 return -errno;
373
0db64366
TG
374 if (type == SOCK_STREAM) {
375 r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
376 if (r < 0)
377 return -errno;
378 }
623a4c97
LP
379
380 if (s->link) {
2817157b 381 be32_t ifindex_be = htobe32(ifindex);
623a4c97
LP
382
383 if (sa.sa.sa_family == AF_INET) {
2817157b 384 r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be));
623a4c97
LP
385 if (r < 0)
386 return -errno;
387 } else if (sa.sa.sa_family == AF_INET6) {
2817157b 388 r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be));
623a4c97
LP
389 if (r < 0)
390 return -errno;
391 }
392 }
393
394 if (s->protocol == DNS_PROTOCOL_LLMNR) {
bf3f1271 395 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
623a4c97
LP
396
397 if (sa.sa.sa_family == AF_INET) {
398 r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
399 if (r < 0)
400 return -errno;
401 } else if (sa.sa.sa_family == AF_INET6) {
402 r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
403 if (r < 0)
404 return -errno;
405 }
406 }
ad867662
LP
407
408 r = connect(fd, &sa.sa, salen);
409 if (r < 0 && errno != EINPROGRESS)
410 return -errno;
411
c10d6bdb 412 return TAKE_FD(fd);
ad867662
LP
413}
414
519ef046
LP
415int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port) {
416 return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port);
0db64366
TG
417}
418
519ef046
LP
419int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port) {
420 return dns_scope_socket(s, SOCK_STREAM, family, address, server, port);
0db64366
TG
421}
422
51323288 423DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
a51c1048 424 DnsSearchDomain *d;
74b2466e
LP
425
426 assert(s);
427 assert(domain);
428
28b9b764
LP
429 /* Checks if the specified domain is something to look up on
430 * this scope. Note that this accepts non-qualified hostnames,
431 * i.e. those without any search path prefixed yet. */
432
51323288
LP
433 if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex))
434 return DNS_SCOPE_NO;
435
931851e8 436 if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, 0) & flags) == 0)
51323288
LP
437 return DNS_SCOPE_NO;
438
78c6a153
LP
439 /* Never resolve any loopback hostname or IP address via DNS,
440 * LLMNR or mDNS. Instead, always rely on synthesized RRs for
441 * these. */
442 if (is_localhost(domain) ||
443 dns_name_endswith(domain, "127.in-addr.arpa") > 0 ||
9436e8ca
LP
444 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)
445 return DNS_SCOPE_NO;
446
c9ad0edb
LP
447 /* Never respond to some of the domains listed in RFC6303 */
448 if (dns_name_endswith(domain, "0.in-addr.arpa") > 0 ||
449 dns_name_equal(domain, "255.255.255.255.in-addr.arpa") > 0 ||
450 dns_name_equal(domain, "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.0.ip6.arpa") > 0)
451 return DNS_SCOPE_NO;
452
7bcffc2e
LP
453 /* Never respond to some of the domains listed in RFC6761 */
454 if (dns_name_endswith(domain, "invalid") > 0)
455 return DNS_SCOPE_NO;
456
106784eb 457 switch (s->protocol) {
801ad6a6 458
613dca46
LP
459 case DNS_PROTOCOL_DNS: {
460 DnsServer *dns_server;
461
462 /* Never route things to scopes that lack DNS servers */
463 dns_server = dns_scope_get_dns_server(s);
464 if (!dns_server)
465 return DNS_SCOPE_NO;
466
467 /* Always honour search domains for routing queries, except if this scope lacks DNS servers. Note that
468 * we return DNS_SCOPE_YES here, rather than just DNS_SCOPE_MAYBE, which means other wildcard scopes
469 * won't be considered anymore. */
470 LIST_FOREACH(domains, d, dns_scope_get_search_domains(s))
471 if (dns_name_endswith(domain, d->name) > 0)
472 return DNS_SCOPE_YES;
473
474 /* If the DNS server has route-only domains, don't send other requests to it. This would be a privacy
475 * violation, will most probably fail anyway, and adds unnecessary load. */
476 if (dns_server_limited_domains(dns_server))
477 return DNS_SCOPE_NO;
801ad6a6 478
28b9b764
LP
479 /* Exclude link-local IP ranges */
480 if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
c9ad0edb
LP
481 dns_name_endswith(domain, "8.e.f.ip6.arpa") == 0 &&
482 dns_name_endswith(domain, "9.e.f.ip6.arpa") == 0 &&
483 dns_name_endswith(domain, "a.e.f.ip6.arpa") == 0 &&
b43d96b0
DM
484 dns_name_endswith(domain, "b.e.f.ip6.arpa") == 0 &&
485 /* If networks use .local in their private setups, they are supposed to also add .local to their search
486 * domains, which we already checked above. Otherwise, we consider .local specific to mDNS and won't
487 * send such queries ordinary DNS servers. */
488 dns_name_endswith(domain, "local") == 0)
faa133f3 489 return DNS_SCOPE_MAYBE;
1716f6dc 490
faa133f3 491 return DNS_SCOPE_NO;
613dca46 492 }
1716f6dc 493
106784eb 494 case DNS_PROTOCOL_MDNS:
78c6a153
LP
495 if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
496 (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) ||
497 (dns_name_endswith(domain, "local") > 0 && /* only resolve names ending in .local via mDNS */
498 dns_name_equal(domain, "local") == 0 && /* but not the single-label "local" name itself */
499 manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via mDNS */
d8b7e75f 500 return DNS_SCOPE_MAYBE;
74b2466e
LP
501
502 return DNS_SCOPE_NO;
74b2466e 503
106784eb 504 case DNS_PROTOCOL_LLMNR:
78c6a153
LP
505 if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
506 (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) ||
dc477e73 507 (dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */
78c6a153
LP
508 !is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
509 manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
1716f6dc 510 return DNS_SCOPE_MAYBE;
74b2466e 511
1716f6dc 512 return DNS_SCOPE_NO;
74b2466e 513
106784eb
DM
514 default:
515 assert_not_reached("Unknown scope protocol");
516 }
1716f6dc
LP
517}
518
011696f7
LP
519bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
520 int key_family;
521
1716f6dc
LP
522 assert(s);
523 assert(key);
524
28b9b764
LP
525 /* Check if it makes sense to resolve the specified key on
526 * this scope. Note that this call assumes as fully qualified
527 * name, i.e. the search suffixes already appended. */
528
011696f7
LP
529 if (key->class != DNS_CLASS_IN)
530 return false;
531
28b9b764
LP
532 if (s->protocol == DNS_PROTOCOL_DNS) {
533
e5abebab 534 /* On classic DNS, looking up non-address RRs is always
28b9b764
LP
535 * fine. (Specifically, we want to permit looking up
536 * DNSKEY and DS records on the root and top-level
537 * domains.) */
538 if (!dns_resource_key_is_address(key))
539 return true;
540
541 /* However, we refuse to look up A and AAAA RRs on the
542 * root and single-label domains, under the assumption
543 * that those should be resolved via LLMNR or search
544 * path only, and should not be leaked onto the
545 * internet. */
1c02e7ba
ZJS
546 return !(dns_name_is_single_label(dns_resource_key_name(key)) ||
547 dns_name_is_root(dns_resource_key_name(key)));
28b9b764 548 }
1716f6dc
LP
549
550 /* On mDNS and LLMNR, send A and AAAA queries only on the
551 * respective scopes */
552
011696f7
LP
553 key_family = dns_type_to_af(key->type);
554 if (key_family < 0)
555 return true;
1716f6dc 556
011696f7 557 return key_family == s->family;
1716f6dc
LP
558}
559
0db4c90a 560static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in, struct in6_addr in6) {
1716f6dc
LP
561 int fd;
562
5ba73e9b 563 assert(s);
5ba73e9b
LP
564 assert(s->link);
565
1716f6dc
LP
566 if (s->family == AF_INET) {
567 struct ip_mreqn mreqn = {
0db4c90a 568 .imr_multiaddr = in,
1716f6dc
LP
569 .imr_ifindex = s->link->ifindex,
570 };
571
d37baf40
DR
572 if (s->protocol == DNS_PROTOCOL_LLMNR)
573 fd = manager_llmnr_ipv4_udp_fd(s->manager);
574 else
575 fd = manager_mdns_ipv4_fd(s->manager);
576
1716f6dc
LP
577 if (fd < 0)
578 return fd;
579
7b4c2ee7
LP
580 /* Always first try to drop membership before we add
581 * one. This is necessary on some devices, such as
582 * veth. */
583 if (b)
dc751688 584 (void) setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
7b4c2ee7 585
1716f6dc
LP
586 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
587 return -errno;
588
589 } else if (s->family == AF_INET6) {
590 struct ipv6_mreq mreq = {
0db4c90a 591 .ipv6mr_multiaddr = in6,
1716f6dc
LP
592 .ipv6mr_interface = s->link->ifindex,
593 };
594
d37baf40
DR
595 if (s->protocol == DNS_PROTOCOL_LLMNR)
596 fd = manager_llmnr_ipv6_udp_fd(s->manager);
597 else
598 fd = manager_mdns_ipv6_fd(s->manager);
599
1716f6dc
LP
600 if (fd < 0)
601 return fd;
602
7b4c2ee7 603 if (b)
dc751688 604 (void) setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
7b4c2ee7 605
1716f6dc
LP
606 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
607 return -errno;
608 } else
609 return -EAFNOSUPPORT;
610
611 return 0;
74b2466e 612}
623a4c97 613
0db4c90a 614int dns_scope_llmnr_membership(DnsScope *s, bool b) {
f471bc11 615 assert(s);
0db4c90a
DM
616
617 if (s->protocol != DNS_PROTOCOL_LLMNR)
618 return 0;
619
620 return dns_scope_multicast_membership(s, b, LLMNR_MULTICAST_IPV4_ADDRESS, LLMNR_MULTICAST_IPV6_ADDRESS);
621}
622
623int dns_scope_mdns_membership(DnsScope *s, bool b) {
f471bc11 624 assert(s);
0db4c90a
DM
625
626 if (s->protocol != DNS_PROTOCOL_MDNS)
627 return 0;
628
629 return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS);
630}
631
3b991089 632int dns_scope_make_reply_packet(
ec2c5e43
LP
633 DnsScope *s,
634 uint16_t id,
635 int rcode,
636 DnsQuestion *q,
637 DnsAnswer *answer,
638 DnsAnswer *soa,
639 bool tentative,
640 DnsPacket **ret) {
641
623a4c97 642 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
623a4c97
LP
643 int r;
644
645 assert(s);
a4076574 646 assert(ret);
623a4c97 647
501e8eb0
LP
648 if (dns_question_isempty(q) &&
649 dns_answer_isempty(answer) &&
650 dns_answer_isempty(soa))
623a4c97
LP
651 return -EINVAL;
652
51027656 653 r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
623a4c97
LP
654 if (r < 0)
655 return r;
656
657 DNS_PACKET_HEADER(p)->id = id;
ea917db9
LP
658 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
659 1 /* qr */,
660 0 /* opcode */,
661 0 /* c */,
662 0 /* tc */,
ec2c5e43 663 tentative,
ea917db9
LP
664 0 /* (ra) */,
665 0 /* (ad) */,
666 0 /* (cd) */,
667 rcode));
623a4c97 668
f471bc11
LP
669 r = dns_packet_append_question(p, q);
670 if (r < 0)
671 return r;
672 DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));
8bf52d3d 673
f471bc11
LP
674 r = dns_packet_append_answer(p, answer);
675 if (r < 0)
676 return r;
677 DNS_PACKET_HEADER(p)->ancount = htobe16(dns_answer_size(answer));
8bf52d3d 678
f471bc11
LP
679 r = dns_packet_append_answer(p, soa);
680 if (r < 0)
681 return r;
682 DNS_PACKET_HEADER(p)->arcount = htobe16(dns_answer_size(soa));
623a4c97 683
1cc6c93a 684 *ret = TAKE_PTR(p);
623a4c97
LP
685
686 return 0;
687}
688
a4076574 689static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
2a3900d7
LP
690 DnsResourceRecord *rr;
691 DnsResourceKey *key;
a4076574
LP
692
693 assert(s);
694 assert(p);
695
2a3900d7
LP
696 DNS_QUESTION_FOREACH(key, p->question)
697 dns_zone_verify_conflicts(&s->zone, key);
698
699 DNS_ANSWER_FOREACH(rr, p->answer)
700 dns_zone_verify_conflicts(&s->zone, rr->key);
a4076574
LP
701}
702
623a4c97 703void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
8bf52d3d 704 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
b30bf55d 705 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
5032b16d 706 DnsResourceKey *key = NULL;
ec2c5e43 707 bool tentative = false;
b30bf55d 708 int r;
623a4c97
LP
709
710 assert(s);
711 assert(p);
712
713 if (p->protocol != DNS_PROTOCOL_LLMNR)
714 return;
715
2442b93d
LP
716 if (p->ipproto == IPPROTO_UDP) {
717 /* Don't accept UDP queries directed to anything but
718 * the LLMNR multicast addresses. See RFC 4795,
d076c6f9 719 * section 2.5. */
2442b93d
LP
720
721 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
722 return;
723
724 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
725 return;
726 }
727
623a4c97
LP
728 r = dns_packet_extract(p);
729 if (r < 0) {
b30bf55d 730 log_debug_errno(r, "Failed to extract resource records from incoming packet: %m");
623a4c97
LP
731 return;
732 }
733
8b757a38 734 if (DNS_PACKET_LLMNR_C(p)) {
a4076574
LP
735 /* Somebody notified us about a possible conflict */
736 dns_scope_verify_conflicts(s, p);
ea917db9
LP
737 return;
738 }
739
501e8eb0 740 assert(dns_question_size(p->question) == 1);
5032b16d
LP
741 key = p->question->keys[0];
742
97ebebbc 743 r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
623a4c97 744 if (r < 0) {
da927ba9 745 log_debug_errno(r, "Failed to lookup key: %m");
623a4c97
LP
746 return;
747 }
748 if (r == 0)
749 return;
750
fcf57f9c
LP
751 if (answer)
752 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
af93291c 753
ec2c5e43 754 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
623a4c97 755 if (r < 0) {
da927ba9 756 log_debug_errno(r, "Failed to build reply packet: %m");
623a4c97
LP
757 return;
758 }
759
b30bf55d 760 if (stream) {
623a4c97 761 r = dns_stream_write_packet(stream, reply);
b30bf55d
LP
762 if (r < 0) {
763 log_debug_errno(r, "Failed to enqueue reply packet: %m");
764 return;
765 }
766
767 /* Let's take an extra reference on this stream, so that it stays around after returning. The reference
768 * will be dangling until the stream is disconnected, and the default completion handler of the stream
769 * will then unref the stream and destroy it */
770 if (DNS_STREAM_QUEUED(stream))
771 dns_stream_ref(stream);
772 } else {
773 int fd;
774
aea2429d
LP
775 if (!ratelimit_test(&s->ratelimit))
776 return;
777
623a4c97
LP
778 if (p->family == AF_INET)
779 fd = manager_llmnr_ipv4_udp_fd(s->manager);
780 else if (p->family == AF_INET6)
781 fd = manager_llmnr_ipv6_udp_fd(s->manager);
782 else {
783 log_debug("Unknown protocol");
784 return;
785 }
786 if (fd < 0) {
da927ba9 787 log_debug_errno(fd, "Failed to get reply socket: %m");
623a4c97
LP
788 return;
789 }
790
6e068472
LP
791 /* Note that we always immediately reply to all LLMNR
792 * requests, and do not wait any time, since we
793 * verified uniqueness for all records. Also see RFC
794 * 4795, Section 2.7 */
795
b30bf55d
LP
796 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, NULL, reply);
797 if (r < 0) {
798 log_debug_errno(r, "Failed to send reply packet: %m");
799 return;
800 }
623a4c97
LP
801 }
802}
ec2c5e43 803
f52e61da 804DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok) {
ec2c5e43
LP
805 DnsTransaction *t;
806
807 assert(scope);
f52e61da 808 assert(key);
ec2c5e43 809
da0c630e
LP
810 /* Try to find an ongoing transaction that is a equal to the
811 * specified question */
f9ebb22a 812 t = hashmap_get(scope->transactions_by_key, key);
4a46ed1b
LP
813 if (!t)
814 return NULL;
dc4d47e2 815
da0c630e
LP
816 /* Refuse reusing transactions that completed based on cached
817 * data instead of a real packet, if that's requested. */
818 if (!cache_ok &&
3bbdc31d 819 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_RCODE_FAILURE) &&
c3bc53e6 820 t->answer_source != DNS_TRANSACTION_NETWORK)
da0c630e 821 return NULL;
ec2c5e43 822
da0c630e 823 return t;
ec2c5e43 824}
a4076574
LP
825
826static int dns_scope_make_conflict_packet(
827 DnsScope *s,
828 DnsResourceRecord *rr,
829 DnsPacket **ret) {
830
831 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
832 int r;
833
834 assert(s);
835 assert(rr);
836 assert(ret);
837
51027656 838 r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
a4076574
LP
839 if (r < 0)
840 return r;
841
842 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
843 0 /* qr */,
844 0 /* opcode */,
845 1 /* conflict */,
846 0 /* tc */,
847 0 /* t */,
848 0 /* (ra) */,
849 0 /* (ad) */,
850 0 /* (cd) */,
851 0));
fe2dfc8b
DM
852
853 /* For mDNS, the transaction ID should always be 0 */
854 if (s->protocol != DNS_PROTOCOL_MDNS)
855 random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
856
a4076574
LP
857 DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
858 DNS_PACKET_HEADER(p)->arcount = htobe16(1);
859
58ab31d5 860 r = dns_packet_append_key(p, rr->key, 0, NULL);
a4076574
LP
861 if (r < 0)
862 return r;
863
58ab31d5 864 r = dns_packet_append_rr(p, rr, 0, NULL, NULL);
a4076574
LP
865 if (r < 0)
866 return r;
867
1cc6c93a 868 *ret = TAKE_PTR(p);
a4076574
LP
869
870 return 0;
871}
872
873static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
874 DnsScope *scope = userdata;
875 int r;
876
877 assert(es);
878 assert(scope);
879
880 scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
881
882 for (;;) {
432d108c 883 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
a4076574
LP
884 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
885 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
886
432d108c
DR
887 key = ordered_hashmap_first_key(scope->conflict_queue);
888 if (!key)
a4076574
LP
889 break;
890
432d108c
DR
891 rr = ordered_hashmap_remove(scope->conflict_queue, key);
892 assert(rr);
893
a4076574
LP
894 r = dns_scope_make_conflict_packet(scope, rr, &p);
895 if (r < 0) {
da927ba9 896 log_error_errno(r, "Failed to make conflict packet: %m");
a4076574
LP
897 return 0;
898 }
899
519ef046 900 r = dns_scope_emit_udp(scope, -1, p);
a4076574 901 if (r < 0)
da927ba9 902 log_debug_errno(r, "Failed to send conflict packet: %m");
a4076574
LP
903 }
904
905 return 0;
906}
907
908int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
909 usec_t jitter;
910 int r;
911
912 assert(scope);
913 assert(rr);
914
915 /* We don't send these queries immediately. Instead, we queue
916 * them, and send them after some jitter delay. */
1e43061b 917 r = ordered_hashmap_ensure_allocated(&scope->conflict_queue, &dns_resource_key_hash_ops);
a4076574
LP
918 if (r < 0) {
919 log_oom();
920 return r;
921 }
922
923 /* We only place one RR per key in the conflict
924 * messages, not all of them. That should be enough to
925 * indicate where there might be a conflict */
1e43061b 926 r = ordered_hashmap_put(scope->conflict_queue, rr->key, rr);
4c701096 927 if (IN_SET(r, 0, -EEXIST))
a4076574 928 return 0;
f647962d
MS
929 if (r < 0)
930 return log_debug_errno(r, "Failed to queue conflicting RR: %m");
a4076574 931
432d108c 932 dns_resource_key_ref(rr->key);
a4076574
LP
933 dns_resource_record_ref(rr);
934
935 if (scope->conflict_event_source)
936 return 0;
937
938 random_bytes(&jitter, sizeof(jitter));
939 jitter %= LLMNR_JITTER_INTERVAL_USEC;
940
941 r = sd_event_add_time(scope->manager->event,
942 &scope->conflict_event_source,
943 clock_boottime_or_monotonic(),
944 now(clock_boottime_or_monotonic()) + jitter,
945 LLMNR_JITTER_INTERVAL_USEC,
946 on_conflict_dispatch, scope);
f647962d
MS
947 if (r < 0)
948 return log_debug_errno(r, "Failed to add conflict dispatch event: %m");
a4076574 949
aa4a9deb
LP
950 (void) sd_event_source_set_description(scope->conflict_event_source, "scope-conflict");
951
a4076574
LP
952 return 0;
953}
954
955void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
c1227a18 956 DnsResourceRecord *rr;
a4076574
LP
957 int r;
958
959 assert(scope);
960 assert(p);
961
53fda2bb 962 if (!IN_SET(p->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS))
a4076574
LP
963 return;
964
965 if (DNS_PACKET_RRCOUNT(p) <= 0)
966 return;
967
53fda2bb
DR
968 if (p->protocol == DNS_PROTOCOL_LLMNR) {
969 if (DNS_PACKET_LLMNR_C(p) != 0)
970 return;
a4076574 971
53fda2bb
DR
972 if (DNS_PACKET_LLMNR_T(p) != 0)
973 return;
974 }
a4076574
LP
975
976 if (manager_our_packet(scope->manager, p))
977 return;
978
979 r = dns_packet_extract(p);
980 if (r < 0) {
da927ba9 981 log_debug_errno(r, "Failed to extract packet: %m");
a4076574
LP
982 return;
983 }
984
985 log_debug("Checking for conflicts...");
986
c1227a18 987 DNS_ANSWER_FOREACH(rr, p->answer) {
cfcc8dcc 988 /* No conflict if it is DNS-SD RR used for service enumeration. */
c1227a18 989 if (dns_resource_key_is_dnssd_ptr(rr->key))
cfcc8dcc
DR
990 continue;
991
a4076574
LP
992 /* Check for conflicts against the local zone. If we
993 * found one, we won't check any further */
c1227a18 994 r = dns_zone_check_conflicts(&scope->zone, rr);
a4076574
LP
995 if (r != 0)
996 continue;
997
998 /* Check for conflicts against the local cache. If so,
999 * send out an advisory query, to inform everybody */
c1227a18 1000 r = dns_cache_check_conflicts(&scope->cache, rr, p->family, &p->sender);
a4076574
LP
1001 if (r <= 0)
1002 continue;
1003
c1227a18 1004 dns_scope_notify_conflict(scope, rr);
a4076574
LP
1005 }
1006}
4d506d6b
LP
1007
1008void dns_scope_dump(DnsScope *s, FILE *f) {
1009 assert(s);
1010
1011 if (!f)
1012 f = stdout;
1013
1014 fputs("[Scope protocol=", f);
1015 fputs(dns_protocol_to_string(s->protocol), f);
1016
1017 if (s->link) {
1018 fputs(" interface=", f);
1019 fputs(s->link->name, f);
1020 }
1021
1022 if (s->family != AF_UNSPEC) {
1023 fputs(" family=", f);
1024 fputs(af_to_name(s->family), f);
1025 }
1026
1027 fputs("]\n", f);
1028
1029 if (!dns_zone_is_empty(&s->zone)) {
1030 fputs("ZONE:\n", f);
1031 dns_zone_dump(&s->zone, f);
1032 }
1033
1034 if (!dns_cache_is_empty(&s->cache)) {
1035 fputs("CACHE:\n", f);
1036 dns_cache_dump(&s->cache, f);
1037 }
1038}
a51c1048
LP
1039
1040DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
801ad6a6
LP
1041 assert(s);
1042
a51c1048
LP
1043 if (s->protocol != DNS_PROTOCOL_DNS)
1044 return NULL;
1045
1046 if (s->link)
1047 return s->link->search_domains;
1048
28b9b764 1049 return s->manager->search_domains;
801ad6a6
LP
1050}
1051
dc477e73 1052bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
801ad6a6
LP
1053 assert(s);
1054
1055 if (s->protocol != DNS_PROTOCOL_DNS)
dc477e73 1056 return false;
801ad6a6 1057
dc477e73 1058 return dns_name_is_single_label(name);
801ad6a6 1059}
edbcc1fd
LP
1060
1061bool dns_scope_network_good(DnsScope *s) {
edbcc1fd
LP
1062 /* Checks whether the network is in good state for lookups on this scope. For mDNS/LLMNR/Classic DNS scopes
1063 * bound to links this is easy, as they don't even exist if the link isn't in a suitable state. For the global
1064 * DNS scope we check whether there are any links that are up and have an address. */
1065
1066 if (s->link)
1067 return true;
1068
011696f7 1069 return manager_routable(s->manager, AF_UNSPEC);
edbcc1fd 1070}
97ebebbc
LP
1071
1072int dns_scope_ifindex(DnsScope *s) {
1073 assert(s);
1074
1075 if (s->link)
1076 return s->link->ifindex;
1077
1078 return 0;
1079}
53fda2bb
DR
1080
1081static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userdata) {
1082 DnsScope *scope = userdata;
1083
1084 assert(s);
1085
1086 scope->announce_event_source = sd_event_source_unref(scope->announce_event_source);
1087
1a63fc54 1088 (void) dns_scope_announce(scope, false);
53fda2bb
DR
1089 return 0;
1090}
1091
1a63fc54 1092int dns_scope_announce(DnsScope *scope, bool goodbye) {
53fda2bb
DR
1093 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1094 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
a2bf8a19
DR
1095 _cleanup_set_free_ Set *types = NULL;
1096 DnsTransaction *t;
400f54fb 1097 DnsZoneItem *z, *i;
a2bf8a19
DR
1098 unsigned size = 0;
1099 Iterator iterator;
1100 char *service_type;
53fda2bb
DR
1101 int r;
1102
1103 if (!scope)
1a63fc54 1104 return 0;
53fda2bb
DR
1105
1106 if (scope->protocol != DNS_PROTOCOL_MDNS)
1a63fc54 1107 return 0;
53fda2bb 1108
a2bf8a19
DR
1109 /* Check if we're done with probing. */
1110 LIST_FOREACH(transactions_by_scope, t, scope->transactions)
1111 if (DNS_TRANSACTION_IS_LIVE(t->state))
1112 return 0;
1113
e7c1b0e4
DR
1114 /* Check if there're services pending conflict resolution. */
1115 if (manager_next_dnssd_names(scope->manager))
1116 return 0; /* we reach this point only if changing hostname didn't help */
1117
a2bf8a19
DR
1118 /* Calculate answer's size. */
1119 HASHMAP_FOREACH(z, scope->zone.by_key, iterator) {
1120 if (z->state != DNS_ZONE_ITEM_ESTABLISHED)
1121 continue;
1122
1123 if (z->rr->key->type == DNS_TYPE_PTR &&
1124 !dns_zone_contains_name(&scope->zone, z->rr->ptr.name)) {
1125 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
1126
1127 log_debug("Skip PTR RR <%s> since its counterparts seem to be withdrawn", dns_resource_key_to_string(z->rr->key, key_str, sizeof key_str));
1128 z->state = DNS_ZONE_ITEM_WITHDRAWN;
1129 continue;
1130 }
1131
1132 /* Collect service types for _services._dns-sd._udp.local RRs in a set */
1133 if (!scope->announced &&
1134 dns_resource_key_is_dnssd_ptr(z->rr->key)) {
1135 if (!set_contains(types, dns_resource_key_name(z->rr->key))) {
1136 r = set_ensure_allocated(&types, &dns_name_hash_ops);
1137 if (r < 0)
1138 return log_debug_errno(r, "Failed to allocate set: %m");
1139
1140 r = set_put(types, dns_resource_key_name(z->rr->key));
1141 if (r < 0)
1142 return log_debug_errno(r, "Failed to add item to set: %m");
1143 }
1144 }
1145
400f54fb
DR
1146 LIST_FOREACH(by_key, i, z)
1147 size++;
a2bf8a19
DR
1148 }
1149
1150 answer = dns_answer_new(size + set_size(types));
1a63fc54
LP
1151 if (!answer)
1152 return log_oom();
1153
a2bf8a19 1154 /* Second iteration, actually add RRs to the answer. */
400f54fb
DR
1155 HASHMAP_FOREACH(z, scope->zone.by_key, iterator)
1156 LIST_FOREACH (by_key, i, z) {
1157 DnsAnswerFlags flags;
a2bf8a19 1158
400f54fb
DR
1159 if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
1160 continue;
a2bf8a19 1161
400f54fb
DR
1162 if (dns_resource_key_is_dnssd_ptr(i->rr->key))
1163 flags = goodbye ? DNS_ANSWER_GOODBYE : 0;
1164 else
1165 flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH;
a2bf8a19 1166
400f54fb
DR
1167 r = dns_answer_add(answer, i->rr, 0 , flags);
1168 if (r < 0)
1169 return log_debug_errno(r, "Failed to add RR to announce: %m");
1170 }
a2bf8a19
DR
1171
1172 /* Since all the active services are in the zone make them discoverable now. */
1173 SET_FOREACH(service_type, types, iterator) {
1174 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
1175
1176 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR,
1177 "_services._dns-sd._udp.local");
1178 rr->ptr.name = strdup(service_type);
1179 rr->ttl = MDNS_DEFAULT_TTL;
1180
1181 r = dns_zone_put(&scope->zone, scope, rr, false);
1a63fc54 1182 if (r < 0)
a2bf8a19 1183 log_warning_errno(r, "Failed to add DNS-SD PTR record to MDNS zone: %m");
1a63fc54 1184
a2bf8a19 1185 r = dns_answer_add(answer, rr, 0 , 0);
1a63fc54 1186 if (r < 0)
a2bf8a19 1187 return log_debug_errno(r, "Failed to add RR to announce: %m");
53fda2bb
DR
1188 }
1189
1190 if (dns_answer_isempty(answer))
1a63fc54 1191 return 0;
53fda2bb
DR
1192
1193 r = dns_scope_make_reply_packet(scope, 0, DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &p);
1a63fc54
LP
1194 if (r < 0)
1195 return log_debug_errno(r, "Failed to build reply packet: %m");
1196
53fda2bb 1197 r = dns_scope_emit_udp(scope, -1, p);
1a63fc54
LP
1198 if (r < 0)
1199 return log_debug_errno(r, "Failed to send reply packet: %m");
53fda2bb
DR
1200
1201 /* In section 8.3 of RFC6762: "The Multicast DNS responder MUST send at least two unsolicited
1202 * responses, one second apart." */
1203 if (!scope->announced) {
1204 usec_t ts;
1205
1206 scope->announced = true;
1207
1208 assert_se(sd_event_now(scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
1209 ts += MDNS_ANNOUNCE_DELAY;
1210
1211 r = sd_event_add_time(
1212 scope->manager->event,
1213 &scope->announce_event_source,
1214 clock_boottime_or_monotonic(),
1215 ts,
1216 MDNS_JITTER_RANGE_USEC,
1217 on_announcement_timeout, scope);
1218 if (r < 0)
1a63fc54 1219 return log_debug_errno(r, "Failed to schedule second announcement: %m");
19fee3ef
LP
1220
1221 (void) sd_event_source_set_description(scope->announce_event_source, "mdns-announce");
53fda2bb 1222 }
1a63fc54
LP
1223
1224 return 0;
53fda2bb 1225}
6db6a464
DR
1226
1227int dns_scope_add_dnssd_services(DnsScope *scope) {
1228 Iterator i;
1229 DnssdService *service;
400f54fb 1230 DnssdTxtData *txt_data;
6db6a464
DR
1231 int r;
1232
1233 assert(scope);
1234
1235 if (hashmap_size(scope->manager->dnssd_services) == 0)
1236 return 0;
1237
1238 scope->announced = false;
1239
1240 HASHMAP_FOREACH(service, scope->manager->dnssd_services, i) {
c3036641
DR
1241 service->withdrawn = false;
1242
6db6a464
DR
1243 r = dns_zone_put(&scope->zone, scope, service->ptr_rr, false);
1244 if (r < 0)
1245 log_warning_errno(r, "Failed to add PTR record to MDNS zone: %m");
1246
1247 r = dns_zone_put(&scope->zone, scope, service->srv_rr, true);
1248 if (r < 0)
1249 log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m");
1250
400f54fb
DR
1251 LIST_FOREACH(items, txt_data, service->txt_data_items) {
1252 r = dns_zone_put(&scope->zone, scope, txt_data->rr, true);
1253 if (r < 0)
1254 log_warning_errno(r, "Failed to add TXT record to MDNS zone: %m");
1255 }
6db6a464
DR
1256 }
1257
1258 return 0;
1259}
1260
1261int dns_scope_remove_dnssd_services(DnsScope *scope) {
1262 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
1263 Iterator i;
1264 DnssdService *service;
400f54fb 1265 DnssdTxtData *txt_data;
6db6a464
DR
1266 int r;
1267
1268 assert(scope);
1269
1270 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_PTR,
1271 "_services._dns-sd._udp.local");
1272 if (!key)
1273 return log_oom();
1274
1275 r = dns_zone_remove_rrs_by_key(&scope->zone, key);
1276 if (r < 0)
1277 return r;
1278
1279 HASHMAP_FOREACH(service, scope->manager->dnssd_services, i) {
1280 dns_zone_remove_rr(&scope->zone, service->ptr_rr);
1281 dns_zone_remove_rr(&scope->zone, service->srv_rr);
400f54fb
DR
1282 LIST_FOREACH(items, txt_data, service->txt_data_items)
1283 dns_zone_remove_rr(&scope->zone, txt_data->rr);
6db6a464
DR
1284 }
1285
1286 return 0;
1287}