Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include "alloc-util.h"
4 : : #include "bus-common-errors.h"
5 : : #include "bus-util.h"
6 : : #include "dns-domain.h"
7 : : #include "memory-util.h"
8 : : #include "missing_capability.h"
9 : : #include "resolved-bus.h"
10 : : #include "resolved-def.h"
11 : : #include "resolved-dns-synthesize.h"
12 : : #include "resolved-dnssd-bus.h"
13 : : #include "resolved-dnssd.h"
14 : : #include "resolved-link-bus.h"
15 : : #include "user-util.h"
16 : : #include "utf8.h"
17 : :
18 [ # # # # : 0 : BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_resolve_support, resolve_support, ResolveSupport);
# # ]
19 : :
20 : 0 : static int reply_query_state(DnsQuery *q) {
21 : :
22 [ # # # # : 0 : switch (q->state) {
# # # # #
# # # # ]
23 : :
24 : 0 : case DNS_TRANSACTION_NO_SERVERS:
25 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
26 : :
27 : 0 : case DNS_TRANSACTION_TIMEOUT:
28 : 0 : return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
29 : :
30 : 0 : case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
31 : 0 : return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
32 : :
33 : 0 : case DNS_TRANSACTION_INVALID_REPLY:
34 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
35 : :
36 : 0 : case DNS_TRANSACTION_ERRNO:
37 : 0 : return sd_bus_reply_method_errnof(q->request, q->answer_errno, "Lookup failed due to system error: %m");
38 : :
39 : 0 : case DNS_TRANSACTION_ABORTED:
40 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
41 : :
42 : 0 : case DNS_TRANSACTION_DNSSEC_FAILED:
43 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s",
44 : : dnssec_result_to_string(q->answer_dnssec_result));
45 : :
46 : 0 : case DNS_TRANSACTION_NO_TRUST_ANCHOR:
47 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known");
48 : :
49 : 0 : case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
50 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
51 : :
52 : 0 : case DNS_TRANSACTION_NETWORK_DOWN:
53 : 0 : return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NETWORK_DOWN, "Network is down");
54 : :
55 : 0 : case DNS_TRANSACTION_NOT_FOUND:
56 : : /* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we
57 : : * thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
58 : 0 : return sd_bus_reply_method_errorf(q->request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
59 : :
60 : 0 : case DNS_TRANSACTION_RCODE_FAILURE: {
61 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
62 : :
63 [ # # ]: 0 : if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
64 : 0 : sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
65 : : else {
66 : : const char *rc, *n;
67 : : char p[DECIMAL_STR_MAX(q->answer_rcode)];
68 : :
69 : 0 : rc = dns_rcode_to_string(q->answer_rcode);
70 [ # # ]: 0 : if (!rc) {
71 : 0 : sprintf(p, "%i", q->answer_rcode);
72 : 0 : rc = p;
73 : : }
74 : :
75 [ # # # # : 0 : n = strjoina(_BUS_ERROR_DNS, rc);
# # # # #
# # # ]
76 : 0 : sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", dns_query_string(q), rc);
77 : : }
78 : :
79 : 0 : return sd_bus_reply_method_error(q->request, &error);
80 : : }
81 : :
82 : 0 : case DNS_TRANSACTION_NULL:
83 : : case DNS_TRANSACTION_PENDING:
84 : : case DNS_TRANSACTION_VALIDATING:
85 : : case DNS_TRANSACTION_SUCCESS:
86 : : default:
87 : 0 : assert_not_reached("Impossible state");
88 : : }
89 : : }
90 : :
91 : 0 : static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
92 : : int r;
93 : :
94 [ # # ]: 0 : assert(reply);
95 [ # # ]: 0 : assert(rr);
96 : :
97 : 0 : r = sd_bus_message_open_container(reply, 'r', "iiay");
98 [ # # ]: 0 : if (r < 0)
99 : 0 : return r;
100 : :
101 : 0 : r = sd_bus_message_append(reply, "i", ifindex);
102 [ # # ]: 0 : if (r < 0)
103 : 0 : return r;
104 : :
105 [ # # ]: 0 : if (rr->key->type == DNS_TYPE_A) {
106 : 0 : r = sd_bus_message_append(reply, "i", AF_INET);
107 [ # # ]: 0 : if (r < 0)
108 : 0 : return r;
109 : :
110 : 0 : r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
111 : :
112 [ # # ]: 0 : } else if (rr->key->type == DNS_TYPE_AAAA) {
113 : 0 : r = sd_bus_message_append(reply, "i", AF_INET6);
114 [ # # ]: 0 : if (r < 0)
115 : 0 : return r;
116 : :
117 : 0 : r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
118 : : } else
119 : 0 : return -EAFNOSUPPORT;
120 : :
121 [ # # ]: 0 : if (r < 0)
122 : 0 : return r;
123 : :
124 : 0 : r = sd_bus_message_close_container(reply);
125 [ # # ]: 0 : if (r < 0)
126 : 0 : return r;
127 : :
128 : 0 : return 0;
129 : : }
130 : :
131 : 0 : static void bus_method_resolve_hostname_complete(DnsQuery *q) {
132 [ # # ]: 0 : _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
133 [ # # ]: 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
134 [ # # ]: 0 : _cleanup_free_ char *normalized = NULL;
135 : : DnsResourceRecord *rr;
136 : 0 : unsigned added = 0;
137 : : int ifindex, r;
138 : :
139 [ # # ]: 0 : assert(q);
140 : :
141 [ # # ]: 0 : if (q->state != DNS_TRANSACTION_SUCCESS) {
142 : 0 : r = reply_query_state(q);
143 : 0 : goto finish;
144 : : }
145 : :
146 : 0 : r = dns_query_process_cname(q);
147 [ # # ]: 0 : if (r == -ELOOP) {
148 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
149 : 0 : goto finish;
150 : : }
151 [ # # ]: 0 : if (r < 0)
152 : 0 : goto finish;
153 [ # # ]: 0 : if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
154 : 0 : return;
155 : :
156 : 0 : r = sd_bus_message_new_method_return(q->request, &reply);
157 [ # # ]: 0 : if (r < 0)
158 : 0 : goto finish;
159 : :
160 : 0 : r = sd_bus_message_open_container(reply, 'a', "(iiay)");
161 [ # # ]: 0 : if (r < 0)
162 : 0 : goto finish;
163 : :
164 [ # # # # : 0 : DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
# # # # #
# # # # #
# # ]
165 : : DnsQuestion *question;
166 : :
167 : 0 : question = dns_query_question_for_protocol(q, q->answer_protocol);
168 : :
169 : 0 : r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
170 [ # # ]: 0 : if (r < 0)
171 : 0 : goto finish;
172 [ # # ]: 0 : if (r == 0)
173 : 0 : continue;
174 : :
175 : 0 : r = append_address(reply, rr, ifindex);
176 [ # # ]: 0 : if (r < 0)
177 : 0 : goto finish;
178 : :
179 [ # # ]: 0 : if (!canonical)
180 : 0 : canonical = dns_resource_record_ref(rr);
181 : :
182 : 0 : added++;
183 : : }
184 : :
185 [ # # ]: 0 : if (added <= 0) {
186 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
187 : 0 : goto finish;
188 : : }
189 : :
190 : 0 : r = sd_bus_message_close_container(reply);
191 [ # # ]: 0 : if (r < 0)
192 : 0 : goto finish;
193 : :
194 : : /* The key names are not necessarily normalized, make sure that they are when we return them to our bus
195 : : * clients. */
196 : 0 : r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
197 [ # # ]: 0 : if (r < 0)
198 : 0 : goto finish;
199 : :
200 : : /* Return the precise spelling and uppercasing and CNAME target reported by the server */
201 [ # # ]: 0 : assert(canonical);
202 : 0 : r = sd_bus_message_append(
203 : : reply, "st",
204 : : normalized,
205 : 0 : SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
206 [ # # ]: 0 : if (r < 0)
207 : 0 : goto finish;
208 : :
209 : 0 : r = sd_bus_send(q->manager->bus, reply, NULL);
210 : :
211 : 0 : finish:
212 [ # # ]: 0 : if (r < 0) {
213 [ # # ]: 0 : log_error_errno(r, "Failed to send hostname reply: %m");
214 : 0 : sd_bus_reply_method_errno(q->request, r, NULL);
215 : : }
216 : :
217 : 0 : dns_query_free(q);
218 : : }
219 : :
220 : 0 : static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
221 [ # # ]: 0 : assert(flags);
222 : :
223 [ # # ]: 0 : if (ifindex < 0)
224 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
225 : :
226 [ # # ]: 0 : if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
227 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
228 : :
229 [ # # ]: 0 : if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
230 : 0 : *flags |= SD_RESOLVED_PROTOCOLS_ALL;
231 : :
232 : 0 : return 0;
233 : : }
234 : :
235 : 0 : static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) {
236 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
237 : 0 : _cleanup_free_ char *canonical = NULL;
238 : : union in_addr_union parsed;
239 : 0 : int r, ff, parsed_ifindex = 0;
240 : :
241 : : /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it,
242 : : * let's not attempt to look it up. */
243 : :
244 : 0 : r = in_addr_ifindex_from_string_auto(hostname, &ff, &parsed, &parsed_ifindex);
245 [ # # ]: 0 : if (r < 0) /* not an address */
246 : 0 : return 0;
247 : :
248 [ # # # # ]: 0 : if (family != AF_UNSPEC && ff != family)
249 : 0 : return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family.");
250 [ # # # # : 0 : if (ifindex > 0 && parsed_ifindex > 0 && parsed_ifindex != ifindex)
# # ]
251 : 0 : return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address interface index does not match requested interface.");
252 : :
253 [ # # ]: 0 : if (parsed_ifindex > 0)
254 : 0 : ifindex = parsed_ifindex;
255 : :
256 : 0 : r = sd_bus_message_new_method_return(m, &reply);
257 [ # # ]: 0 : if (r < 0)
258 : 0 : return r;
259 : :
260 : 0 : r = sd_bus_message_open_container(reply, 'a', "(iiay)");
261 [ # # ]: 0 : if (r < 0)
262 : 0 : return r;
263 : :
264 : 0 : r = sd_bus_message_open_container(reply, 'r', "iiay");
265 [ # # ]: 0 : if (r < 0)
266 : 0 : return r;
267 : :
268 : 0 : r = sd_bus_message_append(reply, "ii", ifindex, ff);
269 [ # # ]: 0 : if (r < 0)
270 : 0 : return r;
271 : :
272 : 0 : r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff));
273 [ # # ]: 0 : if (r < 0)
274 : 0 : return r;
275 : :
276 : 0 : r = sd_bus_message_close_container(reply);
277 [ # # ]: 0 : if (r < 0)
278 : 0 : return r;
279 : :
280 : 0 : r = sd_bus_message_close_container(reply);
281 [ # # ]: 0 : if (r < 0)
282 : 0 : return r;
283 : :
284 : : /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS
285 : : * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner
286 : : * omissions are always done the same way). */
287 : 0 : r = in_addr_ifindex_to_string(ff, &parsed, ifindex, &canonical);
288 [ # # ]: 0 : if (r < 0)
289 : 0 : return r;
290 : :
291 : 0 : r = sd_bus_message_append(reply, "st", canonical,
292 : : SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true));
293 [ # # ]: 0 : if (r < 0)
294 : 0 : return r;
295 : :
296 : 0 : return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
297 : : }
298 : :
299 : 0 : static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
300 : 0 : _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
301 : 0 : Manager *m = userdata;
302 : : const char *hostname;
303 : : int family, ifindex;
304 : : uint64_t flags;
305 : : DnsQuery *q;
306 : : int r;
307 : :
308 [ # # ]: 0 : assert(message);
309 [ # # ]: 0 : assert(m);
310 : :
311 : : assert_cc(sizeof(int) == sizeof(int32_t));
312 : :
313 : 0 : r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
314 [ # # ]: 0 : if (r < 0)
315 : 0 : return r;
316 : :
317 [ # # # # ]: 0 : if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
318 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
319 : :
320 : 0 : r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
321 [ # # ]: 0 : if (r < 0)
322 : 0 : return r;
323 : :
324 : 0 : r = parse_as_address(message, ifindex, hostname, family, flags);
325 [ # # ]: 0 : if (r != 0)
326 : 0 : return r;
327 : :
328 : 0 : r = dns_name_is_valid(hostname);
329 [ # # ]: 0 : if (r < 0)
330 : 0 : return r;
331 [ # # ]: 0 : if (r == 0)
332 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
333 : :
334 : 0 : r = dns_question_new_address(&question_utf8, family, hostname, false);
335 [ # # ]: 0 : if (r < 0)
336 : 0 : return r;
337 : :
338 : 0 : r = dns_question_new_address(&question_idna, family, hostname, true);
339 [ # # # # ]: 0 : if (r < 0 && r != -EALREADY)
340 : 0 : return r;
341 : :
342 [ # # ]: 0 : r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, ifindex, flags);
343 [ # # ]: 0 : if (r < 0)
344 : 0 : return r;
345 : :
346 : 0 : q->request = sd_bus_message_ref(message);
347 : 0 : q->request_family = family;
348 : 0 : q->complete = bus_method_resolve_hostname_complete;
349 : 0 : q->suppress_unroutable_family = family == AF_UNSPEC;
350 : :
351 : 0 : r = dns_query_bus_track(q, message);
352 [ # # ]: 0 : if (r < 0)
353 : 0 : goto fail;
354 : :
355 : 0 : r = dns_query_go(q);
356 [ # # ]: 0 : if (r < 0)
357 : 0 : goto fail;
358 : :
359 : 0 : return 1;
360 : :
361 : 0 : fail:
362 : 0 : dns_query_free(q);
363 : 0 : return r;
364 : : }
365 : :
366 : 0 : static void bus_method_resolve_address_complete(DnsQuery *q) {
367 [ # # ]: 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
368 : : DnsQuestion *question;
369 : : DnsResourceRecord *rr;
370 : 0 : unsigned added = 0;
371 : : int ifindex, r;
372 : :
373 [ # # ]: 0 : assert(q);
374 : :
375 [ # # ]: 0 : if (q->state != DNS_TRANSACTION_SUCCESS) {
376 : 0 : r = reply_query_state(q);
377 : 0 : goto finish;
378 : : }
379 : :
380 : 0 : r = dns_query_process_cname(q);
381 [ # # ]: 0 : if (r == -ELOOP) {
382 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
383 : 0 : goto finish;
384 : : }
385 [ # # ]: 0 : if (r < 0)
386 : 0 : goto finish;
387 [ # # ]: 0 : if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
388 : 0 : return;
389 : :
390 : 0 : r = sd_bus_message_new_method_return(q->request, &reply);
391 [ # # ]: 0 : if (r < 0)
392 : 0 : goto finish;
393 : :
394 : 0 : r = sd_bus_message_open_container(reply, 'a', "(is)");
395 [ # # ]: 0 : if (r < 0)
396 : 0 : goto finish;
397 : :
398 : 0 : question = dns_query_question_for_protocol(q, q->answer_protocol);
399 : :
400 [ # # # # : 0 : DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
# # # # #
# # # # #
# # ]
401 [ # # # ]: 0 : _cleanup_free_ char *normalized = NULL;
402 : :
403 : 0 : r = dns_question_matches_rr(question, rr, NULL);
404 [ # # ]: 0 : if (r < 0)
405 : 0 : goto finish;
406 [ # # ]: 0 : if (r == 0)
407 : 0 : continue;
408 : :
409 : 0 : r = dns_name_normalize(rr->ptr.name, 0, &normalized);
410 [ # # ]: 0 : if (r < 0)
411 : 0 : goto finish;
412 : :
413 : 0 : r = sd_bus_message_append(reply, "(is)", ifindex, normalized);
414 [ # # ]: 0 : if (r < 0)
415 : 0 : goto finish;
416 : :
417 : 0 : added++;
418 : : }
419 : :
420 [ # # ]: 0 : if (added <= 0) {
421 : 0 : _cleanup_free_ char *ip = NULL;
422 : :
423 : 0 : (void) in_addr_to_string(q->request_family, &q->request_address, &ip);
424 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR,
425 : : "Address '%s' does not have any RR of requested type", strnull(ip));
426 : 0 : goto finish;
427 : : }
428 : :
429 : 0 : r = sd_bus_message_close_container(reply);
430 [ # # ]: 0 : if (r < 0)
431 : 0 : goto finish;
432 : :
433 : 0 : r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
434 [ # # ]: 0 : if (r < 0)
435 : 0 : goto finish;
436 : :
437 : 0 : r = sd_bus_send(q->manager->bus, reply, NULL);
438 : :
439 : 0 : finish:
440 [ # # ]: 0 : if (r < 0) {
441 [ # # ]: 0 : log_error_errno(r, "Failed to send address reply: %m");
442 : 0 : sd_bus_reply_method_errno(q->request, r, NULL);
443 : : }
444 : :
445 : 0 : dns_query_free(q);
446 : : }
447 : :
448 : 0 : static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
449 : 0 : _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
450 : 0 : Manager *m = userdata;
451 : : int family, ifindex;
452 : : uint64_t flags;
453 : : const void *d;
454 : : DnsQuery *q;
455 : : size_t sz;
456 : : int r;
457 : :
458 [ # # ]: 0 : assert(message);
459 [ # # ]: 0 : assert(m);
460 : :
461 : : assert_cc(sizeof(int) == sizeof(int32_t));
462 : :
463 : 0 : r = sd_bus_message_read(message, "ii", &ifindex, &family);
464 [ # # ]: 0 : if (r < 0)
465 : 0 : return r;
466 : :
467 [ # # # # ]: 0 : if (!IN_SET(family, AF_INET, AF_INET6))
468 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
469 : :
470 : 0 : r = sd_bus_message_read_array(message, 'y', &d, &sz);
471 [ # # ]: 0 : if (r < 0)
472 : 0 : return r;
473 : :
474 [ # # ]: 0 : if (sz != FAMILY_ADDRESS_SIZE(family))
475 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
476 : :
477 : 0 : r = sd_bus_message_read(message, "t", &flags);
478 [ # # ]: 0 : if (r < 0)
479 : 0 : return r;
480 : :
481 : 0 : r = check_ifindex_flags(ifindex, &flags, 0, error);
482 [ # # ]: 0 : if (r < 0)
483 : 0 : return r;
484 : :
485 : 0 : r = dns_question_new_reverse(&question, family, d);
486 [ # # ]: 0 : if (r < 0)
487 : 0 : return r;
488 : :
489 : 0 : r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
490 [ # # ]: 0 : if (r < 0)
491 : 0 : return r;
492 : :
493 : 0 : q->request = sd_bus_message_ref(message);
494 : 0 : q->request_family = family;
495 : 0 : memcpy(&q->request_address, d, sz);
496 : 0 : q->complete = bus_method_resolve_address_complete;
497 : :
498 : 0 : r = dns_query_bus_track(q, message);
499 [ # # ]: 0 : if (r < 0)
500 : 0 : goto fail;
501 : :
502 : 0 : r = dns_query_go(q);
503 [ # # ]: 0 : if (r < 0)
504 : 0 : goto fail;
505 : :
506 : 0 : return 1;
507 : :
508 : 0 : fail:
509 : 0 : dns_query_free(q);
510 : 0 : return r;
511 : : }
512 : :
513 : 0 : static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) {
514 : : int r;
515 : :
516 [ # # ]: 0 : assert(m);
517 [ # # ]: 0 : assert(rr);
518 : :
519 : 0 : r = sd_bus_message_open_container(m, 'r', "iqqay");
520 [ # # ]: 0 : if (r < 0)
521 : 0 : return r;
522 : :
523 : 0 : r = sd_bus_message_append(m, "iqq",
524 : : ifindex,
525 : 0 : rr->key->class,
526 : 0 : rr->key->type);
527 [ # # ]: 0 : if (r < 0)
528 : 0 : return r;
529 : :
530 : 0 : r = dns_resource_record_to_wire_format(rr, false);
531 [ # # ]: 0 : if (r < 0)
532 : 0 : return r;
533 : :
534 : 0 : r = sd_bus_message_append_array(m, 'y', rr->wire_format, rr->wire_format_size);
535 [ # # ]: 0 : if (r < 0)
536 : 0 : return r;
537 : :
538 : 0 : return sd_bus_message_close_container(m);
539 : : }
540 : :
541 : 0 : static void bus_method_resolve_record_complete(DnsQuery *q) {
542 [ # # ]: 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
543 : : DnsResourceRecord *rr;
544 : : DnsQuestion *question;
545 : 0 : unsigned added = 0;
546 : : int ifindex;
547 : : int r;
548 : :
549 [ # # ]: 0 : assert(q);
550 : :
551 [ # # ]: 0 : if (q->state != DNS_TRANSACTION_SUCCESS) {
552 : 0 : r = reply_query_state(q);
553 : 0 : goto finish;
554 : : }
555 : :
556 : 0 : r = dns_query_process_cname(q);
557 [ # # ]: 0 : if (r == -ELOOP) {
558 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
559 : 0 : goto finish;
560 : : }
561 [ # # ]: 0 : if (r < 0)
562 : 0 : goto finish;
563 [ # # ]: 0 : if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
564 : 0 : return;
565 : :
566 : 0 : r = sd_bus_message_new_method_return(q->request, &reply);
567 [ # # ]: 0 : if (r < 0)
568 : 0 : goto finish;
569 : :
570 : 0 : r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
571 [ # # ]: 0 : if (r < 0)
572 : 0 : goto finish;
573 : :
574 : 0 : question = dns_query_question_for_protocol(q, q->answer_protocol);
575 : :
576 [ # # # # : 0 : DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
# # # # #
# # # # #
# # ]
577 : 0 : r = dns_question_matches_rr(question, rr, NULL);
578 [ # # ]: 0 : if (r < 0)
579 : 0 : goto finish;
580 [ # # ]: 0 : if (r == 0)
581 : 0 : continue;
582 : :
583 : 0 : r = bus_message_append_rr(reply, rr, ifindex);
584 [ # # ]: 0 : if (r < 0)
585 : 0 : goto finish;
586 : :
587 : 0 : added++;
588 : : }
589 : :
590 [ # # ]: 0 : if (added <= 0) {
591 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_query_string(q));
592 : 0 : goto finish;
593 : : }
594 : :
595 : 0 : r = sd_bus_message_close_container(reply);
596 [ # # ]: 0 : if (r < 0)
597 : 0 : goto finish;
598 : :
599 : 0 : r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
600 [ # # ]: 0 : if (r < 0)
601 : 0 : goto finish;
602 : :
603 : 0 : r = sd_bus_send(q->manager->bus, reply, NULL);
604 : :
605 : 0 : finish:
606 [ # # ]: 0 : if (r < 0) {
607 [ # # ]: 0 : log_error_errno(r, "Failed to send record reply: %m");
608 : 0 : sd_bus_reply_method_errno(q->request, r, NULL);
609 : : }
610 : :
611 : 0 : dns_query_free(q);
612 : : }
613 : :
614 : 0 : static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
615 : 0 : _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
616 : 0 : _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
617 : 0 : Manager *m = userdata;
618 : : uint16_t class, type;
619 : : const char *name;
620 : : int r, ifindex;
621 : : uint64_t flags;
622 : : DnsQuery *q;
623 : :
624 [ # # ]: 0 : assert(message);
625 [ # # ]: 0 : assert(m);
626 : :
627 : : assert_cc(sizeof(int) == sizeof(int32_t));
628 : :
629 : 0 : r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
630 [ # # ]: 0 : if (r < 0)
631 : 0 : return r;
632 : :
633 : 0 : r = dns_name_is_valid(name);
634 [ # # ]: 0 : if (r < 0)
635 : 0 : return r;
636 [ # # ]: 0 : if (r == 0)
637 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
638 : :
639 [ # # ]: 0 : if (!dns_type_is_valid_query(type))
640 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified resource record type %" PRIu16 " may not be used in a query.", type);
641 [ # # ]: 0 : if (dns_type_is_zone_transer(type))
642 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Zone transfers not permitted via this programming interface.");
643 [ # # ]: 0 : if (dns_type_is_obsolete(type))
644 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
645 : :
646 : 0 : r = check_ifindex_flags(ifindex, &flags, 0, error);
647 [ # # ]: 0 : if (r < 0)
648 : 0 : return r;
649 : :
650 : 0 : question = dns_question_new(1);
651 [ # # ]: 0 : if (!question)
652 : 0 : return -ENOMEM;
653 : :
654 : 0 : key = dns_resource_key_new(class, type, name);
655 [ # # ]: 0 : if (!key)
656 : 0 : return -ENOMEM;
657 : :
658 : 0 : r = dns_question_add(question, key);
659 [ # # ]: 0 : if (r < 0)
660 : 0 : return r;
661 : :
662 : 0 : r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
663 [ # # ]: 0 : if (r < 0)
664 : 0 : return r;
665 : :
666 : : /* Let's request that the TTL is fixed up for locally cached entries, after all we return it in the wire format
667 : : * blob */
668 : 0 : q->clamp_ttl = true;
669 : :
670 : 0 : q->request = sd_bus_message_ref(message);
671 : 0 : q->complete = bus_method_resolve_record_complete;
672 : :
673 : 0 : r = dns_query_bus_track(q, message);
674 [ # # ]: 0 : if (r < 0)
675 : 0 : goto fail;
676 : :
677 : 0 : r = dns_query_go(q);
678 [ # # ]: 0 : if (r < 0)
679 : 0 : goto fail;
680 : :
681 : 0 : return 1;
682 : :
683 : 0 : fail:
684 : 0 : dns_query_free(q);
685 : 0 : return r;
686 : : }
687 : :
688 : 0 : static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
689 : 0 : _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
690 : 0 : _cleanup_free_ char *normalized = NULL;
691 : : DnsQuery *aux;
692 : : int r;
693 : :
694 [ # # ]: 0 : assert(q);
695 [ # # ]: 0 : assert(reply);
696 [ # # ]: 0 : assert(rr);
697 [ # # ]: 0 : assert(rr->key);
698 : :
699 [ # # ]: 0 : if (rr->key->type != DNS_TYPE_SRV)
700 : 0 : return 0;
701 : :
702 [ # # ]: 0 : if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
703 : : /* First, let's see if we could find an appropriate A or AAAA
704 : : * record for the SRV record */
705 [ # # ]: 0 : LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
706 : : DnsResourceRecord *zz;
707 : : DnsQuestion *question;
708 : :
709 [ # # ]: 0 : if (aux->state != DNS_TRANSACTION_SUCCESS)
710 : 0 : continue;
711 [ # # ]: 0 : if (aux->auxiliary_result != 0)
712 : 0 : continue;
713 : :
714 : 0 : question = dns_query_question_for_protocol(aux, aux->answer_protocol);
715 : :
716 : 0 : r = dns_name_equal(dns_question_first_name(question), rr->srv.name);
717 [ # # ]: 0 : if (r < 0)
718 : 0 : return r;
719 [ # # ]: 0 : if (r == 0)
720 : 0 : continue;
721 : :
722 [ # # # # : 0 : DNS_ANSWER_FOREACH(zz, aux->answer) {
# # # # ]
723 : :
724 : 0 : r = dns_question_matches_rr(question, zz, NULL);
725 [ # # ]: 0 : if (r < 0)
726 : 0 : return r;
727 [ # # ]: 0 : if (r == 0)
728 [ # # ]: 0 : continue;
729 : :
730 : 0 : canonical = dns_resource_record_ref(zz);
731 : 0 : break;
732 : : }
733 : :
734 [ # # ]: 0 : if (canonical)
735 : 0 : break;
736 : : }
737 : :
738 : : /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */
739 [ # # ]: 0 : if (!canonical)
740 : 0 : return 0;
741 : : }
742 : :
743 : 0 : r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s");
744 [ # # ]: 0 : if (r < 0)
745 : 0 : return r;
746 : :
747 : 0 : r = dns_name_normalize(rr->srv.name, 0, &normalized);
748 [ # # ]: 0 : if (r < 0)
749 : 0 : return r;
750 : :
751 : 0 : r = sd_bus_message_append(
752 : : reply,
753 : : "qqqs",
754 : 0 : rr->srv.priority, rr->srv.weight, rr->srv.port, normalized);
755 [ # # ]: 0 : if (r < 0)
756 : 0 : return r;
757 : :
758 : 0 : r = sd_bus_message_open_container(reply, 'a', "(iiay)");
759 [ # # ]: 0 : if (r < 0)
760 : 0 : return r;
761 : :
762 [ # # ]: 0 : if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
763 [ # # ]: 0 : LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
764 : : DnsResourceRecord *zz;
765 : : DnsQuestion *question;
766 : : int ifindex;
767 : :
768 [ # # ]: 0 : if (aux->state != DNS_TRANSACTION_SUCCESS)
769 : 0 : continue;
770 [ # # ]: 0 : if (aux->auxiliary_result != 0)
771 : 0 : continue;
772 : :
773 : 0 : question = dns_query_question_for_protocol(aux, aux->answer_protocol);
774 : :
775 : 0 : r = dns_name_equal(dns_question_first_name(question), rr->srv.name);
776 [ # # ]: 0 : if (r < 0)
777 : 0 : return r;
778 [ # # ]: 0 : if (r == 0)
779 : 0 : continue;
780 : :
781 [ # # # # : 0 : DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) {
# # # # #
# # # # #
# # ]
782 : :
783 : 0 : r = dns_question_matches_rr(question, zz, NULL);
784 [ # # ]: 0 : if (r < 0)
785 : 0 : return r;
786 [ # # ]: 0 : if (r == 0)
787 : 0 : continue;
788 : :
789 : 0 : r = append_address(reply, zz, ifindex);
790 [ # # ]: 0 : if (r < 0)
791 : 0 : return r;
792 : : }
793 : : }
794 : : }
795 : :
796 : 0 : r = sd_bus_message_close_container(reply);
797 [ # # ]: 0 : if (r < 0)
798 : 0 : return r;
799 : :
800 [ # # ]: 0 : if (canonical) {
801 : 0 : normalized = mfree(normalized);
802 : :
803 : 0 : r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
804 [ # # ]: 0 : if (r < 0)
805 : 0 : return r;
806 : : }
807 : :
808 : : /* Note that above we appended the hostname as encoded in the
809 : : * SRV, and here the canonical hostname this maps to. */
810 : 0 : r = sd_bus_message_append(reply, "s", normalized);
811 [ # # ]: 0 : if (r < 0)
812 : 0 : return r;
813 : :
814 : 0 : r = sd_bus_message_close_container(reply);
815 [ # # ]: 0 : if (r < 0)
816 : 0 : return r;
817 : :
818 : 0 : return 1;
819 : : }
820 : :
821 : 0 : static int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) {
822 : : DnsTxtItem *i;
823 : : int r;
824 : :
825 [ # # ]: 0 : assert(reply);
826 [ # # ]: 0 : assert(rr);
827 [ # # ]: 0 : assert(rr->key);
828 : :
829 [ # # ]: 0 : if (rr->key->type != DNS_TYPE_TXT)
830 : 0 : return 0;
831 : :
832 [ # # ]: 0 : LIST_FOREACH(items, i, rr->txt.items) {
833 : :
834 [ # # ]: 0 : if (i->length <= 0)
835 : 0 : continue;
836 : :
837 : 0 : r = sd_bus_message_append_array(reply, 'y', i->data, i->length);
838 [ # # ]: 0 : if (r < 0)
839 : 0 : return r;
840 : : }
841 : :
842 : 0 : return 1;
843 : : }
844 : :
845 : 0 : static void resolve_service_all_complete(DnsQuery *q) {
846 [ # # ]: 0 : _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
847 [ # # ]: 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
848 [ # # # # : 0 : _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
# # ]
849 : : DnsQuestion *question;
850 : : DnsResourceRecord *rr;
851 : 0 : unsigned added = 0;
852 : : DnsQuery *aux;
853 : : int r;
854 : :
855 [ # # ]: 0 : assert(q);
856 : :
857 [ # # ]: 0 : if (q->block_all_complete > 0)
858 : 0 : return;
859 : :
860 [ # # ]: 0 : if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
861 : 0 : DnsQuery *bad = NULL;
862 : 0 : bool have_success = false;
863 : :
864 [ # # ]: 0 : LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
865 : :
866 [ # # # ]: 0 : switch (aux->state) {
867 : :
868 : 0 : case DNS_TRANSACTION_PENDING:
869 : : /* If an auxiliary query is still pending, let's wait */
870 : 0 : return;
871 : :
872 : 0 : case DNS_TRANSACTION_SUCCESS:
873 [ # # ]: 0 : if (aux->auxiliary_result == 0)
874 : 0 : have_success = true;
875 : : else
876 : 0 : bad = aux;
877 : 0 : break;
878 : :
879 : 0 : default:
880 : 0 : bad = aux;
881 : 0 : break;
882 : : }
883 : : }
884 : :
885 [ # # ]: 0 : if (!have_success) {
886 : : /* We can only return one error, hence pick the last error we encountered */
887 : :
888 [ # # ]: 0 : assert(bad);
889 : :
890 [ # # ]: 0 : if (bad->state == DNS_TRANSACTION_SUCCESS) {
891 [ # # ]: 0 : assert(bad->auxiliary_result != 0);
892 : :
893 [ # # ]: 0 : if (bad->auxiliary_result == -ELOOP) {
894 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(bad));
895 : 0 : goto finish;
896 : : }
897 : :
898 : 0 : r = bad->auxiliary_result;
899 : 0 : goto finish;
900 : : }
901 : :
902 : 0 : r = reply_query_state(bad);
903 : 0 : goto finish;
904 : : }
905 : : }
906 : :
907 : 0 : r = sd_bus_message_new_method_return(q->request, &reply);
908 [ # # ]: 0 : if (r < 0)
909 : 0 : goto finish;
910 : :
911 : 0 : r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)");
912 [ # # ]: 0 : if (r < 0)
913 : 0 : goto finish;
914 : :
915 : 0 : question = dns_query_question_for_protocol(q, q->answer_protocol);
916 [ # # # # : 0 : DNS_ANSWER_FOREACH(rr, q->answer) {
# # # # #
# ]
917 : 0 : r = dns_question_matches_rr(question, rr, NULL);
918 [ # # ]: 0 : if (r < 0)
919 : 0 : goto finish;
920 [ # # ]: 0 : if (r == 0)
921 : 0 : continue;
922 : :
923 : 0 : r = append_srv(q, reply, rr);
924 [ # # ]: 0 : if (r < 0)
925 : 0 : goto finish;
926 [ # # ]: 0 : if (r == 0) /* not an SRV record */
927 : 0 : continue;
928 : :
929 [ # # ]: 0 : if (!canonical)
930 : 0 : canonical = dns_resource_record_ref(rr);
931 : :
932 : 0 : added++;
933 : : }
934 : :
935 [ # # ]: 0 : if (added <= 0) {
936 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
937 : 0 : goto finish;
938 : : }
939 : :
940 : 0 : r = sd_bus_message_close_container(reply);
941 [ # # ]: 0 : if (r < 0)
942 : 0 : goto finish;
943 : :
944 : 0 : r = sd_bus_message_open_container(reply, 'a', "ay");
945 [ # # ]: 0 : if (r < 0)
946 : 0 : goto finish;
947 : :
948 [ # # # # : 0 : DNS_ANSWER_FOREACH(rr, q->answer) {
# # # # #
# ]
949 : 0 : r = dns_question_matches_rr(question, rr, NULL);
950 [ # # ]: 0 : if (r < 0)
951 : 0 : goto finish;
952 [ # # ]: 0 : if (r == 0)
953 : 0 : continue;
954 : :
955 : 0 : r = append_txt(reply, rr);
956 [ # # ]: 0 : if (r < 0)
957 : 0 : goto finish;
958 : : }
959 : :
960 : 0 : r = sd_bus_message_close_container(reply);
961 [ # # ]: 0 : if (r < 0)
962 : 0 : goto finish;
963 : :
964 [ # # ]: 0 : assert(canonical);
965 : 0 : r = dns_service_split(dns_resource_key_name(canonical->key), &name, &type, &domain);
966 [ # # ]: 0 : if (r < 0)
967 : 0 : goto finish;
968 : :
969 : 0 : r = sd_bus_message_append(
970 : : reply,
971 : : "ssst",
972 : : name, type, domain,
973 : 0 : SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
974 [ # # ]: 0 : if (r < 0)
975 : 0 : goto finish;
976 : :
977 : 0 : r = sd_bus_send(q->manager->bus, reply, NULL);
978 : :
979 : 0 : finish:
980 [ # # ]: 0 : if (r < 0) {
981 [ # # ]: 0 : log_error_errno(r, "Failed to send service reply: %m");
982 : 0 : sd_bus_reply_method_errno(q->request, r, NULL);
983 : : }
984 : :
985 : 0 : dns_query_free(q);
986 : : }
987 : :
988 : 0 : static void resolve_service_hostname_complete(DnsQuery *q) {
989 : : int r;
990 : :
991 [ # # ]: 0 : assert(q);
992 [ # # ]: 0 : assert(q->auxiliary_for);
993 : :
994 [ # # ]: 0 : if (q->state != DNS_TRANSACTION_SUCCESS) {
995 : 0 : resolve_service_all_complete(q->auxiliary_for);
996 : 0 : return;
997 : : }
998 : :
999 : 0 : r = dns_query_process_cname(q);
1000 [ # # ]: 0 : if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
1001 : 0 : return;
1002 : :
1003 : : /* This auxiliary lookup is finished or failed, let's see if all are finished now. */
1004 : 0 : q->auxiliary_result = r;
1005 : 0 : resolve_service_all_complete(q->auxiliary_for);
1006 : : }
1007 : :
1008 : 0 : static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) {
1009 : 0 : _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1010 : : DnsQuery *aux;
1011 : : int r;
1012 : :
1013 [ # # ]: 0 : assert(q);
1014 [ # # ]: 0 : assert(rr);
1015 [ # # ]: 0 : assert(rr->key);
1016 [ # # ]: 0 : assert(rr->key->type == DNS_TYPE_SRV);
1017 : :
1018 : : /* OK, we found an SRV record for the service. Let's resolve
1019 : : * the hostname included in it */
1020 : :
1021 : 0 : r = dns_question_new_address(&question, q->request_family, rr->srv.name, false);
1022 [ # # ]: 0 : if (r < 0)
1023 : 0 : return r;
1024 : :
1025 : 0 : r = dns_query_new(q->manager, &aux, question, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
1026 [ # # ]: 0 : if (r < 0)
1027 : 0 : return r;
1028 : :
1029 : 0 : aux->request_family = q->request_family;
1030 : 0 : aux->complete = resolve_service_hostname_complete;
1031 : :
1032 : 0 : r = dns_query_make_auxiliary(aux, q);
1033 [ # # ]: 0 : if (r == -EAGAIN) {
1034 : : /* Too many auxiliary lookups? If so, don't complain,
1035 : : * let's just not add this one, we already have more
1036 : : * than enough */
1037 : :
1038 : 0 : dns_query_free(aux);
1039 : 0 : return 0;
1040 : : }
1041 [ # # ]: 0 : if (r < 0)
1042 : 0 : goto fail;
1043 : :
1044 : : /* Note that auxiliary queries do not track the original bus
1045 : : * client, only the primary request does that. */
1046 : :
1047 : 0 : r = dns_query_go(aux);
1048 [ # # ]: 0 : if (r < 0)
1049 : 0 : goto fail;
1050 : :
1051 : 0 : return 1;
1052 : :
1053 : 0 : fail:
1054 : 0 : dns_query_free(aux);
1055 : 0 : return r;
1056 : : }
1057 : :
1058 : 0 : static void bus_method_resolve_service_complete(DnsQuery *q) {
1059 : 0 : bool has_root_domain = false;
1060 : : DnsResourceRecord *rr;
1061 : : DnsQuestion *question;
1062 : 0 : unsigned found = 0;
1063 : : int ifindex, r;
1064 : :
1065 [ # # ]: 0 : assert(q);
1066 : :
1067 [ # # ]: 0 : if (q->state != DNS_TRANSACTION_SUCCESS) {
1068 : 0 : r = reply_query_state(q);
1069 : 0 : goto finish;
1070 : : }
1071 : :
1072 : 0 : r = dns_query_process_cname(q);
1073 [ # # ]: 0 : if (r == -ELOOP) {
1074 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
1075 : 0 : goto finish;
1076 : : }
1077 [ # # ]: 0 : if (r < 0)
1078 : 0 : goto finish;
1079 [ # # ]: 0 : if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */
1080 : 0 : return;
1081 : :
1082 : 0 : question = dns_query_question_for_protocol(q, q->answer_protocol);
1083 : :
1084 [ # # # # : 0 : DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
# # # # #
# # # # #
# # ]
1085 : 0 : r = dns_question_matches_rr(question, rr, NULL);
1086 [ # # ]: 0 : if (r < 0)
1087 : 0 : goto finish;
1088 [ # # ]: 0 : if (r == 0)
1089 : 0 : continue;
1090 : :
1091 [ # # ]: 0 : if (rr->key->type != DNS_TYPE_SRV)
1092 : 0 : continue;
1093 : :
1094 [ # # ]: 0 : if (dns_name_is_root(rr->srv.name)) {
1095 : 0 : has_root_domain = true;
1096 : 0 : continue;
1097 : : }
1098 : :
1099 [ # # ]: 0 : if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
1100 : 0 : q->block_all_complete++;
1101 : 0 : r = resolve_service_hostname(q, rr, ifindex);
1102 : 0 : q->block_all_complete--;
1103 : :
1104 [ # # ]: 0 : if (r < 0)
1105 : 0 : goto finish;
1106 : : }
1107 : :
1108 : 0 : found++;
1109 : : }
1110 : :
1111 [ # # # # ]: 0 : if (has_root_domain && found <= 0) {
1112 : : /* If there's exactly one SRV RR and it uses
1113 : : * the root domain as host name, then the
1114 : : * service is explicitly not offered on the
1115 : : * domain. Report this as a recognizable
1116 : : * error. See RFC 2782, Section "Usage
1117 : : * Rules". */
1118 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_SERVICE, "'%s' does not provide the requested service", dns_query_string(q));
1119 : 0 : goto finish;
1120 : : }
1121 : :
1122 [ # # ]: 0 : if (found <= 0) {
1123 : 0 : r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
1124 : 0 : goto finish;
1125 : : }
1126 : :
1127 : : /* Maybe we are already finished? check now... */
1128 : 0 : resolve_service_all_complete(q);
1129 : 0 : return;
1130 : :
1131 : 0 : finish:
1132 [ # # ]: 0 : if (r < 0) {
1133 [ # # ]: 0 : log_error_errno(r, "Failed to send service reply: %m");
1134 : 0 : sd_bus_reply_method_errno(q->request, r, NULL);
1135 : : }
1136 : :
1137 : 0 : dns_query_free(q);
1138 : : }
1139 : :
1140 : 0 : static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1141 : 0 : _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
1142 : : const char *name, *type, *domain;
1143 : 0 : Manager *m = userdata;
1144 : : int family, ifindex;
1145 : : uint64_t flags;
1146 : : DnsQuery *q;
1147 : : int r;
1148 : :
1149 [ # # ]: 0 : assert(message);
1150 [ # # ]: 0 : assert(m);
1151 : :
1152 : : assert_cc(sizeof(int) == sizeof(int32_t));
1153 : :
1154 : 0 : r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
1155 [ # # ]: 0 : if (r < 0)
1156 : 0 : return r;
1157 : :
1158 [ # # # # ]: 0 : if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
1159 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
1160 : :
1161 [ # # ]: 0 : if (isempty(name))
1162 : 0 : name = NULL;
1163 [ # # ]: 0 : else if (!dns_service_name_is_valid(name))
1164 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
1165 : :
1166 [ # # ]: 0 : if (isempty(type))
1167 : 0 : type = NULL;
1168 [ # # ]: 0 : else if (!dns_srv_type_is_valid(type))
1169 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
1170 : :
1171 : 0 : r = dns_name_is_valid(domain);
1172 [ # # ]: 0 : if (r < 0)
1173 : 0 : return r;
1174 [ # # ]: 0 : if (r == 0)
1175 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
1176 : :
1177 [ # # # # ]: 0 : if (name && !type)
1178 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
1179 : :
1180 : 0 : r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
1181 [ # # ]: 0 : if (r < 0)
1182 : 0 : return r;
1183 : :
1184 : 0 : r = dns_question_new_service(&question_utf8, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), false);
1185 [ # # ]: 0 : if (r < 0)
1186 : 0 : return r;
1187 : :
1188 : 0 : r = dns_question_new_service(&question_idna, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), true);
1189 [ # # ]: 0 : if (r < 0)
1190 : 0 : return r;
1191 : :
1192 : 0 : r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags|SD_RESOLVED_NO_SEARCH);
1193 [ # # ]: 0 : if (r < 0)
1194 : 0 : return r;
1195 : :
1196 : 0 : q->request = sd_bus_message_ref(message);
1197 : 0 : q->request_family = family;
1198 : 0 : q->complete = bus_method_resolve_service_complete;
1199 : :
1200 : 0 : r = dns_query_bus_track(q, message);
1201 [ # # ]: 0 : if (r < 0)
1202 : 0 : goto fail;
1203 : :
1204 : 0 : r = dns_query_go(q);
1205 [ # # ]: 0 : if (r < 0)
1206 : 0 : goto fail;
1207 : :
1208 : 0 : return 1;
1209 : :
1210 : 0 : fail:
1211 : 0 : dns_query_free(q);
1212 : 0 : return r;
1213 : : }
1214 : :
1215 : 0 : int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) {
1216 : : int r;
1217 : :
1218 [ # # ]: 0 : assert(reply);
1219 : :
1220 [ # # ]: 0 : if (!s) {
1221 [ # # ]: 0 : if (with_ifindex)
1222 : 0 : return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0);
1223 : : else
1224 : 0 : return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0);
1225 : : }
1226 : :
1227 [ # # ]: 0 : r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay");
1228 [ # # ]: 0 : if (r < 0)
1229 : 0 : return r;
1230 : :
1231 [ # # ]: 0 : if (with_ifindex) {
1232 : 0 : r = sd_bus_message_append(reply, "i", dns_server_ifindex(s));
1233 [ # # ]: 0 : if (r < 0)
1234 : 0 : return r;
1235 : : }
1236 : :
1237 : 0 : r = sd_bus_message_append(reply, "i", s->family);
1238 [ # # ]: 0 : if (r < 0)
1239 : 0 : return r;
1240 : :
1241 : 0 : r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
1242 [ # # ]: 0 : if (r < 0)
1243 : 0 : return r;
1244 : :
1245 : 0 : return sd_bus_message_close_container(reply);
1246 : : }
1247 : :
1248 : 0 : static int bus_property_get_dns_servers(
1249 : : sd_bus *bus,
1250 : : const char *path,
1251 : : const char *interface,
1252 : : const char *property,
1253 : : sd_bus_message *reply,
1254 : : void *userdata,
1255 : : sd_bus_error *error) {
1256 : :
1257 : 0 : Manager *m = userdata;
1258 : : DnsServer *s;
1259 : : Iterator i;
1260 : : Link *l;
1261 : : int r;
1262 : :
1263 [ # # ]: 0 : assert(reply);
1264 [ # # ]: 0 : assert(m);
1265 : :
1266 : 0 : r = sd_bus_message_open_container(reply, 'a', "(iiay)");
1267 [ # # ]: 0 : if (r < 0)
1268 : 0 : return r;
1269 : :
1270 [ # # ]: 0 : LIST_FOREACH(servers, s, m->dns_servers) {
1271 : 0 : r = bus_dns_server_append(reply, s, true);
1272 [ # # ]: 0 : if (r < 0)
1273 : 0 : return r;
1274 : : }
1275 : :
1276 [ # # ]: 0 : HASHMAP_FOREACH(l, m->links, i) {
1277 [ # # ]: 0 : LIST_FOREACH(servers, s, l->dns_servers) {
1278 : 0 : r = bus_dns_server_append(reply, s, true);
1279 [ # # ]: 0 : if (r < 0)
1280 : 0 : return r;
1281 : : }
1282 : : }
1283 : :
1284 : 0 : return sd_bus_message_close_container(reply);
1285 : : }
1286 : :
1287 : 0 : static int bus_property_get_fallback_dns_servers(
1288 : : sd_bus *bus,
1289 : : const char *path,
1290 : : const char *interface,
1291 : : const char *property,
1292 : : sd_bus_message *reply,
1293 : : void *userdata,
1294 : : sd_bus_error *error) {
1295 : :
1296 : 0 : DnsServer *s, **f = userdata;
1297 : : int r;
1298 : :
1299 [ # # ]: 0 : assert(reply);
1300 [ # # ]: 0 : assert(f);
1301 : :
1302 : 0 : r = sd_bus_message_open_container(reply, 'a', "(iiay)");
1303 [ # # ]: 0 : if (r < 0)
1304 : 0 : return r;
1305 : :
1306 [ # # ]: 0 : LIST_FOREACH(servers, s, *f) {
1307 : 0 : r = bus_dns_server_append(reply, s, true);
1308 [ # # ]: 0 : if (r < 0)
1309 : 0 : return r;
1310 : : }
1311 : :
1312 : 0 : return sd_bus_message_close_container(reply);
1313 : : }
1314 : :
1315 : 0 : static int bus_property_get_current_dns_server(
1316 : : sd_bus *bus,
1317 : : const char *path,
1318 : : const char *interface,
1319 : : const char *property,
1320 : : sd_bus_message *reply,
1321 : : void *userdata,
1322 : : sd_bus_error *error) {
1323 : :
1324 : : DnsServer *s;
1325 : :
1326 [ # # ]: 0 : assert(reply);
1327 [ # # ]: 0 : assert(userdata);
1328 : :
1329 : 0 : s = *(DnsServer **) userdata;
1330 : :
1331 : 0 : return bus_dns_server_append(reply, s, true);
1332 : : }
1333 : :
1334 : 0 : static int bus_property_get_domains(
1335 : : sd_bus *bus,
1336 : : const char *path,
1337 : : const char *interface,
1338 : : const char *property,
1339 : : sd_bus_message *reply,
1340 : : void *userdata,
1341 : : sd_bus_error *error) {
1342 : :
1343 : 0 : Manager *m = userdata;
1344 : : DnsSearchDomain *d;
1345 : : Iterator i;
1346 : : Link *l;
1347 : : int r;
1348 : :
1349 [ # # ]: 0 : assert(reply);
1350 [ # # ]: 0 : assert(m);
1351 : :
1352 : 0 : r = sd_bus_message_open_container(reply, 'a', "(isb)");
1353 [ # # ]: 0 : if (r < 0)
1354 : 0 : return r;
1355 : :
1356 [ # # ]: 0 : LIST_FOREACH(domains, d, m->search_domains) {
1357 : 0 : r = sd_bus_message_append(reply, "(isb)", 0, d->name, d->route_only);
1358 [ # # ]: 0 : if (r < 0)
1359 : 0 : return r;
1360 : : }
1361 : :
1362 [ # # ]: 0 : HASHMAP_FOREACH(l, m->links, i) {
1363 [ # # ]: 0 : LIST_FOREACH(domains, d, l->search_domains) {
1364 : 0 : r = sd_bus_message_append(reply, "(isb)", l->ifindex, d->name, d->route_only);
1365 [ # # ]: 0 : if (r < 0)
1366 : 0 : return r;
1367 : : }
1368 : : }
1369 : :
1370 : 0 : return sd_bus_message_close_container(reply);
1371 : : }
1372 : :
1373 : 0 : static int bus_property_get_transaction_statistics(
1374 : : sd_bus *bus,
1375 : : const char *path,
1376 : : const char *interface,
1377 : : const char *property,
1378 : : sd_bus_message *reply,
1379 : : void *userdata,
1380 : : sd_bus_error *error) {
1381 : :
1382 : 0 : Manager *m = userdata;
1383 : :
1384 [ # # ]: 0 : assert(reply);
1385 [ # # ]: 0 : assert(m);
1386 : :
1387 : 0 : return sd_bus_message_append(reply, "(tt)",
1388 : 0 : (uint64_t) hashmap_size(m->dns_transactions),
1389 : 0 : (uint64_t) m->n_transactions_total);
1390 : : }
1391 : :
1392 : 0 : static int bus_property_get_cache_statistics(
1393 : : sd_bus *bus,
1394 : : const char *path,
1395 : : const char *interface,
1396 : : const char *property,
1397 : : sd_bus_message *reply,
1398 : : void *userdata,
1399 : : sd_bus_error *error) {
1400 : :
1401 : 0 : uint64_t size = 0, hit = 0, miss = 0;
1402 : 0 : Manager *m = userdata;
1403 : : DnsScope *s;
1404 : :
1405 [ # # ]: 0 : assert(reply);
1406 [ # # ]: 0 : assert(m);
1407 : :
1408 [ # # ]: 0 : LIST_FOREACH(scopes, s, m->dns_scopes) {
1409 : 0 : size += dns_cache_size(&s->cache);
1410 : 0 : hit += s->cache.n_hit;
1411 : 0 : miss += s->cache.n_miss;
1412 : : }
1413 : :
1414 : 0 : return sd_bus_message_append(reply, "(ttt)", size, hit, miss);
1415 : : }
1416 : :
1417 : 0 : static int bus_property_get_dnssec_statistics(
1418 : : sd_bus *bus,
1419 : : const char *path,
1420 : : const char *interface,
1421 : : const char *property,
1422 : : sd_bus_message *reply,
1423 : : void *userdata,
1424 : : sd_bus_error *error) {
1425 : :
1426 : 0 : Manager *m = userdata;
1427 : :
1428 [ # # ]: 0 : assert(reply);
1429 [ # # ]: 0 : assert(m);
1430 : :
1431 : 0 : return sd_bus_message_append(reply, "(tttt)",
1432 : 0 : (uint64_t) m->n_dnssec_verdict[DNSSEC_SECURE],
1433 : 0 : (uint64_t) m->n_dnssec_verdict[DNSSEC_INSECURE],
1434 : 0 : (uint64_t) m->n_dnssec_verdict[DNSSEC_BOGUS],
1435 : 0 : (uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]);
1436 : : }
1437 : :
1438 : 0 : static int bus_property_get_ntas(
1439 : : sd_bus *bus,
1440 : : const char *path,
1441 : : const char *interface,
1442 : : const char *property,
1443 : : sd_bus_message *reply,
1444 : : void *userdata,
1445 : : sd_bus_error *error) {
1446 : :
1447 : 0 : Manager *m = userdata;
1448 : : const char *domain;
1449 : : Iterator i;
1450 : : int r;
1451 : :
1452 [ # # ]: 0 : assert(reply);
1453 [ # # ]: 0 : assert(m);
1454 : :
1455 : 0 : r = sd_bus_message_open_container(reply, 'a', "s");
1456 [ # # ]: 0 : if (r < 0)
1457 : 0 : return r;
1458 : :
1459 [ # # ]: 0 : SET_FOREACH(domain, m->trust_anchor.negative_by_name, i) {
1460 : 0 : r = sd_bus_message_append(reply, "s", domain);
1461 [ # # ]: 0 : if (r < 0)
1462 : 0 : return r;
1463 : : }
1464 : :
1465 : 0 : return sd_bus_message_close_container(reply);
1466 : : }
1467 : :
1468 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode);
# # ]
1469 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET(bus_property_get_dnssec_supported, "b", Manager, manager_dnssec_supported);
# # ]
1470 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string);
# # ]
1471 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dns_over_tls_mode, "s", Manager, manager_get_dns_over_tls_mode, dns_over_tls_mode_to_string);
# # ]
1472 : :
1473 : 0 : static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1474 : 0 : Manager *m = userdata;
1475 : : DnsScope *s;
1476 : :
1477 [ # # ]: 0 : assert(message);
1478 [ # # ]: 0 : assert(m);
1479 : :
1480 [ # # ]: 0 : LIST_FOREACH(scopes, s, m->dns_scopes)
1481 : 0 : s->cache.n_hit = s->cache.n_miss = 0;
1482 : :
1483 : 0 : m->n_transactions_total = 0;
1484 [ # # ]: 0 : zero(m->n_dnssec_verdict);
1485 : :
1486 : 0 : return sd_bus_reply_method_return(message, NULL);
1487 : : }
1488 : :
1489 : 0 : static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
1490 : : Link *l;
1491 : :
1492 [ # # ]: 0 : assert(m);
1493 [ # # ]: 0 : assert(ret);
1494 : :
1495 [ # # ]: 0 : if (ifindex <= 0)
1496 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
1497 : :
1498 : 0 : l = hashmap_get(m->links, INT_TO_PTR(ifindex));
1499 [ # # ]: 0 : if (!l)
1500 : 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
1501 : :
1502 : 0 : *ret = l;
1503 : 0 : return 0;
1504 : : }
1505 : :
1506 : 0 : static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
1507 : : int ifindex, r;
1508 : : Link *l;
1509 : :
1510 [ # # ]: 0 : assert(m);
1511 [ # # ]: 0 : assert(message);
1512 [ # # ]: 0 : assert(handler);
1513 : :
1514 : : assert_cc(sizeof(int) == sizeof(int32_t));
1515 : 0 : r = sd_bus_message_read(message, "i", &ifindex);
1516 [ # # ]: 0 : if (r < 0)
1517 : 0 : return r;
1518 : :
1519 : 0 : r = get_any_link(m, ifindex, &l, error);
1520 [ # # ]: 0 : if (r < 0)
1521 : 0 : return r;
1522 : :
1523 : 0 : return handler(message, l, error);
1524 : : }
1525 : :
1526 : 0 : static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1527 : 0 : return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
1528 : : }
1529 : :
1530 : 0 : static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1531 : 0 : return call_link_method(userdata, message, bus_link_method_set_domains, error);
1532 : : }
1533 : :
1534 : 0 : static int bus_method_set_link_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1535 : 0 : return call_link_method(userdata, message, bus_link_method_set_default_route, error);
1536 : : }
1537 : :
1538 : 0 : static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1539 : 0 : return call_link_method(userdata, message, bus_link_method_set_llmnr, error);
1540 : : }
1541 : :
1542 : 0 : static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1543 : 0 : return call_link_method(userdata, message, bus_link_method_set_mdns, error);
1544 : : }
1545 : :
1546 : 0 : static int bus_method_set_link_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1547 : 0 : return call_link_method(userdata, message, bus_link_method_set_dns_over_tls, error);
1548 : : }
1549 : :
1550 : 0 : static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1551 : 0 : return call_link_method(userdata, message, bus_link_method_set_dnssec, error);
1552 : : }
1553 : :
1554 : 0 : static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1555 : 0 : return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error);
1556 : : }
1557 : :
1558 : 0 : static int bus_method_revert_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1559 : 0 : return call_link_method(userdata, message, bus_link_method_revert, error);
1560 : : }
1561 : :
1562 : 0 : static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1563 : 0 : _cleanup_free_ char *p = NULL;
1564 : 0 : Manager *m = userdata;
1565 : : int r, ifindex;
1566 : : Link *l;
1567 : :
1568 [ # # ]: 0 : assert(message);
1569 [ # # ]: 0 : assert(m);
1570 : :
1571 : : assert_cc(sizeof(int) == sizeof(int32_t));
1572 : 0 : r = sd_bus_message_read(message, "i", &ifindex);
1573 [ # # ]: 0 : if (r < 0)
1574 : 0 : return r;
1575 : :
1576 : 0 : r = get_any_link(m, ifindex, &l, error);
1577 [ # # ]: 0 : if (r < 0)
1578 : 0 : return r;
1579 : :
1580 : 0 : p = link_bus_path(l);
1581 [ # # ]: 0 : if (!p)
1582 : 0 : return -ENOMEM;
1583 : :
1584 : 0 : return sd_bus_reply_method_return(message, "o", p);
1585 : : }
1586 : :
1587 : 0 : static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1588 : 0 : Manager *m = userdata;
1589 : :
1590 [ # # ]: 0 : assert(message);
1591 [ # # ]: 0 : assert(m);
1592 : :
1593 : 0 : manager_flush_caches(m);
1594 : :
1595 : 0 : return sd_bus_reply_method_return(message, NULL);
1596 : : }
1597 : :
1598 : 0 : static int bus_method_reset_server_features(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1599 : 0 : Manager *m = userdata;
1600 : :
1601 [ # # ]: 0 : assert(message);
1602 [ # # ]: 0 : assert(m);
1603 : :
1604 : 0 : manager_reset_server_features(m);
1605 : :
1606 : 0 : return sd_bus_reply_method_return(message, NULL);
1607 : : }
1608 : :
1609 : 0 : static int on_bus_track(sd_bus_track *t, void *userdata) {
1610 : 0 : DnssdService *s = userdata;
1611 : :
1612 [ # # ]: 0 : assert(t);
1613 [ # # ]: 0 : assert(s);
1614 : :
1615 [ # # ]: 0 : log_debug("Client of active request vanished, destroying DNS-SD service.");
1616 : 0 : dnssd_service_free(s);
1617 : :
1618 : 0 : return 0;
1619 : : }
1620 : :
1621 : 0 : static int bus_method_register_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1622 : 0 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1623 : 0 : _cleanup_(dnssd_service_freep) DnssdService *service = NULL;
1624 : 0 : _cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL;
1625 : 0 : _cleanup_free_ char *path = NULL;
1626 : 0 : _cleanup_free_ char *instance_name = NULL;
1627 : 0 : Manager *m = userdata;
1628 : 0 : DnssdService *s = NULL;
1629 : : const char *name;
1630 : : const char *name_template;
1631 : : const char *type;
1632 : : uid_t euid;
1633 : : int r;
1634 : :
1635 [ # # ]: 0 : assert(message);
1636 [ # # ]: 0 : assert(m);
1637 : :
1638 [ # # ]: 0 : if (m->mdns_support != RESOLVE_SUPPORT_YES)
1639 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
1640 : :
1641 : 0 : r = bus_verify_polkit_async(message, CAP_SYS_ADMIN,
1642 : : "org.freedesktop.resolve1.register-service",
1643 : : NULL, false, UID_INVALID,
1644 : : &m->polkit_registry, error);
1645 [ # # ]: 0 : if (r < 0)
1646 : 0 : return r;
1647 [ # # ]: 0 : if (r == 0)
1648 : 0 : return 1; /* Polkit will call us back */
1649 : :
1650 : 0 : service = new0(DnssdService, 1);
1651 [ # # ]: 0 : if (!service)
1652 : 0 : return log_oom();
1653 : :
1654 : 0 : r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
1655 [ # # ]: 0 : if (r < 0)
1656 : 0 : return r;
1657 : :
1658 : 0 : r = sd_bus_creds_get_euid(creds, &euid);
1659 [ # # ]: 0 : if (r < 0)
1660 : 0 : return r;
1661 : 0 : service->originator = euid;
1662 : :
1663 : 0 : r = sd_bus_message_read(message, "sssqqq", &name, &name_template, &type,
1664 : 0 : &service->port, &service->priority,
1665 : 0 : &service->weight);
1666 [ # # ]: 0 : if (r < 0)
1667 : 0 : return r;
1668 : :
1669 : 0 : s = hashmap_get(m->dnssd_services, name);
1670 [ # # ]: 0 : if (s)
1671 : 0 : return sd_bus_error_setf(error, BUS_ERROR_DNSSD_SERVICE_EXISTS, "DNS-SD service '%s' exists already", name);
1672 : :
1673 [ # # ]: 0 : if (!dnssd_srv_type_is_valid(type))
1674 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DNS-SD service type '%s' is invalid", type);
1675 : :
1676 : 0 : service->name = strdup(name);
1677 [ # # ]: 0 : if (!service->name)
1678 : 0 : return log_oom();
1679 : :
1680 : 0 : service->name_template = strdup(name_template);
1681 [ # # ]: 0 : if (!service->name_template)
1682 : 0 : return log_oom();
1683 : :
1684 : 0 : service->type = strdup(type);
1685 [ # # ]: 0 : if (!service->type)
1686 : 0 : return log_oom();
1687 : :
1688 : 0 : r = dnssd_render_instance_name(service, &instance_name);
1689 [ # # ]: 0 : if (r < 0)
1690 : 0 : return r;
1691 : :
1692 : 0 : r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "a{say}");
1693 [ # # ]: 0 : if (r < 0)
1694 : 0 : return r;
1695 : :
1696 [ # # ]: 0 : while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{say}")) > 0) {
1697 [ # # ]: 0 : _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
1698 : 0 : DnsTxtItem *last = NULL;
1699 : :
1700 : 0 : txt_data = new0(DnssdTxtData, 1);
1701 [ # # ]: 0 : if (!txt_data)
1702 : 0 : return log_oom();
1703 : :
1704 [ # # ]: 0 : while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "say")) > 0) {
1705 : : const char *key;
1706 : : const void *value;
1707 : : size_t size;
1708 : : DnsTxtItem *i;
1709 : :
1710 : 0 : r = sd_bus_message_read(message, "s", &key);
1711 [ # # ]: 0 : if (r < 0)
1712 : 0 : return r;
1713 : :
1714 [ # # ]: 0 : if (isempty(key))
1715 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Keys in DNS-SD TXT RRs can't be empty");
1716 : :
1717 [ # # ]: 0 : if (!ascii_is_valid(key))
1718 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TXT key '%s' contains non-ASCII symbols", key);
1719 : :
1720 : 0 : r = sd_bus_message_read_array(message, 'y', &value, &size);
1721 [ # # ]: 0 : if (r < 0)
1722 : 0 : return r;
1723 : :
1724 : 0 : r = dnssd_txt_item_new_from_data(key, value, size, &i);
1725 [ # # ]: 0 : if (r < 0)
1726 : 0 : return r;
1727 : :
1728 [ # # # # : 0 : LIST_INSERT_AFTER(items, txt_data->txt, last, i);
# # # # ]
1729 : 0 : last = i;
1730 : :
1731 : 0 : r = sd_bus_message_exit_container(message);
1732 [ # # ]: 0 : if (r < 0)
1733 : 0 : return r;
1734 : :
1735 : : }
1736 [ # # ]: 0 : if (r < 0)
1737 : 0 : return r;
1738 : :
1739 : 0 : r = sd_bus_message_exit_container(message);
1740 [ # # ]: 0 : if (r < 0)
1741 : 0 : return r;
1742 : :
1743 [ # # ]: 0 : if (txt_data->txt) {
1744 [ # # # # ]: 0 : LIST_PREPEND(items, service->txt_data_items, txt_data);
1745 : 0 : txt_data = NULL;
1746 : : }
1747 : : }
1748 [ # # ]: 0 : if (r < 0)
1749 : 0 : return r;
1750 : :
1751 : 0 : r = sd_bus_message_exit_container(message);
1752 [ # # ]: 0 : if (r < 0)
1753 : 0 : return r;
1754 : :
1755 [ # # ]: 0 : if (!service->txt_data_items) {
1756 [ # # ]: 0 : _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
1757 : :
1758 : 0 : txt_data = new0(DnssdTxtData, 1);
1759 [ # # ]: 0 : if (!txt_data)
1760 : 0 : return log_oom();
1761 : :
1762 : 0 : r = dns_txt_item_new_empty(&txt_data->txt);
1763 [ # # ]: 0 : if (r < 0)
1764 : 0 : return r;
1765 : :
1766 [ # # # # ]: 0 : LIST_PREPEND(items, service->txt_data_items, txt_data);
1767 : 0 : txt_data = NULL;
1768 : : }
1769 : :
1770 : 0 : r = sd_bus_path_encode("/org/freedesktop/resolve1/dnssd", service->name, &path);
1771 [ # # ]: 0 : if (r < 0)
1772 : 0 : return r;
1773 : :
1774 : 0 : r = hashmap_ensure_allocated(&m->dnssd_services, &string_hash_ops);
1775 [ # # ]: 0 : if (r < 0)
1776 : 0 : return r;
1777 : :
1778 : 0 : r = hashmap_put(m->dnssd_services, service->name, service);
1779 [ # # ]: 0 : if (r < 0)
1780 : 0 : return r;
1781 : :
1782 : 0 : r = sd_bus_track_new(sd_bus_message_get_bus(message), &bus_track, on_bus_track, service);
1783 [ # # ]: 0 : if (r < 0)
1784 : 0 : return r;
1785 : :
1786 : 0 : r = sd_bus_track_add_sender(bus_track, message);
1787 [ # # ]: 0 : if (r < 0)
1788 : 0 : return r;
1789 : :
1790 : 0 : service->manager = m;
1791 : :
1792 : 0 : service = NULL;
1793 : :
1794 : 0 : manager_refresh_rrs(m);
1795 : :
1796 : 0 : return sd_bus_reply_method_return(message, "o", path);
1797 : : }
1798 : :
1799 : 0 : static int call_dnssd_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
1800 : 0 : _cleanup_free_ char *name = NULL;
1801 : 0 : DnssdService *s = NULL;
1802 : : const char *path;
1803 : : int r;
1804 : :
1805 [ # # ]: 0 : assert(m);
1806 [ # # ]: 0 : assert(message);
1807 [ # # ]: 0 : assert(handler);
1808 : :
1809 : 0 : r = sd_bus_message_read(message, "o", &path);
1810 [ # # ]: 0 : if (r < 0)
1811 : 0 : return r;
1812 : :
1813 : 0 : r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/dnssd", &name);
1814 [ # # ]: 0 : if (r == 0)
1815 : 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DNSSD_SERVICE, "DNS-SD service with object path '%s' does not exist", path);
1816 [ # # ]: 0 : if (r < 0)
1817 : 0 : return r;
1818 : :
1819 : 0 : s = hashmap_get(m->dnssd_services, name);
1820 [ # # ]: 0 : if (!s)
1821 : 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DNSSD_SERVICE, "DNS-SD service '%s' not known", name);
1822 : :
1823 : 0 : return handler(message, s, error);
1824 : : }
1825 : :
1826 : 0 : static int bus_method_unregister_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1827 : 0 : Manager *m = userdata;
1828 : :
1829 [ # # ]: 0 : assert(message);
1830 [ # # ]: 0 : assert(m);
1831 : :
1832 : 0 : return call_dnssd_method(m, message, bus_dnssd_method_unregister, error);
1833 : : }
1834 : :
1835 : : static const sd_bus_vtable resolve_vtable[] = {
1836 : : SD_BUS_VTABLE_START(0),
1837 : : SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
1838 : : SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Manager, llmnr_support), 0),
1839 : : SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Manager, mdns_support), 0),
1840 : : SD_BUS_PROPERTY("DNSOverTLS", "s", bus_property_get_dns_over_tls_mode, 0, 0),
1841 : : SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
1842 : : SD_BUS_PROPERTY("FallbackDNS", "a(iiay)", bus_property_get_fallback_dns_servers, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
1843 : : SD_BUS_PROPERTY("CurrentDNSServer", "(iiay)", bus_property_get_current_dns_server, offsetof(Manager, current_dns_server), 0),
1844 : : SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0),
1845 : : SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
1846 : : SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
1847 : : SD_BUS_PROPERTY("DNSSEC", "s", bus_property_get_dnssec_mode, 0, 0),
1848 : : SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
1849 : : SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
1850 : : SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
1851 : : SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
1852 : :
1853 : : SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
1854 : : SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
1855 : : SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
1856 : : SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
1857 : : SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
1858 : : SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0),
1859 : : SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, 0),
1860 : : SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
1861 : : SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
1862 : : SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
1863 : : SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, 0),
1864 : : SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
1865 : : SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
1866 : : SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, 0),
1867 : : SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
1868 : : SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0),
1869 : : SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0),
1870 : :
1871 : : SD_BUS_METHOD("RegisterService", "sssqqqaa{say}", "o", bus_method_register_service, SD_BUS_VTABLE_UNPRIVILEGED),
1872 : : SD_BUS_METHOD("UnregisterService", "o", NULL, bus_method_unregister_service, SD_BUS_VTABLE_UNPRIVILEGED),
1873 : : SD_BUS_VTABLE_END,
1874 : : };
1875 : :
1876 : 0 : static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
1877 : 0 : Manager *m = userdata;
1878 : : int b, r;
1879 : :
1880 [ # # ]: 0 : assert(message);
1881 [ # # ]: 0 : assert(m);
1882 : :
1883 : 0 : r = sd_bus_message_read(message, "b", &b);
1884 [ # # ]: 0 : if (r < 0) {
1885 [ # # ]: 0 : log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
1886 : 0 : return 0;
1887 : : }
1888 : :
1889 [ # # ]: 0 : if (b)
1890 : 0 : return 0;
1891 : :
1892 [ # # ]: 0 : log_debug("Coming back from suspend, verifying all RRs...");
1893 : :
1894 : 0 : manager_verify_all(m);
1895 : 0 : return 0;
1896 : : }
1897 : :
1898 : 0 : int manager_connect_bus(Manager *m) {
1899 : : int r;
1900 : :
1901 [ # # ]: 0 : assert(m);
1902 : :
1903 [ # # ]: 0 : if (m->bus)
1904 : 0 : return 0;
1905 : :
1906 : 0 : r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-resolve");
1907 [ # # ]: 0 : if (r < 0)
1908 [ # # ]: 0 : return log_error_errno(r, "Failed to connect to system bus: %m");
1909 : :
1910 : 0 : r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
1911 [ # # ]: 0 : if (r < 0)
1912 [ # # ]: 0 : return log_error_errno(r, "Failed to register object: %m");
1913 : :
1914 : 0 : r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/link", "org.freedesktop.resolve1.Link", link_vtable, link_object_find, m);
1915 [ # # ]: 0 : if (r < 0)
1916 [ # # ]: 0 : return log_error_errno(r, "Failed to register link objects: %m");
1917 : :
1918 : 0 : r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/link", link_node_enumerator, m);
1919 [ # # ]: 0 : if (r < 0)
1920 [ # # ]: 0 : return log_error_errno(r, "Failed to register link enumerator: %m");
1921 : :
1922 : 0 : r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/dnssd", "org.freedesktop.resolve1.DnssdService", dnssd_vtable, dnssd_object_find, m);
1923 [ # # ]: 0 : if (r < 0)
1924 [ # # ]: 0 : return log_error_errno(r, "Failed to register dnssd objects: %m");
1925 : :
1926 : 0 : r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/dnssd", dnssd_node_enumerator, m);
1927 [ # # ]: 0 : if (r < 0)
1928 [ # # ]: 0 : return log_error_errno(r, "Failed to register dnssd enumerator: %m");
1929 : :
1930 : 0 : r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.resolve1", 0, NULL, NULL);
1931 [ # # ]: 0 : if (r < 0)
1932 [ # # ]: 0 : return log_error_errno(r, "Failed to request name: %m");
1933 : :
1934 : 0 : r = sd_bus_attach_event(m->bus, m->event, 0);
1935 [ # # ]: 0 : if (r < 0)
1936 [ # # ]: 0 : return log_error_errno(r, "Failed to attach bus to event loop: %m");
1937 : :
1938 : 0 : r = sd_bus_match_signal_async(
1939 : : m->bus,
1940 : : NULL,
1941 : : "org.freedesktop.login1",
1942 : : "/org/freedesktop/login1",
1943 : : "org.freedesktop.login1.Manager",
1944 : : "PrepareForSleep",
1945 : : match_prepare_for_sleep,
1946 : : NULL,
1947 : : m);
1948 [ # # ]: 0 : if (r < 0)
1949 [ # # ]: 0 : log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
1950 : :
1951 : 0 : return 0;
1952 : : }
|