resolved-bus.c revision 4afd3348c7506dd1d36305b7bcb9feb8952b9d6b
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ad867662936a4c7ab2c7116d804c272338801231Lennart Poetteringstatic int reply_query_state(DnsQuery *q) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = in_addr_to_string(q->request_family, &q->request_address, &ip);
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering name = dns_question_first_name(q->question);
309e9d86f0e7f9c5f0a2a09227bdfdb3174d4436Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
818f766b12e025683cf4fed12b3da2a025bb0b31Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
818f766b12e025683cf4fed12b3da2a025bb0b31Lennart Poettering return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *rc, *n;
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering char p[3]; /* the rcode is 4 bits long */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering rc = dns_rcode_to_string(q->answer_rcode);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering return sd_bus_reply_method_error(q->request, &error);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poetteringstatic int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_open_container(reply, 'r', "iiay");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_append(reply, "i", ifindex);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering r = sd_bus_message_append(reply, "i", AF_INET);
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering } else if (rr->key->type == DNS_TYPE_AAAA) {
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering r = sd_bus_message_append(reply, "i", AF_INET6);
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering r = sd_bus_message_close_container(reply);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poetteringstatic void bus_method_resolve_hostname_complete(DnsQuery *q) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (q->state != DNS_TRANSACTION_SUCCESS) {
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r > 0) /* This was a cname, and the query was restarted. */
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_bus_message_new_method_return(q->request, &reply);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(iiay)");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question));
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_bus_message_close_container(reply);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Return the precise spelling and uppercasing and CNAME target reported by the server */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_bus_send(q->manager->bus, reply, NULL);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to send hostname reply: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_bus_reply_method_errno(q->request, r, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
51323288fc628a5cac50914df915545d685b793eLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
51323288fc628a5cac50914df915545d685b793eLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering assert_cc(sizeof(int) == sizeof(int32_t));
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart 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);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_question_new_address(&question, family, hostname);
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = dns_query_new(m, &q, question, ifindex, flags);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering q->request = sd_bus_message_ref(message);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering q->complete = bus_method_resolve_hostname_complete;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void bus_method_resolve_address_complete(DnsQuery *q) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (q->state != DNS_TRANSACTION_SUCCESS) {
039a8725fdff1d71e9efd28f27741601c5b4235cLennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
95d46fcaa4f27bc5e675e8de39ab3acc4732e39bTom Gundersen if (r > 0) /* This was a cname, and the query was restarted. */
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_bus_message_new_method_return(q->request, &reply);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(is)");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering in_addr_to_string(q->request_family, &q->request_address, &ip);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_bus_message_close_container(reply);
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_bus_send(q->manager->bus, reply, NULL);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to send address reply: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_bus_reply_method_errno(q->request, r, NULL);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *d;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering assert_cc(sizeof(int) == sizeof(int32_t));
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_bus_message_read(message, "ii", &ifindex, &family);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read_array(message, 'y', &d, &sz);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_bus_message_read(message, "t", &flags);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = check_ifindex_flags(ifindex, &flags, 0, error);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_question_new_reverse(&question, family, d);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering q->request = sd_bus_message_ref(message);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering q->complete = bus_method_resolve_address_complete;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_open_container(m, 'r', "iqqay");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_append_array(m, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return sd_bus_message_close_container(m);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic void bus_method_resolve_record_complete(DnsQuery *q) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (q->state != DNS_TRANSACTION_SUCCESS) {
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r > 0) /* Following a CNAME */
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = sd_bus_message_new_method_return(q->request, &reply);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = bus_message_append_rr(reply, rr, ifindex);
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_question_first_name(q->question));
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = sd_bus_message_close_container(reply);
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = sd_bus_send(q->manager->bus, reply, NULL);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to send record reply: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_bus_reply_method_errno(q->request, r, NULL);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering assert_cc(sizeof(int) == sizeof(int32_t));
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
7b9f7afcc04e80b77a2567b0750aa2cd03c1a1cdLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = check_ifindex_flags(ifindex, &flags, 0, error);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering key = dns_resource_key_new(class, type, name);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering q->request = sd_bus_message_ref(message);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering q->complete = bus_method_resolve_record_complete;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* First, let's see if we could find an appropriate A or AAAA
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * record for the SRV record */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (aux->state != DNS_TRANSACTION_SUCCESS)
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = dns_name_equal(dns_question_first_name(aux->question), rr->srv.name);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(aux->question, zz, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_open_container(reply, 'a', "(iiay)");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (aux->state != DNS_TRANSACTION_SUCCESS)
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = dns_name_equal(dns_question_first_name(aux->question), rr->srv.name);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(aux->question, zz, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_close_container(reply);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Note that above we appended the hostname as encoded in the
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * SRV, and here the canonical hostname this maps to. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_close_container(reply);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_append_array(reply, 'y', i->data, i->length);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic void resolve_service_all_complete(DnsQuery *q) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering unsigned added = false;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* If an auxiliary query is still pending, let's wait */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* We can only return one error, hence pick the last error we encountered */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (bad->state == DNS_TRANSACTION_SUCCESS) {
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(bad->question));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_new_method_return(q->request, &reply);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)");
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r == 0) /* not an SRV record */
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_close_container(reply);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_open_container(reply, 'a', "ay");
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_close_container(reply);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_send(q->manager->bus, reply, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error_errno(r, "Failed to send service reply: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_bus_reply_method_errno(q->request, r, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic void resolve_service_hostname_complete(DnsQuery *q) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (q->state != DNS_TRANSACTION_SUCCESS) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering resolve_service_all_complete(q->auxiliary_for);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r > 0) /* This was a cname, and the query was restarted. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* This auxiliary lookup is finished or failed, let's see if all are finished now. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering resolve_service_all_complete(q->auxiliary_for);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* OK, we found an SRV record for the service. Let's resolve
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * the hostname included in it */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_question_new_address(&question, q->request_family, rr->srv.name);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_query_new(q->manager, &aux, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering aux->complete = resolve_service_hostname_complete;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Too many auxiliary lookups? If so, don't complain,
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * let's just not add this one, we already have more
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * than enough */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Note that auxiliary queries do not track the original bus
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * client, only the primary request does that. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic void bus_method_resolve_service_complete(DnsQuery *q) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (q->state != DNS_TRANSACTION_SUCCESS) {
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (r > 0) /* This was a cname, and the query was restarted. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = resolve_service_hostname(q, rr, ifindex);
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Maybe we are already finished? check now... */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error_errno(r, "Failed to send service reply: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_bus_reply_method_errno(q->request, r, NULL);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering const char *name, *type, *domain, *joined;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering assert_cc(sizeof(int) == sizeof(int32_t));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name);
7e8131e9c6c150732503899a092206578fdc13deLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* If the type is specified, we generate the full domain name to look up ourselves */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_service_join(name, type, domain, &n);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* If no type is specified, we assume the domain
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * contains the full domain name to lookup already */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_question_new_service(&question, joined, !(flags & SD_RESOLVED_NO_TXT));
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering q->request = sd_bus_message_ref(message);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering q->complete = bus_method_resolve_service_complete;
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poetteringstatic int append_dns_server(sd_bus_message *reply, DnsServer *s) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_open_container(reply, 'r', "iiay");
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_append(reply, "ii", s->link ? s->link->ifindex : 0, s->family);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family));
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering return sd_bus_message_close_container(reply);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering unsigned c = 0;
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_open_container(reply, 'a', "(iiay)");
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering LIST_FOREACH(servers, s, m->dns_servers) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering LIST_FOREACH(servers, s, l->dns_servers) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering return sd_bus_message_close_container(reply);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poetteringstatic int bus_property_get_search_domains(
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_open_container(reply, 'a', "(is)");
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering LIST_FOREACH(domains, d, m->search_domains) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_append(reply, "(is)", 0, d->name);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering LIST_FOREACH(domains, d, l->search_domains) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering r = sd_bus_message_append(reply, "is", l->ifindex, d->name);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering return sd_bus_message_close_container(reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic const sd_bus_vtable resolve_vtable[] = {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering SD_BUS_PROPERTY("DNSServers", "a(iiay)", bus_property_get_dns_servers, 0, 0),
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering SD_BUS_PROPERTY("SearchDomains", "a(is)", bus_property_get_search_domains, 0, 0),
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering r = sd_bus_message_read(message, "b", &b);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering log_debug("Coming back from suspend, verifying all RRs...");
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... */
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
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);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to install bus reconnect time event: %m");
4d1cf1e229c9bdbc44778c0863eaad918f5724e7Lennart Poettering r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to register object: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to register name: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return log_error_errno(r, "Failed to attach bus to event loop: %m");
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering "type='signal',"
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering "sender='org.freedesktop.login1',"
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering "interface='org.freedesktop.login1.Manager',"
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering "member='PrepareForSleep',"
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to add match for PrepareForSleep: %m");