r5114: the nbtd task can now act as a basic B-node server. It registers its
authorAndrew Tridgell <tridge@samba.org>
Mon, 31 Jan 2005 01:57:58 +0000 (01:57 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:23 +0000 (13:09 -0500)
names on the network and answers name queries. Lots of details are
still missing, but at least this now means you don't need a Samba3
nmbd to use Samba4.

missing pieces include:

 - name registrations should be "shout 3 times, then demand"

 - no WINS server yet

 - no master browser code
(This used to be commit d7d31fdc6670f026f96b50e51a4de19f0b920e5b)

18 files changed:
source4/include/structs.h
source4/lib/netif/interface.c
source4/lib/util_strlist.c
source4/libcli/config.mk
source4/libcli/nbt/libnbt.h
source4/libcli/nbt/namequery.c
source4/libcli/nbt/nameregister.c [new file with mode: 0644]
source4/libcli/nbt/nbtsocket.c
source4/librpc/idl/nbt.idl
source4/nbt_server/config.mk
source4/nbt_server/interfaces.c
source4/nbt_server/nbt_server.c
source4/nbt_server/nbt_server.h
source4/nbt_server/packet.c [new file with mode: 0644]
source4/nbt_server/query.c [new file with mode: 0644]
source4/nbt_server/register.c [new file with mode: 0644]
source4/nbt_server/winsserver.c [new file with mode: 0644]
source4/utils/nmblookup.c

index 0de876ca7c20d1b018b095a05ac9fb6d1fd9e2eb..69f84ea55e1476682c48d2b60a0030defa78c1c3 100644 (file)
@@ -150,7 +150,7 @@ struct nbt_name_packet;
 struct nbt_name_socket;
 struct nbt_name_query;
 struct nbt_name_status;
-
+struct nbt_name_register;
 
 struct messaging_context;
 struct stream_connection;
@@ -159,3 +159,4 @@ struct model_ops;
 struct stream_server_ops;
 
 struct nbt_server;
+struct nbt_interface;
index 4f22095f7a59cdd2408e61ca35f52250e6327e64..bf1e147e02e8c60a1a97552f2ec95dee063d96e0 100644 (file)
@@ -330,6 +330,20 @@ struct ipv4_addr *iface_n_bcast(int n)
        return NULL;
 }
 
+/****************************************************************************
+  return netmask of the Nth interface
+  **************************************************************************/
+struct ipv4_addr *iface_n_netmask(int n)
+{
+       struct interface *i;
+  
+       for (i=local_interfaces;i && n;i=i->next)
+               n--;
+
+       if (i) return &i->nmask;
+       return NULL;
+}
+
 /* these 3 functions return the ip/bcast/nmask for the interface
    most appropriate for the given ip address. If they can't find
    an appropriate interface they return the requested field of the
index 33f824dcf846995ef86a01e245dc8bec91a4b00f..d945c78472cbbca0fd54ed1a99ffe4b1722a0296 100644 (file)
@@ -152,173 +152,5 @@ void str_list_free(char ***list)
        SAFE_FREE(*list);
 }
 
-BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
-{
-       char *p, *s, *t;
-       ssize_t ls, lp, li, ld, i, d;
-
-       if (!list)
-               return False;
-       if (!pattern)
-               return False;
-       if (!insert)
-               return False;
-
-       lp = (ssize_t)strlen(pattern);
-       li = (ssize_t)strlen(insert);
-       ld = li -lp;
-                       
-       while (*list) {
-               s = *list;
-               ls = (ssize_t)strlen(s);
-
-               while ((p = strstr(s, pattern))) {
-                       t = *list;
-                       d = p -t;
-                       if (ld) {
-                               t = (char *) malloc(ls +ld +1);
-                               if (!t) {
-                                       DEBUG(0,("str_list_substitute: Unable to allocate memory"));
-                                       return False;
-                               }
-                               memcpy(t, *list, d);
-                               memcpy(t +d +li, p +lp, ls -d -lp +1);
-                               SAFE_FREE(*list);
-                               *list = t;
-                               ls += ld;
-                               s = t +d +li;
-                       }
-                       
-                       for (i = 0; i < li; i++) {
-                               switch (insert[i]) {
-                                       case '`':
-                                       case '"':
-                                       case '\'':
-                                       case ';':
-                                       case '$':
-                                       case '%':
-                                       case '\r':
-                                       case '\n':
-                                               t[d +i] = '_';
-                                               break;
-                                       default:
-                                               t[d +i] = insert[i];
-                               }
-                       }       
-               }
-               
-               list++;
-       }
-       
-       return True;
-}
 
 
-#define IPSTR_LIST_SEP ","
-
-/**
- * Add ip string representation to ipstr list. Used also
- * as part of @function ipstr_list_make
- *
- * @param ipstr_list pointer to string containing ip list;
- *        MUST BE already allocated and IS reallocated if necessary
- * @param ipstr_size pointer to current size of ipstr_list (might be changed
- *        as a result of reallocation)
- * @param ip IP address which is to be added to list
- * @return pointer to string appended with new ip and possibly
- *         reallocated to new length
- **/
-
-char* ipstr_list_add(char** ipstr_list, const struct ipv4_addr *ip)
-{
-       char* new_ipstr = NULL;
-       
-       /* arguments checking */
-       if (!ipstr_list || !ip) return NULL;
-
-       /* attempt to convert ip to a string and append colon separator to it */
-       if (*ipstr_list) {
-               asprintf(&new_ipstr, "%s%s%s", *ipstr_list, IPSTR_LIST_SEP,sys_inet_ntoa(*ip));
-               SAFE_FREE(*ipstr_list);
-       } else {
-               asprintf(&new_ipstr, "%s", sys_inet_ntoa(*ip));
-       }
-       *ipstr_list = new_ipstr;
-       return *ipstr_list;
-}
-
-/**
- * Allocate and initialise an ipstr list using ip adresses
- * passed as arguments.
- *
- * @param ipstr_list pointer to string meant to be allocated and set
- * @param ip_list array of ip addresses to place in the list
- * @param ip_count number of addresses stored in ip_list
- * @return pointer to allocated ip string
- **/
-char* ipstr_list_make(char** ipstr_list, const struct ipv4_addr* ip_list, int ip_count)
-{
-       int i;
-       
-       /* arguments checking */
-       if (!ip_list && !ipstr_list) return 0;
-
-       *ipstr_list = NULL;
-       
-       /* process ip addresses given as arguments */
-       for (i = 0; i < ip_count; i++)
-               *ipstr_list = ipstr_list_add(ipstr_list, &ip_list[i]);
-       
-       return (*ipstr_list);
-}
-
-
-/**
- * Parse given ip string list into array of ip addresses
- * (as in_addr structures)
- *
- * @param ipstr ip string list to be parsed 
- * @param ip_list pointer to array of ip addresses which is
- *        allocated by this function and must be freed by caller
- * @return number of succesfully parsed addresses
- **/
-int ipstr_list_parse(const char* ipstr_list, struct ipv4_addr** ip_list)
-{
-       fstring token_str;
-       int count;
-
-       if (!ipstr_list || !ip_list) return 0;
-       
-       for (*ip_list = NULL, count = 0;
-            next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN);
-            count++) {
-            
-               struct ipv4_addr addr;
-
-               /* convert single token to ip address */
-               if ( (addr.addr = sys_inet_addr(token_str)) == INADDR_NONE )
-                       break;
-               
-               /* prepare place for another in_addr structure */
-               *ip_list = realloc_p(*ip_list, struct ipv4_addr, count + 1);
-               if (!*ip_list) return -1;
-               
-               (*ip_list)[count] = addr;
-       }
-       
-       return count;
-}
-
-
-/**
- * Safely free ip string list
- *
- * @param ipstr_list ip string list to be freed
- **/
-
-void ipstr_list_free(char* ipstr_list)
-{
-       SAFE_FREE(ipstr_list);
-}
index 06b46c6f18054036a40f486c74509e8204640f1e..c801524c2ffa1ef8691681ab4c311027a6b14849 100644 (file)
@@ -24,7 +24,8 @@ ADD_OBJ_FILES = \
 ADD_OBJ_FILES = \
        libcli/nbt/nbtname.o \
        libcli/nbt/nbtsocket.o \
-       libcli/nbt/namequery.o
+       libcli/nbt/namequery.o \
+       libcli/nbt/nameregister.o
 REQUIRED_SUBSYSTEMS = LIBNDR_RAW NDR_NBT SOCKET
 
 [SUBSYSTEM::LIBCLI_RESOLVE]
index 82069f039030d47290c227147c017ad64363ae7f..3bfffa25d059e3abae0b642b430873bbde609a2b 100644 (file)
@@ -113,7 +113,8 @@ struct nbt_name_query {
        struct {
                const char *reply_from;
                struct nbt_name name;
-               const char *reply_addr;
+               int16_t num_addrs;
+               const char **reply_addrs;
        } out;
 };
 
@@ -130,3 +131,23 @@ struct nbt_name_status {
                struct nbt_rdata_status status;
        } out;
 };
+
+/* a name registration request */
+struct nbt_name_register {
+       struct {
+               struct nbt_name name;
+               const char *dest_addr;
+               const char *address;
+               uint16_t nb_flags;
+               BOOL register_demand;
+               BOOL broadcast;
+               uint32_t ttl;
+               int timeout; /* in seconds */
+       } in;
+       struct {
+               const char *reply_from;
+               struct nbt_name name;
+               const char *reply_addr;
+               uint8_t rcode;
+       } out;
+};
index 6f549e6241a8872d4af0b3f07c4c29a31ec6734b..f6744e9f147400ffc33ddc56cb8e2bf0843d8a48 100644 (file)
@@ -66,7 +66,7 @@ failed:
 }
 
 /*
-  wait for a name query replu
+  wait for a name query reply
 */
 NTSTATUS nbt_name_query_recv(struct nbt_name_request *req, 
                             TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
@@ -75,6 +75,7 @@ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
        struct nbt_name_packet *packet;
        const char *addr;
        struct in_addr in;
+       int i;
 
        status = nbt_name_request_recv(req);
        if (!NT_STATUS_IS_OK(status) ||
@@ -94,13 +95,23 @@ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
        }
 
        io->out.name = packet->answers[0].name;
-       in.s_addr = htonl(packet->answers[0].rdata.netbios.ipaddr);
-       addr = inet_ntoa(in);
-       if (addr == NULL) {
+       io->out.num_addrs = packet->answers[0].rdata.netbios.length / 6;
+       io->out.reply_addrs = talloc_array(mem_ctx, const char *, io->out.num_addrs);
+       if (io->out.reply_addrs == NULL) {
                talloc_free(req);
                return NT_STATUS_NO_MEMORY;
        }
-       io->out.reply_addr = talloc_strdup(mem_ctx, addr);
+       
+       for (i=0;i<io->out.num_addrs;i++) {
+               in.s_addr = htonl(packet->answers[0].rdata.netbios.addresses[i].ipaddr);
+               addr = inet_ntoa(in);
+               if (addr == NULL) {
+                       talloc_free(req);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               io->out.reply_addrs[i] = talloc_strdup(mem_ctx, addr);
+       }
+
        talloc_steal(mem_ctx, io->out.name.name);
        talloc_steal(mem_ctx, io->out.name.scope);
            
@@ -110,7 +121,7 @@ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
 }
 
 /*
-  wait for a name query replu
+  wait for a name query reply
 */
 NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock, 
                        TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
@@ -156,7 +167,7 @@ failed:
 }
 
 /*
-  wait for a name status replu
+  wait for a name status reply
 */
 NTSTATUS nbt_name_status_recv(struct nbt_name_request *req, 
                             TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
@@ -199,7 +210,7 @@ NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
 }
 
 /*
-  wait for a name status replu
+  wait for a name status reply
 */
 NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock, 
                        TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
diff --git a/source4/libcli/nbt/nameregister.c b/source4/libcli/nbt/nameregister.c
new file mode 100644 (file)
index 0000000..2d1e964
--- /dev/null
@@ -0,0 +1,140 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   send out a name registration request
+
+   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 "libcli/nbt/libnbt.h"
+#include "system/network.h"
+
+/*
+  send a nbt name registration request
+*/
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+                                               struct nbt_name_register *io)
+{
+       struct nbt_name_request *req;
+       struct nbt_name_packet *packet;
+
+       packet = talloc_zero(nbtsock, struct nbt_name_packet);
+       if (packet == NULL) return NULL;
+
+       packet->qdcount = 1;
+       packet->arcount = 1;
+       packet->operation = NBT_OPCODE_REGISTER;
+       if (io->in.broadcast) {
+               packet->operation |= NBT_FLAG_BROADCAST;
+       }
+       if (io->in.register_demand) {
+               packet->operation |= NBT_FLAG_RECURSION_DESIRED;
+       }
+
+       packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+       if (packet->questions == NULL) goto failed;
+
+       packet->questions[0].name           = io->in.name;
+       packet->questions[0].question_type  = NBT_QTYPE_NETBIOS;
+       packet->questions[0].question_class = NBT_QCLASS_IP;
+
+       packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+       if (packet->additional == NULL) goto failed;
+
+       packet->additional[0].name                   = io->in.name;
+       packet->additional[0].rr_type                = NBT_QTYPE_NETBIOS;
+       packet->additional[0].rr_class               = NBT_QCLASS_IP;
+       packet->additional[0].ttl                    = io->in.ttl;
+       packet->additional[0].rdata.netbios.length   = 6;
+       packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+                                                                    struct nbt_rdata_address, 1);
+       if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+       packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+       packet->additional[0].rdata.netbios.addresses[0].ipaddr   = htonl(inet_addr(io->in.address));
+       
+       req = nbt_name_request_send(nbtsock, io->in.dest_addr, lp_nbt_port(), packet,
+                                   timeval_current_ofs(io->in.timeout, 0), False);
+       if (req == NULL) goto failed;
+
+       talloc_steal(req, packet);
+
+       return req;
+
+failed:
+       talloc_free(packet);
+       return NULL;    
+}
+
+/*
+  wait for a registration reply
+*/
+NTSTATUS nbt_name_register_recv(struct nbt_name_request *req, 
+                               TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+       NTSTATUS status;
+       struct nbt_name_packet *packet;
+       const char *addr;
+       struct in_addr in;
+
+       status = nbt_name_request_recv(req);
+       if (!NT_STATUS_IS_OK(status) ||
+           req->num_replies == 0) {
+               talloc_free(req);
+               return status;
+       }
+       
+       packet = req->replies[0].packet;
+       io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].reply_addr);
+
+       if (packet->ancount != 1 ||
+           packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+           packet->answers[0].rr_class != NBT_QCLASS_IP) {
+               talloc_free(req);
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
+       io->out.rcode = packet->operation & NBT_RCODE;
+       io->out.name = packet->answers[0].name;
+       if (packet->answers[0].rdata.netbios.length < 6) {
+               talloc_free(req);
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+       in.s_addr = htonl(packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+       addr = inet_ntoa(in);
+       if (addr == NULL) {
+               talloc_free(req);
+               return NT_STATUS_NO_MEMORY;
+       }
+       io->out.reply_addr = talloc_strdup(mem_ctx, addr);
+       talloc_steal(mem_ctx, io->out.name.name);
+       talloc_steal(mem_ctx, io->out.name.scope);
+           
+       talloc_free(req);
+
+       return NT_STATUS_OK;
+}
+
+/*
+  synchronous name registration request
+*/
+NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock, 
+                          TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+       struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
+       return nbt_name_register_recv(req, mem_ctx, io);
+}
index f1964b71587fc98bfb918011eeef4d9c326f3438..90b4f6e0294ef1ef0b6d2b7713395482dbf83a5d 100644 (file)
@@ -41,7 +41,8 @@ static int nbt_name_request_destructor(void *ptr)
        if (req->state == NBT_REQUEST_WAIT) {
                req->nbtsock->num_pending--;
        }
-       if (req->request->name_trn_id != 0) {
+       if (req->request->name_trn_id != 0 && 
+           !(req->request->operation & NBT_FLAG_REPLY)) {
                idr_remove(req->nbtsock->idr, req->request->name_trn_id);
                req->request->name_trn_id = 0;
        }
@@ -65,7 +66,7 @@ static int nbt_name_request_destructor(void *ptr)
 static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
 {
        struct nbt_name_request *req = nbtsock->send_queue;
-       TALLOC_CTX *tmp_ctx = talloc_new(req);
+       TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
        NTSTATUS status;
 
        while ((req = nbtsock->send_queue)) {
@@ -98,9 +99,13 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
                }
 
                DLIST_REMOVE(nbtsock->send_queue, req);
-               req->state = NBT_REQUEST_WAIT;
-               nbtsock->fde->flags |= EVENT_FD_READ;
-               nbtsock->num_pending++;
+               if (req->request->operation & NBT_FLAG_REPLY) {
+                       talloc_free(req);
+               } else {
+                       req->state = NBT_REQUEST_WAIT;
+                       nbtsock->fde->flags |= EVENT_FD_READ;
+                       nbtsock->num_pending++;
+               }
        }
 
        nbtsock->fde->flags &= ~EVENT_FD_WRITE;
@@ -317,7 +322,8 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
        if (req == NULL) goto failed;
 
        req->nbtsock = nbtsock;
-       req->dest_addr = dest_addr;
+       req->dest_addr = talloc_strdup(req, dest_addr);
+       if (req->dest_addr == NULL) goto failed;
        req->dest_port = dest_port;
        req->request = talloc_reference(req, request);
        req->allow_multiple_replies = allow_multiple_replies;
@@ -361,6 +367,39 @@ failed:
        return NULL;
 }
 
+
+/*
+  send off a nbt name reply
+*/
+NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock, 
+                            const char *dest_addr, int dest_port,
+                            struct nbt_name_packet *request)
+{
+       struct nbt_name_request *req;
+
+       req = talloc_zero(nbtsock, struct nbt_name_request);
+       NT_STATUS_HAVE_NO_MEMORY(req);
+
+       req->nbtsock   = nbtsock;
+       req->dest_addr = talloc_strdup(req, dest_addr);
+       if (req->dest_addr == NULL) goto failed;
+       req->dest_port = dest_port;
+       req->request   = talloc_reference(req, request);
+       req->state     = NBT_REQUEST_SEND;
+
+       talloc_set_destructor(req, nbt_name_request_destructor);        
+
+       DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
+
+       nbtsock->fde->flags |= EVENT_FD_WRITE;
+
+       return NT_STATUS_OK;
+
+failed:
+       talloc_free(req);
+       return NT_STATUS_NO_MEMORY;
+}
+
 /*
   wait for a nbt request to complete
 */
@@ -392,7 +431,6 @@ NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
        nbtsock->incoming.handler = handler;
        nbtsock->incoming.private = private;
        nbtsock->fde->flags |= EVENT_FD_READ;
-       socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
        return NT_STATUS_OK;
 }
 
index 429a35267c01bfd171c7538f303721fbb1687151..35fc7d90c4042086e63481e0a93f62d544fcbb55 100644 (file)
@@ -103,8 +103,12 @@ interface nbt
        typedef struct {
                nb_flags nb_flags;
                uint32   ipaddr;
-       } nbt_rdata_netbios;
+       } nbt_rdata_address;
 
+       typedef struct {
+               uint16 length;
+               nbt_rdata_address addresses[length/6];
+       } nbt_rdata_netbios;
 
        typedef struct {
                uint8 unit_id[6];
@@ -135,14 +139,16 @@ interface nbt
                nb_flags  nb_flags;
        } nbt_status_name;
 
-       typedef struct {
+       typedef [gensize] struct {
+               [value(ndr_size_nbt_rdata_status(r, ndr->flags)-2)] uint16 length;
                uint8 num_names;
                nbt_status_name names[num_names];
                nbt_statistics  statistics;
        } nbt_rdata_status;
 
        typedef struct {
-               [flag(NDR_REMAINING)] DATA_BLOB data;
+               uint16 length;
+               uint8  data[length];
        } nbt_rdata_data;
 
        typedef [nodiscriminant] union {
@@ -156,7 +162,7 @@ interface nbt
                nbt_qtype  rr_type;
                nbt_qclass rr_class;
                uint32     ttl;
-               [subcontext(2),switch_is(rr_type)] nbt_rdata rdata;
+               [switch_is(rr_type)] nbt_rdata rdata;
        } nbt_res_rec;
 
        typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
index 093cb61864c49d56b7d8f4174c842de0b41796c8..e3f52a64e6e44ec8075dd790fc7878d128eb3f2f 100644 (file)
@@ -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
index 18893e179b3064bf15c6f623cc8c77df121e0dec..303802e2cd4feeb7e84e72c0073e27f7df01a712 100644 (file)
 #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);
        }
 
index d05a31e42141b5802aa28662620a9425352c7d0a..603ec2a583f498dac48a3382090f533d797e4907 100644 (file)
@@ -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);
 }
 
 
index 9ef510fbb243d6f2121c4fd2b75c66e0bdbea674..49a07ca95e522361713d3a40511534cf41610e78 100644 (file)
    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 (file)
index 0000000..53ccc4d
--- /dev/null
@@ -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 (file)
index 0000000..c962a69
--- /dev/null
@@ -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 (file)
index 0000000..9a416e3
--- /dev/null
@@ -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 (file)
index 0000000..a659772
--- /dev/null
@@ -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));
+}
index 5881b25c7950bd1f41773de202d4b4211b36299f..824ce642985c3ed90b4a8dceaf25e87f18165849 100644 (file)
@@ -141,6 +141,7 @@ static NTSTATUS do_node_query(struct nbt_name_socket *nbtsock,
 {
        struct nbt_name_query io;
        NTSTATUS status;
+       int i;
 
        io.in.name.name = node_name;
        io.in.name.type = node_type;
@@ -151,14 +152,16 @@ static NTSTATUS do_node_query(struct nbt_name_socket *nbtsock,
        io.in.timeout = 3;
 
        status = nbt_name_query(nbtsock, nbtsock, &io);
-       if (NT_STATUS_IS_OK(status)) {
+       NT_STATUS_NOT_OK_RETURN(status);
+               
+       for (i=0;i<io.out.num_addrs;i++) {
                printf("%s %s<%02x>\n",
-                      io.out.reply_addr,
+                      io.out.reply_addrs[i],
                       io.out.name.name,
                       io.out.name.type);
-               if (options.node_status) {
-                       do_node_status(nbtsock, io.out.reply_addr);
-               }
+       }
+       if (options.node_status && io.out.num_addrs > 0) {
+               do_node_status(nbtsock, io.out.reply_addrs[0]);
        }
 
        return status;