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
) {
195 for (j
= 0; j
< n_addresses
; j
++) {
196 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
198 if (af
!= AF_UNSPEC
) {
200 if (addresses
[j
].family
!= af
)
203 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
207 r
= dns_answer_reserve(answer
, 1);
211 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
215 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
, DNS_ANSWER_AUTHENTICATED
);
223 static int synthesize_system_hostname_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
224 _cleanup_free_
struct local_address
*addresses
= NULL
;
231 af
= dns_type_to_af(key
->type
);
233 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
238 struct local_address buffer
[2];
240 /* If we have no local addresses then use ::1
241 * and 127.0.0.2 as local ones. */
243 if (af
== AF_INET
|| af
== AF_UNSPEC
)
244 buffer
[n
++] = (struct local_address
) {
246 .ifindex
= dns_synthesize_ifindex(ifindex
),
247 .address
.in
.s_addr
= htobe32(0x7F000002),
250 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
251 buffer
[n
++] = (struct local_address
) {
253 .ifindex
= dns_synthesize_ifindex(ifindex
),
254 .address
.in6
= in6addr_loopback
,
257 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), buffer
, n
);
261 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), addresses
, n
);
264 static int synthesize_system_hostname_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
265 _cleanup_free_
struct local_address
*addresses
= NULL
;
272 if (af
== AF_INET
&& address
->in
.s_addr
== htobe32(0x7F000002)) {
274 /* Always map the IPv4 address 127.0.0.2 to the local
275 * hostname, in addition to "localhost": */
277 r
= dns_answer_reserve(answer
, 3);
281 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->llmnr_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
285 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", m
->mdns_hostname
, dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
289 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex
), DNS_ANSWER_AUTHENTICATED
);
296 n
= local_addresses(m
->rtnl
, ifindex
, af
, &addresses
);
300 r
= answer_add_addresses_ptr(answer
, m
->llmnr_hostname
, addresses
, n
, af
, address
);
304 return answer_add_addresses_ptr(answer
, m
->mdns_hostname
, addresses
, n
, af
, address
);
307 static int synthesize_gateway_rr(Manager
*m
, const DnsResourceKey
*key
, int ifindex
, DnsAnswer
**answer
) {
308 _cleanup_free_
struct local_address
*addresses
= NULL
;
315 af
= dns_type_to_af(key
->type
);
317 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
322 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), addresses
, n
);
325 static int synthesize_gateway_ptr(Manager
*m
, int af
, const union in_addr_union
*address
, int ifindex
, DnsAnswer
**answer
) {
326 _cleanup_free_
struct local_address
*addresses
= NULL
;
333 n
= local_gateways(m
->rtnl
, ifindex
, af
, &addresses
);
337 return answer_add_addresses_ptr(answer
, "gateway", addresses
, n
, af
, address
);
340 int dns_synthesize_answer(
346 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
354 DNS_QUESTION_FOREACH(key
, q
) {
355 union in_addr_union address
;
359 if (key
->class != DNS_CLASS_IN
&&
360 key
->class != DNS_CLASS_ANY
)
363 name
= DNS_RESOURCE_KEY_NAME(key
);
365 if (is_localhost(name
)) {
367 r
= synthesize_localhost_rr(m
, key
, ifindex
, &answer
);
369 return log_error_errno(r
, "Failed to synthesize localhost RRs: %m");
371 } else if (manager_is_own_hostname(m
, name
)) {
373 r
= synthesize_system_hostname_rr(m
, key
, ifindex
, &answer
);
375 return log_error_errno(r
, "Failed to synthesize system hostname RRs: %m");
377 } else if (is_gateway_hostname(name
)) {
379 r
= synthesize_gateway_rr(m
, key
, ifindex
, &answer
);
381 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
383 } else if ((dns_name_endswith(name
, "127.in-addr.arpa") > 0 && dns_name_equal(name
, "2.0.0.127.in-addr.arpa") == 0) ||
384 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) {
386 r
= synthesize_localhost_ptr(m
, key
, ifindex
, &answer
);
388 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
390 } else if (dns_name_address(name
, &af
, &address
) > 0) {
392 r
= synthesize_system_hostname_ptr(m
, af
, &address
, ifindex
, &answer
);
394 return log_error_errno(r
, "Failed to synthesize system hostname PTR RR: %m");
396 r
= synthesize_gateway_ptr(m
, af
, &address
, ifindex
, &answer
);
398 return log_error_errno(r
, "Failed to synthesize gateway hostname PTR RR: %m");