added QSE_HTTPD_SERVER_TRANSPARENT to allow optional support for TPROXY.

changed to set the target to SECURE when the intercepted connection is known to be SECURE
This commit is contained in:
hyung-hwan 2015-11-15 14:23:59 +00:00
parent c7bd05b419
commit 028646bb54
5 changed files with 98 additions and 69 deletions

View File

@ -527,9 +527,17 @@ static int get_server_root (
} }
if (mth == QSE_HTTP_CONNECT) if (mth == QSE_HTTP_CONNECT)
{
root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_RAW; root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_RAW;
else if (loccfg->proxy.pseudonym[0]) }
root->u.proxy.pseudonym = loccfg->proxy.pseudonym; else
{
if (loccfg->proxy.pseudonym[0])
root->u.proxy.pseudonym = loccfg->proxy.pseudonym;
if (server->dope.flags & QSE_HTTPD_SERVER_SECURE)
root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_SECURE;
}
goto proxy_ok; goto proxy_ok;
} }
@ -2047,6 +2055,7 @@ static qse_httpd_server_t* attach_server (qse_httpd_t* httpd, int num, qse_xli_l
if (pair && pair->val->type == QSE_XLI_STR && if (pair && pair->val->type == QSE_XLI_STR &&
qse_strxcmp (((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len, QSE_T("yes")) == 0) dope.flags |= QSE_HTTPD_SERVER_SECURE; qse_strxcmp (((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len, QSE_T("yes")) == 0) dope.flags |= QSE_HTTPD_SERVER_SECURE;
dope.flags |= QSE_HTTPD_SERVER_TRANSPARENT; /* need this to support TPROXY when proxy.allow_intercept is enabled */
dope.detach = free_server_config; dope.detach = free_server_config;
xserver = qse_httpd_attachserverstd (httpd, &dope, QSE_SIZEOF(server_xtn_t)); xserver = qse_httpd_attachserverstd (httpd, &dope, QSE_SIZEOF(server_xtn_t));
if (xserver == QSE_NULL) if (xserver == QSE_NULL)

View File

@ -211,6 +211,9 @@ struct qse_httpd_peer_t
/* == PRIVATE == */ /* == PRIVATE == */
/* set by httpd to the client this peer has been created for */
qse_httpd_client_t* client;
/* peer links for the proxy peer cache list in client. /* peer links for the proxy peer cache list in client.
* internal use only. don't mess with these */ * internal use only. don't mess with these */
qse_httpd_peer_t* next; qse_httpd_peer_t* next;
@ -749,9 +752,10 @@ struct qse_httpd_client_t
enum qse_httpd_server_flag_t enum qse_httpd_server_flag_t
{ {
QSE_HTTPD_SERVER_ACTIVE = (1 << 0), QSE_HTTPD_SERVER_ACTIVE = (1 << 0),
QSE_HTTPD_SERVER_SECURE = (1 << 1), QSE_HTTPD_SERVER_SECURE = (1 << 1),
QSE_HTTPD_SERVER_BINDTONWIF = (1 << 2) QSE_HTTPD_SERVER_BINDTONWIF = (1 << 2),
QSE_HTTPD_SERVER_TRANSPARENT = (1 << 3)
}; };
typedef enum qse_httpd_server_flag_t qse_httpd_server_flag_t; typedef enum qse_httpd_server_flag_t qse_httpd_server_flag_t;

View File

@ -2270,8 +2270,7 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const
} }
} }
static int task_main_proxy ( static int task_main_proxy (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
task_proxy_t* proxy = (task_proxy_t*)task->ctx; task_proxy_t* proxy = (task_proxy_t*)task->ctx;
proxy_peer_htrd_xtn_t* xtn; proxy_peer_htrd_xtn_t* xtn;
@ -2383,8 +2382,7 @@ static int task_main_proxy (
if (!(proxy->flags & PROXY_RAW)) if (!(proxy->flags & PROXY_RAW))
{ {
/* set up a http reader to read a response from the peer */ /* set up a http reader to read a response from the peer */
proxy->peer_htrd = qse_htrd_open ( proxy->peer_htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t));
httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t));
if (proxy->peer_htrd == QSE_NULL) goto oops; if (proxy->peer_htrd == QSE_NULL) goto oops;
xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (proxy->peer_htrd); xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (proxy->peer_htrd);
xtn->proxy = proxy; xtn->proxy = proxy;
@ -2400,7 +2398,9 @@ static int task_main_proxy (
proxy->res_pending = 0; proxy->res_pending = 0;
/* get a cached peer connection */ /* get a cached peer connection */
peer_from_cache = qse_httpd_decacheproxypeer (httpd, client, &proxy->peer->nwad, &proxy->peer->local, (proxy->peer->flags & QSE_HTTPD_PEER_SECURE)); peer_from_cache = qse_httpd_decacheproxypeer (
httpd, client, &proxy->peer->nwad,
&proxy->peer->local, (proxy->peer->flags & QSE_HTTPD_PEER_SECURE));
if (peer_from_cache) if (peer_from_cache)
{ {
qse_mchar_t tmpch; qse_mchar_t tmpch;
@ -2424,13 +2424,13 @@ static int task_main_proxy (
else else
{ {
/* the cached connection seems to be stale or invalid */ /* the cached connection seems to be stale or invalid */
#if defined(QSE_HTTPD_DEBUG) #if defined(QSE_HTTPD_DEBUG)
{ {
qse_mchar_t tmp[128]; qse_mchar_t tmp[128];
qse_nwadtombs (&peer_from_cache->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); qse_nwadtombs (&peer_from_cache->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL);
HTTPD_DBGOUT2 ("Decached and closed stale peer [%hs] - %zd\n", tmp, (qse_size_t)peer_from_cache->handle); HTTPD_DBGOUT2 ("Decached and closed stale peer [%hs] - %zd\n", tmp, (qse_size_t)peer_from_cache->handle);
} }
#endif #endif
httpd->opt.scb.peer.close (httpd, peer_from_cache); httpd->opt.scb.peer.close (httpd, peer_from_cache);
qse_httpd_freemem (httpd, peer_from_cache); qse_httpd_freemem (httpd, peer_from_cache);
@ -2445,6 +2445,8 @@ static int task_main_proxy (
} }
else else
{ {
proxy->peer->client = client;
httpd->errnum = QSE_HTTPD_ENOERR; httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.peer.open (httpd, proxy->peer); n = httpd->opt.scb.peer.open (httpd, proxy->peer);
if (n <= -1) if (n <= -1)
@ -2452,7 +2454,7 @@ static int task_main_proxy (
/* TODO: translate more error codes to http error codes... */ /* TODO: translate more error codes to http error codes... */
if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404;
else if (httpd->errnum == QSE_HTTPD_EACCES || else if (httpd->errnum == QSE_HTTPD_EACCES ||
httpd->errnum == QSE_HTTPD_ECONN) http_errnum = 403; httpd->errnum == QSE_HTTPD_ECONN) http_errnum = 403;
#if defined(QSE_HTTPD_DEBUG) #if defined(QSE_HTTPD_DEBUG)
{ {

View File

@ -964,66 +964,73 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
{ {
/* TODO: logging. warning only */ /* TODO: logging. warning only */
/* this is not a hard failure */ /* this is not a hard failure */
HTTPD_DBGOUT1 ("Failed to enable SO_REUSERPORT on %zd\n", (qse_size_t)fd); HTTPD_DBGOUT1 ("Failed to set SO_REUSERPORT on %zd\n", (qse_size_t)fd);
} }
#endif #endif
/* TODO: linux. use capset() to set required capabilities just in case */ /* TODO: linux. use capset() to set required capabilities just in case */
if (server->dope.flags & QSE_HTTPD_SERVER_TRANSPARENT)
{
#if defined(IP_TRANSPARENT) #if defined(IP_TRANSPARENT)
/* remove the ip routing restriction that a packet can only /* remove the ip routing restriction that a packet can only
* be sent using a local ip address. this option is useful * be sent using a local ip address. this option is useful
* if transparency is achieved with TPROXY */ * if transparency is achieved with TPROXY */
/* /*
1) 1)
ip rule add fwmark 0x1/0x1 lookup 100 ip rule add fwmark 0x1/0x1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100 ip route add local 0.0.0.0/0 dev lo table 100
2) 2)
iptables -t mangle -N DIVERT iptables -t mangle -N DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 0x1/0x1 iptables -t mangle -A DIVERT -j MARK --set-mark 0x1/0x1
iptables -t mangle -A DIVERT -j ACCEPT iptables -t mangle -A DIVERT -j ACCEPT
iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j DIVERT iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j DIVERT
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000
3) 3)
iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j MARK --set-mark 0x1/0x1 iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j MARK --set-mark 0x1/0x1
iptables -t mangle -A PREROUTING -p tcp -m mark 0x1/0x1 -j RETURN iptables -t mangle -A PREROUTING -p tcp -m mark 0x1/0x1 -j RETURN
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000
4) 4)
iptables -t mangle -A PREROUTING -p tcp --sport 80 -j MARK --set-mark 0x1/0x1 iptables -t mangle -A PREROUTING -p tcp --sport 80 -j MARK --set-mark 0x1/0x1
iptables -t mangle -A PREROUTING -p tcp -m mark 0x1/0x1 -j RETURN iptables -t mangle -A PREROUTING -p tcp -m mark 0x1/0x1 -j RETURN
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000
1) is required. 1) is required.
one of 2), 3), 4), and a variant is needed. one of 2), 3), 4), and a variant is needed.
Specifying -i and -o can narrow down the amount of packets when the upstream interface Specifying -i and -o can narrow down the amount of packets when the upstream interface
and the downstream interface are obvious. and the downstream interface are obvious.
If eth2 is an upstream and the eth1 is a downstream interface, If eth2 is an upstream and the eth1 is a downstream interface,
iptables -t mangle -A PREROUTING -i eth2 -p tcp --sport 80 -j MARK --set-mark 0x1/0x1 iptables -t mangle -A PREROUTING -i eth2 -p tcp --sport 80 -j MARK --set-mark 0x1/0x1
iptables -t mangle -A PREROUTING -p tcp -m mark 0x1/0x1 -j RETURN iptables -t mangle -A PREROUTING -p tcp -m mark 0x1/0x1 -j RETURN
iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000
---------------------------------------------------------------------- ----------------------------------------------------------------------
if the socket is bound to 99.99.99.99:8000, you may do... if the socket is bound to 99.99.99.99:8000, you may do...
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 99.99.99.99 --on-port 8000 iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 99.99.99.99 --on-port 8000
iptables -t mangle -A PREROUTING -p tcp ! -s 127.0.0.0/255.0.0.0 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 0.0.0.0 --on-port 8000 iptables -t mangle -A PREROUTING -p tcp ! -s 127.0.0.0/255.0.0.0 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 0.0.0.0 --on-port 8000
IP_TRANSPRENT is needed for: IP_TRANSPRENT is needed for:
- accepting TPROXYed connections - accepting TPROXYed connections
- binding to a non-local IP address (IP address the local system doesn't have) - binding to a non-local IP address (IP address the local system doesn't have)
- using a non-local IP address as a source - using a non-local IP address as a source
- */
*/ flag = 1;
flag = 1; if (setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)) <= -1)
setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); {
/* TODO: logging. warning only */
/* this is not a hard failure */
HTTPD_DBGOUT1 ("Failed to set IP_TRANSPARENT on %zd\n", (qse_size_t)fd);
}
#endif #endif
}
if (server->dope.flags & QSE_HTTPD_SERVER_BINDTONWIF) if (server->dope.flags & QSE_HTTPD_SERVER_BINDTONWIF)
{ {
@ -1032,11 +1039,10 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
qse_size_t len; qse_size_t len;
len = qse_nwifindextombs (server->dope.nwif, tmp, QSE_COUNTOF(tmp)); len = qse_nwifindextombs (server->dope.nwif, tmp, QSE_COUNTOF(tmp));
if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1)
{ {
/* TODO: logging ... */
qse_httpd_seterrnum (httpd, ((len <= 0)? QSE_HTTPD_EINVAL: SKERR_TO_ERRNUM())); qse_httpd_seterrnum (httpd, ((len <= 0)? QSE_HTTPD_EINVAL: SKERR_TO_ERRNUM()));
HTTPD_DBGOUT2 ("Failed to set SO_BINDTODEVICE to %hs on %zd\n", tmp, (qse_size_t)fd);
goto oops; goto oops;
} }
#endif #endif
@ -1294,7 +1300,6 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server); server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server);
if (!server_xtn->ssl_ctx) if (!server_xtn->ssl_ctx)
{ {
/* performed the delayed ssl initialization */ /* performed the delayed ssl initialization */
@ -1422,11 +1427,18 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
goto oops; goto oops;
} }
/* TODO: set transparent and bind only if the server is transparent */ if (peer->client && peer->client->server &&
(peer->client->server->dope.flags & QSE_HTTPD_SERVER_TRANSPARENT))
{
#if defined(IP_TRANSPARENT) #if defined(IP_TRANSPARENT)
flag = 1; flag = 1;
setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); if (setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)) <= -1)
{
/* this is not a hard failure */
HTTPD_DBGOUT1 ("Failed to set IP_TRANSPARENT on peer socket %zd\n", (qse_size_t)fd);
}
#endif #endif
}
/* don't use invalid binding address */ /* don't use invalid binding address */
if (bindaddrsize >= 0 && if (bindaddrsize >= 0 &&
@ -3457,7 +3469,7 @@ static int query_server (
{ {
case QSE_HTTPD_SERVERSTD_SSL: case QSE_HTTPD_SERVERSTD_SSL:
/* you must specify the certificate and the key file to be able /* you must specify the certificate and the key file to be able
* to use SSL */ * to use SSL. not supported by this sample implmentation. */
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOENT); qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOENT);
return -1; return -1;

View File

@ -822,7 +822,9 @@ static int accept_client (
/* TODO: check maximum number of client. if exceed call client.close */ /* TODO: check maximum number of client. if exceed call client.close */
if (server->dope.flags & QSE_HTTPD_SERVER_SECURE) clibuf.status |= QSE_HTTPD_CLIENT_SECURE; if (server->dope.flags & QSE_HTTPD_SERVER_SECURE)
clibuf.status |= QSE_HTTPD_CLIENT_SECURE;
clibuf.server = server; clibuf.server = server;
#if 0 #if 0