1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-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
18 if (!(flags
& SD_RESOLVED_DNS
)) {
19 if (flags
& (SD_RESOLVED_LLMNR_IPV4
|SD_RESOLVED_MDNS_IPV4
))
21 if (flags
& (SD_RESOLVED_LLMNR_IPV6
|SD_RESOLVED_MDNS_IPV6
))
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
) {
53 r
= dns_answer_reserve(answer
, 2);
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
));
64 rr
->a
.in_addr
.s_addr
= htobe32(INADDR_LOOPBACK
);
66 r
= dns_answer_add(*answer
, rr
, LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
, NULL
);
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
));
78 rr
->aaaa
.in6_addr
= in6addr_loopback
;
80 r
= dns_answer_add(*answer
, rr
, LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
, NULL
);
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
);
95 rr
->ptr
.name
= strdup(to
);
99 return dns_answer_add(*answer
, rr
, ifindex
, flags
, NULL
);
102 static int synthesize_localhost_ptr(Manager
*m
, const DnsResourceKey
*key
, DnsAnswer
**answer
) {
109 if (IN_SET(key
->type
, DNS_TYPE_PTR
, DNS_TYPE_ANY
)) {
110 r
= dns_answer_reserve(answer
, 1);
114 r
= answer_add_ptr(answer
, dns_resource_key_name(key
), "localhost", LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
122 static int answer_add_addresses_rr(
125 struct local_address
*addresses
,
126 unsigned n_addresses
) {
134 r
= dns_answer_reserve(answer
, n_addresses
);
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
);
145 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
153 static int answer_add_addresses_ptr(
156 struct local_address
*addresses
,
157 unsigned n_addresses
,
158 int af
, const union in_addr_union
*match
) {
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
)
175 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
179 r
= dns_answer_reserve(answer
, 1);
183 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
187 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
197 static int synthesize_system_hostname_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
198 _cleanup_free_
struct local_address
*addresses
= NULL
;
205 af
= dns_type_to_af(key
->type
);
207 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
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
) {
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
) {
226 .ifindex
= LOOPBACK_IFINDEX
,
227 .address
.in6
= in6addr_loopback
,
230 return answer_add_addresses_rr(answer
,
231 dns_resource_key_name(key
),
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
;
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);
256 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->full_hostname
, LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
260 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->llmnr_hostname
, LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
264 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->mdns_hostname
, LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
268 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
275 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
279 r
= answer_add_addresses_ptr(answer
, m
->full_hostname
, addresses
, n
, af
, address
);
285 r
= answer_add_addresses_ptr(answer
, m
->llmnr_hostname
, addresses
, n
, af
, address
);
291 r
= answer_add_addresses_ptr(answer
, m
->mdns_hostname
, addresses
, n
, af
, address
);
300 static int synthesize_gateway_rr(
302 const DnsResourceKey
*key
,
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
;
314 af
= dns_type_to_af(key
->type
);
316 n
= lookup(m
->rtnl
, ifindex
, af
, &addresses
);
317 if (n
< 0) /* < 0 means: error */
320 if (n
== 0) { /* == 0 means we have no gateway */
321 /* See if there's a gateway on the other protocol */
323 n
= lookup(m
->rtnl
, ifindex
, AF_INET6
, NULL
);
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) */
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!) */
337 r
= answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
341 return 1; /* > 0 means: we have some gateway */
344 static int synthesize_dns_stub_rr(
346 const DnsResourceKey
*key
,
348 DnsAnswer
**answer
) {
350 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
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);
364 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, dns_resource_key_name(key
));
368 rr
->a
.in_addr
.s_addr
= htobe32(addr
);
370 r
= dns_answer_add(*answer
, rr
, LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
, NULL
);
377 static int synthesize_dns_stub_ptr(
380 const union in_addr_union
*address
,
381 DnsAnswer
**answer
) {
392 if (address
->in
.s_addr
== htobe32(INADDR_DNS_STUB
)) {
394 r
= dns_answer_reserve(answer
, 1);
398 r
= answer_add_ptr(answer
, "53.0.0.127.in-addr.arpa", "_localdnsstub", LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
405 if (address
->in
.s_addr
== htobe32(INADDR_DNS_PROXY_STUB
)) {
407 r
= dns_answer_reserve(answer
, 1);
411 r
= answer_add_ptr(answer
, "54.0.0.127.in-addr.arpa", "_localdnsproxy", LOOPBACK_IFINDEX
, DNS_ANSWER_AUTHENTICATED
);
421 static int synthesize_gateway_ptr(
424 const union in_addr_union
*address
,
426 DnsAnswer
**answer
) {
428 _cleanup_free_
struct local_address
*addresses
= NULL
;
435 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
439 return answer_add_addresses_ptr(answer
, "_gateway", addresses
, n
, af
, address
);
442 int dns_synthesize_answer(
448 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
450 bool found
= false, nxdomain
= false;
456 DNS_QUESTION_FOREACH(key
, q
) {
457 union in_addr_union address
;
461 if (!IN_SET(key
->class, DNS_CLASS_IN
, DNS_CLASS_ANY
))
464 name
= dns_resource_key_name(key
);
466 if (dns_name_is_root(name
) || dns_name_endswith(name
, "resolver.arpa") > 0) {
469 } else if (dns_name_dont_resolve(name
)) {
470 /* Synthesize NXDOMAIN for some of the domains in RFC6303 + RFC6761 */
474 } else if (is_localhost(name
)) {
476 r
= synthesize_localhost_rr(m
, key
, &answer
);
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)
484 r
= synthesize_system_hostname_rr(m
, key
, ifindex
, &answer
);
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
);
492 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
493 if (r
== 0) { /* if we have no gateway return NXDOMAIN */
498 } else if (is_outbound_hostname(name
)) {
500 r
= synthesize_gateway_rr(m
, key
, ifindex
, local_outbounds
, &answer
);
502 return log_error_errno(r
, "Failed to synthesize outbound RRs: %m");
503 if (r
== 0) { /* if we have no gateway return NXDOMAIN */
508 } else if (is_dns_stub_hostname(name
)) {
510 r
= synthesize_dns_stub_rr(m
, key
, INADDR_DNS_STUB
, &answer
);
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
);
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
);
528 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
530 } else if (dns_name_address(name
, &af
, &address
) > 0) {
533 if (getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME") == 0)
536 v
= synthesize_system_hostname_ptr(m
, af
, &address
, ifindex
, &answer
);
538 return log_error_errno(v
, "Failed to synthesize system hostname PTR RR: %m");
540 w
= synthesize_gateway_ptr(m
, af
, &address
, ifindex
, &answer
);
542 return log_error_errno(w
, "Failed to synthesize gateway hostname PTR RR: %m");
544 u
= synthesize_dns_stub_ptr(m
, af
, &address
, &answer
);
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 */
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
564 *ret
= TAKE_PTR(answer
);