diff --git a/LICENSE b/LICENSE index d63457d..8be5fc0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,7 @@ -MIT License +Copyright (c) <2017> mmmdbybyd -Copyright (c) 2017 mmmdbybyd +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 58cd247..f32941b 100644 --- a/README.md +++ b/README.md @@ -27,4 +27,12 @@ SpecialProxy -w 工作进程数 ##### BUG: - 好像有些连接不关闭,需要定时重启代理 + 好像有些连接不关闭,需要定时重启代理 + +##### 编译: +~~~~~ +Linux/Android: + make +Android-ndk: + ndk-build +~~~~~ \ No newline at end of file diff --git a/dns.c b/dns.c index c4ba7f3..930f080 100644 --- a/dns.c +++ b/dns.c @@ -6,13 +6,13 @@ int dnsFd; void read_dns_rsp() { - static char rsp_data[512], *p, ips[16]; - static unsigned char *_p; - static struct dns *dns; - static conn_t *client; - static int16_t len, dns_flag; + char rsp_data[512], *p, ip[16]; + unsigned char *_p; + struct dns *dns; + conn_t *client; + int16_t len, dns_flag; - while ((len = read(dnsFd, rsp_data, BUFFER_SIZE)) > 11) + while ((len = read(dnsFd, rsp_data, 512)) > 11) { memcpy(&dns_flag, rsp_data, 2); dns = dns_list + dns_flag; @@ -26,9 +26,9 @@ void read_dns_rsp() continue; } - /* get ips */ + /* get domain ip */ p = rsp_data + dns->request_len + 11; - ips[0] = '\0'; + ip[0] = 0; while (p - rsp_data + 4 <= len) { //type @@ -38,13 +38,12 @@ void read_dns_rsp() continue; } _p = (unsigned char *)p + 1; - sprintf(ips, "%d.%d.%d.%d", _p[0], _p[1], _p[2], _p[3]); + sprintf(ip, "%d.%d.%d.%d", _p[0], _p[1], _p[2], _p[3]); break; } - if (ips[0]) + if (ip[0]) { - //printf("ips %s\n", ips); - if (connectionToServer(ips, client + 1) != 0) + if (connectionToServer(ip, client + 1) != 0) { close_connection(client); continue; @@ -61,7 +60,7 @@ void read_dns_rsp() /* 完全发送返回0,发送部分返回1,出错返回-1 */ static int8_t send_dns_req(struct dns *dns) { - static int write_len; + int write_len; write_len = write(dnsFd, dns->request + dns->sent_len, dns->request_len - dns->sent_len); if (write_len == dns->request_len - dns->sent_len) @@ -82,7 +81,7 @@ static int8_t send_dns_req(struct dns *dns) void dns_query() { - static int16_t i, ret; + int16_t i, ret; for (i = 0; i < MAX_CONNECTION >> 1; i++) { @@ -95,18 +94,19 @@ void dns_query() close_connection(cts + (i << 1)); } } - if (i == MAX_CONNECTION >> 1) - ev.events = EPOLLIN|EPOLLET; - else + //dnsFd的缓冲区以满 + if (i < MAX_CONNECTION >> 1) + { ev.events = EPOLLIN|EPOLLOUT|EPOLLET; - ev.data.fd = dnsFd; - epoll_ctl(efd, EPOLL_CTL_MOD, dnsFd, &ev); + ev.data.fd = dnsFd; + epoll_ctl(efd, EPOLL_CTL_MOD, dnsFd, &ev); + } } int8_t build_dns_req(struct dns *dns, char *domain) { - static char *p, *_p; - static int8_t domain_size; + char *p, *_p; + int8_t domain_size; domain_size = strlen(domain); p = dns->request + 12; @@ -128,8 +128,6 @@ int8_t build_dns_req(struct dns *dns, char *domain) { case 0: ev.data.fd = dnsFd; - ev.events = EPOLLIN|EPOLLET; - epoll_ctl(efd, EPOLL_CTL_MOD, dnsFd, &ev); return 0; case 1: diff --git a/http.c b/http.c index fcf692f..9f69c36 100644 --- a/http.c +++ b/http.c @@ -10,61 +10,18 @@ char *local_header, *proxy_header, *ssl_proxy; int lisFd, proxy_header_len, local_header_len; uint8_t strict_spilce; -/* - 有时候由于程序代码原因glibc的memcpy不能src + len > dst,调试起来比较麻烦 - 这个函数正是为了解决这样的问题,但是效率会比memcpy低 -*/ -#ifdef XMEMCPY -typedef struct byte256 {char data[256];} byte256_t; -typedef struct byte64 {char data[64];} byte64_t; -typedef struct byte16 {char data[16];} byte16_t; -static void xmemcpy(char *src, const char *dst, size_t len) -{ - static byte256_t *to256, *from256; - static byte64_t *to64, *from64; - static byte16_t *to16, *from16; - - to256 = (byte256_t *)src; - from256 = (byte256_t *)dst; - while (len >= sizeof(byte256_t)) - { - *to256++ = *from256++; - len -= sizeof(byte256_t); - } - to64 = (byte64_t *)to256; - from64 = (byte64_t *)from256; - while (len >= sizeof(byte64_t)) - { - *to64++ = *from64++; - len -= sizeof(byte64_t); - } - to16 = (byte16_t *)to64; - from16 = (byte16_t *)from64; - while (len >= sizeof(byte16_t)) - { - *to16++ = *from16++; - len -= sizeof(byte16_t); - } - src = (char *)to16; - dst = (char *)from16; - while (len--) - *src++ = *dst++; -} -#else -#define xmemcpy memcpy -#endif - int8_t connectionToServer(char *ip, conn_t *server) { server->fd = socket(AF_INET, SOCK_STREAM, 0); if (server->fd < 0) return 1; - fcntl(server->fd, F_SETFL, fcntl(server->fd, F_GETFL)|O_NONBLOCK); + fcntl(server->fd, F_SETFL, O_NONBLOCK); addr.sin_addr.s_addr = inet_addr(ip); addr.sin_port = htons(server->destPort); - connect(server->fd, (struct sockaddr *)&addr, sizeof(addr)); + if (connect(server->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 && errno != EINPROGRESS) + return 1; ev.data.ptr = server; - ev.events = EPOLLIN|EPOLLOUT|EPOLLET; + ev.events = EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLET; epoll_ctl(efd, EPOLL_CTL_ADD, server->fd, &ev); return 0; @@ -76,7 +33,7 @@ void close_connection(conn_t *conn) close(conn->fd); if ((conn - cts) & 1) { - static char *server_data; + char *server_data; server_data = conn->ready_data; memset(conn, 0, sizeof(conn_t)); @@ -85,7 +42,7 @@ void close_connection(conn_t *conn) } else { - static struct dns *d; + struct dns *d; d = dns_list + ((conn - cts) >> 1); d->request_len = d->sent_len = 0; @@ -122,8 +79,8 @@ static int8_t request_type(char *data) static char *read_data(conn_t *in, char *data, int *data_len) { - static char *new_data; - static int read_len; + char *new_data; + int read_len; do { new_data = (char *)realloc(data, *data_len + BUFFER_SIZE + 1); @@ -153,12 +110,12 @@ static char *read_data(conn_t *in, char *data, int *data_len) static char *get_host(char *data) { - static char *hostEnd, *host; + char *hostEnd, *host; host = strstr(data, local_header); if (host != NULL) { - static char *local_host; + char *local_host; host += local_header_len; while (*host == ' ') @@ -171,9 +128,8 @@ static char *get_host(char *data) if (local_host == NULL) return NULL; strcpy(local_host, "127.0.0.1:"); - strncpy(local_host + 10, host, hostEnd - host); + memcpy(local_host + 10, host, hostEnd - host); local_host[10 + (hostEnd - host)] = '\0'; - puts(local_host); return local_host; } host= strstr(data, proxy_header); @@ -192,8 +148,8 @@ static char *get_host(char *data) /* 删除请求头中的头域 */ static void del_hdr(char *header, int *header_len) { - static char *key_end, *line_begin, *line_end; - static int key_len; + char *key_end, *line_begin, *line_end; + int key_len; for (line_begin = strchr(header, '\n'); line_begin++ && *line_begin != '\r'; line_begin = line_end) { @@ -206,7 +162,7 @@ static void del_hdr(char *header, int *header_len) { if (line_end++) { - xmemcpy(line_begin, line_end, *header_len - (line_end - header) + 1); + memmove(line_begin, line_end, *header_len - (line_end - header) + 1); (*header_len) -= line_end - line_begin; line_end = line_begin - 1; //新行前一个字符 } @@ -223,8 +179,8 @@ static void del_hdr(char *header, int *header_len) /* 构建新请求头 */ static char *build_request(char *client_data, int *data_len, char *host) { - static char *uri, *url, *p, *lf, *header, *new_data, *proxy_host; - static int len; + char *uri, *url, *p, *lf, *header, *new_data, *proxy_host; + int len; header = client_data; proxy_host = host; @@ -241,14 +197,14 @@ static char *build_request(char *client_data, int *data_len, char *host) p = lf - 10; //指向HTTP版本前面的空格 if (uri != NULL && uri < p) { - xmemcpy(url, uri, *data_len - (uri - client_data) + 1); + memmove(url, uri, *data_len - (uri - client_data) + 1); *data_len -= uri - url; lf -= uri - url; } else { *url++ = '/'; - xmemcpy(url, p, *data_len - (p - client_data) + 1); + memmove(url, p, *data_len - (p - client_data) + 1); *data_len -= p - url; lf -= p - url; } @@ -294,7 +250,7 @@ static char *build_request(char *client_data, int *data_len, char *host) /* 解析Host */ int8_t parse_host(conn_t *server, char *host) { - static char *port, *p; + char *port, *p; port = strchr(host, ':'); if (port) @@ -323,7 +279,7 @@ static int8_t copy_data(conn_t *ct) { if (ct->ready_data) { - static char *new_data; + char *new_data; new_data = (char *)realloc(ct->ready_data, ct->ready_data_len + ct->incomplete_data_len); if (new_data == NULL) @@ -344,11 +300,31 @@ static int8_t copy_data(conn_t *ct) return 0; } +/* 判断请求是否为长连接 */ +static int is_keepAlive(char *header) +{ + char *ConnectionValue; + + ConnectionValue = strstr(header, "\nConnection: "); + if (ConnectionValue) + { + ConnectionValue += 13; + if (*ConnectionValue == 'C' || *ConnectionValue == 'c') + return 0; + else + return 1; + } + if (strstr(header, "HTTP/1.1")) + return 1; + return 0; +} + static void serverToClient(conn_t *server) { - static conn_t *client; - static int write_len; + conn_t *client; + int write_len; + errno = 0; client = server - 1; while ((server->ready_data_len = read(server->fd, server->ready_data, BUFFER_SIZE)) > 0) { @@ -364,14 +340,23 @@ static void serverToClient(conn_t *server) else if (write_len < server->ready_data_len) { server->sent_len = write_len; - ev.events = EPOLLIN|EPOLLOUT|EPOLLET; + ev.events = EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLET; ev.data.ptr = client; epoll_ctl(efd, EPOLL_CTL_MOD, client->fd, &ev); return; } + /* 判断服务端是否close */ + if (client->request_type == HTTP_TYPE && client->is_ssl == 0) + { + server->ready_data[server->ready_data_len] = '\0'; + if (strncmp(server->ready_data, "HTTP/1.", 7) == 0) + client->keep_alive = server->keep_alive = is_keepAlive(server->ready_data); + } + if (server->ready_data_len < BUFFER_SIZE) + break; } - //判断服务端是否关闭连接 - if (server->ready_data_len == 0 || errno != EAGAIN) + //判断是否关闭连接 + if (server->ready_data_len == 0 || (errno != EAGAIN && errno != 0) || client->keep_alive == 0) close_connection(server); else server->ready_data_len = server->sent_len = 0; @@ -379,8 +364,8 @@ static void serverToClient(conn_t *server) void tcp_out(conn_t *to) { - static conn_t *from; - static int write_len; + conn_t *from; + int write_len; if (to->fd == -1) return; @@ -397,15 +382,14 @@ void tcp_out(conn_t *to) serverToClient(from); if (from->fd >= 0 && from->ready_data_len == 0) { - ev.events = EPOLLIN|EPOLLET; + ev.events = EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLET; ev.data.ptr = to; epoll_ctl(efd, EPOLL_CTL_MOD, to->fd, &ev); } - return; } else { - ev.events = EPOLLIN|EPOLLET; + ev.events = EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLET; ev.data.ptr = to; epoll_ctl(efd, EPOLL_CTL_MOD, to->fd, &ev); free(from->ready_data); @@ -416,7 +400,7 @@ void tcp_out(conn_t *to) else if (write_len > 0) { from->sent_len += write_len; - ev.events = EPOLLIN|EPOLLOUT|EPOLLET; + ev.events = EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLET; ev.data.ptr = to; epoll_ctl(efd, EPOLL_CTL_MOD, to->fd, &ev); } @@ -428,13 +412,11 @@ void tcp_out(conn_t *to) void tcp_in(conn_t *in) { - static int write_len; - static conn_t *server; - static char *host, *headerEnd; + conn_t *server; + char *host, *headerEnd; if (in->fd < 0) return; - //如果in - cts是奇数,那么是服务端触发事件 if ((in - cts) & 1) { @@ -450,7 +432,8 @@ void tcp_in(conn_t *in) return; } server = in + 1; - if (request_type(in->incomplete_data) == OTHER_TYPE) + server->request_type = in->request_type = request_type(in->incomplete_data); + if (in->request_type == OTHER_TYPE) { //如果是第一次读取数据,并且不是HTTP请求的,关闭连接。复制数据失败的也关闭连接 if (in->reread_data == 0 || copy_data(in) != 0) @@ -470,6 +453,8 @@ void tcp_in(conn_t *in) close_connection(in); return; } + /* 判断是否长连接 */ + server->keep_alive = in->keep_alive = is_keepAlive(in->incomplete_data); /* 第一次读取数据 */ if (in->reread_data == 0) { @@ -482,16 +467,10 @@ void tcp_in(conn_t *in) } if (strstr(in->incomplete_data, ssl_proxy)) { - write_len = write(in->fd, SSL_RSP, 39); - if (write_len == 39) - { - ; - } - else if (write_len > 0) - { - memcpy(server->ready_data, SSL_RSP + write_len, 39 - write_len); - } - else + server->keep_alive = in->keep_alive = 1; + server->is_ssl = in->is_ssl = 1; + /* 这时候即使fd是非阻塞也只需要判断返回值是否小于0 */ + if (write(in->fd, SSL_RSP, 39) < 0) { free(host); close_connection(in); @@ -501,7 +480,7 @@ void tcp_in(conn_t *in) if (headerEnd - in->incomplete_data < in->incomplete_data_len) { in->incomplete_data_len -= headerEnd - in->incomplete_data; - xmemcpy(in->incomplete_data, headerEnd, in->incomplete_data_len + 1); + memmove(in->incomplete_data, headerEnd, in->incomplete_data_len + 1); if (request_type(in->incomplete_data) == OTHER_TYPE) { copy_data(in); @@ -528,15 +507,17 @@ void tcp_in(conn_t *in) } //数据处理完毕,可以发送 handle_data_complete: - //多次读取客户端数据,但是和服务端建立连接 + //这个判断是防止 多次读取客户端数据,但是没有和服务端建立连接,导致报错 if (server->fd >= 0) tcp_out(server); } void *accept_loop(void *ptr) { + struct epoll_event epollEvent; conn_t *client; + epollEvent.events = EPOLLIN|EPOLLET; while (1) { /* 偶数为客户端,奇数为服务端 */ @@ -548,14 +529,10 @@ void *accept_loop(void *ptr) sleep(3); continue; } - client->fd = accept(lisFd, (struct sockaddr *)&addr, &addr_len); - if (client->fd >= 0) - { - fcntl(client->fd, F_SETFL, fcntl(client->fd, F_GETFL)|O_NONBLOCK); - ev.data.ptr = client; - ev.events = EPOLLIN|EPOLLET; - epoll_ctl(efd, EPOLL_CTL_ADD, client->fd, &ev); - } + while ((client->fd = accept(lisFd, (struct sockaddr *)&addr, &addr_len)) < 0); + fcntl(client->fd, F_SETFL, O_NONBLOCK); + epollEvent.data.ptr = client; + epoll_ctl(efd, EPOLL_CTL_ADD, client->fd, &epollEvent); } return NULL; diff --git a/http.h b/http.h index 7299d22..eed58f6 100644 --- a/http.h +++ b/http.h @@ -8,6 +8,9 @@ typedef struct tcp_connection { int fd, ready_data_len, incomplete_data_len, sent_len; uint16_t destPort; unsigned reread_data :1; + unsigned request_type :1; + unsigned keep_alive :1; + unsigned is_ssl :1; } conn_t; extern void create_listen(char *ip, int port); diff --git a/main.c b/main.c index 6a905fa..d98cb38 100644 --- a/main.c +++ b/main.c @@ -6,7 +6,7 @@ #define VERSION "0.1" #define DEFAULT_DNS_IP "114.114.114.114" -struct epoll_event evs[MAX_CONNECTION + 2], ev; +struct epoll_event evs[MAX_CONNECTION + 1], ev; struct sockaddr_in addr; socklen_t addr_len; int efd; @@ -37,7 +37,7 @@ static void server_loop() epoll_ctl(efd, EPOLL_CTL_ADD, dnsFd, &ev); while (1) { - n = epoll_wait(efd, evs, MAX_CONNECTION + 2, -1); + n = epoll_wait(efd, evs, MAX_CONNECTION + 1, -1); while (n-- > 0) { if (evs[n].data.fd == dnsFd) @@ -49,6 +49,11 @@ static void server_loop() } else { + if ((evs[n].events & EPOLLERR) || (evs[n].events & EPOLLHUP)) + { + if (((conn_t *)evs[n].data.ptr)->fd >= 0) + close_connection((conn_t *)evs[n].data.ptr); + } if (evs[n].events & EPOLLIN) tcp_in((conn_t *)evs[n].data.ptr); if (evs[n].events & EPOLLOUT) @@ -66,12 +71,6 @@ static void initializate(int argc, char **argv) addr_len = sizeof(addr); lisFd = -1; - efd = epoll_create(MAX_CONNECTION + 2); - if (efd < 0) - { - perror("epoll_create"); - exit(1); - } dnsAddr.sin_family = addr.sin_family = AF_INET; //默认dns地址 dnsAddr.sin_addr.s_addr = inet_addr(DEFAULT_DNS_IP); @@ -96,10 +95,6 @@ static void initializate(int argc, char **argv) *p = '\0'; dnsAddr.sin_port = htons(atoi(p+1)); } - else - { - dnsAddr.sin_port = htons(53); - } dnsAddr.sin_addr.s_addr = inet_addr(optarg); connect(dnsFd, (struct sockaddr *)&dnsAddr, sizeof(dnsAddr)); break; @@ -198,13 +193,20 @@ static void initializate(int argc, char **argv) while (workers-- > 1 && fork() == 0) //子进程中的dnsFd必须重新申请,不然epoll监听可能读取到其他进程得到的数据 dns_connect(&dnsAddr); + efd = epoll_create(MAX_CONNECTION + 1); + if (efd < 0) + { + perror("epoll_create"); + exit(1); + } + } int main(int argc, char **argv) { initializate(argc, argv); - //if (daemon(1, 1)) - if (daemon(1, 0)) + if (daemon(1, 1)) + //if (daemon(1, 0)) { perror("daemon"); return 1; diff --git a/main.h b/main.h index af812f2..0b52b39 100644 --- a/main.h +++ b/main.h @@ -19,7 +19,7 @@ #define BUFFER_SIZE 10240 #define MAX_CONNECTION 1020 -extern struct epoll_event evs[MAX_CONNECTION + 2], ev; +extern struct epoll_event evs[MAX_CONNECTION + 1], ev; extern struct sockaddr_in addr; extern socklen_t addr_len; extern int efd;