1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 
dns_synthesize_ifindex(int ifindex)9 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         if (ifindex > 0)
18                 return ifindex;
19 
20         return LOOPBACK_IFINDEX;
21 }
22 
dns_synthesize_family(uint64_t flags)23 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         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 
dns_synthesize_protocol(uint64_t flags)41 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         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 
synthesize_localhost_rr(Manager * m,const DnsResourceKey * key,int ifindex,DnsAnswer ** answer)59 static 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 
73                 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
74                 if (!rr)
75                         return -ENOMEM;
76 
77                 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
78 
79                 r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
80                 if (r < 0)
81                         return r;
82         }
83 
84         if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY) && socket_ipv6_is_enabled()) {
85                 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
86 
87                 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key));
88                 if (!rr)
89                         return -ENOMEM;
90 
91                 rr->aaaa.in6_addr = in6addr_loopback;
92 
93                 r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL);
94                 if (r < 0)
95                         return r;
96         }
97 
98         return 0;
99 }
100 
answer_add_ptr(DnsAnswer ** answer,const char * from,const char * to,int ifindex,DnsAnswerFlags flags)101 static 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 
112         return dns_answer_add(*answer, rr, ifindex, flags, NULL);
113 }
114 
synthesize_localhost_ptr(Manager * m,const DnsResourceKey * key,int ifindex,DnsAnswer ** answer)115 static 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 
127                 r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
128                 if (r < 0)
129                         return r;
130         }
131 
132         return 0;
133 }
134 
answer_add_addresses_rr(DnsAnswer ** answer,const char * name,struct local_address * addresses,unsigned n_addresses)135 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         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 
158                 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
159                 if (r < 0)
160                         return r;
161         }
162 
163         return 0;
164 }
165 
answer_add_addresses_ptr(DnsAnswer ** answer,const char * name,struct local_address * addresses,unsigned n_addresses,int af,const union in_addr_union * match)166 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         bool added = false;
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 
200                 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
201                 if (r < 0)
202                         return r;
203 
204                 added = true;
205         }
206 
207         return added;
208 }
209 
synthesize_system_hostname_rr(Manager * m,const DnsResourceKey * key,int ifindex,DnsAnswer ** answer)210 static 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 
230                         if (IN_SET(af, AF_INET, AF_UNSPEC))
231                                 buffer[n++] = (struct local_address) {
232                                         .family = AF_INET,
233                                         .ifindex = dns_synthesize_ifindex(ifindex),
234                                         .address.in.s_addr = htobe32(0x7F000002),
235                                 };
236 
237                         if (IN_SET(af, AF_INET6, AF_UNSPEC) && socket_ipv6_is_enabled())
238                                 buffer[n++] = (struct local_address) {
239                                         .family = AF_INET6,
240                                         .ifindex = dns_synthesize_ifindex(ifindex),
241                                         .address.in6 = in6addr_loopback,
242                                 };
243 
244                         return answer_add_addresses_rr(answer,
245                                                        dns_resource_key_name(key),
246                                                        buffer, n);
247                 }
248         }
249 
250         return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
251 }
252 
synthesize_system_hostname_ptr(Manager * m,int af,const union in_addr_union * address,int ifindex,DnsAnswer ** answer)253 static 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;
255         bool added = false;
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 
264                 /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
265 
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);
271                 if (r < 0)
272                         return r;
273 
274                 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
275                 if (r < 0)
276                         return r;
277 
278                 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
279                 if (r < 0)
280                         return r;
281 
282                 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
283                 if (r < 0)
284                         return r;
285 
286                 return 1;
287         }
288 
289         n = local_addresses(m->rtnl, ifindex, af, &addresses);
290         if (n <= 0)
291                 return n;
292 
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 
299         r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address);
300         if (r < 0)
301                 return r;
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;
310 
311         return added;
312 }
313 
synthesize_gateway_rr(Manager * m,const DnsResourceKey * key,int ifindex,int (* lookup)(sd_netlink * context,int ifindex,int af,struct local_address ** ret),DnsAnswer ** answer)314 static 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) {
320         _cleanup_free_ struct local_address *addresses = NULL;
321         int n = 0, af, r;
322 
323         assert(m);
324         assert(key);
325         assert(lookup);
326         assert(answer);
327 
328         af = dns_type_to_af(key->type);
329         if (af >= 0) {
330                 n = lookup(m->rtnl, ifindex, af, &addresses);
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)
337                                 n = lookup(m->rtnl, ifindex, AF_INET6, NULL);
338                         else {
339                                 assert(af == AF_INET6);
340                                 n = lookup(m->rtnl, ifindex, AF_INET, NULL);
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                 }
349         }
350 
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 */
356 }
357 
synthesize_gateway_ptr(Manager * m,int af,const union in_addr_union * address,int ifindex,DnsAnswer ** answer)358 static 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);
367         if (n <= 0)
368                 return n;
369 
370         return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
371 }
372 
dns_synthesize_answer(Manager * m,DnsQuestion * q,int ifindex,DnsAnswer ** ret)373 int dns_synthesize_answer(
374                 Manager *m,
375                 DnsQuestion *q,
376                 int ifindex,
377                 DnsAnswer **ret) {
378 
379         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
380         DnsResourceKey *key;
381         bool found = false, nxdomain = false;
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 
392                 if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
393                         continue;
394 
395                 name = dns_resource_key_name(key);
396 
397                 if (dns_name_is_empty(name)) {
398                         /* Do nothing. */
399 
400                 } else if (dns_name_dont_resolve(name)) {
401                         /* Synthesize NXDOMAIN for some of the domains in RFC6303 + RFC6761 */
402                         nxdomain = true;
403                         continue;
404 
405                 } else if (is_localhost(name)) {
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 
419                         r = synthesize_gateway_rr(m, key, ifindex, local_gateways, &answer);
420                         if (r < 0)
421                                 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
422                         if (r == 0) { /* if we have no gateway return NXDOMAIN */
423                                 nxdomain = true;
424                                 continue;
425                         }
426 
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 
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) {
445                         int v, w;
446 
447                         v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
448                         if (v < 0)
449                                 return log_error_errno(v, "Failed to synthesize system hostname PTR RR: %m");
450 
451                         w = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
452                         if (w < 0)
453                                 return log_error_errno(w, "Failed to synthesize gateway hostname PTR RR: %m");
454 
455                         if (v == 0 && w == 0) /* This IP address is neither a local one nor a gateway */
456                                 continue;
457 
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 
462                 } else
463                         continue;
464 
465                 found = true;
466         }
467 
468         if (found) {
469 
470                 if (ret)
471                         *ret = TAKE_PTR(answer);
472 
473                 return 1;
474         } else if (nxdomain)
475                 return -ENXIO;
476 
477         return 0;
478 }
479