@@ -1870,6 +1870,18 @@
return NULL;
}
+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 void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
{
proxy_server_conf *sconf = ap_get_module_config(s->module_config,
@@ -2082,6 +2094,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}
};
@@ -193,6 +193,9 @@
} 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;
@@ -711,6 +714,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.
@@ -718,7 +722,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);
/**
* Make a connection record for backend connection
* @param proxy_function calling proxy scheme (http, ajp, ...)
@@ -605,11 +605,11 @@
goto cleanup;
/* Step Two: Make the Connection */
- if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "proxy: AJP: failed to make connection to backend: %s",
- backend->hostname);
- status = HTTP_SERVICE_UNAVAILABLE;
+ 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);
+ status = HTTP_SERVICE_UNAVAILABLE;
goto cleanup;
}
@@ -973,11 +973,11 @@
*/
- if (ap_proxy_connect_backend("FTP", backend, worker, r->server)) {
- 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);
- proxy_ftp_cleanup(r, backend);
+ 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);
+ proxy_ftp_cleanup(r, backend);
return HTTP_SERVICE_UNAVAILABLE;
}
@@ -1871,6 +1871,10 @@
* connection ID of the current upstream connection is the same as that
* of the connection when the socket was opened.
*/
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "--> linuxpark: %s/%s/%d %s\n",
+ __FILE__, __FUNCTION__, __LINE__, url);
apr_pool_t *p = r->connection->pool;
conn_rec *c = r->connection;
apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
@@ -1929,7 +1933,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
@@ -1596,8 +1596,8 @@
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
- "proxy: %s: fam %d socket created to connect to %s",
- proxy_function, backend_addr->family, backend_name);
+ "%s/%d proxy: %s: fam %d socket created to connect to %s",
+ __FUNCTION__, __LINE__, proxy_function, backend_addr->family, backend_name);
/* make the connection out of the socket */
rv = apr_socket_connect(*newsock, backend_addr);
@@ -2269,7 +2269,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;
@@ -2342,14 +2343,31 @@
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
" Keepalive");
- }
- }
+ }
+ }
+
+ /* TProxy support */
+ if (conf->tproxy) {
+#if 1
+ //if ((rv = apr_socket_opt_set(newsock, APR_IP_TRANSPARENT, 1)) != APR_SUCCESS) {
+ if ((rv = apr_socket_opt_set(newsock, 32, 1)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+ "apr_socket_opt_set(APR_IP_TRANSPARENT): Failed to set");
+ }
+#endif
+ 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);
+ "%s/%d proxy: %s: fam %d socket created to connect to %s",
+ __FUNCTION__, __LINE__, proxy_function, backend_addr->family, worker->hostname);
- /* make the connection out of the socket */
- rv = apr_socket_connect(newsock, backend_addr);
+ /* make the connection out of the socket */
+ rv = apr_socket_connect(newsock, backend_addr);
/* if an error occurred, loop round and try again */
if (rv != APR_SUCCESS) {
@@ -49,8 +49,10 @@
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
+#include <sys/capability.h>
#endif
+
unixd_config_rec unixd_config;
/* Set group privileges.
@@ -60,6 +62,36 @@
* 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 +149,7 @@
if (set_group_privs()) {
return -1;
}
+ keep_capabilities();
#ifdef MPE
/* Only try to switch if we're running as MANAGER.SYS */
if (geteuid() == 1 && unixd_config.user_id > 1) {
@@ -142,6 +175,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
@@ -461,7 +498,6 @@
#ifdef _OSD_POSIX
int sockdes;
#endif
-
*accepted = NULL;
status = apr_socket_accept(&csd, lr->sd, ptrans);
if (status == APR_SUCCESS) {
@@ -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 */
@@ -151,6 +151,9 @@
apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa)
{
+ int val = 1;
+
+ setsockopt (sock->socketdes, SOL_IP, 19, &val, sizeof (val));
if (bind(sock->socketdes,
(struct sockaddr *)&sa->sa, sa->salen) == -1) {
return errno;
}
@@ -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,15 @@
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;
}