diff --git a/conev.h b/conev.h index 9673bf0..58fee3f 100644 --- a/conev.h +++ b/conev.h @@ -45,6 +45,7 @@ enum eid { #define FLAG_S4 1 #define FLAG_S5 2 #define FLAG_CONN 4 +#define FLAG_HTTP 8 #ifdef EID_STR char *eid_name[] = { diff --git a/main.c b/main.c index 2e3794e..14f1e81 100644 --- a/main.c +++ b/main.c @@ -132,6 +132,7 @@ const struct option options[] = { {"no-domain", 0, 0, 'N'}, {"no-ipv6", 0, 0, 'X'}, {"no-udp", 0, 0, 'U'}, + {"allow-http", 0, 0, 'G'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"ip", 1, 0, 'i'}, @@ -674,6 +675,9 @@ int main(int argc, char **argv) case 'U': params.udp = 0; break; + case 'G': + params.http_connect = 1; + break; #ifdef __linux__ case 'E': params.transparent = 1; diff --git a/params.h b/params.h index 706be71..1408714 100644 --- a/params.h +++ b/params.h @@ -111,12 +111,13 @@ struct params { bool ipv6; bool resolve; bool udp; + bool transparent; + bool http_connect; int max_open; int debug; size_t bfsize; struct sockaddr_in6 baddr; struct sockaddr_in6 laddr; - bool transparent; struct mphdr *mempool; const char *protect_path; diff --git a/proxy.c b/proxy.c index 3f88324..ed9eefb 100644 --- a/proxy.c +++ b/proxy.c @@ -13,6 +13,7 @@ #include "conev.h" #include "extend.h" #include "error.h" +#include "packets.h" #ifdef _WIN32 #include @@ -128,6 +129,8 @@ static int resolve(char *host, int len, hints.ai_socktype = type; hints.ai_flags = AI_ADDRCONFIG; + if (!params.resolve) + hints.ai_flags |= AI_NUMERICHOST; hints.ai_family = params.ipv6 ? AF_UNSPEC : AF_INET; char rchar = host[len]; @@ -205,6 +208,14 @@ static int resp_error(int fd, int e, int flag) } return resp_s5_error(fd, e); } + else if (flag == FLAG_HTTP) { + if (!e) { + static const char r[] = "HTTP/1.1 200 OK\r\n\r\n"; + return send(fd, r, sizeof(r) - 1, 0); + } + static const char r[] = "HTTP/1.1 503 Fail\r\n\r\n"; + return send(fd, r, sizeof(r) - 1, 0); + } #ifdef __linux__ if (params.transparent && (e == ECONNREFUSED || e == ETIMEDOUT)) { @@ -334,6 +345,26 @@ static int s5_set_addr(char *buffer, size_t n, } + +static int http_get_addr(const char *buff, + size_t n, struct sockaddr_ina *dst) +{ + char *host = 0; + uint16_t port = 0; + int host_len = parse_http(buff, n, &host, &port); + + if (host_len < 3 || host_len > 255) { + return -1; + } + if (resolve(host, host_len, dst, SOCK_STREAM)) { + LOG(LOG_E, "not resolved: %.*s\n", host_len, host); + return -1; + } + dst->in.sin_port = htons(port); + return 0; +} + + static int remote_sock(struct sockaddr_ina *dst, int type) { if (params.baddr.sin6_family == AF_INET6) { @@ -841,6 +872,15 @@ static inline int on_request(struct poolhd *pool, struct eval *val, } error = connect_hook(pool, val, &dst, EV_CONNECT); } + else if (params.http_connect + && n > 7 && !memcmp(buffer, "CONNECT", 7)) { + val->flag = FLAG_HTTP; + + if (http_get_addr(buffer, n, &dst)) { + return -1; + } + error = connect_hook(pool, val, &dst, EV_CONNECT); + } else { LOG(LOG_E, "ss: invalid version: 0x%x (%zd)\n", *buffer, n); return -1;