diff --git a/README.md b/README.md index 7d78671..282cc4e 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,29 @@ SpecialProxy ====== -用epoll多路复用io写的一个HTTP代理,轻快,自带DNS解析 +用epoll多路复用io写的一个超匿HTTP代理,轻快,自带DNS解析 +主要用来配合客户端: https://github.com/mmmdbybyd/CProxy ##### SpecialProxy有如下特性: 1. 普通HTTP代理通过请求头首行的host或者Host头域字段获得目标主机, - SpecialProxy不从首行获取目标主机, - 它可以自定义代理头域(默认是Host)。 + SpecialProxy不从首行获取目标主机, 它可以自定义代理头域(默认是Host)。 + 普通http代理用默认的'Host',Host伪装使用自定义代理 2. 普通HTTP代理SSL代理是判断CONNECT请求方法, SpecialProxy可以通过自定义特定字符串进行SSL代理(默认是CONNECT)。 + 用于将TCP伪装成HTTP流量 3. 普通HTTP代理如果遇到多个连续的HTTP请求头只重新拼接第一个请求头, SpecialProxy可以开启严格模式(-a参数),对所以请求头都重新拼接。 + 用于处理客户端一个连接同时发送多个HTTP请求头 4. -L参数设置重定向到本地端口的头域,比如-L Local, - 然后请求头中含有Local: 443,代理会将请求发送到127.0.0.1:443 + 然后请求头中含有Local: 443,代理会将请求发送到127.0.0.1:443。 + 用于openvpn转接之类的 5. -e设置数据编码的代码, 对客户端Host以及请求附带的数据编码, - 服务器的返回数据也编码 + 服务器的返回数据也编码。 + 用于科学上网 ##### 启动参数: -l [监听ip:]监听端口 默认监听IP为 "0.0.0.0" @@ -28,7 +33,7 @@ SpecialProxy -s SSL代理字符串 默认为 "CONNECT" -e host和数据的编码代码(128-255) 默认为0不编码 -t 连接超时时间, 单位: 分 默认不超时 - -i 忽略host前字符个数 默认为0 + -i 忽略host前字符个数 默认为0(部分人用得到) -u 设置uid -a 对所有HTTP请求重新拼接 -h 显示帮助 @@ -41,6 +46,10 @@ SpecialProxy ~~~~~ Linux/Android: make -Android-ndk: - ndk-build +~~~~~ + +##### 启动: +~~~~~ + #SpecialProxy -l 监听端口 -p 代理头 -t 超时(分钟) -e 加密编码 -d dnsIP + SpecialProxy -l 80 -p Meng -t 2 -e 170 -d 8.8.8.8 ~~~~~ \ No newline at end of file diff --git a/SpecialProxy.sh b/SpecialProxy.sh index 20be170..836024e 100644 --- a/SpecialProxy.sh +++ b/SpecialProxy.sh @@ -13,8 +13,7 @@ do echo "Please input 1-65535." done read -p "Please input SpecialProxy proxy header(default is 'Meng'): " proxy_header -echo -n "Please input SpecialProxy encode code(default is 0, no encode): " -read encodeCode +read -p "Please input SpecialProxy encode code(default is 0, no encode): " encodeCode apt-get -y gcc make git || yum install -y gcc make git git clone https://github.com/mmmdbybyd/SpecialProxy.git [ ! -d SpecialProxy ] && Exit "\033[41;37mdownload SpecialProxy source code failed\033[0m" @@ -23,4 +22,4 @@ make || Exit "\033[41;37mcompile tinyproxy failed\033[0m" dnsip=`grep nameserver /etc/resolv.conf | grep -Eo '[1-9]{1,3}[0-9]{0,2}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -n 1` ./SpecialProxy -l $server_port -p ${proxy_header:-Meng} -t 5 -d ${dnsip:-114.114.114.114} -e ${encodeCode:-0} && \ Exit "\033[32mSpeciaoProxy is running.\033[0m" || \ -Exit "\033[41;37mSpeciaoProxy is stopping.\033[0m" +Exit "\033[41;37mSpeciaoProxy is stopping.\033[0m" \ No newline at end of file diff --git a/http.c b/http.c index 97493da..afdc3c7 100644 --- a/http.c +++ b/http.c @@ -2,7 +2,9 @@ #include "dns.h" #include "timeout.h" -#define SSL_RSP "HTTP/1.1 200 Connection established\r\nVia: SpecialProxy_CuteBi\r\n\r\n" +#define SSL_RSP_CONNECT "HTTP/1.1 200 Connection established\r\nServer: SpecialProxy_CuteBi\r\nConnection: keep-alive\r\n\r\n" +#define SSL_RSP_HTTP "HTTP/1.1 200 OK\r\nContent-length: 99999999\r\nServer: SpecialProxy_CuteBi\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: keep-alive\r\n\r\n" +#define SSL_RSP_WEBSOCKET "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: SpecialProxy_CuteBi\r\n\r\n" #define HTTP_TYPE 0 #define OTHER_TYPE 1 @@ -395,6 +397,22 @@ void tcp_out(conn_t *to) } } +/* ssl代理回应 */ +static int respond_sslStatus(conn_t *in) +{ + /* + 可能客户端使用http请求伪装CONNECT代理 + 这时候即使fd是非阻塞也只需要判断返回值是否小于0 + 正常情况非阻塞也可以全部发送,懒得写代码了 + */ + if (memcmp(in->incomplete_data, "CON", 3) == 0) + return (write(in->fd, SSL_RSP_CONNECT, sizeof(SSL_RSP_CONNECT)-1) <= 0); + else if (*in->incomplete_data == 'G' && (strstr(in->incomplete_data, "websocket") || strstr(in->incomplete_data, "WebSocket"))) + return (write(in->fd, SSL_RSP_WEBSOCKET, sizeof(SSL_RSP_WEBSOCKET)-1) <= 0); + + return (write(in->fd, SSL_RSP_HTTP, sizeof(SSL_RSP_HTTP)-1) <= 0); +} + void tcp_in(conn_t *in) { conn_t *server; @@ -453,9 +471,7 @@ void tcp_in(conn_t *in) } if (strstr(in->incomplete_data, ssl_proxy)) { - server->is_ssl = in->is_ssl = 1; - /* 这时候即使fd是非阻塞也只需要判断返回值是否小于0 */ - if (write(in->fd, SSL_RSP, sizeof(SSL_RSP)-1) < 0) + if (respond_sslStatus(in) != 0) { free(host); close_connection(in); diff --git a/http.h b/http.h index 0aea2e9..d644864 100644 --- a/http.h +++ b/http.h @@ -7,10 +7,9 @@ typedef struct tcp_connection { char *ready_data, *incomplete_data; int fd, ready_data_len, incomplete_data_len, sent_len, timer; uint16_t destPort; - unsigned reread_data :1; - unsigned request_type :1; - unsigned keep_alive :1; - unsigned is_ssl :1; + unsigned reread_data :1, + request_type :1, + keep_alive :1; } conn_t; extern void create_listen(char *ip, int port); diff --git a/main.c b/main.c index 33194dc..1664632 100644 --- a/main.c +++ b/main.c @@ -4,8 +4,7 @@ #include "dns.h" #include -#define VERSION "0.4" -#define DEFAULT_DNS_IP "114.114.114.114" +#define VERSION "0.5" struct epoll_event evs[MAX_CONNECTION + 1], ev; int efd; @@ -81,7 +80,7 @@ static void initializate(int argc, char **argv) //默认dns地址 dnsAddr.sin_addr.s_addr = inet_addr(DEFAULT_DNS_IP); dnsAddr.sin_port = htons(53); - dns_connect(&dnsAddr); //主进程中的fd + dns_connect(&dnsAddr); ignore_host_before_count = timeout_minute = strict_spilce = sslEncodeCode = 0; local_header = NULL; ssl_proxy = (char *)"CONNECT"; @@ -102,7 +101,8 @@ static void initializate(int argc, char **argv) dnsAddr.sin_port = htons(atoi(p+1)); } dnsAddr.sin_addr.s_addr = inet_addr(optarg); - connect(dnsFd, (struct sockaddr *)&dnsAddr, sizeof(dnsAddr)); + close(dnsFd); + dns_connect(dnsFd, (struct sockaddr *)&dnsAddr, sizeof(dnsAddr)); break; case 'l':