Messages in this thread Patches in this message | | | From | Patrick Schaaf <> | Subject | Re: [PATCH] getsockopt() on netfilter-redirected socket | Date | Mon, 4 Oct 1999 01:00:53 +0200 (MEST) |
| |
> > 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
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; }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/* 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); }
| |