2 Unix SMB/CIFS implementation.
3 Samba utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Christopher R. Hertel 2000
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* -------------------------------------------------------------------------- **
27 * This module implements WINS failover.
29 * Microsoft's WINS servers provide a feature called WINS replication,
30 * which synchronises the WINS name databases between two or more servers.
31 * This means that the two servers can be used interchangably (more or
32 * less). WINS replication is particularly useful if you are trying to
33 * synchronise the WINS namespace between servers in remote locations, or
34 * if your WINS servers tend to crash a lot.
36 * WINS failover allows the client to 'switch' to a different WINS server
37 * if the current WINS server mysteriously disappears. On Windows
38 * systems, this is typically represented as 'primary' and 'secondary'
41 * Failover only works if the WINS servers are synced. If they are not,
43 * a) if the primary WINS server never fails the client will never 'see'
44 * the secondary (or tertiary or...) WINS server name space.
45 * b) if the primary *does* fail, the client will be entering an
46 * unfamiliar namespace. The client itself will not be registered in
47 * that namespace and any names which match names in the previous
48 * space will likely resolve to different host IP addresses.
50 * One key thing to remember regarding WINS failover is that Samba does
51 * not (yet) implement WINS replication. For those interested, sniff port
52 * 42 (TCP? UDP? ...dunno off hand) and see what two MS WINS servers do.
54 * At this stage, only failover is implemented. The next thing is to add
55 * support for multi-WINS server registration and query (multi-membership).
57 * Multi-membership is a little wierd. The idea is that the client can
58 * register itself with multiple non-replicated WINS servers, and query
59 * all of those servers (in a prescribed sequence) to resolve a name.
61 * The implications of multi-membership are not quite clear. Worth
62 * trying, I suppose. Changes will be needed in the name query and
63 * registration code to accomodate this feature. Also, there will need to
64 * be some sort of syntax extension for the 'wins server' parameter in
65 * smb.conf. I'm thinking that a colon could be used as a separator.
67 * Of course, for each WINS namespace there might be multiple, synced WINS
68 * servers. The change to this module would likely be the addition of a
69 * linked list of linked lists.
74 /* -------------------------------------------------------------------------- **
77 * NECROMANCYCLE - The dead server retry period, in seconds. When a WINS
78 * server is declared dead, wait this many seconds before
79 * attempting to communicate with it.
82 #define NECROMANCYCLE 600 /* 600 seconds == 10 minutes. */
84 /* -------------------------------------------------------------------------- **
90 ubi_slNode node
; /* Linked list node structure. */
91 time_t mourning
; /* If > current time then server is dead, Jim. */
92 char *server
; /* DNS name or IP of NBNS server to query. */
93 struct in_addr ip_addr
; /* Cache translated IP. */
96 /* -------------------------------------------------------------------------- **
97 * Private, static variables.
100 static ubi_slNewList( wins_srv_list
);
102 /* -------------------------------------------------------------------------- **
107 BOOL
wins_srv_load_list( char *src
)
108 /* ------------------------------------------------------------------------ **
109 * Create or recreate the linked list of failover WINS servers.
111 * Input: src - String of DNS names and/or IP addresses delimited by the
112 * characters listed in LIST_SEP (see include/local.h).
114 * Output: True if at least one name or IP could be parsed out of the
117 * Notes: There is no syntax checking done on the names or IPs. We do
118 * check to see if the field is an IP, in which case we copy it
119 * to the ip_addr field of the entry. Don't bother to to a host
120 * name lookup on all names now. They're done as needed in
122 * ------------------------------------------------------------------------ **
127 pstring wins_id_bufr
;
130 /* Empty the list. */
131 while( NULL
!= (entry
=(list_entry
*)ubi_slRemHead( wins_srv_list
)) )
133 SAFE_FREE( entry
->server
);
136 (void)ubi_slInitList( wins_srv_list
); /* shouldn't be needed */
138 /* Parse out the DNS names or IP addresses of the WINS servers. */
139 DEBUG( 4, ("wins_srv_load_list(): Building WINS server list:\n") );
140 while( next_token( &p
, wins_id_bufr
, LIST_SEP
, sizeof( wins_id_bufr
) ) )
142 entry
= (list_entry
*)malloc( sizeof( list_entry
) );
145 DEBUG( 0, ("wins_srv_load_list(): malloc(list_entry) failed.\n") );
150 /* Create a copy of the server name and store it in the list. */
151 if( NULL
== (entry
->server
= strdup( wins_id_bufr
)) )
155 ("wins_srv_load_list(): strdup(\"%s\") failed.\n", wins_id_bufr
) );
159 /* Add server to list.
160 * If the server name was actually an IP address we will store that
161 * too. It it was a DNS name, we will wait until we need to use
162 * the WINS server before doing the DNS lookup. Since this may be
163 * a list, and since we will reload the list whenever smb.conf is
164 * reloaded, there's no point in trying to look up names until we
165 * need them. ...of course, once we do the lookup we will cache
166 * the result. See wins_srv_ip().
168 if( is_ipaddress( wins_id_bufr
) )
169 entry
->ip_addr
= *interpret_addr2( wins_id_bufr
);
171 entry
->ip_addr
= *interpret_addr2( "0.0.0.0" );
172 (void)ubi_slAddTail( wins_srv_list
, entry
);
173 DEBUGADD( 4, ("%s,\n", wins_id_bufr
) );
178 count
= ubi_slCount( wins_srv_list
);
180 ( "%d WINS server%s listed.\n", (int)count
, (1==count
)?"":"s" ) );
182 return( (count
> 0) ? True
: False
);
183 } /* wins_srv_load_list */
186 struct in_addr
wins_srv_ip( void )
187 /* ------------------------------------------------------------------------ **
188 * Return the IP address of an NBNS (WINS) server thought to be active.
192 * Output: An IP address in struct in_addr form.
194 * Notes: This function will return the IP address of the first available
195 * NBNS (WINS) server. The order of the list is determined in
196 * smb.conf. If all of the WINS servers have been marked 'dead'
197 * then the zero IP (0.0.0.0) is returned. The zero IP is not a
198 * valid Unicast address on any system.
200 * ------------------------------------------------------------------------ **
203 time_t now
= time(NULL
);
204 list_entry
*entry
= (list_entry
*)ubi_slFirst( wins_srv_list
);
206 while( NULL
!= entry
)
208 if( now
>= entry
->mourning
) /* Found a live one. */
210 /* If we don't have the IP, look it up. */
211 if( is_zero_ip( entry
->ip_addr
) )
212 entry
->ip_addr
= *interpret_addr2( entry
->server
);
214 /* If we still don't have the IP then kill it, else return it. */
215 if( is_zero_ip( entry
->ip_addr
) )
216 entry
->mourning
= now
+ NECROMANCYCLE
;
218 return( entry
->ip_addr
);
220 entry
= (list_entry
*)ubi_slNext( entry
);
223 /* If there are no live entries, return the zero IP. */
224 return( *interpret_addr2( "0.0.0.0" ) );
228 char *wins_srv_name( void )
229 /* ------------------------------------------------------------------------ **
230 * Return the name of first live WINS server in the list.
234 * Output: A pointer to a string containing either the DNS name or IP
235 * address of the WINS server as given in the WINS SERVER
236 * parameter in smb.conf, or NULL if no (live) WINS servers are
239 * Notes: This function will return the name of the first available
240 * NBNS (WINS) server. The order of the list is determined in
241 * smb.conf. If all of the WINS servers have been marked 'dead'
242 * then NULL is returned.
244 * - This function does not verify that the name can be mapped to
245 * an IP address, or that the WINS server is running.
247 * ------------------------------------------------------------------------ **
250 time_t now
= time(NULL
);
251 list_entry
*entry
= (list_entry
*)ubi_slFirst( wins_srv_list
);
253 while( NULL
!= entry
)
255 if( now
>= entry
->mourning
)
256 return( entry
->server
); /* Found a live one. */
257 entry
= (list_entry
*)ubi_slNext( entry
);
260 /* If there are no live entries, return NULL. */
262 } /* wins_srv_name */
265 void wins_srv_died( struct in_addr boothill_ip
)
266 /* ------------------------------------------------------------------------ **
267 * Called to indicate that a specific WINS server has died.
269 * Input: boothill_ip - IP address of an NBNS (WINS) server that has
272 * Notes: This function marks the record 'dead' for NECROMANCYCLE
275 * ------------------------------------------------------------------------ **
280 if( is_zero_ip( boothill_ip
) )
282 DEBUG( 4, ("wins_srv_died(): Invalid request to mark zero IP down.\n") );
286 entry
= (list_entry
*)ubi_slFirst( wins_srv_list
);
287 while( NULL
!= entry
)
289 /* Match based on IP. */
290 if( ip_equal( boothill_ip
, entry
->ip_addr
) )
292 entry
->mourning
= time(NULL
) + NECROMANCYCLE
;
293 entry
->ip_addr
.s_addr
= 0; /* Force a re-lookup at re-birth. */
294 DEBUG( 2, ( "wins_srv_died(): WINS server %s appears to be down.\n",
298 entry
= (list_entry
*)ubi_slNext( entry
);
303 dbgtext( "wins_srv_died(): Could not mark WINS server %s down.\n",
304 inet_ntoa( boothill_ip
) );
305 dbgtext( "Address not found in server list.\n" );
307 } /* wins_srv_died */
310 unsigned long wins_srv_count( void )
311 /* ------------------------------------------------------------------------ **
312 * Return the total number of entries in the list, dead or alive.
313 * ------------------------------------------------------------------------ **
316 unsigned long count
= ubi_slCount( wins_srv_list
);
320 list_entry
*entry
= (list_entry
*)ubi_slFirst( wins_srv_list
);
321 time_t now
= time(NULL
);
323 dbgtext( "wins_srv_count: WINS status: %ld servers.\n", count
);
324 while( NULL
!= entry
)
326 dbgtext( " %s <%s>: ", entry
->server
, inet_ntoa( entry
->ip_addr
) );
327 if( now
>= entry
->mourning
)
328 dbgtext( "alive\n" );
330 dbgtext( "dead for %d more seconds\n", (int)(entry
->mourning
- now
) );
332 entry
= (list_entry
*)ubi_slNext( entry
);
337 } /* wins_srv_count */
339 /* ========================================================================== */