X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Fresolve%2Fresolved-bus.c;fp=src%2Fresolve%2Fresolved-bus.c;h=0000000000000000000000000000000000000000;hb=2dd57213e1114c1e034e52b7ff8eaeaee752d9f3;hp=fba2afcc8d7838c6366686dbb8fde1d9d7b37ce6;hpb=1dcca8e5fe679b21a7203d6e35d58aa7aa83bbe1;p=elogind.git diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c deleted file mode 100644 index fba2afcc8..000000000 --- a/src/resolve/resolved-bus.c +++ /dev/null @@ -1,755 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "bus-common-errors.h" -#include "bus-util.h" - -#include "resolved-dns-domain.h" -#include "resolved-bus.h" -#include "resolved-def.h" - -static int reply_query_state(DnsQuery *q) { - _cleanup_free_ char *ip = NULL; - const char *name; - int r; - - if (q->request_hostname) - name = q->request_hostname; - else { - r = in_addr_to_string(q->request_family, &q->request_address, &ip); - if (r < 0) - return r; - - name = ip; - } - - switch (q->state) { - - case DNS_TRANSACTION_NO_SERVERS: - return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - - case DNS_TRANSACTION_TIMEOUT: - return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out"); - - case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED: - return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed"); - - case DNS_TRANSACTION_INVALID_REPLY: - return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply"); - - case DNS_TRANSACTION_RESOURCES: - return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources"); - - case DNS_TRANSACTION_ABORTED: - return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted"); - - case DNS_TRANSACTION_FAILURE: { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - if (q->answer_rcode == DNS_RCODE_NXDOMAIN) - sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name); - else { - const char *rc, *n; - char p[3]; /* the rcode is 4 bits long */ - - rc = dns_rcode_to_string(q->answer_rcode); - if (!rc) { - sprintf(p, "%i", q->answer_rcode); - rc = p; - } - - n = strjoina(_BUS_ERROR_DNS, rc); - sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc); - } - - return sd_bus_reply_method_error(q->request, &error); - } - - case DNS_TRANSACTION_NULL: - case DNS_TRANSACTION_PENDING: - case DNS_TRANSACTION_SUCCESS: - default: - assert_not_reached("Impossible state"); - } -} - -static int append_address(sd_bus_message *reply, DnsResourceRecord *rr) { - int r; - - assert(reply); - assert(rr); - - r = sd_bus_message_open_container(reply, 'r', "iay"); - if (r < 0) - return r; - - if (rr->key->type == DNS_TYPE_A) { - r = sd_bus_message_append(reply, "i", AF_INET); - if (r < 0) - return r; - - r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr)); - - } else if (rr->key->type == DNS_TYPE_AAAA) { - r = sd_bus_message_append(reply, "i", AF_INET6); - if (r < 0) - return r; - - r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr)); - } else - return -EAFNOSUPPORT; - - if (r < 0) - return r; - - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; - - return 0; -} - -static void bus_method_resolve_hostname_complete(DnsQuery *q) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; - int r; - - assert(q); - - if (q->state != DNS_TRANSACTION_SUCCESS) { - r = reply_query_state(q); - goto finish; - } - - r = sd_bus_message_new_method_return(q->request, &reply); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "i", q->answer_ifindex); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(reply, 'a', "(iay)"); - if (r < 0) - goto finish; - - if (q->answer) { - answer = dns_answer_ref(q->answer); - - for (i = 0; i < answer->n_rrs; i++) { - r = dns_question_matches_rr(q->question, answer->rrs[i]); - if (r < 0) - goto finish; - if (r == 0) { - /* Hmm, if this is not an address record, - maybe it's a cname? If so, remember this */ - r = dns_question_matches_cname(q->question, answer->rrs[i]); - if (r < 0) - goto finish; - if (r > 0) - cname = dns_resource_record_ref(answer->rrs[i]); - - continue; - } - - r = append_address(reply, answer->rrs[i]); - if (r < 0) - goto finish; - - if (!canonical) - canonical = dns_resource_record_ref(answer->rrs[i]); - - added ++; - } - } - - if (added == 0) { - if (!cname) { - 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); - goto finish; - } - - /* This has a cname? Then update the query with the - * new cname. */ - r = dns_query_cname_redirect(q, cname->cname.name); - if (r < 0) { - if (r == -ELOOP) - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname); - else - r = sd_bus_reply_method_errno(q->request, -r, NULL); - - goto finish; - } - - /* Before we restart the query, let's see if any of - * the RRs we already got already answers our query */ - for (i = 0; i < answer->n_rrs; i++) { - r = dns_question_matches_rr(q->question, answer->rrs[i]); - if (r < 0) - goto finish; - if (r == 0) - continue; - - r = append_address(reply, answer->rrs[i]); - if (r < 0) - goto finish; - - if (!canonical) - canonical = dns_resource_record_ref(answer->rrs[i]); - - added++; - } - - // what about the cache? - - /* If we didn't find anything, then let's restart the - * query, this time with the cname */ - if (added <= 0) { - r = dns_query_go(q); - if (r == -ESRCH) { - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - goto finish; - } - if (r < 0) { - r = sd_bus_reply_method_errno(q->request, -r, NULL); - goto finish; - } - - return; - } - } - - r = sd_bus_message_close_container(reply); - if (r < 0) - goto finish; - - /* Return the precise spelling and uppercasing reported by the server */ - assert(canonical); - r = sd_bus_message_append(reply, "st", DNS_RESOURCE_KEY_NAME(canonical->key), SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); - if (r < 0) - goto finish; - - r = sd_bus_send(q->manager->bus, reply, NULL); - -finish: - if (r < 0) { - log_error_errno(r, "Failed to send hostname reply: %m"); - sd_bus_reply_method_errno(q->request, -r, NULL); - } - - dns_query_free(q); -} - -static int check_ifindex_flags(int ifindex, uint64_t *flags, sd_bus_error *error) { - assert(flags); - - if (ifindex < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); - - if (*flags & ~SD_RESOLVED_FLAGS_ALL) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); - - if (*flags == 0) - *flags = SD_RESOLVED_FLAGS_DEFAULT; - - return 0; -} - -static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; - Manager *m = userdata; - const char *hostname; - int family, ifindex; - uint64_t flags; - DnsQuery *q; - int r; - - assert(bus); - assert(message); - assert(m); - - r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags); - if (r < 0) - return r; - - if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - - r = dns_name_normalize(hostname, NULL); - if (r < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); - - r = check_ifindex_flags(ifindex, &flags, error); - if (r < 0) - return r; - - question = dns_question_new(family == AF_UNSPEC ? 2 : 1); - if (!question) - return -ENOMEM; - - if (family != AF_INET6) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - - key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname); - if (!key) - return -ENOMEM; - - r = dns_question_add(question, key); - if (r < 0) - return r; - } - - if (family != AF_INET) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - - key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname); - if (!key) - return -ENOMEM; - - r = dns_question_add(question, key); - if (r < 0) - return r; - } - - r = dns_query_new(m, &q, question, ifindex, flags); - if (r < 0) - return r; - - q->request = sd_bus_message_ref(message); - q->request_family = family; - q->request_hostname = hostname; - q->complete = bus_method_resolve_hostname_complete; - - r = dns_query_bus_track(q, bus, message); - if (r < 0) - return r; - - r = dns_query_go(q); - if (r < 0) { - dns_query_free(q); - - if (r == -ESRCH) - sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - - return r; - } - - return 1; -} - -static void bus_method_resolve_address_complete(DnsQuery *q) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; - int r; - - assert(q); - - if (q->state != DNS_TRANSACTION_SUCCESS) { - r = reply_query_state(q); - goto finish; - } - - r = sd_bus_message_new_method_return(q->request, &reply); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "i", q->answer_ifindex); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(reply, 'a', "s"); - if (r < 0) - goto finish; - - if (q->answer) { - answer = dns_answer_ref(q->answer); - - for (i = 0; i < answer->n_rrs; i++) { - r = dns_question_matches_rr(q->question, answer->rrs[i]); - if (r < 0) - goto finish; - if (r == 0) - continue; - - r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name); - if (r < 0) - goto finish; - - added ++; - } - } - - if (added == 0) { - _cleanup_free_ char *ip = NULL; - - in_addr_to_string(q->request_family, &q->request_address, &ip); - - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip); - goto finish; - } - - r = sd_bus_message_close_container(reply); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); - if (r < 0) - goto finish; - - r = sd_bus_send(q->manager->bus, reply, NULL); - -finish: - if (r < 0) { - log_error_errno(r, "Failed to send address reply: %m"); - sd_bus_reply_method_errno(q->request, -r, NULL); - } - - dns_query_free(q); -} - -static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; - _cleanup_free_ char *reverse = NULL; - Manager *m = userdata; - int family, ifindex; - uint64_t flags; - const void *d; - DnsQuery *q; - size_t sz; - int r; - - assert(bus); - assert(message); - assert(m); - - r = sd_bus_message_read(message, "ii", &ifindex, &family); - if (r < 0) - return r; - - if (!IN_SET(family, AF_INET, AF_INET6)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - - r = sd_bus_message_read_array(message, 'y', &d, &sz); - if (r < 0) - return r; - - if (sz != FAMILY_ADDRESS_SIZE(family)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); - - r = sd_bus_message_read(message, "t", &flags); - if (r < 0) - return r; - - r = check_ifindex_flags(ifindex, &flags, error); - if (r < 0) - return r; - - r = dns_name_reverse(family, d, &reverse); - if (r < 0) - return r; - - question = dns_question_new(1); - if (!question) - return -ENOMEM; - - key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse); - if (!key) - return -ENOMEM; - - reverse = NULL; - - r = dns_question_add(question, key); - if (r < 0) - return r; - - r = dns_query_new(m, &q, question, ifindex, flags); - if (r < 0) - return r; - - q->request = sd_bus_message_ref(message); - q->request_family = family; - memcpy(&q->request_address, d, sz); - q->complete = bus_method_resolve_address_complete; - - r = dns_query_bus_track(q, bus, message); - if (r < 0) - return r; - - r = dns_query_go(q); - if (r < 0) { - dns_query_free(q); - - if (r == -ESRCH) - sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - - return r; - } - - return 1; -} - -static void bus_method_resolve_record_complete(DnsQuery *q) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; - int r; - - assert(q); - - if (q->state != DNS_TRANSACTION_SUCCESS) { - r = reply_query_state(q); - goto finish; - } - - r = sd_bus_message_new_method_return(q->request, &reply); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "i", q->answer_ifindex); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(reply, 'a', "(qqay)"); - if (r < 0) - goto finish; - - if (q->answer) { - answer = dns_answer_ref(q->answer); - - for (i = 0; i < answer->n_rrs; i++) { - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - size_t start; - - r = dns_question_matches_rr(q->question, answer->rrs[i]); - if (r < 0) - goto finish; - if (r == 0) - continue; - - r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); - if (r < 0) - goto finish; - - r = dns_packet_append_rr(p, answer->rrs[i], &start); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(reply, 'r', "qqay"); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "qq", answer->rrs[i]->key->class, answer->rrs[i]->key->type); - if (r < 0) - goto finish; - - r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start); - if (r < 0) - goto finish; - - r = sd_bus_message_close_container(reply); - if (r < 0) - goto finish; - - added ++; - } - } - - if (added <= 0) { - 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); - goto finish; - } - - r = sd_bus_message_close_container(reply); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); - if (r < 0) - goto finish; - - r = sd_bus_send(q->manager->bus, reply, NULL); - -finish: - if (r < 0) { - log_error_errno(r, "Failed to send record reply: %m"); - sd_bus_reply_method_errno(q->request, -r, NULL); - } - - dns_query_free(q); -} - -static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; - Manager *m = userdata; - uint16_t class, type; - const char *name; - int r, ifindex; - uint64_t flags; - DnsQuery *q; - - assert(bus); - assert(message); - assert(m); - - r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags); - if (r < 0) - return r; - - r = dns_name_normalize(name, NULL); - if (r < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name); - - r = check_ifindex_flags(ifindex, &flags, error); - if (r < 0) - return r; - - question = dns_question_new(1); - if (!question) - return -ENOMEM; - - key = dns_resource_key_new(class, type, name); - if (!key) - return -ENOMEM; - - r = dns_question_add(question, key); - if (r < 0) - return r; - - r = dns_query_new(m, &q, question, ifindex, flags); - if (r < 0) - return r; - - q->request = sd_bus_message_ref(message); - q->request_hostname = name; - q->complete = bus_method_resolve_record_complete; - - r = dns_query_bus_track(q, bus, message); - if (r < 0) - return r; - - r = dns_query_go(q); - if (r < 0) { - dns_query_free(q); - - if (r == -ESRCH) - sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); - - return r; - } - - return 1; -} - -static const sd_bus_vtable resolve_vtable[] = { - SD_BUS_VTABLE_START(0), - SD_BUS_METHOD("ResolveHostname", "isit", "ia(iay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ResolveAddress", "iiayt", "iast", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ResolveRecord", "isqqt", "ia(qqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END, -}; - -static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) { - Manager *m = userdata; - - assert(s); - assert(m); - - m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source); - - manager_connect_bus(m); - return 0; -} - -static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { - Manager *m = userdata; - int b, r; - - assert(bus); - assert(bus); - - r = sd_bus_message_read(message, "b", &b); - if (r < 0) { - log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m"); - return 0; - } - - if (b) - return 0; - - log_debug("Coming back from suspend, verifying all RRs..."); - - manager_verify_all(m); - return 0; -} - -int manager_connect_bus(Manager *m) { - int r; - - assert(m); - - if (m->bus) - return 0; - - r = sd_bus_default_system(&m->bus); - if (r < 0) { - /* We failed to connect? Yuck, we must be in early - * boot. Let's try in 5s again. As soon as we have - * kdbus we can stop doing this... */ - - log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m"); - - 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); - if (r < 0) - return log_error_errno(r, "Failed to install bus reconnect time event: %m"); - - return 0; - } - - r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m); - if (r < 0) - return log_error_errno(r, "Failed to register object: %m"); - - r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0); - if (r < 0) - return log_error_errno(r, "Failed to register name: %m"); - - r = sd_bus_attach_event(m->bus, m->event, 0); - if (r < 0) - return log_error_errno(r, "Failed to attach bus to event loop: %m"); - - r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot, - "type='signal'," - "sender='org.freedesktop.login1'," - "interface='org.freedesktop.login1.Manager'," - "member='PrepareForSleep'," - "path='/org/freedesktop/login1'", - match_prepare_for_sleep, - m); - if (r < 0) - log_error_errno(r, "Failed to add match for PrepareForSleep: %m"); - - return 0; -}