1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
24 #include <sys/types.h>
31 #include <arpa/inet.h>
35 #include "bus-errors.h"
39 #include "in-addr-util.h"
41 NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
42 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
44 #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
46 static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
52 r = sd_bus_message_enter_container(m, 'a', "(iayi)");
56 while ((r = sd_bus_message_enter_container(m, 'r', "iayi")) > 0) {
59 r = sd_bus_message_read(m, "i", &family);
63 r = sd_bus_message_skip(m, "ayi");
67 r = sd_bus_message_exit_container(m);
71 if (af != AF_UNSPEC && family != af)
79 r = sd_bus_message_exit_container(m);
83 r = sd_bus_message_read(m, "s", canonical);
87 r = sd_bus_message_rewind(m, true);
94 enum nss_status _nss_resolve_gethostbyname4_r(
96 struct gaih_addrtuple **pat,
97 char *buffer, size_t buflen,
98 int *errnop, int *h_errnop,
101 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
102 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
103 struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
104 _cleanup_bus_unref_ sd_bus *bus = NULL;
105 const char *canonical = NULL;
116 r = sd_bus_open_system(&bus);
120 r = sd_bus_message_new_method_call(
123 "org.freedesktop.resolve1",
124 "/org/freedesktop/resolve1",
125 "org.freedesktop.resolve1.Manager",
130 r = sd_bus_message_set_auto_start(req, false);
134 r = sd_bus_message_append(req, "si", name, AF_UNSPEC);
138 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
140 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
142 *h_errnop = HOST_NOT_FOUND;
143 return NSS_STATUS_NOTFOUND;
147 *h_errnop = NO_RECOVERY;
148 return NSS_STATUS_UNAVAIL;
151 c = count_addresses(reply, AF_UNSPEC, &canonical);
158 *h_errnop = HOST_NOT_FOUND;
159 return NSS_STATUS_NOTFOUND;
162 if (isempty(canonical))
165 l = strlen(canonical);
166 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
169 *h_errnop = TRY_AGAIN;
170 return NSS_STATUS_TRYAGAIN;
173 /* First, append name */
175 memcpy(r_name, canonical, l+1);
178 /* Second, append addresses */
179 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
181 r = sd_bus_message_enter_container(reply, 'a', "(iayi)");
185 while ((r = sd_bus_message_enter_container(reply, 'r', "iayi")) > 0) {
190 r = sd_bus_message_read(reply, "i", &family);
194 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
198 r = sd_bus_message_read(reply, "i", &ifindex);
202 r = sd_bus_message_exit_container(reply);
206 if (!IN_SET(family, AF_INET, AF_INET6))
209 if (sz != FAMILY_ADDRESS_SIZE(family)) {
219 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
220 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
221 r_tuple->name = r_name;
222 r_tuple->family = family;
223 r_tuple->scopeid = ifindex;
224 memcpy(r_tuple->addr, a, sz);
226 idx += ALIGN(sizeof(struct gaih_addrtuple));
236 **pat = *r_tuple_first;
238 *pat = r_tuple_first;
243 return NSS_STATUS_SUCCESS;
248 return NSS_STATUS_UNAVAIL;
251 enum nss_status _nss_resolve_gethostbyname3_r(
254 struct hostent *result,
255 char *buffer, size_t buflen,
256 int *errnop, int *h_errnop,
260 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
261 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
262 char *r_name, *r_aliases, *r_addr, *r_addr_list;
263 _cleanup_bus_unref_ sd_bus *bus = NULL;
264 size_t l, idx, ms, alen;
265 const char *canonical;
277 if (af != AF_INET && af != AF_INET6) {
282 r = sd_bus_open_system(&bus);
286 r = sd_bus_message_new_method_call(
289 "org.freedesktop.resolve1",
290 "/org/freedesktop/resolve1",
291 "org.freedesktop.resolve1.Manager",
296 r = sd_bus_message_set_auto_start(req, false);
300 r = sd_bus_message_append(req, "si", name, af);
304 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
306 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
308 *h_errnop = HOST_NOT_FOUND;
309 return NSS_STATUS_NOTFOUND;
313 *h_errnop = NO_RECOVERY;
314 return NSS_STATUS_UNAVAIL;
317 c = count_addresses(reply, af, &canonical);
324 *h_errnop = HOST_NOT_FOUND;
325 return NSS_STATUS_NOTFOUND;
328 if (isempty(canonical))
331 alen = FAMILY_ADDRESS_SIZE(af);
332 l = strlen(canonical);
336 (c > 0 ? c : 1) * ALIGN(alen) +
337 (c > 0 ? c+1 : 2) * sizeof(char*);
341 *h_errnop = TRY_AGAIN;
342 return NSS_STATUS_TRYAGAIN;
345 /* First, append name */
347 memcpy(r_name, canonical, l+1);
350 /* Second, create empty aliases array */
351 r_aliases = buffer + idx;
352 ((char**) r_aliases)[0] = NULL;
353 idx += sizeof(char*);
355 /* Third, append addresses */
356 r_addr = buffer + idx;
358 r = sd_bus_message_enter_container(reply, 'a', "(iayi)");
362 while ((r = sd_bus_message_enter_container(reply, 'r', "iayi")) > 0) {
367 r = sd_bus_message_read(reply, "i", &family);
371 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
375 r = sd_bus_message_read(reply, "i", &ifindex);
379 r = sd_bus_message_exit_container(reply);
396 memcpy(r_addr + i*ALIGN(alen), a, alen);
403 idx += c * ALIGN(alen);
405 /* Fourth, append address pointer array */
406 r_addr_list = buffer + idx;
407 for (i = 0; i < c; i++)
408 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
410 ((char**) r_addr_list)[i] = NULL;
411 idx += (c+1) * sizeof(char*);
415 result->h_name = r_name;
416 result->h_aliases = (char**) r_aliases;
417 result->h_addrtype = af;
418 result->h_length = alen;
419 result->h_addr_list = (char**) r_addr_list;
427 return NSS_STATUS_SUCCESS;
432 return NSS_STATUS_UNAVAIL;
435 enum nss_status _nss_resolve_gethostbyaddr2_r(
436 const void* addr, socklen_t len,
438 struct hostent *result,
439 char *buffer, size_t buflen,
440 int *errnop, int *h_errnop,
443 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
444 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
445 char *r_name, *r_aliases, *r_addr, *r_addr_list;
446 _cleanup_bus_unref_ sd_bus *bus = NULL;
447 unsigned c = 0, i = 0;
458 if (!IN_SET(af, AF_INET, AF_INET6)) {
459 *errnop = EAFNOSUPPORT;
461 return NSS_STATUS_UNAVAIL;
464 if (len != FAMILY_ADDRESS_SIZE(af)) {
466 *h_errnop = NO_RECOVERY;
467 return NSS_STATUS_UNAVAIL;
470 r = sd_bus_open_system(&bus);
474 r = sd_bus_message_new_method_call(
477 "org.freedesktop.resolve1",
478 "/org/freedesktop/resolve1",
479 "org.freedesktop.resolve1.Manager",
484 r = sd_bus_message_set_auto_start(req, false);
488 r = sd_bus_message_append(req, "i", af);
492 r = sd_bus_message_append_array(req, 'y', addr, len);
496 r = sd_bus_message_append(req, "i", 0);
500 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
502 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
504 *h_errnop = HOST_NOT_FOUND;
505 return NSS_STATUS_NOTFOUND;
509 *h_errnop = NO_RECOVERY;
510 return NSS_STATUS_UNAVAIL;
513 r = sd_bus_message_enter_container(reply, 'a', "s");
517 while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
519 ms += ALIGN(strlen(n) + 1);
524 r = sd_bus_message_rewind(reply, false);
530 *h_errnop = HOST_NOT_FOUND;
531 return NSS_STATUS_NOTFOUND;
534 ms += ALIGN(len) + /* the address */
535 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
536 c * sizeof(char*); /* pointers to aliases, plus trailing NULL */
540 *h_errnop = TRY_AGAIN;
541 return NSS_STATUS_TRYAGAIN;
544 /* First, place address */
546 memcpy(r_addr, addr, len);
549 /* Second, place address list */
550 r_addr_list = buffer + idx;
551 ((char**) r_addr_list)[0] = r_addr;
552 ((char**) r_addr_list)[1] = NULL;
553 idx += sizeof(char*) * 2;
555 /* Third, reserve space for the aliases array */
556 r_aliases = buffer + idx;
557 idx += sizeof(char*) * c;
559 /* Fourth, place aliases */
561 r_name = buffer + idx;
562 while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
571 ((char**) r_aliases)[i-1] = p;
579 ((char**) r_aliases)[c-1] = NULL;
582 result->h_name = r_name;
583 result->h_aliases = (char**) r_aliases;
584 result->h_addrtype = af;
585 result->h_length = len;
586 result->h_addr_list = (char**) r_addr_list;
591 return NSS_STATUS_SUCCESS;
596 return NSS_STATUS_UNAVAIL;
599 NSS_GETHOSTBYNAME_FALLBACKS(resolve);
600 NSS_GETHOSTBYADDR_FALLBACKS(resolve);