summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/lib/wins_srv.c261
-rw-r--r--source3/libsmb/namequery.c111
-rw-r--r--source3/nmbd/nmbd_nameregister.c298
-rw-r--r--source3/nmbd/nmbd_packets.c97
-rw-r--r--source3/nsswitch/winbindd_wins.c21
-rw-r--r--source3/nsswitch/wins.c29
-rw-r--r--source3/utils/nmblookup.c4
-rw-r--r--source3/web/diagnose.c2
8 files changed, 557 insertions, 266 deletions
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c
index c31e7505f0..95b25b96b2 100644
--- a/source3/lib/wins_srv.c
+++ b/source3/lib/wins_srv.c
@@ -1,6 +1,6 @@
/*
Unix SMB/CIFS implementation.
- Samba utility functions
+ Samba wins server helper functions
Copyright (C) Andrew Tridgell 1992-2002
Copyright (C) Christopher R. Hertel 2000
@@ -21,6 +21,41 @@
#include "includes.h"
+/*
+ this is pretty much a complete rewrite of the earlier code. The main
+ aim of the rewrite is to add support for having multiple wins server
+ lists, so Samba can register with multiple groups of wins servers
+ and each group has a failover list of wins servers.
+
+ Central to the way it all works is the idea of a wins server
+ 'tag'. A wins tag is a label for a group of wins servers. For
+ example if you use
+
+ wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
+
+ then you would have two groups of wins servers, one tagged with the
+ name 'fred' and the other with the name 'mary'. I would usually
+ recommend using interface names instead of 'fred' and 'mary' but
+ they can be any alpha string.
+
+ Now, how does it all work. Well, nmbd needs to register each of its
+ IPs with each of its names once with each group of wins servers. So
+ it tries registering with the first one mentioned in the list, then
+ if that fails it marks that WINS server dead and moves onto the next
+ one.
+
+ In the client code things are a bit different. As each of the groups
+ of wins servers is a separate name space we need to try each of the
+ groups until we either succeed or we run out of wins servers to
+ try. If we get a negative response from a wins server then that
+ means the name doesn't exist in that group, so we give up on that
+ group and move to the next group. If we don't get a response at all
+ then maybe the wins server is down, in which case we need to
+ failover to the next one for that group.
+
+ confused yet? (tridge)
+*/
+
/* how long a server is marked dead for */
#define DEATH_TIME 600
@@ -33,10 +68,17 @@ static struct wins_dead {
} *dead_servers;
+/* an internal convenience structure for an IP with a short string tag
+ attached */
+struct tagged_ip {
+ fstring tag;
+ struct in_addr ip;
+};
+
/*
see if an ip is on the dead list
*/
-static int wins_is_dead(struct in_addr ip)
+BOOL wins_srv_is_dead(struct in_addr ip)
{
struct wins_dead *d;
for (d=dead_servers; d; d=d->next) {
@@ -46,12 +88,12 @@ static int wins_is_dead(struct in_addr ip)
DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip)));
DLIST_REMOVE(dead_servers, d);
free(d);
- return 0;
+ return False;
}
- return 1;
+ return True;
}
}
- return 0;
+ return False;
}
/*
@@ -61,7 +103,7 @@ void wins_srv_died(struct in_addr ip)
{
struct wins_dead *d;
- if (is_zero_ip(ip) || wins_is_dead(ip)) {
+ if (is_zero_ip(ip) || wins_srv_is_dead(ip)) {
return;
}
@@ -79,11 +121,16 @@ void wins_srv_died(struct in_addr ip)
/*
return the total number of wins servers, dead or not
*/
-unsigned long wins_srv_count(void)
+unsigned wins_srv_count(void)
{
char **list;
int count = 0;
+ if (lp_wins_support()) {
+ /* simple - just talk to ourselves */
+ return 1;
+ }
+
list = lp_wins_server_list();
for (count=0; list && list[count]; count++) /* nop */ ;
@@ -92,31 +139,213 @@ unsigned long wins_srv_count(void)
}
/*
+ parse an IP string that might be in tagged format
+ the result is a tagged_ip structure containing the tag
+ and the ip in in_addr format. If there is no tag then
+ use the tag '*'
+*/
+static void parse_ip(struct tagged_ip *ip, const char *str)
+{
+ char *s = strchr(str, ':');
+ if (!s) {
+ fstrcpy(ip->tag, "*");
+ ip->ip = *interpret_addr2(str);
+ return;
+ }
+
+ ip->ip = *interpret_addr2(s+1);
+ fstrcpy(ip->tag, str);
+ s = strchr(ip->tag, ':');
+ if (s) *s = 0;
+}
+
+
+/*
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;
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(&ip);
- return ip;
+ zero_ip(&t_ip.ip);
+ return t_ip.ip;
}
/* find the first live one */
for (i=0; list[i]; i++) {
- ip = *interpret_addr2(list[i]);
- if (!wins_is_dead(ip)) {
- DEBUG(6,("Current wins server is %s\n", inet_ntoa(ip)));
- return ip;
+ 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 */
- ip = *interpret_addr2(list[0]);
+ parse_ip(&t_ip, list[0]);
+
+ return t_ip.ip;
+}
+
+
+/*
+ return the list of wins server tags. A 'tag' is used to distinguish
+ wins server as either belonging to the same name space or a separate
+ name space. Usually you would setup your 'wins server' option to
+ list one or more wins server per interface and use the interface
+ name as your tag, but you are free to use any tag you like.
+*/
+char **wins_srv_tags(void)
+{
+ char **ret = NULL;
+ int count=0, i, j;
+ char **list;
+
+ if (lp_wins_support()) {
+ /* 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);
+ if (!ret) return NULL;
+ ret[0] = strdup("*");
+ ret[1] = NULL;
+ return ret;
+ }
+
+ list = lp_wins_server_list();
+ if (!list) return NULL;
+
+ /* yes, this is O(n^2) but n is very small */
+ for (i=0;list[i];i++) {
+ struct tagged_ip t_ip;
+
+ parse_ip(&t_ip, list[i]);
+
+ /* see if we already have it */
+ for (j=0;j<count;j++) {
+ if (strcmp(ret[j], t_ip.tag) == 0) {
+ break;
+ }
+ }
+
+ if (j != count) {
+ /* we already have it. Move along */
+ continue;
+ }
+
+ /* add it to the list */
+ ret = (char **)Realloc(ret, (count+1) * sizeof(char *));
+ ret[count] = strdup(t_ip.tag);
+ if (!ret[count]) break;
+ count++;
+ }
+
+ if (count) {
+ /* make sure we null terminate */
+ ret[count] = NULL;
+ }
+
+ return ret;
+}
+
+/* free a list of wins server tags given by wins_srv_tags */
+void wins_srv_tags_free(char **list)
+{
+ int i;
+ if (!list) return;
+ for (i=0; list[i]; i++) {
+ free(list[i]);
+ }
+ free(list);
+}
- return ip;
+
+/*
+ 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)
+{
+ 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]) {
+ struct in_addr ip;
+ zero_ip(&ip);
+ return ip;
+ }
+
+ /* find the first live one for this tag */
+ for (i=0; list[i]; i++) {
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) != 0) {
+ /* 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)));
+ return t_ip.ip;
+ }
+ }
+
+ /* they're all dead - try the first one until they revive */
+ for (i=0; list[i]; i++) {
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) != 0) {
+ continue;
+ }
+ return t_ip.ip;
+ }
+
+ /* this can't happen?? */
+ zero_ip(&t_ip.ip);
+ return t_ip.ip;
+}
+
+
+/*
+ return a count of the number of IPs for a particular tag, including
+ dead ones
+*/
+unsigned wins_srv_count_tag(const char *tag)
+{
+ char **list;
+ int i, count=0;
+
+ /* if we are a wins server then we always just talk to ourselves */
+ if (lp_wins_support()) {
+ return 1;
+ }
+
+ list = lp_wins_server_list();
+ if (!list || !list[0]) {
+ return 0;
+ }
+
+ /* find the first live one for this tag */
+ for (i=0; list[i]; i++) {
+ struct tagged_ip t_ip;
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) == 0) {
+ count++;
+ }
+ }
+
+ return count;
}
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index c85c8c48df..2cdcd49b91 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -302,10 +302,12 @@ BOOL name_register(int fd, const char *name, int name_type,
Do a netbios name query to find someones IP.
Returns an array of IP addresses or NULL if none.
*count will be set to the number of addresses returned.
+ *timed_out is set if we failed by timing out
****************************************************************************/
struct in_addr *name_query(int fd,const char *name,int name_type,
BOOL bcast,BOOL recurse,
- struct in_addr to_ip, int *count, int *flags)
+ struct in_addr to_ip, int *count, int *flags,
+ BOOL *timed_out)
{
BOOL found=False;
int i, retries = 3;
@@ -315,6 +317,10 @@ struct in_addr *name_query(int fd,const char *name,int name_type,
struct packet_struct *p2;
struct nmb_packet *nmb = &p.packet.nmb;
struct in_addr *ip_list = NULL;
+
+ if (timed_out) {
+ *timed_out = False;
+ }
memset((char *)&p,'\0',sizeof(p));
(*count) = 0;
@@ -465,10 +471,8 @@ struct in_addr *name_query(int fd,const char *name,int name_type,
}
}
- /* Reach here if we've timed out waiting for replies.. */
- if (!bcast && !found) {
- /* Timed out wating for WINS server to respond. Mark it dead. */
- wins_srv_died( to_ip );
+ if (timed_out) {
+ *timed_out = True;
}
return ip_list;
@@ -619,7 +623,7 @@ BOOL name_resolve_bcast(const char *name, int name_type,
/* Done this way to fix compiler error on IRIX 5.x */
sendto_ip = *iface_n_bcast(i);
*return_ip_list = name_query(sock, name, name_type, True,
- True, sendto_ip, return_count, &flags);
+ True, sendto_ip, return_count, &flags, NULL);
if(*return_ip_list != NULL) {
close(sock);
return True;
@@ -637,59 +641,80 @@ BOOL name_resolve_bcast(const char *name, int name_type,
static BOOL resolve_wins(const char *name, int name_type,
struct in_addr **return_iplist, int *return_count)
{
- int sock;
- struct in_addr wins_ip;
- BOOL wins_ismyip;
+ int sock, t, i;
+ char **wins_tags;
*return_iplist = NULL;
*return_count = 0;
- /*
- * "wins" means do a unicast lookup to the WINS server.
- * Ignore if there is no WINS server specified or if the
- * WINS server is one of our interfaces (if we're being
- * called from within nmbd - we can't do this call as we
- * would then block).
- */
-
DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
- if (lp_wins_support()) {
- /*
- * We're providing WINS support. Call ourselves so
- * long as we're not nmbd.
- */
- extern struct in_addr loopback_ip;
- wins_ip = loopback_ip;
- wins_ismyip = True;
- } else if( wins_srv_count() < 1 ) {
+ if (wins_srv_count() < 1) {
DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
return False;
- } else {
- wins_ip = wins_srv_ip();
- wins_ismyip = ismyip(wins_ip);
}
- DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) );
- if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
- int flags;
- sock = open_socket_in( SOCK_DGRAM, 0, 3,
- interpret_addr(lp_socket_address()),
- True );
- if (sock != -1) {
- *return_iplist = name_query( sock, name,
- name_type, False,
- True, wins_ip,
- return_count, &flags);
- if(*return_iplist != NULL) {
- close(sock);
- return True;
+ /* we try a lookup on each of the WINS tags in turn */
+ wins_tags = wins_srv_tags();
+
+ if (!wins_tags) {
+ /* huh? no tags?? give up in disgust */
+ return False;
+ }
+
+ /* 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++) {
+ struct in_addr wins_ip;
+ int flags;
+ BOOL timed_out;
+
+ wins_ip = wins_srv_ip_tag(wins_tags[t]);
+
+ if (global_in_nmbd && ismyip(wins_ip)) {
+ /* yikes! we'll loop forever */
+ continue;
+ }
+
+ /* skip any that have been unresponsive lately */
+ if (wins_srv_is_dead(wins_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);
+ if (sock == -1) {
+ continue;
+ }
+
+ *return_iplist = name_query(sock,name,name_type, False,
+ True, wins_ip, return_count, &flags,
+ &timed_out);
+ if (*return_iplist != NULL) {
+ goto success;
}
close(sock);
+
+ if (timed_out) {
+ /* Timed out wating for WINS server to respond. Mark it dead. */
+ wins_srv_died(wins_ip);
+ } else {
+ /* The name definately isn't in this
+ group of WINS servers. goto the next group */
+ break;
+ }
}
}
+ wins_srv_tags_free(wins_tags);
return False;
+
+success:
+ wins_srv_tags_free(wins_tags);
+ close(sock);
+ return True;
}
/********************************************************
diff --git a/source3/nmbd/nmbd_nameregister.c b/source3/nmbd/nmbd_nameregister.c
index fc16db9e49..91b6f8b190 100644
--- a/source3/nmbd/nmbd_nameregister.c
+++ b/source3/nmbd/nmbd_nameregister.c
@@ -155,131 +155,193 @@ name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->su
remove_response_record(subrec, rrec);
}
+
+/****************************************************************************
+ Deal with a timeout of a WINS registration request
+****************************************************************************/
+static void wins_registration_timeout(struct subnet_record *subrec,
+ struct response_record *rrec)
+{
+ struct userdata_struct *userdata = rrec->userdata;
+
+ 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);
+
+ /* 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);
+
+ /* also update the UNICODE subnet IPs */
+ subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->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));
+ }
+
+ /* 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. */
+
+ /* 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;
+ rrec->in_expiration_processing = False;
+
+ DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
+ (int)rrec->repeat_interval));
+
+ /* 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 */
+}
+
+
/****************************************************************************
Deal with a timeout when registering one of our names.
****************************************************************************/
static void register_name_timeout_response(struct subnet_record *subrec,
- struct response_record *rrec)
+ struct response_record *rrec)
{
- /*
- * If we are registering unicast, then NOT getting a response is an
- * error - we do not have the name. If we are registering broadcast,
- * then we don't expect to get a response.
- */
+ /*
+ * If we are registering unicast, then NOT getting a response is an
+ * error - we do not have the name. If we are registering 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;
+ uint16 nb_flags = 0;
+ int ttl = 0;
+ struct in_addr registered_ip;
+
+ if (bcast) {
+ if(rrec->num_msgs == 0) {
+ /* Not receiving a message is success for broadcast registration. */
+ success = True;
+
+ /* Pull the success values from the original request packet. */
+ nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+ ttl = sent_nmb->additional->ttl;
+ putip(&registered_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;
+ }
- 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;
- uint16 nb_flags = 0;
- int ttl = 0;
- struct in_addr registered_ip;
+ /* we got responses, but timed out?? bizarre. Treat it as failure. */
+ }
- if(bcast)
- {
- if(rrec->num_msgs == 0)
- {
- /* Not receiving a message is success for broadcast registration. */
- success = True;
+ DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(question_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, question_name, nb_flags, ttl, registered_ip);
+ if( rrec->success_fn)
+ (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_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);
+ }
- /* Pull the success values from the original request packet. */
- nb_flags = get_nb_flags(sent_nmb->additional->rdata);
- ttl = sent_nmb->additional->ttl;
- putip(&registered_ip,&sent_nmb->additional->rdata[2]);
- }
- }
- else
- {
- /* Unicast - if no responses then it's an error. */
- if(rrec->num_msgs == 0)
- {
- 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. */
-
- /* 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;
- rrec->in_expiration_processing = False;
-
- DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
- (int)rrec->repeat_interval));
- return; /* Don't remove the response record. */
- }
- }
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
+}
- DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
- success ? "success" : "failure", nmb_namestr(question_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, question_name, nb_flags, ttl, registered_ip);
- if( rrec->success_fn)
- (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_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);
+/****************************************************************************
+initiate one multi-homed name registration packet
+****************************************************************************/
+static void multihomed_register_one(struct nmb_name *nmbname,
+ uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct in_addr ip,
+ const char *tag)
+{
+ struct userdata_struct *userdata;
+ struct in_addr wins_ip = wins_srv_ip_tag(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);
+
+ DEBUG(6,("Registering name %s with WINS server %s using tag '%s'\n",
+ nmb_namestr(nmbname), inet_ntoa(wins_ip), tag));
+
+ if (queue_register_multihomed_name(unicast_subnet,
+ register_name_response,
+ register_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ nmbname,
+ nb_flags,
+ ip,
+ wins_ip) == NULL) {
+ DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n",
+ nmb_namestr(nmbname), inet_ntoa(ip)));
+ }
}
/****************************************************************************
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)
{
- /*
- If we are adding a group name, we just send multiple
- register name packets to the WINS server (this is an
- internet group name.
-
- If we are adding a unique name, We need first to add
- our names to the unicast subnet namelist. This is
- because when a WINS server receives a multihomed
- registration request, the first thing it does is to
- send a name query to the registering machine, to see
- if it has put the name in it's local namelist.
- We need the name there so the query response code in
- nmbd_incomingrequests.c will find it.
-
- We are adding this name prematurely (we don't really
- have it yet), but as this is on the unicast subnet
- only we will get away with this (only the WINS server
- will ever query names from us on this subnet).
- */
-
+ /*
+ If we are adding a group name, we just send multiple
+ register name packets to the WINS server (this is an
+ internet group name.
+
+ If we are adding a unique name, We need first to add
+ our names to the unicast subnet namelist. This is
+ because when a WINS server receives a multihomed
+ registration request, the first thing it does is to
+ send a name query to the registering machine, to see
+ if it has put the name in it's local namelist.
+ We need the name there so the query response code in
+ nmbd_incomingrequests.c will find it.
+
+ We are adding this name prematurely (we don't really
+ have it yet), but as this is on the unicast subnet
+ only we will get away with this (only the WINS server
+ will ever query names from us on this subnet).
+ */
int num_ips=0;
- int i;
+ int i, t;
struct in_addr *ip_list = NULL;
struct subnet_record *subrec;
-
+ char **wins_tags;
+
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
num_ips++;
@@ -288,7 +350,7 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
return True;
}
- for( subrec = FIRST_SUBNET, i = 0;
+ for (subrec = FIRST_SUBNET, i = 0;
subrec;
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) {
ip_list[i] = subrec->myip;
@@ -298,26 +360,20 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
nb_flags, lp_max_ttl(), SELF_NAME,
num_ips, ip_list);
- /* Now try and register the name, num_ips times. On the last time use
- the given success and fail functions. */
-
- for (i = 0; i < num_ips; i++) {
- if (queue_register_multihomed_name( unicast_subnet,
- register_name_response,
- register_name_timeout_response,
- (i == num_ips - 1) ? success_fn : NULL,
- (i == num_ips - 1) ? fail_fn : NULL,
- NULL,
- nmbname,
- nb_flags,
- ip_list[i]) == NULL) {
- DEBUG(0,("multihomed_register_name: Failed to send packet trying to \
-register name %s IP %s\n", nmb_namestr(nmbname), inet_ntoa(ip_list[i]) ));
-
- SAFE_FREE(ip_list);
- return True;
+ /* 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]);
}
}
+
+ wins_srv_tags_free(wins_tags);
SAFE_FREE(ip_list);
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index b5741caae0..f0c8b755c9 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -519,64 +519,61 @@ struct response_record *queue_register_name( struct subnet_record *subrec,
}
/****************************************************************************
- Queue a multihomed register name packet to the broadcast address of a subnet.
+ Queue a multihomed register name packet to a given WINS server IP
****************************************************************************/
struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- register_name_success_function success_fn,
- register_name_fail_function fail_fn,
- struct userdata_struct *userdata,
- struct nmb_name *nmbname,
- uint16 nb_flags,
- struct in_addr register_ip)
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr register_ip,
+ struct in_addr wins_ip)
{
- struct packet_struct *p;
- struct response_record *rrec;
- BOOL ret;
-
- /* Sanity check. */
- if(subrec != unicast_subnet)
- {
- DEBUG(0,("queue_register_multihomed_name: should only be done on \
+ struct packet_struct *p;
+ struct response_record *rrec;
+ BOOL ret;
+
+ /* Sanity check. */
+ if(subrec != unicast_subnet) {
+ DEBUG(0,("queue_register_multihomed_name: should only be done on \
unicast subnet. subnet is %s\n.", subrec->subnet_name ));
- return NULL;
- }
+ return NULL;
+ }
- if(assert_check_subnet(subrec))
- return NULL;
+ if(assert_check_subnet(subrec))
+ return NULL;
- if(( p = create_and_init_netbios_packet(nmbname, False, True,
- subrec->bcast_ip)) == NULL)
- return NULL;
-
- if (nb_flags & NB_GROUP)
- ret = initiate_name_register_packet( p, nb_flags, &register_ip);
- else
- ret = initiate_multihomed_name_register_packet( p, nb_flags, &register_ip);
-
- if(ret == False)
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
+ if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
+ return NULL;
+
+ if (nb_flags & NB_GROUP)
+ ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+ else
+ ret = initiate_multihomed_name_register_packet(p, nb_flags, &register_ip);
+
+ if (ret == False) {
+ 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;
+ 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;
}
/****************************************************************************
diff --git a/source3/nsswitch/winbindd_wins.c b/source3/nsswitch/winbindd_wins.c
index a8b4566ba0..75d04349e6 100644
--- a/source3/nsswitch/winbindd_wins.c
+++ b/source3/nsswitch/winbindd_wins.c
@@ -92,20 +92,14 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
*count = 0;
- fd = wins_lookup_open_socket_in();
- if (fd == -1)
- return NULL;
-
- p = wins_srv_ip();
- if( !is_zero_ip(p) ) {
- ret = name_query(fd,name,0x20,False,True, p, count, &flags);
- goto out;
+ /* always try with wins first */
+ if (resolve_wins(name,0x20,&ret,count)) {
+ return ret;
}
- if (lp_wins_support()) {
- /* we are our own WINS server */
- ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags);
- goto out;
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1) {
+ return NULL;
}
/* uggh, we have to broadcast to each interface in turn */
@@ -113,12 +107,11 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
j >= 0;
j--) {
struct in_addr *bcast = iface_n_bcast(j);
- ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags);
+ ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL);
if (ret) break;
}
out:
-
close(fd);
return ret;
}
diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c
index 2ecdbf1c51..8b629f1132 100644
--- a/source3/nsswitch/wins.c
+++ b/source3/nsswitch/wins.c
@@ -115,7 +115,7 @@ static struct node_status *lookup_byaddr_backend(char *addr, int *count)
static struct in_addr *lookup_byname_backend(const char *name, int *count)
{
- int fd;
+ int fd = -1;
struct in_addr *ret = NULL;
struct in_addr p;
int j, flags = 0;
@@ -126,33 +126,24 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
*count = 0;
- fd = wins_lookup_open_socket_in();
- if (fd == -1)
- return NULL;
-
- p = wins_srv_ip();
- if( !is_zero_ip(p) ) {
- ret = name_query(fd,name,0x20,False,True, p, count, &flags);
- goto out;
+ /* always try with wins first */
+ if (resolve_wins(name,0x20,&ret,count)) {
+ return ret;
}
- if (lp_wins_support()) {
- /* we are our own WINS server */
- ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags);
- goto out;
+ fd = wins_lookup_open_socket_in();
+ if (fd == -1) {
+ return NULL;
}
/* uggh, we have to broadcast to each interface in turn */
- for (j=iface_count() - 1;
- j >= 0;
- j--) {
+ for (j=iface_count() - 1;j >= 0;j--) {
struct in_addr *bcast = iface_n_bcast(j);
- ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags);
+ ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL);
if (ret) break;
}
- out:
-
+out:
close(fd);
return ret;
}
diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c
index 2373beb0c9..8e4f5aab03 100644
--- a/source3/utils/nmblookup.c
+++ b/source3/utils/nmblookup.c
@@ -159,7 +159,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type)
d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr));
ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
use_bcast?True:recursion_desired,
- bcast_addr,&count, &flags);
+ bcast_addr,&count, &flags, NULL);
} else {
struct in_addr *bcast;
for (j=iface_count() - 1;
@@ -171,7 +171,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type)
ip_list = name_query(ServerFD,lookup,lookup_type,
use_bcast,
use_bcast?True:recursion_desired,
- *bcast,&count, &flags);
+ *bcast,&count, &flags, NULL);
}
}
diff --git a/source3/web/diagnose.c b/source3/web/diagnose.c
index fa550c61b6..e822474aab 100644
--- a/source3/web/diagnose.c
+++ b/source3/web/diagnose.c
@@ -34,7 +34,7 @@ BOOL nmbd_running(void)
interpret_addr("127.0.0.1"), True)) != -1) {
if ((ip_list = name_query(fd, "__SAMBA__", 0,
True, True, loopback_ip,
- &count, &flags)) != NULL) {
+ &count, &flags, NULL)) != NULL) {
SAFE_FREE(ip_list);
close(fd);
return True;