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, unsigned af, const char **canonical) {
52 r = sd_bus_message_enter_container(m, 'a', "(yayi)");
56 while ((r = sd_bus_message_enter_container(m, 'r', "yayi")) > 0) {
59 r = sd_bus_message_read(m, "y", &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, "sy", 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', "(yayi)");
185 while ((r = sd_bus_message_enter_container(reply, 'r', "yayi")) > 0) {
186 unsigned char family;
191 r = sd_bus_message_read(reply, "y", &family);
195 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
199 r = sd_bus_message_read(reply, "i", &ifindex);
203 r = sd_bus_message_exit_container(reply);
207 if (!IN_SET(family, AF_INET, AF_INET6))
210 if (sz != PROTO_ADDRESS_SIZE(family)) {
220 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
221 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
222 r_tuple->name = r_name;
223 r_tuple->family = family;
224 r_tuple->scopeid = ifindex;
225 memcpy(r_tuple->addr, a, sz);
227 idx += ALIGN(sizeof(struct gaih_addrtuple));
237 **pat = *r_tuple_first;
239 *pat = r_tuple_first;
244 return NSS_STATUS_SUCCESS;
249 return NSS_STATUS_UNAVAIL;
252 enum nss_status _nss_resolve_gethostbyname3_r(
255 struct hostent *result,
256 char *buffer, size_t buflen,
257 int *errnop, int *h_errnop,
261 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
262 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
263 char *r_name, *r_aliases, *r_addr, *r_addr_list;
264 _cleanup_bus_unref_ sd_bus *bus = NULL;
265 size_t l, idx, ms, alen;
266 const char *canonical;
278 if (af != AF_INET && af != AF_INET6) {
283 r = sd_bus_open_system(&bus);
287 r = sd_bus_message_new_method_call(
290 "org.freedesktop.resolve1",
291 "/org/freedesktop/resolve1",
292 "org.freedesktop.resolve1.Manager",
297 r = sd_bus_message_set_auto_start(req, false);
301 r = sd_bus_message_append(req, "sy", name, af);
305 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
307 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
309 *h_errnop = HOST_NOT_FOUND;
310 return NSS_STATUS_NOTFOUND;
314 *h_errnop = NO_RECOVERY;
315 return NSS_STATUS_UNAVAIL;
318 c = count_addresses(reply, af, &canonical);
325 *h_errnop = HOST_NOT_FOUND;
326 return NSS_STATUS_NOTFOUND;
329 if (isempty(canonical))
332 alen = PROTO_ADDRESS_SIZE(af);
333 l = strlen(canonical);
337 (c > 0 ? c : 1) * ALIGN(alen) +
338 (c > 0 ? c+1 : 2) * sizeof(char*);
342 *h_errnop = TRY_AGAIN;
343 return NSS_STATUS_TRYAGAIN;
346 /* First, append name */
348 memcpy(r_name, canonical, l+1);
351 /* Second, create empty aliases array */
352 r_aliases = buffer + idx;
353 ((char**) r_aliases)[0] = NULL;
354 idx += sizeof(char*);
356 /* Third, append addresses */
357 r_addr = buffer + idx;
359 r = sd_bus_message_enter_container(reply, 'a', "(yayi)");
363 while ((r = sd_bus_message_enter_container(reply, 'r', "yayi")) > 0) {
364 unsigned char family;
369 r = sd_bus_message_read(reply, "y", &family);
373 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
377 r = sd_bus_message_read(reply, "i", &ifindex);
381 r = sd_bus_message_exit_container(reply);
398 memcpy(r_addr + i*ALIGN(alen), a, alen);
405 idx += c * ALIGN(alen);
407 /* Fourth, append address pointer array */
408 r_addr_list = buffer + idx;
409 for (i = 0; i < c; i++)
410 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
412 ((char**) r_addr_list)[i] = NULL;
413 idx += (c+1) * sizeof(char*);
417 result->h_name = r_name;
418 result->h_aliases = (char**) r_aliases;
419 result->h_addrtype = af;
420 result->h_length = alen;
421 result->h_addr_list = (char**) r_addr_list;
429 return NSS_STATUS_SUCCESS;
434 return NSS_STATUS_UNAVAIL;
437 enum nss_status _nss_resolve_gethostbyaddr2_r(
438 const void* addr, socklen_t len,
440 struct hostent *result,
441 char *buffer, size_t buflen,
442 int *errnop, int *h_errnop,
445 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
446 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
447 char *r_name, *r_aliases, *r_addr, *r_addr_list;
448 _cleanup_bus_unref_ sd_bus *bus = NULL;
449 unsigned c = 0, i = 0;
460 if (!IN_SET(af, AF_INET, AF_INET6)) {
461 *errnop = EAFNOSUPPORT;
463 return NSS_STATUS_UNAVAIL;
466 if (len != PROTO_ADDRESS_SIZE(af)) {
468 *h_errnop = NO_RECOVERY;
469 return NSS_STATUS_UNAVAIL;
472 r = sd_bus_open_system(&bus);
476 r = sd_bus_message_new_method_call(
479 "org.freedesktop.resolve1",
480 "/org/freedesktop/resolve1",
481 "org.freedesktop.resolve1.Manager",
486 r = sd_bus_message_set_auto_start(req, false);
490 r = sd_bus_message_append(req, "y", af);
494 r = sd_bus_message_append_array(req, 'y', addr, len);
498 r = sd_bus_message_append(req, "i", 0);
502 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
504 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
506 *h_errnop = HOST_NOT_FOUND;
507 return NSS_STATUS_NOTFOUND;
511 *h_errnop = NO_RECOVERY;
512 return NSS_STATUS_UNAVAIL;
515 r = sd_bus_message_enter_container(reply, 'a', "s");
519 while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
521 ms += ALIGN(strlen(n) + 1);
526 r = sd_bus_message_rewind(reply, false);
532 *h_errnop = HOST_NOT_FOUND;
533 return NSS_STATUS_NOTFOUND;
536 ms += ALIGN(len) + /* the address */
537 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
538 c * sizeof(char*); /* pointers to aliases, plus trailing NULL */
542 *h_errnop = TRY_AGAIN;
543 return NSS_STATUS_TRYAGAIN;
546 /* First, place address */
548 memcpy(r_addr, addr, len);
551 /* Second, place address list */
552 r_addr_list = buffer + idx;
553 ((char**) r_addr_list)[0] = r_addr;
554 ((char**) r_addr_list)[1] = NULL;
555 idx += sizeof(char*) * 2;
557 /* Third, reserve space for the aliases array */
558 r_aliases = buffer + idx;
559 idx += sizeof(char*) * c;
561 /* Fourth, place aliases */
563 r_name = buffer + idx;
564 while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
573 ((char**) r_aliases)[i-1] = p;
581 ((char**) r_aliases)[c-1] = NULL;
584 result->h_name = r_name;
585 result->h_aliases = (char**) r_aliases;
586 result->h_addrtype = af;
587 result->h_length = len;
588 result->h_addr_list = (char**) r_addr_list;
593 return NSS_STATUS_SUCCESS;
598 return NSS_STATUS_UNAVAIL;
601 NSS_GETHOSTBYNAME_FALLBACKS(resolve);
602 NSS_GETHOSTBYADDR_FALLBACKS(resolve);