chiark / gitweb /
resolved: remove unused variable
[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, "No appropriate name servers or networks for name 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                 int rcode;
63
64                 rcode = dns_query_get_rcode(q);
65                 if (rcode < 0)
66                         return rcode;
67
68                 if (rcode == DNS_RCODE_NXDOMAIN)
69                         sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
70                 else {
71                         const char *rc, *n;
72                         char p[3]; /* the rcode is 4 bits long */
73
74                         rc = dns_rcode_to_string(rcode);
75                         if (!rc) {
76                                 sprintf(p, "%i", rcode);
77                                 rc = p;
78                         }
79
80                         n = strappenda(_BUS_ERROR_DNS, rc);
81                         sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
82                 }
83
84                 return sd_bus_reply_method_error(q->request, &error);
85         }
86
87         case DNS_QUERY_NULL:
88         case DNS_QUERY_PENDING:
89         case DNS_QUERY_SUCCESS:
90         default:
91                 assert_not_reached("Impossible state");
92         }
93 }
94
95 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
96         int r;
97
98         assert(reply);
99         assert(rr);
100
101         r = sd_bus_message_open_container(reply, 'r', "yayi");
102         if (r < 0)
103                 return r;
104
105         if (rr->key.type == DNS_TYPE_A) {
106                 r = sd_bus_message_append(reply, "y", AF_INET);
107                 if (r < 0)
108                         return r;
109
110                 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
111         } else {
112                 r = sd_bus_message_append(reply, "y", AF_INET6);
113                 if (r < 0)
114                         return r;
115
116                 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
117         }
118         if (r < 0)
119                 return r;
120
121         r = sd_bus_message_append(reply, "i", ifindex);
122         if (r < 0)
123                 return r;
124
125         r = sd_bus_message_close_container(reply);
126         if (r < 0)
127                 return r;
128
129         return 0;
130 }
131
132 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
133         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
134         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
135         DnsResourceRecord **rrs;
136         unsigned added = 0;
137         int ifindex;
138         int r, n, i;
139
140         assert(q);
141
142         if (q->state != DNS_QUERY_SUCCESS) {
143                 r = reply_query_state(q);
144                 goto finish;
145         }
146
147         n = dns_query_get_rrs(q, &rrs);
148         if (n < 0) {
149                 r = n;
150                 goto parse_fail;
151         }
152
153         r = sd_bus_message_new_method_return(q->request, &reply);
154         if (r < 0)
155                 goto finish;
156
157         r = sd_bus_message_open_container(reply, 'a', "(yayi)");
158         if (r < 0)
159                 goto finish;
160
161         ifindex = dns_query_get_ifindex(q);
162         if (ifindex < 0)
163                 ifindex = 0;
164
165         for (i = 0; i < n; i++) {
166                 r = dns_query_matches_rr(q, rrs[i]);
167                 if (r < 0)
168                         goto parse_fail;
169                 if (r == 0) {
170                         /* Hmm, if this is not an address record,
171                            maybe it's a cname? If so, remember this */
172                         r = dns_query_matches_cname(q, rrs[i]);
173                         if (r < 0)
174                                 goto parse_fail;
175                         if (r > 0)
176                                 cname = dns_resource_record_ref(rrs[i]);
177
178                         continue;
179                 }
180
181                 r = append_address(reply, rrs[i], ifindex);
182                 if (r < 0)
183                         goto finish;
184
185                 if (!canonical)
186                         canonical = dns_resource_record_ref(rrs[i]);
187
188                 added ++;
189         }
190
191         if (added <= 0) {
192                 if (!cname) {
193                         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);
194                         goto finish;
195                 }
196
197                 /* This has a cname? Then update the query with the
198                  * new cname. */
199                 r = dns_query_cname_redirect(q, cname->cname.name);
200                 if (r < 0) {
201                         if (r == -ELOOP)
202                                 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
203                         else
204                                 r = sd_bus_reply_method_errno(q->request, -r, NULL);
205
206                         goto finish;
207                 }
208
209                 /* Before we restart the query, let's see if any of
210                  * the RRs we already got already answers our query */
211                 for (i = 0; i < n; i++) {
212                         r = dns_query_matches_rr(q, rrs[i]);
213                         if (r < 0)
214                                 goto parse_fail;
215                         if (r == 0)
216                                 continue;
217
218                         r = append_address(reply, rrs[i], ifindex);
219                         if (r < 0)
220                                 goto finish;
221
222                         if (!canonical)
223                                 canonical = dns_resource_record_ref(rrs[i]);
224
225                         added++;
226                 }
227
228                 /* If we didn't find anything, then let's restart the
229                  * query, this time with the cname */
230                 if (added <= 0) {
231                         r = dns_query_go(q);
232                         if (r == -ESRCH) {
233                                 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
234                                 goto finish;
235                         }
236                         if (r < 0) {
237                                 r = sd_bus_reply_method_errno(q->request, -r, NULL);
238                                 goto finish;
239                         }
240                         return;
241                 }
242         }
243
244         r = sd_bus_message_close_container(reply);
245         if (r < 0)
246                 goto finish;
247
248         /* Return the precise spelling and uppercasing reported by the server */
249         assert(canonical);
250         r = sd_bus_message_append(reply, "s", canonical->key.name);
251         if (r < 0)
252                 goto finish;
253
254         r = sd_bus_send(q->manager->bus, reply, NULL);
255         goto finish;
256
257 parse_fail:
258         r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
259
260 finish:
261         if (r < 0)
262                 log_error("Failed to send bus reply: %s", strerror(-r));
263
264         dns_query_free(q);
265 }
266
267 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
268         Manager *m = userdata;
269         const char *hostname;
270         uint8_t family;
271         DnsResourceKey keys[2];
272         DnsQuery *q;
273         unsigned n = 0;
274         int r;
275
276         assert(bus);
277         assert(message);
278         assert(m);
279
280         r = sd_bus_message_read(message, "sy", &hostname, &family);
281         if (r < 0)
282                 return r;
283
284         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
285                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
286
287         if (!hostname_is_valid(hostname))
288                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
289
290         if (family != AF_INET6) {
291                 keys[n].class = DNS_CLASS_IN;
292                 keys[n].type = DNS_TYPE_A;
293                 keys[n].name = (char*) hostname;
294                 n++;
295         }
296
297         if (family != AF_INET) {
298                 keys[n].class = DNS_CLASS_IN;
299                 keys[n].type = DNS_TYPE_AAAA;
300                 keys[n].name = (char*) hostname;
301                 n++;
302         }
303
304         r = dns_query_new(m, &q, keys, n);
305         if (r < 0)
306                 return r;
307
308         q->request = sd_bus_message_ref(message);
309         q->request_family = family;
310         q->request_hostname = hostname;
311         q->complete = bus_method_resolve_hostname_complete;
312
313         r = dns_query_go(q);
314         if (r < 0) {
315                 dns_query_free(q);
316
317                 if (r == -ESRCH)
318                         sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
319
320                 return r;
321         }
322
323         return 1;
324 }
325
326 static void bus_method_resolve_address_complete(DnsQuery *q) {
327         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
328         DnsResourceRecord **rrs;
329         unsigned added = 0;
330         int r, n, i;
331
332         assert(q);
333
334         if (q->state != DNS_QUERY_SUCCESS) {
335                 r = reply_query_state(q);
336                 goto finish;
337         }
338
339         n = dns_query_get_rrs(q, &rrs);
340         if (n < 0) {
341                 r = n;
342                 goto parse_fail;
343         }
344
345         r = sd_bus_message_new_method_return(q->request, &reply);
346         if (r < 0)
347                 goto finish;
348
349         r = sd_bus_message_open_container(reply, 'a', "s");
350         if (r < 0)
351                 goto finish;
352
353         for (i = 0; i < n; i++) {
354                 r = dns_query_matches_rr(q, rrs[i]);
355                 if (r < 0)
356                         goto parse_fail;
357                 if (r == 0)
358                         continue;
359
360                 r = sd_bus_message_append(reply, "s", rrs[i]->ptr.name);
361                 if (r < 0)
362                         goto finish;
363
364                 added ++;
365         }
366
367         if (added <= 0) {
368                 _cleanup_free_ char *ip = NULL;
369
370                 in_addr_to_string(q->request_family, &q->request_address, &ip);
371
372                 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
373                 goto finish;
374         }
375
376         r = sd_bus_message_close_container(reply);
377         if (r < 0)
378                 goto finish;
379
380         r = sd_bus_send(q->manager->bus, reply, NULL);
381         goto finish;
382
383 parse_fail:
384         r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
385
386 finish:
387         if (r < 0)
388                 log_error("Failed to send bus reply: %s", strerror(-r));
389
390         dns_query_free(q);
391 }
392
393 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394         _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
395         Manager *m = userdata;
396         uint8_t family;
397         const void *d;
398         int ifindex;
399         DnsQuery *q;
400         size_t sz;
401         int r;
402
403         assert(bus);
404         assert(message);
405         assert(m);
406
407         r = sd_bus_message_read(message, "y", &family);
408         if (r < 0)
409                 return r;
410
411         if (!IN_SET(family, AF_INET, AF_INET6))
412                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %u", family);
413
414         r = sd_bus_message_read_array(message, 'y', &d, &sz);
415         if (r < 0)
416                 return r;
417
418         if ((family == AF_INET && sz != sizeof(struct in_addr)) ||
419             (family == AF_INET6 && sz != sizeof(struct in6_addr)))
420                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
421
422         r = sd_bus_message_read(message, "i", &ifindex);
423         if (r < 0)
424                 return r;
425         if (ifindex < 0)
426                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
427
428         key.class = DNS_CLASS_IN;
429         key.type = DNS_TYPE_PTR;
430         r = dns_name_reverse(family, d, &key.name);
431         if (r < 0)
432                 return r;
433
434         r = dns_query_new(m, &q, &key, 1);
435         if (r < 0)
436                 return r;
437
438         q->request = sd_bus_message_ref(message);
439         q->request_family = family;
440         memcpy(&q->request_address, d, sz);
441         q->complete = bus_method_resolve_address_complete;
442
443         r = dns_query_go(q);
444         if (r < 0) {
445                 dns_query_free(q);
446                 return r;
447         }
448
449         return 1;
450 }
451
452 static const sd_bus_vtable resolve_vtable[] = {
453         SD_BUS_VTABLE_START(0),
454         SD_BUS_METHOD("ResolveHostname", "sy", "a(yayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
455         SD_BUS_METHOD("ResolveAddress", "yayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
456         SD_BUS_VTABLE_END,
457 };
458
459 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
460         Manager *m = userdata;
461
462         assert(s);
463         assert(m);
464
465         m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
466
467         manager_connect_bus(m);
468         return 0;
469 }
470
471 int manager_connect_bus(Manager *m) {
472         int r;
473
474         assert(m);
475
476         if (m->bus)
477                 return 0;
478
479         r = sd_bus_default_system(&m->bus);
480         if (r < 0) {
481                 /* We failed to connect? Yuck, we must be in early
482                  * boot. Let's try in 5s again. As soon as we have
483                  * kdbus we can stop doing this... */
484
485                 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
486
487                 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);
488                 if (r < 0) {
489                         log_error("Failed to install bus reconnect time event: %s", strerror(-r));
490                         return r;
491                 }
492
493                 return 0;
494         }
495
496         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
497         if (r < 0) {
498                 log_error("Failed to register object: %s", strerror(-r));
499                 return r;
500         }
501
502         r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
503         if (r < 0) {
504                 log_error("Failed to register name: %s", strerror(-r));
505                 return r;
506         }
507
508         r = sd_bus_attach_event(m->bus, m->event, 0);
509         if (r < 0) {
510                 log_error("Failed to attach bus to event loop: %s", strerror(-r));
511                 return r;
512         }
513
514         return 0;
515 }