[1835] in linux-net channel archive

home help back first fref pref prev next nref lref last post

Re: Miulti-homed hosts

daemon@ATHENA.MIT.EDU (Matthias Urlichs)
Sun Feb 4 17:07:45 1996

From: Matthias Urlichs <smurf@smurf.noris.de>
To: alan@lxorguk.ukuu.org.uk (Alan Cox)
Date: 	Sun, 4 Feb 1996 20:59:54 +0100 (MET)
Cc: smurf@smurf.noris.de, linux-net@vger.rutgers.edu
In-Reply-To: <m0tisMg-0005FYC@lightning.swansea.linux.org.uk> from "Alan Cox" at Feb 4, 96 00:31:34 am

Hi,

Alan Cox wrote:
>
>> Problem: The kernel doesn't like two bind() calls in a row. Why not??? BSD
>> handles that fine, as far as I know, as long as there's no connection on
>> the socket. Removing the appropriate check from the kernel doesn't brerak
>> anything...
>
>BSD has a massive security hole.
> [ description deleted ]

That's not what I was talking about.

The hole is there because it allows two programs to access the same port.
That is obviously a Bad Thing.

My problem is that currently, Linux doesn't allow the sequence socket()
bind() bind(), executed by the _same_ process on the _same_ socket, which
is not a security hole in any way as far as I can determine. 

With the following kernel patches, my system runs (apparently) flawlessly
as a true multihomed machine. It even seems possible to run two entirely
separate portmappers and NFS daemons, though I have not verified that.

I do NOT want to hack every program which needs to pretend that its local
port is in fact the "other" IP address. The same can be done with a small
change to libc and with a small kernel patch.

The things I did to libc, below the kernel patch (appended below), may or
may not be a good idea. Feedback wanted. Be aware that you have to patch
and install libc FIRST, or else the kernel patch will break the portmapper
and NFS (because neither of which will get their preferred port, because
they bind to their port first and indirectly call bindresvport()
afterwards, which doesn't check for an existing assignment).


Aside: The BSD hole can be fixed easily. The nameserver already binds to
port 53 on every interface address. rpc.nfsd should do the same thing;
what's more, that way it'll be able to reply with the correct address, and
multihomed NFS hosts would actually work as you'd expect.

With my patches, you could run two concurrent NFS servers for each
interface, which should work even better.


diff -rub /pub/src/linux/kernel/linux-1.3/net/ipv4/af_inet.c ./net/ipv4/af_inet.c
--- /pub/src/linux/kernel/linux-1.3/net/ipv4/af_inet.c	Tue Dec 26 05:03:01 1995
+++ ./net/ipv4/af_inet.c	Sun Feb  4 19:24:30 1996
@@ -842,8 +842,5 @@
 		
 	if(sock->type != SOCK_RAW)
 	{
-		if (sk->num != 0) 
-			return(-EINVAL);
-
 		snum = ntohs(addr->sin_port);
 		


diff -rub /pub/src/linux/library/libc-5.3.4/libc/rpc/svc_tcp.c ./rpc/svc_tcp.c
--- /pub/src/linux/library/libc-5.3.4/libc/rpc/svc_tcp.c	Thu May 25 07:23:02 1995
+++ ./rpc/svc_tcp.c	Sun Feb  4 12:07:10 1996
@@ -158,10 +158,7 @@
 	}
 	bzero((char *)&addr, sizeof (addr));
 	addr.sin_family = AF_INET;
-	if (bindresvport(sock, &addr)) {
-		addr.sin_port = 0;
-		(void)bind(sock, (struct sockaddr *)&addr, len);
-	}
+	(void)bindresvport(sock, &addr);
 	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
 	    (listen(sock, 2) != 0)) {
 #if NLS
diff -rub /pub/src/linux/library/libc-5.3.4/libc/rpc/svc_udp.c ./rpc/svc_udp.c
--- /pub/src/linux/library/libc-5.3.4/libc/rpc/svc_udp.c	Thu May 25 07:23:02 1995
+++ ./rpc/svc_udp.c	Sun Feb  4 12:07:10 1996
@@ -131,10 +131,7 @@
 	}
 	bzero((char *)&addr, sizeof (addr));
 	addr.sin_family = AF_INET;
-	if (bindresvport(sock, &addr)) {
-		addr.sin_port = 0;
-		(void)bind(sock, (struct sockaddr *)&addr, len);
-	}
+	(void)bindresvport(sock, &addr);
 	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
 #if NLS
 		perror(catgets(_libc_cat, RpcMiscSet,
diff -rub /pub/src/linux/library/libc-5.3.4/libc/sysdeps/linux/bind.c ./sysdeps/linux/bind.c
--- /pub/src/linux/library/libc-5.3.4/libc/sysdeps/linux/bind.c	Thu Aug 24 04:03:34 1995
+++ ./sysdeps/linux/bind.c	Sun Feb  4 12:08:00 1996
@@ -1,6 +1,10 @@
 #include <syscall.h>
+#include <stdlib.h>
 #include <sys/socket.h>
 #include <sys/socketcall.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
 
 #ifdef __SVR4_I386_ABI_L1__
 #define socketcall __socketcall
@@ -13,10 +17,31 @@
 bind(int sockfd, const struct sockaddr *myaddr, int addrlen)
 {
 	unsigned long args[3];
+	struct sockaddr_in sin;
 
 	args[0] = sockfd;
 	args[1] = (unsigned long)myaddr;
 	args[2] = addrlen;
+
+#if 1
+	if((myaddr->sa_family == AF_INET)
+			&& (((struct sockaddr_in *)myaddr)->sin_addr.s_addr == INADDR_ANY)) {
+		char *rem = getenv("BIND_INADDR");
+		if(rem != NULL) {
+
+			sin.sin_family = AF_INET;
+			sin.sin_port = ((struct sockaddr_in *)myaddr)->sin_port;
+			if((sin.sin_addr.s_addr = inet_addr(rem)) == 0xFFFFFFFF) {
+				struct hostent *he = gethostbyname(rem);
+				if(he != NULL) {
+					memcpy(&sin.sin_addr.s_addr, he->h_addr, he->h_length);
+					args[1] = (unsigned long)&sin;
+				}
+			} else
+				args[1] = (unsigned long)&sin;
+		}
+	}
+#endif
 	return socketcall(SYS_BIND, args);
 }
 
diff -rub /pub/src/linux/library/libc-5.3.4/libc/sysdeps/linux/socket.c ./sysdeps/linux/socket.c
--- /pub/src/linux/library/libc-5.3.4/libc/sysdeps/linux/socket.c	Thu Aug 24 04:03:40 1995
+++ ./sysdeps/linux/socket.c	Sun Feb  4 12:08:08 1996
@@ -1,6 +1,9 @@
 #include <sys/socket.h>
 #include <syscall.h>
 #include <sys/socketcall.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
 
 #ifdef __SVR4_I386_ABI_L1__
 #define socketcall __socketcall
@@ -13,11 +16,21 @@
 socket(int family, int type, int protocol)
 {
 	unsigned long args[3];
+	int ret;
 
 	args[0] = family;
 	args[1] = type;
 	args[2] = protocol;
-	return socketcall(SYS_SOCKET, args);
+	ret = socketcall(SYS_SOCKET, args);
+#if 1
+	if(ret >= 0 && family == PF_INET && getenv("BIND_INADDR") != NULL) {
+		struct sockaddr_in si;
+		memset(&si,0,sizeof(si));
+		si.sin_family = AF_INET;
+		bind(ret,&si,sizeof(si));
+	}
+#endif
+	return ret;
 }
 
 #ifdef __ELF__
diff -rub /pub/src/linux/library/libc-5.3.4/libc/inet/bindresvport.c ./inet/bindresvport.c
--- /pub/src/linux/library/libc-5.3.4/libc/inet/bindresvport.c	Thu May 25 07:22:45 1995
+++ ./inet/bindresvport.c	Sun Feb  4 15:13:36 1996
@@ -55,6 +55,18 @@
 #define ENDPORT (IPPORT_RESERVED - 1)
 #define NPORTS	(ENDPORT - STARTPORT + 1)
 
+	i = sizeof(myaddr);
+	if (getsockname(sd, (struct sockaddr *)&myaddr, &i) != 0) 
+		return -1;
+	if(myaddr.sin_family != AF_INET) {
+		errno = EPFNOSUPPORT;
+		return -1;
+	}
+	if(ntohs(myaddr.sin_port) != 0) {
+		errno = EADDRINUSE;
+		return -1;
+	}
+
 	if (sin == (struct sockaddr_in *)0) {
 		sin = &myaddr;
 		bzero(sin, sizeof (*sin));

-- 
Re graphics:  A picture is worth 10K words -- but only those to
describe the picture.  Hardly any sets of 10K words can be adequately
described with pictures.
-- 
Matthias Urlichs        \ XLink-POP Nürnberg  | EMail: urlichs@smurf.noris.de
Schleiermacherstraße 12  \  Unix+Linux+Mac    | Phone: ...please use email.
90491 Nürnberg (Germany)  \   Consulting+Networking+Programming+etc'ing     42
          PGP: 1B 89 E2 1C 43 EA 80 44  15 D2 29 CF C6 C7 E0 DE 
       Click <A HREF="http://smurf.noris.de/~smurf/finger">here</A>.


home help back first fref pref prev next nref lref last post