1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
22 #include "bus-errors.h"
25 #include "resolved-dns-domain.h"
26 #include "resolved-bus.h"
28 static int reply_query_state(DnsQuery *q) {
29 _cleanup_free_ char *ip = NULL;
33 if (q->request_hostname)
34 name = q->request_hostname;
36 r = in_addr_to_string(q->request_family, &q->request_address, &ip);
45 case DNS_TRANSACTION_NO_SERVERS:
46 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
48 case DNS_TRANSACTION_TIMEOUT:
49 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
51 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
52 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
54 case DNS_TRANSACTION_INVALID_REPLY:
55 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
57 case DNS_TRANSACTION_RESOURCES:
58 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
60 case DNS_TRANSACTION_ABORTED:
61 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
63 case DNS_TRANSACTION_FAILURE: {
64 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
66 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
67 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
70 char p[3]; /* the rcode is 4 bits long */
72 rc = dns_rcode_to_string(q->answer_rcode);
74 sprintf(p, "%i", q->answer_rcode);
78 n = strappenda(_BUS_ERROR_DNS, rc);
79 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
82 return sd_bus_reply_method_error(q->request, &error);
85 case DNS_TRANSACTION_NULL:
86 case DNS_TRANSACTION_PENDING:
87 case DNS_TRANSACTION_SUCCESS:
89 assert_not_reached("Impossible state");
93 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
99 r = sd_bus_message_open_container(reply, 'r', "iayi");
103 if (rr->key->type == DNS_TYPE_A) {
104 r = sd_bus_message_append(reply, "i", AF_INET);
108 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
110 } else if (rr->key->type == DNS_TYPE_AAAA) {
111 r = sd_bus_message_append(reply, "i", AF_INET6);
115 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
117 return -EAFNOSUPPORT;
122 r = sd_bus_message_append(reply, "i", ifindex);
126 r = sd_bus_message_close_container(reply);
133 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
134 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
135 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
136 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
137 unsigned added = 0, i;
142 if (q->state != DNS_TRANSACTION_SUCCESS) {
143 r = reply_query_state(q);
147 r = sd_bus_message_new_method_return(q->request, &reply);
151 r = sd_bus_message_open_container(reply, 'a', "(iayi)");
155 ifindex = q->answer_ifindex;
158 answer = dns_answer_ref(q->answer);
160 for (i = 0; i < answer->n_rrs; i++) {
161 r = dns_question_matches_rr(q->question, answer->rrs[i]);
165 /* Hmm, if this is not an address record,
166 maybe it's a cname? If so, remember this */
167 r = dns_question_matches_cname(q->question, answer->rrs[i]);
171 cname = dns_resource_record_ref(answer->rrs[i]);
176 r = append_address(reply, answer->rrs[i], ifindex);
181 canonical = dns_resource_record_ref(answer->rrs[i]);
189 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);
193 /* This has a cname? Then update the query with the
195 r = dns_query_cname_redirect(q, cname->cname.name);
198 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
200 r = sd_bus_reply_method_errno(q->request, -r, NULL);
205 /* Before we restart the query, let's see if any of
206 * the RRs we already got already answers our query */
207 for (i = 0; i < answer->n_rrs; i++) {
208 r = dns_question_matches_rr(q->question, answer->rrs[i]);
214 r = append_address(reply, answer->rrs[i], ifindex);
219 canonical = dns_resource_record_ref(answer->rrs[i]);
224 /* If we didn't find anything, then let's restart the
225 * query, this time with the cname */
229 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
233 r = sd_bus_reply_method_errno(q->request, -r, NULL);
241 r = sd_bus_message_close_container(reply);
245 /* Return the precise spelling and uppercasing reported by the server */
247 r = sd_bus_message_append(reply, "s", DNS_RESOURCE_KEY_NAME(canonical->key));
251 r = sd_bus_send(q->manager->bus, reply, NULL);
255 log_error("Failed to send hostname reply: %s", strerror(-r));
256 sd_bus_reply_method_errno(q->request, -r, NULL);
262 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
263 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
264 Manager *m = userdata;
265 const char *hostname;
274 r = sd_bus_message_read(message, "si", &hostname, &family);
278 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
279 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
281 r = dns_name_normalize(hostname, NULL);
283 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
285 question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
289 if (family != AF_INET6) {
290 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
292 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
296 r = dns_question_add(question, key);
301 if (family != AF_INET) {
302 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
304 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
308 r = dns_question_add(question, key);
313 r = dns_query_new(m, &q, question);
317 q->request = sd_bus_message_ref(message);
318 q->request_family = family;
319 q->request_hostname = hostname;
320 q->complete = bus_method_resolve_hostname_complete;
322 r = dns_query_bus_track(q, bus, message);
331 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
339 static void bus_method_resolve_address_complete(DnsQuery *q) {
340 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
341 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
342 unsigned added = 0, i;
347 if (q->state != DNS_TRANSACTION_SUCCESS) {
348 r = reply_query_state(q);
352 r = sd_bus_message_new_method_return(q->request, &reply);
356 r = sd_bus_message_open_container(reply, 'a', "s");
361 answer = dns_answer_ref(q->answer);
363 for (i = 0; i < answer->n_rrs; i++) {
364 r = dns_question_matches_rr(q->question, answer->rrs[i]);
370 r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
379 _cleanup_free_ char *ip = NULL;
381 in_addr_to_string(q->request_family, &q->request_address, &ip);
383 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
387 r = sd_bus_message_close_container(reply);
391 r = sd_bus_send(q->manager->bus, reply, NULL);
395 log_error("Failed to send address reply: %s", strerror(-r));
396 sd_bus_reply_method_errno(q->request, -r, NULL);
402 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
403 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
404 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
405 _cleanup_free_ char *reverse = NULL;
406 Manager *m = userdata;
417 r = sd_bus_message_read(message, "i", &family);
421 if (!IN_SET(family, AF_INET, AF_INET6))
422 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
424 r = sd_bus_message_read_array(message, 'y', &d, &sz);
428 if (sz != FAMILY_ADDRESS_SIZE(family))
429 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
431 r = sd_bus_message_read(message, "i", &ifindex);
435 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
437 r = dns_name_reverse(family, d, &reverse);
441 question = dns_question_new(1);
445 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
451 r = dns_question_add(question, key);
455 r = dns_query_new(m, &q, question);
459 q->request = sd_bus_message_ref(message);
460 q->request_family = family;
461 memcpy(&q->request_address, d, sz);
462 q->complete = bus_method_resolve_address_complete;
464 r = dns_query_bus_track(q, bus, message);
473 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
481 static void bus_method_resolve_record_complete(DnsQuery *q) {
482 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
483 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
484 unsigned added = 0, i;
489 if (q->state != DNS_TRANSACTION_SUCCESS) {
490 r = reply_query_state(q);
494 r = sd_bus_message_new_method_return(q->request, &reply);
498 r = sd_bus_message_open_container(reply, 'a', "(qqay)");
503 answer = dns_answer_ref(q->answer);
505 for (i = 0; i < answer->n_rrs; i++) {
506 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
509 r = dns_question_matches_rr(q->question, answer->rrs[i]);
515 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
519 r = dns_packet_append_rr(p, answer->rrs[i], &start);
523 r = sd_bus_message_open_container(reply, 'r', "qqay");
527 r = sd_bus_message_append(reply, "qq", answer->rrs[i]->key->class, answer->rrs[i]->key->type);
531 r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
535 r = sd_bus_message_close_container(reply);
544 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);
548 r = sd_bus_message_close_container(reply);
552 r = sd_bus_send(q->manager->bus, reply, NULL);
556 log_error("Failed to send record reply: %s", strerror(-r));
557 sd_bus_reply_method_errno(q->request, -r, NULL);
563 static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
564 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
565 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
566 Manager *m = userdata;
569 uint16_t class, type;
576 r = sd_bus_message_read(message, "sqq", &name, &class, &type);
580 r = dns_name_normalize(name, NULL);
582 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
584 question = dns_question_new(1);
588 key = dns_resource_key_new(class, type, name);
592 r = dns_question_add(question, key);
596 r = dns_query_new(m, &q, question);
600 q->request = sd_bus_message_ref(message);
601 q->request_hostname = name;
602 q->complete = bus_method_resolve_record_complete;
604 r = dns_query_bus_track(q, bus, message);
613 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
621 static const sd_bus_vtable resolve_vtable[] = {
622 SD_BUS_VTABLE_START(0),
623 SD_BUS_METHOD("ResolveHostname", "si", "a(iayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
624 SD_BUS_METHOD("ResolveAddress", "iayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
625 SD_BUS_METHOD("ResolveRecord", "sqq", "a(qqay)", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
629 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
630 Manager *m = userdata;
635 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
637 manager_connect_bus(m);
641 static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
642 Manager *m = userdata;
648 r = sd_bus_message_read(message, "b", &b);
650 log_debug("Failed to parse PrepareForSleep signal: %s", strerror(-r));
657 log_debug("Coming back from suspend, verifying all RRs...");
659 manager_verify_all(m);
663 int manager_connect_bus(Manager *m) {
671 r = sd_bus_default_system(&m->bus);
673 /* We failed to connect? Yuck, we must be in early
674 * boot. Let's try in 5s again. As soon as we have
675 * kdbus we can stop doing this... */
677 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
679 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);
681 log_error("Failed to install bus reconnect time event: %s", strerror(-r));
688 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
690 log_error("Failed to register object: %s", strerror(-r));
694 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
696 log_error("Failed to register name: %s", strerror(-r));
700 r = sd_bus_attach_event(m->bus, m->event, 0);
702 log_error("Failed to attach bus to event loop: %s", strerror(-r));
706 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
708 "sender='org.freedesktop.login1',"
709 "interface='org.freedesktop.login1.Manager',"
710 "member='PrepareForSleep',"
711 "path='/org/freedesktop/login1'",
712 match_prepare_for_sleep,
715 log_error("Failed to add match for PrepareForSleep: %s", strerror(-r));