]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-bus.c
resolved: set LLMNR TCP and UDP TTLs to the values suggested by the RFC
[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 answer = dns_answer_ref(q->answer);
153 ifindex = q->answer_ifindex;
154
155 for (i = 0; i < answer->n_rrs; i++) {
156 r = dns_question_matches_rr(q->question, answer->rrs[i]);
157 if (r < 0)
158 goto parse_fail;
159 if (r == 0) {
160 /* Hmm, if this is not an address record,
161 maybe it's a cname? If so, remember this */
162 r = dns_question_matches_cname(q->question, answer->rrs[i]);
163 if (r < 0)
164 goto parse_fail;
165 if (r > 0)
166 cname = dns_resource_record_ref(answer->rrs[i]);
167
168 continue;
169 }
170
171 r = append_address(reply, answer->rrs[i], ifindex);
172 if (r < 0)
173 goto finish;
174
175 if (!canonical)
176 canonical = dns_resource_record_ref(answer->rrs[i]);
177
178 added ++;
179 }
180
181 if (added <= 0) {
182 if (!cname) {
183 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);
184 goto finish;
185 }
186
187 /* This has a cname? Then update the query with the
188 * new cname. */
189 r = dns_query_cname_redirect(q, cname->cname.name);
190 if (r < 0) {
191 if (r == -ELOOP)
192 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
193 else
194 r = sd_bus_reply_method_errno(q->request, -r, NULL);
195
196 goto finish;
197 }
198
199 /* Before we restart the query, let's see if any of
200 * the RRs we already got already answers our query */
201 for (i = 0; i < answer->n_rrs; i++) {
202 r = dns_question_matches_rr(q->question, answer->rrs[i]);
203 if (r < 0)
204 goto parse_fail;
205 if (r == 0)
206 continue;
207
208 r = append_address(reply, answer->rrs[i], ifindex);
209 if (r < 0)
210 goto finish;
211
212 if (!canonical)
213 canonical = dns_resource_record_ref(answer->rrs[i]);
214
215 added++;
216 }
217
218 /* If we didn't find anything, then let's restart the
219 * query, this time with the cname */
220 if (added <= 0) {
221 r = dns_query_go(q);
222 if (r == -ESRCH) {
223 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
224 goto finish;
225 }
226 if (r < 0) {
227 r = sd_bus_reply_method_errno(q->request, -r, NULL);
228 goto finish;
229 }
230 return;
231 }
232 }
233
234 r = sd_bus_message_close_container(reply);
235 if (r < 0)
236 goto finish;
237
238 /* Return the precise spelling and uppercasing reported by the server */
239 assert(canonical);
240 r = sd_bus_message_append(reply, "s", DNS_RESOURCE_KEY_NAME(canonical->key));
241 if (r < 0)
242 goto finish;
243
244 r = sd_bus_send(q->manager->bus, reply, NULL);
245 goto finish;
246
247 parse_fail:
248 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
249
250 finish:
251 if (r < 0)
252 log_error("Failed to send bus reply: %s", strerror(-r));
253
254 dns_query_free(q);
255 }
256
257 static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
258 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
259 Manager *m = userdata;
260 const char *hostname;
261 int family;
262 DnsQuery *q;
263 int r;
264
265 assert(bus);
266 assert(message);
267 assert(m);
268
269 r = sd_bus_message_read(message, "si", &hostname, &family);
270 if (r < 0)
271 return r;
272
273 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
274 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
275
276 if (!hostname_is_valid(hostname))
277 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
278
279 question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
280 if (!question)
281 return -ENOMEM;
282
283 if (family != AF_INET6) {
284 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
285
286 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
287 if (!key)
288 return -ENOMEM;
289
290 r = dns_question_add(question, key);
291 if (r < 0)
292 return r;
293 }
294
295 if (family != AF_INET) {
296 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
297
298 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
299 if (!key)
300 return -ENOMEM;
301
302 r = dns_question_add(question, key);
303 if (r < 0)
304 return r;
305 }
306
307 r = dns_query_new(m, &q, question);
308 if (r < 0)
309 return r;
310
311 q->request = sd_bus_message_ref(message);
312 q->request_family = family;
313 q->request_hostname = hostname;
314 q->complete = bus_method_resolve_hostname_complete;
315
316 r = dns_query_go(q);
317 if (r < 0) {
318 dns_query_free(q);
319
320 if (r == -ESRCH)
321 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
322
323 return r;
324 }
325
326 return 1;
327 }
328
329 static void bus_method_resolve_address_complete(DnsQuery *q) {
330 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
331 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
332 unsigned added = 0, i;
333 int r;
334
335 assert(q);
336
337 if (q->state != DNS_QUERY_SUCCESS) {
338 r = reply_query_state(q);
339 goto finish;
340 }
341
342 r = sd_bus_message_new_method_return(q->request, &reply);
343 if (r < 0)
344 goto finish;
345
346 r = sd_bus_message_open_container(reply, 'a', "s");
347 if (r < 0)
348 goto finish;
349
350 answer = dns_answer_ref(q->answer);
351
352 for (i = 0; i < answer->n_rrs; i++) {
353 r = dns_question_matches_rr(q->question, answer->rrs[i]);
354 if (r < 0)
355 goto parse_fail;
356 if (r == 0)
357 continue;
358
359 r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
360 if (r < 0)
361 goto finish;
362
363 added ++;
364 }
365
366 if (added <= 0) {
367 _cleanup_free_ char *ip = NULL;
368
369 in_addr_to_string(q->request_family, &q->request_address, &ip);
370
371 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
372 goto finish;
373 }
374
375 r = sd_bus_message_close_container(reply);
376 if (r < 0)
377 goto finish;
378
379 r = sd_bus_send(q->manager->bus, reply, NULL);
380 goto finish;
381
382 parse_fail:
383 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
384
385 finish:
386 if (r < 0)
387 log_error("Failed to send bus reply: %s", strerror(-r));
388
389 dns_query_free(q);
390 }
391
392 static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
393 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
394 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
395 _cleanup_free_ char *reverse = NULL;
396 Manager *m = userdata;
397 int family, ifindex;
398 const void *d;
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, "i", &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 %i", family);
413
414 r = sd_bus_message_read_array(message, 'y', &d, &sz);
415 if (r < 0)
416 return r;
417
418 if (sz != FAMILY_ADDRESS_SIZE(family))
419 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
420
421 r = sd_bus_message_read(message, "i", &ifindex);
422 if (r < 0)
423 return r;
424 if (ifindex < 0)
425 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
426
427 r = dns_name_reverse(family, d, &reverse);
428 if (r < 0)
429 return r;
430
431 question = dns_question_new(1);
432 if (!question)
433 return -ENOMEM;
434
435 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
436 if (!key)
437 return -ENOMEM;
438
439 reverse = NULL;
440
441 r = dns_question_add(question, key);
442 if (r < 0)
443 return r;
444
445 r = dns_query_new(m, &q, question);
446 if (r < 0)
447 return r;
448
449 q->request = sd_bus_message_ref(message);
450 q->request_family = family;
451 memcpy(&q->request_address, d, sz);
452 q->complete = bus_method_resolve_address_complete;
453
454 r = dns_query_go(q);
455 if (r < 0) {
456 dns_query_free(q);
457
458 if (r == -ESRCH)
459 sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
460
461 return r;
462 }
463
464 return 1;
465 }
466
467 static const sd_bus_vtable resolve_vtable[] = {
468 SD_BUS_VTABLE_START(0),
469 SD_BUS_METHOD("ResolveHostname", "si", "a(iayi)s", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
470 SD_BUS_METHOD("ResolveAddress", "iayi", "as", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
471 SD_BUS_VTABLE_END,
472 };
473
474 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
475 Manager *m = userdata;
476
477 assert(s);
478 assert(m);
479
480 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
481
482 manager_connect_bus(m);
483 return 0;
484 }
485
486 int manager_connect_bus(Manager *m) {
487 int r;
488
489 assert(m);
490
491 if (m->bus)
492 return 0;
493
494 r = sd_bus_default_system(&m->bus);
495 if (r < 0) {
496 /* We failed to connect? Yuck, we must be in early
497 * boot. Let's try in 5s again. As soon as we have
498 * kdbus we can stop doing this... */
499
500 log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
501
502 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);
503 if (r < 0) {
504 log_error("Failed to install bus reconnect time event: %s", strerror(-r));
505 return r;
506 }
507
508 return 0;
509 }
510
511 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
512 if (r < 0) {
513 log_error("Failed to register object: %s", strerror(-r));
514 return r;
515 }
516
517 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
518 if (r < 0) {
519 log_error("Failed to register name: %s", strerror(-r));
520 return r;
521 }
522
523 r = sd_bus_attach_event(m->bus, m->event, 0);
524 if (r < 0) {
525 log_error("Failed to attach bus to event loop: %s", strerror(-r));
526 return r;
527 }
528
529 return 0;
530 }