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 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, 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;
bool rescan_listen_set = False;
+static struct nb_packet_server *packet_server;
+
+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;
+}
+
/*******************************************************************
The global packet linked-list. Incoming entries are
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;
inet_ntoa(p->ip),p->port));
return False;
}
-
+
return True;
}
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. */
}
**************************************************************************/
static bool create_and_init_additional_record(struct packet_struct *packet,
- uint16 nb_flags,
+ uint16_t nb_flags,
const struct in_addr *register_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
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;
}
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 );
}
**************************************************************************/
static bool initiate_name_register_packet( struct packet_struct *packet,
- uint16 nb_flags, const struct in_addr *register_ip)
+ uint16_t nb_flags, const struct in_addr *register_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
**************************************************************************/
static bool initiate_multihomed_name_register_packet(struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *register_ip)
+ 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),
**************************************************************************/
static bool initiate_name_refresh_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *refresh_ip)
+ uint16_t nb_flags, struct in_addr *refresh_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
**************************************************************************/
static bool initiate_name_release_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *release_ip)
+ uint16_t nb_flags, struct in_addr *release_ip)
{
struct nmb_packet *nmb = &packet->packet.nmb;
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;
return NULL;
in_addr_to_sockaddr_storage(&ss, subrec->bcast_ip);
- pss = iface_ip((struct sockaddr *)&ss);
+ pss = iface_ip((struct sockaddr *)(void *)&ss);
if (!pss || pss->ss_family != AF_INET) {
p->locked = False;
free_packet(p);
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)
{
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;
-
+
/* 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_v4(to_ip)) {
}
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;
}
}
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;
}
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);
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 *);
}
/****************************************************************************
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);
/* 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;
}
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);
/* 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;
}
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));
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);
}
/****************************************************************************
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;
}
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;
}
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:
plus the broadcast sockets.
***************************************************************************/
-static bool create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number, int *maxfd)
+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 = SMB_MALLOC_P(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));
- SAFE_FREE(pset);
- 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 = SMB_MALLOC_ARRAY(int, (count*2) + 2)) == NULL) {
- DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
- SAFE_FREE(pset);
- 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;
- *maxfd = MAX( *maxfd, 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;
- *maxfd = MAX( *maxfd, subrec->nmb_sock);
- }
- /* Add in the broadcast socket on 138. */
- FD_SET(ClientDGRAM,pset);
- sock_array[num++] = ClientDGRAM;
- *maxfd = MAX( *maxfd, 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;
- *maxfd = MAX( *maxfd, 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;
- SAFE_FREE(*ppset);
- SAFE_FREE(*psock_array);
+ TALLOC_FREE(*pattrs);
+ *pattrs = attrs;
- *ppset = pset;
- *psock_array = sock_array;
+ *pnum_sockets = count;
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;
- static int maxfd = 0;
- fd_set r_fds;
- fd_set w_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, &maxfd)) {
+ 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 *)&r_fds, (char *)listen_set, sizeof(fd_set));
- FD_ZERO(&w_fds);
+ /*
+ * "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, &r_fds);
- maxfd = MAX( maxfd, dns_fd);
+ 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(nmbd_event_context(), 0, NULL, NULL)) {
+ if (run_events_poll(nmbd_event_context(), 0, NULL, 0)) {
return False;
}
* 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;
- {
- struct timeval now = timeval_current();
- event_add_to_select_args(nmbd_event_context(), &now,
- &r_fds, &w_fds, &timeout, &maxfd);
- }
+ event_add_to_poll_args(nmbd_event_context(), NULL,
+ &fds, &num_sockets, &timeout);
- selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&timeout);
+ pollrtn = poll(fds, num_sockets, timeout);
- if (run_events(nmbd_event_context(), selrtn, &r_fds, &w_fds)) {
+ 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,&r_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],&r_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_v4(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 ((is_loopback_ip_v4(packet->ip) ||
- ismyip_v4(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],&r_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_v4(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 ((is_loopback_ip_v4(packet->ip) ||
- ismyip_v4(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;
}
SSVAL(ptr,smb_vwv15,1);
SSVAL(ptr,smb_vwv16,2);
p2 = smb_buf(ptr);
- safe_strcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
+ 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)) {
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;