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_RESOURCES:
55 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
57 case DNS_TRANSACTION_INVALID_REPLY:
58 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
60 case DNS_TRANSACTION_FAILURE: {
61 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
63 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
64 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
67 char p[3]; /* the rcode is 4 bits long */
69 rc = dns_rcode_to_string(q->answer_rcode);
71 sprintf(p, "%i", q->answer_rcode);
75 n = strappenda(_BUS_ERROR_DNS, rc);
76 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
79 return sd_bus_reply_method_error(q->request, &error);
82 case DNS_TRANSACTION_NULL:
83 case DNS_TRANSACTION_PENDING:
84 case DNS_TRANSACTION_SUCCESS:
86 assert_not_reached("Impossible state");
90 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
96 r = sd_bus_message_open_container(reply, 'r', "iayi");
100 if (rr->key->type == DNS_TYPE_A) {
101 r = sd_bus_message_append(reply, "i", AF_INET);
105 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
107 } else if (rr->key->type == DNS_TYPE_AAAA) {
108 r = sd_bus_message_append(reply, "i", AF_INET6);
112 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
114 return -EAFNOSUPPORT;
119 r = sd_bus_message_append(reply, "i", ifindex);
123 r = sd_bus_message_close_container(reply);
130 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
131 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
132 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
133 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
134 unsigned added = 0, i;
139 if (q->state != DNS_TRANSACTION_SUCCESS) {
140 r = reply_query_state(q);
144 r = sd_bus_message_new_method_return(q->request, &reply);
148 r = sd_bus_message_open_container(reply, 'a', "(iayi)");
152 ifindex = q->answer_ifindex;
155 answer = dns_answer_ref(q->answer);
157 for (i = 0; i < answer->n_rrs; i++) {
158 r = dns_question_matches_rr(q->question, answer->rrs[i]);
162 /* Hmm, if this is not an address record,
163 maybe it's a cname? If so, remember this */
164 r = dns_question_matches_cname(q->question, answer->rrs[i]);
168 cname = dns_resource_record_ref(answer->rrs[i]);
173 r = append_address(reply, answer->rrs[i], ifindex);
178 canonical = dns_resource_record_ref(answer->rrs[i]);
186 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);
190 /* This has a cname? Then update the query with the
192 r = dns_query_cname_redirect(q, cname->cname.name);
195 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
197 r = sd_bus_reply_method_errno(q->request, -r, NULL);
202 /* Before we restart the query, let's see if any of
203 * the RRs we already got already answers our query */
204 for (i = 0; i < answer->n_rrs; i++) {
205 r = dns_question_matches_rr(q->question, answer->rrs[i]);
211 r = append_address(reply, answer->rrs[i], ifindex);
216 canonical = dns_resource_record_ref(answer->rrs[i]);
221 /* If we didn't find anything, then let's restart the
222 * query, this time with the cname */
226 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
230 r = sd_bus_reply_method_errno(q->request, -r, NULL);
238 r = sd_bus_message_close_container(reply);
242 /* Return the precise spelling and uppercasing reported by the server */
244 r = sd_bus_message_append(reply, "s", DNS_RESOURCE_KEY_NAME(canonical->key));
248 r = sd_bus_send(q->manager->bus, reply, NULL);
252 log_error("Failed to send hostname reply: %s", strerror(-r));
253 sd_bus_reply_method_errno(q->request, -r, NULL);
259 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
260 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
261 Manager *m = userdata;
262 const char *hostname;
271 r = sd_bus_message_read(message, "si", &hostname, &family);
275 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
276 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
278 r = dns_name_normalize(hostname, NULL);
280 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
282 question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
286 if (family != AF_INET6) {
287 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
289 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
293 r = dns_question_add(question, key);
298 if (family != AF_INET) {
299 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
301 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
305 r = dns_question_add(question, key);
310 r = dns_query_new(m, &q, question);
314 q->request = sd_bus_message_ref(message);
315 q->request_family = family;
316 q->request_hostname = hostname;
317 q->complete = bus_method_resolve_hostname_complete;
324 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
332 static void bus_method_resolve_address_complete(DnsQuery *q) {
333 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
334 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
335 unsigned added = 0, i;
340 if (q->state != DNS_TRANSACTION_SUCCESS) {
341 r = reply_query_state(q);
345 r = sd_bus_message_new_method_return(q->request, &reply);
349 r = sd_bus_message_open_container(reply, 'a', "s");
354 answer = dns_answer_ref(q->answer);
356 for (i = 0; i < answer->n_rrs; i++) {
357 r = dns_question_matches_rr(q->question, answer->rrs[i]);
363 r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
372 _cleanup_free_ char *ip = NULL;
374 in_addr_to_string(q->request_family, &q->request_address, &ip);
376 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
380 r = sd_bus_message_close_container(reply);
384 r = sd_bus_send(q->manager->bus, reply, NULL);
388 log_error("Failed to send address reply: %s", strerror(-r));
389 sd_bus_reply_method_errno(q->request, -r, NULL);
395 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
396 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
397 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
398 _cleanup_free_ char *reverse = NULL;
399 Manager *m = userdata;
410 r = sd_bus_message_read(message, "i", &family);
414 if (!IN_SET(family, AF_INET, AF_INET6))
415 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
417 r = sd_bus_message_read_array(message, 'y', &d, &sz);
421 if (sz != FAMILY_ADDRESS_SIZE(family))
422 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
424 r = sd_bus_message_read(message, "i", &ifindex);
428 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
430 r = dns_name_reverse(family, d, &reverse);
434 question = dns_question_new(1);
438 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
444 r = dns_question_add(question, key);
448 r = dns_query_new(m, &q, question);
452 q->request = sd_bus_message_ref(message);
453 q->request_family = family;
454 memcpy(&q->request_address, d, sz);
455 q->complete = bus_method_resolve_address_complete;
462 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
470 static void bus_method_resolve_record_complete(DnsQuery *q) {
471 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
472 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
473 unsigned added = 0, i;
478 if (q->state != DNS_TRANSACTION_SUCCESS) {
479 r = reply_query_state(q);
483 r = sd_bus_message_new_method_return(q->request, &reply);
487 r = sd_bus_message_open_container(reply, 'a', "(qqay)");
492 answer = dns_answer_ref(q->answer);
494 for (i = 0; i < answer->n_rrs; i++) {
495 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
498 r = dns_question_matches_rr(q->question, answer->rrs[i]);
504 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
508 r = dns_packet_append_rr(p, answer->rrs[i], &start);
512 r = sd_bus_message_open_container(reply, 'r', "qqay");
516 r = sd_bus_message_append(reply, "qq", answer->rrs[i]->key->class, answer->rrs[i]->key->type);
520 r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
524 r = sd_bus_message_close_container(reply);
533 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);
537 r = sd_bus_message_close_container(reply);
541 r = sd_bus_send(q->manager->bus, reply, NULL);
545 log_error("Failed to send record reply: %s", strerror(-r));
546 sd_bus_reply_method_errno(q->request, -r, NULL);
552 static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
553 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
554 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
555 _cleanup_free_ char *reverse = NULL;
556 Manager *m = userdata;
559 uint16_t class, type;
566 r = sd_bus_message_read(message, "sqq", &name, &class, &type);
570 r = dns_name_normalize(name, NULL);
572 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
574 question = dns_question_new(1);
578 key = dns_resource_key_new(class, type, name);
582 r = dns_question_add(question, key);
586 r = dns_query_new(m, &q, question);
590 q->request = sd_bus_message_ref(message);
591 q->request_hostname = name;
592 q->complete = bus_method_resolve_record_complete;
599 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
607 static const sd_bus_vtable resolve_vtable[] = {
608 SD_BUS_VTABLE_START(0),
609 SD_BUS_METHOD("ResolveHostname", "si", "a(iayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
610 SD_BUS_METHOD("ResolveAddress", "iayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
611 SD_BUS_METHOD("ResolveRecord", "sqq", "a(qqay)", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
615 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
616 Manager *m = userdata;
621 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
623 manager_connect_bus(m);
627 int manager_connect_bus(Manager *m) {
635 r = sd_bus_default_system(&m->bus);
637 /* We failed to connect? Yuck, we must be in early
638 * boot. Let's try in 5s again. As soon as we have
639 * kdbus we can stop doing this... */
641 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
643 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);
645 log_error("Failed to install bus reconnect time event: %s", strerror(-r));
652 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
654 log_error("Failed to register object: %s", strerror(-r));
658 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
660 log_error("Failed to register name: %s", strerror(-r));
664 r = sd_bus_attach_event(m->bus, m->event, 0);
666 log_error("Failed to attach bus to event loop: %s", strerror(-r));