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