]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-synthesize.c
resolved: maintain only a single list of "dont-resolve" domain names
[thirdparty/systemd.git] / src / resolve / resolved-dns-synthesize.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
839a4a20
LP
2
3#include "alloc-util.h"
4#include "hostname-util.h"
5#include "local-addresses.h"
ef118d00 6#include "missing_network.h"
839a4a20
LP
7#include "resolved-dns-synthesize.h"
8
dd0bc0f1 9int dns_synthesize_ifindex(int ifindex) {
839a4a20
LP
10
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
15 * localhost. */
16
17 if (ifindex > 0)
18 return ifindex;
19
20 return LOOPBACK_IFINDEX;
21}
22
dd0bc0f1 23int dns_synthesize_family(uint64_t flags) {
839a4a20
LP
24
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
29 * here. */
30
31 if (!(flags & SD_RESOLVED_DNS)) {
32 if (flags & (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_MDNS_IPV4))
33 return AF_INET;
34 if (flags & (SD_RESOLVED_LLMNR_IPV6|SD_RESOLVED_MDNS_IPV6))
35 return AF_INET6;
36 }
37
38 return AF_UNSPEC;
39}
40
dd0bc0f1 41DnsProtocol dns_synthesize_protocol(uint64_t flags) {
839a4a20 42
dd0bc0f1 43 /* Similar as dns_synthesize_family() but does this for the
839a4a20
LP
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. */
48
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;
55
56 return DNS_PROTOCOL_DNS;
57}
58
59static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
60 int r;
61
62 assert(m);
63 assert(key);
64 assert(answer);
65
66 r = dns_answer_reserve(answer, 2);
67 if (r < 0)
68 return r;
69
70 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
71 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
72
1c02e7ba 73 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
839a4a20
LP
74 if (!rr)
75 return -ENOMEM;
76
77 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
78
04617bf8 79 r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
839a4a20
LP
80 if (r < 0)
81 return r;
82 }
83
747b596f 84 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY) && socket_ipv6_is_enabled()) {
839a4a20
LP
85 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
86
1c02e7ba 87 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key));
839a4a20
LP
88 if (!rr)
89 return -ENOMEM;
90
91 rr->aaaa.in6_addr = in6addr_loopback;
92
04617bf8 93 r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
839a4a20
LP
94 if (r < 0)
95 return r;
96 }
97
98 return 0;
99}
100
101static 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;
103
104 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
105 if (!rr)
106 return -ENOMEM;
107
108 rr->ptr.name = strdup(to);
109 if (!rr->ptr.name)
110 return -ENOMEM;
111
04617bf8 112 return dns_answer_add(*answer, rr, ifindex, flags, NULL);
839a4a20
LP
113}
114
115static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
116 int r;
117
118 assert(m);
119 assert(key);
120 assert(answer);
121
122 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
123 r = dns_answer_reserve(answer, 1);
124 if (r < 0)
125 return r;
126
1c02e7ba 127 r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
128 if (r < 0)
129 return r;
130 }
131
132 return 0;
133}
134
135static int answer_add_addresses_rr(
136 DnsAnswer **answer,
137 const char *name,
138 struct local_address *addresses,
139 unsigned n_addresses) {
140
141 unsigned j;
142 int r;
143
144 assert(answer);
145 assert(name);
146
147 r = dns_answer_reserve(answer, n_addresses);
148 if (r < 0)
149 return r;
150
151 for (j = 0; j < n_addresses; j++) {
152 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
153
154 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
155 if (r < 0)
156 return r;
157
04617bf8 158 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
839a4a20
LP
159 if (r < 0)
160 return r;
161 }
162
163 return 0;
164}
165
166static int answer_add_addresses_ptr(
167 DnsAnswer **answer,
168 const char *name,
169 struct local_address *addresses,
170 unsigned n_addresses,
171 int af, const union in_addr_union *match) {
172
2855b6c3 173 bool added = false;
839a4a20
LP
174 unsigned j;
175 int r;
176
177 assert(answer);
178 assert(name);
179
180 for (j = 0; j < n_addresses; j++) {
181 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
182
183 if (af != AF_UNSPEC) {
184
185 if (addresses[j].family != af)
186 continue;
187
188 if (match && !in_addr_equal(af, match, &addresses[j].address))
189 continue;
190 }
191
192 r = dns_answer_reserve(answer, 1);
193 if (r < 0)
194 return r;
195
196 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
197 if (r < 0)
198 return r;
199
04617bf8 200 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
839a4a20
LP
201 if (r < 0)
202 return r;
2855b6c3
LP
203
204 added = true;
839a4a20
LP
205 }
206
2855b6c3 207 return added;
839a4a20
LP
208}
209
210static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
211 _cleanup_free_ struct local_address *addresses = NULL;
212 int n = 0, af;
213
214 assert(m);
215 assert(key);
216 assert(answer);
217
218 af = dns_type_to_af(key->type);
219 if (af >= 0) {
220 n = local_addresses(m->rtnl, ifindex, af, &addresses);
221 if (n < 0)
222 return n;
223
224 if (n == 0) {
225 struct local_address buffer[2];
226
227 /* If we have no local addresses then use ::1
228 * and 127.0.0.2 as local ones. */
229
3742095b 230 if (IN_SET(af, AF_INET, AF_UNSPEC))
839a4a20
LP
231 buffer[n++] = (struct local_address) {
232 .family = AF_INET,
dd0bc0f1 233 .ifindex = dns_synthesize_ifindex(ifindex),
839a4a20
LP
234 .address.in.s_addr = htobe32(0x7F000002),
235 };
236
747b596f 237 if (IN_SET(af, AF_INET6, AF_UNSPEC) && socket_ipv6_is_enabled())
839a4a20
LP
238 buffer[n++] = (struct local_address) {
239 .family = AF_INET6,
dd0bc0f1 240 .ifindex = dns_synthesize_ifindex(ifindex),
839a4a20
LP
241 .address.in6 = in6addr_loopback,
242 };
243
3742095b
AR
244 return answer_add_addresses_rr(answer,
245 dns_resource_key_name(key),
246 buffer, n);
839a4a20
LP
247 }
248 }
249
1c02e7ba 250 return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
839a4a20
LP
251}
252
253static 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;
2855b6c3 255 bool added = false;
839a4a20
LP
256 int n, r;
257
258 assert(m);
259 assert(address);
260 assert(answer);
261
262 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
263
a4f3375d 264 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
839a4a20 265
a4f3375d
LP
266 r = dns_answer_reserve(answer, 4);
267 if (r < 0)
268 return r;
269
270 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
271 if (r < 0)
272 return r;
273
dd0bc0f1 274 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
275 if (r < 0)
276 return r;
277
dd0bc0f1 278 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
279 if (r < 0)
280 return r;
281
dd0bc0f1 282 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
283 if (r < 0)
284 return r;
285
2855b6c3 286 return 1;
839a4a20
LP
287 }
288
289 n = local_addresses(m->rtnl, ifindex, af, &addresses);
2855b6c3 290 if (n <= 0)
839a4a20
LP
291 return n;
292
a4f3375d
LP
293 r = answer_add_addresses_ptr(answer, m->full_hostname, addresses, n, af, address);
294 if (r < 0)
295 return r;
296 if (r > 0)
297 added = true;
298
839a4a20
LP
299 r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address);
300 if (r < 0)
301 return r;
2855b6c3
LP
302 if (r > 0)
303 added = true;
304
305 r = answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
306 if (r < 0)
307 return r;
308 if (r > 0)
309 added = true;
839a4a20 310
2855b6c3 311 return added;
839a4a20
LP
312}
313
ee18f107
LP
314static int synthesize_gateway_rr(
315 Manager *m,
316 const DnsResourceKey *key,
317 int ifindex,
318 int (*lookup)(sd_netlink *context, int ifindex, int af, struct local_address **ret), /* either local_gateways() or local_outbound() */
319 DnsAnswer **answer) {
839a4a20 320 _cleanup_free_ struct local_address *addresses = NULL;
acf06088 321 int n = 0, af, r;
839a4a20
LP
322
323 assert(m);
324 assert(key);
ee18f107 325 assert(lookup);
839a4a20
LP
326 assert(answer);
327
328 af = dns_type_to_af(key->type);
329 if (af >= 0) {
ee18f107 330 n = lookup(m->rtnl, ifindex, af, &addresses);
877884fc
LP
331 if (n < 0) /* < 0 means: error */
332 return n;
333
334 if (n == 0) { /* == 0 means we have no gateway */
335 /* See if there's a gateway on the other protocol */
336 if (af == AF_INET)
ee18f107 337 n = lookup(m->rtnl, ifindex, AF_INET6, NULL);
877884fc
LP
338 else {
339 assert(af == AF_INET6);
ee18f107 340 n = lookup(m->rtnl, ifindex, AF_INET, NULL);
877884fc
LP
341 }
342 if (n <= 0) /* error (if < 0) or really no gateway at all (if == 0) */
343 return n;
344
345 /* We have a gateway on the other protocol. Let's return > 0 without adding any RR to
346 * the answer, i.e. synthesize NODATA (and not NXDOMAIN!) */
347 return 1;
348 }
839a4a20
LP
349 }
350
acf06088
LP
351 r = answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
352 if (r < 0)
353 return r;
354
355 return 1; /* > 0 means: we have some gateway */
839a4a20
LP
356}
357
358static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
359 _cleanup_free_ struct local_address *addresses = NULL;
360 int n;
361
362 assert(m);
363 assert(address);
364 assert(answer);
365
366 n = local_gateways(m->rtnl, ifindex, af, &addresses);
2855b6c3 367 if (n <= 0)
839a4a20
LP
368 return n;
369
5248e7e1 370 return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
839a4a20
LP
371}
372
373int dns_synthesize_answer(
374 Manager *m,
375 DnsQuestion *q,
376 int ifindex,
dd0bc0f1 377 DnsAnswer **ret) {
839a4a20
LP
378
379 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
380 DnsResourceKey *key;
acf06088 381 bool found = false, nxdomain = false;
839a4a20
LP
382 int r;
383
384 assert(m);
385 assert(q);
386
387 DNS_QUESTION_FOREACH(key, q) {
388 union in_addr_union address;
389 const char *name;
390 int af;
391
4c701096 392 if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
839a4a20
LP
393 continue;
394
1c02e7ba 395 name = dns_resource_key_name(key);
839a4a20 396
3b2ac14a
YW
397 if (dns_name_is_empty(name)) {
398 /* Do nothing. */
399
f4526f82
LP
400 } else if (dns_name_dont_resolve(name)) {
401 /* Synthesize NXDOMAIN for some of the domains in RFC6303 + RFC6761 */
46b53e80
YW
402 nxdomain = true;
403 continue;
404
3b2ac14a 405 } else if (is_localhost(name)) {
839a4a20
LP
406
407 r = synthesize_localhost_rr(m, key, ifindex, &answer);
408 if (r < 0)
409 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
410
411 } else if (manager_is_own_hostname(m, name)) {
412
413 r = synthesize_system_hostname_rr(m, key, ifindex, &answer);
414 if (r < 0)
415 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
416
417 } else if (is_gateway_hostname(name)) {
418
ee18f107 419 r = synthesize_gateway_rr(m, key, ifindex, local_gateways, &answer);
839a4a20
LP
420 if (r < 0)
421 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
acf06088
LP
422 if (r == 0) { /* if we have no gateway return NXDOMAIN */
423 nxdomain = true;
424 continue;
425 }
839a4a20 426
ee18f107
LP
427 } else if (is_outbound_hostname(name)) {
428
429 r = synthesize_gateway_rr(m, key, ifindex, local_outbounds, &answer);
430 if (r < 0)
431 return log_error_errno(r, "Failed to synthesize outbound RRs: %m");
432 if (r == 0) { /* if we have no gateway return NXDOMAIN */
433 nxdomain = true;
434 continue;
435 }
436
839a4a20
LP
437 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
438 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) {
439
440 r = synthesize_localhost_ptr(m, key, ifindex, &answer);
441 if (r < 0)
442 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
443
444 } else if (dns_name_address(name, &af, &address) > 0) {
2855b6c3 445 int v, w;
839a4a20 446
2855b6c3
LP
447 v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
448 if (v < 0)
4a0e9289 449 return log_error_errno(v, "Failed to synthesize system hostname PTR RR: %m");
839a4a20 450
2855b6c3
LP
451 w = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
452 if (w < 0)
4a0e9289 453 return log_error_errno(w, "Failed to synthesize gateway hostname PTR RR: %m");
2855b6c3
LP
454
455 if (v == 0 && w == 0) /* This IP address is neither a local one nor a gateway */
456 continue;
457
ee18f107
LP
458 /* Note that we never synthesize reverse PTR for _outbound, since those are local
459 * addresses and thus mapped to the local hostname anyway, hence they already have a
460 * mapping. */
461
528e685e
LP
462 } else
463 continue;
464
465 found = true;
839a4a20
LP
466 }
467
acf06088 468 if (found) {
839a4a20 469
1cc6c93a
YW
470 if (ret)
471 *ret = TAKE_PTR(answer);
acf06088
LP
472
473 return 1;
474 } else if (nxdomain)
475 return -ENXIO;
839a4a20 476
acf06088 477 return 0;
839a4a20 478}