From 2e19c24eff80105754aa68774cf203ff1f458432 Mon Sep 17 00:00:00 2001 From: aixiao Date: Thu, 30 Jul 2020 18:10:31 +0800 Subject: [PATCH] add httpdns client --- CProxy.conf | 22 +- CProxy.conf.explain | 45 +- Makefile | 6 +- conf.c | 62 ++- conf.h | 12 +- help.c | 10 +- http.c => http_proxy.c | 5 +- http.h => http_proxy.h | 3 +- request.c => http_request.c | 189 +++++--- request.h => http_request.h | 8 +- httpdns.c | 831 +++++++++++++++++++----------------- httpdns.h | 72 ++-- proxy.c => main.c | 30 +- proxy.h => main.h | 2 +- picohttpparser.c | 631 --------------------------- picohttpparser.h | 84 ---- timeout.c | 5 +- 17 files changed, 735 insertions(+), 1282 deletions(-) rename http.c => http_proxy.c (99%) rename http.h => http_proxy.h (96%) rename request.c => http_request.c (74%) rename request.h => http_request.h (80%) rename proxy.c => main.c (94%) rename proxy.h => main.h (96%) delete mode 100644 picohttpparser.c delete mode 100644 picohttpparser.h diff --git a/CProxy.conf b/CProxy.conf index 5318b50..e1e01fc 100644 --- a/CProxy.conf +++ b/CProxy.conf @@ -1,26 +1,32 @@ global { uid=3004; process=2; - timer=60; + timeout=60; sslencoding=128; - local_port=0124; + tcp_listen=0124; + dns_listen=0125; } http { - http_ip=cproxy.aixiao.me; - http_port=8911; + http_ip=47.240.75.93; + http_port=124; http_del="x-online-host,X-Online-Host,host,Host"; - http_first="[M] [U] [V]\r\nHost: [host]\r\n"; + http_first="[M] [U] [V]\r\nHost: [H]\r\n"; //strrep="Windows NT 10.0->Linux"; //regrep="Host*.+?->Host: hu60.cn:443"; } https { - https_ip=cproxy.aixiao.me; - https_port=8911; + https_ip=47.240.75.93; + https_port=124; https_del="Host,host,x-online-host"; - https_first="[M] [H] [V]\r\nHost: [host]\r\n"; + https_first="[M] [U] [V]\r\nHost: [H]\r\n"; strrep="Windows NT 10.0->Linux"; //regrep="Host*.+?->Host: hu60.cn:443"; } +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; +} diff --git a/CProxy.conf.explain b/CProxy.conf.explain index 164f785..c7c0d70 100644 --- a/CProxy.conf.explain +++ b/CProxy.conf.explain @@ -1,44 +1,36 @@ global { - // 设置进程UID uid=3004; - - // 进程数 process=2; - - // 超时 - timer=60; - - // ssl编码,1-128 - sslencoding=0; - - // 本地端口 - local_port=9606; + timeout=60; + sslencoding=128; + tcp_listen=0124; + dns_listen=0125; } http { - // 代理IP - http_ip=192.168.1.102; - // 代理端口 - http_port=1080; + http_ip=cproxy.aixiao.me; + http_port=124; http_del="x-online-host,X-Online-Host,host,Host"; - http_first="[M] [U] [V]\r\nHost: [host]\r\n"; + http_first="[M] [U] [V]\r\nHost: [H]\r\n"; //strrep="Windows NT 10.0->Linux"; //regrep="Host*.+?->Host: hu60.cn:443"; } https { - // 代理IP - https_ip=192.168.1.102; - // 代理端口 - https_port=1080; - // 删除Host行 + https_ip=cproxy.aixiao.me; + https_port=124; https_del="Host,host,x-online-host"; - // https头第一行 - https_first="[M] [H] [V]\r\nHost: [host]\r\n"; - //strrep="Windows NT 10.0->Linux"; + https_first="[M] [U] [V]\r\nhost: [host]\r\n"; + strrep="Windows NT 10.0->Linux"; //regrep="Host*.+?->Host: hu60.cn:443"; } +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"; +} + + http、https 模块关键字: [M], [method], [uri], [U], [V], [version], [H], [host], [port], \r, \n, \v, \f, \b, \t, \a. 如果原本请求头含有关键字也会被替换. [M]、[method] 原请求方法 @@ -55,3 +47,6 @@ strrep = "Mi MIX 2->Linux"; 以"->"为分界符,"Mi MIX 2"字符串替换为"Lin 关键字regrep正则匹配替换字符串. regrep = "Host*.+?->Host: iread.wo.cn:443"; 以"->"为分界符,匹配到的内容"Host*.+?"替换为"Host: iread.wo.cn:443"字符串. +httpdns 模块关键字: [M], [D], [V], \r, \n, \v, \f, \b, \t, \a. +默认 [M] 为 GET +默认 [V] 为 HTTP/1.0 diff --git a/Makefile b/Makefile index 07df736..6317e3c 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ CROSS_COMPILE ?= CC := $(CROSS_COMPILE)gcc STRIP := $(CROSS_COMPILE)strip -CFLAGS += -g -O2 -Wall -pthread -LIBS = -static +CFLAGS += -g -O2 -Wall -pthread -static +LIBS = OBJ := CProxy -all: proxy.o http.o httpdns.o request.o picohttpparser.o conf.o timeout.o kill.o help.o +all: main.o http_proxy.o httpdns.o http_request.o conf.o timeout.o kill.o help.o $(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS) .c.o: $(CC) $(CFLAGS) -c $< $(LIBS) diff --git a/conf.c b/conf.c index b632e85..86a7d20 100644 --- a/conf.c +++ b/conf.c @@ -112,12 +112,14 @@ static void parse_global_module(char *content, conf * p) p->uid = atoi(val_begin); } else if (strcasecmp(var, "process") == 0) { p->process = atoi(val_begin); - } else if (strcasecmp(var, "timer") == 0) { - p->timer = atoi(val_begin); + } else if (strcasecmp(var, "timeout") == 0) { + p->timeout = atoi(val_begin); } else if (strcasecmp(var, "sslencoding") == 0) { p->sslencoding = atoi(val_begin); - } else if (strcasecmp(var, "local_port") == 0) { - p->local_port = atoi(val_begin); + } else if (strcasecmp(var, "tcp_listen") == 0) { + p->tcp_listen = atoi(val_begin); + } else if (strcasecmp(var, "dns_listen") == 0) { + p->dns_listen = atoi(val_begin); } content = strchr(lineEnd + 1, '\n'); @@ -141,10 +143,12 @@ static void parse_http_module(char *content, conf * p) val_begin_len = strlen(val_begin) + 1; p->http_del = (char *)malloc(val_begin_len); memcpy(p->http_del, val_begin, val_begin_len); + p->http_del_len = val_begin_len; } else if (strcasecmp(var, "http_first") == 0) { val_begin_len = strlen(val_begin) + 1; p->http_first = (char *)malloc(val_begin_len); memcpy(p->http_first, val_begin, val_begin_len); + p->http_first_len = val_begin_len; } else if (strcasecmp(var, "strrep") == 0) { val_begin_len = strlen(val_begin) + 1; @@ -210,10 +214,12 @@ static void parse_https_module(char *content, conf * p) val_begin_len = strlen(val_begin) + 1; p->https_del = (char *)malloc(val_begin_len); memcpy(p->https_del, val_begin, val_begin_len); + p->https_del_len = val_begin_len; } else if (strcasecmp(var, "https_first") == 0) { val_begin_len = strlen(val_begin) + 1; p->https_first = (char *)malloc(val_begin_len); memcpy(p->https_first, val_begin, val_begin_len); + p->https_first_len = val_begin_len; } else if (strcasecmp(var, "strrep") == 0) { val_begin_len = strlen(val_begin) + 1; @@ -260,6 +266,28 @@ static void parse_https_module(char *content, conf * p) } } +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) { + if (strcasecmp(var, "addr") == 0) { + val_begin_len = strlen(val_begin) + 1; + p->addr = (char *)malloc(val_begin_len); + memcpy(p->addr, val_begin, val_begin_len); + } else if (strcasecmp(var, "http_req") == 0) { + val_begin_len = strlen(val_begin) + 1; + p->http_req = (char *)malloc(val_begin_len); + memcpy(p->http_req, val_begin, val_begin_len); + p->http_req_len = val_begin_len; + } else if (strcasecmp(var, "encode") == 0) { + p->encode = atoi(val_begin); + } + content = strchr(lineEnd + 1, '\n'); + } +} + void free_conf(conf * p) { free(p->server_pid_file); @@ -283,12 +311,15 @@ void free_conf(conf * p) free(p->https_regrep); free(p->https_regrep_aim); free(p->https_regrep_obj); + + free(p->addr); + free(p->http_req); return; } void read_conf(char *filename, conf * configure) { - char *buff, *global_content, *http_content, *https_content; + char *buff, *global_content, *http_content, *https_content, *httpdns_content; FILE *file; long file_size; @@ -303,7 +334,9 @@ void read_conf(char *filename, conf * configure) if (buff == NULL) perror("out of memory."); rewind(file); - fread(buff, file_size, 1, file); + if (fread(buff, file_size, 1, file) < 1) { + perror("fread"); + } fclose(file); buff[file_size] = '\0'; @@ -321,16 +354,21 @@ void read_conf(char *filename, conf * configure) perror("read https module error"); 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); + free(httpdns_content); } void printfconf(conf * configure) { printf("%d\n", configure->uid); printf("%d\n", configure->process); - printf("%d\n", configure->timer); + printf("%d\n", configure->timeout); printf("%d\n", configure->sslencoding); - printf("%d\n", configure->local_port); + printf("%d\n", configure->tcp_listen); + printf("%d\n", configure->dns_listen); printf("\n"); if (configure->http_ip) printf("%s\n", configure->http_ip); @@ -372,4 +410,10 @@ void printfconf(conf * configure) printf("%s\n", configure->https_regrep_aim); if (configure->https_regrep_obj) printf("%s\n", configure->https_regrep_obj); + + printf("\n"); + if (configure->addr) + printf("%s\n", configure->addr); + if (configure->http_req) + printf("%s\n", configure->http_req); } diff --git a/conf.h b/conf.h index a0c2d94..4af9876 100644 --- a/conf.h +++ b/conf.h @@ -12,10 +12,11 @@ typedef struct CONF { // server module int uid; int process; - int timer; + int timeout; int sslencoding; //int server_port; - int local_port; + int tcp_listen; + int dns_listen; char *server_pid_file; int server_pid_file_len; // length @@ -44,6 +45,13 @@ typedef struct CONF { char *https_regrep_aim, *https_regrep_obj; int https_regrep_aim_len, https_regrep_obj_len; + + + // http dns_listen + char *addr; + char *http_req; + int http_req_len; + int encode; } conf; char *strncpy_(char *dest, const char *src, size_t n); diff --git a/help.c b/help.c index 213e30c..46601bf 100644 --- a/help.c +++ b/help.c @@ -14,11 +14,11 @@ char help_information(void) static const char *s_help[] = { "", "Options:", - " -l --local_address : localip:localport", - " -f --remote_address : remoteip:remote:port", - " -p --process : process number, default: 2", - " -t --timeout : timeout minute, default: no timeout", - " -e --coding : ssl coding, default: [0-128]", + " -l --local_address : localIP:localPORT", + " -f --remote_address : remoteIP:remotePORT", + " -p --process : process number", + " -t --timeout : timeout minute", + " -e --coding : ssl coding, [0-128]", " -s --signal : send signal to a master process: stop, quit, restart, reload, status", " -c --config : set configuration file, default: CProxy.conf", " -? -h --? --help : help information", diff --git a/http.c b/http_proxy.c similarity index 99% rename from http.c rename to http_proxy.c index 83de51f..787d7bf 100644 --- a/http.c +++ b/http_proxy.c @@ -1,5 +1,5 @@ -#include "http.h" -#include "proxy.h" +#include "http_proxy.h" +#include "main.h" int sslEncodeCode; @@ -132,6 +132,7 @@ void tcp_in(conn * in, conf * configure) if (in->header_buffer != NULL) { if (request_type(in->header_buffer) == HTTP_TYPE) { in->header_buffer = request_head(in, configure); + struct epoll_event epollEvent; conn *remote; remote = in + 1; diff --git a/http.h b/http_proxy.h similarity index 96% rename from http.h rename to http_proxy.h index 689de60..97c09ee 100644 --- a/http.h +++ b/http_proxy.h @@ -2,7 +2,7 @@ #define HTTP_H #include "conf.h" -#include "proxy.h" +#include "main.h" #define HTTP_TYPE 0 #define OTHER_TYPE 1 @@ -10,7 +10,6 @@ int remote_port; char remote_host[128]; - extern int sslEncodeCode; typedef struct conn_t { diff --git a/request.c b/http_request.c similarity index 74% rename from request.c rename to http_request.c index fd7805f..ead6ac2 100644 --- a/request.c +++ b/http_request.c @@ -1,4 +1,4 @@ -#include "request.h" +#include "http_request.h" // 字符串替换 char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len) @@ -154,8 +154,8 @@ char *delete_head(char *head, const char *character, int string) int extract_host(char *header, char *host, char *port) { - bzero(host, strlen(host)); - bzero(port, strlen(port)); + memset(host, 0, strlen(host)); + memset(port, 0, strlen(port)); char *_p = strstr(header, "CONNECT"); // 在 CONNECT 方法中解析 隧道主机名称及端口号 if (_p) { char *_p1 = strchr(_p, ' '); @@ -217,51 +217,108 @@ char *get_path(char *url, char *path) return NULL; } +void free_http_request(struct http_request *http_request) { + if (http_request->M) + free(http_request->M); + if (http_request->U) + free(http_request->U); + if (http_request->V) + free(http_request->V); +} + +void parse_request_head(char *http_request_line, struct http_request *http_request) { + char *p; + char *head; + size_t head_len; + char *m, *u; + + p = strstr(http_request_line, "\r\n"); // 查找"\r\n" + if(p == NULL) { + return ; + } + + head_len = strlen(http_request_line) - strlen(p); + head = (char *)malloc(sizeof(char) * head_len*2); + if (head == NULL) + free(head); + memset(head, 0, head_len*2); + memcpy(head, http_request_line, head_len); + //printf("HEAD: %s\n", head); + + http_request->M = (char *)malloc(sizeof(char) * head_len); + http_request->U = (char *)malloc(sizeof(char) * head_len); + http_request->V = (char *)malloc(10); + if (http_request->M == NULL) { + free(http_request->M); + perror("malloc"); + } + if (http_request->U == NULL) { + free(http_request->M); + perror("malloc"); + } + if (http_request->V == NULL) { + free(http_request->M); + perror("malloc"); + } + + memset(http_request->M, 0, head_len); + memset(http_request->U, 0, head_len); + memset(http_request->V, 0, 10); + + m = strstr(head, " "); + http_request->M_len = strlen(head) - strlen(m); + memset(http_request->M, 0, head_len); + memcpy(http_request->M, head, http_request->M_len); + + + u = strstr(m+1, " "); + http_request->U_len = strlen(m+1) - strlen(u); + memset(http_request->U, 0, head_len); + memcpy(http_request->U, m+1, http_request->U_len); + + memset(http_request->V, 0, 8); + memcpy(http_request->V, u+1, 8); + http_request->V_len = 8; + + free(head); + printf("%s\n", http_request->M); + printf("%s\n", http_request->U); + printf("%s\n", http_request->V); + printf("%d\n", http_request->M_len); + printf("%d\n", http_request->U_len); + printf("%d\n", http_request->V_len); + +} + char *request_head(conn * in, conf * configure) { - const char *method, *path; - size_t method_len, path_len, num_headers; - int minor_version; - struct phr_header headers[32]; - - num_headers = sizeof(headers) / sizeof(headers[0]); - phr_parse_request(in->header_buffer, strlen(in->header_buffer) - 1, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); - - char M[method_len + 2]; - strncpy_(M, method, method_len); - int M_len = strlen(M); - //printf("%s\n", M); - - char U[path_len + 1]; - strncpy_(U, path, path_len); - int U_len = strlen(U); - //printf("%s\n", U); - - char V[9]; - sprintf(V, "HTTP/1.%.d", minor_version); - int V_len = strlen(V); - //printf("%s\n", V); - - char host[path_len]; - char port[path_len]; - char H[path_len * 2]; - extract_host(in->header_buffer, host, port); - -//printfconf(configure); - - if (strncmp(M, "CONNECT", 7) == 0) { - char https_del_copy[configure->https_del_len]; - char *result = NULL; + struct http_request *http_request; + http_request = (struct http_request *)malloc(sizeof(struct http_request)); + parse_request_head(in->header_buffer, http_request); + + //printfconf(configure); // 打印配置 + if (strncmp(http_request->M, "CONNECT", 7) == 0) { + char host[http_request->U_len], port[http_request->U_len], H[http_request->U_len * 2]; char *incomplete_head; int incomplete_head_len; + char https_del_copy[configure->https_del_len * 2]; + char *result = NULL; + + extract_host(in->header_buffer, host, port); if (configure->https_port > 0) remote_port = configure->https_port; if (configure->https_ip != NULL) strcpy(remote_host, configure->https_ip); - incomplete_head = (char *)malloc(1024 + 10240); - strcpy(incomplete_head, in->header_buffer); - strcpy(https_del_copy, configure->https_del); + incomplete_head = (char *)malloc(sizeof(char) * (1024 + BUFFER_SIZE)); + if (incomplete_head == NULL) { + free(incomplete_head); + perror("malloc"); + } + memset(incomplete_head, 0, sizeof(char) * (1024 + BUFFER_SIZE)); + memcpy(incomplete_head, in->header_buffer, strlen(in->header_buffer)); + memcpy(https_del_copy, configure->https_del, configure->https_del_len); + result = strtok(https_del_copy, ","); while (result != NULL) { delete_head(incomplete_head, result, '\n'); @@ -278,15 +335,15 @@ char *request_head(conn * 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, M, M_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[method]", 8, M, M_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[U]", 3, U, U_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[V]", 3, V, V_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[version]", 9, V, V_len); + 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, "[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, "[host]", 6, host, (int)strlen(host)); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, port, (int)strlen(port)); memset(H, 0, strlen(H)); - memcpy(H, host, path_len); + strcpy(H, host); strcat(H, ":"); strcat(H, port); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, H, (int)strlen(H)); @@ -296,32 +353,40 @@ char *request_head(conn * in, conf * configure) if (configure->https_regrep) { incomplete_head = regrep(incomplete_head, &incomplete_head_len, configure->https_regrep_aim, configure->https_regrep_obj, configure->https_regrep_obj_len); } - //printf("%s", incomplete_head); + printf("%s", incomplete_head); // 打印HTTP HEADER memset(in->header_buffer, 0, strlen(in->header_buffer)); strcpy(in->header_buffer, incomplete_head); in->header_buffer_len = strlen(in->header_buffer); - free(incomplete_head); + } else { + char host[http_request->U_len], port[http_request->U_len], H[http_request->U_len * 2]; + char url[http_request->U_len], uri[http_request->U_len]; + int uri_len; char *incomplete_head; + int incomplete_head_len; char https_del_copy[configure->http_del_len]; char *result = NULL; - int incomplete_head_len; - char url[U_len], uri[U_len]; - int uri_len; - strcpy(url, U); + extract_host(in->header_buffer, host, port); + strcpy(url, http_request->U); get_path(url, uri); uri_len = strlen(uri); - //printf("%s\n", uri); + if (configure->http_port > 0) remote_port = configure->http_port; if (configure->https_ip != NULL) strcpy(remote_host, configure->http_ip); - incomplete_head = (char *)malloc(1024 + 10240); + incomplete_head = (char *)malloc(sizeof(char) * (1024 + BUFFER_SIZE)); + if (incomplete_head == NULL) { + free(incomplete_head); + perror("malloc"); + } + memset(incomplete_head, 0, sizeof(char) * (1024 + BUFFER_SIZE)); strcpy(incomplete_head, in->header_buffer); strcpy(https_del_copy, configure->http_del); + result = strtok(https_del_copy, ","); while (result != NULL) { delete_head(incomplete_head, result, '\n'); @@ -338,16 +403,16 @@ char *request_head(conn * 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, M, M_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[method]", 8, M, M_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[U]", 3, U, U_len); + 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, "[U]", 3, http_request->U, http_request->U_len); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[uri]", 5, uri, uri_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[V]", 3, V, V_len); - incomplete_head = replace(incomplete_head, &incomplete_head_len, "[version]", 9, V, V_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, "[host]", 6, host, (int)strlen(host)); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, port, (int)strlen(port)); memset(H, 0, strlen(H)); - memcpy(H, host, path_len); + strcpy(H, host); strcat(H, ":"); strcat(H, port); incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, H, (int)strlen(H)); @@ -357,12 +422,14 @@ char *request_head(conn * in, conf * configure) if (configure->http_regrep) { incomplete_head = regrep(incomplete_head, &incomplete_head_len, configure->http_regrep_aim, configure->http_regrep_obj, configure->http_regrep_obj_len); } - //printf("%s", incomplete_head); + printf("%s", incomplete_head); + memset(in->header_buffer, 0, strlen(in->header_buffer)); strcpy(in->header_buffer, incomplete_head); in->header_buffer_len = strlen(in->header_buffer); free(incomplete_head); } - + free_http_request(http_request); + free(http_request); return in->header_buffer; } diff --git a/request.h b/http_request.h similarity index 80% rename from request.h rename to http_request.h index bbf8956..4caf6c4 100644 --- a/request.h +++ b/http_request.h @@ -5,9 +5,13 @@ #include #include #include -#include "http.h" +#include "http_proxy.h" #include "conf.h" -#include "picohttpparser.h" + +struct http_request { + char *M, *U, *V; + int M_len, U_len, V_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); diff --git a/httpdns.c b/httpdns.c index 45a3214..2d6e7b4 100644 --- a/httpdns.c +++ b/httpdns.c @@ -1,450 +1,503 @@ #include "httpdns.h" +#include "http_request.h" -int encodeCode=0; -/* hosts变量 */ -char *hosts_path = NULL; -FILE *hostsfp = NULL; -struct dns_hosts *hosts, *last_hosts = NULL; +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; +/* 缓存变量 */ +FILE *cfp = NULL; +char *cachePath = NULL; +struct dns_cache *cache, *cache_temp; +socklen_t addr_len = sizeof(dst_addr); +unsigned int cache_using, cacheLimit; -/* encode domain and ipAddress */ -static void dataEncode(unsigned char *data, int data_len) + +int read_cache_file() { - while (data_len-- > 0) - data[data_len] ^= encodeCode; -} + char *buff, *answer, *question; + long file_size; -int read_hosts_file(char *path) -{ - char *ip_begin, *ip_end, *host_begin, *host_end, *buff, *next_line; - int file_size, i; - - hosts = last_hosts = NULL; - if ((hostsfp = fopen(path, "r")) == NULL) { - fputs("error hosts file path", stderr); - return 1; + cache = cache_temp = NULL; + cache_using = 0; + if ((cfp = fopen(cachePath, "rb+")) == NULL) { + //保持文件打开状态,防止切换uid后权限不足导致无法写入文件 + cfp = fopen(cachePath, "wb"); + return cfp == NULL ? 1 : 0; } //读取文件内容 - fseek(hostsfp, 0, SEEK_END); - file_size = ftell(hostsfp); - //文件没有内容则不用读取 - if (file_size == 0) - return 0; - if ((buff = (char *)alloca(file_size + 1)) == NULL) { - fclose(hostsfp); - fputs("out of memory", stderr); + fseek(cfp, 0, SEEK_END); + file_size = ftell(cfp); + if ((buff = (char *)alloca(file_size)) == NULL) { + fclose(cfp); return 1; } - rewind(hostsfp); - fread(buff, file_size, 1, hostsfp); - *(buff + file_size) = '\0'; - fclose(hostsfp); + rewind(cfp); + fread(buff, file_size, 1, cfp); - struct dns_hosts *h = NULL; - for (ip_begin = buff; ip_begin; ip_begin = next_line) { - next_line = strchr(ip_begin, '\n'); - if (next_line != NULL) - *next_line++ = '\0'; - while (*ip_begin == '\t' || *ip_begin == ' ' || *ip_begin == '\r') - if (*ip_begin++ == '\0') - continue; - for (i = 0, ip_end = ip_begin; *ip_end != ' ' && *ip_end != '\t' && *ip_end != '\r' && *ip_end != '\0'; ip_end++) { - if (*ip_end == '.') - i++; - else if (*ip_end == '\0') - continue; - } - if (i != 3) - continue; - for (host_begin = ip_end; *host_begin == '\t' || *host_begin == ' ' || *host_begin == '\r';) { - if (*host_begin++ == '\0') - continue; - } - for (host_end = host_begin; *host_end != ' ' && *host_end != '\t' && *host_end != '\r' && *host_end != '\n' && *host_end != '\0'; host_end++) ; - if (h) { - h->next = (struct dns_hosts *)malloc(sizeof(struct dns_hosts)); - if (h->next == NULL) - return 1; - h = h->next; - } else { - hosts = h = (struct dns_hosts *)malloc(sizeof(struct dns_hosts)); - if (hosts == NULL) { - fputs("out of memory", stderr); - return 1; + //读取缓存,一组缓存的内容为[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)); + 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) + 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) { + before->next = after->next; + free(after->question); + free(after->answer); + free(after); + cache_using--; } } - h->next = NULL; - h->ip = strndup(ip_begin, ip_end - ip_begin); - if (*(host_end - 1) == '.') - host_end--; - h->host = strndup(host_begin, host_end - host_begin); - if (h->ip == NULL || h->host == NULL) { - fputs("out of memory", stderr); - return 1; - } - } - last_hosts = h; + fclose(cfp); + cfp = fopen(cachePath, "wb"); return 0; } -char *hosts_lookup(char *host) +void write_dns_cache() { - struct dns_hosts *h; + while (cache) { + fputs(cache->answer, cfp); + fputs(cache->question, cfp); + fputc('\0', cfp); + cache = cache->next; + } - h = hosts; - while (h) { - if (strcmp(h->host, host) == 0) - return h->ip; - h = h->next; + exit(0); +} + +char *cache_lookup(char *question, dns_t * dns) +{ + struct dns_cache *c; + + 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; + } } return NULL; } -void close_client(dns_t * dns) +void cache_record(dns_t * dns) { - close(dns->fd); - if (dns->http_rsp_len != sizeof(ERROR_MSG) - 1) //ERROR_MSG not free() - free(dns->http_rsp); - dns->http_rsp = NULL; - dns->sent_len = dns->dns_req_len = 0; - dns->fd = -1; -} - -void build_http_rsp(dns_t * dns, char *ips) -{ - int ips_len = strlen(ips); - - if (encodeCode) - dataEncode((unsigned char *)ips, ips_len); - dns->http_rsp_len = sizeof(SUCCESS_HEADER) - 1 + ips_len; - dns->http_rsp = (char *)malloc(dns->http_rsp_len + 1); - if (dns->http_rsp == NULL) + cache_temp = (struct dns_cache *)malloc(sizeof(*cache)); + if (cache_temp == NULL) + return; + cache_temp->question = strdup(dns->dns_req + 12); + if (cache_temp->question == NULL) { + free(cache_temp); return; - strcpy(dns->http_rsp, SUCCESS_HEADER); - memcpy(dns->http_rsp + sizeof(SUCCESS_HEADER) - 1, ips, ips_len); - dns->sent_len = 0; -} - -void response_client(dns_t * out) -{ - int write_len = write(out->fd, out->http_rsp + out->sent_len, out->http_rsp_len - out->sent_len); - if (write_len == out->http_rsp_len - out->sent_len || write_len == -1) - close_client(out); - else - out->sent_len += write_len; -} - -void build_dns_req(dns_t * dns, char *domain, int domain_size) -{ - char *p, *_p; - - p = dns->dns_req + 12; - memcpy(p + 1, domain, domain_size + 1); //copy '\0' - while ((_p = strchr(p + 1, '.')) != NULL) { - *p = _p - p - 1; - p = _p; } - *p = strlen(p + 1); - p = dns->dns_req + 14 + domain_size; - *p++ = 0; - *p++ = 1; - *p++ = 0; - *p++ = 1; - dns->dns_req_len = p - dns->dns_req; + cache_temp->next = cache; + cache = cache_temp; + cache->question_len = dns->host_len; + cache->answer = dns->reply; + if (cacheLimit) { + //到达缓存记录条目限制则释放前一半缓存 + if (cache_using >= cacheLimit) { + struct dns_cache *free_c; + int i; + for (i = cache_using = 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); + } + } + cache_using++; + } } -int send_dns_req(char *dns_req, int req_len) +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; + } + } + ev.events = EPOLLIN; + ev.data.fd = dnsListenFd; + epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &ev); +} + +/* 分析DNS请求 */ +int parse_dns_request(char *dns_req, dns_t * dns) +{ + 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); + return 0; + + default: + dns->host = NULL; + return 1; + } +} + +/* 建立DNS回应 */ +int build_dns_response(dns_t * dns) +{ + char *p; + + //18: 查询资源的前(12字节)后(6字节)部分 + dns->dns_rsp_len = 18 + dns->host_len + (dns->reply ? 16 : 0); + if (dns->dns_rsp_len > DATA_SIZE) { + dns->query_type = 0; + return 1; //超出缓冲大小 + } + /* 问题数 */ + dns->dns_req[4] = 0; + dns->dns_req[5] = 1; + /* 资源记录数 */ + dns->dns_req[6] = 0; + dns->dns_req[7] = 0; + /* 授权资源记录数 */ + dns->dns_req[8] = 0; + dns->dns_req[9] = 0; + /* 额外资源记录数 */ + dns->dns_req[10] = 0; + dns->dns_req[11] = 0; + /* 如果有回应内容(资源记录) */ + if (dns->reply) { + p = dns->dns_req + 18 + dns->host_len; + /* 资源记录数+1 */ + dns->dns_req[7]++; + /* 成功标志 */ + dns->dns_req[2] = (char)133; + dns->dns_req[3] = (char)128; + /* 指向主机域名 */ + p[0] = (char)192; + p[1] = 12; + /* 回应类型 */ + p[2] = 0; + p[3] = dns->query_type; + /* 区域类别 */ + p[4] = 0; + p[5] = 1; + /* 生存时间 (1 ora) */ + p[6] = 0; + p[7] = 0; + p[8] = 14; + p[9] = 16; + /* 回应长度 */ + p[10] = 0; + p[11] = 4; //reply中包含回应长度 + strcpy(p + 12, dns->reply); + } else { + /* 失败标志 */ + dns->dns_req[2] = (char)129; + dns->dns_req[3] = (char)130; + } + if (respond_client(dns) == 1) { + dns->wait_response_client = 1; + ev.events = EPOLLIN | EPOLLOUT; + ev.data.fd = dnsListenFd; + epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &ev); + } + + return 0; +} + +void http_out(dns_t * out) { int write_len; - write_len = write(dstFd, dns_req, req_len); - if (write_len == req_len) - return 0; - return write_len; -} - -void query_dns() -{ - dns_t *dns; - int i, ret; - - for (i = MAX_FD - 2, dns = &dns_list[MAX_FD - 3]; i--; dns--) { - if (dns->http_rsp == NULL && dns->dns_req_len != dns->sent_len) { - ret = send_dns_req(dns->dns_req + dns->sent_len, dns->dns_req_len - dns->sent_len); - if (ret == 0) { - dns->sent_len = dns->dns_req_len; - } else if (ret > -1) { - dns->sent_len += ret; - return; - } else { - close_client(dns); - break; - } - } - } - ev.events = EPOLLIN | EPOLLET; - ev.data.fd = dstFd; - epoll_ctl(eFd, EPOLL_CTL_MOD, dstFd, &ev); -} - -void recv_dns_rsp() -{ - static char rsp_data[BUFF_SIZE + 1], *p, *ips, *ips_save; - unsigned char *_p; - dns_t *dns; - int len, ips_len; - int16_t flag; - - len = read(dstFd, rsp_data, BUFF_SIZE); - if (len < 2) - return; - memcpy(&flag, rsp_data, sizeof(int16_t)); - if (flag > MAX_FD - 3) - return; - dns = dns_list + flag; - dns->sent_len = 0; - dns->http_rsp = ERROR_MSG; - dns->http_rsp_len = sizeof(ERROR_MSG) - 1; - if (dns->dns_req_len + 12 > len || (unsigned char)rsp_data[3] != 128 /*(signed char) max is 127 */ ) - goto modEvToOut; - rsp_data[len] = '\0'; - /* get ips */ - p = rsp_data + dns->dns_req_len + 11; - ips_len = 0; - ips = NULL; - while (p - rsp_data + 4 <= len) { - //type - if (*(p - 8) != 1) { - p += *p + 12; - continue; - } - ips_save = ips; - ips = (char *)realloc(ips, ips_len + 16); - if (ips == NULL) { - ips = ips_save; - break; - } - _p = (unsigned char *)p + 1; - ips_len += sprintf(ips + ips_len, "%d.%d.%d.%d", _p[0], _p[1], _p[2], _p[3]); - p += 16; //next address - ips[ips_len++] = ';'; - } - if (ips) { - ips[ips_len - 1] = '\0'; - //printf("ips %s\n", ips); - build_http_rsp(dns, ips); - free(ips); - if (dns->http_rsp) { - response_client(dns); - if (dns->http_rsp == NULL) { - dns->http_rsp = ERROR_MSG; - dns->http_rsp_len = sizeof(ERROR_MSG) - 1; - } - } - } -modEvToOut: - ev.data.ptr = dns; - ev.events = EPOLLOUT | EPOLLET; - epoll_ctl(eFd, EPOLL_CTL_MOD, dns->fd, &ev); -} - -void read_client(dns_t * in) -{ - static char httpReq[BUFF_SIZE + 1]; - int domain_size, httpReq_len; - char *domain_begin, *domain_end, *domain = NULL, *ips; - - httpReq_len = read(in->fd, httpReq, BUFF_SIZE); - //必须大于5,否则不处理 - if (httpReq_len < 6) { - close_client(in); - return; - } - httpReq[httpReq_len] = '\0'; - in->http_rsp = ERROR_MSG; - in->http_rsp_len = sizeof(ERROR_MSG) - 1; - if ((domain_begin = strstr(httpReq, "?dn="))) - domain_begin += 4; - else if ((domain_begin = strstr(httpReq, "?host="))) - domain_begin += 6; - else - goto response_client; - - domain_end = strchr(domain_begin, ' '); - if (domain_end == NULL) - goto response_client; - if (*(domain_end - 1) == '.') - domain_size = domain_end - domain_begin - 1; - else - domain_size = domain_end - domain_begin; - domain = strndup(domain_begin, domain_size); - if (encodeCode) - dataEncode((unsigned char *)domain, domain_size); - if (domain == NULL || domain_size <= 0) - goto response_client; - if (hostsfp && (ips = hosts_lookup(domain)) != NULL) { - free(domain); - build_http_rsp(in, ips); - if (in->http_rsp == NULL) { - in->http_rsp = ERROR_MSG; - in->http_rsp_len = sizeof(ERROR_MSG) - 1; - } + //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); + ev.events = EPOLLIN | EPOLLET; + ev.data.ptr = out; + epoll_ctl(dns_efd, EPOLL_CTL_MOD, out->fd, &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); } else { - build_dns_req(in, domain, domain_size); - free(domain); - int ret = send_dns_req(in->dns_req, in->dns_req_len); - switch (ret) { - case 0: - in->sent_len = in->dns_req_len; - ev.events = EPOLLIN; - break; + //puts("write error"); + free(out->http_request); + epoll_ctl(dns_efd, EPOLL_CTL_DEL, out->fd, NULL); + close(out->fd); + out->query_type = 0; + } +} - case -1: - close_client(in); +void http_in(dns_t * in) +{ + char *ip_ptr, *p; + int len, 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"); + if (p) { + //部分代理服务器使用长连接,第二次读取数据才读到域名的IP + if (p + 3 - http_rsp >= len) return; - - default: - in->sent_len += ret; - ev.events = EPOLLIN | EPOLLOUT; - break; + 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; + do { + if (*p == '\n') + p++; + /* 匹配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, '.')) { + if (i < 3) { + if (p == NULL) + goto error; + //查找下一行 + if (p - ip_ptr > 3) + break; + in->reply[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); + return; + } } - ev.data.fd = dstFd; - epoll_ctl(eFd, EPOLL_CTL_MOD, dstFd, &ev); - return; - } + } while ((p = strchr(p, '\n')) != NULL); -response_client: - response_client(in); - if (in->http_rsp) { - ev.data.ptr = in; - ev.events = EPOLLOUT | EPOLLET; - epoll_ctl(eFd, EPOLL_CTL_MOD, in->fd, &ev); - } +error: + free(in->reply); + in->reply = NULL; + if (build_dns_response(in) == 1) + in->query_type = 0; } -void httpdns_accept_client() +void new_client(conf *configure) { - struct sockaddr_in addr; - dns_t *client; - int i; + dns_t *dns; + int i, len; - for (i = MAX_FD - 2; i--;) { - if (dns_list[i].fd < 0) { - client = &dns_list[i]; + for (i = 0; i < DNS_MAX_CONNECTION; i++) + if (dns_list[i].query_type == 0) break; + if (i == DNS_MAX_CONNECTION) + 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)); + //dns请求必须大于18 + if (len <= 18) + return; + /* 查询缓存 */ + 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; } } - //printf("i = %d\n" , i); - if (i < 0) - return; - client->fd = accept(listenFd, (struct sockaddr *)&addr, &addr_len); - if (client->fd < 0) { + 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; return; } - fcntl(client->fd, F_SETFL, O_NONBLOCK); - ev.data.ptr = client; - ev.events = EPOLLIN | EPOLLET; - if (epoll_ctl(eFd, EPOLL_CTL_ADD, client->fd, &ev) != 0) { - close(client->fd); - client->fd = -1; + 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); + + ev.events = EPOLLOUT | EPOLLERR | EPOLLET; + ev.data.ptr = dns; + epoll_ctl(dns_efd, EPOLL_CTL_ADD, dns->fd, &ev); } -int httpdns_initialize() +void *httpdns_loop(void *p) { - struct sockaddr_in listenAddr, dnsAddr; - int optval = 0; + conf *configure = (conf *) p; + int n; - //ignore PIPE signal - signal(SIGPIPE, SIG_IGN); - dnsAddr.sin_family = listenAddr.sin_family = AF_INET; // IPv4 - dnsAddr.sin_addr.s_addr = inet_addr(DEFAULT_UPPER_IP); // 本地监听 - dnsAddr.sin_port = htons(53); - - listenAddr.sin_addr.s_addr = INADDR_ANY; - listenAddr.sin_port = htons(53); - - listenFd = socket(AF_INET, SOCK_STREAM, 0); // 本地监听,TCP协议 - dstFd = socket(AF_INET, SOCK_DGRAM, 0); // DNS监听,UDP协议 - if (dstFd < 0 || listenFd < 0) { - perror("socket"); - return 1; - } - fcntl(dstFd, F_SETFL, O_NONBLOCK); // dstFd 非阻塞 - fcntl(listenFd, F_SETFL, O_NONBLOCK); // listenFd 非阻塞 - - optval = 1; - if (setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0) { - perror("setsockopt"); - return 1; - } - if (bind(listenFd, (struct sockaddr *)&listenAddr, sizeof(listenAddr)) != 0) { - perror("bind"); - return 1; - } - if (listen(listenFd, 20) != 0) { - perror("listen"); - return 1; - } - - eFd = epoll_create(MAX_FD - 1); - if (eFd < 0) { + fcntl(dnsListenFd, F_SETFL, O_NONBLOCK); + dns_efd = epoll_create(DNS_MAX_CONNECTION + 1); + if (dns_efd < 0) { perror("epoll_create"); - return 1; + return NULL; } - connect(dstFd, (struct sockaddr *)&dnsAddr, sizeof(dnsAddr)); - ev.data.fd = listenFd; + ev.data.fd = dnsListenFd; ev.events = EPOLLIN; - epoll_ctl(eFd, EPOLL_CTL_ADD, listenFd, &ev); - ev.data.fd = dstFd; - ev.events = EPOLLIN; - epoll_ctl(eFd, EPOLL_CTL_ADD, dstFd, &ev); + epoll_ctl(dns_efd, EPOLL_CTL_ADD, dnsListenFd, &ev); memset(dns_list, 0, sizeof(dns_list)); - //初始化DNS请求结构 - int16_t i; - for (i = MAX_FD - 2; i--;) { - dns_list[i].fd = -1; - memcpy(dns_list[i].dns_req, &i, sizeof(i)); - dns_list[i].dns_req[2] = 1; - dns_list[i].dns_req[3] = 0; - dns_list[i].dns_req[4] = 0; - dns_list[i].dns_req[5] = 1; - dns_list[i].dns_req[6] = 0; - dns_list[i].dns_req[7] = 0; - dns_list[i].dns_req[8] = 0; - dns_list[i].dns_req[9] = 0; - dns_list[i].dns_req[10] = 0; - dns_list[i].dns_req[11] = 0; + + while (1) { + n = epoll_wait(dns_efd, evs, DNS_MAX_CONNECTION + 1, -1); + while (n-- > 0) { + if (evs[n].data.fd == dnsListenFd) { + if (evs[n].events & EPOLLIN) { + new_client(configure); + } + if (evs[n].events & EPOLLOUT) { + respond_clients(); + } + } 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; } -void *httpdns_start_server(void *p) -{ - int n; - - while (1) { - n = epoll_wait(eFd, evs, MAX_FD - 1, -1); - //printf("n = %d\n", n); - while (n-- > 0) { - if (evs[n].data.fd == listenFd) { - httpdns_accept_client(); - } else if (evs[n].data.fd == dstFd) { - if (evs[n].events & EPOLLIN) { - recv_dns_rsp(); - } else if (evs[n].events & EPOLLOUT) { - query_dns(); - } - } else if (evs[n].events & EPOLLIN) { - read_client(evs[n].data.ptr); - } else if (evs[n].events & EPOLLOUT) { - response_client(evs[n].data.ptr); - } - } - } - return NULL; -} diff --git a/httpdns.h b/httpdns.h index d2c369a..bbce974 100644 --- a/httpdns.h +++ b/httpdns.h @@ -2,54 +2,52 @@ #define _HTTPDNS_ #include -#include #include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#define DEFAULT_UPPER_IP "114.114.114.114" -#define MAX_FD 1024 -#define DNS_REQUEST_SIZE 512 -#define BUFF_SIZE 1024 +#include "conf.h" -typedef struct dns_request { - char dns_req[DNS_REQUEST_SIZE + 1]; - char *http_rsp; - unsigned int http_rsp_len, sent_len, dns_req_len; +#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_hosts { - char *host; - char *ip; - struct dns_hosts *next; +struct dns_cache { + int question_len; + char *question; + char *answer; + struct dns_cache *next; }; -#define VERSION "0.3" -#define ERROR_MSG "HTTP/1.0 404 Not Found\r\nConnection: close\r\nVia: Mmmdbybyd(HTTP-DNS Server "VERSION")\r\nContent-type: charset=utf-8\r\n\r\nHTTP DNS Server查询域名失败

By: 萌萌萌得不要不要哒
E-mail: 915445800@qq.com" -#define SUCCESS_HEADER "HTTP/1.0 200 OK\r\nConnection: close\r\nVia: Mmmdbybyd(HTTP-DNS Server "VERSION")\r\n\r\n" +dns_t dns_list[DNS_MAX_CONNECTION]; +struct epoll_event evs[DNS_MAX_CONNECTION+1], ev; -dns_t dns_list[MAX_FD - 2]; //监听客户端FD DNS服务端fd -struct epoll_event evs[MAX_FD - 1], ev; -int listenFd, dstFd, eFd; -socklen_t addr_len; -void recv_dns_rsp(); -void query_dns(); -void read_client(dns_t * in); -void response_client(dns_t * out); -void httpdns_accept_client(); -int httpdns_initialize(); -void *httpdns_start_server(); +void *httpdns_loop(void *p); +int httpdns_initialize(conf * configure); + #endif diff --git a/proxy.c b/main.c similarity index 94% rename from proxy.c rename to main.c index 68e5e52..9f197a2 100644 --- a/proxy.c +++ b/main.c @@ -1,6 +1,6 @@ -#include "proxy.h" -#include "http.h" -#include "request.h" +#include "main.h" +#include "http_proxy.h" +#include "http_request.h" #include "timeout.h" #include "conf.h" #include "kill.h" @@ -185,19 +185,11 @@ int process_signal(int signal, char *process_name) printf("\t%d\n", num[n]); } } - if (signal == SERVER_STOP) { // 关闭 + if (signal == SERVER_STOP || signal == SERVER_RELOAD) { // 关闭 struct passwd *pwent = NULL; pwent = getpwnam("root"); return kill_all(15, 1, &process_name, pwent); } - if (signal == SERVER_RELOAD) { // 重启 - n -= 2; - for (; n >= 0; n--) { - //printf("\t%d\n", num[n]); - //printf("kill 返回 %d\n", kill(num[n], SIGTERM)); - kill(num[n], SIGTERM); - } - } return 0; } @@ -241,8 +233,8 @@ void _main(int argc, char *argv[]) if (configure->sslencoding > 0) // 如果配置文件有sslencoding值,优先使用配置文件读取的值 sslEncodeCode = configure->sslencoding; timeout_minute = 0; // 默认不超时 - if (configure->timer > 0) // 如果配置文件有值,优先使用配置文件读取的值 - timeout_minute = configure->timer; + if (configure->timeout > 0) // 如果配置文件有值,优先使用配置文件读取的值 + timeout_minute = configure->timeout; process = 2; // 默认开启2个进程 if (configure->process > 0) // 如果配置文件有值,优先使用配置文件读取的值 process = configure->process; @@ -319,7 +311,7 @@ void _main(int argc, char *argv[]) } } - httpdns_initialize(); // 初始化http_dns + httpdns_initialize(configure); // 初始化http_dns memset(cts, 0, sizeof(cts)); for (i = MAX_CONNECTION; i--;) cts[i].fd = -1; @@ -331,7 +323,7 @@ void _main(int argc, char *argv[]) exit(1); } } - server_sock = create_server_socket(configure->local_port); + server_sock = create_server_socket(configure->tcp_listen); epollfd = epoll_create(MAX_CONNECTION); if (epollfd == -1) { perror("epoll_create"); @@ -347,7 +339,7 @@ void _main(int argc, char *argv[]) exit(1); server_ini(); // 初始化http_proxy - pthread_t thread_id; + pthread_t thread_id = 0; sigset_t signal_mask; sigemptyset(&signal_mask); sigaddset(&signal_mask, SIGPIPE); // 忽略PIPE信号 @@ -359,13 +351,13 @@ void _main(int argc, char *argv[]) pthread_create(&thread_id, NULL, &close_timeout_connectionLoop, NULL); if (pthread_create(&thread_id, NULL, &http_proxy_loop, (void *)configure) != 0) perror("pthread_create"); - - if (pthread_create(&thread_id, NULL, &httpdns_start_server, NULL) != 0) + if (pthread_create(&thread_id, NULL, &httpdns_loop, (void *)configure) != 0) perror("pthread_create"); pthread_join(thread_id, NULL); pthread_exit(NULL); + return ; } int main(int argc, char *argv[]) diff --git a/proxy.h b/main.h similarity index 96% rename from proxy.h rename to main.h index 62bcde5..63f49bd 100644 --- a/proxy.h +++ b/main.h @@ -21,7 +21,7 @@ #include #define MAX_CONNECTION 1020 -#define BUFFER_SIZE 10240 +#define BUFFER_SIZE 8192 #define PATH_SIZE 270 int local_port; diff --git a/picohttpparser.c b/picohttpparser.c deleted file mode 100644 index 72fffee..0000000 --- a/picohttpparser.c +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, - * Shigeo Mitsunari - * - * The software is licensed under either the MIT License (below) or the Perl - * license. - * - * 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 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. - */ - -#include -#include -#include -#ifdef __SSE4_2__ -#ifdef _MSC_VER -#include -#else -#include -#endif -#endif -#include "picohttpparser.h" - -#if __GNUC__ >= 3 -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else -#define likely(x) (x) -#define unlikely(x) (x) -#endif - -#ifdef _MSC_VER -#define ALIGNED(n) _declspec(align(n)) -#else -#define ALIGNED(n) __attribute__((aligned(n))) -#endif - -#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u) - -#define CHECK_EOF() \ - if (buf == buf_end) { \ - *ret = -2; \ - return NULL; \ - } - -#define EXPECT_CHAR_NO_CHECK(ch) \ - if (*buf++ != ch) { \ - *ret = -1; \ - return NULL; \ - } - -#define EXPECT_CHAR(ch) \ - CHECK_EOF(); \ - EXPECT_CHAR_NO_CHECK(ch); - -#define ADVANCE_TOKEN(tok, toklen) \ - do { \ - const char *tok_start = buf; \ - static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \ - int found2; \ - buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \ - if (!found2) { \ - CHECK_EOF(); \ - } \ - while (1) { \ - if (*buf == ' ') { \ - break; \ - } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ - if ((unsigned char)*buf < '\040' || *buf == '\177') { \ - *ret = -1; \ - return NULL; \ - } \ - } \ - ++buf; \ - CHECK_EOF(); \ - } \ - tok = tok_start; \ - toklen = buf - tok_start; \ - } while (0) - -static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - -static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) -{ - *found = 0; -#if __SSE4_2__ - if (likely(buf_end - buf >= 16)) { - __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); - - size_t left = (buf_end - buf) & ~15; - do { - __m128i b16 = _mm_loadu_si128((const __m128i *)buf); - int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); - if (unlikely(r != 16)) { - buf += r; - *found = 1; - break; - } - buf += 16; - left -= 16; - } while (likely(left != 0)); - } -#else - /* suppress unused parameter warning */ - (void)buf_end; - (void)ranges; - (void)ranges_size; -#endif - return buf; -} - -static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) -{ - const char *token_start = buf; - -#ifdef __SSE4_2__ - static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ - "\012\037" /* allow SP and up to but not including DEL */ - "\177\177"; /* allow chars w. MSB set */ - int found; - buf = findchar_fast(buf, buf_end, ranges1, 6, &found); - if (found) - goto FOUND_CTL; -#else - /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ - while (likely(buf_end - buf >= 8)) { -#define DOIT() \ - do { \ - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ - goto NonPrintable; \ - ++buf; \ - } while (0) - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); -#undef DOIT - continue; -NonPrintable: - if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { - goto FOUND_CTL; - } - ++buf; - } -#endif - for (;; ++buf) { - CHECK_EOF(); - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { - if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { - goto FOUND_CTL; - } - } - } -FOUND_CTL: - if (likely(*buf == '\015')) { - ++buf; - EXPECT_CHAR('\012'); - *token_len = buf - 2 - token_start; - } else if (*buf == '\012') { - *token_len = buf - token_start; - ++buf; - } else { - *ret = -1; - return NULL; - } - *token = token_start; - - return buf; -} - -static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) -{ - int ret_cnt = 0; - buf = last_len < 3 ? buf : buf + last_len - 3; - - while (1) { - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - CHECK_EOF(); - EXPECT_CHAR('\012'); - ++ret_cnt; - } else if (*buf == '\012') { - ++buf; - ++ret_cnt; - } else { - ++buf; - ret_cnt = 0; - } - if (ret_cnt == 2) { - return buf; - } - } - - *ret = -2; - return NULL; -} - -#define PARSE_INT(valp_, mul_) \ - if (*buf < '0' || '9' < *buf) { \ - buf++; \ - *ret = -1; \ - return NULL; \ - } \ - *(valp_) = (mul_) * (*buf++ - '0'); - -#define PARSE_INT_3(valp_) \ - do { \ - int res_ = 0; \ - PARSE_INT(&res_, 100) \ - *valp_ = res_; \ - PARSE_INT(&res_, 10) \ - *valp_ += res_; \ - PARSE_INT(&res_, 1) \ - *valp_ += res_; \ - } while (0) - -/* returned pointer is always within [buf, buf_end), or null */ -static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) -{ - /* we want at least [HTTP/1.] to try to parse */ - if (buf_end - buf < 9) { - *ret = -2; - return NULL; - } - EXPECT_CHAR_NO_CHECK('H'); - EXPECT_CHAR_NO_CHECK('T'); - EXPECT_CHAR_NO_CHECK('T'); - EXPECT_CHAR_NO_CHECK('P'); - EXPECT_CHAR_NO_CHECK('/'); - EXPECT_CHAR_NO_CHECK('1'); - EXPECT_CHAR_NO_CHECK('.'); - PARSE_INT(minor_version, 1); - return buf; -} - -static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) -{ - for (;; ++*num_headers) { - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - break; - } else if (*buf == '\012') { - ++buf; - break; - } - if (*num_headers == max_headers) { - *ret = -1; - return NULL; - } - if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { - /* parsing name, but do not discard SP before colon, see - * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ - headers[*num_headers].name = buf; - static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */ - "\"\"" /* 0x22 */ - "()" /* 0x28,0x29 */ - ",," /* 0x2c */ - "//" /* 0x2f */ - ":@" /* 0x3a-0x40 */ - "[]" /* 0x5b-0x5d */ - "{\377"; /* 0x7b-0xff */ - int found; - buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); - if (!found) { - CHECK_EOF(); - } - while (1) { - if (*buf == ':') { - break; - } else if (!token_char_map[(unsigned char)*buf]) { - *ret = -1; - return NULL; - } - ++buf; - CHECK_EOF(); - } - if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) { - *ret = -1; - return NULL; - } - ++buf; - for (;; ++buf) { - CHECK_EOF(); - if (!(*buf == ' ' || *buf == '\t')) { - break; - } - } - } else { - headers[*num_headers].name = NULL; - headers[*num_headers].name_len = 0; - } - const char *value; - size_t value_len; - if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) { - return NULL; - } - /* remove trailing SPs and HTABs */ - const char *value_end = value + value_len; - for (; value_end != value; --value_end) { - const char c = *(value_end - 1); - if (!(c == ' ' || c == '\t')) { - break; - } - } - headers[*num_headers].value = value; - headers[*num_headers].value_len = value_end - value; - } - return buf; -} - -static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) -{ - /* skip first empty line (some clients add CRLF after POST content) */ - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - } else if (*buf == '\012') { - ++buf; - } - - /* parse request line */ - ADVANCE_TOKEN(*method, *method_len); - do { - ++buf; - } while (*buf == ' '); - ADVANCE_TOKEN(*path, *path_len); - do { - ++buf; - } while (*buf == ' '); - if (*method_len == 0 || *path_len == 0) { - *ret = -1; - return NULL; - } - if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { - return NULL; - } - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - } else if (*buf == '\012') { - ++buf; - } else { - *ret = -1; - return NULL; - } - - return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); -} - -int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf_start + len; - size_t max_headers = *num_headers; - int r; - - *method = NULL; - *method_len = 0; - *path = NULL; - *path_len = 0; - *minor_version = -1; - *num_headers = 0; - - /* if last_len != 0, check if the request is complete (a fast countermeasure - againt slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status, const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) -{ - /* parse "HTTP/1.x" */ - if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { - return NULL; - } - /* skip space */ - if (*buf != ' ') { - *ret = -1; - return NULL; - } - do { - ++buf; - } while (*buf == ' '); - /* parse status code, we want at least [:digit:][:digit:][:digit:] to try to parse */ - if (buf_end - buf < 4) { - *ret = -2; - return NULL; - } - PARSE_INT_3(status); - - /* get message includig preceding space */ - if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { - return NULL; - } - if (*msg_len == 0) { - /* ok */ - } else if (**msg == ' ') { - /* remove preceding space */ - do { - ++*msg; - --*msg_len; - } while (**msg == ' '); - } else { - /* garbage found after status code */ - *ret = -1; - return NULL; - } - - return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); -} - -int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; - - *minor_version = -1; - *status = 0; - *msg = NULL; - *msg_len = 0; - *num_headers = 0; - - /* if last_len != 0, check if the response is complete (a fast countermeasure - against slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; - - *num_headers = 0; - - /* if last_len != 0, check if the response is complete (a fast countermeasure - against slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -enum { - CHUNKED_IN_CHUNK_SIZE, - CHUNKED_IN_CHUNK_EXT, - CHUNKED_IN_CHUNK_DATA, - CHUNKED_IN_CHUNK_CRLF, - CHUNKED_IN_TRAILERS_LINE_HEAD, - CHUNKED_IN_TRAILERS_LINE_MIDDLE -}; - -static int decode_hex(int ch) -{ - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } else if ('A' <= ch && ch <= 'F') { - return ch - 'A' + 0xa; - } else if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } else { - return -1; - } -} - -ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) -{ - size_t dst = 0, src = 0, bufsz = *_bufsz; - ssize_t ret = -2; /* incomplete */ - - while (1) { - switch (decoder->_state) { - case CHUNKED_IN_CHUNK_SIZE: - for (;; ++src) { - int v; - if (src == bufsz) - goto Exit; - if ((v = decode_hex(buf[src])) == -1) { - if (decoder->_hex_count == 0) { - ret = -1; - goto Exit; - } - break; - } - if (decoder->_hex_count == sizeof(size_t) * 2) { - ret = -1; - goto Exit; - } - decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; - ++decoder->_hex_count; - } - decoder->_hex_count = 0; - decoder->_state = CHUNKED_IN_CHUNK_EXT; - /* fallthru */ - case CHUNKED_IN_CHUNK_EXT: - /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - if (decoder->bytes_left_in_chunk == 0) { - if (decoder->consume_trailer) { - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - } else { - goto Complete; - } - } - decoder->_state = CHUNKED_IN_CHUNK_DATA; - /* fallthru */ - case CHUNKED_IN_CHUNK_DATA:{ - size_t avail = bufsz - src; - if (avail < decoder->bytes_left_in_chunk) { - if (dst != src) - memmove(buf + dst, buf + src, avail); - src += avail; - dst += avail; - decoder->bytes_left_in_chunk -= avail; - goto Exit; - } - if (dst != src) - memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); - src += decoder->bytes_left_in_chunk; - dst += decoder->bytes_left_in_chunk; - decoder->bytes_left_in_chunk = 0; - decoder->_state = CHUNKED_IN_CHUNK_CRLF; - } - /* fallthru */ - case CHUNKED_IN_CHUNK_CRLF: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src] != '\012') { - ret = -1; - goto Exit; - } - ++src; - decoder->_state = CHUNKED_IN_CHUNK_SIZE; - break; - case CHUNKED_IN_TRAILERS_LINE_HEAD: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src++] == '\012') - goto Complete; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; - /* fallthru */ - case CHUNKED_IN_TRAILERS_LINE_MIDDLE: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - default: - assert(!"decoder is corrupt"); - } - } - -Complete: - ret = bufsz - src; -Exit: - if (dst != src) - memmove(buf + dst, buf + src, bufsz - src); - *_bufsz = dst; - return ret; -} - -int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) -{ - return decoder->_state == CHUNKED_IN_CHUNK_DATA; -} - -#undef CHECK_EOF -#undef EXPECT_CHAR -#undef ADVANCE_TOKEN diff --git a/picohttpparser.h b/picohttpparser.h deleted file mode 100644 index d9f8fd6..0000000 --- a/picohttpparser.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, - * Shigeo Mitsunari - * - * The software is licensed under either the MIT License (below) or the Perl - * license. - * - * 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 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. - */ - -#ifndef picohttpparser_h -#define picohttpparser_h - -#include - -#ifdef _MSC_VER -#define ssize_t intptr_t -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* contains name and value of a header (name == NULL if is a continuing line - * of a multiline header */ - struct phr_header { - const char *name; - size_t name_len; - const char *value; - size_t value_len; - }; - -/* returns number of bytes consumed if successful, -2 if request is partial, - * -1 if failed */ - int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len); - -/* ditto */ - int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len); - -/* ditto */ - int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len); - -/* should be zero-filled before start */ - struct phr_chunked_decoder { - size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ - char consume_trailer; /* if trailing headers should be consumed */ - char _hex_count; - char _state; - }; - -/* the function rewrites the buffer given as (buf, bufsz) removing the chunked- - * encoding headers. When the function returns without an error, bufsz is - * updated to the length of the decoded data available. Applications should - * repeatedly call the function while it returns -2 (incomplete) every time - * supplying newly arrived data. If the end of the chunked-encoded data is - * found, the function returns a non-negative number indicating the number of - * octets left undecoded at the tail of the supplied buffer. Returns -1 on - * error. - */ - ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *bufsz); - -/* returns if the chunked decoder is in middle of chunked data */ - int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/timeout.c b/timeout.c index 80ec010..8b28344 100644 --- a/timeout.c +++ b/timeout.c @@ -1,5 +1,6 @@ -#include "proxy.h" -#include "http.h" +#include "timeout.h" +#include "main.h" +#include "http_proxy.h" int timeout_minute;