diff options
Diffstat (limited to 'source4/nbt_server')
-rw-r--r-- | source4/nbt_server/config.mk | 6 | ||||
-rw-r--r-- | source4/nbt_server/interfaces.c | 97 | ||||
-rw-r--r-- | source4/nbt_server/nbt_server.c | 18 | ||||
-rw-r--r-- | source4/nbt_server/nbt_server.h | 22 | ||||
-rw-r--r-- | source4/nbt_server/packet.c | 38 | ||||
-rw-r--r-- | source4/nbt_server/query.c | 122 | ||||
-rw-r--r-- | source4/nbt_server/register.c | 161 | ||||
-rw-r--r-- | source4/nbt_server/winsserver.c | 35 |
8 files changed, 483 insertions, 16 deletions
diff --git a/source4/nbt_server/config.mk b/source4/nbt_server/config.mk index 093cb61864..e3f52a64e6 100644 --- a/source4/nbt_server/config.mk +++ b/source4/nbt_server/config.mk @@ -6,7 +6,11 @@ INIT_OBJ_FILES = \ nbt_server/nbt_server.o ADD_OBJ_FILES = \ - nbt_server/interfaces.o + nbt_server/interfaces.o \ + nbt_server/register.o \ + nbt_server/query.o \ + nbt_server/winsserver.o \ + nbt_server/packet.o REQUIRED_SUBSYSTEMS = \ LIBCLI_NBT # End SUBSYSTEM SMB diff --git a/source4/nbt_server/interfaces.c b/source4/nbt_server/interfaces.c index 18893e179b..303802e2cd 100644 --- a/source4/nbt_server/interfaces.c +++ b/source4/nbt_server/interfaces.c @@ -24,13 +24,72 @@ #include "dlinklist.h" #include "nbt_server/nbt_server.h" #include "smbd/service_task.h" -#include "libcli/nbt/libnbt.h" + +/* + find a registered name on an interface +*/ +struct nbt_iface_name *nbt_find_iname(struct nbt_interface *iface, struct nbt_name *name, + uint16_t nb_flags) +{ + struct nbt_iface_name *iname; + for (iname=iface->names;iname;iname=iname->next) { + if (iname->name.type == name->type && + StrCaseCmp(name->name, iname->name.name) == 0 && + ((iname->nb_flags & nb_flags) == nb_flags)) { + return iname; + } + } + return NULL; +} + +/* + see if a src address matches an interface +*/ +static BOOL nbt_iface_match(struct nbt_interface *iface, const char *src_address) +{ + struct ipv4_addr ip1, ip2, mask; + ip1 = interpret_addr2(iface->ip_address); + ip2 = interpret_addr2(src_address); + mask = interpret_addr2(iface->netmask); + return same_net(ip1, ip2, mask); +} + + +/* + find the appropriate interface for a incoming packet. If a local interface isn't + found then the general broadcast interface is used +*/ +struct nbt_interface *nbt_iface_find(struct nbt_name_socket *nbtsock, const char *src_address) +{ + struct nbt_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbt_interface); + struct nbt_server *nbtsrv = iface->nbtsrv; + + /* it might have been received by one of our specific bound + addresses */ + if (iface != nbtsrv->bcast_interface) { + return iface; + } + + /* it came in on our broadcast interface - try to find a match */ + for (iface=nbtsrv->interfaces;iface;iface=iface->next) { + if (nbt_iface_match(iface, src_address)) { + return iface; + } + } + + /* it didn't match any specific interface - use our general broadcast interface */ + return nbtsrv->bcast_interface; +} + /* start listening on the given address */ static NTSTATUS nbt_add_socket(struct nbt_server *nbtsrv, - const char *address, const char *bcast) + const char *bind_address, + const char *address, + const char *bcast, + const char *netmask) { struct nbt_interface *iface; NTSTATUS status; @@ -38,14 +97,16 @@ static NTSTATUS nbt_add_socket(struct nbt_server *nbtsrv, iface = talloc(nbtsrv, struct nbt_interface); NT_STATUS_HAVE_NO_MEMORY(iface); - iface->nbtsrv = nbtsrv; + iface->nbtsrv = nbtsrv; iface->bcast_address = talloc_steal(iface, bcast); - iface->ip_address = talloc_steal(iface, address); + iface->ip_address = talloc_steal(iface, address); + iface->netmask = talloc_steal(iface, netmask); + iface->names = NULL; iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx); NT_STATUS_HAVE_NO_MEMORY(iface->ip_address); - status = socket_listen(iface->nbtsock->sock, address, lp_nbt_port(), 0, 0); + status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to bind to %s:%d - %s\n", address, lp_nbt_port(), nt_errstr(status))); @@ -53,7 +114,13 @@ static NTSTATUS nbt_add_socket(struct nbt_server *nbtsrv, return status; } - DLIST_ADD(nbtsrv->interfaces, iface); + socket_set_option(iface->nbtsock->sock, "SO_BROADCAST", "1"); + + if (strcmp(netmask, "0.0.0.0") == 0) { + DLIST_ADD(nbtsrv->bcast_interface, iface); + } else { + DLIST_ADD(nbtsrv->interfaces, iface); + } return NT_STATUS_OK; } @@ -68,17 +135,29 @@ NTSTATUS nbt_startup_interfaces(struct nbt_server *nbtsrv) int i; TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv); NTSTATUS status; + const char *primary_address; + + /* the primary address is the address we will return for non-WINS queries + not made on a specific interface */ + if (num_interfaces > 0) { + primary_address = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_ip(0))); + } else { + primary_address = sys_inet_ntoa(interpret_addr2(lp_netbios_name())); + } status = nbt_add_socket(nbtsrv, - talloc_strdup(tmp_ctx, "0.0.0.0"), - talloc_strdup(tmp_ctx, "255.255.255.255")); + "0.0.0.0", + primary_address, + talloc_strdup(tmp_ctx, "255.255.255.255"), + talloc_strdup(tmp_ctx, "0.0.0.0")); NT_STATUS_NOT_OK_RETURN(status); for (i=0; i<num_interfaces; i++) { const char *address = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_ip(i))); const char *bcast = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_bcast(i))); + const char *netmask = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_netmask(i))); - status = nbt_add_socket(nbtsrv, address, bcast); + status = nbt_add_socket(nbtsrv, address, address, bcast, netmask); NT_STATUS_NOT_OK_RETURN(status); } diff --git a/source4/nbt_server/nbt_server.c b/source4/nbt_server/nbt_server.c index d05a31e421..603ec2a583 100644 --- a/source4/nbt_server/nbt_server.c +++ b/source4/nbt_server/nbt_server.c @@ -22,7 +22,6 @@ #include "includes.h" #include "events.h" -#include "libcli/nbt/libnbt.h" #include "smbd/service_task.h" #include "nbt_server/nbt_server.h" @@ -36,9 +35,12 @@ static void nbt_request_handler(struct nbt_name_socket *nbtsock, { struct nbt_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbt_interface); - DEBUG(0,("nbtd request from %s:%d\n", src_address, src_port)); - NDR_PRINT_DEBUG(nbt_name_packet, packet); + switch (packet->operation & NBT_OPCODE) { + case NBT_OPCODE_QUERY: + nbt_request_query(nbtsock, packet, src_address, src_port); + break; + } } @@ -57,8 +59,9 @@ static void nbtd_task_init(struct task_server *task) return; } - nbtsrv->task = task; - nbtsrv->interfaces = NULL; + nbtsrv->task = task; + nbtsrv->interfaces = NULL; + nbtsrv->bcast_interface = NULL; /* start listening on the configured network interfaces */ status = nbt_startup_interfaces(nbtsrv); @@ -71,6 +74,11 @@ static void nbtd_task_init(struct task_server *task) for (iface=nbtsrv->interfaces;iface;iface=iface->next) { nbt_set_incoming_handler(iface->nbtsock, nbt_request_handler, iface); } + nbt_set_incoming_handler(nbtsrv->bcast_interface->nbtsock, nbt_request_handler, + nbtsrv->bcast_interface); + + /* start the process of registering our names on all interfaces */ + nbt_register_names(nbtsrv); } diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h index 9ef510fbb2..49a07ca95e 100644 --- a/source4/nbt_server/nbt_server.h +++ b/source4/nbt_server/nbt_server.h @@ -20,14 +20,30 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "libcli/nbt/libnbt.h" + +/* + a list of our registered names on each interface +*/ +struct nbt_iface_name { + struct nbt_iface_name *next, *prev; + struct nbt_interface *iface; + struct nbt_name name; + uint16_t nb_flags; + struct timeval registration_time; + uint32_t ttl; +}; + /* a list of network interfaces we are listening on */ struct nbt_interface { struct nbt_interface *next, *prev; + struct nbt_server *nbtsrv; const char *ip_address; const char *bcast_address; + const char *netmask; struct nbt_name_socket *nbtsock; - struct nbt_server *nbtsrv; + struct nbt_iface_name *names; }; @@ -37,7 +53,11 @@ struct nbt_interface { struct nbt_server { struct task_server *task; + /* the list of local network interfaces */ struct nbt_interface *interfaces; + + /* broadcast interface used for receiving packets only */ + struct nbt_interface *bcast_interface; }; diff --git a/source4/nbt_server/packet.c b/source4/nbt_server/packet.c new file mode 100644 index 0000000000..53ccc4d93f --- /dev/null +++ b/source4/nbt_server/packet.c @@ -0,0 +1,38 @@ +/* + Unix SMB/CIFS implementation. + + packet utility functions + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "dlinklist.h" +#include "nbt_server/nbt_server.h" + +/* + we received a badly formed packet - log it +*/ +void nbt_bad_packet(struct nbt_name_packet *packet, + const char *src_address, const char *reason) +{ + DEBUG(2,("nbtd: bad packet '%s' from %s\n", reason, src_address)); + if (DEBUGLVL(5)) { + NDR_PRINT_DEBUG(nbt_name_packet, packet); + } +} + diff --git a/source4/nbt_server/query.c b/source4/nbt_server/query.c new file mode 100644 index 0000000000..c962a691c6 --- /dev/null +++ b/source4/nbt_server/query.c @@ -0,0 +1,122 @@ +/* + Unix SMB/CIFS implementation. + + answer name queries + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "dlinklist.h" +#include "system/network.h" +#include "nbt_server/nbt_server.h" + +/* check a condition on an incoming packet */ +#define NBT_ASSERT_PACKET(packet, src_address, test) do { \ + if (!(test)) { \ + nbt_bad_packet(packet, src_address, #test); \ + return; \ + } \ +} while (0) + + +/* + send a name query reply +*/ +static void nbt_name_query_reply(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *request_packet, + const char *src_address, int src_port, + struct nbt_name *name, uint32_t ttl, + uint16_t nb_flags, const char *address) +{ + struct nbt_name_packet *packet; + + packet = talloc_zero(nbtsock, struct nbt_name_packet); + if (packet == NULL) return; + + packet->name_trn_id = request_packet->name_trn_id; + packet->ancount = 1; + packet->operation = + NBT_FLAG_REPLY | + NBT_OPCODE_QUERY | + NBT_FLAG_AUTHORITIVE | + NBT_FLAG_RECURSION_DESIRED | + NBT_FLAG_RECURSION_AVAIL; + + packet->answers = talloc_array(packet, struct nbt_res_rec, 1); + if (packet->answers == NULL) goto failed; + + packet->answers[0].name = *name; + packet->answers[0].rr_type = NBT_QTYPE_NETBIOS; + packet->answers[0].rr_class = NBT_QCLASS_IP; + packet->answers[0].ttl = ttl; + packet->answers[0].rdata.netbios.length = 6; + packet->answers[0].rdata.netbios.addresses = talloc_array(packet->answers, + struct nbt_rdata_address, 1); + if (packet->answers[0].rdata.netbios.addresses == NULL) goto failed; + packet->answers[0].rdata.netbios.addresses[0].nb_flags = nb_flags; + packet->answers[0].rdata.netbios.addresses[0].ipaddr = htonl(inet_addr(address)); + + DEBUG(7,("Sending name query reply for %s<%02x> at %s to %s:%d\n", + name->name, name->type, src_address, address, src_port)); + + nbt_name_reply_send(nbtsock, src_address, src_port, packet); + +failed: + talloc_free(packet); +} + + +/* + answer a name query +*/ +void nbt_request_query(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + struct nbt_interface *iface; + struct nbt_iface_name *iname; + struct nbt_name *name; + + /* if its a WINS query then direct to our WINS server */ + if ((packet->operation & NBT_FLAG_RECURSION_DESIRED) && + !(packet->operation & NBT_FLAG_BROADCAST)) { + nbt_query_wins(nbtsock, packet, src_address, src_port); + return; + } + + /* find the interface for this query */ + iface = nbt_iface_find(nbtsock, src_address); + + NBT_ASSERT_PACKET(packet, src_address, packet->qdcount == 1); + NBT_ASSERT_PACKET(packet, src_address, packet->questions[0].question_type == NBT_QTYPE_NETBIOS); + NBT_ASSERT_PACKET(packet, src_address, packet->questions[0].question_class == NBT_QCLASS_IP); + + /* see if we have the requested name on this interface */ + name = &packet->questions[0].name; + + iname = nbt_find_iname(iface, name, NBT_NM_ACTIVE); + if (iname == NULL) { + DEBUG(7,("Query for %s<%02x> from %s - not found on %s\n", + name->name, name->type, src_address, iface->ip_address)); + return; + } + + nbt_name_query_reply(nbtsock, packet, src_address, src_port, + &iname->name, iname->ttl, iname->nb_flags, + iface->ip_address); +} diff --git a/source4/nbt_server/register.c b/source4/nbt_server/register.c new file mode 100644 index 0000000000..9a416e37aa --- /dev/null +++ b/source4/nbt_server/register.c @@ -0,0 +1,161 @@ +/* + Unix SMB/CIFS implementation. + + register our names + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "dlinklist.h" +#include "nbt_server/nbt_server.h" + +/* + start a timer to refresh this name +*/ +static void nbt_start_refresh_timer(struct nbt_iface_name *iname) +{ +} + + +/* + a name registration has completed +*/ +static void nbt_register_handler(struct nbt_name_request *req) +{ + struct nbt_iface_name *iname = talloc_get_type(req->async.private, struct nbt_iface_name); + NTSTATUS status; + struct nbt_name_register io; + + status = nbt_name_register_recv(req, iname, &io); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + /* good - nobody complained about our registration */ + iname->nb_flags |= NBT_NM_ACTIVE; + DEBUG(3,("Registered %s<%02x> on interface %s\n", + iname->name.name, iname->name.type, iname->iface->bcast_address)); + nbt_start_refresh_timer(iname); + return; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1,("Error registering %s<%02x> on interface %s - %s\n", + iname->name.name, iname->name.type, iname->iface->bcast_address, + nt_errstr(status))); + return; + } + + /* someone must have replied with an objection! */ + iname->nb_flags |= NBT_NM_CONFLICT; + + DEBUG(1,("Name conflict registering %s<%02x> on interface %s - rcode %d from %s for %s\n", + iname->name.name, iname->name.type, iname->iface->bcast_address, + io.out.rcode, io.out.reply_from, io.out.reply_addr)); +} + + +/* + register a name on a network interface +*/ +static void nbt_register_name_iface(struct nbt_interface *iface, + const char *name, enum nbt_name_type type, + uint16_t nb_flags) +{ + struct nbt_iface_name *iname; + const char *scope = lp_netbios_scope(); + struct nbt_name_register io; + struct nbt_name_request *req; + + iname = talloc(iface, struct nbt_iface_name); + if (!iname) return; + + iname->iface = iface; + iname->name.name = talloc_strdup(iname, name); + iname->name.type = type; + if (scope && *scope) { + iname->name.scope = talloc_strdup(iname, scope); + } else { + iname->name.scope = NULL; + } + iname->nb_flags = nb_flags; + iname->ttl = lp_parm_int(-1, "nbtd", "bcast_ttl", 300000); + iname->registration_time = timeval_zero(); + + DLIST_ADD(iface->names, iname); + + if (nb_flags & NBT_NM_PERMANENT) { + /* permanent names are not announced and are immediately active */ + iname->nb_flags |= NBT_NM_ACTIVE; + iname->ttl = 0; + return; + } + + /* setup a broadcast name registration request */ + io.in.name = iname->name; + io.in.dest_addr = iface->bcast_address; + io.in.address = iface->ip_address; + io.in.nb_flags = nb_flags; + io.in.register_demand = False; + io.in.broadcast = True; + io.in.ttl = iname->ttl; + io.in.timeout = 1; + + req = nbt_name_register_send(iface->nbtsock, &io); + if (req == NULL) return; + + req->async.fn = nbt_register_handler; + req->async.private = iname; +} + + +/* + register one name on all our interfaces +*/ +static void nbt_register_name(struct nbt_server *nbtsrv, + const char *name, enum nbt_name_type type, + uint16_t nb_flags) +{ + struct nbt_interface *iface; + + /* register with all the local interfaces */ + for (iface=nbtsrv->interfaces;iface;iface=iface->next) { + nbt_register_name_iface(iface, name, type, nb_flags); + } + + /* register on our general broadcast interface as a permanent name */ + nbt_register_name_iface(nbtsrv->bcast_interface, name, type, nb_flags | NBT_NM_PERMANENT); + + /* TODO: register with our WINS servers */ +} + + +/* + register our names on all interfaces +*/ +void nbt_register_names(struct nbt_server *nbtsrv) +{ + uint16_t nb_flags = NBT_NODE_M; + + /* note that we don't initially mark the names "ACTIVE". They are + marked active once registration is successful */ + nbt_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_CLIENT, nb_flags); + nbt_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_USER, nb_flags); + nbt_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_SERVER, nb_flags); + nbt_register_name(nbtsrv, lp_workgroup(), NBT_NAME_CLIENT, nb_flags | NBT_NM_GROUP); + nbt_register_name(nbtsrv, lp_workgroup(), NBT_NAME_SERVER, nb_flags | NBT_NM_GROUP); + nbt_register_name(nbtsrv, "__SAMBA__", NBT_NAME_CLIENT, nb_flags | NBT_NM_PERMANENT); + nbt_register_name(nbtsrv, "__SAMBA__", NBT_NAME_SERVER, nb_flags | NBT_NM_PERMANENT); +} diff --git a/source4/nbt_server/winsserver.c b/source4/nbt_server/winsserver.c new file mode 100644 index 0000000000..a659772cb3 --- /dev/null +++ b/source4/nbt_server/winsserver.c @@ -0,0 +1,35 @@ +/* + Unix SMB/CIFS implementation. + + core wins server handling + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "dlinklist.h" +#include "nbt_server/nbt_server.h" + +/* + answer a name query +*/ +void nbt_query_wins(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const char *src_address, int src_port) +{ + DEBUG(0,("WINS query from %s\n", src_address)); +} |