summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2005-02-08 01:09:21 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:09:36 -0500
commit998c856d9005cd8e1111a939db6fa7b25196b766 (patch)
treecc562247c591a12fbad4d9fce76c7e816636d511
parent2513ac33de03e4c92f6d4a10595db44700971bb8 (diff)
downloadsamba-998c856d9005cd8e1111a939db6fa7b25196b766.tar.gz
samba-998c856d9005cd8e1111a939db6fa7b25196b766.tar.bz2
samba-998c856d9005cd8e1111a939db6fa7b25196b766.zip
r5276: - added support for NBT_OPCODE_REFRESH2 (type 0x9)
- 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)
-rw-r--r--source4/nbt_server/interfaces.c25
-rw-r--r--source4/nbt_server/packet.c3
-rw-r--r--source4/nbt_server/query.c2
-rw-r--r--source4/nbt_server/register.c8
-rw-r--r--source4/nbt_server/winsclient.c141
5 files changed, 145 insertions, 34 deletions
diff --git a/source4/nbt_server/interfaces.c b/source4/nbt_server/interfaces.c
index 7572e4e336..3cb690b85d 100644
--- a/source4/nbt_server/interfaces.c
+++ b/source4/nbt_server/interfaces.c
@@ -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;
}
diff --git a/source4/nbt_server/packet.c b/source4/nbt_server/packet.c
index ac803f3d5e..a6df618a3f 100644
--- a/source4/nbt_server/packet.c
+++ b/source4/nbt_server/packet.c
@@ -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;
}
diff --git a/source4/nbt_server/query.c b/source4/nbt_server/query.c
index 28406081ea..2bcc2b1892 100644
--- a/source4/nbt_server/query.c
+++ b/source4/nbt_server/query.c
@@ -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);
diff --git a/source4/nbt_server/register.c b/source4/nbt_server/register.c
index b65bd6d5ac..3b7d57efaf 100644
--- a/source4/nbt_server/register.c
+++ b/source4/nbt_server/register.c
@@ -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;
}
diff --git a/source4/nbt_server/winsclient.c b/source4/nbt_server/winsclient.c
index 80168c9181..e941d77e28 100644
--- a/source4/nbt_server/winsclient.c
+++ b/source4/nbt_server/winsclient.c
@@ -28,20 +28,33 @@
#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;
@@ -51,28 +64,119 @@ static void nbtd_refresh_wins_handler(struct composite_context *c)
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;
}