summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2002-06-26 06:44:37 +0000
committerAndrew Tridgell <tridge@samba.org>2002-06-26 06:44:37 +0000
commit07f35f68e00b48ad6ec4d18c628d0bb57bad85ef (patch)
treec275131d8156d06f06c83421ffe30eb5056cc586
parent788c2c655baab3bf87cd984a8599b0829029f6c2 (diff)
downloadsamba-07f35f68e00b48ad6ec4d18c628d0bb57bad85ef.tar.gz
samba-07f35f68e00b48ad6ec4d18c628d0bb57bad85ef.tar.bz2
samba-07f35f68e00b48ad6ec4d18c628d0bb57bad85ef.zip
- completely rewrote the wins_srv.c code. It is now much simpler, and
gives us a good grounding to properly support multiple wins servers for different interfaces (which will be coming soon ...) - fixed our wins registration failover code to actually do failover! We were not trying to register with a secondary wins server at all when the primary was down. We now fallback correctly. - fixed the multi-homed name registration packets so that they work even in a non-connected network (ie. when one of our interfaces is not routable from the wins server. Yes, this really happens in the real world). (This used to be commit a049360d5b0d95a935b06aad43efc17d34de46dc)
-rw-r--r--source3/lib/wins_srv.c393
-rw-r--r--source3/libsmb/namequery.c6
-rw-r--r--source3/nmbd/nmbd_nameregister.c9
-rw-r--r--source3/nmbd/nmbd_namerelease.c11
-rw-r--r--source3/nmbd/nmbd_packets.c16
-rw-r--r--source3/param/loadparm.c22
6 files changed, 126 insertions, 331 deletions
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c
index 0181ee0956..cad0d06e49 100644
--- a/source3/lib/wins_srv.c
+++ b/source3/lib/wins_srv.c
@@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Andrew Tridgell 1992-2002
Copyright (C) Christopher R. Hertel 2000
This program is free software; you can redistribute it and/or modify
@@ -21,319 +21,106 @@
#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.
- */
+/* how long a server is marked dead for */
+#define DEATH_TIME 600
-#define NECROMANCYCLE 600 /* 600 seconds == 10 minutes. */
+/* a list of wins server that are marked dead. */
+static struct wins_dead {
+ struct in_addr ip;
+ time_t revival; /* when it will be revived */
+ struct wins_dead *next, *prev;
+} *dead_servers;
-/* -------------------------------------------------------------------------- **
- * 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;
+/*
+ see if an ip is on the dead list
+*/
+static int wins_is_dead(struct in_addr ip)
+{
+ struct wins_dead *d;
+ for (d=dead_servers; d; d=d->next) {
+ if (ip_equal(ip, d->ip)) {
+ /* it might be due for revival */
+ if (d->revival <= time(NULL)) {
+ DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip)));
+ DLIST_REMOVE(dead_servers, d);
+ free(d);
+ return 0;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
- if( is_zero_ip( boothill_ip ) )
- {
- DEBUG( 4, ("wins_srv_died(): Invalid request to mark zero IP down.\n") );
- return;
- }
+/*
+ mark a wins server as temporarily dead
+*/
+void wins_srv_died(struct in_addr ip)
+{
+ struct wins_dead *d;
- 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 (is_zero_ip(ip) || wins_is_dead(ip)) {
+ return;
+ }
- 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 */
+ d = (struct wins_dead *)malloc(sizeof(*d));
+ if (!d) return;
+ d->ip = ip;
+ d->revival = time(NULL) + DEATH_TIME;
-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 );
+ DEBUG(4,("Marking wins server %s dead for %u seconds\n", inet_ntoa(ip), DEATH_TIME));
- if( DEBUGLVL( 8 ) )
- {
- list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
- time_t now = time(NULL);
+ DLIST_ADD(dead_servers, d);
+}
- 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) );
+/*
+ return the total number of wins servers, dead or not
+*/
+unsigned long wins_srv_count(void)
+{
+ char **list;
+ int count = 0;
- entry = (list_entry *)ubi_slNext( entry );
- }
- }
+ list = lp_wins_server_list();
+ while (list && *list) {
+ count++;
+ list++;
+ }
- return( count );
- } /* wins_srv_count */
+ DEBUG(6,("Found %u wins servers in list\n", count));
+ return count;
+}
-/* ========================================================================== */
+/*
+ return the IP of the currently active wins server, or the zero IP otherwise
+*/
+struct in_addr wins_srv_ip(void)
+{
+ char **list;
+ struct in_addr ip;
+
+ list = lp_wins_server_list();
+ if (!list || !*list) {
+ zero_ip(&ip);
+ return ip;
+ }
+
+ /* find the first live one */
+ while (list && *list) {
+ ip = *interpret_addr2(*list);
+ if (!wins_is_dead(ip)) {
+ DEBUG(6,("Current wins server is %s\n", inet_ntoa(ip)));
+ return ip;
+ }
+ list++;
+ }
+
+ /* damn, they are all dead. Keep trying the primary until they revive */
+ list = lp_wins_server_list();
+ ip = *interpret_addr2(list[0]);
+
+ return ip;
+}
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index a97270b7d4..d709f997f5 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -603,10 +603,12 @@ BOOL name_register_wins(const char *name, int name_type)
if (0 == wins_srv_count())
return False;
+ sendto_ip = wins_srv_ip();
+
if( DEBUGLVL( 4 ) )
{
dbgtext( "name_register_wins: Registering my name %s ", name );
- dbgtext( "with WINS server %s.\n", wins_srv_name() );
+ dbgtext( "with WINS server %s.\n", inet_ntoa(sendto_ip));
}
sock = open_socket_in( SOCK_DGRAM, 0, 3,
@@ -616,8 +618,6 @@ BOOL name_register_wins(const char *name, int name_type)
set_socket_options(sock, "SO_BROADCAST"); /* ????! crh */
- sendto_ip = wins_srv_ip();
-
if (num_interfaces > 1) {
for (i = 0; i < num_interfaces; i++) {
diff --git a/source3/nmbd/nmbd_nameregister.c b/source3/nmbd/nmbd_nameregister.c
index cbc72fe2a9..cc1fac5577 100644
--- a/source3/nmbd/nmbd_nameregister.c
+++ b/source3/nmbd/nmbd_nameregister.c
@@ -197,6 +197,15 @@ static void register_name_timeout_response(struct subnet_record *subrec,
DEBUG(2,("register_name_timeout_response: WINS server at address %s is not \
responding.\n", inet_ntoa(rrec->packet->ip)));
+ /* mark it temporarily dead */
+ wins_srv_died(rrec->packet->ip);
+
+ /* and try the next wins server in our failover list */
+ rrec->packet->ip = wins_srv_ip();
+
+ /* also update the UNICODE subnet IPs */
+ subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
+
/* Keep trying to contact the WINS server periodically. This allows
us to work correctly if the WINS server is down temporarily when
we come up. */
diff --git a/source3/nmbd/nmbd_namerelease.c b/source3/nmbd/nmbd_namerelease.c
index fd35181f33..cefab44a08 100644
--- a/source3/nmbd/nmbd_namerelease.c
+++ b/source3/nmbd/nmbd_namerelease.c
@@ -147,9 +147,14 @@ static void release_name_timeout_response(struct subnet_record *subrec,
DEBUG(2,("release_name_timeout_response: WINS server at address %s is not \
responding.\n", inet_ntoa(rrec->packet->ip)));
- /* Keep trying to contact the WINS server periodically. This allows
- us to work correctly if the WINS server is down temporarily when
- we want to delete the name. */
+ /* mark it temporarily dead */
+ wins_srv_died(rrec->packet->ip);
+
+ /* and try the next wins server */
+ rrec->packet->ip = wins_srv_ip();
+
+ /* also update the UNICODE subnet IPs */
+ subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
/* Reset the number of attempts to zero and double the interval between
retries. Max out at 5 minutes. */
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index a11b30b1dc..b5741caae0 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -264,11 +264,19 @@ static BOOL create_and_init_additional_record(struct packet_struct *packet,
/* Set the address for the name we are registering. */
putip(&nmb->additional->rdata[2], register_ip);
- /* Ensure that we send out the file descriptor to give us the
- the specific source address we are registering as our
- IP source address. */
-
+#if 0
+ /* I removed this forced source IP as it breaks wins failover. The
+ problem is that our 2nd interface IP may not be routable to the
+ wins server, in which case all these nice packets we are senidng
+ out will never get a response and we end up marking a perfectly good wins server dead.
+
+ In general I can't see any reason why we should force the source
+ ip on a packet anyway. We should just let the kernels routin
+ table take care of it, as that is the only place which really
+ knows what is routable and what isn't. (tridge)
+ */
packet->fd = find_subnet_fd_for_address( *register_ip );
+#endif
return True;
}
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 4aa7d3b656..5051d67d34 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -121,7 +121,7 @@ typedef struct
char *szLogonPath;
char *szLogonDrive;
char *szLogonHome;
- char *szWINSserver;
+ char **szWINSservers;
char **szInterfaces;
char *szRemoteAnnounce;
char *szRemoteBrowseSync;
@@ -521,7 +521,6 @@ static BOOL handle_netbios_name(char *pszParmValue, char **ptr);
static BOOL handle_winbind_uid(char *pszParmValue, char **ptr);
static BOOL handle_winbind_gid(char *pszParmValue, char **ptr);
static BOOL handle_non_unix_account_range(char *pszParmValue, char **ptr);
-static BOOL handle_wins_server_list(char *pszParmValue, char **ptr);
static BOOL handle_debug_list( char *pszParmValue, char **ptr );
static BOOL handle_ldap_machine_suffix ( char *pszParmValue, char **ptr );
@@ -927,7 +926,7 @@ static struct parm_struct parm_table[] = {
{"dns proxy", P_BOOL, P_GLOBAL, &Globals.bDNSproxy, NULL, NULL, 0},
{"wins proxy", P_BOOL, P_GLOBAL, &Globals.bWINSproxy, NULL, NULL, 0},
- {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, handle_wins_server_list, NULL, FLAG_BASIC},
+ {"wins server", P_LIST, P_GLOBAL, &Globals.szWINSservers, NULL, NULL, FLAG_BASIC},
{"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC},
{"wins hook", P_STRING, P_GLOBAL, &Globals.szWINSHook, NULL, NULL, 0},
{"wins partners", P_STRING, P_GLOBAL, &Globals.szWINSPartners, NULL, NULL, 0},
@@ -1488,7 +1487,7 @@ FN_GLOBAL_CONST_STRING(lp_logon_drive, &Globals.szLogonDrive)
FN_GLOBAL_CONST_STRING(lp_logon_home, &Globals.szLogonHome)
FN_GLOBAL_STRING(lp_remote_announce, &Globals.szRemoteAnnounce)
FN_GLOBAL_STRING(lp_remote_browse_sync, &Globals.szRemoteBrowseSync)
-FN_GLOBAL_STRING(lp_wins_server_list, &Globals.szWINSserver)
+FN_GLOBAL_LIST(lp_wins_server_list, &Globals.szWINSservers)
FN_GLOBAL_LIST(lp_interfaces, &Globals.szInterfaces)
FN_GLOBAL_STRING(lp_socket_address, &Globals.szSocketAddress)
FN_GLOBAL_STRING(lp_nis_home_map_name, &Globals.szNISHomeMapName)
@@ -2614,19 +2613,6 @@ static BOOL handle_non_unix_account_range(char *pszParmValue, char **ptr)
}
/***************************************************************************
- Handle the WINS SERVER list
-***************************************************************************/
-static BOOL handle_wins_server_list( char *pszParmValue, char **ptr )
- {
- if( !wins_srv_load_list( pszParmValue ) )
- return( False ); /* Parse failed. */
-
- string_set( ptr, pszParmValue );
- return( True );
- }
-
-
-/***************************************************************************
Handle the DEBUG level list
***************************************************************************/
static BOOL handle_debug_list( char *pszParmValueIn, char **ptr )
@@ -3588,7 +3574,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults,
/* Now we check bWINSsupport and set szWINSserver to 127.0.0.1 */
/* if bWINSsupport is true and we are in the client */
if (in_client && Globals.bWINSsupport) {
- string_set(&Globals.szWINSserver, "127.0.0.1");
+ lp_do_parameter(-1, "wins server", "127.0.0.1");
}
init_iconv();