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

Patrick Schaaf (phbof@bof.de)
Sun, 3 Oct 1999 11:49:16 +0200 (MEST)


> (Rusty screams `NO!!!' as he reads the patch to put NAT back into the
> IP stack...)

(Patrick nods and agrees - that's why I called the patch "dirty")

> Please use the NAT code's SO_ORIGINAL_DST. Yes, this means recoding
> squid, and yes I've been bad for not fixing that, but please send me
> the squid patch instead...

Well, first of all I simply did not see SO_ORIGINAL_DST exists.
While that means recoding applications, it is certainly the nicer
way - and most applications like squid (or my patched ssh) need to do
something special in that place anyway. The approach does pose some
problems, though:

- what should I #include to get at the SO_ORIGINAL_DST #define?
The include/ directory from the netfilter distribution is not
installed anywhere. The includes crossreference each other.
so something like
'ln -s /some/where/netfilter-0.1.9/include /usr/include/netfilter'
(and then #include <netfilter/NAT/ip_nat.h>) does not work.
I don't see an elegant way out of this.

- after finding testsuite/get_address (well, not really, I first grepped
through the kernel for some time :), it was clear that I should use
SOL_IP in the getsockopt() call.

- the call works for root, but not for an ordinary user. The same getsockopt()
call (e.g. using get_address) that succeeds for root, returns EPERM for my
own processes. The cause, if I don't misread, is these lines in
net/core/netfilter.c:nf_sockopt

if (!capable(CAP_NET_ADMIN))
return -EPERM;

I am not using the capability mechanism, but I'll assume I don't have
that as a normal user (and squid, apache and consorts also won't have
it, hopefully). So, I vote for removing that check, at least for the
GET part of the equation, or better: move it into the individual handlers
instead of that central place.

Find appended the source for an 'nf_getsockname()' function, with the
SO_ORIGINAL_DST #defined locally to work around the #include stuff.
My ssh is happily using that (when run as root :), and for squid and
other applications it should simply be a matter of linking that function
in, and replacing all calls to 'getsockname' with 'nf_getsockname'.

Rusty, as an alternative to this approach, how would you like the
kernel side getsockname() implementation to try SO_ORIGINAL_DST in-kernel?
That way user level need not care, sk_buff and struct sock is left alone,
and there's only that one place learning a small bit about NAT. Still a
bit ugly and inconsequential, but I would prefer that.

best regards
Patrick

/* nf_getsockname() - netfilter SO_ORIGINAL_DST variant of getsockname()
*
* 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>
#if 0
#include "NAT/ip_nat.h"
#endif
#ifndef SO_ORIGINAL_DST
#define SO_ORIGINAL_DST 80
#endif

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

-
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/