1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
);
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
);
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
);
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
);
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
);
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
);
326 return n
; /* < 0 means: error; == 0 means we have no gateway */
329 r
= answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
333 return 1; /* > 0 means: we have some gateway */
336 static int synthesize_gateway_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
337 _cleanup_free_
struct local_address
*addresses
= NULL
;
344 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
348 return answer_add_addresses_ptr(answer
, "_gateway", addresses
, n
, af
, address
);
351 int dns_synthesize_answer(
357 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
359 bool found
= false, nxdomain
= false;
365 DNS_QUESTION_FOREACH(key
, q
) {
366 union in_addr_union address
;
370 if (!IN_SET(key
->class, DNS_CLASS_IN
, DNS_CLASS_ANY
))
373 name
= dns_resource_key_name(key
);
375 if (is_localhost(name
)) {
377 r
= synthesize_localhost_rr(m
, key
, ifindex
, &answer
);
379 return log_error_errno(r
, "Failed to synthesize localhost RRs: %m");
381 } else if (manager_is_own_hostname(m
, name
)) {
383 r
= synthesize_system_hostname_rr(m
, key
, ifindex
, &answer
);
385 return log_error_errno(r
, "Failed to synthesize system hostname RRs: %m");
387 } else if (is_gateway_hostname(name
)) {
389 r
= synthesize_gateway_rr(m
, key
, ifindex
, &answer
);
391 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
392 if (r
== 0) { /* if we have no gateway return NXDOMAIN */
397 } else if ((dns_name_endswith(name
, "127.in-addr.arpa") > 0 && dns_name_equal(name
, "2.0.0.127.in-addr.arpa") == 0) ||
398 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) {
400 r
= synthesize_localhost_ptr(m
, key
, ifindex
, &answer
);
402 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
404 } else if (dns_name_address(name
, &af
, &address
) > 0) {
407 v
= synthesize_system_hostname_ptr(m
, af
, &address
, ifindex
, &answer
);
409 return log_error_errno(v
, "Failed to synthesize system hostname PTR RR: %m");
411 w
= synthesize_gateway_ptr(m
, af
, &address
, ifindex
, &answer
);
413 return log_error_errno(w
, "Failed to synthesize gateway hostname PTR RR: %m");
415 if (v
== 0 && w
== 0) /* This IP address is neither a local one nor a gateway */
427 *ret
= TAKE_PTR(answer
);