1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
|
/*
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( const 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;
const 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;
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( 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 )
/* ------------------------------------------------------------------------ **
*/
{
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 */
void wins_srv_died( struct in_addr boothill_ip )
/* ------------------------------------------------------------------------ **
* Called to indicate that a specific WINS server has died.
*/
{
list_entry *entry;
if( is_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 */
/* ========================================================================== */
|