1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

r5108: the beginnings of a nbtd server for Samba4. Currently just displays

the packets it receives, but it at least shows how the server
structure will work.

To implement it I extended the libcli/nbt/ library to allow for an
incoming packet handler to be registered. That allows the nbt client
library to be used for low level processing of the nbtd server packets.

Other changes:

 - made the socket library always set SO_REUSEADDR when binding to an
   interface, to ensure that restarts of a server don't have to wait
   for a couple of minutes.

 - made the nbt port configurable. Defaults to 137, but other ports
   will be useful for testing.
(This used to be commit 2fedca6adfd4df9e85cc86896dfa79630777a917)
This commit is contained in:
Andrew Tridgell 2005-01-30 10:24:36 +00:00 committed by Gerald (Jerry) Carter
parent a0ab1f7afd
commit c7ded5ab0a
14 changed files with 285 additions and 4 deletions

View File

@ -41,6 +41,7 @@ sub smb_build_main($)
"rpc_server/config.mk",
"ldap_server/config.mk",
"winbind/config.mk",
"nbt_server/config.mk",
"libcli/auth/gensec.mk",
"libcli/auth/config.mk",
"libcli/ldap/config.mk",

View File

@ -157,3 +157,5 @@ struct stream_connection;
struct task_server;
struct model_ops;
struct stream_server_ops;
struct nbt_server;

View File

@ -139,6 +139,8 @@ static NTSTATUS ipv4_listen(struct socket_context *sock,
struct ipv4_addr ip_addr;
int ret;
socket_set_option(sock, "SO_REUSEADDR=1", NULL);
ip_addr = interpret_addr2(my_address);
ZERO_STRUCT(my_addr);

View File

@ -125,6 +125,8 @@ static NTSTATUS ipv6_tcp_listen(struct socket_context *sock,
struct in6_addr ip_addr;
int ret;
socket_set_option(sock, "SO_REUSEADDR=1", NULL);
ip_addr = interpret_addr6(my_address);
ZERO_STRUCT(my_addr);

View File

@ -90,6 +90,14 @@ struct nbt_name_socket {
/* how many requests are waiting for a reply */
uint16_t num_pending;
/* what to do with incoming request packets */
struct {
void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
const char *, int );
void *private;
} incoming;
};

View File

@ -52,7 +52,7 @@ struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock,
packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
packet->questions[0].question_class = NBT_QCLASS_IP;
req = nbt_name_request_send(nbtsock, io->in.dest_addr, NBT_NAME_SERVICE_PORT, packet,
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;
@ -142,7 +142,7 @@ struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock,
packet->questions[0].question_type = NBT_QTYPE_STATUS;
packet->questions[0].question_class = NBT_QCLASS_IP;
req = nbt_name_request_send(nbtsock, io->in.dest_addr, NBT_NAME_SERVICE_PORT, packet,
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;

View File

@ -51,7 +51,8 @@ static int nbt_name_request_destructor(void *ptr)
if (req->nbtsock->send_queue == NULL) {
req->nbtsock->fde->flags &= ~EVENT_FD_WRITE;
}
if (req->nbtsock->num_pending == 0) {
if (req->nbtsock->num_pending == 0 &&
req->nbtsock->incoming.handler == NULL) {
req->nbtsock->fde->flags &= ~EVENT_FD_READ;
}
return 0;
@ -170,6 +171,9 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
}
if (!(packet->operation & NBT_FLAG_REPLY)) {
if (nbtsock->incoming.handler) {
nbtsock->incoming.handler(nbtsock, packet, src_addr, src_port);
}
talloc_free(tmp_ctx);
return;
}
@ -375,3 +379,20 @@ NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
}
return req->status;
}
/*
setup a handler for incoming requests
*/
NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
const char *, int ),
void *private)
{
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

@ -0,0 +1,13 @@
# NBTD server subsystem
#######################
# Start SUBSYSTEM NBTD
[SUBSYSTEM::NBTD]
INIT_OBJ_FILES = \
nbt_server/nbt_server.o
ADD_OBJ_FILES = \
nbt_server/interfaces.o
REQUIRED_SUBSYSTEMS = \
LIBCLI_NBT
# End SUBSYSTEM SMB
#######################

View File

@ -0,0 +1,88 @@
/*
Unix SMB/CIFS implementation.
NBT interface 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"
#include "smbd/service_task.h"
#include "libcli/nbt/libnbt.h"
/*
start listening on the given address
*/
static NTSTATUS nbt_add_socket(struct nbt_server *nbtsrv,
const char *address, const char *bcast)
{
struct nbt_interface *iface;
NTSTATUS status;
iface = talloc(nbtsrv, struct nbt_interface);
NT_STATUS_HAVE_NO_MEMORY(iface);
iface->nbtsrv = nbtsrv;
iface->bcast_address = talloc_steal(iface, bcast);
iface->ip_address = talloc_steal(iface, address);
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);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to bind to %s:%d - %s\n",
address, lp_nbt_port(), nt_errstr(status)));
talloc_free(iface);
return status;
}
DLIST_ADD(nbtsrv->interfaces, iface);
return NT_STATUS_OK;
}
/*
setup our listening sockets on the configured network interfaces
*/
NTSTATUS nbt_startup_interfaces(struct nbt_server *nbtsrv)
{
int num_interfaces = iface_count();
int i;
TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
NTSTATUS status;
status = nbt_add_socket(nbtsrv,
talloc_strdup(tmp_ctx, "0.0.0.0"),
talloc_strdup(tmp_ctx, "255.255.255.255"));
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)));
status = nbt_add_socket(nbtsrv, address, bcast);
NT_STATUS_NOT_OK_RETURN(status);
}
talloc_free(tmp_ctx);
return NT_STATUS_OK;
}

View File

@ -0,0 +1,85 @@
/*
Unix SMB/CIFS implementation.
NBT server task
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 "events.h"
#include "libcli/nbt/libnbt.h"
#include "smbd/service_task.h"
#include "nbt_server/nbt_server.h"
/*
receive an incoming request
*/
static void nbt_request_handler(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
const char *src_address, int src_port)
{
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);
}
/*
startup the nbtd task
*/
static void nbtd_task_init(struct task_server *task)
{
struct nbt_server *nbtsrv;
struct nbt_interface *iface;
nbtsrv = talloc(task, struct nbt_server);
if (nbtsrv == NULL) {
task_terminate(task, "nbtd: out of memory");
return;
}
nbtsrv->task = task;
nbtsrv->interfaces = NULL;
nbt_startup_interfaces(nbtsrv);
for (iface=nbtsrv->interfaces;iface;iface=iface->next) {
nbt_set_incoming_handler(iface->nbtsock, nbt_request_handler, iface);
}
}
/*
initialise the nbt server
*/
static NTSTATUS nbtd_init(struct event_context *event_ctx, const struct model_ops *model_ops)
{
return task_server_startup(event_ctx, model_ops, nbtd_task_init);
}
/*
register ourselves as a available server
*/
NTSTATUS server_service_nbtd_init(void)
{
return register_server_service("nbt", nbtd_init);
}

View File

@ -0,0 +1,44 @@
/*
Unix SMB/CIFS implementation.
NBT server structures
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.
*/
/* a list of network interfaces we are listening on */
struct nbt_interface {
struct nbt_interface *next, *prev;
const char *ip_address;
const char *bcast_address;
struct nbt_name_socket *nbtsock;
struct nbt_server *nbtsrv;
};
/*
top level context structure for the nbt server
*/
struct nbt_server {
struct task_server *task;
struct nbt_interface *interfaces;
};

View File

@ -61,6 +61,7 @@
#include "system/printing.h"
#include "librpc/gen_ndr/ndr_svcctl.h"
#include "librpc/gen_ndr/ndr_samr.h"
#include "librpc/gen_ndr/ndr_nbt.h"
#include "dlinklist.h"
BOOL in_client = False; /* Not in the client by default */
@ -233,6 +234,7 @@ typedef struct
int winbind_cache_time;
int iLockSpinCount;
int iLockSpinTime;
int nbt_port;
char *socket_options;
BOOL bDNSproxy;
BOOL bWINSsupport;
@ -612,6 +614,7 @@ static struct parm_struct parm_table[] = {
{"Protocol Options", P_SEP, P_SEPARATOR},
{"smb ports", P_LIST, P_GLOBAL, &Globals.smb_ports, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"nbt port", P_INTEGER, P_GLOBAL, &Globals.nbt_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, FLAG_DEVELOPER},
{"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
{"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, FLAG_DEVELOPER},
@ -1044,6 +1047,7 @@ static void init_globals(void)
do_parameter("use spnego", "True");
do_parameter("smb ports", SMB_PORTS);
do_parameter("nbt port", "137");
do_parameter("nt status support", "True");
}
@ -1141,6 +1145,7 @@ static const char *lp_string(const char *s)
int fn_name(int i) {return(LP_SNUM_OK(i)? ServicePtrs[(i)]->val : sDefault.val);}
FN_GLOBAL_LIST(lp_smb_ports, &Globals.smb_ports)
FN_GLOBAL_INTEGER(lp_nbt_port, &Globals.nbt_port)
FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset)
FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset)
FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset)

View File

@ -40,6 +40,16 @@ REQUIRED_SUBSYSTEMS = \
# End MODULE server_ldap
################################################
################################################
# Start MODULE server_service_nbtd
[MODULE::server_service_nbtd]
INIT_FUNCTION = server_service_nbtd_init
SUBSYSTEM = SERVER_SERVICE
REQUIRED_SUBSYSTEMS = \
NBTD
# End MODULE server_service_nbtd
################################################
#######################
# Start SUBSYSTEM SERVICE
[SUBSYSTEM::SERVER_SERVICE]

View File

@ -170,7 +170,7 @@ NTSTATUS stream_setup_socket(struct event_context *event_context,
talloc_steal(stream_socket, stream_socket->sock);
/* ready to listen */
status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL);
NT_STATUS_NOT_OK_RETURN(status);
status = socket_set_option(stream_socket->sock, lp_socket_options(), NULL);