0001-01-01 02:30:17 +02:30
/*
Unix SMB / Netbios implementation .
0001-01-01 02:30:17 +02:30
Version 2.
0001-01-01 02:30:17 +02:30
Samba utility functions
Copyright ( C ) Andrew Tridgell 1992 - 1998
0001-01-01 02:30:17 +02:30
Copyright ( C ) Christopher R . Hertel 2000
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"
/* -------------------------------------------------------------------------- **
* Discussion . . .
*
* This module implements WINS failover .
*
* Microsoft ' s WINS servers provide a feature called WINS replication ,
* which synchronises the WINS name databases between two or more servers .
* This means that the two servers can be used interchangably ( more or
* less ) . WINS replication is particularly useful if you are trying to
* synchronise the WINS namespace between servers in remote locations , or
* if your WINS servers tend to crash a lot .
*
* WINS failover allows the client to ' switch ' to a different WINS server
* if the current WINS server mysteriously disappears . On Windows
* systems , this is typically represented as ' primary ' and ' secondary '
* WINS servers .
*
* Failover only works if the WINS servers are synced . If they are not ,
* then
* a ) if the primary WINS server never fails the client will never ' see '
* the secondary ( or tertiary or . . . ) WINS server name space .
* b ) if the primary * does * fail , the client will be entering an
* unfamiliar namespace . The client itself will not be registered in
* that namespace and any names which match names in the previous
* space will likely resolve to different host IP addresses .
*
* One key thing to remember regarding WINS failover is that Samba does
* not ( yet ) implement WINS replication . For those interested , sniff port
* 42 ( TCP ? UDP ? . . . dunno off hand ) and see what two MS WINS servers do .
*
* At this stage , only failover is implemented . The next thing is to add
0001-01-01 02:30:17 +02:30
* support for multi - WINS server registration and query ( multi - membership ) .
0001-01-01 02:30:17 +02:30
*
* Multi - membership is a little wierd . The idea is that the client can
* register itself with multiple non - replicated WINS servers , and query
* all of those servers ( in a prescribed sequence ) to resolve a name .
*
* The implications of multi - membership are not quite clear . Worth
* trying , I suppose . Changes will be needed in the name query and
* registration code to accomodate this feature . Also , there will need to
* be some sort of syntax extension for the ' wins server ' parameter in
* smb . conf . I ' m thinking that a colon could be used as a separator .
*
* Of course , for each WINS namespace there might be multiple , synced WINS
* servers . The change to this module would likely be the addition of a
* linked list of linked lists .
*
* crh @ samba . org
*/
/* -------------------------------------------------------------------------- **
* Defines . . .
*
* NECROMANCYCLE - The dead server retry period , in seconds . When a WINS
* server is declared dead , wait this many seconds before
* attempting to communicate with it .
*/
# define NECROMANCYCLE 600 /* 600 seconds == 10 minutes. */
/* -------------------------------------------------------------------------- **
* Typedefs . . .
*/
typedef struct
{
0001-01-01 02:30:17 +02:30
ubi_slNode node ; /* Linked list node structure. */
time_t mourning ; /* If > current time then server is dead, Jim. */
char * server ; /* DNS name or IP of NBNS server to query. */
struct in_addr ip_addr ; /* Cache translated IP. */
0001-01-01 02:30:17 +02:30
} list_entry ;
/* -------------------------------------------------------------------------- **
* Private , static variables .
*/
static ubi_slNewList ( wins_srv_list ) ;
/* -------------------------------------------------------------------------- **
* Functions . . .
*/
BOOL wins_srv_load_list ( char * src )
/* ------------------------------------------------------------------------ **
* Create or recreate the linked list of failover WINS servers .
0001-01-01 02:30:17 +02:30
*
* Input : src - String of DNS names and / or IP addresses delimited by the
* characters listed in LIST_SEP ( see include / local . h ) .
*
* Output : True if at least one name or IP could be parsed out of the
* list , else False .
*
* Notes : There is no syntax checking done on the names or IPs . We do
* check to see if the field is an IP , in which case we copy it
* to the ip_addr field of the entry . Don ' t bother to to a host
* name lookup on all names now . They ' re done as needed in
* wins_srv_ip ( ) .
0001-01-01 02:30:17 +02:30
*/
{
list_entry * entry ;
char * p = src ;
pstring wins_id_bufr ;
unsigned long count ;
/* Empty the list. */
while ( NULL ! = ( entry = ( list_entry * ) ubi_slRemHead ( wins_srv_list ) ) )
{
if ( entry - > server )
free ( entry - > server ) ;
free ( entry ) ;
}
( void ) ubi_slInitList ( wins_srv_list ) ; /* shouldn't be needed */
/* Parse out the DNS names or IP addresses of the WINS servers. */
0001-01-01 02:30:17 +02:30
DEBUG ( 4 , ( " wins_srv_load_list(): Building WINS server list: \n " ) ) ;
0001-01-01 02:30:17 +02:30
while ( next_token ( & p , wins_id_bufr , LIST_SEP , sizeof ( wins_id_bufr ) ) )
{
entry = ( list_entry * ) malloc ( sizeof ( list_entry ) ) ;
if ( NULL = = entry )
{
DEBUG ( 0 , ( " wins_srv_load_list(): malloc(list_entry) failed. \n " ) ) ;
}
else
{
entry - > mourning = 0 ;
if ( NULL = = ( entry - > server = strdup ( wins_id_bufr ) ) )
{
free ( entry ) ;
DEBUG ( 0 , ( " wins_srv_load_list(): strdup( \" %s \" ) failed. \n " , wins_id_bufr ) ) ;
}
else
{
/* Add server to list. */
0001-01-01 02:30:17 +02:30
if ( is_ipaddress ( wins_id_bufr ) )
entry - > ip_addr = * interpret_addr2 ( wins_id_bufr ) ;
else
entry - > ip_addr = * interpret_addr2 ( " 0.0.0.0 " ) ;
0001-01-01 02:30:17 +02:30
( void ) ubi_slAddTail ( wins_srv_list , entry ) ;
0001-01-01 02:30:17 +02:30
DEBUGADD ( 4 , ( " %s, \n " , wins_id_bufr ) ) ;
0001-01-01 02:30:17 +02:30
}
}
}
count = ubi_slCount ( wins_srv_list ) ;
0001-01-01 02:30:17 +02:30
DEBUGADD ( 4 , ( " %d WINS server%s listed. \n " , ( int ) count , ( 1 = = count ) ? " " : " s " ) ) ;
0001-01-01 02:30:17 +02:30
return ( ( count > 0 ) ? True : False ) ;
} /* wins_srv_load_list */
0001-01-01 02:30:17 +02:30
struct in_addr wins_srv_ip ( void )
0001-01-01 02:30:17 +02:30
/* ------------------------------------------------------------------------ **
*/
{
time_t now = time ( NULL ) ;
list_entry * entry = ( list_entry * ) ubi_slFirst ( wins_srv_list ) ;
0001-01-01 02:30:17 +02:30
while ( NULL ! = entry )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
if ( now > = entry - > mourning ) /* Found a live one. */
{
/* If we don't have the IP, look it up. */
if ( zero_ip ( entry - > ip_addr ) )
entry - > ip_addr = * interpret_addr2 ( entry - > server ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/* If we still don't have the IP then kill it, else return it. */
if ( zero_ip ( entry - > ip_addr ) )
entry - > mourning = now + NECROMANCYCLE ;
else
return ( entry - > ip_addr ) ;
}
entry = ( list_entry * ) ubi_slNext ( entry ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/* If there are no live entries, return the zero IP. */
return ( * interpret_addr2 ( " 0.0.0.0 " ) ) ;
} /* wins_srv_ip */
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
void wins_srv_died ( struct in_addr boothill_ip )
0001-01-01 02:30:17 +02:30
/* ------------------------------------------------------------------------ **
* Called to indicate that a specific WINS server has died .
*/
{
0001-01-01 02:30:17 +02:30
list_entry * entry ;
if ( zero_ip ( boothill_ip ) )
{
DEBUG ( 4 , ( " wins_srv_died(): Got request to mark zero IP down. \n " ) ) ;
return ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
entry = ( list_entry * ) ubi_slFirst ( wins_srv_list ) ;
0001-01-01 02:30:17 +02:30
while ( NULL ! = entry )
{
0001-01-01 02:30:17 +02:30
/* Match based on IP. */
if ( ip_equal ( boothill_ip , entry - > ip_addr ) )
0001-01-01 02:30:17 +02:30
{
entry - > mourning = time ( NULL ) + NECROMANCYCLE ;
0001-01-01 02:30:17 +02:30
entry - > ip_addr . s_addr = 0 ; /* Force a re-lookup at re-birth. */
DEBUG ( 2 , ( " wins_srv_died(): WINS server %s appears to be down. \n " ,
entry - > server ) ) ;
0001-01-01 02:30:17 +02:30
return ;
}
entry = ( list_entry * ) ubi_slNext ( entry ) ;
}
0001-01-01 02:30:17 +02:30
if ( DEBUGLVL ( 1 ) )
{
dbgtext ( " wins_srv_died(): Could not mark WINS server %s down. \n " ,
inet_ntoa ( boothill_ip ) ) ;
dbgtext ( " Address not found in server list. \n " ) ;
}
0001-01-01 02:30:17 +02:30
} /* wins_srv_died */
unsigned long wins_srv_count ( void )
/* ------------------------------------------------------------------------ **
* Return the total number of entries in the list , dead or alive .
*/
{
0001-01-01 02:30:17 +02:30
unsigned long count = ubi_slCount ( wins_srv_list ) ;
if ( DEBUGLVL ( 8 ) )
{
list_entry * entry = ( list_entry * ) ubi_slFirst ( wins_srv_list ) ;
time_t now = time ( NULL ) ;
dbgtext ( " wins_srv_count: WINS status: %ld servers. \n " , count ) ;
while ( NULL ! = entry )
{
dbgtext ( " %s <%s>: " , entry - > server , inet_ntoa ( entry - > ip_addr ) ) ;
if ( now > = entry - > mourning )
dbgtext ( " alive \n " ) ;
else
dbgtext ( " dead for %d more seconds \n " , ( int ) ( entry - > mourning - now ) ) ;
entry = ( list_entry * ) ubi_slNext ( entry ) ;
}
}
return ( count ) ;
0001-01-01 02:30:17 +02:30
} /* wins_srv_count */
/* ========================================================================== */