]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-nss-hosts.c
env-util: rename getenv_bool_secure() → secure_getenv_bool()
[thirdparty/systemd.git] / src / test / test-nss-hosts.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2abb5b3b 2
2abb5b3b 3#include <net/if.h>
eb43e8a7 4#include <stdlib.h>
ca78ad1d 5#include <unistd.h>
2abb5b3b 6
eb43e8a7
YW
7#include "af-list.h"
8#include "alloc-util.h"
e2aa384b 9#include "dlfcn-util.h"
8ef114c6 10#include "env-util.h"
eb43e8a7 11#include "errno-list.h"
518a66ec 12#include "format-util.h"
eb43e8a7
YW
13#include "hexdecoct.h"
14#include "hostname-util.h"
15#include "in-addr-util.h"
16#include "local-addresses.h"
2abb5b3b 17#include "log.h"
f68a2622 18#include "main-func.h"
f0d12668 19#include "nss-test-util.h"
2abb5b3b 20#include "nss-util.h"
f0cb09bb 21#include "parse-util.h"
2abb5b3b 22#include "path-util.h"
bb78da17 23#include "socket-util.h"
2abb5b3b 24#include "stdio-util.h"
eb43e8a7 25#include "string-util.h"
2abb5b3b 26#include "strv.h"
f68a2622 27#include "tests.h"
2abb5b3b 28
f0cb09bb
ZJS
29static size_t arg_bufsize = 1024;
30
2abb5b3b
ZJS
31static const char* af_to_string(int family, char *buf, size_t buf_len) {
32 const char *name;
33
34 if (family == AF_UNSPEC)
35 return "*";
36
37 name = af_to_name(family);
38 if (name)
39 return name;
40
121ed16c 41 (void) snprintf(buf, buf_len, "%i", family);
2abb5b3b
ZJS
42 return buf;
43}
44
2abb5b3b 45static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
01afd0f7 46 int r, n = 0;
2abb5b3b 47
890e5a4d 48 for (const struct gaih_addrtuple *it = tuples; it; it = it->next) {
2abb5b3b
ZJS
49 _cleanup_free_ char *a = NULL;
50 union in_addr_union u;
2abb5b3b 51 char family_name[DECIMAL_STR_MAX(int)];
2abb5b3b
ZJS
52
53 memcpy(&u, it->addr, 16);
54 r = in_addr_to_string(it->family, &u, &a);
4c701096 55 assert_se(IN_SET(r, 0, -EAFNOSUPPORT));
2abb5b3b 56 if (r == -EAFNOSUPPORT)
dcd6361e 57 assert_se(a = hexmem(it->addr, 16));
2abb5b3b 58
01afd0f7 59 log_info(" \"%s\" %s %s %s",
2abb5b3b
ZJS
60 it->name,
61 af_to_string(it->family, family_name, sizeof family_name),
62 a,
01afd0f7
YW
63 FORMAT_IFNAME_FULL(it->scopeid, FORMAT_IFNAME_IFINDEX_WITH_PERCENT));
64
65 n++;
2abb5b3b
ZJS
66 }
67 return n;
68}
69
70static void print_struct_hostent(struct hostent *host, const char *canon) {
2abb5b3b
ZJS
71 log_info(" \"%s\"", host->h_name);
72 STRV_FOREACH(s, host->h_aliases)
73 log_info(" alias \"%s\"", *s);
74 STRV_FOREACH(s, host->h_addr_list) {
75 union in_addr_union u;
76 _cleanup_free_ char *a = NULL;
77 char family_name[DECIMAL_STR_MAX(int)];
78 int r;
79
80 assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype));
81 memcpy(&u, *s, host->h_length);
82 r = in_addr_to_string(host->h_addrtype, &u, &a);
83 assert_se(r == 0);
84 log_info(" %s %s",
85 af_to_string(host->h_addrtype, family_name, sizeof family_name),
86 a);
87 }
88 if (canon)
89 log_info(" canonical: \"%s\"", canon);
90}
91
92static void test_gethostbyname4_r(void *handle, const char *module, const char *name) {
93 const char *fname;
94 _nss_gethostbyname4_r_t f;
f0cb09bb 95 char buffer[arg_bufsize];
2abb5b3b
ZJS
96 struct gaih_addrtuple *pat = NULL;
97 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
98 int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
99 and will access this variable through *ttlp,
100 so we need to set it to something.
101 I'm not sure if this is a bug in nss-dns
102 or not. */
103 enum nss_status status;
104 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
105 int n;
106
107 fname = strjoina("_nss_", module, "_gethostbyname4_r");
108 f = dlsym(handle, fname);
109 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
08554d47
ZJS
110 if (!f) {
111 log_info("%s not defined", fname);
112 return;
113 }
2abb5b3b
ZJS
114
115 status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl);
116 if (status == NSS_STATUS_SUCCESS) {
5570a097 117 log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%"PRIxPTR" errno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
2abb5b3b
ZJS
118 fname, name,
119 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
5570a097 120 pat ? (uintptr_t) pat - (uintptr_t) buffer : 0,
2abb5b3b
ZJS
121 errno1, errno_to_name(errno1) ?: "---",
122 errno2, hstrerror(errno2),
123 ttl);
124 n = print_gaih_addrtuples(pat);
125 } else {
126 log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s",
127 fname, name,
128 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
129 pat,
130 errno1, errno_to_name(errno1) ?: "---",
131 errno2, hstrerror(errno2));
132 n = 0;
133 }
134
135 if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL)
136 return;
137
bb78da17
YW
138 if (streq(name, "localhost")) {
139 if (streq(module, "myhostname")) {
140 assert_se(status == NSS_STATUS_SUCCESS);
141 assert_se(n == socket_ipv6_is_enabled() + 1);
142
efb9b3ba 143 } else if (streq(module, "resolve") && secure_getenv_bool("SYSTEMD_NSS_RESOLVE_SYNTHESIZE") != 0) {
bb78da17
YW
144 assert_se(status == NSS_STATUS_SUCCESS);
145 if (socket_ipv6_is_enabled())
146 assert_se(n == 2);
147 else
148 assert_se(n <= 2); /* Even if IPv6 is disabled, /etc/hosts may contain ::1. */
149 }
2abb5b3b
ZJS
150 }
151}
152
2abb5b3b
ZJS
153static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) {
154 const char *fname;
155 _nss_gethostbyname3_r_t f;
f0cb09bb 156 char buffer[arg_bufsize];
2abb5b3b
ZJS
157 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
158 int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
159 and will access this variable through *ttlp,
160 so we need to set it to something.
161 I'm not sure if this is a bug in nss-dns
162 or not. */
163 enum nss_status status;
164 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
165 struct hostent host;
166 char *canon;
167 char family_name[DECIMAL_STR_MAX(int)];
168
169 fname = strjoina("_nss_", module, "_gethostbyname3_r");
170 f = dlsym(handle, fname);
171 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
08554d47
ZJS
172 if (!f) {
173 log_info("%s not defined", fname);
174 return;
175 }
2abb5b3b
ZJS
176
177 status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon);
178 log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
179 fname, name, af_to_string(af, family_name, sizeof family_name),
180 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
181 errno1, errno_to_name(errno1) ?: "---",
182 errno2, hstrerror(errno2),
183 ttl);
184 if (status == NSS_STATUS_SUCCESS)
185 print_struct_hostent(&host, canon);
186}
187
188static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) {
189 const char *fname;
190 _nss_gethostbyname2_r_t f;
f0cb09bb 191 char buffer[arg_bufsize];
2abb5b3b
ZJS
192 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
193 enum nss_status status;
194 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
195 struct hostent host;
196 char family_name[DECIMAL_STR_MAX(int)];
197
198 fname = strjoina("_nss_", module, "_gethostbyname2_r");
199 f = dlsym(handle, fname);
200 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
08554d47
ZJS
201 if (!f) {
202 log_info("%s not defined", fname);
203 return;
204 }
2abb5b3b
ZJS
205
206 status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2);
207 log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s",
208 fname, name, af_to_string(af, family_name, sizeof family_name),
209 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
210 errno1, errno_to_name(errno1) ?: "---",
211 errno2, hstrerror(errno2));
212 if (status == NSS_STATUS_SUCCESS)
213 print_struct_hostent(&host, NULL);
214}
215
216static void test_gethostbyname_r(void *handle, const char *module, const char *name) {
217 const char *fname;
218 _nss_gethostbyname_r_t f;
f0cb09bb 219 char buffer[arg_bufsize];
2abb5b3b
ZJS
220 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
221 enum nss_status status;
222 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
223 struct hostent host;
224
225 fname = strjoina("_nss_", module, "_gethostbyname_r");
226 f = dlsym(handle, fname);
227 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
08554d47
ZJS
228 if (!f) {
229 log_info("%s not defined", fname);
230 return;
231 }
2abb5b3b
ZJS
232
233 status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2);
234 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
235 fname, name,
236 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
237 errno1, errno_to_name(errno1) ?: "---",
238 errno2, hstrerror(errno2));
239 if (status == NSS_STATUS_SUCCESS)
240 print_struct_hostent(&host, NULL);
241}
242
243static void test_gethostbyaddr2_r(void *handle,
244 const char *module,
245 const void* addr, socklen_t len,
246 int af) {
247
248 const char *fname;
249 _nss_gethostbyaddr2_r_t f;
f0cb09bb 250 char buffer[arg_bufsize];
2abb5b3b
ZJS
251 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
252 enum nss_status status;
253 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
254 struct hostent host;
255 int32_t ttl = INT32_MAX;
256 _cleanup_free_ char *addr_pretty = NULL;
257
258 fname = strjoina("_nss_", module, "_gethostbyaddr2_r");
259 f = dlsym(handle, fname);
260
261 log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno,
262 "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
08554d47
ZJS
263 if (!f) {
264 log_info("%s not defined", fname);
2abb5b3b 265 return;
08554d47 266 }
2abb5b3b
ZJS
267
268 assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
269
270 status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl);
271 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
272 fname, addr_pretty,
273 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
274 errno1, errno_to_name(errno1) ?: "---",
275 errno2, hstrerror(errno2),
276 ttl);
277 if (status == NSS_STATUS_SUCCESS)
278 print_struct_hostent(&host, NULL);
279}
280
281static void test_gethostbyaddr_r(void *handle,
282 const char *module,
283 const void* addr, socklen_t len,
284 int af) {
285
286 const char *fname;
287 _nss_gethostbyaddr_r_t f;
f0cb09bb 288 char buffer[arg_bufsize];
2abb5b3b
ZJS
289 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
290 enum nss_status status;
291 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
292 struct hostent host;
293 _cleanup_free_ char *addr_pretty = NULL;
294
295 fname = strjoina("_nss_", module, "_gethostbyaddr_r");
296 f = dlsym(handle, fname);
297
298 log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno,
299 "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
08554d47
ZJS
300 if (!f) {
301 log_info("%s not defined", fname);
2abb5b3b 302 return;
08554d47 303 }
2abb5b3b
ZJS
304
305 assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
306
307 status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2);
308 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
309 fname, addr_pretty,
310 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
311 errno1, errno_to_name(errno1) ?: "---",
312 errno2, hstrerror(errno2));
313 if (status == NSS_STATUS_SUCCESS)
314 print_struct_hostent(&host, NULL);
315}
316
317static void test_byname(void *handle, const char *module, const char *name) {
318 test_gethostbyname4_r(handle, module, name);
319 puts("");
320
321 test_gethostbyname3_r(handle, module, name, AF_INET);
322 puts("");
323 test_gethostbyname3_r(handle, module, name, AF_INET6);
324 puts("");
325 test_gethostbyname3_r(handle, module, name, AF_UNSPEC);
326 puts("");
618b3642 327 test_gethostbyname3_r(handle, module, name, AF_UNIX);
2abb5b3b
ZJS
328 puts("");
329
330 test_gethostbyname2_r(handle, module, name, AF_INET);
331 puts("");
332 test_gethostbyname2_r(handle, module, name, AF_INET6);
333 puts("");
334 test_gethostbyname2_r(handle, module, name, AF_UNSPEC);
335 puts("");
618b3642 336 test_gethostbyname2_r(handle, module, name, AF_UNIX);
2abb5b3b
ZJS
337 puts("");
338
339 test_gethostbyname_r(handle, module, name);
340 puts("");
341}
342
343static void test_byaddr(void *handle,
344 const char *module,
345 const void* addr, socklen_t len,
346 int af) {
347 test_gethostbyaddr2_r(handle, module, addr, len, af);
348 puts("");
349
350 test_gethostbyaddr_r(handle, module, addr, len, af);
351 puts("");
352}
353
9f7672b3
ZJS
354static int make_addresses(struct local_address **addresses) {
355 int n;
9f7672b3
ZJS
356 _cleanup_free_ struct local_address *addrs = NULL;
357
358 n = local_addresses(NULL, 0, AF_UNSPEC, &addrs);
359 if (n < 0)
360 log_info_errno(n, "Failed to query local addresses: %m");
361
319a4f4b 362 assert_se(GREEDY_REALLOC(addrs, n + 3));
9f7672b3
ZJS
363
364 addrs[n++] = (struct local_address) { .family = AF_INET,
365 .address.in = { htobe32(0x7F000001) } };
366 addrs[n++] = (struct local_address) { .family = AF_INET,
367 .address.in = { htobe32(0x7F000002) } };
368 addrs[n++] = (struct local_address) { .family = AF_INET6,
369 .address.in6 = in6addr_loopback };
1d6052ba
FS
370
371 *addresses = TAKE_PTR(addrs);
372 return n;
9f7672b3
ZJS
373}
374
890e5a4d 375static int test_one_module(const char *dir,
9f7672b3
ZJS
376 const char *module,
377 char **names,
378 struct local_address *addresses,
379 int n_addresses) {
9f7672b3 380
9f7672b3
ZJS
381 log_info("======== %s ========", module);
382
e2aa384b 383 _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
9f7672b3
ZJS
384 if (!handle)
385 return -EINVAL;
386
387 STRV_FOREACH(name, names)
388 test_byname(handle, module, *name);
389
890e5a4d 390 for (int i = 0; i < n_addresses; i++)
9f7672b3
ZJS
391 test_byaddr(handle, module,
392 &addresses[i].address,
393 FAMILY_ADDRESS_SIZE(addresses[i].family),
394 addresses[i].family);
395
396 log_info(" ");
9f7672b3
ZJS
397 return 0;
398}
399
400static int parse_argv(int argc, char **argv,
401 char ***the_modules,
402 char ***the_names,
403 struct local_address **the_addresses, int *n_addresses) {
404
9f7672b3
ZJS
405 _cleanup_strv_free_ char **modules = NULL, **names = NULL;
406 _cleanup_free_ struct local_address *addrs = NULL;
f0cb09bb 407 const char *p;
f0d12668 408 int r, n = 0;
9f7672b3 409
f0cb09bb
ZJS
410 p = getenv("SYSTEMD_TEST_NSS_BUFSIZE");
411 if (p) {
412 r = safe_atozu(p, &arg_bufsize);
413 if (r < 0)
414 return log_error_errno(r, "Failed to parse $SYSTEMD_TEST_NSS_BUFSIZE");
415 }
416
9f7672b3 417 if (argc > 1)
bea1a013 418 modules = strv_new(argv[1]);
9f7672b3
ZJS
419 else
420 modules = strv_new(
08540a95 421#if ENABLE_NSS_MYHOSTNAME
9f7672b3 422 "myhostname",
2abb5b3b 423#endif
08540a95 424#if ENABLE_NSS_RESOLVE
9f7672b3 425 "resolve",
2abb5b3b 426#endif
08540a95 427#if ENABLE_NSS_MYMACHINES
9f7672b3 428 "mymachines",
2abb5b3b 429#endif
951280ce 430 NULL);
e2aa384b 431 assert_se(modules);
9f7672b3
ZJS
432
433 if (argc > 2) {
9f7672b3
ZJS
434 int family;
435 union in_addr_union address;
436
437 STRV_FOREACH(name, argv + 2) {
438 r = in_addr_from_string_auto(*name, &family, &address);
439 if (r < 0) {
440 /* assume this is a name */
441 r = strv_extend(&names, *name);
442 if (r < 0)
443 return r;
444 } else {
319a4f4b 445 assert_se(GREEDY_REALLOC0(addrs, n + 1));
9f7672b3
ZJS
446
447 addrs[n++] = (struct local_address) { .family = family,
448 .address = address };
449 }
450 }
451 } else {
3d41b6b8 452 _cleanup_free_ char *hostname = NULL;
e2aa384b 453 assert_se(hostname = gethostname_malloc());
37eba4b3
ZJS
454 assert_se(names = strv_new("localhost",
455 "_gateway",
456 "_outbound",
457 hostname,
458 slow_tests_enabled() ? "foo_no_such_host" : NULL));
9f7672b3
ZJS
459
460 n = make_addresses(&addrs);
e2aa384b 461 assert_se(n >= 0);
9f7672b3
ZJS
462 }
463
f0d12668
ZJS
464 *the_modules = TAKE_PTR(modules);
465 *the_names = TAKE_PTR(names);
466 *the_addresses = TAKE_PTR(addrs);
9f7672b3 467 *n_addresses = n;
9f7672b3
ZJS
468 return 0;
469}
470
f68a2622 471static int run(int argc, char **argv) {
9f7672b3
ZJS
472 _cleanup_free_ char *dir = NULL;
473 _cleanup_strv_free_ char **modules = NULL, **names = NULL;
2abb5b3b 474 _cleanup_free_ struct local_address *addresses = NULL;
6a909d41 475 int n_addresses = 0;
9f7672b3 476 int r;
2abb5b3b 477
f68a2622 478 test_setup_logging(LOG_INFO);
2abb5b3b 479
9f7672b3 480 r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
e2aa384b
ZJS
481 if (r < 0)
482 return log_error_errno(r, "Failed to parse arguments: %m");
2abb5b3b 483
e2aa384b 484 assert_se(path_extract_directory(argv[0], &dir) >= 0);
2abb5b3b 485
9f7672b3
ZJS
486 STRV_FOREACH(module, modules) {
487 r = test_one_module(dir, *module, names, addresses, n_addresses);
488 if (r < 0)
f68a2622 489 return r;
2abb5b3b
ZJS
490 }
491
f68a2622 492 return 0;
2abb5b3b 493}
f68a2622
ZJS
494
495DEFINE_MAIN_FUNCTION(run);