]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-bus.c
Merge pull request #25929 from poettering/resolvectl-loopback-fix
[thirdparty/systemd.git] / src / resolve / resolved-bus.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
74b2466e 2
b5efdb8a 3#include "alloc-util.h"
96aad8d1 4#include "bus-common-errors.h"
40af3d02 5#include "bus-get-properties.h"
4c452078 6#include "bus-log-control-api.h"
7695e2cb 7#include "bus-message-util.h"
269e4d2d 8#include "bus-polkit.h"
4ad7f276 9#include "dns-domain.h"
1e69eadd 10#include "format-util.h"
0a970718 11#include "memory-util.h"
ef118d00 12#include "missing_capability.h"
39d8db04 13#include "resolved-bus.h"
51323288 14#include "resolved-def.h"
c3be369f 15#include "resolved-dns-synthesize.h"
c3036641 16#include "resolved-dnssd-bus.h"
0a970718 17#include "resolved-dnssd.h"
3abaabda 18#include "resolved-link-bus.h"
4261ab65 19#include "resolved-resolv-conf.h"
5c3fa98d 20#include "socket-netlink.h"
0a6c0745 21#include "stdio-util.h"
5f3340ca 22#include "strv.h"
df957849 23#include "syslog-util.h"
84b0f133 24#include "user-util.h"
c3036641 25#include "utf8.h"
74b2466e 26
bf4e5c4c
YW
27BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_resolve_support, resolve_support, ResolveSupport);
28
65a01e82 29static int query_on_bus_track(sd_bus_track *t, void *userdata) {
99534007 30 DnsQuery *q = ASSERT_PTR(userdata);
65a01e82
LP
31
32 assert(t);
65a01e82
LP
33
34 if (!DNS_TRANSACTION_IS_LIVE(q->state))
35 return 0;
36
37 log_debug("Client of active query vanished, aborting query.");
38 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
39 return 0;
40}
41
42static int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
43 int r;
44
45 assert(q);
46 assert(m);
47
48 if (!q->bus_track) {
49 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, query_on_bus_track, q);
50 if (r < 0)
51 return r;
52 }
53
54 r = sd_bus_track_add_sender(q->bus_track, m);
55 if (r < 0)
56 return r;
57
58 return 0;
59}
60
2471a977
LP
61static sd_bus_message *dns_query_steal_request(DnsQuery *q) {
62 assert(q);
63
64 /* Find the main query, it's the one that owns the message */
65 while (q->auxiliary_for)
66 q = q->auxiliary_for;
67
68 /* Let's take the request message out of the DnsQuery object, so that we never send requests twice */
69 return TAKE_PTR(q->bus_request);
70}
71
72_sd_printf_(3, 4) static int reply_method_errorf(
73 DnsQuery *query,
74 const char *error_name,
75 const char *format,
76 ...) {
77
78 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
79 va_list ap;
80 int r;
81
82 assert(query);
83 assert(format);
84
85 req = dns_query_steal_request(query);
86 if (!req) /* No bus message set anymore? then we already replied already, let's not answer a second time */
87 return 0;
88
89 va_start(ap, format);
90 r = sd_bus_reply_method_errorfv(req, error_name, format, ap);
91 va_end(ap);
92
93 return r;
94}
ad867662 95
2471a977
LP
96_sd_printf_(3, 4) static int reply_method_errnof(
97 DnsQuery *query,
98 int err,
99 const char *format,
100 ...) {
101
102 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
103 int r;
104
105 assert(query);
106
107 req = dns_query_steal_request(query);
108 if (!req) /* No bus message set anymore? then we already replied already, let's not answer a second time */
109 return 0;
110
111 if (format) {
112 va_list ap;
113
114 va_start(ap, format);
115 r = sd_bus_reply_method_errnofv(req, err, format, ap);
116 va_end(ap);
117 } else
118 r = sd_bus_reply_method_errno(req, err, NULL);
119
120 return r;
121}
122
123static int reply_query_state(DnsQuery *q) {
c17b5ce7 124 assert(q);
c17b5ce7 125
ad867662 126 switch (q->state) {
74b2466e 127
ec2c5e43 128 case DNS_TRANSACTION_NO_SERVERS:
2471a977 129 return reply_method_errorf(q, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
74b2466e 130
ec2c5e43 131 case DNS_TRANSACTION_TIMEOUT:
2471a977 132 return reply_method_errorf(q, SD_BUS_ERROR_TIMEOUT, "Query timed out");
74b2466e 133
ec2c5e43 134 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
2471a977 135 return reply_method_errorf(q, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
ad867662 136
818f766b 137 case DNS_TRANSACTION_INVALID_REPLY:
2471a977 138 return reply_method_errorf(q, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
818f766b 139
7cc6ed7b 140 case DNS_TRANSACTION_ERRNO:
2471a977 141 return reply_method_errnof(q, q->answer_errno, "Lookup failed due to system error: %m");
ad867662 142
818f766b 143 case DNS_TRANSACTION_ABORTED:
2471a977 144 return reply_method_errorf(q, BUS_ERROR_ABORTED, "Query aborted");
74b2466e 145
547973de 146 case DNS_TRANSACTION_DNSSEC_FAILED:
2471a977
LP
147 return reply_method_errorf(q, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s",
148 dnssec_result_to_string(q->answer_dnssec_result));
547973de 149
b2b796b8 150 case DNS_TRANSACTION_NO_TRUST_ANCHOR:
2471a977 151 return reply_method_errorf(q, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known");
b2b796b8 152
91adc4db 153 case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
2471a977 154 return reply_method_errorf(q, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
91adc4db 155
edbcc1fd 156 case DNS_TRANSACTION_NETWORK_DOWN:
2471a977 157 return reply_method_errorf(q, BUS_ERROR_NETWORK_DOWN, "Network is down");
edbcc1fd 158
0791110f
LP
159 case DNS_TRANSACTION_NOT_FOUND:
160 /* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we
161 * thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */
2471a977 162 return reply_method_errorf(q, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
0791110f 163
775ae354 164 case DNS_TRANSACTION_NO_SOURCE:
2471a977 165 return reply_method_errorf(q, BUS_ERROR_NO_SOURCE, "All suitable resolution sources turned off");
775ae354 166
49ef064c 167 case DNS_TRANSACTION_STUB_LOOP:
2471a977 168 return reply_method_errorf(q, BUS_ERROR_STUB_LOOP, "Configured DNS server loops back to us");
49ef064c 169
3bbdc31d 170 case DNS_TRANSACTION_RCODE_FAILURE: {
4afd3348 171 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2471a977
LP
172 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
173
174 req = dns_query_steal_request(q);
175 if (!req) /* No bus message set anymore? then we already replied already, let's not answer a second time */
176 return 0;
74b2466e 177
faa133f3 178 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
23b298bc 179 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q));
74b2466e
LP
180 else {
181 const char *rc, *n;
74b2466e 182
0d609349 183 rc = FORMAT_DNS_RCODE(q->answer_rcode);
63c372cb 184 n = strjoina(_BUS_ERROR_DNS, rc);
23b298bc 185 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", dns_query_string(q), rc);
74b2466e
LP
186 }
187
2471a977 188 return sd_bus_reply_method_error(req, &error);
74b2466e
LP
189 }
190
ec2c5e43
LP
191 case DNS_TRANSACTION_NULL:
192 case DNS_TRANSACTION_PENDING:
ef9fb66c 193 case DNS_TRANSACTION_VALIDATING:
ec2c5e43 194 case DNS_TRANSACTION_SUCCESS:
8ba9fd9c 195 default:
04499a70 196 assert_not_reached();
ad867662
LP
197 }
198}
74b2466e 199
ca9fab88 200static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
8ba9fd9c
LP
201 int r;
202
203 assert(reply);
204 assert(rr);
205
ca9fab88
LP
206 r = sd_bus_message_open_container(reply, 'r', "iiay");
207 if (r < 0)
208 return r;
78c6a153
LP
209
210 r = sd_bus_message_append(reply, "i", ifindex);
8ba9fd9c
LP
211 if (r < 0)
212 return r;
213
faa133f3 214 if (rr->key->type == DNS_TYPE_A) {
0dd25fb9 215 r = sd_bus_message_append(reply, "i", AF_INET);
8ba9fd9c
LP
216 if (r < 0)
217 return r;
218
219 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
faa133f3
LP
220
221 } else if (rr->key->type == DNS_TYPE_AAAA) {
0dd25fb9 222 r = sd_bus_message_append(reply, "i", AF_INET6);
8ba9fd9c
LP
223 if (r < 0)
224 return r;
225
226 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
faa133f3
LP
227 } else
228 return -EAFNOSUPPORT;
229
8ba9fd9c
LP
230 if (r < 0)
231 return r;
232
ca9fab88
LP
233 r = sd_bus_message_close_container(reply);
234 if (r < 0)
235 return r;
8ba9fd9c
LP
236
237 return 0;
238}
239
c704288c 240static void bus_method_resolve_hostname_complete(DnsQuery *query) {
45ec7efb 241 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
4afd3348 242 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c704288c 243 _cleanup_(dns_query_freep) DnsQuery *q = query;
c77d2612 244 _cleanup_free_ char *normalized = NULL;
c17b5ce7 245 DnsQuestion *question;
ce736ace 246 DnsResourceRecord *rr;
45ec7efb 247 unsigned added = 0;
ce736ace 248 int ifindex, r;
74b2466e 249
ad867662 250 assert(q);
74b2466e 251
ec2c5e43 252 if (q->state != DNS_TRANSACTION_SUCCESS) {
ad867662
LP
253 r = reply_query_state(q);
254 goto finish;
255 }
74b2466e 256
1db8e6d1 257 r = dns_query_process_cname_many(q);
45ec7efb 258 if (r == -ELOOP) {
2471a977 259 r = reply_method_errorf(q, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
45ec7efb
LP
260 goto finish;
261 }
262 if (r < 0)
263 goto finish;
c704288c
YW
264 if (r == DNS_QUERY_CNAME) {
265 /* This was a cname, and the query was restarted. */
266 TAKE_PTR(q);
45ec7efb 267 return;
c704288c 268 }
45ec7efb 269
c9de4e0f 270 r = sd_bus_message_new_method_return(q->bus_request, &reply);
ad867662
LP
271 if (r < 0)
272 goto finish;
74b2466e 273
78c6a153 274 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
51323288
LP
275 if (r < 0)
276 goto finish;
8ba9fd9c 277
c17b5ce7 278 question = dns_query_question_for_protocol(q, q->answer_protocol);
23b298bc 279
c17b5ce7 280 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
23b298bc 281
ce736ace
LP
282 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
283 if (r < 0)
284 goto finish;
285 if (r == 0)
286 continue;
74b2466e 287
ca9fab88 288 r = append_address(reply, rr, ifindex);
ce736ace
LP
289 if (r < 0)
290 goto finish;
74b2466e 291
ce736ace
LP
292 if (!canonical)
293 canonical = dns_resource_record_ref(rr);
309e9d86 294
313cefa1 295 added++;
8ba9fd9c 296 }
74b2466e 297
45ec7efb 298 if (added <= 0) {
2471a977 299 r = reply_method_errorf(q, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
45ec7efb 300 goto finish;
74b2466e
LP
301 }
302
ad867662
LP
303 r = sd_bus_message_close_container(reply);
304 if (r < 0)
305 goto finish;
306
c17b5ce7
LP
307 /* The key names are not necessarily normalized, make sure that they are when we return them to our
308 * bus clients. */
309 assert(canonical);
7470cc4c 310 r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
c77d2612
LP
311 if (r < 0)
312 goto finish;
313
45ec7efb 314 /* Return the precise spelling and uppercasing and CNAME target reported by the server */
45ec7efb
LP
315 r = sd_bus_message_append(
316 reply, "st",
c77d2612 317 normalized,
43fc4baa 318 dns_query_reply_flags_make(q));
309e9d86
LP
319 if (r < 0)
320 goto finish;
321
2471a977 322 q->bus_request = sd_bus_message_unref(q->bus_request);
ad867662 323 r = sd_bus_send(q->manager->bus, reply, NULL);
ad867662 324
74b2466e 325finish:
2d4c5cbc 326 if (r < 0) {
da927ba9 327 log_error_errno(r, "Failed to send hostname reply: %m");
2471a977 328 (void) reply_method_errnof(q, r, NULL);
2d4c5cbc 329 }
74b2466e
LP
330}
331
3354f500
LP
332static int validate_and_mangle_flags(
333 const char *name,
334 uint64_t *flags,
335 uint64_t ok,
336 sd_bus_error *error) {
337
51323288
LP
338 assert(flags);
339
c17b5ce7
LP
340 /* Checks that the client supplied interface index and flags parameter actually are valid and make
341 * sense in our method call context. Specifically:
342 *
343 * 1. Checks that the interface index is either 0 (meaning *all* interfaces) or positive
344 *
775ae354
LP
345 * 2. Only the protocols flags and a bunch of NO_XYZ flags are set, at most. Plus additional flags
346 * specific to our method, passed in the "ok" parameter.
c17b5ce7
LP
347 *
348 * 3. If zero protocol flags are specified it is automatically turned into *all* protocols. This way
349 * clients can simply pass 0 as flags and all will work as it should. They can also use this so
350 * that clients don't have to know all the protocols resolved implements, but can just specify 0
351 * to mean "all supported protocols".
352 */
353
775ae354
LP
354 if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|
355 SD_RESOLVED_NO_CNAME|
356 SD_RESOLVED_NO_VALIDATE|
357 SD_RESOLVED_NO_SYNTHESIZE|
358 SD_RESOLVED_NO_CACHE|
359 SD_RESOLVED_NO_ZONE|
360 SD_RESOLVED_NO_TRUST_ANCHOR|
361 SD_RESOLVED_NO_NETWORK|
362 ok))
1b09b81c 363 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
51323288 364
45ec7efb
LP
365 if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
366 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
51323288 367
3354f500
LP
368 /* Imply SD_RESOLVED_NO_SEARCH if permitted and name is dot suffixed. */
369 if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0)
370 *flags |= SD_RESOLVED_NO_SEARCH;
371
51323288
LP
372 return 0;
373}
374
c3be369f
LP
375static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) {
376 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
377 _cleanup_free_ char *canonical = NULL;
378 union in_addr_union parsed;
94831eae 379 int r, ff, parsed_ifindex = 0;
c3be369f
LP
380
381 /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it,
382 * let's not attempt to look it up. */
383
94831eae 384 r = in_addr_ifindex_from_string_auto(hostname, &ff, &parsed, &parsed_ifindex);
c3be369f
LP
385 if (r < 0) /* not an address */
386 return 0;
387
388 if (family != AF_UNSPEC && ff != family)
389 return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family.");
94831eae
LP
390 if (ifindex > 0 && parsed_ifindex > 0 && parsed_ifindex != ifindex)
391 return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address interface index does not match requested interface.");
392
393 if (parsed_ifindex > 0)
394 ifindex = parsed_ifindex;
c3be369f
LP
395
396 r = sd_bus_message_new_method_return(m, &reply);
397 if (r < 0)
398 return r;
399
400 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
401 if (r < 0)
402 return r;
403
404 r = sd_bus_message_open_container(reply, 'r', "iiay");
405 if (r < 0)
406 return r;
407
408 r = sd_bus_message_append(reply, "ii", ifindex, ff);
409 if (r < 0)
410 return r;
411
412 r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff));
413 if (r < 0)
414 return r;
415
416 r = sd_bus_message_close_container(reply);
417 if (r < 0)
418 return r;
419
420 r = sd_bus_message_close_container(reply);
421 if (r < 0)
422 return r;
423
424 /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS
425 * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner
426 * omissions are always done the same way). */
94831eae 427 r = in_addr_ifindex_to_string(ff, &parsed, ifindex, &canonical);
c3be369f
LP
428 if (r < 0)
429 return r;
430
431 r = sd_bus_message_append(reply, "st", canonical,
5c1790d1
LP
432 SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true, true) |
433 SD_RESOLVED_SYNTHETIC);
c3be369f
LP
434 if (r < 0)
435 return r;
436
437 return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
438}
439
1e69eadd
LP
440void bus_client_log(sd_bus_message *m, const char *what) {
441 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
442 const char *comm = NULL;
443 uid_t uid = UID_INVALID;
444 pid_t pid = 0;
445 int r;
446
447 assert(m);
448 assert(what);
449
450 if (!DEBUG_LOGGING)
451 return;
452
453 r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
454 if (r < 0)
455 return (void) log_debug_errno(r, "Failed to query client credentials, ignoring: %m");
456
457 (void) sd_bus_creds_get_uid(creds, &uid);
458 (void) sd_bus_creds_get_pid(creds, &pid);
459 (void) sd_bus_creds_get_comm(creds, &comm);
460
461 log_debug("D-Bus %s request from client PID " PID_FMT " (%s) with UID " UID_FMT,
462 what, pid, strna(comm), uid);
463}
464
19070062 465static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
23b298bc 466 _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
c704288c 467 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
99534007 468 Manager *m = ASSERT_PTR(userdata);
74b2466e 469 const char *hostname;
51323288
LP
470 int family, ifindex;
471 uint64_t flags;
74b2466e
LP
472 int r;
473
74b2466e 474 assert(message);
74b2466e 475
45ec7efb
LP
476 assert_cc(sizeof(int) == sizeof(int32_t));
477
51323288 478 r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
74b2466e
LP
479 if (r < 0)
480 return r;
481
3354f500 482 if (ifindex < 0)
1b09b81c 483 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
3354f500 484
74b2466e 485 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
0dd25fb9 486 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e 487
3354f500 488 r = validate_and_mangle_flags(hostname, &flags, SD_RESOLVED_NO_SEARCH, error);
7b9f7afc 489 if (r < 0)
45ec7efb 490 return r;
74b2466e 491
c3be369f
LP
492 r = parse_as_address(message, ifindex, hostname, family, flags);
493 if (r != 0)
494 return r;
495
496 r = dns_name_is_valid(hostname);
51323288
LP
497 if (r < 0)
498 return r;
c3be369f
LP
499 if (r == 0)
500 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
51323288 501
23b298bc
LP
502 r = dns_question_new_address(&question_utf8, family, hostname, false);
503 if (r < 0)
504 return r;
505
506 r = dns_question_new_address(&question_idna, family, hostname, true);
ad1f3fe6 507 if (r < 0 && r != -EALREADY)
45ec7efb 508 return r;
74b2466e 509
1e69eadd
LP
510 bus_client_log(message, "hostname resolution");
511
775ae354 512 r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, NULL, ifindex, flags);
74b2466e
LP
513 if (r < 0)
514 return r;
515
c9de4e0f 516 q->bus_request = sd_bus_message_ref(message);
74b2466e 517 q->request_family = family;
74b2466e
LP
518 q->complete = bus_method_resolve_hostname_complete;
519
966c66e3 520 r = dns_query_bus_track(q, message);
82bd6ddd 521 if (r < 0)
c704288c 522 return r;
82bd6ddd 523
322345fd 524 r = dns_query_go(q);
45ec7efb 525 if (r < 0)
c704288c 526 return r;
74b2466e 527
c704288c 528 TAKE_PTR(q);
74b2466e
LP
529 return 1;
530}
531
c704288c 532static void bus_method_resolve_address_complete(DnsQuery *query) {
4afd3348 533 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c704288c 534 _cleanup_(dns_query_freep) DnsQuery *q = query;
23b298bc 535 DnsQuestion *question;
45ec7efb
LP
536 DnsResourceRecord *rr;
537 unsigned added = 0;
538 int ifindex, r;
74b2466e
LP
539
540 assert(q);
541
ec2c5e43 542 if (q->state != DNS_TRANSACTION_SUCCESS) {
ad867662
LP
543 r = reply_query_state(q);
544 goto finish;
545 }
74b2466e 546
1db8e6d1 547 r = dns_query_process_cname_many(q);
95d46fca 548 if (r == -ELOOP) {
2471a977 549 r = reply_method_errorf(q, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
95d46fca
TG
550 goto finish;
551 }
552 if (r < 0)
553 goto finish;
c704288c
YW
554 if (r == DNS_QUERY_CNAME) {
555 /* This was a cname, and the query was restarted. */
556 TAKE_PTR(q);
95d46fca 557 return;
c704288c 558 }
45ec7efb 559
c9de4e0f 560 r = sd_bus_message_new_method_return(q->bus_request, &reply);
ad867662
LP
561 if (r < 0)
562 goto finish;
74b2466e 563
78c6a153 564 r = sd_bus_message_open_container(reply, 'a', "(is)");
ad867662
LP
565 if (r < 0)
566 goto finish;
74b2466e 567
23b298bc 568 question = dns_query_question_for_protocol(q, q->answer_protocol);
74b2466e 569
23b298bc 570 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
c77d2612
LP
571 _cleanup_free_ char *normalized = NULL;
572
23b298bc
LP
573 r = dns_question_matches_rr(question, rr, NULL);
574 if (r < 0)
575 goto finish;
576 if (r == 0)
577 continue;
74b2466e 578
7470cc4c 579 r = dns_name_normalize(rr->ptr.name, 0, &normalized);
c77d2612
LP
580 if (r < 0)
581 goto finish;
582
583 r = sd_bus_message_append(reply, "(is)", ifindex, normalized);
23b298bc
LP
584 if (r < 0)
585 goto finish;
586
313cefa1 587 added++;
ad867662 588 }
74b2466e 589
45ec7efb 590 if (added <= 0) {
2471a977 591 r = reply_method_errorf(q, BUS_ERROR_NO_SUCH_RR,
84dbb3fd
ZJS
592 "Address %s does not have any RR of requested type",
593 IN_ADDR_TO_STRING(q->request_family, &q->request_address));
ad867662 594 goto finish;
74b2466e
LP
595 }
596
ad867662
LP
597 r = sd_bus_message_close_container(reply);
598 if (r < 0)
599 goto finish;
74b2466e 600
43fc4baa 601 r = sd_bus_message_append(reply, "t", dns_query_reply_flags_make(q));
51323288
LP
602 if (r < 0)
603 goto finish;
604
2471a977 605 q->bus_request = sd_bus_message_unref(q->bus_request);
ad867662 606 r = sd_bus_send(q->manager->bus, reply, NULL);
74b2466e
LP
607
608finish:
2d4c5cbc 609 if (r < 0) {
da927ba9 610 log_error_errno(r, "Failed to send address reply: %m");
2471a977 611 (void) reply_method_errnof(q, r, NULL);
2d4c5cbc 612 }
74b2466e
LP
613}
614
19070062 615static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3 616 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
c704288c 617 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
99534007 618 Manager *m = ASSERT_PTR(userdata);
7695e2cb 619 union in_addr_union a;
faa133f3 620 int family, ifindex;
51323288 621 uint64_t flags;
74b2466e
LP
622 int r;
623
74b2466e 624 assert(message);
74b2466e 625
45ec7efb
LP
626 assert_cc(sizeof(int) == sizeof(int32_t));
627
7695e2cb 628 r = sd_bus_message_read(message, "i", &ifindex);
74b2466e
LP
629 if (r < 0)
630 return r;
631
7695e2cb 632 r = bus_message_read_in_addr_auto(message, error, &family, &a);
74b2466e
LP
633 if (r < 0)
634 return r;
635
51323288
LP
636 r = sd_bus_message_read(message, "t", &flags);
637 if (r < 0)
638 return r;
639
3354f500 640 if (ifindex < 0)
1b09b81c 641 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
3354f500
LP
642
643 r = validate_and_mangle_flags(NULL, &flags, 0, error);
faa133f3
LP
644 if (r < 0)
645 return r;
646
7695e2cb 647 r = dns_question_new_reverse(&question, family, &a);
74b2466e
LP
648 if (r < 0)
649 return r;
650
1e69eadd
LP
651 bus_client_log(message, "address resolution");
652
775ae354 653 r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH);
74b2466e
LP
654 if (r < 0)
655 return r;
656
c9de4e0f 657 q->bus_request = sd_bus_message_ref(message);
74b2466e 658 q->request_family = family;
7695e2cb 659 q->request_address = a;
74b2466e
LP
660 q->complete = bus_method_resolve_address_complete;
661
966c66e3 662 r = dns_query_bus_track(q, message);
82bd6ddd 663 if (r < 0)
c704288c 664 return r;
82bd6ddd 665
322345fd 666 r = dns_query_go(q);
45ec7efb 667 if (r < 0)
c704288c 668 return r;
74b2466e 669
c704288c 670 TAKE_PTR(q);
74b2466e 671 return 1;
45ec7efb
LP
672}
673
674static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) {
45ec7efb
LP
675 int r;
676
677 assert(m);
678 assert(rr);
679
680 r = sd_bus_message_open_container(m, 'r', "iqqay");
681 if (r < 0)
682 return r;
683
684 r = sd_bus_message_append(m, "iqq",
685 ifindex,
686 rr->key->class,
687 rr->key->type);
688 if (r < 0)
689 return r;
690
4e2d538f 691 r = dns_resource_record_to_wire_format(rr, false);
45ec7efb
LP
692 if (r < 0)
693 return r;
694
4e2d538f 695 r = sd_bus_message_append_array(m, 'y', rr->wire_format, rr->wire_format_size);
45ec7efb
LP
696 if (r < 0)
697 return r;
698
699 return sd_bus_message_close_container(m);
74b2466e
LP
700}
701
c704288c 702static void bus_method_resolve_record_complete(DnsQuery *query) {
4afd3348 703 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c704288c 704 _cleanup_(dns_query_freep) DnsQuery *q = query;
23b298bc
LP
705 DnsResourceRecord *rr;
706 DnsQuestion *question;
45ec7efb 707 unsigned added = 0;
23b298bc 708 int ifindex;
2d4c5cbc
LP
709 int r;
710
711 assert(q);
712
ec2c5e43 713 if (q->state != DNS_TRANSACTION_SUCCESS) {
2d4c5cbc
LP
714 r = reply_query_state(q);
715 goto finish;
716 }
717
1db8e6d1 718 r = dns_query_process_cname_many(q);
45ec7efb 719 if (r == -ELOOP) {
2471a977 720 r = reply_method_errorf(q, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
45ec7efb
LP
721 goto finish;
722 }
723 if (r < 0)
724 goto finish;
c704288c
YW
725 if (r == DNS_QUERY_CNAME) {
726 /* This was a cname, and the query was restarted. */
727 TAKE_PTR(q);
45ec7efb 728 return;
c704288c 729 }
45ec7efb 730
c9de4e0f 731 r = sd_bus_message_new_method_return(q->bus_request, &reply);
2d4c5cbc
LP
732 if (r < 0)
733 goto finish;
734
78c6a153 735 r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
2d4c5cbc
LP
736 if (r < 0)
737 goto finish;
738
23b298bc 739 question = dns_query_question_for_protocol(q, q->answer_protocol);
2d4c5cbc 740
23b298bc
LP
741 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
742 r = dns_question_matches_rr(question, rr, NULL);
743 if (r < 0)
744 goto finish;
745 if (r == 0)
746 continue;
2d4c5cbc 747
23b298bc
LP
748 r = bus_message_append_rr(reply, rr, ifindex);
749 if (r < 0)
750 goto finish;
2d4c5cbc 751
313cefa1 752 added++;
2d4c5cbc
LP
753 }
754
755 if (added <= 0) {
2471a977 756 r = reply_method_errorf(q, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_query_string(q));
2d4c5cbc
LP
757 goto finish;
758 }
759
760 r = sd_bus_message_close_container(reply);
761 if (r < 0)
762 goto finish;
763
43fc4baa 764 r = sd_bus_message_append(reply, "t", dns_query_reply_flags_make(q));
51323288
LP
765 if (r < 0)
766 goto finish;
767
2471a977 768 q->bus_request = sd_bus_message_unref(q->bus_request);
2d4c5cbc
LP
769 r = sd_bus_send(q->manager->bus, reply, NULL);
770
771finish:
772 if (r < 0) {
da927ba9 773 log_error_errno(r, "Failed to send record reply: %m");
2471a977 774 (void) reply_method_errnof(q, r, NULL);
2d4c5cbc 775 }
2d4c5cbc
LP
776}
777
19070062 778static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
2d4c5cbc
LP
779 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
780 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
c704288c 781 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
99534007 782 Manager *m = ASSERT_PTR(userdata);
2d4c5cbc
LP
783 uint16_t class, type;
784 const char *name;
51323288
LP
785 int r, ifindex;
786 uint64_t flags;
2d4c5cbc 787
2d4c5cbc 788 assert(message);
2d4c5cbc 789
45ec7efb
LP
790 assert_cc(sizeof(int) == sizeof(int32_t));
791
51323288 792 r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
2d4c5cbc
LP
793 if (r < 0)
794 return r;
795
3354f500 796 if (ifindex < 0)
1b09b81c 797 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
3354f500 798
45ec7efb 799 r = dns_name_is_valid(name);
7b9f7afc 800 if (r < 0)
45ec7efb
LP
801 return r;
802 if (r == 0)
7b9f7afc
LP
803 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
804
c463eb78 805 if (!dns_type_is_valid_query(type))
eee026a7 806 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified resource record type %" PRIu16 " may not be used in a query.", type);
6ebd1e33 807 if (dns_type_is_zone_transer(type))
1b09b81c 808 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Zone transfers not permitted via this programming interface.");
d0129ddb 809 if (dns_type_is_obsolete(type))
eee026a7 810 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
c463eb78 811
3354f500 812 r = validate_and_mangle_flags(name, &flags, 0, error);
51323288
LP
813 if (r < 0)
814 return r;
815
2d4c5cbc
LP
816 question = dns_question_new(1);
817 if (!question)
818 return -ENOMEM;
819
820 key = dns_resource_key_new(class, type, name);
821 if (!key)
822 return -ENOMEM;
823
ab715ddb 824 r = dns_question_add(question, key, 0);
2d4c5cbc
LP
825 if (r < 0)
826 return r;
827
1e69eadd
LP
828 bus_client_log(message, "resource record resolution");
829
775ae354
LP
830 /* Setting SD_RESOLVED_CLAMP_TTL: let's request that the TTL is fixed up for locally cached entries,
831 * after all we return it in the wire format blob. */
832 r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_CLAMP_TTL);
2d4c5cbc
LP
833 if (r < 0)
834 return r;
835
c9de4e0f 836 q->bus_request = sd_bus_message_ref(message);
2d4c5cbc
LP
837 q->complete = bus_method_resolve_record_complete;
838
966c66e3 839 r = dns_query_bus_track(q, message);
82bd6ddd 840 if (r < 0)
c704288c 841 return r;
82bd6ddd 842
2d4c5cbc 843 r = dns_query_go(q);
45ec7efb 844 if (r < 0)
c704288c 845 return r;
45ec7efb 846
c704288c 847 TAKE_PTR(q);
45ec7efb 848 return 1;
45ec7efb
LP
849}
850
851static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
852 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
c77d2612 853 _cleanup_free_ char *normalized = NULL;
45ec7efb
LP
854 int r;
855
856 assert(q);
857 assert(reply);
858 assert(rr);
859 assert(rr->key);
860
861 if (rr->key->type != DNS_TYPE_SRV)
862 return 0;
863
864 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
865 /* First, let's see if we could find an appropriate A or AAAA
866 * record for the SRV record */
867 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
868 DnsResourceRecord *zz;
23b298bc 869 DnsQuestion *question;
45ec7efb
LP
870
871 if (aux->state != DNS_TRANSACTION_SUCCESS)
872 continue;
873 if (aux->auxiliary_result != 0)
874 continue;
875
23b298bc
LP
876 question = dns_query_question_for_protocol(aux, aux->answer_protocol);
877
878 r = dns_name_equal(dns_question_first_name(question), rr->srv.name);
45ec7efb
LP
879 if (r < 0)
880 return r;
881 if (r == 0)
882 continue;
883
884 DNS_ANSWER_FOREACH(zz, aux->answer) {
885
23b298bc 886 r = dns_question_matches_rr(question, zz, NULL);
45ec7efb
LP
887 if (r < 0)
888 return r;
889 if (r == 0)
890 continue;
891
892 canonical = dns_resource_record_ref(zz);
893 break;
894 }
895
896 if (canonical)
897 break;
898 }
899
900 /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */
901 if (!canonical)
902 return 0;
903 }
904
905 r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s");
906 if (r < 0)
907 return r;
908
7470cc4c 909 r = dns_name_normalize(rr->srv.name, 0, &normalized);
c77d2612
LP
910 if (r < 0)
911 return r;
912
45ec7efb
LP
913 r = sd_bus_message_append(
914 reply,
915 "qqqs",
c77d2612 916 rr->srv.priority, rr->srv.weight, rr->srv.port, normalized);
45ec7efb
LP
917 if (r < 0)
918 return r;
919
920 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
921 if (r < 0)
922 return r;
923
924 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
925 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
926 DnsResourceRecord *zz;
23b298bc 927 DnsQuestion *question;
45ec7efb
LP
928 int ifindex;
929
930 if (aux->state != DNS_TRANSACTION_SUCCESS)
931 continue;
932 if (aux->auxiliary_result != 0)
933 continue;
934
23b298bc
LP
935 question = dns_query_question_for_protocol(aux, aux->answer_protocol);
936
937 r = dns_name_equal(dns_question_first_name(question), rr->srv.name);
45ec7efb
LP
938 if (r < 0)
939 return r;
940 if (r == 0)
941 continue;
942
943 DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) {
944
23b298bc 945 r = dns_question_matches_rr(question, zz, NULL);
45ec7efb
LP
946 if (r < 0)
947 return r;
948 if (r == 0)
949 continue;
950
ca9fab88 951 r = append_address(reply, zz, ifindex);
45ec7efb
LP
952 if (r < 0)
953 return r;
954 }
955 }
956 }
957
958 r = sd_bus_message_close_container(reply);
959 if (r < 0)
960 return r;
961
c77d2612
LP
962 if (canonical) {
963 normalized = mfree(normalized);
964
7470cc4c 965 r = dns_name_normalize(dns_resource_key_name(canonical->key), 0, &normalized);
c77d2612
LP
966 if (r < 0)
967 return r;
968 }
969
45ec7efb
LP
970 /* Note that above we appended the hostname as encoded in the
971 * SRV, and here the canonical hostname this maps to. */
c77d2612 972 r = sd_bus_message_append(reply, "s", normalized);
45ec7efb
LP
973 if (r < 0)
974 return r;
975
976 r = sd_bus_message_close_container(reply);
977 if (r < 0)
978 return r;
979
980 return 1;
981}
982
983static int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) {
45ec7efb
LP
984 int r;
985
986 assert(reply);
987 assert(rr);
988 assert(rr->key);
989
990 if (rr->key->type != DNS_TYPE_TXT)
991 return 0;
992
993 LIST_FOREACH(items, i, rr->txt.items) {
994
995 if (i->length <= 0)
996 continue;
997
998 r = sd_bus_message_append_array(reply, 'y', i->data, i->length);
999 if (r < 0)
1000 return r;
1001 }
1002
1003 return 1;
1004}
1005
c704288c 1006static void resolve_service_all_complete(DnsQuery *query) {
45ec7efb
LP
1007 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
1008 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1009 _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
c704288c 1010 _cleanup_(dns_query_freep) DnsQuery *q = query;
23b298bc
LP
1011 DnsQuestion *question;
1012 DnsResourceRecord *rr;
1013 unsigned added = 0;
45ec7efb
LP
1014 int r;
1015
1016 assert(q);
1017
c704288c
YW
1018 if (q->block_all_complete > 0) {
1019 TAKE_PTR(q);
45ec7efb 1020 return;
c704288c 1021 }
45ec7efb
LP
1022
1023 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
1024 DnsQuery *bad = NULL;
1025 bool have_success = false;
1026
1027 LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
1028
1029 switch (aux->state) {
1030
1031 case DNS_TRANSACTION_PENDING:
1032 /* If an auxiliary query is still pending, let's wait */
c704288c 1033 TAKE_PTR(q);
45ec7efb
LP
1034 return;
1035
1036 case DNS_TRANSACTION_SUCCESS:
1037 if (aux->auxiliary_result == 0)
1038 have_success = true;
1039 else
1040 bad = aux;
1041 break;
1042
1043 default:
1044 bad = aux;
1045 break;
1046 }
1047 }
1048
1049 if (!have_success) {
1050 /* We can only return one error, hence pick the last error we encountered */
1051
1052 assert(bad);
1053
1054 if (bad->state == DNS_TRANSACTION_SUCCESS) {
1055 assert(bad->auxiliary_result != 0);
1056
1057 if (bad->auxiliary_result == -ELOOP) {
2471a977 1058 r = reply_method_errorf(q, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(bad));
45ec7efb
LP
1059 goto finish;
1060 }
1061
5a78106a 1062 assert(bad->auxiliary_result < 0);
45ec7efb
LP
1063 r = bad->auxiliary_result;
1064 goto finish;
1065 }
1066
1067 r = reply_query_state(bad);
1068 goto finish;
1069 }
1070 }
1071
c9de4e0f 1072 r = sd_bus_message_new_method_return(q->bus_request, &reply);
45ec7efb
LP
1073 if (r < 0)
1074 goto finish;
1075
1076 r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)");
1077 if (r < 0)
1078 goto finish;
1079
23b298bc 1080 question = dns_query_question_for_protocol(q, q->answer_protocol);
c17b5ce7 1081
23b298bc
LP
1082 DNS_ANSWER_FOREACH(rr, q->answer) {
1083 r = dns_question_matches_rr(question, rr, NULL);
1084 if (r < 0)
1085 goto finish;
1086 if (r == 0)
1087 continue;
45ec7efb 1088
23b298bc
LP
1089 r = append_srv(q, reply, rr);
1090 if (r < 0)
1091 goto finish;
1092 if (r == 0) /* not an SRV record */
1093 continue;
45ec7efb 1094
23b298bc
LP
1095 if (!canonical)
1096 canonical = dns_resource_record_ref(rr);
45ec7efb 1097
23b298bc 1098 added++;
45ec7efb
LP
1099 }
1100
1101 if (added <= 0) {
2471a977 1102 r = reply_method_errorf(q, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
45ec7efb
LP
1103 goto finish;
1104 }
1105
1106 r = sd_bus_message_close_container(reply);
1107 if (r < 0)
1108 goto finish;
1109
1110 r = sd_bus_message_open_container(reply, 'a', "ay");
1111 if (r < 0)
1112 goto finish;
1113
23b298bc
LP
1114 DNS_ANSWER_FOREACH(rr, q->answer) {
1115 r = dns_question_matches_rr(question, rr, NULL);
1116 if (r < 0)
1117 goto finish;
1118 if (r == 0)
1119 continue;
45ec7efb 1120
23b298bc
LP
1121 r = append_txt(reply, rr);
1122 if (r < 0)
1123 goto finish;
45ec7efb
LP
1124 }
1125
1126 r = sd_bus_message_close_container(reply);
1127 if (r < 0)
1128 goto finish;
1129
1130 assert(canonical);
1c02e7ba 1131 r = dns_service_split(dns_resource_key_name(canonical->key), &name, &type, &domain);
45ec7efb
LP
1132 if (r < 0)
1133 goto finish;
1134
1135 r = sd_bus_message_append(
1136 reply,
1137 "ssst",
1138 name, type, domain,
43fc4baa 1139 dns_query_reply_flags_make(q));
45ec7efb
LP
1140 if (r < 0)
1141 goto finish;
1142
2471a977 1143 q->bus_request = sd_bus_message_unref(q->bus_request);
45ec7efb
LP
1144 r = sd_bus_send(q->manager->bus, reply, NULL);
1145
1146finish:
1147 if (r < 0) {
1148 log_error_errno(r, "Failed to send service reply: %m");
2471a977 1149 (void) reply_method_errnof(q, r, NULL);
45ec7efb 1150 }
45ec7efb
LP
1151}
1152
1153static void resolve_service_hostname_complete(DnsQuery *q) {
1154 int r;
1155
1156 assert(q);
1157 assert(q->auxiliary_for);
1158
1159 if (q->state != DNS_TRANSACTION_SUCCESS) {
1160 resolve_service_all_complete(q->auxiliary_for);
1161 return;
1162 }
1163
1db8e6d1
LP
1164 r = dns_query_process_cname_many(q);
1165 if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */
45ec7efb
LP
1166 return;
1167
1168 /* This auxiliary lookup is finished or failed, let's see if all are finished now. */
5a78106a 1169 q->auxiliary_result = r < 0 ? r : 0;
45ec7efb
LP
1170 resolve_service_all_complete(q->auxiliary_for);
1171}
1172
1173static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) {
1174 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
c704288c 1175 _cleanup_(dns_query_freep) DnsQuery *aux = NULL;
45ec7efb
LP
1176 int r;
1177
1178 assert(q);
1179 assert(rr);
1180 assert(rr->key);
1181 assert(rr->key->type == DNS_TYPE_SRV);
1182
1183 /* OK, we found an SRV record for the service. Let's resolve
1184 * the hostname included in it */
1185
23b298bc 1186 r = dns_question_new_address(&question, q->request_family, rr->srv.name, false);
45ec7efb
LP
1187 if (r < 0)
1188 return r;
1189
775ae354 1190 r = dns_query_new(q->manager, &aux, question, question, NULL, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
45ec7efb
LP
1191 if (r < 0)
1192 return r;
1193
1194 aux->request_family = q->request_family;
1195 aux->complete = resolve_service_hostname_complete;
1196
1197 r = dns_query_make_auxiliary(aux, q);
c704288c 1198 if (r == -EAGAIN)
45ec7efb
LP
1199 /* Too many auxiliary lookups? If so, don't complain,
1200 * let's just not add this one, we already have more
1201 * than enough */
45ec7efb 1202 return 0;
45ec7efb 1203 if (r < 0)
c704288c 1204 return r;
45ec7efb
LP
1205
1206 /* Note that auxiliary queries do not track the original bus
1207 * client, only the primary request does that. */
1208
1209 r = dns_query_go(aux);
1210 if (r < 0)
c704288c 1211 return r;
45ec7efb 1212
c704288c 1213 TAKE_PTR(aux);
45ec7efb 1214 return 1;
45ec7efb
LP
1215}
1216
c704288c
YW
1217static void bus_method_resolve_service_complete(DnsQuery *query) {
1218 _cleanup_(dns_query_freep) DnsQuery *q = query;
23b298bc
LP
1219 bool has_root_domain = false;
1220 DnsResourceRecord *rr;
1221 DnsQuestion *question;
45ec7efb 1222 unsigned found = 0;
23b298bc 1223 int ifindex, r;
45ec7efb
LP
1224
1225 assert(q);
1226
1227 if (q->state != DNS_TRANSACTION_SUCCESS) {
1228 r = reply_query_state(q);
1229 goto finish;
1230 }
1231
1db8e6d1 1232 r = dns_query_process_cname_many(q);
45ec7efb 1233 if (r == -ELOOP) {
2471a977 1234 r = reply_method_errorf(q, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q));
45ec7efb
LP
1235 goto finish;
1236 }
1237 if (r < 0)
1238 goto finish;
c704288c
YW
1239 if (r == DNS_QUERY_CNAME) {
1240 /* This was a cname, and the query was restarted. */
1241 TAKE_PTR(q);
45ec7efb 1242 return;
c704288c 1243 }
45ec7efb 1244
23b298bc 1245 question = dns_query_question_for_protocol(q, q->answer_protocol);
45ec7efb 1246
23b298bc
LP
1247 DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
1248 r = dns_question_matches_rr(question, rr, NULL);
1249 if (r < 0)
1250 goto finish;
1251 if (r == 0)
1252 continue;
45ec7efb 1253
23b298bc
LP
1254 if (rr->key->type != DNS_TYPE_SRV)
1255 continue;
9a1f0c28 1256
23b298bc
LP
1257 if (dns_name_is_root(rr->srv.name)) {
1258 has_root_domain = true;
1259 continue;
1260 }
45ec7efb 1261
23b298bc 1262 if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
313cefa1 1263 q->block_all_complete++;
23b298bc 1264 r = resolve_service_hostname(q, rr, ifindex);
313cefa1 1265 q->block_all_complete--;
45ec7efb 1266
23b298bc
LP
1267 if (r < 0)
1268 goto finish;
45ec7efb 1269 }
9a1f0c28 1270
23b298bc
LP
1271 found++;
1272 }
9a1f0c28 1273
23b298bc 1274 if (has_root_domain && found <= 0) {
2471a977
LP
1275 /* If there's exactly one SRV RR and it uses the root domain as hostname, then the service is
1276 * explicitly not offered on the domain. Report this as a recognizable error. See RFC 2782,
1277 * Section "Usage Rules". */
1278 r = reply_method_errorf(q, BUS_ERROR_NO_SUCH_SERVICE, "'%s' does not provide the requested service", dns_query_string(q));
23b298bc 1279 goto finish;
45ec7efb
LP
1280 }
1281
1282 if (found <= 0) {
2471a977 1283 r = reply_method_errorf(q, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_query_string(q));
45ec7efb
LP
1284 goto finish;
1285 }
1286
1287 /* Maybe we are already finished? check now... */
c704288c 1288 resolve_service_all_complete(TAKE_PTR(q));
45ec7efb
LP
1289 return;
1290
1291finish:
2d4c5cbc 1292 if (r < 0) {
45ec7efb 1293 log_error_errno(r, "Failed to send service reply: %m");
2471a977 1294 (void) reply_method_errnof(q, r, NULL);
45ec7efb 1295 }
45ec7efb
LP
1296}
1297
1298static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
23b298bc 1299 _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
c704288c 1300 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
23b298bc 1301 const char *name, *type, *domain;
99534007 1302 Manager *m = ASSERT_PTR(userdata);
45ec7efb
LP
1303 int family, ifindex;
1304 uint64_t flags;
45ec7efb
LP
1305 int r;
1306
1307 assert(message);
45ec7efb
LP
1308
1309 assert_cc(sizeof(int) == sizeof(int32_t));
1310
1311 r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
1312 if (r < 0)
2d4c5cbc 1313 return r;
45ec7efb 1314
3354f500 1315 if (ifindex < 0)
1b09b81c 1316 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
3354f500 1317
45ec7efb
LP
1318 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
1319 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
1320
1321 if (isempty(name))
1322 name = NULL;
23b298bc
LP
1323 else if (!dns_service_name_is_valid(name))
1324 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
2d4c5cbc 1325
45ec7efb
LP
1326 if (isempty(type))
1327 type = NULL;
7e8131e9
LP
1328 else if (!dns_srv_type_is_valid(type))
1329 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
45ec7efb
LP
1330
1331 r = dns_name_is_valid(domain);
1332 if (r < 0)
1333 return r;
1334 if (r == 0)
1335 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
1336
1337 if (name && !type)
1b09b81c 1338 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
45ec7efb 1339
3354f500 1340 r = validate_and_mangle_flags(name, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
45ec7efb
LP
1341 if (r < 0)
1342 return r;
1343
23b298bc
LP
1344 r = dns_question_new_service(&question_utf8, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), false);
1345 if (r < 0)
1346 return r;
45ec7efb 1347
23b298bc 1348 r = dns_question_new_service(&question_idna, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), true);
45ec7efb
LP
1349 if (r < 0)
1350 return r;
1351
1e69eadd
LP
1352 bus_client_log(message, "service resolution");
1353
775ae354 1354 r = dns_query_new(m, &q, question_utf8, question_idna, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH);
45ec7efb
LP
1355 if (r < 0)
1356 return r;
1357
c9de4e0f 1358 q->bus_request = sd_bus_message_ref(message);
45ec7efb
LP
1359 q->request_family = family;
1360 q->complete = bus_method_resolve_service_complete;
1361
1362 r = dns_query_bus_track(q, message);
1363 if (r < 0)
c704288c 1364 return r;
45ec7efb
LP
1365
1366 r = dns_query_go(q);
1367 if (r < 0)
c704288c 1368 return r;
45ec7efb 1369
c704288c 1370 TAKE_PTR(q);
2d4c5cbc
LP
1371 return 1;
1372}
1373
5707fb12
LP
1374int bus_dns_server_append(
1375 sd_bus_message *reply,
1376 DnsServer *s,
1377 bool with_ifindex, /* include "ifindex" field */
1378 bool extended) { /* also include port number and server name */
7f220d94
LP
1379 int r;
1380
1381 assert(reply);
b7ac92cd
YW
1382
1383 if (!s) {
8e56ea4c
YW
1384 if (with_ifindex) {
1385 if (extended)
1386 return sd_bus_message_append(reply, "(iiayqs)", 0, AF_UNSPEC, 0, 0, NULL);
1387 else
1388 return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0);
1389 } else {
1390 if (extended)
1391 return sd_bus_message_append(reply, "(iayqs)", AF_UNSPEC, 0, 0, NULL);
1392 else
1393 return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0);
1394 }
b7ac92cd 1395 }
7f220d94 1396
5707fb12
LP
1397 r = sd_bus_message_open_container(
1398 reply,
1399 'r',
1400 with_ifindex ? (extended ? "iiayqs" : "iiay") :
1401 (extended ? "iayqs" : "iay"));
7f220d94
LP
1402 if (r < 0)
1403 return r;
1404
3abaabda 1405 if (with_ifindex) {
2817157b 1406 r = sd_bus_message_append(reply, "i", dns_server_ifindex(s));
3abaabda
LP
1407 if (r < 0)
1408 return r;
1409 }
1410
1411 r = sd_bus_message_append(reply, "i", s->family);
7f220d94
LP
1412 if (r < 0)
1413 return r;
1414
1415 r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
1416 if (r < 0)
1417 return r;
1418
8e56ea4c
YW
1419 if (extended) {
1420 r = sd_bus_message_append(reply, "q", s->port);
1421 if (r < 0)
1422 return r;
1423
1424 r = sd_bus_message_append(reply, "s", s->server_name);
1425 if (r < 0)
1426 return r;
1427 }
1428
7f220d94
LP
1429 return sd_bus_message_close_container(reply);
1430}
1431
8e56ea4c 1432static int bus_property_get_dns_servers_internal(
7f220d94
LP
1433 sd_bus *bus,
1434 const char *path,
1435 const char *interface,
1436 const char *property,
1437 sd_bus_message *reply,
1438 void *userdata,
8e56ea4c
YW
1439 sd_bus_error *error,
1440 bool extended) {
7f220d94 1441
99534007 1442 Manager *m = ASSERT_PTR(userdata);
7f220d94
LP
1443 Link *l;
1444 int r;
1445
1446 assert(reply);
7f220d94 1447
8e56ea4c 1448 r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)");
7f220d94
LP
1449 if (r < 0)
1450 return r;
1451
1452 LIST_FOREACH(servers, s, m->dns_servers) {
8e56ea4c 1453 r = bus_dns_server_append(reply, s, true, extended);
7f220d94
LP
1454 if (r < 0)
1455 return r;
7f220d94
LP
1456 }
1457
90e74a66 1458 HASHMAP_FOREACH(l, m->links)
7f220d94 1459 LIST_FOREACH(servers, s, l->dns_servers) {
8e56ea4c 1460 r = bus_dns_server_append(reply, s, true, extended);
7f220d94
LP
1461 if (r < 0)
1462 return r;
7f220d94 1463 }
7f220d94 1464
ad32ac53
YW
1465 return sd_bus_message_close_container(reply);
1466}
1467
8e56ea4c 1468static int bus_property_get_dns_servers(
ad32ac53
YW
1469 sd_bus *bus,
1470 const char *path,
1471 const char *interface,
1472 const char *property,
1473 sd_bus_message *reply,
1474 void *userdata,
1475 sd_bus_error *error) {
8e56ea4c
YW
1476 return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false);
1477}
1478
1479static int bus_property_get_dns_servers_ex(
1480 sd_bus *bus,
1481 const char *path,
1482 const char *interface,
1483 const char *property,
1484 sd_bus_message *reply,
1485 void *userdata,
1486 sd_bus_error *error) {
1487 return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true);
1488}
1489
1490static int bus_property_get_fallback_dns_servers_internal(
1491 sd_bus *bus,
1492 const char *path,
1493 const char *interface,
1494 const char *property,
1495 sd_bus_message *reply,
1496 void *userdata,
1497 sd_bus_error *error,
1498 bool extended) {
ad32ac53 1499
99534007 1500 DnsServer **f = ASSERT_PTR(userdata);
ad32ac53
YW
1501 int r;
1502
1503 assert(reply);
ad32ac53 1504
8e56ea4c 1505 r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)");
ad32ac53
YW
1506 if (r < 0)
1507 return r;
1508
1509 LIST_FOREACH(servers, s, *f) {
8e56ea4c 1510 r = bus_dns_server_append(reply, s, true, extended);
ad32ac53
YW
1511 if (r < 0)
1512 return r;
7f220d94
LP
1513 }
1514
1515 return sd_bus_message_close_container(reply);
1516}
1517
8e56ea4c 1518static int bus_property_get_fallback_dns_servers(
b7ac92cd
YW
1519 sd_bus *bus,
1520 const char *path,
1521 const char *interface,
1522 const char *property,
1523 sd_bus_message *reply,
1524 void *userdata,
1525 sd_bus_error *error) {
8e56ea4c
YW
1526 return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false);
1527}
1528
1529static int bus_property_get_fallback_dns_servers_ex(
1530 sd_bus *bus,
1531 const char *path,
1532 const char *interface,
1533 const char *property,
1534 sd_bus_message *reply,
1535 void *userdata,
1536 sd_bus_error *error) {
1537 return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true);
1538}
1539
1540static int bus_property_get_current_dns_server_internal(
1541 sd_bus *bus,
1542 const char *path,
1543 const char *interface,
1544 const char *property,
1545 sd_bus_message *reply,
1546 void *userdata,
1547 sd_bus_error *error,
1548 bool extended) {
b7ac92cd
YW
1549
1550 DnsServer *s;
1551
1552 assert(reply);
1553 assert(userdata);
1554
1555 s = *(DnsServer **) userdata;
1556
8e56ea4c
YW
1557 return bus_dns_server_append(reply, s, true, extended);
1558}
1559
1560static int bus_property_get_current_dns_server(
1561 sd_bus *bus,
1562 const char *path,
1563 const char *interface,
1564 const char *property,
1565 sd_bus_message *reply,
1566 void *userdata,
1567 sd_bus_error *error) {
1568 return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
1569}
1570
1571static int bus_property_get_current_dns_server_ex(
1572 sd_bus *bus,
1573 const char *path,
1574 const char *interface,
1575 const char *property,
1576 sd_bus_message *reply,
1577 void *userdata,
1578 sd_bus_error *error) {
1579 return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
b7ac92cd
YW
1580}
1581
ee116b54 1582static int bus_property_get_domains(
7f220d94
LP
1583 sd_bus *bus,
1584 const char *path,
1585 const char *interface,
1586 const char *property,
1587 sd_bus_message *reply,
1588 void *userdata,
1589 sd_bus_error *error) {
1590
99534007 1591 Manager *m = ASSERT_PTR(userdata);
7f220d94
LP
1592 Link *l;
1593 int r;
1594
1595 assert(reply);
7f220d94 1596
ad44b56b 1597 r = sd_bus_message_open_container(reply, 'a', "(isb)");
7f220d94
LP
1598 if (r < 0)
1599 return r;
1600
1601 LIST_FOREACH(domains, d, m->search_domains) {
ad44b56b 1602 r = sd_bus_message_append(reply, "(isb)", 0, d->name, d->route_only);
7f220d94
LP
1603 if (r < 0)
1604 return r;
1605 }
1606
90e74a66 1607 HASHMAP_FOREACH(l, m->links) {
7f220d94 1608 LIST_FOREACH(domains, d, l->search_domains) {
ad44b56b 1609 r = sd_bus_message_append(reply, "(isb)", l->ifindex, d->name, d->route_only);
7f220d94
LP
1610 if (r < 0)
1611 return r;
1612 }
1613 }
1614
1615 return sd_bus_message_close_container(reply);
1616}
1617
a150ff5e
LP
1618static int bus_property_get_transaction_statistics(
1619 sd_bus *bus,
1620 const char *path,
1621 const char *interface,
1622 const char *property,
1623 sd_bus_message *reply,
1624 void *userdata,
1625 sd_bus_error *error) {
1626
99534007 1627 Manager *m = ASSERT_PTR(userdata);
a150ff5e
LP
1628
1629 assert(reply);
a150ff5e
LP
1630
1631 return sd_bus_message_append(reply, "(tt)",
1632 (uint64_t) hashmap_size(m->dns_transactions),
1633 (uint64_t) m->n_transactions_total);
1634}
1635
1636static int bus_property_get_cache_statistics(
1637 sd_bus *bus,
1638 const char *path,
1639 const char *interface,
1640 const char *property,
1641 sd_bus_message *reply,
1642 void *userdata,
1643 sd_bus_error *error) {
1644
1645 uint64_t size = 0, hit = 0, miss = 0;
99534007 1646 Manager *m = ASSERT_PTR(userdata);
a150ff5e
LP
1647
1648 assert(reply);
a150ff5e
LP
1649
1650 LIST_FOREACH(scopes, s, m->dns_scopes) {
1651 size += dns_cache_size(&s->cache);
1652 hit += s->cache.n_hit;
1653 miss += s->cache.n_miss;
1654 }
1655
1656 return sd_bus_message_append(reply, "(ttt)", size, hit, miss);
1657}
1658
1659static int bus_property_get_dnssec_statistics(
1660 sd_bus *bus,
1661 const char *path,
1662 const char *interface,
1663 const char *property,
1664 sd_bus_message *reply,
1665 void *userdata,
1666 sd_bus_error *error) {
1667
99534007 1668 Manager *m = ASSERT_PTR(userdata);
a150ff5e
LP
1669
1670 assert(reply);
a150ff5e
LP
1671
1672 return sd_bus_message_append(reply, "(tttt)",
59c5b597
LP
1673 (uint64_t) m->n_dnssec_verdict[DNSSEC_SECURE],
1674 (uint64_t) m->n_dnssec_verdict[DNSSEC_INSECURE],
1675 (uint64_t) m->n_dnssec_verdict[DNSSEC_BOGUS],
1676 (uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]);
a150ff5e
LP
1677}
1678
476798b1
LP
1679static int bus_property_get_ntas(
1680 sd_bus *bus,
1681 const char *path,
1682 const char *interface,
1683 const char *property,
1684 sd_bus_message *reply,
1685 void *userdata,
1686 sd_bus_error *error) {
1687
99534007 1688 Manager *m = ASSERT_PTR(userdata);
476798b1 1689 const char *domain;
476798b1
LP
1690 int r;
1691
1692 assert(reply);
476798b1
LP
1693
1694 r = sd_bus_message_open_container(reply, 'a', "s");
1695 if (r < 0)
1696 return r;
1697
90e74a66 1698 SET_FOREACH(domain, m->trust_anchor.negative_by_name) {
476798b1
LP
1699 r = sd_bus_message_append(reply, "s", domain);
1700 if (r < 0)
1701 return r;
1702 }
1703
1704 return sd_bus_message_close_container(reply);
1705}
1706
7ed1565a 1707static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode);
acd380c4
YW
1708static BUS_DEFINE_PROPERTY_GET(bus_property_get_dnssec_supported, "b", Manager, manager_dnssec_supported);
1709static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string);
c9299be2 1710static 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);
7ed1565a 1711
4261ab65
LP
1712static int bus_property_get_resolv_conf_mode(
1713 sd_bus *bus,
1714 const char *path,
1715 const char *interface,
1716 const char *property,
1717 sd_bus_message *reply,
1718 void *userdata,
1719 sd_bus_error *error) {
1720
1721 int r;
1722
1723 assert(reply);
1724
1725 r = resolv_conf_mode();
1726 if (r < 0) {
1727 log_warning_errno(r, "Failed to test /etc/resolv.conf mode, ignoring: %m");
1728 return sd_bus_message_append(reply, "s", NULL);
1729 }
1730
1731 return sd_bus_message_append(reply, "s", resolv_conf_mode_to_string(r));
1732}
1733
a150ff5e 1734static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 1735 Manager *m = ASSERT_PTR(userdata);
a150ff5e
LP
1736
1737 assert(message);
a150ff5e 1738
1e69eadd
LP
1739 bus_client_log(message, "statistics reset");
1740
a150ff5e
LP
1741 LIST_FOREACH(scopes, s, m->dns_scopes)
1742 s->cache.n_hit = s->cache.n_miss = 0;
1743
1744 m->n_transactions_total = 0;
59c5b597 1745 zero(m->n_dnssec_verdict);
a150ff5e
LP
1746
1747 return sd_bus_reply_method_return(message, NULL);
1748}
1749
3abaabda 1750static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
97e5d693
LP
1751 Link *l;
1752
1753 assert(m);
3abaabda 1754 assert(ret);
97e5d693 1755
97e5d693
LP
1756 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
1757 if (!l)
1758 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
3abaabda
LP
1759
1760 *ret = l;
1761 return 0;
1762}
1763
d2ec6608 1764static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
97e5d693 1765 int ifindex, r;
97e5d693
LP
1766 Link *l;
1767
97e5d693 1768 assert(m);
97e5d693 1769 assert(message);
d2ec6608 1770 assert(handler);
97e5d693 1771
7695e2cb 1772 r = bus_message_read_ifindex(message, error, &ifindex);
97e5d693
LP
1773 if (r < 0)
1774 return r;
1775
04b764bf 1776 r = get_any_link(m, ifindex, &l, error);
97e5d693
LP
1777 if (r < 0)
1778 return r;
1779
d2ec6608
LP
1780 return handler(message, l, error);
1781}
97e5d693 1782
d2ec6608
LP
1783static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1784 return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
1785}
97e5d693 1786
95ce1ba8
YW
1787static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1788 return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error);
1789}
1790
ee116b54
LP
1791static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1792 return call_link_method(userdata, message, bus_link_method_set_domains, error);
97e5d693
LP
1793}
1794
77673795
LP
1795static int bus_method_set_link_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1796 return call_link_method(userdata, message, bus_link_method_set_default_route, error);
1797}
1798
97e5d693 1799static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1800 return call_link_method(userdata, message, bus_link_method_set_llmnr, error);
97e5d693
LP
1801}
1802
1803static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1804 return call_link_method(userdata, message, bus_link_method_set_mdns, error);
97e5d693
LP
1805}
1806
c9299be2
IT
1807static int bus_method_set_link_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1808 return call_link_method(userdata, message, bus_link_method_set_dns_over_tls, error);
b761a107
YW
1809}
1810
97e5d693 1811static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1812 return call_link_method(userdata, message, bus_link_method_set_dnssec, error);
97e5d693
LP
1813}
1814
1815static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1816 return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error);
97e5d693
LP
1817}
1818
1819static int bus_method_revert_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d2ec6608 1820 return call_link_method(userdata, message, bus_link_method_revert, error);
97e5d693
LP
1821}
1822
3abaabda
LP
1823static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1824 _cleanup_free_ char *p = NULL;
99534007 1825 Manager *m = ASSERT_PTR(userdata);
3abaabda
LP
1826 int r, ifindex;
1827 Link *l;
1828
1829 assert(message);
3abaabda 1830
7695e2cb 1831 r = bus_message_read_ifindex(message, error, &ifindex);
3abaabda
LP
1832 if (r < 0)
1833 return r;
1834
1835 r = get_any_link(m, ifindex, &l, error);
1836 if (r < 0)
1837 return r;
1838
1839 p = link_bus_path(l);
1840 if (!p)
1841 return -ENOMEM;
1842
1843 return sd_bus_reply_method_return(message, "o", p);
1844}
1845
ba35662f 1846static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 1847 Manager *m = ASSERT_PTR(userdata);
ba35662f
LP
1848
1849 assert(message);
ba35662f 1850
1e69eadd
LP
1851 bus_client_log(message, "cache flush");
1852
90df0fbe 1853 manager_flush_caches(m, LOG_INFO);
ba35662f
LP
1854
1855 return sd_bus_reply_method_return(message, NULL);
1856}
1857
d55b0463 1858static int bus_method_reset_server_features(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 1859 Manager *m = ASSERT_PTR(userdata);
d55b0463
LP
1860
1861 assert(message);
d55b0463 1862
1e69eadd
LP
1863 bus_client_log(message, "server feature reset");
1864
d55b0463
LP
1865 manager_reset_server_features(m);
1866
1867 return sd_bus_reply_method_return(message, NULL);
1868}
1869
65a01e82 1870static int dnssd_service_on_bus_track(sd_bus_track *t, void *userdata) {
99534007 1871 DnssdService *s = ASSERT_PTR(userdata);
c3036641
DR
1872
1873 assert(t);
c3036641
DR
1874
1875 log_debug("Client of active request vanished, destroying DNS-SD service.");
1876 dnssd_service_free(s);
1877
1878 return 0;
1879}
1880
1881static int bus_method_register_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
84b0f133 1882 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
c3036641
DR
1883 _cleanup_(dnssd_service_freep) DnssdService *service = NULL;
1884 _cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL;
4f6ebd43 1885 const char *name, *name_template, *type;
c3036641 1886 _cleanup_free_ char *path = NULL;
c3036641 1887 DnssdService *s = NULL;
99534007 1888 Manager *m = ASSERT_PTR(userdata);
84b0f133 1889 uid_t euid;
c3036641
DR
1890 int r;
1891
1892 assert(message);
c3036641
DR
1893
1894 if (m->mdns_support != RESOLVE_SUPPORT_YES)
1b09b81c 1895 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
c3036641
DR
1896
1897 service = new0(DnssdService, 1);
1898 if (!service)
1899 return log_oom();
1900
84b0f133
DR
1901 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
1902 if (r < 0)
1903 return r;
1904
1905 r = sd_bus_creds_get_euid(creds, &euid);
1906 if (r < 0)
1907 return r;
1908 service->originator = euid;
1909
c3036641
DR
1910 r = sd_bus_message_read(message, "sssqqq", &name, &name_template, &type,
1911 &service->port, &service->priority,
1912 &service->weight);
1913 if (r < 0)
1914 return r;
1915
1916 s = hashmap_get(m->dnssd_services, name);
1917 if (s)
1918 return sd_bus_error_setf(error, BUS_ERROR_DNSSD_SERVICE_EXISTS, "DNS-SD service '%s' exists already", name);
1919
1920 if (!dnssd_srv_type_is_valid(type))
1921 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DNS-SD service type '%s' is invalid", type);
1922
1923 service->name = strdup(name);
1924 if (!service->name)
1925 return log_oom();
1926
1927 service->name_template = strdup(name_template);
1928 if (!service->name_template)
1929 return log_oom();
1930
1931 service->type = strdup(type);
1932 if (!service->type)
1933 return log_oom();
1934
a3f87e32 1935 r = dnssd_render_instance_name(m, service, NULL);
07e4a8dc
RB
1936 if (r < 0)
1937 return r;
1938
400f54fb 1939 r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "a{say}");
c3036641 1940 if (r < 0)
400f54fb 1941 return r;
c3036641 1942
400f54fb
DR
1943 while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{say}")) > 0) {
1944 _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
1945 DnsTxtItem *last = NULL;
c3036641 1946
400f54fb
DR
1947 txt_data = new0(DnssdTxtData, 1);
1948 if (!txt_data)
1949 return log_oom();
1950
1951 while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "say")) > 0) {
1952 const char *key;
1953 const void *value;
1954 size_t size;
1955 DnsTxtItem *i;
1956
1957 r = sd_bus_message_read(message, "s", &key);
1958 if (r < 0)
1959 return r;
1960
1961 if (isempty(key))
1b09b81c 1962 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Keys in DNS-SD TXT RRs can't be empty");
c3036641 1963
400f54fb
DR
1964 if (!ascii_is_valid(key))
1965 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TXT key '%s' contains non-ASCII symbols", key);
c3036641 1966
400f54fb
DR
1967 r = sd_bus_message_read_array(message, 'y', &value, &size);
1968 if (r < 0)
1969 return r;
c3036641 1970
400f54fb
DR
1971 r = dnssd_txt_item_new_from_data(key, value, size, &i);
1972 if (r < 0)
1973 return r;
1974
d70f15f5 1975 LIST_INSERT_AFTER(items, txt_data->txts, last, i);
400f54fb
DR
1976 last = i;
1977
1978 r = sd_bus_message_exit_container(message);
1979 if (r < 0)
1980 return r;
1981
1982 }
c3036641 1983 if (r < 0)
400f54fb 1984 return r;
c3036641 1985
400f54fb 1986 r = sd_bus_message_exit_container(message);
c3036641 1987 if (r < 0)
400f54fb 1988 return r;
c3036641 1989
d70f15f5 1990 if (txt_data->txts) {
400f54fb
DR
1991 LIST_PREPEND(items, service->txt_data_items, txt_data);
1992 txt_data = NULL;
1993 }
c3036641 1994 }
400f54fb
DR
1995 if (r < 0)
1996 return r;
c3036641
DR
1997
1998 r = sd_bus_message_exit_container(message);
1999 if (r < 0)
400f54fb
DR
2000 return r;
2001
2002 if (!service->txt_data_items) {
2003 _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
c3036641 2004
400f54fb
DR
2005 txt_data = new0(DnssdTxtData, 1);
2006 if (!txt_data)
2007 return log_oom();
2008
d70f15f5 2009 r = dns_txt_item_new_empty(&txt_data->txts);
c3036641 2010 if (r < 0)
400f54fb
DR
2011 return r;
2012
2013 LIST_PREPEND(items, service->txt_data_items, txt_data);
2014 txt_data = NULL;
c3036641
DR
2015 }
2016
2017 r = sd_bus_path_encode("/org/freedesktop/resolve1/dnssd", service->name, &path);
2018 if (r < 0)
2019 return r;
2020
fd73184f
ZJS
2021 r = bus_verify_polkit_async(message, CAP_SYS_ADMIN,
2022 "org.freedesktop.resolve1.register-service",
2023 NULL, false, UID_INVALID,
2024 &m->polkit_registry, error);
2025 if (r < 0)
2026 return r;
2027 if (r == 0)
2028 return 1; /* Polkit will call us back */
2029
71fb97c7 2030 r = hashmap_ensure_put(&m->dnssd_services, &string_hash_ops, service->name, service);
c3036641
DR
2031 if (r < 0)
2032 return r;
2033
65a01e82 2034 r = sd_bus_track_new(sd_bus_message_get_bus(message), &bus_track, dnssd_service_on_bus_track, service);
c3036641
DR
2035 if (r < 0)
2036 return r;
2037
2038 r = sd_bus_track_add_sender(bus_track, message);
2039 if (r < 0)
2040 return r;
2041
2042 service->manager = m;
2043
2044 service = NULL;
2045
2046 manager_refresh_rrs(m);
2047
2048 return sd_bus_reply_method_return(message, "o", path);
2049}
2050
2051static int call_dnssd_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
2052 _cleanup_free_ char *name = NULL;
2053 DnssdService *s = NULL;
2054 const char *path;
2055 int r;
2056
2057 assert(m);
2058 assert(message);
2059 assert(handler);
2060
2061 r = sd_bus_message_read(message, "o", &path);
2062 if (r < 0)
2063 return r;
2064
2065 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/dnssd", &name);
2066 if (r == 0)
2067 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DNSSD_SERVICE, "DNS-SD service with object path '%s' does not exist", path);
2068 if (r < 0)
2069 return r;
2070
2071 s = hashmap_get(m->dnssd_services, name);
2072 if (!s)
2073 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DNSSD_SERVICE, "DNS-SD service '%s' not known", name);
2074
2075 return handler(message, s, error);
2076}
2077
2078static int bus_method_unregister_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 2079 Manager *m = ASSERT_PTR(userdata);
c3036641
DR
2080
2081 assert(message);
c3036641
DR
2082
2083 return call_dnssd_method(m, message, bus_dnssd_method_unregister, error);
2084}
2085
74b2466e
LP
2086static const sd_bus_vtable resolve_vtable[] = {
2087 SD_BUS_VTABLE_START(0),
86c0411e 2088 SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
bf4e5c4c
YW
2089 SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Manager, llmnr_support), 0),
2090 SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Manager, mdns_support), 0),
c9299be2 2091 SD_BUS_PROPERTY("DNSOverTLS", "s", bus_property_get_dns_over_tls_mode, 0, 0),
5f3340ca 2092 SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
8e56ea4c 2093 SD_BUS_PROPERTY("DNSEx", "a(iiayqs)", bus_property_get_dns_servers_ex, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
ad32ac53 2094 SD_BUS_PROPERTY("FallbackDNS", "a(iiay)", bus_property_get_fallback_dns_servers, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
8e56ea4c 2095 SD_BUS_PROPERTY("FallbackDNSEx", "a(iiayqs)", bus_property_get_fallback_dns_servers_ex, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
4a6f996c 2096 SD_BUS_PROPERTY("CurrentDNSServer", "(iiay)", bus_property_get_current_dns_server, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
8e56ea4c 2097 SD_BUS_PROPERTY("CurrentDNSServerEx", "(iiayqs)", bus_property_get_current_dns_server_ex, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
ee116b54 2098 SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0),
a150ff5e
LP
2099 SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
2100 SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
bf4e5c4c 2101 SD_BUS_PROPERTY("DNSSEC", "s", bus_property_get_dnssec_mode, 0, 0),
a150ff5e 2102 SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
593f665c 2103 SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
476798b1 2104 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
7ed1565a 2105 SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
4261ab65 2106 SD_BUS_PROPERTY("ResolvConfMode", "s", bus_property_get_resolv_conf_mode, 0, 0),
7f220d94 2107
eff7c2d3
DDM
2108 SD_BUS_METHOD_WITH_ARGS("ResolveHostname",
2109 SD_BUS_ARGS("i", ifindex, "s", name, "i", family, "t", flags),
2110 SD_BUS_RESULT("a(iiay)", addresses, "s", canonical, "t", flags),
2111 bus_method_resolve_hostname,
2112 SD_BUS_VTABLE_UNPRIVILEGED),
2113 SD_BUS_METHOD_WITH_ARGS("ResolveAddress",
2114 SD_BUS_ARGS("i", ifindex, "i", family, "ay", address, "t", flags),
2115 SD_BUS_RESULT("a(is)", names, "t", flags),
2116 bus_method_resolve_address,
2117 SD_BUS_VTABLE_UNPRIVILEGED),
2118 SD_BUS_METHOD_WITH_ARGS("ResolveRecord",
2119 SD_BUS_ARGS("i", ifindex, "s", name, "q", class, "q", type, "t", flags),
2120 SD_BUS_RESULT("a(iqqay)", records, "t", flags),
2121 bus_method_resolve_record,
2122 SD_BUS_VTABLE_UNPRIVILEGED),
2123 SD_BUS_METHOD_WITH_ARGS("ResolveService",
2124 SD_BUS_ARGS("i", ifindex,
2125 "s", name,
2126 "s", type,
2127 "s", domain,
2128 "i", family,
2129 "t", flags),
2130 SD_BUS_RESULT("a(qqqsa(iiay)s)", srv_data,
2131 "aay", txt_data,
2132 "s", canonical_name,
2133 "s", canonical_type,
2134 "s", canonical_domain,
2135 "t", flags),
2136 bus_method_resolve_service,
2137 SD_BUS_VTABLE_UNPRIVILEGED),
2138 SD_BUS_METHOD_WITH_ARGS("GetLink",
2139 SD_BUS_ARGS("i", ifindex),
2140 SD_BUS_RESULT("o", path),
2141 bus_method_get_link,
2142 SD_BUS_VTABLE_UNPRIVILEGED),
2143 SD_BUS_METHOD_WITH_ARGS("SetLinkDNS",
2144 SD_BUS_ARGS("i", ifindex, "a(iay)", addresses),
2145 SD_BUS_NO_RESULT,
2146 bus_method_set_link_dns_servers,
2147 SD_BUS_VTABLE_UNPRIVILEGED),
95ce1ba8
YW
2148 SD_BUS_METHOD_WITH_ARGS("SetLinkDNSEx",
2149 SD_BUS_ARGS("i", ifindex, "a(iayqs)", addresses),
2150 SD_BUS_NO_RESULT,
2151 bus_method_set_link_dns_servers_ex,
2152 SD_BUS_VTABLE_UNPRIVILEGED),
eff7c2d3
DDM
2153 SD_BUS_METHOD_WITH_ARGS("SetLinkDomains",
2154 SD_BUS_ARGS("i", ifindex, "a(sb)", domains),
2155 SD_BUS_NO_RESULT,
2156 bus_method_set_link_domains,
2157 SD_BUS_VTABLE_UNPRIVILEGED),
2158 SD_BUS_METHOD_WITH_ARGS("SetLinkDefaultRoute",
2159 SD_BUS_ARGS("i", ifindex, "b", enable),
2160 SD_BUS_NO_RESULT,
2161 bus_method_set_link_default_route,
2162 SD_BUS_VTABLE_UNPRIVILEGED),
2163 SD_BUS_METHOD_WITH_ARGS("SetLinkLLMNR",
2164 SD_BUS_ARGS("i", ifindex, "s", mode),
2165 SD_BUS_NO_RESULT,
2166 bus_method_set_link_llmnr,
2167 SD_BUS_VTABLE_UNPRIVILEGED),
2168 SD_BUS_METHOD_WITH_ARGS("SetLinkMulticastDNS",
2169 SD_BUS_ARGS("i", ifindex, "s", mode),
2170 SD_BUS_NO_RESULT,
2171 bus_method_set_link_mdns,
2172 SD_BUS_VTABLE_UNPRIVILEGED),
2173 SD_BUS_METHOD_WITH_ARGS("SetLinkDNSOverTLS",
2174 SD_BUS_ARGS("i", ifindex, "s", mode),
2175 SD_BUS_NO_RESULT,
2176 bus_method_set_link_dns_over_tls,
2177 SD_BUS_VTABLE_UNPRIVILEGED),
2178 SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSEC",
2179 SD_BUS_ARGS("i", ifindex, "s", mode),
2180 SD_BUS_NO_RESULT,
2181 bus_method_set_link_dnssec,
2182 SD_BUS_VTABLE_UNPRIVILEGED),
2183 SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSECNegativeTrustAnchors",
2184 SD_BUS_ARGS("i", ifindex, "as", names),
2185 SD_BUS_NO_RESULT,
2186 bus_method_set_link_dnssec_negative_trust_anchors,
2187 SD_BUS_VTABLE_UNPRIVILEGED),
2188 SD_BUS_METHOD_WITH_ARGS("RevertLink",
2189 SD_BUS_ARGS("i", ifindex),
2190 SD_BUS_NO_RESULT,
2191 bus_method_revert_link,
2192 SD_BUS_VTABLE_UNPRIVILEGED),
2193 SD_BUS_METHOD_WITH_ARGS("RegisterService",
2194 SD_BUS_ARGS("s", name,
2195 "s", name_template,
2196 "s", type,
2197 "q", service_port,
2198 "q", service_priority,
2199 "q", service_weight,
0894f08b 2200 "aa{say}", txt_datas),
eff7c2d3
DDM
2201 SD_BUS_RESULT("o", service_path),
2202 bus_method_register_service,
2203 SD_BUS_VTABLE_UNPRIVILEGED),
2204 SD_BUS_METHOD_WITH_ARGS("UnregisterService",
2205 SD_BUS_ARGS("o", service_path),
2206 SD_BUS_NO_RESULT,
2207 bus_method_unregister_service,
2208 SD_BUS_VTABLE_UNPRIVILEGED),
2209 SD_BUS_METHOD_WITH_ARGS("ResetStatistics",
2210 SD_BUS_NO_ARGS,
2211 SD_BUS_NO_RESULT,
2212 bus_method_reset_statistics,
2213 SD_BUS_VTABLE_UNPRIVILEGED),
2214 SD_BUS_METHOD_WITH_ARGS("FlushCaches",
2215 SD_BUS_NO_ARGS,
2216 SD_BUS_NO_RESULT,
2217 bus_method_flush_caches,
2218 SD_BUS_VTABLE_UNPRIVILEGED),
2219 SD_BUS_METHOD_WITH_ARGS("ResetServerFeatures",
2220 SD_BUS_NO_ARGS,
2221 SD_BUS_NO_RESULT,
2222 bus_method_reset_server_features,
2223 SD_BUS_VTABLE_UNPRIVILEGED),
ca9fab88 2224
74b2466e
LP
2225 SD_BUS_VTABLE_END,
2226};
2227
8d128089
ZJS
2228const BusObjectImplementation manager_object = {
2229 "/org/freedesktop/resolve1",
2230 "org.freedesktop.resolve1.Manager",
2231 .vtables = BUS_VTABLES(resolve_vtable),
2232 .children = BUS_IMPLEMENTATIONS(&link_object,
2233 &dnssd_object),
2234};
2235
19070062 2236static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
99534007 2237 Manager *m = ASSERT_PTR(userdata);
902bb5d8
LP
2238 int b, r;
2239
19070062 2240 assert(message);
902bb5d8
LP
2241
2242 r = sd_bus_message_read(message, "b", &b);
2243 if (r < 0) {
d67b1d18 2244 bus_log_parse_error(r);
902bb5d8
LP
2245 return 0;
2246 }
2247
2248 if (b)
2249 return 0;
2250
2251 log_debug("Coming back from suspend, verifying all RRs...");
2252
2253 manager_verify_all(m);
2254 return 0;
2255}
2256
74b2466e
LP
2257int manager_connect_bus(Manager *m) {
2258 int r;
2259
2260 assert(m);
2261
2262 if (m->bus)
2263 return 0;
2264
8c6afb77 2265 r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-resolve");
d7afd945
LP
2266 if (r < 0)
2267 return log_error_errno(r, "Failed to connect to system bus: %m");
74b2466e 2268
8d128089 2269 r = bus_add_implementation(m->bus, &manager_object, m);
3abaabda 2270 if (r < 0)
8d128089 2271 return r;
c3036641 2272
4c452078
LP
2273 r = bus_log_control_api_register(m->bus);
2274 if (r < 0)
2275 return r;
2276
62fb7e80 2277 r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.resolve1", 0, NULL, NULL);
f647962d 2278 if (r < 0)
0c0b9306 2279 return log_error_errno(r, "Failed to request name: %m");
74b2466e
LP
2280
2281 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
2282 if (r < 0)
2283 return log_error_errno(r, "Failed to attach bus to event loop: %m");
74b2466e 2284
75152a4d
LP
2285 r = sd_bus_match_signal_async(
2286 m->bus,
4b0051b1 2287 NULL,
75152a4d
LP
2288 "org.freedesktop.login1",
2289 "/org/freedesktop/login1",
2290 "org.freedesktop.login1.Manager",
2291 "PrepareForSleep",
2292 match_prepare_for_sleep,
2293 NULL,
2294 m);
2295 if (r < 0)
d7afd945 2296 log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
902bb5d8 2297
74b2466e
LP
2298 return 0;
2299}
5f3340ca
ZJS
2300
2301int _manager_send_changed(Manager *manager, const char *property, ...) {
2302 assert(manager);
2303
b8d6689a
YW
2304 if (sd_bus_is_ready(manager->bus) <= 0)
2305 return 0;
2306
5f3340ca
ZJS
2307 char **l = strv_from_stdarg_alloca(property);
2308
2309 int r = sd_bus_emit_properties_changed_strv(
2310 manager->bus,
2311 "/org/freedesktop/resolve1",
2312 "org.freedesktop.resolve1.Manager",
2313 l);
2314 if (r < 0)
2315 log_notice_errno(r, "Failed to emit notification about changed property %s: %m", property);
2316 return r;
2317}