From cf2d43e7f47aaa5ea295b40fb80478883e74a48a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 3 Mar 2016 15:35:34 -0500 Subject: Move nss typedefs into nss-util.h In preparation for subsequent changes. --- src/basic/nss-util.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/basic') diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index df565a3593..14e950869d 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -154,3 +154,27 @@ enum nss_status _nss_##module##_getgrgid_r( \ struct group *gr, \ char *buffer, size_t buflen, \ int *errnop) _public_ + +typedef enum nss_status (*_nss_gethostbyname4_r_t)( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + +typedef enum nss_status (*_nss_gethostbyname3_r_t)( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp); + +typedef enum nss_status (*_nss_gethostbyaddr2_r_t)( + const void* addr, socklen_t len, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); -- cgit v1.2.3-54-g00ecf From 8e98476e143519aa3f0a2e0db6fccfe9ef134cbc Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 4 Mar 2016 11:28:04 -0500 Subject: string-table: split long definitions --- src/basic/string-table.h | 54 +++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 21 deletions(-) (limited to 'src/basic') diff --git a/src/basic/string-table.h b/src/basic/string-table.h index b180488fe8..d88625fca7 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -56,26 +56,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } -#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) - -#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ +#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \ + scope int name##_to_string_alloc(type i, char **str) { \ char *s; \ if (i < 0 || i > max) \ return -ERANGE; \ @@ -89,7 +71,9 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k } \ *str = s; \ return 0; \ - } \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \ type name##_from_string(const char *s) { \ type i; \ unsigned u = 0; \ @@ -102,4 +86,32 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) u; \ return (type) -1; \ } \ + + +#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) + +#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) -- cgit v1.2.3-54-g00ecf From 2abb5b3b10e3a9ed8ffd0189e8a1828ec086f69e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 4 Mar 2016 10:50:45 -0500 Subject: test-nss: test the resolution of various names nss-dns is also "tested". It should be almost always available, and provides a reference for comparison. --- .gitignore | 1 + Makefile.am | 11 ++ configure.ac | 4 +- src/basic/nss-util.h | 19 +++ src/test/test-nss.c | 448 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 src/test/test-nss.c (limited to 'src/basic') diff --git a/.gitignore b/.gitignore index 18db046cac..0e467b0c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -230,6 +230,7 @@ /test-network /test-network-tables /test-ns +/test-nss /test-parse-util /test-path /test-path-lookup diff --git a/Makefile.am b/Makefile.am index 0f17bad8b1..dc9f9afa9c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4777,6 +4777,17 @@ EXTRA_DIST += \ units/systemd-timesyncd.service.in \ src/timesync/timesyncd.conf.in +# ------------------------------------------------------------------------------ +test_nss_SOURCES = \ + src/test/test-nss.c + +test_nss_LDADD = \ + libsystemd-internal.la \ + -ldl + +tests += \ + test-nss + # ------------------------------------------------------------------------------ if HAVE_MYHOSTNAME libnss_myhostname_la_SOURCES = \ diff --git a/configure.ac b/configure.ac index e55d1a02a6..a02185d252 100644 --- a/configure.ac +++ b/configure.ac @@ -1008,9 +1008,9 @@ have_machined=no AC_ARG_ENABLE(machined, AS_HELP_STRING([--disable-machined], [disable machine daemon])) if test "x$enable_machined" != "xno"; then have_machined=yes + AC_DEFINE(HAVE_MACHINED, [1], [systemd-machined is enabled]) fi AM_CONDITIONAL(ENABLE_MACHINED, [test "$have_machined" = "yes"]) -AS_IF([test "$have_machined" = "yes"], [ AC_DEFINE(HAVE_MACHINED, [1], [Machined support available]) ]) # ------------------------------------------------------------------------------ have_importd=no @@ -1120,6 +1120,7 @@ AS_IF([test "x$enable_resolved" != "xno"], [ have_resolved=yes M4_DEFINES="$M4_DEFINES -DENABLE_RESOLVED" + AC_DEFINE(HAVE_RESOLVED, [1], [systemd-resolved is enabled]) ]) AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"]) @@ -1321,6 +1322,7 @@ if test "x$enable_myhostname" != "xno"; then AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn]) have_myhostname=yes + AC_DEFINE(HAVE_MYHOSTNAME, [1], [nss-myhostname is enabled]) fi AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"]) diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index 14e950869d..bf7c4854fc 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -171,6 +171,19 @@ typedef enum nss_status (*_nss_gethostbyname3_r_t)( int32_t *ttlp, char **canonp); +typedef enum nss_status (*_nss_gethostbyname2_r_t)( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop); + +typedef enum nss_status (*_nss_gethostbyname_r_t)( + const char *name, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop); + typedef enum nss_status (*_nss_gethostbyaddr2_r_t)( const void* addr, socklen_t len, int af, @@ -178,3 +191,9 @@ typedef enum nss_status (*_nss_gethostbyaddr2_r_t)( char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp); +typedef enum nss_status (*_nss_gethostbyaddr_r_t)( + const void* addr, socklen_t len, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop); diff --git a/src/test/test-nss.c b/src/test/test-nss.c new file mode 100644 index 0000000000..9c13288d2e --- /dev/null +++ b/src/test/test-nss.c @@ -0,0 +1,448 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "log.h" +#include "nss-util.h" +#include "path-util.h" +#include "string-util.h" +#include "alloc-util.h" +#include "in-addr-util.h" +#include "hexdecoct.h" +#include "af-list.h" +#include "stdio-util.h" +#include "strv.h" +#include "errno-list.h" +#include "hostname-util.h" +#include "local-addresses.h" + +static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) { + switch (status) { + case NSS_STATUS_TRYAGAIN: + return "NSS_STATUS_TRYAGAIN"; + case NSS_STATUS_UNAVAIL: + return "NSS_STATUS_UNAVAIL"; + case NSS_STATUS_NOTFOUND: + return "NSS_STATUS_NOTFOUND"; + case NSS_STATUS_SUCCESS: + return "NSS_STATUS_SUCCESS"; + case NSS_STATUS_RETURN: + return "NSS_STATUS_RETURN"; + default: + snprintf(buf, buf_len, "%i", status); + return buf; + } +}; + +static const char* af_to_string(int family, char *buf, size_t buf_len) { + const char *name; + + if (family == AF_UNSPEC) + return "*"; + + name = af_to_name(family); + if (name) + return name; + + snprintf(buf, buf_len, "%i", family); + return buf; +} + +static void* open_handle(const char* dir, const char* module, int flags) { + const char *path; + void *handle; + + if (dir) + path = strjoina(dir, "/.libs/libnss_", module, ".so.2"); + else + path = strjoina("libnss_", module, ".so.2"); + + handle = dlopen(path, flags); + assert_se(handle); + return handle; +} + +static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) { + const struct gaih_addrtuple *it; + int n = 0; + + for (it = tuples; it; it = it->next) { + _cleanup_free_ char *a = NULL; + union in_addr_union u; + int r; + char family_name[DECIMAL_STR_MAX(int)]; + char ifname[IF_NAMESIZE]; + + memcpy(&u, it->addr, 16); + r = in_addr_to_string(it->family, &u, &a); + assert_se(r == 0 || r == -EAFNOSUPPORT); + if (r == -EAFNOSUPPORT) + assert_se((a = hexmem(it->addr, 16))); + + if (it->scopeid == 0) + goto numerical_index; + + if (if_indextoname(it->scopeid, ifname) == NULL) { + log_warning("if_indextoname(%d) failed: %m", it->scopeid); + numerical_index: + xsprintf(ifname, "%i", it->scopeid); + }; + + log_info(" \"%s\" %s %s %%%s", + it->name, + af_to_string(it->family, family_name, sizeof family_name), + a, + ifname); + n ++; + } + return n; +} + +static void print_struct_hostent(struct hostent *host, const char *canon) { + char **s; + + log_info(" \"%s\"", host->h_name); + STRV_FOREACH(s, host->h_aliases) + log_info(" alias \"%s\"", *s); + STRV_FOREACH(s, host->h_addr_list) { + union in_addr_union u; + _cleanup_free_ char *a = NULL; + char family_name[DECIMAL_STR_MAX(int)]; + int r; + + assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype)); + memcpy(&u, *s, host->h_length); + r = in_addr_to_string(host->h_addrtype, &u, &a); + assert_se(r == 0); + log_info(" %s %s", + af_to_string(host->h_addrtype, family_name, sizeof family_name), + a); + } + if (canon) + log_info(" canonical: \"%s\"", canon); +} + +static void test_gethostbyname4_r(void *handle, const char *module, const char *name) { + const char *fname; + _nss_gethostbyname4_r_t f; + char buffer[2000]; + struct gaih_addrtuple *pat = NULL; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl, + and will access this variable through *ttlp, + so we need to set it to something. + I'm not sure if this is a bug in nss-dns + or not. */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + int n; + + fname = strjoina("_nss_", module, "_gethostbyname4_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl); + if (status == NSS_STATUS_SUCCESS) { + log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%tx errno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + pat ? (char*) pat - buffer : 0, + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + n = print_gaih_addrtuples(pat); + } else { + log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s", + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + pat, + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + n = 0; + } + + if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL) + return; + + if (STR_IN_SET(module, "myhostname", "resolve") && streq(name, "localhost")) { + assert_se(status == NSS_STATUS_SUCCESS); + assert_se(n == 2); + } +} + + +static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) { + const char *fname; + _nss_gethostbyname3_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl, + and will access this variable through *ttlp, + so we need to set it to something. + I'm not sure if this is a bug in nss-dns + or not. */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + char *canon; + char family_name[DECIMAL_STR_MAX(int)]; + + fname = strjoina("_nss_", module, "_gethostbyname3_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon); + log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, name, af_to_string(af, family_name, sizeof family_name), + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, canon); +} + +static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) { + const char *fname; + _nss_gethostbyname2_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + char family_name[DECIMAL_STR_MAX(int)]; + + fname = strjoina("_nss_", module, "_gethostbyname2_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, name, af_to_string(af, family_name, sizeof family_name), + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyname_r(void *handle, const char *module, const char *name) { + const char *fname; + _nss_gethostbyname_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + + fname = strjoina("_nss_", module, "_gethostbyname_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyaddr2_r(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + + const char *fname; + _nss_gethostbyaddr2_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + int32_t ttl = INT32_MAX; + _cleanup_free_ char *addr_pretty = NULL; + + fname = strjoina("_nss_", module, "_gethostbyaddr2_r"); + f = dlsym(handle, fname); + + log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno, + "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f); + if (!f) + return; + + assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0); + + status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, addr_pretty, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyaddr_r(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + + const char *fname; + _nss_gethostbyaddr_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + _cleanup_free_ char *addr_pretty = NULL; + + fname = strjoina("_nss_", module, "_gethostbyaddr_r"); + f = dlsym(handle, fname); + + log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno, + "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f); + if (!f) + return; + + assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0); + + status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, addr_pretty, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_byname(void *handle, const char *module, const char *name) { + test_gethostbyname4_r(handle, module, name); + puts(""); + + test_gethostbyname3_r(handle, module, name, AF_INET); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_INET6); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_UNSPEC); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_LOCAL); + puts(""); + + test_gethostbyname2_r(handle, module, name, AF_INET); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_INET6); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_UNSPEC); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_LOCAL); + puts(""); + + test_gethostbyname_r(handle, module, name); + puts(""); +} + +static void test_byaddr(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + test_gethostbyaddr2_r(handle, module, addr, len, af); + puts(""); + + test_gethostbyaddr_r(handle, module, addr, len, af); + puts(""); +} + +#ifdef HAVE_MYHOSTNAME +# define MODULE1 "myhostname\0" +#endif +#ifdef HAVE_RESOLVED +# define MODULE2 "resolve\0" +#endif +#ifdef HAVE_MACHINED +# define MODULE3 "mymachines\0" +#endif +#define MODULE4 "dns\0" + +int main(int argc, char **argv) { + _cleanup_free_ char *dir = NULL, *hostname = NULL; + const char *module; + + const uint32_t local_address_ipv4 = htonl(0x7F000001); + const uint32_t local_address_ipv4_2 = htonl(0x7F000002); + _cleanup_free_ struct local_address *addresses = NULL; + int n_addresses; + + log_set_max_level(LOG_INFO); + log_parse_environment(); + + dir = dirname_malloc(argv[0]); + assert_se(dir); + + hostname = gethostname_malloc(); + assert_se(hostname); + + n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses); + if (n_addresses < 0) { + log_info_errno(n_addresses, "Failed to query local addresses: %m"); + n_addresses = 0; + } + + NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) { + void *handle; + const char *name; + int i; + + log_info("======== %s ========", module); + + handle = open_handle(streq(module, "dns") ? NULL : dir, + module, + RTLD_LAZY|RTLD_NODELETE); + NULSTR_FOREACH(name, "localhost\0" "gateway\0" "foo_no_such_host\0") + test_byname(handle, module, name); + + test_byname(handle, module, hostname); + + test_byaddr(handle, module, &local_address_ipv4, sizeof local_address_ipv4, AF_INET); + test_byaddr(handle, module, &local_address_ipv4_2, sizeof local_address_ipv4_2, AF_INET); + test_byaddr(handle, module, &in6addr_loopback, sizeof in6addr_loopback, AF_INET6); + + for (i = 0; i < n_addresses; i++) + test_byaddr(handle, module, + &addresses[i].address, + FAMILY_ADDRESS_SIZE(addresses[i].family), + addresses[i].family); + + dlclose(handle); + + log_info(" "); + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3-54-g00ecf