Merge pull request #2947 from keszybz/test-nss

Add a test for nss modules and some related fixes
This commit is contained in:
Lennart Poettering 2016-04-06 10:48:55 +02:00
commit 056f0498fe
9 changed files with 585 additions and 103 deletions

1
.gitignore vendored
View File

@ -238,6 +238,7 @@
/test-network
/test-network-tables
/test-ns
/test-nss
/test-parse-util
/test-path
/test-path-lookup

View File

@ -4874,6 +4874,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 = \

View File

@ -1019,9 +1019,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
@ -1131,6 +1131,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"])
@ -1332,6 +1333,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"])

View File

@ -154,3 +154,46 @@ 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_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,
struct hostent *result,
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);

View File

@ -56,6 +56,38 @@ 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_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; \
if (i < (type) ELEMENTSOF(name##_table)) { \
s = strdup(name##_table[i]); \
if (!s) \
return -ENOMEM; \
} else { \
if (asprintf(&s, "%i", i) < 0) \
return -ENOMEM; \
} \
*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; \
if (!s) \
return (type) -1; \
for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
if (streq_ptr(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
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) \
@ -75,31 +107,11 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
/* 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) { \
char *s; \
if (i < 0 || i > max) \
return -ERANGE; \
if (i < (type) ELEMENTSOF(name##_table)) { \
s = strdup(name##_table[i]); \
if (!s) \
return -ENOMEM; \
} else { \
if (asprintf(&s, "%i", i) < 0) \
return -ENOMEM; \
} \
*str = s; \
return 0; \
} \
type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
if (!s) \
return (type) -1; \
for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
if (streq_ptr(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
return (type) u; \
return (type) -1; \
} \
_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)

View File

@ -155,8 +155,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
n_list++;
};
if (n_list > 0)
qsort(list, n_list, sizeof(struct local_address), address_compare);
qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
*ret = list;
list = NULL;

View File

@ -127,7 +127,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
memcpy(r_name, canonical, l+1);
idx = ALIGN(l+1);
if (n_addresses <= 0) {
assert(n_addresses >= 0);
if (n_addresses == 0) {
/* Second, fill in IPv6 tuple */
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
r_tuple->next = r_tuple_prev;
@ -453,38 +454,33 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
}
n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
if (n_addresses > 0) {
for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
if (af != a->family)
continue;
for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
if (af != a->family)
continue;
if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
goto found;
}
if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
goto found;
}
addresses = mfree(addresses);
n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
if (n_addresses > 0) {
for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
if (af != a->family)
continue;
for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
if (af != a->family)
continue;
if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
canonical = "gateway";
goto found;
}
if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
canonical = "gateway";
goto found;
}
}
*errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
found:
if (!canonical || (!additional && additional_from_hostname)) {
if (!canonical || additional_from_hostname) {
hn = gethostname_malloc();
if (!hn) {
*errnop = ENOMEM;
@ -494,8 +490,7 @@ found:
if (!canonical)
canonical = hn;
if (!additional && additional_from_hostname)
else
additional = hn;
}

View File

@ -117,13 +117,6 @@ enum nss_status _nss_resolve_gethostbyname4_r(
int *errnop, int *h_errnop,
int32_t *ttlp) {
enum nss_status (*fallback)(
const char *name,
struct gaih_addrtuple **pat,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp);
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
@ -275,15 +268,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
return NSS_STATUS_SUCCESS;
fallback:
fallback = (enum nss_status (*)(const char *name,
struct gaih_addrtuple **pat,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp))
find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
{
_nss_gethostbyname4_r_t fallback;
if (fallback)
return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
fallback = (_nss_gethostbyname4_r_t)
find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
if (fallback)
return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
}
fail:
*errnop = -r;
@ -300,15 +293,6 @@ enum nss_status _nss_resolve_gethostbyname3_r(
int32_t *ttlp,
char **canonp) {
enum nss_status (*fallback)(
const char *name,
int af,
struct hostent *result,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp,
char **canonp);
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *r_name, *r_aliases, *r_addr, *r_addr_list;
@ -480,16 +464,14 @@ enum nss_status _nss_resolve_gethostbyname3_r(
return NSS_STATUS_SUCCESS;
fallback:
fallback = (enum nss_status (*)(const char *name,
int af,
struct hostent *result,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp,
char **canonp))
find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
if (fallback)
return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
{
_nss_gethostbyname3_r_t fallback;
fallback = (_nss_gethostbyname3_r_t)
find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
if (fallback)
return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
}
fail:
*errnop = -r;
@ -505,15 +487,6 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
int *errnop, int *h_errnop,
int32_t *ttlp) {
enum nss_status (*fallback)(
const void* addr, socklen_t len,
int af,
struct hostent *result,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp);
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *r_name, *r_aliases, *r_addr, *r_addr_list;
@ -682,17 +655,15 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
return NSS_STATUS_SUCCESS;
fallback:
fallback = (enum nss_status (*)(
const void* addr, socklen_t len,
int af,
struct hostent *result,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp))
find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
{
_nss_gethostbyaddr2_r_t fallback;
if (fallback)
return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
fallback = (_nss_gethostbyaddr2_r_t)
find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
if (fallback)
return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
}
fail:
*errnop = -r;

448
src/test/test-nss.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
***/
#include <dlfcn.h>
#include <stdlib.h>
#include <net/if.h>
#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;
}