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;
}