1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
22 #include "hostname-util.h"
23 #include "local-addresses.h"
24 #include "resolved-dns-synthesize.h"
26 int dns_synthesize_ifindex(int ifindex
) {
28 /* When the caller asked for resolving on a specific
29 * interface, we synthesize the answer for that
30 * interface. However, if nothing specific was claimed and we
31 * only return localhost RRs, we synthesize the answer for
37 return LOOPBACK_IFINDEX
;
40 int dns_synthesize_family(uint64_t flags
) {
42 /* Picks an address family depending on set flags. This is
43 * purely for synthesized answers, where the family we return
44 * for the reply should match what was requested in the
45 * question, even though we are synthesizing the answer
48 if (!(flags
& SD_RESOLVED_DNS
)) {
49 if (flags
& (SD_RESOLVED_LLMNR_IPV4
|SD_RESOLVED_MDNS_IPV4
))
51 if (flags
& (SD_RESOLVED_LLMNR_IPV6
|SD_RESOLVED_MDNS_IPV6
))
58 DnsProtocol
dns_synthesize_protocol(uint64_t flags
) {
60 /* Similar as dns_synthesize_family() but does this for the
61 * protocol. If resolving via DNS was requested, we claim it
62 * was DNS. Similar, if nothing specific was
63 * requested. However, if only resolving via LLMNR was
64 * requested we return that. */
66 if (flags
& SD_RESOLVED_DNS
)
67 return DNS_PROTOCOL_DNS
;
68 if (flags
& SD_RESOLVED_LLMNR
)
69 return DNS_PROTOCOL_LLMNR
;
70 if (flags
& SD_RESOLVED_MDNS
)
71 return DNS_PROTOCOL_MDNS
;
73 return DNS_PROTOCOL_DNS
;
76 static int synthesize_localhost_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
83 r
= dns_answer_reserve(answer
, 2);
87 if (IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_ANY
)) {
88 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
90 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, dns_resource_key_name(key
));
94 rr
->a
.in_addr
.s_addr
= htobe32(INADDR_LOOPBACK
);
96 r
= dns_answer_add(*answer
, rr
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
101 if (IN_SET(key
->type
, DNS_TYPE_AAAA
, DNS_TYPE_ANY
)) {
102 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
104 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, dns_resource_key_name(key
));
108 rr
->aaaa
.in6_addr
= in6addr_loopback
;
110 r
= dns_answer_add(*answer
, rr
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
118 static int answer_add_ptr(DnsAnswer
**answer
, const char *from
, const char *to
, int ifindex
, DnsAnswerFlags flags
) {
119 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
121 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_PTR
, from
);
125 rr
->ptr
.name
= strdup(to
);
129 return dns_answer_add(*answer
, rr
, ifindex
, flags
);
132 static int synthesize_localhost_ptr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
139 if (IN_SET(key
->type
, DNS_TYPE_PTR
, DNS_TYPE_ANY
)) {
140 r
= dns_answer_reserve(answer
, 1);
144 r
= answer_add_ptr(answer
, dns_resource_key_name(key
), "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
152 static int answer_add_addresses_rr(
155 struct local_address
*addresses
,
156 unsigned n_addresses
) {
164 r
= dns_answer_reserve(answer
, n_addresses
);
168 for (j
= 0; j
< n_addresses
; j
++) {
169 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
171 r
= dns_resource_record_new_address(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
175 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
183 static int answer_add_addresses_ptr(
186 struct local_address
*addresses
,
187 unsigned n_addresses
,
188 int af
, const union in_addr_union
*match
) {
197 for (j
= 0; j
< n_addresses
; j
++) {
198 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
200 if (af
!= AF_UNSPEC
) {
202 if (addresses
[j
].family
!= af
)
205 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
209 r
= dns_answer_reserve(answer
, 1);
213 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
217 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
227 static int synthesize_system_hostname_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
228 _cleanup_free_
struct local_address
*addresses
= NULL
;
235 af
= dns_type_to_af(key
->type
);
237 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
242 struct local_address buffer
[2];
244 /* If we have no local addresses then use ::1
245 * and 127.0.0.2 as local ones. */
247 if (IN_SET(af
, AF_INET
, AF_UNSPEC
))
248 buffer
[n
++] = (struct local_address
) {
250 .ifindex
= dns_synthesize_ifindex(ifindex
),
251 .address
.in
.s_addr
= htobe32(0x7F000002),
254 if (IN_SET(af
, AF_INET6
, AF_UNSPEC
))
255 buffer
[n
++] = (struct local_address
) {
257 .ifindex
= dns_synthesize_ifindex(ifindex
),
258 .address
.in6
= in6addr_loopback
,
261 return answer_add_addresses_rr(answer
,
262 dns_resource_key_name(key
),
267 return answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
270 static int synthesize_system_hostname_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
271 _cleanup_free_
struct local_address
*addresses
= NULL
;
279 if (af
== AF_INET
&& address
->in
.s_addr
== htobe32(0x7F000002)) {
281 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
283 r
= dns_answer_reserve(answer
, 4);
287 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->full_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
291 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->llmnr_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
295 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->mdns_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
299 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
306 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
310 r
= answer_add_addresses_ptr(answer
, m
->full_hostname
, addresses
, n
, af
, address
);
316 r
= answer_add_addresses_ptr(answer
, m
->llmnr_hostname
, addresses
, n
, af
, address
);
322 r
= answer_add_addresses_ptr(answer
, m
->mdns_hostname
, addresses
, n
, af
, address
);
331 static int synthesize_gateway_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
332 _cleanup_free_
struct local_address
*addresses
= NULL
;
339 af
= dns_type_to_af(key
->type
);
341 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
343 return n
; /* < 0 means: error; == 0 means we have no gateway */
346 r
= answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
350 return 1; /* > 0 means: we have some gateway */
353 static int synthesize_gateway_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
354 _cleanup_free_
struct local_address
*addresses
= NULL
;
361 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
365 return answer_add_addresses_ptr(answer
, "_gateway", addresses
, n
, af
, address
);
368 int dns_synthesize_answer(
374 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
376 bool found
= false, nxdomain
= false;
382 DNS_QUESTION_FOREACH(key
, q
) {
383 union in_addr_union address
;
387 if (!IN_SET(key
->class, DNS_CLASS_IN
, DNS_CLASS_ANY
))
390 name
= dns_resource_key_name(key
);
392 if (is_localhost(name
)) {
394 r
= synthesize_localhost_rr(m
, key
, ifindex
, &answer
);
396 return log_error_errno(r
, "Failed to synthesize localhost RRs: %m");
398 } else if (manager_is_own_hostname(m
, name
)) {
400 r
= synthesize_system_hostname_rr(m
, key
, ifindex
, &answer
);
402 return log_error_errno(r
, "Failed to synthesize system hostname RRs: %m");
404 } else if (is_gateway_hostname(name
)) {
406 r
= synthesize_gateway_rr(m
, key
, ifindex
, &answer
);
408 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
409 if (r
== 0) { /* if we have no gateway return NXDOMAIN */
414 } else if ((dns_name_endswith(name
, "127.in-addr.arpa") > 0 && dns_name_equal(name
, "2.0.0.127.in-addr.arpa") == 0) ||
415 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) {
417 r
= synthesize_localhost_ptr(m
, key
, ifindex
, &answer
);
419 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
421 } else if (dns_name_address(name
, &af
, &address
) > 0) {
424 v
= synthesize_system_hostname_ptr(m
, af
, &address
, ifindex
, &answer
);
426 return log_error_errno(v
, "Failed to synthesize system hostname PTR RR: %m");
428 w
= synthesize_gateway_ptr(m
, af
, &address
, ifindex
, &answer
);
430 return log_error_errno(w
, "Failed to synthesize gateway hostname PTR RR: %m");
432 if (v
== 0 && w
== 0) /* This IP address is neither a local one nor a gateway */