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