Bug 3851 - [PATCH]nmbd does not allow to explicitly use multiple interfaces for broadcasting
Summary: [PATCH]nmbd does not allow to explicitly use multiple interfaces for broadca...
Status: RESOLVED DUPLICATE of bug 7118
Alias: None
Product: Samba 3.0
Classification: Unclassified
Component: nmbd (show other bugs)
Version: 3.0.22
Hardware: x86 FreeBSD
: P3 normal
Target Milestone: none
Assignee: Samba Bugzilla Account
QA Contact: Samba QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-06-23 00:03 UTC by Artemiev Igor
Modified: 2010-02-08 17:30 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Artemiev Igor 2006-06-23 00:03:41 UTC
nmbd does not allow to explicitly use multiple interfaces for
a broadcasting, thus making impossible to use samba3 and samba4wins
simultaneously on a multihomed host.

diff -rub nmbd.orig/nmbd.c nmbd/nmbd.c
--- nmbd.orig/nmbd.c	Tue Jun 20 10:20:27 2006
+++ nmbd/nmbd.c	Tue Jun 20 16:03:12 2006
@@ -23,8 +23,6 @@
 
 #include "includes.h"
 
-int ClientNMB       = -1;
-int ClientDGRAM     = -1;
 int global_nmb_port = -1;
 
 extern BOOL rescan_listen_set;
@@ -258,6 +256,24 @@
 			close_subnet(subrec);
 		}
 	}
+	for (subrec=remote_broadcast_subnet; subrec; subrec=subrec->next) {
+		for (n=iface_count() - 1; n >= 0; n--) {
+			struct interface *iface = get_interface(n);
+			if (ip_equal(iface->bcast, subrec->myip) &&
+			    ip_equal(iface->nmask, subrec->mask_ip)) break;
+		}
+		if (n == -1) {
+			/* oops, an interface has disapeared. This is
+			 tricky, we don't dare actually free the
+			 interface as it could be being used, so
+			 instead we just wear the memory leak and
+			 remove it from the list of interfaces without
+			 freeing it */
+			DEBUG(2,("Deleting dead interface %s\n", 
+				 inet_ntoa(subrec->myip)));
+			close_bcast_subnet(subrec);
+		}
+	}
 	
 	rescan_listen_set = True;
 
@@ -612,44 +628,6 @@
 }
 
 /**************************************************************************** **
- Open the socket communication.
- **************************************************************************** */
-
-static BOOL open_sockets(BOOL isdaemon, int port)
-{
-	/*
-	 * The sockets opened here will be used to receive broadcast
-	 * packets *only*. Interface specific sockets are opened in
-	 * make_subnet() in namedbsubnet.c. Thus we bind to the
-	 * address "0.0.0.0". The parameter 'socket address' is
-	 * now deprecated.
-	 */
-
-	if ( isdaemon )
-		ClientNMB = open_socket_in(SOCK_DGRAM, port,
-					   0, interpret_addr(lp_socket_address()),
-					   True);
-	else
-		ClientNMB = 0;
-  
-	ClientDGRAM = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
-					   3, interpret_addr(lp_socket_address()),
-					   True);
-
-	if ( ClientNMB == -1 )
-		return( False );
-
-	/* we are never interested in SIGPIPE */
-	BlockSignals(True,SIGPIPE);
-
-	set_socket_options( ClientNMB,   "SO_BROADCAST" );
-	set_socket_options( ClientDGRAM, "SO_BROADCAST" );
-
-	DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
-	return( True );
-}
-
-/**************************************************************************** **
  main program
  **************************************************************************** */
  int main(int argc, const char *argv[])
@@ -788,10 +766,7 @@
 
 	DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
 
-	if ( !open_sockets( is_daemon, global_nmb_port ) ) {
-		kill_async_dns_child();
-		return 1;
-	}
+	BlockSignals(True,SIGPIPE);
 
 	/* Determine all the IP addresses we have. */
 	load_interfaces();
diff -rub nmbd.orig/nmbd_packets.c nmbd/nmbd_packets.c
--- nmbd.orig/nmbd_packets.c	Tue Jun 20 10:20:27 2006
+++ nmbd/nmbd_packets.c	Wed Jun 21 14:34:54 2006
@@ -23,8 +23,6 @@
 
 #include "includes.h"
 
-extern int ClientNMB;
-extern int ClientDGRAM;
 extern int global_nmb_port;
 
 extern int num_response_packets;
@@ -56,7 +54,13 @@
 		if(ip_equal(local_ip, subrec->myip))
 			return subrec->nmb_sock;
 
-	return ClientNMB;
+	for( subrec = remote_broadcast_subnet; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+		if(same_net(subrec->bcast_ip, local_ip, subrec->mask_ip))	
+			return subrec->nmb_sock;
+
+	DEBUG(0, ("find_subnet_fd_for_address: Cannot locate subnet for %s\n",
+		inet_ntoa(local_ip)));
+	return remote_broadcast_subnet->nmb_sock;
 }
 
 /***************************************************************************
@@ -71,7 +75,14 @@
 		if(ip_equal(local_ip, subrec->myip))
 			return subrec->dgram_sock;
 
-	return ClientDGRAM;
+	for( subrec = remote_broadcast_subnet; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+		if(same_net(local_ip, subrec->bcast_ip, subrec->mask_ip));	
+			return subrec->dgram_sock;
+
+	DEBUG(0, ("find_subnet_fd_for_address: Cannot locate subnet for %s\n",
+		inet_ntoa(local_ip)));
+
+	return remote_broadcast_subnet->dgram_sock;
 }
 
 /***************************************************************************
@@ -212,7 +223,7 @@
 
 	packet->ip = to_ip;
 	packet->port = NMB_PORT;
-	packet->fd = ClientNMB;
+	packet->fd = find_subnet_fd_for_address(to_ip);
 	packet->timestamp = time(NULL);
 	packet->packet_type = NMB_PACKET;
 	packet->locked = False;
@@ -1664,36 +1675,33 @@
 	/* 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 = remote_broadcast_subnet; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
+		count++;
 
-	if((count*2) + 2 > FD_SETSIZE) {
+	if((count*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));
+only use %d.\n", (count*2), FD_SETSIZE));
 		return True;
 	}
 
-	if((sock_array = SMB_MALLOC_ARRAY(int, (count*2) + 2)) == NULL) {
+	if((sock_array = SMB_MALLOC_ARRAY(int, (count*2))) == NULL) {
 		DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
 		return True;
 	}
 
 	FD_ZERO(pset);
 
-	/* Add in the broadcast socket on 137. */
-	FD_SET(ClientNMB,pset);
-	sock_array[num++] = ClientNMB;
-	*maxfd = MAX( *maxfd, ClientNMB);
-
 	/* 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);
+	for (subrec = remote_broadcast_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 138 sockets on all the interfaces. */
 	for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
@@ -1701,8 +1709,13 @@
 		sock_array[num++] = subrec->dgram_sock;
 		*maxfd = MAX( *maxfd, subrec->dgram_sock);
 	}
+	for (subrec = remote_broadcast_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);
+	}
 
-	*listen_number = (count*2) + 2;
+	*listen_number = (count*2);
 
 	SAFE_FREE(*ppset);
 	SAFE_FREE(*psock_array);
@@ -1787,16 +1800,7 @@
 			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) || 
+					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",
@@ -1814,16 +1818,7 @@
 				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) || 
+					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));	  
diff -rub nmbd.orig/nmbd_responserecordsdb.c nmbd/nmbd_responserecordsdb.c
--- nmbd.orig/nmbd_responserecordsdb.c	Tue Jun 20 10:20:27 2006
+++ nmbd/nmbd_responserecordsdb.c	Tue Jun 20 10:31:43 2006
@@ -23,8 +23,6 @@
 
 #include "includes.h"
 
-extern int ClientNMB;
-
 int num_response_packets = 0;
 
 /***************************************************************************
diff -rub nmbd.orig/nmbd_serverlistdb.c nmbd/nmbd_serverlistdb.c
--- nmbd.orig/nmbd_serverlistdb.c	Tue Jun 20 10:20:27 2006
+++ nmbd/nmbd_serverlistdb.c	Tue Jun 20 10:31:19 2006
@@ -23,8 +23,6 @@
 
 #include "includes.h"
 
-extern int ClientNMB;
-
 int updatecount = 0;
 
 /*******************************************************************
diff -rub nmbd.orig/nmbd_subnetdb.c nmbd/nmbd_subnetdb.c
--- nmbd.orig/nmbd_subnetdb.c	Tue Jun 20 10:20:27 2006
+++ nmbd/nmbd_subnetdb.c	Tue Jun 20 14:16:59 2006
@@ -26,8 +26,6 @@
 #include "includes.h"
 
 extern struct in_addr loopback_ip;
-extern int ClientNMB;
-extern int ClientDGRAM;
 extern int global_nmb_port;
 
 /* This is the broadcast subnets database. */
@@ -99,6 +97,20 @@
 	}
 }
 
+void close_bcast_subnet(struct subnet_record *subrec)
+{
+	DLIST_REMOVE(remote_broadcast_subnet, subrec);
+
+	if (subrec->dgram_sock != -1) {
+		close(subrec->dgram_sock);
+		subrec->dgram_sock = -1;
+	}
+	if (subrec->nmb_sock != -1) {
+		close(subrec->nmb_sock);
+		subrec->nmb_sock = -1;
+	}
+}
+
 /****************************************************************************
   Create a subnet entry.
   ****************************************************************************/
@@ -113,10 +125,35 @@
 	/* 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 == REMOTE_BROADCAST_SUBNET) {
+	    /* Creating broadcast subnet */
+	    if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,
+		    0, bcast_ip.s_addr,True)) == -1) {
+		if( DEBUGLVL( 0 ) ) {
+		    Debug1( "nmbd_subnetdb:make_subnet()\n" );
+		    Debug1( "  Failed to open nmb socket on interface %s ", 
+		    	inet_ntoa(bcast_ip) );
+		    Debug1( "for port %d.  ", global_nmb_port );
+		    Debug1( "Error was %s\n", strerror(errno) );
+		}
+		return NULL;
+	    }
+
+	    if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, 
+		bcast_ip.s_addr,True)) == -1) {
+		if( DEBUGLVL( 0 ) ) {
+		    Debug1( "nmbd_subnetdb:make_subnet()\n" );
+		    Debug1( "  Failed to open dgram socket on interface %s ", 
+		    	inet_ntoa(bcast_ip) );
+		    Debug1( "for port %d.  ", DGRAM_PORT );
+		    Debug1( "Error was %s\n", strerror(errno) );
+		}
+		return NULL;
+	    }
+	    set_socket_options(nmb_sock,"SO_BROADCAST");
+	    set_socket_options(dgram_sock,"SO_BROADCAST");
+
+	} else if(type == NORMAL_SUBNET) { 
 		/*
 		 * Attempt to open the sockets on port 137/138 for this interface
 		 * and bind them.
@@ -146,6 +183,9 @@
 		/* Make sure we can broadcast from these sockets. */
 		set_socket_options(nmb_sock,"SO_BROADCAST");
 		set_socket_options(dgram_sock,"SO_BROADCAST");
+	} else {
+	    nmb_sock = -1;
+	    dgram_sock = 1;
 	}
 
 	subrec = SMB_MALLOC_P(struct subnet_record);
@@ -203,6 +243,18 @@
 	return subrec;
 }
 
+struct subnet_record *make_broadcast_subnet(struct interface *iface)
+{
+	struct subnet_record *subrec;
+
+	subrec = make_subnet(inet_ntoa(iface->bcast), REMOTE_BROADCAST_SUBNET,
+			     iface->bcast, iface->bcast, iface->nmask);
+	if (subrec) {
+		DLIST_ADD(remote_broadcast_subnet, subrec);
+	}
+	return subrec;
+}
+
 /****************************************************************************
   Create subnet entries.
 **************************************************************************/
@@ -245,6 +297,9 @@
 
 		if (!make_normal_subnet(iface))
 			return False;
+
+		if (!make_broadcast_subnet(iface))
+			return False;
 	}
 
 	if (lp_we_are_a_wins_server()) {
@@ -267,13 +322,8 @@
 	unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
 				unicast_ip, unicast_ip, unicast_ip);
 
-	zero_ip(&ipzero);
-
-	remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
-				REMOTE_BROADCAST_SUBNET,
-				ipzero, ipzero, ipzero);
 
-	if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
+	if((unicast_subnet == NULL))
 		return False;
 
 	/* 
diff -rub nmbd.orig/nmbd_workgroupdb.c nmbd/nmbd_workgroupdb.c
--- nmbd.orig/nmbd_workgroupdb.c	Tue Jun 20 10:20:27 2006
+++ nmbd/nmbd_workgroupdb.c	Tue Jun 20 10:31:00 2006
@@ -23,7 +23,6 @@
 
 #include "includes.h"
 
-extern int ClientNMB;
 
 extern uint16 samba_nb_type;
Comment 1 Timur Bakeyev 2007-06-03 15:53:24 UTC
Hi, Igor!

(In reply to comment #0)
> nmbd does not allow to explicitly use multiple interfaces for
> a broadcasting, thus making impossible to use samba3 and samba4wins
> simultaneously on a multihomed host.

Can you attach proposed patch to the bug and update it to the latest Samba version?

With regards,
Timur
Comment 2 Jeremy Allison 2010-02-08 17:30:14 UTC

*** This bug has been marked as a duplicate of bug 7118 ***