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