Re: [PATCH] getsockopt() on netfilter-redirected socket

Patrick Schaaf (phbof@bof.de)
Mon, 4 Oct 1999 01:00:53 +0200 (MEST)


--ELM938991653-369-0_
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

> > I'll cook up a patch for that way to run things. If it proves acceptable,
> > we might want to extract the "register another sockopt" stuff out of
> > netfilter into a more generic location.
>
> Sounds like a good idea. SO_ORIGINAL_DST should be an integral part
> of networking with some hooks for netfilter/nat, and on the long term
> the kernel could have the generic register sockopt hooks.

OK, patch relative to 2.3.18 appended. That one
- adds SO_ORIGINAL_DST to asm-*/socket.h
(after doing that - what about a generic place to avoid that kind
of duplication?)
- moves the "write IP/port from struct sock to sockaddr_in" code from
af_inet.c:inet_getname() to a new ip_getsockname() in ip_sockglue.c
- makes SO_ORIGINAL_DST return the normal sockname in the general case
- moves the setsockopt/getsockopt netfilter checks up, so they run before
ip_setsockopt/ip_getsockopt do the general case; if the nf_ functions
return -ENOPROTOOPT, the general case is run.
- makes net/core/netfilter.c:nf_sockopt() check CAP_NET_ADMIN for 'set' only,
and changes all error returns there to -ENOPROTOOPT to conform to the
previous bullet.

The second attachment (patch against netfilter-0.1.9) is cosmetic:
if SO_ORIGINAL_DST is defined include/NAT/ip_nat.h does not redefine it.

The third attachment is a slightly modified version of the nf_getsockname()
implementation (user level) I already posted. My patched 'ssh -X' runs that
fine right now, with the kernel using the patch from above.

best regards
Patrick

--ELM938991653-369-0_
Content-Type: text/plain; charset=ISO-8859-1
Content-Disposition: attachment; filename=linux-2.3.18-bof-2.patch
Content-Description: kernel patch against plain 2.3.18
Content-Transfer-Encoding: 7bit

diff -urN linux-2.3.18/include/asm-alpha/socket.h linux-2.3.18-bof-2/include/asm-alpha/socket.h
--- linux-2.3.18/include/asm-alpha/socket.h Mon Dec 22 02:41:24 1997
+++ linux-2.3.18-bof-2/include/asm-alpha/socket.h Sun Oct 3 23:08:33 1999
@@ -43,6 +43,9 @@
#define SO_ATTACH_FILTER 26
#define SO_DETACH_FILTER 27

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 19
#define SO_SECURITY_ENCRYPTION_TRANSPORT 20
diff -urN linux-2.3.18/include/asm-arm/socket.h linux-2.3.18-bof-2/include/asm-arm/socket.h
--- linux-2.3.18/include/asm-arm/socket.h Thu Dec 17 18:05:43 1998
+++ linux-2.3.18-bof-2/include/asm-arm/socket.h Sun Oct 3 23:08:44 1999
@@ -39,4 +39,7 @@
#define SO_ATTACH_FILTER 26
#define SO_DETACH_FILTER 27

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
#endif /* _ASM_SOCKET_H */
diff -urN linux-2.3.18/include/asm-i386/socket.h linux-2.3.18-bof-2/include/asm-i386/socket.h
--- linux-2.3.18/include/asm-i386/socket.h Mon Dec 22 02:41:24 1997
+++ linux-2.3.18-bof-2/include/asm-i386/socket.h Sun Oct 3 23:08:51 1999
@@ -39,4 +39,7 @@
#define SO_ATTACH_FILTER 26
#define SO_DETACH_FILTER 27

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
#endif /* _ASM_SOCKET_H */
diff -urN linux-2.3.18/include/asm-m68k/socket.h linux-2.3.18-bof-2/include/asm-m68k/socket.h
--- linux-2.3.18/include/asm-m68k/socket.h Fri Feb 13 01:30:13 1998
+++ linux-2.3.18-bof-2/include/asm-m68k/socket.h Sun Oct 3 23:08:56 1999
@@ -39,4 +39,7 @@
#define SO_ATTACH_FILTER 26
#define SO_DETACH_FILTER 27

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
#endif /* _ASM_SOCKET_H */
diff -urN linux-2.3.18/include/asm-mips/socket.h linux-2.3.18-bof-2/include/asm-mips/socket.h
--- linux-2.3.18/include/asm-mips/socket.h Tue Oct 20 22:52:54 1998
+++ linux-2.3.18-bof-2/include/asm-mips/socket.h Sun Oct 3 23:09:00 1999
@@ -56,6 +56,9 @@
#define SO_ATTACH_FILTER 26
#define SO_DETACH_FILTER 27

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
/* Types of sockets. */
#define SOCK_DGRAM 1 /* Connectionless, unreliable datagrams
of fixed maximum length. */
diff -urN linux-2.3.18/include/asm-ppc/socket.h linux-2.3.18-bof-2/include/asm-ppc/socket.h
--- linux-2.3.18/include/asm-ppc/socket.h Wed Apr 15 02:34:00 1998
+++ linux-2.3.18-bof-2/include/asm-ppc/socket.h Sun Oct 3 23:09:05 1999
@@ -45,4 +45,7 @@
#define SO_ATTACH_FILTER 26
#define SO_DETACH_FILTER 27

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
#endif /* _ASM_SOCKET_H */
diff -urN linux-2.3.18/include/asm-sparc/socket.h linux-2.3.18-bof-2/include/asm-sparc/socket.h
--- linux-2.3.18/include/asm-sparc/socket.h Wed Aug 5 01:03:35 1998
+++ linux-2.3.18-bof-2/include/asm-sparc/socket.h Sun Oct 3 23:09:14 1999
@@ -40,6 +40,9 @@
#define SO_ATTACH_FILTER 0x001a
#define SO_DETACH_FILTER 0x001b

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff -urN linux-2.3.18/include/asm-sparc64/socket.h linux-2.3.18-bof-2/include/asm-sparc64/socket.h
--- linux-2.3.18/include/asm-sparc64/socket.h Wed Aug 5 01:03:35 1998
+++ linux-2.3.18-bof-2/include/asm-sparc64/socket.h Sun Oct 3 23:09:26 1999
@@ -40,6 +40,9 @@
#define SO_ATTACH_FILTER 0x001a
#define SO_DETACH_FILTER 0x001b

+/* netfilter */
+#define SO_ORIGINAL_DST 80
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff -urN linux-2.3.18/include/net/ip.h linux-2.3.18-bof-2/include/net/ip.h
--- linux-2.3.18/include/net/ip.h Tue Sep 7 20:52:51 1999
+++ linux-2.3.18-bof-2/include/net/ip.h Sun Oct 3 23:34:38 1999
@@ -225,5 +225,6 @@
u16 port, u32 info, u8 *payload);
extern void ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
u32 info);
+extern void ip_getsockname(struct sock *sk, void *data);

#endif /* _IP_H */
diff -urN linux-2.3.18/net/core/netfilter.c linux-2.3.18-bof-2/net/core/netfilter.c
--- linux-2.3.18/net/core/netfilter.c Fri Oct 1 18:10:55 1999
+++ linux-2.3.18-bof-2/net/core/netfilter.c Mon Oct 4 00:27:47 1999
@@ -310,11 +310,11 @@
struct list_head *i;
int ret;

- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
+ if (!get && !capable(CAP_NET_ADMIN))
+ return -ENOPROTOOPT;

if (down_interruptible(&nf_sockopt_mutex) != 0)
- return -EINTR;
+ return -ENOPROTOOPT;

for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) {
struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
diff -urN linux-2.3.18/net/ipv4/af_inet.c linux-2.3.18-bof-2/net/ipv4/af_inet.c
--- linux-2.3.18/net/ipv4/af_inet.c Fri Oct 1 18:10:56 1999
+++ linux-2.3.18-bof-2/net/ipv4/af_inet.c Sun Oct 3 23:37:27 1999
@@ -685,7 +685,6 @@
return err;
}

-
/*
* This does both peername and sockname.
*/
@@ -703,17 +702,11 @@
sin->sin_port = sk->dport;
sin->sin_addr.s_addr = sk->daddr;
} else {
- __u32 addr = sk->rcv_saddr;
- if (!addr)
- addr = sk->saddr;
- sin->sin_port = sk->sport;
- sin->sin_addr.s_addr = addr;
+ ip_getsockname(sk, sin);
}
*uaddr_len = sizeof(*sin);
- return(0);
+ return 0;
}
-
-

int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int flags, struct scm_cookie *scm)
diff -urN linux-2.3.18/net/ipv4/ip_sockglue.c linux-2.3.18-bof-2/net/ipv4/ip_sockglue.c
--- linux-2.3.18/net/ipv4/ip_sockglue.c Fri Oct 1 18:10:56 1999
+++ linux-2.3.18-bof-2/net/ipv4/ip_sockglue.c Mon Oct 4 00:29:07 1999
@@ -398,9 +398,18 @@
}
#endif

- err = 0;
lock_sock(sk);

+#ifdef CONFIG_NETFILTER
+ err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
+ if (err != -ENOPROTOOPT) {
+ release_sock(sk);
+ return err;
+ }
+#endif
+
+ err = 0;
+
switch(optname)
{
case IP_OPTIONS:
@@ -597,12 +606,7 @@
break;

default:
-#ifdef CONFIG_NETFILTER
- err = nf_setsockopt(sk, PF_INET, optname, optval,
- optlen);
-#else
err = -ENOPROTOOPT;
-#endif
break;
}
release_sock(sk);
@@ -638,7 +642,28 @@

lock_sock(sk);

+#ifdef CONFIG_NETFILTER
+ val = nf_getsockopt(sk, PF_INET, optname, optval, &len);
+ if (val != -ENOPROTOOPT) {
+ release_sock(sk);
+ if (val >= 0)
+ val = put_user(len, optlen);
+ return val;
+ }
+#endif
+
switch(optname) {
+ case SO_ORIGINAL_DST:
+ {
+ struct sockaddr_in sin;
+ if (len != sizeof(sin))
+ return -EINVAL;
+ ip_getsockname(sk, &sin);
+ release_sock(sk);
+ return (copy_to_user(optval, &sin, len) != 0)
+ ? -EFAULT
+ : 0;
+ }
case IP_OPTIONS:
{
unsigned char optbuf[sizeof(struct ip_options)+40];
@@ -757,17 +782,8 @@
return put_user(len, optlen);
}
default:
-#ifdef CONFIG_NETFILTER
- val = nf_getsockopt(sk, PF_INET, optname, optval,
- &len);
- release_sock(sk);
- if (val >= 0)
- val = put_user(len, optlen);
- return val;
-#else
release_sock(sk);
return -ENOPROTOOPT;
-#endif
}
release_sock(sk);

@@ -786,4 +802,18 @@
return -EFAULT;
}
return 0;
+}
+
+/*
+ * Given a 'struct sock', extract the local sockaddr_in - all in-kernel
+ */
+
+void ip_getsockname(struct sock *sk, void *data)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *) data;
+ __u32 addr = sk->rcv_saddr;
+ if (!addr)
+ addr = sk->saddr;
+ sin->sin_port = sk->sport;
+ sin->sin_addr.s_addr = addr;
}

--ELM938991653-369-0_
Content-Type: text/plain; charset=ISO-8859-1
Content-Disposition: attachment; filename=netfilter-0.1.9-bof-2.patch
Content-Description: patch against netfilter-0.1.9
Content-Transfer-Encoding: 7bit

diff -urN netfilter-0.1.9/include/NAT/ip_nat.h netfilter-0.1.9-bof-2/include/NAT/ip_nat.h
--- netfilter-0.1.9/include/NAT/ip_nat.h Thu Sep 23 22:49:56 1999
+++ netfilter-0.1.9-bof-2/include/NAT/ip_nat.h Sun Oct 3 23:56:19 1999
@@ -23,7 +23,9 @@
/* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */
/* 2.2 firewalling (+ masq) went from 64 through 76 */
/* 2.4 firewalling went 64 through 67. */
+#ifndef SO_ORIGINAL_DST
#define SO_ORIGINAL_DST 80
+#endif

#define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2

--ELM938991653-369-0_
Content-Type: text/plain; charset=ISO-8859-1
Content-Disposition: attachment; filename=nf_getsockname.c
Content-Description: nf_getsockname() function - user level
Content-Transfer-Encoding: 7bit

/* nf_getsockname() - netfilter SO_ORIGINAL_DST variant of getsockopt()
*
* Within the new Linux netfilter framework, NAT functionality is cleanly
* separated from the TCP/IP core processing. In old days, you could easily
* retrieve the original destination (IP address and port) of a transparently
* proxied connection by calling the normal getsockname() syscall.
* With netfilter, getsockname() returns the real local IP address and port.
* However, the netfilter code gives all TCP sockets a new socket option,
* SO_ORIGINAL_DST, for retrieval of the original IP/port combination.
*
* This file implements a function nf_getsockname(), with the same calling
* convention as getsockname() itself; it uses SO_ORIGINAL_DST, and if that
* fails, falls back to using getsockname() itself.
*/

#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>

int nf_getsockname(int fd, struct sockaddr *sa, int *salen)
{
if (*salen != sizeof(struct sockaddr_in)) {
errno = EINVAL;
return -1;
}
#ifdef SO_ORIGINAL_DST
if (0 == getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, salen)) {
return 0;
}
#endif
return getsockname(fd, sa, salen);
}

--ELM938991653-369-0_--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/