]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-bus.c
treewide: no need to negate errno for log_*_errno()
[thirdparty/systemd.git] / src / resolve / resolved-bus.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include "bus-errors.h"
23#include "bus-util.h"
24
74b2466e 25#include "resolved-dns-domain.h"
39d8db04 26#include "resolved-bus.h"
51323288 27#include "resolved-def.h"
74b2466e 28
ad867662
LP
29static int reply_query_state(DnsQuery *q) {
30 _cleanup_free_ char *ip = NULL;
31 const char *name;
74b2466e
LP
32 int r;
33
ad867662
LP
34 if (q->request_hostname)
35 name = q->request_hostname;
36 else {
37 r = in_addr_to_string(q->request_family, &q->request_address, &ip);
38 if (r < 0)
39 return r;
74b2466e 40
ad867662
LP
41 name = ip;
42 }
43
44 switch (q->state) {
74b2466e 45
ec2c5e43 46 case DNS_TRANSACTION_NO_SERVERS:
309e9d86 47 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
74b2466e 48
ec2c5e43 49 case DNS_TRANSACTION_TIMEOUT:
ad867662 50 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
74b2466e 51
ec2c5e43 52 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
ad867662
LP
53 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
54
818f766b
LP
55 case DNS_TRANSACTION_INVALID_REPLY:
56 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
57
ec2c5e43 58 case DNS_TRANSACTION_RESOURCES:
ad867662
LP
59 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
60
818f766b
LP
61 case DNS_TRANSACTION_ABORTED:
62 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
74b2466e 63
ec2c5e43 64 case DNS_TRANSACTION_FAILURE: {
74b2466e
LP
65 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
66
faa133f3 67 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
ad867662 68 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
74b2466e
LP
69 else {
70 const char *rc, *n;
ad867662 71 char p[3]; /* the rcode is 4 bits long */
74b2466e 72
faa133f3 73 rc = dns_rcode_to_string(q->answer_rcode);
74b2466e 74 if (!rc) {
faa133f3 75 sprintf(p, "%i", q->answer_rcode);
74b2466e
LP
76 rc = p;
77 }
78
79 n = strappenda(_BUS_ERROR_DNS, rc);
ad867662 80 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
74b2466e
LP
81 }
82
ad867662 83 return sd_bus_reply_method_error(q->request, &error);
74b2466e
LP
84 }
85
ec2c5e43
LP
86 case DNS_TRANSACTION_NULL:
87 case DNS_TRANSACTION_PENDING:
88 case DNS_TRANSACTION_SUCCESS:
8ba9fd9c 89 default:
ad867662
LP
90 assert_not_reached("Impossible state");
91 }
92}
74b2466e 93
51323288 94static int append_address(sd_bus_message *reply, DnsResourceRecord *rr) {
8ba9fd9c
LP
95 int r;
96
97 assert(reply);
98 assert(rr);
99
51323288 100 r = sd_bus_message_open_container(reply, 'r', "iay");
8ba9fd9c
LP
101 if (r < 0)
102 return r;
103
faa133f3 104 if (rr->key->type == DNS_TYPE_A) {
0dd25fb9 105 r = sd_bus_message_append(reply, "i", AF_INET);
8ba9fd9c
LP
106 if (r < 0)
107 return r;
108
109 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
faa133f3
LP
110
111 } else if (rr->key->type == DNS_TYPE_AAAA) {
0dd25fb9 112 r = sd_bus_message_append(reply, "i", AF_INET6);
8ba9fd9c
LP
113 if (r < 0)
114 return r;
115
116 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
faa133f3
LP
117 } else
118 return -EAFNOSUPPORT;
119
8ba9fd9c
LP
120 if (r < 0)
121 return r;
122
8ba9fd9c
LP
123 r = sd_bus_message_close_container(reply);
124 if (r < 0)
125 return r;
126
127 return 0;
128}
129
ad867662 130static void bus_method_resolve_hostname_complete(DnsQuery *q) {
309e9d86 131 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
ad867662 132 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
faa133f3
LP
133 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
134 unsigned added = 0, i;
51323288 135 int r;
74b2466e 136
ad867662 137 assert(q);
74b2466e 138
ec2c5e43 139 if (q->state != DNS_TRANSACTION_SUCCESS) {
ad867662
LP
140 r = reply_query_state(q);
141 goto finish;
142 }
74b2466e 143
ad867662
LP
144 r = sd_bus_message_new_method_return(q->request, &reply);
145 if (r < 0)
146 goto finish;
74b2466e 147
51323288 148 r = sd_bus_message_append(reply, "i", q->answer_ifindex);
ad867662
LP
149 if (r < 0)
150 goto finish;
74b2466e 151
51323288
LP
152 r = sd_bus_message_open_container(reply, 'a', "(iay)");
153 if (r < 0)
154 goto finish;
8ba9fd9c 155
3339cb71
LP
156 if (q->answer) {
157 answer = dns_answer_ref(q->answer);
158
159 for (i = 0; i < answer->n_rrs; i++) {
160 r = dns_question_matches_rr(q->question, answer->rrs[i]);
8ba9fd9c 161 if (r < 0)
2d4c5cbc 162 goto finish;
3339cb71
LP
163 if (r == 0) {
164 /* Hmm, if this is not an address record,
165 maybe it's a cname? If so, remember this */
166 r = dns_question_matches_cname(q->question, answer->rrs[i]);
167 if (r < 0)
2d4c5cbc 168 goto finish;
3339cb71
LP
169 if (r > 0)
170 cname = dns_resource_record_ref(answer->rrs[i]);
74b2466e 171
3339cb71
LP
172 continue;
173 }
74b2466e 174
51323288 175 r = append_address(reply, answer->rrs[i]);
3339cb71
LP
176 if (r < 0)
177 goto finish;
74b2466e 178
3339cb71
LP
179 if (!canonical)
180 canonical = dns_resource_record_ref(answer->rrs[i]);
309e9d86 181
3339cb71
LP
182 added ++;
183 }
8ba9fd9c 184 }
74b2466e 185
8ba9fd9c
LP
186 if (added <= 0) {
187 if (!cname) {
309e9d86 188 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of requested type", q->request_hostname);
ad867662 189 goto finish;
8ba9fd9c 190 }
74b2466e 191
8ba9fd9c
LP
192 /* This has a cname? Then update the query with the
193 * new cname. */
322345fd 194 r = dns_query_cname_redirect(q, cname->cname.name);
8ba9fd9c
LP
195 if (r < 0) {
196 if (r == -ELOOP)
197 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
198 else
199 r = sd_bus_reply_method_errno(q->request, -r, NULL);
74b2466e 200
74b2466e 201 goto finish;
8ba9fd9c 202 }
74b2466e 203
8ba9fd9c
LP
204 /* Before we restart the query, let's see if any of
205 * the RRs we already got already answers our query */
faa133f3
LP
206 for (i = 0; i < answer->n_rrs; i++) {
207 r = dns_question_matches_rr(q->question, answer->rrs[i]);
8ba9fd9c 208 if (r < 0)
2d4c5cbc 209 goto finish;
8ba9fd9c
LP
210 if (r == 0)
211 continue;
212
51323288 213 r = append_address(reply, answer->rrs[i]);
8ba9fd9c
LP
214 if (r < 0)
215 goto finish;
216
309e9d86 217 if (!canonical)
faa133f3 218 canonical = dns_resource_record_ref(answer->rrs[i]);
309e9d86 219
8ba9fd9c
LP
220 added++;
221 }
222
223 /* If we didn't find anything, then let's restart the
224 * query, this time with the cname */
225 if (added <= 0) {
322345fd 226 r = dns_query_go(q);
309e9d86
LP
227 if (r == -ESRCH) {
228 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
229 goto finish;
230 }
8ba9fd9c
LP
231 if (r < 0) {
232 r = sd_bus_reply_method_errno(q->request, -r, NULL);
233 goto finish;
234 }
2d4c5cbc 235
8ba9fd9c
LP
236 return;
237 }
74b2466e
LP
238 }
239
ad867662
LP
240 r = sd_bus_message_close_container(reply);
241 if (r < 0)
242 goto finish;
243
309e9d86
LP
244 /* Return the precise spelling and uppercasing reported by the server */
245 assert(canonical);
51323288 246 r = sd_bus_message_append(reply, "st", DNS_RESOURCE_KEY_NAME(canonical->key), SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
309e9d86
LP
247 if (r < 0)
248 goto finish;
249
ad867662 250 r = sd_bus_send(q->manager->bus, reply, NULL);
ad867662 251
74b2466e 252finish:
2d4c5cbc 253 if (r < 0) {
da927ba9 254 log_error_errno(r, "Failed to send hostname reply: %m");
2d4c5cbc
LP
255 sd_bus_reply_method_errno(q->request, -r, NULL);
256 }
74b2466e
LP
257
258 dns_query_free(q);
259}
260
51323288
LP
261static int check_ifindex_flags(int ifindex, uint64_t *flags, sd_bus_error *error) {
262 assert(flags);
263
264 if (ifindex < 0)
265 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
266
267 if (*flags & ~SD_RESOLVED_FLAGS_ALL)
268 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
269
270 if (*flags == 0)
271 *flags = SD_RESOLVED_FLAGS_DEFAULT;
272
273 return 0;
274}
275
74b2466e 276static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3 277 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
74b2466e
LP
278 Manager *m = userdata;
279 const char *hostname;
51323288
LP
280 int family, ifindex;
281 uint64_t flags;
74b2466e 282 DnsQuery *q;
74b2466e
LP
283 int r;
284
285 assert(bus);
286 assert(message);
287 assert(m);
288
51323288 289 r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
74b2466e
LP
290 if (r < 0)
291 return r;
292
293 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
0dd25fb9 294 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e 295
7b9f7afc
LP
296 r = dns_name_normalize(hostname, NULL);
297 if (r < 0)
74b2466e
LP
298 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
299
51323288
LP
300 r = check_ifindex_flags(ifindex, &flags, error);
301 if (r < 0)
302 return r;
303
faa133f3
LP
304 question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
305 if (!question)
306 return -ENOMEM;
307
74b2466e 308 if (family != AF_INET6) {
faa133f3
LP
309 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
310
311 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
312 if (!key)
313 return -ENOMEM;
314
315 r = dns_question_add(question, key);
316 if (r < 0)
317 return r;
74b2466e
LP
318 }
319
320 if (family != AF_INET) {
faa133f3
LP
321 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
322
323 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
324 if (!key)
325 return -ENOMEM;
326
327 r = dns_question_add(question, key);
328 if (r < 0)
329 return r;
74b2466e
LP
330 }
331
51323288 332 r = dns_query_new(m, &q, question, ifindex, flags);
74b2466e
LP
333 if (r < 0)
334 return r;
335
336 q->request = sd_bus_message_ref(message);
337 q->request_family = family;
338 q->request_hostname = hostname;
339 q->complete = bus_method_resolve_hostname_complete;
340
82bd6ddd
LP
341 r = dns_query_bus_track(q, bus, message);
342 if (r < 0)
343 return r;
344
322345fd 345 r = dns_query_go(q);
74b2466e
LP
346 if (r < 0) {
347 dns_query_free(q);
309e9d86
LP
348
349 if (r == -ESRCH)
350 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
351
74b2466e
LP
352 return r;
353 }
354
355 return 1;
356}
357
358static void bus_method_resolve_address_complete(DnsQuery *q) {
ad867662 359 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
faa133f3
LP
360 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
361 unsigned added = 0, i;
362 int r;
74b2466e
LP
363
364 assert(q);
365
ec2c5e43 366 if (q->state != DNS_TRANSACTION_SUCCESS) {
ad867662
LP
367 r = reply_query_state(q);
368 goto finish;
369 }
74b2466e 370
ad867662
LP
371 r = sd_bus_message_new_method_return(q->request, &reply);
372 if (r < 0)
373 goto finish;
74b2466e 374
51323288
LP
375 r = sd_bus_message_append(reply, "i", q->answer_ifindex);
376 if (r < 0)
377 goto finish;
378
ad867662
LP
379 r = sd_bus_message_open_container(reply, 'a', "s");
380 if (r < 0)
381 goto finish;
74b2466e 382
3339cb71
LP
383 if (q->answer) {
384 answer = dns_answer_ref(q->answer);
faa133f3 385
3339cb71
LP
386 for (i = 0; i < answer->n_rrs; i++) {
387 r = dns_question_matches_rr(q->question, answer->rrs[i]);
388 if (r < 0)
2d4c5cbc 389 goto finish;
3339cb71
LP
390 if (r == 0)
391 continue;
74b2466e 392
3339cb71
LP
393 r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
394 if (r < 0)
395 goto finish;
74b2466e 396
3339cb71
LP
397 added ++;
398 }
ad867662 399 }
74b2466e 400
ad867662
LP
401 if (added <= 0) {
402 _cleanup_free_ char *ip = NULL;
74b2466e 403
ad867662 404 in_addr_to_string(q->request_family, &q->request_address, &ip);
74b2466e 405
309e9d86 406 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
ad867662 407 goto finish;
74b2466e
LP
408 }
409
ad867662
LP
410 r = sd_bus_message_close_container(reply);
411 if (r < 0)
412 goto finish;
74b2466e 413
51323288
LP
414 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
415 if (r < 0)
416 goto finish;
417
ad867662 418 r = sd_bus_send(q->manager->bus, reply, NULL);
74b2466e
LP
419
420finish:
2d4c5cbc 421 if (r < 0) {
da927ba9 422 log_error_errno(r, "Failed to send address reply: %m");
2d4c5cbc
LP
423 sd_bus_reply_method_errno(q->request, -r, NULL);
424 }
74b2466e
LP
425
426 dns_query_free(q);
427}
428
429static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3
LP
430 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
431 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
432 _cleanup_free_ char *reverse = NULL;
74b2466e 433 Manager *m = userdata;
faa133f3 434 int family, ifindex;
51323288 435 uint64_t flags;
74b2466e 436 const void *d;
74b2466e
LP
437 DnsQuery *q;
438 size_t sz;
439 int r;
440
441 assert(bus);
442 assert(message);
443 assert(m);
444
51323288 445 r = sd_bus_message_read(message, "ii", &ifindex, &family);
74b2466e
LP
446 if (r < 0)
447 return r;
448
449 if (!IN_SET(family, AF_INET, AF_INET6))
0dd25fb9 450 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e
LP
451
452 r = sd_bus_message_read_array(message, 'y', &d, &sz);
453 if (r < 0)
454 return r;
455
0dd25fb9 456 if (sz != FAMILY_ADDRESS_SIZE(family))
74b2466e
LP
457 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
458
51323288
LP
459 r = sd_bus_message_read(message, "t", &flags);
460 if (r < 0)
461 return r;
462
463 r = check_ifindex_flags(ifindex, &flags, error);
74b2466e
LP
464 if (r < 0)
465 return r;
74b2466e 466
faa133f3
LP
467 r = dns_name_reverse(family, d, &reverse);
468 if (r < 0)
469 return r;
470
471 question = dns_question_new(1);
472 if (!question)
473 return -ENOMEM;
474
475 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
476 if (!key)
477 return -ENOMEM;
478
479 reverse = NULL;
480
481 r = dns_question_add(question, key);
74b2466e
LP
482 if (r < 0)
483 return r;
484
51323288 485 r = dns_query_new(m, &q, question, ifindex, flags);
74b2466e
LP
486 if (r < 0)
487 return r;
488
489 q->request = sd_bus_message_ref(message);
490 q->request_family = family;
491 memcpy(&q->request_address, d, sz);
492 q->complete = bus_method_resolve_address_complete;
493
82bd6ddd
LP
494 r = dns_query_bus_track(q, bus, message);
495 if (r < 0)
496 return r;
497
322345fd 498 r = dns_query_go(q);
74b2466e
LP
499 if (r < 0) {
500 dns_query_free(q);
faa133f3
LP
501
502 if (r == -ESRCH)
503 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
504
74b2466e
LP
505 return r;
506 }
507
508 return 1;
509}
510
2d4c5cbc
LP
511static void bus_method_resolve_record_complete(DnsQuery *q) {
512 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
513 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
514 unsigned added = 0, i;
515 int r;
516
517 assert(q);
518
ec2c5e43 519 if (q->state != DNS_TRANSACTION_SUCCESS) {
2d4c5cbc
LP
520 r = reply_query_state(q);
521 goto finish;
522 }
523
524 r = sd_bus_message_new_method_return(q->request, &reply);
525 if (r < 0)
526 goto finish;
527
51323288
LP
528 r = sd_bus_message_append(reply, "i", q->answer_ifindex);
529 if (r < 0)
530 goto finish;
531
2d4c5cbc
LP
532 r = sd_bus_message_open_container(reply, 'a', "(qqay)");
533 if (r < 0)
534 goto finish;
535
536 if (q->answer) {
537 answer = dns_answer_ref(q->answer);
538
539 for (i = 0; i < answer->n_rrs; i++) {
540 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
541 size_t start;
542
543 r = dns_question_matches_rr(q->question, answer->rrs[i]);
544 if (r < 0)
545 goto finish;
546 if (r == 0)
547 continue;
548
549 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
550 if (r < 0)
551 goto finish;
552
553 r = dns_packet_append_rr(p, answer->rrs[i], &start);
554 if (r < 0)
555 goto finish;
556
557 r = sd_bus_message_open_container(reply, 'r', "qqay");
558 if (r < 0)
559 goto finish;
560
561 r = sd_bus_message_append(reply, "qq", answer->rrs[i]->key->class, answer->rrs[i]->key->type);
562 if (r < 0)
563 goto finish;
564
565 r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
566 if (r < 0)
567 goto finish;
568
569 r = sd_bus_message_close_container(reply);
570 if (r < 0)
571 goto finish;
572
573 added ++;
574 }
575 }
576
577 if (added <= 0) {
578 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", q->request_hostname);
579 goto finish;
580 }
581
582 r = sd_bus_message_close_container(reply);
583 if (r < 0)
584 goto finish;
585
51323288
LP
586 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
587 if (r < 0)
588 goto finish;
589
2d4c5cbc
LP
590 r = sd_bus_send(q->manager->bus, reply, NULL);
591
592finish:
593 if (r < 0) {
da927ba9 594 log_error_errno(r, "Failed to send record reply: %m");
2d4c5cbc
LP
595 sd_bus_reply_method_errno(q->request, -r, NULL);
596 }
597
598 dns_query_free(q);
599}
600
601static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
602 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
603 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
2d4c5cbc 604 Manager *m = userdata;
2d4c5cbc
LP
605 uint16_t class, type;
606 const char *name;
51323288
LP
607 int r, ifindex;
608 uint64_t flags;
609 DnsQuery *q;
2d4c5cbc
LP
610
611 assert(bus);
612 assert(message);
613 assert(m);
614
51323288 615 r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
2d4c5cbc
LP
616 if (r < 0)
617 return r;
618
7b9f7afc
LP
619 r = dns_name_normalize(name, NULL);
620 if (r < 0)
621 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
622
51323288
LP
623 r = check_ifindex_flags(ifindex, &flags, error);
624 if (r < 0)
625 return r;
626
2d4c5cbc
LP
627 question = dns_question_new(1);
628 if (!question)
629 return -ENOMEM;
630
631 key = dns_resource_key_new(class, type, name);
632 if (!key)
633 return -ENOMEM;
634
635 r = dns_question_add(question, key);
636 if (r < 0)
637 return r;
638
51323288 639 r = dns_query_new(m, &q, question, ifindex, flags);
2d4c5cbc
LP
640 if (r < 0)
641 return r;
642
643 q->request = sd_bus_message_ref(message);
644 q->request_hostname = name;
645 q->complete = bus_method_resolve_record_complete;
646
82bd6ddd
LP
647 r = dns_query_bus_track(q, bus, message);
648 if (r < 0)
649 return r;
650
2d4c5cbc
LP
651 r = dns_query_go(q);
652 if (r < 0) {
653 dns_query_free(q);
654
655 if (r == -ESRCH)
656 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
657
658 return r;
659 }
660
661 return 1;
662}
663
74b2466e
LP
664static const sd_bus_vtable resolve_vtable[] = {
665 SD_BUS_VTABLE_START(0),
51323288
LP
666 SD_BUS_METHOD("ResolveHostname", "isit", "ia(iay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
667 SD_BUS_METHOD("ResolveAddress", "iiayt", "iast", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
668 SD_BUS_METHOD("ResolveRecord", "isqqt", "ia(qqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
74b2466e
LP
669 SD_BUS_VTABLE_END,
670};
671
672static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
673 Manager *m = userdata;
674
675 assert(s);
676 assert(m);
677
678 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
679
680 manager_connect_bus(m);
681 return 0;
682}
683
902bb5d8
LP
684static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
685 Manager *m = userdata;
686 int b, r;
687
688 assert(bus);
689 assert(bus);
690
691 r = sd_bus_message_read(message, "b", &b);
692 if (r < 0) {
da927ba9 693 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
902bb5d8
LP
694 return 0;
695 }
696
697 if (b)
698 return 0;
699
700 log_debug("Coming back from suspend, verifying all RRs...");
701
702 manager_verify_all(m);
703 return 0;
704}
705
74b2466e
LP
706int manager_connect_bus(Manager *m) {
707 int r;
708
709 assert(m);
710
711 if (m->bus)
712 return 0;
713
714 r = sd_bus_default_system(&m->bus);
715 if (r < 0) {
716 /* We failed to connect? Yuck, we must be in early
717 * boot. Let's try in 5s again. As soon as we have
718 * kdbus we can stop doing this... */
719
da927ba9 720 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
74b2466e
LP
721
722 r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
723 if (r < 0) {
da927ba9 724 log_error_errno(r, "Failed to install bus reconnect time event: %m");
74b2466e
LP
725 return r;
726 }
727
728 return 0;
729 }
730
4d1cf1e2 731 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
74b2466e 732 if (r < 0) {
da927ba9 733 log_error_errno(r, "Failed to register object: %m");
74b2466e
LP
734 return r;
735 }
736
737 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
738 if (r < 0) {
da927ba9 739 log_error_errno(r, "Failed to register name: %m");
74b2466e
LP
740 return r;
741 }
742
743 r = sd_bus_attach_event(m->bus, m->event, 0);
744 if (r < 0) {
da927ba9 745 log_error_errno(r, "Failed to attach bus to event loop: %m");
74b2466e
LP
746 return r;
747 }
748
902bb5d8
LP
749 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
750 "type='signal',"
751 "sender='org.freedesktop.login1',"
752 "interface='org.freedesktop.login1.Manager',"
753 "member='PrepareForSleep',"
754 "path='/org/freedesktop/login1'",
755 match_prepare_for_sleep,
756 m);
757 if (r < 0)
da927ba9 758 log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
902bb5d8 759
74b2466e
LP
760 return 0;
761}