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, "Not appropriate name servers or networks 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;
65 if (DNS_PACKET_RCODE(q->received) == DNS_RCODE_NXDOMAIN)
66 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
69 char p[3]; /* the rcode is 4 bits long */
71 rc = dns_rcode_to_string(DNS_PACKET_RCODE(q->received));
73 sprintf(p, "%i", DNS_PACKET_RCODE(q->received));
77 n = strappenda(_BUS_ERROR_DNS, rc);
78 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
81 return sd_bus_reply_method_error(q->request, &error);
85 case DNS_QUERY_PENDING:
86 case DNS_QUERY_SUCCESS:
88 assert_not_reached("Impossible state");
92 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
98 r = sd_bus_message_open_container(reply, 'r', "yayi");
102 if (rr->key.type == DNS_TYPE_A) {
103 r = sd_bus_message_append(reply, "y", AF_INET);
107 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
109 r = sd_bus_message_append(reply, "y", AF_INET6);
113 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
118 r = sd_bus_message_append(reply, "i", ifindex);
122 r = sd_bus_message_close_container(reply);
129 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
130 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
131 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
132 unsigned i, n, added = 0;
133 size_t answer_rindex;
138 if (q->state != DNS_QUERY_SUCCESS) {
139 r = reply_query_state(q);
145 r = dns_packet_skip_question(q->received);
149 answer_rindex = q->received->rindex;
151 r = sd_bus_message_new_method_return(q->request, &reply);
155 r = sd_bus_message_open_container(reply, 'a', "(yayi)");
159 n = DNS_PACKET_ANCOUNT(q->received) +
160 DNS_PACKET_NSCOUNT(q->received) +
161 DNS_PACKET_ARCOUNT(q->received);
163 for (i = 0; i < n; i++) {
164 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
166 r = dns_packet_read_rr(q->received, &rr, NULL);
170 r = dns_query_matches_rr(q, rr);
174 /* Hmm, if this is not an address record,
175 maybe it's a cname? If so, remember this */
176 r = dns_query_matches_cname(q, rr);
180 cname = dns_resource_record_ref(rr);
185 r = append_address(reply, rr, q->received->ifindex);
194 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have RR of this type", q->request_hostname);
198 /* This has a cname? Then update the query with the
200 r = dns_query_follow_cname(q, cname->cname.name);
203 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
205 r = sd_bus_reply_method_errno(q->request, -r, NULL);
210 /* Before we restart the query, let's see if any of
211 * the RRs we already got already answers our query */
212 dns_packet_rewind(q->received, answer_rindex);
213 for (i = 0; i < n; i++) {
214 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
216 r = dns_packet_read_rr(q->received, &rr, NULL);
220 r = dns_query_matches_rr(q, rr);
226 r = append_address(reply, rr, q->received->ifindex);
233 /* If we didn't find anything, then let's restart the
234 * query, this time with the cname */
236 r = dns_query_start(q);
238 r = sd_bus_reply_method_errno(q->request, -r, NULL);
245 r = sd_bus_message_close_container(reply);
249 r = sd_bus_send(q->manager->bus, reply, NULL);
253 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
257 log_error("Failed to send bus reply: %s", strerror(-r));
262 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
263 Manager *m = userdata;
264 const char *hostname;
266 DnsResourceKey keys[2];
275 r = sd_bus_message_read(message, "sy", &hostname, &family);
279 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
280 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
282 if (!hostname_is_valid(hostname))
283 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
285 if (family != AF_INET6) {
286 keys[n].class = DNS_CLASS_IN;
287 keys[n].type = DNS_TYPE_A;
288 keys[n].name = (char*) hostname;
292 if (family != AF_INET) {
293 keys[n].class = DNS_CLASS_IN;
294 keys[n].type = DNS_TYPE_AAAA;
295 keys[n].name = (char*) hostname;
299 r = dns_query_new(m, &q, keys, n);
303 q->request = sd_bus_message_ref(message);
304 q->request_family = family;
305 q->request_hostname = hostname;
306 q->complete = bus_method_resolve_hostname_complete;
308 r = dns_query_start(q);
317 static void bus_method_resolve_address_complete(DnsQuery *q) {
318 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
319 unsigned i, n, added = 0;
324 if (q->state != DNS_QUERY_SUCCESS) {
325 r = reply_query_state(q);
331 r = dns_packet_skip_question(q->received);
335 r = sd_bus_message_new_method_return(q->request, &reply);
339 r = sd_bus_message_open_container(reply, 'a', "s");
343 n = DNS_PACKET_ANCOUNT(q->received) +
344 DNS_PACKET_NSCOUNT(q->received) +
345 DNS_PACKET_ARCOUNT(q->received);
347 for (i = 0; i < n; i++) {
348 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
350 r = dns_packet_read_rr(q->received, &rr, NULL);
354 r = dns_query_matches_rr(q, rr);
360 r = sd_bus_message_append(reply, "s", rr->ptr.name);
368 _cleanup_free_ char *ip = NULL;
370 in_addr_to_string(q->request_family, &q->request_address, &ip);
372 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have RR of this type", ip);
376 r = sd_bus_message_close_container(reply);
380 r = sd_bus_send(q->manager->bus, reply, NULL);
384 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
388 log_error("Failed to send bus reply: %s", strerror(-r));
393 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
395 Manager *m = userdata;
407 r = sd_bus_message_read(message, "y", &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 %u", family);
414 r = sd_bus_message_read_array(message, 'y', &d, &sz);
418 if ((family == AF_INET && sz != sizeof(struct in_addr)) ||
419 (family == AF_INET6 && sz != sizeof(struct in6_addr)))
420 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
422 r = sd_bus_message_read(message, "i", &ifindex);
426 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
428 key.class = DNS_CLASS_IN;
429 key.type = DNS_TYPE_PTR;
430 r = dns_name_reverse(family, d, &key.name);
434 r = dns_query_new(m, &q, &key, 1);
438 q->request = sd_bus_message_ref(message);
439 q->request_family = family;
440 memcpy(&q->request_address, d, sz);
441 q->complete = bus_method_resolve_address_complete;
443 r = dns_query_start(q);
452 static const sd_bus_vtable resolve_vtable[] = {
453 SD_BUS_VTABLE_START(0),
454 SD_BUS_METHOD("ResolveHostname", "sy", "a(yayi)", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
455 SD_BUS_METHOD("ResolveAddress", "yayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
459 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
460 Manager *m = userdata;
465 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
467 manager_connect_bus(m);
471 int manager_connect_bus(Manager *m) {
479 r = sd_bus_default_system(&m->bus);
481 /* We failed to connect? Yuck, we must be in early
482 * boot. Let's try in 5s again. As soon as we have
483 * kdbus we can stop doing this... */
485 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
487 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);
489 log_error("Failed to install bus reconnect time event: %s", strerror(-r));
496 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
498 log_error("Failed to register object: %s", strerror(-r));
502 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
504 log_error("Failed to register name: %s", strerror(-r));
508 r = sd_bus_attach_event(m->bus, m->event, 0);
510 log_error("Failed to attach bus to event loop: %s", strerror(-r));