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