TPROXY patch

From: Ken Moberg <sf@dont-contact.us>
Date: Wed, 26 Oct 2005 16:04:55 -0700

Here are the diffs in a little better format.

Ken

------------------------------------------------------------------------------------------------------------------------------------------------------
Index: configure.in
--- base/squid-2.5.STABLE9/configure.in 2005-02-23 15:54:54.000000000
-0800
+++ change/squid-2.5.STABLE9/configure.in 2005-10-26
15:37:48.000000000 -0700
@@ -747,6 +747,17 @@
   fi
 ])
 
+dnl Enable Linux transparent proxy support
+AC_ARG_ENABLE(linux-tproxy,
+[ --enable-linux-tproxy
+ Enable real Transparent Proxy support for
Netfilter TPROXY.],
+[ if test "$enableval" = "yes" ; then
+ echo "Linux Netfilter/TPROXY enabled"
+ AC_DEFINE(LINUX_TPROXY)
+ LINUX_TPROXY="yes"
+ fi
+])
+
 AM_CONDITIONAL(MAKE_LEAKFINDER, false)
 dnl Enable Leak Finding Functions
 AC_ARG_ENABLE(leakfinder,
@@ -1209,6 +1220,7 @@
     libc.h \
     limits.h \
     linux/netfilter_ipv4.h \
+ linux/netfilter_ipv4/ip_tproxy.h \
     malloc.h \
     math.h \
     memory.h \
@@ -1893,6 +1905,27 @@
     sleep 10
 fi
 
+dnl Linux Netfilter/TPROXY support requires some specific header files
+dnl Shamelessly copied from shamelessly copied from above
+if test "$LINUX_TPROXY" ; then
+ AC_MSG_CHECKING(if TPROXY header files are installed)
+ # hold on to your hats...
+ if test "$ac_cv_header_linux_netfilter_ipv4_ip_tproxy_h" = "yes"; then
+ LINUX_TPROXY="yes"
+ AC_DEFINE(LINUX_TPROXY, 1)
+ else
+ LINUX_TPROXY="no"
+ AC_DEFINE(LINUX_TPROXY, 0)
+ fi
+ AC_MSG_RESULT($LINUX_TPROXY)
+fi
+if test "$LINUX_TPROXY" = "no" ; then
+ echo "WARNING: Cannot find TPROXY headers, you need to install the"
+ echo "tproxy package from:"
+ echo " - lynx http://www.balabit.com/downloads/tproxy/linux-2.4/"
+ sleep 10
+fi
+
 if test -z "$USE_GNUREGEX" ; then
     case "$host" in
     *-sun-solaris2.[[0-4]])
Index: cf.data.pre
--- base/squid-2.5.STABLE9/src/cf.data.pre 2005-02-22
16:06:34.000000000 -0800
+++ change/squid-2.5.STABLE9/src/cf.data.pre 2005-06-14
15:53:09.000000000 -0700
@@ -1,4 +1,3 @@
-
 #
 # $Id: cf.data.pre,v 1.245.2.85 2005/02/23 00:06:34 hno Exp $
 #
@@ -3958,6 +3957,21 @@
 DOC_START
     If the one-minute average page fault rate exceeds this
     value, Squid prints a WARNING with debug level 0 to get
+DOC_END
+
+NAME: linux_tproxy
+COMMENT: on|off
+TYPE: onoff
+LOC: Config.onoff.linux_tproxy
+DEFAULT: off
+DOC_START
+ If you have Linux 2.4 with netfilter and TPROXY support and you
+ have compiled squid with the correct options then you can enable
+ this option to allow squid to spoof the source address of
+ outgoing connections to servers so that they see connections from
+ the original client IP addresses. Enable this only if you know
+ what you are doing. You will need to set a valid
+ tcp_outgoing_address.
     the administrators attention. The value is in page faults
     per second.
 DOC_END
Index: src/client_side.c
--- base/squid-2.5.STABLE9/src/client_side.c 2005-02-20
11:07:45.000000000 -0800
+++ change/squid-2.5.STABLE9/src/client_side.c 2005-06-14
15:53:11.000000000 -0700
@@ -355,6 +355,7 @@
     new_request->http_ver = old_request->http_ver;
     httpHeaderAppend(&new_request->header, &old_request->header);
     new_request->client_addr = old_request->client_addr;
+ new_request->client_port = old_request->client_port;
     new_request->my_addr = old_request->my_addr;
     new_request->my_port = old_request->my_port;
     new_request->flags.redirected = 1;
@@ -2480,7 +2481,12 @@
 {
     char *url = http->uri;
     request_t *r = http->request;
+ const HttpHeader *req_hdr = &r->header;
     ErrorState *err = NULL;
+ String xfwd;
+
+ int status;
+
     debug(33, 4) ("clientProcessMiss: '%s %s'\n",
     RequestMethodStr[r->method], url);
     /*
@@ -2535,6 +2541,35 @@
     }
     if (http->flags.internal)
     r->protocol = PROTO_INTERNAL;
+
+ /*
+ * If we have TPROXY enabled, parse the http header for
'X-Forwarded-for'.
+ * If it's there, convert it into an in_addr and put it into the
request
+ * structure we pass to forward.
+ */
+ if (Config.onoff.linux_tproxy) {
+ xfwd = httpHeaderGetList(req_hdr, HDR_X_FORWARDED_FOR);
+ if (xfwd.len != 0) {
+ debug(33, 2) ("%s: xfwd_ip[%s]\n", __func__, xfwd.buf);
+ status = inet_aton(xfwd.buf, &r->xfwd_ip);
+ if (status == 0) {
+ r->xfwd_ip.s_addr = htonl(INADDR_ANY);
+ }
+ } else {
+ r->xfwd_ip.s_addr = htonl(INADDR_ANY);
+ }
+
+ if (r->xfwd_ip.s_addr != INADDR_ANY) {
+ debug(33, 2) ("xfwd: %s:%d\n", inet_ntoa(r->xfwd_ip),
+ htons(r->client_port));
+ } else {
+ debug(33, 2) ("xfwd: Field Empty [%s]\n",
+ inet_ntoa(r->xfwd_ip));
+ }
+
+
+ }
+
     fwdStart(http->conn->fd, http->entry, r);
 }
 
@@ -3131,6 +3166,7 @@
         safe_free(http->log_uri);
         http->log_uri = xstrdup(urlCanonicalClean(request));
         request->client_addr = conn->peer.sin_addr;
+ request->client_port = conn->peer.sin_port;
         request->my_addr = conn->me.sin_addr;
         request->my_port = ntohs(conn->me.sin_port);
         request->http_ver = http->http_ver;
Index: src/forward.c
--- base/squid-2.5.STABLE9/src/forward.c 2005-02-22
16:06:35.000000000 -0800
+++ change/squid-2.5.STABLE9/src/forward.c 2005-06-14
15:53:11.000000000 -0700
@@ -1,4 +1,3 @@
-
 /*
  * $Id: forward.c,v 1.82.2.14 2005/02/23 00:06:35 hno Exp $
  *
@@ -36,6 +35,9 @@
 
 #include "squid.h"
 
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_tproxy.h>
+
 static PSC fwdStartComplete;
 static void fwdDispatch(FwdState *);
 static void fwdConnectStart(void *); /* should be same as EVH */
@@ -348,6 +350,118 @@
 }
 
 static void
+forward_handle_tproxy (int fd, FwdState *fwdState)
+{
+ struct in_tproxy itp;
+ int itp_flags;
+ struct in_addr client_addr;
+ struct in_addr my_addr;
+ struct in_addr out_addr;
+
+ debug(20, 2)("%s: client[%s][%d], proxy[%s][%d], my[%s][%d]\n",
+ __func__,
+ inet_ntoa(fwdState->request->client_addr),
+ ntohs(fwdState->request->client_port),
+ inet_ntoa(fwdState->request->xfwd_ip),
+ ntohs(fwdState->request->client_port),
+ inet_ntoa(fwdState->request->my_addr),
+ ntohs(fwdState->request->my_port));
+
+
+ /*
+ * If the client address as stored in the X-FORWARD field is a
local address,
+ * don't try to proxy.
+ */
+ client_addr.s_addr = ntohl(fwdState->request->xfwd_ip.s_addr);
+ my_addr.s_addr = ntohl(fwdState->request->my_addr.s_addr);
+ out_addr = getOutgoingAddr(fwdState->request);
+ out_addr.s_addr = ntohl(out_addr.s_addr);
+
+ if (client_addr.s_addr == INADDR_ANY) {
+ return;
+ }
+
+ if (client_addr.s_addr == INADDR_LOOPBACK) {
+ return;
+ }
+
+ if (client_addr.s_addr == my_addr.s_addr) {
+ return;
+ }
+
+ if (client_addr.s_addr == out_addr.s_addr) {
+ return;
+ }
+
+ /*
+ * OK, it's safe to proxy for the client.
+ */
+ itp.itp_faddr.s_addr = fwdState->request->xfwd_ip.s_addr;
+
+ /*
+ * On a connect, the port number is assigned by the system
+ */
+ itp.itp_fport = 0;
+
+
+ /* If these syscalls fail then we just fallback to connecting
+ * normally by simply ignoring the errors...
+ */
+
+ /*
+ * We need to be superuser to set the proxy address.
+ */
+ enter_suid();
+
+ /*
+ * Register the client address we're interested in.
+ */
+ if (setsockopt(fd, SOL_IP, IP_TPROXY_ASSIGN, &itp, sizeof(itp))
== -1)
+ {
+ debug(20, 2)("%s: tproxy ip=%s, port=%d, ERROR ASSIGN: %s\n",
+ __func__,
+ inet_ntoa(itp.itp_faddr),
+ ntohs(itp.itp_fport), strerror(errno));
+ /*
+ * If this fails, don't try the proxy connect
+ */
+ leave_suid();
+ return;
+
+ } else {
+ debug(20, 2)("%s: tproxy ip=%s,0x%x,port=%d TPROXY_ASSIGN\n",
+ __func__,
+ inet_ntoa(itp.itp_faddr),
+ ntohl(itp.itp_faddr.s_addr),
+ ntohs(itp.itp_fport));
+ }
+
+ /*
+ * Set the socket up for an outgoing connect using
+ * the client address.
+ */
+ itp_flags = ITP_CONNECT;
+ if (setsockopt(fd, SOL_IP, IP_TPROXY_FLAGS, &itp_flags,
+ sizeof(itp_flags)) == -1)
+ {
+ debug(20, 2)("%s: tproxy ip=%x,port=%d, ERROR CONNECT: %s\n",
+ __func__,
+ ntohl(itp.itp_faddr.s_addr),
+ ntohs(itp.itp_fport), strerror(errno));
+ } else {
+ debug(20, 2)("%s: tproxy ip=%x,port=%d TPROXY_CONNECT\n",
+ __func__,
+ ntohl(itp.itp_faddr.s_addr),
+ ntohs(itp.itp_fport));
+ }
+
+ /*
+ * Back to previous user id
+ */
+ leave_suid();
+}
+
+static void
 fwdConnectStart(void *data)
 {
     FwdState *fwdState = data;
@@ -361,6 +475,14 @@
     int ftimeout = Config.Timeout.forward - (squid_curtime -
fwdState->start);
     struct in_addr outgoing;
     unsigned short tos;
+ struct in_addr *local;
+
+ if (Config.onoff.linux_tproxy) {
+ local=&fwdState->src.sin_addr;
+ } else {
+ local = NULL;
+ }
+
     assert(fs);
     assert(fwdState->server_fd == -1);
     debug(17, 3) ("fwdConnectStart: %s\n", url);
@@ -383,7 +505,7 @@
     ftimeout = 5;
     if (ftimeout < ctimeout)
     ctimeout = ftimeout;
- if ((fd = pconnPop(host, port)) >= 0) {
+ if ((fd = pconnPop(host, port, local)) >= 0) {
     if (fwdCheckRetriable(fwdState)) {
         debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd);
         fwdState->server_fd = fd;
@@ -407,8 +529,8 @@
     outgoing = getOutgoingAddr(fwdState->request);
     tos = getOutgoingTOS(fwdState->request);
 
- debug(17, 3) ("fwdConnectStart: got addr %s, tos %d\n",
- inet_ntoa(outgoing), tos);
+ debug(17, 3) ("%s: outgoing addr %s, tos %d\n",
+ __func__, inet_ntoa(outgoing), tos);
     fd = comm_openex(SOCK_STREAM,
     0,
     outgoing,
@@ -417,7 +539,7 @@
     tos,
     url);
     if (fd < 0) {
- debug(50, 4) ("fwdConnectStart: %s\n", xstrerror());
+ debug(50, 3) ("fwdConnectStart: %s\n", xstrerror());
     err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
     err->xerrno = errno;
     err->request = requestLink(fwdState->request);
@@ -444,6 +566,18 @@
     ctimeout,
     fwdConnectTimeout,
     fwdState);
+
+ switch (Config.onoff.linux_tproxy) {
+ case 0:
+ break;
+ case 1:
+ forward_handle_tproxy(fd, fwdState);
+ break;
+
+ default:
+ break;
+ }
+
     commConnectStart(fd, host, port, fwdConnectDone, fwdState);
 }
 
Index: src/http.c
--- base/squid-2.5.STABLE9/src/http.c 2005-02-11 02:52:59.000000000 -0800
+++ change/squid-2.5.STABLE9/src/http.c 2005-06-14 15:53:09.000000000
-0700
@@ -566,6 +566,10 @@
     int bin;
     int clen;
     size_t read_sz;
+ struct in_addr *local;
+
+ local = NULL;
+
 #if DELAY_POOLS
     delay_id delay_id;
 
@@ -575,6 +579,11 @@
     else
     delay_id = delayMostBytesAllowed(entry->mem_obj);
 #endif
+
+ if ( Config.onoff.linux_tproxy ) {
+ local=&httpState->request->client_addr;
+ }
+
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
     comm_close(fd);
     return;
@@ -761,7 +770,7 @@
 #endif
             comm_remove_close_handler(fd, httpStateFree, httpState);
             fwdUnregister(fd, httpState->fwd);
- pconnPush(fd, request->host, request->port);
+ pconnPush(fd, request->host, request->port, local);
             fwdComplete(httpState->fwd);
             httpState->fd = -1;
             httpStateFree(fd, httpState);
Index: src/pconn.c
--- base/squid-2.5.STABLE9/src/pconn.c 2003-12-15 15:38:43.000000000
-0800
+++ change/squid-2.5.STABLE9/src/pconn.c 2005-06-14
15:53:11.000000000 -0700
@@ -49,7 +49,6 @@
 
 static PF pconnRead;
 static PF pconnTimeout;
-static const char *pconnKey(const char *host, u_short port);
 static hash_table *table = NULL;
 static struct _pconn *pconnNew(const char *key);
 static void pconnDelete(struct _pconn *p);
@@ -58,12 +57,17 @@
 static MemPool *pconn_data_pool = NULL;
 static MemPool *pconn_fds_pool = NULL;
 
-static const char *
-pconnKey(const char *host, u_short port)
+#define PCONN_KEYLEN (SQUIDHOSTNAMELEN + 24)
+
+static inline const int
+pconnKey(char *buf, const char *peer, u_short port, struct in_addr *local)
 {
- LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN + 10);
- snprintf(buf, SQUIDHOSTNAMELEN + 10, "%s.%d", host, (int) port);
- return buf;
+ if ( local == NULL ) {
+ return snprintf(buf, PCONN_KEYLEN, "%s.%d", peer, (int) port);
+ }else{
+ return snprintf(buf, PCONN_KEYLEN, "%s.%d.%s",
+ peer, (int) port, inet_ntoa(*local));
+ }
 }
 
 static struct _pconn *
@@ -184,11 +188,11 @@
 }
 
 void
-pconnPush(int fd, const char *host, u_short port)
+pconnPush(int fd, const char *peer, u_short port, struct in_addr *local)
 {
     struct _pconn *p;
     int *old;
- LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10);
+ LOCAL_ARRAY(char, key, PCONN_KEYLEN);
     LOCAL_ARRAY(char, desc, FD_DESC_SZ);
     if (fdUsageHigh()) {
     debug(48, 3) ("pconnPush: Not many unused FDs\n");
@@ -199,7 +203,7 @@
     return;
     }
     assert(table != NULL);
- strcpy(key, pconnKey(host, port));
+ pconnKey(key, peer, port, local);
     p = (struct _pconn *) hash_lookup(table, key);
     if (p == NULL)
     p = pconnNew(key);
@@ -217,20 +221,20 @@
     p->fds[p->nfds++] = fd;
     commSetSelect(fd, COMM_SELECT_READ, pconnRead, p, 0);
     commSetTimeout(fd, Config.Timeout.pconn, pconnTimeout, p);
- snprintf(desc, FD_DESC_SZ, "%s idle connection", host);
+ snprintf(desc, FD_DESC_SZ, "%s idle connection", peer);
     fd_note(fd, desc);
     debug(48, 3) ("pconnPush: pushed FD %d for %s\n", fd, key);
 }
 
 int
-pconnPop(const char *host, u_short port)
+pconnPop(const char *peer, u_short port, struct in_addr *local)
 {
     struct _pconn *p;
     hash_link *hptr;
     int fd = -1;
- LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10);
+ LOCAL_ARRAY(char, key, PCONN_KEYLEN);
     assert(table != NULL);
- strcpy(key, pconnKey(host, port));
+ pconnKey(key, peer, port, local);
     hptr = hash_lookup(table, key);
     if (hptr != NULL) {
     p = (struct _pconn *) hptr;
Index: src/protos.h
--- base/squid-2.5.STABLE9/src/protos.h 2005-02-20 18:55:04.000000000
-0800
+++ change/squid-2.5.STABLE9/src/protos.h 2005-06-14
15:53:11.000000000 -0700
@@ -1137,8 +1137,8 @@
 extern int errorReservePageId(const char *page_name);
 extern ErrorState *errorCon(err_type type, http_status);
 
-extern void pconnPush(int, const char *host, u_short port);
-extern int pconnPop(const char *host, u_short port);
+extern void pconnPush(int, const char *peer, u_short port, struct
in_addr *local);
+extern int pconnPop(const char *peer, u_short port, struct in_addr *local);
 extern void pconnInit(void);
 
 extern int asnMatchIp(void *, struct in_addr);
Index: src/structs.h
--- base/squid-2.5.STABLE9/src/structs.h 2005-02-22
16:06:35.000000000 -0800
+++ change/squid-2.5.STABLE9/src/structs.h 2005-06-14
15:53:11.000000000 -0700
@@ -608,6 +608,9 @@
     int relaxed_header_parser;
     int accel_uses_host_header;
     int accel_no_pmtu_disc;
+#if LINUX_NETFILTER
+ int linux_tproxy;
+#endif
     } onoff;
     acl *aclList;
     struct {
@@ -1657,6 +1660,7 @@
 struct _request_t {
     method_t method;
     protocol_t protocol;
+ in_port_t client_port;
     char login[MAX_LOGIN_SZ];
     char host[SQUIDHOSTNAMELEN + 1];
     auth_user_request_t *auth_user_request;
@@ -1675,6 +1679,11 @@
     struct in_addr client_addr;
     struct in_addr my_addr;
     unsigned short my_port;
+ /*
+ * The client IP addresses from the X-Forwarded-For field in the
+ * request header.
+ */
+ struct in_addr xfwd_ip;
     HttpHeader header;
     int content_length;
     HierarchyLogEntry hier;
@@ -1992,6 +2001,9 @@
     unsigned int dont_retry:1;
     unsigned int ftp_pasv_failed:1;
     } flags;
+#if LINUX_NETFILTER
+ struct sockaddr_in src;
+#endif
 };
 
 #if USE_HTCP
Received on Wed Oct 26 2005 - 17:13:47 MDT

This archive was generated by hypermail pre-2.1.9 : Tue Nov 01 2005 - 12:00:07 MST