2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
2005-02-10 06:22:47 +03:00
2003-08-13 05:53:07 +04:00
multiple interface handling
2005-02-10 06:22:47 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 2005
2003-08-13 05:53:07 +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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +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 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2004-11-02 01:48:25 +03:00
# include "system/network.h"
2006-08-17 17:37:04 +04:00
# include "lib/socket/netif.h"
2006-08-30 15:29:34 +04:00
# include "lib/util/dlinklist.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2003-08-13 05:53:07 +04:00
2006-03-07 14:07:23 +03:00
/** used for network interfaces */
2004-11-01 08:46:52 +03:00
struct interface {
struct interface * next , * prev ;
2007-10-13 22:24:37 +04:00
struct in_addr ip ;
struct in_addr nmask ;
2006-01-09 05:43:38 +03:00
const char * ip_s ;
const char * bcast_s ;
const char * nmask_s ;
2004-11-01 08:46:52 +03:00
} ;
2003-08-13 05:53:07 +04:00
static struct interface * local_interfaces ;
2004-05-25 20:24:13 +04:00
# define ALLONES ((uint32_t)0xFFFFFFFF)
2006-02-15 05:56:31 +03:00
/*
address construction based on a patch from fred @ datalync . com
*/
2003-08-13 05:53:07 +04:00
# define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
# define MKNETADDR(_IP, _NM) (_IP & _NM)
/****************************************************************************
Try and find an interface that matches an ip . If we cannot , return NULL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-12-10 20:42:01 +03:00
static struct interface * iface_find ( struct interface * interfaces ,
struct in_addr ip , bool CheckMask )
2003-08-13 05:53:07 +04:00
{
struct interface * i ;
2007-12-10 20:42:01 +03:00
if ( is_zero_ip ( ip ) ) return interfaces ;
2003-08-13 05:53:07 +04:00
2007-12-10 20:42:01 +03:00
for ( i = interfaces ; i ; i = i - > next )
2003-08-13 05:53:07 +04:00
if ( CheckMask ) {
2007-10-13 22:24:37 +04:00
if ( same_net ( i - > ip , ip , i - > nmask ) ) return i ;
} else if ( i - > ip . s_addr = = ip . s_addr ) return i ;
2003-08-13 05:53:07 +04:00
return NULL ;
}
/****************************************************************************
add an interface to the linked list of interfaces
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-12-10 20:42:01 +03:00
static void add_interface ( struct in_addr ip , struct in_addr nmask , struct interface * * interfaces )
2003-08-13 05:53:07 +04:00
{
struct interface * iface ;
2007-10-13 22:24:37 +04:00
struct in_addr bcast ;
2007-09-09 05:08:50 +04:00
2007-12-10 20:42:01 +03:00
if ( iface_find ( * interfaces , ip , false ) ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 3 , ( " not adding duplicate interface %s \n " , inet_ntoa ( ip ) ) ) ;
return ;
}
2007-12-10 20:42:01 +03:00
iface = talloc ( * interfaces = = NULL ? talloc_autofree_context ( ) : * interfaces , struct interface ) ;
if ( iface = = NULL )
return ;
2003-08-13 05:53:07 +04:00
ZERO_STRUCTPN ( iface ) ;
2007-10-13 22:24:37 +04:00
iface - > ip = ip ;
iface - > nmask = nmask ;
bcast . s_addr = MKBCADDR ( iface - > ip . s_addr , iface - > nmask . s_addr ) ;
2003-08-13 05:53:07 +04:00
2006-01-09 05:43:38 +03:00
/* keep string versions too, to avoid people tripping over the implied
2007-10-13 22:24:37 +04:00
static in inet_ntoa ( ) */
iface - > ip_s = talloc_strdup ( iface , inet_ntoa ( iface - > ip ) ) ;
iface - > nmask_s = talloc_strdup ( iface , inet_ntoa ( iface - > nmask ) ) ;
2006-02-15 07:18:11 +03:00
if ( nmask . s_addr ! = ~ 0 ) {
2007-10-13 22:24:37 +04:00
iface - > bcast_s = talloc_strdup ( iface , inet_ntoa ( bcast ) ) ;
2006-02-15 07:18:11 +03:00
}
2006-01-09 05:43:38 +03:00
2007-12-10 20:42:01 +03:00
DLIST_ADD_END ( * interfaces , iface , struct interface * ) ;
2003-08-13 05:53:07 +04:00
2006-02-15 07:18:11 +03:00
DEBUG ( 2 , ( " added interface ip=%s nmask=%s \n " , iface - > ip_s , iface - > nmask_s ) ) ;
2003-08-13 05:53:07 +04:00
}
2006-03-07 14:07:23 +03:00
/**
2003-08-13 05:53:07 +04: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
2006-03-07 14:07:23 +03:00
* */
2005-12-28 06:04:40 +03:00
static void interpret_interface ( const char * token ,
struct iface_struct * probed_ifaces ,
int total_probed )
2003-08-13 05:53:07 +04:00
{
struct in_addr ip , nmask ;
char * p ;
int i , added = 0 ;
2004-11-02 01:48:25 +03:00
ip . s_addr = 0 ;
nmask . s_addr = 0 ;
2003-08-13 05:53:07 +04:00
/* first check if it is an interface name */
for ( i = 0 ; i < total_probed ; i + + ) {
if ( gen_fnmatch ( token , probed_ifaces [ i ] . name ) = = 0 ) {
add_interface ( probed_ifaces [ i ] . ip ,
2007-12-10 20:42:01 +03:00
probed_ifaces [ i ] . netmask ,
& local_interfaces ) ;
2003-08-13 05:53:07 +04:00
added = 1 ;
}
}
if ( added ) return ;
/* maybe it is a DNS name */
p = strchr_m ( token , ' / ' ) ;
if ( ! p ) {
2005-08-02 05:22:38 +04:00
/* don't try to do dns lookups on wildcard names */
if ( strpbrk ( token , " *? " ) ! = NULL ) {
return ;
}
2007-10-13 22:24:37 +04:00
ip . s_addr = interpret_addr2 ( token ) . s_addr ;
2003-08-13 05:53:07 +04:00
for ( i = 0 ; i < total_probed ; i + + ) {
2006-02-15 07:18:11 +03:00
if ( ip . s_addr = = probed_ifaces [ i ] . ip . s_addr ) {
2003-08-13 05:53:07 +04:00
add_interface ( probed_ifaces [ i ] . ip ,
2007-12-10 20:42:01 +03:00
probed_ifaces [ i ] . netmask ,
& local_interfaces ) ;
2003-08-13 05:53:07 +04:00
return ;
}
}
DEBUG ( 2 , ( " can't determine netmask for %s \n " , token ) ) ;
return ;
}
/* parse it into an IP address/netmasklength pair */
* p + + = 0 ;
2007-10-13 22:24:37 +04:00
ip . s_addr = interpret_addr2 ( token ) . s_addr ;
2003-08-13 05:53:07 +04:00
if ( strlen ( p ) > 2 ) {
2007-10-13 22:24:37 +04:00
nmask . s_addr = interpret_addr2 ( p ) . s_addr ;
2003-08-13 05:53:07 +04:00
} 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-13 22:24:37 +04:00
if ( same_net ( ip , probed_ifaces [ i ] . ip , nmask ) ) {
2007-12-10 20:42:01 +03:00
add_interface ( probed_ifaces [ i ] . ip , nmask ,
& local_interfaces ) ;
2003-08-13 05:53:07 +04:00
return ;
}
}
DEBUG ( 2 , ( " Can't determine ip for broadcast address %s \n " , token ) ) ;
return ;
}
2007-12-10 20:42:01 +03:00
add_interface ( ip , nmask , & local_interfaces ) ;
2003-08-13 05:53:07 +04:00
}
2006-03-07 14:07:23 +03:00
/**
2003-08-13 05:53:07 +04:00
load the list of network interfaces
2006-03-07 14:07:23 +03:00
* */
2007-12-06 18:54:34 +03:00
static void load_interfaces ( const char * * interfaces )
2003-08-13 05:53:07 +04:00
{
2007-12-06 18:54:34 +03:00
const char * * ptr = interfaces ;
2003-08-13 05:53:07 +04:00
int i ;
struct iface_struct ifaces [ MAX_INTERFACES ] ;
2007-10-13 22:24:37 +04:00
struct in_addr loopback_ip ;
2005-12-28 06:04:40 +03:00
int total_probed ;
2003-08-13 05:53:07 +04:00
2005-12-28 06:04:40 +03:00
if ( local_interfaces ! = NULL ) {
2003-08-13 05:53:07 +04:00
return ;
2005-01-28 14:23:31 +03:00
}
2003-08-13 05:53:07 +04:00
2004-10-27 07:15:42 +04:00
loopback_ip = interpret_addr2 ( " 127.0.0.1 " ) ;
2003-08-13 05:53:07 +04:00
/* probe the kernel for interfaces */
total_probed = get_interfaces ( ifaces , MAX_INTERFACES ) ;
2006-02-15 07:18:11 +03:00
/* if we don't have a interfaces line then use all interfaces
except loopback */
2003-08-13 05:53:07 +04:00
if ( ! ptr | | ! * ptr | | ! * * ptr ) {
if ( total_probed < = 0 ) {
DEBUG ( 0 , ( " ERROR: Could not determine network interfaces, you must use a interfaces config line \n " ) ) ;
}
for ( i = 0 ; i < total_probed ; i + + ) {
2007-10-13 22:24:37 +04:00
if ( ifaces [ i ] . ip . s_addr ! = loopback_ip . s_addr ) {
2005-12-28 06:04:40 +03:00
add_interface ( ifaces [ i ] . ip ,
2007-12-10 20:42:01 +03:00
ifaces [ i ] . netmask , & local_interfaces ) ;
2003-08-13 05:53:07 +04:00
}
}
}
2005-12-28 06:04:40 +03:00
while ( ptr & & * ptr ) {
interpret_interface ( * ptr , ifaces , total_probed ) ;
ptr + + ;
2003-08-13 05:53:07 +04:00
}
if ( ! local_interfaces ) {
DEBUG ( 0 , ( " WARNING: no network interfaces found \n " ) ) ;
}
}
2006-03-07 14:07:23 +03:00
/**
2005-12-28 06:04:40 +03:00
unload the interfaces list , so it can be reloaded when needed
*/
2006-03-07 14:07:23 +03:00
void unload_interfaces ( void )
2003-08-13 05:53:07 +04:00
{
2005-12-28 06:04:40 +03:00
talloc_free ( local_interfaces ) ;
local_interfaces = NULL ;
2003-08-13 05:53:07 +04:00
}
2006-03-07 14:07:23 +03:00
/**
2003-08-13 05:53:07 +04:00
how many interfaces do we have
2006-03-07 14:07:23 +03:00
* */
2007-12-07 01:57:22 +03:00
int iface_count ( struct loadparm_context * lp_ctx )
2003-08-13 05:53:07 +04:00
{
int ret = 0 ;
struct interface * i ;
2007-12-07 01:57:22 +03:00
load_interfaces ( lp_interfaces ( lp_ctx ) ) ;
2005-12-28 06:04:40 +03:00
2003-08-13 05:53:07 +04:00
for ( i = local_interfaces ; i ; i = i - > next )
ret + + ;
return ret ;
}
2006-03-07 14:07:23 +03:00
/**
2003-08-13 05:53:07 +04:00
return IP of the Nth interface
2006-03-07 14:07:23 +03:00
* */
2007-12-07 01:57:22 +03:00
const char * iface_n_ip ( struct loadparm_context * lp_ctx , int n )
2003-08-13 05:53:07 +04:00
{
struct interface * i ;
2007-12-07 01:57:22 +03:00
load_interfaces ( lp_interfaces ( lp_ctx ) ) ;
2005-12-28 06:04:40 +03:00
2003-08-13 05:53:07 +04:00
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
2005-02-10 06:22:47 +03:00
if ( i ) {
2006-01-09 05:43:38 +03:00
return i - > ip_s ;
2005-02-10 06:22:47 +03:00
}
2003-08-13 05:53:07 +04:00
return NULL ;
}
2006-03-07 14:07:23 +03:00
/**
2003-08-13 05:53:07 +04:00
return bcast of the Nth interface
2006-03-07 14:07:23 +03:00
* */
2007-12-07 01:57:22 +03:00
const char * iface_n_bcast ( struct loadparm_context * lp_ctx , int n )
2003-08-13 05:53:07 +04:00
{
struct interface * i ;
2007-12-07 01:57:22 +03:00
load_interfaces ( lp_interfaces ( lp_ctx ) ) ;
2005-12-28 06:04:40 +03:00
2003-08-13 05:53:07 +04:00
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
2005-02-10 06:22:47 +03:00
if ( i ) {
2006-01-09 05:43:38 +03:00
return i - > bcast_s ;
2005-02-10 06:22:47 +03:00
}
2003-08-13 05:53:07 +04:00
return NULL ;
}
2006-03-07 14:07:23 +03:00
/**
2005-01-31 04:57:58 +03:00
return netmask of the Nth interface
2006-03-07 14:07:23 +03:00
* */
2007-12-07 01:57:22 +03:00
const char * iface_n_netmask ( struct loadparm_context * lp_ctx , int n )
2005-01-31 04:57:58 +03:00
{
struct interface * i ;
2007-12-07 01:57:22 +03:00
load_interfaces ( lp_interfaces ( lp_ctx ) ) ;
2005-12-28 06:04:40 +03:00
2005-01-31 04:57:58 +03:00
for ( i = local_interfaces ; i & & n ; i = i - > next )
n - - ;
2005-02-10 06:22:47 +03:00
if ( i ) {
2006-01-09 05:43:38 +03:00
return i - > nmask_s ;
2005-02-10 06:22:47 +03:00
}
2005-01-31 04:57:58 +03:00
return NULL ;
}
2006-03-07 14:07:23 +03:00
/**
2005-02-16 04:48:11 +03:00
return the local IP address that best matches a destination IP , or
our first interface if none match
*/
2007-12-07 01:57:22 +03:00
const char * iface_best_ip ( struct loadparm_context * lp_ctx , const char * dest )
2005-02-16 04:48:11 +03:00
{
struct interface * iface ;
struct in_addr ip ;
2005-12-28 06:04:40 +03:00
2007-12-07 01:57:22 +03:00
load_interfaces ( lp_interfaces ( lp_ctx ) ) ;
2005-12-28 06:04:40 +03:00
2005-02-16 04:48:11 +03:00
ip . s_addr = interpret_addr ( dest ) ;
2007-12-10 20:42:01 +03:00
iface = iface_find ( local_interfaces , ip , true ) ;
2005-02-16 04:48:11 +03:00
if ( iface ) {
2006-01-09 05:43:38 +03:00
return iface - > ip_s ;
2005-02-16 04:48:11 +03:00
}
2007-12-07 01:57:22 +03:00
return iface_n_ip ( lp_ctx , 0 ) ;
2005-02-16 04:48:11 +03:00
}
2005-06-30 05:26:52 +04:00
2006-03-07 14:07:23 +03:00
/**
2007-10-05 22:03:01 +04:00
return true if an IP is one one of our local networks
2005-06-30 05:26:52 +04:00
*/
2007-12-07 01:57:22 +03:00
bool iface_is_local ( struct loadparm_context * lp_ctx , const char * dest )
2005-06-30 05:26:52 +04:00
{
struct in_addr ip ;
2005-12-28 06:04:40 +03:00
2007-12-07 01:57:22 +03:00
load_interfaces ( lp_interfaces ( lp_ctx ) ) ;
2005-12-28 06:04:40 +03:00
2005-06-30 05:26:52 +04:00
ip . s_addr = interpret_addr ( dest ) ;
2007-12-10 20:42:01 +03:00
if ( iface_find ( local_interfaces , ip , true ) ) {
2007-10-05 22:03:01 +04:00
return true ;
2005-06-30 05:26:52 +04:00
}
2007-10-05 22:03:01 +04:00
return false ;
2005-06-30 05:26:52 +04:00
}
2005-11-14 04:50:26 +03:00
2006-03-07 14:07:23 +03:00
/**
2007-10-05 22:03:01 +04:00
return true if a IP matches a IP / netmask pair
2005-11-14 04:50:26 +03:00
*/
2007-10-05 22:03:01 +04:00
bool iface_same_net ( const char * ip1 , const char * ip2 , const char * netmask )
2005-11-14 04:50:26 +03:00
{
return same_net ( interpret_addr2 ( ip1 ) ,
interpret_addr2 ( ip2 ) ,
interpret_addr2 ( netmask ) ) ;
}