resolved-bus.c revision 3339cb71d44c5198f9546f113674f06dc7b01a6f
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen This file is part of systemd.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Copyright 2014 Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is free software; you can redistribute it and/or modify it
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen under the terms of the GNU Lesser General Public License as published by
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen (at your option) any later version.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is distributed in the hope that it will be useful, but
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Lesser General Public License for more details.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen You should have received a copy of the GNU Lesser General Public License
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = in_addr_to_string(q->request_family, &q->request_address, &ip);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *rc, *n;
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering char p[3]; /* the rcode is 4 bits long */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering rc = dns_rcode_to_string(q->answer_rcode);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_error(q->request, &error);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_open_container(reply, 'r', "iayi");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append(reply, "i", AF_INET);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering } else if (rr->key->type == DNS_TYPE_AAAA) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append(reply, "i", AF_INET6);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append(reply, "i", ifindex);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_close_container(reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void bus_method_resolve_hostname_complete(DnsQuery *q) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned added = 0, i;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_new_method_return(q->request, &reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(iayi)");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_question_matches_rr(q->question, answer->rrs[i]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Hmm, if this is not an address record,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering maybe it's a cname? If so, remember this */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_question_matches_cname(q->question, answer->rrs[i]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering cname = dns_resource_record_ref(answer->rrs[i]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = append_address(reply, answer->rrs[i], ifindex);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering canonical = dns_resource_record_ref(answer->rrs[i]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering 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);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* This has a cname? Then update the query with the
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * new cname. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_query_cname_redirect(q, cname->cname.name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_reply_method_errno(q->request, -r, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Before we restart the query, let's see if any of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * the RRs we already got already answers our query */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_question_matches_rr(q->question, answer->rrs[i]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = append_address(reply, answer->rrs[i], ifindex);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering canonical = dns_resource_record_ref(answer->rrs[i]);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* If we didn't find anything, then let's restart the
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * query, this time with the cname */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_reply_method_errno(q->request, -r, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_close_container(reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Return the precise spelling and uppercasing reported by the server */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append(reply, "s", DNS_RESOURCE_KEY_NAME(canonical->key));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_send(q->manager->bus, reply, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to send bus reply: %s", strerror(-r));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read(message, "si", &hostname, &family);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering q->request = sd_bus_message_ref(message);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering q->complete = bus_method_resolve_hostname_complete;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic void bus_method_resolve_address_complete(DnsQuery *q) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering unsigned added = 0, i;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_new_method_return(q->request, &reply);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "s");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_question_matches_rr(q->question, answer->rrs[i]);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering in_addr_to_string(q->request_family, &q->request_address, &ip);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_close_container(reply);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_send(q->manager->bus, reply, NULL);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering log_error("Failed to send bus reply: %s", strerror(-r));
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering const void *d;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_message_read(message, "i", &family);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_message_read_array(message, 'y', &d, &sz);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_message_read(message, "i", &ifindex);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = dns_name_reverse(family, d, &reverse);
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering q->request = sd_bus_message_ref(message);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering q->complete = bus_method_resolve_address_complete;
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic const sd_bus_vtable resolve_vtable[] = {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering SD_BUS_METHOD("ResolveHostname", "si", "a(iayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering SD_BUS_METHOD("ResolveAddress", "iayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* We failed to connect? Yuck, we must be in early
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * boot. Let's try in 5s again. As soon as we have
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * kdbus we can stop doing this... */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering 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);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to install bus reconnect time event: %s", strerror(-r));
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering log_error("Failed to register object: %s", strerror(-r));
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering log_error("Failed to register name: %s", strerror(-r));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_attach_event(m->bus, m->event, 0);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to attach bus to event loop: %s", strerror(-r));