r5276: - added support for NBT_OPCODE_REFRESH2 (type 0x9)
authorAndrew Tridgell <tridge@samba.org>
Tue, 8 Feb 2005 01:09:21 +0000 (01:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:36 +0000 (13:09 -0500)
- when registering with a WINS server, initially use multi-homed
  registration, then switch to name refresh requests. Send refresh
  requests only to the WINS server that responded to our
  registration. If that server goes away, then start the registration
  from scratch. This makes registration more robust to WINS server
  failure.

- send WINS registration requests out on our first interface rather
  than an unbound interface, to avoid the problem of WACK replies
  being sent to the wrong port (w2k3 WINS server does this)
(This used to be commit f7712ac7468184c07b3e3c10cb7b847ad1791dd2)

source4/nbt_server/interfaces.c
source4/nbt_server/packet.c
source4/nbt_server/query.c
source4/nbt_server/register.c
source4/nbt_server/winsclient.c

index 7572e4e336cae43165836da1c532e9c98e9ce1a0..3cb690b85df0a15e2e346388f1b830b67f7674c1 100644 (file)
@@ -49,13 +49,14 @@ static void nbtd_request_handler(struct nbt_name_socket *nbtsock,
        }
 
        /* the request is to us in our role as a B node */
-       switch (packet->operation & NBT_OPCODE) {
+       switch ((enum nbt_opcode)(packet->operation & NBT_OPCODE)) {
        case NBT_OPCODE_QUERY:
                nbtd_request_query(nbtsock, packet, src_address, src_port);
                break;
 
        case NBT_OPCODE_REGISTER:
        case NBT_OPCODE_REFRESH:
+       case NBT_OPCODE_REFRESH2:
                nbtd_request_defense(nbtsock, packet, src_address, src_port);
                break;
 
@@ -165,9 +166,6 @@ static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
 
        iface->nbtsrv        = nbtsrv;
 
-       iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
-       NT_STATUS_HAVE_NO_MEMORY(iface->nbtsock);
-
        DLIST_ADD(nbtsrv->wins_interface, iface);
 
        return NT_STATUS_OK;
@@ -238,21 +236,24 @@ const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx
        struct nbtd_server *nbtsrv = iface->nbtsrv;
        const char **ret = NULL;
        struct nbtd_interface *iface2;
-       int count;
+       int count = 0;
 
-       ret = talloc_array(mem_ctx, const char *, 2);
-       if (ret == NULL) goto failed;
+       if (iface->ip_address) {
+               ret = talloc_array(mem_ctx, const char *, 2);
+               if (ret == NULL) goto failed;
 
-       ret[0] = talloc_strdup(ret, iface->ip_address);
-       if (ret[0] == NULL) goto failed;
-       ret[1] = NULL;
+               ret[0] = talloc_strdup(ret, iface->ip_address);
+               if (ret[0] == NULL) goto failed;
+               ret[1] = NULL;
 
-       count = 1;
+               count = 1;
+       }
 
        for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
                const char **ret2;
 
-               if (strcmp(iface2->ip_address, iface->ip_address) == 0) {
+               if (iface->ip_address &&
+                   strcmp(iface2->ip_address, iface->ip_address) == 0) {
                        continue;
                }
 
index ac803f3d5ee4fcb83bcb16dc524c0c2b5b8f2d41..a6df618a3f53b0caf09212959f1ad10520eb6b11 100644 (file)
@@ -61,7 +61,8 @@ BOOL nbtd_self_packet(struct nbt_name_socket *nbtsock,
 
        /* this uses the fact that iface->nbtsock is our non-broadcast
           listen address */
-       if (iface->nbtsock == nbtsock) {
+       if (iface->nbtsock == nbtsock &&
+           iface != iface->nbtsrv->bcast_interface) {
                return False;
        }
 
index 28406081eaf8ec4c5ca93c28f1d3e810fc699298..2bcc2b1892afc68f1fdf2cc581a2792889a4032f 100644 (file)
@@ -76,7 +76,7 @@ static void nbtd_name_query_reply(struct nbt_name_socket *nbtsock,
        }
 
        DEBUG(7,("Sending name query reply for %s<%02x> at %s to %s:%d\n", 
-                name->name, name->type, src_address, addresses[0], src_port));
+                name->name, name->type, addresses[0], src_address, src_port));
        
        nbt_name_reply_send(nbtsock, src_address, src_port, packet);
 
index b65bd6d5acd7a802b335e72a2eb35668a3e6efe3..3b7d57efaf061c6f2b4aa0e3f7ffb21d83289c9a 100644 (file)
@@ -56,9 +56,10 @@ static void refresh_completion_handler(struct nbt_name_request *req)
        iname->nb_flags &= ~NBT_NM_ACTIVE;
 
        if (NT_STATUS_IS_OK(status)) {
-               DEBUG(1,("Name conflict from %s refreshing name %s<%02x> on %s - rcode %d\n", 
+               DEBUG(1,("Name conflict from %s refreshing name %s<%02x> on %s - %s\n", 
                         io.out.reply_addr, iname->name.name, iname->name.type, 
-                        iname->iface->ip_address, io.out.rcode));
+                        iname->iface->ip_address, 
+                        nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
        } else {
                DEBUG(1,("Error refreshing name %s<%02x> on %s - %s\n", 
                         iname->name.name, iname->name.type, iname->iface->ip_address,
@@ -92,6 +93,7 @@ static void name_refresh_handler(struct event_context *ev, struct timed_event *t
        io.in.ttl             = iname->ttl;
        io.in.register_demand = False;
        io.in.broadcast       = True;
+       io.in.multi_homed     = False;
        io.in.timeout         = 3;
        io.in.retries         = 0;
 
@@ -189,7 +191,7 @@ static void nbtd_register_name_iface(struct nbtd_interface *iface,
        /* if this is the wins interface, then we need to do a special
           wins name registration */
        if (iface == iface->nbtsrv->wins_interface) {
-               nbtd_winsclient_refresh(iname);
+               nbtd_winsclient_register(iname);
                return;
        }
 
index 80168c9181fd07cb35316ce05f048b2e18caebed..e941d77e2882d178c5523870e4c63b2b71bb123f 100644 (file)
 #include "smbd/service_task.h"
 
 
+/* we send WINS client requests using our primary network interface 
+*/
+static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface)
+{
+       struct nbtd_server *nbtsrv = iface->nbtsrv;
+       return nbtsrv->interfaces->nbtsock;
+}
+
+
+static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
+                             struct timeval t, void *private);
+
 /*
-  refresh a WINS name registration
+  retry a WINS name registration
 */
-static void nbtd_refresh_wins_refresh(struct event_context *ev, struct timed_event *te,
-                                      struct timeval t, void *private)
+static void nbtd_wins_register_retry(struct event_context *ev, struct timed_event *te,
+                                    struct timeval t, void *private)
 {
        struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name);
-       nbtd_winsclient_refresh(iname);
+       nbtd_winsclient_register(iname);
 }
 
+
 /*
   called when a wins name refresh has completed
 */
-static void nbtd_refresh_wins_handler(struct composite_context *c)
+static void nbtd_wins_refresh_handler(struct composite_context *c)
 {
        NTSTATUS status;
        struct nbt_name_refresh_wins io;
@@ -50,29 +63,120 @@ static void nbtd_refresh_wins_handler(struct composite_context *c)
        TALLOC_CTX *tmp_ctx = talloc_new(iname);
 
        status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               /* our WINS server is dead - start registration over
+                  from scratch */
+               DEBUG(2,("Failed to refresh %s<%02x> with WINS server %s\n",
+                        iname->name.name, iname->name.type, iname->wins_server));
+               nbtd_winsclient_register(iname);
+               return;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("Name refresh failure with WINS for %s<%02x> - %s\n", 
+                        iname->name.name, iname->name.type, nt_errstr(status)));
+               talloc_free(tmp_ctx);
+               return;
+       }       
+
+       if (io.out.rcode != 0) {
+               DEBUG(1,("WINS server %s rejected name refresh of %s<%02x> - %s\n", 
+                        io.out.wins_server, iname->name.name, iname->name.type, 
+                        nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
+               iname->nb_flags |= NBT_NM_CONFLICT;
+               talloc_free(tmp_ctx);
+               return;
+       }       
+
+       DEBUG(4,("Refreshed name %s<%02x> with WINS server %s\n",
+                iname->name.name, iname->name.type, iname->wins_server));
+       /* success - start a periodic name refresh */
+       iname->nb_flags |= NBT_NM_ACTIVE;
+       if (iname->wins_server) {
+               talloc_free(iname->wins_server);
+       }
+       iname->wins_server = talloc_steal(iname, io.out.wins_server);
+
+       iname->registration_time = timeval_current();
+       event_add_timed(iname->iface->nbtsrv->task->event_ctx, 
+                       iname,
+                       timeval_add(&iname->registration_time, iname->ttl/2, 0),
+                       nbtd_wins_refresh,
+                       iname);
+
+       talloc_free(tmp_ctx);
+}
+
+
+/*
+  refresh a WINS name registration
+*/
+static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
+                             struct timeval t, void *private)
+{
+       struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name);
+       struct nbtd_interface *iface = iname->iface;
+       struct nbt_name_refresh_wins io;
+       struct composite_context *c;
+       TALLOC_CTX *tmp_ctx = talloc_new(iname);
+
+       /* setup a wins name refresh request */
+       io.in.name            = iname->name;
+       io.in.wins_servers    = str_list_make(tmp_ctx, iname->wins_server, NULL);
+       io.in.addresses       = nbtd_address_list(iface, tmp_ctx);
+       io.in.nb_flags        = iname->nb_flags;
+       io.in.ttl             = iname->ttl;
+
+       c = nbt_name_refresh_wins_send(wins_socket(iface), &io);
+       if (c == NULL) {
+               talloc_free(tmp_ctx);
+               return;
+       }
+       talloc_steal(c, io.in.addresses);
+
+       c->async.fn = nbtd_wins_refresh_handler;
+       c->async.private = iname;
+
+       talloc_free(tmp_ctx);
+}
+
+
+/*
+  called when a wins name register has completed
+*/
+static void nbtd_wins_register_handler(struct composite_context *c)
+{
+       NTSTATUS status;
+       struct nbt_name_register_wins io;
+       struct nbtd_iface_name *iname = talloc_get_type(c->async.private, 
+                                                       struct nbtd_iface_name);
+       TALLOC_CTX *tmp_ctx = talloc_new(iname);
+
+       status = nbt_name_register_wins_recv(c, tmp_ctx, &io);
        if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
                /* none of the WINS servers responded - try again 
                   periodically */
-               int wins_retry_time = lp_parm_int(-1, "nbt", "wins_retry", 300);
+               int wins_retry_time = lp_parm_int(-1, "nbtd", "wins_retry", 300);
                event_add_timed(iname->iface->nbtsrv->task->event_ctx, 
                                iname,
                                timeval_current_ofs(wins_retry_time, 0),
-                               nbtd_refresh_wins_refresh,
+                               nbtd_wins_register_retry,
                                iname);
                talloc_free(tmp_ctx);
                return;
        }
 
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1,("Name refresh failure with WINS for %s<%02x> - %s\n", 
+               DEBUG(1,("Name register failure with WINS for %s<%02x> - %s\n", 
                         iname->name.name, iname->name.type, nt_errstr(status)));
                talloc_free(tmp_ctx);
                return;
        }       
 
        if (io.out.rcode != 0) {
-               DEBUG(1,("WINS server %s rejected name refresh of %s<%02x> - rcode %d\n", 
-                        io.out.wins_server, iname->name.name, iname->name.type, io.out.rcode));
+               DEBUG(1,("WINS server %s rejected name register of %s<%02x> - %s\n", 
+                        io.out.wins_server, iname->name.name, iname->name.type, 
+                        nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
                iname->nb_flags |= NBT_NM_CONFLICT;
                talloc_free(tmp_ctx);
                return;
@@ -89,35 +193,38 @@ static void nbtd_refresh_wins_handler(struct composite_context *c)
        event_add_timed(iname->iface->nbtsrv->task->event_ctx, 
                        iname,
                        timeval_add(&iname->registration_time, iname->ttl/2, 0),
-                       nbtd_refresh_wins_refresh,
+                       nbtd_wins_refresh,
                        iname);
 
+       DEBUG(3,("Registered %s<%02x> with WINS server %s\n",
+                iname->name.name, iname->name.type, iname->wins_server));
+
        talloc_free(tmp_ctx);
 }
 
 /*
-  refresh a name with our WINS servers
+  register a name with our WINS servers
 */
-void nbtd_winsclient_refresh(struct nbtd_iface_name *iname)
+void nbtd_winsclient_register(struct nbtd_iface_name *iname)
 {
        struct nbtd_interface *iface = iname->iface;
-       struct nbt_name_refresh_wins io;
+       struct nbt_name_register_wins io;
        struct composite_context *c;
 
-       /* setup a wins name refresh request */
+       /* setup a wins name register request */
        io.in.name            = iname->name;
        io.in.wins_servers    = lp_wins_server_list();
        io.in.addresses       = nbtd_address_list(iface, iname);
        io.in.nb_flags        = iname->nb_flags;
        io.in.ttl             = iname->ttl;
 
-       c = nbt_name_refresh_wins_send(iface->nbtsock, &io);
+       c = nbt_name_register_wins_send(wins_socket(iface), &io);
        if (c == NULL) {
                talloc_free(io.in.addresses);
                return;
        }
        talloc_steal(c, io.in.addresses);
 
-       c->async.fn = nbtd_refresh_wins_handler;
+       c->async.fn = nbtd_wins_register_handler;
        c->async.private = iname;
 }