2005-01-30 13:24:36 +03:00
/*
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-01-30 13:24:36 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-01-30 13:24:36 +03:00
*/
# include "includes.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
2005-01-30 13:24:36 +03:00
# include "nbt_server/nbt_server.h"
# include "smbd/service_task.h"
2005-02-10 09:59:29 +03:00
# include "lib/socket/socket.h"
2005-12-30 15:43:11 +03:00
# include "nbt_server/wins/winsserver.h"
2006-03-07 14:07:23 +03:00
# include "nbt_server/dgram/proto.h"
# include "system/network.h"
2006-08-17 17:37:04 +04:00
# include "lib/socket/netif.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2010-03-26 09:36:02 +03:00
# include "lib/util/util_net.h"
2005-01-31 04:57:58 +03:00
2005-02-02 13:29:50 +03:00
/*
receive an incoming request and dispatch it to the right place
*/
2005-02-04 04:39:10 +03:00
static void nbtd_request_handler ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
2006-01-10 01:12:53 +03:00
struct socket_address * src )
2005-02-02 13:29:50 +03:00
{
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2005-07-10 12:41:02 +04:00
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
nbtsrv - > stats . total_received + + ;
2005-02-04 05:05:27 +03:00
/* see if its from one of our own interfaces - if so, then ignore it */
2006-01-18 19:36:53 +03:00
if ( nbtd_self_packet_and_bcast ( nbtsock , packet , src ) ) {
DEBUG ( 10 , ( " Ignoring bcast self packet from %s:%d \n " , src - > addr , src - > port ) ) ;
2005-02-04 05:05:27 +03:00
return ;
}
2005-02-12 02:54:37 +03:00
switch ( packet - > operation & NBT_OPCODE ) {
2005-02-02 13:29:50 +03:00
case NBT_OPCODE_QUERY :
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . query_count + + ;
2005-10-14 16:22:15 +04:00
nbtd_request_query ( nbtsock , packet , src ) ;
2005-02-04 04:55:50 +03:00
break ;
case NBT_OPCODE_REGISTER :
case NBT_OPCODE_REFRESH :
2005-02-08 04:09:21 +03:00
case NBT_OPCODE_REFRESH2 :
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . register_count + + ;
2005-10-14 16:22:15 +04:00
nbtd_request_defense ( nbtsock , packet , src ) ;
2005-02-02 13:29:50 +03:00
break ;
2005-02-06 11:25:53 +03:00
2005-02-12 02:54:37 +03:00
case NBT_OPCODE_RELEASE :
case NBT_OPCODE_MULTI_HOME_REG :
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . release_count + + ;
2005-10-14 16:22:15 +04:00
nbtd_winsserver_request ( nbtsock , packet , src ) ;
2005-02-12 02:54:37 +03:00
break ;
2005-02-06 11:25:53 +03:00
default :
2005-10-14 16:22:15 +04:00
nbtd_bad_packet ( packet , src , " Unexpected opcode " ) ;
2005-02-06 11:25:53 +03:00
break ;
2005-02-02 13:29:50 +03:00
}
}
2008-01-16 15:57:50 +03:00
static void nbtd_unexpected_handler ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * packet ,
struct socket_address * src )
{
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
struct nbtd_interface * i ;
struct nbt_name_request * req = NULL ;
nbtsrv - > stats . total_received + + ;
DEBUG ( 10 , ( " unexpected from src[%s] on interface[%p] %s/%s \n " ,
src - > addr , iface , iface - > ip_address , iface - > netmask ) ) ;
/* try the broadcast interface */
if ( nbtsrv - > bcast_interface ) {
i = nbtsrv - > bcast_interface ;
req = idr_find ( i - > nbtsock - > idr , packet - > name_trn_id ) ;
}
/* try the wins server client interface */
2008-02-08 13:50:34 +03:00
if ( ! req & & nbtsrv - > wins_interface & & nbtsrv - > wins_interface - > nbtsock ) {
2008-01-16 15:57:50 +03:00
i = nbtsrv - > wins_interface ;
req = idr_find ( i - > nbtsock - > idr , packet - > name_trn_id ) ;
}
/* try all other interfaces... */
if ( ! req ) {
for ( i = nbtsrv - > interfaces ; i ; i = i - > next ) {
if ( i = = iface ) {
continue ;
}
req = idr_find ( i - > nbtsock - > idr , packet - > name_trn_id ) ;
if ( req ) break ;
}
}
if ( ! req ) {
DEBUG ( 10 , ( " unexpected from src[%s] unable to redirected \n " , src - > addr ) ) ;
return ;
}
DEBUG ( 10 , ( " unexpected from src[%s] redirected to interface[%p] %s/%s \n " ,
src - > addr , i , i - > ip_address , i - > netmask ) ) ;
/*
* redirect the incoming response to the socket
* we sent the matching request
*/
nbt_name_socket_handle_response_packet ( req , packet , src ) ;
}
2005-02-02 13:29:50 +03:00
2005-01-31 04:57:58 +03:00
/*
find a registered name on an interface
*/
2005-02-06 11:25:53 +03:00
struct nbtd_iface_name * nbtd_find_iname ( struct nbtd_interface * iface ,
struct nbt_name * name ,
uint16_t nb_flags )
2005-01-31 04:57:58 +03:00
{
2005-02-06 11:25:53 +03:00
struct nbtd_iface_name * iname ;
2005-01-31 04:57:58 +03:00
for ( iname = iface - > names ; iname ; iname = iname - > next ) {
if ( iname - > name . type = = name - > type & &
2005-02-11 11:18:55 +03:00
strcmp ( name - > name , iname - > name . name ) = = 0 & &
2005-01-31 04:57:58 +03:00
( ( iname - > nb_flags & nb_flags ) = = nb_flags ) ) {
return iname ;
}
}
return NULL ;
}
2005-01-30 13:24:36 +03:00
/*
start listening on the given address
*/
2005-02-06 11:25:53 +03:00
static NTSTATUS nbtd_add_socket ( struct nbtd_server * nbtsrv ,
2007-12-03 20:47:42 +03:00
struct loadparm_context * lp_ctx ,
2005-02-04 04:39:10 +03:00
const char * bind_address ,
const char * address ,
const char * bcast ,
const char * netmask )
2005-01-30 13:24:36 +03:00
{
2005-02-06 11:25:53 +03:00
struct nbtd_interface * iface ;
2005-01-30 13:24:36 +03:00
NTSTATUS status ;
2006-01-10 01:12:53 +03:00
struct socket_address * bcast_address ;
struct socket_address * unicast_address ;
2005-02-02 13:29:50 +03:00
2008-01-16 15:43:07 +03:00
DEBUG ( 6 , ( " nbtd_add_socket(%s, %s, %s, %s) \n " , bind_address , address , bcast , netmask ) ) ;
2005-02-02 13:29:50 +03:00
/*
we actually create two sockets . One listens on the broadcast address
for the interface , and the other listens on our specific address . This
allows us to run with " bind interfaces only " while still receiving
broadcast addresses , and also simplifies matching incoming requests
to interfaces
*/
2005-01-30 13:24:36 +03:00
2005-02-06 11:25:53 +03:00
iface = talloc ( nbtsrv , struct nbtd_interface ) ;
2005-01-30 13:24:36 +03:00
NT_STATUS_HAVE_NO_MEMORY ( iface ) ;
2005-01-31 04:57:58 +03:00
iface - > nbtsrv = nbtsrv ;
2005-01-30 13:24:36 +03:00
iface - > bcast_address = talloc_steal ( iface , bcast ) ;
2005-01-31 04:57:58 +03:00
iface - > ip_address = talloc_steal ( iface , address ) ;
iface - > netmask = talloc_steal ( iface , netmask ) ;
iface - > names = NULL ;
2008-01-11 18:11:59 +03:00
iface - > wack_queue = NULL ;
2005-01-30 13:24:36 +03:00
2005-02-02 13:29:50 +03:00
if ( strcmp ( netmask , " 0.0.0.0 " ) ! = 0 ) {
2005-04-03 08:32:37 +04:00
struct nbt_name_socket * bcast_nbtsock ;
/* listen for broadcasts on port 137 */
2010-05-09 19:20:01 +04:00
bcast_nbtsock = nbt_name_socket_init ( iface , nbtsrv - > task - > event_ctx ) ;
2006-01-10 01:12:53 +03:00
if ( ! bcast_nbtsock ) {
talloc_free ( iface ) ;
return NT_STATUS_NO_MEMORY ;
}
bcast_address = socket_address_from_strings ( bcast_nbtsock , bcast_nbtsock - > sock - > backend_name ,
2010-07-16 08:32:42 +04:00
bcast , lpcfg_nbt_port ( lp_ctx ) ) ;
2006-01-10 01:12:53 +03:00
if ( ! bcast_address ) {
talloc_free ( iface ) ;
return NT_STATUS_NO_MEMORY ;
}
2005-02-02 13:29:50 +03:00
2006-01-10 01:12:53 +03:00
status = socket_listen ( bcast_nbtsock - > sock , bcast_address , 0 , 0 ) ;
2005-02-02 13:29:50 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to bind to %s:%d - %s \n " ,
2010-07-16 08:32:42 +04:00
bcast , lpcfg_nbt_port ( lp_ctx ) , nt_errstr ( status ) ) ) ;
2005-02-02 13:29:50 +03:00
talloc_free ( iface ) ;
return status ;
}
2006-01-10 01:12:53 +03:00
talloc_free ( bcast_address ) ;
2005-02-02 13:29:50 +03:00
2005-02-04 04:39:10 +03:00
nbt_set_incoming_handler ( bcast_nbtsock , nbtd_request_handler , iface ) ;
2005-02-02 13:29:50 +03:00
}
2005-04-03 08:32:37 +04:00
/* listen for unicasts on port 137 */
2010-05-09 19:20:01 +04:00
iface - > nbtsock = nbt_name_socket_init ( iface , nbtsrv - > task - > event_ctx ) ;
2006-01-10 01:12:53 +03:00
if ( ! iface - > nbtsock ) {
talloc_free ( iface ) ;
return NT_STATUS_NO_MEMORY ;
}
2005-01-30 13:24:36 +03:00
2007-09-28 05:17:46 +04:00
unicast_address = socket_address_from_strings ( iface - > nbtsock ,
iface - > nbtsock - > sock - > backend_name ,
2010-07-16 08:32:42 +04:00
bind_address , lpcfg_nbt_port ( lp_ctx ) ) ;
2006-01-10 01:12:53 +03:00
status = socket_listen ( iface - > nbtsock - > sock , unicast_address , 0 , 0 ) ;
2005-01-30 13:24:36 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to bind to %s:%d - %s \n " ,
2010-07-16 08:32:42 +04:00
bind_address , lpcfg_nbt_port ( lp_ctx ) , nt_errstr ( status ) ) ) ;
2005-01-30 13:24:36 +03:00
talloc_free ( iface ) ;
return status ;
}
2006-01-10 01:12:53 +03:00
talloc_free ( unicast_address ) ;
2005-02-04 04:39:10 +03:00
nbt_set_incoming_handler ( iface - > nbtsock , nbtd_request_handler , iface ) ;
2008-01-16 15:57:50 +03:00
nbt_set_unexpected_handler ( iface - > nbtsock , nbtd_unexpected_handler , iface ) ;
2005-02-02 13:29:50 +03:00
2005-04-08 12:57:09 +04:00
/* also setup the datagram listeners */
status = nbtd_dgram_setup ( iface , bind_address ) ;
2005-04-03 08:32:37 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-04-08 12:57:09 +04:00
DEBUG ( 0 , ( " Failed to setup dgram listen on %s - %s \n " ,
bind_address , nt_errstr ( status ) ) ) ;
2005-04-03 08:32:37 +04:00
talloc_free ( iface ) ;
return status ;
}
2005-04-08 12:57:09 +04:00
2005-01-31 04:57:58 +03:00
if ( strcmp ( netmask , " 0.0.0.0 " ) = = 0 ) {
DLIST_ADD ( nbtsrv - > bcast_interface , iface ) ;
} else {
DLIST_ADD ( nbtsrv - > interfaces , iface ) ;
}
2005-01-30 13:24:36 +03:00
return NT_STATUS_OK ;
}
2005-02-06 11:25:53 +03:00
/*
setup a socket for talking to our WINS servers
*/
static NTSTATUS nbtd_add_wins_socket ( struct nbtd_server * nbtsrv )
{
struct nbtd_interface * iface ;
iface = talloc_zero ( nbtsrv , struct nbtd_interface ) ;
NT_STATUS_HAVE_NO_MEMORY ( iface ) ;
iface - > nbtsrv = nbtsrv ;
DLIST_ADD ( nbtsrv - > wins_interface , iface ) ;
return NT_STATUS_OK ;
}
2005-01-30 13:24:36 +03:00
/*
setup our listening sockets on the configured network interfaces
*/
2007-12-12 00:23:14 +03:00
NTSTATUS nbtd_startup_interfaces ( struct nbtd_server * nbtsrv , struct loadparm_context * lp_ctx ,
struct interface * ifaces )
2005-01-30 13:24:36 +03:00
{
2011-05-02 09:57:19 +04:00
int num_interfaces = iface_list_count ( ifaces ) ;
2005-01-30 13:24:36 +03:00
int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( nbtsrv ) ;
NTSTATUS status ;
2005-01-31 04:57:58 +03:00
2005-02-02 13:29:50 +03:00
/* if we are allowing incoming packets from any address, then
we also need to bind to the wildcard address */
2010-07-16 08:32:42 +04:00
if ( ! lpcfg_bind_interfaces_only ( lp_ctx ) ) {
2005-02-02 13:29:50 +03:00
const char * primary_address ;
2011-05-12 14:37:34 +04:00
primary_address = iface_list_first_v4 ( ifaces ) ;
2005-02-02 13:29:50 +03:00
/* the primary address is the address we will return
for non - WINS queries not made on a specific
interface */
2011-05-12 14:37:34 +04:00
if ( primary_address = = NULL ) {
2007-10-13 22:24:37 +04:00
primary_address = inet_ntoa ( interpret_addr2 (
2011-05-12 14:37:34 +04:00
lpcfg_netbios_name ( lp_ctx ) ) ) ;
2005-02-02 13:29:50 +03:00
}
2011-05-12 14:37:34 +04:00
2005-02-02 13:29:50 +03:00
primary_address = talloc_strdup ( tmp_ctx , primary_address ) ;
NT_STATUS_HAVE_NO_MEMORY ( primary_address ) ;
2005-01-30 13:24:36 +03:00
2005-02-04 04:39:10 +03:00
status = nbtd_add_socket ( nbtsrv ,
2007-12-03 20:47:42 +03:00
lp_ctx ,
2005-02-04 04:39:10 +03:00
" 0.0.0.0 " ,
primary_address ,
talloc_strdup ( tmp_ctx , " 255.255.255.255 " ) ,
talloc_strdup ( tmp_ctx , " 0.0.0.0 " ) ) ;
2005-02-02 13:29:50 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2005-01-30 13:24:36 +03:00
for ( i = 0 ; i < num_interfaces ; i + + ) {
2011-05-12 14:37:34 +04:00
const char * bcast ;
2006-02-15 07:18:11 +03:00
const char * address , * netmask ;
2011-05-12 14:37:34 +04:00
if ( ! iface_list_n_is_v4 ( ifaces , i ) ) {
/* v4 only for NBT protocol */
continue ;
}
bcast = iface_list_n_bcast ( ifaces , i ) ;
2006-02-15 07:18:11 +03:00
/* we can't assume every interface is broadcast capable */
if ( bcast = = NULL ) continue ;
2011-05-02 09:57:19 +04:00
address = talloc_strdup ( tmp_ctx , iface_list_n_ip ( ifaces , i ) ) ;
2006-02-15 07:18:11 +03:00
bcast = talloc_strdup ( tmp_ctx , bcast ) ;
2011-05-02 09:57:19 +04:00
netmask = talloc_strdup ( tmp_ctx , iface_list_n_netmask ( ifaces , i ) ) ;
2005-01-30 13:24:36 +03:00
2010-07-16 08:32:42 +04:00
status = nbtd_add_socket ( nbtsrv , lp_ctx ,
2007-12-03 20:47:42 +03:00
address , address , bcast , netmask ) ;
2005-01-30 13:24:36 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2010-07-16 08:32:42 +04:00
if ( lpcfg_wins_server_list ( lp_ctx ) ) {
2005-02-06 11:25:53 +03:00
status = nbtd_add_wins_socket ( nbtsrv ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2005-01-30 13:24:36 +03:00
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2005-02-06 11:25:53 +03:00
/*
form a list of addresses that we should use in name query replies
2005-02-07 14:49:55 +03:00
we always place the IP in the given interface first
2005-02-06 11:25:53 +03:00
*/
2005-02-07 14:49:55 +03:00
const char * * nbtd_address_list ( struct nbtd_interface * iface , TALLOC_CTX * mem_ctx )
2005-02-06 11:25:53 +03:00
{
2005-02-07 14:49:55 +03:00
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
2005-02-06 11:25:53 +03:00
const char * * ret = NULL ;
2005-02-07 14:49:55 +03:00
struct nbtd_interface * iface2 ;
2007-10-07 01:33:16 +04:00
bool is_loopback = false ;
2005-02-07 14:49:55 +03:00
2005-02-08 04:09:21 +03:00
if ( iface - > ip_address ) {
2011-05-02 09:57:19 +04:00
is_loopback = iface_list_same_net ( iface - > ip_address , " 127.0.0.1 " , " 255.0.0.0 " ) ;
2005-12-28 07:55:53 +03:00
ret = str_list_add ( ret , iface - > ip_address ) ;
2005-02-08 04:09:21 +03:00
}
2005-02-07 14:49:55 +03:00
for ( iface2 = nbtsrv - > interfaces ; iface2 ; iface2 = iface2 - > next ) {
2005-12-29 19:58:35 +03:00
if ( iface2 = = iface ) continue ;
if ( ! iface2 - > ip_address ) continue ;
if ( ! is_loopback ) {
2011-05-02 09:57:19 +04:00
if ( iface_list_same_net ( iface2 - > ip_address , " 127.0.0.1 " , " 255.0.0.0 " ) ) {
2005-12-29 19:58:35 +03:00
continue ;
}
2005-02-07 14:49:55 +03:00
}
2005-02-06 11:25:53 +03:00
2005-12-28 07:55:53 +03:00
ret = str_list_add ( ret , iface2 - > ip_address ) ;
2005-02-06 11:25:53 +03:00
}
2005-12-23 01:03:25 +03:00
2005-12-28 07:55:53 +03:00
talloc_steal ( mem_ctx , ret ) ;
2005-12-23 01:03:25 +03:00
2005-12-28 07:55:53 +03:00
return ret ;
2005-02-06 11:25:53 +03:00
}
2005-11-14 04:50:55 +03:00
/*
find the interface to use for sending a outgoing request
*/
2006-03-25 12:24:53 +03:00
struct nbtd_interface * nbtd_find_request_iface ( struct nbtd_server * nbtd_server ,
2007-10-07 01:33:16 +04:00
const char * address , bool allow_bcast_iface )
2005-11-14 04:50:55 +03:00
{
2006-03-25 12:24:53 +03:00
struct nbtd_interface * cur ;
2005-11-14 04:50:55 +03:00
/* try to find a exact match */
2006-03-25 12:24:53 +03:00
for ( cur = nbtd_server - > interfaces ; cur ; cur = cur - > next ) {
2011-05-02 09:57:19 +04:00
if ( iface_list_same_net ( address , cur - > ip_address , cur - > netmask ) ) {
2008-01-16 15:43:07 +03:00
DEBUG ( 10 , ( " find interface for dst[%s] ip: %s/%s (iface[%p]) \n " ,
address , cur - > ip_address , cur - > netmask , cur ) ) ;
2006-03-25 12:24:53 +03:00
return cur ;
2005-11-14 04:50:55 +03:00
}
}
/* no exact match, if we have the broadcast interface, use that */
2006-03-25 12:24:53 +03:00
if ( allow_bcast_iface & & nbtd_server - > bcast_interface ) {
2008-01-16 15:43:07 +03:00
cur = nbtd_server - > bcast_interface ;
DEBUG ( 10 , ( " find interface for dst[%s] ip: %s/%s (bcast iface[%p]) \n " ,
address , cur - > ip_address , cur - > netmask , cur ) ) ;
return cur ;
2005-11-14 04:50:55 +03:00
}
/* fallback to first interface */
2008-01-16 15:43:07 +03:00
cur = nbtd_server - > interfaces ;
DEBUG ( 10 , ( " find interface for dst[%s] ip: %s/%s (default iface[%p]) \n " ,
address , cur - > ip_address , cur - > netmask , cur ) ) ;
return cur ;
2005-11-14 04:50:55 +03:00
}
2006-03-25 12:24:53 +03:00
/*
* find the interface to use for sending a outgoing reply
*/
struct nbtd_interface * nbtd_find_reply_iface ( struct nbtd_interface * iface ,
2007-10-07 01:33:16 +04:00
const char * address , bool allow_bcast_iface )
2006-03-25 12:24:53 +03:00
{
struct nbtd_server * nbtd_server = iface - > nbtsrv ;
/* first try to use the given interfacel when it's not the broadcast one */
if ( iface ! = nbtd_server - > bcast_interface ) {
return iface ;
}
return nbtd_find_request_iface ( nbtd_server , address , allow_bcast_iface ) ;
}