[libvirt] [PATCH v5 0/9] NSS module for libvirt

v5 of: https://www.redhat.com/archives/libvir-list/2016-February/msg00693.html diff to v4: - Dropped the virjson const correctness patch - Worked in Martin's review (small nits here and there) - Dropped libxml2 dependency Patches 1, 4, and 5 have been ACKed already, but I'm sending them for completeness. Michal Privoznik (9): Export virLease* functions for leases file handling virLeaseReadCustomLeaseFile: Allow server_duid to be NULL virsocketaddr: Introduce virSocketAddrSetIPv6Addr Initial support for NSS plugin skeleton libvirt.spec.in: Introduce libvirt-nss package nss: Implement _nss_libvirt_gethostbyname3_r Implement _nss_libvirt_gethostbyname4_r nss: Introduce a test tests: Introduce nsslinktest cfg.mk | 2 +- config-post.h | 24 +++ configure.ac | 2 + libvirt.spec.in | 21 ++ m4/virt-nss.m4 | 51 +++++ po/POTFILES.in | 1 + src/Makefile.am | 58 ++++++ src/libvirt_private.syms | 7 + src/network/leaseshelper.c | 270 +------------------------- src/util/virfile.c | 3 +- src/util/virfile.h | 10 +- src/util/virlease.c | 305 +++++++++++++++++++++++++++++ src/util/virlease.h | 44 +++++ src/util/virsocketaddr.c | 15 ++ src/util/virsocketaddr.h | 1 + tests/Makefile.am | 31 ++- tests/nssdata/virbr0.status | 20 ++ tests/nssdata/virbr1.status | 20 ++ tests/nsslinktest.c | 39 ++++ tests/nssmock.c | 140 ++++++++++++++ tests/nsstest.c | 208 ++++++++++++++++++++ tools/Makefile.am | 43 +++++ tools/nss/libvirt_nss.c | 458 ++++++++++++++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.h | 52 +++++ tools/nss/libvirt_nss.syms | 12 ++ 25 files changed, 1562 insertions(+), 275 deletions(-) create mode 100644 m4/virt-nss.m4 create mode 100644 src/util/virlease.c create mode 100644 src/util/virlease.h create mode 100644 tests/nssdata/virbr0.status create mode 100644 tests/nssdata/virbr1.status create mode 100644 tests/nsslinktest.c create mode 100644 tests/nssmock.c create mode 100644 tests/nsstest.c create mode 100644 tools/nss/libvirt_nss.c create mode 100644 tools/nss/libvirt_nss.h create mode 100644 tools/nss/libvirt_nss.syms -- 2.4.10

These functions are going to be reused very shortly. So instead of duplicating the code, lets move them into utils module. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 6 + src/network/leaseshelper.c | 270 +--------------------------------------- src/util/virlease.c | 304 +++++++++++++++++++++++++++++++++++++++++++++ src/util/virlease.h | 44 +++++++ 6 files changed, 357 insertions(+), 269 deletions(-) create mode 100644 src/util/virlease.c create mode 100644 src/util/virlease.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 171d2b1..aa086cc 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -205,6 +205,7 @@ src/util/viriptables.c src/util/viriscsi.c src/util/virjson.c src/util/virkeyfile.c +src/util/virlease.c src/util/virlockspace.c src/util/virnetdev.c src/util/virnetdevbandwidth.c diff --git a/src/Makefile.am b/src/Makefile.am index d57d303..2ba397f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -126,6 +126,7 @@ UTIL_SOURCES = \ util/virkeycode.c util/virkeycode.h \ util/virkeyfile.c util/virkeyfile.h \ util/virkeymaps.h \ + util/virlease.c util/virlease.h \ util/virlockspace.c util/virlockspace.h \ util/virlog.c util/virlog.h \ util/virmacaddr.h util/virmacaddr.c \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 55c3047..3ae18b8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1719,6 +1719,12 @@ virKModLoad; virKModUnload; +# util/virlease.h +virLeaseNew; +virLeasePrintLeases; +virLeaseReadCustomLeaseFile; + + # util/virlockspace.h virLockSpaceAcquireResource; virLockSpaceCreateResource; diff --git a/src/network/leaseshelper.c b/src/network/leaseshelper.c index 55ddd58..097cd11 100644 --- a/src/network/leaseshelper.c +++ b/src/network/leaseshelper.c @@ -28,34 +28,19 @@ #include <locale.h> #include <stdio.h> #include <stdlib.h> -#include <sys/stat.h> -#include "virutil.h" #include "virthread.h" #include "virfile.h" #include "virpidfile.h" -#include "virbuffer.h" #include "virstring.h" #include "virerror.h" #include "viralloc.h" #include "virjson.h" +#include "virlease.h" #include "configmake.h" #define VIR_FROM_THIS VIR_FROM_NETWORK -/** - * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: - * - * Macro providing the upper limit on the size of leases file - */ -#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024) - -/* - * Use this when passing possibly-NULL strings to printf-a-likes. - * Required for unknown parameters during init call. - */ -#define EMPTY_STR(s) ((s) ? (s) : "*") - static const char *program_name; /* Display version information. */ @@ -105,259 +90,6 @@ VIR_ENUM_DECL(virLeaseAction); VIR_ENUM_IMPL(virLeaseAction, VIR_LEASE_ACTION_LAST, "add", "old", "del", "init"); -static int -virLeaseReadCustomLeaseFile(virJSONValuePtr leases_array_new, - const char *custom_lease_file, - const char *ip_to_delete, - char **server_duid) -{ - char *lease_entries = NULL; - virJSONValuePtr leases_array = NULL; - long long currtime = 0; - long long expirytime; - int custom_lease_file_len = 0; - virJSONValuePtr lease_tmp = NULL; - const char *ip_tmp = NULL; - const char *server_duid_tmp = NULL; - size_t i; - int ret = -1; - - currtime = (long long) time(NULL); - - /* Read entire contents */ - if ((custom_lease_file_len = virFileReadAll(custom_lease_file, - VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX, - &lease_entries)) < 0) { - goto cleanup; - } - - /* Check for previous leases */ - if (custom_lease_file_len == 0) { - ret = 0; - goto cleanup; - } - - if (!(leases_array = virJSONValueFromString(lease_entries))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid json in file: %s, rewriting it"), - custom_lease_file); - ret = 0; - goto cleanup; - } - - if (!virJSONValueIsArray(leases_array)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("couldn't fetch array of leases")); - goto cleanup; - } - - i = 0; - while (i < virJSONValueArraySize(leases_array)) { - if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to parse json")); - goto cleanup; - } - - if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address")) || - (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime) < 0)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to parse json")); - goto cleanup; - } - /* Check whether lease has expired or not */ - if (expirytime < currtime) { - i++; - continue; - } - - /* Check whether lease has to be included or not */ - if (ip_to_delete && STREQ(ip_tmp, ip_to_delete)) { - i++; - continue; - } - - if (strchr(ip_tmp, ':')) { - /* This is an ipv6 lease */ - if ((server_duid_tmp - = virJSONValueObjectGetString(lease_tmp, "server-duid"))) { - if (!*server_duid && VIR_STRDUP(*server_duid, server_duid_tmp) < 0) { - /* Control reaches here when the 'action' is not for an - * ipv6 lease or, for some weird reason the env var - * DNSMASQ_SERVER_DUID wasn't set*/ - goto cleanup; - } - } else { - /* Inject server-duid into those ipv6 leases which - * didn't have it previously, for example, those - * created by leaseshelper from libvirt 1.2.6 */ - if (virJSONValueObjectAppendString(lease_tmp, "server-duid", *server_duid) < 0) - goto cleanup; - } - } - - /* Move old lease to new array */ - if (virJSONValueArrayAppend(leases_array_new, lease_tmp) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to create json")); - goto cleanup; - } - - ignore_value(virJSONValueArraySteal(leases_array, i)); - } - - ret = 0; - - cleanup: - virJSONValueFree(leases_array); - VIR_FREE(lease_entries); - return ret; -} - -static int -virLeasePrintLeases(virJSONValuePtr leases_array_new, - const char *server_duid) -{ - virJSONValuePtr lease_tmp = NULL; - const char *ip_tmp = NULL; - long long expirytime = 0; - int ret = -1; - size_t i; - - /* Man page of dnsmasq says: the script (helper program, in our case) - * should write the saved state of the lease database, in dnsmasq - * leasefile format, to stdout and exit with zero exit code, when - * called with argument init. Format: - * $expirytime $mac $ip $hostname $clientid # For all ipv4 leases - * duid $server-duid # If DHCPv6 is present - * $expirytime $iaid $ip $hostname $clientduid # For all ipv6 leases */ - - /* Traversing the ipv4 leases */ - for (i = 0; i < virJSONValueArraySize(leases_array_new); i++) { - lease_tmp = virJSONValueArrayGet(leases_array_new, i); - if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to parse json")); - goto cleanup; - } - if (!strchr(ip_tmp, ':')) { - if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", - &expirytime) < 0) - continue; - - printf("%lld %s %s %s %s\n", - expirytime, - virJSONValueObjectGetString(lease_tmp, "mac-address"), - virJSONValueObjectGetString(lease_tmp, "ip-address"), - EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")), - EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id"))); - } - } - - /* Traversing the ipv6 leases */ - if (server_duid) { - printf("duid %s\n", server_duid); - for (i = 0; i < virJSONValueArraySize(leases_array_new); i++) { - lease_tmp = virJSONValueArrayGet(leases_array_new, i); - if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to parse json")); - goto cleanup; - } - if (strchr(ip_tmp, ':')) { - if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", - &expirytime) < 0) - continue; - - printf("%lld %s %s %s %s\n", - expirytime, - virJSONValueObjectGetString(lease_tmp, "iaid"), - virJSONValueObjectGetString(lease_tmp, "ip-address"), - EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")), - EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id"))); - } - } - } - - ret = 0; - - cleanup: - return ret; -} - -static int -virLeaseNew(virJSONValuePtr *lease_ret, - const char *mac, - const char *clientid, - const char *ip, - const char *hostname, - const char *iaid, - const char *server_duid) -{ - virJSONValuePtr lease_new = NULL; - const char *exptime_tmp = virGetEnvAllowSUID("DNSMASQ_LEASE_EXPIRES"); - long long expirytime = 0; - char *exptime = NULL; - int ret = -1; - - /* In case hostname is still unknown, use the last known one */ - if (!hostname) - hostname = virGetEnvAllowSUID("DNSMASQ_OLD_HOSTNAME"); - - if (!mac) { - ret = 0; - goto cleanup; - } - - if (exptime_tmp) { - if (VIR_STRDUP(exptime, exptime_tmp) < 0) - goto cleanup; - - /* Removed extraneous trailing space in DNSMASQ_LEASE_EXPIRES - * (dnsmasq < 2.52) */ - if (exptime[strlen(exptime) - 1] == ' ') - exptime[strlen(exptime) - 1] = '\0'; - } - - if (!exptime || - virStrToLong_ll(exptime, NULL, 10, &expirytime) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to convert lease expiry time to long long: %s"), - NULLSTR(exptime)); - goto cleanup; - } - - /* Create new lease */ - if (!(lease_new = virJSONValueNewObject())) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to create json")); - goto cleanup; - } - - if (iaid && virJSONValueObjectAppendString(lease_new, "iaid", iaid) < 0) - goto cleanup; - if (ip && virJSONValueObjectAppendString(lease_new, "ip-address", ip) < 0) - goto cleanup; - if (mac && virJSONValueObjectAppendString(lease_new, "mac-address", mac) < 0) - goto cleanup; - if (hostname && virJSONValueObjectAppendString(lease_new, "hostname", hostname) < 0) - goto cleanup; - if (clientid && virJSONValueObjectAppendString(lease_new, "client-id", clientid) < 0) - goto cleanup; - if (server_duid && virJSONValueObjectAppendString(lease_new, "server-duid", server_duid) < 0) - goto cleanup; - if (expirytime && virJSONValueObjectAppendNumberLong(lease_new, "expiry-time", expirytime) < 0) - goto cleanup; - - ret = 0; - *lease_ret = lease_new; - lease_new = NULL; - cleanup: - VIR_FREE(exptime); - virJSONValueFree(lease_new); - return ret; -} - int main(int argc, char **argv) { diff --git a/src/util/virlease.c b/src/util/virlease.c new file mode 100644 index 0000000..b8e9d8b --- /dev/null +++ b/src/util/virlease.c @@ -0,0 +1,304 @@ +/* + * virlease.c: Leases file handling + * + * Copyright (C) 2014 Red Hat, Inc. + * Copyright (C) 2014 Nehal J Wani + * + * 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/>. + * + */ + +#include <config.h> + +#include "virlease.h" + +#include <time.h> + +#include "virfile.h" +#include "virstring.h" +#include "virerror.h" +#include "viralloc.h" + +#define VIR_FROM_THIS VIR_FROM_NETWORK + +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024) + + +/* + * Use this when passing possibly-NULL strings to printf-a-likes. + * Required for unknown parameters during init call. + */ +#define EMPTY_STR(s) ((s) ? (s) : "*") + + +int +virLeaseReadCustomLeaseFile(virJSONValuePtr leases_array_new, + const char *custom_lease_file, + const char *ip_to_delete, + char **server_duid) +{ + char *lease_entries = NULL; + virJSONValuePtr leases_array = NULL; + long long currtime = 0; + long long expirytime; + int custom_lease_file_len = 0; + virJSONValuePtr lease_tmp = NULL; + const char *ip_tmp = NULL; + const char *server_duid_tmp = NULL; + size_t i; + int ret = -1; + + currtime = (long long) time(NULL); + + /* Read entire contents */ + if ((custom_lease_file_len = virFileReadAll(custom_lease_file, + VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX, + &lease_entries)) < 0) { + goto cleanup; + } + + /* Check for previous leases */ + if (custom_lease_file_len == 0) { + ret = 0; + goto cleanup; + } + + if (!(leases_array = virJSONValueFromString(lease_entries))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid json in file: %s, rewriting it"), + custom_lease_file); + ret = 0; + goto cleanup; + } + + if (!virJSONValueIsArray(leases_array)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("couldn't fetch array of leases")); + goto cleanup; + } + + i = 0; + while (i < virJSONValueArraySize(leases_array)) { + if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse json")); + goto cleanup; + } + + if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address")) || + (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime) < 0)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse json")); + goto cleanup; + } + /* Check whether lease has expired or not */ + if (expirytime < currtime) { + i++; + continue; + } + + /* Check whether lease has to be included or not */ + if (ip_to_delete && STREQ(ip_tmp, ip_to_delete)) { + i++; + continue; + } + + if (strchr(ip_tmp, ':')) { + /* This is an ipv6 lease */ + if ((server_duid_tmp + = virJSONValueObjectGetString(lease_tmp, "server-duid"))) { + if (!*server_duid && VIR_STRDUP(*server_duid, server_duid_tmp) < 0) { + /* Control reaches here when the 'action' is not for an + * ipv6 lease or, for some weird reason the env var + * DNSMASQ_SERVER_DUID wasn't set*/ + goto cleanup; + } + } else { + /* Inject server-duid into those ipv6 leases which + * didn't have it previously, for example, those + * created by leaseshelper from libvirt 1.2.6 */ + if (virJSONValueObjectAppendString(lease_tmp, "server-duid", *server_duid) < 0) + goto cleanup; + } + } + + /* Move old lease to new array */ + if (virJSONValueArrayAppend(leases_array_new, lease_tmp) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to create json")); + goto cleanup; + } + + ignore_value(virJSONValueArraySteal(leases_array, i)); + } + + ret = 0; + + cleanup: + virJSONValueFree(leases_array); + VIR_FREE(lease_entries); + return ret; +} + + +int +virLeasePrintLeases(virJSONValuePtr leases_array_new, + const char *server_duid) +{ + virJSONValuePtr lease_tmp = NULL; + const char *ip_tmp = NULL; + long long expirytime = 0; + int ret = -1; + size_t i; + + /* Man page of dnsmasq says: the script (helper program, in our case) + * should write the saved state of the lease database, in dnsmasq + * leasefile format, to stdout and exit with zero exit code, when + * called with argument init. Format: + * $expirytime $mac $ip $hostname $clientid # For all ipv4 leases + * duid $server-duid # If DHCPv6 is present + * $expirytime $iaid $ip $hostname $clientduid # For all ipv6 leases */ + + /* Traversing the ipv4 leases */ + for (i = 0; i < virJSONValueArraySize(leases_array_new); i++) { + lease_tmp = virJSONValueArrayGet(leases_array_new, i); + if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse json")); + goto cleanup; + } + if (!strchr(ip_tmp, ':')) { + if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", + &expirytime) < 0) + continue; + + printf("%lld %s %s %s %s\n", + expirytime, + virJSONValueObjectGetString(lease_tmp, "mac-address"), + virJSONValueObjectGetString(lease_tmp, "ip-address"), + EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")), + EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id"))); + } + } + + /* Traversing the ipv6 leases */ + if (server_duid) { + printf("duid %s\n", server_duid); + for (i = 0; i < virJSONValueArraySize(leases_array_new); i++) { + lease_tmp = virJSONValueArrayGet(leases_array_new, i); + if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse json")); + goto cleanup; + } + if (strchr(ip_tmp, ':')) { + if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", + &expirytime) < 0) + continue; + + printf("%lld %s %s %s %s\n", + expirytime, + virJSONValueObjectGetString(lease_tmp, "iaid"), + virJSONValueObjectGetString(lease_tmp, "ip-address"), + EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")), + EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id"))); + } + } + } + + ret = 0; + + cleanup: + return ret; +} + + +int +virLeaseNew(virJSONValuePtr *lease_ret, + const char *mac, + const char *clientid, + const char *ip, + const char *hostname, + const char *iaid, + const char *server_duid) +{ + virJSONValuePtr lease_new = NULL; + const char *exptime_tmp = virGetEnvAllowSUID("DNSMASQ_LEASE_EXPIRES"); + long long expirytime = 0; + char *exptime = NULL; + int ret = -1; + + /* In case hostname is still unknown, use the last known one */ + if (!hostname) + hostname = virGetEnvAllowSUID("DNSMASQ_OLD_HOSTNAME"); + + if (!mac) { + ret = 0; + goto cleanup; + } + + if (exptime_tmp) { + if (VIR_STRDUP(exptime, exptime_tmp) < 0) + goto cleanup; + + /* Removed extraneous trailing space in DNSMASQ_LEASE_EXPIRES + * (dnsmasq < 2.52) */ + if (exptime[strlen(exptime) - 1] == ' ') + exptime[strlen(exptime) - 1] = '\0'; + } + + if (!exptime || + virStrToLong_ll(exptime, NULL, 10, &expirytime) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to convert lease expiry time to long long: %s"), + NULLSTR(exptime)); + goto cleanup; + } + + /* Create new lease */ + if (!(lease_new = virJSONValueNewObject())) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to create json")); + goto cleanup; + } + + if (iaid && virJSONValueObjectAppendString(lease_new, "iaid", iaid) < 0) + goto cleanup; + if (ip && virJSONValueObjectAppendString(lease_new, "ip-address", ip) < 0) + goto cleanup; + if (mac && virJSONValueObjectAppendString(lease_new, "mac-address", mac) < 0) + goto cleanup; + if (hostname && virJSONValueObjectAppendString(lease_new, "hostname", hostname) < 0) + goto cleanup; + if (clientid && virJSONValueObjectAppendString(lease_new, "client-id", clientid) < 0) + goto cleanup; + if (server_duid && virJSONValueObjectAppendString(lease_new, "server-duid", server_duid) < 0) + goto cleanup; + if (expirytime && virJSONValueObjectAppendNumberLong(lease_new, "expiry-time", expirytime) < 0) + goto cleanup; + + ret = 0; + *lease_ret = lease_new; + lease_new = NULL; + cleanup: + VIR_FREE(exptime); + virJSONValueFree(lease_new); + return ret; +} diff --git a/src/util/virlease.h b/src/util/virlease.h new file mode 100644 index 0000000..b9f394e --- /dev/null +++ b/src/util/virlease.h @@ -0,0 +1,44 @@ +/* + * virlease.h: Leases file handling + * + * Copyright (C) 2014 Red Hat, Inc. + * Copyright (C) 2014 Nehal J Wani + * + * 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/>. + * + */ + +#ifndef __VIR_LEASE_H_ +# define __VIR_LEASE_H_ + +# include "virjson.h" + +int virLeaseReadCustomLeaseFile(virJSONValuePtr leases_array_new, + const char *custom_lease_file, + const char *ip_to_delete, + char **server_duid); + +int virLeasePrintLeases(virJSONValuePtr leases_array_new, + const char *server_duid); + + +int virLeaseNew(virJSONValuePtr *lease_ret, + const char *mac, + const char *clientid, + const char *ip, + const char *hostname, + const char *iaid, + const char *server_duid); +#endif /* __VIR_LEASE_H */ -- 2.4.10

This function is going to be used later in such context where the argument makes no sense. Teach this function to cope with that instead of the caller having to deal with passing some dummy argument. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virlease.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/virlease.c b/src/util/virlease.c index b8e9d8b..910c003 100644 --- a/src/util/virlease.c +++ b/src/util/virlease.c @@ -120,7 +120,7 @@ virLeaseReadCustomLeaseFile(virJSONValuePtr leases_array_new, continue; } - if (strchr(ip_tmp, ':')) { + if (server_duid && strchr(ip_tmp, ':')) { /* This is an ipv6 lease */ if ((server_duid_tmp = virJSONValueObjectGetString(lease_tmp, "server-duid"))) { -- 2.4.10

This is a missing counterpart for virSocketAddrSetIPv4Addr() and is going to be needed later in the tests. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virsocketaddr.c | 15 +++++++++++++++ src/util/virsocketaddr.h | 1 + 3 files changed, 17 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3ae18b8..640c6b3 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2165,6 +2165,7 @@ virSocketAddrParseIPv4; virSocketAddrParseIPv6; virSocketAddrPrefixToNetmask; virSocketAddrSetIPv4Addr; +virSocketAddrSetIPv6Addr; virSocketAddrSetPort; # util/virstats.h diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 900aa5b..b44d12e 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -189,6 +189,21 @@ virSocketAddrSetIPv4Addr(virSocketAddrPtr addr, uint32_t val) } /* + * virSocketAddrSetIPv6Addr: + * @addr: the location to store the result + * @val: the 128bit integer in host byte order representing the IPv6 address + * + * Set the IPv6 address given an integer in host order. This function does not + * touch any previously set port. + */ +void virSocketAddrSetIPv6Addr(virSocketAddrPtr addr, uint32_t val[4]) +{ + addr->data.stor.ss_family = AF_INET6; + memcpy(addr->data.inet6.sin6_addr.s6_addr, val, 4 * sizeof(*val)); + addr->len = sizeof(struct sockaddr_in6); +} + +/* * virSocketAddrEqual: * @s1: the location of the one IP address * @s2: the location of the other IP address diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 9e2680a..9a6e1ec 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -85,6 +85,7 @@ int virSocketAddrParseIPv6(virSocketAddrPtr addr, const char *val); void virSocketAddrSetIPv4Addr(virSocketAddrPtr s, uint32_t addr); +void virSocketAddrSetIPv6Addr(virSocketAddrPtr s, uint32_t addr[4]); char *virSocketAddrFormat(const virSocketAddr *addr); char *virSocketAddrFormatFull(const virSocketAddr *addr, -- 2.4.10

Name Service Switch is a glibc feature responsible for many things. Translating domain names into IP addresses and vice versa is just one of them. However, currently it's the only functionality that this commit is tickling. Well, in this commit the plugin skeleton is introduced. Implementation to come in next patches. Because of the future testing, where the implementation is to be linked with a test, this needs to go into static library. Linking a program with an .so statically is not portable. Therefore a dummy libnss_libvirt_impl library is being introduced too. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- configure.ac | 2 ++ m4/virt-nss.m4 | 51 ++++++++++++++++++++++++++++++++++++++++++++++ tools/Makefile.am | 38 ++++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.c | 36 ++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.h | 36 ++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.syms | 9 ++++++++ 6 files changed, 172 insertions(+) create mode 100644 m4/virt-nss.m4 create mode 100644 tools/nss/libvirt_nss.c create mode 100644 tools/nss/libvirt_nss.h create mode 100644 tools/nss/libvirt_nss.syms diff --git a/configure.ac b/configure.ac index eed2050..4d64998 100644 --- a/configure.ac +++ b/configure.ac @@ -257,6 +257,7 @@ LIBVIRT_CHECK_SSH2 LIBVIRT_CHECK_SYSTEMD_DAEMON LIBVIRT_CHECK_UDEV LIBVIRT_CHECK_WIRESHARK +LIBVIRT_CHECK_NSS LIBVIRT_CHECK_YAJL AC_MSG_CHECKING([for CPUID instruction]) @@ -2843,6 +2844,7 @@ LIBVIRT_RESULT_SSH2 LIBVIRT_RESULT_SYSTEMD_DAEMON LIBVIRT_RESULT_UDEV LIBVIRT_RESULT_WIRESHARK +LIBVIRT_RESULT_NSS LIBVIRT_RESULT_YAJL AC_MSG_NOTICE([ libxml: $LIBXML_CFLAGS $LIBXML_LIBS]) AC_MSG_NOTICE([ dlopen: $DLOPEN_LIBS]) diff --git a/m4/virt-nss.m4 b/m4/virt-nss.m4 new file mode 100644 index 0000000..3fa4ad3 --- /dev/null +++ b/m4/virt-nss.m4 @@ -0,0 +1,51 @@ +dnl The libvirt nsswitch plugin +dnl +dnl Copyright (C) 2016 Red Hat, Inc. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_CHECK_NSS],[ + AC_ARG_WITH([nss-plugin], + [AS_HELP_STRING([--with-nss-plugin], + [enable Name Servie Switch plugin for resolving guest IP addresses])], + [], [with_nss_plugin=check]) + + fail=0 + if test "x$with_nss_plugin" != "xno" ; then + AC_CHECK_HEADERS([nss.h], [ + with_nss_plugin=yes + ],[ + if test "x$with_nss_plugin" = "xyes" ; then + fail = 1 + fi + ]) + + if test $fail = 1 ; then + AC_MSG_ERROR([Can't build nss plugin without nss.h]) + fi + + if test "x$with_nss_plugin" = "xyes" ; then + AC_DEFINE_UNQUOTED([NSS], 1, [whether nss plugin is enabled]) + fi + fi + + AM_CONDITIONAL(WITH_NSS, [test "x$with_nss_plugin" = "xyes"]) + +]) + +AC_DEFUN([LIBVIRT_RESULT_NSS],[ + LIBVIRT_RESULT([nss], [$with_nss_plugin]) +]) diff --git a/tools/Makefile.am b/tools/Makefile.am index 0be3567..97ae4e1 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -417,6 +417,44 @@ CLEANFILES += wireshark/src/plugin.c endif WITH_WIRESHARK_DISSECTOR +LIBVIRT_NSS_SYMBOL_FILE = \ + $(srcdir)/nss/libvirt_nss.syms + +LIBVIRT_NSS_SOURCES = \ + nss/libvirt_nss.c \ + nss/libvirt_nss.h + +noinst_LTLIBRARIES += nss/libnss_libvirt_impl.la +nss_libnss_libvirt_impl_la_SOURCES = \ + $(LIBVIRT_NSS_SOURCES) + +nss_libnss_libvirt_impl_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(WARN_CFLAGS) \ + $(PIE_CFLAGS) \ + $(COVERAGE_CFLAGS) + +if WITH_NSS +nss_libnss_libvirt_la_SOURCES = +nss_libnss_libvirt_la_LDFLAGS = \ + $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_NSS_SYMBOL_FILE) \ + $(AM_LDFLAGS) \ + -module \ + -export-dynamic \ + -avoid-version \ + -shared \ + -shrext .so.2 + +nss_libnss_libvirt_la_LIBADD = \ + nss/libnss_libvirt_impl.la + +lib_LTLIBRARIES = \ + nss/libnss_libvirt.la + +endif WITH_NSS + +EXTRA_DIST += $(LIBVIRT_NSS_SYMBOL_FILE) \ + $(LIBVIRT_NSS_SOURCES) clean-local: -rm -rf wireshark/src/libvirt diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c new file mode 100644 index 0000000..461d8ca --- /dev/null +++ b/tools/nss/libvirt_nss.c @@ -0,0 +1,36 @@ +/* + * libvirt_nss: Name Service Switch plugin + * + * The aim is to enable users and applications to translate + * domain names into IP addresses. However, this is currently + * available only for those domains which gets their IP addresses + * from a libvirt managed network. + * + * 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/>. + * + * Authors: + * Michal Privoznik <mprivozn@redhat.com> + */ +#include <config.h> + +#include "libvirt_nss.h" + +int +blah(int c) +{ + return c; +} diff --git a/tools/nss/libvirt_nss.h b/tools/nss/libvirt_nss.h new file mode 100644 index 0000000..b54e5e3 --- /dev/null +++ b/tools/nss/libvirt_nss.h @@ -0,0 +1,36 @@ +/* + * libvirt_nss: Name Service Switch plugin + * + * The aim is to enable users and applications to translate + * domain names into IP addresses. However, this is currently + * available only for those domains which gets their IP addresses + * from a libvirt managed network. + * + * 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/>. + * + * Authors: + * Michal Privoznik <mprivozn@redhat.com> + */ + +#ifndef __LIBVIRT_NSS_H__ +# define __LIBVIRT_NSS_H__ + +# include <nss.h> +# include <netdb.h> + +int blah(int c); +#endif /* __LIBVIRT_NSS_H__ */ diff --git a/tools/nss/libvirt_nss.syms b/tools/nss/libvirt_nss.syms new file mode 100644 index 0000000..3246213 --- /dev/null +++ b/tools/nss/libvirt_nss.syms @@ -0,0 +1,9 @@ +# +# Officially exported symbols. +# + +{ +global: + blah; +local: *; +}; -- 2.4.10

Lets put the NSS module into its own package. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- libvirt.spec.in | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/libvirt.spec.in b/libvirt.spec.in index 03e2438..a617949 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -155,6 +155,7 @@ # Non-server/HV driver defaults which are always enabled %define with_sasl 0%{!?_without_sasl:1} %define with_audit 0%{!?_without_audit:1} +%define with_nss_plugin 0%{!?_without_nss_plugin:1} # Finally set the OS / architecture specific special cases @@ -1218,6 +1219,16 @@ Includes the Sanlock lock manager plugin for the QEMU driver %endif +%if %{with_nss_plugin} +%package nss +Summary: Libvirt plugin for Name Service Switch +Group: Development/Libraries +Requires: libvirt-daemon-driver-network = %{version}-%{release} + +%description nss +Libvirt plugin for NSS for translating domain names into IP addresses. +%endif + %prep %setup -q @@ -1451,6 +1462,10 @@ rm -rf .git %define _without_pm_utils --without-pm-utils %endif +%if ! %{with_nss_plugin} + %define _without_nss_plugin --without-nss-plugin +%endif + %define when %(date +"%%F-%%T") %define where %(hostname) %define who %{?packager}%{!?packager:Unknown} @@ -1528,6 +1543,7 @@ rm -f po/stamp-po %{?_without_wireshark} \ %{?_without_systemd_daemon} \ %{?_without_pm_utils} \ + %{?_without_nss_plugin} \ %{with_packager} \ %{with_packager_version} \ --with-qemu-user=%{qemu_user} \ @@ -2324,6 +2340,11 @@ exit 0 %{_libdir}/wireshark/plugins/libvirt.so %endif +%if %{with_nss_plugin} +%files nss +%{_libdir}/libnss_libvirt.so.2 +%endif + %if %{with_lxc} %files login-shell %attr(4750, root, virtlogin) %{_bindir}/virt-login-shell -- 2.4.10

The implementation is pretty straightforward. Moreover, because of the nature of things, gethostbyname_r and gethostbyname2_r can be implemented at the same time too. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- config-post.h | 24 ++++ src/Makefile.am | 57 ++++++++ src/util/virfile.c | 3 +- src/util/virfile.h | 10 +- src/util/virlease.c | 1 + tests/Makefile.am | 2 +- tools/Makefile.am | 5 + tools/nss/libvirt_nss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++- tools/nss/libvirt_nss.h | 14 +- tools/nss/libvirt_nss.syms | 4 +- 10 files changed, 447 insertions(+), 9 deletions(-) diff --git a/config-post.h b/config-post.h index 8367200..2398d3d 100644 --- a/config-post.h +++ b/config-post.h @@ -43,3 +43,27 @@ # undef WITH_YAJL # undef WITH_YAJL2 #endif + +/* + * With the NSS module it's the same story as virt-login-shell. See the + * explanation above. + */ +#ifdef LIBVIRT_NSS +# undef HAVE_LIBDEVMAPPER_H +# undef HAVE_LIBNL +# undef HAVE_LIBNL3 +# undef HAVE_LIBSASL2 +# undef WITH_CAPNG +# undef WITH_CURL +# undef WITH_DTRACE_PROBES +# undef WITH_GNUTLS +# undef WITH_GNUTLS_GCRYPT +# undef WITH_MACVTAP +# undef WITH_NUMACTL +# undef WITH_SASL +# undef WITH_SSH2 +# undef WITH_VIRTUALPORT +# undef WITH_SECDRIVER_SELINUX +# undef WITH_SECDRIVER_APPARMOR +# undef WITH_CAPNG +#endif /* LIBVIRT_NSS */ diff --git a/src/Makefile.am b/src/Makefile.am index 2ba397f..dad7bab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2946,6 +2946,63 @@ endif WITH_LIBVIRTD endif WITH_SECDRIVER_APPARMOR EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES) +noinst_LTLIBRARIES += libvirt-nss.la + +libvirt_nss_la_SOURCES = \ + util/viralloc.c \ + util/viralloc.h \ + util/virbitmap.c \ + util/virbitmap.h \ + util/virbuffer.c \ + util/virbuffer.h \ + util/vircommand.c \ + util/vircommand.h \ + util/virerror.c \ + util/virerror.h \ + util/virfile.c \ + util/virfile.h \ + util/virjson.c \ + util/virjson.h \ + util/virkmod.c \ + util/virkmod.h \ + util/virlease.c \ + util/virlease.h \ + util/virlog.c \ + util/virlog.h \ + util/virobject.c \ + util/virobject.h \ + util/virpidfile.c \ + util/virpidfile.h \ + util/virprocess.c \ + util/virprocess.h \ + util/virsocketaddr.c \ + util/virsocketaddr.h \ + util/virstring.c \ + util/virstring.h \ + util/virthread.c \ + util/virthread.h \ + util/virthreadjob.c \ + util/virthreadjob.h \ + util/virtime.c \ + util/virtime.h \ + util/virutil.c \ + util/virutil.h \ + $(NULL) + +libvirt_nss_la_CFLAGS = \ + -DLIBVIRT_NSS \ + $(AM_CFLAGS) \ + $(YAJL_CFLAGS) \ + $(NULL) +libvirt_nss_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(NULL) + +libvirt_nss_la_LIBADD = \ + $(YAJL_LIBS) \ + $(NULL) + + install-data-local: install-init install-systemd if WITH_LIBVIRTD $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd" diff --git a/src/util/virfile.c b/src/util/virfile.c index 0bba850..f0412c6 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -67,7 +67,6 @@ #include "virlog.h" #include "virprocess.h" #include "virstring.h" -#include "virstoragefile.h" #include "virutil.h" #include "c-ctype.h" @@ -554,7 +553,7 @@ int virFileUpdatePerm(const char *path, #if defined(__linux__) && HAVE_DECL_LO_FLAGS_AUTOCLEAR && \ - !defined(LIBVIRT_SETUID_RPC_CLIENT) + !defined(LIBVIRT_SETUID_RPC_CLIENT) && !defined(LIBVIRT_NSS) # if HAVE_DECL_LOOP_CTL_GET_FREE diff --git a/src/util/virfile.h b/src/util/virfile.h index 312f226..50a3995 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -30,7 +30,15 @@ # include <dirent.h> # include "internal.h" -# include "virstoragefile.h" + +/* Okay, this is not nice, but we want resulting nss module as + * small as possible. Including virstoragefile.h would drag in + * libxml2 dependencies which is unfavorable. */ +# ifdef LIBVIRT_NSS +# define virStorageFileFormat int +# else +# include "virstoragefile.h" +# endif typedef enum { VIR_FILE_CLOSE_PRESERVE_ERRNO = 1 << 0, diff --git a/src/util/virlease.c b/src/util/virlease.c index 910c003..920ebaf 100644 --- a/src/util/virlease.c +++ b/src/util/virlease.c @@ -30,6 +30,7 @@ #include "virstring.h" #include "virerror.h" #include "viralloc.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NETWORK diff --git a/tests/Makefile.am b/tests/Makefile.am index 90981dc..55e8432 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,7 +65,7 @@ GNULIB_LIBS = \ ../gnulib/lib/libgnu.la LDADDS = \ - $(WARN_CFLAGS) \ + $(WARN_CFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ $(PROBES_O) \ $(GNULIB_LIBS) \ diff --git a/tools/Makefile.am b/tools/Makefile.am index 97ae4e1..d72cfd8 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -429,11 +429,16 @@ nss_libnss_libvirt_impl_la_SOURCES = \ $(LIBVIRT_NSS_SOURCES) nss_libnss_libvirt_impl_la_CFLAGS = \ + -DLIBVIRT_NSS \ $(AM_CFLAGS) \ $(WARN_CFLAGS) \ $(PIE_CFLAGS) \ $(COVERAGE_CFLAGS) +nss_libnss_libvirt_impl_la_LIBADD = \ + ../gnulib/lib/libgnu.la \ + ../src/libvirt-nss.la + if WITH_NSS nss_libnss_libvirt_la_SOURCES = nss_libnss_libvirt_la_LDFLAGS = \ diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c index 461d8ca..1b9ccba 100644 --- a/tools/nss/libvirt_nss.c +++ b/tools/nss/libvirt_nss.c @@ -29,8 +29,338 @@ #include "libvirt_nss.h" -int -blah(int c) +#include <resolv.h> +#include <sys/types.h> +#include <dirent.h> +#include <arpa/inet.h> + +#include "virlease.h" +#include "viralloc.h" +#include "virfile.h" +#include "virerror.h" +#include "virstring.h" +#include "virsocketaddr.h" +#include "configmake.h" + +#if 0 +# define ERROR(...) \ +do { \ + char ebuf[1024]; \ + fprintf(stderr, "ERROR %s:%d : ", __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " : %s\n", virStrerror(errno, ebuf, sizeof(ebuf))); \ + fprintf(stderr, "\n"); \ +} while (0) + +# define DEBUG(...) \ +do { \ + fprintf(stderr, "DEBUG %s:%d : ", __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) +#else +# define ERROR(...) do { } while (0) +# define DEBUG(...) do { } while (0) +#endif + +#define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/" + +#define ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1)) +#define FAMILY_ADDRESS_SIZE(family) ((family) == AF_INET6 ? 16 : 4) + +typedef struct { + unsigned char addr[16]; + int af; +} leaseAddress; + +/** + * findLease: + * @name: domain name to lookup + * @af: address family + * @address: all the addresses found for selected @af + * @naddress: number of elements in @address array + * @found: whether @name has been found + * @errnop: errno pointer + * + * Lookup @name in libvirt's IP database, parse it and store all + * addresses found in @address array. Callers can choose which + * address family (@af) should be returned. Currently only + * AF_INET (IPv4) and AF_INET6 (IPv6) are supported. As a corner + * case, AF_UNSPEC may be passed to @af in which case no address + * filtering is done and addresses from both families are + * returned. + * + * Returns -1 on error + * 0 on success + */ +static int +findLease(const char *name, + int af, + leaseAddress **address, + size_t *naddress, + bool *found, + int *errnop) { - return c; + DIR *dir = NULL; + int ret = -1; + const char *leaseDir = LEASEDIR; + struct dirent *entry; + virJSONValuePtr leases_array = NULL; + ssize_t i, nleases; + leaseAddress *tmpAddress = NULL; + size_t ntmpAddress = 0; + + *address = NULL; + *naddress = 0; + *found = false; + + if (af != AF_UNSPEC && af != AF_INET && af != AF_INET6) { + errno = EAFNOSUPPORT; + goto cleanup; + } + + + if (!(dir = opendir(leaseDir))) { + ERROR("Failed to open dir '%s'", leaseDir); + goto cleanup; + } + + if (!(leases_array = virJSONValueNewArray())) { + ERROR("Failed to create json array"); + goto cleanup; + } + + DEBUG("Dir: %s", leaseDir); + while ((ret = virDirRead(dir, &entry, leaseDir)) > 0) { + char *path; + + if (entry->d_name[0] == '.') + continue; + + if (!virFileHasSuffix(entry->d_name, ".status")) + continue; + + if (!(path = virFileBuildPath(leaseDir, entry->d_name, NULL))) + goto cleanup; + + DEBUG("Processing %s", path); + + if (virLeaseReadCustomLeaseFile(leases_array, path, NULL, NULL) < 0) { + ERROR("Unable to parse %s", path); + VIR_FREE(path); + goto cleanup; + } + + VIR_FREE(path); + } + + closedir(dir); + dir = NULL; + + nleases = virJSONValueArraySize(leases_array); + DEBUG("Read %zd leases", nleases); + + for (i = 0; i < nleases; i++) { + virJSONValuePtr lease; + const char *lease_name; + virSocketAddr sa; + const char *ipAddr; + int family; + + lease = virJSONValueArrayGet(leases_array, i); + + if (!lease) { + /* This should never happen (TM) */ + ERROR("Unable to get element %zd of %zd", i, nleases); + goto cleanup; + } + + lease_name = virJSONValueObjectGetString(lease, "hostname"); + + if (STRNEQ_NULLABLE(name, lease_name)) + continue; + + DEBUG("Found record for %s", lease_name); + *found = true; + + if (!(ipAddr = virJSONValueObjectGetString(lease, "ip-address"))) { + ERROR("ip-address field missing for %s", name); + goto cleanup; + } + + DEBUG("IP address: %s", ipAddr); + + if (virSocketAddrParse(&sa, ipAddr, AF_UNSPEC) < 0) { + ERROR("Unable to parse %s", ipAddr); + goto cleanup; + } + + family = VIR_SOCKET_ADDR_FAMILY(&sa); + if (af != AF_UNSPEC && af != family) { + DEBUG("Skipping address which family is %d, %d requested", family, af); + continue; + } + + if (VIR_REALLOC_N_QUIET(tmpAddress, ntmpAddress + 1) < 0) { + ERROR("Out of memory"); + goto cleanup; + } + + tmpAddress[ntmpAddress].af = family; + memcpy(tmpAddress[ntmpAddress].addr, + (family == AF_INET ? + (void *) &sa.data.inet4.sin_addr.s_addr : + (void *) &sa.data.inet6.sin6_addr.s6_addr), + FAMILY_ADDRESS_SIZE(family)); + ntmpAddress++; + } + + *address = tmpAddress; + *naddress = ntmpAddress; + tmpAddress = NULL; + ntmpAddress = 0; + + ret = 0; + + cleanup: + *errnop = errno; + VIR_FREE(tmpAddress); + virJSONValueFree(leases_array); + if (dir) + closedir(dir); + return ret; +} + + +enum nss_status +_nss_libvirt_gethostbyname_r(const char *name, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + int af = ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET); + + return _nss_libvirt_gethostbyname3_r(name, af, result, buffer, buflen, + errnop, herrnop, NULL, NULL); +} + +enum nss_status +_nss_libvirt_gethostbyname2_r(const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + return _nss_libvirt_gethostbyname3_r(name, af, result, buffer, buflen, + errnop, herrnop, NULL, NULL); +} + +enum nss_status +_nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp, char **canonp) +{ + enum nss_status ret = NSS_STATUS_UNAVAIL; + char *r_name, **r_aliases, *r_addr, **r_addr_list; + leaseAddress *addr = NULL; + size_t naddr, i; + bool found = false; + size_t nameLen, need, idx; + int alen; + int r; + + /* findLease is capable of returning both IPv4 and IPv6. + * However, this function has no way of telling user back the + * family per each address returned. Therefore, if @af == + * AF_UNSPEC return just one family instead of a mixture of + * both. Dice picked the former one. */ + if (af == AF_UNSPEC) + af = AF_INET; + + if ((r = findLease(name, af, &addr, &naddr, &found, errnop)) < 0) { + /* Error occurred. Return immediately. */ + if (*errnop == EAGAIN) { + *herrnop = TRY_AGAIN; + return NSS_STATUS_TRYAGAIN; + } else { + *herrnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + } + + if (!found) { + /* NOT found */ + *errnop = ESRCH; + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } else if (!naddr) { + /* Found, but no data */ + *errnop = ENXIO; + *herrnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* Found and have data */ + + alen = FAMILY_ADDRESS_SIZE(addr[0].af); + + nameLen = strlen(name); + /* We need space for: + * a) name + * b) alias + * c) addresses + * d) NULL stem */ + need = ALIGN(nameLen + 1) + naddr * ALIGN(alen) + (naddr + 2) * sizeof(char*); + + if (buflen < need) { + *errnop = ENOMEM; + *herrnop = TRY_AGAIN; + ret = NSS_STATUS_TRYAGAIN; + goto cleanup; + } + + /* First, append name */ + r_name = buffer; + memcpy(r_name, name, nameLen + 1); + idx = ALIGN(nameLen + 1); + + /* Second, create aliases array */ + r_aliases = (char **) buffer + idx; + r_aliases[0] = NULL; + idx += sizeof(char*); + + /* Third, append address */ + r_addr = buffer + idx; + for (i = 0; i < naddr; i++) + memcpy(r_addr + i * ALIGN(alen), addr[i].addr, alen); + idx += naddr * ALIGN(alen); + + /* Third, append address pointer array */ + r_addr_list = (char **) buffer + idx; + for (i = 0; i < naddr; i++) + r_addr_list[i] = r_addr + i * ALIGN(alen); + r_addr_list[i] = NULL; + idx += (naddr + 1) * sizeof(char*); + + /* At this point, idx == need */ + DEBUG("Done idx:%zd need:%zd", idx, need); + + result->h_name = r_name; + result->h_aliases = r_aliases; + result->h_addrtype = af; + result->h_length = alen; + result->h_addr_list = r_addr_list; + + if (ttlp) + *ttlp = 0; + + if (canonp) + *canonp = r_name; + + /* Explicitly reset all error variables */ + *errnop = 0; + *herrnop = NETDB_SUCCESS; + h_errno = 0; + + ret = NSS_STATUS_SUCCESS; + cleanup: + VIR_FREE(addr); + return ret; } diff --git a/tools/nss/libvirt_nss.h b/tools/nss/libvirt_nss.h index b54e5e3..dd037f5 100644 --- a/tools/nss/libvirt_nss.h +++ b/tools/nss/libvirt_nss.h @@ -32,5 +32,17 @@ # include <nss.h> # include <netdb.h> -int blah(int c); +enum nss_status +_nss_libvirt_gethostbyname_r(const char *name, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop); + +enum nss_status +_nss_libvirt_gethostbyname2_r(const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop); +enum nss_status +_nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp, char **canonp); #endif /* __LIBVIRT_NSS_H__ */ diff --git a/tools/nss/libvirt_nss.syms b/tools/nss/libvirt_nss.syms index 3246213..b88b8be 100644 --- a/tools/nss/libvirt_nss.syms +++ b/tools/nss/libvirt_nss.syms @@ -4,6 +4,8 @@ { global: - blah; + _nss_libvirt_gethostbyname_r; + _nss_libvirt_gethostbyname2_r; + _nss_libvirt_gethostbyname3_r; local: *; }; -- 2.4.10

On Tue, Mar 15, 2016 at 06:05:53PM +0100, Michal Privoznik wrote:
The implementation is pretty straightforward. Moreover, because of the nature of things, gethostbyname_r and gethostbyname2_r can be implemented at the same time too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- config-post.h | 24 ++++ src/Makefile.am | 57 ++++++++ src/util/virfile.c | 3 +- src/util/virfile.h | 10 +- src/util/virlease.c | 1 + tests/Makefile.am | 2 +- tools/Makefile.am | 5 + tools/nss/libvirt_nss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++- tools/nss/libvirt_nss.h | 14 +- tools/nss/libvirt_nss.syms | 4 +- 10 files changed, 447 insertions(+), 9 deletions(-)
diff --git a/src/util/virfile.c b/src/util/virfile.c index 0bba850..f0412c6 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -67,7 +67,6 @@ #include "virlog.h" #include "virprocess.h" #include "virstring.h" -#include "virstoragefile.h"
Yep, this is bogus anyway since its already in the header
#include "virutil.h"
#include "c-ctype.h" @@ -554,7 +553,7 @@ int virFileUpdatePerm(const char *path,
#if defined(__linux__) && HAVE_DECL_LO_FLAGS_AUTOCLEAR && \ - !defined(LIBVIRT_SETUID_RPC_CLIENT) + !defined(LIBVIRT_SETUID_RPC_CLIENT) && !defined(LIBVIRT_NSS)
# if HAVE_DECL_LOOP_CTL_GET_FREE
diff --git a/src/util/virfile.h b/src/util/virfile.h index 312f226..50a3995 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -30,7 +30,15 @@ # include <dirent.h>
# include "internal.h" -# include "virstoragefile.h" + +/* Okay, this is not nice, but we want resulting nss module as + * small as possible. Including virstoragefile.h would drag in + * libxml2 dependencies which is unfavorable. */ +# ifdef LIBVIRT_NSS +# define virStorageFileFormat int +# else +# include "virstoragefile.h" +# endif
I don't think this is needed. The header file merely uses the enum declaration which is fine. You only get the dep on libxml2 if you actually build the virstoragefile.c
diff --git a/src/util/virlease.c b/src/util/virlease.c index 910c003..920ebaf 100644 --- a/src/util/virlease.c +++ b/src/util/virlease.c @@ -30,6 +30,7 @@ #include "virstring.h" #include "virerror.h" #include "viralloc.h" +#include "virutil.h"
Unrelated change
#define VIR_FROM_THIS VIR_FROM_NETWORK
diff --git a/tests/Makefile.am b/tests/Makefile.am index 90981dc..55e8432 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,7 +65,7 @@ GNULIB_LIBS = \ ../gnulib/lib/libgnu.la
LDADDS = \ - $(WARN_CFLAGS) \ + $(WARN_CFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ $(PROBES_O) \ $(GNULIB_LIBS) \
Unrelated cleanup. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Mar 15, 2016 at 06:05:53PM +0100, Michal Privoznik wrote:
The implementation is pretty straightforward. Moreover, because of the nature of things, gethostbyname_r and gethostbyname2_r can be implemented at the same time too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- config-post.h | 24 ++++ src/Makefile.am | 57 ++++++++ src/util/virfile.c | 3 +- src/util/virfile.h | 10 +- src/util/virlease.c | 1 + tests/Makefile.am | 2 +- tools/Makefile.am | 5 + tools/nss/libvirt_nss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++- tools/nss/libvirt_nss.h | 14 +- tools/nss/libvirt_nss.syms | 4 +- 10 files changed, 447 insertions(+), 9 deletions(-)
diff --git a/src/util/virfile.h b/src/util/virfile.h index 312f226..50a3995 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -30,7 +30,15 @@ # include <dirent.h>
# include "internal.h" -# include "virstoragefile.h" + +/* Okay, this is not nice, but we want resulting nss module as + * small as possible. Including virstoragefile.h would drag in + * libxml2 dependencies which is unfavorable. */ +# ifdef LIBVIRT_NSS +# define virStorageFileFormat int +# else +# include "virstoragefile.h" +# endif
I agree with Daniel here. Just add LIBXML2_CFLAGS to needed targets so that it compiles properly. And don't compile in the virstoragefile.c.
typedef enum { VIR_FILE_CLOSE_PRESERVE_ERRNO = 1 << 0, diff --git a/src/util/virlease.c b/src/util/virlease.c index 910c003..920ebaf 100644 --- a/src/util/virlease.c +++ b/src/util/virlease.c @@ -30,6 +30,7 @@ #include "virstring.h" #include "virerror.h" #include "viralloc.h" +#include "virutil.h"
This should be in the patch where you introduce virlease.c, I guess.
#define VIR_FROM_THIS VIR_FROM_NETWORK
diff --git a/tests/Makefile.am b/tests/Makefile.am index 90981dc..55e8432 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,7 +65,7 @@ GNULIB_LIBS = \ ../gnulib/lib/libgnu.la
LDADDS = \ - $(WARN_CFLAGS) \ + $(WARN_CFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ $(PROBES_O) \ $(GNULIB_LIBS) \
Drop this hunk. ACK with those nits fixed.

On 18.03.2016 15:10, Martin Kletzander wrote:
On Tue, Mar 15, 2016 at 06:05:53PM +0100, Michal Privoznik wrote:
The implementation is pretty straightforward. Moreover, because of the nature of things, gethostbyname_r and gethostbyname2_r can be implemented at the same time too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- config-post.h | 24 ++++ src/Makefile.am | 57 ++++++++ src/util/virfile.c | 3 +- src/util/virfile.h | 10 +- src/util/virlease.c | 1 + tests/Makefile.am | 2 +- tools/Makefile.am | 5 + tools/nss/libvirt_nss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++- tools/nss/libvirt_nss.h | 14 +- tools/nss/libvirt_nss.syms | 4 +- 10 files changed, 447 insertions(+), 9 deletions(-)
diff --git a/src/util/virfile.h b/src/util/virfile.h index 312f226..50a3995 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -30,7 +30,15 @@ # include <dirent.h>
# include "internal.h" -# include "virstoragefile.h" + +/* Okay, this is not nice, but we want resulting nss module as + * small as possible. Including virstoragefile.h would drag in + * libxml2 dependencies which is unfavorable. */ +# ifdef LIBVIRT_NSS +# define virStorageFileFormat int +# else +# include "virstoragefile.h" +# endif
I agree with Daniel here. Just add LIBXML2_CFLAGS to needed targets so that it compiles properly. And don't compile in the virstoragefile.c.
typedef enum { VIR_FILE_CLOSE_PRESERVE_ERRNO = 1 << 0, diff --git a/src/util/virlease.c b/src/util/virlease.c index 910c003..920ebaf 100644 --- a/src/util/virlease.c +++ b/src/util/virlease.c @@ -30,6 +30,7 @@ #include "virstring.h" #include "virerror.h" #include "viralloc.h" +#include "virutil.h"
This should be in the patch where you introduce virlease.c, I guess.
It was here because after I started including virstoragefile.h conditionally, I experienced couple of build errors which proven to be due to a missing include of virutil.h. If we include virstoragefile.h without any condition, just like it is now, virutil.h is included indirectly from there as well. Yes, we can be nice and include it here directly. But truth to be told I'm tired of putting every little change into its own commit. I can't put this change into 1/9 because then it wouldn't be just a pure code movement. I need to save it for a separate patch then. And write a sensible commit message (which will end up being longer than change itself). D'oh!
#define VIR_FROM_THIS VIR_FROM_NETWORK
diff --git a/tests/Makefile.am b/tests/Makefile.am index 90981dc..55e8432 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,7 +65,7 @@ GNULIB_LIBS = \ ../gnulib/lib/libgnu.la
LDADDS = \ - $(WARN_CFLAGS) \ + $(WARN_CFLAGS) \ $(NO_INDIRECT_LDFLAGS) \ $(PROBES_O) \ $(GNULIB_LIBS) \
Drop this hunk.
ACK with those nits fixed.
Thanks. Michal

On Fri, Mar 18, 2016 at 04:18:15PM +0100, Michal Privoznik wrote:
On 18.03.2016 15:10, Martin Kletzander wrote:
On Tue, Mar 15, 2016 at 06:05:53PM +0100, Michal Privoznik wrote:
The implementation is pretty straightforward. Moreover, because of the nature of things, gethostbyname_r and gethostbyname2_r can be implemented at the same time too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- config-post.h | 24 ++++ src/Makefile.am | 57 ++++++++ src/util/virfile.c | 3 +- src/util/virfile.h | 10 +- src/util/virlease.c | 1 + tests/Makefile.am | 2 +- tools/Makefile.am | 5 + tools/nss/libvirt_nss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++- tools/nss/libvirt_nss.h | 14 +- tools/nss/libvirt_nss.syms | 4 +- 10 files changed, 447 insertions(+), 9 deletions(-)
diff --git a/src/util/virfile.h b/src/util/virfile.h index 312f226..50a3995 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -30,7 +30,15 @@ # include <dirent.h>
# include "internal.h" -# include "virstoragefile.h" + +/* Okay, this is not nice, but we want resulting nss module as + * small as possible. Including virstoragefile.h would drag in + * libxml2 dependencies which is unfavorable. */ +# ifdef LIBVIRT_NSS +# define virStorageFileFormat int +# else +# include "virstoragefile.h" +# endif
I agree with Daniel here. Just add LIBXML2_CFLAGS to needed targets so that it compiles properly. And don't compile in the virstoragefile.c.
typedef enum { VIR_FILE_CLOSE_PRESERVE_ERRNO = 1 << 0, diff --git a/src/util/virlease.c b/src/util/virlease.c index 910c003..920ebaf 100644 --- a/src/util/virlease.c +++ b/src/util/virlease.c @@ -30,6 +30,7 @@ #include "virstring.h" #include "virerror.h" #include "viralloc.h" +#include "virutil.h"
This should be in the patch where you introduce virlease.c, I guess.
It was here because after I started including virstoragefile.h conditionally, I experienced couple of build errors which proven to be due to a missing include of virutil.h. If we include virstoragefile.h without any condition, just like it is now, virutil.h is included indirectly from there as well. Yes, we can be nice and include it here directly. But truth to be told I'm tired of putting every little change into its own commit. I can't put this change into 1/9 because then it wouldn't be just a pure code movement. I need to save it for a separate patch then. And write a sensible commit message (which will end up being longer than change itself). D'oh!
I would say just take all of such cleanups and put them together to one commit, but others will tell you not to do that. We should come up with some universal works-for-all way to do this.

This function is a different beast compared to previous ones. But yet again, nothing surprising is happening here. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tools/nss/libvirt_nss.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.h | 4 ++ tools/nss/libvirt_nss.syms | 1 + 3 files changed, 97 insertions(+) diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c index 1b9ccba..9b80ace 100644 --- a/tools/nss/libvirt_nss.c +++ b/tools/nss/libvirt_nss.c @@ -364,3 +364,95 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, VIR_FREE(addr); return ret; } + +enum nss_status +_nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + enum nss_status ret = NSS_STATUS_UNAVAIL; + leaseAddress *addr = NULL; + size_t naddr, i; + bool found = false; + int r; + size_t nameLen, need, idx; + struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; + char *r_name; + + if ((r = findLease(name, AF_UNSPEC, &addr, &naddr, &found, errnop)) < 0) { + /* Error occurred. Return immediately. */ + if (*errnop == EAGAIN) { + *herrnop = TRY_AGAIN; + return NSS_STATUS_TRYAGAIN; + } else { + *herrnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + } + + if (!found) { + /* NOT found */ + *errnop = ESRCH; + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } else if (!naddr) { + /* Found, but no data */ + *errnop = ENXIO; + *herrnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* Found and have data */ + + nameLen = strlen(name); + /* We need space for: + * a) name + * b) address */ + need = ALIGN(nameLen + 1) + ALIGN(sizeof(struct gaih_addrtuple)); + + if (buflen < need) { + *errnop = ENOMEM; + *herrnop = TRY_AGAIN; + ret = NSS_STATUS_TRYAGAIN; + goto cleanup; + } + + /* First, append name */ + r_name = buffer; + memcpy(r_name, name, nameLen + 1); + idx = ALIGN(nameLen + 1); + + + /* Second, append addresses */ + r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); + for (i = 0; i < naddr; i++) { + int family = addr[i].af; + + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = i == naddr - 1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple))); + r_tuple->name = r_name; + r_tuple->family = family; + r_tuple->scopeid = 0; + memcpy(r_tuple->addr, addr[i].addr, FAMILY_ADDRESS_SIZE(family)); + + idx += ALIGN(sizeof(struct gaih_addrtuple)); + } + + /* At this point, idx == need */ + DEBUG("Done idx:%zd need:%zd", idx, need); + + if (*pat) + **pat = *r_tuple_first; + else + *pat = r_tuple_first; + + if (ttlp) + *ttlp = 0; + + /* Explicitly reset all error variables */ + *errnop = 0; + *herrnop = NETDB_SUCCESS; + ret = NSS_STATUS_SUCCESS; + cleanup: + return ret; +} diff --git a/tools/nss/libvirt_nss.h b/tools/nss/libvirt_nss.h index dd037f5..589c1e6 100644 --- a/tools/nss/libvirt_nss.h +++ b/tools/nss/libvirt_nss.h @@ -45,4 +45,8 @@ enum nss_status _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *herrnop, int32_t *ttlp, char **canonp); +enum nss_status +_nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp); #endif /* __LIBVIRT_NSS_H__ */ diff --git a/tools/nss/libvirt_nss.syms b/tools/nss/libvirt_nss.syms index b88b8be..5a793e4 100644 --- a/tools/nss/libvirt_nss.syms +++ b/tools/nss/libvirt_nss.syms @@ -7,5 +7,6 @@ global: _nss_libvirt_gethostbyname_r; _nss_libvirt_gethostbyname2_r; _nss_libvirt_gethostbyname3_r; + _nss_libvirt_gethostbyname4_r; local: *; }; -- 2.4.10

On Tue, Mar 15, 2016 at 06:05:54PM +0100, Michal Privoznik wrote:
This function is a different beast compared to previous ones. But yet again, nothing surprising is happening here.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tools/nss/libvirt_nss.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.h | 4 ++ tools/nss/libvirt_nss.syms | 1 + 3 files changed, 97 insertions(+)
diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c index 1b9ccba..9b80ace 100644 --- a/tools/nss/libvirt_nss.c +++ b/tools/nss/libvirt_nss.c @@ -364,3 +364,95 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, VIR_FREE(addr); return ret; } + +enum nss_status +_nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + enum nss_status ret = NSS_STATUS_UNAVAIL; + leaseAddress *addr = NULL; + size_t naddr, i; + bool found = false; + int r; + size_t nameLen, need, idx; + struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; + char *r_name; + + if ((r = findLease(name, AF_UNSPEC, &addr, &naddr, &found, errnop)) < 0) { + /* Error occurred. Return immediately. */ + if (*errnop == EAGAIN) { + *herrnop = TRY_AGAIN; + return NSS_STATUS_TRYAGAIN; + } else { + *herrnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + } + + if (!found) { + /* NOT found */ + *errnop = ESRCH; + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } else if (!naddr) { + /* Found, but no data */ + *errnop = ENXIO; + *herrnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* Found and have data */ + + nameLen = strlen(name); + /* We need space for: + * a) name + * b) address */ + need = ALIGN(nameLen + 1) + ALIGN(sizeof(struct gaih_addrtuple)); +
Shouldn't this be ' + naddr * ALIGN('... ???
+ if (buflen < need) { + *errnop = ENOMEM; + *herrnop = TRY_AGAIN; + ret = NSS_STATUS_TRYAGAIN; + goto cleanup; + } + + /* First, append name */ + r_name = buffer; + memcpy(r_name, name, nameLen + 1); + idx = ALIGN(nameLen + 1); + + + /* Second, append addresses */ + r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); + for (i = 0; i < naddr; i++) { + int family = addr[i].af; + + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = i == naddr - 1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
This would be more readable with a proper condition instead of this long line.

On 18.03.2016 15:09, Martin Kletzander wrote:
On Tue, Mar 15, 2016 at 06:05:54PM +0100, Michal Privoznik wrote:
This function is a different beast compared to previous ones. But yet again, nothing surprising is happening here.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tools/nss/libvirt_nss.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ tools/nss/libvirt_nss.h | 4 ++ tools/nss/libvirt_nss.syms | 1 + 3 files changed, 97 insertions(+)
diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c index 1b9ccba..9b80ace 100644 --- a/tools/nss/libvirt_nss.c +++ b/tools/nss/libvirt_nss.c @@ -364,3 +364,95 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, VIR_FREE(addr); return ret; } + +enum nss_status +_nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + enum nss_status ret = NSS_STATUS_UNAVAIL; + leaseAddress *addr = NULL; + size_t naddr, i; + bool found = false; + int r; + size_t nameLen, need, idx; + struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; + char *r_name; + + if ((r = findLease(name, AF_UNSPEC, &addr, &naddr, &found, errnop)) < 0) { + /* Error occurred. Return immediately. */ + if (*errnop == EAGAIN) { + *herrnop = TRY_AGAIN; + return NSS_STATUS_TRYAGAIN; + } else { + *herrnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + } + + if (!found) { + /* NOT found */ + *errnop = ESRCH; + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } else if (!naddr) { + /* Found, but no data */ + *errnop = ENXIO; + *herrnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* Found and have data */ + + nameLen = strlen(name); + /* We need space for: + * a) name + * b) address */ + need = ALIGN(nameLen + 1) + ALIGN(sizeof(struct gaih_addrtuple)); +
Shouldn't this be ' + naddr * ALIGN('... ???
Yes, good catch.
+ if (buflen < need) { + *errnop = ENOMEM; + *herrnop = TRY_AGAIN; + ret = NSS_STATUS_TRYAGAIN; + goto cleanup; + } + + /* First, append name */ + r_name = buffer; + memcpy(r_name, name, nameLen + 1); + idx = ALIGN(nameLen + 1); + + + /* Second, append addresses */ + r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); + for (i = 0; i < naddr; i++) { + int family = addr[i].af; + + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = i == naddr - 1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
This would be more readable with a proper condition instead of this long line.
Okay. Michal

A small test to see how is the nss module working. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- cfg.mk | 2 +- tests/Makefile.am | 18 ++++ tests/nssdata/virbr0.status | 20 +++++ tests/nssdata/virbr1.status | 20 +++++ tests/nssmock.c | 140 +++++++++++++++++++++++++++++ tests/nsstest.c | 208 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 tests/nssdata/virbr0.status create mode 100644 tests/nssdata/virbr1.status create mode 100644 tests/nssmock.c create mode 100644 tests/nsstest.c diff --git a/cfg.mk b/cfg.mk index 5b864af..6f28eef 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1139,7 +1139,7 @@ exclude_file_name_regexp--sc_copyright_usage = \ ^COPYING(|\.LESSER)$$ 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 = \ ^(src/rpc/gendispatch\.pl$$|tests/) diff --git a/tests/Makefile.am b/tests/Makefile.am index 55e8432..2bb9d28 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -108,6 +108,7 @@ EXTRA_DIST = \ nodedevschemadata \ nodedevschematest \ nodeinfodata \ + nssdata \ nwfilterschematest \ nwfilterxml2firewalldata \ nwfilterxml2xmlin \ @@ -190,6 +191,7 @@ test_programs = virshtest sockettest \ vircaps2xmltest \ virnetdevtest \ virtypedparamtest \ + nsstest \ $(NULL) if WITH_REMOTE @@ -421,6 +423,7 @@ test_libraries = libshunload.la \ virpcimock.la \ virnetdevmock.la \ nodeinfomock.la \ + nssmock.la \ $(NULL) if WITH_QEMU test_libraries += libqemumonitortestutils.la \ @@ -1067,6 +1070,21 @@ nodeinfomock_la_CFLAGS = $(AM_CFLAGS) nodeinfomock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) 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.c testutils.h testutils.c virnetdevtest_CFLAGS = $(AM_CFLAGS) $(LIBNL_CFLAGS) diff --git a/tests/nssdata/virbr0.status b/tests/nssdata/virbr0.status new file mode 100644 index 0000000..6ebe954 --- /dev/null +++ b/tests/nssdata/virbr0.status @@ -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 + } +] diff --git a/tests/nssdata/virbr1.status b/tests/nssdata/virbr1.status new file mode 100644 index 0000000..f8a9157 --- /dev/null +++ b/tests/nssdata/virbr1.status @@ -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 + } +] diff --git a/tests/nssmock.c b/tests/nssmock.c new file mode 100644 index 0000000..b4a4260 --- /dev/null +++ b/tests/nssmock.c @@ -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 diff --git a/tests/nsstest.c b/tests/nsstest.c new file mode 100644 index 0000000..340f313 --- /dev/null +++ b/tests/nsstest.c @@ -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 -- 2.4.10

On Tue, Mar 15, 2016 at 06:05:55PM +0100, Michal Privoznik wrote:
A small test to see how is the nss module working.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- cfg.mk | 2 +- tests/Makefile.am | 18 ++++ tests/nssdata/virbr0.status | 20 +++++ tests/nssdata/virbr1.status | 20 +++++ tests/nssmock.c | 140 +++++++++++++++++++++++++++++ tests/nsstest.c | 208 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 tests/nssdata/virbr0.status create mode 100644 tests/nssdata/virbr1.status create mode 100644 tests/nssmock.c create mode 100644 tests/nsstest.c
[...]
+ 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)));
I would rather we didn't call at all instead of twice, but that's something we can change later on. We can live with that for now ;)

The only purpose of this test is to catch possible linking problems with libnss_libvirt.so.2. One of the problems I faced was that the NSS plugin was unloaded immediately after it got loaded and the name resolution process continued with next configured option. Without any error. It was very hard to debug why until I created this simple test and found out immediately that there were some symbols missing. The reason why problem was not caught in nsstest is that in the test we want to use all the fancy stuff and therefore link it with libvirt.la. So even if there's a symbol missing in the NSS plugin it will be found in the libvirt.la. But even after I resolved the issue we still need this test because files the NSS plugin is built from are still live (mostly those under utils/ dir). So as they change new symbol might be required which would render the NSS plugin unusable. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/Makefile.am | 11 ++++++++++- tests/nsslinktest.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/nsslinktest.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 2bb9d28..6d040b1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -158,7 +158,7 @@ EXTRA_DIST = \ xml2sexprdata \ xml2vmxdata -test_helpers = commandhelper ssh test_conf +test_helpers = commandhelper ssh test_conf nsslinktest test_programs = virshtest sockettest \ nodeinfotest virbuftest \ commandtest seclabeltest \ @@ -1085,6 +1085,15 @@ nssmock_la_CFLAGS = $(AM_CFLAGS) nssmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) nssmock_la_LIBADD = $(MOCKLIBS_LIBS) +## Intentionaly not linking with anything else. +## See the test source for more detailed explanation. +nsslinktest_SOURCES = nsslinktest.c +nsslinktest_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(top_srcdir)/tools/nss +nsslinktest_LDADD = ../tools/nss/libnss_libvirt_impl.la +nsslinktest_LDFLAGS = $(NULL) + virnetdevtest_SOURCES = \ virnetdevtest.c testutils.h testutils.c virnetdevtest_CFLAGS = $(AM_CFLAGS) $(LIBNL_CFLAGS) diff --git a/tests/nsslinktest.c b/tests/nsslinktest.c new file mode 100644 index 0000000..0232e36 --- /dev/null +++ b/tests/nsslinktest.c @@ -0,0 +1,39 @@ +/* + * 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 "internal.h" +#include "libvirt_nss.h" + +int main(int argc ATTRIBUTE_UNUSED, + char *argv[] ATTRIBUTE_UNUSED) +{ + int err, herrno; /* Dummy variables to prevent SIGSEGV */ + + /* The only aim of this test is to catch link errors as those + * are hard to trace for resulting .so library. Therefore, + * the fact this test has been built successfully means + * there's no linkage problem and therefore success is + * returned. */ + _nss_libvirt_gethostbyname_r(NULL, NULL, NULL, 0, &err, &herrno); + + return EXIT_SUCCESS; +} -- 2.4.10

On Tue, Mar 15, 2016 at 06:05:47PM +0100, Michal Privoznik wrote:
v5 of:
https://www.redhat.com/archives/libvir-list/2016-February/msg00693.html
diff to v4: - Dropped the virjson const correctness patch - Worked in Martin's review (small nits here and there) - Dropped libxml2 dependency
Patches 1, 4, and 5 have been ACKed already, but I'm sending them for completeness.
ACK series with the nits in 6/9 and 7/9 fixed. Good job. Martin

On 18.03.2016 16:49, Martin Kletzander wrote:
On Tue, Mar 15, 2016 at 06:05:47PM +0100, Michal Privoznik wrote:
v5 of:
https://www.redhat.com/archives/libvir-list/2016-February/msg00693.html
diff to v4: - Dropped the virjson const correctness patch - Worked in Martin's review (small nits here and there) - Dropped libxml2 dependency
Patches 1, 4, and 5 have been ACKed already, but I'm sending them for completeness.
ACK series with the nits in 6/9 and 7/9 fixed. Good job.
Martin
Thank you. I've just pushed this. I'm planning to write a wiki page on this feature during weekend. Mainly how to enable the feature. Well, that should be fairly easy - just changing one line in /etc/nsswitch.conf. Michal
participants (3)
-
Daniel P. Berrange
-
Martin Kletzander
-
Michal Privoznik