Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998
Copyright (C) Jeremy Allison 1994-2003
-
+
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
+ the Free Software Foundation; either version 3 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.
-
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+#include "nmbd/nmbd.h"
+#include "../lib/util/select.h"
+#include "system/select.h"
+#include "libsmb/libsmb.h"
extern int ClientNMB;
extern int ClientDGRAM;
extern int num_response_packets;
-extern struct in_addr loopback_ip;
+bool rescan_listen_set = False;
-static void queue_packet(struct packet_struct *packet);
+static struct nb_packet_server *packet_server;
-BOOL rescan_listen_set = False;
+bool nmbd_init_packet_server(void)
+{
+ NTSTATUS status;
+
+ status = nb_packet_server_create(
+ NULL, nmbd_event_context(),
+ lp_parm_int(-1, "nmbd", "unexpected_clients", 200),
+ &packet_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ERROR: nb_packet_server_create failed: %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+ return true;
+}
/*******************************************************************
struct subnet_record *subrec;
for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
- if(ip_equal(local_ip, subrec->myip))
+ if(ip_equal_v4(local_ip, subrec->myip))
return subrec->nmb_sock;
return ClientNMB;
struct subnet_record *subrec;
for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
- if(ip_equal(local_ip, subrec->myip))
+ if(ip_equal_v4(local_ip, subrec->myip))
return subrec->dgram_sock;
return ClientDGRAM;
Get/Set problematic nb_flags as network byte order 16 bit int.
**************************************************************************/
-uint16 get_nb_flags(char *buf)
+uint16_t get_nb_flags(char *buf)
{
- return ((((uint16)*buf)&0xFFFF) & NB_FLGMSK);
+ return ((((uint16_t)*buf)&0xFFFF) & NB_FLGMSK);
}
-void set_nb_flags(char *buf, uint16 nb_flags)
+void set_nb_flags(char *buf, uint16_t nb_flags)
{
*buf++ = ((nb_flags & NB_FLGMSK) & 0xFF);
*buf = '\0';
Dumps out the browse packet data.
**************************************************************************/
-static void debug_browse_data(char *outbuf, int len)
+static void debug_browse_data(const char *outbuf, int len)
{
int i,j;
x = outbuf[i+j];
if (x < 32 || x > 127)
x = '.';
-
+
DEBUGADD( 4, ( "%c", x ) );
}
Generates the unique transaction identifier
**************************************************************************/
-static uint16 name_trn_id=0;
+static uint16_t name_trn_id=0;
-static uint16 generate_name_trn_id(void)
+static uint16_t generate_name_trn_id(void)
{
if (!name_trn_id) {
- name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+ name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)getpid()%(unsigned)100);
}
name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
return name_trn_id;
Either loops back or sends out a completed NetBIOS packet.
**************************************************************************/
-static BOOL send_netbios_packet(struct packet_struct *p)
+static bool send_netbios_packet(struct packet_struct *p)
{
- BOOL loopback_this_packet = False;
+ bool loopback_this_packet = False;
/* Check if we are sending to or from ourselves as a WINS server. */
- if(ismyip(p->ip) && (p->port == global_nmb_port))
+ if(ismyip_v4(p->ip) && (p->port == global_nmb_port))
loopback_this_packet = True;
if(loopback_this_packet) {
inet_ntoa(p->ip),p->port));
return False;
}
-
+
return True;
}
**************************************************************************/
static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
- BOOL bcast, BOOL rec_des,
+ bool bcast, bool rec_des,
struct in_addr to_ip)
{
struct packet_struct *packet = NULL;
struct nmb_packet *nmb = NULL;
/* Allocate the packet_struct we will return. */
- if((packet = (struct packet_struct *)malloc(sizeof(*packet))) == NULL) {
+ if((packet = SMB_MALLOC_P(struct packet_struct)) == NULL) {
DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
return NULL;
}
-
+
memset((char *)packet,'\0',sizeof(*packet));
nmb = &packet->packet.nmb;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = False;
nmb->header.nm_flags.bcast = bcast;
-
+
nmb->header.rcode = 0;
nmb->header.qdcount = 1;
nmb->header.ancount = 0;
packet->ip = to_ip;
packet->port = NMB_PORT;
- packet->fd = ClientNMB;
+ packet->recv_fd = -1;
+ packet->send_fd = ClientNMB;
packet->timestamp = time(NULL);
packet->packet_type = NMB_PACKET;
packet->locked = False;
-
+
return packet; /* Caller must free. */
}
Sets up the common elements of register, refresh or release packet.
**************************************************************************/
-static BOOL create_and_init_additional_record(struct packet_struct *packet,
- uint16 nb_flags,
- struct in_addr *register_ip)
+static bool create_and_init_additional_record(struct packet_struct *packet,
+ uint16_t nb_flags,
+ const struct in_addr *register_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
- if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
- DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
+ if((nmb->additional = SMB_MALLOC_P(struct res_rec)) == NULL) {
+ DEBUG(0,("create_and_init_additional_record: malloc fail for additional record.\n"));
return False;
}
nmb->additional->rr_name = nmb->question.question_name;
nmb->additional->rr_type = RR_TYPE_NB;
nmb->additional->rr_class = RR_CLASS_IN;
-
+
/* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
if (nmb->header.nm_flags.bcast)
nmb->additional->ttl = PERMANENT_TTL;
else
nmb->additional->ttl = lp_max_ttl();
-
+
nmb->additional->rdlength = 6;
-
+
set_nb_flags(nmb->additional->rdata,nb_flags);
-
+
/* Set the address for the name we are registering. */
putip(&nmb->additional->rdata[2], register_ip);
-
+
/*
it turns out that Jeremys code was correct, we are supposed
to send registrations from the IP we are registering. The
our standard refresh cycle for that name which copes nicely
with disconnected networks.
*/
- packet->fd = find_subnet_fd_for_address(*register_ip);
+ packet->recv_fd = -1;
+ packet->send_fd = find_subnet_fd_for_address(*register_ip);
return True;
}
Sends out a name query.
**************************************************************************/
-static BOOL initiate_name_query_packet( struct packet_struct *packet)
+static bool initiate_name_query_packet( struct packet_struct *packet)
{
struct nmb_packet *nmb = NULL;
Sends out a name query - from a WINS server.
**************************************************************************/
-static BOOL initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
+static bool initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
{
struct nmb_packet *nmb = NULL;
-
+
nmb = &packet->packet.nmb;
nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
nmb->header.arcount = 0;
-
+
nmb->header.nm_flags.recursion_desired = False;
-
+
DEBUG(4,("initiate_name_query_packet_from_wins_server: sending query for name %s (bcast=%s) to IP %s\n",
nmb_namestr(&nmb->question.question_name),
BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
-
+
return send_netbios_packet( packet );
}
Sends out a name register.
**************************************************************************/
-static BOOL initiate_name_register_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *register_ip)
+static bool initiate_name_register_packet( struct packet_struct *packet,
+ uint16_t nb_flags, const struct in_addr *register_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
Sends out a multihomed name register.
**************************************************************************/
-static BOOL initiate_multihomed_name_register_packet(struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *register_ip)
+static bool initiate_multihomed_name_register_packet(struct packet_struct *packet,
+ uint16_t nb_flags, struct in_addr *register_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
fstring second_ip_buf;
nmb->header.arcount = 1;
nmb->header.nm_flags.recursion_desired = True;
-
+
if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
return False;
-
+
DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
for name %s IP %s (bcast=%s) to IP %s\n",
nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
Sends out a name refresh.
**************************************************************************/
-static BOOL initiate_name_refresh_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *refresh_ip)
+static bool initiate_name_refresh_packet( struct packet_struct *packet,
+ uint16_t nb_flags, struct in_addr *refresh_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
Sends out a name release.
**************************************************************************/
-static BOOL initiate_name_release_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *release_ip)
+static bool initiate_name_release_packet( struct packet_struct *packet,
+ uint16_t nb_flags, struct in_addr *release_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
Sends out a node status.
**************************************************************************/
-static BOOL initiate_node_status_packet( struct packet_struct *packet )
+static bool initiate_node_status_packet( struct packet_struct *packet )
{
struct nmb_packet *nmb = &packet->packet.nmb;
broadcast subnet.
****************************************************************************/
-static BOOL assert_check_subnet(struct subnet_record *subrec)
+static bool assert_check_subnet(struct subnet_record *subrec)
{
if( subrec == remote_broadcast_subnet) {
DEBUG(0,("assert_check_subnet: Attempt to send packet on remote broadcast subnet. \
register_name_fail_function fail_fn,
struct userdata_struct *userdata,
struct nmb_name *nmbname,
- uint16 nb_flags)
+ uint16_t nb_flags)
{
struct packet_struct *p;
struct response_record *rrec;
-
+ struct sockaddr_storage ss;
+ const struct sockaddr_storage *pss = NULL;
if(assert_check_subnet(subrec))
return NULL;
subrec->bcast_ip)) == NULL)
return NULL;
- if(initiate_name_register_packet( p, nb_flags, iface_ip(subrec->bcast_ip)) == False) {
+ in_addr_to_sockaddr_storage(&ss, subrec->bcast_ip);
+ pss = iface_ip((struct sockaddr *)(void *)&ss);
+ if (!pss || pss->ss_family != AF_INET) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ if(initiate_name_register_packet(p, nb_flags,
+ &((const struct sockaddr_in *)pss)->sin_addr) == False) {
p->locked = False;
free_packet(p);
return NULL;
void queue_wins_refresh(struct nmb_name *nmbname,
response_function resp_fn,
timeout_response_function timeout_fn,
- uint16 nb_flags,
+ uint16_t nb_flags,
struct in_addr refresh_ip,
const char *tag)
{
DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n",
nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
- userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1);
+ userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
if (!userdata) {
+ p->locked = False;
+ free_packet(p);
DEBUG(0,("Failed to allocate userdata structure!\n"));
return;
}
register_name_fail_function fail_fn,
struct userdata_struct *userdata,
struct nmb_name *nmbname,
- uint16 nb_flags,
+ uint16_t nb_flags,
struct in_addr register_ip,
struct in_addr wins_ip)
{
struct packet_struct *p;
struct response_record *rrec;
- BOOL ret;
-
+ bool ret;
+
/* Sanity check. */
if(subrec != unicast_subnet) {
DEBUG(0,("queue_register_multihomed_name: should only be done on \
if(assert_check_subnet(subrec))
return NULL;
-
+
if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
return NULL;
free_packet(p);
return NULL;
}
-
+
if ((rrec = make_response_record(subrec, /* subnet record. */
p, /* packet we sent. */
resp_fn, /* function to call on response. */
free_packet(p);
return NULL;
}
-
+
return rrec;
}
release_name_fail_function fail_fn,
struct userdata_struct *userdata,
struct nmb_name *nmbname,
- uint16 nb_flags,
+ uint16_t nb_flags,
struct in_addr release_ip,
struct in_addr dest_ip)
{
/****************************************************************************
Queue a query name packet to the broadcast address of a subnet.
****************************************************************************/
-
+
struct response_record *queue_query_name( struct subnet_record *subrec,
response_function resp_fn,
timeout_response_function timeout_fn,
return NULL;
to_ip = subrec->bcast_ip;
-
+
/* queries to the WINS server turn up here as queries to IP 0.0.0.0
These need to be handled a bit differently */
- if (subrec->type == UNICAST_SUBNET && is_zero_ip(to_ip)) {
+ if (subrec->type == UNICAST_SUBNET && is_zero_ip_v4(to_ip)) {
/* What we really need to do is loop over each of our wins
* servers and wins server tags here, but that just doesn't
* fit our architecture at the moment (userdata may already
DEBUG(10,("queue_query_name: bind_interfaces_only is set, looking for suitable source IP\n"));
for(i = 0; i < iface_count(); i++) {
- struct in_addr *ifip = iface_n_ip(i);
+ const struct in_addr *ifip = iface_n_ip_v4(i);
- if(ifip == NULL) {
+ if (ifip == NULL) {
DEBUG(0,("queue_query_name: interface %d has NULL IP address !\n", i));
continue;
}
- if (ip_equal(*ifip,loopback_ip)) {
+ if (is_loopback_ip_v4(*ifip)) {
DEBUG(5,("queue_query_name: ignoring loopback interface (%d)\n", i));
continue;
}
DEBUG(10,("queue_query_name: using source IP %s\n",inet_ntoa(*ifip)));
- p->fd = find_subnet_fd_for_address( *ifip );
+ p->send_fd = find_subnet_fd_for_address( *ifip );
break;
}
}
/****************************************************************************
Queue a query name packet to a given address from the WINS subnet.
****************************************************************************/
-
+
struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
response_function resp_fn,
timeout_response_function timeout_fn,
/****************************************************************************
Queue a node status packet to a given name and address.
****************************************************************************/
-
+
struct response_record *queue_node_status( struct subnet_record *subrec,
response_function resp_fn,
timeout_response_function timeout_fn,
p->locked = False;
free_packet(p);
return NULL;
- }
+ }
if((rrec = make_response_record(subrec, /* subnet record. */
p, /* packet we sent. */
struct nmb_packet *nmb = NULL;
struct res_rec answers;
struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
- BOOL loopback_this_packet = False;
+ bool loopback_this_packet = False;
+ int rr_type = RR_TYPE_NB;
const char *packet_type = "unknown";
-
+
/* Check if we are sending to or from ourselves. */
- if(ismyip(orig_packet->ip) && (orig_packet->port == global_nmb_port))
+ if(ismyip_v4(orig_packet->ip) && (orig_packet->port == global_nmb_port))
loopback_this_packet = True;
-
+
nmb = &packet.packet.nmb;
/* Do a partial copy of the packet. We clear the locked flag and
packet_type = "nmb_status";
nmb->header.nm_flags.recursion_desired = False;
nmb->header.nm_flags.recursion_available = False;
+ rr_type = RR_TYPE_NBSTAT;
break;
case NMB_QUERY:
packet_type = "nmb_query";
nmb->header.nm_flags.recursion_desired = True;
nmb->header.nm_flags.recursion_available = True;
+ if (rcode) {
+ rr_type = RR_TYPE_NULL;
+ }
break;
case NMB_REG:
case NMB_REG_REFRESH:
packet_type = "nmb_wack";
nmb->header.nm_flags.recursion_desired = False;
nmb->header.nm_flags.recursion_available = False;
+ rr_type = RR_TYPE_NULL;
break;
case WINS_REG:
packet_type = "wins_reg";
packet_type = "wins_query";
nmb->header.nm_flags.recursion_desired = True;
nmb->header.nm_flags.recursion_available = True;
+ if (rcode) {
+ rr_type = RR_TYPE_NULL;
+ }
break;
default:
DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
return;
}
- DEBUG(4,("reply_netbios_packet: sending a reply of packet type: %s %s to ip %s \
-for id %hu\n", packet_type, nmb_namestr(&orig_nmb->question.question_name),
- inet_ntoa(packet.ip), orig_nmb->header.name_trn_id));
+ DEBUG(4, ("reply_netbios_packet: sending a reply of packet type: %s "
+ "%s to ip %s for id %d\n", packet_type,
+ nmb_namestr(&orig_nmb->question.question_name),
+ inet_ntoa(packet.ip), orig_nmb->header.name_trn_id));
nmb->header.name_trn_id = orig_nmb->header.name_trn_id;
nmb->header.opcode = opcode;
nmb->header.nm_flags.bcast = False;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = True;
-
+
nmb->header.rcode = rcode;
nmb->header.qdcount = 0;
nmb->header.ancount = 1;
nmb->header.nscount = 0;
nmb->header.arcount = 0;
-
+
memset((char*)&nmb->question,'\0',sizeof(nmb->question));
-
+
nmb->answers = &answers;
memset((char*)nmb->answers,'\0',sizeof(*nmb->answers));
-
+
nmb->answers->rr_name = orig_nmb->question.question_name;
- nmb->answers->rr_type = orig_nmb->question.question_type;
- nmb->answers->rr_class = orig_nmb->question.question_class;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = RR_CLASS_IN;
nmb->answers->ttl = ttl;
-
+
if (data && len) {
+ if (len < 0 || len > sizeof(nmb->answers->rdata)) {
+ DEBUG(5,("reply_netbios_packet: "
+ "invalid packet len (%d)\n",
+ len ));
+ return;
+ }
nmb->answers->rdlength = len;
memcpy(nmb->answers->rdata, data, len);
}
-
+
packet.packet_type = NMB_PACKET;
+ packet.recv_fd = -1;
/* Ensure we send out on the same fd that the original
packet came in on to give the correct source IP address. */
- packet.fd = orig_packet->fd;
+ if (orig_packet->send_fd != -1) {
+ packet.send_fd = orig_packet->send_fd;
+ } else {
+ packet.send_fd = orig_packet->recv_fd;
+ }
packet.timestamp = time(NULL);
debug_nmb_packet(&packet);
-
+
if(loopback_this_packet) {
struct packet_struct *lo_packet;
DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
Queue a packet into a packet queue
******************************************************************/
-static void queue_packet(struct packet_struct *packet)
+void queue_packet(struct packet_struct *packet)
{
- struct packet_struct *p;
-
- if (!packet_queue) {
- packet->prev = NULL;
- packet->next = NULL;
- packet_queue = packet;
- return;
- }
-
- /* find the bottom */
- for (p=packet_queue;p->next;p=p->next)
- ;
-
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
+ DLIST_ADD_END(packet_queue, packet, struct packet_struct *);
}
/****************************************************************************
/* Go through all the broadcast subnets and see if the mask matches. */
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
- if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
return subrec;
}
Dispatch a browse frame from port 138 to the correct processing function.
****************************************************************************/
-static void process_browse_packet(struct packet_struct *p, char *buf,int len)
+static void process_browse_packet(struct packet_struct *p, const char *buf,int len)
{
struct dgram_packet *dgram = &p->packet.dgram;
int command = CVAL(buf,0);
struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
char scope[64];
- fstring src_name;
+ unstring src_name;
/* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
- if (!strequal(scope, global_scope())) {
+ if (!strequal(scope, lp_netbios_scope())) {
DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
-mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, lp_netbios_scope()));
return;
}
pull_ascii_nstring(src_name, sizeof(src_name), dgram->source_name.name);
if (is_myname(src_name)) {
- DEBUG(0,("process_browse_packet: Discarding datagram from IP %s. Source name \
+ DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Source name \
%s is one of our names !\n", inet_ntoa(p->ip), nmb_namestr(&dgram->source_name)));
return;
}
process_master_browser_announce(subrec, p, buf+1);
break;
case ANN_BecomeBackup:
- /*
+ /*
* We don't currently implement this. Log it just in case.
*/
debug_browse_data(buf, len);
command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
break;
- }
+ }
}
/****************************************************************************
Dispatch a LanMan browse frame from port 138 to the correct processing function.
****************************************************************************/
-static void process_lanman_packet(struct packet_struct *p, char *buf,int len)
+static void process_lanman_packet(struct packet_struct *p, const char *buf,int len)
{
struct dgram_packet *dgram = &p->packet.dgram;
int command = SVAL(buf,0);
struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
char scope[64];
- fstring src_name;
+ unstring src_name;
/* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
- if (!strequal(scope, global_scope())) {
+ if (!strequal(scope, lp_netbios_scope())) {
DEBUG(7,("process_lanman_packet: Discarding datagram from IP %s. Scope (%s) \
-mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, lp_netbios_scope()));
return;
}
switch (command) {
case ANN_HostAnnouncement:
debug_browse_data(buf, len);
- process_lm_host_announce(subrec, p, buf+1);
+ process_lm_host_announce(subrec, p, buf+1, len > 1 ? len-1 : 0);
break;
case ANN_AnnouncementRequest:
- process_lm_announce_request(subrec, p, buf+1);
+ process_lm_announce_request(subrec, p, buf+1, len > 1 ? len-1 : 0);
break;
default:
DEBUG(0,("process_lanman_packet: On subnet %s ignoring browse packet \
stage as subsequent processing is expensive.
****************************************************************************/
-static BOOL listening(struct packet_struct *p,struct nmb_name *nbname)
+static bool listening(struct packet_struct *p,struct nmb_name *nbname)
{
struct subnet_record *subrec = NULL;
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
- if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
break;
}
static void process_dgram(struct packet_struct *p)
{
- char *buf;
- char *buf2;
+ const char *buf;
+ const char *buf2;
int len;
struct dgram_packet *dgram = &p->packet.dgram;
/* If we aren't listening to the destination name then ignore the packet */
if (!listening(p,&dgram->dest_name)) {
- unexpected_packet(p);
+ nb_packet_dispatch(packet_server, p);
DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from %s\n",
nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip)));
return;
}
if (dgram->header.msg_type != 0x10 && dgram->header.msg_type != 0x11 && dgram->header.msg_type != 0x12) {
- unexpected_packet(p);
+ nb_packet_dispatch(packet_server, p);
/* Don't process error packets etc yet */
DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from IP %s as it is \
an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip), dgram->header.msg_type));
return;
}
+ /* Ensure we have a large enough packet before looking inside. */
+ if (dgram->datasize < (smb_vwv12 - 2)) {
+ /* That's the offset minus the 4 byte length + 2 bytes of offset. */
+ DEBUG(0,("process_dgram: ignoring too short dgram packet (%u) sent to name %s from IP %s\n",
+ (unsigned int)dgram->datasize,
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
buf = &dgram->data[0];
buf -= 4; /* XXXX for the pseudo tcp length - someday I need to get rid of this */
len = SVAL(buf,smb_vwv11);
buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
- if (len <= 0)
+ if (len <= 0 || len > dgram->datasize) {
+ DEBUG(0,("process_dgram: ignoring malformed1 (datasize = %d, len = %d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
return;
+ }
- if (buf2 + len > buf + sizeof(dgram->data)) {
- DEBUG(2,("process_dgram: datagram from %s to %s IP %s for %s len=%d too long.\n",
- nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
- inet_ntoa(p->ip), smb_buf(buf),len));
- len = (buf + sizeof(dgram->data)) - buf;
+ if (buf2 < dgram->data || (buf2 >= dgram->data + dgram->datasize)) {
+ DEBUG(0,("process_dgram: ignoring malformed2 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ (int)PTR_DIFF(buf2, dgram->data),
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
+ if ((buf2 + len < dgram->data) || (buf2 + len > dgram->data + dgram->datasize)) {
+ DEBUG(0,("process_dgram: ignoring malformed3 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ (int)PTR_DIFF(buf2, dgram->data),
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
}
DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
- inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
+ inet_ntoa(p->ip), smb_buf_const(buf),CVAL(buf2,0),len));
/* Datagram packet received for the browser mailslot */
- if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
+ if (strequal(smb_buf_const(buf),BROWSE_MAILSLOT)) {
process_browse_packet(p,buf2,len);
return;
}
/* Datagram packet received for the LAN Manager mailslot */
- if (strequal(smb_buf(buf),LANMAN_MAILSLOT)) {
+ if (strequal(smb_buf_const(buf),LANMAN_MAILSLOT)) {
process_lanman_packet(p,buf2,len);
return;
}
/* Datagram packet received for the domain logon mailslot */
- if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
+ if (strequal(smb_buf_const(buf),NET_LOGON_MAILSLOT)) {
process_logon_packet(p,buf2,len,NET_LOGON_MAILSLOT);
return;
}
/* Datagram packet received for the NT domain logon mailslot */
- if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT)) {
+ if (strequal(smb_buf_const(buf),NT_LOGON_MAILSLOT)) {
process_logon_packet(p,buf2,len,NT_LOGON_MAILSLOT);
return;
}
- unexpected_packet(p);
+ nb_packet_dispatch(packet_server, p);
}
/****************************************************************************
Validate a response nmb packet.
****************************************************************************/
-static BOOL validate_nmb_response_packet( struct nmb_packet *nmb )
+static bool validate_nmb_response_packet( struct nmb_packet *nmb )
{
- BOOL ignore = False;
+ bool ignore = False;
switch (nmb->header.opcode) {
case NMB_NAME_REG_OPCODE:
return ignore;
}
-
+
/****************************************************************************
Validate a request nmb packet.
****************************************************************************/
-static BOOL validate_nmb_packet( struct nmb_packet *nmb )
+static bool validate_nmb_packet( struct nmb_packet *nmb )
{
- BOOL ignore = False;
+ bool ignore = False;
switch (nmb->header.opcode) {
case NMB_NAME_REG_OPCODE:
rrec = find_response_record( &subrec, nmb->header.name_trn_id);
if(rrec == NULL) {
- DEBUG(3,("find_subnet_for_nmb_packet: response record not found for response id %hu\n",
- nmb->header.name_trn_id));
- unexpected_packet(p);
+ DEBUG(3, ("find_subnet_for_nmb_packet: response "
+ "record not found for response id %d\n",
+ nmb->header.name_trn_id));
+ nb_packet_dispatch(packet_server, p);
return NULL;
}
if(subrec == NULL) {
- DEBUG(0,("find_subnet_for_nmb_packet: subnet record not found for response id %hu\n",
- nmb->header.name_trn_id));
+ DEBUG(0, ("find_subnet_for_nmb_packet: subnet record "
+ "not found for response id %d\n",
+ nmb->header.name_trn_id));
return NULL;
}
/* Go through all the broadcast subnets and see if the mask matches. */
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
- if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+ if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
return subrec;
}
break;
}
break;
-
+
case NMB_NAME_RELEASE_OPCODE:
if(subrec == wins_server_subnet)
wins_process_name_release_request(subrec, p);
return;
if(rrec == NULL) {
- DEBUG(0,("process_nmb_response: response packet received but no response record \
-found for id = %hu. Ignoring packet.\n", nmb->header.name_trn_id));
+ DEBUG(0, ("process_nmb_response: response packet received but "
+ "no response record found for id = %d. Ignoring "
+ "packet.\n", nmb->header.name_trn_id));
return;
}
rrec->num_msgs++;
/* Ensure we don't re-send the request. */
rrec->repeat_count = 0;
-
+
/* Call the response received function for this packet. */
(*rrec->resp_fn)(subrec, rrec, p);
}
struct packet_struct *p;
while ((p = packet_queue)) {
- packet_queue = p->next;
- if (packet_queue)
- packet_queue->prev = NULL;
- p->next = p->prev = NULL;
+ DLIST_REMOVE(packet_queue, p);
switch (p->packet_type) {
case NMB_PACKET:
}
free_packet(p);
}
-}
+}
/*******************************************************************
Retransmit or timeout elements from all the outgoing subnet response
for (subrec = FIRST_SUBNET; subrec; subrec = get_next_subnet_maybe_unicast_or_wins_server(subrec)) {
struct response_record *rrec, *nextrrec;
+ restart:
+
for (rrec = subrec->responselist; rrec; rrec = nextrrec) {
nextrrec = rrec->next;
-
+
if (rrec->repeat_time <= t) {
if (rrec->repeat_count > 0) {
/* Resend while we have a non-zero repeat_count. */
no timeout function. */
remove_response_record(subrec, rrec);
}
+ /* We have changed subrec->responselist,
+ * restart from the beginning of this list. */
+ goto restart;
} /* !rrec->in_expitation_processing */
} /* rrec->repeat_count > 0 */
} /* rrec->repeat_time <= t */
plus the broadcast sockets.
***************************************************************************/
-static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
+struct socket_attributes {
+ enum packet_type type;
+ bool broadcast;
+};
+
+static bool create_listen_pollfds(struct pollfd **pfds,
+ struct socket_attributes **pattrs,
+ int *pnum_sockets)
{
- int *sock_array = NULL;
struct subnet_record *subrec = NULL;
int count = 0;
int num = 0;
- fd_set *pset = (fd_set *)malloc(sizeof(fd_set));
+ struct pollfd *fds;
+ struct socket_attributes *attrs;
- if(pset == NULL) {
- DEBUG(0,("create_listen_fdset: malloc fail !\n"));
- return True;
- }
+ /* The ClientNMB and ClientDGRAM sockets */
+ count = 2;
/* Check that we can add all the fd's we need. */
- for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
- count++;
+ for (subrec = FIRST_SUBNET;
+ subrec != NULL;
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ if (subrec->nmb_sock != -1) {
+ count += 1;
+ }
+ if (subrec->dgram_sock != -1) {
+ count += 1;
+ }
+ if (subrec->nmb_bcast != -1) {
+ count += 1;
+ }
+ if (subrec->dgram_bcast != -1) {
+ count += 1;
+ }
+ }
- if((count*2) + 2 > FD_SETSIZE) {
- DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
-only use %d.\n", (count*2) + 2, FD_SETSIZE));
- return True;
+ fds = talloc_zero_array(NULL, struct pollfd, count);
+ if (fds == NULL) {
+ DEBUG(1, ("create_listen_pollfds: malloc fail for fds. "
+ "size %d\n", count));
+ return true;
}
- if((sock_array = (int *)malloc(((count*2) + 2)*sizeof(int))) == NULL) {
- DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
- return True;
+ attrs = talloc_array(NULL, struct socket_attributes, count);
+ if (fds == NULL) {
+ DEBUG(1, ("create_listen_pollfds: malloc fail for attrs. "
+ "size %d\n", count));
+ TALLOC_FREE(fds);
+ return true;
}
- FD_ZERO(pset);
+ num = 0;
- /* Add in the broadcast socket on 137. */
- FD_SET(ClientNMB,pset);
- sock_array[num++] = ClientNMB;
+ fds[num].fd = ClientNMB;
+ attrs[num].type = NMB_PACKET;
+ attrs[num].broadcast = false;
+ num += 1;
+
+ fds[num].fd = ClientDGRAM;
+ attrs[num].type = DGRAM_PACKET;
+ attrs[num].broadcast = false;
+ num += 1;
- /* Add in the 137 sockets on all the interfaces. */
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
- FD_SET(subrec->nmb_sock,pset);
- sock_array[num++] = subrec->nmb_sock;
- }
- /* Add in the broadcast socket on 138. */
- FD_SET(ClientDGRAM,pset);
- sock_array[num++] = ClientDGRAM;
+ if (subrec->nmb_sock != -1) {
+ fds[num].fd = subrec->nmb_sock;
+ attrs[num].type = NMB_PACKET;
+ attrs[num].broadcast = false;
+ num += 1;
+ }
- /* Add in the 138 sockets on all the interfaces. */
- for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
- FD_SET(subrec->dgram_sock,pset);
- sock_array[num++] = subrec->dgram_sock;
+ if (subrec->nmb_bcast != -1) {
+ fds[num].fd = subrec->nmb_bcast;
+ attrs[num].type = NMB_PACKET;
+ attrs[num].broadcast = true;
+ num += 1;
+ }
+
+ if (subrec->dgram_sock != -1) {
+ fds[num].fd = subrec->dgram_sock;
+ attrs[num].type = DGRAM_PACKET;
+ attrs[num].broadcast = false;
+ num += 1;
+ }
+
+ if (subrec->dgram_bcast != -1) {
+ fds[num].fd = subrec->dgram_bcast;
+ attrs[num].type = DGRAM_PACKET;
+ attrs[num].broadcast = true;
+ num += 1;
+ }
}
- *listen_number = (count*2) + 2;
+ TALLOC_FREE(*pfds);
+ *pfds = fds;
+
+ TALLOC_FREE(*pattrs);
+ *pattrs = attrs;
- SAFE_FREE(*ppset);
- SAFE_FREE(*psock_array);
+ *pnum_sockets = count;
- *ppset = pset;
- *psock_array = sock_array;
-
return False;
}
+/****************************************************************************
+ List of packets we're processing this select.
+***************************************************************************/
+
+struct processed_packet {
+ struct processed_packet *next;
+ struct processed_packet *prev;
+ enum packet_type packet_type;
+ struct in_addr ip;
+ int packet_id;
+};
+
+/****************************************************************************
+ Have we seen this before ?
+***************************************************************************/
+
+static bool is_processed_packet(struct processed_packet *processed_packet_list,
+ struct packet_struct *packet)
+{
+ struct processed_packet *p = NULL;
+
+ for (p = processed_packet_list; p; p = p->next) {
+ if (ip_equal_v4(p->ip, packet->ip) && p->packet_type == packet->packet_type) {
+ if ((p->packet_type == NMB_PACKET) &&
+ (p->packet_id ==
+ packet->packet.nmb.header.name_trn_id)) {
+ return true;
+ } else if ((p->packet_type == DGRAM_PACKET) &&
+ (p->packet_id ==
+ packet->packet.dgram.header.dgm_id)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/****************************************************************************
+ Keep a list of what we've seen before.
+***************************************************************************/
+
+static bool store_processed_packet(struct processed_packet **pp_processed_packet_list,
+ struct packet_struct *packet)
+{
+ struct processed_packet *p = SMB_MALLOC_P(struct processed_packet);
+ if (!p) {
+ return false;
+ }
+ p->packet_type = packet->packet_type;
+ p->ip = packet->ip;
+ if (packet->packet_type == NMB_PACKET) {
+ p->packet_id = packet->packet.nmb.header.name_trn_id;
+ } else if (packet->packet_type == DGRAM_PACKET) {
+ p->packet_id = packet->packet.dgram.header.dgm_id;
+ } else {
+ SAFE_FREE(p);
+ return false;
+ }
+
+ DLIST_ADD(*pp_processed_packet_list, p);
+ return true;
+}
+
+/****************************************************************************
+ Throw away what we've seen before.
+***************************************************************************/
+
+static void free_processed_packet_list(struct processed_packet **pp_processed_packet_list)
+{
+ struct processed_packet *p = NULL, *next = NULL;
+
+ for (p = *pp_processed_packet_list; p; p = next) {
+ next = p->next;
+ DLIST_REMOVE(*pp_processed_packet_list, p);
+ SAFE_FREE(p);
+ }
+}
+
/****************************************************************************
Listens for NMB or DGRAM packets, and queues them.
return True if the socket is dead
***************************************************************************/
-BOOL listen_for_packets(BOOL run_election)
+bool listen_for_packets(struct messaging_context *msg, bool run_election)
{
- static fd_set *listen_set = NULL;
+ static struct pollfd *fds = NULL;
+ static struct socket_attributes *attrs = NULL;
static int listen_number = 0;
- static int *sock_array = NULL;
+ int num_sockets;
int i;
- fd_set fds;
- int selrtn;
- struct timeval timeout;
+ int pollrtn;
+ int timeout;
#ifndef SYNC_DNS
int dns_fd;
+ int dns_pollidx = -1;
#endif
+ struct processed_packet *processed_packet_list = NULL;
- if(listen_set == NULL || rescan_listen_set) {
- if(create_listen_fdset(&listen_set, &sock_array, &listen_number)) {
+ if ((fds == NULL) || rescan_listen_set) {
+ if (create_listen_pollfds(&fds, &attrs, &listen_number)) {
DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
return True;
}
rescan_listen_set = False;
}
- memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+ /*
+ * "fds" can be enlarged by event_add_to_poll_args
+ * below. Shrink it again to what was given to us by
+ * create_listen_pollfds.
+ */
+
+ fds = talloc_realloc(NULL, fds, struct pollfd, listen_number);
+ if (fds == NULL) {
+ return true;
+ }
+ num_sockets = listen_number;
#ifndef SYNC_DNS
dns_fd = asyncdns_fd();
if (dns_fd != -1) {
- FD_SET(dns_fd, &fds);
+ fds = talloc_realloc(NULL, fds, struct pollfd, num_sockets+1);
+ if (fds == NULL) {
+ return true;
+ }
+ dns_pollidx = num_sockets;
+ fds[num_sockets].fd = dns_fd;
+ num_sockets += 1;
}
#endif
- /*
+ for (i=0; i<num_sockets; i++) {
+ fds[i].events = POLLIN|POLLHUP;
+ }
+
+ /* Process a signal and timer events now... */
+ if (run_events_poll(nmbd_event_context(), 0, NULL, 0)) {
+ return False;
+ }
+
+ /*
* During elections and when expecting a netbios response packet we
* need to send election packets at tighter intervals.
* Ideally it needs to be the interval (in ms) between time now and
* the time we are expecting the next netbios packet.
*/
- timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
- timeout.tv_usec = 0;
+ timeout = ((run_election||num_response_packets)
+ ? 1 : NMBD_SELECT_LOOP) * 1000;
- /* Prepare for the select - allow certain signals. */
+ event_add_to_poll_args(nmbd_event_context(), NULL,
+ &fds, &num_sockets, &timeout);
- BlockSignals(False, SIGTERM);
+ pollrtn = poll(fds, num_sockets, timeout);
- selrtn = sys_select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
-
- /* We can only take signals when we are in the select - block them again here. */
-
- BlockSignals(True, SIGTERM);
+ if (run_events_poll(nmbd_event_context(), pollrtn, fds, num_sockets)) {
+ return False;
+ }
- if(selrtn == -1) {
+ if (pollrtn == -1) {
return False;
}
#ifndef SYNC_DNS
- if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
- run_dns_queue();
+ if ((dns_fd != -1) && (dns_pollidx != -1) &&
+ (fds[dns_pollidx].revents & (POLLIN|POLLHUP|POLLERR))) {
+ run_dns_queue(msg);
}
#endif
for(i = 0; i < listen_number; i++) {
- if (i < (listen_number/2)) {
- /* Processing a 137 socket. */
- if (FD_ISSET(sock_array[i],&fds)) {
- struct packet_struct *packet = read_packet(sock_array[i], NMB_PACKET);
- if (packet) {
- /*
- * If we got a packet on the broadcast socket and interfaces
- * only is set then check it came from one of our local nets.
- */
- if(lp_bind_interfaces_only() && (sock_array[i] == ClientNMB) &&
- (!is_local_net(packet->ip))) {
- DEBUG(7,("discarding nmb packet sent to broadcast socket from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- } else if ((ip_equal(loopback_ip, packet->ip) ||
- ismyip(packet->ip)) && packet->port == global_nmb_port &&
- packet->packet.nmb.header.nm_flags.bcast) {
- DEBUG(7,("discarding own bcast packet from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- } else {
- /* Save the file descriptor this packet came in on. */
- packet->fd = sock_array[i];
- queue_packet(packet);
- }
- }
- }
+ enum packet_type packet_type;
+ struct packet_struct *packet;
+ const char *packet_name;
+ int client_fd;
+ int client_port;
+
+ if ((fds[i].revents & (POLLIN|POLLHUP|POLLERR)) == 0) {
+ continue;
+ }
+
+ if (attrs[i].type == NMB_PACKET) {
+ /* Port 137 */
+ packet_type = NMB_PACKET;
+ packet_name = "nmb";
+ client_fd = ClientNMB;
+ client_port = global_nmb_port;
} else {
- /* Processing a 138 socket. */
- if (FD_ISSET(sock_array[i],&fds)) {
- struct packet_struct *packet = read_packet(sock_array[i], DGRAM_PACKET);
- if (packet) {
- /*
- * If we got a packet on the broadcast socket and interfaces
- * only is set then check it came from one of our local nets.
- */
- if(lp_bind_interfaces_only() && (sock_array[i] == ClientDGRAM) &&
- (!is_local_net(packet->ip))) {
- DEBUG(7,("discarding dgram packet sent to broadcast socket from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- } else if ((ip_equal(loopback_ip, packet->ip) ||
- ismyip(packet->ip)) && packet->port == DGRAM_PORT) {
- DEBUG(7,("discarding own dgram packet from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- } else {
- /* Save the file descriptor this packet came in on. */
- packet->fd = sock_array[i];
- queue_packet(packet);
- }
+ /* Port 138 */
+ packet_type = DGRAM_PACKET;
+ packet_name = "dgram";
+ client_fd = ClientDGRAM;
+ client_port = DGRAM_PORT;
+ }
+
+ packet = read_packet(fds[i].fd, packet_type);
+ if (!packet) {
+ continue;
+ }
+
+ /*
+ * If we got a packet on the broadcast socket and interfaces
+ * only is set then check it came from one of our local nets.
+ */
+ if (lp_bind_interfaces_only() &&
+ (fds[i].fd == client_fd) &&
+ (!is_local_net_v4(packet->ip))) {
+ DEBUG(7,("discarding %s packet sent to broadcast socket from %s:%d\n",
+ packet_name, inet_ntoa(packet->ip), packet->port));
+ free_packet(packet);
+ continue;
+ }
+
+ if (!IS_DC) {
+ if ((is_loopback_ip_v4(packet->ip) || ismyip_v4(packet->ip)) &&
+ packet->port == client_port)
+ {
+ if (client_port == DGRAM_PORT) {
+ DEBUG(7,("discarding own dgram packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ continue;
+ }
+
+ if (packet->packet.nmb.header.nm_flags.bcast) {
+ DEBUG(7,("discarding own nmb bcast packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ continue;
}
}
- } /* end processing 138 socket. */
- } /* end for */
+ }
+
+ if (is_processed_packet(processed_packet_list, packet)) {
+ DEBUG(7,("discarding duplicate packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ continue;
+ }
+
+ store_processed_packet(&processed_packet_list, packet);
+
+ if (attrs[i].broadcast) {
+ /* this is a broadcast socket */
+ packet->send_fd = fds[i-1].fd;
+ } else {
+ /* this is already a unicast socket */
+ packet->send_fd = fds[i].fd;
+ }
+
+ queue_packet(packet);
+ }
+
+ free_processed_packet_list(&processed_packet_list);
return False;
}
Construct and send a netbios DGRAM.
**************************************************************************/
-BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf, size_t len,
+bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t len,
const char *srcname, int src_type,
const char *dstname, int dest_type,
struct in_addr dest_ip,struct in_addr src_ip,
int dest_port)
{
- BOOL loopback_this_packet = False;
+ bool loopback_this_packet = False;
struct packet_struct p;
struct dgram_packet *dgram = &p.packet.dgram;
char *ptr,*p2;
memset((char *)&p,'\0',sizeof(p));
- if(ismyip(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
+ if(ismyip_v4(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
loopback_this_packet = True;
/* generate_name_trn_id(); */ /* Not used, so gone, RJS */
/* DIRECT GROUP or UNIQUE datagram. */
- dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
dgram->header.flags.node_type = M_NODE;
dgram->header.flags.first = True;
dgram->header.flags.more = False;
dgram->header.source_port = DGRAM_PORT;
dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
dgram->header.packet_offset = 0;
-
+
make_nmb_name(&dgram->source_name,srcname,src_type);
make_nmb_name(&dgram->dest_name,dstname,dest_type);
/* Setup the smb part. */
ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
memcpy(tmp,ptr,4);
- set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+
+ if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) {
+ DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
+ return false;
+ }
+
+ cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
memcpy(ptr,tmp,4);
SCVAL(ptr,smb_com,SMBtrans);
SSVAL(ptr,smb_vwv15,1);
SSVAL(ptr,smb_vwv16,2);
p2 = smb_buf(ptr);
- safe_strcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
- p2 = skip_string(p2,1);
-
+ strlcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
+ p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
+
if (((p2+len) > dgram->data+sizeof(dgram->data)) || ((p2+len) < p2)) {
DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
return False;
} else {
- memcpy(p2,buf,len);
+ if (len) {
+ memcpy(p2,buf,len);
+ }
p2 += len;
}
p.ip = dest_ip;
p.port = dest_port;
- p.fd = find_subnet_mailslot_fd_for_address( src_ip );
+ p.recv_fd = -1;
+ p.send_fd = find_subnet_mailslot_fd_for_address( src_ip );
p.timestamp = time(NULL);
p.packet_type = DGRAM_PACKET;