1:255.13-alt1
[systemd_ALT.git] / src / resolve / resolved-dns-synthesize.c
blob6144dc01733cb3bdfb2f487a715755c9112c655b
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "env-util.h"
5 #include "hostname-util.h"
6 #include "local-addresses.h"
7 #include "missing_network.h"
8 #include "resolved-dns-synthesize.h"
10 int dns_synthesize_family(uint64_t flags) {
12 /* Picks an address family depending on set flags. This is
13 * purely for synthesized answers, where the family we return
14 * for the reply should match what was requested in the
15 * question, even though we are synthesizing the answer
16 * here. */
18 if (!(flags & SD_RESOLVED_DNS)) {
19 if (flags & (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_MDNS_IPV4))
20 return AF_INET;
21 if (flags & (SD_RESOLVED_LLMNR_IPV6|SD_RESOLVED_MDNS_IPV6))
22 return AF_INET6;
25 return AF_UNSPEC;
28 DnsProtocol dns_synthesize_protocol(uint64_t flags) {
30 /* Similar as dns_synthesize_family() but does this for the
31 * protocol. If resolving via DNS was requested, we claim it
32 * was DNS. Similar, if nothing specific was
33 * requested. However, if only resolving via LLMNR was
34 * requested we return that. */
36 if (flags & SD_RESOLVED_DNS)
37 return DNS_PROTOCOL_DNS;
38 if (flags & SD_RESOLVED_LLMNR)
39 return DNS_PROTOCOL_LLMNR;
40 if (flags & SD_RESOLVED_MDNS)
41 return DNS_PROTOCOL_MDNS;
43 return DNS_PROTOCOL_DNS;
46 static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, DnsAnswer **answer) {
47 int r;
49 assert(m);
50 assert(key);
51 assert(answer);
53 r = dns_answer_reserve(answer, 2);
54 if (r < 0)
55 return r;
57 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
58 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
60 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
61 if (!rr)
62 return -ENOMEM;
64 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
66 r = dns_answer_add(*answer, rr, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED, NULL);
67 if (r < 0)
68 return r;
71 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY) && socket_ipv6_is_enabled()) {
72 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
74 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key));
75 if (!rr)
76 return -ENOMEM;
78 rr->aaaa.in6_addr = in6addr_loopback;
80 r = dns_answer_add(*answer, rr, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED, NULL);
81 if (r < 0)
82 return r;
85 return 0;
88 static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
89 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
91 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
92 if (!rr)
93 return -ENOMEM;
95 rr->ptr.name = strdup(to);
96 if (!rr->ptr.name)
97 return -ENOMEM;
99 return dns_answer_add(*answer, rr, ifindex, flags, NULL);
102 static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, DnsAnswer **answer) {
103 int r;
105 assert(m);
106 assert(key);
107 assert(answer);
109 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
110 r = dns_answer_reserve(answer, 1);
111 if (r < 0)
112 return r;
114 r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
115 if (r < 0)
116 return r;
119 return 0;
122 static int answer_add_addresses_rr(
123 DnsAnswer **answer,
124 const char *name,
125 struct local_address *addresses,
126 unsigned n_addresses) {
128 unsigned j;
129 int r;
131 assert(answer);
132 assert(name);
134 r = dns_answer_reserve(answer, n_addresses);
135 if (r < 0)
136 return r;
138 for (j = 0; j < n_addresses; j++) {
139 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
141 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
142 if (r < 0)
143 return r;
145 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
146 if (r < 0)
147 return r;
150 return 0;
153 static int answer_add_addresses_ptr(
154 DnsAnswer **answer,
155 const char *name,
156 struct local_address *addresses,
157 unsigned n_addresses,
158 int af, const union in_addr_union *match) {
160 bool added = false;
161 unsigned j;
162 int r;
164 assert(answer);
165 assert(name);
167 for (j = 0; j < n_addresses; j++) {
168 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
170 if (af != AF_UNSPEC) {
172 if (addresses[j].family != af)
173 continue;
175 if (match && !in_addr_equal(af, match, &addresses[j].address))
176 continue;
179 r = dns_answer_reserve(answer, 1);
180 if (r < 0)
181 return r;
183 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
184 if (r < 0)
185 return r;
187 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
188 if (r < 0)
189 return r;
191 added = true;
194 return added;
197 static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
198 _cleanup_free_ struct local_address *addresses = NULL;
199 int n = 0, af;
201 assert(m);
202 assert(key);
203 assert(answer);
205 af = dns_type_to_af(key->type);
206 if (af >= 0) {
207 n = local_addresses(m->rtnl, ifindex, af, &addresses);
208 if (n < 0)
209 return n;
211 if (n == 0) {
212 struct local_address buffer[2];
214 /* If we have no local addresses then use ::1 and 127.0.0.2 as local ones. */
216 if (IN_SET(af, AF_INET, AF_UNSPEC))
217 buffer[n++] = (struct local_address) {
218 .family = AF_INET,
219 .ifindex = LOOPBACK_IFINDEX,
220 .address.in.s_addr = htobe32(INADDR_LOCALADDRESS),
223 if (IN_SET(af, AF_INET6, AF_UNSPEC) && socket_ipv6_is_enabled())
224 buffer[n++] = (struct local_address) {
225 .family = AF_INET6,
226 .ifindex = LOOPBACK_IFINDEX,
227 .address.in6 = in6addr_loopback,
230 return answer_add_addresses_rr(answer,
231 dns_resource_key_name(key),
232 buffer, n);
236 return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
239 static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
240 _cleanup_free_ struct local_address *addresses = NULL;
241 bool added = false;
242 int n, r;
244 assert(m);
245 assert(address);
246 assert(answer);
248 if (af == AF_INET && address->in.s_addr == htobe32(INADDR_LOCALADDRESS)) {
250 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
252 r = dns_answer_reserve(answer, 4);
253 if (r < 0)
254 return r;
256 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
257 if (r < 0)
258 return r;
260 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
261 if (r < 0)
262 return r;
264 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
265 if (r < 0)
266 return r;
268 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
269 if (r < 0)
270 return r;
272 return 1;
275 n = local_addresses(m->rtnl, ifindex, af, &addresses);
276 if (n <= 0)
277 return n;
279 r = answer_add_addresses_ptr(answer, m->full_hostname, addresses, n, af, address);
280 if (r < 0)
281 return r;
282 if (r > 0)
283 added = true;
285 r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address);
286 if (r < 0)
287 return r;
288 if (r > 0)
289 added = true;
291 r = answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
292 if (r < 0)
293 return r;
294 if (r > 0)
295 added = true;
297 return added;
300 static int synthesize_gateway_rr(
301 Manager *m,
302 const DnsResourceKey *key,
303 int ifindex,
304 int (*lookup)(sd_netlink *context, int ifindex, int af, struct local_address **ret), /* either local_gateways() or local_outbound() */
305 DnsAnswer **answer) {
306 _cleanup_free_ struct local_address *addresses = NULL;
307 int n = 0, af, r;
309 assert(m);
310 assert(key);
311 assert(lookup);
312 assert(answer);
314 af = dns_type_to_af(key->type);
315 if (af >= 0) {
316 n = lookup(m->rtnl, ifindex, af, &addresses);
317 if (n < 0) /* < 0 means: error */
318 return n;
320 if (n == 0) { /* == 0 means we have no gateway */
321 /* See if there's a gateway on the other protocol */
322 if (af == AF_INET)
323 n = lookup(m->rtnl, ifindex, AF_INET6, NULL);
324 else {
325 assert(af == AF_INET6);
326 n = lookup(m->rtnl, ifindex, AF_INET, NULL);
328 if (n <= 0) /* error (if < 0) or really no gateway at all (if == 0) */
329 return n;
331 /* We have a gateway on the other protocol. Let's return > 0 without adding any RR to
332 * the answer, i.e. synthesize NODATA (and not NXDOMAIN!) */
333 return 1;
337 r = answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
338 if (r < 0)
339 return r;
341 return 1; /* > 0 means: we have some gateway */
344 static int synthesize_dns_stub_rr(
345 Manager *m,
346 const DnsResourceKey *key,
347 in_addr_t addr,
348 DnsAnswer **answer) {
350 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
351 int r;
353 assert(m);
354 assert(key);
355 assert(answer);
357 if (!IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY))
358 return 1; /* we still consider ourselves the owner of this name */
360 r = dns_answer_reserve(answer, 1);
361 if (r < 0)
362 return r;
364 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
365 if (!rr)
366 return -ENOMEM;
368 rr->a.in_addr.s_addr = htobe32(addr);
370 r = dns_answer_add(*answer, rr, LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED, NULL);
371 if (r < 0)
372 return r;
374 return 1;
377 static int synthesize_dns_stub_ptr(
378 Manager *m,
379 int af,
380 const union in_addr_union *address,
381 DnsAnswer **answer) {
383 int r;
385 assert(m);
386 assert(address);
387 assert(answer);
389 if (af != AF_INET)
390 return 0;
392 if (address->in.s_addr == htobe32(INADDR_DNS_STUB)) {
394 r = dns_answer_reserve(answer, 1);
395 if (r < 0)
396 return r;
398 r = answer_add_ptr(answer, "53.0.0.127.in-addr.arpa", "_localdnsstub", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
399 if (r < 0)
400 return r;
402 return 1;
405 if (address->in.s_addr == htobe32(INADDR_DNS_PROXY_STUB)) {
407 r = dns_answer_reserve(answer, 1);
408 if (r < 0)
409 return r;
411 r = answer_add_ptr(answer, "54.0.0.127.in-addr.arpa", "_localdnsproxy", LOOPBACK_IFINDEX, DNS_ANSWER_AUTHENTICATED);
412 if (r < 0)
413 return r;
415 return 1;
418 return 0;
421 static int synthesize_gateway_ptr(
422 Manager *m,
423 int af,
424 const union in_addr_union *address,
425 int ifindex,
426 DnsAnswer **answer) {
428 _cleanup_free_ struct local_address *addresses = NULL;
429 int n;
431 assert(m);
432 assert(address);
433 assert(answer);
435 n = local_gateways(m->rtnl, ifindex, af, &addresses);
436 if (n <= 0)
437 return n;
439 return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
442 int dns_synthesize_answer(
443 Manager *m,
444 DnsQuestion *q,
445 int ifindex,
446 DnsAnswer **ret) {
448 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
449 DnsResourceKey *key;
450 bool found = false, nxdomain = false;
451 int r;
453 assert(m);
454 assert(q);
456 DNS_QUESTION_FOREACH(key, q) {
457 union in_addr_union address;
458 const char *name;
459 int af;
461 if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
462 continue;
464 name = dns_resource_key_name(key);
466 if (dns_name_is_root(name) || dns_name_endswith(name, "resolver.arpa") > 0) {
467 /* Do nothing. */
469 } else if (dns_name_dont_resolve(name)) {
470 /* Synthesize NXDOMAIN for some of the domains in RFC6303 + RFC6761 */
471 nxdomain = true;
472 continue;
474 } else if (is_localhost(name)) {
476 r = synthesize_localhost_rr(m, key, &answer);
477 if (r < 0)
478 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
480 } else if (manager_is_own_hostname(m, name)) {
482 if (getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME") == 0)
483 continue;
484 r = synthesize_system_hostname_rr(m, key, ifindex, &answer);
485 if (r < 0)
486 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
488 } else if (is_gateway_hostname(name)) {
490 r = synthesize_gateway_rr(m, key, ifindex, local_gateways, &answer);
491 if (r < 0)
492 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
493 if (r == 0) { /* if we have no gateway return NXDOMAIN */
494 nxdomain = true;
495 continue;
498 } else if (is_outbound_hostname(name)) {
500 r = synthesize_gateway_rr(m, key, ifindex, local_outbounds, &answer);
501 if (r < 0)
502 return log_error_errno(r, "Failed to synthesize outbound RRs: %m");
503 if (r == 0) { /* if we have no gateway return NXDOMAIN */
504 nxdomain = true;
505 continue;
508 } else if (is_dns_stub_hostname(name)) {
510 r = synthesize_dns_stub_rr(m, key, INADDR_DNS_STUB, &answer);
511 if (r < 0)
512 return log_error_errno(r, "Failed to synthesize local DNS stub RRs: %m");
514 } else if (is_dns_proxy_stub_hostname(name)) {
516 r = synthesize_dns_stub_rr(m, key, INADDR_DNS_PROXY_STUB, &answer);
517 if (r < 0)
518 return log_error_errno(r, "Failed to synthesize local DNS stub RRs: %m");
520 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 &&
521 dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0 &&
522 dns_name_equal(name, "53.0.0.127.in-addr.arpa") == 0 &&
523 dns_name_equal(name, "54.0.0.127.in-addr.arpa") == 0) ||
524 dns_name_equal(name, "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) {
526 r = synthesize_localhost_ptr(m, key, &answer);
527 if (r < 0)
528 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
530 } else if (dns_name_address(name, &af, &address) > 0) {
531 int v, w, u;
533 if (getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME") == 0)
534 continue;
536 v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
537 if (v < 0)
538 return log_error_errno(v, "Failed to synthesize system hostname PTR RR: %m");
540 w = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
541 if (w < 0)
542 return log_error_errno(w, "Failed to synthesize gateway hostname PTR RR: %m");
544 u = synthesize_dns_stub_ptr(m, af, &address, &answer);
545 if (u < 0)
546 return log_error_errno(u, "Failed to synthesize local stub hostname PTR PR: %m");
548 if (v == 0 && w == 0 && u == 0) /* This IP address is neither a local one, nor a gateway, nor a stub address */
549 continue;
551 /* Note that we never synthesize reverse PTR for _outbound, since those are local
552 * addresses and thus mapped to the local hostname anyway, hence they already have a
553 * mapping. */
555 } else
556 continue;
558 found = true;
561 if (found) {
563 if (ret)
564 *ret = TAKE_PTR(answer);
566 return 1;
567 } else if (nxdomain)
568 return -ENXIO;
570 return 0;