• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.55
/src/resolve/resolved-dns-scope.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <netinet/tcp.h>
4

5
#include "af-list.h"
6
#include "alloc-util.h"
7
#include "dns-domain.h"
8
#include "dns-type.h"
9
#include "errno-util.h"
10
#include "fd-util.h"
11
#include "hostname-util.h"
12
#include "missing_network.h"
13
#include "random-util.h"
14
#include "resolved-dnssd.h"
15
#include "resolved-dns-answer.h"
16
#include "resolved-dns-packet.h"
17
#include "resolved-dns-query.h"
18
#include "resolved-dns-question.h"
19
#include "resolved-dns-rr.h"
20
#include "resolved-dns-scope.h"
21
#include "resolved-dns-search-domain.h"
22
#include "resolved-dns-server.h"
23
#include "resolved-dns-synthesize.h"
24
#include "resolved-dns-transaction.h"
25
#include "resolved-dns-zone.h"
26
#include "resolved-link.h"
27
#include "resolved-llmnr.h"
28
#include "resolved-manager.h"
29
#include "resolved-mdns.h"
30
#include "resolved-timeouts.h"
31
#include "socket-util.h"
32
#include "strv.h"
33

34
#define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
35
#define MULTICAST_RATELIMIT_BURST 1000
36

37
/* After how much time to repeat LLMNR requests, see RFC 4795 Section 7 */
38
#define MULTICAST_RESEND_TIMEOUT_MIN_USEC (100 * USEC_PER_MSEC)
39
#define MULTICAST_RESEND_TIMEOUT_MAX_USEC (1 * USEC_PER_SEC)
40

41
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
817✔
42
        DnsScope *s;
817✔
43

44
        assert(m);
817✔
45
        assert(ret);
817✔
46

47
        s = new(DnsScope, 1);
817✔
48
        if (!s)
817✔
49
                return -ENOMEM;
50

51
        *s = (DnsScope) {
817✔
52
                .manager = m,
53
                .link = l,
54
                .protocol = protocol,
55
                .family = family,
56
                .resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC,
57

58
                /* Enforce ratelimiting for the multicast protocols */
59
                .ratelimit = { MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST },
60
        };
61

62
        if (protocol == DNS_PROTOCOL_DNS) {
817✔
63
                /* Copy DNSSEC mode from the link if it is set there,
64
                 * otherwise take the manager's DNSSEC mode. Note that
65
                 * we copy this only at scope creation time, and do
66
                 * not update it from the on, even if the setting
67
                 * changes. */
68

69
                if (l) {
296✔
70
                        s->dnssec_mode = link_get_dnssec_mode(l);
100✔
71
                        s->dns_over_tls_mode = link_get_dns_over_tls_mode(l);
100✔
72
                } else {
73
                        s->dnssec_mode = manager_get_dnssec_mode(m);
196✔
74
                        s->dns_over_tls_mode = manager_get_dns_over_tls_mode(m);
196✔
75
                }
76

77
        } else {
78
                s->dnssec_mode = DNSSEC_NO;
79
                s->dns_over_tls_mode = DNS_OVER_TLS_NO;
80
        }
81

82
        LIST_PREPEND(scopes, m->dns_scopes, s);
817✔
83

84
        dns_scope_llmnr_membership(s, true);
817✔
85
        dns_scope_mdns_membership(s, true);
817✔
86

87
        log_debug("New scope on link %s, protocol %s, family %s", l ? l->ifname : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
817✔
88

89
        *ret = s;
817✔
90
        return 0;
817✔
91
}
92

93
static void dns_scope_abort_transactions(DnsScope *s) {
808✔
94
        assert(s);
808✔
95

96
        while (s->transactions) {
1,039✔
97
                DnsTransaction *t = s->transactions;
231✔
98

99
                /* Abort the transaction, but make sure it is not
100
                 * freed while we still look at it */
101

102
                t->block_gc++;
231✔
103
                if (DNS_TRANSACTION_IS_LIVE(t->state))
231✔
104
                        dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
231✔
105
                t->block_gc--;
231✔
106

107
                dns_transaction_free(t);
231✔
108
        }
109
}
808✔
110

111
DnsScope* dns_scope_free(DnsScope *s) {
285,727✔
112
        if (!s)
285,727✔
113
                return NULL;
114

115
        log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->ifname : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
808✔
116

117
        dns_scope_llmnr_membership(s, false);
808✔
118
        dns_scope_mdns_membership(s, false);
808✔
119
        dns_scope_abort_transactions(s);
808✔
120

121
        while (s->query_candidates)
808✔
122
                dns_query_candidate_unref(s->query_candidates);
×
123

124
        hashmap_free(s->transactions_by_key);
808✔
125

126
        ordered_hashmap_free(s->conflict_queue);
808✔
127
        sd_event_source_disable_unref(s->conflict_event_source);
808✔
128

129
        sd_event_source_disable_unref(s->announce_event_source);
808✔
130

131
        sd_event_source_disable_unref(s->mdns_goodbye_event_source);
808✔
132

133
        dns_cache_flush(&s->cache);
808✔
134
        dns_zone_flush(&s->zone);
808✔
135

136
        LIST_REMOVE(scopes, s->manager->dns_scopes, s);
808✔
137
        return mfree(s);
808✔
138
}
139

140
DnsServer *dns_scope_get_dns_server(DnsScope *s) {
23,732✔
141
        assert(s);
23,732✔
142

143
        if (s->protocol != DNS_PROTOCOL_DNS)
23,732✔
144
                return NULL;
145

146
        if (s->link)
23,732✔
147
                return link_get_dns_server(s->link);
2,008✔
148
        else
149
                return manager_get_dns_server(s->manager);
21,724✔
150
}
151

152
unsigned dns_scope_get_n_dns_servers(DnsScope *s) {
422✔
153
        assert(s);
422✔
154

155
        if (s->protocol != DNS_PROTOCOL_DNS)
422✔
156
                return 0;
157

158
        if (s->link)
422✔
159
                return s->link->n_dns_servers;
138✔
160
        else
161
                return s->manager->n_dns_servers;
284✔
162
}
163

164
void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current) {
11,067✔
165
        assert(s);
11,067✔
166

167
        if (s->protocol != DNS_PROTOCOL_DNS)
11,067✔
168
                return;
169

170
        /* Changes to the next DNS server in the list. If 'if_current' is passed will do so only if the
171
         * current DNS server still matches it. */
172

173
        if (s->link)
9,455✔
174
                link_next_dns_server(s->link, if_current);
469✔
175
        else
176
                manager_next_dns_server(s->manager, if_current);
8,986✔
177
}
178

179
void dns_scope_packet_received(DnsScope *s, usec_t rtt) {
10✔
180
        assert(s);
10✔
181

182
        if (rtt <= s->max_rtt)
10✔
183
                return;
184

185
        s->max_rtt = rtt;
10✔
186
        s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2), MULTICAST_RESEND_TIMEOUT_MAX_USEC);
10✔
187
}
188

189
void dns_scope_packet_lost(DnsScope *s, usec_t usec) {
1,116✔
190
        assert(s);
1,116✔
191

192
        if (s->resend_timeout <= usec)
1,116✔
193
                s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC);
1,112✔
194
}
1,116✔
195

196
static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) {
1,999✔
197
        int r;
1,999✔
198

199
        assert(s);
1,999✔
200
        assert(p);
1,999✔
201
        assert(p->protocol == s->protocol);
1,999✔
202

203
        if (family == AF_UNSPEC) {
1,999✔
204
                if (s->family == AF_UNSPEC)
1,270✔
205
                        return -EAFNOSUPPORT;
206

207
                family = s->family;
208
        }
209

210
        switch (s->protocol) {
1,999✔
211

212
        case DNS_PROTOCOL_DNS: {
729✔
213
                size_t mtu, udp_size, min_mtu, socket_mtu = 0;
729✔
214

215
                assert(fd >= 0);
729✔
216

217
                if (DNS_PACKET_QDCOUNT(p) > 1) /* Classic DNS only allows one question per packet */
1,458✔
218
                        return -EOPNOTSUPP;
4✔
219

220
                if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
729✔
221
                        return -EMSGSIZE;
222

223
                /* Determine the local most accurate MTU */
224
                if (s->link)
729✔
225
                        mtu = s->link->mtu;
276✔
226
                else
227
                        mtu = manager_find_mtu(s->manager);
453✔
228

229
                /* Acquire the socket's PMDU MTU */
230
                r = socket_get_mtu(fd, family, &socket_mtu);
729✔
231
                if (r < 0 && !ERRNO_IS_DISCONNECT(r)) /* Will return ENOTCONN if no information is available yet */
729✔
232
                        return log_debug_errno(r, "Failed to read socket MTU: %m");
×
233

234
                /* Determine the appropriate UDP header size */
235
                udp_size = udp_header_size(family);
729✔
236
                min_mtu = udp_size + DNS_PACKET_HEADER_SIZE;
729✔
237

238
                log_debug("Emitting UDP, link MTU is %zu, socket MTU is %zu, minimal MTU is %zu",
729✔
239
                          mtu, socket_mtu, min_mtu);
240

241
                /* Clamp by the kernel's idea of the (path) MTU */
242
                if (socket_mtu != 0 && socket_mtu < mtu)
729✔
243
                        mtu = socket_mtu;
×
244

245
                /* Put a lower limit, in case all MTU data we acquired was rubbish */
246
                if (mtu < min_mtu)
729✔
247
                        mtu = min_mtu;
1✔
248

249
                /* Now check our packet size against the MTU we determined */
250
                if (udp_size + p->size > mtu)
729✔
251
                        return -EMSGSIZE; /* This means: try TCP instead */
252

253
                r = manager_write(s->manager, fd, p);
728✔
254
                if (r < 0)
728✔
255
                        return r;
256

257
                break;
725✔
258
        }
259

260
        case DNS_PROTOCOL_LLMNR: {
1,211✔
261
                union in_addr_union addr;
1,211✔
262

263
                assert(fd < 0);
1,211✔
264

265
                if (DNS_PACKET_QDCOUNT(p) > 1)
2,422✔
266
                        return -EOPNOTSUPP;
1✔
267

268
                if (!ratelimit_below(&s->ratelimit))
1,211✔
269
                        return -EBUSY;
270

271
                if (family == AF_INET) {
1,211✔
272
                        addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
482✔
273
                        fd = manager_llmnr_ipv4_udp_fd(s->manager);
482✔
274
                } else if (family == AF_INET6) {
729✔
275
                        addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
729✔
276
                        fd = manager_llmnr_ipv6_udp_fd(s->manager);
729✔
277
                } else
278
                        return -EAFNOSUPPORT;
279
                if (fd < 0)
1,211✔
280
                        return fd;
281

282
                r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, LLMNR_PORT, NULL, p);
1,211✔
283
                if (r < 0)
1,211✔
284
                        return r;
285

286
                break;
1,210✔
287
        }
288

289
        case DNS_PROTOCOL_MDNS: {
59✔
290
                union in_addr_union addr;
59✔
291
                assert(fd < 0);
59✔
292

293
                if (!ratelimit_below(&s->ratelimit))
59✔
294
                        return -EBUSY;
×
295

296
                if (family == AF_INET) {
59✔
297
                        if (in4_addr_is_null(&p->destination.in))
33✔
298
                                addr.in = MDNS_MULTICAST_IPV4_ADDRESS;
33✔
299
                        else
300
                                addr = p->destination;
×
301
                        fd = manager_mdns_ipv4_fd(s->manager);
33✔
302
                } else if (family == AF_INET6) {
26✔
303
                        if (in6_addr_is_null(&p->destination.in6))
26✔
304
                                addr.in6 = MDNS_MULTICAST_IPV6_ADDRESS;
26✔
305
                        else
306
                                addr = p->destination;
×
307
                        fd = manager_mdns_ipv6_fd(s->manager);
26✔
308
                } else
309
                        return -EAFNOSUPPORT;
310
                if (fd < 0)
59✔
311
                        return fd;
312

313
                r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, p->destination_port ?: MDNS_PORT, NULL, p);
59✔
314
                if (r < 0)
59✔
315
                        return r;
316

317
                break;
59✔
318
        }
319

320
        default:
321
                return -EAFNOSUPPORT;
322
        }
323

324
        return 1;
325
}
326

327
int dns_scope_emit_udp(DnsScope *s, int fd, int af, DnsPacket *p) {
1,999✔
328
        int r;
1,999✔
329

330
        assert(s);
1,999✔
331
        assert(p);
1,999✔
332
        assert(p->protocol == s->protocol);
1,999✔
333
        assert((s->protocol == DNS_PROTOCOL_DNS) == (fd >= 0));
1,999✔
334

335
        do {
1,999✔
336
                /* If there are multiple linked packets, set the TC bit in all but the last of them */
337
                if (p->more) {
1,999✔
338
                        assert(p->protocol == DNS_PROTOCOL_MDNS);
×
339
                        dns_packet_set_flags(p, true, true);
×
340
                }
341

342
                r = dns_scope_emit_one(s, fd, af, p);
1,999✔
343
                if (r < 0)
1,999✔
344
                        return r;
345

346
                p = p->more;
1,994✔
347
        } while (p);
1,994✔
348

349
        return 0;
350
}
351

352
static int dns_scope_socket(
9,687✔
353
                DnsScope *s,
354
                int type,
355
                int family,
356
                const union in_addr_union *address,
357
                DnsServer *server,
358
                uint16_t port,
359
                union sockaddr_union *ret_socket_address) {
360

361
        _cleanup_close_ int fd = -EBADF;
9,687✔
362
        union sockaddr_union sa;
9,687✔
363
        socklen_t salen;
9,687✔
364
        int r, ifindex;
9,687✔
365

366
        assert(s);
9,687✔
367

368
        if (server) {
9,687✔
369
                assert(family == AF_UNSPEC);
9,677✔
370
                assert(!address);
9,677✔
371

372
                ifindex = dns_server_ifindex(server);
9,677✔
373

374
                switch (server->family) {
9,677✔
375
                case AF_INET:
4,683✔
376
                        sa = (union sockaddr_union) {
4,683✔
377
                                .in.sin_family = server->family,
378
                                .in.sin_port = htobe16(port),
4,683✔
379
                                .in.sin_addr = server->address.in,
4,683✔
380
                        };
381
                        salen = sizeof(sa.in);
4,683✔
382
                        break;
4,683✔
383
                case AF_INET6:
4,994✔
384
                        sa = (union sockaddr_union) {
4,994✔
385
                                .in6.sin6_family = server->family,
386
                                .in6.sin6_port = htobe16(port),
4,994✔
387
                                .in6.sin6_addr = server->address.in6,
4,994✔
388
                                .in6.sin6_scope_id = ifindex,
389
                        };
390
                        salen = sizeof(sa.in6);
4,994✔
391
                        break;
4,994✔
392
                default:
393
                        return -EAFNOSUPPORT;
394
                }
395
        } else {
396
                assert(family != AF_UNSPEC);
10✔
397
                assert(address);
10✔
398

399
                ifindex = dns_scope_ifindex(s);
10✔
400

401
                switch (family) {
10✔
402
                case AF_INET:
5✔
403
                        sa = (union sockaddr_union) {
5✔
404
                                .in.sin_family = family,
405
                                .in.sin_port = htobe16(port),
5✔
406
                                .in.sin_addr = address->in,
5✔
407
                        };
408
                        salen = sizeof(sa.in);
5✔
409
                        break;
5✔
410
                case AF_INET6:
5✔
411
                        sa = (union sockaddr_union) {
5✔
412
                                .in6.sin6_family = family,
413
                                .in6.sin6_port = htobe16(port),
5✔
414
                                .in6.sin6_addr = address->in6,
5✔
415
                                .in6.sin6_scope_id = ifindex,
416
                        };
417
                        salen = sizeof(sa.in6);
5✔
418
                        break;
5✔
419
                default:
420
                        return -EAFNOSUPPORT;
421
                }
422
        }
423

424
        fd = socket(sa.sa.sa_family, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
9,687✔
425
        if (fd < 0)
9,687✔
426
                return -errno;
×
427

428
        if (type == SOCK_STREAM) {
9,687✔
429
                r = setsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY, true);
78✔
430
                if (r < 0)
78✔
431
                        return r;
432
        }
433

434
        bool addr_is_nonlocal = s->link &&
636✔
435
            !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) &&
10,062✔
436
            in_addr_is_localhost(sa.sa.sa_family, sockaddr_in_addr(&sa.sa)) == 0;
375✔
437

438
        if (addr_is_nonlocal && ifindex != 0) {
9,687✔
439
                /* As a special exception we don't use UNICAST_IF if we notice that the specified IP address
440
                 * is on the local host. Otherwise, destination addresses on the local host result in
441
                 * EHOSTUNREACH, since Linux won't send the packets out of the specified interface, but
442
                 * delivers them directly to the local socket. */
443
                r = socket_set_unicast_if(fd, sa.sa.sa_family, ifindex);
373✔
444
                if (r < 0)
373✔
445
                        return r;
446
        }
447

448
        if (s->protocol == DNS_PROTOCOL_LLMNR) {
9,687✔
449
                /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
450
                r = socket_set_ttl(fd, sa.sa.sa_family, 1);
10✔
451
                if (r < 0)
10✔
452
                        return r;
453
        }
454

455
        if (type == SOCK_DGRAM) {
9,687✔
456
                /* Set IP_RECVERR or IPV6_RECVERR to get ICMP error feedback. See discussion in #10345. */
457
                r = socket_set_recverr(fd, sa.sa.sa_family, true);
9,609✔
458
                if (r < 0)
9,609✔
459
                        return r;
460

461
                r = socket_set_recvpktinfo(fd, sa.sa.sa_family, true);
9,609✔
462
                if (r < 0)
9,609✔
463
                        return r;
464

465
                /* Turn of path MTU discovery for security reasons */
466
                r = socket_disable_pmtud(fd, sa.sa.sa_family);
9,609✔
467
                if (r < 0)
9,609✔
468
                        log_debug_errno(r, "Failed to disable UDP PMTUD, ignoring: %m");
×
469

470
                /* Learn about fragmentation taking place */
471
                r = socket_set_recvfragsize(fd, sa.sa.sa_family, true);
9,609✔
472
                if (r < 0)
9,609✔
473
                        log_debug_errno(r, "Failed to enable fragment size reception, ignoring: %m");
×
474
        }
475

476
        if (ret_socket_address)
9,687✔
477
                *ret_socket_address = sa;
78✔
478
        else {
479
                bool bound = false;
9,609✔
480

481
                /* Let's temporarily bind the socket to the specified ifindex. Older kernels only take
482
                 * the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions
483
                 * in connect() — and not IP_UNICAST_IF. We don't really want any of the other semantics of
484
                 * SO_BINDTODEVICE/SO_BINDTOINDEX, hence we immediately unbind the socket after the fact
485
                 * again.
486
                 */
487
                if (addr_is_nonlocal) {
9,609✔
488
                        r = socket_bind_to_ifindex(fd, ifindex);
354✔
489
                        if (r < 0)
354✔
490
                                return r;
491

492
                        bound = true;
493
                }
494

495
                r = connect(fd, &sa.sa, salen);
9,609✔
496
                if (r < 0 && errno != EINPROGRESS)
9,609✔
497
                        return -errno;
8,882✔
498

499
                if (bound) {
727✔
500
                        r = socket_bind_to_ifindex(fd, 0);
66✔
501
                        if (r < 0)
66✔
502
                                return r;
×
503
                }
504
        }
505

506
        return TAKE_FD(fd);
507
}
508

509
int dns_scope_socket_udp(DnsScope *s, DnsServer *server) {
9,609✔
510
        return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, dns_server_port(server), NULL);
9,609✔
511
}
512

513
int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address) {
78✔
514
        /* If ret_socket_address is not NULL, the caller is responsible
515
         * for calling connect() or sendmsg(). This is required by TCP
516
         * Fast Open, to be able to send the initial SYN packet along
517
         * with the first data packet. */
518
        return dns_scope_socket(s, SOCK_STREAM, family, address, server, port, ret_socket_address);
78✔
519
}
520

521
static DnsScopeMatch match_link_local_reverse_lookups(const char *domain) {
2,959✔
522
        assert(domain);
2,959✔
523

524
        if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0)
2,959✔
525
                return DNS_SCOPE_YES_BASE + 4; /* 4 labels match */
526

527
        if (dns_name_endswith(domain, "8.e.f.ip6.arpa") > 0 ||
5,918✔
528
            dns_name_endswith(domain, "9.e.f.ip6.arpa") > 0 ||
5,918✔
529
            dns_name_endswith(domain, "a.e.f.ip6.arpa") > 0 ||
5,918✔
530
            dns_name_endswith(domain, "b.e.f.ip6.arpa") > 0)
2,959✔
531
                return DNS_SCOPE_YES_BASE + 5; /* 5 labels match */
×
532

533
        return _DNS_SCOPE_MATCH_INVALID;
534
}
535

536
static DnsScopeMatch match_subnet_reverse_lookups(
2,959✔
537
                DnsScope *s,
538
                const char *domain,
539
                bool exclude_own) {
540

541
        union in_addr_union ia;
2,959✔
542
        int f, r;
2,959✔
543

544
        assert(s);
2,959✔
545
        assert(domain);
2,959✔
546

547
        /* Checks whether the specified domain is a reverse address domain (i.e. in the .in-addr.arpa or
548
         * .ip6.arpa area), and if so, whether the address matches any of the local subnets of the link the
549
         * scope is associated with. If so, our scope should consider itself relevant for any lookup in the
550
         * domain, since it apparently refers to hosts on this link's subnet.
551
         *
552
         * If 'exclude_own' is true this will return DNS_SCOPE_NO for any IP addresses assigned locally. This
553
         * is useful for LLMNR/mDNS as we never want to look up our own hostname on LLMNR/mDNS but always use
554
         * the locally synthesized one. */
555

556
        if (!s->link)
2,959✔
557
                return _DNS_SCOPE_MATCH_INVALID; /* No link, hence no local addresses to check */
2,959✔
558

559
        r = dns_name_address(domain, &f, &ia);
1,366✔
560
        if (r < 0)
1,366✔
561
                log_debug_errno(r, "Failed to determine whether '%s' is an address domain: %m", domain);
×
562
        if (r <= 0)
1,366✔
563
                return _DNS_SCOPE_MATCH_INVALID;
564

565
        if (s->family != AF_UNSPEC && f != s->family)
×
566
                return _DNS_SCOPE_MATCH_INVALID; /* Don't look for IPv4 addresses on LLMNR/mDNS over IPv6 and vice versa */
567

568
        if (in_addr_is_null(f, &ia))
×
569
                return DNS_SCOPE_NO;
570

571
        LIST_FOREACH(addresses, a, s->link->addresses) {
×
572

573
                if (a->family != f)
×
574
                        continue;
×
575

576
                /* Equals our own address? nah, let's not use this scope. The local synthesizer will pick it up for us. */
577
                if (exclude_own &&
×
578
                    in_addr_equal(f, &a->in_addr, &ia) > 0)
×
579
                        return DNS_SCOPE_NO;
580

581
                if (a->prefixlen == UCHAR_MAX) /* don't know subnet mask */
×
582
                        continue;
×
583

584
                /* Don't send mDNS queries for the IPv4 broadcast address */
585
                if (f == AF_INET && in_addr_equal(f, &a->in_addr_broadcast, &ia) > 0)
×
586
                        return DNS_SCOPE_NO;
587

588
                /* Check if the address is in the local subnet */
589
                r = in_addr_prefix_covers(f, &a->in_addr, a->prefixlen, &ia);
×
590
                if (r < 0)
×
591
                        log_debug_errno(r, "Failed to determine whether link address covers lookup address '%s': %m", domain);
×
592
                if (r > 0)
×
593
                        /* Note that we only claim zero labels match. This is so that this is at the same
594
                         * priority a DNS scope with "." as routing domain is. */
595
                        return DNS_SCOPE_YES_BASE + 0;
596
        }
597

598
        return _DNS_SCOPE_MATCH_INVALID;
599
}
600

601
/* https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml */
602
/* https://www.iana.org/assignments/locally-served-dns-zones/locally-served-dns-zones.xhtml */
603
static bool dns_refuse_special_use_domain(const char *domain, DnsQuestion *question) {
3,377✔
604
        /* RFC9462 § 6.4: resolvers SHOULD respond to queries of any type other than SVCB for
605
         * _dns.resolver.arpa. with NODATA and queries of any type for any domain name under
606
         * resolver.arpa with NODATA. */
607
        if (dns_name_equal(domain, "_dns.resolver.arpa") > 0) {
3,377✔
608
                DnsResourceKey *t;
×
609

610
                /* Only SVCB is permitted to _dns.resolver.arpa */
611
                DNS_QUESTION_FOREACH(t, question)
×
612
                        if (t->type == DNS_TYPE_SVCB)
×
613
                                return false;
614

615
                return true;
616
        }
617

618
        if (dns_name_endswith(domain, "resolver.arpa") > 0)
3,377✔
619
                return true;
×
620

621
        return false;
622
}
623

624
DnsScopeMatch dns_scope_good_domain(
3,447✔
625
                DnsScope *s,
626
                DnsQuery *q,
627
                uint64_t query_flags) {
628

629
        DnsQuestion *question;
3,447✔
630
        const char *domain;
3,447✔
631
        uint64_t flags;
3,447✔
632
        int ifindex, r;
3,447✔
633

634
        /* This returns the following return values:
635
         *
636
         *    DNS_SCOPE_NO         → This scope is not suitable for lookups of this domain, at all
637
         *    DNS_SCOPE_LAST_RESORT→ This scope is not suitable, unless we have no alternative
638
         *    DNS_SCOPE_MAYBE      → This scope is suitable, but only if nothing else wants it
639
         *    DNS_SCOPE_YES_BASE+n → This scope is suitable, and 'n' suffix labels match
640
         *
641
         *  (The idea is that the caller will only use the scopes with the longest 'n' returned. If no scopes return
642
         *  DNS_SCOPE_YES_BASE+n, then it should use those which returned DNS_SCOPE_MAYBE. It should never use those
643
         *  which returned DNS_SCOPE_NO.)
644
         */
645

646
        assert(s);
3,447✔
647
        assert(q);
3,447✔
648

649
        question = dns_query_question_for_protocol(q, s->protocol);
3,447✔
650
        if (!question)
3,447✔
651
                return DNS_SCOPE_NO;
652

653
        domain = dns_question_first_name(question);
3,447✔
654
        if (!domain)
3,447✔
655
                return DNS_SCOPE_NO;
656

657
        ifindex = q->ifindex;
3,447✔
658
        flags = q->flags;
3,447✔
659

660
        /* Checks if the specified domain is something to look up on this scope. Note that this accepts
661
         * non-qualified hostnames, i.e. those without any search path suffixed. */
662

663
        if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex))
3,447✔
664
                return DNS_SCOPE_NO;
665

666
        if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, false, false) & flags) == 0)
3,429✔
667
                return DNS_SCOPE_NO;
668

669
        /* Never resolve any loopback hostname or IP address via DNS, LLMNR or mDNS. Instead, always rely on
670
         * synthesized RRs for these. */
671
        if (is_localhost(domain) ||
6,830✔
672
            dns_name_endswith(domain, "127.in-addr.arpa") > 0 ||
6,790✔
673
            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)
3,389✔
674
                return DNS_SCOPE_NO;
42✔
675

676
        /* Never respond to some of the domains listed in RFC6303 + RFC6761 */
677
        if (dns_name_dont_resolve(domain))
3,387✔
678
                return DNS_SCOPE_NO;
679

680
        /* Avoid asking invalid questions of some special use domains */
681
        if (dns_refuse_special_use_domain(domain, question))
3,377✔
682
                return DNS_SCOPE_NO;
683

684
        /* Never go to network for the _gateway, _outbound, _localdnsstub, _localdnsproxy domain — they're something special, synthesized locally. */
685
        if (is_gateway_hostname(domain) ||
6,746✔
686
            is_outbound_hostname(domain) ||
6,730✔
687
            is_dns_stub_hostname(domain) ||
6,720✔
688
            is_dns_proxy_stub_hostname(domain))
3,359✔
689
                return DNS_SCOPE_NO;
690

691
        /* Don't look up the local host name via the network, unless user turned of local synthesis of it */
692
        if (manager_is_own_hostname(s->manager, domain) && shall_synthesize_own_hostname_rrs())
3,357✔
693
                return DNS_SCOPE_NO;
694

695
        /* Never send SOA or NS or DNSSEC request to LLMNR, where they make little sense. */
696
        r = dns_question_types_suitable_for_protocol(question, s->protocol);
3,349✔
697
        if (r <= 0)
3,349✔
698
                return DNS_SCOPE_NO;
699

700
        switch (s->protocol) {
3,349✔
701

702
        case DNS_PROTOCOL_DNS: {
2,152✔
703
                bool has_search_domains = false;
2,152✔
704
                DnsScopeMatch m;
2,152✔
705
                int n_best = -1;
2,152✔
706

707
                if (dns_name_is_root(domain)) {
2,152✔
708
                        DnsResourceKey *t;
30✔
709
                        bool found = false;
30✔
710

711
                        /* Refuse root name if only A and/or AAAA records are requested. */
712

713
                        DNS_QUESTION_FOREACH(t, question)
60✔
714
                                if (!IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_AAAA)) {
30✔
715
                                        found = true;
716
                                        break;
717
                                }
718

719
                        if (!found)
30✔
720
                                return DNS_SCOPE_NO;
2,152✔
721
                }
722

723
                /* Never route things to scopes that lack DNS servers */
724
                if (!dns_scope_get_dns_server(s))
2,152✔
725
                        return DNS_SCOPE_NO;
726

727
                /* Route DS requests to the parent */
728
                const char *route_domain = domain;
1,781✔
729
                if (dns_question_contains_key_type(question, DNS_TYPE_DS))
1,781✔
730
                        (void) dns_name_parent(&route_domain);
18✔
731

732
                /* Always honour search domains for routing queries, except if this scope lacks DNS servers. Note that
733
                 * we return DNS_SCOPE_YES here, rather than just DNS_SCOPE_MAYBE, which means other wildcard scopes
734
                 * won't be considered anymore. */
735
                LIST_FOREACH(domains, d, dns_scope_get_search_domains(s)) {
1,820✔
736

737
                        if (!d->route_only && !dns_name_is_root(d->name))
39✔
738
                                has_search_domains = true;
39✔
739

740
                        if (dns_name_endswith(route_domain, d->name) > 0) {
39✔
741
                                int c;
×
742

743
                                c = dns_name_count_labels(d->name);
×
744
                                if (c < 0)
×
745
                                        continue;
×
746

747
                                if (c > n_best)
×
748
                                        n_best = c;
×
749
                        }
750
                }
751

752
                /* If there's a true search domain defined for this scope, and the query is single-label,
753
                 * then let's resolve things here, preferably. Note that LLMNR considers itself
754
                 * authoritative for single-label names too, at the same preference, see below. */
755
                if (has_search_domains && dns_name_is_single_label(domain))
1,781✔
756
                        return DNS_SCOPE_YES_BASE + 1;
757

758
                /* If ResolveUnicastSingleLabel=yes and the query is single-label, then bump match result
759
                   to prevent LLMNR monopoly among candidates. */
760
                if ((s->manager->resolve_unicast_single_label || (query_flags & SD_RESOLVED_RELAX_SINGLE_LABEL)) &&
1,838✔
761
                    dns_name_is_single_label(domain))
58✔
762
                        return DNS_SCOPE_YES_BASE + 1;
763

764
                /* Let's return the number of labels in the best matching result */
765
                if (n_best >= 0) {
1,762✔
766
                        assert(n_best <= DNS_SCOPE_YES_END - DNS_SCOPE_YES_BASE);
×
767
                        return DNS_SCOPE_YES_BASE + n_best;
×
768
                }
769

770
                /* Exclude link-local IP ranges */
771
                if (match_link_local_reverse_lookups(domain) >= DNS_SCOPE_YES_BASE ||
3,524✔
772
                    /* If networks use .local in their private setups, they are supposed to also add .local
773
                     * to their search domains, which we already checked above. Otherwise, we consider .local
774
                     * specific to mDNS and won't send such queries ordinary DNS servers. */
775
                    dns_name_endswith(domain, "local") > 0)
1,762✔
776
                        return DNS_SCOPE_NO;
×
777

778
                /* If the IP address to look up matches the local subnet, then implicitly synthesizes
779
                 * DNS_SCOPE_YES_BASE + 0 on this interface, i.e. preferably resolve IP addresses via the DNS
780
                 * server belonging to this interface. */
781
                m = match_subnet_reverse_lookups(s, domain, false);
1,762✔
782
                if (m >= 0)
1,762✔
783
                        return m;
784

785
                /* If there was no match at all, then see if this scope is suitable as default route. */
786
                if (!dns_scope_is_default_route(s))
1,762✔
787
                        return DNS_SCOPE_NO;
788

789
                /* Prefer suitable per-link scopes where possible */
790
                if (dns_server_is_fallback(dns_scope_get_dns_server(s)))
3,914✔
791
                        return DNS_SCOPE_LAST_RESORT;
1,583✔
792

793
                return DNS_SCOPE_MAYBE;
794
        }
795

796
        case DNS_PROTOCOL_MDNS: {
8✔
797
                DnsScopeMatch m;
8✔
798

799
                m = match_link_local_reverse_lookups(domain);
8✔
800
                if (m >= 0)
8✔
801
                        return m;
802

803
                m = match_subnet_reverse_lookups(s, domain, true);
8✔
804
                if (m >= 0)
8✔
805
                        return m;
806

807
                if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
8✔
808
                    (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0))
8✔
809
                        return DNS_SCOPE_LAST_RESORT;
×
810

811
                if ((dns_name_endswith(domain, "local") > 0 && /* only resolve names ending in .local via mDNS */
8✔
812
                     dns_name_equal(domain, "local") == 0 &&   /* but not the single-label "local" name itself */
×
813
                     manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via mDNS */
×
814
                        return DNS_SCOPE_YES_BASE + 1; /* Return +1, as the top-level .local domain matches, i.e. one label */
×
815

816
                return DNS_SCOPE_NO;
817
        }
818

819
        case DNS_PROTOCOL_LLMNR: {
1,189✔
820
                DnsScopeMatch m;
1,189✔
821

822
                m = match_link_local_reverse_lookups(domain);
1,189✔
823
                if (m >= 0)
1,189✔
824
                        return m;
825

826
                m = match_subnet_reverse_lookups(s, domain, true);
1,189✔
827
                if (m >= 0)
1,189✔
828
                        return m;
829

830
                if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
1,189✔
831
                    (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0))
1,189✔
832
                        return DNS_SCOPE_LAST_RESORT;
×
833

834
                if ((dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */
1,189✔
835
                     dns_name_equal(domain, "local") == 0 && /* don't resolve "local" with LLMNR, it's the top-level domain of mDNS after all, see above */
×
836
                     manager_is_own_hostname(s->manager, domain) <= 0))  /* never resolve the local hostname via LLMNR */
×
837
                        return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
×
838
                                                        * for single-label names, i.e. one label. This is
839
                                                        * particularly relevant as it means a "." route on some
840
                                                        * other scope won't pull all traffic away from
841
                                                        * us. (If people actually want to pull traffic away
842
                                                        * from us they should turn off LLMNR on the
843
                                                        * link). Note that unicast DNS scopes with search
844
                                                        * domains also consider themselves authoritative for
845
                                                        * single-label domains, at the same preference (see
846
                                                        * above). */
847

848
                return DNS_SCOPE_NO;
849
        }
850

851
        default:
×
852
                assert_not_reached();
×
853
        }
854
}
855

856
bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
3,446✔
857
        int key_family;
3,446✔
858

859
        assert(s);
3,446✔
860
        assert(key);
3,446✔
861

862
        /* Check if it makes sense to resolve the specified key on this scope. Note that this call assumes a
863
         * fully qualified name, i.e. the search suffixes already appended. */
864

865
        if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
3,446✔
866
                return false;
867

868
        if (s->protocol == DNS_PROTOCOL_DNS) {
3,446✔
869

870
                /* On classic DNS, looking up non-address RRs is always fine. (Specifically, we want to
871
                 * permit looking up DNSKEY and DS records on the root and top-level domains.) */
872
                if (!dns_resource_key_is_address(key))
3,446✔
873
                        return true;
874

875
                /* Unless explicitly overridden, we refuse to look up A and AAAA RRs on the root and
876
                 * single-label domains, under the assumption that those should be resolved via LLMNR or
877
                 * search path only, and should not be leaked onto the internet. */
878
                const char* name = dns_resource_key_name(key);
3,364✔
879

880
                if (!s->manager->resolve_unicast_single_label &&
6,728✔
881
                    dns_name_is_single_label(name))
3,364✔
882
                        return false;
883

884
                return !dns_name_is_root(name);
3,364✔
885
        }
886

887
        /* Never route DNSSEC RR queries to LLMNR/mDNS scopes */
888
        if (dns_type_is_dnssec(key->type))
×
889
                return false;
890

891
        /* On mDNS and LLMNR, send A and AAAA queries only on the respective scopes */
892

893
        key_family = dns_type_to_af(key->type);
×
894
        if (key_family < 0)
×
895
                return true;
896

897
        return key_family == s->family;
×
898
}
899

900
static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in, struct in6_addr in6) {
1,038✔
901
        int fd;
1,038✔
902

903
        assert(s);
1,038✔
904
        assert(s->link);
1,038✔
905

906
        if (s->family == AF_INET) {
1,038✔
907
                struct ip_mreqn mreqn = {
406✔
908
                        .imr_multiaddr = in,
909
                        .imr_ifindex = s->link->ifindex,
406✔
910
                };
911

912
                if (s->protocol == DNS_PROTOCOL_LLMNR)
406✔
913
                        fd = manager_llmnr_ipv4_udp_fd(s->manager);
355✔
914
                else
915
                        fd = manager_mdns_ipv4_fd(s->manager);
51✔
916

917
                if (fd < 0)
406✔
918
                        return fd;
2✔
919

920
                /* Always first try to drop membership before we add
921
                 * one. This is necessary on some devices, such as
922
                 * veth. */
923
                if (b)
406✔
924
                        (void) setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
204✔
925

926
                if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
406✔
927
                        return -errno;
2✔
928

929
        } else if (s->family == AF_INET6) {
632✔
930
                struct ipv6_mreq mreq = {
632✔
931
                        .ipv6mr_multiaddr = in6,
932
                        .ipv6mr_interface = s->link->ifindex,
632✔
933
                };
934

935
                if (s->protocol == DNS_PROTOCOL_LLMNR)
632✔
936
                        fd = manager_llmnr_ipv6_udp_fd(s->manager);
571✔
937
                else
938
                        fd = manager_mdns_ipv6_fd(s->manager);
61✔
939

940
                if (fd < 0)
632✔
941
                        return fd;
2✔
942

943
                if (b)
632✔
944
                        (void) setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
317✔
945

946
                if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
632✔
947
                        return -errno;
2✔
948
        } else
949
                return -EAFNOSUPPORT;
950

951
        return 0;
952
}
953

954
int dns_scope_llmnr_membership(DnsScope *s, bool b) {
1,625✔
955
        assert(s);
1,625✔
956

957
        if (s->protocol != DNS_PROTOCOL_LLMNR)
1,625✔
958
                return 0;
1,625✔
959

960
        return dns_scope_multicast_membership(s, b, LLMNR_MULTICAST_IPV4_ADDRESS, LLMNR_MULTICAST_IPV6_ADDRESS);
926✔
961
}
962

963
int dns_scope_mdns_membership(DnsScope *s, bool b) {
1,625✔
964
        assert(s);
1,625✔
965

966
        if (s->protocol != DNS_PROTOCOL_MDNS)
1,625✔
967
                return 0;
1,625✔
968

969
        return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS);
112✔
970
}
971

972
int dns_scope_make_reply_packet(
14✔
973
                DnsScope *s,
974
                uint16_t id,
975
                int rcode,
976
                DnsQuestion *q,
977
                DnsAnswer *answer,
978
                DnsAnswer *soa,
979
                bool tentative,
980
                DnsPacket **ret) {
981

982
        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
14✔
983
        unsigned n_answer = 0, n_soa = 0;
14✔
984
        int r;
14✔
985
        bool c_or_aa;
14✔
986

987
        assert(s);
14✔
988
        assert(ret);
14✔
989

990
        if (dns_question_isempty(q) &&
18✔
991
            dns_answer_isempty(answer) &&
4✔
992
            dns_answer_isempty(soa))
×
993
                return -EINVAL;
994

995
        r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
14✔
996
        if (r < 0)
14✔
997
                return r;
998

999
        /* mDNS answers must have the Authoritative Answer bit set, see RFC 6762, section 18.4. */
1000
        c_or_aa = s->protocol == DNS_PROTOCOL_MDNS;
14✔
1001

1002
        DNS_PACKET_HEADER(p)->id = id;
14✔
1003
        DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
52✔
1004
                                                              1 /* qr */,
1005
                                                              0 /* opcode */,
1006
                                                              c_or_aa,
1007
                                                              0 /* tc */,
1008
                                                              tentative,
1009
                                                              0 /* (ra) */,
1010
                                                              0 /* (ad) */,
1011
                                                              0 /* (cd) */,
1012
                                                              rcode));
1013

1014
        r = dns_packet_append_question(p, q);
14✔
1015
        if (r < 0)
14✔
1016
                return r;
1017
        DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));
38✔
1018

1019
        r = dns_packet_append_answer(p, answer, &n_answer);
14✔
1020
        if (r < 0)
14✔
1021
                return r;
1022
        DNS_PACKET_HEADER(p)->ancount = htobe16(n_answer);
28✔
1023

1024
        r = dns_packet_append_answer(p, soa, &n_soa);
14✔
1025
        if (r < 0)
14✔
1026
                return r;
1027
        DNS_PACKET_HEADER(p)->arcount = htobe16(n_soa);
28✔
1028

1029
        *ret = TAKE_PTR(p);
14✔
1030

1031
        return 0;
14✔
1032
}
1033

1034
static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
×
1035
        DnsResourceRecord *rr;
×
1036
        DnsResourceKey *key;
×
1037

1038
        assert(s);
×
1039
        assert(p);
×
1040

1041
        DNS_QUESTION_FOREACH(key, p->question)
×
1042
                dns_zone_verify_conflicts(&s->zone, key);
×
1043

1044
        DNS_ANSWER_FOREACH(rr, p->answer)
×
1045
                dns_zone_verify_conflicts(&s->zone, rr->key);
×
1046
}
×
1047

1048
void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
10✔
1049
        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
10✔
1050
        _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
10✔
1051
        DnsResourceKey *key = NULL;
10✔
1052
        bool tentative = false;
10✔
1053
        int r;
10✔
1054

1055
        assert(s);
10✔
1056
        assert(p);
10✔
1057

1058
        if (p->protocol != DNS_PROTOCOL_LLMNR)
10✔
1059
                return;
1060

1061
        if (p->ipproto == IPPROTO_UDP) {
10✔
1062
                /* Don't accept UDP queries directed to anything but
1063
                 * the LLMNR multicast addresses. See RFC 4795,
1064
                 * section 2.5. */
1065

1066
                if (p->family == AF_INET && !in4_addr_equal(&p->destination.in, &LLMNR_MULTICAST_IPV4_ADDRESS))
×
1067
                        return;
×
1068

1069
                if (p->family == AF_INET6 && !in6_addr_equal(&p->destination.in6, &LLMNR_MULTICAST_IPV6_ADDRESS))
×
1070
                        return;
×
1071
        }
1072

1073
        r = dns_packet_extract(p);
10✔
1074
        if (r < 0) {
10✔
1075
                log_debug_errno(r, "Failed to extract resource records from incoming packet: %m");
×
1076
                return;
×
1077
        }
1078

1079
        if (DNS_PACKET_LLMNR_C(p)) {
20✔
1080
                /* Somebody notified us about a possible conflict */
1081
                dns_scope_verify_conflicts(s, p);
×
1082
                return;
1083
        }
1084

1085
        if (dns_question_size(p->question) != 1)
10✔
1086
                return (void) log_debug("Received LLMNR query without question or multiple questions, ignoring.");
×
1087

1088
        key = dns_question_first_key(p->question);
10✔
1089

1090
        r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
10✔
1091
        if (r < 0) {
10✔
1092
                log_debug_errno(r, "Failed to look up key: %m");
×
1093
                return;
×
1094
        }
1095
        if (r == 0)
10✔
1096
                return;
1097

1098
        if (answer)
10✔
1099
                dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
10✔
1100

1101
        r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
20✔
1102
        if (r < 0) {
10✔
1103
                log_debug_errno(r, "Failed to build reply packet: %m");
×
1104
                return;
×
1105
        }
1106

1107
        if (stream) {
10✔
1108
                r = dns_stream_write_packet(stream, reply);
10✔
1109
                if (r < 0) {
10✔
1110
                        log_debug_errno(r, "Failed to enqueue reply packet: %m");
×
1111
                        return;
×
1112
                }
1113

1114
                /* Let's take an extra reference on this stream, so that it stays around after returning. The reference
1115
                 * will be dangling until the stream is disconnected, and the default completion handler of the stream
1116
                 * will then unref the stream and destroy it */
1117
                if (DNS_STREAM_QUEUED(stream))
10✔
1118
                        dns_stream_ref(stream);
10✔
1119
        } else {
1120
                int fd;
×
1121

1122
                if (!ratelimit_below(&s->ratelimit))
×
1123
                        return;
1124

1125
                if (p->family == AF_INET)
×
1126
                        fd = manager_llmnr_ipv4_udp_fd(s->manager);
×
1127
                else if (p->family == AF_INET6)
×
1128
                        fd = manager_llmnr_ipv6_udp_fd(s->manager);
×
1129
                else {
1130
                        log_debug("Unknown protocol");
×
1131
                        return;
×
1132
                }
1133
                if (fd < 0) {
×
1134
                        log_debug_errno(fd, "Failed to get reply socket: %m");
×
1135
                        return;
×
1136
                }
1137

1138
                /* Note that we always immediately reply to all LLMNR
1139
                 * requests, and do not wait any time, since we
1140
                 * verified uniqueness for all records. Also see RFC
1141
                 * 4795, Section 2.7 */
1142

1143
                r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, NULL, reply);
×
1144
                if (r < 0) {
×
1145
                        log_debug_errno(r, "Failed to send reply packet: %m");
×
1146
                        return;
×
1147
                }
1148
        }
1149
}
1150

1151
DnsTransaction *dns_scope_find_transaction(
4,323✔
1152
                DnsScope *scope,
1153
                DnsResourceKey *key,
1154
                uint64_t query_flags) {
1155

1156
        DnsTransaction *first;
4,323✔
1157

1158
        assert(scope);
4,323✔
1159
        assert(key);
4,323✔
1160

1161
        /* Iterate through the list of transactions with a matching key */
1162
        first = hashmap_get(scope->transactions_by_key, key);
4,323✔
1163
        LIST_FOREACH(transactions_by_key, t, first) {
4,323✔
1164

1165
                /* These four flags must match exactly: we cannot use a validated response for a
1166
                 * non-validating client, and we cannot use a non-validated response for a validating
1167
                 * client. Similar, if the sources don't match things aren't usable either. */
1168
                if (((query_flags ^ t->query_flags) &
337✔
1169
                     (SD_RESOLVED_NO_VALIDATE|
1170
                     SD_RESOLVED_NO_ZONE|
1171
                      SD_RESOLVED_NO_TRUST_ANCHOR|
1172
                      SD_RESOLVED_NO_NETWORK)) != 0)
1173
                        continue;
×
1174

1175
                /* We can reuse a primary query if a regular one is requested, but not vice versa */
1176
                if ((query_flags & SD_RESOLVED_REQUIRE_PRIMARY) &&
337✔
1177
                    !(t->query_flags & SD_RESOLVED_REQUIRE_PRIMARY))
9✔
1178
                        continue;
×
1179

1180
                /* Don't reuse a transaction that allowed caching when we got told not to use it */
1181
                if ((query_flags & SD_RESOLVED_NO_CACHE) &&
337✔
1182
                    !(t->query_flags & SD_RESOLVED_NO_CACHE))
114✔
1183
                        continue;
×
1184

1185
                /* If we are asked to clamp ttls and the existing transaction doesn't do it, we can't
1186
                 * reuse */
1187
                if ((query_flags & SD_RESOLVED_CLAMP_TTL) &&
337✔
1188
                    !(t->query_flags & SD_RESOLVED_CLAMP_TTL))
46✔
1189
                        continue;
×
1190

1191
                return t;
1192
        }
1193

1194
        return NULL;
1195
}
1196

1197
static int dns_scope_make_conflict_packet(
×
1198
                DnsScope *s,
1199
                DnsResourceRecord *rr,
1200
                DnsPacket **ret) {
1201

1202
        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
×
1203
        int r;
×
1204

1205
        assert(s);
×
1206
        assert(rr);
×
1207
        assert(ret);
×
1208

1209
        r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
×
1210
        if (r < 0)
×
1211
                return r;
1212

1213
        DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
×
1214
                                                              0 /* qr */,
1215
                                                              0 /* opcode */,
1216
                                                              1 /* conflict */,
1217
                                                              0 /* tc */,
1218
                                                              0 /* t */,
1219
                                                              0 /* (ra) */,
1220
                                                              0 /* (ad) */,
1221
                                                              0 /* (cd) */,
1222
                                                              0));
1223

1224
        /* For mDNS, the transaction ID should always be 0 */
1225
        if (s->protocol != DNS_PROTOCOL_MDNS)
×
1226
                random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
×
1227

1228
        DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
×
1229
        DNS_PACKET_HEADER(p)->arcount = htobe16(1);
×
1230

1231
        r = dns_packet_append_key(p, rr->key, 0, NULL);
×
1232
        if (r < 0)
×
1233
                return r;
1234

1235
        r = dns_packet_append_rr(p, rr, 0, NULL, NULL);
×
1236
        if (r < 0)
×
1237
                return r;
1238

1239
        *ret = TAKE_PTR(p);
×
1240

1241
        return 0;
×
1242
}
1243

1244
static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
×
1245
        DnsScope *scope = ASSERT_PTR(userdata);
×
1246
        int r;
×
1247

1248
        assert(es);
×
1249

1250
        scope->conflict_event_source = sd_event_source_disable_unref(scope->conflict_event_source);
×
1251

1252
        for (;;) {
×
1253
                _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
×
1254
                _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
×
1255
                _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
×
1256

1257
                rr = ordered_hashmap_steal_first_key_and_value(scope->conflict_queue, (void**) &key);
×
1258
                if (!rr)
×
1259
                        break;
1260

1261
                r = dns_scope_make_conflict_packet(scope, rr, &p);
×
1262
                if (r < 0) {
×
1263
                        log_error_errno(r, "Failed to make conflict packet: %m");
×
1264
                        return 0;
×
1265
                }
1266

1267
                r = dns_scope_emit_udp(scope, -1, AF_UNSPEC, p);
×
1268
                if (r < 0)
×
1269
                        log_debug_errno(r, "Failed to send conflict packet: %m");
×
1270
        }
1271

1272
        return 0;
×
1273
}
1274

1275
int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
×
1276
        int r;
×
1277

1278
        assert(scope);
×
1279
        assert(rr);
×
1280

1281
        /* We don't send these queries immediately. Instead, we queue them, and send them after some jitter
1282
         * delay.  We only place one RR per key in the conflict messages, not all of them. That should be
1283
         * enough to indicate where there might be a conflict */
1284
        r = ordered_hashmap_ensure_put(&scope->conflict_queue, &dns_resource_record_hash_ops_by_key, rr->key, rr);
×
1285
        if (IN_SET(r, 0, -EEXIST))
×
1286
                return 0;
1287
        if (r < 0)
×
1288
                return log_debug_errno(r, "Failed to queue conflicting RR: %m");
×
1289

1290
        dns_resource_key_ref(rr->key);
×
1291
        dns_resource_record_ref(rr);
×
1292

1293
        if (scope->conflict_event_source)
×
1294
                return 0;
1295

1296
        r = sd_event_add_time_relative(
×
1297
                        scope->manager->event,
×
1298
                        &scope->conflict_event_source,
1299
                        CLOCK_BOOTTIME,
1300
                        random_u64_range(LLMNR_JITTER_INTERVAL_USEC),
1301
                        0,
1302
                        on_conflict_dispatch, scope);
1303
        if (r < 0)
×
1304
                return log_debug_errno(r, "Failed to add conflict dispatch event: %m");
×
1305

1306
        (void) sd_event_source_set_description(scope->conflict_event_source, "scope-conflict");
×
1307

1308
        return 0;
×
1309
}
1310

1311
void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
10✔
1312
        DnsResourceRecord *rr;
10✔
1313
        int r;
10✔
1314

1315
        assert(scope);
10✔
1316
        assert(p);
10✔
1317

1318
        if (!IN_SET(p->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS))
10✔
1319
                return;
1320

1321
        if (DNS_PACKET_RRCOUNT(p) <= 0)
10✔
1322
                return;
1323

1324
        if (p->protocol == DNS_PROTOCOL_LLMNR) {
10✔
1325
                if (DNS_PACKET_LLMNR_C(p) != 0)
20✔
1326
                        return;
1327

1328
                if (DNS_PACKET_LLMNR_T(p) != 0)
20✔
1329
                        return;
1330
        }
1331

1332
        if (manager_packet_from_local_address(scope->manager, p))
10✔
1333
                return;
1334

1335
        r = dns_packet_extract(p);
×
1336
        if (r < 0) {
×
1337
                log_debug_errno(r, "Failed to extract packet: %m");
×
1338
                return;
×
1339
        }
1340

1341
        log_debug("Checking for conflicts...");
×
1342

1343
        DNS_ANSWER_FOREACH(rr, p->answer) {
×
1344
                /* No conflict if it is DNS-SD RR used for service enumeration. */
1345
                if (dns_resource_key_is_dnssd_ptr(rr->key))
×
1346
                        continue;
×
1347

1348
                /* Check for conflicts against the local zone. If we
1349
                 * found one, we won't check any further */
1350
                r = dns_zone_check_conflicts(&scope->zone, rr);
×
1351
                if (r != 0)
×
1352
                        continue;
×
1353

1354
                /* Check for conflicts against the local cache. If so,
1355
                 * send out an advisory query, to inform everybody */
1356
                r = dns_cache_check_conflicts(&scope->cache, rr, p->family, &p->sender);
×
1357
                if (r <= 0)
×
1358
                        continue;
×
1359

1360
                dns_scope_notify_conflict(scope, rr);
×
1361
        }
1362
}
1363

1364
void dns_scope_dump(DnsScope *s, FILE *f) {
×
1365
        assert(s);
×
1366

1367
        if (!f)
×
1368
                f = stdout;
×
1369

1370
        fputs("[Scope protocol=", f);
×
1371
        fputs(dns_protocol_to_string(s->protocol), f);
×
1372

1373
        if (s->link) {
×
1374
                fputs(" interface=", f);
×
1375
                fputs(s->link->ifname, f);
×
1376
        }
1377

1378
        if (s->family != AF_UNSPEC) {
×
1379
                fputs(" family=", f);
×
1380
                fputs(af_to_name(s->family), f);
×
1381
        }
1382

1383
        fputs("]\n", f);
×
1384

1385
        if (!dns_zone_is_empty(&s->zone)) {
×
1386
                fputs("ZONE:\n", f);
×
1387
                dns_zone_dump(&s->zone, f);
×
1388
        }
1389

1390
        if (!dns_cache_is_empty(&s->cache)) {
×
1391
                fputs("CACHE:\n", f);
×
1392
                dns_cache_dump(&s->cache, f);
×
1393
        }
1394
}
×
1395

1396
DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
1,782✔
1397
        assert(s);
1,782✔
1398

1399
        if (s->protocol != DNS_PROTOCOL_DNS)
1,782✔
1400
                return NULL;
1401

1402
        if (s->link)
1,782✔
1403
                return s->link->search_domains;
187✔
1404

1405
        return s->manager->search_domains;
1,595✔
1406
}
1407

1408
bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name) {
1,650✔
1409
        assert(s);
1,650✔
1410

1411
        if (s->protocol != DNS_PROTOCOL_DNS)
1,650✔
1412
                return false;
1413

1414
        if (!dns_name_is_single_label(name))
1,650✔
1415
                return false;
1416

1417
        /* If we allow single-label domain lookups on unicast DNS, and this scope has a search domain that matches
1418
         * _exactly_ this name, then do not use search domains. */
1419
        if (s->manager->resolve_unicast_single_label)
1✔
1420
                LIST_FOREACH(domains, d, dns_scope_get_search_domains(s))
×
1421
                        if (dns_name_equal(name, d->name) > 0)
×
1422
                                return false;
1423

1424
        return true;
1425
}
1426

1427
bool dns_scope_network_good(DnsScope *s) {
15,114✔
1428
        /* Checks whether the network is in good state for lookups on this scope. For mDNS/LLMNR/Classic DNS scopes
1429
         * bound to links this is easy, as they don't even exist if the link isn't in a suitable state. For the global
1430
         * DNS scope we check whether there are any links that are up and have an address.
1431
         *
1432
         * Note that Linux routing is complex and even systems that superficially have no IPv4 address might
1433
         * be able to route IPv4 (and similar for IPv6), hence let's make a check here independent of address
1434
         * family. */
1435

1436
        if (s->link)
15,114✔
1437
                return true;
1438

1439
        return manager_routable(s->manager);
12,076✔
1440
}
1441

1442
int dns_scope_ifindex(DnsScope *s) {
10,031✔
1443
        assert(s);
10,031✔
1444

1445
        if (s->link)
10,031✔
1446
                return s->link->ifindex;
945✔
1447

1448
        return 0;
1449
}
1450

1451
const char* dns_scope_ifname(DnsScope *s) {
6✔
1452
        assert(s);
6✔
1453

1454
        if (s->link)
6✔
1455
                return s->link->ifname;
3✔
1456

1457
        return NULL;
1458
}
1459

1460
static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userdata) {
×
1461
        DnsScope *scope = userdata;
×
1462

1463
        assert(s);
×
1464

1465
        scope->announce_event_source = sd_event_source_disable_unref(scope->announce_event_source);
×
1466

1467
        (void) dns_scope_announce(scope, false);
×
1468
        return 0;
×
1469
}
1470

1471
int dns_scope_announce(DnsScope *scope, bool goodbye) {
2,468✔
1472
        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
2,468✔
1473
        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
2,468✔
1474
        _cleanup_set_free_ Set *types = NULL;
×
1475
        DnsZoneItem *z;
2,468✔
1476
        unsigned size = 0;
2,468✔
1477
        char *service_type;
2,468✔
1478
        int r;
2,468✔
1479

1480
        if (!scope)
2,468✔
1481
                return 0;
1482

1483
        if (scope->protocol != DNS_PROTOCOL_MDNS)
4✔
1484
                return 0;
1485

1486
        r = sd_event_get_state(scope->manager->event);
4✔
1487
        if (r < 0)
4✔
1488
                return log_debug_errno(r, "Failed to get event loop state: %m");
×
1489

1490
        /* If this is called on exit, through manager_free() -> link_free(), then we cannot announce. */
1491
        if (r == SD_EVENT_FINISHED)
4✔
1492
                return 0;
1493

1494
        /* Check if we're done with probing. */
1495
        LIST_FOREACH(transactions_by_scope, t, scope->transactions)
8✔
1496
                if (t->probing && DNS_TRANSACTION_IS_LIVE(t->state))
2,472✔
1497
                        return 0;
1498

1499
        /* Check if there're services pending conflict resolution. */
1500
        if (manager_next_dnssd_names(scope->manager))
4✔
1501
                return 0; /* we reach this point only if changing hostname didn't help */
1502

1503
        /* Calculate answer's size. */
1504
        HASHMAP_FOREACH(z, scope->zone.by_key) {
12✔
1505
                if (z->state != DNS_ZONE_ITEM_ESTABLISHED)
8✔
1506
                        continue;
×
1507

1508
                if (z->rr->key->type == DNS_TYPE_PTR &&
12✔
1509
                    !dns_zone_contains_name(&scope->zone, z->rr->ptr.name)) {
4✔
1510
                        char key_str[DNS_RESOURCE_KEY_STRING_MAX];
×
1511

1512
                        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));
×
1513
                        z->state = DNS_ZONE_ITEM_WITHDRAWN;
×
1514
                        continue;
×
1515
                }
1516

1517
                /* Collect service types for _services._dns-sd._udp.local RRs in a set. Only two-label names
1518
                 * (not selective names) are considered according to RFC6763 § 9. */
1519
                if (!scope->announced &&
16✔
1520
                    dns_resource_key_is_dnssd_two_label_ptr(z->rr->key)) {
8✔
1521
                        if (!set_contains(types, dns_resource_key_name(z->rr->key))) {
×
1522
                                r = set_ensure_put(&types, &dns_name_hash_ops, dns_resource_key_name(z->rr->key));
×
1523
                                if (r < 0)
×
1524
                                        return log_debug_errno(r, "Failed to add item to set: %m");
×
1525
                        }
1526
                }
1527

1528
                LIST_FOREACH(by_key, i, z)
16✔
1529
                        size++;
8✔
1530
        }
1531

1532
        answer = dns_answer_new(size + set_size(types));
4✔
1533
        if (!answer)
4✔
1534
                return log_oom();
×
1535

1536
        /* Second iteration, actually add RRs to the answer. */
1537
        HASHMAP_FOREACH(z, scope->zone.by_key)
12✔
1538
                LIST_FOREACH (by_key, i, z) {
16✔
1539
                        DnsAnswerFlags flags;
8✔
1540

1541
                        if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
8✔
1542
                                continue;
×
1543

1544
                        if (dns_resource_key_is_dnssd_ptr(i->rr->key))
8✔
1545
                                flags = goodbye ? DNS_ANSWER_GOODBYE : 0;
×
1546
                        else
1547
                                flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH;
8✔
1548

1549
                        r = dns_answer_add(answer, i->rr, 0, flags, NULL);
8✔
1550
                        if (r < 0)
8✔
1551
                                return log_debug_errno(r, "Failed to add RR to announce: %m");
×
1552
                }
1553

1554
        /* Since all the active services are in the zone make them discoverable now. */
1555
        SET_FOREACH(service_type, types) {
4✔
1556
                _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
×
1557

1558
                rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR,
×
1559
                                                  "_services._dns-sd._udp.local");
1560
                if (!rr)
×
1561
                        return log_oom();
×
1562

1563
                rr->ptr.name = strdup(service_type);
×
1564
                if (!rr->ptr.name)
×
1565
                        return log_oom();
×
1566

1567
                rr->ttl = MDNS_DEFAULT_TTL;
×
1568

1569
                r = dns_zone_put(&scope->zone, scope, rr, false);
×
1570
                if (r < 0)
×
1571
                        log_warning_errno(r, "Failed to add DNS-SD PTR record to MDNS zone, ignoring: %m");
×
1572

1573
                r = dns_answer_add(answer, rr, 0, 0, NULL);
×
1574
                if (r < 0)
×
1575
                        return log_debug_errno(r, "Failed to add RR to announce: %m");
×
1576
        }
1577

1578
        if (dns_answer_isempty(answer))
4✔
1579
                return 0;
1580

1581
        r = dns_scope_make_reply_packet(scope, 0, DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &p);
4✔
1582
        if (r < 0)
4✔
1583
                return log_debug_errno(r, "Failed to build reply packet: %m");
×
1584

1585
        r = dns_scope_emit_udp(scope, -1, AF_UNSPEC, p);
4✔
1586
        if (r < 0)
4✔
1587
                return log_debug_errno(r, "Failed to send reply packet: %m");
×
1588

1589
        /* In section 8.3 of RFC6762: "The Multicast DNS responder MUST send at least two unsolicited
1590
         * responses, one second apart." */
1591
        if (!scope->announced) {
4✔
1592
                scope->announced = true;
4✔
1593

1594
                r = sd_event_add_time_relative(
8✔
1595
                                scope->manager->event,
4✔
1596
                                &scope->announce_event_source,
1597
                                CLOCK_BOOTTIME,
1598
                                MDNS_ANNOUNCE_DELAY,
1599
                                0,
1600
                                on_announcement_timeout, scope);
1601
                if (r < 0)
4✔
1602
                        return log_debug_errno(r, "Failed to schedule second announcement: %m");
×
1603

1604
                (void) sd_event_source_set_description(scope->announce_event_source, "mdns-announce");
4✔
1605
        }
1606

1607
        return 0;
1608
}
1609

1610
int dns_scope_add_dnssd_services(DnsScope *scope) {
331✔
1611
        DnssdService *service;
331✔
1612
        int r;
331✔
1613

1614
        assert(scope);
331✔
1615

1616
        if (hashmap_isempty(scope->manager->dnssd_services))
331✔
1617
                return 0;
331✔
1618

1619
        scope->announced = false;
×
1620

1621
        HASHMAP_FOREACH(service, scope->manager->dnssd_services) {
×
1622
                service->withdrawn = false;
×
1623

1624
                r = dns_zone_put(&scope->zone, scope, service->ptr_rr, false);
×
1625
                if (r < 0)
×
1626
                        log_warning_errno(r, "Failed to add PTR record to MDNS zone: %m");
×
1627

1628
                if (service->sub_ptr_rr) {
×
1629
                        r = dns_zone_put(&scope->zone, scope, service->sub_ptr_rr, false);
×
1630
                        if (r < 0)
×
1631
                                log_warning_errno(r, "Failed to add selective PTR record to MDNS zone: %m");
×
1632
                }
1633

1634
                r = dns_zone_put(&scope->zone, scope, service->srv_rr, true);
×
1635
                if (r < 0)
×
1636
                        log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m");
×
1637

1638
                LIST_FOREACH(items, txt_data, service->txt_data_items) {
×
1639
                        r = dns_zone_put(&scope->zone, scope, txt_data->rr, true);
×
1640
                        if (r < 0)
×
1641
                                log_warning_errno(r, "Failed to add TXT record to MDNS zone: %m");
×
1642
                }
1643
        }
1644

1645
        return 0;
×
1646
}
1647

1648
int dns_scope_remove_dnssd_services(DnsScope *scope) {
×
1649
        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
×
1650
        DnssdService *service;
×
1651
        int r;
×
1652

1653
        assert(scope);
×
1654

1655
        key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_PTR,
×
1656
                                   "_services._dns-sd._udp.local");
1657
        if (!key)
×
1658
                return log_oom();
×
1659

1660
        r = dns_zone_remove_rrs_by_key(&scope->zone, key);
×
1661
        if (r < 0)
×
1662
                return r;
1663

1664
        HASHMAP_FOREACH(service, scope->manager->dnssd_services) {
×
1665
                dns_zone_remove_rr(&scope->zone, service->ptr_rr);
×
1666
                dns_zone_remove_rr(&scope->zone, service->sub_ptr_rr);
×
1667
                dns_zone_remove_rr(&scope->zone, service->srv_rr);
×
1668
                LIST_FOREACH(items, txt_data, service->txt_data_items)
×
1669
                        dns_zone_remove_rr(&scope->zone, txt_data->rr);
×
1670
        }
1671

1672
        return 0;
×
1673
}
1674

1675
static bool dns_scope_has_route_only_domains(DnsScope *scope) {
717✔
1676
        DnsSearchDomain *first;
717✔
1677
        bool route_only = false;
717✔
1678

1679
        assert(scope);
717✔
1680
        assert(scope->protocol == DNS_PROTOCOL_DNS);
717✔
1681

1682
        /* Returns 'true' if this scope is suitable for queries to specific domains only. For that we check
1683
         * if there are any route-only domains on this interface, as a heuristic to discern VPN-style links
1684
         * from non-VPN-style links. Returns 'false' for all other cases, i.e. if the scope is intended to
1685
         * take queries to arbitrary domains, i.e. has no routing domains set. */
1686

1687
        if (scope->link)
717✔
1688
                first = scope->link->search_domains;
717✔
1689
        else
1690
                first = scope->manager->search_domains;
×
1691

1692
        LIST_FOREACH(domains, domain, first) {
922✔
1693
                /* "." means "any domain", thus the interface takes any kind of traffic. Thus, we exit early
1694
                 * here, as it doesn't really matter whether this link has any route-only domains or not,
1695
                 * "~."  really trumps everything and clearly indicates that this interface shall receive all
1696
                 * traffic it can get. */
1697
                if (dns_name_is_root(DNS_SEARCH_DOMAIN_NAME(domain)))
210✔
1698
                        return false;
1699

1700
                if (domain->route_only)
205✔
1701
                        route_only = true;
26✔
1702
        }
1703

1704
        return route_only;
1705
}
1706

1707
bool dns_scope_is_default_route(DnsScope *scope) {
54,315✔
1708
        assert(scope);
54,315✔
1709

1710
        /* Only use DNS scopes as default routes */
1711
        if (scope->protocol != DNS_PROTOCOL_DNS)
54,315✔
1712
                return false;
1713

1714
        /* The global DNS scope is always suitable as default route */
1715
        if (!scope->link)
54,315✔
1716
                return true;
1717

1718
        /* Honour whatever is explicitly configured. This is really the best approach, and trumps any
1719
         * automatic logic. */
1720
        if (scope->link->default_route >= 0)
717✔
1721
                return scope->link->default_route;
×
1722

1723
        /* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not
1724
         * volunteer as default route. */
1725
        return !dns_scope_has_route_only_domains(scope);
717✔
1726
}
1727

1728
int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret) {
6✔
1729
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *cache = NULL;
6✔
1730
        int r;
6✔
1731

1732
        assert(scope);
6✔
1733
        assert(ret);
6✔
1734

1735
        r = dns_cache_dump_to_json(&scope->cache, &cache);
6✔
1736
        if (r < 0)
6✔
1737
                return r;
1738

1739
        return sd_json_buildo(
6✔
1740
                        ret,
1741
                        SD_JSON_BUILD_PAIR_STRING("protocol", dns_protocol_to_string(scope->protocol)),
1742
                        SD_JSON_BUILD_PAIR_CONDITION(scope->family != AF_UNSPEC, "family", SD_JSON_BUILD_INTEGER(scope->family)),
1743
                        SD_JSON_BUILD_PAIR_CONDITION(!!scope->link, "ifindex", SD_JSON_BUILD_INTEGER(dns_scope_ifindex(scope))),
1744
                        SD_JSON_BUILD_PAIR_CONDITION(!!scope->link, "ifname", SD_JSON_BUILD_STRING(dns_scope_ifname(scope))),
1745
                        SD_JSON_BUILD_PAIR_VARIANT("cache", cache));
1746
}
1747

1748
int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol) {
3,349✔
1749

1750
        /* Tests whether it makes sense to route queries for the specified DNS RR types to the specified
1751
         * protocol. For classic DNS pretty much all RR types are suitable, but for LLMNR/mDNS let's
1752
         * allowlist only a few that make sense. We use this when routing queries so that we can more quickly
1753
         * return errors for queries that will almost certainly fail/time out otherwise. For example, this
1754
         * ensures that SOA, NS, or DS/DNSKEY queries are never routed to mDNS/LLMNR where they simply make
1755
         * no sense. */
1756

1757
        if (dns_type_is_obsolete(type))
3,349✔
1758
                return false;
1759

1760
        if (!dns_type_is_valid_query(type))
3,349✔
1761
                return false;
1762

1763
        switch (protocol) {
3,349✔
1764

1765
        case DNS_PROTOCOL_DNS:
1766
                return true;
1767

1768
        case DNS_PROTOCOL_LLMNR:
1,189✔
1769
                return IN_SET(type,
1,189✔
1770
                              DNS_TYPE_ANY,
1771
                              DNS_TYPE_A,
1772
                              DNS_TYPE_AAAA,
1773
                              DNS_TYPE_CNAME,
1774
                              DNS_TYPE_PTR,
1775
                              DNS_TYPE_TXT);
1776

1777
        case DNS_PROTOCOL_MDNS:
8✔
1778
                return IN_SET(type,
8✔
1779
                              DNS_TYPE_ANY,
1780
                              DNS_TYPE_A,
1781
                              DNS_TYPE_AAAA,
1782
                              DNS_TYPE_CNAME,
1783
                              DNS_TYPE_PTR,
1784
                              DNS_TYPE_TXT,
1785
                              DNS_TYPE_SRV,
1786
                              DNS_TYPE_NSEC,
1787
                              DNS_TYPE_HINFO);
1788

1789
        default:
×
1790
                return -EPROTONOSUPPORT;
×
1791
        }
1792
}
1793

1794
int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol) {
3,349✔
1795
        DnsResourceKey *key;
3,349✔
1796
        int r;
3,349✔
1797

1798
        /* Tests whether the types in the specified question make any sense to be routed to the specified
1799
         * protocol, i.e. if dns_type_suitable_for_protocol() is true for any of the contained RR types */
1800

1801
        DNS_QUESTION_FOREACH(key, q) {
6,698✔
1802
                r = dns_type_suitable_for_protocol(key->type, protocol);
3,349✔
1803
                if (r != 0)
3,349✔
1804
                        return r;
1805
        }
1806

1807
        return false;
1808
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc