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