From b35f21fb3a19417e2aab82a573ff121a086b224c Mon Sep 17 00:00:00 2001 From: "Christopher R. Hertel" Date: Wed, 19 Jul 2000 01:21:30 +0000 Subject: First cut toward adding WINS server failover. *Note: failover doesn't actually work yet!* It's just that the code I'm adding provides all of the pieces necessary. I do have one big question. Something that I'll have to ask Jeremy, I'm thinkin'. In nmbd/nmbd_subnetdb.c the IP of the WINS server is used to set up the Unicast subnet. ...so what happens if the WINS server changes? My guess is either: a) nothing. b) I'd have to change the unicast subnet entry whenever the WINS server changes. Urq. BTW, the lp_wins_server() function no longer returns the WINS server name or IP. It returns the list of WINS servers entered in smb.conf. To get the currently 'live' WINS server, use the wins_srv() function. Fun, eh? Chris -)----- (This used to be commit cc08bdc74f4cd111fdc582ee7babef47ed8a950d) --- source3/Makefile.in | 2 +- source3/include/proto.h | 17 ++-- source3/lib/wins_srv.c | 218 +++++++++++++++++++++++++++++++++++++++++++ source3/libsmb/namequery.c | 6 +- source3/nmbd/nmbd_subnetdb.c | 6 +- source3/nsswitch/wins.c | 2 +- source3/param/loadparm.c | 16 +++- 7 files changed, 250 insertions(+), 17 deletions(-) create mode 100644 source3/lib/wins_srv.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 07a6fbbe94..fa80957aac 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -103,7 +103,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/interfaces.o lib/pidfile.o lib/replace.o \ lib/signal.o lib/slprintf.o lib/system.o lib/doscalls.o lib/time.o \ lib/ufc.o lib/genrand.o lib/username.o lib/access.o lib/smbrun.o \ - lib/bitmap.o lib/crc32.o lib/snprintf.o \ + lib/bitmap.o lib/crc32.o lib/snprintf.o lib/wins_srv.o \ lib/util_array.o lib/util_str.o lib/util_sid.o \ lib/util_unistr.o lib/util_file.o \ lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \ diff --git a/source3/include/proto.h b/source3/include/proto.h index 2335b8f07d..1b7225d6b9 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -410,16 +410,6 @@ char **file_lines_pload(char *syscmd, int *numlines); void file_lines_free(char **lines); void file_lines_slashcont(char **lines); -/*The following definitions come from lib/util_list.c */ - -BOOL copy_policy_hnd (POLICY_HND *dest, const POLICY_HND *src); -BOOL compare_rpc_hnd_node(const RPC_HND_NODE *x, - const RPC_HND_NODE *y); -BOOL RpcHndList_set_connection(const POLICY_HND *hnd, - struct cli_connection *con); -BOOL RpcHndList_del_connection(const POLICY_HND *hnd); -struct cli_connection* RpcHndList_get_connection(const POLICY_HND *hnd); - /*The following definitions come from lib/util_seaccess.c */ BOOL se_access_check(SEC_DESC *sd, struct current_user *user, @@ -603,6 +593,13 @@ void split_at_last_component_w(smb_ucs2_t *path, smb_ucs2_t *front, smb_ucs2_t s smb_ucs2_t *octal_string_w(int i); smb_ucs2_t *string_truncate_w(smb_ucs2_t *s, size_t length); +/*The following definitions come from lib/wins_srv.c */ + +BOOL wins_srv_load_list( char *src ); +char *wins_srv( void ); +void wins_srv_died( char *boothill ); +unsigned long wins_srv_count( void ); + /*The following definitions come from libsmb/cliconnect.c */ BOOL cli_session_setup(struct cli_state *cli, diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c new file mode 100644 index 0000000000..e84ac342f5 --- /dev/null +++ b/source3/lib/wins_srv.c @@ -0,0 +1,218 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1998 + + 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 greater than current time server is dead, Jim. */ + char *server; /* DNS name or IP of NBNS server to query. */ + } 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. + */ + { + 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: 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. */ + (void)ubi_slAddTail( wins_srv_list, entry ); + DEBUGADD( 4, ("\t\t%s,\n", wins_id_bufr) ); + } + } + } + + count = ubi_slCount( wins_srv_list ); + DEBUGADD( 4, ( "\t\t%d WINS server%s listed.\n", count, (1==count)?"":"s" ) ); + + return( (count > 0) ? True : False ); + } /* wins_srv_load_list */ + + +char *wins_srv( void ) + /* ------------------------------------------------------------------------ ** + */ + { + time_t now = time(NULL); + list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list ); + list_entry *coldest = entry; + + /* Go through the list. Look for the first live entry. */ + while( (NULL != entry) && (now < entry->mourning) ) + { + entry = (list_entry *)ubi_slNext( entry ); + if( entry->mourning < coldest->mourning ) + coldest = entry; + } + + /* If they were all dead, then return the one that's been dead longest. */ + if( NULL == entry ) + { + entry = coldest; + DEBUG( 4, ("wins_srv: All WINS servers appear to have failed.\n") ); + } + + /* The list could be empty. Check it. */ + if( NULL == entry ) + return( NULL ); + return( entry->server ); + } /* wins_srv */ + + +void wins_srv_died( char *boothill ) + /* ------------------------------------------------------------------------ ** + * Called to indicate that a specific WINS server has died. + */ + { + list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list ); + + while( NULL != entry ) + { + /* Match based on server ID [DNS name or IP]. */ + if( 0 == strcmp( boothill, entry->server ) ) + { + entry->mourning = time(NULL) + NECROMANCYCLE; + DEBUG( 2, ("wins_srv: WINS server %s appears to be down.\n", boothill) ); + return; + } + entry = (list_entry *)ubi_slNext( entry ); + } + } /* wins_srv_died */ + + +unsigned long wins_srv_count( void ) + /* ------------------------------------------------------------------------ ** + * Return the total number of entries in the list, dead or alive. + */ + { + return( ubi_slCount( wins_srv_list ) ); + } /* wins_srv_count */ + +/* ========================================================================== */ diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 193731768f..0237a9752f 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -529,12 +529,12 @@ static BOOL resolve_wins(const char *name, int name_type, DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type)); - if(!*lp_wins_server()) { - DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS server present.\n")); + if( wins_srv_count() < 1 ) { + DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n")); return False; } - wins_ip = *interpret_addr2(lp_wins_server()); + wins_ip = *interpret_addr2( wins_srv() ); wins_ismyip = ismyip(wins_ip); DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) ); diff --git a/source3/nmbd/nmbd_subnetdb.c b/source3/nmbd/nmbd_subnetdb.c index 330be4057f..57f937148e 100644 --- a/source3/nmbd/nmbd_subnetdb.c +++ b/source3/nmbd/nmbd_subnetdb.c @@ -271,12 +271,16 @@ BOOL create_subnets(void) * get the ip address of it here. If we are the WINS server then * set the unicast subnet address to be the first of our own real * addresses. + * + * NOTE: I'm not sure of the implications of WINS server failover + * on this bit of code. Because of failover, the WINS + * server address can change. */ if(*lp_wins_server()) { struct in_addr real_wins_ip; - real_wins_ip = *interpret_addr2(lp_wins_server()); + real_wins_ip = *interpret_addr2( wins_srv() ); if (!zero_ip(real_wins_ip)) { diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c index f8a05a9fbf..41b71c64bb 100644 --- a/source3/nsswitch/wins.c +++ b/source3/nsswitch/wins.c @@ -56,7 +56,7 @@ struct in_addr *lookup_backend(const char *name, int *count) set_socket_options(fd,"SO_BROADCAST"); - p = lp_wins_server(); + p = wins_srv(); if (p && *p) { ret = name_query(fd,name,0x20,False,True, *interpret_addr2(p), count); goto out; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 3650d4edd3..61e38bea60 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -509,6 +509,7 @@ static BOOL handle_vfs_object(char *pszParmValue, char **ptr); static BOOL handle_source_env(char *pszParmValue, char **ptr); static BOOL handle_netbios_name(char *pszParmValue, char **ptr); static BOOL handle_winbind_id(char *pszParmValue, char **ptr); +static BOOL handle_wins_server_list(char *pszParmValue, char **ptr); static void set_server_role(void); static void set_default_server_announce_type(void); @@ -863,7 +864,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, NULL, NULL, FLAG_BASIC}, + {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, handle_wins_server_list, 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}, @@ -2372,6 +2373,19 @@ static BOOL handle_winbind_id(char *pszParmValue, char **ptr) return True; } +/*************************************************************************** + 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 ); + } + + /*************************************************************************** initialise a copymap ***************************************************************************/ -- cgit