diff options
Diffstat (limited to 'source4/libcli/resolve')
-rw-r--r-- | source4/libcli/resolve/bcast.c | 115 | ||||
-rw-r--r-- | source4/libcli/resolve/host.c | 225 | ||||
-rw-r--r-- | source4/libcli/resolve/nbtlist.c | 216 | ||||
-rw-r--r-- | source4/libcli/resolve/resolve.c | 225 | ||||
-rw-r--r-- | source4/libcli/resolve/resolve.h | 32 | ||||
-rw-r--r-- | source4/libcli/resolve/resolve_lp.c | 46 | ||||
-rw-r--r-- | source4/libcli/resolve/testsuite.c | 90 | ||||
-rw-r--r-- | source4/libcli/resolve/wins.c | 95 |
8 files changed, 1044 insertions, 0 deletions
diff --git a/source4/libcli/resolve/bcast.c b/source4/libcli/resolve/bcast.c new file mode 100644 index 0000000000..2e2eb05397 --- /dev/null +++ b/source4/libcli/resolve/bcast.c @@ -0,0 +1,115 @@ +/* + Unix SMB/CIFS implementation. + + broadcast name resolution module + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/resolve/resolve.h" +#include "system/network.h" +#include "lib/socket/netif.h" +#include "param/param.h" + +struct resolve_bcast_data { + struct interface *ifaces; + uint16_t nbt_port; + int nbt_timeout; +}; + +/** + broadcast name resolution method - async send + */ +struct composite_context *resolve_name_bcast_send(TALLOC_CTX *mem_ctx, + struct event_context *event_ctx, + void *userdata, + struct nbt_name *name) +{ + int num_interfaces; + const char **address_list; + struct composite_context *c; + int i, count=0; + struct resolve_bcast_data *data = talloc_get_type(userdata, struct resolve_bcast_data); + + num_interfaces = iface_count(data->ifaces); + + address_list = talloc_array(mem_ctx, const char *, num_interfaces+1); + if (address_list == NULL) return NULL; + + for (i=0;i<num_interfaces;i++) { + const char *bcast = iface_n_bcast(data->ifaces, i); + if (bcast == NULL) continue; + address_list[count] = talloc_strdup(address_list, bcast); + if (address_list[count] == NULL) { + talloc_free(address_list); + return NULL; + } + count++; + } + address_list[count] = NULL; + + c = resolve_name_nbtlist_send(mem_ctx, event_ctx, name, address_list, data->ifaces, data->nbt_port, data->nbt_timeout, true, false); + talloc_free(address_list); + + return c; +} + +/* + broadcast name resolution method - recv side + */ +NTSTATUS resolve_name_bcast_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + return resolve_name_nbtlist_recv(c, mem_ctx, reply_addr); +} + +/* + broadcast name resolution method - sync call + */ +NTSTATUS resolve_name_bcast(struct nbt_name *name, + TALLOC_CTX *mem_ctx, + struct interface *ifaces, + uint16_t nbt_port, + int nbt_timeout, + const char **reply_addr) +{ + struct resolve_bcast_data *data = talloc(mem_ctx, struct resolve_bcast_data); + struct composite_context *c; + data->ifaces = talloc_reference(data, ifaces); + data->nbt_port = nbt_port; + data->nbt_timeout = nbt_timeout; + + c = resolve_name_bcast_send(mem_ctx, NULL, data, name); + return resolve_name_bcast_recv(c, mem_ctx, reply_addr); +} + +bool resolve_context_add_bcast_method(struct resolve_context *ctx, struct interface *ifaces, uint16_t nbt_port, int nbt_timeout) +{ + struct resolve_bcast_data *data = talloc(ctx, struct resolve_bcast_data); + data->ifaces = ifaces; + data->nbt_port = nbt_port; + data->nbt_timeout = nbt_timeout; + return resolve_context_add_method(ctx, resolve_name_bcast_send, resolve_name_bcast_recv, data); +} + +bool resolve_context_add_bcast_method_lp(struct resolve_context *ctx, struct loadparm_context *lp_ctx) +{ + struct interface *ifaces; + load_interfaces(ctx, lp_interfaces(lp_ctx), &ifaces); + return resolve_context_add_bcast_method(ctx, ifaces, lp_nbt_port(lp_ctx), lp_parm_int(lp_ctx, NULL, "nbt", "timeout", 1)); +} diff --git a/source4/libcli/resolve/host.c b/source4/libcli/resolve/host.c new file mode 100644 index 0000000000..1a695432ee --- /dev/null +++ b/source4/libcli/resolve/host.c @@ -0,0 +1,225 @@ +/* + Unix SMB/CIFS implementation. + + async gethostbyname() name resolution module + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + this module uses a fork() per gethostbyname() call. At first that + might seem crazy, but it is actually very fast, and solves many of + the tricky problems of keeping a child hanging around in a library + (like what happens when the parent forks). We use a talloc + destructor to ensure that the child is cleaned up when we have + finished with this name resolution. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "system/network.h" +#include "system/filesys.h" +#include "libcli/composite/composite.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "libcli/resolve/resolve.h" + +struct host_state { + struct nbt_name name; + const char *reply_addr; + pid_t child; + int child_fd; + struct fd_event *fde; + struct event_context *event_ctx; +}; + + +/* + kill off a wayward child if needed. This allows us to stop an async + name resolution without leaving a potentially blocking call running + in a child +*/ +static int host_destructor(struct host_state *state) +{ + close(state->child_fd); + if (state->child != (pid_t)-1) { + kill(state->child, SIGTERM); + } + return 0; +} + +/* + the blocking child +*/ +static void run_child(struct composite_context *c, int fd) +{ + struct host_state *state = talloc_get_type(c->private_data, struct host_state); + struct in_addr ip; + const char *address; + + /* this is the blocking call we are going to lots of trouble + to avoid in the parent */ + ip = interpret_addr2(state->name.name); + + address = inet_ntoa(ip); + if (address != NULL) { + write(fd, address, strlen(address)+1); + } + close(fd); +} + +/* + handle a read event on the pipe +*/ +static void pipe_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *private_data) +{ + struct composite_context *c = talloc_get_type(private_data, struct composite_context); + struct host_state *state = talloc_get_type(c->private_data, struct host_state); + char address[128]; + int ret; + + /* if we get any event from the child then we know that we + won't need to kill it off */ + state->child = (pid_t)-1; + + /* yes, we don't care about EAGAIN or other niceities + here. They just can't happen with this parent/child + relationship, and even if they did then giving an error is + the right thing to do */ + ret = read(state->child_fd, address, sizeof(address)-1); + if (ret <= 0) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + /* enusre the address looks good */ + address[ret] = 0; + if (strcmp(address, "0.0.0.0") == 0 || + inet_addr(address) == INADDR_NONE) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + state->reply_addr = talloc_strdup(state, address); + if (composite_nomem(state->reply_addr, c)) return; + + composite_done(c); +} + +/* + gethostbyname name resolution method - async send + */ +struct composite_context *resolve_name_host_send(TALLOC_CTX *mem_ctx, + struct event_context *event_ctx, + void *privdata, + struct nbt_name *name) +{ + struct composite_context *c; + struct host_state *state; + int fd[2] = { -1, -1 }; + int ret; + + c = composite_create(mem_ctx, event_ctx); + if (c == NULL) return NULL; + + if (composite_nomem(c->event_ctx, c)) return c; + + state = talloc(c, struct host_state); + if (composite_nomem(state, c)) return c; + c->private_data = state; + + c->status = nbt_name_dup(state, name, &state->name); + if (!composite_is_ok(c)) return c; + + /* setup a pipe to chat to our child */ + ret = pipe(fd); + if (ret == -1) { + composite_error(c, map_nt_error_from_unix(errno)); + return c; + } + + state->child_fd = fd[0]; + state->event_ctx = c->event_ctx; + + /* we need to put the child in our event context so + we know when the gethostbyname() has finished */ + state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ, + pipe_handler, c); + if (composite_nomem(state->fde, c)) { + close(fd[0]); + close(fd[1]); + return c; + } + + /* signal handling in posix really sucks - doing this in a library + affects the whole app, but what else to do?? */ + signal(SIGCHLD, SIG_IGN); + + state->child = fork(); + if (state->child == (pid_t)-1) { + composite_error(c, map_nt_error_from_unix(errno)); + return c; + } + + + if (state->child == 0) { + close(fd[0]); + run_child(c, fd[1]); + _exit(0); + } + close(fd[1]); + + /* cleanup wayward children */ + talloc_set_destructor(state, host_destructor); + + return c; +} + +/* + gethostbyname name resolution method - recv side +*/ +NTSTATUS resolve_name_host_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + NTSTATUS status; + + status = composite_wait(c); + + if (NT_STATUS_IS_OK(status)) { + struct host_state *state = talloc_get_type(c->private_data, struct host_state); + *reply_addr = talloc_steal(mem_ctx, state->reply_addr); + } + + talloc_free(c); + return status; +} + +/* + gethostbyname name resolution method - sync call + */ +NTSTATUS resolve_name_host(struct nbt_name *name, + TALLOC_CTX *mem_ctx, + const char **reply_addr) +{ + struct composite_context *c = resolve_name_host_send(mem_ctx, NULL, NULL, name); + return resolve_name_host_recv(c, mem_ctx, reply_addr); +} + +bool resolve_context_add_host_method(struct resolve_context *ctx) +{ + return resolve_context_add_method(ctx, resolve_name_host_send, resolve_name_host_recv, + NULL); +} diff --git a/source4/libcli/resolve/nbtlist.c b/source4/libcli/resolve/nbtlist.c new file mode 100644 index 0000000000..8f085c5404 --- /dev/null +++ b/source4/libcli/resolve/nbtlist.c @@ -0,0 +1,216 @@ +/* + Unix SMB/CIFS implementation. + + nbt list of addresses name resolution module + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + TODO: we should lower the timeout, and add retries for each name +*/ + +#include "includes.h" +#include "libcli/composite/composite.h" +#include "system/network.h" +#include "lib/socket/netif.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "libcli/nbt/libnbt.h" +#include "param/param.h" + +struct nbtlist_state { + struct nbt_name name; + struct nbt_name_socket *nbtsock; + int num_queries; + struct nbt_name_request **queries; + struct nbt_name_query *io_queries; + const char *reply_addr; + struct interface *ifaces; +}; + +/* + handle events during nbtlist name resolution +*/ +static void nbtlist_handler(struct nbt_name_request *req) +{ + struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context); + struct nbtlist_state *state = talloc_get_type(c->private_data, struct nbtlist_state); + struct nbt_name_query *q; + int i; + + for (i=0;i<state->num_queries;i++) { + if (req == state->queries[i]) break; + } + + if (i == state->num_queries) { + /* not for us?! */ + composite_error(c, NT_STATUS_INTERNAL_ERROR); + return; + } + + q = &state->io_queries[i]; + + c->status = nbt_name_query_recv(req, state, q); + + /* free the network resource directly */ + talloc_free(state->nbtsock); + if (!composite_is_ok(c)) return; + + if (state->io_queries[i].out.num_addrs < 1) { + composite_error(c, NT_STATUS_UNEXPECTED_NETWORK_ERROR); + return; + } + + /* favor a local address if possible */ + state->reply_addr = NULL; + for (i=0;i<q->out.num_addrs;i++) { + if (iface_is_local(state->ifaces, q->out.reply_addrs[i])) { + state->reply_addr = talloc_steal(state, + q->out.reply_addrs[i]); + break; + } + } + + if (state->reply_addr == NULL) { + state->reply_addr = talloc_steal(state, + q->out.reply_addrs[0]); + } + + composite_done(c); +} + +/* + nbtlist name resolution method - async send + */ +struct composite_context *resolve_name_nbtlist_send(TALLOC_CTX *mem_ctx, + struct event_context *event_ctx, + struct nbt_name *name, + const char **address_list, + struct interface *ifaces, + uint16_t nbt_port, + int nbt_timeout, + bool broadcast, + bool wins_lookup) +{ + struct composite_context *c; + struct nbtlist_state *state; + int i; + + c = composite_create(mem_ctx, event_ctx); + if (c == NULL) return NULL; + + if (composite_nomem(c->event_ctx, c)) return c; + + state = talloc(c, struct nbtlist_state); + if (composite_nomem(state, c)) return c; + c->private_data = state; + + c->status = nbt_name_dup(state, name, &state->name); + if (!composite_is_ok(c)) return c; + + state->name.name = strupper_talloc(state, state->name.name); + if (composite_nomem(state->name.name, c)) return c; + if (state->name.scope) { + state->name.scope = strupper_talloc(state, state->name.scope); + if (composite_nomem(state->name.scope, c)) return c; + } + + state->ifaces = talloc_reference(state, ifaces); + + /* + * we can't push long names on the wire, + * so bail out here to give a useful error message + */ + if (strlen(state->name.name) > 15) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return c; + } + + state->nbtsock = nbt_name_socket_init(state, event_ctx, + lp_iconv_convenience(global_loadparm)); + if (composite_nomem(state->nbtsock, c)) return c; + + /* count the address_list size */ + for (i=0;address_list[i];i++) /* noop */ ; + + state->num_queries = i; + state->io_queries = talloc_array(state, struct nbt_name_query, state->num_queries); + if (composite_nomem(state->io_queries, c)) return c; + + state->queries = talloc_array(state, struct nbt_name_request *, state->num_queries); + if (composite_nomem(state->queries, c)) return c; + + for (i=0;i<state->num_queries;i++) { + state->io_queries[i].in.name = state->name; + state->io_queries[i].in.dest_addr = talloc_strdup(state->io_queries, address_list[i]); + state->io_queries[i].in.dest_port = nbt_port; + if (composite_nomem(state->io_queries[i].in.dest_addr, c)) return c; + + state->io_queries[i].in.broadcast = broadcast; + state->io_queries[i].in.wins_lookup = wins_lookup; + state->io_queries[i].in.timeout = nbt_timeout; + state->io_queries[i].in.retries = 2; + + state->queries[i] = nbt_name_query_send(state->nbtsock, &state->io_queries[i]); + if (composite_nomem(state->queries[i], c)) return c; + + state->queries[i]->async.fn = nbtlist_handler; + state->queries[i]->async.private = c; + } + + return c; +} + +/* + nbt list of addresses name resolution method - recv side + */ +NTSTATUS resolve_name_nbtlist_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + NTSTATUS status; + + status = composite_wait(c); + + if (NT_STATUS_IS_OK(status)) { + struct nbtlist_state *state = talloc_get_type(c->private_data, struct nbtlist_state); + *reply_addr = talloc_steal(mem_ctx, state->reply_addr); + } + + talloc_free(c); + return status; +} + +/* + nbt list of addresses name resolution method - sync call + */ +NTSTATUS resolve_name_nbtlist(struct nbt_name *name, + TALLOC_CTX *mem_ctx, + const char **address_list, + struct interface *ifaces, + uint16_t nbt_port, + int nbt_timeout, + bool broadcast, bool wins_lookup, + const char **reply_addr) +{ + struct composite_context *c = resolve_name_nbtlist_send(mem_ctx, NULL, + name, address_list, + ifaces, nbt_port, + nbt_timeout, + broadcast, wins_lookup); + return resolve_name_nbtlist_recv(c, mem_ctx, reply_addr); +} + diff --git a/source4/libcli/resolve/resolve.c b/source4/libcli/resolve/resolve.c new file mode 100644 index 0000000000..d89b50e430 --- /dev/null +++ b/source4/libcli/resolve/resolve.c @@ -0,0 +1,225 @@ +/* + Unix SMB/CIFS implementation. + + general name resolution interface + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "libcli/composite/composite.h" +#include "libcli/resolve/resolve.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "param/param.h" +#include "system/network.h" +#include "util/dlinklist.h" + +struct resolve_state { + struct resolve_context *ctx; + struct resolve_method *method; + struct nbt_name name; + struct composite_context *creq; + const char *reply_addr; +}; + +static struct composite_context *setup_next_method(struct composite_context *c); + + +struct resolve_context { + struct resolve_method { + resolve_name_send_fn send_fn; + resolve_name_recv_fn recv_fn; + void *privdata; + struct resolve_method *prev, *next; + } *methods; +}; + +/** + * Initialize a resolve context + */ +struct resolve_context *resolve_context_init(TALLOC_CTX *mem_ctx) +{ + return talloc_zero(mem_ctx, struct resolve_context); +} + +/** + * Add a resolve method + */ +bool resolve_context_add_method(struct resolve_context *ctx, resolve_name_send_fn send_fn, + resolve_name_recv_fn recv_fn, void *userdata) +{ + struct resolve_method *method = talloc_zero(ctx, struct resolve_method); + + if (method == NULL) + return false; + + method->send_fn = send_fn; + method->recv_fn = recv_fn; + method->privdata = userdata; + DLIST_ADD_END(ctx->methods, method, struct resolve_method *); + return true; +} + +/** + handle completion of one name resolve method +*/ +static void resolve_handler(struct composite_context *creq) +{ + struct composite_context *c = (struct composite_context *)creq->async.private_data; + struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state); + const struct resolve_method *method = state->method; + + c->status = method->recv_fn(creq, state, &state->reply_addr); + + if (!NT_STATUS_IS_OK(c->status)) { + state->method = state->method->next; + state->creq = setup_next_method(c); + if (state->creq != NULL) { + return; + } + } + + if (!NT_STATUS_IS_OK(c->status)) { + c->state = COMPOSITE_STATE_ERROR; + } else { + c->state = COMPOSITE_STATE_DONE; + } + if (c->async.fn) { + c->async.fn(c); + } +} + + +static struct composite_context *setup_next_method(struct composite_context *c) +{ + struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state); + struct composite_context *creq = NULL; + + do { + if (state->method) { + creq = state->method->send_fn(c, c->event_ctx, state->method->privdata, &state->name); + } + if (creq == NULL && state->method) state->method = state->method->next; + + } while (!creq && state->method); + + if (creq) { + creq->async.fn = resolve_handler; + creq->async.private_data = c; + } + + return creq; +} + +/* + general name resolution - async send + */ +struct composite_context *resolve_name_send(struct resolve_context *ctx, + struct nbt_name *name, + struct event_context *event_ctx) +{ + struct composite_context *c; + struct resolve_state *state; + + if (ctx == NULL || event_ctx == NULL) { + return NULL; + } + + c = composite_create(ctx, event_ctx); + if (c == NULL) return NULL; + + if (composite_nomem(c->event_ctx, c)) return c; + + state = talloc(c, struct resolve_state); + if (composite_nomem(state, c)) return c; + c->private_data = state; + + c->status = nbt_name_dup(state, name, &state->name); + if (!composite_is_ok(c)) return c; + + state->ctx = talloc_reference(state, ctx); + if (composite_nomem(state->ctx, c)) return c; + + if (is_ipaddress(state->name.name) || + strcasecmp(state->name.name, "localhost") == 0) { + struct in_addr ip = interpret_addr2(state->name.name); + state->reply_addr = talloc_strdup(state, inet_ntoa(ip)); + if (composite_nomem(state->reply_addr, c)) return c; + composite_done(c); + return c; + } + + state->method = ctx->methods; + state->creq = setup_next_method(c); + if (composite_nomem(state->creq, c)) return c; + + return c; +} + +/* + general name resolution method - recv side + */ +NTSTATUS resolve_name_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + NTSTATUS status; + + status = composite_wait(c); + + if (NT_STATUS_IS_OK(status)) { + struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state); + *reply_addr = talloc_steal(mem_ctx, state->reply_addr); + } + + talloc_free(c); + return status; +} + +/* + general name resolution - sync call + */ +NTSTATUS resolve_name(struct resolve_context *ctx, struct nbt_name *name, TALLOC_CTX *mem_ctx, const char **reply_addr, struct event_context *ev) +{ + struct composite_context *c = resolve_name_send(ctx, name, ev); + return resolve_name_recv(c, mem_ctx, reply_addr); +} + +/* Initialise a struct nbt_name with a NULL scope */ + +void make_nbt_name(struct nbt_name *nbt, const char *name, int type) +{ + nbt->name = name; + nbt->scope = NULL; + nbt->type = type; +} + +/* Initialise a struct nbt_name with a NBT_NAME_CLIENT (0x00) name */ + +void make_nbt_name_client(struct nbt_name *nbt, const char *name) +{ + make_nbt_name(nbt, name, NBT_NAME_CLIENT); +} + +/* Initialise a struct nbt_name with a NBT_NAME_SERVER (0x20) name */ + +void make_nbt_name_server(struct nbt_name *nbt, const char *name) +{ + make_nbt_name(nbt, name, NBT_NAME_SERVER); +} + + diff --git a/source4/libcli/resolve/resolve.h b/source4/libcli/resolve/resolve.h new file mode 100644 index 0000000000..79b91dc836 --- /dev/null +++ b/source4/libcli/resolve/resolve.h @@ -0,0 +1,32 @@ +/* + Unix SMB/CIFS implementation. + + general name resolution interface + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __RESOLVE_H__ +#define __RESOLVE_H__ + +#include "libcli/nbt/libnbt.h" +typedef struct composite_context *(*resolve_name_send_fn)(TALLOC_CTX *mem_ctx, struct event_context *, void *privdata, struct nbt_name *); +typedef NTSTATUS (*resolve_name_recv_fn)(struct composite_context *, TALLOC_CTX *, const char **); +#include "libcli/resolve/proto.h" +struct interface; +#include "libcli/resolve/lp_proto.h" + +#endif /* __RESOLVE_H__ */ diff --git a/source4/libcli/resolve/resolve_lp.c b/source4/libcli/resolve/resolve_lp.c new file mode 100644 index 0000000000..b41e2b98d8 --- /dev/null +++ b/source4/libcli/resolve/resolve_lp.c @@ -0,0 +1,46 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/resolve/resolve.h" +#include "param/param.h" + +struct resolve_context *lp_resolve_context(struct loadparm_context *lp_ctx) +{ + const char **methods = lp_name_resolve_order(lp_ctx); + int i; + struct resolve_context *ret = resolve_context_init(lp_ctx); + + if (ret == NULL) + return NULL; + + for (i = 0; methods != NULL && methods[i] != NULL; i++) { + if (!strcmp(methods[i], "wins")) { + resolve_context_add_wins_method_lp(ret, lp_ctx); + } else if (!strcmp(methods[i], "bcast")) { + resolve_context_add_bcast_method_lp(ret, lp_ctx); + } else if (!strcmp(methods[i], "host")) { + resolve_context_add_host_method(ret); + } else { + DEBUG(0, ("Unknown resolve method '%s'\n", methods[i])); + } + } + + return ret; +} diff --git a/source4/libcli/resolve/testsuite.c b/source4/libcli/resolve/testsuite.c new file mode 100644 index 0000000000..73a8c841bb --- /dev/null +++ b/source4/libcli/resolve/testsuite.c @@ -0,0 +1,90 @@ +/* + Unix SMB/CIFS implementation. + + local test for async resolve code + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "libcli/resolve/resolve.h" +#include "torture/torture.h" +#include "system/network.h" + +static bool test_async_resolve(struct torture_context *tctx) +{ + struct nbt_name n; + struct event_context *ev; + int timelimit = torture_setting_int(tctx, "timelimit", 2); + const char *host = torture_setting_string(tctx, "host", NULL); + int count = 0; + struct timeval tv = timeval_current(); + TALLOC_CTX *mem_ctx = tctx; + + ev = tctx->ev; + + ZERO_STRUCT(n); + n.name = host; + + torture_comment(tctx, "Testing async resolve of '%s' for %d seconds\n", + host, timelimit); + while (timeval_elapsed(&tv) < timelimit) { + const char *s; + struct composite_context *c = resolve_name_host_send(mem_ctx, ev, NULL, &n); + torture_assert(tctx, c != NULL, "resolve_name_host_send"); + torture_assert_ntstatus_ok(tctx, resolve_name_host_recv(c, mem_ctx, &s), + "async resolve failed"); + count++; + } + + torture_comment(tctx, "async rate of %.1f resolves/sec\n", + count/timeval_elapsed(&tv)); + return true; +} + +/* + test resolution using sync method +*/ +static bool test_sync_resolve(struct torture_context *tctx) +{ + int timelimit = torture_setting_int(tctx, "timelimit", 2); + struct timeval tv = timeval_current(); + int count = 0; + const char *host = torture_setting_string(tctx, "host", NULL); + + torture_comment(tctx, "Testing sync resolve of '%s' for %d seconds\n", + host, timelimit); + while (timeval_elapsed(&tv) < timelimit) { + inet_ntoa(interpret_addr2(host)); + count++; + } + + torture_comment(tctx, "sync rate of %.1f resolves/sec\n", + count/timeval_elapsed(&tv)); + return true; +} + + +struct torture_suite *torture_local_resolve(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "RESOLVE"); + + torture_suite_add_simple_test(suite, "async", test_async_resolve); + torture_suite_add_simple_test(suite, "sync", test_sync_resolve); + + return suite; +} diff --git a/source4/libcli/resolve/wins.c b/source4/libcli/resolve/wins.c new file mode 100644 index 0000000000..3ec180f332 --- /dev/null +++ b/source4/libcli/resolve/wins.c @@ -0,0 +1,95 @@ +/* + Unix SMB/CIFS implementation. + + wins name resolution module + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/nbt/libnbt.h" +#include "libcli/resolve/resolve.h" +#include "param/param.h" +#include "lib/socket/netif.h" + +struct resolve_wins_data { + const char **address_list; + struct interface *ifaces; + uint16_t nbt_port; + int nbt_timeout; +}; + +/** + wins name resolution method - async send + */ +struct composite_context *resolve_name_wins_send( + TALLOC_CTX *mem_ctx, + struct event_context *event_ctx, + void *userdata, + struct nbt_name *name) +{ + struct resolve_wins_data *wins_data = talloc_get_type(userdata, struct resolve_wins_data); + if (wins_data->address_list == NULL) return NULL; + return resolve_name_nbtlist_send(mem_ctx, event_ctx, name, wins_data->address_list, wins_data->ifaces, wins_data->nbt_port, wins_data->nbt_timeout, false, true); +} + +/* + wins name resolution method - recv side + */ +NTSTATUS resolve_name_wins_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + return resolve_name_nbtlist_recv(c, mem_ctx, reply_addr); +} + +/* + wins name resolution method - sync call + */ +NTSTATUS resolve_name_wins(struct nbt_name *name, + TALLOC_CTX *mem_ctx, + const char **address_list, + struct interface *ifaces, + uint16_t nbt_port, + int nbt_timeout, + const char **reply_addr) +{ + struct composite_context *c; + struct resolve_wins_data *wins_data = talloc(mem_ctx, struct resolve_wins_data); + wins_data->address_list = address_list; + wins_data->ifaces = ifaces; + wins_data->nbt_port = nbt_port; + wins_data->nbt_timeout = nbt_timeout; + c = resolve_name_wins_send(mem_ctx, NULL, wins_data, name); + return resolve_name_wins_recv(c, mem_ctx, reply_addr); +} + +bool resolve_context_add_wins_method(struct resolve_context *ctx, const char **address_list, struct interface *ifaces, uint16_t nbt_port, int nbt_timeout) +{ + struct resolve_wins_data *wins_data = talloc(ctx, struct resolve_wins_data); + wins_data->address_list = str_list_copy(wins_data, address_list); + wins_data->ifaces = talloc_reference(wins_data, ifaces); + wins_data->nbt_port = nbt_port; + wins_data->nbt_timeout = nbt_timeout; + return resolve_context_add_method(ctx, resolve_name_wins_send, resolve_name_wins_recv, + wins_data); +} + +bool resolve_context_add_wins_method_lp(struct resolve_context *ctx, struct loadparm_context *lp_ctx) +{ + struct interface *ifaces; + load_interfaces(ctx, lp_interfaces(lp_ctx), &ifaces); + return resolve_context_add_wins_method(ctx, lp_wins_server_list(lp_ctx), ifaces, lp_nbt_port(lp_ctx), lp_parm_int(lp_ctx, NULL, "nbt", "timeout", 1)); +} |