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