/*
Unix SMB / Netbios implementation .
Version 1.9 .
multiple interface handling
Copyright ( C ) Andrew Tridgell 1992 - 1997
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include <assert.h> /* added by philipp */
extern int DEBUGLEVEL ;
struct in_addr ipzero ;
struct in_addr wins_ip ;
struct interface * local_interfaces = NULL ;
struct interface * present_interfaces = NULL ;
struct interface * last_iface ;
static void get_interfaces ( )
{
int sock = - 1 ; /* AF_INET raw socket desc */
char buff [ 1024 ] ;
struct ifreq * ifr = NULL , ifr2 ;
int i ;
struct interface * iface , * last_iface = NULL ;
# ifndef ifr_mtu
# define ifr_mtu ifr_metric
# endif
# if defined(EVEREST)
int n_interfaces ;
struct ifconf ifc ;
struct ifreq * ifreqs ;
# elif defined(USE_IFREQ)
struct ifreq ifreq ;
struct strioctl strioctl ;
struct ifconf * ifc ;
# else
struct ifconf ifc ;
# endif
if ( present_interfaces ) return ; /* already initialized */
/* Create a socket to the INET kernel. */
# if USE_SOCKRAW
if ( ( sock = socket ( AF_INET , SOCK_RAW , PF_INET ) ) < 0 )
# else
if ( ( sock = socket ( AF_INET , SOCK_DGRAM , 0 ) ) < 0 )
# endif
{
DEBUG ( 0 , ( " Unable to open socket to get broadcast address \n " ) ) ;
return ;
}
/* Get a list of the configured interfaces */
# ifdef EVEREST
/* This is part of SCO Openserver 5: The ioctls are no longer part
if the lower level STREAMS interface glue . They are now real
ioctl calls */
if ( ioctl ( sock , SIOCGIFANUM , & n_interfaces ) < 0 ) {
DEBUG ( 0 , ( " SIOCGIFANUM: %s \n " , strerror ( errno ) ) ) ;
} else {
DEBUG ( 0 , ( " number of interfaces returned is: %d \n " , n_interfaces ) ) ;
ifc . ifc_len = sizeof ( struct ifreq ) * n_interfaces ;
ifc . ifc_buf = ( caddr_t ) alloca ( ifc . ifc_len ) ;
if ( ioctl ( sock , SIOCGIFCONF , & ifc ) < 0 )
DEBUG ( 0 , ( " SIOCGIFCONF: %s \n " , strerror ( errno ) ) ) ;
else {
ifr = ifc . ifc_req ;
for ( i = 0 ; i < n_interfaces ; + + i ) {
ifr2 = ifr [ i ] ;
if ( ioctl ( sock , SIOCGIFFLAGS , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFFLAGS failed \n " ) ) ;
if ( ( ifr2 . ifr_flags & ( IFF_RUNNING | IFF_LOOPBACK ) ) ! = IFF_RUNNING )
continue ;
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
assert ( iface ! = NULL ) ;
iface - > next = NULL ;
iface - > ip = ( ( struct sockaddr_in * ) & ifr [ i ] . ifr_addr ) - > sin_addr ;
iface - > name = strdup ( ifr [ i ] . ifr_name ) ;
iface - > flags = ifr2 . ifr_flags ;
/* complete with netmask and b'cast address */
ifr2 = * ifr ;
if ( ioctl ( sock , SIOCGIFNETMASK , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFNETMASK failed \n " ) ) ;
else
iface - > nmask = ( ( struct sockaddr_in * ) & ifr2 . ifr_addr ) - > sin_addr ;
if ( ioctl ( sock , SIOCGIFBRDADDR , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFBRDADDR failed \n " ) ) ;
else
iface - > bcast = ( ( struct sockaddr_in * ) & ifr2 . ifr_addr ) - > sin_addr ;
if ( ioctl ( sock , SIOCGIFMTU , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFMTU failed \n " ) ) ;
else
iface - > mtu = ifr2 . ifr_mtu ;
DEBUG ( 4 , ( " Netmask for %s = %s \n " , iface - > name , inet_ntoa ( iface - > nmask ) ) ) ;
if ( ! present_interfaces )
present_interfaces = iface ;
else
last_iface - > next = iface ;
last_iface = iface ;
}
}
}
# elif defined(USE_IFREQ)
ifc = ( struct ifconf * ) buff ;
ifc - > ifc_len = BUFSIZ - sizeof ( struct ifconf ) ;
strioctl . ic_cmd = SIOCGIFCONF ;
strioctl . ic_dp = ( char * ) ifc ;
strioctl . ic_len = sizeof ( buff ) ;
if ( ioctl ( sock , I_STR , & strioctl ) < 0 ) {
DEBUG ( 0 , ( " I_STR/SIOCGIFCONF: %s \n " , strerror ( errno ) ) ) ;
} else {
ifr = ( struct ifreq * ) ifc - > ifc_req ;
/* Loop through interfaces, looking for given IP address */
for ( i = ifc - > ifc_len / sizeof ( struct ifreq ) ; - - i > = 0 ; ifr + + ) {
ifr2 = * ifr ;
if ( ioctl ( sock , SIOCGIFFLAGS , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFFLAGS failed \n " ) ) ;
if ( ( ifr2 . ifr_flags & ( IFF_RUNNING | IFF_LOOPBACK ) ) = = IFF_RUNNING ) {
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
assert ( iface ! = NULL ) ;
iface - > next = NULL ;
iface - > ip = ( * ( struct sockaddr_in * ) & ifr - > ifr_addr ) . sin_addr ;
iface - > name = strdup ( ifr - > ifr_name ) ;
iface - > flags = ifr2 . ifr_flags ;
/* complete with netmask and b'cast address */
ifr2 = * ifr ;
strioctl . ic_cmd = SIOCGIFNETMASK ;
strioctl . ic_dp = ( char * ) & ifr2 ;
strioctl . ic_len = sizeof ( struct ifr2 ) ;
if ( ioctl ( sock , I_STR , & strioctl ) < 0 )
DEBUG ( 0 , ( " Failed I_STR/SIOCGIFNETMASK: %s \n " , strerror ( errno ) ) ) ;
else
iface - > nmask = ( ( struct sockaddr_in * ) & ifr2 . ifr_addr ) - > sin_addr ;
strioctl . ic_cmd = SIOCGIFBRDADDR ;
if ( ioctl ( sock , I_STR , & strioctl ) < 0 )
DEBUG ( 0 , ( " SIOCGIFBRDADDR failed \n " ) ) ;
else
iface - > bcast = ( ( struct sockaddr_in * ) & ifr2 . ifr_addr ) - > sin_addr ;
strioctl . ic_cmd = SIOCGIFMTU ;
if ( ioctl ( sock , I_STR , & strioctl ) < 0 )
DEBUG ( 0 , ( " SIOCGIFMTU failed \n " ) ) ;
else
iface - > mtu = ifr2 . ifr_mtu ;
DEBUG ( 4 , ( " Netmask for %s = %s \n " , iface - > name , inet_ntoa ( iface - > nmask ) ) ) ;
if ( ! present_interfaces )
present_interfaces = iface ;
else
last_iface - > next = iface ;
last_iface = iface ;
}
}
}
# elif defined(__FreeBSD__) || defined(NETBSD) || defined(AMIGA) || defined(_AIX41)
ifc . ifc_len = sizeof ( buff ) ;
ifc . ifc_buf = buff ;
if ( ioctl ( sock , SIOCGIFCONF , & ifc ) < 0 ) {
DEBUG ( 0 , ( " SIOCGIFCONF: %s \n " , strerror ( errno ) ) ) ;
} else {
ifr = ifc . ifc_req ;
/* Loop through interfaces, looking for given IP address */
i = ifc . ifc_len ;
while ( i > 0 ) {
ifr2 = * ifr ;
if ( ioctl ( sock , SIOCGIFFLAGS , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFFLAGS failed \n " ) ) ;
if ( ( ifr2 . ifr_flags & ( IFF_RUNNING | IFF_LOOPBACK ) ) = = IFF_RUNNING ) {
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
assert ( iface ! = NULL ) ;
iface - > next = NULL ;
iface - > ip = ( * ( struct sockaddr_in * ) & ifr - > ifr_addr ) . sin_addr ;
iface - > name = strdup ( ifr - > ifr_name ) ;
iface - > flags = ifr2 . ifr_flags ;
/* complete with netmask and b'cast address */
ifr2 = * ifr ;
if ( ioctl ( sock , SIOCGIFNETMASK , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFNETMASK failed \n " ) ) ;
else
iface - > nmask = ( * ( struct sockaddr_in * ) & ifr2 . ifr_addr ) . sin_addr ;
if ( ioctl ( sock , SIOCGIFBRDADDR , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFBRDADDR failed \n " ) ) ;
else
iface - > bcast = ( * ( struct sockaddr_in * ) & ifr2 . ifr_addr ) . sin_addr ;
if ( ioctl ( sock , SIOCGIFMTU , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFMTU failed \n " ) ) ;
else
iface - > mtu = ifr2 . ifr_mtu ;
DEBUG ( 4 , ( " Netmask for %s = %s \n " , iface - > name , inet_ntoa ( iface - > nmask ) ) ) ;
if ( ! present_interfaces )
present_interfaces = iface ;
else
last_iface - > next = iface ;
last_iface = iface ;
}
i - = ifr - > ifr_addr . sa_len + IFNAMSIZ ;
ifr = ( struct ifreq * ) ( ( char * ) ifr + ifr - > ifr_addr . sa_len + IFNAMSIZ ) ;
}
}
# else
ifc . ifc_len = sizeof ( buff ) ;
ifc . ifc_buf = buff ;
if ( ioctl ( sock , SIOCGIFCONF , & ifc ) < 0 ) {
DEBUG ( 0 , ( " SIOCGIFCONF: %s \n " , strerror ( errno ) ) ) ;
} else {
ifr = ifc . ifc_req ;
/* Loop through interfaces, looking for given IP address */
for ( i = ifc . ifc_len / sizeof ( struct ifreq ) ; - - i > = 0 ; ifr + + ) {
ifr2 = * ifr ;
if ( ioctl ( sock , SIOCGIFFLAGS , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFFLAGS failed \n " ) ) ;
if ( ( ifr2 . ifr_flags & ( IFF_RUNNING | IFF_LOOPBACK ) ) = = IFF_RUNNING ) {
# ifdef BSDI
if ( ioctl ( sock , SIOCGIFADDR , ifr ) < 0 ) break ;
# endif
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
assert ( iface ! = NULL ) ;
iface - > next = NULL ;
iface - > ip = ( * ( struct sockaddr_in * ) & ifr - > ifr_addr ) . sin_addr ;
iface - > name = strdup ( ifr - > ifr_name ) ;
iface - > flags = ifr2 . ifr_flags ;
/* complete with netmask and b'cast address */
ifr2 = * ifr ;
if ( ioctl ( sock , SIOCGIFNETMASK , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFNETMASK failed \n " ) ) ;
else
iface - > nmask = ( * ( struct sockaddr_in * ) & ifr2 . ifr_addr ) . sin_addr ;
if ( ioctl ( sock , SIOCGIFBRDADDR , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFBRDADDR failed \n " ) ) ;
else
iface - > bcast = ( * ( struct sockaddr_in * ) & ifr2 . ifr_addr ) . sin_addr ;
if ( ioctl ( sock , SIOCGIFMTU , & ifr2 ) < 0 )
DEBUG ( 0 , ( " SIOCGIFMTU failed \n " ) ) ;
else
iface - > mtu = ifr2 . ifr_mtu ;
DEBUG ( 4 , ( " Netmask for %s = %s \n " , iface - > name , inet_ntoa ( iface - > nmask ) ) ) ;
if ( ! present_interfaces )
present_interfaces = iface ;
else
last_iface - > next = iface ;
last_iface = iface ;
}
}
}
# endif
/* Close up shop */
( void ) close ( sock ) ;
} /* get_interfaces */
/****************************************************************************
load a list of network interfaces
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void interpret_interfaces ( char * s , struct interface * * interfaces ,
char * description )
{
char * ptr = s ;
fstring token ;
struct interface * iface , * i ;
BOOL seenALL = False ;
ipzero = * interpret_addr2 ( " 0.0.0.0 " ) ;
wins_ip = * interpret_addr2 ( " 255.255.255.255 " ) ;
get_interfaces ( ) ;
while ( next_token ( & ptr , token , NULL ) ) {
if ( strcasecmp ( token , " ALL " ) ) {
if ( * interfaces ) {
DEBUG ( 0 , ( " Error: interface name \" ALL \" must occur alone \n " ) ) ;
/* should do something here ... */
}
/* should we copy the list, or just point at it? */
for ( i = present_interfaces ; i ; i = i - > next ) {
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
if ( ! iface ) return ;
* iface = * i ;
iface - > next = NULL ;
if ( ! ( * interfaces ) )
( * interfaces ) = iface ;
else
last_iface - > next = iface ;
last_iface = iface ;
}
seenALL = True ;
continue ;
} else if ( seenALL ) {
DEBUG ( 0 , ( " Error: can't mix interface \" ALL \" with other interface namess \n " ) ) ;
continue ;
}
/* maybe we already have it listed */
for ( i = ( * interfaces ) ; i ; i = i - > next )
if ( strcasecmp ( token , i - > name ) ) break ;
if ( i ) continue ;
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
if ( ! iface ) return ;
/* make sure name is known */
for ( i = present_interfaces ; i ; i = i - > next )
if ( strcasecmp ( token , i - > name ) ) break ;
if ( ! i ) {
DEBUG ( 0 , ( " Warning: unknown interface \" %s \" specified \n " , token ) ) ;
continue ;
}
* iface = * i ;
iface - > next = NULL ;
if ( iface - > bcast . s_addr ! = ( iface - > ip . s_addr | ~ iface - > nmask . s_addr ) ) {
DEBUG ( 0 , ( " Warning: overriding b'cast address %s on interface %s \n " ,
inet_ntoa ( iface - > bcast ) , iface - > name ) ) ;
iface - > bcast . s_addr = iface - > ip . s_addr | ~ iface - > nmask . s_addr ;
}
if ( ! ( * interfaces ) ) {
( * interfaces ) = iface ;
} else {
last_iface - > next = iface ;
}
last_iface = iface ;
DEBUG ( 1 , ( " Added %s ip=%s " , description , inet_ntoa ( iface - > ip ) ) ) ;
DEBUG ( 1 , ( " bcast=%s " , inet_ntoa ( iface - > bcast ) ) ) ;
DEBUG ( 1 , ( " nmask=%s \n " , inet_ntoa ( iface - > nmask ) ) ) ;
}
if ( ! * interfaces )
DEBUG ( 0 , ( " Error: no interfaces specified. \n " ) ) ;
}
/****************************************************************************
load the remote and local interfaces
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void load_interfaces ( void )
{
/* add the machine's interfaces to local interface structure*/
interpret_interfaces ( lp_interfaces ( ) , & local_interfaces , " interface " ) ;
}
/****************************************************************************
override the defaults
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void iface_set_default ( char * ip , char * bcast , char * nmask )
{
DEBUG ( 0 , ( " iface_set_default: function deprecated. \n " ) ) ;
exit ( 1 ) ;
}
/****************************************************************************
check if an IP is one of mine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL ismyip ( struct in_addr ip )
{
struct interface * i ;
for ( i = local_interfaces ; i ; i = i - > next )
if ( ip_equal ( i - > ip , ip ) ) return True ;
return False ;
}
/****************************************************************************
check if a bcast is one of mine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL ismybcast ( struct in_addr bcast )
{
struct interface * i ;
for ( i = local_interfaces ; i ; i = i - > next )
if ( ip_equal ( i - > bcast , bcast ) ) return True ;
return False ;
}
/****************************************************************************
how many interfaces do we have
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int iface_count ( void )
{
int ret = 0 ;
struct interface * i ;
for ( i = local_interfaces ; i ; i = i - > next )
ret + + ;
return ret ;
}
/****************************************************************************
return IP of the Nth interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct in_addr * iface_n_ip ( int n )
{
struct interface * i ;
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
if ( i ) return & i - > ip ;
return NULL ;
}
static struct interface * iface_find ( struct in_addr ip )
{
struct interface * i ;
if ( zero_ip ( ip ) ) return local_interfaces ;
for ( i = local_interfaces ; i ; i = i - > next )
if ( same_net ( i - > ip , ip , i - > nmask ) ) return i ;
return local_interfaces ;
}
/* these 3 functions return the ip/bcast/nmask for the interface
most appropriate for the given ip address */
struct in_addr * iface_bcast ( struct in_addr ip )
{
return ( & iface_find ( ip ) - > bcast ) ;
}
struct in_addr * iface_nmask ( struct in_addr ip )
{
return ( & iface_find ( ip ) - > nmask ) ;
}
struct in_addr * iface_ip ( struct in_addr ip )
{
return ( & iface_find ( ip ) - > ip ) ;
}