diff options
-rw-r--r-- | source3/lib/interface.c | 8 | ||||
-rw-r--r-- | source3/lib/wins_srv.c | 104 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 16 | ||||
-rw-r--r-- | source3/nmbd/nmbd.c | 13 | ||||
-rw-r--r-- | source3/nmbd/nmbd_incomingrequests.c | 316 | ||||
-rw-r--r-- | source3/nmbd/nmbd_mynames.c | 93 | ||||
-rw-r--r-- | source3/nmbd/nmbd_namelistdb.c | 2 | ||||
-rw-r--r-- | source3/nmbd/nmbd_nameregister.c | 539 | ||||
-rw-r--r-- | source3/nmbd/nmbd_namerelease.c | 366 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 232 | ||||
-rw-r--r-- | source3/nmbd/nmbd_responserecordsdb.c | 12 | ||||
-rw-r--r-- | source3/nmbd/nmbd_subnetdb.c | 58 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_wins.c | 2 |
13 files changed, 867 insertions, 894 deletions
diff --git a/source3/lib/interface.c b/source3/lib/interface.c index 672a7621e6..85c49789c4 100644 --- a/source3/lib/interface.c +++ b/source3/lib/interface.c @@ -276,14 +276,6 @@ int iface_count(void) } /**************************************************************************** - True if we have two or more interfaces. - **************************************************************************/ -BOOL we_are_multihomed(void) -{ - return (iface_count() > 1 ? True : False); -} - -/**************************************************************************** return the Nth interface **************************************************************************/ struct interface *get_interface(int n) diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c index 95b25b96b2..27b5adf6b5 100644 --- a/source3/lib/wins_srv.c +++ b/source3/lib/wins_srv.c @@ -60,13 +60,19 @@ /* how long a server is marked dead for */ #define DEATH_TIME 600 -/* a list of wins server that are marked dead. */ +/* a list of wins server that are marked dead from the point of view + of a given source address. We keep a separate dead list for each src address + to cope with multiple interfaces that are not routable to each other + */ static struct wins_dead { - struct in_addr ip; + struct in_addr dest_ip; + struct in_addr src_ip; time_t revival; /* when it will be revived */ struct wins_dead *next, *prev; } *dead_servers; +extern BOOL global_in_nmbd; + /* an internal convenience structure for an IP with a short string tag attached */ @@ -78,14 +84,17 @@ struct tagged_ip { /* see if an ip is on the dead list */ -BOOL wins_srv_is_dead(struct in_addr ip) +BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip) { struct wins_dead *d; for (d=dead_servers; d; d=d->next) { - if (ip_equal(ip, d->ip)) { + if (ip_equal(wins_ip, d->dest_ip) && ip_equal(src_ip, d->src_ip)) { /* it might be due for revival */ if (d->revival <= time(NULL)) { - DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip))); + fstring src_name; + fstrcpy(src_name, inet_ntoa(src_ip)); + DEBUG(4,("Reviving wins server %s for source %s\n", + inet_ntoa(wins_ip), src_name)); DLIST_REMOVE(dead_servers, d); free(d); return False; @@ -96,24 +105,49 @@ BOOL wins_srv_is_dead(struct in_addr ip) return False; } + +/* + mark a wins server as being alive (for the moment) +*/ +void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip) +{ + struct wins_dead *d; + for (d=dead_servers; d; d=d->next) { + if (ip_equal(wins_ip, d->dest_ip) && ip_equal(src_ip, d->src_ip)) { + fstring src_name; + fstrcpy(src_name, inet_ntoa(src_ip)); + DEBUG(4,("Reviving wins server %s for source %s\n", + inet_ntoa(wins_ip), src_name)); + DLIST_REMOVE(dead_servers, d); + return; + } + } +} + + /* mark a wins server as temporarily dead */ -void wins_srv_died(struct in_addr ip) +void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip) { struct wins_dead *d; + fstring src_name; - if (is_zero_ip(ip) || wins_srv_is_dead(ip)) { + if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip)) { return; } d = (struct wins_dead *)malloc(sizeof(*d)); if (!d) return; - d->ip = ip; + d->dest_ip = wins_ip; + d->src_ip = src_ip; d->revival = time(NULL) + DEATH_TIME; - DEBUG(4,("Marking wins server %s dead for %u seconds\n", inet_ntoa(ip), DEATH_TIME)); + fstrcpy(src_name, inet_ntoa(src_ip)); + + DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n", + inet_ntoa(wins_ip), DEATH_TIME, src_name)); DLIST_ADD(dead_servers, d); } @@ -127,6 +161,8 @@ unsigned wins_srv_count(void) int count = 0; if (lp_wins_support()) { + if (global_in_nmbd) return 0; + /* simple - just talk to ourselves */ return 1; } @@ -134,7 +170,6 @@ unsigned wins_srv_count(void) list = lp_wins_server_list(); for (count=0; list && list[count]; count++) /* nop */ ; - DEBUG(6,("Found %u wins servers in list\n", count)); return count; } @@ -160,42 +195,6 @@ static void parse_ip(struct tagged_ip *ip, const char *str) } -/* - return the IP of the currently active wins server, or the zero IP otherwise -*/ -struct in_addr wins_srv_ip(void) -{ - char **list; - int i; - struct tagged_ip t_ip; - - /* if we are a wins server then we always just talk to ourselves */ - if (lp_wins_support()) { - extern struct in_addr loopback_ip; - return loopback_ip; - } - - list = lp_wins_server_list(); - if (!list || !list[0]) { - zero_ip(&t_ip.ip); - return t_ip.ip; - } - - /* find the first live one */ - for (i=0; list[i]; i++) { - parse_ip(&t_ip, list[i]); - if (!wins_srv_is_dead(t_ip.ip)) { - DEBUG(6,("Current wins server is %s\n", inet_ntoa(t_ip.ip))); - return t_ip.ip; - } - } - - /* damn, they are all dead. Keep trying the primary until they revive */ - parse_ip(&t_ip, list[0]); - - return t_ip.ip; -} - /* return the list of wins server tags. A 'tag' is used to distinguish @@ -211,6 +210,7 @@ char **wins_srv_tags(void) char **list; if (lp_wins_support()) { + if (global_in_nmbd) return NULL; /* give the caller something to chew on. This makes the rest of the logic simpler (ie. less special cases) */ ret = (char **)malloc(sizeof(char *)*2); @@ -272,7 +272,7 @@ void wins_srv_tags_free(char **list) return the IP of the currently active wins server for the given tag, or the zero IP otherwise */ -struct in_addr wins_srv_ip_tag(const char *tag) +struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip) { char **list; int i; @@ -298,8 +298,13 @@ struct in_addr wins_srv_ip_tag(const char *tag) /* not for the right tag. Move along */ continue; } - if (!wins_srv_is_dead(t_ip.ip)) { - DEBUG(6,("Current wins server for tag '%s' is %s\n", tag, inet_ntoa(t_ip.ip))); + if (!wins_srv_is_dead(t_ip.ip, src_ip)) { + fstring src_name; + fstrcpy(src_name, inet_ntoa(src_ip)); + DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n", + tag, + src_name, + inet_ntoa(t_ip.ip))); return t_ip.ip; } } @@ -330,6 +335,7 @@ unsigned wins_srv_count_tag(const char *tag) /* if we are a wins server then we always just talk to ourselves */ if (lp_wins_support()) { + if (global_in_nmbd) return 0; return 1; } diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 7cd7d70815..2c6fb2fd71 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -637,12 +637,12 @@ BOOL name_resolve_bcast(const char *name, int name_type, /******************************************************** Resolve via "wins" method. *********************************************************/ - BOOL resolve_wins(const char *name, int name_type, struct in_addr **return_iplist, int *return_count) { int sock, t, i; char **wins_tags; + struct in_addr src_ip; *return_iplist = NULL; *return_count = 0; @@ -662,15 +662,19 @@ BOOL resolve_wins(const char *name, int name_type, return False; } + /* the address we will be sending from */ + src_ip = *interpret_addr2(lp_socket_address()); + /* in the worst case we will try every wins server with every tag! */ for (t=0; wins_tags && wins_tags[t]; t++) { - for (i=0; i<wins_srv_count_tag(wins_tags[t]); i++) { + int srv_count = wins_srv_count_tag(wins_tags[t]); + for (i=0; i<srv_count; i++) { struct in_addr wins_ip; int flags; BOOL timed_out; - wins_ip = wins_srv_ip_tag(wins_tags[t]); + wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip); if (global_in_nmbd && ismyip(wins_ip)) { /* yikes! we'll loop forever */ @@ -678,13 +682,13 @@ BOOL resolve_wins(const char *name, int name_type, } /* skip any that have been unresponsive lately */ - if (wins_srv_is_dead(wins_ip)) { + if (wins_srv_is_dead(wins_ip, src_ip)) { continue; } DEBUG(3,("resolve_wins: using WINS server %s and tag '%s'\n", inet_ntoa(wins_ip), wins_tags[t])); - sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True); + sock = open_socket_in(SOCK_DGRAM, 0, 3, src_ip.s_addr, True); if (sock == -1) { continue; } @@ -699,7 +703,7 @@ BOOL resolve_wins(const char *name, int name_type, if (timed_out) { /* Timed out wating for WINS server to respond. Mark it dead. */ - wins_srv_died(wins_ip); + wins_srv_died(wins_ip, src_ip); } else { /* The name definately isn't in this group of WINS servers. goto the next group */ diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index f698b396b2..06d6bc3bb3 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/nmbd/nmbd.c @@ -53,8 +53,8 @@ static void terminate(void) /* Write out wins.dat file if samba is a WINS server */ wins_write_database(False); - /* Remove all SELF registered names. */ - release_my_names(); + /* Remove all SELF registered names from WINS */ + release_wins_names(); /* Announce all server entries as 0 time-to-live, 0 type. */ announce_my_servers_removed(); @@ -293,15 +293,6 @@ static BOOL reload_nmbd_services(BOOL test) reload_nmbd_services( True ); } - /* Do a sanity check for a misconfigured nmbd */ - if( lp_wins_support() && wins_srv_count() ) { - if( DEBUGLVL(0) ) { - dbgtext( "ERROR: 'wins support = true' and 'wins server = <server>'\n" ); - dbgtext( "are conflicting settings. nmbd aborting.\n" ); - } - exit(10); - } - return(ret); } diff --git a/source3/nmbd/nmbd_incomingrequests.c b/source3/nmbd/nmbd_incomingrequests.c index 3f2b921074..834f237a2c 100644 --- a/source3/nmbd/nmbd_incomingrequests.c +++ b/source3/nmbd/nmbd_incomingrequests.c @@ -449,175 +449,151 @@ For broadcast name queries: void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p) { - struct nmb_packet *nmb = &p->packet.nmb; - struct nmb_name *question = &nmb->question.question_name; - int name_type = question->name_type; - BOOL bcast = nmb->header.nm_flags.bcast; - int ttl=0; - int rcode = 0; - char *prdata = NULL; - char rdata[6]; - BOOL success = False; - struct name_record *namerec = NULL; - int reply_data_len = 0; - int i; - - DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n", - inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question))); + struct nmb_packet *nmb = &p->packet.nmb; + struct nmb_name *question = &nmb->question.question_name; + int name_type = question->name_type; + BOOL bcast = nmb->header.nm_flags.bcast; + int ttl=0; + int rcode = 0; + char *prdata = NULL; + char rdata[6]; + BOOL success = False; + struct name_record *namerec = NULL; + int reply_data_len = 0; + int i; + + DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n", + inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question))); - /* Look up the name in the cache - if the request is a broadcast request that - came from a subnet we don't know about then search all the broadcast subnets - for a match (as we don't know what interface the request came in on). */ - - if(subrec == remote_broadcast_subnet) - namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME); - else - namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME); - - - /* Check if it is a name that expired */ - if( namerec - && ( (namerec->data.death_time != PERMANENT_TTL) - && (namerec->data.death_time < p->timestamp) ) ) - { - DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name))); - namerec = NULL; - } - - if (namerec) - { - - /* - * Always respond to unicast queries. - * Don't respond to broadcast queries unless the query is for - * a name we own, a Primary Domain Controller name, or a WINS_PROXY - * name with type 0 or 0x20. WINS_PROXY names are only ever added - * into the namelist if we were configured as a WINS proxy. - */ - - if( !bcast - || ( bcast - && ( (name_type == 0x1b) - || (namerec->data.source == SELF_NAME) - || (namerec->data.source == PERMANENT_NAME) - || ( (namerec->data.source == WINS_PROXY_NAME) - && ( (name_type == 0) || (name_type == 0x20) ) - ) - ) - ) - ) - { - - /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY, - or it's a Domain Master type. */ - - /* - * If this is a WINS_PROXY_NAME, then ceck that none of the IP - * addresses we are returning is on the same broadcast subnet - * as the requesting packet. If it is then don't reply as the - * actual machine will be replying also and we don't want two - * replies to a broadcast query. - */ - - if( namerec->data.source == WINS_PROXY_NAME ) - { - for( i = 0; i < namerec->data.num_ips; i++) - { - if(same_net( namerec->data.ip[i], subrec->myip, subrec->mask_ip )) - { - DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also \ -on the same subnet (%s) as the requestor. Not replying.\n", - nmb_namestr(&namerec->name), subrec->subnet_name )); - return; - } - } - } - - ttl = (namerec->data.death_time != PERMANENT_TTL) ? - namerec->data.death_time - p->timestamp : lp_max_ttl(); - - /* Copy all known ip addresses into the return data. */ - /* Optimise for the common case of one IP address so - we don't need a malloc. */ - - if( namerec->data.num_ips == 1 ) - prdata = rdata; - else - { - if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL) - { - DEBUG(0,("process_name_query_request: malloc fail !\n")); - return; - } - } - - for( i = 0; i < namerec->data.num_ips; i++ ) - { - set_nb_flags(&prdata[i*6],namerec->data.nb_flags); - putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]); - } - - sort_query_replies(prdata, i, p->ip); - - reply_data_len = namerec->data.num_ips * 6; - success = True; - } - } - - /* - * If a machine is broadcasting a name lookup request and we have lp_wins_proxy() - * set we should initiate a WINS query here. On success we add the resolved name - * into our namelist with a type of WINS_PROXY_NAME and then reply to the query. - */ - - if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() && - bcast && (subrec != remote_broadcast_subnet)) - { - make_wins_proxy_name_query_request( subrec, p, question ); - return; - } - - if (!success && bcast) - { - if(prdata != rdata) - SAFE_FREE(prdata); - return; /* Never reply with a negative response to broadcasts. */ - } - - /* - * Final check. From observation, if a unicast packet is sent - * to a non-WINS server with the recursion desired bit set - * then never send a negative response. - */ - - if(!success && !bcast && nmb->header.nm_flags.recursion_desired) - { - if(prdata != rdata) - SAFE_FREE(prdata); - return; - } - - if (success) - { - rcode = 0; - DEBUG(3,("OK\n")); - } - else - { - rcode = NAM_ERR; - DEBUG(3,("UNKNOWN\n")); - } - - /* See rfc1002.txt 4.2.13. */ - - reply_netbios_packet(p, /* Packet to reply to. */ - rcode, /* Result code. */ - NMB_QUERY, /* nmbd type code. */ - NMB_NAME_QUERY_OPCODE, /* opcode. */ - ttl, /* ttl. */ - prdata, /* data to send. */ - reply_data_len); /* data length. */ - - if(prdata != rdata) - SAFE_FREE(prdata); + /* Look up the name in the cache - if the request is a broadcast request that + came from a subnet we don't know about then search all the broadcast subnets + for a match (as we don't know what interface the request came in on). */ + + if(subrec == remote_broadcast_subnet) + namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME); + else + namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME); + + /* Check if it is a name that expired */ + if (namerec && + ((namerec->data.death_time != PERMANENT_TTL) && + (namerec->data.death_time < p->timestamp))) { + DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name))); + namerec = NULL; + } + + if (namerec) { + /* + * Always respond to unicast queries. + * Don't respond to broadcast queries unless the query is for + * a name we own, a Primary Domain Controller name, or a WINS_PROXY + * name with type 0 or 0x20. WINS_PROXY names are only ever added + * into the namelist if we were configured as a WINS proxy. + */ + + if (!bcast || + (bcast && ((name_type == 0x1b) || + (namerec->data.source == SELF_NAME) || + (namerec->data.source == PERMANENT_NAME) || + ((namerec->data.source == WINS_PROXY_NAME) && + ((name_type == 0) || (name_type == 0x20)))))) { + /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY, + or it's a Domain Master type. */ + + /* + * If this is a WINS_PROXY_NAME, then ceck that none of the IP + * addresses we are returning is on the same broadcast subnet + * as the requesting packet. If it is then don't reply as the + * actual machine will be replying also and we don't want two + * replies to a broadcast query. + */ + + if (namerec->data.source == WINS_PROXY_NAME) { + for( i = 0; i < namerec->data.num_ips; i++) { + if (same_net(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) { + DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying.\n", + nmb_namestr(&namerec->name), subrec->subnet_name )); + return; + } + } + } + + ttl = (namerec->data.death_time != PERMANENT_TTL) ? + namerec->data.death_time - p->timestamp : lp_max_ttl(); + + /* Copy all known ip addresses into the return data. */ + /* Optimise for the common case of one IP address so + we don't need a malloc. */ + + if (namerec->data.num_ips == 1) { + prdata = rdata; + } else { + if ((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL) { + DEBUG(0,("process_name_query_request: malloc fail !\n")); + return; + } + } + + for (i = 0; i < namerec->data.num_ips; i++) { + set_nb_flags(&prdata[i*6],namerec->data.nb_flags); + putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]); + } + + sort_query_replies(prdata, i, p->ip); + + reply_data_len = namerec->data.num_ips * 6; + success = True; + } + } + + /* + * If a machine is broadcasting a name lookup request and we have lp_wins_proxy() + * set we should initiate a WINS query here. On success we add the resolved name + * into our namelist with a type of WINS_PROXY_NAME and then reply to the query. + */ + + if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() && + bcast && (subrec != remote_broadcast_subnet)) { + make_wins_proxy_name_query_request( subrec, p, question ); + return; + } + + if (!success && bcast) { + if(prdata != rdata) + SAFE_FREE(prdata); + return; /* Never reply with a negative response to broadcasts. */ + } + + /* + * Final check. From observation, if a unicast packet is sent + * to a non-WINS server with the recursion desired bit set + * then never send a negative response. + */ + + if(!success && !bcast && nmb->header.nm_flags.recursion_desired) { + if(prdata != rdata) + SAFE_FREE(prdata); + return; + } + + if (success) { + rcode = 0; + DEBUG(3,("OK\n")); + } else { + rcode = NAM_ERR; + DEBUG(3,("UNKNOWN\n")); + } + + /* See rfc1002.txt 4.2.13. */ + + reply_netbios_packet(p, /* Packet to reply to. */ + rcode, /* Result code. */ + NMB_QUERY, /* nmbd type code. */ + NMB_NAME_QUERY_OPCODE, /* opcode. */ + ttl, /* ttl. */ + prdata, /* data to send. */ + reply_data_len); /* data length. */ + + if(prdata != rdata) + SAFE_FREE(prdata); } diff --git a/source3/nmbd/nmbd_mynames.c b/source3/nmbd/nmbd_mynames.c index aac188db2b..345245c57d 100644 --- a/source3/nmbd/nmbd_mynames.c +++ b/source3/nmbd/nmbd_mynames.c @@ -184,67 +184,48 @@ BOOL register_my_workgroup_and_names(void) /**************************************************************************** Remove all the names we registered. **************************************************************************/ - -void release_my_names(void) +void release_wins_names(void) { -#if 0 /*JRR: do WINS server only, otherwise clients ignore us when we come back up*/ - struct subnet_record *subrec; - - for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) -#else - struct subnet_record *subrec = unicast_subnet; -#endif - { - struct name_record *namerec, *nextnamerec; - - for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); - namerec; - namerec = nextnamerec) - { - nextnamerec = (struct name_record *)ubi_trNext( namerec ); - if( (namerec->data.source == SELF_NAME) - && !NAME_IS_DEREGISTERING(namerec) ) - release_name( subrec, namerec, standard_success_release, - NULL, NULL); - } - } + struct subnet_record *subrec = unicast_subnet; + struct name_record *namerec, *nextnamerec; + + for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); + namerec; + namerec = nextnamerec) { + nextnamerec = (struct name_record *)ubi_trNext( namerec ); + if( (namerec->data.source == SELF_NAME) + && !NAME_IS_DEREGISTERING(namerec) ) + release_name( subrec, namerec, standard_success_release, + NULL, NULL); + } } /******************************************************************* - Refresh our registered names. + Refresh our registered names with WINS ******************************************************************/ - void refresh_my_names(time_t t) { - struct subnet_record *subrec; - - for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) - { - struct name_record *namerec; - - /* B nodes don't send out name refresh requests, see RFC 1001, 15.5.1 */ - if (subrec != unicast_subnet) - continue; - - for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); - namerec; - namerec = (struct name_record *)ubi_trNext( namerec ) ) - { - /* Each SELF name has an individual time to be refreshed. */ - if( (namerec->data.source == SELF_NAME) - && (namerec->data.refresh_time < t) - && ( namerec->data.death_time != PERMANENT_TTL) ) - { - /* We cheat here and pretend the refresh is going to be - successful & update the refresh times. This stops - multiple refresh calls being done. We actually - deal with refresh failure in the fail_fn. - */ - if( !is_refresh_already_queued( subrec, namerec) ) - refresh_name( subrec, namerec, NULL, NULL, NULL ); - namerec->data.death_time = t + lp_max_ttl(); - namerec->data.refresh_time = t + MIN(lp_max_ttl(), MAX_REFRESH_TIME); - } - } - } + struct name_record *namerec; + + if (wins_srv_count() < 1) return; + + for (namerec = (struct name_record *)ubi_trFirst(unicast_subnet->namelist); + namerec; + namerec = (struct name_record *)ubi_trNext(namerec)) { + /* Each SELF name has an individual time to be refreshed. */ + if ((namerec->data.source == SELF_NAME) && + (namerec->data.refresh_time < t) && + (namerec->data.death_time != PERMANENT_TTL)) { + /* We cheat here and pretend the refresh is going to be + successful & update the refresh times. This stops + multiple refresh calls being done. We actually + deal with refresh failure in the fail_fn. + */ + if (!is_refresh_already_queued(unicast_subnet, namerec)) { + wins_refresh_name(namerec); + } + namerec->data.death_time = t + lp_max_ttl(); + namerec->data.refresh_time = t + MIN(lp_max_ttl(), MAX_REFRESH_TIME); + } + } } diff --git a/source3/nmbd/nmbd_namelistdb.c b/source3/nmbd/nmbd_namelistdb.c index 68b44d618f..bca79ef0c8 100644 --- a/source3/nmbd/nmbd_namelistdb.c +++ b/source3/nmbd/nmbd_namelistdb.c @@ -35,7 +35,7 @@ uint16 samba_nb_type = 0; /* samba's NetBIOS name type */ void set_samba_nb_type(void) { if( lp_wins_support() || wins_srv_count() ) - samba_nb_type = NB_MFLAG; /* samba is a 'hybrid' node type. */ + samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */ else samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */ } /* set_samba_nb_type */ diff --git a/source3/nmbd/nmbd_nameregister.c b/source3/nmbd/nmbd_nameregister.c index 91b6f8b190..4ac5473d4a 100644 --- a/source3/nmbd/nmbd_nameregister.c +++ b/source3/nmbd/nmbd_nameregister.c @@ -25,6 +25,10 @@ extern fstring global_myworkgroup; +/* forward declarations */ +static void wins_next_registration(struct response_record *rrec); + + /**************************************************************************** Deal with a response packet when registering one of our names. ****************************************************************************/ @@ -32,127 +36,131 @@ extern fstring global_myworkgroup; static void register_name_response(struct subnet_record *subrec, struct response_record *rrec, struct packet_struct *p) { - /* - * If we are registering broadcast, then getting a response is an - * error - we do not have the name. If we are registering unicast, - * then we expect to get a response. - */ - - struct nmb_packet *nmb = &p->packet.nmb; - BOOL bcast = nmb->header.nm_flags.bcast; - BOOL success = True; - struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; - struct nmb_name *answer_name = &nmb->answers->rr_name; - int ttl = 0; - uint16 nb_flags = 0; - struct in_addr registered_ip; - - /* Sanity check. Ensure that the answer name in the incoming packet is the - same as the requested name in the outgoing packet. */ - - if(!question_name || !answer_name) - { - DEBUG(0,("register_name_response: malformed response (%s is NULL).\n", - question_name ? "question_name" : "answer_name" )); - return; - } - - if(!nmb_name_equal(question_name, answer_name)) - { - DEBUG(0,("register_name_response: Answer name %s differs from question \ -name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name))); - return; - } - - if(bcast) - { - /* - * Special hack to cope with old Samba nmbd's. - * Earlier versions of Samba (up to 1.9.16p11) respond - * to a broadcast name registration of WORKGROUP<1b> when - * they should not. Hence, until these versions are gone, - * we should treat such errors as success for this particular - * case only. jallison@whistle.com. - */ + /* + * If we are registering broadcast, then getting a response is an + * error - we do not have the name. If we are registering unicast, + * then we expect to get a response. + */ + + struct nmb_packet *nmb = &p->packet.nmb; + BOOL bcast = nmb->header.nm_flags.bcast; + BOOL success = True; + struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; + struct nmb_name *answer_name = &nmb->answers->rr_name; + struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; + int ttl = 0; + uint16 nb_flags = 0; + struct in_addr register_ip; + fstring reg_name; + + putip(®ister_ip,&sent_nmb->additional->rdata[2]); + fstrcpy(reg_name, inet_ntoa(register_ip)); + + if (subrec == unicast_subnet) { + /* we know that this wins server is definately alive - for the moment! */ + wins_srv_alive(rrec->packet->ip, register_ip); + } + + /* Sanity check. Ensure that the answer name in the incoming packet is the + same as the requested name in the outgoing packet. */ + + if(!question_name || !answer_name) { + DEBUG(0,("register_name_response: malformed response (%s is NULL).\n", + question_name ? "question_name" : "answer_name" )); + return; + } + + if(!nmb_name_equal(question_name, answer_name)) { + DEBUG(0,("register_name_response: Answer name %s differs from question name %s.\n", + nmb_namestr(answer_name), nmb_namestr(question_name))); + return; + } + if(bcast) { + /* + * Special hack to cope with old Samba nmbd's. + * Earlier versions of Samba (up to 1.9.16p11) respond + * to a broadcast name registration of WORKGROUP<1b> when + * they should not. Hence, until these versions are gone, + * we should treat such errors as success for this particular + * case only. jallison@whistle.com. + */ + #if 1 /* OLD_SAMBA_SERVER_HACK */ - if((nmb->header.rcode == ACT_ERR) && strequal(global_myworkgroup, answer_name->name) && - (answer_name->name_type == 0x1b)) - { - /* Pretend we did not get this. */ - rrec->num_msgs--; - - DEBUG(5,("register_name_response: Ignoring broadcast response to \ -registration of name %s due to old Samba server bug.\n", nmb_namestr(answer_name))); - return; - } + if((nmb->header.rcode == ACT_ERR) && strequal(global_myworkgroup, answer_name->name) && + (answer_name->name_type == 0x1b)) { + /* Pretend we did not get this. */ + rrec->num_msgs--; + + DEBUG(5,("register_name_response: Ignoring broadcast response to registration of name %s due to old Samba server bug.\n", + nmb_namestr(answer_name))); + return; + } #endif /* OLD_SAMBA_SERVER_HACK */ - /* Someone else has the name. Log the problem. */ - DEBUG(1,("register_name_response: Failed to register \ -name %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n", - nmb_namestr(answer_name), - subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip))); - success = False; - } - else - { - /* Unicast - check to see if the response allows us to have the name. */ - if(nmb->header.rcode != 0) - { - /* Error code - we didn't get the name. */ - success = False; - - DEBUG(0,("register_name_response: server at IP %s rejected our \ -name registration of %s with error code %d.\n", inet_ntoa(p->ip), - nmb_namestr(answer_name), nmb->header.rcode)); - - } - else if(nmb->header.opcode == NMB_WACK_OPCODE) - { - /* WINS server is telling us to wait. Pretend we didn't get - the response but don't send out any more register requests. */ - - DEBUG(5,("register_name_response: WACK from WINS server %s in registering \ -name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name)); - - rrec->repeat_count = 0; - /* How long we should wait for. */ - rrec->repeat_time = p->timestamp + nmb->answers->ttl; - rrec->num_msgs--; - return; - } - else - { - success = True; - /* Get the data we need to pass to the success function. */ - nb_flags = get_nb_flags(nmb->answers->rdata); - putip((char*)®istered_ip,&nmb->answers->rdata[2]); - ttl = nmb->answers->ttl; - } - } - - DEBUG(5,("register_name_response: %s in registering name %s on subnet %s.\n", - success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name)); - - if(success) - { - /* Enter the registered name into the subnet name database before calling - the success function. */ - standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip); - if( rrec->success_fn) - (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip); - } - else - { - if( rrec->fail_fn) - (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name); - /* Remove the name. */ - standard_fail_register( subrec, rrec, question_name); - } - - /* Ensure we don't retry. */ - remove_response_record(subrec, rrec); + /* Someone else has the name. Log the problem. */ + DEBUG(1,("register_name_response: Failed to register name %s IP %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n", + nmb_namestr(answer_name), + reg_name, + subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip))); + success = False; + } else { + /* Unicast - check to see if the response allows us to have the name. */ + if(nmb->header.rcode != 0) { + /* Error code - we didn't get the name. */ + success = False; + + DEBUG(0,("register_name_response: %sserver at IP %s rejected our name registration of %s IP %s with error code %d.\n", + subrec==unicast_subnet?"WINS ":"", + inet_ntoa(p->ip), + nmb_namestr(answer_name), + reg_name, + nmb->header.rcode)); + } else if (nmb->header.opcode == NMB_WACK_OPCODE) { + /* WINS server is telling us to wait. Pretend we didn't get + the response but don't send out any more register requests. */ + + DEBUG(5,("register_name_response: WACK from WINS server %s in registering name %s IP %s\n", + inet_ntoa(p->ip), nmb_namestr(answer_name), reg_name)); + + rrec->repeat_count = 0; + /* How long we should wait for. */ + rrec->repeat_time = p->timestamp + nmb->answers->ttl; + rrec->num_msgs--; + return; + } else { + success = True; + /* Get the data we need to pass to the success function. */ + nb_flags = get_nb_flags(nmb->answers->rdata); + ttl = nmb->answers->ttl; + + /* send off a registration for the next IP, if any */ + wins_next_registration(rrec); + } + } + + DEBUG(5,("register_name_response: %s in registering %sname %s IP %s with %s.\n", + success ? "success" : "failure", + subrec==unicast_subnet?"WINS ":"", + nmb_namestr(answer_name), + reg_name, + inet_ntoa(rrec->packet->ip))); + + if(success) { + /* Enter the registered name into the subnet name database before calling + the success function. */ + standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip); + if( rrec->success_fn) + (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip); + } else { + if( rrec->fail_fn) + (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name); + /* Remove the name. */ + standard_fail_register( subrec, rrec, question_name); + } + + /* Ensure we don't retry. */ + remove_response_record(subrec, rrec); } @@ -163,49 +171,68 @@ static void wins_registration_timeout(struct subnet_record *subrec, struct response_record *rrec) { struct userdata_struct *userdata = rrec->userdata; + struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; + struct nmb_name *nmbname = &sent_nmb->question.question_name; + struct in_addr register_ip; + fstring src_addr; - DEBUG(2,("register_name_timeout_response: WINS server at address %s is not responding.\n", - inet_ntoa(rrec->packet->ip))); + putip(®ister_ip,&sent_nmb->additional->rdata[2]); + + fstrcpy(src_addr, inet_ntoa(register_ip)); + + DEBUG(2,("wins_registration_timeout: WINS server %s timed out registering IP %s\n", + inet_ntoa(rrec->packet->ip), src_addr)); - /* mark it temporarily dead */ - wins_srv_died(rrec->packet->ip); + /* mark it temporarily dead for this source address */ + wins_srv_died(rrec->packet->ip, register_ip); /* if we have some userdata then use that to work out what wins server to try next */ if (userdata) { const char *tag = (const char *)userdata->data; - struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; - struct nmb_name *nmbname = &sent_nmb->question.question_name; - /* and try the next wins server in our failover list */ - rrec->packet->ip = wins_srv_ip_tag(tag); + /* try the next wins server in our failover list for + this tag */ + rrec->packet->ip = wins_srv_ip_tag(tag, register_ip); + } - /* also update the UNICODE subnet IPs */ - subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip; + /* if we have run out of wins servers for this tag then they + must all have timed out. We treat this as *success*, not + failure, and go into our standard name refresh mode. This + copes with all the wins servers being down */ + if (wins_srv_is_dead(rrec->packet->ip, register_ip)) { + uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata); + int ttl = sent_nmb->additional->ttl; + + standard_success_register(subrec, userdata, nmbname, nb_flags, ttl, register_ip); + if(rrec->success_fn) { + (*(register_name_success_function)rrec->success_fn)(subrec, + rrec->userdata, + nmbname, + nb_flags, + ttl, + register_ip); + } - DEBUG(6,("Retrying register of name %s with WINS server %s using tag '%s'\n", - nmb_namestr(nmbname), inet_ntoa(rrec->packet->ip), tag)); - } + /* send off a registration for the next IP, if any */ + wins_next_registration(rrec); - /* 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. */ + /* don't need to send this packet any more */ + remove_response_record(subrec, rrec); + return; + } - /* Reset the number of attempts to zero and double the interval between - retries. Max out at 5 minutes. */ - rrec->repeat_count = 3; - rrec->repeat_interval *= 2; - if(rrec->repeat_interval > (5 * 60)) - rrec->repeat_interval = (5 * 60); - rrec->repeat_time = time(NULL) + rrec->repeat_interval; + /* we will be moving to the next WINS server for this group, + send it immediately */ + rrec->repeat_count = 2; + rrec->repeat_time = time(NULL) + 1; rrec->in_expiration_processing = False; - - DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n", - (int)rrec->repeat_interval)); + + DEBUG(6,("Retrying register of name %s IP %s with WINS server %s\n", + nmb_namestr(nmbname), src_addr, inet_ntoa(rrec->packet->ip))); /* notice that we don't remove the response record. This keeps - us trying to register with each of our failover wins - servers until we succeed */ + us trying to register with each of our failover wins servers */ } @@ -241,13 +268,9 @@ static void register_name_timeout_response(struct subnet_record *subrec, putip(®istered_ip,&sent_nmb->additional->rdata[2]); } } else { - /* Unicast - if no responses then it's an error. */ - if(rrec->num_msgs == 0) { - wins_registration_timeout(subrec, rrec); - return; - } - - /* we got responses, but timed out?? bizarre. Treat it as failure. */ + /* wins timeouts are special */ + wins_registration_timeout(subrec, rrec); + return; } DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n", @@ -281,7 +304,8 @@ static void multihomed_register_one(struct nmb_name *nmbname, const char *tag) { struct userdata_struct *userdata; - struct in_addr wins_ip = wins_srv_ip_tag(tag); + struct in_addr wins_ip = wins_srv_ip_tag(tag, ip); + fstring ip_str; userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1); if (!userdata) { @@ -292,8 +316,10 @@ static void multihomed_register_one(struct nmb_name *nmbname, userdata->userdata_len = strlen(tag) + 1; strlcpy(userdata->data, tag, userdata->userdata_len); - DEBUG(6,("Registering name %s with WINS server %s using tag '%s'\n", - nmb_namestr(nmbname), inet_ntoa(wins_ip), tag)); + fstrcpy(ip_str, inet_ntoa(ip)); + + DEBUG(6,("Registering name %s IP %s with WINS server %s using tag '%s'\n", + nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag)); if (queue_register_multihomed_name(unicast_subnet, register_name_response, @@ -308,14 +334,65 @@ static void multihomed_register_one(struct nmb_name *nmbname, DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n", nmb_namestr(nmbname), inet_ntoa(ip))); } + + free(userdata); +} + + +/**************************************************************************** +we have finished the registration of one IP and need to see if we have +any more IPs left to register with this group of wins server for this name +****************************************************************************/ +static void wins_next_registration(struct response_record *rrec) +{ + struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; + struct nmb_name *nmbname = &sent_nmb->question.question_name; + uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata); + struct userdata_struct *userdata = rrec->userdata; + const char *tag; + struct in_addr last_ip; + struct subnet_record *subrec; + + putip(&last_ip,&sent_nmb->additional->rdata[2]); + + if (!userdata) { + /* it wasn't multi-homed */ + return; + } + + tag = (const char *)userdata->data; + + for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { + if (ip_equal(last_ip, subrec->myip)) { + subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec); + break; + } + } + + if (!subrec) { + /* no more to do! */ + return; + } + + switch (sent_nmb->header.opcode) { + case NMB_NAME_MULTIHOMED_REG_OPCODE: + multihomed_register_one(nmbname, nb_flags, NULL, NULL, subrec->myip, tag); + break; + case NMB_NAME_REFRESH_OPCODE_8: + queue_wins_refresh(nmbname, + register_name_response, + register_name_timeout_response, + nb_flags, subrec->myip, tag); + break; + } } /**************************************************************************** Try and register one of our names on the unicast subnet - multihomed. ****************************************************************************/ -static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags, - register_name_success_function success_fn, - register_name_fail_function fail_fn) +static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags, + register_name_success_function success_fn, + register_name_fail_function fail_fn) { /* If we are adding a group name, we just send multiple @@ -338,16 +415,16 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags, */ int num_ips=0; int i, t; - struct in_addr *ip_list = NULL; struct subnet_record *subrec; char **wins_tags; + struct in_addr *ip_list; for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) num_ips++; if((ip_list = (struct in_addr *)malloc(num_ips * sizeof(struct in_addr)))==NULL) { DEBUG(0,("multihomed_register_name: malloc fail !\n")); - return True; + return; } for (subrec = FIRST_SUBNET, i = 0; @@ -356,106 +433,92 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags, ip_list[i] = subrec->myip; } - (void)add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type, - nb_flags, lp_max_ttl(), SELF_NAME, - num_ips, ip_list); + add_name_to_subnet(unicast_subnet, nmbname->name, nmbname->name_type, + nb_flags, lp_max_ttl(), SELF_NAME, + num_ips, ip_list); /* get the list of wins tags - we try to register for each of them */ wins_tags = wins_srv_tags(); - /* Now try and register the name, num_ips times for each wins tag. */ - for (t=0; wins_tags[t]; t++) { - for (i = 0; i < num_ips; i++) { - multihomed_register_one(nmbname, nb_flags, - success_fn, fail_fn, - ip_list[i], - wins_tags[t]); - } + /* Now try and register the name for each wins tag. Note that + at this point we only register our first IP with each wins + group. We will register the rest from + wins_next_registration() when we get the reply for this + one. That follows the way W2K does things (tridge) + */ + for (t=0; wins_tags && wins_tags[t]; t++) { + multihomed_register_one(nmbname, nb_flags, + success_fn, fail_fn, + ip_list[0], + wins_tags[t]); } wins_srv_tags_free(wins_tags); SAFE_FREE(ip_list); - - return False; } + /**************************************************************************** Try and register one of our names. ****************************************************************************/ - -BOOL register_name(struct subnet_record *subrec, +void register_name(struct subnet_record *subrec, char *name, int type, uint16 nb_flags, register_name_success_function success_fn, register_name_fail_function fail_fn, struct userdata_struct *userdata) { - struct nmb_name nmbname; - - make_nmb_name(&nmbname, name, type); - - /* Always set the NB_ACTIVE flag on the name we are - registering. Doesn't make sense without it. - */ - - nb_flags |= NB_ACTIVE; - - /* If this is the unicast subnet, and we are a multi-homed - host, then register a multi-homed name. */ - - if( (subrec == unicast_subnet) && we_are_multihomed()) { - return multihomed_register_name(&nmbname, nb_flags, - success_fn, fail_fn); - } - - if(queue_register_name( subrec, - register_name_response, - register_name_timeout_response, - success_fn, - fail_fn, - userdata, - &nmbname, - nb_flags) == NULL) - { - DEBUG(0,("register_name: Failed to send packet trying to register name %s\n", - nmb_namestr(&nmbname))); - return True; - } - return False; + struct nmb_name nmbname; + + make_nmb_name(&nmbname, name, type); + + /* Always set the NB_ACTIVE flag on the name we are + registering. Doesn't make sense without it. + */ + + nb_flags |= NB_ACTIVE; + + if (subrec == unicast_subnet) { + /* we now always do multi-homed registration if we are + registering to a WINS server. This copes much + better with complex WINS setups */ + multihomed_register_name(&nmbname, nb_flags, + success_fn, fail_fn); + return; + } + + if (queue_register_name(subrec, + register_name_response, + register_name_timeout_response, + success_fn, + fail_fn, + userdata, + &nmbname, + nb_flags) == NULL) { + DEBUG(0,("register_name: Failed to send packet trying to register name %s\n", + nmb_namestr(&nmbname))); + } } + /**************************************************************************** - Try and refresh one of our names. + Try and refresh one of our names. This is *only* called for WINS refresh ****************************************************************************/ - -BOOL refresh_name(struct subnet_record *subrec, struct name_record *namerec, - refresh_name_success_function success_fn, - refresh_name_fail_function fail_fn, - struct userdata_struct *userdata) +void wins_refresh_name(struct name_record *namerec) { - int i; - - /* - * Go through and refresh the name for all known ip addresses. - * Only call the success/fail function on the last one (it should - * only be done once). - */ - - for( i = 0; i < namerec->data.num_ips; i++) - { - if(queue_refresh_name( subrec, - register_name_response, - register_name_timeout_response, - (i == (namerec->data.num_ips - 1)) ? success_fn : NULL, - (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL, - (i == (namerec->data.num_ips - 1)) ? userdata : NULL, - namerec, - namerec->data.ip[i]) == NULL) - { - DEBUG(0,("refresh_name: Failed to send packet trying to refresh name %s\n", - nmb_namestr(&namerec->name))); - return True; - } - } - return False; + int t; + char **wins_tags; + + /* get the list of wins tags - we try to refresh for each of them */ + wins_tags = wins_srv_tags(); + + for (t=0; wins_tags && wins_tags[t]; t++) { + queue_wins_refresh(&namerec->name, + register_name_response, + register_name_timeout_response, + namerec->data.nb_flags, + namerec->data.ip[0], wins_tags[t]); + } + + wins_srv_tags_free(wins_tags); } diff --git a/source3/nmbd/nmbd_namerelease.c b/source3/nmbd/nmbd_namerelease.c index cefab44a08..0611ca9323 100644 --- a/source3/nmbd/nmbd_namerelease.c +++ b/source3/nmbd/nmbd_namerelease.c @@ -28,85 +28,72 @@ ****************************************************************************/ static void release_name_response(struct subnet_record *subrec, - struct response_record *rrec, struct packet_struct *p) + struct response_record *rrec, struct packet_struct *p) { - /* - * If we are releasing broadcast, then getting a response is an - * error. If we are releasing unicast, then we expect to get a response. - */ - - struct nmb_packet *nmb = &p->packet.nmb; - BOOL bcast = nmb->header.nm_flags.bcast; - BOOL success = True; - struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; - struct nmb_name *answer_name = &nmb->answers->rr_name; - struct in_addr released_ip; - - /* Sanity check. Ensure that the answer name in the incoming packet is the - same as the requested name in the outgoing packet. */ - - if(!nmb_name_equal(question_name, answer_name)) - { - DEBUG(0,("release_name_response: Answer name %s differs from question \ -name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name))); - return; - } - - if(bcast) - { - /* Someone sent a response. This shouldn't happen/ */ - DEBUG(1,("release_name_response: A response for releasing name %s was received on a \ -broadcast subnet %s. This should not happen !\n", nmb_namestr(answer_name), subrec->subnet_name)); - return; - } - else - { - /* Unicast - check to see if the response allows us to release the name. */ - if(nmb->header.rcode != 0) - { - /* Error code - we were told not to release the name ! What now ! */ - success = False; - - DEBUG(0,("release_name_response: WINS server at IP %s rejected our \ -name release of name %s with error code %d.\n", inet_ntoa(p->ip), - nmb_namestr(answer_name), nmb->header.rcode)); - - } - else if(nmb->header.opcode == NMB_WACK_OPCODE) - { - /* WINS server is telling us to wait. Pretend we didn't get - the response but don't send out any more release requests. */ - - DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \ -name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name)); - - rrec->repeat_count = 0; - /* How long we should wait for. */ - rrec->repeat_time = p->timestamp + nmb->answers->ttl; - rrec->num_msgs--; - return; - } - } - - DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n", - success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name)); - - if(success) - { - putip((char*)&released_ip ,&nmb->answers->rdata[2]); - - if(rrec->success_fn) - (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip); - standard_success_release( subrec, rrec->userdata, answer_name, released_ip); - } - else - { - /* We have no standard_fail_release - maybe we should add one ? */ - if(rrec->fail_fn) - (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name); - } - - remove_response_record(subrec, rrec); + /* + * If we are releasing broadcast, then getting a response is an + * error. If we are releasing unicast, then we expect to get a response. + */ + struct nmb_packet *nmb = &p->packet.nmb; + BOOL bcast = nmb->header.nm_flags.bcast; + BOOL success = True; + struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; + struct nmb_name *answer_name = &nmb->answers->rr_name; + struct in_addr released_ip; + + /* Sanity check. Ensure that the answer name in the incoming packet is the + same as the requested name in the outgoing packet. */ + if (!nmb_name_equal(question_name, answer_name)) { + DEBUG(0,("release_name_response: Answer name %s differs from question name %s.\n", + nmb_namestr(answer_name), nmb_namestr(question_name))); + return; + } + + if (bcast) { + /* Someone sent a response to a bcast release? ignore it. */ + return; + } + + /* Unicast - check to see if the response allows us to release the name. */ + if (nmb->header.rcode != 0) { + /* Error code - we were told not to release the name ! What now ! */ + success = False; + + DEBUG(0,("release_name_response: WINS server at IP %s rejected our \ +name release of name %s with error code %d.\n", + inet_ntoa(p->ip), + nmb_namestr(answer_name), nmb->header.rcode)); + } else if (nmb->header.opcode == NMB_WACK_OPCODE) { + /* WINS server is telling us to wait. Pretend we didn't get + the response but don't send out any more release requests. */ + + DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \ +name %s on subnet %s.\n", + inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name)); + + rrec->repeat_count = 0; + /* How long we should wait for. */ + rrec->repeat_time = p->timestamp + nmb->answers->ttl; + rrec->num_msgs--; + return; + } + + DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n", + success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name)); + if (success) { + putip((char*)&released_ip ,&nmb->answers->rdata[2]); + + if(rrec->success_fn) + (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip); + standard_success_release( subrec, rrec->userdata, answer_name, released_ip); + } else { + /* We have no standard_fail_release - maybe we should add one ? */ + if (rrec->fail_fn) { + (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name); + } + } + + remove_response_record(subrec, rrec); } /**************************************************************************** @@ -114,125 +101,122 @@ name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->su ****************************************************************************/ static void release_name_timeout_response(struct subnet_record *subrec, - struct response_record *rrec) + struct response_record *rrec) { - /* - * If we are releasing unicast, then NOT getting a response is an - * error - we could not release the name. If we are releasing broadcast, - * then we don't expect to get a response. - */ - - struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; - BOOL bcast = sent_nmb->header.nm_flags.bcast; - BOOL success = False; - struct nmb_name *question_name = &sent_nmb->question.question_name; - struct in_addr released_ip; - - if(bcast) - { - if(rrec->num_msgs == 0) - { - /* Not receiving a message is success for broadcast release. */ - success = True; - - /* Get the ip address we were trying to release. */ - putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]); - } - } - else - { - /* Unicast - if no responses then it's an error. */ - if(rrec->num_msgs == 0) - { - DEBUG(2,("release_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 */ - 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. */ - rrec->repeat_count = 3; - rrec->repeat_interval *= 2; - if(rrec->repeat_interval > (5 * 60)) - rrec->repeat_interval = (5 * 60); - rrec->repeat_time = time(NULL) + rrec->repeat_interval; - - DEBUG(5,("release_name_timeout_response: increasing WINS timeout to %d seconds.\n", - (int)rrec->repeat_interval)); - return; /* Don't remove the response record. */ - } - } - - DEBUG(5,("release_name_timeout_response: %s in releasing name %s on subnet %s.\n", - success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name)); - - if(success && rrec->success_fn) - { - if(rrec->success_fn) - (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip); - standard_success_release( subrec, rrec->userdata, question_name, released_ip); - } - else - { - /* We have no standard_fail_release - maybe we should add one ? */ - if( rrec->fail_fn) - (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name); - } - - remove_response_record(subrec, rrec); + /* a release is *always* considered to be successful when it + times out. This doesn't cause problems as if a WINS server + doesn't respond and someone else wants the name then the + normal WACK/name query from the WINS server will cope */ + struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; + BOOL bcast = sent_nmb->header.nm_flags.bcast; + struct nmb_name *question_name = &sent_nmb->question.question_name; + struct in_addr released_ip; + + /* Get the ip address we were trying to release. */ + putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]); + + if (!bcast) { + /* mark the WINS server temporarily dead */ + wins_srv_died(rrec->packet->ip, released_ip); + } + + DEBUG(5,("release_name_timeout_response: success in releasing name %s on subnet %s.\n", + nmb_namestr(question_name), subrec->subnet_name)); + + if (rrec->success_fn) { + (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip); + } + + standard_success_release( subrec, rrec->userdata, question_name, released_ip); + remove_response_record(subrec, rrec); } + +/* + when releasing a name with WINS we need to send the release to each of + the WINS groups +*/ +static void wins_release_name(struct name_record *namerec, + release_name_success_function success_fn, + release_name_fail_function fail_fn, + struct userdata_struct *userdata) +{ + int t, i; + char **wins_tags; + + /* get the list of wins tags - we try to release for each of them */ + wins_tags = wins_srv_tags(); + + for (t=0;wins_tags && wins_tags[t]; t++) { + for (i = 0; i < namerec->data.num_ips; i++) { + struct in_addr wins_ip = wins_srv_ip_tag(wins_tags[t], namerec->data.ip[i]); + + BOOL last_one = ((i==namerec->data.num_ips - 1) && !wins_tags[t+1]); + if (queue_release_name(unicast_subnet, + release_name_response, + release_name_timeout_response, + last_one?success_fn : NULL, + last_one? fail_fn : NULL, + last_one? userdata : NULL, + &namerec->name, + namerec->data.nb_flags, + namerec->data.ip[i], + wins_ip) == NULL) { + DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n", + nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) )); + } + } + } + + wins_srv_tags_free(wins_tags); +} + + /**************************************************************************** Try and release one of our names. ****************************************************************************/ -BOOL release_name(struct subnet_record *subrec, struct name_record *namerec, - release_name_success_function success_fn, - release_name_fail_function fail_fn, - struct userdata_struct *userdata) +void release_name(struct subnet_record *subrec, struct name_record *namerec, + release_name_success_function success_fn, + release_name_fail_function fail_fn, + struct userdata_struct *userdata) { - int i; - - /* Ensure it's a SELF name, and in the ACTIVE state. */ - if((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec)) - { - DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n", - nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source)); - return True; - } - - /* Set the name into the deregistering state. */ - namerec->data.nb_flags |= NB_DEREG; - - /* - * Go through and release the name for all known ip addresses. - * Only call the success/fail function on the last one (it should - * only be done once). - */ - - for( i = 0; i < namerec->data.num_ips; i++) - { - if(queue_release_name( subrec, - release_name_response, - release_name_timeout_response, - (i == (namerec->data.num_ips - 1)) ? success_fn : NULL, - (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL, - (i == (namerec->data.num_ips - 1)) ? userdata : NULL, - &namerec->name, - namerec->data.nb_flags, - namerec->data.ip[i]) == NULL) - { - DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n", - nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) )); - return True; - } - } - return False; + int i; + + /* Ensure it's a SELF name, and in the ACTIVE state. */ + if ((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec)) { + DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n", + nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source)); + return; + } + + /* Set the name into the deregistering state. */ + namerec->data.nb_flags |= NB_DEREG; + + /* wins releases are a bit different */ + if (subrec == unicast_subnet) { + wins_release_name(namerec, success_fn, fail_fn, userdata); + return; + } + + /* + * Go through and release the name for all known ip addresses. + * Only call the success/fail function on the last one (it should + * only be done once). + */ + for (i = 0; i < namerec->data.num_ips; i++) { + if (queue_release_name(subrec, + release_name_response, + release_name_timeout_response, + (i == (namerec->data.num_ips - 1)) ? success_fn : NULL, + (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL, + (i == (namerec->data.num_ips - 1)) ? userdata : NULL, + &namerec->name, + namerec->data.nb_flags, + namerec->data.ip[i], + subrec->bcast_ip) == NULL) { + DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n", + nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) )); + } + } } diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c index f0c8b755c9..64b63627d7 100644 --- a/source3/nmbd/nmbd_packets.c +++ b/source3/nmbd/nmbd_packets.c @@ -237,48 +237,44 @@ static BOOL create_and_init_additional_record(struct packet_struct *packet, uint16 nb_flags, struct in_addr *register_ip) { - struct nmb_packet *nmb = &packet->packet.nmb; - - if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) - { - DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n")); - return False; - } - - memset((char *)nmb->additional,'\0',sizeof(struct res_rec)); - - nmb->additional->rr_name = nmb->question.question_name; - nmb->additional->rr_type = RR_TYPE_NB; - nmb->additional->rr_class = RR_CLASS_IN; - - /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */ - if (nmb->header.nm_flags.bcast) - nmb->additional->ttl = PERMANENT_TTL; - else - nmb->additional->ttl = lp_max_ttl(); - - nmb->additional->rdlength = 6; - - set_nb_flags(nmb->additional->rdata,nb_flags); - - /* Set the address for the name we are registering. */ - putip(&nmb->additional->rdata[2], register_ip); + struct nmb_packet *nmb = &packet->packet.nmb; -#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. + if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) { + DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n")); + return False; + } - 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 + memset((char *)nmb->additional,'\0',sizeof(struct res_rec)); - return True; + nmb->additional->rr_name = nmb->question.question_name; + nmb->additional->rr_type = RR_TYPE_NB; + nmb->additional->rr_class = RR_CLASS_IN; + + /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */ + if (nmb->header.nm_flags.bcast) + nmb->additional->ttl = PERMANENT_TTL; + else + nmb->additional->ttl = lp_max_ttl(); + + nmb->additional->rdlength = 6; + + set_nb_flags(nmb->additional->rdata,nb_flags); + + /* Set the address for the name we are registering. */ + putip(&nmb->additional->rdata[2], register_ip); + + /* + it turns out that Jeremys code was correct, we are supposed + to send registrations from the IP we are registering. The + trick is what to do on timeouts! When we send on a + non-routable IP then the reply will timeout, and we should + treat this as success, not failure. That means we go into + our standard refresh cycle for that name which copes nicely + with disconnected networks. + */ + packet->fd = find_subnet_fd_for_address(*register_ip); + + return True; } /*************************************************************************** @@ -353,28 +349,28 @@ static BOOL initiate_name_register_packet( struct packet_struct *packet, Sends out a multihomed name register. **************************************************************************/ -static BOOL initiate_multihomed_name_register_packet( struct packet_struct *packet, - uint16 nb_flags, struct in_addr *register_ip) +static BOOL initiate_multihomed_name_register_packet(struct packet_struct *packet, + uint16 nb_flags, struct in_addr *register_ip) { - struct nmb_packet *nmb = &packet->packet.nmb; - fstring second_ip_buf; + struct nmb_packet *nmb = &packet->packet.nmb; + fstring second_ip_buf; - fstrcpy(second_ip_buf, inet_ntoa(packet->ip)); + fstrcpy(second_ip_buf, inet_ntoa(packet->ip)); - nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE; - nmb->header.arcount = 1; + nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE; + nmb->header.arcount = 1; - nmb->header.nm_flags.recursion_desired = True; - - if(create_and_init_additional_record(packet, nb_flags, register_ip) == False) - return False; - - DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \ + nmb->header.nm_flags.recursion_desired = True; + + if(create_and_init_additional_record(packet, nb_flags, register_ip) == False) + return False; + + DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \ for name %s IP %s (bcast=%s) to IP %s\n", - nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip), - BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf )); + nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip), + BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf )); - return send_netbios_packet( packet ); + return send_netbios_packet( packet ); } /*************************************************************************** @@ -518,6 +514,67 @@ struct response_record *queue_register_name( struct subnet_record *subrec, return rrec; } + +/**************************************************************************** + Queue a refresh name packet to the broadcast address of a subnet. +****************************************************************************/ +void queue_wins_refresh(struct nmb_name *nmbname, + response_function resp_fn, + timeout_response_function timeout_fn, + uint16 nb_flags, + struct in_addr refresh_ip, + const char *tag) +{ + struct packet_struct *p; + struct response_record *rrec; + struct in_addr wins_ip; + struct userdata_struct *userdata; + fstring ip_str; + + wins_ip = wins_srv_ip_tag(tag, refresh_ip); + + if ((p = create_and_init_netbios_packet(nmbname, False, False, wins_ip)) == NULL) { + return; + } + + if (!initiate_name_refresh_packet(p, nb_flags, &refresh_ip)) { + p->locked = False; + free_packet(p); + return; + } + + fstrcpy(ip_str, inet_ntoa(refresh_ip)); + + DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n", + nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag)); + + userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1); + if (!userdata) { + DEBUG(0,("Failed to allocate userdata structure!\n")); + return; + } + ZERO_STRUCTP(userdata); + userdata->userdata_len = strlen(tag) + 1; + strlcpy(userdata->data, tag, userdata->userdata_len); + + if ((rrec = make_response_record(unicast_subnet, + p, + resp_fn, timeout_fn, + NULL, + NULL, + userdata)) == NULL) { + p->locked = False; + free_packet(p); + return; + } + + free(userdata); + + /* we don't want to repeat refresh packets */ + rrec->repeat_count = 0; +} + + /**************************************************************************** Queue a multihomed register name packet to a given WINS server IP ****************************************************************************/ @@ -581,14 +638,15 @@ unicast subnet. subnet is %s\n.", subrec->subnet_name )); ****************************************************************************/ struct response_record *queue_release_name( struct subnet_record *subrec, - response_function resp_fn, - timeout_response_function timeout_fn, - release_name_success_function success_fn, - release_name_fail_function fail_fn, - struct userdata_struct *userdata, - struct nmb_name *nmbname, - uint16 nb_flags, - struct in_addr release_ip) + response_function resp_fn, + timeout_response_function timeout_fn, + release_name_success_function success_fn, + release_name_fail_function fail_fn, + struct userdata_struct *userdata, + struct nmb_name *nmbname, + uint16 nb_flags, + struct in_addr release_ip, + struct in_addr dest_ip) { struct packet_struct *p; struct response_record *rrec; @@ -597,7 +655,7 @@ struct response_record *queue_release_name( struct subnet_record *subrec, return NULL; if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False, - subrec->bcast_ip)) == NULL) + dest_ip)) == NULL) return NULL; if(initiate_name_release_packet( p, nb_flags, &release_ip) == False) @@ -634,52 +692,6 @@ struct response_record *queue_release_name( struct subnet_record *subrec, } /**************************************************************************** - Queue a refresh name packet to the broadcast address of a subnet. -****************************************************************************/ - -struct response_record *queue_refresh_name( struct subnet_record *subrec, - response_function resp_fn, - timeout_response_function timeout_fn, - refresh_name_success_function success_fn, - refresh_name_fail_function fail_fn, - struct userdata_struct *userdata, - struct name_record *namerec, - struct in_addr refresh_ip) -{ - struct packet_struct *p; - struct response_record *rrec; - - if(assert_check_subnet(subrec)) - return NULL; - - if(( p = create_and_init_netbios_packet(&namerec->name, (subrec != unicast_subnet), False, - subrec->bcast_ip)) == NULL) - return NULL; - - if( !initiate_name_refresh_packet( p, namerec->data.nb_flags, &refresh_ip ) ) - { - p->locked = False; - free_packet(p); - return NULL; - } - - if((rrec = make_response_record(subrec, /* subnet record. */ - p, /* packet we sent. */ - resp_fn, /* function to call on response. */ - timeout_fn, /* function to call on timeout. */ - (success_function)success_fn, /* function to call on operation success. */ - (fail_function)fail_fn, /* function to call on operation fail. */ - userdata)) == NULL) - { - p->locked = False; - free_packet(p); - return NULL; - } - - return rrec; -} - -/**************************************************************************** Queue a query name packet to the broadcast address of a subnet. ****************************************************************************/ diff --git a/source3/nmbd/nmbd_responserecordsdb.c b/source3/nmbd/nmbd_responserecordsdb.c index a2da5ddf4a..7e8c8025ae 100644 --- a/source3/nmbd/nmbd_responserecordsdb.c +++ b/source3/nmbd/nmbd_responserecordsdb.c @@ -97,12 +97,12 @@ void remove_response_record(struct subnet_record *subrec, **************************************************************************/ struct response_record *make_response_record( struct subnet_record *subrec, - struct packet_struct *p, - response_function resp_fn, - timeout_response_function timeout_fn, - success_function success_fn, - fail_function fail_fn, - struct userdata_struct *userdata) + struct packet_struct *p, + response_function resp_fn, + timeout_response_function timeout_fn, + success_function success_fn, + fail_function fail_fn, + struct userdata_struct *userdata) { struct response_record *rrec; struct nmb_packet *nmb = &p->packet.nmb; diff --git a/source3/nmbd/nmbd_subnetdb.c b/source3/nmbd/nmbd_subnetdb.c index 146b6cbdfe..e68fc1589c 100644 --- a/source3/nmbd/nmbd_subnetdb.c +++ b/source3/nmbd/nmbd_subnetdb.c @@ -267,45 +267,14 @@ BOOL create_subnets(void) if (!make_normal_subnet(iface)) return False; } - /* - * If we have been configured to use a WINS server, then try and - * 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. crh - */ - - if( wins_srv_count() ) - { - struct in_addr real_wins_ip; - real_wins_ip = wins_srv_ip(); - - if (!is_zero_ip(real_wins_ip)) - { - unicast_ip = real_wins_ip; - } - else - { - /* wins_srv_ip() can return a zero IP if all servers are - * either down or incorrectly entered in smb.conf. crh - */ - DEBUG(0,("No 'live' WINS servers found. Check 'wins server' parameter.\n")); - return False; - } - } - else if(lp_we_are_a_wins_server()) - { - /* Pick the first interface ip address as the WINS server ip. */ - unicast_ip = *iface_n_ip(0); - } - else - { - /* We should not be using a WINS server at all. Set the - ip address of the subnet to be zero. */ - zero_ip(&unicast_ip); + if (lp_we_are_a_wins_server()) { + /* Pick the first interface ip address as the WINS server ip. */ + unicast_ip = *iface_n_ip(0); + } else { + /* note that we do not set the wins server IP here. We just + set it at zero and let the wins registration code cope + with getting the IPs right for each packet */ + zero_ip(&unicast_ip); } /* @@ -346,16 +315,13 @@ BOOL create_subnets(void) /******************************************************************* Function to tell us if we can use the unicast subnet. ******************************************************************/ - BOOL we_are_a_wins_client(void) { - static int cache_we_are_a_wins_client = -1; - - if(cache_we_are_a_wins_client == -1) - cache_we_are_a_wins_client = (is_zero_ip(unicast_subnet->myip) ? - False : True); + if (wins_srv_count() > 0) { + return True; + } - return cache_we_are_a_wins_client; + return False; } /******************************************************************* diff --git a/source3/nsswitch/winbindd_wins.c b/source3/nsswitch/winbindd_wins.c index 75d04349e6..8f9a7414bd 100644 --- a/source3/nsswitch/winbindd_wins.c +++ b/source3/nsswitch/winbindd_wins.c @@ -87,7 +87,6 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count) { int fd; struct in_addr *ret = NULL; - struct in_addr p; int j, flags = 0; *count = 0; @@ -111,7 +110,6 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count) if (ret) break; } - out: close(fd); return ret; } |