mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-04 21:35:45 +00:00
nss: Introduce a test
A small test to see how is the nss module working. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
917038c110
commit
38e32d4ac1
2
cfg.mk
2
cfg.mk
@ -1139,7 +1139,7 @@ exclude_file_name_regexp--sc_copyright_usage = \
|
|||||||
^COPYING(|\.LESSER)$$
|
^COPYING(|\.LESSER)$$
|
||||||
|
|
||||||
exclude_file_name_regexp--sc_flags_usage = \
|
exclude_file_name_regexp--sc_flags_usage = \
|
||||||
^(docs/|src/util/virnetdevtap\.c$$|tests/vir(cgroup|pci|usb)mock\.c$$)
|
^(docs/|src/util/virnetdevtap\.c$$|tests/(vir(cgroup|pci|usb)|nss)mock\.c$$)
|
||||||
|
|
||||||
exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \
|
exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \
|
||||||
^(src/rpc/gendispatch\.pl$$|tests/)
|
^(src/rpc/gendispatch\.pl$$|tests/)
|
||||||
|
@ -108,6 +108,7 @@ EXTRA_DIST = \
|
|||||||
nodedevschemadata \
|
nodedevschemadata \
|
||||||
nodedevschematest \
|
nodedevschematest \
|
||||||
nodeinfodata \
|
nodeinfodata \
|
||||||
|
nssdata \
|
||||||
nwfilterschematest \
|
nwfilterschematest \
|
||||||
nwfilterxml2firewalldata \
|
nwfilterxml2firewalldata \
|
||||||
nwfilterxml2xmlin \
|
nwfilterxml2xmlin \
|
||||||
@ -190,6 +191,7 @@ test_programs = virshtest sockettest \
|
|||||||
vircaps2xmltest \
|
vircaps2xmltest \
|
||||||
virnetdevtest \
|
virnetdevtest \
|
||||||
virtypedparamtest \
|
virtypedparamtest \
|
||||||
|
nsstest \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if WITH_REMOTE
|
if WITH_REMOTE
|
||||||
@ -421,6 +423,7 @@ test_libraries = libshunload.la \
|
|||||||
virpcimock.la \
|
virpcimock.la \
|
||||||
virnetdevmock.la \
|
virnetdevmock.la \
|
||||||
nodeinfomock.la \
|
nodeinfomock.la \
|
||||||
|
nssmock.la \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
if WITH_QEMU
|
if WITH_QEMU
|
||||||
test_libraries += libqemumonitortestutils.la \
|
test_libraries += libqemumonitortestutils.la \
|
||||||
@ -1064,6 +1067,21 @@ nodeinfomock_la_CFLAGS = $(AM_CFLAGS)
|
|||||||
nodeinfomock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
|
nodeinfomock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
|
||||||
nodeinfomock_la_LIBADD = $(MOCKLIBS_LIBS)
|
nodeinfomock_la_LIBADD = $(MOCKLIBS_LIBS)
|
||||||
|
|
||||||
|
nsstest_SOURCES = \
|
||||||
|
nsstest.c testutils.h testutils.c
|
||||||
|
nsstest_CFLAGS = \
|
||||||
|
$(AM_CFLAGS) \
|
||||||
|
-I$(top_srcdir)/tools/nss
|
||||||
|
nsstest_LDADD = \
|
||||||
|
$(LDADDS) \
|
||||||
|
../tools/nss/libnss_libvirt_impl.la
|
||||||
|
|
||||||
|
nssmock_la_SOURCES = \
|
||||||
|
nssmock.c
|
||||||
|
nssmock_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
nssmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
|
||||||
|
nssmock_la_LIBADD = $(MOCKLIBS_LIBS)
|
||||||
|
|
||||||
virnetdevtest_SOURCES = \
|
virnetdevtest_SOURCES = \
|
||||||
virnetdevtest.c testutils.h testutils.c
|
virnetdevtest.c testutils.h testutils.c
|
||||||
virnetdevtest_CFLAGS = $(AM_CFLAGS) $(LIBNL_CFLAGS)
|
virnetdevtest_CFLAGS = $(AM_CFLAGS) $(LIBNL_CFLAGS)
|
||||||
|
20
tests/nssdata/virbr0.status
Normal file
20
tests/nssdata/virbr0.status
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"ip-address": "192.168.122.197",
|
||||||
|
"mac-address": "52:54:00:a4:6f:91",
|
||||||
|
"hostname": "fedora",
|
||||||
|
"expiry-time": 1900000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ip-address": "192.168.122.198",
|
||||||
|
"mac-address": "52:54:00:a4:6f:92",
|
||||||
|
"hostname": "fedora",
|
||||||
|
"expiry-time": 1900000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ip-address": "192.168.122.254",
|
||||||
|
"mac-address": "52:54:00:3a:b5:0c",
|
||||||
|
"hostname": "gentoo",
|
||||||
|
"expiry-time": 2000000000
|
||||||
|
}
|
||||||
|
]
|
20
tests/nssdata/virbr1.status
Normal file
20
tests/nssdata/virbr1.status
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"ip-address": "192.168.122.199",
|
||||||
|
"mac-address": "52:54:00:a4:6f:93",
|
||||||
|
"hostname": "fedora",
|
||||||
|
"expiry-time": 1900000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ip-address": "2001:1234:dead:beef::2",
|
||||||
|
"mac-address": "52:54:00:04:be:64",
|
||||||
|
"hostname": "gentoo",
|
||||||
|
"expiry-time": 1900000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ip-address": "192.168.122.200",
|
||||||
|
"mac-address": "52:54:00:a4:6f:94",
|
||||||
|
"hostname": "fedora",
|
||||||
|
"expiry-time": 1
|
||||||
|
}
|
||||||
|
]
|
140
tests/nssmock.c
Normal file
140
tests/nssmock.c
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library 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.
|
||||||
|
*
|
||||||
|
* This library 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 this library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Michal Privoznik <mprivozn@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <dlfcn.h>
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <dirent.h>
|
||||||
|
# include <sys/stat.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
|
||||||
|
# include "configmake.h"
|
||||||
|
# include "internal.h"
|
||||||
|
# include "virstring.h"
|
||||||
|
# include "viralloc.h"
|
||||||
|
|
||||||
|
static int (*realopen)(const char *path, int flags, ...);
|
||||||
|
static DIR * (*realopendir)(const char *name);
|
||||||
|
|
||||||
|
# define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/"
|
||||||
|
|
||||||
|
# define STDERR(...) \
|
||||||
|
fprintf(stderr, "%s %zu: ", __FUNCTION__, (size_t) __LINE__); \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
fprintf(stderr, "\n"); \
|
||||||
|
|
||||||
|
# define ABORT(...) \
|
||||||
|
do { \
|
||||||
|
STDERR(__VA_ARGS__); \
|
||||||
|
abort(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
# define ABORT_OOM() \
|
||||||
|
ABORT("Out of memory")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions to load the symbols and init the environment
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
init_syms(void)
|
||||||
|
{
|
||||||
|
if (realopen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
# define LOAD_SYM(name) \
|
||||||
|
do { \
|
||||||
|
if (!(real ## name = dlsym(RTLD_NEXT, #name))) \
|
||||||
|
ABORT("Cannot find real '%s' symbol\n", #name); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
LOAD_SYM(open);
|
||||||
|
LOAD_SYM(opendir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getrealpath(char **newpath,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
if (STRPREFIX(path, LEASEDIR)) {
|
||||||
|
if (virAsprintfQuiet(newpath, "%s/nssdata/%s",
|
||||||
|
abs_srcdir,
|
||||||
|
path + strlen(LEASEDIR)) < 0) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (VIR_STRDUP_QUIET(*newpath, path) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
open(const char *path, int flags, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *newpath = NULL;
|
||||||
|
|
||||||
|
init_syms();
|
||||||
|
|
||||||
|
if (STRPREFIX(path, LEASEDIR) &&
|
||||||
|
getrealpath(&newpath, path) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (flags & O_CREAT) {
|
||||||
|
va_list ap;
|
||||||
|
mode_t mode;
|
||||||
|
va_start(ap, flags);
|
||||||
|
mode = va_arg(ap, mode_t);
|
||||||
|
va_end(ap);
|
||||||
|
ret = realopen(newpath ? newpath : path, flags, mode);
|
||||||
|
} else {
|
||||||
|
ret = realopen(newpath ? newpath : path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_FREE(newpath);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR *
|
||||||
|
opendir(const char *path)
|
||||||
|
{
|
||||||
|
DIR *ret;
|
||||||
|
char *newpath = NULL;
|
||||||
|
|
||||||
|
init_syms();
|
||||||
|
|
||||||
|
if (STRPREFIX(path, LEASEDIR) &&
|
||||||
|
getrealpath(&newpath, path) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = realopendir(newpath ? newpath : path);
|
||||||
|
|
||||||
|
VIR_FREE(newpath);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* Nothing to override on non-__linux__ platforms */
|
||||||
|
#endif
|
208
tests/nsstest.c
Normal file
208
tests/nsstest.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library 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.
|
||||||
|
*
|
||||||
|
* This library 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 this library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Michal Privoznik <mprivozn@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "testutils.h"
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
# include <stdbool.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# include "libvirt_nss.h"
|
||||||
|
# include "virsocketaddr.h"
|
||||||
|
|
||||||
|
# define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
|
# define BUF_SIZE 1024
|
||||||
|
|
||||||
|
struct testNSSData {
|
||||||
|
const char *hostname;
|
||||||
|
const char *const *ipAddr;
|
||||||
|
int af;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
testGetHostByName(const void *opaque)
|
||||||
|
{
|
||||||
|
const struct testNSSData *data = opaque;
|
||||||
|
const bool existent = data->hostname && data->ipAddr && data->ipAddr[0];
|
||||||
|
int ret = -1;
|
||||||
|
struct hostent resolved;
|
||||||
|
char buf[BUF_SIZE] = { 0 };
|
||||||
|
char **addrList;
|
||||||
|
int rv, tmp_errno = 0, tmp_herrno = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
memset(&resolved, 0, sizeof(resolved));
|
||||||
|
|
||||||
|
rv = _nss_libvirt_gethostbyname2_r(data->hostname,
|
||||||
|
data->af,
|
||||||
|
&resolved,
|
||||||
|
buf, sizeof(buf),
|
||||||
|
&tmp_errno,
|
||||||
|
&tmp_herrno);
|
||||||
|
|
||||||
|
if (rv == NSS_STATUS_TRYAGAIN ||
|
||||||
|
rv == NSS_STATUS_UNAVAIL ||
|
||||||
|
rv == NSS_STATUS_RETURN) {
|
||||||
|
/* Resolving failed in unexpected fashion. */
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Resolving of %s failed due to internal error",
|
||||||
|
data->hostname);
|
||||||
|
goto cleanup;
|
||||||
|
} else if (rv == NSS_STATUS_NOTFOUND) {
|
||||||
|
/* Resolving failed. Should it? */
|
||||||
|
if (!existent)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Resolving of %s failed",
|
||||||
|
data->hostname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolving succeeded. Should it? */
|
||||||
|
if (!existent) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Resolving of %s succeeded but was expected to fail",
|
||||||
|
data->hostname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now lets see if resolved address match our expectations. */
|
||||||
|
|
||||||
|
if (!resolved.h_name) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
"resolved.h_name empty");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->af != AF_UNSPEC &&
|
||||||
|
resolved.h_addrtype != data->af) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Expected AF_INET (%d) got %d",
|
||||||
|
data->af, resolved.h_addrtype);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((resolved.h_addrtype == AF_INET && resolved.h_length != 4) ||
|
||||||
|
(resolved.h_addrtype == AF_INET6 && resolved.h_length != 16)) {
|
||||||
|
/* IPv4 addresses are encoded into 4 bytes */
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Expected %d bytes long address, got %d",
|
||||||
|
resolved.h_addrtype == AF_INET ? 4 : 16,
|
||||||
|
resolved.h_length);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resolved.h_addr_list) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
"resolved.h_addr_list empty");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
addrList = resolved.h_addr_list;
|
||||||
|
while (*addrList) {
|
||||||
|
virSocketAddr sa;
|
||||||
|
char *ipAddr;
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
|
||||||
|
if (resolved.h_addrtype == AF_INET) {
|
||||||
|
/* For some reason, virSocketAddrSetIPv4Addr does htonl() conversion.
|
||||||
|
* But the data we already have is in network order. */
|
||||||
|
virSocketAddrSetIPv4Addr(&sa, ntohl(*((uint32_t *) *addrList)));
|
||||||
|
} else {
|
||||||
|
virSocketAddrSetIPv6Addr(&sa, (uint32_t *) *addrList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ipAddr = virSocketAddrFormat(&sa))) {
|
||||||
|
/* error reported by helper */
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data->ipAddr[i]) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Unexpected address %s", ipAddr);
|
||||||
|
VIR_FREE(ipAddr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STRNEQ(data->ipAddr[i], ipAddr)) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Address mismatch. Expected %s got %s",
|
||||||
|
data->ipAddr[i], ipAddr);
|
||||||
|
VIR_FREE(ipAddr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
VIR_FREE(ipAddr);
|
||||||
|
|
||||||
|
addrList++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->ipAddr[i]) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"Address mismatch. Expected %s got nothing",
|
||||||
|
data->ipAddr[i]);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mymain(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
# define DO_TEST(name, family, ...) \
|
||||||
|
do { \
|
||||||
|
const char *addr[] = { __VA_ARGS__, NULL}; \
|
||||||
|
struct testNSSData data = { \
|
||||||
|
.hostname = name, .ipAddr = addr, .af = family, \
|
||||||
|
}; \
|
||||||
|
if (virtTestRun(name, testGetHostByName, &data) < 0) \
|
||||||
|
ret = -1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
DO_TEST("fedora", AF_INET, "192.168.122.197", "192.168.122.198", "192.168.122.199");
|
||||||
|
DO_TEST("gentoo", AF_INET, "192.168.122.254");
|
||||||
|
DO_TEST("gentoo", AF_INET6, "2001:1234:dead:beef::2");
|
||||||
|
DO_TEST("gentoo", AF_UNSPEC, "192.168.122.254");
|
||||||
|
DO_TEST("non-existent", AF_UNSPEC, NULL);
|
||||||
|
|
||||||
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/nssmock.so")
|
||||||
|
#else
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
return EXIT_AM_SKIP;
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user