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