Hi,

some time ago a discussion occurred about a tproxy patch for apache (
http://marc.info/?l=apache-httpd-dev&m=122953956229413&w=2 ).
It seems that, at the end of the discussion, you were interested in
this patch, but I couldn't find any news since then, and didn't find
anything about tproxy in the apache trunk.
I could retrieve the patch (
http://miscfiles.googlecode.com/svn/trunk/tproxy.patch , based on
apache 2.2.9), but couldn't make it work on my system.

After investigation, I found that there are some missing things:
- merge_proxy_config() didn't take care of the new tproxy variables in
structure proxy_server_conf
- the listen sockets did not received the IP_TRANSPARENT socket option.

I made the changes and also ported the patch to apache 2.2.14 but
three points still bugs me:
- the original patch included <sys/capability.h>, but this file does
not exist on my system. <linux/capability.h> does, so I'm wondering
about the portability of <sys/capability.h>. And it is clear that
<linux/capability.h> needs to be guarded with macros which prevents
the inclusion if it does not exist.
- The listen socket needs to receive the IP_TRANSPARENT socket option,
but it should be customizable in the configuration file. I thought to
alter the "Listen" syntax to add an optional argument "TProxy" or
"Transparent". I'd like comments for this idea.
- in file server/listen.c, line 311 (or 316 applied patch), a socket
is created. I was able to successfully run the tproxy patch without
setting the IP_TRANSPARENT to the sockets created here, but I don't
know if I am missing something or not.

Thanks for the comments.
Nicolas
diff -ru httpd-2.2.14/modules/proxy/mod_proxy_ajp.c httpd-2.2.14.tproxy/modules/proxy/mod_proxy_ajp.c
--- httpd-2.2.14/modules/proxy/mod_proxy_ajp.c	2009-04-25 12:04:21.000000000 +0200
+++ httpd-2.2.14.tproxy/modules/proxy/mod_proxy_ajp.c	2010-02-17 18:46:47.000000000 +0100
@@ -673,7 +673,7 @@
             break;
 
         /* Step Two: Make the Connection */
-        if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
+        if (ap_proxy_connect_backend(scheme, backend, worker, r->server, r->connection->remote_addr)) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                          "proxy: AJP: failed to make connection to backend: %s",
                          backend->hostname);
diff -ru httpd-2.2.14/modules/proxy/mod_proxy.c httpd-2.2.14.tproxy/modules/proxy/mod_proxy.c
--- httpd-2.2.14/modules/proxy/mod_proxy.c	2009-01-31 21:58:07.000000000 +0100
+++ httpd-2.2.14.tproxy/modules/proxy/mod_proxy.c	2010-02-17 18:46:47.000000000 +0100
@@ -1133,6 +1133,8 @@
     ps->proxy_status = (overrides->proxy_status_set == 0) ? base->proxy_status : overrides->proxy_status;
     ps->proxy_status_set = overrides->proxy_status_set || base->proxy_status_set;
     ps->pool = p;
+    ps->tproxy = (overrides->tproxy_set != 0) ? overrides->tproxy: base->tproxy;
+    ps->tproxy_set = overrides->tproxy_set || base->tproxy_set;
     return ps;
 }
 
@@ -1909,6 +1911,18 @@
     *new_space = dir_config;
 }
 
+static const char *
+    set_tproxy(cmd_parms *parms, void *dummy, int flag)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    psf->tproxy = flag;
+    psf->tproxy_set = 1;
+
+    return NULL;
+}
+
 static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
 {
     const char *errmsg;
@@ -2112,6 +2126,8 @@
      "A balancer or worker name with list of params"),
     AP_INIT_TAKE1("ProxyFtpDirCharset", set_ftp_directory_charset, NULL,
      RSRC_CONF|ACCESS_CONF, "Define the character set for proxied FTP listings"),
+    AP_INIT_FLAG("ProxyTProxy", set_tproxy, NULL, RSRC_CONF,
+     "on if the proxy should use client IP to connect to the origin server"),
     {NULL}
 };
 
diff -ru httpd-2.2.14/modules/proxy/mod_proxy_ftp.c httpd-2.2.14.tproxy/modules/proxy/mod_proxy_ftp.c
--- httpd-2.2.14/modules/proxy/mod_proxy_ftp.c	2009-09-14 22:53:28.000000000 +0200
+++ httpd-2.2.14.tproxy/modules/proxy/mod_proxy_ftp.c	2010-02-17 18:46:47.000000000 +0100
@@ -1010,7 +1010,7 @@
      */
 
 
-    if (ap_proxy_connect_backend("FTP", backend, worker, r->server)) {
+    if (ap_proxy_connect_backend("FTP", backend, worker, r->server, c->remote_addr)) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                      "proxy: FTP: an error occurred creating a new connection to %pI (%s)",
                      connect_addr, connectname);
diff -ru httpd-2.2.14/modules/proxy/mod_proxy.h httpd-2.2.14.tproxy/modules/proxy/mod_proxy.h
--- httpd-2.2.14/modules/proxy/mod_proxy.h	2008-11-11 21:04:34.000000000 +0100
+++ httpd-2.2.14.tproxy/modules/proxy/mod_proxy.h	2010-02-17 18:46:47.000000000 +0100
@@ -193,6 +193,8 @@
     } proxy_status;             /* Status display options */
     char proxy_status_set;
     apr_pool_t *pool;           /* Pool used for allocating this struct */
+    int tproxy;                 /* true if tproxy is enabled */
+    char tproxy_set;
 } proxy_server_conf;
 
 
@@ -714,6 +716,7 @@
  * @param conn    acquired connection
  * @param worker  connection worker
  * @param s       current server record
+ * @param remote_addr  client addr
  * @return        OK or HTTP_XXX error
  * @note In case the socket already exists for conn, just check the link
  * status.
@@ -721,7 +724,9 @@
 PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
                                             proxy_conn_rec *conn,
                                             proxy_worker *worker,
-                                            server_rec *s);
+                                            server_rec *s,
+                                            apr_sockaddr_t *remote_addr);
+
 /**
  * Make a connection record for backend connection
  * @param proxy_function calling proxy scheme (http, ajp, ...)
diff -ru httpd-2.2.14/modules/proxy/mod_proxy_http.c httpd-2.2.14.tproxy/modules/proxy/mod_proxy_http.c
--- httpd-2.2.14/modules/proxy/mod_proxy_http.c	2009-07-10 14:22:21.000000000 +0200
+++ httpd-2.2.14.tproxy/modules/proxy/mod_proxy_http.c	2010-02-17 18:46:48.000000000 +0100
@@ -1973,7 +1973,7 @@
         goto cleanup;
 
     /* Step Two: Make the Connection */
-    if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
+    if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server, c->remote_addr)) {
         if (r->proxyreq == PROXYREQ_PROXY)
             status = HTTP_NOT_FOUND;
         else
diff -ru httpd-2.2.14/modules/proxy/mod_proxy_scgi.c httpd-2.2.14.tproxy/modules/proxy/mod_proxy_scgi.c
--- httpd-2.2.14/modules/proxy/mod_proxy_scgi.c	2009-09-24 00:20:00.000000000 +0200
+++ httpd-2.2.14.tproxy/modules/proxy/mod_proxy_scgi.c	2010-02-17 18:46:48.000000000 +0100
@@ -527,7 +527,7 @@
     }
 
     /* Step Two: Make the Connection */
-    if (ap_proxy_connect_backend(PROXY_FUNCTION, backend, worker, r->server)) {
+    if (ap_proxy_connect_backend(PROXY_FUNCTION, backend, worker, r->server, r->connection->remote_addr)) {
         ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                      "proxy: " PROXY_FUNCTION ": failed to make connection "
                      "to backend: %s:%u", backend->hostname, backend->port);
diff -ru httpd-2.2.14/modules/proxy/proxy_util.c httpd-2.2.14.tproxy/modules/proxy/proxy_util.c
--- httpd-2.2.14/modules/proxy/proxy_util.c	2009-07-03 13:57:02.000000000 +0200
+++ httpd-2.2.14.tproxy/modules/proxy/proxy_util.c	2010-02-17 18:46:48.000000000 +0100
@@ -2227,7 +2227,8 @@
 PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
                                             proxy_conn_rec *conn,
                                             proxy_worker *worker,
-                                            server_rec *s)
+                                            server_rec *s,
+					    apr_sockaddr_t *remote_addr)
 {
     apr_status_t rv;
     int connected = 0;
@@ -2305,6 +2306,21 @@
                              " Keepalive");
             }
         }
+
+        /* TProxy support */
+        if (conf->tproxy) {
+            if ((rv = apr_socket_opt_set(newsock, APR_IP_TRANSPARENT, 1)) != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                             "apr_socket_opt_set(APR_IP_TRANSPARENT): Failed to set");
+            }
+
+            if ((rv = apr_socket_bind(newsock, remote_addr)) != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                "proxy: error binding to socket %pI", remote_addr);
+                return HTTP_INTERNAL_SERVER_ERROR;
+            }
+        }
+
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                      "proxy: %s: fam %d socket created to connect to %s",
                      proxy_function, backend_addr->family, worker->hostname);
diff -ru httpd-2.2.14/os/unix/unixd.c httpd-2.2.14.tproxy/os/unix/unixd.c
--- httpd-2.2.14/os/unix/unixd.c	2008-09-18 20:42:18.000000000 +0200
+++ httpd-2.2.14.tproxy/os/unix/unixd.c	2010-02-18 10:52:59.000000000 +0100
@@ -49,6 +49,7 @@
 #endif
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
+#include <linux/capability.h> /* The original patch included sys/capability.h, but this file doesn't exist on my system */
 #endif
 
 unixd_config_rec unixd_config;
@@ -60,6 +61,34 @@
  * with different sets of groups for each.
  */
 
+void
+keep_capabilities(void)
+{
+    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "prctl Failed");
+    }
+}
+
+static void
+set_capabilities(int capability)
+{
+    cap_user_header_t head = (cap_user_header_t) calloc(1, sizeof(*head));
+    cap_user_data_t cap = (cap_user_data_t) calloc(1, sizeof(*cap));
+
+    head->version = _LINUX_CAPABILITY_VERSION;
+    head->pid = 0;
+    cap->effective = (1 << capability);
+    cap->inheritable = cap->effective;
+    cap->permitted = cap->effective;
+
+    if (capset(head, cap) != 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "capset Failed");
+    }
+
+    free(head);
+    free(cap);
+}
+
 static int set_group_privs(void)
 {
     if (!geteuid()) {
@@ -117,6 +146,7 @@
     if (set_group_privs()) {
         return -1;
     }
+    keep_capabilities();
 
     if (NULL != unixd_config.chroot_dir) {
         if (geteuid()) {
@@ -166,6 +196,10 @@
                     (long) unixd_config.user_id);
         return -1;
     }
+
+    /* Needed for tproxy */
+    set_capabilities(CAP_NET_ADMIN);
+
 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
     /* this applies to Linux 2.4+ */
 #ifdef AP_MPM_WANT_SET_COREDUMPDIR
diff -ru httpd-2.2.14/server/listen.c httpd-2.2.14.tproxy/server/listen.c
--- httpd-2.2.14/server/listen.c	2008-12-18 18:22:54.000000000 +0100
+++ httpd-2.2.14.tproxy/server/listen.c	2010-02-18 10:49:01.000000000 +0100
@@ -61,6 +61,11 @@
         return stat;
     }
 #endif
+    /* Needed for tproxy; however, this code should be optionnal and depend of the configuration file */
+    if ((stat = apr_socket_opt_set(s, APR_IP_TRANSPARENT, 1)) != APR_SUCCESS) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, stat, p,
+		     "apr_socket_opt_set(APR_IP_TRANSPARENT): Failed to set");
+    }
 
     stat = apr_socket_opt_set(s, APR_SO_KEEPALIVE, one);
     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
diff -ru httpd-2.2.14/srclib/apr/include/apr_network_io.h httpd-2.2.14.tproxy/srclib/apr/include/apr_network_io.h
--- httpd-2.2.14/srclib/apr/include/apr_network_io.h	2007-12-15 05:10:38.000000000 +0100
+++ httpd-2.2.14.tproxy/srclib/apr/include/apr_network_io.h	2010-02-17 18:46:48.000000000 +0100
@@ -65,6 +65,7 @@
 #define APR_SO_DEBUG         4    /**< Debug */
 #define APR_SO_NONBLOCK      8    /**< Non-blocking IO */
 #define APR_SO_REUSEADDR     16   /**< Reuse addresses */
+#define APR_IP_TRANSPARENT   32   /**< TProxy support */
 #define APR_SO_SNDBUF        64   /**< Send buffer */
 #define APR_SO_RCVBUF        128  /**< Receive buffer */
 #define APR_SO_DISCONNECTED  256  /**< Disconnected */
diff -ru httpd-2.2.14/srclib/apr/network_io/unix/sockopt.c httpd-2.2.14.tproxy/srclib/apr/network_io/unix/sockopt.c
--- httpd-2.2.14/srclib/apr/network_io/unix/sockopt.c	2006-08-03 12:55:31.000000000 +0200
+++ httpd-2.2.14.tproxy/srclib/apr/network_io/unix/sockopt.c	2010-02-17 18:46:48.000000000 +0100
@@ -17,6 +17,7 @@
 #include "apr_arch_networkio.h"
 #include "apr_strings.h"
 
+#define IP_TRANSPARENT 19
 
 static apr_status_t soblock(int sd)
 {
@@ -318,6 +319,16 @@
         return APR_ENOTIMPL;
 #endif
         break;
+    case APR_IP_TRANSPARENT:
+#ifdef IP_TRANSPARENT
+        if (setsockopt(sock->socketdes, SOL_IP, IP_TRANSPARENT, (void *)&one, sizeof(int)) == -1) {
+            return errno;
+        }
+#else
+        return APR_ENOTIMPL;
+#endif
+        break;
+
     default:
         return APR_EINVAL;
     }

Reply via email to