1996-06-06 15:43:09 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-06-06 15:43:09 +04:00
multiple interface handling
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1996-06-06 15:43:09 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1996-06-06 15:43:09 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-06-06 15:43:09 +04:00
*/
# include "includes.h"
1999-12-13 16:27:58 +03:00
static struct iface_struct * probed_ifaces ;
static int total_probed ;
1997-12-13 17:16:07 +03:00
struct in_addr allones_ip ;
1997-10-15 13:16:30 +04:00
struct in_addr loopback_ip ;
1996-06-06 15:43:09 +04:00
2001-11-23 04:00:54 +03:00
static struct interface * local_interfaces ;
1996-06-29 23:27:12 +04:00
1997-12-29 21:46:20 +03:00
# define ALLONES ((uint32)0xFFFFFFFF)
# define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
1999-12-13 16:27:58 +03:00
# define MKNETADDR(_IP, _NM) (_IP & _NM)
1997-09-26 23:23:26 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Try and find an interface that matches an ip . If we cannot , return NULL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-02-15 22:50:34 +03:00
static struct interface * iface_find ( struct in_addr ip , BOOL CheckMask )
1997-09-26 23:23:26 +04:00
{
1999-12-13 16:27:58 +03:00
struct interface * i ;
2001-11-26 06:11:44 +03:00
if ( is_zero_ip ( ip ) ) return local_interfaces ;
1999-12-13 16:27:58 +03:00
for ( i = local_interfaces ; i ; i = i - > next )
2001-02-15 22:50:34 +03:00
if ( CheckMask ) {
if ( same_net ( i - > ip , ip , i - > nmask ) ) return i ;
} else if ( ( i - > ip ) . s_addr = = ip . s_addr ) return i ;
1999-12-13 16:27:58 +03:00
return NULL ;
1997-09-26 23:23:26 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
add an interface to the linked list of interfaces
1997-09-26 23:23:26 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
static void add_interface ( struct in_addr ip , struct in_addr nmask )
{
struct interface * iface ;
2001-02-15 22:50:34 +03:00
if ( iface_find ( ip , False ) ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 3 , ( " not adding duplicate interface %s \n " , inet_ntoa ( ip ) ) ) ;
return ;
1998-07-29 07:08:05 +04:00
}
1999-12-13 16:27:58 +03:00
2005-02-01 22:32:54 +03:00
# if !defined(__s390__)
1999-12-13 16:27:58 +03:00
if ( ip_equal ( nmask , allones_ip ) ) {
DEBUG ( 3 , ( " not adding non-broadcast interface %s \n " , inet_ntoa ( ip ) ) ) ;
return ;
1997-09-26 23:23:26 +04:00
}
2005-02-01 22:32:54 +03:00
# endif
1997-09-26 23:23:26 +04:00
2004-12-07 21:25:53 +03:00
iface = SMB_MALLOC_P ( struct interface ) ;
1999-12-13 16:27:58 +03:00
if ( ! iface ) return ;
ZERO_STRUCTPN ( iface ) ;
iface - > ip = ip ;
iface - > nmask = nmask ;
iface - > bcast . s_addr = MKBCADDR ( iface - > ip . s_addr , iface - > nmask . s_addr ) ;
DLIST_ADD ( local_interfaces , iface ) ;
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 ) ) ) ;
1998-07-29 07:08:05 +04:00
}
1996-06-06 15:43:09 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
interpret a single element from a interfaces = config line
This handles the following different forms :
1 ) wildcard interface name
2 ) DNS name
3 ) IP / masklen
4 ) ip / mask
5 ) bcast / mask
1996-06-06 15:43:09 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-25 03:27:00 +04:00
static void interpret_interface ( char * token )
1996-06-06 15:43:09 +04:00
{
1999-12-13 16:27:58 +03:00
struct in_addr ip , nmask ;
char * p ;
int i , added = 0 ;
2001-11-26 06:11:44 +03:00
zero_ip ( & ip ) ;
zero_ip ( & nmask ) ;
2007-10-02 23:27:25 +04:00
1999-12-13 16:27:58 +03:00
/* first check if it is an interface name */
for ( i = 0 ; i < total_probed ; i + + ) {
2001-08-20 09:15:26 +04:00
if ( gen_fnmatch ( token , probed_ifaces [ i ] . name ) = = 0 ) {
2007-10-02 23:27:25 +04:00
add_interface ( probed_ifaces [ i ] . iface_addr . ip ,
probed_ifaces [ i ] . iface_netmask . netmask ) ;
1999-12-13 16:27:58 +03:00
added = 1 ;
}
}
if ( added ) return ;
/* maybe it is a DNS name */
2001-07-04 11:36:09 +04:00
p = strchr_m ( token , ' / ' ) ;
1999-12-13 16:27:58 +03:00
if ( ! p ) {
ip = * interpret_addr2 ( token ) ;
for ( i = 0 ; i < total_probed ; i + + ) {
2007-10-02 23:27:25 +04:00
if ( ip . s_addr = = probed_ifaces [ i ] . iface_addr . ip . s_addr & &
! ip_equal ( allones_ip ,
probed_ifaces [ i ] . iface_netmask . netmask ) ) {
add_interface ( probed_ifaces [ i ] . iface_addr . ip ,
probed_ifaces [ i ] . iface_netmask . netmask ) ;
1999-12-13 16:27:58 +03:00
return ;
}
}
DEBUG ( 2 , ( " can't determine netmask for %s \n " , token ) ) ;
return ;
}
/* parse it into an IP address/netmasklength pair */
2004-06-25 03:27:00 +04:00
* p = 0 ;
1999-12-13 16:27:58 +03:00
ip = * interpret_addr2 ( token ) ;
2004-06-25 03:27:00 +04:00
* p + + = ' / ' ;
1999-12-13 16:27:58 +03:00
if ( strlen ( p ) > 2 ) {
nmask = * interpret_addr2 ( p ) ;
} else {
nmask . s_addr = htonl ( ( ( ALLONES > > atoi ( p ) ) ^ ALLONES ) ) ;
}
/* maybe the first component was a broadcast address */
if ( ip . s_addr = = MKBCADDR ( ip . s_addr , nmask . s_addr ) | |
ip . s_addr = = MKNETADDR ( ip . s_addr , nmask . s_addr ) ) {
for ( i = 0 ; i < total_probed ; i + + ) {
2007-10-02 23:27:25 +04:00
if ( same_net ( ip , probed_ifaces [ i ] . iface_addr . ip , nmask ) ) {
add_interface ( probed_ifaces [ i ] . iface_addr . ip , nmask ) ;
1999-12-13 16:27:58 +03:00
return ;
}
}
DEBUG ( 2 , ( " Can't determine ip for broadcast address %s \n " , token ) ) ;
return ;
}
add_interface ( ip , nmask ) ;
1996-06-06 15:43:09 +04:00
}
1996-06-29 23:27:12 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
load the list of network interfaces
1996-06-29 23:27:12 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void load_interfaces ( void )
{
2002-11-13 02:20:50 +03:00
const char * * ptr ;
1999-12-13 16:27:58 +03:00
int i ;
struct iface_struct ifaces [ MAX_INTERFACES ] ;
ptr = lp_interfaces ( ) ;
allones_ip = * interpret_addr2 ( " 255.255.255.255 " ) ;
loopback_ip = * interpret_addr2 ( " 127.0.0.1 " ) ;
2001-09-17 06:19:44 +04:00
SAFE_FREE ( probed_ifaces ) ;
1999-12-13 16:27:58 +03:00
/* dump the current interfaces if any */
while ( local_interfaces ) {
struct interface * iface = local_interfaces ;
DLIST_REMOVE ( local_interfaces , local_interfaces ) ;
ZERO_STRUCTPN ( iface ) ;
2001-09-17 06:19:44 +04:00
SAFE_FREE ( iface ) ;
1999-12-13 16:27:58 +03:00
}
/* probe the kernel for interfaces */
total_probed = get_interfaces ( ifaces , MAX_INTERFACES ) ;
if ( total_probed > 0 ) {
2006-07-31 08:30:55 +04:00
probed_ifaces = ( struct iface_struct * ) memdup ( ifaces , sizeof ( ifaces [ 0 ] ) * total_probed ) ;
2006-06-28 04:50:14 +04:00
if ( ! probed_ifaces ) {
DEBUG ( 0 , ( " ERROR: memdup failed \n " ) ) ;
exit ( 1 ) ;
}
1999-12-13 16:27:58 +03:00
}
/* if we don't have a interfaces line then use all broadcast capable
interfaces except loopback */
2001-07-02 03:24:08 +04:00
if ( ! ptr | | ! * ptr | | ! * * ptr ) {
1999-12-13 16:27:58 +03:00
if ( total_probed < = 0 ) {
DEBUG ( 0 , ( " ERROR: Could not determine network interfaces, you must use a interfaces config line \n " ) ) ;
exit ( 1 ) ;
}
for ( i = 0 ; i < total_probed ; i + + ) {
2005-02-01 22:32:54 +03:00
if (
# if !defined(__s390__)
2007-10-02 23:27:25 +04:00
probed_ifaces [ i ] . iface_netmask . netmask . s_addr ! = allones_ip . s_addr & &
2005-02-01 22:32:54 +03:00
# endif
2007-10-02 23:27:25 +04:00
probed_ifaces [ i ] . iface_addr . ip . s_addr ! = loopback_ip . s_addr ) {
add_interface ( probed_ifaces [ i ] . iface_addr . ip ,
probed_ifaces [ i ] . iface_netmask . netmask ) ;
1999-12-13 16:27:58 +03:00
}
}
return ;
}
2001-07-03 04:54:55 +04:00
if ( ptr ) {
while ( * ptr ) {
2004-12-07 21:25:53 +03:00
char * ptr_cpy = SMB_STRDUP ( * ptr ) ;
2004-06-25 03:27:00 +04:00
if ( ptr_cpy ) {
interpret_interface ( ptr_cpy ) ;
free ( ptr_cpy ) ;
}
2001-07-03 04:54:55 +04:00
ptr + + ;
}
1999-12-13 16:27:58 +03:00
}
if ( ! local_interfaces ) {
DEBUG ( 0 , ( " WARNING: no network interfaces found \n " ) ) ;
}
1996-06-29 23:27:12 +04:00
}
2007-03-16 17:13:46 +03:00
void gfree_interfaces ( void )
{
while ( local_interfaces ) {
struct interface * iface = local_interfaces ;
DLIST_REMOVE ( local_interfaces , local_interfaces ) ;
ZERO_STRUCTPN ( iface ) ;
SAFE_FREE ( iface ) ;
}
SAFE_FREE ( probed_ifaces ) ;
}
1996-06-06 15:43:09 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
return True if the list of probed interfaces has changed
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL interfaces_changed ( void )
1996-06-06 15:43:09 +04:00
{
1999-12-13 16:27:58 +03:00
int n ;
struct iface_struct ifaces [ MAX_INTERFACES ] ;
n = get_interfaces ( ifaces , MAX_INTERFACES ) ;
2000-11-10 22:02:32 +03:00
if ( ( n > 0 ) & & ( n ! = total_probed | |
memcmp ( ifaces , probed_ifaces , sizeof ( ifaces [ 0 ] ) * n ) ) ) {
1999-12-13 16:27:58 +03:00
return True ;
}
return False ;
1996-06-06 15:43:09 +04:00
}
/****************************************************************************
check if an IP is one of mine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL ismyip ( struct in_addr ip )
{
1999-12-13 16:27:58 +03:00
struct interface * i ;
for ( i = local_interfaces ; i ; i = i - > next )
if ( ip_equal ( i - > ip , ip ) ) return True ;
return False ;
1996-06-06 15:43:09 +04:00
}
1997-10-18 03:08:07 +04:00
/****************************************************************************
check if a packet is from a local ( known ) net
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL is_local_net ( struct in_addr from )
{
1999-12-13 16:27:58 +03:00
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 ;
1997-10-18 03:08:07 +04:00
}
1996-06-07 07:34:22 +04:00
/****************************************************************************
how many interfaces do we have
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int iface_count ( void )
{
1999-12-13 16:27:58 +03:00
int ret = 0 ;
struct interface * i ;
1996-06-07 07:34:22 +04:00
1999-12-13 16:27:58 +03:00
for ( i = local_interfaces ; i ; i = i - > next )
ret + + ;
return ret ;
1996-06-07 07:34:22 +04:00
}
1997-12-13 17:16:07 +03:00
/****************************************************************************
return the Nth interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct interface * get_interface ( int n )
{
1999-12-13 16:27:58 +03:00
struct interface * i ;
1997-12-13 17:16:07 +03:00
1999-12-13 16:27:58 +03:00
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
1997-12-13 17:16:07 +03:00
1999-12-13 16:27:58 +03:00
if ( i ) return i ;
return NULL ;
1997-12-13 17:16:07 +03:00
}
1996-06-07 07:34:22 +04:00
/****************************************************************************
return IP of the Nth interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct in_addr * iface_n_ip ( int n )
{
1999-12-13 16:27:58 +03:00
struct interface * i ;
1996-06-07 07:34:22 +04:00
1999-12-13 16:27:58 +03:00
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
1996-06-07 07:34:22 +04:00
1999-12-13 16:27:58 +03:00
if ( i ) return & i - > ip ;
return NULL ;
1996-06-07 07:34:22 +04:00
}
1997-10-24 02:30:57 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
return bcast of the Nth interface
1997-10-24 02:30:57 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
struct in_addr * iface_n_bcast ( int n )
1996-06-06 15:43:09 +04:00
{
1999-12-13 16:27:58 +03:00
struct interface * i ;
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
1996-06-06 15:43:09 +04:00
1999-12-13 16:27:58 +03:00
if ( i ) return & i - > bcast ;
return NULL ;
1996-06-06 15:43:09 +04:00
}
1998-08-30 09:43:59 +04:00
1996-06-06 15:43:09 +04:00
/* these 3 functions return the ip/bcast/nmask for the interface
1997-12-13 17:16:07 +03:00
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 . */
1996-06-06 15:43:09 +04:00
2002-07-15 14:35:28 +04:00
struct in_addr * iface_ip ( struct in_addr ip )
1996-06-06 15:43:09 +04:00
{
2001-02-15 22:50:34 +03:00
struct interface * i = iface_find ( ip , True ) ;
2002-07-15 14:35:28 +04:00
return ( i ? & i - > ip : & local_interfaces - > ip ) ;
1996-06-06 15:43:09 +04:00
}
2002-07-15 14:35:28 +04:00
/*
return True if a IP is directly reachable on one of our interfaces
*/
BOOL iface_local ( struct in_addr ip )
1996-06-06 15:43:09 +04:00
{
2002-07-15 14:35:28 +04:00
return iface_find ( ip , True ) ? True : False ;
1996-06-06 15:43:09 +04:00
}