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