summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/nameserv.h5
-rw-r--r--source3/libsmb/namequery.c6
-rw-r--r--source3/libsmb/nmblib.c9
-rw-r--r--source3/nmbd/nmbd.c5
-rw-r--r--source3/nmbd/nmbd_packets.c189
-rw-r--r--source3/nmbd/nmbd_subnetdb.c123
6 files changed, 222 insertions, 115 deletions
diff --git a/source3/include/nameserv.h b/source3/include/nameserv.h
index 496d87e2db..53ffd6faec 100644
--- a/source3/include/nameserv.h
+++ b/source3/include/nameserv.h
@@ -434,7 +434,9 @@ struct subnet_record {
struct in_addr mask_ip;
struct in_addr myip;
int nmb_sock; /* socket to listen for unicast 137. */
+ int nmb_bcast; /* socket to listen for broadcast 137. */
int dgram_sock; /* socket to listen for unicast 138. */
+ int dgram_bcast; /* socket to listen for broadcast 138. */
};
/* A resource record. */
@@ -530,7 +532,8 @@ struct packet_struct
bool locked;
struct in_addr ip;
int port;
- int fd;
+ int recv_fd;
+ int send_fd;
time_t timestamp;
enum packet_type packet_type;
union {
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index a6fc612a0f..be038ecdad 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -289,7 +289,8 @@ NODE_STATUS_STRUCT *node_status_query(int fd,
p.ip = ((const struct sockaddr_in *)to_ss)->sin_addr;
p.port = NMB_PORT;
- p.fd = fd;
+ p.recv_fd = -1;
+ p.send_fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
@@ -698,7 +699,8 @@ struct sockaddr_storage *name_query(int fd,
p.ip = ((struct sockaddr_in *)to_ss)->sin_addr;
p.port = NMB_PORT;
- p.fd = fd;
+ p.recv_fd = -1;
+ p.send_fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index 5f3eda44fe..1a2106675b 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -601,6 +601,8 @@ static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
/* Ensure this copy is not locked. */
pkt_copy->locked = False;
+ pkt_copy->recv_fd = -1;
+ pkt_copy->send_fd = -1;
/* Ensure this copy has no resource records. */
nmb = &packet->packet.nmb;
@@ -666,6 +668,8 @@ static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
/* Ensure this copy is not locked. */
pkt_copy->locked = False;
+ pkt_copy->recv_fd = -1;
+ pkt_copy->send_fd = -1;
/* There are no additional pointers in a dgram packet,
we are finished. */
@@ -791,7 +795,8 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
if (!packet)
return NULL;
- packet->fd = fd;
+ packet->recv_fd = fd;
+ packet->send_fd = -1;
DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
length, inet_ntoa(packet->ip), packet->port ) );
@@ -1075,7 +1080,7 @@ bool send_packet(struct packet_struct *p)
if (!len)
return(False);
- return(send_udp(p->fd,buf,len,p->ip,p->port));
+ return(send_udp(p->send_fd,buf,len,p->ip,p->port));
}
/****************************************************************************
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index 961e930728..3b51a78dfe 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -443,13 +443,14 @@ static void msg_nmbd_send_packet(struct messaging_context *msg,
local_ip = &((const struct sockaddr_in *)pss)->sin_addr;
subrec = FIRST_SUBNET;
- p->fd = (p->packet_type == NMB_PACKET) ?
+ p->recv_fd = -1;
+ p->send_fd = (p->packet_type == NMB_PACKET) ?
subrec->nmb_sock : subrec->dgram_sock;
for (subrec = FIRST_SUBNET; subrec != NULL;
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
if (ip_equal_v4(*local_ip, subrec->myip)) {
- p->fd = (p->packet_type == NMB_PACKET) ?
+ p->send_fd = (p->packet_type == NMB_PACKET) ?
subrec->nmb_sock : subrec->dgram_sock;
break;
}
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index 6136c6d171..013ebf6589 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -207,7 +207,8 @@ static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmb
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;
@@ -258,7 +259,8 @@ static bool create_and_init_additional_record(struct packet_struct *packet,
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;
}
@@ -743,7 +745,7 @@ struct response_record *queue_query_name( struct subnet_record *subrec,
}
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;
}
}
@@ -979,9 +981,14 @@ for id %hu\n", packet_type, nmb_namestr(&orig_nmb->question.question_name),
}
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);
@@ -1679,50 +1686,74 @@ static bool create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_n
return True;
}
+ /* The Client* sockets */
+ count++;
+
/* Check that we can add all the fd's we need. */
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
count++;
- if((count*2) + 2 > FD_SETSIZE) {
+ /* each interface gets 4 sockets */
+ count *= 4;
+
+ if(count > FD_SETSIZE) {
DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
-only use %d.\n", (count*2) + 2, FD_SETSIZE));
+only use %d.\n", count, FD_SETSIZE));
SAFE_FREE(pset);
return True;
}
- if((sock_array = SMB_MALLOC_ARRAY(int, (count*2) + 2)) == NULL) {
- DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
+ if((sock_array = SMB_MALLOC_ARRAY(int, count)) == NULL) {
+ DEBUG(0,("create_listen_fdset: malloc fail for socket array. size %d\n", count));
SAFE_FREE(pset);
return True;
}
FD_ZERO(pset);
- /* Add in the broadcast socket on 137. */
+ /* Add in the lp_socket_address() interface on 137. */
FD_SET(ClientNMB,pset);
sock_array[num++] = ClientNMB;
*maxfd = MAX( *maxfd, ClientNMB);
+ /* the lp_socket_address() interface has only one socket */
+ sock_array[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);
+
+ sock_array[num++] = subrec->nmb_bcast;
+ if (subrec->nmb_bcast != -1) {
+ FD_SET(subrec->nmb_bcast,pset);
+ *maxfd = MAX( *maxfd, subrec->nmb_bcast);
+ }
}
- /* Add in the broadcast socket on 138. */
+ /* Add in the lp_socket_address() interface on 138. */
FD_SET(ClientDGRAM,pset);
sock_array[num++] = ClientDGRAM;
*maxfd = MAX( *maxfd, ClientDGRAM);
+ /* the lp_socket_address() interface has only one socket */
+ sock_array[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);
+
+ sock_array[num++] = subrec->dgram_bcast;
+ if (subrec->dgram_bcast != -1) {
+ FD_SET(subrec->dgram_bcast,pset);
+ *maxfd = MAX( *maxfd, subrec->dgram_bcast);
+ }
}
- *listen_number = (count*2) + 2;
+ *listen_number = count;
SAFE_FREE(*ppset);
SAFE_FREE(*psock_array);
@@ -1811,61 +1842,90 @@ bool listen_for_packets(bool run_election)
#endif
for(i = 0; i < listen_number; i++) {
+ enum packet_type packet_type;
+ struct packet_struct *packet;
+ const char *packet_name;
+ int client_fd;
+ int client_port;
+
+ if (sock_array[i] == -1) {
+ continue;
+ }
+
+ if (!FD_ISSET(sock_array[i],&r_fds)) {
+ continue;
+ }
+
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);
- }
- }
- }
+ /* 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 137 */
+ packet_type = DGRAM_PACKET;
+ packet_name = "dgram";
+ client_fd = ClientDGRAM;
+ client_port = DGRAM_PORT;
+ }
+
+ packet = read_packet(sock_array[i], 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() &&
+ (sock_array[i] == 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_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;
}
- } /* end processing 138 socket. */
- } /* end for */
+
+ 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;
+ }
+ }
+
+ /*
+ * 0,2,4,... are unicast sockets
+ * 1,3,5,... are broadcast sockets
+ *
+ * on broadcast socket we only receive packets
+ * and send replies via the unicast socket.
+ *
+ * 0,1 and 2,3 and ... belong together.
+ */
+ if ((i % 2) != 0) {
+ /* this is a broadcast socket */
+ packet->send_fd = sock_array[i-1];
+ } else {
+ /* this is already a unicast socket */
+ packet->send_fd = sock_array[i];
+ }
+
+ queue_packet(packet);
+ }
+
return False;
}
@@ -1946,7 +2006,8 @@ bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t 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;
diff --git a/source3/nmbd/nmbd_subnetdb.c b/source3/nmbd/nmbd_subnetdb.c
index 13bc931863..96d7b3211e 100644
--- a/source3/nmbd/nmbd_subnetdb.c
+++ b/source3/nmbd/nmbd_subnetdb.c
@@ -76,18 +76,21 @@ static struct subnet_record *make_subnet(const char *name, enum subnet_type type
struct in_addr mask_ip)
{
struct subnet_record *subrec = NULL;
- int nmb_sock, dgram_sock;
+ int nmb_sock = -1;
+ int dgram_sock = -1;
+ int nmb_bcast = -1;
+ int dgram_bcast = -1;
+ bool bind_bcast = lp_parm_bool(-1, "nmbd", "bind explicit broadcast", false);
/* Check if we are creating a non broadcast subnet - if so don't create
sockets. */
- if(type != NORMAL_SUBNET) {
- nmb_sock = -1;
- dgram_sock = -1;
- } else {
+ if (type == NORMAL_SUBNET) {
struct sockaddr_storage ss;
+ struct sockaddr_storage ss_bcast;
in_addr_to_sockaddr_storage(&ss, myip);
+ in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip);
/*
* Attempt to open the sockets on port 137/138 for this interface
@@ -95,60 +98,74 @@ static struct subnet_record *make_subnet(const char *name, enum subnet_type type
* Fail the subnet creation if this fails.
*/
- if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, &ss,true)) == -1) {
- if( DEBUGLVL( 0 ) ) {
- Debug1( "nmbd_subnetdb:make_subnet()\n" );
- Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
- Debug1( "for port %d. ", global_nmb_port );
- Debug1( "Error was %s\n", strerror(errno) );
+ nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,
+ 0, &ss, true);
+ if (nmb_sock == -1) {
+ DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
+ DEBUGADD(0,(" Failed to open nmb socket on interface %s ",
+ inet_ntoa(myip)));
+ DEBUGADD(0,("for port %d. ", global_nmb_port));
+ DEBUGADD(0,("Error was %s\n", strerror(errno)));
+ goto failed;
+ }
+ set_socket_options(nmb_sock,"SO_BROADCAST");
+ set_blocking(nmb_sock, false);
+
+ if (bind_bcast) {
+ nmb_bcast = open_socket_in(SOCK_DGRAM, global_nmb_port,
+ 0, &ss_bcast, true);
+ if (nmb_bcast == -1) {
+ DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
+ DEBUGADD(0,(" Failed to open nmb bcast socket on interface %s ",
+ inet_ntoa(bcast_ip)));
+ DEBUGADD(0,("for port %d. ", global_nmb_port));
+ DEBUGADD(0,("Error was %s\n", strerror(errno)));
+ goto failed;
}
- return NULL;
+ set_socket_options(nmb_bcast, "SO_BROADCAST");
+ set_blocking(nmb_bcast, false);
}
- if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, &ss, true)) == -1) {
- if( DEBUGLVL( 0 ) ) {
- Debug1( "nmbd_subnetdb:make_subnet()\n" );
- Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
- Debug1( "for port %d. ", DGRAM_PORT );
- Debug1( "Error was %s\n", strerror(errno) );
+ dgram_sock = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
+ 3, &ss, true);
+ if (dgram_sock == -1) {
+ DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
+ DEBUGADD(0,(" Failed to open dgram socket on interface %s ",
+ inet_ntoa(myip)));
+ DEBUGADD(0,("for port %d. ", DGRAM_PORT));
+ DEBUGADD(0,("Error was %s\n", strerror(errno)));
+ goto failed;
+ }
+ set_socket_options(dgram_sock, "SO_BROADCAST");
+ set_blocking(dgram_sock, false);
+
+ if (bind_bcast) {
+ dgram_bcast = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
+ 3, &ss_bcast, true);
+ if (dgram_bcast == -1) {
+ DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
+ DEBUGADD(0,(" Failed to open dgram bcast socket on interface %s ",
+ inet_ntoa(bcast_ip)));
+ DEBUGADD(0,("for port %d. ", DGRAM_PORT));
+ DEBUGADD(0,("Error was %s\n", strerror(errno)));
+ goto failed;
}
- return NULL;
+ set_socket_options(dgram_bcast, "SO_BROADCAST");
+ set_blocking(dgram_bcast, false);
}
-
- /* Make sure we can broadcast from these sockets. */
- set_socket_options(nmb_sock,"SO_BROADCAST");
- set_socket_options(dgram_sock,"SO_BROADCAST");
-
- /* Set them non-blocking. */
- set_blocking(nmb_sock, False);
- set_blocking(dgram_sock, False);
}
subrec = SMB_MALLOC_P(struct subnet_record);
if (!subrec) {
DEBUG(0,("make_subnet: malloc fail !\n"));
- if (nmb_sock != -1) {
- close(nmb_sock);
- }
- if (dgram_sock != -1) {
- close(dgram_sock);
- }
- return(NULL);
+ goto failed;
}
ZERO_STRUCTP(subrec);
if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
- if (nmb_sock != -1) {
- close(nmb_sock);
- }
- if (dgram_sock != -1) {
- close(dgram_sock);
- }
- ZERO_STRUCTP(subrec);
- SAFE_FREE(subrec);
- return(NULL);
+ goto failed;
}
DEBUG(2, ("making subnet name:%s ", name ));
@@ -163,9 +180,27 @@ static struct subnet_record *make_subnet(const char *name, enum subnet_type type
subrec->myip = myip;
subrec->type = type;
subrec->nmb_sock = nmb_sock;
+ subrec->nmb_bcast = nmb_bcast;
subrec->dgram_sock = dgram_sock;
-
+ subrec->dgram_bcast = dgram_bcast;
+
return subrec;
+
+failed:
+ SAFE_FREE(subrec);
+ if (nmb_sock != -1) {
+ close(nmb_sock);
+ }
+ if (nmb_bcast != -1) {
+ close(nmb_bcast);
+ }
+ if (dgram_sock != -1) {
+ close(dgram_sock);
+ }
+ if (dgram_bcast != -1) {
+ close(dgram_bcast);
+ }
+ return NULL;
}
/****************************************************************************