2007-12-16 04:39:01 +03:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright ( C ) Andrew Tridgell 1998
Copyright ( C ) Jeremy Allison 2007
Copyright ( C ) Jelmer Vernooij < jelmer @ samba . org > 2007
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2008-02-22 15:53:05 +03:00
# define SOCKET_WRAPPER_NOT_REPLACE
2007-12-16 04:39:01 +03:00
# include "replace.h"
# include "system/network.h"
# include <unistd.h>
# include <stdio.h>
# include <sys/types.h>
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
# ifndef SIOCGIFCONF
# ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
# endif
# endif
# ifdef HAVE_IFACE_GETIFADDRS
# define _FOUND_IFACE_ANY
# else
2007-12-17 10:20:29 +03:00
void rep_freeifaddrs ( struct ifaddrs * ifp )
2007-12-16 04:39:01 +03:00
{
2008-02-29 04:23:29 +03:00
if ( ifp ! = NULL ) {
free ( ifp - > ifa_name ) ;
free ( ifp - > ifa_addr ) ;
free ( ifp - > ifa_netmask ) ;
free ( ifp - > ifa_dstaddr ) ;
2007-12-16 04:39:01 +03:00
freeifaddrs ( ifp - > ifa_next ) ;
2008-02-29 04:23:29 +03:00
free ( ifp ) ;
}
2007-12-16 04:39:01 +03:00
}
2007-12-17 10:20:29 +03:00
static struct sockaddr * sockaddr_dup ( struct sockaddr * sa )
2007-12-16 04:39:01 +03:00
{
2007-12-17 07:53:37 +03:00
struct sockaddr * ret ;
socklen_t socklen ;
# ifdef HAVE_SOCKADDR_SA_LEN
socklen = sa - > sa_len ;
# else
socklen = sizeof ( struct sockaddr_storage ) ;
# endif
2007-12-17 08:30:50 +03:00
ret = calloc ( 1 , socklen ) ;
2007-12-16 04:39:01 +03:00
if ( ret = = NULL )
return NULL ;
2007-12-17 07:53:37 +03:00
memcpy ( ret , sa , socklen ) ;
2007-12-16 04:39:01 +03:00
return ret ;
}
# endif
# if HAVE_IFACE_IFCONF
/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
V4 .0 , Ultrix 4.4 , SCO Unix 3.2 , IRIX 6.4 and FreeBSD 3.2 .
It probably also works on any BSD style system . */
2007-12-17 10:20:29 +03:00
int rep_getifaddrs ( struct ifaddrs * * ifap )
2007-12-16 04:39:01 +03:00
{
struct ifconf ifc ;
char buff [ 8192 ] ;
int fd , i , n ;
struct ifreq * ifr = NULL ;
2008-02-22 02:24:11 +03:00
struct ifaddrs * curif ;
struct ifaddrs * lastif = NULL ;
2007-12-16 04:39:01 +03:00
* ifap = NULL ;
if ( ( fd = socket ( AF_INET , SOCK_DGRAM , 0 ) ) = = - 1 ) {
return - 1 ;
}
ifc . ifc_len = sizeof ( buff ) ;
ifc . ifc_buf = buff ;
if ( ioctl ( fd , SIOCGIFCONF , & ifc ) ! = 0 ) {
close ( fd ) ;
return - 1 ;
}
ifr = ifc . ifc_req ;
n = ifc . ifc_len / sizeof ( struct ifreq ) ;
/* Loop through interfaces, looking for given IP address */
2008-02-21 20:16:10 +03:00
for ( i = n - 1 ; i > = 0 ; i - - ) {
2008-02-29 02:06:55 +03:00
if ( ioctl ( fd , SIOCGIFFLAGS , & ifr [ i ] ) = = - 1 ) {
2007-12-16 04:39:01 +03:00
freeifaddrs ( * ifap ) ;
2008-02-29 02:06:55 +03:00
return - 1 ;
2007-12-16 04:39:01 +03:00
}
curif = calloc ( 1 , sizeof ( struct ifaddrs ) ) ;
curif - > ifa_name = strdup ( ifr [ i ] . ifr_name ) ;
2008-02-29 02:06:55 +03:00
curif - > ifa_flags = ifr [ i ] . ifr_flags ;
2007-12-16 04:39:01 +03:00
curif - > ifa_dstaddr = NULL ;
curif - > ifa_data = NULL ;
curif - > ifa_next = NULL ;
2008-02-29 03:25:54 +03:00
curif - > ifa_addr = NULL ;
2008-02-29 02:06:55 +03:00
if ( ioctl ( fd , SIOCGIFADDR , & ifr [ i ] ) ! = - 1 ) {
curif - > ifa_addr = sockaddr_dup ( & ifr [ i ] . ifr_addr ) ;
}
2007-12-16 04:39:01 +03:00
2008-02-29 02:06:55 +03:00
curif - > ifa_netmask = NULL ;
if ( ioctl ( fd , SIOCGIFNETMASK , & ifr [ i ] ) ! = - 1 ) {
curif - > ifa_netmask = sockaddr_dup ( & ifr [ i ] . ifr_addr ) ;
}
2007-12-16 04:39:01 +03:00
2008-02-29 02:06:55 +03:00
if ( lastif = = NULL ) {
* ifap = curif ;
} else {
lastif - > ifa_next = curif ;
}
2007-12-16 04:39:01 +03:00
lastif = curif ;
}
close ( fd ) ;
return 0 ;
}
# define _FOUND_IFACE_ANY
# endif /* HAVE_IFACE_IFCONF */
# ifdef HAVE_IFACE_IFREQ
# ifndef I_STR
# include <sys/stropts.h>
# endif
/****************************************************************************
this should cover most of the streams based systems
Thanks to Andrej . Borsenkow @ mow . siemens . ru for several ideas in this code
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-12-17 10:20:29 +03:00
int rep_getifaddrs ( struct ifaddrs * * ifap )
2007-12-16 04:39:01 +03:00
{
struct ifreq ifreq ;
struct strioctl strioctl ;
char buff [ 8192 ] ;
int fd , i , n ;
struct ifreq * ifr = NULL ;
2008-02-22 02:24:11 +03:00
struct ifaddrs * curif ;
struct ifaddrs * lastif = NULL ;
2007-12-16 04:39:01 +03:00
* ifap = NULL ;
if ( ( fd = socket ( AF_INET , SOCK_DGRAM , 0 ) ) = = - 1 ) {
return - 1 ;
}
strioctl . ic_cmd = SIOCGIFCONF ;
strioctl . ic_dp = buff ;
strioctl . ic_len = sizeof ( buff ) ;
if ( ioctl ( fd , I_STR , & strioctl ) < 0 ) {
close ( fd ) ;
return - 1 ;
}
/* we can ignore the possible sizeof(int) here as the resulting
number of interface structures won ' t change */
n = strioctl . ic_len / sizeof ( struct ifreq ) ;
/* we will assume that the kernel returns the length as an int
at the start of the buffer if the offered size is a
multiple of the structure size plus an int */
if ( n * sizeof ( struct ifreq ) + sizeof ( int ) = = strioctl . ic_len ) {
ifr = ( struct ifreq * ) ( buff + sizeof ( int ) ) ;
} else {
ifr = ( struct ifreq * ) buff ;
}
/* Loop through interfaces */
2008-02-21 20:16:10 +03:00
for ( i = 0 ; i < n ; i + + ) {
2007-12-16 04:39:01 +03:00
ifreq = ifr [ i ] ;
2007-12-16 04:49:52 +03:00
curif = calloc ( 1 , sizeof ( struct ifaddrs ) ) ;
if ( lastif = = NULL ) {
* ifap = curif ;
} else {
2008-02-22 02:27:00 +03:00
lastif - > ifa_next = curif ;
2007-12-16 04:49:52 +03:00
}
2007-12-16 04:39:01 +03:00
strioctl . ic_cmd = SIOCGIFFLAGS ;
strioctl . ic_dp = ( char * ) & ifreq ;
strioctl . ic_len = sizeof ( struct ifreq ) ;
if ( ioctl ( fd , I_STR , & strioctl ) ! = 0 ) {
freeifaddrs ( * ifap ) ;
return - 1 ;
}
2007-12-16 04:49:52 +03:00
curif - > ifa_flags = ifreq . ifr_flags ;
2007-12-16 04:39:01 +03:00
strioctl . ic_cmd = SIOCGIFADDR ;
strioctl . ic_dp = ( char * ) & ifreq ;
strioctl . ic_len = sizeof ( struct ifreq ) ;
if ( ioctl ( fd , I_STR , & strioctl ) ! = 0 ) {
freeifaddrs ( * ifap ) ;
return - 1 ;
}
curif - > ifa_name = strdup ( ifreq . ifr_name ) ;
curif - > ifa_addr = sockaddr_dup ( & ifreq . ifr_addr ) ;
curif - > ifa_dstaddr = NULL ;
curif - > ifa_data = NULL ;
curif - > ifa_next = NULL ;
curif - > ifa_netmask = NULL ;
strioctl . ic_cmd = SIOCGIFNETMASK ;
strioctl . ic_dp = ( char * ) & ifreq ;
strioctl . ic_len = sizeof ( struct ifreq ) ;
if ( ioctl ( fd , I_STR , & strioctl ) ! = 0 ) {
freeifaddrs ( * ifap ) ;
return - 1 ;
}
curif - > ifa_netmask = sockaddr_dup ( & ifreq . ifr_addr ) ;
lastif = curif ;
}
close ( fd ) ;
return 0 ;
}
# define _FOUND_IFACE_ANY
# endif /* HAVE_IFACE_IFREQ */
# ifdef HAVE_IFACE_AIX
/****************************************************************************
this one is for AIX ( tested on 4.2 )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-12-17 10:20:29 +03:00
int rep_getifaddrs ( struct ifaddrs * * ifap )
2007-12-16 04:39:01 +03:00
{
char buff [ 8192 ] ;
int fd , i ;
struct ifconf ifc ;
struct ifreq * ifr = NULL ;
2008-02-22 02:24:11 +03:00
struct ifaddrs * curif ;
struct ifaddrs * lastif = NULL ;
2007-12-16 04:39:01 +03:00
* ifap = NULL ;
if ( ( fd = socket ( AF_INET , SOCK_DGRAM , 0 ) ) = = - 1 ) {
return - 1 ;
}
ifc . ifc_len = sizeof ( buff ) ;
ifc . ifc_buf = buff ;
if ( ioctl ( fd , SIOCGIFCONF , & ifc ) ! = 0 ) {
close ( fd ) ;
return - 1 ;
}
ifr = ifc . ifc_req ;
/* Loop through interfaces */
i = ifc . ifc_len ;
while ( i > 0 ) {
2010-01-05 20:43:24 +03:00
unsigned int inc ;
2007-12-16 04:39:01 +03:00
inc = ifr - > ifr_addr . sa_len ;
if ( ioctl ( fd , SIOCGIFADDR , ifr ) ! = 0 ) {
freeaddrinfo ( * ifap ) ;
return - 1 ;
}
curif = calloc ( 1 , sizeof ( struct ifaddrs ) ) ;
if ( lastif = = NULL ) {
* ifap = curif ;
} else {
2008-02-22 02:27:00 +03:00
lastif - > ifa_next = curif ;
2007-12-16 04:39:01 +03:00
}
curif - > ifa_name = strdup ( ifr - > ifr_name ) ;
curif - > ifa_addr = sockaddr_dup ( & ifr - > ifr_addr ) ;
curif - > ifa_dstaddr = NULL ;
curif - > ifa_data = NULL ;
curif - > ifa_netmask = NULL ;
curif - > ifa_next = NULL ;
if ( ioctl ( fd , SIOCGIFFLAGS , ifr ) ! = 0 ) {
freeaddrinfo ( * ifap ) ;
return - 1 ;
}
2007-12-16 04:49:52 +03:00
curif - > ifa_flags = ifr - > ifr_flags ;
2007-12-16 04:39:01 +03:00
if ( ioctl ( fd , SIOCGIFNETMASK , ifr ) ! = 0 ) {
freeaddrinfo ( * ifap ) ;
return - 1 ;
}
curif - > ifa_netmask = sockaddr_dup ( & ifr - > ifr_addr ) ;
lastif = curif ;
next :
/*
* Patch from Archie Cobbs ( archie @ whistle . com ) . The
* addresses in the SIOCGIFCONF interface list have a
* minimum size . Usually this doesn ' t matter , but if
* your machine has tunnel interfaces , etc . that have
* a zero length " link address " , this does matter . */
if ( inc < sizeof ( ifr - > ifr_addr ) )
inc = sizeof ( ifr - > ifr_addr ) ;
inc + = IFNAMSIZ ;
ifr = ( struct ifreq * ) ( ( ( char * ) ifr ) + inc ) ;
i - = inc ;
}
close ( fd ) ;
return 0 ;
}
# define _FOUND_IFACE_ANY
# endif /* HAVE_IFACE_AIX */
# ifndef _FOUND_IFACE_ANY
2007-12-17 10:20:29 +03:00
int rep_getifaddrs ( struct ifaddrs * * ifap )
2007-12-16 04:39:01 +03:00
{
errno = ENOSYS ;
return - 1 ;
}
# endif