Modify httpdns for Android, and fix the problem of negative number when get gets the length of host.
This commit is contained in:
parent
247f56f925
commit
627051ac94
11
CProxy.conf
11
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";
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
6
Makefile
6
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
|
||||
|
@ -4,7 +4,7 @@
|
||||
可以修改HTTP协议消息头(request).
|
||||
可以修改HTTP协议CONNECT方法消息头.
|
||||
可以修改HTTP协议GET方法消息头.
|
||||
支持IPV6.
|
||||
支持IPV4/IPV6.
|
||||
|
||||
## Build
|
||||
|
||||
|
98
conf.c
98
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");
|
||||
else
|
||||
parse_global_module(global_content, configure);
|
||||
free(global_content);
|
||||
|
||||
if ((http_content = read_module(buff, "http")) == NULL)
|
||||
perror("read http module error");
|
||||
else
|
||||
parse_http_module(http_content, configure);
|
||||
free(http_content);
|
||||
|
||||
if ((https_content = read_module(buff, "https")) == NULL)
|
||||
perror("read https module error");
|
||||
else
|
||||
parse_https_module(https_content, configure);
|
||||
free(https_content);
|
||||
|
||||
if ((httpdns_content = read_module(buff, "httpdns")) == NULL)
|
||||
perror("read httpdns module error");
|
||||
else
|
||||
parse_httpdns_module(httpdns_content, configure);
|
||||
free(httpdns_content);
|
||||
}
|
||||
|
6
help.c
6
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]";
|
||||
|
17
http_proxy.c
17
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;
|
||||
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)
|
||||
@ -122,13 +121,7 @@ static int8_t request_type(char *data)
|
||||
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)
|
||||
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;
|
||||
|
||||
|
10
http_proxy.h
10
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
|
||||
|
156
http_request.c
156
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)
|
||||
@ -198,7 +215,6 @@ int extract_host(char *header, char *host, char *port)
|
||||
}
|
||||
|
||||
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);
|
||||
@ -241,30 +257,33 @@ int extract_host(char *header, char *host, char *port)
|
||||
} 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));
|
||||
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,6 +296,11 @@ char *get_http_path(char *url, char *path)
|
||||
{
|
||||
char *_p0;
|
||||
_p0 = NULL;
|
||||
int url_len;
|
||||
url_len = 0;
|
||||
url_len = strlen(url);
|
||||
|
||||
if (url_len > 7) {
|
||||
if (url) {
|
||||
_p0 = strstr(url + 7, "/");
|
||||
if (_p0)
|
||||
@ -284,18 +308,21 @@ char *get_http_path(char *url, char *path)
|
||||
else
|
||||
memcpy(path, "/", 1); // 如果没有资源路径就默认"/"
|
||||
}
|
||||
} else {
|
||||
memcpy(path, "/", 1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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,7 +335,8 @@ 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行
|
||||
@ -316,13 +344,13 @@ void get_http_host_port_len(char *head, int *host_len, int *port_len) {
|
||||
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;
|
||||
}
|
||||
@ -332,13 +360,13 @@ void get_http_host_port_len(char *head, int *host_len, int *port_len) {
|
||||
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;
|
||||
}
|
||||
@ -348,18 +376,15 @@ void get_http_host_port_len(char *head, int *host_len, int *port_len) {
|
||||
}
|
||||
}
|
||||
|
||||
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,32 +398,30 @@ 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长度
|
||||
@ -420,26 +443,26 @@ void parse_request_head(char *http_request_line, struct http_request *http_reque
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -523,19 +546,10 @@ char *request_head(conn_t * in, conf * configure)
|
||||
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内存
|
||||
|
||||
}
|
||||
|
||||
if (strncmp(in->incomplete_data, "GET", 3) == 0 || strncmp(in->incomplete_data, "POST", 4) == 0) {
|
||||
@ -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);
|
||||
@ -595,14 +609,6 @@ char *request_head(conn_t * in, conf * configure)
|
||||
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长度
|
||||
|
@ -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
|
||||
|
763
httpdns.c
763
httpdns.c
@ -1,130 +1,184 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
void cache_record(dns_t * dns)
|
||||
/* 查询缓存 */
|
||||
static uint8_t cache_lookup(dns_t * dns)
|
||||
{
|
||||
cache_temp = (struct dns_cache *)malloc(sizeof(*cache));
|
||||
struct dns_cache *c;
|
||||
char *rsp;
|
||||
|
||||
for (c = cache; c; c = c->next) {
|
||||
//不匹配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 1;
|
||||
}
|
||||
|
||||
/* 记录缓存 */
|
||||
static void cache_record(char *request, uint16_t request_len, char *response, uint16_t response_len)
|
||||
{
|
||||
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,52 +186,20 @@ 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)
|
||||
dns->query_type = *(dns_req + 2 + dns->host_len);
|
||||
//tcpdns不需要解析域名
|
||||
if (httpdns.tcpDNS_mode == 1)
|
||||
return 0;
|
||||
//httpdns只支持域名查询ipv4
|
||||
if (dns->query_type != 1 || (dns->host = strdup(dns_req)) == NULL)
|
||||
return 1;
|
||||
int len;
|
||||
for (len = *(--dns_req); dns_req[len + 1] != 0; len += dns_req[len]) {
|
||||
//防止数组越界
|
||||
if (len > dns->host_len) {
|
||||
@ -186,46 +208,47 @@ int parse_dns_request(char *dns_req, dns_t * dns)
|
||||
}
|
||||
dns->host[len++] = '.';
|
||||
}
|
||||
//printf("dns->host: %s\n", dns->host);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
dns->host = NULL;
|
||||
return 1;
|
||||
}
|
||||
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);
|
||||
} 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->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) {
|
||||
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;i<dns->out_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)
|
||||
break;
|
||||
if (i == DNS_MAX_CONNECTION)
|
||||
return;
|
||||
for (i = 0; i < DNS_MAX_CONCURRENT; i++) {
|
||||
if (dns_list[i].query_type == 0) {
|
||||
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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == DNS_MAX_CONCURRENT)
|
||||
return;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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; //消除编译警告
|
||||
}
|
||||
|
62
httpdns.h
Normal file → Executable file
62
httpdns.h
Normal file → Executable file
@ -1,51 +1,25 @@
|
||||
#ifndef _HTTPDNS_
|
||||
#define _HTTPDNS_
|
||||
#ifndef HTTPDNS_H
|
||||
#define HTTPDNS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <signal.h>
|
||||
#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
|
||||
|
463
kill.c
463
kill.c
@ -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;
|
||||
}
|
60
kill.h
60
kill.h
@ -1,60 +0,0 @@
|
||||
#ifndef KILL_H
|
||||
#define KILL_H
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <getopt.h>
|
||||
#include <pwd.h>
|
||||
#include <regex.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <locale.h>
|
||||
|
||||
#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
|
190
main.c
190
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)
|
||||
{
|
||||
@ -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));
|
||||
@ -387,6 +498,7 @@ void _main(int argc, char *argv[])
|
||||
break;
|
||||
case 'c':
|
||||
free_conf(configure);
|
||||
memset(configure, 0, sizeof(struct CONF));
|
||||
read_conf(optarg, configure);
|
||||
break;
|
||||
case 'e':
|
||||
@ -413,69 +525,19 @@ 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;
|
||||
}
|
||||
|
||||
|
22
main.h
22
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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user