diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-02-08 01:09:21 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:09:36 -0500 |
commit | 998c856d9005cd8e1111a939db6fa7b25196b766 (patch) | |
tree | cc562247c591a12fbad4d9fce76c7e816636d511 /source4/nbt_server | |
parent | 2513ac33de03e4c92f6d4a10595db44700971bb8 (diff) | |
download | samba-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)
Diffstat (limited to 'source4/nbt_server')
-rw-r--r-- | source4/nbt_server/interfaces.c | 25 | ||||
-rw-r--r-- | source4/nbt_server/packet.c | 3 | ||||
-rw-r--r-- | source4/nbt_server/query.c | 2 | ||||
-rw-r--r-- | source4/nbt_server/register.c | 8 | ||||
-rw-r--r-- | source4/nbt_server/winsclient.c | 141 |
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; } |