1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "hostname-util.h"
5 #include "local-addresses.h"
6 #include "missing_network.h"
7 #include "resolved-dns-synthesize.h"
9 int dns_synthesize_ifindex(int ifindex
) {
11 /* When the caller asked for resolving on a specific
12 * interface, we synthesize the answer for that
13 * interface. However, if nothing specific was claimed and we
14 * only return localhost RRs, we synthesize the answer for
20 return LOOPBACK_IFINDEX
;
23 int dns_synthesize_family(uint64_t flags
) {
25 /* Picks an address family depending on set flags. This is
26 * purely for synthesized answers, where the family we return
27 * for the reply should match what was requested in the
28 * question, even though we are synthesizing the answer
31 if (!(flags
& SD_RESOLVED_DNS
)) {
32 if (flags
& (SD_RESOLVED_LLMNR_IPV4
|SD_RESOLVED_MDNS_IPV4
))
34 if (flags
& (SD_RESOLVED_LLMNR_IPV6
|SD_RESOLVED_MDNS_IPV6
))
41 DnsProtocol
dns_synthesize_protocol(uint64_t flags
) {
43 /* Similar as dns_synthesize_family() but does this for the
44 * protocol. If resolving via DNS was requested, we claim it
45 * was DNS. Similar, if nothing specific was
46 * requested. However, if only resolving via LLMNR was
47 * requested we return that. */
49 if (flags
& SD_RESOLVED_DNS
)
50 return DNS_PROTOCOL_DNS
;
51 if (flags
& SD_RESOLVED_LLMNR
)
52 return DNS_PROTOCOL_LLMNR
;
53 if (flags
& SD_RESOLVED_MDNS
)
54 return DNS_PROTOCOL_MDNS
;
56 return DNS_PROTOCOL_DNS
;
59 static int synthesize_localhost_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
66 r
= dns_answer_reserve(answer
, 2);
70 if (IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_ANY
)) {
71 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
73 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, dns_resource_key_name(key
));
77 rr
->a
.in_addr
.s_addr
= htobe32(INADDR_LOOPBACK
);
79 r
= dns_answer_add(*answer
, rr
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
, NULL
);
84 if (IN_SET(key
->type
, DNS_TYPE_AAAA
, DNS_TYPE_ANY
)) {
85 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
87 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, dns_resource_key_name(key
));
91 rr
->aaaa
.in6_addr
= in6addr_loopback
;
93 r
= dns_answer_add(*answer
, rr
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
, NULL
);
101 static int answer_add_ptr(DnsAnswer
**answer
, const char *from
, const char *to
, int ifindex
, DnsAnswerFlags flags
) {
102 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
104 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_PTR
, from
);
108 rr
->ptr
.name
= strdup(to
);
112 return dns_answer_add(*answer
, rr
, ifindex
, flags
, NULL
);
115 static int synthesize_localhost_ptr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
122 if (IN_SET(key
->type
, DNS_TYPE_PTR
, DNS_TYPE_ANY
)) {
123 r
= dns_answer_reserve(answer
, 1);
127 r
= answer_add_ptr(answer
, dns_resource_key_name(key
), "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
135 static int answer_add_addresses_rr(
138 struct local_address
*addresses
,
139 unsigned n_addresses
) {
147 r
= dns_answer_reserve(answer
, n_addresses
);
151 for (j
= 0; j
< n_addresses
; j
++) {
152 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
154 r
= dns_resource_record_new_address(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
158 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
166 static int answer_add_addresses_ptr(
169 struct local_address
*addresses
,
170 unsigned n_addresses
,
171 int af
, const union in_addr_union
*match
) {
180 for (j
= 0; j
< n_addresses
; j
++) {
181 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
183 if (af
!= AF_UNSPEC
) {
185 if (addresses
[j
].family
!= af
)
188 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
192 r
= dns_answer_reserve(answer
, 1);
196 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
200 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
210 static int synthesize_system_hostname_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
211 _cleanup_free_
struct local_address
*addresses
= NULL
;
218 af
= dns_type_to_af(key
->type
);
220 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
225 struct local_address buffer
[2];
227 /* If we have no local addresses then use ::1
228 * and 127.0.0.2 as local ones. */
230 if (IN_SET(af
, AF_INET
, AF_UNSPEC
))
231 buffer
[n
++] = (struct local_address
) {
233 .ifindex
= dns_synthesize_ifindex(ifindex
),
234 .address
.in
.s_addr
= htobe32(0x7F000002),
237 if (IN_SET(af
, AF_INET6
, AF_UNSPEC
))
238 buffer
[n
++] = (struct local_address
) {
240 .ifindex
= dns_synthesize_ifindex(ifindex
),
241 .address
.in6
= in6addr_loopback
,
244 return answer_add_addresses_rr(answer
,
245 dns_resource_key_name(key
),
250 return answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
253 static int synthesize_system_hostname_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
254 _cleanup_free_
struct local_address
*addresses
= NULL
;
262 if (af
== AF_INET
&& address
->in
.s_addr
== htobe32(0x7F000002)) {
264 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
266 r
= dns_answer_reserve(answer
, 4);
270 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->full_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
274 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->llmnr_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
278 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->mdns_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
282 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
289 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
293 r
= answer_add_addresses_ptr(answer
, m
->full_hostname
, addresses
, n
, af
, address
);
299 r
= answer_add_addresses_ptr(answer
, m
->llmnr_hostname
, addresses
, n
, af
, address
);
305 r
= answer_add_addresses_ptr(answer
, m
->mdns_hostname
, addresses
, n
, af
, address
);
314 static int synthesize_gateway_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
315 _cleanup_free_
struct local_address
*addresses
= NULL
;
322 af
= dns_type_to_af(key
->type
);
324 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
325 if (n
< 0) /* < 0 means: error */
328 if (n
== 0) { /* == 0 means we have no gateway */
329 /* See if there's a gateway on the other protocol */
331 n
= local_gateways(m
->rtnl
, ifindex
, AF_INET6
, NULL
);
333 assert(af
== AF_INET6
);
334 n
= local_gateways(m
->rtnl
, ifindex
, AF_INET
, NULL
);
336 if (n
<= 0) /* error (if < 0) or really no gateway at all (if == 0) */
339 /* We have a gateway on the other protocol. Let's return > 0 without adding any RR to
340 * the answer, i.e. synthesize NODATA (and not NXDOMAIN!) */
345 r
= answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
349 return 1; /* > 0 means: we have some gateway */
352 static int synthesize_gateway_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
353 _cleanup_free_
struct local_address
*addresses
= NULL
;
360 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
364 return answer_add_addresses_ptr(answer
, "_gateway", addresses
, n
, af
, address
);
367 int dns_synthesize_answer(
373 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
375 bool found
= false, nxdomain
= false;
381 DNS_QUESTION_FOREACH(key
, q
) {
382 union in_addr_union address
;
386 if (!IN_SET(key
->class, DNS_CLASS_IN
, DNS_CLASS_ANY
))
389 name
= dns_resource_key_name(key
);
391 if (is_localhost(name
)) {
393 r
= synthesize_localhost_rr(m
, key
, ifindex
, &answer
);
395 return log_error_errno(r
, "Failed to synthesize localhost RRs: %m");
397 } else if (manager_is_own_hostname(m
, name
)) {
399 r
= synthesize_system_hostname_rr(m
, key
, ifindex
, &answer
);
401 return log_error_errno(r
, "Failed to synthesize system hostname RRs: %m");
403 } else if (is_gateway_hostname(name
)) {
405 r
= synthesize_gateway_rr(m
, key
, ifindex
, &answer
);
407 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
408 if (r
== 0) { /* if we have no gateway return NXDOMAIN */
413 } else if ((dns_name_endswith(name
, "127.in-addr.arpa") > 0 && dns_name_equal(name
, "2.0.0.127.in-addr.arpa") == 0) ||
414 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) {
416 r
= synthesize_localhost_ptr(m
, key
, ifindex
, &answer
);
418 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
420 } else if (dns_name_address(name
, &af
, &address
) > 0) {
423 v
= synthesize_system_hostname_ptr(m
, af
, &address
, ifindex
, &answer
);
425 return log_error_errno(v
, "Failed to synthesize system hostname PTR RR: %m");
427 w
= synthesize_gateway_ptr(m
, af
, &address
, ifindex
, &answer
);
429 return log_error_errno(w
, "Failed to synthesize gateway hostname PTR RR: %m");
431 if (v
== 0 && w
== 0) /* This IP address is neither a local one nor a gateway */
443 *ret
= TAKE_PTR(answer
);