1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-31 17:18:04 +03:00
samba-mirror/source/lib/wins_srv.c
Christopher R. Hertel 73aa188320 Instead of handing back a string (which might be a DNS name or an IP
string), the wins_srv module now hands back a struct in_addr when it's
called.  It caches the IP address once it has been looked up.  The IP
is cleared (and must be looked up again) if the 'wins server' parameter
is reread, or if the node is marked 'dead'.  A dead node will not be
re-tried for 10 minutes (per a #define in wins_srv.c).

As it was, the code was reading the WINS server name or IP directly from
lp_wins_server.  That's okay, except that if the value was expressed as
a name, then a DNS lookup would be done every time the client wanted to
talk to the server.

I still need to work out the implications of failover regarding the
'unicast subnet' list.

Chris -)-----
0001-01-01 00:00:00 +00:00

271 lines
9.4 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 )) )
{
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. */
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;
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. */
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", count, (1==count)?"":"s" ) );
return( (count > 0) ? True : False );
} /* wins_srv_load_list */
struct in_addr wins_srv_ip( void )
/* ------------------------------------------------------------------------ **
*/
{
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( 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( 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 */
void wins_srv_died( struct in_addr boothill_ip )
/* ------------------------------------------------------------------------ **
* Called to indicate that a specific WINS server has died.
*/
{
list_entry *entry;
if( zero_ip( boothill_ip ) )
{
DEBUG( 4, ("wins_srv_died(): Got 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 */
/* ========================================================================== */