diff --git a/CProxy.conf b/CProxy.conf index 7d5115a..6111db7 100755 --- a/CProxy.conf +++ b/CProxy.conf @@ -1,10 +1,10 @@ global { uid=3004; process=2; - timeout=10; + timeout=1; encode=128; tcp_listen=0124; - tcp6_listen=0124; + tcp6_listen=0125; dns_listen=0126; } @@ -18,7 +18,7 @@ http { } https { - https_ip="47.240.75.93"; + https_ip="174.137.54.215"; https_port=127; https_del="Host,host,x-online-host"; https_first="[M] [U] [V]\r\nHost: [host]\r\n"; @@ -27,7 +27,6 @@ https { } httpdns { - addr=119.29.29.29:53; - http_req="[M] http://wap.10010.com/d?dn=[D] [V]\r\nHost: wap.10010.com\r\n"; - encode = 0; + addr = 119.29.29.29:80; + http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n"; } diff --git a/CProxy.conf.explain b/CProxy.conf.explain index 4e41557..a48315a 100755 --- a/CProxy.conf.explain +++ b/CProxy.conf.explain @@ -65,5 +65,5 @@ httpdns模块 httpdns 模块关键字: [M], [D], [V], \r, \n, \v, \f, \b, \t, \a. 默认 [M] 为 GET 默认 [V] 为 HTTP/1.0 -addr=119.29.29.29:53; //HTTPDNS服务器IP +addr=119.29.29.29:80; //HTTPDNS服务器IP diff --git a/Makefile b/Makefile index 75e1eb6..73b16b7 100755 --- a/Makefile +++ b/Makefile @@ -5,14 +5,14 @@ CFLAGS += -g -O2 -Wall -pthread LIBS = OBJ := CProxy -all: main.o http_proxy.o httpdns.o http_request.o conf.o timeout.o kill.o help.o +all: main.o http_proxy.o httpdns.o http_request.o conf.o timeout.o help.o $(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS) .c.o: - $(CC) $(CFLAGS) -c $< $(LIBS) + $(CC) $(CFLAGS) -c $< clean: rm -rf *.o rm $(OBJ) android: - ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk APP_BUILD_SCRIPT=Android.mk + /usr/lib/android-ndk/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk APP_BUILD_SCRIPT=Android.mk diff --git a/README.md b/README.md index 6a7e3f4..587d05d 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 可以修改HTTP协议消息头(request). 可以修改HTTP协议CONNECT方法消息头. 可以修改HTTP协议GET方法消息头. - 支持IPV6. + 支持IPV4/IPV6. ## Build diff --git a/conf.c b/conf.c index 8216d36..ebb102d 100755 --- a/conf.c +++ b/conf.c @@ -15,6 +15,28 @@ char *strncpy_(char *dest, const char *src, size_t n) } } +/* 字符串预处理,设置转义字符 */ +static void string_pretreatment(char *str, int *len) +{ + char *lf, *p, *ori_strs[] = { "\\r", "\\n", "\\b", "\\v", "\\f", "\\t", "\\a", "\\b", "\\0" }, to_chrs[] = { '\r', '\n', '\b', '\v', '\f', '\t', '\a', '\b', '\0' }; + int i; + + while ((lf = strchr(str, '\n')) != NULL) { + for (p = lf + 1; *p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'; p++) + *len -= 1; + strcpy(lf, p); + *len -= 1; + } + for (i = 0; i < sizeof(to_chrs); i++) { + for (p = strstr(str, ori_strs[i]); p; p = strstr(p, ori_strs[i])) { + //支持\\r + *(p - 1) == '\\' ? (*p--) : (*p = to_chrs[i]); + memmove(p + 1, p + 2, strlen(p + 2)); + (*len)--; + } + } +} + /* 在content中,设置变量(var)的首地址,值(val)的位置首地址和末地址,返回下一行指针 */ static char *set_var_val_lineEnd(char *content, char **var, char **val_begin, char **val_end) { @@ -71,6 +93,69 @@ static char *set_var_val_lineEnd(char *content, char **var, char **val_begin, ch val_len = strlen(*val_begin); *val_end = lineEnd = *val_begin + val_len; } + //string_pretreatment(*val_begin, &val_len); + *val_end = *val_begin + val_len; + //printf("var[%s]\nbegin[%s]\n\n", *var, *val_begin); + return lineEnd; +} + +/* 在content中,设置变量(var)的首地址,值(val)的位置首地址和末地址,返回下一行指针 */ +static char *set_var_val_lineEnd2(char *content, char **var, char **val_begin, char **val_end) +{ + char *p, *pn, *lineEnd; + ; + int val_len; + + while (1) { + if (content == NULL) + return NULL; + + for (; *content == ' ' || *content == '\t' || *content == '\r' || *content == '\n'; content++) ; + if (*content == '\0') + return NULL; + *var = content; + pn = strchr(content, '\n'); + p = strchr(content, '='); + if (p == NULL) { + if (pn) { + content = pn + 1; + continue; + } else + return NULL; + } + content = p; + //将变量以\0结束 + for (p--; *p == ' ' || *p == '\t'; p--) ; + *(p + 1) = '\0'; + //值的首地址 + for (content++; *content == ' ' || *content == '\t'; content++) ; + if (*content == '\0') + return NULL; + //双引号引起来的值支持换行 + if (*content == '"') { + *val_begin = content + 1; + *val_end = strstr(*val_begin, "\";"); + if (*val_end != NULL) + break; + } else + *val_begin = content; + *val_end = strchr(content, ';'); + if (pn && *val_end > pn) { + content = pn + 1; + continue; + } + break; + } + + if (*val_end) { + **val_end = '\0'; + val_len = *val_end - *val_begin; + lineEnd = *val_end; + } else { + val_len = strlen(*val_begin); + *val_end = lineEnd = *val_begin + val_len; + } + string_pretreatment(*val_begin, &val_len); *val_end = *val_begin + val_len; //printf("var[%s]\nbegin[%s]\n\n", *var, *val_begin); return lineEnd; @@ -289,7 +374,7 @@ static void parse_httpdns_module(char *content, conf * p) char *var, *val_begin, *val_end, *lineEnd; int val_begin_len; - while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) { + while ((lineEnd = set_var_val_lineEnd2(content, &var, &val_begin, &val_end)) != NULL) { if (strcasecmp(var, "addr") == 0) { val_begin_len = strlen(val_begin) + 1; p->addr = (char *)malloc(val_begin_len); @@ -350,8 +435,11 @@ void free_conf(conf * p) if (p->addr) free(p->addr); - if (p->http_req) + if (p->http_req) { + bzero(p->http_req, 0); + p->http_req_len = 0; free(p->http_req); + } return; } @@ -363,7 +451,7 @@ void read_conf(char *filename, conf * configure) file = fopen(filename, "r"); if (file == NULL) { - printf("cannot open config file."); + perror("cannot open config file."); exit(-1); } fseek(file, 0, SEEK_END); @@ -380,21 +468,25 @@ void read_conf(char *filename, conf * configure) if ((global_content = read_module(buff, "global")) == NULL) perror("read global module error"); - parse_global_module(global_content, configure); + else + parse_global_module(global_content, configure); free(global_content); if ((http_content = read_module(buff, "http")) == NULL) perror("read http module error"); - parse_http_module(http_content, configure); + else + parse_http_module(http_content, configure); free(http_content); if ((https_content = read_module(buff, "https")) == NULL) perror("read https module error"); - parse_https_module(https_content, configure); + else + parse_https_module(https_content, configure); free(https_content); if ((httpdns_content = read_module(buff, "httpdns")) == NULL) perror("read httpdns module error"); - parse_httpdns_module(httpdns_content, configure); + else + parse_httpdns_module(httpdns_content, configure); free(httpdns_content); } diff --git a/help.c b/help.c index 593948a..c46e772 100755 --- a/help.c +++ b/help.c @@ -2,12 +2,12 @@ char help_information(void) { - static const char name[] = "CProxy"; - static const char subject[] = "proxy server"; + static const char name[] = "C"; + static const char subject[] = "Proxy Server"; static const struct { const char *email; } author = { - "aixiao@aixiao.me", + "AIXIAO@AIXIAO.ME", }; static const char usage[] = "Usage: [-?h] [-s signal] [-c filename]"; diff --git a/http_proxy.c b/http_proxy.c index bd078aa..9a35c14 100755 --- a/http_proxy.c +++ b/http_proxy.c @@ -6,11 +6,10 @@ int remote_port; char remote_host[CACHE_SIZE]; /* 对数据进行编码 */ -void dataEncode(char *data, int data_len) +void dataEncode(char *data, int data_len, unsigned code) { - if (sslEncodeCode) - while (data_len-- > 0) - data[data_len] ^= sslEncodeCode; + while (data_len-- > 0) + data[data_len] ^= code; } static char *read_data(conn_t * in, char *data, int *data_len) @@ -69,7 +68,7 @@ static void serverToClient(conn_t * server) client = server - 1; while ((server->ready_data_len = read(server->fd, server->ready_data, BUFFER_SIZE)) > 0) { - dataEncode(server->ready_data, server->ready_data_len); + dataEncode(server->ready_data, server->ready_data_len, sslEncodeCode); write_len = write(client->fd, server->ready_data, server->ready_data_len); if (write_len <= 0) { if (write_len == 0 || errno != EAGAIN) @@ -115,20 +114,14 @@ void clientToserver(conn_t * in) // 判断请求类型 static int8_t request_type(char *data) { - if (strncmp(data, "GET", 3) == 0 || - strncmp(data, "POST", 4) == 0 || - strncmp(data, "CONNECT", 7) == 0 || - strncmp(data, "HEAD", 4) == 0 || - strncmp(data, "PUT", 3) == 0 || - strncmp(data, "OPTIONS", 7) == 0 || - strncmp(data, "MOVE", 4) == 0 || - strncmp(data, "COPY", 4) == 0 || - strncmp(data, "TRACE", 5) == 0 || - strncmp(data, "DELETE", 6) == 0 || - strncmp(data, "LINK", 4) == 0 || - strncmp(data, "UNLINK", 6) == 0 || - strncmp(data, "PATCH", 5) == 0 || - strncmp(data, "WRAPPED", 7) == 0) + if (strncmp(data, "GET", 3) == 0 || + strncmp(data, "POST", 4) == 0 || + strncmp(data, "CONNECT", 7) == 0 || + strncmp(data, "HEAD", 4) == 0 || + strncmp(data, "PUT", 3) == 0 || + strncmp(data, "OPTIONS", 7) == 0 || + strncmp(data, "MOVE", 4) == 0 || + strncmp(data, "COPY", 4) == 0 || strncmp(data, "TRACE", 5) == 0 || strncmp(data, "DELETE", 6) == 0 || strncmp(data, "LINK", 4) == 0 || strncmp(data, "UNLINK", 6) == 0 || strncmp(data, "PATCH", 5) == 0 || strncmp(data, "WRAPPED", 7) == 0) return HTTP_TYPE; return OTHER_TYPE; } @@ -194,7 +187,7 @@ int create_connection6(char *remote_host, int remote_port) /* 读取到的数据全部就绪,将incomplete_data复制到ready_data */ static int8_t copy_data(conn_t * ct) { - dataEncode(ct->incomplete_data, ct->incomplete_data_len); + dataEncode(ct->incomplete_data, ct->incomplete_data_len, sslEncodeCode); if (ct->ready_data) { char *new_data; diff --git a/http_proxy.h b/http_proxy.h index c107b95..d2d71d7 100755 --- a/http_proxy.h +++ b/http_proxy.h @@ -8,10 +8,6 @@ #define HTTP_TYPE 0 #define OTHER_TYPE 1 -extern int remote_port; -extern char remote_host[CACHE_SIZE]; -extern int sslEncodeCode; - typedef struct tcp_connection { char *ready_data, *incomplete_data; int fd, ready_data_len, incomplete_data_len, sent_len, timer; @@ -19,12 +15,14 @@ typedef struct tcp_connection { unsigned reread_data:1, request_type:1, keep_alive:1; } conn_t; +extern int remote_port; +extern char remote_host[CACHE_SIZE]; +extern int sslEncodeCode; extern conn_t cts[MAX_CONNECTION]; extern void tcp_in(conn_t * in, conf * configure); extern void tcp_out(conn_t * out); extern void close_connection(conn_t * conn); - extern char *request_head(conn_t * in, conf * configure); -void dataEncode(char *data, int data_len); +extern void dataEncode(char *data, int data_len, unsigned code); #endif diff --git a/http_request.c b/http_request.c index c4a0da3..484bc83 100755 --- a/http_request.c +++ b/http_request.c @@ -1,5 +1,16 @@ #include "http_request.h" +int8_t copy_new_mem(char *src, int src_len, char **dest) +{ + *dest = (char *)malloc(src_len + 1); + if (*dest == NULL) + return 1; + memcpy(*dest, src, src_len); + *((*dest) + src_len) = '\0'; + + return 0; +} + // 字符串替换 char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len) { @@ -140,20 +151,26 @@ char *splice_head(char *head, const char *character, char *string) char *delete_head(char *head, const char *character, int string) { int head_len = strlen(head); - char *_p1 = strstr(head, character); + char *_p1, *_p2; + _p1 = _p2 = NULL; + char temporary[head_len]; + memset(temporary, 0, head_len); + + _p1 = strstr(head, character); if (_p1 == NULL) { return head; } - char *_p2 = strchr(_p1, string); + + _p2 = strchr(_p1, string); if (_p2 == NULL) { return head; } - char temporary[head_len]; - memset(temporary, 0, head_len); - memcpy(temporary, head, (head_len - strlen(_p1) - 1)); + + memcpy(temporary, head, _p1 - head - 1); strcat(temporary, _p2); memset(head, 0, strlen(head)); - return memcpy(head, temporary, head_len); + //printf("%s\n", temporary); + return memcpy(head, temporary, strlen(temporary)); } int extract_host(char *header, char *host, char *port) @@ -197,8 +214,7 @@ int extract_host(char *header, char *host, char *port) return -1; } - char *p2 = strchr(p + 5, ':'); // 5是指'Host:'的长度 - + char *p2 = strchr(p + 5, ':'); // 5是指'Host:'的长度 int h_len = (int)(p1 - p - 6); char s_host[h_len]; strncpy(s_host, p + 6, p1 - p - 6); @@ -208,7 +224,7 @@ int extract_host(char *header, char *host, char *port) if (p3) p4 = strchr(p3 + 1, ':'); - if (p4 != NULL) { // IPV6 + if (p4 != NULL) { // IPV6 char *p5 = NULL; char *p6 = NULL; p5 = strchr(header, ' '); @@ -219,14 +235,14 @@ int extract_host(char *header, char *host, char *port) memset(url, 0, p6 - p5 - 1); strncpy(url, p5 + 1, p6 - p5 - 1); url[p6 - p5 - 1] = '\0'; - - if (strstr(url, "http") != NULL) { // 去除 'http://' + + if (strstr(url, "http") != NULL) { // 去除 'http://' memcpy(url, url + 7, strlen(url) - 7); url[strlen(url) - 7] = '\0'; char *p7 = strchr(url, '/'); - if (p7) // 去除 uri + if (p7) // 去除 uri url[p7 - url] = '\0'; - + char *p8 = strchr(url, ']'); if (p8) { strcpy(port, p8 + 2); @@ -238,33 +254,36 @@ int extract_host(char *header, char *host, char *port) } } return 0; - } else { // HTTP头为不规范的url时处理Host, 主要Proxifier转发url为'/'时 + } else { // HTTP头为不规范的url时处理Host, 主要Proxifier转发url为'/'时 //printf("s_host: %s\n", s_host); char *_p1 = strchr(s_host, '['); - char *_p2 = strchr(_p1+1, ']'); + char *_p2 = strchr(_p1 + 1, ']'); if (_p1 && _p2) { - memcpy(host, _p1+1, _p2 - _p1 -1); + memcpy(host, _p1 + 1, _p2 - _p1 - 1); if (strlen(_p2) < 3) { strcpy(port, "80"); } else { - strcpy(port, _p2+2); + strcpy(port, _p2 + 2); } - + } return 0; } - - return -1; } if (p2 && p2 < p1) { memcpy(port, p2 + 1, (int)(p1 - p2 - 1)); - memcpy(host, p + 5 + 1, (int)(p2 - p - 5 - 1)); + memcpy(host, p + 5 + 1, (int)(p2 - p - 5 - 1 - 1)); } else { - memcpy(host, p + 5 + 1, (int)(p1 - p - 5 - 1 - 1)); - memcpy(port, "80", 2); + if (0 < (int)(p1 - p - 5 - 1 - 1)) { + memcpy(host, p + 5 + 1, (p1 - p - 5 - 1 - 1)); + memcpy(port, "80", 2); + } else { + memcpy(host, p + 5 + 1, (strlen(p) - strlen(p1) - 6)); + memcpy(port, "80", 2); + } } return 0; @@ -277,12 +296,20 @@ char *get_http_path(char *url, char *path) { char *_p0; _p0 = NULL; - if (url) { - _p0 = strstr(url + 7, "/"); - if (_p0) - return memcpy(path, _p0, (int)strlen(_p0)); - else - memcpy(path, "/", 1); // 如果没有资源路径就默认"/" + int url_len; + url_len = 0; + url_len = strlen(url); + + if (url_len > 7) { + if (url) { + _p0 = strstr(url + 7, "/"); + if (_p0) + return memcpy(path, _p0, (int)strlen(_p0)); + else + memcpy(path, "/", 1); // 如果没有资源路径就默认"/" + } + } else { + memcpy(path, "/", 1); } return NULL; @@ -290,12 +317,12 @@ char *get_http_path(char *url, char *path) void free_http_request(struct http_request *http_request) { - if (http_request->M) - free(http_request->M); + if (http_request->method) + free(http_request->method); if (http_request->U) free(http_request->U); - if (http_request->V) - free(http_request->V); + if (http_request->version) + free(http_request->version); if (http_request->host) free(http_request->host); if (http_request->port) @@ -308,58 +335,56 @@ void free_http_request(struct http_request *http_request) free(http_request->uri); } -void get_http_host_port_len(char *head, int *host_len, int *port_len) { +void get_http_host_port_len(char *head, int *host_len, int *port_len) +{ *host_len = 0; *port_len = 0; - char *_p1 = strstr(head, "Host"); // 判断Host行 - if (_p1) { // 为真时 + char *_p1 = strstr(head, "Host"); // 判断Host行 + if (_p1) { // 为真时 char *_p2 = strstr(_p1, "\n"); *host_len = (int)(_p2 - _p1); - - char host[*host_len+1]; + + char host[*host_len + 1]; memcpy(host, _p1, *host_len); host[*host_len] = '\0'; - + char *_p3 = strrchr(host, ':'); if (_p3) { - *port_len = strlen(_p3+1); + *port_len = strlen(_p3 + 1); } else { *port_len = *host_len; } - } else { // 为假时 + } else { // 为假时 char *_p1 = strstr(head, "host"); if (_p1) { char *_p2 = strstr(_p1, "\n"); *host_len = (int)(_p2 - _p1); - - char host[*host_len+1]; + + char host[*host_len + 1]; memcpy(host, _p1, *host_len); host[*host_len] = '\0'; - + char *_p3 = strrchr(host, ':'); if (_p3) { - *port_len = strlen(_p3+1); + *port_len = strlen(_p3 + 1); } else { *port_len = *host_len; } - } else { // 未找到时使用HTTP_HEAD_CACHE_SIZE大小 + } else { // 未找到时使用HTTP_HEAD_CACHE_SIZE大小 *host_len = HTTP_HEAD_CACHE_SIZE; *port_len = HTTP_HEAD_CACHE_SIZE; } } - return ; + return; } void parse_request_head(char *http_request_line, struct http_request *http_request) { - char *p; - char *head; + char *p, *head, *m, *u; size_t head_len; - char *m, *u; - int host_len = 0; - int port_len = 0; - int uri_len = 0; + int host_len, port_len, uri_len; + host_len = port_len = uri_len = 0; p = strstr(http_request_line, "\r\n"); // 查找"\r\n" if (p == NULL) { @@ -373,73 +398,71 @@ void parse_request_head(char *http_request_line, struct http_request *http_reque memset(head, 0, head_len * 2); memcpy(head, http_request_line, head_len); - http_request->M = (char *)malloc(sizeof(char) * 7); + http_request->method = (char *)malloc(sizeof(char) * 7); http_request->U = (char *)malloc(sizeof(char) * HTTP_HEAD_CACHE_SIZE); - http_request->V = (char *)malloc(10); - if (http_request->M == NULL) { + http_request->version = (char *)malloc(10); + if (http_request->method == NULL) { perror("malloc"); } if (http_request->U == NULL) { perror("malloc"); } - if (http_request->V == NULL) { + if (http_request->version == NULL) { perror("malloc"); } - memset(http_request->M, 0, 7); + memset(http_request->method, 0, 7); memset(http_request->U, 0, HTTP_HEAD_CACHE_SIZE); - memset(http_request->V, 0, 10); + memset(http_request->version, 0, 10); m = strchr(head, ' '); - http_request->M_len = strlen(head) - strlen(m); - //http_request->M_len = m - head; - memcpy(http_request->M, head, http_request->M_len); + http_request->method_len = strlen(head) - strlen(m); + memcpy(http_request->method, head, http_request->method_len); u = strchr(m + 1, ' '); http_request->U_len = strlen(m + 1) - strlen(u); - //http_request->U_len = u - m -1; memcpy(http_request->U, m + 1, http_request->U_len); - memcpy(http_request->V, u + 1, 8); - http_request->V_len = 8; + memcpy(http_request->version, u + 1, 8); + http_request->version_len = 8; http_request->U_len = (int)strlen(http_request->U); - + // 获取Host、Port长度 get_http_host_port_len(http_request_line, &host_len, &port_len); - + // URI LENGTH char *_p0 = strstr(http_request->U, "http://"); - if (_p0) { // 标准头 + if (_p0) { // 标准头 char *_p1 = strchr(http_request->U + 7, '/'); if (_p1) { uri_len = (int)strlen(_p1); } - } else { // 非标准头 + } else { // 非标准头 char *_p1 = strchr(http_request->U, '/'); if (_p1) { uri_len = (int)strlen(_p1); } else { - uri_len = 1; // 没有uri时 + uri_len = 1; // 没有uri时 } } - http_request->host = (char *)malloc(sizeof(char) * host_len+1); + http_request->host = (char *)malloc(sizeof(char) * host_len + 1); if (http_request->host == NULL) perror("malloc"); - http_request->port = (char *)malloc(sizeof(char) * port_len+1); + http_request->port = (char *)malloc(sizeof(char) * port_len + 1); if (http_request->port == NULL) perror("malloc"); - http_request->url = (char *)malloc(sizeof(char) * http_request->U_len+1); + http_request->url = (char *)malloc(sizeof(char) * http_request->U_len + 1); if (http_request->url == NULL) perror("malloc"); - http_request->uri = (char *)malloc(sizeof(char) * uri_len+1); + http_request->uri = (char *)malloc(sizeof(char) * uri_len + 1); if (http_request->uri == NULL) perror("malloc"); http_request->H = (char *)malloc(sizeof(char) * host_len + port_len + 1); if (http_request->H == NULL) perror("malloc"); - memset(http_request->host, 0, host_len+1); - memset(http_request->port, 0, port_len+1); - memset(http_request->url, 0, http_request->U_len+1); - memset(http_request->uri, 0, uri_len+1); + memset(http_request->host, 0, host_len + 1); + memset(http_request->port, 0, port_len + 1); + memset(http_request->url, 0, http_request->U_len + 1); + memset(http_request->uri, 0, uri_len + 1); memset(http_request->H, 0, host_len + port_len + 1); if (extract_host(http_request_line, http_request->host, http_request->port) == -1) @@ -505,11 +528,11 @@ char *request_head(conn_t * in, conf * configure) incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\t", 2, "\t", 1); incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\r", 2, "\r", 1); incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\n", 2, "\n", 1); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[M]", 3, http_request->M, http_request->M_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[method]", 8, http_request->M, http_request->M_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[M]", 3, http_request->method, http_request->method_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[method]", 8, http_request->method, http_request->method_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[U]", 3, http_request->U, http_request->U_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[V]", 3, http_request->V, http_request->V_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[version]", 9, http_request->V, http_request->V_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[V]", 3, http_request->version, http_request->version_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[version]", 9, http_request->version, http_request->version_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[host]", 6, http_request->host, http_request->host_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, http_request->port, http_request->port_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len); @@ -520,25 +543,16 @@ char *request_head(conn_t * in, conf * configure) incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[host]", 6, http_request->host, http_request->host_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, http_request->port, http_request->port_len); - incomplete_head_len = strlen(incomplete_head); // 更新HTTPS HEADER长度 + incomplete_head_len = strlen(incomplete_head); // 更新HTTPS HEADER长度 //printf("%s", incomplete_head); // 打印HTTPS HEADER - - char *new_incomplete_data; - new_incomplete_data = (char *)realloc(in->incomplete_data, incomplete_head_len + 1); // 更新incomplete_data堆内存 - if (new_incomplete_data == NULL) { - perror("realloc"); - return NULL; - } - in->incomplete_data = new_incomplete_data; - memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空incomplete_data数据 - strcpy(in->incomplete_data, incomplete_head); // 更新incomplete_data数据 - in->incomplete_data_len = strlen(in->incomplete_data); // 更新incomplete_data长度 - free(incomplete_head); // 释放incomplete_head内存 - + memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空incomplete_data数据 + strcpy(in->incomplete_data, incomplete_head); // 更新incomplete_data数据 + in->incomplete_data_len = strlen(in->incomplete_data); // 更新incomplete_data长度 + free(incomplete_head); // 释放incomplete_head内存 } - - if (strncmp(in->incomplete_data, "GET", 3) == 0 || strncmp(in->incomplete_data, "POST", 4) == 0) { + + if (strncmp(in->incomplete_data, "GET", 3) == 0 || strncmp(in->incomplete_data, "POST", 4) == 0) { char *incomplete_head; int incomplete_head_len; char http_del_copy[configure->http_del_len]; @@ -575,11 +589,11 @@ char *request_head(conn_t * in, conf * configure) incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\t", 2, "\t", 1); incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\r", 2, "\r", 1); incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\n", 2, "\n", 1); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[M]", 3, http_request->M, http_request->M_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[method]", 8, http_request->M, http_request->M_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[M]", 3, http_request->method, http_request->method_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[method]", 8, http_request->method, http_request->method_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[U]", 3, http_request->U, http_request->U_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[V]", 3, http_request->V, http_request->V_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[version]", 9, http_request->V, http_request->V_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[V]", 3, http_request->version, http_request->version_len); + incomplete_head = replace(incomplete_head, &incomplete_head_len, "[version]", 9, http_request->version, http_request->version_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[url]", 5, http_request->url, http_request->url_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[uri]", 5, http_request->uri, http_request->uri_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[host]", 6, http_request->host, http_request->host_len); @@ -592,21 +606,13 @@ char *request_head(conn_t * in, conf * configure) incomplete_head = replace(incomplete_head, &incomplete_head_len, "[host]", 6, http_request->host, http_request->host_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, http_request->port, http_request->port_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len); - incomplete_head_len = strlen(incomplete_head); // 更新HTTP HEADER长度 + incomplete_head_len = strlen(incomplete_head); // 更新HTTP HEADER长度 //printf("%s", incomplete_head); // 打印HTTP HEADER - - char *new_incomplete_data; - new_incomplete_data = (char *)realloc(in->incomplete_data, incomplete_head_len + 1); // 更新incomplete_data堆内存 - if (new_incomplete_data == NULL) { - perror("realloc"); - return NULL; - } - in->incomplete_data = new_incomplete_data; - memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空incomplete_data数据 - memmove(in->incomplete_data, incomplete_head, incomplete_head_len + 1); // 更新incomplete_data数据 - in->incomplete_data_len = strlen(in->incomplete_data); // 更新incomplete_data长度 - free(incomplete_head); // 释放incomplete_head内存 + memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空incomplete_data数据 + memmove(in->incomplete_data, incomplete_head, incomplete_head_len + 1); // 更新incomplete_data数据 + in->incomplete_data_len = strlen(in->incomplete_data); // 更新incomplete_data长度 + free(incomplete_head); // 释放incomplete_head内存 } free_http_request(http_request); diff --git a/http_request.h b/http_request.h index e540634..3c62c44 100755 --- a/http_request.h +++ b/http_request.h @@ -9,17 +9,18 @@ #include "conf.h" struct http_request { - char *M, *U, *V; + char *method, *U, *version; char *host, *port, *H; char *url, *uri; - int M_len, U_len, V_len; + int method_len, U_len, version_len; int host_len, port_len, H_len; int url_len, uri_len; }; void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len); +extern char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len); char *request_head(conn_t * in, conf * configure); +extern int8_t copy_new_mem(char *src, int src_len, char **dest); #endif diff --git a/httpdns.c b/httpdns.c index ff21103..ab81a61 100755 --- a/httpdns.c +++ b/httpdns.c @@ -1,130 +1,184 @@ +#include +#include #include "httpdns.h" #include "http_request.h" -char http_rsp[HTTP_RSP_SIZE + 1]; -struct sockaddr_in dst_addr; -char *host_value; -int dnsListenFd = -1, dns_efd; -unsigned int host_value_len; -static int8_t encodeCode = 0; +#define DNS_MAX_CONCURRENT 512 +#define DNS_REQUEST_MAX_SIZE 512+2 //2是TCPDNS头部用于指定dns的长度 +#define HTTP_RSP_SIZE 2048 +/* + 缓存结构: (dns查询请求长度-2)(2字节) + dns原查询请求(删除2字节的dnsID) + dns回应长度(2字节) + dns回应 +*/ +struct dns_cache { + char *dns_cache; + struct dns_cache *next; +}; +typedef struct dns_connection { + char dns_req[DNS_REQUEST_MAX_SIZE + 1]; + struct sockaddr_in src_addr; + char *out_request; + char *host; + int out_request_len, fd, timer; + /* + sent_CONNECT_len: + 在使用SSL代理的情况下,与httpDNS的CONNECT请求长度对比 + 小于表示需要发送CONNECT请求,并且还没有发送完成 + 等于表示已经完成CONNECT连接 + 大于表示已发送完成CONNECT连接,但是没有读取CONNECT的回应包 + */ + int sent_CONNECT_len; + uint16_t dns_req_len; + char query_type; + unsigned host_len:7; +} dns_t; + +static dns_t dns_list[DNS_MAX_CONCURRENT]; +static struct epoll_event dns_evs[DNS_MAX_CONCURRENT + 1], dns_ev; +struct httpdns httpdns; +static int dns_efd; /* 缓存变量 */ FILE *cfp = NULL; -char *cachePath = NULL; -struct dns_cache *cache, *cache_temp; -socklen_t addr_len = sizeof(dst_addr); -unsigned int cache_using, cacheLimit; -dns_t dns_list[DNS_MAX_CONNECTION]; -struct epoll_event evs[DNS_MAX_CONNECTION + 1], event; +static struct dns_cache *cache = NULL; +static int cache_using; +//子进程先写入缓存,再到父进程写入,否则可能导致缓存文件错乱 +pid_t child_pid = 0; -int read_cache_file() +/* 读取缓存文件 */ +int8_t read_cache_file() { - char *buff, *answer, *question; + char *buff, *cache_ptr; + struct dns_cache *cache_temp; long file_size; - int fn; + int len; - fn = 0; - cache = cache_temp = NULL; + cache_temp = NULL; cache_using = 0; - if ((cfp = fopen(cachePath, "rb+")) == NULL) { - //保持文件打开状态,防止切换uid后权限不足导致无法写入文件 - cfp = fopen(cachePath, "wb"); - return cfp == NULL ? 1 : 0; + if ((cfp = fopen(httpdns.cachePath, "r+")) == NULL) { + //创建文件并设置权限 + if ((cfp = fopen(httpdns.cachePath, "w")) != NULL) { + chmod(httpdns.cachePath, S_IWOTH | S_IROTH | S_IWGRP | S_IRGRP | S_IWUSR | S_IRUSR); + fclose(cfp); + return 0; + } + return 1; } + //读取文件内容 fseek(cfp, 0, SEEK_END); file_size = ftell(cfp); - if ((buff = (char *)alloca(file_size)) == NULL) { - fclose(cfp); + if ((buff = (char *)alloca(file_size)) == NULL) return 1; - } rewind(cfp); - if ((fn = fread(buff, file_size, 1, cfp)) < 0) { - perror("fread"); - } + fread(buff, file_size, 1, cfp); + fclose(cfp); - //读取缓存,一组缓存的内容为[ipDomain\0],其中ip占5字节 - for (answer = buff; answer - buff < file_size; answer = question + cache->question_len + 2) { - cache_temp = (struct dns_cache *)malloc(sizeof(*cache)); + for (cache_ptr = buff; cache_ptr - buff < file_size; cache_ptr += len) { + cache_temp = (struct dns_cache *)malloc(sizeof(struct dns_cache)); if (cache_temp == NULL) return 1; cache_temp->next = cache; cache = cache_temp; cache_using++; - cache->answer = strndup(answer, 5); - question = answer + 5; - cache->question = strdup(question); - if (cache->question == NULL || cache->answer == NULL) + len = *(uint16_t *) cache_ptr + *(uint16_t *) (cache_ptr + *(uint16_t *) cache_ptr + 2) + 4; + copy_new_mem(cache_ptr, len, &cache->dns_cache); + if (cache->dns_cache == NULL) return 1; - cache->question_len = strlen(question) - 1; } /* 删除重复记录 */ struct dns_cache *before, *after; for (; cache_temp; cache_temp = cache_temp->next) { for (before = cache_temp; before && (after = before->next) != NULL; before = before->next) { - if (strcmp(after->question, cache_temp->question) == 0) { + if (*(uint16_t *) after->dns_cache == *(uint16_t *) cache_temp->dns_cache && memcmp(after->dns_cache + 2, cache_temp->dns_cache + 2, *(uint16_t *) after->dns_cache) == 0) { before->next = after->next; - free(after->question); - free(after->answer); + free(after->dns_cache); free(after); cache_using--; } } } - fclose(cfp); - cfp = fopen(cachePath, "wb"); + chmod(httpdns.cachePath, S_IWOTH | S_IROTH | S_IWGRP | S_IRGRP | S_IWUSR | S_IRUSR); return 0; } -void write_dns_cache() +/* 程序结束时将缓存写入文件 */ +static void write_dns_cache(int sig) { + //子进程先写入缓存 + if (child_pid) { + wait(NULL); + cfp = fopen(httpdns.cachePath, "a"); + } else { + cfp = fopen(httpdns.cachePath, "w"); + } while (cache) { - fputs(cache->answer, cfp); - fputs(cache->question, cfp); - fputc('\0', cfp); + fwrite(cache->dns_cache, *(uint16_t *) cache->dns_cache + *(uint16_t *) (cache->dns_cache + *(uint16_t *) cache->dns_cache + 2) + 4, 1, cfp); cache = cache->next; } exit(0); } -char *cache_lookup(char *question, dns_t * dns) +static void dnsProxyStop(dns_t * dns) +{ + epoll_ctl(dns_efd, EPOLL_CTL_DEL, dns->fd, NULL); + close(dns->fd); + if (httpdns.tcpDNS_mode == 0) + free(dns->out_request); + memset(((char *)dns) + DNS_REQUEST_MAX_SIZE + sizeof(struct sockaddr_in), 0, sizeof(dns_t) - DNS_REQUEST_MAX_SIZE + -sizeof(struct sockaddr_in)); + dns->fd = -1; +} + +/* 查询缓存 */ +static uint8_t cache_lookup(dns_t * dns) { struct dns_cache *c; + char *rsp; for (c = cache; c; c = c->next) { - if (strcmp(c->question, question) == 0) { - dns->host_len = c->question_len; - dns->query_type = 1; - return c->answer; + //不匹配dnsID + if (dns->dns_req_len - 2 == *(uint16_t *) c->dns_cache && memcmp(dns->dns_req + 2, c->dns_cache + 2, dns->dns_req_len - 2) == 0) { + rsp = c->dns_cache + *(uint16_t *) c->dns_cache + 2; + *(uint16_t *) (rsp + 2) = *(uint16_t *) dns->dns_req; //设置dns id + sendto(global.dns_listen_fd, rsp + 2, *(uint16_t *) rsp, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in)); + return 0; } } - return NULL; + return 1; } -void cache_record(dns_t * dns) +/* 记录缓存 */ +static void cache_record(char *request, uint16_t request_len, char *response, uint16_t response_len) { - cache_temp = (struct dns_cache *)malloc(sizeof(*cache)); + struct dns_cache *cache_temp; + + cache_temp = (struct dns_cache *)malloc(sizeof(struct dns_cache)); if (cache_temp == NULL) return; - cache_temp->question = strdup(dns->dns_req + 12); - if (cache_temp->question == NULL) { + cache_temp->dns_cache = (char *)malloc(request_len + response_len + 2); + if (cache_temp->dns_cache == NULL) { free(cache_temp); return; } cache_temp->next = cache; cache = cache_temp; - cache->question_len = dns->host_len; - cache->answer = dns->reply; - if (cacheLimit) { + //不缓存dnsid + request += 2; + request_len -= 2; + memcpy(cache_temp->dns_cache, &request_len, 2); + memcpy(cache_temp->dns_cache + 2, request, request_len); + memcpy(cache_temp->dns_cache + request_len + 2, &response_len, 2); + memcpy(cache_temp->dns_cache + request_len + 4, response, response_len); + if (httpdns.cacheLimit) { //到达缓存记录条目限制则释放前一半缓存 - if (cache_using >= cacheLimit) { + if (cache_using >= httpdns.cacheLimit) { struct dns_cache *free_c; int i; - for (i = cache_using = cacheLimit >> 1; i--; cache_temp = cache_temp->next) ; + for (i = cache_using = httpdns.cacheLimit >> 1; i--; cache_temp = cache_temp->next) ; for (free_c = cache_temp->next, cache_temp->next = NULL; free_c; free_c = cache_temp) { cache_temp = free_c->next; + free(free_c->dns_cache); free(free_c); } } @@ -132,100 +186,69 @@ void cache_record(dns_t * dns) } } -int respond_client(dns_t * dns) -{ - int write_len = sendto(dnsListenFd, dns->dns_req, dns->dns_rsp_len, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in)); - if (write_len == dns->dns_rsp_len) { - dns->query_type = 0; - return 0; - } else if (write_len == -1) - return -1; - else { - dns->dns_rsp_len -= write_len; - memcpy(dns->dns_req, dns->dns_req + write_len, dns->dns_rsp_len); - return 1; - } -} - -void respond_clients() -{ - int i; - for (i = 0; i < DNS_MAX_CONNECTION; i++) { - if (dns_list[i].wait_response_client) { - if (respond_client(&dns_list[i]) == 1) - return; - else - dns_list[i].wait_response_client = 0; - } - } - event.events = EPOLLIN; - event.data.fd = dnsListenFd; - epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &event); -} - /* 分析DNS请求 */ -int parse_dns_request(char *dns_req, dns_t * dns) +static int8_t parse_dns_request(char *dns_req, dns_t * dns) { + int len; + dns_req += 13; //跳到域名部分 dns->host_len = strlen(dns_req); - //判断请求类型 - switch ((dns->query_type = *(dns_req + 2 + dns->host_len))) { - //case 28: //查询ipv6地址 - //dns->query_type = 1; //httpDNS不支持查询ipv6,所以改成ipv4 - - case 1: //查询ipv4地址 - dns->host = strdup(dns_req); - if (dns->host == NULL) - return 1; - int len; - for (len = *(--dns_req); dns_req[len + 1] != 0; len += dns_req[len]) { - //防止数组越界 - if (len > dns->host_len) { - free(dns->host); - return 1; - } - dns->host[len++] = '.'; - } - //printf("dns->host: %s\n", dns->host); + dns->query_type = *(dns_req + 2 + dns->host_len); + //tcpdns不需要解析域名 + if (httpdns.tcpDNS_mode == 1) return 0; - - default: - dns->host = NULL; + //httpdns只支持域名查询ipv4 + if (dns->query_type != 1 || (dns->host = strdup(dns_req)) == NULL) return 1; + for (len = *(--dns_req); dns_req[len + 1] != 0; len += dns_req[len]) { + //防止数组越界 + if (len > dns->host_len) { + free(dns->host); + return 1; + } + dns->host[len++] = '.'; } + + return 0; } -/* 建立DNS回应 */ -int build_dns_response(dns_t * dns) +/* 回应dns客户端 */ +static int8_t httpDNS_respond_client(dns_t * dns, char *rspIp) { + static char rsp[DNS_REQUEST_MAX_SIZE + 16]; char *p; + int rsp_len; //18: 查询资源的前(12字节)后(6字节)部分 - dns->dns_rsp_len = 18 + dns->host_len + (dns->reply ? 16 : 0); - if (dns->dns_rsp_len > DATA_SIZE) { + rsp_len = 18 + dns->host_len + (rspIp ? 16 : 0); + //判断是否超出缓冲大小 + if (rsp_len > DNS_REQUEST_MAX_SIZE) { dns->query_type = 0; - return 1; //超出缓冲大小 + return 1; } + /* dns ID */ + memcpy(rsp, dns->dns_req, 2); /* 问题数 */ - dns->dns_req[4] = 0; - dns->dns_req[5] = 1; + rsp[4] = 0; + rsp[5] = 1; /* 资源记录数 */ - dns->dns_req[6] = 0; - dns->dns_req[7] = 0; + rsp[6] = 0; + rsp[7] = 0; /* 授权资源记录数 */ - dns->dns_req[8] = 0; - dns->dns_req[9] = 0; + rsp[8] = 0; + rsp[9] = 0; /* 额外资源记录数 */ - dns->dns_req[10] = 0; - dns->dns_req[11] = 0; + rsp[10] = 0; + rsp[11] = 0; + memcpy(rsp + 12, dns->dns_req + 12, dns->host_len + 6); /* 如果有回应内容(资源记录) */ - if (dns->reply) { - p = dns->dns_req + 18 + dns->host_len; + if (rspIp) { + p = rsp + 18 + dns->host_len; /* 资源记录数+1 */ - dns->dns_req[7]++; + rsp[7]++; /* 成功标志 */ - dns->dns_req[2] = (char)133; - dns->dns_req[3] = (char)128; + rsp[2] = (char)133; + rsp[3] = (char)128; /* 指向主机域名 */ p[0] = (char)192; p[1] = 12; @@ -242,267 +265,341 @@ int build_dns_response(dns_t * dns) p[9] = 16; /* 回应长度 */ p[10] = 0; - p[11] = 4; //reply中包含回应长度 - strcpy(p + 12, dns->reply); + p[11] = 4; + memcpy(p + 12, rspIp, 4); } else { /* 失败标志 */ - dns->dns_req[2] = (char)129; - dns->dns_req[3] = (char)130; - } - if (respond_client(dns) == 1) { - dns->wait_response_client = 1; - event.events = EPOLLIN | EPOLLOUT; - event.data.fd = dnsListenFd; - epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &event); + rsp[2] = (char)129; + rsp[3] = (char)130; } + //因为UDP是无连接协议,所以不做返回值判断 + sendto(global.dns_listen_fd, rsp, rsp_len, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in)); + dns->query_type = 0; //表示结构体空闲 + if (cfp && rspIp) + cache_record(dns->dns_req, dns->dns_req_len, rsp, rsp_len); return 0; } -void http_out(dns_t * out) +void dns_timeout_check() +{ + int i; + + for (i = 0; i < DNS_MAX_CONCURRENT; i++) { + if (dns_list[i].fd > -1) { + if (dns_list[i].timer >= global.timeout_m) { + dnsProxyStop(dns_list + i); + } else { + dns_list[i].timer++; + } + } + } +} + +static void http_out(dns_t * out) { int write_len; - //puts("writing"); - //printf("%s\n", out->http_request); - write_len = write(out->fd, out->http_request, out->http_request_len); - if (write_len == out->http_request_len) { - //puts("write success"); - free(out->http_request); - event.events = EPOLLIN | EPOLLET; - event.data.ptr = out; - epoll_ctl(dns_efd, EPOLL_CTL_MOD, out->fd, &event); + out->timer = 0; + if (httpdns.connect_request && out->sent_CONNECT_len < httpdns.connect_request_len) { + write_len = write(out->fd, httpdns.connect_request + out->sent_CONNECT_len, httpdns.connect_request_len - out->sent_CONNECT_len); + if (write_len == -1) { + dnsProxyStop(out); + } else { + out->sent_CONNECT_len += write_len; + if (out->sent_CONNECT_len == httpdns.connect_request_len) { + out->sent_CONNECT_len++; //表示已完全发送CONNECT请求,等待HTTP回应 + dns_ev.events = EPOLLIN | EPOLLET; + dns_ev.data.ptr = out; + epoll_ctl(dns_efd, EPOLL_CTL_MOD, out->fd, &dns_ev); + } + } + return; + } + + write_len = write(out->fd, out->out_request, out->out_request_len); + if (write_len == out->out_request_len) { + dns_ev.events = EPOLLIN | EPOLLET; + dns_ev.data.ptr = out; + epoll_ctl(dns_efd, EPOLL_CTL_MOD, out->fd, &dns_ev); } else if (write_len > 0) { - //puts("write a little"); - out->http_request_len -= write_len; - memcpy(out->http_request, out->http_request + write_len, out->http_request_len); + out->out_request_len -= write_len; + memmove(out->out_request, out->out_request + write_len, out->out_request_len); } else { - //puts("write error"); - free(out->http_request); epoll_ctl(dns_efd, EPOLL_CTL_DEL, out->fd, NULL); close(out->fd); out->query_type = 0; } } -void http_in(dns_t * in) +static void handle_httpDNS_rsp(dns_t * dns, char *rsp, int rsp_len) { - char *ip_ptr, *p; - int len, i; + char *ip_ptr, *p, ip[4]; + int i; - len = read(in->fd, http_rsp, HTTP_RSP_SIZE); - if (len <= 0) { - in->query_type = 0; - epoll_ctl(dns_efd, EPOLL_CTL_DEL, in->fd, NULL); - close(in->fd); - return; - } - if (encodeCode) - dataEncode(http_rsp, len); - http_rsp[len] = '\0'; - //printf("[%s]\n", http_rsp); - p = strstr(http_rsp, "\n\r"); + p = strstr(rsp, "\n\r"); if (p) { - //部分代理服务器使用长连接,第二次读取数据才读到域名的IP - if (p + 3 - http_rsp >= len) - return; p += 3; - } else - p = http_rsp; - epoll_ctl(dns_efd, EPOLL_CTL_DEL, in->fd, NULL); - close(in->fd); - in->reply = (char *)malloc(5); - if (in->reply == NULL) - goto error; + rsp_len -= p - rsp; + //部分代理服务器使用长连接,第二次读取数据才读到域名的IP + if (rsp_len <= 0) + return; + rsp = p; + } + if (httpdns.encodeCode) + dataEncode(rsp, rsp_len, httpdns.encodeCode); do { - if (*p == '\n') - p++; + if (*rsp == '\n') + rsp++; /* 匹配IP */ - if (*p > 57 || *p < 49) - continue; - for (i = 0, ip_ptr = p, p = strchr(ip_ptr, '.');; ip_ptr = p + 1, p = strchr(ip_ptr, '.')) { + while ((*rsp > 57 || *rsp < 49) && *rsp != '\0') + rsp++; + for (i = 0, ip_ptr = rsp, rsp = strchr(ip_ptr, '.');; ip_ptr = rsp + 1, rsp = strchr(ip_ptr, '.')) { if (i < 3) { - if (p == NULL) - goto error; + if (rsp == NULL) { + httpDNS_respond_client(dns, NULL); + return; + } //查找下一行 - if (p - ip_ptr > 3) + if (rsp - ip_ptr > 3) break; - in->reply[i++] = atoi(ip_ptr); + ip[i++] = atoi(ip_ptr); } else { - in->reply[3] = atoi(ip_ptr); - in->reply[4] = 0; - build_dns_response(in); - cfp ? cache_record(in) : free(in->reply); + ip[3] = atoi(ip_ptr); + httpDNS_respond_client(dns, ip); return; } } - } while ((p = strchr(p, '\n')) != NULL); - -error: - free(in->reply); - in->reply = NULL; - if (build_dns_response(in) == 1) - in->query_type = 0; + } while ((rsp = strchr(rsp, '\n')) != NULL); } -void new_client(conf * configure) +static void handle_tcpDNS_rsp(dns_t * dns, char *rsp, int rsp_len) +{ + /* 转换为UDPdns请求(为什么不做长度判断?因为懒) */ + rsp += 2; + rsp_len -= 2; + //回应客户端 + sendto(global.dns_listen_fd, rsp, rsp_len, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in)); + if (cfp && (unsigned char)rsp[3] == 128) { + //如果使用编码,则需要还原dns请求 + if (httpdns.httpsProxy_encodeCode) + dataEncode(dns->dns_req + 2 /* 换成TCPDNS请求时原本请求后移动了2字节 */ , dns->dns_req_len, httpdns.httpsProxy_encodeCode); + cache_record(dns->dns_req + 2, dns->dns_req_len, rsp, (uint16_t) rsp_len); + } +} + +static void http_in(dns_t * in) +{ + static char http_rsp[HTTP_RSP_SIZE + 1]; + int len; + + in->timer = 0; + if (httpdns.connect_request && in->sent_CONNECT_len > httpdns.connect_request_len) { + in->sent_CONNECT_len--; + do { + len = read(in->fd, http_rsp, HTTP_RSP_SIZE); + //没有数据读取,CONNECT代理连接完成 + if (len < 0 && errno == EAGAIN) + break; + if (len <= 0) { + dnsProxyStop(in); + return; + } + } while (len == HTTP_RSP_SIZE); + dns_ev.events = EPOLLIN | EPOLLOUT | EPOLLET; + dns_ev.data.ptr = in; + epoll_ctl(dns_efd, EPOLL_CTL_MOD, in->fd, &dns_ev); + return; + } + len = read(in->fd, http_rsp, HTTP_RSP_SIZE); + if (len <= 0) { + if (len == 0 || errno != EAGAIN) + dnsProxyStop(in); + return; + } + http_rsp[len] = '\0'; + if (httpdns.httpsProxy_encodeCode) + dataEncode(http_rsp, len, httpdns.httpsProxy_encodeCode); + if (httpdns.tcpDNS_mode == 1) { + handle_tcpDNS_rsp(in, http_rsp, len); + } else { + handle_httpDNS_rsp(in, http_rsp, len); + } + dnsProxyStop(in); +} + +static int8_t create_outRequest(dns_t * dns) +{ + if (parse_dns_request(dns->dns_req, dns) != 0) { + dns->out_request = NULL; + return 1; + } + if (httpdns.tcpDNS_mode == 1) { + memmove(dns->dns_req + 2, dns->dns_req, dns->dns_req_len); + dns->dns_req[0] = *((char *)(&dns->dns_req_len) + 1); + dns->dns_req[1] = *((char *)&dns->dns_req_len); + dns->out_request = dns->dns_req; + dns->out_request_len = dns->dns_req_len + 2; + dns->host = NULL; + /* + //调试用 + int i; + printf("("); + for (i=0;iout_request_len;i++) + printf("%u ", dns->out_request[i]); + puts(")"); + */ + } else { + if (httpdns.encodeCode) + dataEncode(dns->host, dns->host_len, httpdns.encodeCode); + dns->out_request_len = httpdns.http_req_len; + copy_new_mem(httpdns.http_req, httpdns.http_req_len, &dns->out_request); + dns->out_request = replace(dns->out_request, &dns->out_request_len, "[D]", 3, dns->host, dns->host_len); + free(dns->host); + if (dns->out_request == NULL) + return 1; + } + if (httpdns.httpsProxy_encodeCode) + dataEncode(dns->out_request, dns->out_request_len, httpdns.httpsProxy_encodeCode); + dns->sent_CONNECT_len = 0; + + return 0; +} + +/* 连接到dns服务器 */ +static int connectToDnsServer(dns_t * dns) +{ + dns->fd = socket(AF_INET, SOCK_STREAM, 0); + if (dns->fd < 0) + return 1; + dns->timer = 0; //超时计时器设为0 + fcntl(dns->fd, F_SETFL, O_NONBLOCK); + dns_ev.events = EPOLLERR | EPOLLOUT | EPOLLET; + dns_ev.data.ptr = dns; + if (epoll_ctl(dns_efd, EPOLL_CTL_ADD, dns->fd, &dns_ev) != 0) { + close(dns->fd); + return 1; + } + if (connect(dns->fd, (struct sockaddr *)&httpdns.dst, sizeof(httpdns.dst)) != 0 && errno != EINPROGRESS) { + epoll_ctl(dns_efd, EPOLL_CTL_DEL, dns->fd, NULL); + close(dns->fd); + return 1; + } + + return 0; +} + +static void new_client() { dns_t *dns; + socklen_t addr_len = sizeof(struct sockaddr_in); int i, len; - for (i = 0; i < DNS_MAX_CONNECTION; i++) - if (dns_list[i].query_type == 0) + for (i = 0; i < DNS_MAX_CONCURRENT; i++) { + if (dns_list[i].query_type == 0) { + dns = &dns_list[i]; break; - if (i == DNS_MAX_CONNECTION) + } + } + if (i == DNS_MAX_CONCURRENT) return; - dns = &dns_list[i]; - len = recvfrom(dnsListenFd, &dns->dns_req, DATA_SIZE, 0, (struct sockaddr *)&dns->src_addr, &addr_len); - //printf("addr: [%s:%d]\n", inet_ntoa(dns->src_addr.sin_addr), ntohs(dns->src_addr.sin_port)); + len = recvfrom(global.dns_listen_fd, dns->dns_req, DNS_REQUEST_MAX_SIZE - 2, 0, (struct sockaddr *)&dns->src_addr, &addr_len); //dns请求必须大于18 if (len <= 18) return; + dns->dns_req_len = (uint16_t) len; /* 查询缓存 */ - if (cachePath) { - dns->reply = cache_lookup(dns->dns_req + 12, dns); - if (dns->reply != NULL) { - if (build_dns_response(dns) != 0) - dns->query_type = 0; - return; - } - } - if (parse_dns_request(dns->dns_req, dns) != 0) { - if (dns->host == NULL) { - if (build_dns_response(dns) != 0) - dns->query_type = 0; - } else - dns->query_type = 0; + if (cfp && cache_lookup(dns) == 0) return; + if (create_outRequest(dns) != 0 || connectToDnsServer(dns) != 0) { + if (dns->out_request != dns->dns_req) + free(dns->out_request); + httpDNS_respond_client(dns, NULL); } - dns->fd = socket(AF_INET, SOCK_STREAM, 0); - if (dns->fd < 0) { - dns->query_type = 0; - return; - } - fcntl(dns->fd, F_SETFL, O_NONBLOCK); - if (connect(dns->fd, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) != 0 && errno != EINPROGRESS) { - close(dns->fd); - dns->query_type = 0; - return; - } - if (encodeCode) - dataEncode(dns->host, strlen(dns->host)); - /* "GET /d?dn=" + dns->host + " HTTP/1.0\r\nHost: " + host_value + "\r\n\r\n" */ - dns->http_request = (char *)malloc(10 + strlen(dns->host) + 17 + host_value_len + 4 + 1); - free(dns->host); - if (dns->http_request == NULL) { - close(dns->fd); - dns->query_type = 0; - return; - } - //dns->http_request_len = sprintf(dns->http_request, "GET /d?dn=%s HTTP/1.0\r\nHost: %s\r\n\r\n", dns->host, host_value); - - strcpy(dns->http_request, configure->http_req); - dns->http_request_len = strlen(dns->http_request); - int http_request_len = (int)dns->http_request_len; - dns->http_request = replace(dns->http_request, &http_request_len, "[M]", 3, "GET", 3); - dns->host_len = strlen(dns->host); - dns->http_request = replace(dns->http_request, &http_request_len, "[D]", 3, dns->host, dns->host_len); - dns->http_request = replace(dns->http_request, &http_request_len, "[V]", 3, "HTTP/1.0", 8); - dns->http_request = replace(dns->http_request, &http_request_len, "\\r", 2, "\r", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\n", 2, "\n", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\b", 2, "\b", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\v", 2, "\v", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\f", 2, "\f", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\a", 2, "\a", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\t", 2, "\t", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\r", 2, "\r", 1); - dns->http_request = replace(dns->http_request, &http_request_len, "\\n", 2, "\n", 1); - dns->http_request_len = strlen(dns->http_request); - //printf("%s\n", dns->http_request); - - event.events = EPOLLOUT | EPOLLERR | EPOLLET; - event.data.ptr = dns; - epoll_ctl(dns_efd, EPOLL_CTL_ADD, dns->fd, &event); } -void *httpdns_loop(void *p) +static void httpRequest_init() { - conf *configure = (conf *) p; - int n; + char dest[22]; + uint16_t port; - fcntl(dnsListenFd, F_SETFL, O_NONBLOCK); - dns_efd = epoll_create(DNS_MAX_CONNECTION + 1); + port = ntohs(httpdns.dst.sin_port); + sprintf(dest, "%s:%u", inet_ntoa(httpdns.dst.sin_addr), port); + + //如果设置http_req = "";则不创建请求头 + if (httpdns.http_req_len > 0) { + httpdns.http_req_len = strlen(httpdns.http_req); + httpdns.http_req_len += 2; + httpdns.http_req = (char *)realloc(httpdns.http_req, httpdns.http_req_len + 1); + if (httpdns.http_req == NULL) + printf("out of memory.\n"); + strcat(httpdns.http_req, "\r\n"); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[V]", 3, "HTTP/1.1", 8); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[H]", 3, dest, strlen(dest)); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "\\0", 2, "\0", 1); + if (httpdns.tcpDNS_mode == 0) { + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[M]", 3, "GET", 3); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[url]", 5, "/d?dn=[D]", 9); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[U]", 3, "/d?dn=[D]", 9); + if (httpdns.http_req == NULL) + printf("out of memory.\n"); + } else { + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[M]", 3, "CONNECT", 7); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[url]", 5, "/", 1); + httpdns.http_req = replace(httpdns.http_req, &httpdns.http_req_len, "[U]", 3, "/", 1); + if (httpdns.http_req == NULL) + printf("out of memory.\n"); + httpdns.connect_request = httpdns.http_req; + httpdns.connect_request_len = httpdns.http_req_len; + httpdns.http_req = NULL; + } + } +} + +void dns_init() +{ + httpRequest_init(); + dns_efd = epoll_create(DNS_MAX_CONCURRENT + 1); if (dns_efd < 0) { perror("epoll_create"); - return NULL; + exit(1); } - event.data.fd = dnsListenFd; - event.events = EPOLLIN; - epoll_ctl(dns_efd, EPOLL_CTL_ADD, dnsListenFd, &event); + fcntl(global.dns_listen_fd, F_SETFL, O_NONBLOCK); + dns_ev.data.fd = global.dns_listen_fd; + dns_ev.events = EPOLLIN; + epoll_ctl(dns_efd, EPOLL_CTL_ADD, global.dns_listen_fd, &dns_ev); memset(dns_list, 0, sizeof(dns_list)); + //程序关闭时写入dns缓存 + if (cfp) { + signal(SIGTERM, write_dns_cache); + signal(SIGHUP, write_dns_cache); + signal(SIGINT, write_dns_cache); + signal(SIGABRT, write_dns_cache); + signal(SIGILL, write_dns_cache); + signal(SIGSEGV, write_dns_cache); + } +} + +void *dns_loop(void *nullPtr) +{ + int n; while (1) { - n = epoll_wait(dns_efd, evs, DNS_MAX_CONNECTION + 1, -1); + n = epoll_wait(dns_efd, dns_evs, DNS_MAX_CONCURRENT + 1, -1); + while (n-- > 0) { - if (evs[n].data.fd == dnsListenFd) { - if (evs[n].events & EPOLLIN) { - new_client(configure); + if (dns_evs[n].data.fd == global.dns_listen_fd) { + new_client(); + } else { + if (dns_evs[n].events & EPOLLIN) { + http_in((dns_t *) dns_evs[n].data.ptr); } - if (evs[n].events & EPOLLOUT) { - respond_clients(); + if (dns_evs[n].events & EPOLLOUT) { + http_out((dns_t *) dns_evs[n].data.ptr); } - } else if (evs[n].events & EPOLLIN) { - http_in(evs[n].data.ptr); - } else if (evs[n].events & EPOLLOUT) { - http_out(evs[n].data.ptr); - } else if (evs[n].events & EPOLLERR) { - dns_t *err = evs[n].data.ptr; - free(err->http_request); - epoll_ctl(dns_efd, EPOLL_CTL_DEL, err->fd, NULL); - close(err->fd); - err->query_type = 0; } } } - return NULL; -} - -int udp_listen(char *ip, int port) -{ - int fd; - struct sockaddr_in addr; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("udp socket"); - exit(1); - } - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(ip); - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - perror("udp bind"); - exit(1); - } - - return fd; -} - -int httpdns_initialize(conf * configure) -{ - char *p; - p = strchr(configure->addr, ':'); - host_value = configure->addr; - *p = '\0'; - //printf("udp: %s %d %d\n", configure->addr, configure->dns_listen, atoi(p+1)); - - dnsListenFd = udp_listen("0.0.0.0", configure->dns_listen); - dst_addr.sin_addr.s_addr = inet_addr(configure->addr); - dst_addr.sin_family = AF_INET; - dst_addr.sin_port = htons(atoi(p + 1)); - - signal(SIGPIPE, SIG_IGN); - signal(SIGTERM, write_dns_cache); - host_value_len = strlen(host_value); - return 0; + return NULL; //消除编译警告 } diff --git a/httpdns.h b/httpdns.h old mode 100644 new mode 100755 index eed1b2e..3a45a3f --- a/httpdns.h +++ b/httpdns.h @@ -1,51 +1,25 @@ -#ifndef _HTTPDNS_ -#define _HTTPDNS_ +#ifndef HTTPDNS_H +#define HTTPDNS_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "main.h" -#include "conf.h" +#define HTTPDNS_REQUEST "GET /d?dn=[D] HTTP/1.0\r\nHost: [H]\r\n\r\n" -#define DNS_MAX_CONNECTION 256 //此值的大小关系到respod_clients函数的效率 -#define DATA_SIZE 512 -#define HTTP_RSP_SIZE 1024 - -typedef struct dns_connection { - char dns_req[DATA_SIZE]; - struct sockaddr_in src_addr; - char *reply; //回应内容 - char *http_request, *host; - unsigned int http_request_len, dns_rsp_len; - int fd; - char query_type; - unsigned host_len:7; //域名最大长度64位 - unsigned wait_response_client:1; //已构建好DNS回应,等待可写事件 -} dns_t; - -struct dns_cache { - int question_len; - char *question; - char *answer; - struct dns_cache *next; +struct httpdns { + struct sockaddr_in dst; + char *http_req, *original_http_req, *connect_request, *original_connect_request, *cachePath, *ssl_request; //original_http_req, original_connect_request为初始化生成的请求头,用来配合use_hdr语法 + int http_req_len, original_http_req_len, connect_request_len, original_connect_request_len, cacheLimit, ssl_request_len; + unsigned encodeCode, //Host编码传输 + httpsProxy_encodeCode, //CONNECT代理编码 + tcpDNS_mode:1; //判断是否开启TCPDNS }; -extern dns_t dns_list[DNS_MAX_CONNECTION]; -extern struct epoll_event evs[DNS_MAX_CONNECTION + 1], event; - -void *httpdns_loop(void *p); -int httpdns_initialize(conf * configure); +extern void dns_timeout_check(); +extern void *dns_loop(void *nullPtr); +extern int8_t read_cache_file(); +extern void dns_init(); +extern struct httpdns httpdns; +extern pid_t child_pid; +extern FILE *cfp; #endif diff --git a/kill.c b/kill.c deleted file mode 100644 index 8a42d1d..0000000 --- a/kill.c +++ /dev/null @@ -1,463 +0,0 @@ -#include "kill.h" - -static pid_t opt_ns_pid = 0; - -static int exact = 1, reg = 0, wait_until_dead = 1, process_group = 0, ignore_case = 0; -static long younger_than = 0, older_than = 0; - -typedef struct NAMEINFO { - const char *name; - int name_length; - struct stat st; -} NAMEINFO; - -static double uptime() -{ - char *savelocale; - char buf[2048]; - FILE *file; - if (!(file = fopen(PROC_BASE "/uptime", "r"))) { - exit(1); - } - savelocale = setlocale(LC_NUMERIC, "C"); - if (fscanf(file, "%2047s", buf) == EOF) - perror("uptime"); - fclose(file); - setlocale(LC_NUMERIC, savelocale); - return atof(buf); -} - -static double process_age(const unsigned long long jf) -{ - double age; - double sc_clk_tck = sysconf(_SC_CLK_TCK); - assert(sc_clk_tck > 0); - age = uptime() - jf / sc_clk_tck; - if (age < 0L) - return 0L; - return age; -} - -enum ns_type { - IPCNS = 0, - MNTNS, - NETNS, - PIDNS, - USERNS, - UTSNS -}; - -static const char *ns_names[] = { - [IPCNS] = "ipc", - [MNTNS] = "mnt", - [NETNS] = "net", - [PIDNS] = "pid", - [USERNS] = "user", - [UTSNS] = "uts", -}; - -const char *get_ns_name(int id) -{ - if (id >= 6) - return NULL; - return ns_names[id]; -} - -static int get_ns(pid_t pid, int id) -{ - struct stat st; - char buff[50]; - snprintf(buff, sizeof(buff), "/proc/%i/ns/%s", pid, get_ns_name(id)); - if (stat(buff, &st)) - return 0; - else - return st.st_ino; -} - -static int match_process_uid(pid_t pid, uid_t uid) -{ - char buf[128]; - uid_t puid; - FILE *f; - int re = -1; - - snprintf(buf, sizeof buf, PROC_BASE "/%d/status", pid); - if (!(f = fopen(buf, "r"))) - return 0; - - while (fgets(buf, sizeof buf, f)) { - if (sscanf(buf, "Uid:\t%d", &puid)) { - re = uid == puid; - break; - } - } - fclose(f); - if (re == -1) { - exit(1); - } - return re; -} - -static void free_regexp_list(regex_t * reglist, int names) -{ - int i; - for (i = 0; i < names; i++) - regfree(®list[i]); - free(reglist); -} - -static regex_t *build_regexp_list(int names, char **namelist) -{ - int i; - regex_t *reglist; - int flag = REG_EXTENDED | REG_NOSUB; - - if (!(reglist = malloc(sizeof(regex_t) * names))) { - perror("malloc"); - exit(1); - } - - if (ignore_case) - flag |= REG_ICASE; - - for (i = 0; i < names; i++) { - if (regcomp(®list[i], namelist[i], flag) != 0) { - free_regexp_list(reglist, i); - exit(1); - } - } - return reglist; -} - -static NAMEINFO *build_nameinfo(const int names, char **namelist) -{ - int i; - NAMEINFO *ni = NULL; - if ((ni = malloc(sizeof(NAMEINFO) * names)) == NULL) - return NULL; - - for (i = 0; i < names; i++) { - ni[i].name = namelist[i]; - ni[i].st.st_dev = 0; - if (!strchr(namelist[i], '/')) { - ni[i].name_length = strlen(namelist[i]); - } else if (stat(namelist[i], &(ni[i].st)) < 0) { - perror(namelist[i]); - free(ni); - return NULL; - } - } - return ni; -} - -static int load_process_name_and_age(char *comm, double *process_age_sec, const pid_t pid, int load_age) -{ - FILE *file; - char *path; - char buf[1024]; - char *startcomm, *endcomm; - unsigned lencomm; - *process_age_sec = 0; - - if (asprintf(&path, PROC_BASE "/%d/stat", pid) < 0) - return -1; - if (!(file = fopen(path, "r"))) { - free(path); - return -1; - } - free(path); - if (fgets(buf, 1024, file) == NULL) { - fclose(file); - return -1; - } - fclose(file); - startcomm = strchr(buf, '(') + 1; - endcomm = strrchr(startcomm, ')'); - lencomm = endcomm - startcomm; - if (lencomm < 0) - lencomm = 0; - if (lencomm > COMM_LEN - 1) - lencomm = COMM_LEN - 1; - strncpy(comm, startcomm, lencomm); - comm[lencomm] = '\0'; - - endcomm += 2; // skip ") " - if (load_age) { - unsigned long long proc_stt_jf = 0; - if (sscanf(endcomm, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %Lu", &proc_stt_jf) != 1) { - return -1; - } - *process_age_sec = process_age(proc_stt_jf); - } - return lencomm; -} - -static int load_proc_cmdline(const pid_t pid, const char *comm, char **command, int *got_long) -{ - FILE *file; - char *path, *p, *command_buf; - int cmd_size = 128; - int okay; - - if (asprintf(&path, PROC_BASE "/%d/cmdline", pid) < 0) - return -1; - if (!(file = fopen(path, "r"))) { - free(path); - return -1; - } - free(path); - - if ((command_buf = (char *)malloc(cmd_size)) == NULL) - exit(1); - - while (1) { - for (p = command_buf;; p++) { - int c; - if (p == (command_buf + cmd_size)) { - char *new_command_buf; - int cur_size = cmd_size; - cmd_size *= 2; - new_command_buf = (char *)realloc(command_buf, cmd_size); - if (!new_command_buf) { - if (command_buf) - free(command_buf); - exit(1); - } - command_buf = new_command_buf; - p = command_buf + cur_size; - } - c = fgetc(file); - if (c == EOF || c == '\0') { - *p = '\0'; - break; - } else { - *p = c; - } - } - if (strlen(command_buf) == 0) { - okay = 0; - break; - } - p = strrchr(command_buf, '/'); - p = p ? p + 1 : command_buf; - if (strncmp(p, comm, COMM_LEN - 1) == 0) { - okay = 1; - if (!(*command = strdup(p))) { - free(command_buf); - exit(1); - } - break; - } - } - (void)fclose(file); - free(command_buf); - command_buf = NULL; - - if (exact && !okay) { - *got_long = okay; - return -1; - } - *got_long = okay; - return 0; -} - -static pid_t *create_pid_table(int *max_pids, int *pids) -{ - pid_t self, *pid_table; - int pid; - DIR *dir; - struct dirent *de; - - self = getpid(); - if (!(dir = opendir(PROC_BASE))) { - perror(PROC_BASE); - exit(1); - } - *max_pids = 256; - pid_table = malloc(*max_pids * sizeof(pid_t)); - if (!pid_table) { - perror("malloc"); - exit(1); - } - *pids = 0; - while ((de = readdir(dir)) != NULL) { - if (!(pid = (pid_t) atoi(de->d_name)) || pid == self) - continue; - if (*pids == *max_pids) { - if (!(pid_table = realloc(pid_table, 2 * *pids * sizeof(pid_t)))) { - perror("realloc"); - exit(1); - } - *max_pids *= 2; - } - pid_table[(*pids)++] = pid; - } - (void)closedir(dir); - return pid_table; -} - -#define strcmp2(A,B,I) (I? strcasecmp((A),(B)):strcmp((A),(B))) -#define strncmp2(A,B,L,I) (I? strncasecmp((A),(B),(L)):strncmp((A),(B),(L))) -static int match_process_name(const char *proc_comm, const int comm_len, const char *proc_cmdline, const char *match_name, const int match_len, const int got_long) -{ - if (comm_len == OLD_COMM_LEN - 1 && match_len >= OLD_COMM_LEN - 1) { - if (got_long) { - return (0 == strncmp2(match_name, proc_cmdline, OLD_COMM_LEN - 1, ignore_case)); - } else { - return (0 == strncmp2(match_name, proc_comm, OLD_COMM_LEN - 1, ignore_case)); - } - } - - if (comm_len == COMM_LEN - 1 && match_len >= COMM_LEN - 1) { - if (got_long) { - return (0 == strncmp2(match_name, proc_cmdline, COMM_LEN - 1, ignore_case)); - } else { - return (0 == strncmp2(match_name, proc_comm, COMM_LEN - 1, ignore_case)); - } - } - if (got_long) { - return (0 == strcmp2(match_name, proc_cmdline, ignore_case)); - } - return (0 == strcmp2(match_name, proc_comm, ignore_case)); -} - -int kill_all(int signal, int name_count, char **namelist, struct passwd *pwent) -{ - struct stat st; - NAMEINFO *name_info = NULL; - char *path, comm[COMM_LEN]; - char *command = NULL; - pid_t *pid_table, *pid_killed; - pid_t *pgids = NULL; - int i, j, length, got_long, error; - int pids, max_pids, pids_killed; - unsigned long found; - regex_t *reglist = NULL; - long ns_ino = 0; - - if (opt_ns_pid) - ns_ino = get_ns(opt_ns_pid, PIDNS); - - if (name_count && reg) - reglist = build_regexp_list(name_count, namelist); - else if ((name_info = build_nameinfo(name_count, namelist)) == NULL) - exit(1); - - pid_table = create_pid_table(&max_pids, &pids); - found = 0; - pids_killed = 0; - pid_killed = malloc(max_pids * sizeof(pid_t)); - if (!pid_killed) { - perror("malloc"); - exit(1); - } - if (process_group) { - pgids = calloc(pids, sizeof(pid_t)); - if (!pgids) { - perror("malloc"); - exit(1); - } - } - got_long = 0; - for (i = 0; i < pids; i++) { - pid_t id; - int found_name = -1; - double process_age_sec = 0; - if (pwent && match_process_uid(pid_table[i], pwent->pw_uid) == 0) - continue; - if (opt_ns_pid && ns_ino && ns_ino != get_ns(pid_table[i], PIDNS)) - continue; - length = load_process_name_and_age(comm, &process_age_sec, pid_table[i], (younger_than || older_than)); - if (length < 0) - continue; - if (younger_than && (process_age_sec > younger_than)) - continue; - if (older_than && (process_age_sec < older_than)) - continue; - - got_long = 0; - if (command) { - free(command); - command = NULL; - } - if (length == COMM_LEN - 1) - if (load_proc_cmdline(pid_table[i], comm, &command, &got_long) < 0) - continue; - for (j = 0; j < name_count; j++) { - if (reg) { - if (regexec(®list[j], got_long ? command : comm, 0, NULL, 0) - != 0) - continue; - } else { - if (!name_info[j].st.st_dev) { - if (!match_process_name(comm, length, command, namelist[j], name_info[j].name_length, got_long)) - continue; - - } else { - int ok = 1; - if (asprintf(&path, PROC_BASE "/%d/exe", pid_table[i]) < 0) - continue; - if (stat(path, &st) < 0) - ok = 0; - else if (name_info[j].st.st_dev != st.st_dev || name_info[j].st.st_ino != st.st_ino) { - size_t len = strlen(namelist[j]); - char *linkbuf = malloc(len + 1); - - if (!linkbuf || readlink(path, linkbuf, len + 1) != (ssize_t) len || memcmp(namelist[j], linkbuf, len)) - ok = 0; - free(linkbuf); - } - free(path); - if (!ok) - continue; - } - } - found_name = j; - break; - } - if (name_count && found_name == -1) - continue; - if (!process_group) - id = pid_table[i]; - else { - int j; - - id = getpgid(pid_table[i]); - pgids[i] = id; - for (j = 0; j < i; j++) - if (pgids[j] == id) - break; - if (j < i) - continue; - } - - if (kill(process_group ? -id : id, signal) >= 0) { - if (found_name >= 0) - found |= 1UL << found_name; - pid_killed[pids_killed++] = id; - } - } - if (command) - free(command); - if (reglist) - free_regexp_list(reglist, name_count); - free(pgids); - if (name_count) - error = found == ((1UL << (name_count - 1)) | ((1UL << (name_count - 1)) - 1)) ? 0 : 1; - else - error = pids_killed ? 0 : 1; - while (pids_killed && wait_until_dead) { - for (i = 0; i < pids_killed;) { - if (kill(process_group ? -pid_killed[i] : pid_killed[i], 0) < 0 && errno == ESRCH) { - pid_killed[i] = pid_killed[--pids_killed]; - continue; - } - i++; - } - //sleep(1); - } - free(pid_killed); - free(pid_table); - free(name_info); - return error; -} diff --git a/kill.h b/kill.h deleted file mode 100644 index f2c7d31..0000000 --- a/kill.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef KILL_H -#define KILL_H - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define COMM_LEN 64 -#define OLD_COMM_LEN 16 -#define _(String) (String) -#define rpmatch(line) \ - ( (line == NULL)? -1 : \ - (*line == 'y' || *line == 'Y')? 1 : \ - (*line == 'n' || *line == 'N')? 0 : \ - -1 ) - -#define PROC_BASE "/proc" -#define MAX_NAMES (int)(sizeof(unsigned long)*8) - -#define TSECOND "s" -#define TMINUTE "m" -#define THOUR "h" -#define TDAY "d" -#define TWEEK "w" -#define TMONTH "M" -#define TYEAR "y" - -#define TMAX_SECOND 31536000 -#define TMAX_MINUTE 525600 -#define TMAX_HOUR 8760 -#define TMAX_DAY 365 -#define TMAX_WEEK 48 -#define TMAX_MONTH 12 -#define TMAX_YEAR 1 - -#define ER_REGFAIL -1 -#define ER_NOMEM -2 -#define ER_UNKWN -3 -#define ER_OOFRA -4 - -int kill_all(int signal, int name_count, char **namelist, struct passwd *pwent); - -#endif diff --git a/main.c b/main.c index 0849d7b..4dbd356 100755 --- a/main.c +++ b/main.c @@ -1,22 +1,22 @@ #include "main.h" #include "http_proxy.h" #include "http_request.h" +#include "httpdns.h" #include "timeout.h" #include "conf.h" -#include "kill.h" #include "help.h" -#include "httpdns.h" #define SERVER_STOP 1 #define SERVER_RELOAD 2 #define SERVER_STATUS 3 +struct global global; +uint16_t tcp_listen_port; +struct httpudp udp; struct epoll_event ev, events[MAX_CONNECTION + 1]; -int epollfd, server_sock, server_sock6; +int epollfd, server_sock, server_sock6, local_port, process; conn_t cts[MAX_CONNECTION]; -int local_port; char local_host[CACHE_SIZE]; -int process; int create_connection(char *remote_host, int remote_port) { @@ -195,7 +195,7 @@ void *http_proxy_loop(void *p) } } } - + close(epollfd); return NULL; } @@ -204,7 +204,7 @@ void *start_server(conf * configure) { int n; pthread_t thread_id; - + ev.events = EPOLLIN; ev.data.fd = server_sock; if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, server_sock, &ev)) { @@ -217,7 +217,7 @@ void *start_server(conf * configure) perror("epoll_ctl"); exit(1); } - + if (timeout_minute) pthread_create(&thread_id, NULL, &tcp_timeout_check, NULL); @@ -238,7 +238,7 @@ void *start_server(conf * configure) } } } - + close(epollfd); return NULL; } @@ -284,10 +284,12 @@ int process_signal(int signal, char *process_name) printf("\t%d\n", number[n]); } } + if (signal == SERVER_STOP || signal == SERVER_RELOAD) { // 关闭 - struct passwd *pwent = NULL; - pwent = getpwnam("root"); - return kill_all(15, 1, &process_name, pwent); + n -= 2; + for (; n >= 0; n--) { + kill(number[n], SIGTERM); + } } return 0; @@ -315,13 +317,122 @@ void server_ini() perror("daemon"); return; } - //while (process-- > 1 && fork() == 0); } +// 监听一个UDP接口 +int udp_listen(char *ip, int port) +{ + struct sockaddr_in addr; + int fd, opt = 1; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("udp socket"); + exit(1); + } + setsockopt(fd, SOL_IP, IP_TRANSPARENT, &opt, sizeof(opt)); + setsockopt(fd, SOL_IP, IP_RECVORIGDSTADDR, &opt, sizeof(opt)); + memset(&addr, 0, sizeof(addr)); + addr.sin_addr.s_addr = inet_addr(ip); + addr.sin_port = htons(port); + addr.sin_family = AF_INET; + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + perror("udp bind"); + exit(1); + } + + return fd; +} + +void *timeout_check(void *nullPtr) +{ + while (1) { + sleep(60); + if (global.dns_listen_fd >= 0) + dns_timeout_check(); + } + + return NULL; +} + +void initialize(conf * configure) +{ + int i; + char *p; + + memset(cts, 0, sizeof(cts)); + for (i = MAX_CONNECTION; i--;) + cts[i].fd = -1; + // 为服务端的结构体分配内存 + for (i = 1; i < MAX_CONNECTION; i += 2) { + cts[i].ready_data = (char *)malloc(BUFFER_SIZE); + if (cts[i].ready_data == NULL) { + fputs("out of memory.", stderr); + exit(1); + } + } + + memset(&global, 0, sizeof(global)); + memset(&httpdns, 0, sizeof(httpdns)); + httpdns.dst.sin_family = AF_INET; + global.tcp_listen_fd = global.dns_listen_fd = global.udp_listen_fd = global.uid = -1; + global.dns_listen_fd = udp_listen((char *)"127.0.0.1", configure->dns_listen); + if ((p = strchr(configure->addr, ':')) != NULL) { + *p = '\0'; + httpdns.dst.sin_port = htons(atoi(p + 1)); + } else { + httpdns.dst.sin_port = htons(80); + } + httpdns.dst.sin_addr.s_addr = inet_addr(configure->addr); + httpdns.http_req_len = configure->http_req_len; + copy_new_mem(configure->http_req, httpdns.http_req_len, &httpdns.http_req); + + server_sock = create_server_socket(configure->tcp_listen); // IPV4 + server_sock6 = create_server_socket6(configure->tcp6_listen); // IPV6 + epollfd = epoll_create(MAX_CONNECTION); + if (epollfd == -1) { + perror("epoll_create"); + exit(1); + } + +} + +void thread_loop(conf * configure) +{ + pthread_t thread_id = 0; + sigset_t signal_mask; + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGPIPE); // 忽略PIPE信号 + if (pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) != 0) { + printf("block sigpipe error\n"); + } + if (timeout_minute) + pthread_create(&thread_id, NULL, &tcp_timeout_check, NULL); + if (pthread_create(&thread_id, NULL, &http_proxy_loop, (void *)configure) != 0) + perror("pthread_create"); + if (global.timeout_m) + pthread_create(&thread_id, NULL, &timeout_check, NULL); + if (global.dns_listen_fd >= 0) { + dns_init(); + dns_loop(NULL); + } + pthread_join(thread_id, NULL); + pthread_exit(NULL); + + /* 线程分离 + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread_id, &attr, &tcp_timeout_check, NULL); + pthread_create(&thread_id, &attr, &http_proxy_loop, (void *)configure); + pthread_exit(NULL); + */ +} + void _main(int argc, char *argv[]) { - int opt, i; + int opt; char path[PATH_SIZE] = { 0 }; char executable_filename[PATH_SIZE] = { 0 }; (void)get_executable_path(path, executable_filename, sizeof(path)); @@ -332,14 +443,14 @@ void _main(int argc, char *argv[]) memset(configure, 0, sizeof(struct CONF)); read_conf(inifile, configure); - sslEncodeCode = 0; // 默认SSL不转码 + sslEncodeCode = 0; // 默认SSL不转码 if (configure->sslencoding > 0) // 如果配置文件有sslencoding值,优先使用配置文件读取的值 sslEncodeCode = configure->sslencoding; - timeout_minute = 0; // 默认不超时 - if (configure->timeout > 0) // 如果配置文件有值,优先使用配置文件读取的值 + timeout_minute = 0; // 默认不超时 + if (configure->timeout > 0) // 如果配置文件有值,优先使用配置文件读取的值 timeout_minute = configure->timeout; - process = 2; // 默认开启2个进程 - if (configure->process > 0) // 如果配置文件有值,优先使用配置文件读取的值 + process = 2; // 默认开启2个进程 + if (configure->process > 0) // 如果配置文件有值,优先使用配置文件读取的值 process = configure->process; int longindex = 0; @@ -380,13 +491,14 @@ void _main(int argc, char *argv[]) } break; case 't': - timeout_minute = (time_t) atoi(optarg); // 如果指定-t,优先使用参数提供的值(输入值 > 配置文件读取的值) + timeout_minute = (time_t) atoi(optarg); // 如果指定-t,优先使用参数提供的值(输入值 > 配置文件读取的值) break; case 'p': process = atoi(optarg); break; case 'c': free_conf(configure); + memset(configure, 0, sizeof(struct CONF)); read_conf(optarg, configure); break; case 'e': @@ -412,70 +524,20 @@ void _main(int argc, char *argv[]) ; } } - + + server_ini(); // 守护进程 + // 设置每个进程允许打开的最大文件数 rt.rlim_max = rt.rlim_cur = MAX_CONNECTION * 2; if (setrlimit(RLIMIT_NOFILE, &rt) == -1) { perror("setrlimit"); } - - server_ini(); // 守护进程 - httpdns_initialize(configure); // 初始化httpdns - memset(cts, 0, sizeof(cts)); - for (i = MAX_CONNECTION; i--;) - cts[i].fd = -1; - // 为服务端的结构体分配内存 - for (i = 1; i < MAX_CONNECTION; i += 2) { - cts[i].ready_data = (char *)malloc(BUFFER_SIZE); - if (cts[i].ready_data == NULL) { - fputs("out of memory.", stderr); - exit(1); - } - } - - server_sock = create_server_socket(configure->tcp_listen); // IPV4 - server_sock6 = create_server_socket6(configure->tcp6_listen); // IPV6 - epollfd = epoll_create(MAX_CONNECTION); - if (epollfd == -1) { - perror("epoll_create"); - exit(1); - } + initialize(configure); if (setegid(configure->uid) == -1 || seteuid(configure->uid) == -1) // 设置uid exit(1); -/* - start_server(configure); // 单线程 - httpdns_loop(configure); -*/ + thread_loop(configure); - pthread_t thread_id = 0; - sigset_t signal_mask; - sigemptyset(&signal_mask); - sigaddset(&signal_mask, SIGPIPE); // 忽略PIPE信号 - if (pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) != 0) { - printf("block sigpipe error\n"); - } - - if (timeout_minute) - pthread_create(&thread_id, NULL, &tcp_timeout_check, NULL); - if (pthread_create(&thread_id, NULL, &http_proxy_loop, (void *)configure) != 0) - perror("pthread_create"); - if (pthread_create(&thread_id, NULL, &httpdns_loop, (void *)configure) != 0) - perror("pthread_create"); - - pthread_join(thread_id, NULL); - pthread_exit(NULL); - -/* 线程分离 - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread_id, &attr, &tcp_timeout_check, NULL); - pthread_create(&thread_id, &attr, &http_proxy_loop, (void *)configure); - pthread_create(&thread_id, &attr, &httpdns_loop, (void *)configure); - pthread_exit(NULL); -*/ return; } diff --git a/main.h b/main.h index 9e28961..55f41c8 100755 --- a/main.h +++ b/main.h @@ -27,14 +27,28 @@ #define PATH_SIZE 270 #define CACHE_SIZE 270 #define HTTP_HEAD_CACHE_SIZE 1024 +#define ERRDEBUG fprintf(stderr,"Error Occured at File: %s, Function: %s, Line: %d, Date: %s, Time: %s.\n", __FILE__, __FUNCTION__, __LINE__, __DATE__, __TIME__); + +struct httpudp { + struct sockaddr_in dst; + char *http_request, *original_http_request; //original_http_request为初始化生成的请求头,用来配合use_hdr语法 + int http_request_len, original_http_request_len; + unsigned encodeCode, //数据编码传输 + httpsProxy_encodeCode; //CONNECT代理编码 +}; + +struct global { + int tcp_listen_fd, dns_listen_fd, udp_listen_fd, uid, procs, timeout_m; + unsigned mode:3, strict_modify:1; +}; -extern int local_port; extern char local_host[CACHE_SIZE]; -extern int process; - -extern int epollfd; +extern int epollfd, local_port, process; extern struct epoll_event ev, events[MAX_CONNECTION + 1]; int create_connection(char *remote_host, int remote_port); int create_connection6(char *remote_host, int remote_port); +extern struct global global; +extern uint16_t tcp_listen_port; +extern struct httpudp udp; #endif diff --git a/timeout.c b/timeout.c index 264a10d..8d9d9d8 100755 --- a/timeout.c +++ b/timeout.c @@ -9,7 +9,7 @@ void *tcp_timeout_check(void *nullPtr) int i; while (1) { - sleep(60); + sleep(10); for (i = 0; i < MAX_CONNECTION; i += 2) { if (cts[i].fd > -1) { if (cts[i].timer >= timeout_minute) { diff --git a/timeout.h b/timeout.h old mode 100644 new mode 100755