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

Reply via email to