This patch is built on top of the NETALIAS functionality, in addition
to which it allows programs to bind a listening socket to a NETALIASed
interface. To enable it you need to add ``options NETALIAS'' and
``options NETBIND'' to the kernel configuration file and recompile the
kernel. You also need to recompile any userland utilities that depend
on struct inpcb, in particular systat, netstat, and fstat (and also
ipfilter). This can be done by rebuilding the world, or by installing
the new /usr/include/netinet/in_pcb.h and then e.g.
	cd /usr/src/usr.bin/systat
	make all install clean
You must do this if you have applied this patch even if you only use
the NETALIAS functionality because struct inpcb is changed
unconditionally.

See also the NETALIAS patch, and the file fanf/webdev/six-squid-cure
in the CVS repository.

--- /usr/src/sys/conf/options.orig	Mon Sep 27 20:52:05 1999
+++ /usr/src/sys/conf/options	Mon Sep 27 20:52:16 1999
@@ -379,3 +379,4 @@
 
 # Demon virtual hosting hacks
 NETALIAS
+NETBIND
--- /usr/src/sys/netinet/in_pcb.c.orig	Mon Sep 27 18:59:09 1999
+++ /usr/src/sys/netinet/in_pcb.c	Mon Sep 27 20:48:15 1999
@@ -34,6 +34,8 @@
  * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.46.2.3 1999/08/29 16:29:35 peter Exp $
  */
 
+#include "opt_netbind.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
@@ -135,6 +137,9 @@
 	bzero((caddr_t)inp, sizeof(*inp));
 	inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
 	inp->inp_pcbinfo = pcbinfo;
+#ifdef NETBIND
+	inp->inp_lmask.s_addr = INADDR_BROADCAST;
+#endif
 	inp->inp_socket = so;
 	LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
 	pcbinfo->ipi_count++;
@@ -152,6 +157,7 @@
 	unsigned short *lastport;
 	struct sockaddr_in *sin;
 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+	struct in_ifaddr *ia;
 	u_short lport = 0;
 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
 	int error;
@@ -187,8 +193,19 @@
 				reuseport = SO_REUSEADDR|SO_REUSEPORT;
 		} else if (sin->sin_addr.s_addr != INADDR_ANY) {
 			sin->sin_port = 0;		/* yech... */
-			if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
+			ia = (struct in_ifaddr *)
+				ifa_ifwithaddr((struct sockaddr *)sin);
+			if (ia == 0)
 				return (EADDRNOTAVAIL);
+#ifdef NETBIND
+			/* if this socket is a network address then copy the netmask into the PCB */
+			if (ntohl(IA_SIN(ia)->sin_addr.s_addr) == ia->ia_subnet)
+				inp->inp_lmask = ia->ia_sockmask.sin_addr;
+#ifdef notdef
+			log(LOG_DEBUG, "netbind check: in_pcbbind addr %08x mask %08x\n",
+			    sin->sin_addr.s_addr, inp->inp_lmask.s_addr);
+#endif
+#endif
 		}
 		if (lport) {
 			struct inpcb *t;
@@ -802,8 +819,21 @@
 		for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
 			    inp->inp_lport == lport) {
+#ifdef NETBIND
+#ifdef notdef
+				if (inp->inp_lmask.s_addr != INADDR_BROADCAST)
+					log(LOG_DEBUG,
+					    "netbind check: in_pcblookup_hash addr %08x mask %08x options %x\n",
+					    inp->inp_laddr.s_addr, inp->inp_lmask.s_addr, inp->inp_socket->so_options);
+#endif
+				/* allow matches to any address within netmask */
+				if ((inp->inp_laddr.s_addr & inp->inp_lmask.s_addr)
+				    == (laddr.s_addr & inp->inp_lmask.s_addr))
+					return (inp);
+#else
 				if (inp->inp_laddr.s_addr == laddr.s_addr)
 					return (inp);
+#endif /* NETBIND */
 				else if (inp->inp_laddr.s_addr == INADDR_ANY)
 					local_wild = inp;
 			}
--- /usr/src/sys/netinet/in_pcb.h.orig	Mon Sep 27 18:59:07 1999
+++ /usr/src/sys/netinet/in_pcb.h	Mon Sep 27 20:48:15 1999
@@ -77,6 +77,7 @@
 	LIST_ENTRY(inpcb) inp_portlist;	/* list for this PCB's local port */
 	struct	inpcbport *inp_phd;	/* head of this list */
 	inp_gen_t inp_gencnt;		/* generation count of this instance */
+	struct  in_addr inp_lmask;	/* local netmask (NETBIND) */
 };
 /*
  * The range of the generation count, as used in this implementation,
