[libvirt] [PATCH] nss: FreeBSD support

Michal Privoznik mprivozn at redhat.com
Fri Mar 25 10:19:17 UTC 2016


On 25.03.2016 08:43, Roman Bogorodskiy wrote:
>  * tools/nss/libvirt_nss.[ch]: add BSD-comptabile wrappers and
>    register via the nss_module_register() interface
>  * m4/virt-nss.m4: add checks if we're building NSS for FreeBSD
>  * tools/Makefile.am: handle target library name differences, as
>    Linux needs libnss_libvirt.so.2 and FreeBSD needs
>    nss_libvirt.so.1. Also, different syms files have to be used
>    as Linux needs to export all the methods while FreeBSD
>    only needs to have nss_module_register()
>  * libvirt_nss_bsd.syms: FreeBSD syms file
> ---
>  m4/virt-nss.m4                 |  12 +++-
>  tools/Makefile.am              |  16 ++++-
>  tools/nss/libvirt_nss.c        | 140 +++++++++++++++++++++++++++++++++++++++--
>  tools/nss/libvirt_nss.h        |   9 +++
>  tools/nss/libvirt_nss_bsd.syms |   9 +++
>  5 files changed, 179 insertions(+), 7 deletions(-)
>  create mode 100644 tools/nss/libvirt_nss_bsd.syms
> 
> diff --git a/m4/virt-nss.m4 b/m4/virt-nss.m4
> index 3fa4ad3..a8ed8b9 100644
> --- a/m4/virt-nss.m4
> +++ b/m4/virt-nss.m4
> @@ -23,6 +23,7 @@ AC_DEFUN([LIBVIRT_CHECK_NSS],[
>        [enable Name Servie Switch plugin for resolving guest IP addresses])],
>        [], [with_nss_plugin=check])
>  
> +  bsd_nss=no
>    fail=0
>    if test "x$with_nss_plugin" != "xno" ; then
>      AC_CHECK_HEADERS([nss.h], [
> @@ -39,11 +40,20 @@ AC_DEFUN([LIBVIRT_CHECK_NSS],[
>  
>      if test "x$with_nss_plugin" = "xyes" ; then
>        AC_DEFINE_UNQUOTED([NSS], 1, [whether nss plugin is enabled])
> +
> +      AC_CHECK_TYPES([ns_mtab, nss_module_unregister_fn],
> +                     [AC_DEFINE([HAVE_BSD_NSS],
> +                                [1],
> +                                [whether using BSD style NSS])
> +                      bsd_nss=yes
> +                     ],
> +                     [],
> +                     [#include <nsswitch.h>])
>      fi
>    fi
>  
>    AM_CONDITIONAL(WITH_NSS, [test "x$with_nss_plugin" = "xyes"])
> -
> +  AM_CONDITIONAL(WITH_BSD_NSS, [test "x$bsd_nss" = "xyes"])
>  ])
>  
>  AC_DEFUN([LIBVIRT_RESULT_NSS],[
> diff --git a/tools/Makefile.am b/tools/Makefile.am
> index 4320040..6005b8b 100644
> --- a/tools/Makefile.am
> +++ b/tools/Makefile.am
> @@ -417,8 +417,22 @@ CLEANFILES += wireshark/src/plugin.c
>  
>  endif WITH_WIRESHARK_DISSECTOR
>  
> +if WITH_BSD_NSS
> +LIBVIRT_NSS_SYMBOL_FILE = \
> +	$(srcdir)/nss/libvirt_nss_bsd.syms
> +NSS_SO_VER = 1
> +
> +install-exec-hook:
> +	cd $(DESTDIR)$(libdir) && \
> +	  $(LN_S) libnss_libvirt.so.$(NSS_SO_VER) nss_libvirt.so.$(NSS_SO_VER)
> +

Yeah, very similar link exists on my linux machine too (except for the
version at EOL). Maybe one day I'll add the link for Linux too.

> +uninstall-local:
> +	rm $(DESTDIR)$(libdir)/libnss_libvirt.so.$(NSS_SO_VER)
> +else ! WITH_BSD_NSS
>  LIBVIRT_NSS_SYMBOL_FILE = \
>  	$(srcdir)/nss/libvirt_nss.syms
> +NSS_SO_VER = 2
> +endif ! WITH_BSD_NSS
>  
>  LIBVIRT_NSS_SOURCES = \
>  	nss/libvirt_nss.c	\
> @@ -449,7 +463,7 @@ nss_libnss_libvirt_la_LDFLAGS = \
>  	-export-dynamic \
>  	-avoid-version \
>  	-shared \
> -	-shrext .so.2
> +	-shrext .so.$(NSS_SO_VER)
>  
>  nss_libnss_libvirt_la_LIBADD =  \
>  	nss/libnss_libvirt_impl.la
> diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c
> index 218c62a..0ff1348 100644
> --- a/tools/nss/libvirt_nss.c
> +++ b/tools/nss/libvirt_nss.c
> @@ -1,5 +1,4 @@
>  /*
> - * libvirt_nss: Name Service Switch plugin

This is unintended, right?

>   *
>   * The aim is to enable users and applications to translate
>   * domain names into IP addresses. However, this is currently
> @@ -29,11 +28,16 @@
>  
>  #include "libvirt_nss.h"
>  
> +#include <netinet/in.h>
>  #include <resolv.h>
>  #include <sys/types.h>
>  #include <dirent.h>
>  #include <arpa/inet.h>
>  
> +#if defined(HAVE_BSD_NSS)
> +# include <nsswitch.h>
> +#endif
> +
>  #include "virlease.h"
>  #include "viralloc.h"
>  #include "virfile.h"
> @@ -65,7 +69,7 @@ do {                                                            \
>  
>  #define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/"
>  
> -#define ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1))
> +#define LIBVIRT_ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1))

Yeah, I've seen the name clash with some header file when trying to
compile on my freebsd machine too.

>  #define FAMILY_ADDRESS_SIZE(family) ((family) == AF_INET6 ? 16 : 4)
>  
>  typedef struct {
> @@ -256,7 +260,7 @@ static inline void *
>  move_and_align(void *buf, size_t len, size_t *idx)
>  {
>      char *buffer = buf;
> -    size_t move = ALIGN(len);
> +    size_t move = LIBVIRT_ALIGN(len);
>  
>      if (!idx)
>          return buffer + move;
> @@ -321,7 +325,7 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result,
>       * b) alias
>       * c) addresses
>       * d) NULL stem */
> -    need = ALIGN(nameLen + 1) + naddr * ALIGN(alen) + (naddr + 2) * sizeof(char*);
> +    need = LIBVIRT_ALIGN(nameLen + 1) + naddr * LIBVIRT_ALIGN(alen) + (naddr + 2) * sizeof(char*);
>  
>      if (buflen < need) {
>          *errnop = ENOMEM;
> @@ -383,6 +387,7 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result,
>      return ret;
>  }
>  
> +#ifdef HAVE_STRUCT_GAIH_ADDRTUPLE
>  enum nss_status
>  _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat,
>                                char *buffer, size_t buflen, int *errnop,
> @@ -426,7 +431,7 @@ _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat,
>      /* We need space for:
>       * a) name
>       * b) addresses */
> -    need = ALIGN(nameLen + 1) + naddr * ALIGN(sizeof(struct gaih_addrtuple));
> +    need = LIBVIRT_ALIGN(nameLen + 1) + naddr * LIBVIRT_ALIGN(sizeof(struct gaih_addrtuple));
>  
>      if (buflen < need) {
>          *errnop = ENOMEM;
> @@ -474,3 +479,128 @@ _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat,
>   cleanup:
>      return ret;
>  }
> +#endif /* HAVE_STRUCT_GAIH_ADDRTUPLE */

I guess this will not fly. I mean, the symbol is exported so I guess we
need an #else branch providing a dummy implementation, don't we?
Honestly, I don't know. Maybe we don't as long as we don't run
check-symfile whether all symbols are exported I guess we are good. Or
we can just introduce yet another symbol file that would be included
conditionally.

BUT, you forgot to include bit that checks for struct gaih_ddrtuple and
defines HAVE_STRUCT_..?

> +
> +#if defined(HAVE_BSD_NSS)
> +NSS_METHOD_PROTOTYPE(_nss_compat_getaddrinfo);
> +NSS_METHOD_PROTOTYPE(_nss_compat_gethostbyname2_r);
> +
> +ns_mtab methods[] = {
> +    { NSDB_HOSTS, "getaddrinfo", _nss_compat_getaddrinfo, NULL },
> +    { NSDB_HOSTS, "gethostbyname", _nss_compat_gethostbyname2_r, NULL },
> +    { NSDB_HOSTS, "gethostbyname2_r", _nss_compat_gethostbyname2_r, NULL },
> +};
> +
> +static void
> +aiforaf(const char *name, int af, struct addrinfo *pai, struct addrinfo **aip)
> +{
> +    int ret;
> +    struct hostent resolved;
> +    char buf[1024] = { 0 };
> +    int err, herr;
> +    struct addrinfo hints, *res0, *res;
> +    char **addrList;
> +
> +    if ((ret = _nss_libvirt_gethostbyname2_r(name, af, &resolved,
> +                                             buf, sizeof(buf),
> +                                             &err, &herr)) != NS_SUCCESS)
> +        return;
> +
> +    addrList = resolved.h_addr_list;
> +    while (*addrList) {
> +        virSocketAddr sa;
> +        char *ipAddr = NULL;
> +        void *address = *addrList;
> +
> +        memset(&sa, 0, sizeof(sa));
> +        if (resolved.h_addrtype == AF_INET) {
> +            virSocketAddrSetIPv4AddrNetOrder(&sa, *((uint32_t *) address));
> +        } else {
> +            virSocketAddrSetIPv6AddrNetOrder(&sa, address);
> +        }
> +
> +        ipAddr = virSocketAddrFormat(&sa);
> +
> +        hints = *pai;
> +        hints.ai_flags = AI_NUMERICHOST;
> +        hints.ai_family = af;
> +
> +        if (getaddrinfo(ipAddr, NULL, &hints, &res0)) {

Interesting. I don't know how NSS works on *bsd but this function is
called from getaddrinfo() and it is calling getaddrinfo yet again. Is
that okay?

> +            addrList++;
> +            continue;
> +        }
> +
> +        for (res = res0; res; res = res->ai_next)
> +            res->ai_flags = pai->ai_flags;
> +
> +        (*aip)->ai_next = res0;
> +        while ((*aip)->ai_next)
> +           *aip = (*aip)->ai_next;
> +
> +        addrList++;
> +    }
> +}
> +
> +int
> +_nss_compat_getaddrinfo(void *retval, void *mdata ATTRIBUTE_UNUSED, va_list ap)
> +{
> +    struct addrinfo sentinel, *cur, *ai;
> +    const char *name;
> +  

Trailing space.

> +    name  = va_arg(ap, char *);
> +    ai = va_arg(ap, struct addrinfo *);
> +
> +    memset(&sentinel, 0, sizeof(sentinel));
> +    cur = &sentinel;
> +
> +    if ((ai->ai_family == AF_UNSPEC) || (ai->ai_family == AF_INET6))
> +        aiforaf(name, AF_INET6, ai, &cur);
> +    if ((ai->ai_family == AF_UNSPEC) || (ai->ai_family == AF_INET))
> +        aiforaf(name, AF_INET, ai, &cur);
> +
> +    if (sentinel.ai_next == NULL) {
> +        h_errno = HOST_NOT_FOUND;
> +        return NS_NOTFOUND;
> +    }
> +    *((struct addrinfo **)retval) = sentinel.ai_next;
> +
> +    return NS_SUCCESS;
> +}
> +
> +int
> +_nss_compat_gethostbyname2_r(void *retval, void *mdata ATTRIBUTE_UNUSED, va_list ap)
> +{
> +    int ret;
> +
> +    const char *name;
> +    int af;
> +    struct hostent *result;
> +    char *buffer;
> +    size_t buflen;
> +    int *errnop;
> +    int *herrnop;
> +
> +    name = va_arg(ap, const char *);
> +    af = va_arg(ap, int);
> +    result = va_arg(ap, struct hostent *);
> +    buffer = va_arg(ap, char *);
> +    buflen = va_arg(ap, size_t);
> +    errnop = va_arg(ap, int *);
> +    herrnop = va_arg(ap, int *);
> +
> +    ret = _nss_libvirt_gethostbyname2_r(
> +              name, af, result, buffer, buflen, errnop, herrnop);
> +    *(struct hostent **)retval = (ret == NS_SUCCESS) ? result : NULL;
> +
> +    return ret;
> +}
> +
> +ns_mtab*
> +nss_module_register(const char *name ATTRIBUTE_UNUSED, unsigned int *size,
> +                    nss_module_unregister_fn *unregister)
> +{
> +    *size = sizeof(methods) / sizeof(methods[0]);
> +    *unregister = NULL;
> +    return methods;
> +}
> +#endif /* HAVE_BSD_NSS */
> diff --git a/tools/nss/libvirt_nss.h b/tools/nss/libvirt_nss.h
> index 589c1e6..e025e63 100644
> --- a/tools/nss/libvirt_nss.h
> +++ b/tools/nss/libvirt_nss.h
> @@ -45,8 +45,17 @@ 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);
> +# ifdef HAVE_STRUCT_GAIH_ADDRTUPLE
>  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 /* HAVE_STRUCT_GAIH_ADDRTUPLE */
> +
> +# if defined(HAVE_BSD_NSS)
> +ns_mtab*
> +nss_module_register(const char *name, unsigned int *size,
> +                    nss_module_unregister_fn *unregister);
> +# endif /* HAVE_BSD_NSS */
> +
>  #endif /* __LIBVIRT_NSS_H__ */
> diff --git a/tools/nss/libvirt_nss_bsd.syms b/tools/nss/libvirt_nss_bsd.syms
> new file mode 100644
> index 0000000..7da3926
> --- /dev/null
> +++ b/tools/nss/libvirt_nss_bsd.syms
> @@ -0,0 +1,9 @@
> +#
> +# Officially exported symbols.
> +#
> +
> +{
> +global:
> +    nss_module_register;
> +local: *;
> +};
> 

Michal




More information about the libvir-list mailing list