2016-02-13 11:27:50 +03:00
/*
* 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/>.
*/
# include <config.h>
# include "libvirt_nss.h"
2016-03-27 21:07:10 +03:00
# include <netinet/in.h>
2016-02-14 13:38:37 +03:00
# include <resolv.h>
# include <sys/types.h>
# include <dirent.h>
# include <arpa/inet.h>
2016-03-27 21:07:10 +03:00
# if defined(HAVE_BSD_NSS)
# include <nsswitch.h>
# endif
2016-02-14 13:38:37 +03:00
# include "virlease.h"
# include "viralloc.h"
2016-09-30 18:11:38 +03:00
# include "virtime.h"
2016-02-14 13:38:37 +03:00
# include "virerror.h"
# include "virsocketaddr.h"
# include "configmake.h"
2016-11-29 15:48:53 +03:00
# include "virmacmap.h"
# include "virobject.h"
2016-02-14 13:38:37 +03:00
#if 0
2017-11-03 15:09:47 +03:00
# define ERROR(...) \
do { \
char ebuf [ 1024 ] ; \
fprintf ( stderr , " ERROR %s:%d : " , __FUNCTION__ , __LINE__ ) ; \
fprintf ( stderr , __VA_ARGS__ ) ; \
2016-02-14 13:38:37 +03:00
fprintf ( stderr , " : %s \n " , virStrerror ( errno , ebuf , sizeof ( ebuf ) ) ) ; \
2017-11-03 15:09:47 +03:00
fprintf ( stderr , " \n " ) ; \
2016-02-14 13:38:37 +03:00
} while ( 0 )
2017-11-03 15:09:47 +03:00
# define DEBUG(...) \
do { \
fprintf ( stderr , " DEBUG %s:%d : " , __FUNCTION__ , __LINE__ ) ; \
fprintf ( stderr , __VA_ARGS__ ) ; \
fprintf ( stderr , " \n " ) ; \
2016-02-14 13:38:37 +03:00
} while ( 0 )
# else
# define ERROR(...) do { } while (0)
# define DEBUG(...) do { } while (0)
# endif
# define LEASEDIR LOCALSTATEDIR " / lib / libvirt / dnsmasq / "
2016-03-27 21:07:10 +03:00
# define LIBVIRT_ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1))
2016-02-14 13:38:37 +03:00
# define FAMILY_ADDRESS_SIZE(family) ((family) == AF_INET6 ? 16 : 4)
typedef struct {
unsigned char addr [ 16 ] ;
int af ;
2019-07-10 15:30:11 +03:00
long long expirytime ;
2016-02-14 13:38:37 +03:00
} leaseAddress ;
2016-12-04 15:05:43 +03:00
2019-07-10 15:30:11 +03:00
static int
leaseAddressSorter ( const void * a ,
const void * b )
{
const leaseAddress * la = a ;
const leaseAddress * lb = b ;
return lb - > expirytime - la - > expirytime ;
}
static void
sortAddr ( leaseAddress * tmpAddress ,
size_t ntmpAddress )
{
qsort ( tmpAddress , ntmpAddress , sizeof ( * tmpAddress ) , leaseAddressSorter ) ;
}
2016-12-04 15:05:43 +03:00
static int
2019-07-10 11:34:53 +03:00
appendAddr ( const char * name ATTRIBUTE_UNUSED ,
leaseAddress * * tmpAddress ,
2016-12-04 15:05:43 +03:00
size_t * ntmpAddress ,
virJSONValuePtr lease ,
int af )
{
const char * ipAddr ;
virSocketAddr sa ;
int family ;
2019-07-10 15:30:11 +03:00
long long expirytime ;
2016-12-04 15:05:43 +03:00
size_t i ;
if ( ! ( ipAddr = virJSONValueObjectGetString ( lease , " ip-address " ) ) ) {
ERROR ( " ip-address field missing for %s " , name ) ;
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-04 15:05:43 +03:00
}
DEBUG ( " IP address: %s " , ipAddr ) ;
if ( virSocketAddrParse ( & sa , ipAddr , AF_UNSPEC ) < 0 ) {
ERROR ( " Unable to parse %s " , ipAddr ) ;
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-04 15:05:43 +03:00
}
family = VIR_SOCKET_ADDR_FAMILY ( & sa ) ;
if ( af ! = AF_UNSPEC & & af ! = family ) {
DEBUG ( " Skipping address which family is %d, %d requested " , family , af ) ;
2019-07-10 11:09:46 +03:00
return 0 ;
2016-12-04 15:05:43 +03:00
}
2019-07-10 15:30:11 +03:00
if ( virJSONValueObjectGetNumberLong ( lease , " expiry-time " , & expirytime ) < 0 ) {
/* A lease cannot be present without expiry-time */
ERROR ( " expiry-time field missing for %s " , name ) ;
return - 1 ;
}
2016-12-04 15:05:43 +03:00
for ( i = 0 ; i < * ntmpAddress ; i + + ) {
if ( memcmp ( ( * tmpAddress ) [ i ] . addr ,
( family = = AF_INET ?
( void * ) & sa . data . inet4 . sin_addr . s_addr :
( void * ) & sa . data . inet6 . sin6_addr . s6_addr ) ,
FAMILY_ADDRESS_SIZE ( family ) ) = = 0 ) {
DEBUG ( " IP address already in the list " ) ;
2019-07-10 11:09:46 +03:00
return 0 ;
2016-12-04 15:05:43 +03:00
}
}
if ( VIR_REALLOC_N_QUIET ( * tmpAddress , * ntmpAddress + 1 ) < 0 ) {
ERROR ( " Out of memory " ) ;
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-04 15:05:43 +03:00
}
2019-07-10 15:30:11 +03:00
( * tmpAddress ) [ * ntmpAddress ] . expirytime = expirytime ;
2016-12-04 15:05:43 +03:00
( * 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 ) + + ;
2019-07-10 11:09:46 +03:00
return 0 ;
2016-12-04 15:05:43 +03:00
}
2016-12-06 14:54:43 +03:00
static int
findLeaseInJSON ( leaseAddress * * tmpAddress ,
size_t * ntmpAddress ,
virJSONValuePtr leases_array ,
size_t nleases ,
const char * name ,
2016-11-29 15:48:53 +03:00
const char * * macs ,
2016-12-06 14:54:43 +03:00
int af ,
bool * found )
{
size_t i ;
long long expirytime ;
time_t currtime ;
if ( ( currtime = time ( NULL ) ) = = ( time_t ) - 1 ) {
ERROR ( " Failed to get current system time " ) ;
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-06 14:54:43 +03:00
}
for ( i = 0 ; i < nleases ; i + + ) {
virJSONValuePtr lease = virJSONValueArrayGet ( leases_array , i ) ;
if ( ! lease ) {
/* This should never happen (TM) */
ERROR ( " Unable to get element %zu of %zu " , i , nleases ) ;
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-06 14:54:43 +03:00
}
2016-11-29 15:48:53 +03:00
if ( macs ) {
2019-07-30 17:33:20 +03:00
const char * * macstmp = macs ;
2016-11-29 15:48:53 +03:00
const char * macAddr ;
2019-07-30 17:33:20 +03:00
bool match = false ;
2016-12-06 14:54:43 +03:00
2016-11-29 15:48:53 +03:00
macAddr = virJSONValueObjectGetString ( lease , " mac-address " ) ;
if ( ! macAddr )
continue ;
2019-07-30 17:33:20 +03:00
while ( * macstmp & & ! match ) {
if ( STREQ ( * macstmp , macAddr ) )
match = true ;
macstmp + + ;
}
if ( ! match )
2016-11-29 15:48:53 +03:00
continue ;
} else {
const char * lease_name ;
lease_name = virJSONValueObjectGetString ( lease , " hostname " ) ;
if ( STRNEQ_NULLABLE ( name , lease_name ) )
continue ;
}
2016-12-06 14:54:43 +03:00
if ( virJSONValueObjectGetNumberLong ( lease , " expiry-time " , & expirytime ) < 0 ) {
/* A lease cannot be present without expiry-time */
ERROR ( " expiry-time field missing for %s " , name ) ;
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-06 14:54:43 +03:00
}
/* Do not report expired lease */
if ( expirytime < ( long long ) currtime ) {
DEBUG ( " Skipping expired lease for %s " , name ) ;
continue ;
}
DEBUG ( " Found record for %s " , name ) ;
* found = true ;
2019-07-10 11:34:53 +03:00
if ( appendAddr ( name , tmpAddress , ntmpAddress , lease , af ) < 0 )
2019-07-10 11:09:46 +03:00
return - 1 ;
2016-12-06 14:54:43 +03:00
}
2019-07-10 11:09:46 +03:00
return 0 ;
2016-12-06 14:54:43 +03:00
}
2016-02-14 13:38:37 +03:00
/**
* 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 )
2016-02-13 11:27:50 +03:00
{
2016-02-14 13:38:37 +03:00
DIR * dir = NULL ;
int ret = - 1 ;
const char * leaseDir = LEASEDIR ;
struct dirent * entry ;
2019-07-10 11:03:49 +03:00
VIR_AUTOPTR ( virJSONValue ) leases_array = NULL ;
2016-12-06 14:54:43 +03:00
ssize_t nleases ;
2019-07-10 11:03:49 +03:00
VIR_AUTOFREE ( leaseAddress * ) tmpAddress = NULL ;
2016-02-14 13:38:37 +03:00
size_t ntmpAddress = 0 ;
2019-07-10 11:03:49 +03:00
VIR_AUTOFREE ( virMacMapPtr * ) macmaps = NULL ;
2016-11-29 15:48:53 +03:00
size_t nMacmaps = 0 ;
2016-02-14 13:38:37 +03:00
* address = NULL ;
* naddress = 0 ;
* found = false ;
if ( af ! = AF_UNSPEC & & af ! = AF_INET & & af ! = AF_INET6 ) {
errno = EAFNOSUPPORT ;
goto cleanup ;
}
2019-07-30 17:33:20 +03:00
dir = opendir ( leaseDir ) ;
if ( ! dir ) {
2016-02-14 13:38:37 +03:00
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 ) ;
2019-07-30 17:33:20 +03:00
while ( ( entry = readdir ( dir ) ) ! = NULL ) {
2016-02-14 13:38:37 +03:00
char * path ;
2019-07-30 17:33:20 +03:00
size_t dlen = strlen ( entry - > d_name ) ;
2016-02-14 13:38:37 +03:00
2019-07-30 17:33:20 +03:00
if ( dlen > = 7 & & STREQ ( entry - > d_name + dlen - 7 , " .status " ) ) {
2019-07-30 17:33:20 +03:00
if ( asprintf ( & path , " %s/%s " , leaseDir , entry - > d_name ) < 0 )
2016-11-29 15:48:53 +03:00
goto cleanup ;
2016-02-14 13:38:37 +03:00
2016-11-29 15:48:53 +03:00
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 ) ;
2019-07-30 17:33:20 +03:00
} else if ( dlen > = 5 & & STREQ ( entry - > d_name + dlen - 5 , " .macs " ) ) {
2019-07-30 17:33:20 +03:00
if ( asprintf ( & path , " %s/%s " , leaseDir , entry - > d_name ) < 0 )
2016-11-29 15:48:53 +03:00
goto cleanup ;
if ( VIR_REALLOC_N_QUIET ( macmaps , nMacmaps + 1 ) < 0 ) {
VIR_FREE ( path ) ;
goto cleanup ;
}
DEBUG ( " Processing %s " , path ) ;
if ( ! ( macmaps [ nMacmaps ] = virMacMapNew ( path ) ) ) {
ERROR ( " Unable to parse %s " , path ) ;
VIR_FREE ( path ) ;
goto cleanup ;
}
nMacmaps + + ;
2016-02-14 13:38:37 +03:00
VIR_FREE ( path ) ;
}
2019-07-30 17:33:20 +03:00
errno = 0 ;
2016-02-14 13:38:37 +03:00
}
2019-07-30 17:33:20 +03:00
closedir ( dir ) ;
dir = NULL ;
2016-02-14 13:38:37 +03:00
2018-04-20 00:29:02 +03:00
nleases = virJSONValueArraySize ( leases_array ) ;
2016-02-14 13:38:37 +03:00
DEBUG ( " Read %zd leases " , nleases ) ;
2016-11-29 15:48:53 +03:00
# if !defined(LIBVIRT_NSS_GUEST)
2016-12-06 14:54:43 +03:00
if ( findLeaseInJSON ( & tmpAddress , & ntmpAddress ,
leases_array , nleases ,
2016-11-29 15:48:53 +03:00
name , NULL , af , found ) < 0 )
2016-09-30 18:11:38 +03:00
goto cleanup ;
2016-02-14 13:38:37 +03:00
2016-11-29 15:48:53 +03:00
# else /* defined(LIBVIRT_NSS_GUEST) */
size_t i ;
for ( i = 0 ; i < nMacmaps ; i + + ) {
const char * * macs = ( const char * * ) virMacMapLookup ( macmaps [ i ] , name ) ;
if ( ! macs )
continue ;
if ( findLeaseInJSON ( & tmpAddress , & ntmpAddress ,
leases_array , nleases ,
name , macs , af , found ) < 0 )
goto cleanup ;
}
# endif /* defined(LIBVIRT_NSS_GUEST) */
2019-07-10 15:30:11 +03:00
sortAddr ( tmpAddress , ntmpAddress ) ;
2019-07-10 11:01:56 +03:00
VIR_STEAL_PTR ( * address , tmpAddress ) ;
2016-02-14 13:38:37 +03:00
* naddress = ntmpAddress ;
ntmpAddress = 0 ;
ret = 0 ;
cleanup :
* errnop = errno ;
2019-07-30 17:33:20 +03:00
if ( dir )
closedir ( dir ) ;
2016-11-29 15:48:53 +03:00
while ( nMacmaps )
virObjectUnref ( macmaps [ - - nMacmaps ] ) ;
2016-02-14 13:38:37 +03:00
return ret ;
}
enum nss_status
2016-12-04 13:56:44 +03:00
NSS_NAME ( gethostbyname ) ( const char * name , struct hostent * result ,
char * buffer , size_t buflen , int * errnop ,
int * herrnop )
2016-02-14 13:38:37 +03:00
{
2017-01-18 20:30:18 +03:00
return NSS_NAME ( gethostbyname3 ) ( name , AF_INET , result , buffer , buflen ,
2016-12-04 13:56:44 +03:00
errnop , herrnop , NULL , NULL ) ;
2016-02-14 13:38:37 +03:00
}
enum nss_status
2016-12-04 13:56:44 +03:00
NSS_NAME ( gethostbyname2 ) ( const char * name , int af , struct hostent * result ,
char * buffer , size_t buflen , int * errnop ,
int * herrnop )
2016-02-14 13:38:37 +03:00
{
2016-12-04 13:56:44 +03:00
return NSS_NAME ( gethostbyname3 ) ( name , af , result , buffer , buflen ,
errnop , herrnop , NULL , NULL ) ;
2016-02-14 13:38:37 +03:00
}
2016-03-18 18:46:41 +03:00
static inline void *
move_and_align ( void * buf , size_t len , size_t * idx )
{
char * buffer = buf ;
2016-03-27 21:07:10 +03:00
size_t move = LIBVIRT_ALIGN ( len ) ;
2016-03-18 18:46:41 +03:00
if ( ! idx )
return buffer + move ;
* idx + = move ;
return buffer + * idx ;
}
2016-02-14 13:38:37 +03:00
enum nss_status
2016-12-04 13:56:44 +03:00
NSS_NAME ( gethostbyname3 ) ( const char * name , int af , struct hostent * result ,
char * buffer , size_t buflen , int * errnop ,
int * herrnop , int32_t * ttlp , char * * canonp )
2016-02-14 13:38:37 +03:00
{
enum nss_status ret = NSS_STATUS_UNAVAIL ;
2016-03-18 18:46:41 +03:00
char * r_name , * * r_aliases , * r_addr , * r_addr_next , * * r_addr_list ;
2019-07-10 11:03:49 +03:00
VIR_AUTOFREE ( leaseAddress * ) addr = NULL ;
2016-02-14 13:38:37 +03:00
size_t naddr , i ;
bool found = false ;
2016-03-18 18:46:41 +03:00
size_t nameLen , need , idx = 0 ;
2016-02-14 13:38:37 +03:00
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 */
2016-03-27 21:07:10 +03:00
need = LIBVIRT_ALIGN ( nameLen + 1 ) + naddr * LIBVIRT_ALIGN ( alen ) + ( naddr + 2 ) * sizeof ( char * ) ;
2016-02-14 13:38:37 +03:00
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 ) ;
2016-03-18 18:46:41 +03:00
r_aliases = move_and_align ( buffer , nameLen + 1 , & idx ) ;
2016-02-14 13:38:37 +03:00
/* Second, create aliases array */
r_aliases [ 0 ] = NULL ;
/* Third, append address */
2016-03-18 18:46:41 +03:00
r_addr = move_and_align ( buffer , sizeof ( char * ) , & idx ) ;
r_addr_next = r_addr ;
for ( i = 0 ; i < naddr ; i + + ) {
memcpy ( r_addr_next , addr [ i ] . addr , alen ) ;
r_addr_next = move_and_align ( buffer , alen , & idx ) ;
}
2016-02-14 13:38:37 +03:00
2016-03-18 18:46:41 +03:00
r_addr_list = move_and_align ( buffer , 0 , & idx ) ;
r_addr_next = r_addr ;
2016-02-14 13:38:37 +03:00
/* Third, append address pointer array */
2016-03-18 18:46:41 +03:00
for ( i = 0 ; i < naddr ; i + + ) {
r_addr_list [ i ] = r_addr_next ;
r_addr_next = move_and_align ( r_addr_next , alen , NULL ) ;
}
2016-02-14 13:38:37 +03:00
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 :
return ret ;
2016-02-13 11:27:50 +03:00
}
2016-02-14 10:13:54 +03:00
2016-03-27 21:07:10 +03:00
# ifdef HAVE_STRUCT_GAIH_ADDRTUPLE
2016-02-14 10:13:54 +03:00
enum nss_status
2016-12-04 13:56:44 +03:00
NSS_NAME ( gethostbyname4 ) ( const char * name , struct gaih_addrtuple * * pat ,
char * buffer , size_t buflen , int * errnop ,
int * herrnop , int32_t * ttlp )
2016-02-14 10:13:54 +03:00
{
enum nss_status ret = NSS_STATUS_UNAVAIL ;
leaseAddress * addr = NULL ;
size_t naddr , i ;
bool found = false ;
int r ;
2016-03-18 18:46:41 +03:00
size_t nameLen , need , idx = 0 ;
2016-02-14 10:13:54 +03:00
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 ) addresses */
2016-03-27 21:07:10 +03:00
need = LIBVIRT_ALIGN ( nameLen + 1 ) + naddr * LIBVIRT_ALIGN ( sizeof ( struct gaih_addrtuple ) ) ;
2016-02-14 10:13:54 +03:00
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 ) ;
/* Second, append addresses */
2016-03-18 18:46:41 +03:00
r_tuple_first = move_and_align ( buffer , nameLen + 1 , & idx ) ;
2016-02-14 10:13:54 +03:00
for ( i = 0 ; i < naddr ; i + + ) {
int family = addr [ i ] . af ;
2016-03-18 18:46:41 +03:00
r_tuple = move_and_align ( buffer , 0 , & idx ) ;
2016-02-14 10:13:54 +03:00
if ( i = = naddr - 1 )
r_tuple - > next = NULL ;
else
2016-03-18 18:46:41 +03:00
r_tuple - > next = move_and_align ( buffer , sizeof ( struct gaih_addrtuple ) , & idx ) ;
2016-02-14 10:13:54 +03:00
r_tuple - > name = r_name ;
r_tuple - > family = family ;
r_tuple - > scopeid = 0 ;
memcpy ( r_tuple - > addr , addr [ i ] . addr , FAMILY_ADDRESS_SIZE ( family ) ) ;
}
/* 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 ;
}
2016-03-27 21:07:10 +03:00
# endif /* HAVE_STRUCT_GAIH_ADDRTUPLE */
# 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 ;
2016-12-04 13:56:44 +03:00
if ( ( ret = NSS_NAME ( gethostbyname2 ) ( name , af , & resolved ,
buf , sizeof ( buf ) ,
& err , & herr ) ) ! = NS_SUCCESS )
2016-03-27 21:07:10 +03:00
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 ) ) {
2017-09-22 13:41:51 +03:00
VIR_FREE ( ipAddr ) ;
2016-03-27 21:07:10 +03:00
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 ;
2017-09-22 13:41:51 +03:00
VIR_FREE ( ipAddr ) ;
2016-03-27 21:07:10 +03:00
addrList + + ;
}
}
int
_nss_compat_getaddrinfo ( void * retval , void * mdata ATTRIBUTE_UNUSED , va_list ap )
{
struct addrinfo sentinel , * cur , * ai ;
const char * name ;
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 * ) ;
2016-12-04 13:56:44 +03:00
ret = NSS_NAME ( gethostbyname2 ) ( name , af , result , buffer , buflen , errnop , herrnop ) ;
2016-03-27 21:07:10 +03:00
* ( 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 */