From 028646bb541193921f83b451e6d058f7673b21c1 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 15 Nov 2015 14:23:59 +0000 Subject: [PATCH] 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 --- qse/cmd/http/httpd.c | 13 +++- qse/include/qse/http/httpd.h | 10 ++- qse/lib/http/httpd-proxy.c | 18 +++--- qse/lib/http/httpd-std.c | 122 +++++++++++++++++++---------------- qse/lib/http/httpd.c | 4 +- 5 files changed, 98 insertions(+), 69 deletions(-) diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c index c6d028a0..d359b805 100644 --- a/qse/cmd/http/httpd.c +++ b/qse/cmd/http/httpd.c @@ -527,9 +527,17 @@ static int get_server_root ( } if (mth == QSE_HTTP_CONNECT) + { 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; } @@ -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 && 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; xserver = qse_httpd_attachserverstd (httpd, &dope, QSE_SIZEOF(server_xtn_t)); if (xserver == QSE_NULL) diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h index 804069a0..bece6938 100644 --- a/qse/include/qse/http/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -211,6 +211,9 @@ struct qse_httpd_peer_t /* == 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. * internal use only. don't mess with these */ qse_httpd_peer_t* next; @@ -749,9 +752,10 @@ struct qse_httpd_client_t enum qse_httpd_server_flag_t { - QSE_HTTPD_SERVER_ACTIVE = (1 << 0), - QSE_HTTPD_SERVER_SECURE = (1 << 1), - QSE_HTTPD_SERVER_BINDTONWIF = (1 << 2) + QSE_HTTPD_SERVER_ACTIVE = (1 << 0), + QSE_HTTPD_SERVER_SECURE = (1 << 1), + QSE_HTTPD_SERVER_BINDTONWIF = (1 << 2), + QSE_HTTPD_SERVER_TRANSPARENT = (1 << 3) }; typedef enum qse_httpd_server_flag_t qse_httpd_server_flag_t; diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index 9ea44c48..eab70071 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -2270,8 +2270,7 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const } } -static int task_main_proxy ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) +static int task_main_proxy (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { task_proxy_t* proxy = (task_proxy_t*)task->ctx; proxy_peer_htrd_xtn_t* xtn; @@ -2383,8 +2382,7 @@ static int task_main_proxy ( if (!(proxy->flags & PROXY_RAW)) { /* set up a http reader to read a response from the peer */ - proxy->peer_htrd = qse_htrd_open ( - httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t)); + proxy->peer_htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t)); if (proxy->peer_htrd == QSE_NULL) goto oops; xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (proxy->peer_htrd); xtn->proxy = proxy; @@ -2400,7 +2398,9 @@ static int task_main_proxy ( proxy->res_pending = 0; /* 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) { qse_mchar_t tmpch; @@ -2424,13 +2424,13 @@ static int task_main_proxy ( else { /* 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_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); } - #endif + #endif httpd->opt.scb.peer.close (httpd, peer_from_cache); qse_httpd_freemem (httpd, peer_from_cache); @@ -2445,6 +2445,8 @@ static int task_main_proxy ( } else { + proxy->peer->client = client; + httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->opt.scb.peer.open (httpd, proxy->peer); if (n <= -1) @@ -2452,7 +2454,7 @@ static int task_main_proxy ( /* TODO: translate more error codes to http error codes... */ if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; 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) { diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index 3d539075..01d8908c 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -964,66 +964,73 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) { /* TODO: logging. warning only */ /* 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 /* TODO: linux. use capset() to set required capabilities just in case */ + if (server->dope.flags & QSE_HTTPD_SERVER_TRANSPARENT) + { #if defined(IP_TRANSPARENT) - /* remove the ip routing restriction that a packet can only - * be sent using a local ip address. this option is useful - * if transparency is achieved with TPROXY */ + /* remove the ip routing restriction that a packet can only + * be sent using a local ip address. this option is useful + * if transparency is achieved with TPROXY */ + + /* + 1) + ip rule add fwmark 0x1/0x1 lookup 100 + ip route add local 0.0.0.0/0 dev lo table 100 + + 2) + iptables -t mangle -N DIVERT + iptables -t mangle -A DIVERT -j MARK --set-mark 0x1/0x1 + 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 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 + + 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 mark 0x1/0x1 -j RETURN + iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 + + 4) + 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 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 + + + 1) is required. + 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 + and the downstream interface are obvious. - /* - 1) - ip rule add fwmark 0x1/0x1 lookup 100 - ip route add local 0.0.0.0/0 dev lo table 100 + 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 -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 - 2) - iptables -t mangle -N DIVERT - iptables -t mangle -A DIVERT -j MARK --set-mark 0x1/0x1 - 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 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 + ---------------------------------------------------------------------- - 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 mark 0x1/0x1 -j RETURN - iptables -t mangle -A PREROUTING -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... + iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 99.99.99.99 --on-port 8000 - 4) - 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 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --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 - - 1) is required. - 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 - and the downstream interface are obvious. - - 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 -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 - - ---------------------------------------------------------------------- - - 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 ! -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: - - accepting TPROXYed connections - - binding to a non-local IP address (IP address the local system doesn't have) - - using a non-local IP address as a source - - - */ - flag = 1; - setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); + IP_TRANSPRENT is needed for: + - accepting TPROXYed connections + - binding to a non-local IP address (IP address the local system doesn't have) + - using a non-local IP address as a source + */ + flag = 1; + if (setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)) <= -1) + { + /* 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 + } 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; len = qse_nwifindextombs (server->dope.nwif, tmp, QSE_COUNTOF(tmp)); - 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())); + HTTPD_DBGOUT2 ("Failed to set SO_BINDTODEVICE to %hs on %zd\n", tmp, (qse_size_t)fd); goto oops; } #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); - if (!server_xtn->ssl_ctx) { /* performed the delayed ssl initialization */ @@ -1422,11 +1427,18 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) 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) - flag = 1; - setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); + flag = 1; + 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 + } /* don't use invalid binding address */ if (bindaddrsize >= 0 && @@ -3457,7 +3469,7 @@ static int query_server ( { case QSE_HTTPD_SERVERSTD_SSL: /* 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); return -1; diff --git a/qse/lib/http/httpd.c b/qse/lib/http/httpd.c index 0cd980a8..9cb3a566 100644 --- a/qse/lib/http/httpd.c +++ b/qse/lib/http/httpd.c @@ -822,7 +822,9 @@ static int accept_client ( /* 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; #if 0