From 2513ac33de03e4c92f6d4a10595db44700971bb8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 8 Feb 2005 01:05:41 +0000 Subject: r5275: - added support for NBT_OPCODE_MULTI_HOME_REG (opcode 0xf) for WINS name registrations - fixed a bug in the send queue handling on timeouts - added support for handling unexpected replies (replies to the wrong port) at the nbtsocket layer - added separate layer 2 code for wins refresh and wins registration (This used to be commit 2502b02898407e3262c09a5a4aa573c5f87b8f5f) --- source4/include/structs.h | 1 + source4/libcli/nbt/libnbt.h | 33 +++++++- source4/libcli/nbt/namerefresh.c | 4 +- source4/libcli/nbt/nameregister.c | 169 +++++++++++++++++++++++++++++++++++++- source4/libcli/nbt/nbtsocket.c | 28 ++++--- source4/librpc/idl/nbt.idl | 14 ++-- 6 files changed, 228 insertions(+), 21 deletions(-) (limited to 'source4') diff --git a/source4/include/structs.h b/source4/include/structs.h index d8164c9b06..1781ee09ec 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -159,6 +159,7 @@ struct nbt_name_register; struct nbt_name_refresh; struct nbt_name_register_bcast; struct nbt_name_refresh_wins; +struct nbt_name_register_wins; struct messaging_context; struct stream_connection; diff --git a/source4/libcli/nbt/libnbt.h b/source4/libcli/nbt/libnbt.h index c126f59280..63711490fe 100644 --- a/source4/libcli/nbt/libnbt.h +++ b/source4/libcli/nbt/libnbt.h @@ -113,7 +113,13 @@ struct nbt_name_socket { const char *, int ); void *private; } incoming; - + + /* what to do with unexpected replies */ + struct { + void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, + const char *, int ); + void *private; + } unexpected; }; @@ -161,6 +167,7 @@ struct nbt_name_register { uint16_t nb_flags; BOOL register_demand; BOOL broadcast; + BOOL multi_homed; uint32_t ttl; int timeout; /* in seconds */ int retries; @@ -184,9 +191,10 @@ struct nbt_name_register_bcast { } in; }; -/* wins name refresh with multiple wins servers to try and multiple + +/* wins name register with multiple wins servers to try and multiple addresses to register */ -struct nbt_name_refresh_wins { +struct nbt_name_register_wins { struct { struct nbt_name name; const char **wins_servers; @@ -201,6 +209,7 @@ struct nbt_name_refresh_wins { }; + /* a name refresh request */ struct nbt_name_refresh { struct { @@ -220,3 +229,21 @@ struct nbt_name_refresh { uint8_t rcode; } out; }; + +/* wins name refresh with multiple wins servers to try and multiple + addresses to register */ +struct nbt_name_refresh_wins { + struct { + struct nbt_name name; + const char **wins_servers; + const char **addresses; + uint16_t nb_flags; + uint32_t ttl; + } in; + struct { + const char *wins_server; + uint8_t rcode; + } out; +}; + + diff --git a/source4/libcli/nbt/namerefresh.c b/source4/libcli/nbt/namerefresh.c index d8dbede727..99d79054a6 100644 --- a/source4/libcli/nbt/namerefresh.c +++ b/source4/libcli/nbt/namerefresh.c @@ -141,8 +141,8 @@ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock, struct refresh_wins_state { struct nbt_name_socket *nbtsock; struct nbt_name_refresh *io; - char **wins_servers; - char **addresses; + const char **wins_servers; + const char **addresses; int address_idx; struct nbt_name_request *req; }; diff --git a/source4/libcli/nbt/nameregister.c b/source4/libcli/nbt/nameregister.c index 9e9a1e1710..b0ed1ae89c 100644 --- a/source4/libcli/nbt/nameregister.c +++ b/source4/libcli/nbt/nameregister.c @@ -40,7 +40,11 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock, packet->qdcount = 1; packet->arcount = 1; - packet->operation = NBT_OPCODE_REGISTER; + if (io->in.multi_homed) { + packet->operation = NBT_OPCODE_MULTI_HOME_REG; + } else { + packet->operation = NBT_OPCODE_REGISTER; + } if (io->in.broadcast) { packet->operation |= NBT_FLAG_BROADCAST; } @@ -221,6 +225,7 @@ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *n state->io->in.nb_flags = io->in.nb_flags; state->io->in.register_demand = False; state->io->in.broadcast = True; + state->io->in.multi_homed = False; state->io->in.ttl = io->in.ttl; state->io->in.timeout = 1; state->io->in.retries = 2; @@ -264,3 +269,165 @@ NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock, struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io); return nbt_name_register_bcast_recv(c); } + + +/* + a wins name register with multiple WINS servers and multiple + addresses to register. Try each WINS server in turn, until we get a + reply for each address +*/ +struct register_wins_state { + struct nbt_name_socket *nbtsock; + struct nbt_name_register *io; + const char **wins_servers; + const char **addresses; + int address_idx; + struct nbt_name_request *req; +}; + + +/* + state handler for WINS multi-homed multi-server name register +*/ +static void name_register_wins_handler(struct nbt_name_request *req) +{ + struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context); + struct register_wins_state *state = talloc_get_type(c->private, + struct register_wins_state); + NTSTATUS status; + + status = nbt_name_register_recv(state->req, state, state->io); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + /* the register timed out - try the next WINS server */ + state->wins_servers++; + state->address_idx = 0; + if (state->wins_servers[0] == NULL) { + c->state = SMBCLI_REQUEST_ERROR; + c->status = status; + goto done; + } + state->io->in.dest_addr = state->wins_servers[0]; + state->io->in.address = state->addresses[0]; + state->req = nbt_name_register_send(state->nbtsock, state->io); + if (state->req == NULL) { + c->state = SMBCLI_REQUEST_ERROR; + c->status = NT_STATUS_NO_MEMORY; + } else { + state->req->async.fn = name_register_wins_handler; + state->req->async.private = c; + } + } else if (!NT_STATUS_IS_OK(status)) { + c->state = SMBCLI_REQUEST_ERROR; + c->status = status; + } else { + if (state->io->out.rcode == 0 && + state->addresses[state->address_idx+1] != NULL) { + /* register our next address */ + state->io->in.address = state->addresses[++(state->address_idx)]; + state->req = nbt_name_register_send(state->nbtsock, state->io); + if (state->req == NULL) { + c->state = SMBCLI_REQUEST_ERROR; + c->status = NT_STATUS_NO_MEMORY; + } else { + state->req->async.fn = name_register_wins_handler; + state->req->async.private = c; + } + } else { + c->state = SMBCLI_REQUEST_DONE; + c->status = NT_STATUS_OK; + } + } + +done: + if (c->state >= SMBCLI_REQUEST_DONE && + c->async.fn) { + c->async.fn(c); + } +} + +/* + the async send call for a multi-server WINS register +*/ +struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock, + struct nbt_name_register_wins *io) +{ + struct composite_context *c; + struct register_wins_state *state; + + c = talloc_zero(nbtsock, struct composite_context); + if (c == NULL) goto failed; + + state = talloc(c, struct register_wins_state); + if (state == NULL) goto failed; + + state->io = talloc(state, struct nbt_name_register); + if (state->io == NULL) goto failed; + + state->wins_servers = str_list_copy(state, io->in.wins_servers); + if (state->wins_servers == NULL || + state->wins_servers[0] == NULL) goto failed; + + state->addresses = str_list_copy(state, io->in.addresses); + if (state->addresses == NULL || + state->addresses[0] == NULL) goto failed; + + state->io->in.name = io->in.name; + state->io->in.dest_addr = state->wins_servers[0]; + state->io->in.address = io->in.addresses[0]; + state->io->in.nb_flags = io->in.nb_flags; + state->io->in.broadcast = False; + state->io->in.register_demand = False; + state->io->in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?False:True; + state->io->in.ttl = io->in.ttl; + state->io->in.timeout = 3; + state->io->in.retries = 2; + + state->nbtsock = nbtsock; + state->address_idx = 0; + + state->req = nbt_name_register_send(nbtsock, state->io); + if (state->req == NULL) goto failed; + + state->req->async.fn = name_register_wins_handler; + state->req->async.private = c; + + c->private = state; + c->state = SMBCLI_REQUEST_SEND; + c->event_ctx = nbtsock->event_ctx; + + return c; + +failed: + talloc_free(c); + return NULL; +} + +/* + multi-homed WINS name register - recv side +*/ +NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, + struct nbt_name_register_wins *io) +{ + NTSTATUS status; + status = composite_wait(c); + if (NT_STATUS_IS_OK(status)) { + struct register_wins_state *state = + talloc_get_type(c->private, struct register_wins_state); + io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]); + io->out.rcode = state->io->out.rcode; + } + talloc_free(c); + return status; +} + +/* + multi-homed WINS register - sync interface +*/ +NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock, + TALLOC_CTX *mem_ctx, + struct nbt_name_register_wins *io) +{ + struct composite_context *c = nbt_name_register_wins_send(nbtsock, io); + return nbt_name_register_wins_recv(c, mem_ctx, io); +} diff --git a/source4/libcli/nbt/nbtsocket.c b/source4/libcli/nbt/nbtsocket.c index 38b356338c..c771d3b4f5 100644 --- a/source4/libcli/nbt/nbtsocket.c +++ b/source4/libcli/nbt/nbtsocket.c @@ -82,10 +82,10 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock) } DLIST_REMOVE(nbtsock->send_queue, req); + req->state = NBT_REQUEST_WAIT; if (req->is_reply) { talloc_free(req); } else { - req->state = NBT_REQUEST_WAIT; EVENT_FD_READABLE(nbtsock->fde); nbtsock->num_pending++; } @@ -122,7 +122,11 @@ static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event req->te = event_add_timed(req->nbtsock->event_ctx, req, timeval_add(&t, req->timeout, 0), nbt_name_socket_timeout, req); - DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *); + if (req->state != NBT_REQUEST_SEND) { + req->state = NBT_REQUEST_SEND; + DLIST_ADD_END(req->nbtsock->send_queue, req, + struct nbt_name_request *); + } EVENT_FD_WRITEABLE(req->nbtsock->fde); return; } @@ -206,8 +210,12 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock) /* find the matching request */ req = idr_find(nbtsock->idr, packet->name_trn_id); if (req == NULL) { - DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n", - packet->name_trn_id)); + if (nbtsock->unexpected.handler) { + nbtsock->unexpected.handler(nbtsock, packet, src_addr, src_port); + } else { + DEBUG(2,("Failed to match request for incoming name packet id 0x%04x on %p\n", + packet->name_trn_id, nbtsock)); + } talloc_free(tmp_ctx); return; } @@ -227,13 +235,11 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock) req->num_retries = 0; req->received_wack = True; if (packet->answers[0].ttl != 0) { - req->timeout = MIN(packet->answers[0].ttl, 20); + req->timeout = MIN(packet->answers[0].ttl, 20); } - req->te = event_add_timed(req->nbtsock->event_ctx, req, - timeval_current_ofs(req->timeout, 0), - nbt_name_socket_timeout, req); - DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *); - EVENT_FD_WRITEABLE(req->nbtsock->fde); + req->te = event_add_timed(req->nbtsock->event_ctx, req, + timeval_current_ofs(req->timeout, 0), + nbt_name_socket_timeout, req); talloc_free(tmp_ctx); return; } @@ -319,6 +325,7 @@ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx, nbtsock->send_queue = NULL; nbtsock->num_pending = 0; nbtsock->incoming.handler = NULL; + nbtsock->unexpected.handler = NULL; nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock, socket_get_fd(nbtsock->sock), 0, @@ -375,6 +382,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock, UINT16_MAX); } if (id == -1) goto failed; + request->name_trn_id = id; req->name_trn_id = id; diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl index 08dde1f018..859cecd593 100644 --- a/source4/librpc/idl/nbt.idl +++ b/source4/librpc/idl/nbt.idl @@ -26,11 +26,15 @@ interface nbt /* the opcodes are in the operation field, masked with NBT_OPCODE */ - const int NBT_OPCODE_QUERY = (0<<11); - const int NBT_OPCODE_REGISTER = (5<<11); - const int NBT_OPCODE_RELEASE = (6<<11); - const int NBT_OPCODE_WACK = (7<<11); - const int NBT_OPCODE_REFRESH = (8<<11); + typedef enum { + NBT_OPCODE_QUERY = (0x0<<11), + NBT_OPCODE_REGISTER = (0x5<<11), + NBT_OPCODE_RELEASE = (0x6<<11), + NBT_OPCODE_WACK = (0x7<<11), + NBT_OPCODE_REFRESH = (0x8<<11), + NBT_OPCODE_REFRESH2 = (0x9<<11), + NBT_OPCODE_MULTI_HOME_REG = (0xf<<11) + } nbt_opcode; /* rcode values */ typedef enum { -- cgit