1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

r5114: the nbtd task can now act as a basic B-node server. It registers its

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 d7d31fdc66)
This commit is contained in:
Andrew Tridgell 2005-01-31 01:57:58 +00:00 committed by Gerald (Jerry) Carter
parent 37449657a8
commit 414f6c80b2
18 changed files with 745 additions and 211 deletions

View 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;

View 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

View 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);
}

View 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]

View 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;
};

View 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)

View File

@ -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);
}

View 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;
}

View 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 {

View 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

View File

@ -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);
}

View 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);
}

View File

@ -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;
};

View File

@ -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);
}
}

122
source4/nbt_server/query.c Normal file
View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}

View 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;