Author: adrian.chadd Date: Sun Jun 14 06:30:02 2009 New Revision: 14093 Modified: branches/LUSCA_HEAD/configure.in branches/LUSCA_HEAD/libiapp/comm.c branches/LUSCA_HEAD/libiapp/comm.h branches/LUSCA_HEAD/libiapp/comm_ips.h branches/LUSCA_HEAD/libiapp/comm_ips_freebsd.c branches/LUSCA_HEAD/libiapp/comm_ips_null.c branches/LUSCA_HEAD/libiapp/comm_ips_tproxy2.c branches/LUSCA_HEAD/libiapp/comm_ips_tproxy4.c branches/LUSCA_HEAD/libiapp/comm_types.h branches/LUSCA_HEAD/src/client_side.c branches/LUSCA_HEAD/src/forward.c
Log: This commit both tries to bring sanity to the whole interception/spoofing mess -and- fix TPROXY-4. * Firstly, separate out the "spoofing" flag (fd_table[fd].flags.tproxy) into two flags - tproxy_lcl and tproxy_rem. tproxy_lcl is for listen() sockets listening for intercepted requests. tproxy_rem is for outbound connections to upstreams/origin servers which want the client IP spoofed. * Add in hooks in the http listen socket connection code in client_side.c to set the COMM_TPROXY_LCL flag so the relevant fiddling of the listen socket occurs for interception. * Disable the netfilter requirement for TPROXY4. This is the magic/special undocumented thing. For TPROXY2, incoming sockets are redirected and handled by netfilter. For TPROXY4, the incoming sockets are redirected and handled by TPROXY4. TPROXY4 returns the original destination IP in getsockname(), like BSD's ipfw transparent hijack method. Trying the netfilter method under TPROXY4 returns an error. Now, this isn't explicitly defined in the Squid-3 code or the TPROXY4 documentation. The TPROXY4 intercepted connection code IMHO works "by accident". If netfilter is compiled in it will fail; Squid-3 has it fail gracefully down to the default getsockname() method which works. There's a whole lot of tidying up which needs to happen with the interception lookup code, currently done in client_side.c:clientNatLookup(). Just for now, TPROXY2 should use netfilter's destination lookup; TPROXY4 should use the default getsockname() lookup and FreeBSD's interception method should use getsockname() also. I've verified this works for TPROXY4, WCCPv2 in mask assignment / l2 redirection mode. I haven't tested TPROXY2 or FreeBSD. It is quite possible this commit breaks existing functionality. Modified: branches/LUSCA_HEAD/configure.in ============================================================================== --- branches/LUSCA_HEAD/configure.in (original) +++ branches/LUSCA_HEAD/configure.in Sun Jun 14 06:30:02 2009 @@ -1158,13 +1158,9 @@ [ --enable-linux-tproxy4 Enable real Transparent Proxy support for Netfilter TPROXY v4.], [ if test "$enableval" = "yes" ; then - echo "Linux Netfilter/TPROXY v4 enabled" + echo "Linux TPROXY v4 enabled" AC_DEFINE(LINUX_TPROXY4, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v4.]) LINUX_TPROXY4="yes" - if test -z "$LINUX_NETFILTER"; then - echo "Linux-Netfilter Transparent Proxy automatically enabled" - LINUX_NETFILTER="yes" - fi fi ]) Modified: branches/LUSCA_HEAD/libiapp/comm.c ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm.c (original) +++ branches/LUSCA_HEAD/libiapp/comm.c Sun Jun 14 06:30:02 2009 @@ -269,8 +269,10 @@ commSetCloseOnExec(new_socket); if ((flags & COMM_REUSEADDR)) commSetReuseAddr(new_socket); - if ((flags & COMM_TPROXY)) - F->flags.tproxy = 1; + if ((flags & COMM_TPROXY_LCL)) + F->flags.tproxy_lcl = 1; + if ((flags & COMM_TPROXY_REM)) + F->flags.tproxy_rem = 1; if (sqinet_get_port(a) > 0) { #ifdef _SQUID_MSWIN_ if (sock_type != SOCK_DGRAM) @@ -280,9 +282,32 @@ commSetReuseAddr(new_socket); } - if (F->flags.tproxy) { - if (comm_ips_bind(new_socket, &F->local_address) != COMM_OK) { - debug(1, 1) ("comm_fdopen6: FD %d: TPROXY comm_ips_bind failed? Why?\n", new_socket); + /* + * The local endpoint bind() stuff is a bit of a mess. + * + * There's three kinds of "bind" going on. + * + * The default bind(), for a normal socket. This is used both for setting the listen address for + * an incoming socket and the local address of a remote connection socket. + * + * The "spoof connection" bind, which is a bind() to a non-local address, for a remote connection + * socket. Ie, spoofing the client IP when connecting to an upstream. + * + * Finally, the "non-local listen" bind, which is a bind() for the purposes of intercepting + * connections which aren't targetted at a local IP. + * + * These are all treated differently by the various interception techniques on various operating + * systems; this is why things are broken out. + */ + if (F->flags.tproxy_lcl) { + if (comm_ips_bind_lcl(new_socket, &F->local_address) != COMM_OK) { + debug(1, 1) ("comm_fdopen6: FD %d: TPROXY comm_ips_bind_lcl() failed? Why?\n", new_socket); + comm_close(new_socket); + return -1; + } + } else if (F->flags.tproxy_rem) { + if (comm_ips_bind_rem(new_socket, &F->local_address) != COMM_OK) { + debug(1, 1) ("comm_fdopen6: FD %d: TPROXY comm_ips_bind_rem() failed? Why?\n", new_socket); comm_close(new_socket); return -1; } Modified: branches/LUSCA_HEAD/libiapp/comm.h ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm.h (original) +++ branches/LUSCA_HEAD/libiapp/comm.h Sun Jun 14 06:30:02 2009 @@ -81,7 +81,8 @@ unsigned int close_on_exec:1; unsigned int backoff:1; /* keep track of whether the fd is backed off */ unsigned int dnsfailed:1; /* did the dns lookup fail */ - unsigned int tproxy:1; /* should the source address of this FD be spoofed via comm_ips_bind()? */ + unsigned int tproxy_lcl:1; /* should this listen socket have its listen details spoofed via comm_ips_lcl_bind()? */ + unsigned int tproxy_rem:1; /* should the source address of this FD be spoofed via comm_ips_rem_bind()? */ } flags; comm_pending read_pending; comm_pending write_pending; Modified: branches/LUSCA_HEAD/libiapp/comm_ips.h ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm_ips.h (original) +++ branches/LUSCA_HEAD/libiapp/comm_ips.h Sun Jun 14 06:30:02 2009 @@ -2,7 +2,12 @@ #define __LIBIAPP_COMM_IPS_H__ -extern int comm_ips_bind(int fd, sqaddr_t *a); +/* "Local" bind spoofing is for listen sockets wishing to listen on non-local addresses */ +extern int comm_ips_bind_lcl(int fd, sqaddr_t *a); + +/* "Remote" bind spoofing is for connect sockets wishing to bind to a non-local address */ +extern int comm_ips_bind_rem(int fd, sqaddr_t *a); + extern void comm_ips_keepCapabilities(void); extern void comm_ips_restoreCapabilities(void); Modified: branches/LUSCA_HEAD/libiapp/comm_ips_freebsd.c ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm_ips_freebsd.c (original) +++ branches/LUSCA_HEAD/libiapp/comm_ips_freebsd.c Sun Jun 14 06:30:02 2009 @@ -19,8 +19,21 @@ #include "comm_types.h" #include "globals.h" +/* + * FreeBSD non-local bind listen() sockets bind to the relevant address and use + * getsockname() to determine the original destination (local address being spoofed) + * of the new connection. + */ int -comm_ips_bind(int fd, sqaddr_t *a) +comm_ips_bind_lcl(int fd, sqaddr_t *a) +{ + if (bind(fd, sqinet_get_entry(a), sqinet_get_length(a)) != 0) + return COMM_ERROR; + return COMM_OK; +} + +int +comm_ips_bind_rem(int fd, sqaddr_t *a) { int on = 1; Modified: branches/LUSCA_HEAD/libiapp/comm_ips_null.c ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm_ips_null.c (original) +++ branches/LUSCA_HEAD/libiapp/comm_ips_null.c Sun Jun 14 06:30:02 2009 @@ -20,7 +20,13 @@ #include "globals.h" int -comm_ips_bind(int fd, sqaddr_t *a) +comm_ips_bind_lcl(int fd, sqaddr_t *a) +{ + return COMM_ERROR; +} + +int +comm_ips_bind_rem(int fd, sqaddr_t *a) { return COMM_ERROR; } Modified: branches/LUSCA_HEAD/libiapp/comm_ips_tproxy2.c ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm_ips_tproxy2.c (original) +++ branches/LUSCA_HEAD/libiapp/comm_ips_tproxy2.c Sun Jun 14 06:30:02 2009 @@ -40,9 +40,19 @@ #include "../include/util.h" +/* + * TPROXY2 listen() sockets just bind() to the specified address and receive connections that way. + */ +int +comm_ips_bind_lcl(int fd, sqaddr_t *a) +{ + if (bind(fd, sqinet_get_entry(a), sqinet_get_length(a)) != 0) + return COMM_ERROR; + return COMM_OK; +} int -comm_ips_bind(int fd, sqaddr_t *a) +comm_ips_bind_rem(int fd, sqaddr_t *a) { if (sqinet_get_family(a) != AF_INET) return COMM_ERROR; Modified: branches/LUSCA_HEAD/libiapp/comm_ips_tproxy4.c ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm_ips_tproxy4.c (original) +++ branches/LUSCA_HEAD/libiapp/comm_ips_tproxy4.c Sun Jun 14 06:30:02 2009 @@ -49,8 +49,8 @@ #include "comm_types.h" #include "globals.h" -int -comm_ips_bind(int fd, sqaddr_t *a) +static int +tproxy4_set_transparent(int fd, sqaddr_t *a) { int on = 1; @@ -59,6 +59,22 @@ if (bind(fd, sqinet_get_entry(a), sqinet_get_length(a)) != 0) return COMM_ERROR; return COMM_OK; +} + +/* + * TPROXY4 requires the local socket be set IP_TRANSPARENT and then the bind() address + * will determine which TCP/UDP connections are hijacked. + */ +int +comm_ips_bind_lcl(int fd, sqaddr_t *a) +{ + return tproxy4_set_transparent(fd, a); +} + +int +comm_ips_bind_rem(int fd, sqaddr_t *a) +{ + return tproxy4_set_transparent(fd, a); } void Modified: branches/LUSCA_HEAD/libiapp/comm_types.h ============================================================================== --- branches/LUSCA_HEAD/libiapp/comm_types.h (original) +++ branches/LUSCA_HEAD/libiapp/comm_types.h Sun Jun 14 06:30:02 2009 @@ -30,7 +30,8 @@ COMM_NONBLOCKING = 1, COMM_NOCLOEXEC = 2, COMM_REUSEADDR = 4, - COMM_TPROXY = 8 + COMM_TPROXY_LCL = 8, + COMM_TPROXY_REM = 16 } comm_flags_t; /* The default "no TOS" value */ Modified: branches/LUSCA_HEAD/src/client_side.c ============================================================================== --- branches/LUSCA_HEAD/src/client_side.c (original) +++ branches/LUSCA_HEAD/src/client_side.c Sun Jun 14 06:30:02 2009 @@ -5193,7 +5193,11 @@ { http_port_list *s; int fd; + int comm_flags; for (s = Config.Sockaddr.http; s; s = s->next) { + comm_flags = COMM_NONBLOCKING; + if (s->tproxy) + comm_flags |= COMM_TPROXY_LCL; if (MAXHTTPPORTS == NHttpSockets) { debug(1, 1) ("WARNING: You have too many 'http_port' lines.\n"); debug(1, 1) (" The limit is %d\n", MAXHTTPPORTS); @@ -5210,7 +5214,7 @@ SOCK_STREAM, no_addr, ntohs(s->s.sin_port), - COMM_NONBLOCKING, + comm_flags, COMM_TOS_DEFAULT, "HTTP Socket"); } else { @@ -5219,7 +5223,7 @@ IPPROTO_TCP, s->s.sin_addr, ntohs(s->s.sin_port), - COMM_NONBLOCKING, + comm_flags, COMM_TOS_DEFAULT, "HTTP Socket"); leave_suid(); @@ -5233,10 +5237,11 @@ * peg the CPU with select() when we hit the FD limit. */ commSetDefer(fd, httpAcceptDefer, NULL); - debug(1, 1) ("Accepting %s HTTP connections at %s, port %d, FD %d.\n", + debug(1, 1) ("Accepting %s %sHTTP connections at %s, port %d, FD %d.\n", s->transparent ? "transparently proxied" : s->accel ? "accelerated" : "proxy", + s->tproxy ? "and tproxy'ied " : "", inet_ntoa(s->s.sin_addr), (int) ntohs(s->s.sin_port), fd); Modified: branches/LUSCA_HEAD/src/forward.c ============================================================================== --- branches/LUSCA_HEAD/src/forward.c (original) +++ branches/LUSCA_HEAD/src/forward.c Sun Jun 14 06:30:02 2009 @@ -527,7 +527,7 @@ /* XXX at the moment the local port is still 0; should this change to support FreeBSD's tproxy derivative? -adrian */ if (fwdState->request->flags.tproxy) { fd = comm_open(SOCK_STREAM, IPPROTO_TCP, fwdState->src.sin_addr, 0, - COMM_NONBLOCKING | COMM_TPROXY, tos, url); + COMM_NONBLOCKING | COMM_TPROXY_REM, tos, url); } if (fd == -1) { fd = comm_open(SOCK_STREAM, IPPROTO_TCP, outgoing, 0, --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "lusca-commit" group. To post to this group, send email to lusca-commit@googlegroups.com To unsubscribe from this group, send email to lusca-commit+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/lusca-commit?hl=en -~----------~----~----~----~------~----~------~--~---