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"
26 #include "resolved-dns-domain.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_QUERY_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_QUERY_TIMEOUT:
49 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
51 case DNS_QUERY_ATTEMPTS_MAX:
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_QUERY_RESOURCES:
55 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
57 case DNS_QUERY_INVALID_REPLY:
58 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
60 case DNS_QUERY_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);
83 case DNS_QUERY_PENDING:
84 case DNS_QUERY_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_QUERY_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 answer = dns_answer_ref(q->answer);
153 ifindex = q->answer_ifindex;
155 for (i = 0; i < answer->n_rrs; i++) {
156 r = dns_question_matches_rr(q->question, answer->rrs[i]);
160 /* Hmm, if this is not an address record,
161 maybe it's a cname? If so, remember this */
162 r = dns_question_matches_cname(q->question, answer->rrs[i]);
166 cname = dns_resource_record_ref(answer->rrs[i]);
171 r = append_address(reply, answer->rrs[i], ifindex);
176 canonical = dns_resource_record_ref(answer->rrs[i]);
183 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);
187 /* This has a cname? Then update the query with the
189 r = dns_query_cname_redirect(q, cname->cname.name);
192 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
194 r = sd_bus_reply_method_errno(q->request, -r, NULL);
199 /* Before we restart the query, let's see if any of
200 * the RRs we already got already answers our query */
201 for (i = 0; i < answer->n_rrs; i++) {
202 r = dns_question_matches_rr(q->question, answer->rrs[i]);
208 r = append_address(reply, answer->rrs[i], ifindex);
213 canonical = dns_resource_record_ref(answer->rrs[i]);
218 /* If we didn't find anything, then let's restart the
219 * query, this time with the cname */
223 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
227 r = sd_bus_reply_method_errno(q->request, -r, NULL);
234 r = sd_bus_message_close_container(reply);
238 /* Return the precise spelling and uppercasing reported by the server */
240 r = sd_bus_message_append(reply, "s", DNS_RESOURCE_KEY_NAME(canonical->key));
244 r = sd_bus_send(q->manager->bus, reply, NULL);
248 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
252 log_error("Failed to send bus reply: %s", strerror(-r));
257 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
258 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
259 Manager *m = userdata;
260 const char *hostname;
269 r = sd_bus_message_read(message, "si", &hostname, &family);
273 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
274 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
276 if (!hostname_is_valid(hostname))
277 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
279 question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
283 if (family != AF_INET6) {
284 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
286 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
290 r = dns_question_add(question, key);
295 if (family != AF_INET) {
296 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
298 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
302 r = dns_question_add(question, key);
307 r = dns_query_new(m, &q, question);
311 q->request = sd_bus_message_ref(message);
312 q->request_family = family;
313 q->request_hostname = hostname;
314 q->complete = bus_method_resolve_hostname_complete;
321 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
329 static void bus_method_resolve_address_complete(DnsQuery *q) {
330 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
331 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
332 unsigned added = 0, i;
337 if (q->state != DNS_QUERY_SUCCESS) {
338 r = reply_query_state(q);
342 r = sd_bus_message_new_method_return(q->request, &reply);
346 r = sd_bus_message_open_container(reply, 'a', "s");
350 answer = dns_answer_ref(q->answer);
352 for (i = 0; i < answer->n_rrs; i++) {
353 r = dns_question_matches_rr(q->question, answer->rrs[i]);
359 r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
367 _cleanup_free_ char *ip = NULL;
369 in_addr_to_string(q->request_family, &q->request_address, &ip);
371 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
375 r = sd_bus_message_close_container(reply);
379 r = sd_bus_send(q->manager->bus, reply, NULL);
383 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
387 log_error("Failed to send bus reply: %s", strerror(-r));
392 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
393 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
394 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
395 _cleanup_free_ char *reverse = NULL;
396 Manager *m = userdata;
407 r = sd_bus_message_read(message, "i", &family);
411 if (!IN_SET(family, AF_INET, AF_INET6))
412 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
414 r = sd_bus_message_read_array(message, 'y', &d, &sz);
418 if (sz != FAMILY_ADDRESS_SIZE(family))
419 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
421 r = sd_bus_message_read(message, "i", &ifindex);
425 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
427 r = dns_name_reverse(family, d, &reverse);
431 question = dns_question_new(1);
435 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
441 r = dns_question_add(question, key);
445 r = dns_query_new(m, &q, question);
449 q->request = sd_bus_message_ref(message);
450 q->request_family = family;
451 memcpy(&q->request_address, d, sz);
452 q->complete = bus_method_resolve_address_complete;
459 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
467 static const sd_bus_vtable resolve_vtable[] = {
468 SD_BUS_VTABLE_START(0),
469 SD_BUS_METHOD("ResolveHostname", "si", "a(iayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
470 SD_BUS_METHOD("ResolveAddress", "iayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
474 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
475 Manager *m = userdata;
480 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
482 manager_connect_bus(m);
486 int manager_connect_bus(Manager *m) {
494 r = sd_bus_default_system(&m->bus);
496 /* We failed to connect? Yuck, we must be in early
497 * boot. Let's try in 5s again. As soon as we have
498 * kdbus we can stop doing this... */
500 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
502 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);
504 log_error("Failed to install bus reconnect time event: %s", strerror(-r));
511 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
513 log_error("Failed to register object: %s", strerror(-r));
517 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
519 log_error("Failed to register name: %s", strerror(-r));
523 r = sd_bus_attach_event(m->bus, m->event, 0);
525 log_error("Failed to attach bus to event loop: %s", strerror(-r));