chiark / gitweb /
resolved: support for TCP DNS queries
[elogind.git] / src / resolve / resolved-bus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include "bus-errors.h"
23 #include "bus-util.h"
24
25 #include "resolved.h"
26 #include "resolved-dns-domain.h"
27
28 static int reply_query_state(DnsQuery *q) {
29         _cleanup_free_ char *ip = NULL;
30         const char *name;
31         int r;
32
33         if (q->request_hostname)
34                 name = q->request_hostname;
35         else {
36                 r = in_addr_to_string(q->request_family, &q->request_address, &ip);
37                 if (r < 0)
38                         return r;
39
40                 name = ip;
41         }
42
43         switch (q->state) {
44
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");
47
48         case DNS_QUERY_TIMEOUT:
49                 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
50
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");
53
54         case DNS_QUERY_RESOURCES:
55                 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
56
57         case DNS_QUERY_INVALID_REPLY:
58                 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
59
60         case DNS_QUERY_FAILURE: {
61                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
62
63                 assert(q->received);
64
65                 if (DNS_PACKET_RCODE(q->received) == DNS_RCODE_NXDOMAIN)
66                         sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
67                 else {
68                         const char *rc, *n;
69                         char p[3]; /* the rcode is 4 bits long */
70
71                         rc = dns_rcode_to_string(DNS_PACKET_RCODE(q->received));
72                         if (!rc) {
73                                 sprintf(p, "%i", DNS_PACKET_RCODE(q->received));
74                                 rc = p;
75                         }
76
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);
79                 }
80
81                 return sd_bus_reply_method_error(q->request, &error);
82         }
83
84         case DNS_QUERY_NULL:
85         case DNS_QUERY_SENT:
86         case DNS_QUERY_SUCCESS:
87                 assert_not_reached("Impossible state");
88         }
89 }
90
91 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
92         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
93         unsigned i, n, added = 0;
94         int r;
95
96         assert(q);
97
98         if (q->state != DNS_QUERY_SUCCESS) {
99                 r = reply_query_state(q);
100                 goto finish;
101         }
102
103         assert(q->received);
104
105         r = dns_packet_skip_question(q->received);
106         if (r < 0)
107                 goto parse_fail;
108
109         r = sd_bus_message_new_method_return(q->request, &reply);
110         if (r < 0)
111                 goto finish;
112
113         r = sd_bus_message_open_container(reply, 'a', "(yayi)");
114         if (r < 0)
115                 goto finish;
116
117         n = DNS_PACKET_ANCOUNT(q->received) +
118             DNS_PACKET_NSCOUNT(q->received) +
119             DNS_PACKET_ARCOUNT(q->received);
120         for (i = 0; i < n; i++) {
121                 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
122
123                 r = dns_packet_read_rr(q->received, &rr, NULL);
124                 if (r < 0)
125                         goto parse_fail;
126
127                 if (rr->key.class != DNS_CLASS_IN)
128                         continue;
129
130                 if (!(q->request_family != AF_INET6 && rr->key.type == DNS_TYPE_A) &&
131                     !(q->request_family != AF_INET && rr->key.type == DNS_TYPE_AAAA))
132                         continue;
133
134                 if (!dns_name_equal(rr->key.name, q->request_hostname))
135                         continue;
136
137                 r = sd_bus_message_open_container(reply, 'r', "yayi");
138                 if (r < 0)
139                         goto finish;
140
141                 if (rr->key.type == DNS_TYPE_A) {
142                         r = sd_bus_message_append(reply, "y", AF_INET);
143                         if (r < 0)
144                                 goto finish;
145
146                         r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
147                 } else {
148                         r = sd_bus_message_append(reply, "y", AF_INET6);
149                         if (r < 0)
150                                 goto finish;
151
152                         r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
153                 }
154                 if (r < 0)
155                         goto finish;
156
157                 r = sd_bus_message_append(reply, "i", q->received->ifindex);
158                 if (r < 0)
159                         goto finish;
160
161                 r = sd_bus_message_close_container(reply);
162                 if (r < 0)
163                         goto finish;
164
165                 added ++;
166         }
167
168         if (added <= 0) {
169                 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have RR of this type", q->request_hostname);
170                 goto finish;
171         }
172
173         r = sd_bus_message_close_container(reply);
174         if (r < 0)
175                 goto finish;
176
177         r = sd_bus_send(q->manager->bus, reply, NULL);
178         goto finish;
179
180 parse_fail:
181         r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
182
183 finish:
184         if (r < 0)
185                 log_error("Failed to send bus reply: %s", strerror(-r));
186
187         dns_query_free(q);
188 }
189
190 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
191         Manager *m = userdata;
192         const char *hostname;
193         uint8_t family;
194         DnsResourceKey keys[2];
195         DnsQuery *q;
196         unsigned n = 0;
197         int r;
198
199         assert(bus);
200         assert(message);
201         assert(m);
202
203         r = sd_bus_message_read(message, "sy", &hostname, &family);
204         if (r < 0)
205                 return r;
206
207         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
208                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
209
210         if (!hostname_is_valid(hostname))
211                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
212
213         if (family != AF_INET6) {
214                 keys[n].class = DNS_CLASS_IN;
215                 keys[n].type = DNS_TYPE_A;
216                 keys[n].name = (char*) hostname;
217                 n++;
218         }
219
220         if (family != AF_INET) {
221                 keys[n].class = DNS_CLASS_IN;
222                 keys[n].type = DNS_TYPE_AAAA;
223                 keys[n].name = (char*) hostname;
224                 n++;
225         }
226
227         r = dns_query_new(m, &q, keys, n);
228         if (r < 0)
229                 return r;
230
231         q->request = sd_bus_message_ref(message);
232         q->request_family = family;
233         q->request_hostname = hostname;
234         q->complete = bus_method_resolve_hostname_complete;
235
236         r = dns_query_start(q);
237         if (r < 0) {
238                 dns_query_free(q);
239                 return r;
240         }
241
242         return 1;
243 }
244
245 static void bus_method_resolve_address_complete(DnsQuery *q) {
246         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
247         unsigned i, n, added = 0;
248         _cleanup_free_ char *reverse = NULL;
249         int r;
250
251         assert(q);
252
253         if (q->state != DNS_QUERY_SUCCESS) {
254                 r = reply_query_state(q);
255                 goto finish;
256         }
257
258         assert(q->received);
259
260         r = dns_name_reverse(q->request_family, &q->request_address, &reverse);
261         if (r < 0)
262                 goto finish;
263
264         r = dns_packet_skip_question(q->received);
265         if (r < 0)
266                 goto parse_fail;
267
268         r = sd_bus_message_new_method_return(q->request, &reply);
269         if (r < 0)
270                 goto finish;
271
272         r = sd_bus_message_open_container(reply, 'a', "s");
273         if (r < 0)
274                 goto finish;
275
276         n = DNS_PACKET_ANCOUNT(q->received) +
277             DNS_PACKET_NSCOUNT(q->received) +
278             DNS_PACKET_ARCOUNT(q->received);
279
280         for (i = 0; i < n; i++) {
281                 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
282
283                 r = dns_packet_read_rr(q->received, &rr, NULL);
284                 if (r < 0)
285                         goto parse_fail;
286
287                 if (rr->key.class != DNS_CLASS_IN)
288                         continue;
289                 if (rr->key.type != DNS_TYPE_PTR)
290                         continue;
291                 if (!dns_name_equal(rr->key.name, reverse))
292                         continue;
293
294                 r = sd_bus_message_append(reply, "s", rr->ptr.name);
295                 if (r < 0)
296                         goto finish;
297
298                 added ++;
299         }
300
301         if (added <= 0) {
302                 _cleanup_free_ char *ip = NULL;
303
304                 in_addr_to_string(q->request_family, &q->request_address, &ip);
305
306                 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have RR of this type", ip);
307                 goto finish;
308         }
309
310         r = sd_bus_message_close_container(reply);
311         if (r < 0)
312                 goto finish;
313
314         r = sd_bus_send(q->manager->bus, reply, NULL);
315         goto finish;
316
317 parse_fail:
318         r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
319
320 finish:
321         if (r < 0)
322                 log_error("Failed to send bus reply: %s", strerror(-r));
323
324         dns_query_free(q);
325 }
326
327 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
328         _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
329         Manager *m = userdata;
330         uint8_t family;
331         const void *d;
332         int ifindex;
333         DnsQuery *q;
334         size_t sz;
335         int r;
336
337         assert(bus);
338         assert(message);
339         assert(m);
340
341         r = sd_bus_message_read(message, "y", &family);
342         if (r < 0)
343                 return r;
344
345         if (!IN_SET(family, AF_INET, AF_INET6))
346                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
347
348         r = sd_bus_message_read_array(message, 'y', &d, &sz);
349         if (r < 0)
350                 return r;
351
352         if ((family == AF_INET && sz != sizeof(struct in_addr)) ||
353             (family == AF_INET6 && sz != sizeof(struct in6_addr)))
354                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
355
356         r = sd_bus_message_read(message, "i", &ifindex);
357         if (r < 0)
358                 return r;
359         if (ifindex < 0)
360                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
361
362         key.class = DNS_CLASS_IN;
363         key.type = DNS_TYPE_PTR;
364         r = dns_name_reverse(family, d, &key.name);
365         if (r < 0)
366                 return r;
367
368         r = dns_query_new(m, &q, &key, 1);
369         if (r < 0)
370                 return r;
371
372         q->request = sd_bus_message_ref(message);
373         q->request_family = family;
374         memcpy(&q->request_address, d, sz);
375         q->complete = bus_method_resolve_address_complete;
376
377         r = dns_query_start(q);
378         if (r < 0) {
379                 dns_query_free(q);
380                 return r;
381         }
382
383         return 1;
384 }
385
386 static const sd_bus_vtable resolve_vtable[] = {
387         SD_BUS_VTABLE_START(0),
388         SD_BUS_METHOD("ResolveHostname", "sy", "a(yayi)", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
389         SD_BUS_METHOD("ResolveAddress", "yayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
390         SD_BUS_VTABLE_END,
391 };
392
393 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
394         Manager *m = userdata;
395
396         assert(s);
397         assert(m);
398
399         m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
400
401         manager_connect_bus(m);
402         return 0;
403 }
404
405 int manager_connect_bus(Manager *m) {
406         int r;
407
408         assert(m);
409
410         if (m->bus)
411                 return 0;
412
413         r = sd_bus_default_system(&m->bus);
414         if (r < 0) {
415                 /* We failed to connect? Yuck, we must be in early
416                  * boot. Let's try in 5s again. As soon as we have
417                  * kdbus we can stop doing this... */
418
419                 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
420
421                 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);
422                 if (r < 0) {
423                         log_error("Failed to install bus reconnect time event: %s", strerror(-r));
424                         return r;
425                 }
426
427                 return 0;
428         }
429
430         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
431         if (r < 0) {
432                 log_error("Failed to register object: %s", strerror(-r));
433                 return r;
434         }
435
436         r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
437         if (r < 0) {
438                 log_error("Failed to register name: %s", strerror(-r));
439                 return r;
440         }
441
442         r = sd_bus_attach_event(m->bus, m->event, 0);
443         if (r < 0) {
444                 log_error("Failed to attach bus to event loop: %s", strerror(-r));
445                 return r;
446         }
447
448         return 0;
449 }