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