0001-01-01 02:30:17 +02:30
/*
Unix SMB / Netbios implementation .
Version 1.9 .
multiple interface handling
0001-01-01 02:30:17 +02:30
Copyright ( C ) Andrew Tridgell 1992 - 1998
0001-01-01 02:30:17 +02:30
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"
extern int DEBUGLEVEL ;
struct in_addr ipzero ;
0001-01-01 02:30:17 +02:30
struct in_addr allones_ip ;
0001-01-01 02:30:17 +02:30
struct in_addr loopback_ip ;
0001-01-01 02:30:17 +02:30
static struct in_addr default_ip ;
static struct in_addr default_bcast ;
static struct in_addr default_nmask ;
static BOOL got_ip = False ;
static BOOL got_bcast = False ;
static BOOL got_nmask = False ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
static struct interface * local_interfaces = NULL ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
struct interface * last_iface ;
0001-01-01 02:30:17 +02:30
# define ALLONES ((uint32)0xFFFFFFFF)
# define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
0001-01-01 02:30:17 +02:30
/****************************************************************************
calculate the default netmask for an address
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void default_netmask ( struct in_addr * inm , struct in_addr * iad )
{
0001-01-01 02:30:17 +02:30
/*
* * Guess a netmask based on the class of the IP address given .
*/
switch ( ( ntohl ( iad - > s_addr ) & 0xE0000000 ) ) {
0001-01-01 02:30:17 +02:30
case 0x00000000 : /* Class A addr */
case 0x20000000 :
case 0x40000000 :
case 0x60000000 :
0001-01-01 02:30:17 +02:30
inm - > s_addr = htonl ( 0xFF000000 ) ;
break ;
case 0x80000000 : /* Class B addr */
0001-01-01 02:30:17 +02:30
case 0xA0000000 :
0001-01-01 02:30:17 +02:30
inm - > s_addr = htonl ( 0xFFFF0000 ) ;
break ;
case 0xC0000000 : /* Class C addr */
inm - > s_addr = htonl ( 0xFFFFFF00 ) ;
break ;
default : /* ??? */
inm - > s_addr = htonl ( 0xFFFFFFF0 ) ;
}
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
get the broadcast address for our address
( troyer @ saifr00 . ateng . az . honeywell . com )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void get_broadcast ( struct in_addr * if_ipaddr ,
struct in_addr * if_bcast ,
struct in_addr * if_nmask )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
uint32 nm ;
short onbc ;
short offbc ;
/* get a default netmask and broadcast */
default_netmask ( if_nmask , if_ipaddr ) ;
get_netmask ( if_ipaddr , if_nmask ) ;
/* sanity check on the netmask */
nm = ntohl ( if_nmask - > s_addr ) ;
onbc = 0 ;
offbc = 0 ;
while ( ( onbc + offbc ) < 32 ) {
if ( nm & 0x80000000 ) {
onbc + + ;
if ( offbc ) {
/* already found an off bit, so mask
is wrong */
onbc = 34 ;
}
} else {
offbc + + ;
}
nm < < = 1 ;
}
if ( ( onbc < 8 ) | | ( onbc = = 34 ) ) {
DEBUG ( 0 , ( " Impossible netmask %s - using defaults \n " ,
inet_ntoa ( * if_nmask ) ) ) ;
default_netmask ( if_nmask , if_ipaddr ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/* derive the broadcast assuming a 1's broadcast, as this is what
all MS operating systems do , we have to comply even if the unix
box is setup differently */
if_bcast - > s_addr = MKBCADDR ( if_ipaddr - > s_addr , if_nmask - > s_addr ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
DEBUG ( 4 , ( " Derived broadcast address %s \n " , inet_ntoa ( * if_bcast ) ) ) ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
load a list of network interfaces
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static void interpret_interfaces ( char * s , struct interface * * interfaces ,
char * description )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
char * ptr ;
0001-01-01 02:30:17 +02:30
fstring token ;
0001-01-01 02:30:17 +02:30
struct interface * iface ;
struct in_addr ip ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ptr = s ;
0001-01-01 02:30:17 +02:30
ipzero = * interpret_addr2 ( " 0.0.0.0 " ) ;
0001-01-01 02:30:17 +02:30
allones_ip = * interpret_addr2 ( " 255.255.255.255 " ) ;
0001-01-01 02:30:17 +02:30
loopback_ip = * interpret_addr2 ( " 127.0.0.1 " ) ;
0001-01-01 02:30:17 +02:30
while ( next_token ( & ptr , token , NULL ) ) {
0001-01-01 02:30:17 +02:30
/* parse it into an IP address/netmasklength pair */
char * p = strchr ( token , ' / ' ) ;
0001-01-01 02:30:17 +02:30
if ( p ) * p + + = 0 ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ip = * interpret_addr2 ( token ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* maybe we already have it listed */
0001-01-01 02:30:17 +02:30
{
struct interface * i ;
for ( i = ( * interfaces ) ; i ; i = i - > next )
if ( ip_equal ( ip , i - > ip ) ) break ;
if ( i ) continue ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
if ( ! iface ) return ;
0001-01-01 02:30:17 +02:30
iface - > ip = ip ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( p ) {
0001-01-01 02:30:17 +02:30
if ( strlen ( p ) > 2 )
iface - > nmask = * interpret_addr2 ( p ) ;
0001-01-01 02:30:17 +02:30
else
0001-01-01 02:30:17 +02:30
iface - > nmask . s_addr = htonl ( ( ( ALLONES > > atoi ( p ) ) ^ ALLONES ) ) ;
0001-01-01 02:30:17 +02:30
} else {
default_netmask ( & iface - > nmask , & iface - > ip ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
iface - > bcast . s_addr = MKBCADDR ( iface - > ip . s_addr , iface - > nmask . s_addr ) ;
0001-01-01 02:30:17 +02:30
iface - > next = NULL ;
0001-01-01 02:30:17 +02:30
if ( ! ( * interfaces ) ) {
( * interfaces ) = iface ;
0001-01-01 02:30:17 +02:30
} else {
last_iface - > next = iface ;
}
last_iface = iface ;
0001-01-01 02:30:17 +02:30
DEBUG ( 2 , ( " Added %s ip=%s " , description , inet_ntoa ( iface - > ip ) ) ) ;
DEBUG ( 2 , ( " bcast=%s " , inet_ntoa ( iface - > bcast ) ) ) ;
DEBUG ( 2 , ( " nmask=%s \n " , inet_ntoa ( iface - > nmask ) ) ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
if ( * interfaces ) return ;
/* setup a default interface */
iface = ( struct interface * ) malloc ( sizeof ( * iface ) ) ;
if ( ! iface ) return ;
iface - > next = NULL ;
if ( got_ip ) {
iface - > ip = default_ip ;
} else {
get_myname ( NULL , & iface - > ip ) ;
}
if ( got_bcast ) {
iface - > bcast = default_bcast ;
} else {
get_broadcast ( & iface - > ip , & iface - > bcast , & iface - > nmask ) ;
}
if ( got_nmask ) {
iface - > nmask = default_nmask ;
0001-01-01 02:30:17 +02:30
iface - > bcast . s_addr = MKBCADDR ( iface - > ip . s_addr , iface - > nmask . s_addr ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
if ( iface - > bcast . s_addr ! = MKBCADDR ( iface - > ip . s_addr , iface - > nmask . s_addr ) ) {
0001-01-01 02:30:17 +02:30
DEBUG ( 2 , ( " Warning: inconsistant interface %s \n " , inet_ntoa ( iface - > ip ) ) ) ;
}
iface - > next = NULL ;
( * interfaces ) = last_iface = iface ;
0001-01-01 02:30:17 +02:30
DEBUG ( 2 , ( " Added interface ip=%s " , inet_ntoa ( iface - > ip ) ) ) ;
DEBUG ( 2 , ( " bcast=%s " , inet_ntoa ( iface - > bcast ) ) ) ;
DEBUG ( 2 , ( " nmask=%s \n " , inet_ntoa ( iface - > nmask ) ) ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
load the remote and local interfaces
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void load_interfaces ( void )
{
/* add the machine's interfaces to local interface structure*/
0001-01-01 02:30:17 +02:30
interpret_interfaces ( lp_interfaces ( ) , & local_interfaces , " interface " ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
override the defaults
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void iface_set_default ( char * ip , char * bcast , char * nmask )
{
0001-01-01 02:30:17 +02:30
if ( ip ) {
got_ip = True ;
default_ip = * interpret_addr2 ( ip ) ;
}
if ( bcast ) {
got_bcast = True ;
default_bcast = * interpret_addr2 ( bcast ) ;
}
if ( nmask ) {
got_nmask = True ;
default_nmask = * interpret_addr2 ( nmask ) ;
}
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
check if an IP is one of mine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL ismyip ( struct in_addr ip )
{
struct interface * i ;
0001-01-01 02:30:17 +02:30
for ( i = local_interfaces ; i ; i = i - > next )
0001-01-01 02:30:17 +02:30
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 ;
0001-01-01 02:30:17 +02:30
for ( i = local_interfaces ; i ; i = i - > next )
0001-01-01 02:30:17 +02:30
if ( ip_equal ( i - > bcast , bcast ) ) return True ;
return False ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
check if a packet is from a local ( known ) net
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL is_local_net ( struct in_addr from )
{
struct interface * i ;
for ( i = local_interfaces ; i ; i = i - > next )
if ( ( from . s_addr & i - > nmask . s_addr ) = = ( i - > ip . s_addr & i - > nmask . s_addr ) )
return True ;
return False ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
how many interfaces do we have
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int iface_count ( void )
{
int ret = 0 ;
struct interface * i ;
0001-01-01 02:30:17 +02:30
for ( i = local_interfaces ; i ; i = i - > next )
0001-01-01 02:30:17 +02:30
ret + + ;
return ret ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
True if we have two or more interfaces .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
BOOL we_are_multihomed ( void )
0001-01-01 02:30:17 +02:30
{
static int multi = - 1 ;
if ( multi = = - 1 )
multi = ( iface_count ( ) > 1 ? True : False ) ;
return multi ;
}
/****************************************************************************
return the Nth interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct interface * get_interface ( int n )
{
struct interface * i ;
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
if ( i ) return i ;
return NULL ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
return IP of the Nth interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct in_addr * iface_n_ip ( int n )
{
struct interface * i ;
0001-01-01 02:30:17 +02:30
for ( i = local_interfaces ; i & & n ; i = i - > next )
0001-01-01 02:30:17 +02:30
n - - ;
if ( i ) return & i - > ip ;
return NULL ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Try and find an interface that matches an ip . If we cannot , return NULL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static struct interface * iface_find ( struct in_addr ip )
{
struct interface * i ;
0001-01-01 02:30:17 +02:30
if ( zero_ip ( ip ) ) return local_interfaces ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
for ( i = local_interfaces ; i ; i = i - > next )
0001-01-01 02:30:17 +02:30
if ( same_net ( i - > ip , ip , i - > nmask ) ) return i ;
0001-01-01 02:30:17 +02:30
return NULL ;
0001-01-01 02:30:17 +02:30
}
/* these 3 functions return the ip/bcast/nmask for the interface
0001-01-01 02:30:17 +02:30
most appropriate for the given ip address . If they can ' t find
an appropriate interface they return the requested field of the
first known interface . */
0001-01-01 02:30:17 +02:30
struct in_addr * iface_bcast ( struct in_addr ip )
{
0001-01-01 02:30:17 +02:30
struct interface * i = iface_find ( ip ) ;
return ( i ? & i - > bcast : & local_interfaces - > bcast ) ;
0001-01-01 02:30:17 +02:30
}
struct in_addr * iface_nmask ( struct in_addr ip )
{
0001-01-01 02:30:17 +02:30
struct interface * i = iface_find ( ip ) ;
return ( i ? & i - > nmask : & local_interfaces - > nmask ) ;
0001-01-01 02:30:17 +02:30
}
struct in_addr * iface_ip ( struct in_addr ip )
{
0001-01-01 02:30:17 +02:30
struct interface * i = iface_find ( ip ) ;
return ( i ? & i - > ip : & local_interfaces - > ip ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30