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, unsigned *ret) {
53 while ((r = sd_bus_message_enter_container(m, 'r', "yayi")) > 0) {
56 r = sd_bus_message_read(m, "y", &family);
60 r = sd_bus_message_skip(m, "ayi");
64 r = sd_bus_message_exit_container(m);
68 if (af != AF_UNSPEC && family != af)
76 r = sd_bus_message_rewind(m, false);
84 enum nss_status _nss_resolve_gethostbyname4_r(
86 struct gaih_addrtuple **pat,
87 char *buffer, size_t buflen,
88 int *errnop, int *h_errnop,
91 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
92 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
93 struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
94 _cleanup_bus_unref_ sd_bus *bus = NULL;
97 unsigned i = 0, c = 0;
106 r = sd_bus_open_system(&bus);
110 r = sd_bus_message_new_method_call(
113 "org.freedesktop.resolve1",
114 "/org/freedesktop/resolve1",
115 "org.freedesktop.resolve1.Manager",
120 r = sd_bus_message_set_auto_start(req, false);
124 r = sd_bus_message_append(req, "sy", name, AF_UNSPEC);
128 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
130 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
132 *h_errnop = HOST_NOT_FOUND;
133 return NSS_STATUS_NOTFOUND;
137 *h_errnop = NO_RECOVERY;
138 return NSS_STATUS_UNAVAIL;
141 r = sd_bus_message_enter_container(reply, 'a', "(yayi)");
145 r = count_addresses(reply, AF_UNSPEC, &c);
151 *h_errnop = HOST_NOT_FOUND;
152 return NSS_STATUS_NOTFOUND;
156 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
159 *h_errnop = TRY_AGAIN;
160 return NSS_STATUS_TRYAGAIN;
163 /* First, append name */
165 memcpy(r_name, name, l+1);
168 /* Second, append addresses */
169 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
170 while ((r = sd_bus_message_enter_container(reply, 'r', "yayi")) > 0) {
171 unsigned char family;
176 r = sd_bus_message_read(reply, "y", &family);
180 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
184 r = sd_bus_message_read(reply, "i", &ifindex);
188 r = sd_bus_message_exit_container(reply);
192 if (!IN_SET(family, AF_INET, AF_INET6))
195 if (sz != PROTO_ADDRESS_SIZE(family)) {
205 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
206 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
207 r_tuple->name = r_name;
208 r_tuple->family = family;
209 r_tuple->scopeid = ifindex;
210 memcpy(r_tuple->addr, a, sz);
212 idx += ALIGN(sizeof(struct gaih_addrtuple));
218 r = sd_bus_message_exit_container(reply);
225 **pat = *r_tuple_first;
227 *pat = r_tuple_first;
232 return NSS_STATUS_SUCCESS;
237 return NSS_STATUS_UNAVAIL;
240 enum nss_status _nss_resolve_gethostbyname3_r(
243 struct hostent *result,
244 char *buffer, size_t buflen,
245 int *errnop, int *h_errnop,
249 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
250 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
251 char *r_name, *r_aliases, *r_addr, *r_addr_list;
252 _cleanup_bus_unref_ sd_bus *bus = NULL;
253 unsigned c = 0, i = 0;
254 size_t l, idx, ms, alen;
266 if (af != AF_INET && af != AF_INET6) {
271 r = sd_bus_open_system(&bus);
275 r = sd_bus_message_new_method_call(
278 "org.freedesktop.resolve1",
279 "/org/freedesktop/resolve1",
280 "org.freedesktop.resolve1.Manager",
285 r = sd_bus_message_set_auto_start(req, false);
289 r = sd_bus_message_append(req, "sy", name, af);
293 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
295 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
297 *h_errnop = HOST_NOT_FOUND;
298 return NSS_STATUS_NOTFOUND;
302 *h_errnop = NO_RECOVERY;
303 return NSS_STATUS_UNAVAIL;
306 r = sd_bus_message_enter_container(reply, 'a', "(yayi)");
310 r = count_addresses(reply, af, &c);
316 *h_errnop = HOST_NOT_FOUND;
317 return NSS_STATUS_NOTFOUND;
320 alen = PROTO_ADDRESS_SIZE(af);
325 (c > 0 ? c : 1) * ALIGN(alen) +
326 (c > 0 ? c+1 : 2) * sizeof(char*);
330 *h_errnop = TRY_AGAIN;
331 return NSS_STATUS_TRYAGAIN;
334 /* First, append name */
336 memcpy(r_name, name, l+1);
339 /* Second, create aliases array */
340 r_aliases = buffer + idx;
341 ((char**) r_aliases)[0] = NULL;
342 idx += sizeof(char*);
344 /* Third, append addresses */
345 r_addr = buffer + idx;
346 while ((r = sd_bus_message_enter_container(reply, 'r', "yayi")) > 0) {
347 unsigned char family;
352 r = sd_bus_message_read(reply, "y", &family);
356 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
360 r = sd_bus_message_read(reply, "i", &ifindex);
364 r = sd_bus_message_exit_container(reply);
381 memcpy(r_addr + i*ALIGN(alen), a, alen);
386 idx += c * ALIGN(alen);
388 r = sd_bus_message_exit_container(reply);
392 /* Third, append address pointer array */
393 r_addr_list = buffer + idx;
394 for (i = 0; i < c; i++)
395 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
397 ((char**) r_addr_list)[i] = NULL;
398 idx += (c+1) * sizeof(char*);
402 result->h_name = r_name;
403 result->h_aliases = (char**) r_aliases;
404 result->h_addrtype = af;
405 result->h_length = alen;
406 result->h_addr_list = (char**) r_addr_list;
414 return NSS_STATUS_SUCCESS;
419 return NSS_STATUS_UNAVAIL;
422 enum nss_status _nss_resolve_gethostbyaddr2_r(
423 const void* addr, socklen_t len,
425 struct hostent *result,
426 char *buffer, size_t buflen,
427 int *errnop, int *h_errnop,
430 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
431 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
432 char *r_name, *r_aliases, *r_addr, *r_addr_list;
433 _cleanup_bus_unref_ sd_bus *bus = NULL;
434 unsigned c = 0, i = 0;
445 if (!IN_SET(af, AF_INET, AF_INET6)) {
446 *errnop = EAFNOSUPPORT;
448 return NSS_STATUS_UNAVAIL;
451 if (len != PROTO_ADDRESS_SIZE(af)) {
453 *h_errnop = NO_RECOVERY;
454 return NSS_STATUS_UNAVAIL;
457 r = sd_bus_open_system(&bus);
461 r = sd_bus_message_new_method_call(
464 "org.freedesktop.resolve1",
465 "/org/freedesktop/resolve1",
466 "org.freedesktop.resolve1.Manager",
471 r = sd_bus_message_set_auto_start(req, false);
475 r = sd_bus_message_append(req, "y", af);
479 r = sd_bus_message_append_array(req, 'y', addr, len);
483 r = sd_bus_message_append(req, "i", 0);
487 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
489 if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
491 *h_errnop = HOST_NOT_FOUND;
492 return NSS_STATUS_NOTFOUND;
496 *h_errnop = NO_RECOVERY;
497 return NSS_STATUS_UNAVAIL;
500 r = sd_bus_message_enter_container(reply, 'a', "s");
504 while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
506 ms += ALIGN(strlen(n) + 1);
511 r = sd_bus_message_rewind(reply, false);
517 *h_errnop = HOST_NOT_FOUND;
518 return NSS_STATUS_NOTFOUND;
521 ms += ALIGN(len) + /* the address */
522 2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
523 c * sizeof(char*); /* pointers to aliases, plus trailing NULL */
527 *h_errnop = TRY_AGAIN;
528 return NSS_STATUS_TRYAGAIN;
531 /* First, place address */
533 memcpy(r_addr, addr, len);
536 /* Second, place address list */
537 r_addr_list = buffer + idx;
538 ((char**) r_addr_list)[0] = r_addr;
539 ((char**) r_addr_list)[1] = NULL;
540 idx += sizeof(char*) * 2;
542 /* Third, reserve space for the aliases array */
543 r_aliases = buffer + idx;
544 idx += sizeof(char*) * c;
546 /* Fourth, place aliases */
548 r_name = buffer + idx;
549 while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
558 ((char**) r_aliases)[i-1] = p;
564 ((char**) r_aliases)[c-1] = NULL;
567 result->h_name = r_name;
568 result->h_aliases = (char**) r_aliases;
569 result->h_addrtype = af;
570 result->h_length = len;
571 result->h_addr_list = (char**) r_addr_list;
576 return NSS_STATUS_SUCCESS;
581 return NSS_STATUS_UNAVAIL;
584 NSS_GETHOSTBYNAME_FALLBACKS(resolve);
585 NSS_GETHOSTBYADDR_FALLBACKS(resolve);