]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-synthesize.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / resolve / resolved-dns-synthesize.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
839a4a20 2/***
839a4a20 3 Copyright 2014 Lennart Poettering
839a4a20
LP
4***/
5
6#include "alloc-util.h"
7#include "hostname-util.h"
8#include "local-addresses.h"
9#include "resolved-dns-synthesize.h"
10
dd0bc0f1 11int dns_synthesize_ifindex(int ifindex) {
839a4a20
LP
12
13 /* When the caller asked for resolving on a specific
14 * interface, we synthesize the answer for that
15 * interface. However, if nothing specific was claimed and we
16 * only return localhost RRs, we synthesize the answer for
17 * localhost. */
18
19 if (ifindex > 0)
20 return ifindex;
21
22 return LOOPBACK_IFINDEX;
23}
24
dd0bc0f1 25int dns_synthesize_family(uint64_t flags) {
839a4a20
LP
26
27 /* Picks an address family depending on set flags. This is
28 * purely for synthesized answers, where the family we return
29 * for the reply should match what was requested in the
30 * question, even though we are synthesizing the answer
31 * here. */
32
33 if (!(flags & SD_RESOLVED_DNS)) {
34 if (flags & (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_MDNS_IPV4))
35 return AF_INET;
36 if (flags & (SD_RESOLVED_LLMNR_IPV6|SD_RESOLVED_MDNS_IPV6))
37 return AF_INET6;
38 }
39
40 return AF_UNSPEC;
41}
42
dd0bc0f1 43DnsProtocol dns_synthesize_protocol(uint64_t flags) {
839a4a20 44
dd0bc0f1 45 /* Similar as dns_synthesize_family() but does this for the
839a4a20
LP
46 * protocol. If resolving via DNS was requested, we claim it
47 * was DNS. Similar, if nothing specific was
48 * requested. However, if only resolving via LLMNR was
49 * requested we return that. */
50
51 if (flags & SD_RESOLVED_DNS)
52 return DNS_PROTOCOL_DNS;
53 if (flags & SD_RESOLVED_LLMNR)
54 return DNS_PROTOCOL_LLMNR;
55 if (flags & SD_RESOLVED_MDNS)
56 return DNS_PROTOCOL_MDNS;
57
58 return DNS_PROTOCOL_DNS;
59}
60
61static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
62 int r;
63
64 assert(m);
65 assert(key);
66 assert(answer);
67
68 r = dns_answer_reserve(answer, 2);
69 if (r < 0)
70 return r;
71
72 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
73 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
74
1c02e7ba 75 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
839a4a20
LP
76 if (!rr)
77 return -ENOMEM;
78
79 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
80
dd0bc0f1 81 r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
82 if (r < 0)
83 return r;
84 }
85
86 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
87 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
88
1c02e7ba 89 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key));
839a4a20
LP
90 if (!rr)
91 return -ENOMEM;
92
93 rr->aaaa.in6_addr = in6addr_loopback;
94
dd0bc0f1 95 r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
96 if (r < 0)
97 return r;
98 }
99
100 return 0;
101}
102
103static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
104 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
105
106 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
107 if (!rr)
108 return -ENOMEM;
109
110 rr->ptr.name = strdup(to);
111 if (!rr->ptr.name)
112 return -ENOMEM;
113
114 return dns_answer_add(*answer, rr, ifindex, flags);
115}
116
117static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
118 int r;
119
120 assert(m);
121 assert(key);
122 assert(answer);
123
124 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
125 r = dns_answer_reserve(answer, 1);
126 if (r < 0)
127 return r;
128
1c02e7ba 129 r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
130 if (r < 0)
131 return r;
132 }
133
134 return 0;
135}
136
137static int answer_add_addresses_rr(
138 DnsAnswer **answer,
139 const char *name,
140 struct local_address *addresses,
141 unsigned n_addresses) {
142
143 unsigned j;
144 int r;
145
146 assert(answer);
147 assert(name);
148
149 r = dns_answer_reserve(answer, n_addresses);
150 if (r < 0)
151 return r;
152
153 for (j = 0; j < n_addresses; j++) {
154 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
155
156 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
157 if (r < 0)
158 return r;
159
160 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
161 if (r < 0)
162 return r;
163 }
164
165 return 0;
166}
167
168static int answer_add_addresses_ptr(
169 DnsAnswer **answer,
170 const char *name,
171 struct local_address *addresses,
172 unsigned n_addresses,
173 int af, const union in_addr_union *match) {
174
2855b6c3 175 bool added = false;
839a4a20
LP
176 unsigned j;
177 int r;
178
179 assert(answer);
180 assert(name);
181
182 for (j = 0; j < n_addresses; j++) {
183 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
184
185 if (af != AF_UNSPEC) {
186
187 if (addresses[j].family != af)
188 continue;
189
190 if (match && !in_addr_equal(af, match, &addresses[j].address))
191 continue;
192 }
193
194 r = dns_answer_reserve(answer, 1);
195 if (r < 0)
196 return r;
197
198 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
199 if (r < 0)
200 return r;
201
202 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
203 if (r < 0)
204 return r;
2855b6c3
LP
205
206 added = true;
839a4a20
LP
207 }
208
2855b6c3 209 return added;
839a4a20
LP
210}
211
212static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
213 _cleanup_free_ struct local_address *addresses = NULL;
214 int n = 0, af;
215
216 assert(m);
217 assert(key);
218 assert(answer);
219
220 af = dns_type_to_af(key->type);
221 if (af >= 0) {
222 n = local_addresses(m->rtnl, ifindex, af, &addresses);
223 if (n < 0)
224 return n;
225
226 if (n == 0) {
227 struct local_address buffer[2];
228
229 /* If we have no local addresses then use ::1
230 * and 127.0.0.2 as local ones. */
231
3742095b 232 if (IN_SET(af, AF_INET, AF_UNSPEC))
839a4a20
LP
233 buffer[n++] = (struct local_address) {
234 .family = AF_INET,
dd0bc0f1 235 .ifindex = dns_synthesize_ifindex(ifindex),
839a4a20
LP
236 .address.in.s_addr = htobe32(0x7F000002),
237 };
238
3742095b 239 if (IN_SET(af, AF_INET6, AF_UNSPEC))
839a4a20
LP
240 buffer[n++] = (struct local_address) {
241 .family = AF_INET6,
dd0bc0f1 242 .ifindex = dns_synthesize_ifindex(ifindex),
839a4a20
LP
243 .address.in6 = in6addr_loopback,
244 };
245
3742095b
AR
246 return answer_add_addresses_rr(answer,
247 dns_resource_key_name(key),
248 buffer, n);
839a4a20
LP
249 }
250 }
251
1c02e7ba 252 return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
839a4a20
LP
253}
254
255static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
256 _cleanup_free_ struct local_address *addresses = NULL;
2855b6c3 257 bool added = false;
839a4a20
LP
258 int n, r;
259
260 assert(m);
261 assert(address);
262 assert(answer);
263
264 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
265
a4f3375d 266 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
839a4a20 267
a4f3375d
LP
268 r = dns_answer_reserve(answer, 4);
269 if (r < 0)
270 return r;
271
272 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
273 if (r < 0)
274 return r;
275
dd0bc0f1 276 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
277 if (r < 0)
278 return r;
279
dd0bc0f1 280 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
281 if (r < 0)
282 return r;
283
dd0bc0f1 284 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
839a4a20
LP
285 if (r < 0)
286 return r;
287
2855b6c3 288 return 1;
839a4a20
LP
289 }
290
291 n = local_addresses(m->rtnl, ifindex, af, &addresses);
2855b6c3 292 if (n <= 0)
839a4a20
LP
293 return n;
294
a4f3375d
LP
295 r = answer_add_addresses_ptr(answer, m->full_hostname, addresses, n, af, address);
296 if (r < 0)
297 return r;
298 if (r > 0)
299 added = true;
300
839a4a20
LP
301 r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address);
302 if (r < 0)
303 return r;
2855b6c3
LP
304 if (r > 0)
305 added = true;
306
307 r = answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
308 if (r < 0)
309 return r;
310 if (r > 0)
311 added = true;
839a4a20 312
2855b6c3 313 return added;
839a4a20
LP
314}
315
316static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
317 _cleanup_free_ struct local_address *addresses = NULL;
acf06088 318 int n = 0, af, r;
839a4a20
LP
319
320 assert(m);
321 assert(key);
322 assert(answer);
323
324 af = dns_type_to_af(key->type);
325 if (af >= 0) {
326 n = local_gateways(m->rtnl, ifindex, af, &addresses);
acf06088
LP
327 if (n <= 0)
328 return n; /* < 0 means: error; == 0 means we have no gateway */
839a4a20
LP
329 }
330
acf06088
LP
331 r = answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
332 if (r < 0)
333 return r;
334
335 return 1; /* > 0 means: we have some gateway */
839a4a20
LP
336}
337
338static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
339 _cleanup_free_ struct local_address *addresses = NULL;
340 int n;
341
342 assert(m);
343 assert(address);
344 assert(answer);
345
346 n = local_gateways(m->rtnl, ifindex, af, &addresses);
2855b6c3 347 if (n <= 0)
839a4a20
LP
348 return n;
349
5248e7e1 350 return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
839a4a20
LP
351}
352
353int dns_synthesize_answer(
354 Manager *m,
355 DnsQuestion *q,
356 int ifindex,
dd0bc0f1 357 DnsAnswer **ret) {
839a4a20
LP
358
359 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
360 DnsResourceKey *key;
acf06088 361 bool found = false, nxdomain = false;
839a4a20
LP
362 int r;
363
364 assert(m);
365 assert(q);
366
367 DNS_QUESTION_FOREACH(key, q) {
368 union in_addr_union address;
369 const char *name;
370 int af;
371
4c701096 372 if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
839a4a20
LP
373 continue;
374
1c02e7ba 375 name = dns_resource_key_name(key);
839a4a20
LP
376
377 if (is_localhost(name)) {
378
379 r = synthesize_localhost_rr(m, key, ifindex, &answer);
380 if (r < 0)
381 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
382
383 } else if (manager_is_own_hostname(m, name)) {
384
385 r = synthesize_system_hostname_rr(m, key, ifindex, &answer);
386 if (r < 0)
387 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
388
389 } else if (is_gateway_hostname(name)) {
390
391 r = synthesize_gateway_rr(m, key, ifindex, &answer);
392 if (r < 0)
393 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
acf06088
LP
394 if (r == 0) { /* if we have no gateway return NXDOMAIN */
395 nxdomain = true;
396 continue;
397 }
839a4a20
LP
398
399 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
400 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) {
401
402 r = synthesize_localhost_ptr(m, key, ifindex, &answer);
403 if (r < 0)
404 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
405
406 } else if (dns_name_address(name, &af, &address) > 0) {
2855b6c3 407 int v, w;
839a4a20 408
2855b6c3
LP
409 v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
410 if (v < 0)
4a0e9289 411 return log_error_errno(v, "Failed to synthesize system hostname PTR RR: %m");
839a4a20 412
2855b6c3
LP
413 w = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
414 if (w < 0)
4a0e9289 415 return log_error_errno(w, "Failed to synthesize gateway hostname PTR RR: %m");
2855b6c3
LP
416
417 if (v == 0 && w == 0) /* This IP address is neither a local one nor a gateway */
418 continue;
419
528e685e
LP
420 } else
421 continue;
422
423 found = true;
839a4a20
LP
424 }
425
acf06088 426 if (found) {
839a4a20 427
1cc6c93a
YW
428 if (ret)
429 *ret = TAKE_PTR(answer);
acf06088
LP
430
431 return 1;
432 } else if (nxdomain)
433 return -ENXIO;
839a4a20 434
acf06088 435 return 0;
839a4a20 436}