mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
585d0efbc6
and replaced with two functions:
void zero_ip(struct in_adder *ip);
BOOL is_zero_ip(struct in_addr ip);
(This used to be commit 778f5f77a6
)
341 lines
12 KiB
C
341 lines
12 KiB
C
/*
|
|
Unix SMB/Netbios implementation.
|
|
Version 2.
|
|
Samba utility functions
|
|
Copyright (C) Andrew Tridgell 1992-1998
|
|
Copyright (C) Christopher R. Hertel 2000
|
|
|
|
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 02139, 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
|
|
* support for multi-WINS server registration and query (multi-membership).
|
|
*
|
|
* 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
|
|
{
|
|
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. */
|
|
} 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.
|
|
*
|
|
* 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().
|
|
* ------------------------------------------------------------------------ **
|
|
*/
|
|
{
|
|
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 )) )
|
|
{
|
|
SAFE_FREE( entry->server );
|
|
SAFE_FREE( entry );
|
|
}
|
|
(void)ubi_slInitList( wins_srv_list ); /* shouldn't be needed */
|
|
|
|
/* Parse out the DNS names or IP addresses of the WINS servers. */
|
|
DEBUG( 4, ("wins_srv_load_list(): Building WINS server list:\n") );
|
|
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;
|
|
/* Create a copy of the server name and store it in the list. */
|
|
if( NULL == (entry->server = strdup( wins_id_bufr )) )
|
|
{
|
|
SAFE_FREE( entry );
|
|
DEBUG( 0,
|
|
("wins_srv_load_list(): strdup(\"%s\") failed.\n", wins_id_bufr) );
|
|
}
|
|
else
|
|
{
|
|
/* Add server to list.
|
|
* If the server name was actually an IP address we will store that
|
|
* too. It it was a DNS name, we will wait until we need to use
|
|
* the WINS server before doing the DNS lookup. Since this may be
|
|
* a list, and since we will reload the list whenever smb.conf is
|
|
* reloaded, there's no point in trying to look up names until we
|
|
* need them. ...of course, once we do the lookup we will cache
|
|
* the result. See wins_srv_ip().
|
|
*/
|
|
if( is_ipaddress( wins_id_bufr ) )
|
|
entry->ip_addr = *interpret_addr2( wins_id_bufr );
|
|
else
|
|
entry->ip_addr = *interpret_addr2( "0.0.0.0" );
|
|
(void)ubi_slAddTail( wins_srv_list, entry );
|
|
DEBUGADD( 4, ("%s,\n", wins_id_bufr) );
|
|
}
|
|
}
|
|
}
|
|
|
|
count = ubi_slCount( wins_srv_list );
|
|
DEBUGADD( 4,
|
|
( "%d WINS server%s listed.\n", (int)count, (1==count)?"":"s" ) );
|
|
|
|
return( (count > 0) ? True : False );
|
|
} /* wins_srv_load_list */
|
|
|
|
|
|
struct in_addr wins_srv_ip( void )
|
|
/* ------------------------------------------------------------------------ **
|
|
* Return the IP address of an NBNS (WINS) server thought to be active.
|
|
*
|
|
* Input: none.
|
|
*
|
|
* Output: An IP address in struct in_addr form.
|
|
*
|
|
* Notes: This function will return the IP address of the first available
|
|
* NBNS (WINS) server. The order of the list is determined in
|
|
* smb.conf. If all of the WINS servers have been marked 'dead'
|
|
* then the zero IP (0.0.0.0) is returned. The zero IP is not a
|
|
* valid Unicast address on any system.
|
|
*
|
|
* ------------------------------------------------------------------------ **
|
|
*/
|
|
{
|
|
time_t now = time(NULL);
|
|
list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
|
|
|
|
while( NULL != entry )
|
|
{
|
|
if( now >= entry->mourning ) /* Found a live one. */
|
|
{
|
|
/* If we don't have the IP, look it up. */
|
|
if( is_zero_ip( entry->ip_addr ) )
|
|
entry->ip_addr = *interpret_addr2( entry->server );
|
|
|
|
/* If we still don't have the IP then kill it, else return it. */
|
|
if( is_zero_ip( entry->ip_addr ) )
|
|
entry->mourning = now + NECROMANCYCLE;
|
|
else
|
|
return( entry->ip_addr );
|
|
}
|
|
entry = (list_entry *)ubi_slNext( entry );
|
|
}
|
|
|
|
/* If there are no live entries, return the zero IP. */
|
|
return( *interpret_addr2( "0.0.0.0" ) );
|
|
} /* wins_srv_ip */
|
|
|
|
|
|
char *wins_srv_name( void )
|
|
/* ------------------------------------------------------------------------ **
|
|
* Return the name of first live WINS server in the list.
|
|
*
|
|
* Input: none.
|
|
*
|
|
* Output: A pointer to a string containing either the DNS name or IP
|
|
* address of the WINS server as given in the WINS SERVER
|
|
* parameter in smb.conf, or NULL if no (live) WINS servers are
|
|
* in the list.
|
|
*
|
|
* Notes: This function will return the name of the first available
|
|
* NBNS (WINS) server. The order of the list is determined in
|
|
* smb.conf. If all of the WINS servers have been marked 'dead'
|
|
* then NULL is returned.
|
|
*
|
|
* - This function does not verify that the name can be mapped to
|
|
* an IP address, or that the WINS server is running.
|
|
*
|
|
* ------------------------------------------------------------------------ **
|
|
*/
|
|
{
|
|
time_t now = time(NULL);
|
|
list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
|
|
|
|
while( NULL != entry )
|
|
{
|
|
if( now >= entry->mourning )
|
|
return( entry->server ); /* Found a live one. */
|
|
entry = (list_entry *)ubi_slNext( entry );
|
|
}
|
|
|
|
/* If there are no live entries, return NULL. */
|
|
return( NULL );
|
|
} /* wins_srv_name */
|
|
|
|
|
|
void wins_srv_died( struct in_addr boothill_ip )
|
|
/* ------------------------------------------------------------------------ **
|
|
* Called to indicate that a specific WINS server has died.
|
|
*
|
|
* Input: boothill_ip - IP address of an NBNS (WINS) server that has
|
|
* failed.
|
|
*
|
|
* Notes: This function marks the record 'dead' for NECROMANCYCLE
|
|
* seconds.
|
|
*
|
|
* ------------------------------------------------------------------------ **
|
|
*/
|
|
{
|
|
list_entry *entry;
|
|
|
|
if( is_zero_ip( boothill_ip ) )
|
|
{
|
|
DEBUG( 4, ("wins_srv_died(): Invalid request to mark zero IP down.\n") );
|
|
return;
|
|
}
|
|
|
|
entry = (list_entry *)ubi_slFirst( wins_srv_list );
|
|
while( NULL != entry )
|
|
{
|
|
/* Match based on IP. */
|
|
if( ip_equal( boothill_ip, entry->ip_addr ) )
|
|
{
|
|
entry->mourning = time(NULL) + NECROMANCYCLE;
|
|
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 ) );
|
|
return;
|
|
}
|
|
entry = (list_entry *)ubi_slNext( entry );
|
|
}
|
|
|
|
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" );
|
|
}
|
|
} /* wins_srv_died */
|
|
|
|
|
|
unsigned long wins_srv_count( void )
|
|
/* ------------------------------------------------------------------------ **
|
|
* Return the total number of entries in the list, dead or alive.
|
|
* ------------------------------------------------------------------------ **
|
|
*/
|
|
{
|
|
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 );
|
|
} /* wins_srv_count */
|
|
|
|
/* ========================================================================== */
|