diff options
author | Andrew Tridgell <tridge@samba.org> | 2002-06-26 06:44:37 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2002-06-26 06:44:37 +0000 |
commit | 07f35f68e00b48ad6ec4d18c628d0bb57bad85ef (patch) | |
tree | c275131d8156d06f06c83421ffe30eb5056cc586 /source3 | |
parent | 788c2c655baab3bf87cd984a8599b0829029f6c2 (diff) | |
download | samba-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)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/lib/wins_srv.c | 393 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 6 | ||||
-rw-r--r-- | source3/nmbd/nmbd_nameregister.c | 9 | ||||
-rw-r--r-- | source3/nmbd/nmbd_namerelease.c | 11 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 16 | ||||
-rw-r--r-- | source3/param/loadparm.c | 22 |
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(); |