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;
64 rcode = dns_query_get_rcode(q);
68 if (rcode == DNS_RCODE_NXDOMAIN)
69 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
72 char p[3]; /* the rcode is 4 bits long */
74 rc = dns_rcode_to_string(rcode);
76 sprintf(p, "%i", rcode);
80 n = strappenda(_BUS_ERROR_DNS, rc);
81 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
84 return sd_bus_reply_method_error(q->request, &error);
88 case DNS_QUERY_PENDING:
89 case DNS_QUERY_SUCCESS:
91 assert_not_reached("Impossible state");
95 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
101 r = sd_bus_message_open_container(reply, 'r', "yayi");
105 if (rr->key.type == DNS_TYPE_A) {
106 r = sd_bus_message_append(reply, "y", AF_INET);
110 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
112 r = sd_bus_message_append(reply, "y", AF_INET6);
116 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
121 r = sd_bus_message_append(reply, "i", ifindex);
125 r = sd_bus_message_close_container(reply);
132 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
133 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
134 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
135 DnsResourceRecord **rrs;
142 if (q->state != DNS_QUERY_SUCCESS) {
143 r = reply_query_state(q);
147 n = dns_query_get_rrs(q, &rrs);
151 r = sd_bus_message_new_method_return(q->request, &reply);
155 r = sd_bus_message_open_container(reply, 'a', "(yayi)");
159 ifindex = dns_query_get_ifindex(q);
163 for (i = 0; i < n; i++) {
164 r = dns_query_matches_rr(q, rrs[i]);
168 /* Hmm, if this is not an address record,
169 maybe it's a cname? If so, remember this */
170 r = dns_query_matches_cname(q, rrs[i]);
174 cname = dns_resource_record_ref(rrs[i]);
179 r = append_address(reply, rrs[i], ifindex);
184 canonical = dns_resource_record_ref(rrs[i]);
191 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);
195 /* This has a cname? Then update the query with the
197 r = dns_query_cname_redirect(q, cname->cname.name);
200 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
202 r = sd_bus_reply_method_errno(q->request, -r, NULL);
207 /* Before we restart the query, let's see if any of
208 * the RRs we already got already answers our query */
209 for (i = 0; i < n; i++) {
210 r = dns_query_matches_rr(q, rrs[i]);
216 r = append_address(reply, rrs[i], ifindex);
221 canonical = dns_resource_record_ref(rrs[i]);
226 /* If we didn't find anything, then let's restart the
227 * query, this time with the cname */
231 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
235 r = sd_bus_reply_method_errno(q->request, -r, NULL);
242 r = sd_bus_message_close_container(reply);
246 /* Return the precise spelling and uppercasing reported by the server */
248 r = sd_bus_message_append(reply, "s", canonical->key.name);
252 r = sd_bus_send(q->manager->bus, reply, NULL);
256 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
260 log_error("Failed to send bus reply: %s", strerror(-r));
265 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
266 Manager *m = userdata;
267 const char *hostname;
269 DnsResourceKey keys[2];
278 r = sd_bus_message_read(message, "sy", &hostname, &family);
282 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
283 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
285 if (!hostname_is_valid(hostname))
286 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
288 if (family != AF_INET6) {
289 keys[n].class = DNS_CLASS_IN;
290 keys[n].type = DNS_TYPE_A;
291 keys[n].name = (char*) hostname;
295 if (family != AF_INET) {
296 keys[n].class = DNS_CLASS_IN;
297 keys[n].type = DNS_TYPE_AAAA;
298 keys[n].name = (char*) hostname;
302 r = dns_query_new(m, &q, keys, n);
306 q->request = sd_bus_message_ref(message);
307 q->request_family = family;
308 q->request_hostname = hostname;
309 q->complete = bus_method_resolve_hostname_complete;
316 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
324 static void bus_method_resolve_address_complete(DnsQuery *q) {
325 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
326 DnsResourceRecord **rrs;
332 if (q->state != DNS_QUERY_SUCCESS) {
333 r = reply_query_state(q);
337 n = dns_query_get_rrs(q, &rrs);
341 r = sd_bus_message_new_method_return(q->request, &reply);
345 r = sd_bus_message_open_container(reply, 'a', "s");
349 for (i = 0; i < n; i++) {
350 r = dns_query_matches_rr(q, rrs[i]);
356 r = sd_bus_message_append(reply, "s", rrs[i]->ptr.name);
364 _cleanup_free_ char *ip = NULL;
366 in_addr_to_string(q->request_family, &q->request_address, &ip);
368 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
372 r = sd_bus_message_close_container(reply);
376 r = sd_bus_send(q->manager->bus, reply, NULL);
380 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
384 log_error("Failed to send bus reply: %s", strerror(-r));
389 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
390 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
391 Manager *m = userdata;
403 r = sd_bus_message_read(message, "y", &family);
407 if (!IN_SET(family, AF_INET, AF_INET6))
408 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
410 r = sd_bus_message_read_array(message, 'y', &d, &sz);
414 if ((family == AF_INET && sz != sizeof(struct in_addr)) ||
415 (family == AF_INET6 && sz != sizeof(struct in6_addr)))
416 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
418 r = sd_bus_message_read(message, "i", &ifindex);
422 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
424 key.class = DNS_CLASS_IN;
425 key.type = DNS_TYPE_PTR;
426 r = dns_name_reverse(family, d, &key.name);
430 r = dns_query_new(m, &q, &key, 1);
434 q->request = sd_bus_message_ref(message);
435 q->request_family = family;
436 memcpy(&q->request_address, d, sz);
437 q->complete = bus_method_resolve_address_complete;
448 static const sd_bus_vtable resolve_vtable[] = {
449 SD_BUS_VTABLE_START(0),
450 SD_BUS_METHOD("ResolveHostname", "sy", "a(yayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
451 SD_BUS_METHOD("ResolveAddress", "yayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
455 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
456 Manager *m = userdata;
461 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
463 manager_connect_bus(m);
467 int manager_connect_bus(Manager *m) {
475 r = sd_bus_default_system(&m->bus);
477 /* We failed to connect? Yuck, we must be in early
478 * boot. Let's try in 5s again. As soon as we have
479 * kdbus we can stop doing this... */
481 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
483 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);
485 log_error("Failed to install bus reconnect time event: %s", strerror(-r));
492 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
494 log_error("Failed to register object: %s", strerror(-r));
498 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
500 log_error("Failed to register name: %s", strerror(-r));
504 r = sd_bus_attach_event(m->bus, m->event, 0);
506 log_error("Failed to attach bus to event loop: %s", strerror(-r));