samba3 nmbd and samba4wins simultaneously on multihomed host

Artemiev Igor ai at bmc.brk.ru
Wed Jun 21 11:06:13 GMT 2006


Currently, 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. I've written small patch, that
allows to get around of this limitation, but I'm not sure it works as
it should. Can someone say something on this point? 
In previous implementation there was only one broadcasting socket, now 
there is one for an each interface. Which is a right way of returning a descriptor
in case of a multihomed host in find_subnet_fd_for_address and
find_subnet_mailslot_fd_for_address functions, and, anyway, was it a
correct approach? 
If not, how else is it possible to make samba3 and samba4wins work at a 
multihomed host?.. May be, with SO_REUSEADDR&SO_REUSEPORT? 

-- 
iprefetch ai

P.S. With this patch I've been testing samba 3.0.22 and samba4wins
without a replication for a few days. It looks good for me, i hope :)

-------------- next part --------------
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;
 


More information about the samba-technical mailing list