2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "hostname-util.h"
22 #include "local-addresses.h"
23 #include "resolved-dns-synthesize.h"
25 int dns_synthesize_ifindex(int ifindex
) {
27 /* When the caller asked for resolving on a specific
28 * interface, we synthesize the answer for that
29 * interface. However, if nothing specific was claimed and we
30 * only return localhost RRs, we synthesize the answer for
36 return LOOPBACK_IFINDEX
;
39 int dns_synthesize_family(uint64_t flags
) {
41 /* Picks an address family depending on set flags. This is
42 * purely for synthesized answers, where the family we return
43 * for the reply should match what was requested in the
44 * question, even though we are synthesizing the answer
47 if (!(flags
& SD_RESOLVED_DNS
)) {
48 if (flags
& (SD_RESOLVED_LLMNR_IPV4
|SD_RESOLVED_MDNS_IPV4
))
50 if (flags
& (SD_RESOLVED_LLMNR_IPV6
|SD_RESOLVED_MDNS_IPV6
))
57 DnsProtocol
dns_synthesize_protocol(uint64_t flags
) {
59 /* Similar as dns_synthesize_family() but does this for the
60 * protocol. If resolving via DNS was requested, we claim it
61 * was DNS. Similar, if nothing specific was
62 * requested. However, if only resolving via LLMNR was
63 * requested we return that. */
65 if (flags
& SD_RESOLVED_DNS
)
66 return DNS_PROTOCOL_DNS
;
67 if (flags
& SD_RESOLVED_LLMNR
)
68 return DNS_PROTOCOL_LLMNR
;
69 if (flags
& SD_RESOLVED_MDNS
)
70 return DNS_PROTOCOL_MDNS
;
72 return DNS_PROTOCOL_DNS
;
75 static int synthesize_localhost_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
82 r
= dns_answer_reserve(answer
, 2);
86 if (IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_ANY
)) {
87 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
89 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, dns_resource_key_name(key
));
93 rr
->a
.in_addr
.s_addr
= htobe32(INADDR_LOOPBACK
);
95 r
= dns_answer_add(*answer
, rr
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
100 if (IN_SET(key
->type
, DNS_TYPE_AAAA
, DNS_TYPE_ANY
)) {
101 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
103 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, dns_resource_key_name(key
));
107 rr
->aaaa
.in6_addr
= in6addr_loopback
;
109 r
= dns_answer_add(*answer
, rr
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
117 static int answer_add_ptr(DnsAnswer
**answer
, const char *from
, const char *to
, int ifindex
, DnsAnswerFlags flags
) {
118 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
120 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_PTR
, from
);
124 rr
->ptr
.name
= strdup(to
);
128 return dns_answer_add(*answer
, rr
, ifindex
, flags
);
131 static int synthesize_localhost_ptr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
138 if (IN_SET(key
->type
, DNS_TYPE_PTR
, DNS_TYPE_ANY
)) {
139 r
= dns_answer_reserve(answer
, 1);
143 r
= answer_add_ptr(answer
, dns_resource_key_name(key
), "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
151 static int answer_add_addresses_rr(
154 struct local_address
*addresses
,
155 unsigned n_addresses
) {
163 r
= dns_answer_reserve(answer
, n_addresses
);
167 for (j
= 0; j
< n_addresses
; j
++) {
168 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
170 r
= dns_resource_record_new_address(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
174 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
182 static int answer_add_addresses_ptr(
185 struct local_address
*addresses
,
186 unsigned n_addresses
,
187 int af
, const union in_addr_union
*match
) {
196 for (j
= 0; j
< n_addresses
; j
++) {
197 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
199 if (af
!= AF_UNSPEC
) {
201 if (addresses
[j
].family
!= af
)
204 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
208 r
= dns_answer_reserve(answer
, 1);
212 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
216 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
226 static int synthesize_system_hostname_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
227 _cleanup_free_
struct local_address
*addresses
= NULL
;
234 af
= dns_type_to_af(key
->type
);
236 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
241 struct local_address buffer
[2];
243 /* If we have no local addresses then use ::1
244 * and 127.0.0.2 as local ones. */
246 if (IN_SET(af
, AF_INET
, AF_UNSPEC
))
247 buffer
[n
++] = (struct local_address
) {
249 .ifindex
= dns_synthesize_ifindex(ifindex
),
250 .address
.in
.s_addr
= htobe32(0x7F000002),
253 if (IN_SET(af
, AF_INET6
, AF_UNSPEC
))
254 buffer
[n
++] = (struct local_address
) {
256 .ifindex
= dns_synthesize_ifindex(ifindex
),
257 .address
.in6
= in6addr_loopback
,
260 return answer_add_addresses_rr(answer
,
261 dns_resource_key_name(key
),
266 return answer_add_addresses_rr(answer
, dns_resource_key_name(key
), addresses
, n
);
269 static int synthesize_system_hostname_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
270 _cleanup_free_
struct local_address
*addresses
= NULL
;
278 if (af
== AF_INET
&& address
->in
.s_addr
== htobe32(0x7F000002)) {
280 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
282 r
= dns_answer_reserve(answer
, 4);
286 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->full_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
290 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->llmnr_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
294 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->mdns_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
298 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
305 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
309 r
= answer_add_addresses_ptr(answer
, m
->full_hostname
, addresses
, n
, af
, address
);
315 r
= answer_add_addresses_ptr(answer
, m
->llmnr_hostname
, addresses
, n
, af
, address
);
321 r
= answer_add_addresses_ptr(answer
, m
->mdns_hostname
, addresses
, n
, af
, address
);
330 static int synthesize_gateway_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
331 _cleanup_free_
struct local_address
*addresses
= NULL
;
338 af
= dns_type_to_af(key
->type
);
340 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
342 return n
; /* < 0 means: error; == 0 means we have no gateway */
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(r
, "Failed to synthesize system hostname PTR RR: %m");
427 w
= synthesize_gateway_ptr(m
, af
, &address
, ifindex
, &answer
);
429 return log_error_errno(r
, "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 */