Compare commits
12 Commits
247f56f925
...
master
Author | SHA1 | Date | |
---|---|---|---|
1e162d641b | |||
9a2c98f059 | |||
0efa5309a6 | |||
f6800178f4 | |||
5e3b8d0194 | |||
890afe93c8 | |||
2881609c0c | |||
c0e238eb0c | |||
cb68da2b3c | |||
40df4da8b8 | |||
9aa4d19547 | |||
627051ac94 |
0
Android.mk
Normal file → Executable file
0
Android.mk
Normal file → Executable file
0
Application.mk
Normal file → Executable file
0
Application.mk
Normal file → Executable file
47
CProxy.conf
47
CProxy.conf
@ -1,33 +1,44 @@
|
|||||||
global {
|
global {
|
||||||
uid=3004;
|
uid=3004;
|
||||||
|
timeout=60;
|
||||||
process=2;
|
process=2;
|
||||||
timeout=10;
|
|
||||||
encode=128;
|
|
||||||
tcp_listen=0124;
|
tcp_listen=0124;
|
||||||
tcp6_listen=0124;
|
|
||||||
dns_listen=0126;
|
dns_listen=0126;
|
||||||
|
udp_listen = 10010;
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
http_ip="47.240.75.93";
|
http_ip="43.142.66.71";
|
||||||
http_port=127;
|
http_port=129;
|
||||||
http_del="Host";
|
http_del="Host,";
|
||||||
http_first="[M] http://[host][U] [V]\r\nHost: [H]\r\n";
|
http_first="[M] [U] [V]\r\nHost: [H]\r\n";
|
||||||
//strrep="Windows NT 10.0->Linux";
|
strrep="Windows NT 10.0" -> "Linux";
|
||||||
//regrep="Host:*.+?->Host: [host]:80";
|
strrep="Linux" -> "aixiao.me";
|
||||||
|
strrep="aixiao.me" -> "AIXIAO.ME";
|
||||||
|
regrep="Accept-Encoding*.+?" -> "Accept-Encoding: GZIP, deflate";
|
||||||
|
regrep="Connection*.+?" -> "Connection: KEEP-alive";
|
||||||
|
encode=129;
|
||||||
}
|
}
|
||||||
|
|
||||||
https {
|
https {
|
||||||
https_ip="47.240.75.93";
|
https_ip="43.142.66.71";
|
||||||
https_port=127;
|
https_port=129;
|
||||||
https_del="Host,host,x-online-host";
|
https_del="Host,host,x-online-host,Proxy-Connection";
|
||||||
https_first="[M] [U] [V]\r\nHost: [host]\r\n";
|
https_first="[M] [U] [V]\r\nHost: [host]:[port]\r\n";
|
||||||
//strrep="Windows NT 10.0->Linux";
|
strrep="Windows NT 10.0" -> "Linux";
|
||||||
//regrep="Host*.+?->host: [host]:443";
|
strrep="Linux" -> "aixiao.me";
|
||||||
|
strrep="aixiao.me" -> "AIXIAO.ME";
|
||||||
|
regrep="Accept-Encoding*.+?" -> "Accept-Encoding: GZIP, deflate";
|
||||||
|
regrep="Connection*.+?" -> "Connection: KEEP-alive";
|
||||||
|
encode=129;
|
||||||
}
|
}
|
||||||
|
|
||||||
httpdns {
|
httpdns {
|
||||||
addr=119.29.29.29:53;
|
addr = 119.29.29.29:80;
|
||||||
http_req="[M] http://wap.10010.com/d?dn=[D] [V]\r\nHost: wap.10010.com\r\n";
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n";
|
||||||
encode = 0;
|
}
|
||||||
|
|
||||||
|
httpudp {
|
||||||
|
addr = 47.240.75.93:10010;
|
||||||
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n";
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,90 @@
|
|||||||
|
|
||||||
|
//global模块
|
||||||
global {
|
global {
|
||||||
|
//进程UID
|
||||||
uid=3004;
|
uid=3004;
|
||||||
process=2;
|
|
||||||
|
//超时时间(秒)
|
||||||
timeout=60;
|
timeout=60;
|
||||||
sslencoding=128;
|
|
||||||
|
//TCP, DNS, UDP监听地址
|
||||||
tcp_listen=0124;
|
tcp_listen=0124;
|
||||||
tcp6_listen=0124;
|
dns_listen=0126;
|
||||||
dns_listen=0125;
|
udp_listen = 10010;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//http模块
|
||||||
http {
|
http {
|
||||||
http_ip=cproxy.aixiao.me;
|
//http模块关键字: [M], [method], [uri], [U], [V], [version], [H], [host], [port], \r, \n, \v, \f, \b, \t, \a. 如果原本请求头含有关键字也会被替换.
|
||||||
http_port=124;
|
//[M]、[method] 原请求方法
|
||||||
http_del="x-online-host,X-Online-Host,host,Host";
|
//[U] 原请求url
|
||||||
|
//[uri] 原请求uri(http 模块)
|
||||||
|
//[V]、[version] 原请求协议版本
|
||||||
|
//[host] 原请求host
|
||||||
|
//[port] 原请求端口
|
||||||
|
//[H] 原请求[host]:[port]
|
||||||
|
|
||||||
|
|
||||||
|
//指定HTTP服务器IP
|
||||||
|
http_ip="aixiao.me";
|
||||||
|
|
||||||
|
//指定HTTP服务器端口
|
||||||
|
http_port=129;
|
||||||
|
|
||||||
|
//删除HTTP头字段,逗号分开
|
||||||
|
http_del="Host,";
|
||||||
|
|
||||||
|
//自定义HTTP请求头
|
||||||
http_first="[M] [U] [V]\r\nHost: [H]\r\n";
|
http_first="[M] [U] [V]\r\nHost: [H]\r\n";
|
||||||
//strrep="Windows NT 10.0->Linux";
|
|
||||||
//regrep="Host*.+?->Host: hu60.cn:443";
|
//字符串替换, 以"->"为分界符,"Windows NT 10.0"字符串替换为"Linux"字符串.(可以有多个)
|
||||||
|
strrep="Windows NT 10.0" -> "Linux";
|
||||||
|
strrep="Linux" -> "aixiao.me";
|
||||||
|
strrep="aixiao.me" -> "AIXIAO.ME";
|
||||||
|
|
||||||
|
//正则表达式替换, 以"->"为分界符,匹配到的内容"Accept-Encoding*.+?"替换为"Accept-Encoding: GZIP, deflate"字符串.(可以有多个)
|
||||||
|
regrep="Accept-Encoding*.+?" -> "Accept-Encoding: GZIP, deflate";
|
||||||
|
regrep="Connection*.+?" -> "Connection: KEEP-alive";
|
||||||
|
|
||||||
|
// 编码, 代码128-255要与服务端一致,默认为0不编码
|
||||||
|
encode=129;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//https模块
|
||||||
https {
|
https {
|
||||||
https_ip=cproxy.aixiao.me;
|
|
||||||
https_port=124;
|
https_ip="aixiao.me";
|
||||||
|
https_port=129;
|
||||||
https_del="Host,host,x-online-host";
|
https_del="Host,host,x-online-host";
|
||||||
https_first="[M] [U] [V]\r\nhost: [host]\r\n";
|
https_first="[M] [U] [V]\r\nHost: [host]:[port]\r\n";
|
||||||
strrep="Windows NT 10.0->Linux";
|
encode=129;
|
||||||
//regrep="Host*.+?->Host: hu60.cn:443";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//httpdns模块
|
||||||
httpdns {
|
httpdns {
|
||||||
addr=119.29.29.29:53;
|
//httpdns 模块关键字: [M], [D], [V], \r, \n, \v, \f, \b, \t, \a.
|
||||||
http_req="[M] http://wap.10010.com/d?dn=[D] [V]\r\nHost: wap.10010.com\r\n";
|
//默认 [M] 为 GET
|
||||||
|
//默认 [V] 为 HTTP/1.0
|
||||||
|
|
||||||
|
|
||||||
|
//HTTPDNS服务器IP
|
||||||
|
addr = 119.29.29.29:80;
|
||||||
|
|
||||||
|
//自定义HTTPDNS请求头
|
||||||
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//httpudp模块
|
||||||
global模块
|
httpudp {
|
||||||
uid=3004; //进程UID
|
//httpudp 模块关键字: [M], [U], [V], [H].
|
||||||
process=2; //进程数量(已经弃用)
|
//默认 [M] 为 CONNECT
|
||||||
timeout=60; //超时时间(秒)
|
//默认 [V] 为 HTTP/1.1
|
||||||
sslencoding=128; //编码(非零生效)
|
|
||||||
tcp_listen=0124; //TCP监听端口
|
|
||||||
tcp6_listen=0124; //TCP6监听端口 (TCP和TCP6可以使用同一个端口, IPV4的数据走内部IPV4程序结构, IPV6数据走内部IPV6程序结构.)
|
|
||||||
dns_listen=0125; //UDP监听端口
|
|
||||||
|
|
||||||
|
|
||||||
http、https模块
|
//HTTPUDP服务器IP
|
||||||
http、https 模块关键字: [M], [method], [uri], [U], [V], [version], [H], [host], [port], \r, \n, \v, \f, \b, \t, \a. 如果原本请求头含有关键字也会被替换.
|
addr = 47.240.75.93:10010;
|
||||||
[M]、[method] 原请求方法
|
|
||||||
[U] 原请求url
|
|
||||||
[uri] 原请求uri(http 模块)
|
|
||||||
[V]、[version] 原请求协议版本
|
|
||||||
[host] 原请求host
|
|
||||||
[port] 原请求端口
|
|
||||||
[H] 原请求[host]:[port]
|
|
||||||
|
|
||||||
http_ip=cproxy.aixiao.me; //指定HTTP服务器IP
|
//自定义HTTPUDP请求头
|
||||||
http_port=124; //指定HTTP服务器端口
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n";
|
||||||
http_del="x-online-host,X-Online-Host,host,Host"; //删除HTTP头字段,逗号分开
|
}
|
||||||
http_first="[M] [U] [V]\r\nHost: [H]\r\n"; //自定义HTTP头
|
|
||||||
关键字strrep替换字符串指令.
|
|
||||||
strrep = "Mi MIX 2->Linux"; 以"->"为分界符,"Mi MIX 2"字符串替换为"Linux"字符串.
|
|
||||||
关键字regrep正则匹配替换字符串.
|
|
||||||
regrep = "Host*.+?->Host: iread.wo.cn:443"; 以"->"为分界符,匹配到的内容"Host*.+?"替换为"Host: iread.wo.cn:443"字符串.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
6
Makefile
6
Makefile
@ -5,14 +5,14 @@ CFLAGS += -g -O2 -Wall -pthread
|
|||||||
LIBS =
|
LIBS =
|
||||||
OBJ := CProxy
|
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 http_request.o httpdns.o httpudp.o conf.o
|
||||||
$(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS)
|
$(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS)
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) -c $< $(LIBS)
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.o
|
rm -rf *.o
|
||||||
rm $(OBJ)
|
rm $(OBJ)
|
||||||
|
|
||||||
android:
|
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,8 @@
|
|||||||
可以修改HTTP协议消息头(request).
|
可以修改HTTP协议消息头(request).
|
||||||
可以修改HTTP协议CONNECT方法消息头.
|
可以修改HTTP协议CONNECT方法消息头.
|
||||||
可以修改HTTP协议GET方法消息头.
|
可以修改HTTP协议GET方法消息头.
|
||||||
支持IPV6.
|
HttpTCP支持IPV4/IPV6.
|
||||||
|
支持HttpDNS、HttpUDP代理
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
@ -22,8 +23,8 @@
|
|||||||
|
|
||||||
## Help Information
|
## Help Information
|
||||||
|
|
||||||
CProxy proxy server
|
C Proxy Server
|
||||||
Author: aixiao@aixiao.me
|
Author: AIXIAO@AIXIAO.ME
|
||||||
Usage: [-?h] [-s signal] [-c filename]
|
Usage: [-?h] [-s signal] [-c filename]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@ -31,7 +32,6 @@
|
|||||||
-c --config : set configuration file, default: CProxy.conf
|
-c --config : set configuration file, default: CProxy.conf
|
||||||
-? -h --? --help : help information
|
-? -h --? --help : help information
|
||||||
|
|
||||||
Dec 19 2020 09:18:15 Compile、link.
|
|
||||||
|
|
||||||
#启动
|
#启动
|
||||||
./CProxy -c CProxy.conf
|
./CProxy -c CProxy.conf
|
||||||
|
461
conf.c
461
conf.c
@ -1,17 +1,25 @@
|
|||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "http_request.h"
|
||||||
|
|
||||||
char *strncpy_(char *dest, const char *src, size_t n)
|
/* 字符串预处理,设置转义字符 */
|
||||||
|
static void string_pretreatment(char *str, int *len)
|
||||||
{
|
{
|
||||||
int size = sizeof(char) * (n + 1);
|
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' };
|
||||||
char *tmp = (char *)malloc(size); // 开辟大小为n+1的临时内存tmp
|
int i;
|
||||||
if (tmp) {
|
|
||||||
memset(tmp, '\0', size); // 将内存初始化为0
|
while ((lf = strchr(str, '\n')) != NULL) {
|
||||||
memcpy(tmp, src, size - 1); // 将src的前n个字节拷贝到tmp
|
for (p = lf + 1; *p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'; p++)
|
||||||
memcpy(dest, tmp, size); // 将临时空间tmp的内容拷贝到dest
|
*len -= 1;
|
||||||
free(tmp); // 释放内存
|
strcpy(lf, p);
|
||||||
return dest;
|
*len -= 1;
|
||||||
} else {
|
}
|
||||||
return NULL;
|
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)--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +79,7 @@ static char *set_var_val_lineEnd(char *content, char **var, char **val_begin, ch
|
|||||||
val_len = strlen(*val_begin);
|
val_len = strlen(*val_begin);
|
||||||
*val_end = lineEnd = *val_begin + val_len;
|
*val_end = lineEnd = *val_begin + val_len;
|
||||||
}
|
}
|
||||||
|
string_pretreatment(*val_begin, &val_len);
|
||||||
*val_end = *val_begin + val_len;
|
*val_end = *val_begin + val_len;
|
||||||
//printf("var[%s]\nbegin[%s]\n\n", *var, *val_begin);
|
//printf("var[%s]\nbegin[%s]\n\n", *var, *val_begin);
|
||||||
return lineEnd;
|
return lineEnd;
|
||||||
@ -122,6 +131,8 @@ static void parse_global_module(char *content, conf * p)
|
|||||||
p->tcp6_listen = atoi(val_begin);
|
p->tcp6_listen = atoi(val_begin);
|
||||||
} else if (strcasecmp(var, "dns_listen") == 0) {
|
} else if (strcasecmp(var, "dns_listen") == 0) {
|
||||||
p->dns_listen = atoi(val_begin);
|
p->dns_listen = atoi(val_begin);
|
||||||
|
} else if (strcasecmp(var, "udp_listen") == 0) {
|
||||||
|
p->udp_listen = atoi(val_begin);;
|
||||||
}
|
}
|
||||||
|
|
||||||
content = strchr(lineEnd + 1, '\n');
|
content = strchr(lineEnd + 1, '\n');
|
||||||
@ -131,76 +142,95 @@ static void parse_global_module(char *content, conf * p)
|
|||||||
static void parse_http_module(char *content, conf * p)
|
static void parse_http_module(char *content, conf * p)
|
||||||
{
|
{
|
||||||
char *var, *val_begin, *val_end, *lineEnd;
|
char *var, *val_begin, *val_end, *lineEnd;
|
||||||
int val_begin_len;
|
tcp *http_node = NULL;
|
||||||
|
char *p1 = NULL, *s = NULL, *t = NULL;
|
||||||
|
char *p2 = NULL;
|
||||||
|
|
||||||
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
|
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
|
||||||
if (strcasecmp(var, "http_ip") == 0) {
|
if (strcasecmp(var, "http_ip") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->http_ip_len = val_end - val_begin;
|
||||||
p->http_ip = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->http_ip_len, &p->http_ip) != 0)
|
||||||
memset(p->http_ip, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->http_ip, val_begin, val_begin_len);
|
} else if (strcasecmp(var, "encode") == 0) {
|
||||||
|
p->http_encode = atoi(val_begin);
|
||||||
} else if (strcasecmp(var, "http_port") == 0) {
|
} else if (strcasecmp(var, "http_port") == 0) {
|
||||||
p->http_port = atoi(val_begin);
|
p->http_port = atoi(val_begin);
|
||||||
} else if (strcasecmp(var, "http_del") == 0) {
|
} else if (strcasecmp(var, "http_del") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->http_del_len = val_end - val_begin;
|
||||||
p->http_del = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->http_del_len, &p->http_del) != 0)
|
||||||
memset(p->http_del, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->http_del, val_begin, val_begin_len);
|
|
||||||
p->http_del_len = val_begin_len;
|
|
||||||
} else if (strcasecmp(var, "http_first") == 0) {
|
} else if (strcasecmp(var, "http_first") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->http_first_len = val_end - val_begin;
|
||||||
p->http_first = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->http_first_len, &p->http_first) != 0)
|
||||||
memset(p->http_first, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->http_first, val_begin, val_begin_len);
|
|
||||||
p->http_first_len = val_begin_len;
|
|
||||||
} else if (strcasecmp(var, "strrep") == 0) {
|
} else if (strcasecmp(var, "strrep") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
http_node = (tcp *) malloc(sizeof(struct tcp));
|
||||||
|
if (http_node == NULL)
|
||||||
|
return;
|
||||||
|
memset(http_node, 0, sizeof(struct tcp));
|
||||||
|
http_node->strrep = strdup(val_begin);
|
||||||
|
http_node->strrep_len = val_end - val_begin;
|
||||||
|
|
||||||
p->http_strrep = (char *)malloc(val_begin_len);
|
p1 = strstr(val_begin, "->");
|
||||||
if (p->http_strrep == NULL)
|
for (t = p1; *t != '"'; ++t) ;
|
||||||
free(p->http_strrep);
|
http_node->strrep_t = strdup(t + 1);
|
||||||
memset(p->http_strrep, 0, val_begin_len);
|
p2 = strchr(t + 1, '\0');
|
||||||
memcpy(p->http_strrep, val_begin, val_begin_len);
|
http_node->strrep_t_len = p2 - (t + 1);
|
||||||
|
|
||||||
char *p1 = strstr(val_begin, "->");
|
for (s = p1 - 1; *s == ' '; s--) {
|
||||||
p->http_strrep_aim = (char *)malloc(val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (s == val_begin)
|
||||||
if (p->http_strrep_aim == NULL) {
|
return;
|
||||||
free(p->http_strrep_aim);
|
|
||||||
}
|
}
|
||||||
memset(p->http_strrep_aim, 0, val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (*s == '"')
|
||||||
strncpy_(p->http_strrep_aim, val_begin, val_begin_len - strlen(p1 + 2) - 3); // 实际 val_begin_len 多1
|
s--;
|
||||||
p->http_strrep_obj = (char *)malloc(strlen(p1 + 2) + 1);
|
|
||||||
if (p->http_strrep_obj == NULL) {
|
http_node->strrep_s = strndup(val_begin, s - val_begin + 1);
|
||||||
free(p->http_strrep_obj);
|
http_node->strrep_s_len = s - val_begin + 1;
|
||||||
|
|
||||||
|
http_node->next = NULL;
|
||||||
|
if (http_head_strrep == NULL) {
|
||||||
|
http_head_strrep = http_node;
|
||||||
|
} else {
|
||||||
|
http_node->next = http_head_strrep;
|
||||||
|
http_head_strrep = http_node;
|
||||||
|
|
||||||
|
//http_node->next = http_head_strrep->next;
|
||||||
|
//http_head_strrep->next = http_node;
|
||||||
}
|
}
|
||||||
memset(p->http_strrep_obj, 0, strlen(p1 + 2) + 1);
|
|
||||||
strncpy_(p->http_strrep_obj, p1 + 2, strlen(p1 + 2));
|
|
||||||
p->http_strrep_aim_len = strlen(p->http_strrep_aim);
|
|
||||||
p->http_strrep_obj_len = strlen(p->http_strrep_obj);
|
|
||||||
} else if (strcasecmp(var, "regrep") == 0) {
|
} else if (strcasecmp(var, "regrep") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
http_node = (tcp *) malloc(sizeof(struct tcp));
|
||||||
|
if (http_node == NULL)
|
||||||
|
return;
|
||||||
|
memset(http_node, 0, sizeof(struct tcp));
|
||||||
|
http_node->regrep = strdup(val_begin);
|
||||||
|
http_node->regrep_len = val_end - val_begin;
|
||||||
|
|
||||||
p->http_regrep = (char *)malloc(val_begin_len);
|
p1 = strstr(val_begin, "->");
|
||||||
if (p->http_regrep == NULL)
|
for (t = p1; *t != '"'; ++t) ;
|
||||||
free(p->http_regrep);
|
http_node->regrep_t = strdup(t + 1);
|
||||||
memset(p->http_regrep, 0, val_begin_len);
|
p2 = strchr(t + 1, '\0');
|
||||||
memcpy(p->http_regrep, val_begin, val_begin_len);
|
http_node->regrep_t_len = p2 - (t + 1);
|
||||||
|
|
||||||
char *p1 = strstr(val_begin, "->");
|
for (s = p1 - 1; *s == ' '; s--) {
|
||||||
p->http_regrep_aim = (char *)malloc(val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (s == val_begin)
|
||||||
if (p->http_regrep_aim == NULL) {
|
return;
|
||||||
free(p->http_regrep_aim);
|
|
||||||
}
|
}
|
||||||
memset(p->http_regrep_aim, 0, val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (*s == '"')
|
||||||
strncpy_(p->http_regrep_aim, val_begin, val_begin_len - strlen(p1 + 2) - 3);
|
s--;
|
||||||
p->http_regrep_obj = (char *)malloc(strlen(p1 + 2) + 1);
|
|
||||||
if (p->http_regrep_obj == NULL) {
|
http_node->regrep_s = strndup(val_begin, s - val_begin + 1);
|
||||||
free(p->http_regrep_obj);
|
http_node->regrep_s_len = s - val_begin + 1;
|
||||||
|
|
||||||
|
http_node->next = NULL;
|
||||||
|
if (http_head_regrep == NULL) {
|
||||||
|
http_head_regrep = http_node;
|
||||||
|
} else {
|
||||||
|
http_node->next = http_head_regrep;
|
||||||
|
http_head_regrep = http_node;
|
||||||
|
|
||||||
|
//http_node->next = http_head_regrep->next;
|
||||||
|
//http_head_regrep->next = http_node;
|
||||||
}
|
}
|
||||||
memset(p->http_regrep_obj, 0, strlen(p1 + 2) + 1);
|
|
||||||
strncpy_(p->http_regrep_obj, p1 + 2, strlen(p1 + 2));
|
|
||||||
p->http_regrep_aim_len = strlen(p->http_regrep_aim);
|
|
||||||
p->http_regrep_obj_len = strlen(p->http_regrep_obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
content = strchr(lineEnd + 1, '\n');
|
content = strchr(lineEnd + 1, '\n');
|
||||||
@ -210,160 +240,259 @@ static void parse_http_module(char *content, conf * p)
|
|||||||
static void parse_https_module(char *content, conf * p)
|
static void parse_https_module(char *content, conf * p)
|
||||||
{
|
{
|
||||||
char *var, *val_begin, *val_end, *lineEnd;
|
char *var, *val_begin, *val_end, *lineEnd;
|
||||||
int val_begin_len;
|
tcp *https_node = NULL;
|
||||||
|
char *p1 = NULL, *s = NULL, *t = NULL;
|
||||||
|
char *p2 = NULL;
|
||||||
|
|
||||||
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
|
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
|
||||||
if (strcasecmp(var, "https_ip") == 0) {
|
if (strcasecmp(var, "https_ip") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->https_ip_len = val_end - val_begin;
|
||||||
p->https_ip = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->https_ip_len, &p->https_ip) != 0)
|
||||||
memset(p->https_ip, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->https_ip, val_begin, val_begin_len);
|
} else if (strcasecmp(var, "encode") == 0) {
|
||||||
|
p->https_encode = atoi(val_begin);
|
||||||
} else if (strcasecmp(var, "https_port") == 0) {
|
} else if (strcasecmp(var, "https_port") == 0) {
|
||||||
p->https_port = atoi(val_begin);
|
p->https_port = atoi(val_begin);
|
||||||
} else if (strcasecmp(var, "https_del") == 0) {
|
} else if (strcasecmp(var, "https_del") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->https_del_len = val_end - val_begin;
|
||||||
p->https_del = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->https_del_len, &p->https_del) != 0)
|
||||||
memset(p->https_del, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->https_del, val_begin, val_begin_len);
|
|
||||||
p->https_del_len = val_begin_len;
|
|
||||||
} else if (strcasecmp(var, "https_first") == 0) {
|
} else if (strcasecmp(var, "https_first") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
|
||||||
p->https_first = (char *)malloc(val_begin_len);
|
p->https_first_len = val_end - val_begin;
|
||||||
memset(p->https_first, 0, val_begin_len);
|
if (copy_new_mem(val_begin, p->https_first_len, &p->https_first) != 0)
|
||||||
memcpy(p->https_first, val_begin, val_begin_len);
|
return;
|
||||||
p->https_first_len = val_begin_len;
|
|
||||||
} else if (strcasecmp(var, "strrep") == 0) {
|
} else if (strcasecmp(var, "strrep") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
// 链表操作,支持多个相同配置KEY
|
||||||
|
https_node = (tcp *) malloc(sizeof(struct tcp));
|
||||||
|
if (https_node == NULL)
|
||||||
|
return;
|
||||||
|
memset(https_node, 0, sizeof(struct tcp));
|
||||||
|
https_node->strrep = strdup(val_begin);
|
||||||
|
https_node->strrep_len = val_end - val_begin;
|
||||||
|
|
||||||
p->https_strrep = (char *)malloc(val_begin_len);
|
p1 = strstr(val_begin, "->");
|
||||||
if (p->https_strrep == NULL)
|
for (t = p1; *t != '"'; ++t) ;
|
||||||
free(p->https_strrep);
|
https_node->strrep_t = strdup(t + 1);
|
||||||
memset(p->https_strrep, 0, val_begin_len);
|
p2 = strchr(t + 1, '\0');
|
||||||
memcpy(p->https_strrep, val_begin, val_begin_len);
|
https_node->strrep_t_len = p2 - (t + 1);
|
||||||
|
|
||||||
char *p1 = strstr(val_begin, "->");
|
for (s = p1 - 1; *s == ' '; s--) {
|
||||||
p->https_strrep_aim = (char *)malloc(val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (s == val_begin)
|
||||||
if (p->https_strrep_aim == NULL) {
|
return;
|
||||||
free(p->https_strrep_aim);
|
|
||||||
}
|
}
|
||||||
memset(p->https_strrep_aim, 0, val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (*s == '"')
|
||||||
strncpy_(p->https_strrep_aim, val_begin, val_begin_len - strlen(p1 + 2) - 3);
|
s--;
|
||||||
p->https_strrep_obj = (char *)malloc(strlen(p1 + 2) + 1);
|
|
||||||
if (p->https_strrep_obj == NULL) {
|
https_node->strrep_s = strndup(val_begin, s - val_begin + 1);
|
||||||
free(p->https_strrep_obj);
|
https_node->strrep_s_len = s - val_begin + 1;
|
||||||
|
|
||||||
|
https_node->next = NULL;
|
||||||
|
|
||||||
|
if (https_head_strrep == NULL) {
|
||||||
|
https_head_strrep = https_node;
|
||||||
|
} else {
|
||||||
|
https_node->next = https_head_strrep;
|
||||||
|
https_head_strrep = https_node;
|
||||||
|
|
||||||
|
//https_node->next = https_head_strrep->next;
|
||||||
|
//https_head_strrep->next = https_node;
|
||||||
}
|
}
|
||||||
memset(p->https_strrep_obj, 0, strlen(p1 + 2) + 1);
|
|
||||||
strncpy_(p->https_strrep_obj, p1 + 2, strlen(p1 + 2));
|
|
||||||
p->https_strrep_aim_len = strlen(p->https_strrep_aim);
|
|
||||||
p->https_strrep_obj_len = strlen(p->https_strrep_obj);
|
|
||||||
} else if (strcasecmp(var, "regrep") == 0) {
|
} else if (strcasecmp(var, "regrep") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
https_node = (tcp *) malloc(sizeof(struct tcp));
|
||||||
|
if (https_node == NULL)
|
||||||
|
return;
|
||||||
|
memset(https_node, 0, sizeof(struct tcp));
|
||||||
|
https_node->regrep = strdup(val_begin);
|
||||||
|
https_node->regrep_len = val_end - val_begin;
|
||||||
|
|
||||||
p->https_regrep = (char *)malloc(val_begin_len);
|
p1 = strstr(val_begin, "->");
|
||||||
if (p->https_regrep == NULL)
|
for (t = p1; *t != '"'; ++t) ;
|
||||||
free(p->https_regrep);
|
https_node->regrep_t = strdup(t + 1);
|
||||||
memset(p->https_regrep, 0, val_begin_len);
|
p2 = strchr(t + 1, '\0');
|
||||||
memcpy(p->https_regrep, val_begin, val_begin_len);
|
https_node->regrep_t_len = p2 - (t + 1);
|
||||||
|
|
||||||
char *p1 = strstr(val_begin, "->");
|
for (s = p1 - 1; *s == ' '; s--) {
|
||||||
p->https_regrep_aim = (char *)malloc(val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (s == val_begin)
|
||||||
if (p->https_regrep_aim == NULL)
|
return;
|
||||||
free(p->https_regrep_aim);
|
}
|
||||||
memset(p->https_regrep_aim, 0, val_begin_len - strlen(p1 + 2) - 2 + 1);
|
if (*s == '"')
|
||||||
strncpy_(p->https_regrep_aim, val_begin, val_begin_len - strlen(p1 + 2) - 3);
|
s--;
|
||||||
p->https_regrep_obj = (char *)malloc(strlen(p1 + 2) + 1);
|
|
||||||
if (p->https_regrep_obj == NULL)
|
https_node->regrep_s = strndup(val_begin, s - val_begin + 1);
|
||||||
free(p->https_regrep_obj);
|
https_node->regrep_s_len = s - val_begin + 1;
|
||||||
memset(p->https_regrep_obj, 0, strlen(p1 + 2) + 1);
|
|
||||||
strncpy_(p->https_regrep_obj, p1 + 2, strlen(p1 + 2));
|
https_node->next = NULL;
|
||||||
p->https_regrep_aim_len = strlen(p->https_regrep_aim);
|
if (https_head_regrep == NULL) {
|
||||||
p->https_regrep_obj_len = strlen(p->https_regrep_obj);
|
https_head_regrep = https_node;
|
||||||
|
} else {
|
||||||
|
https_node->next = https_head_regrep;
|
||||||
|
https_head_regrep = https_node;
|
||||||
|
|
||||||
|
//https_node->next = https_head_regrep->next;
|
||||||
|
//https_head_regrep->next = https_node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content = strchr(lineEnd + 1, '\n');
|
content = strchr(lineEnd + 1, '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打印tcp链表
|
||||||
|
void print_tcp(tcp * p)
|
||||||
|
{
|
||||||
|
tcp *temp = p;
|
||||||
|
while (temp) {
|
||||||
|
if (temp->strrep)
|
||||||
|
printf("%s %d\n", temp->strrep, temp->strrep_len);
|
||||||
|
if (temp->strrep_s)
|
||||||
|
printf("%s %d\n", temp->strrep_s, temp->strrep_s_len);
|
||||||
|
if (temp->strrep_t)
|
||||||
|
printf("%s %d\n", temp->strrep_t, temp->strrep_t_len);
|
||||||
|
|
||||||
|
if (temp->regrep)
|
||||||
|
printf("%s %d\n", temp->regrep, temp->regrep_len);
|
||||||
|
if (temp->regrep_s)
|
||||||
|
printf("%s %d\n", temp->regrep_s, temp->regrep_s_len);
|
||||||
|
if (temp->regrep_t)
|
||||||
|
printf("%s %d\n", temp->regrep_t, temp->regrep_t_len);
|
||||||
|
|
||||||
|
temp = temp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp *local_reverse(tcp * head)
|
||||||
|
{
|
||||||
|
tcp *beg = NULL;
|
||||||
|
tcp *end = NULL;
|
||||||
|
if (head == NULL || head->next == NULL) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
beg = head;
|
||||||
|
end = head->next;
|
||||||
|
while (end != NULL) {
|
||||||
|
//将 end 从链表中摘除
|
||||||
|
beg->next = end->next;
|
||||||
|
//将 end 移动至链表头
|
||||||
|
end->next = head;
|
||||||
|
head = end;
|
||||||
|
//调整 end 的指向,另其指向 beg 后的一个节点,为反转下一个节点做准备
|
||||||
|
end = beg->next;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free tcp 链表
|
||||||
|
void free_tcp(tcp ** conf_head)
|
||||||
|
{
|
||||||
|
tcp *t;
|
||||||
|
while (*conf_head != NULL) {
|
||||||
|
t = *conf_head;
|
||||||
|
*conf_head = t->next;
|
||||||
|
|
||||||
|
if (t->strrep)
|
||||||
|
free(t->strrep);
|
||||||
|
if (t->strrep_s)
|
||||||
|
free(t->strrep_s);
|
||||||
|
if (t->strrep_t)
|
||||||
|
free(t->strrep_t);
|
||||||
|
|
||||||
|
if (t->regrep)
|
||||||
|
free(t->regrep);
|
||||||
|
if (t->regrep_s)
|
||||||
|
free(t->regrep_s);
|
||||||
|
if (t->regrep_t)
|
||||||
|
free(t->regrep_t);
|
||||||
|
if (t)
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_httpdns_module(char *content, conf * p)
|
static void parse_httpdns_module(char *content, conf * p)
|
||||||
{
|
{
|
||||||
char *var, *val_begin, *val_end, *lineEnd;
|
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_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
|
||||||
if (strcasecmp(var, "addr") == 0) {
|
if (strcasecmp(var, "addr") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->httpdns_addr_len = val_end - val_begin;
|
||||||
p->addr = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->httpdns_addr_len, &p->httpdns_addr) != 0)
|
||||||
memset(p->addr, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->addr, val_begin, val_begin_len);
|
|
||||||
} else if (strcasecmp(var, "http_req") == 0) {
|
} else if (strcasecmp(var, "http_req") == 0) {
|
||||||
val_begin_len = strlen(val_begin) + 1;
|
p->httpdns_http_req_len = val_end - val_begin;
|
||||||
p->http_req = (char *)malloc(val_begin_len);
|
if (copy_new_mem(val_begin, p->httpdns_http_req_len, &p->httpdns_http_req) != 0)
|
||||||
memset(p->http_req, 0, val_begin_len);
|
return;
|
||||||
memcpy(p->http_req, val_begin, val_begin_len);
|
|
||||||
p->http_req_len = val_begin_len;
|
|
||||||
} else if (strcasecmp(var, "encode") == 0) {
|
} else if (strcasecmp(var, "encode") == 0) {
|
||||||
p->encode = atoi(val_begin);
|
p->encode = atoi(val_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
content = strchr(lineEnd + 1, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_httpudp_module(char *content, conf * p)
|
||||||
|
{
|
||||||
|
char *var, *val_begin, *val_end, *lineEnd;
|
||||||
|
|
||||||
|
while ((lineEnd = set_var_val_lineEnd(content, &var, &val_begin, &val_end)) != NULL) {
|
||||||
|
if (strcasecmp(var, "addr") == 0) {
|
||||||
|
p->httpudp_addr_len = val_end - val_begin;
|
||||||
|
if (copy_new_mem(val_begin, p->httpudp_addr_len, &p->httpudp_addr) != 0)
|
||||||
|
return;
|
||||||
|
} else if (strcasecmp(var, "http_req") == 0) {
|
||||||
|
p->httpudp_http_req_len = val_end - val_begin;
|
||||||
|
if (copy_new_mem(val_begin, p->httpudp_http_req_len, &p->httpudp_http_req) != 0)
|
||||||
|
return;
|
||||||
|
} else if (strcasecmp(var, "encode") == 0) {
|
||||||
|
p->httpudp_encode = atoi(val_begin);
|
||||||
|
}
|
||||||
|
|
||||||
content = strchr(lineEnd + 1, '\n');
|
content = strchr(lineEnd + 1, '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_conf(conf * p)
|
void free_conf(conf * p)
|
||||||
{
|
{
|
||||||
|
// http module
|
||||||
if (p->http_ip)
|
if (p->http_ip)
|
||||||
free(p->http_ip);
|
free(p->http_ip);
|
||||||
if (p->http_del)
|
if (p->http_del)
|
||||||
free(p->http_del);
|
free(p->http_del);
|
||||||
if (p->http_first)
|
if (p->http_first)
|
||||||
free(p->http_first);
|
free(p->http_first);
|
||||||
if (p->http_strrep)
|
|
||||||
free(p->http_strrep);
|
|
||||||
if (p->http_strrep_aim)
|
|
||||||
free(p->http_strrep_aim);
|
|
||||||
if (p->http_strrep_obj)
|
|
||||||
free(p->http_strrep_obj);
|
|
||||||
if (p->http_regrep)
|
|
||||||
free(p->http_regrep);
|
|
||||||
if (p->http_regrep_aim)
|
|
||||||
free(p->http_regrep_aim);
|
|
||||||
if (p->http_regrep_obj)
|
|
||||||
free(p->http_regrep_obj);
|
|
||||||
|
|
||||||
|
// https module
|
||||||
if (p->https_ip)
|
if (p->https_ip)
|
||||||
free(p->https_ip);
|
free(p->https_ip);
|
||||||
if (p->https_del)
|
if (p->https_del)
|
||||||
free(p->https_del);
|
free(p->https_del);
|
||||||
if (p->https_first)
|
if (p->https_first)
|
||||||
free(p->https_first);
|
free(p->https_first);
|
||||||
if (p->https_strrep)
|
|
||||||
free(p->https_strrep);
|
|
||||||
if (p->https_strrep_aim)
|
|
||||||
free(p->https_strrep_aim);
|
|
||||||
if (p->https_strrep_obj)
|
|
||||||
free(p->https_strrep_obj);
|
|
||||||
if (p->https_regrep)
|
|
||||||
free(p->https_regrep);
|
|
||||||
if (p->https_regrep_aim)
|
|
||||||
free(p->https_regrep_aim);
|
|
||||||
if (p->https_regrep_obj)
|
|
||||||
free(p->https_regrep_obj);
|
|
||||||
|
|
||||||
if (p->addr)
|
// httpdns module
|
||||||
free(p->addr);
|
if (p->httpdns_addr)
|
||||||
if (p->http_req)
|
free(p->httpdns_addr);
|
||||||
free(p->http_req);
|
if (p->httpdns_http_req)
|
||||||
|
free(p->httpdns_http_req);
|
||||||
|
|
||||||
|
// httpudp module
|
||||||
|
if (p->httpudp_addr)
|
||||||
|
free(p->httpudp_addr);
|
||||||
|
if (p->httpudp_http_req)
|
||||||
|
free(p->httpudp_http_req);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_conf(char *filename, conf * configure)
|
void read_conf(char *filename, conf * configure)
|
||||||
{
|
{
|
||||||
char *buff, *global_content, *http_content, *https_content, *httpdns_content;
|
char *buff, *global_content, *http_content, *https_content, *httpdns_content, *httpudp_content;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
long file_size;
|
long file_size;
|
||||||
|
|
||||||
file = fopen(filename, "r");
|
file = fopen(filename, "r");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
printf("cannot open config file.");
|
perror("cannot open config file.");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
@ -380,21 +509,31 @@ void read_conf(char *filename, conf * configure)
|
|||||||
|
|
||||||
if ((global_content = read_module(buff, "global")) == NULL)
|
if ((global_content = read_module(buff, "global")) == NULL)
|
||||||
perror("read global module error");
|
perror("read global module error");
|
||||||
parse_global_module(global_content, configure);
|
else
|
||||||
|
parse_global_module(global_content, configure);
|
||||||
free(global_content);
|
free(global_content);
|
||||||
|
|
||||||
if ((http_content = read_module(buff, "http")) == NULL)
|
if ((http_content = read_module(buff, "http")) == NULL)
|
||||||
perror("read http module error");
|
perror("read http module error");
|
||||||
parse_http_module(http_content, configure);
|
else
|
||||||
|
parse_http_module(http_content, configure);
|
||||||
free(http_content);
|
free(http_content);
|
||||||
|
|
||||||
if ((https_content = read_module(buff, "https")) == NULL)
|
if ((https_content = read_module(buff, "https")) == NULL)
|
||||||
perror("read https module error");
|
perror("read https module error");
|
||||||
parse_https_module(https_content, configure);
|
else
|
||||||
|
parse_https_module(https_content, configure);
|
||||||
free(https_content);
|
free(https_content);
|
||||||
|
|
||||||
if ((httpdns_content = read_module(buff, "httpdns")) == NULL)
|
if ((httpdns_content = read_module(buff, "httpdns")) == NULL)
|
||||||
perror("read httpdns module error");
|
perror("read httpdns module error");
|
||||||
parse_httpdns_module(httpdns_content, configure);
|
else
|
||||||
|
parse_httpdns_module(httpdns_content, configure);
|
||||||
free(httpdns_content);
|
free(httpdns_content);
|
||||||
|
|
||||||
|
if ((httpudp_content = read_module(buff, "httpudp")) == NULL)
|
||||||
|
perror("read httpdns module error");
|
||||||
|
else
|
||||||
|
parse_httpudp_module(httpudp_content, configure);
|
||||||
|
free(httpudp_content);
|
||||||
}
|
}
|
||||||
|
61
conf.h
Normal file → Executable file
61
conf.h
Normal file → Executable file
@ -18,40 +18,61 @@ typedef struct CONF {
|
|||||||
int tcp_listen;
|
int tcp_listen;
|
||||||
int tcp6_listen;
|
int tcp6_listen;
|
||||||
int dns_listen;
|
int dns_listen;
|
||||||
|
int udp_listen;
|
||||||
|
|
||||||
// http module
|
// http module
|
||||||
int http_port;
|
int http_port;
|
||||||
char *http_ip, *http_del, *http_first;
|
char *http_ip, *http_del, *http_first;
|
||||||
int http_ip_len, http_del_len, http_first_len;
|
int http_ip_len, http_del_len, http_first_len;
|
||||||
char *http_strrep, *http_regrep;
|
int http_encode;
|
||||||
int http_strrep_len, http_regrep_len;
|
|
||||||
|
|
||||||
char *http_strrep_aim, *http_strrep_obj;
|
|
||||||
int http_strrep_aim_len, http_strrep_obj_len;
|
|
||||||
|
|
||||||
char *http_regrep_aim, *http_regrep_obj;
|
|
||||||
int http_regrep_aim_len, http_regrep_obj_len;
|
|
||||||
|
|
||||||
// https module
|
// https module
|
||||||
int https_port;
|
int https_port;
|
||||||
char *https_ip, *https_del, *https_first;
|
char *https_ip, *https_del, *https_first;
|
||||||
int https_ip_len, https_del_len, https_first_len;
|
int https_ip_len, https_del_len, https_first_len;
|
||||||
char *https_strrep, *https_regrep;
|
int https_encode;
|
||||||
int https_strrep_len, https_regrep_len;
|
|
||||||
|
|
||||||
char *https_strrep_aim, *https_strrep_obj;
|
// httpdns module
|
||||||
int https_strrep_aim_len, https_strrep_obj_len;
|
char *httpdns_addr;
|
||||||
|
char *httpdns_http_req;
|
||||||
char *https_regrep_aim, *https_regrep_obj;
|
int httpdns_addr_len;
|
||||||
int https_regrep_aim_len, https_regrep_obj_len;
|
int httpdns_http_req_len;
|
||||||
|
|
||||||
// http dns_listen
|
|
||||||
char *addr;
|
|
||||||
char *http_req;
|
|
||||||
int http_req_len;
|
|
||||||
int encode;
|
int encode;
|
||||||
|
|
||||||
|
// httpudp module
|
||||||
|
char *httpudp_addr;
|
||||||
|
char *httpudp_http_req;
|
||||||
|
int httpudp_addr_len;
|
||||||
|
int httpudp_http_req_len;
|
||||||
|
int httpudp_encode;
|
||||||
} conf;
|
} conf;
|
||||||
|
|
||||||
|
typedef struct tcp {
|
||||||
|
char *strrep;
|
||||||
|
int strrep_len;
|
||||||
|
char *strrep_s, *strrep_t;
|
||||||
|
int strrep_s_len, strrep_t_len;
|
||||||
|
|
||||||
|
char *regrep;
|
||||||
|
int regrep_len;
|
||||||
|
char *regrep_s, *regrep_t;
|
||||||
|
int regrep_s_len, regrep_t_len;
|
||||||
|
|
||||||
|
struct tcp *next;
|
||||||
|
} tcp;
|
||||||
|
|
||||||
|
extern tcp *http_head_strrep;
|
||||||
|
extern tcp *http_head_regrep;
|
||||||
|
extern tcp *http_node;
|
||||||
|
|
||||||
|
extern tcp *https_head_strrep;
|
||||||
|
extern tcp *https_head_regrep;
|
||||||
|
extern tcp *https_node;
|
||||||
|
|
||||||
|
extern void print_tcp(tcp * p);
|
||||||
|
extern void free_tcp(tcp ** p);
|
||||||
|
extern tcp *local_reverse(tcp * head);
|
||||||
|
|
||||||
char *strncpy_(char *dest, const char *src, size_t n);
|
char *strncpy_(char *dest, const char *src, size_t n);
|
||||||
void read_conf(char *file, conf * p);
|
void read_conf(char *file, conf * p);
|
||||||
void free_conf(conf * p);
|
void free_conf(conf * p);
|
||||||
|
36
help.c
36
help.c
@ -1,36 +0,0 @@
|
|||||||
#include "help.h"
|
|
||||||
|
|
||||||
char help_information(void)
|
|
||||||
{
|
|
||||||
static const char name[] = "CProxy";
|
|
||||||
static const char subject[] = "proxy server";
|
|
||||||
static const struct {
|
|
||||||
const char *email;
|
|
||||||
} author = {
|
|
||||||
"aixiao@aixiao.me",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char usage[] = "Usage: [-?h] [-s signal] [-c filename]";
|
|
||||||
static const char *s_help[] = {
|
|
||||||
"",
|
|
||||||
"Options:",
|
|
||||||
" -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",
|
|
||||||
"",
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
fprintf(stderr, "%s %s\n", name, subject);
|
|
||||||
fprintf(stderr, "Author: %s\n", author.email);
|
|
||||||
fprintf(stderr, "%s\n", usage);
|
|
||||||
|
|
||||||
int l;
|
|
||||||
for (l = 0; s_help[l]; l++) {
|
|
||||||
fprintf(stderr, "%s\n", s_help[l]);
|
|
||||||
}
|
|
||||||
|
|
||||||
BUILD("Compile、link.\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
9
help.h
9
help.h
@ -1,9 +0,0 @@
|
|||||||
#ifndef HELP_H
|
|
||||||
#define HELP_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0)
|
|
||||||
|
|
||||||
char help_information(void);
|
|
||||||
|
|
||||||
#endif
|
|
152
http_proxy.c
152
http_proxy.c
@ -4,13 +4,30 @@
|
|||||||
int sslEncodeCode;
|
int sslEncodeCode;
|
||||||
int remote_port;
|
int remote_port;
|
||||||
char remote_host[CACHE_SIZE];
|
char remote_host[CACHE_SIZE];
|
||||||
|
int timeout_minute;
|
||||||
|
|
||||||
/* 对数据进行编码 */
|
/* 对数据进行编码 */
|
||||||
void dataEncode(char *data, int data_len)
|
void dataEncode(char *data, int data_len, unsigned code)
|
||||||
{
|
{
|
||||||
if (sslEncodeCode)
|
while (data_len-- > 0)
|
||||||
while (data_len-- > 0)
|
data[data_len] ^= code;
|
||||||
data[data_len] ^= sslEncodeCode;
|
}
|
||||||
|
|
||||||
|
void *tcp_timeout_check(void *nullPtr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CONNECTION; i += 2) {
|
||||||
|
if (cts[i].fd > -1) {
|
||||||
|
if (cts[i].timer >= timeout_minute) {
|
||||||
|
printf("关闭连接\n");
|
||||||
|
close_connection(cts + i);
|
||||||
|
} else
|
||||||
|
cts[i].timer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *read_data(conn_t * in, char *data, int *data_len)
|
static char *read_data(conn_t * in, char *data, int *data_len)
|
||||||
@ -26,7 +43,7 @@ static char *read_data(conn_t * in, char *data, int *data_len)
|
|||||||
}
|
}
|
||||||
data = new_data;
|
data = new_data;
|
||||||
read_len = read(in->fd, data + *data_len, BUFFER_SIZE);
|
read_len = read(in->fd, data + *data_len, BUFFER_SIZE);
|
||||||
// 判断是否关闭连接
|
/* 判断是否关闭连接 */
|
||||||
if (read_len <= 0) {
|
if (read_len <= 0) {
|
||||||
if (read_len == 0 || *data_len == 0 || errno != EAGAIN) {
|
if (read_len == 0 || *data_len == 0 || errno != EAGAIN) {
|
||||||
free(data);
|
free(data);
|
||||||
@ -69,7 +86,7 @@ static void serverToClient(conn_t * server)
|
|||||||
|
|
||||||
client = server - 1;
|
client = server - 1;
|
||||||
while ((server->ready_data_len = read(server->fd, server->ready_data, BUFFER_SIZE)) > 0) {
|
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);
|
write_len = write(client->fd, server->ready_data, server->ready_data_len);
|
||||||
if (write_len <= 0) {
|
if (write_len <= 0) {
|
||||||
if (write_len == 0 || errno != EAGAIN)
|
if (write_len == 0 || errno != EAGAIN)
|
||||||
@ -145,12 +162,14 @@ int check_ipversion(char *address)
|
|||||||
return AF_INET6;
|
return AF_INET6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_connection6(char *remote_host, int remote_port)
|
int create_connection6(char *remote_host, int remote_port)
|
||||||
{
|
{
|
||||||
struct addrinfo hints, *res = NULL;
|
struct addrinfo hints;
|
||||||
|
|
||||||
int sock;
|
int sock;
|
||||||
int validfamily = 0;
|
int validfamily = 0;
|
||||||
char portstr[CACHE_SIZE];
|
char portstr[CACHE_SIZE];
|
||||||
@ -166,9 +185,12 @@ int create_connection6(char *remote_host, int remote_port)
|
|||||||
// check for numeric IP to specify IPv6 or IPv4 socket
|
// check for numeric IP to specify IPv6 or IPv4 socket
|
||||||
if ((validfamily = check_ipversion(remote_host)) != 0) {
|
if ((validfamily = check_ipversion(remote_host)) != 0) {
|
||||||
hints.ai_family = validfamily;
|
hints.ai_family = validfamily;
|
||||||
hints.ai_flags |= AI_NUMERICHOST; // remote_host是有效的数字ip,跳过解析
|
hints.ai_flags |= AI_NUMERICHOST;
|
||||||
}
|
}
|
||||||
// 检查指定的主机是否有效。 如果remote_host是主机名,尝试解析地址
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct addrinfo *res = NULL;
|
||||||
if (getaddrinfo(remote_host, portstr, &hints, &res) != 0) {
|
if (getaddrinfo(remote_host, portstr, &hints, &res) != 0) {
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
perror("getaddrinfo");
|
perror("getaddrinfo");
|
||||||
@ -187,6 +209,81 @@ int create_connection6(char *remote_host, int remote_port)
|
|||||||
|
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//通用sockaddr_storage结构体
|
||||||
|
struct sockaddr_storage remote_addr;
|
||||||
|
memset(&remote_addr, 0, sizeof(struct sockaddr_storage));
|
||||||
|
if (validfamily == AF_INET) {
|
||||||
|
struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&remote_addr;
|
||||||
|
addr_v4->sin_family = AF_INET;
|
||||||
|
addr_v4->sin_port = htons(remote_port);
|
||||||
|
inet_aton(remote_host, &(addr_v4->sin_addr));
|
||||||
|
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)&remote_addr;
|
||||||
|
addr_v6->sin6_family = AF_INET6;
|
||||||
|
addr_v6->sin6_port = htons(remote_port);
|
||||||
|
inet_pton(AF_INET6, remote_host, &(addr_v6->sin6_addr));
|
||||||
|
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_storage)) < 0)
|
||||||
|
{
|
||||||
|
perror("connect");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
//普通方法
|
||||||
|
if (validfamily == AF_INET) {
|
||||||
|
struct sockaddr_in remote_addr;
|
||||||
|
memset(&remote_addr, 0, sizeof(remote_addr));
|
||||||
|
remote_addr.sin_family = AF_INET;
|
||||||
|
remote_addr.sin_port = htons(remote_port);
|
||||||
|
remote_addr.sin_addr.s_addr = inet_addr(remote_host);
|
||||||
|
|
||||||
|
if ((sock = socket(validfamily, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) < 0) {
|
||||||
|
perror("connect");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6 remote_addr;
|
||||||
|
memset(&remote_addr, 0, sizeof(remote_addr));
|
||||||
|
remote_addr.sin6_family = AF_INET6;
|
||||||
|
remote_addr.sin6_port = htons(remote_port);
|
||||||
|
inet_pton(AF_INET6, remote_host, &(remote_addr.sin6_addr));
|
||||||
|
|
||||||
|
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) < 0) {
|
||||||
|
perror("connect");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
@ -194,7 +291,8 @@ int create_connection6(char *remote_host, int remote_port)
|
|||||||
/* 读取到的数据全部就绪,将incomplete_data复制到ready_data */
|
/* 读取到的数据全部就绪,将incomplete_data复制到ready_data */
|
||||||
static int8_t copy_data(conn_t * ct)
|
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) {
|
if (ct->ready_data) {
|
||||||
char *new_data;
|
char *new_data;
|
||||||
|
|
||||||
@ -209,7 +307,6 @@ static int8_t copy_data(conn_t * ct)
|
|||||||
ct->ready_data = ct->incomplete_data;
|
ct->ready_data = ct->incomplete_data;
|
||||||
ct->ready_data_len = ct->incomplete_data_len;
|
ct->ready_data_len = ct->incomplete_data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ct->incomplete_data = NULL;
|
ct->incomplete_data = NULL;
|
||||||
ct->incomplete_data_len = 0;
|
ct->incomplete_data_len = 0;
|
||||||
|
|
||||||
@ -219,6 +316,7 @@ static int8_t copy_data(conn_t * ct)
|
|||||||
void tcp_in(conn_t * in, conf * configure)
|
void tcp_in(conn_t * in, conf * configure)
|
||||||
{
|
{
|
||||||
conn_t *server;
|
conn_t *server;
|
||||||
|
char *headerEnd;
|
||||||
|
|
||||||
if (in->fd < 0)
|
if (in->fd < 0)
|
||||||
return;
|
return;
|
||||||
@ -232,30 +330,51 @@ void tcp_in(conn_t * in, conf * configure)
|
|||||||
|
|
||||||
in->timer = (in + 1)->timer = 0;
|
in->timer = (in + 1)->timer = 0;
|
||||||
in->incomplete_data = read_data(in, in->incomplete_data, &in->incomplete_data_len);
|
in->incomplete_data = read_data(in, in->incomplete_data, &in->incomplete_data_len);
|
||||||
|
|
||||||
//printf("%s", in->incomplete_data);
|
|
||||||
if (in->incomplete_data == NULL) {
|
if (in->incomplete_data == NULL) {
|
||||||
close_connection(in);
|
close_connection(in);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
server = in + 1;
|
server = in + 1;
|
||||||
server->request_type = in->request_type = request_type(in->incomplete_data);
|
server->request_type = in->request_type = request_type(in->incomplete_data);
|
||||||
|
if (in->request_type == OTHER_TYPE) {
|
||||||
|
//如果是第一次读取数据,并且不是HTTP请求的,关闭连接。复制数据失败的也关闭连接
|
||||||
|
if (in->reread_data == 0 || copy_data(in) != 0) {
|
||||||
|
close_connection(in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
goto handle_data_complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerEnd = strstr(in->incomplete_data, "\n\r");
|
||||||
|
//请求头不完整,等待下次读取
|
||||||
|
if (headerEnd == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (in->reread_data == 0) {
|
||||||
|
in->reread_data = 1;
|
||||||
|
|
||||||
if (request_type(in->incomplete_data) == HTTP_TYPE) {
|
|
||||||
in->incomplete_data = request_head(in, configure);
|
in->incomplete_data = request_head(in, configure);
|
||||||
server->fd = create_connection6(remote_host, remote_port);
|
server->fd = create_connection6(remote_host, remote_port);
|
||||||
if (server->fd < 0)
|
|
||||||
|
if (server->fd < 0) {
|
||||||
printf("remote->fd ERROR!\n");
|
printf("remote->fd ERROR!\n");
|
||||||
|
close_connection(in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
fcntl(server->fd, F_SETFL, O_NONBLOCK);
|
fcntl(server->fd, F_SETFL, O_NONBLOCK);
|
||||||
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||||
ev.data.ptr = server;
|
ev.data.ptr = server;
|
||||||
epoll_ctl(epollfd, EPOLL_CTL_ADD, server->fd, &ev);
|
epoll_ctl(epollfd, EPOLL_CTL_ADD, server->fd, &ev);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in->incomplete_data == NULL || copy_data(in) != 0) {
|
if (in->incomplete_data == NULL || copy_data(in) != 0) {
|
||||||
close_connection(in);
|
close_connection(server);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 数据处理完毕,可以发送
|
||||||
|
handle_data_complete:
|
||||||
// 这个判断是防止 多次读取客户端数据,但是没有和服务端建立连接,导致报错
|
// 这个判断是防止 多次读取客户端数据,但是没有和服务端建立连接,导致报错
|
||||||
if (server->fd >= 0)
|
if (server->fd >= 0)
|
||||||
tcp_out(server);
|
tcp_out(server);
|
||||||
@ -273,6 +392,7 @@ void tcp_out(conn_t * to)
|
|||||||
else
|
else
|
||||||
from = to + 1;
|
from = to + 1;
|
||||||
from->timer = to->timer = 0;
|
from->timer = to->timer = 0;
|
||||||
|
|
||||||
write_len = write(to->fd, from->ready_data + from->sent_len, from->ready_data_len - from->sent_len);
|
write_len = write(to->fd, from->ready_data + from->sent_len, from->ready_data_len - from->sent_len);
|
||||||
if (write_len == from->ready_data_len - from->sent_len) {
|
if (write_len == from->ready_data_len - from->sent_len) {
|
||||||
//服务端的数据可能没全部写入到客户端
|
//服务端的数据可能没全部写入到客户端
|
||||||
|
12
http_proxy.h
12
http_proxy.h
@ -8,10 +8,6 @@
|
|||||||
#define HTTP_TYPE 0
|
#define HTTP_TYPE 0
|
||||||
#define OTHER_TYPE 1
|
#define OTHER_TYPE 1
|
||||||
|
|
||||||
extern int remote_port;
|
|
||||||
extern char remote_host[CACHE_SIZE];
|
|
||||||
extern int sslEncodeCode;
|
|
||||||
|
|
||||||
typedef struct tcp_connection {
|
typedef struct tcp_connection {
|
||||||
char *ready_data, *incomplete_data;
|
char *ready_data, *incomplete_data;
|
||||||
int fd, ready_data_len, incomplete_data_len, sent_len, timer;
|
int fd, ready_data_len, incomplete_data_len, sent_len, timer;
|
||||||
@ -19,12 +15,16 @@ typedef struct tcp_connection {
|
|||||||
unsigned reread_data:1, request_type:1, keep_alive:1;
|
unsigned reread_data:1, request_type:1, keep_alive:1;
|
||||||
} conn_t;
|
} conn_t;
|
||||||
|
|
||||||
|
extern int remote_port;
|
||||||
|
extern char remote_host[CACHE_SIZE];
|
||||||
|
extern int sslEncodeCode;
|
||||||
extern conn_t cts[MAX_CONNECTION];
|
extern conn_t cts[MAX_CONNECTION];
|
||||||
extern void tcp_in(conn_t * in, conf * configure);
|
extern void tcp_in(conn_t * in, conf * configure);
|
||||||
extern void tcp_out(conn_t * out);
|
extern void tcp_out(conn_t * out);
|
||||||
extern void close_connection(conn_t * conn);
|
extern void close_connection(conn_t * conn);
|
||||||
|
|
||||||
extern char *request_head(conn_t * in, conf * configure);
|
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);
|
||||||
|
extern int timeout_minute;
|
||||||
|
void *tcp_timeout_check(void *nullPtr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
698
http_request.c
698
http_request.c
@ -1,5 +1,22 @@
|
|||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
|
|
||||||
|
void errors(const char *error_info)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n\n", error_info);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len)
|
||||||
{
|
{
|
||||||
@ -119,47 +136,9 @@ static char *regrep(char *str, int *str_len, const char *src, char *dest, int de
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除字符串head中第一位到 character 处并拼接 string, character 为空返回原字符串.(string 字符替换第一个字符到 character 处)
|
|
||||||
char *splice_head(char *head, const char *character, char *string)
|
|
||||||
{
|
|
||||||
int first_len = strlen(string);
|
|
||||||
char *_p1 = strstr(head, character);
|
|
||||||
if (_p1 == NULL) {
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
_p1 = _p1 + 1;
|
|
||||||
char temporary[first_len + strlen(_p1) + 1];
|
|
||||||
memset(temporary, 0, (first_len + strlen(_p1) + 1));
|
|
||||||
strcpy(temporary, string);
|
|
||||||
strcat(temporary, _p1);
|
|
||||||
memset(head, 0, strlen(head));
|
|
||||||
return strcpy(head, temporary);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除字符串 head 中 character 到 string 处, character 为空返回原字符串.
|
|
||||||
char *delete_head(char *head, const char *character, int string)
|
|
||||||
{
|
|
||||||
int head_len = strlen(head);
|
|
||||||
char *_p1 = strstr(head, character);
|
|
||||||
if (_p1 == NULL) {
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
char *_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));
|
|
||||||
strcat(temporary, _p2);
|
|
||||||
memset(head, 0, strlen(head));
|
|
||||||
return memcpy(head, temporary, head_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int extract_host(char *header, char *host, char *port)
|
int extract_host(char *header, char *host, char *port)
|
||||||
{
|
{
|
||||||
memset(port, 0, strlen(port));
|
|
||||||
memset(host, 0, strlen(host));
|
|
||||||
//printf("%s\n", header);
|
//printf("%s\n", header);
|
||||||
char *_p = strstr(header, "CONNECT"); // 在 CONNECT 方法中解析 隧道主机名称及端口号
|
char *_p = strstr(header, "CONNECT"); // 在 CONNECT 方法中解析 隧道主机名称及端口号
|
||||||
if (_p) {
|
if (_p) {
|
||||||
@ -167,10 +146,10 @@ int extract_host(char *header, char *host, char *port)
|
|||||||
if (strchr(header, '[') || strchr(header, ']')) { // IPv6
|
if (strchr(header, '[') || strchr(header, ']')) { // IPv6
|
||||||
char *_p1 = strchr(header, '[');
|
char *_p1 = strchr(header, '[');
|
||||||
char *_p2 = strchr(_p1 + 1, ']');
|
char *_p2 = strchr(_p1 + 1, ']');
|
||||||
strncpy(host, _p1 + 1, (int)(_p2 - _p1) - 1);
|
memcpy(host, _p1 + 1, (int)(_p2 - _p1) - 1);
|
||||||
|
|
||||||
char *_p3 = strchr(_p2 + 1, ' ');
|
char *_p3 = strchr(_p2 + 1, ' ');
|
||||||
strncpy(port, _p2 + 2, (int)(_p3 - _p2) - 1);
|
memcpy(port, _p2 + 2, (int)(_p3 - _p2) - 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -185,86 +164,108 @@ int extract_host(char *header, char *host, char *port)
|
|||||||
} else { // 如果_p2等于空就返回-1
|
} else { // 如果_p2等于空就返回-1
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
char *p = strstr(header, "Host:");
|
char *_p = strstr(header, "Host:");
|
||||||
if (!p) {
|
if (_p == NULL) {
|
||||||
return -1;
|
_p = strstr(header, "host:");
|
||||||
}
|
}
|
||||||
char *p1 = strchr(p, '\n');
|
if (_p == NULL) { // 都为空时
|
||||||
if (!p1) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *p2 = strchr(p + 5, ':'); // 5是指'Host:'的长度
|
char *_p1 = strchr(_p, '\n'); // 指向末尾'\n'
|
||||||
|
if (!_p1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int h_len = (int)(p1 - p - 6);
|
char *_p2 = strchr(_p + 5, ':'); // 5是指'Host:'的长度
|
||||||
|
int h_len = (int)(_p1 - _p - 6);
|
||||||
char s_host[h_len];
|
char s_host[h_len];
|
||||||
strncpy(s_host, p + 6, p1 - p - 6);
|
memcpy(s_host, _p + 6, _p1 - _p - 6);
|
||||||
s_host[h_len] = '\0';
|
s_host[h_len] = '\0';
|
||||||
char *p3 = strchr(s_host, ':');
|
|
||||||
char *p4 = NULL;
|
|
||||||
if (p3)
|
|
||||||
p4 = strchr(p3 + 1, ':');
|
|
||||||
|
|
||||||
if (p4 != NULL) { // IPV6
|
char *_p3 = strchr(s_host, ':');
|
||||||
char *p5 = NULL;
|
char *_p4 = NULL;
|
||||||
char *p6 = NULL;
|
if (_p3)
|
||||||
p5 = strchr(header, ' ');
|
_p4 = strchr(_p3 + 1, ':'); // 二次确认':'
|
||||||
if (p5)
|
{ // IPV6
|
||||||
p6 = strchr(p5 + 1, ' ');
|
if (_p4 != NULL) {
|
||||||
|
char *_p5 = NULL;
|
||||||
|
char *_p6 = NULL;
|
||||||
|
_p5 = strchr(header, ' ');
|
||||||
|
if (_p5)
|
||||||
|
_p6 = strchr(_p5 + 1, ' ');
|
||||||
|
|
||||||
char url[p6 - p5 - 1];
|
char url[_p6 - _p5 - 1];
|
||||||
memset(url, 0, p6 - p5 - 1);
|
memset(url, 0, _p6 - _p5 - 1);
|
||||||
strncpy(url, p5 + 1, p6 - p5 - 1);
|
memcpy(url, _p5 + 1, _p6 - _p5 - 1);
|
||||||
url[p6 - p5 - 1] = '\0';
|
url[_p6 - _p5 - 1] = '\0';
|
||||||
|
|
||||||
if (strstr(url, "http") != NULL) { // 去除 'http://'
|
if (strstr(url, "http") != NULL) { // 去除 'http://'
|
||||||
memcpy(url, url + 7, strlen(url) - 7);
|
memcpy(url, url + 7, (_p6 - _p5 - 1) - 7);
|
||||||
url[strlen(url) - 7] = '\0';
|
url[(_p6 - _p5 - 1) - 7] = '\0';
|
||||||
char *p7 = strchr(url, '/');
|
char *_p7 = strchr(url, '/');
|
||||||
if (p7) // 去除 uri
|
if (_p7) // 去除 uri
|
||||||
url[p7 - url] = '\0';
|
url[_p7 - url] = '\0';
|
||||||
|
|
||||||
char *p8 = strchr(url, ']');
|
char *_p8 = strchr(url, ']');
|
||||||
if (p8) {
|
char *_p9 = strchr(url, '\0');
|
||||||
strcpy(port, p8 + 2);
|
if (_p8) {
|
||||||
strncpy(host, url + 1, strlen(url) - strlen(p8) - 1);
|
if ((_p9 - _p8) == 1) { // 如果不带端口就默认80, 并结束
|
||||||
|
memcpy(port, "80", 2);
|
||||||
|
memcpy(host, url + 1, _p8 - (url + 1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(p8) < 3) {
|
memcpy(port, _p8 + 2, _p9 - (_p8 + 2));
|
||||||
strcpy(port, "80");
|
memcpy(host, url + 1, _p8 - (url + 1));
|
||||||
strncpy(host, url + 1, strlen(url) - strlen(p8) - 1);
|
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
} else { // HTTP头为不规范的url时处理Host, 主要Proxifier转发url为'/'时
|
||||||
} else { // HTTP头为不规范的url时处理Host, 主要Proxifier转发url为'/'时
|
//printf("s_host: %s\n", s_host);
|
||||||
//printf("s_host: %s\n", s_host);
|
char *_p1 = strchr(s_host, '[');
|
||||||
char *_p1 = strchr(s_host, '[');
|
if (_p1 == NULL) // 涉及到自定义的Host, 不带'['、']'时, 默认截取最后为端口
|
||||||
char *_p2 = strchr(_p1+1, ']');
|
{
|
||||||
if (_p1 && _p2) {
|
char *_p2 = strrchr(s_host, ':');
|
||||||
memcpy(host, _p1+1, _p2 - _p1 -1);
|
remote_port = atoi(_p2 + 1);
|
||||||
if (strlen(_p2) < 3) {
|
memcpy(remote_host, s_host, _p2 - s_host);
|
||||||
strcpy(port, "80");
|
return 0;
|
||||||
} else {
|
|
||||||
strcpy(port, _p2+2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *_p2 = strchr(_p1 + 1, ']');
|
||||||
|
char *_p3 = strchr(s_host, '\0');
|
||||||
|
if (_p1 && _p2) {
|
||||||
|
memcpy(host, _p1 + 1, _p2 - _p1 - 1);
|
||||||
|
if ((_p3-(_p2+1)) < 2) {
|
||||||
|
memcpy(port, "80", 2);
|
||||||
|
} else {
|
||||||
|
memcpy(port, _p2 + 2, _p3 - (_p2 + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
// HTTP 非 CONNECT 方法
|
||||||
if (p2 && p2 < p1) {
|
{
|
||||||
memcpy(port, p2 + 1, (int)(p1 - p2 - 1));
|
if (_p2 && _p2 < _p1) { // 带端口, p2指向':', p1指向末尾'\n', _p指向Host
|
||||||
memcpy(host, p + 5 + 1, (int)(p2 - p - 5 - 1));
|
memcpy(port, _p2 + 1, (int)(_p1 - _p2 - 1));
|
||||||
} else {
|
memcpy(host, _p + 5 + 1, (int)(_p2 - _p - 5 - 1));
|
||||||
memcpy(host, p + 5 + 1, (int)(p1 - p - 5 - 1 - 1));
|
} else { // 不带端口
|
||||||
memcpy(port, "80", 2);
|
if (0 < (int)(_p1 - _p - 5 - 1 - 1)) {
|
||||||
|
memcpy(host, _p + 5 + 1, (_p1 - _p - 5 - 1 - 1));
|
||||||
|
memcpy(port, "80", 2);
|
||||||
|
} else {
|
||||||
|
memcpy(host, _p + 5 + 1, (_p1 - _p) - 6);
|
||||||
|
memcpy(port, "80", 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -273,29 +274,82 @@ int extract_host(char *header, char *host, char *port)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_http_path(char *url, char *path)
|
char *get_http_path(char *url, int url_len, char *path)
|
||||||
{
|
{
|
||||||
char *_p0;
|
char *_p0, *_p1;
|
||||||
_p0 = NULL;
|
_p0 = _p1 = NULL;
|
||||||
if (url) {
|
|
||||||
_p0 = strstr(url + 7, "/");
|
_p1 = strchr(url, '\0');
|
||||||
if (_p0)
|
|
||||||
return memcpy(path, _p0, (int)strlen(_p0));
|
if (url_len > 7) {
|
||||||
else
|
if (url) {
|
||||||
memcpy(path, "/", 1); // 如果没有资源路径就默认"/"
|
_p0 = strstr(url + 7, "/");
|
||||||
|
if (_p0)
|
||||||
|
return memcpy(path, _p0, _p1 - _p0);
|
||||||
|
else
|
||||||
|
return memcpy(path, "/", 1); // 如果没有资源路径就默认"/"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return memcpy(path, "/", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_http_host_port_len(char *head, int *host_len, int *port_len)
|
||||||
|
{
|
||||||
|
*host_len = 0;
|
||||||
|
*port_len = 0;
|
||||||
|
char *_p1 = strstr(head, "Host"); // 判断Host行
|
||||||
|
if (_p1) { // 为真时
|
||||||
|
char *_p2 = strstr(_p1, "\n");
|
||||||
|
*host_len = (int)(_p2 - _p1);
|
||||||
|
|
||||||
|
char host[*host_len + 1];
|
||||||
|
memcpy(host, _p1, *host_len);
|
||||||
|
host[*host_len] = '\0';
|
||||||
|
|
||||||
|
char *_p3 = strrchr(host, ':');
|
||||||
|
char *_p4 = strchr(host, '\0');
|
||||||
|
if (_p3) {
|
||||||
|
*port_len = _p4 - (_p3 + 1);
|
||||||
|
} else {
|
||||||
|
*port_len = *host_len;
|
||||||
|
}
|
||||||
|
} else { // 为假时
|
||||||
|
char *_p1 = strstr(head, "host");
|
||||||
|
if (_p1) {
|
||||||
|
char *_p2 = strstr(_p1, "\n");
|
||||||
|
*host_len = (int)(_p2 - _p1);
|
||||||
|
|
||||||
|
char host[*host_len + 1];
|
||||||
|
memcpy(host, _p1, *host_len);
|
||||||
|
host[*host_len] = '\0';
|
||||||
|
|
||||||
|
char *_p3 = strrchr(host, ':');
|
||||||
|
char *_p4 = strchr(host, '\0');
|
||||||
|
if (_p3) {
|
||||||
|
*port_len = _p4 - (_p3 + 1);
|
||||||
|
} else {
|
||||||
|
*port_len = *host_len;
|
||||||
|
}
|
||||||
|
} else { // 未找到时使用HTTP_HEAD_CACHE_SIZE大小
|
||||||
|
*host_len = HTTP_HEAD_HOST_CACHE_SIZE;
|
||||||
|
*port_len = HTTP_HEAD_HOST_CACHE_SIZE / 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void free_http_request(struct http_request *http_request)
|
void free_http_request(struct http_request *http_request)
|
||||||
{
|
{
|
||||||
if (http_request->M)
|
if (http_request->method)
|
||||||
free(http_request->M);
|
free(http_request->method);
|
||||||
if (http_request->U)
|
if (http_request->U)
|
||||||
free(http_request->U);
|
free(http_request->U);
|
||||||
if (http_request->V)
|
if (http_request->version)
|
||||||
free(http_request->V);
|
free(http_request->version);
|
||||||
if (http_request->host)
|
if (http_request->host)
|
||||||
free(http_request->host);
|
free(http_request->host);
|
||||||
if (http_request->port)
|
if (http_request->port)
|
||||||
@ -308,247 +362,304 @@ void free_http_request(struct http_request *http_request)
|
|||||||
free(http_request->uri);
|
free(http_request->uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_http_host_port_len(char *head, int *host_len, int *port_len) {
|
|
||||||
*host_len = 0;
|
|
||||||
*port_len = 0;
|
|
||||||
char *_p1 = strstr(head, "Host"); // 判断Host行
|
|
||||||
if (_p1) { // 为真时
|
|
||||||
char *_p2 = strstr(_p1, "\n");
|
|
||||||
*host_len = (int)(_p2 - _p1);
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
*port_len = *host_len;
|
|
||||||
}
|
|
||||||
} else { // 为假时
|
|
||||||
char *_p1 = strstr(head, "host");
|
|
||||||
if (_p1) {
|
|
||||||
char *_p2 = strstr(_p1, "\n");
|
|
||||||
*host_len = (int)(_p2 - _p1);
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
*port_len = *host_len;
|
|
||||||
}
|
|
||||||
} else { // 未找到时使用HTTP_HEAD_CACHE_SIZE大小
|
|
||||||
*host_len = HTTP_HEAD_CACHE_SIZE;
|
|
||||||
*port_len = HTTP_HEAD_CACHE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_request_head(char *http_request_line, struct http_request *http_request)
|
void parse_request_head(char *http_request_line, struct http_request *http_request)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p, *head, *m, *u;
|
||||||
char *head;
|
|
||||||
size_t head_len;
|
size_t head_len;
|
||||||
char *m, *u;
|
int host_len, port_len, uri_len;
|
||||||
int host_len = 0;
|
host_len = port_len = uri_len = 0;
|
||||||
int port_len = 0;
|
|
||||||
int uri_len = 0;
|
|
||||||
|
|
||||||
p = strstr(http_request_line, "\r\n"); // 查找"\r\n"
|
p = strstr(http_request_line, "\r\n"); // 查找"\r\n"
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
head_len = strlen(http_request_line) - strlen(p);
|
head_len = p - http_request_line;
|
||||||
head = (char *)malloc(sizeof(char) * head_len * 2);
|
head = (char *)malloc(sizeof(char) * head_len + 1);
|
||||||
if (head == NULL)
|
if (head == NULL)
|
||||||
free(head);
|
free(head);
|
||||||
memset(head, 0, head_len * 2);
|
memset(head, 0, sizeof(char) * head_len + 1);
|
||||||
memcpy(head, http_request_line, head_len);
|
memcpy(head, http_request_line, head_len);
|
||||||
|
|
||||||
http_request->M = (char *)malloc(sizeof(char) * 7);
|
http_request->method = (char *)malloc(sizeof(char) * 8);
|
||||||
http_request->U = (char *)malloc(sizeof(char) * HTTP_HEAD_CACHE_SIZE);
|
http_request->U = (char *)malloc(sizeof(char) * head_len);
|
||||||
http_request->V = (char *)malloc(10);
|
http_request->version = (char *)malloc(10);
|
||||||
if (http_request->M == NULL) {
|
if (http_request->method == NULL)
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
}
|
if (http_request->U == NULL)
|
||||||
if (http_request->U == NULL) {
|
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
}
|
if (http_request->version == NULL)
|
||||||
if (http_request->V == NULL) {
|
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
}
|
memset(http_request->method, 0, 8);
|
||||||
memset(http_request->M, 0, 7);
|
memset(http_request->U, 0, sizeof(char) * head_len);
|
||||||
memset(http_request->U, 0, HTTP_HEAD_CACHE_SIZE);
|
memset(http_request->version, 0, 10);
|
||||||
memset(http_request->V, 0, 10);
|
|
||||||
|
|
||||||
m = strchr(head, ' ');
|
m = strchr(head, ' ');
|
||||||
http_request->M_len = strlen(head) - strlen(m);
|
http_request->method_len = m - head;
|
||||||
//http_request->M_len = m - head;
|
memmove(http_request->method, head, http_request->method_len);
|
||||||
memcpy(http_request->M, head, http_request->M_len);
|
|
||||||
u = strchr(m + 1, ' ');
|
u = strchr(m + 1, ' ');
|
||||||
http_request->U_len = strlen(m + 1) - strlen(u);
|
memmove(http_request->U, m + 1, u - (m + 1));
|
||||||
//http_request->U_len = u - m -1;
|
http_request->U_len = u - (m + 1);
|
||||||
memcpy(http_request->U, m + 1, http_request->U_len);
|
|
||||||
memcpy(http_request->V, u + 1, 8);
|
memmove(http_request->version, u + 1, 8);
|
||||||
http_request->V_len = 8;
|
http_request->version_len = 8;
|
||||||
http_request->U_len = (int)strlen(http_request->U);
|
|
||||||
|
|
||||||
// 获取Host、Port长度
|
// 获取Host、Port长度
|
||||||
get_http_host_port_len(http_request_line, &host_len, &port_len);
|
get_http_host_port_len(http_request_line, &host_len, &port_len);
|
||||||
|
|
||||||
// URI LENGTH
|
// URI LENGTH
|
||||||
char *_p0 = strstr(http_request->U, "http://");
|
char *_p0 = strstr(http_request->U, "http://");
|
||||||
if (_p0) { // 标准头
|
if (_p0) { // 标准头
|
||||||
char *_p1 = strchr(http_request->U + 7, '/');
|
char *_p1 = strchr(http_request->U + 7, '/');
|
||||||
|
char *_p2 = strchr(http_request->U + 7, '\0');
|
||||||
if (_p1) {
|
if (_p1) {
|
||||||
uri_len = (int)strlen(_p1);
|
uri_len = _p2 - _p1;
|
||||||
}
|
}
|
||||||
} else { // 非标准头
|
} else { // 非标准头
|
||||||
char *_p1 = strchr(http_request->U, '/');
|
char *_p1 = strchr(http_request->U, '/');
|
||||||
|
char *_p2 = strchr(http_request->U, '\0');
|
||||||
if (_p1) {
|
if (_p1) {
|
||||||
uri_len = (int)strlen(_p1);
|
uri_len = _p2 - _p1;
|
||||||
} else {
|
} else {
|
||||||
uri_len = 1; // 没有uri时
|
uri_len = 1; // 没有uri时
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
http_request->host = (char *)malloc(sizeof(char) * host_len+1);
|
http_request->host = (char *)malloc(sizeof(char) * host_len + 1);
|
||||||
if (http_request->host == NULL)
|
if (http_request->host == NULL)
|
||||||
perror("malloc");
|
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)
|
if (http_request->port == NULL)
|
||||||
perror("malloc");
|
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)
|
if (http_request->url == NULL)
|
||||||
perror("malloc");
|
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)
|
if (http_request->uri == NULL)
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
http_request->H = (char *)malloc(sizeof(char) * host_len + port_len + 1);
|
http_request->H = (char *)malloc(sizeof(char) * host_len + port_len + 1);
|
||||||
if (http_request->H == NULL)
|
if (http_request->H == NULL)
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
|
|
||||||
memset(http_request->host, 0, host_len+1);
|
memset(http_request->host, 0, host_len + 1);
|
||||||
memset(http_request->port, 0, port_len+1);
|
memset(http_request->port, 0, port_len + 1);
|
||||||
memset(http_request->url, 0, http_request->U_len+1);
|
memset(http_request->url, 0, http_request->U_len + 1);
|
||||||
memset(http_request->uri, 0, uri_len+1);
|
memset(http_request->uri, 0, uri_len + 1);
|
||||||
memset(http_request->H, 0, host_len + port_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)
|
if (extract_host(http_request_line, http_request->host, http_request->port) == -1)
|
||||||
return;
|
return;
|
||||||
http_request->host_len = (int)strlen(http_request->host);
|
http_request->host_len = (int)strlen(http_request->host);
|
||||||
http_request->port_len = (int)strlen(http_request->port);
|
http_request->port_len = (int)strlen(http_request->port);
|
||||||
memcpy(http_request->H, http_request->host, http_request->host_len);
|
memcpy(http_request->H, http_request->host, http_request->host_len);
|
||||||
strcat(http_request->H, ":");
|
strncat(http_request->H, ":", 2);
|
||||||
strcat(http_request->H, http_request->port);
|
strncat(http_request->H, http_request->port, http_request->port_len);
|
||||||
memcpy(http_request->url, http_request->U, http_request->U_len);
|
memcpy(http_request->url, http_request->U, http_request->U_len);
|
||||||
get_http_path(http_request->url, http_request->uri);
|
http_request->url_len = http_request->U_len;
|
||||||
|
if (get_http_path(http_request->url, http_request->url_len, http_request->uri) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
http_request->U_len = (int)strlen(http_request->U);
|
http_request->uri_len = uri_len;
|
||||||
http_request->url_len = (int)strlen(http_request->url);
|
http_request->H_len = http_request->host_len + http_request->port_len + 1;
|
||||||
http_request->uri_len = (int)strlen(http_request->uri);
|
|
||||||
http_request->H_len = (int)strlen(http_request->H);
|
/*
|
||||||
|
// 调试
|
||||||
|
printf("%s %d\n", http_request->method, http_request->method_len);
|
||||||
|
printf("%s %d\n", http_request->U, http_request->U_len);
|
||||||
|
printf("%s %d\n", http_request->version, http_request->version_len);
|
||||||
|
printf("%s %d\n", http_request->host, http_request->host_len);
|
||||||
|
printf("%s %d\n", http_request->port, http_request->port_len);
|
||||||
|
printf("%s %d\n", http_request->H, http_request->H_len);
|
||||||
|
printf("%s %d\n", http_request->url, http_request->url_len);
|
||||||
|
printf("%s %d\n", http_request->uri, http_request->uri_len);
|
||||||
|
*/
|
||||||
|
|
||||||
free(head);
|
free(head);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *splice_head(char *head, int *head_len, const char *needle, char *string, int string_len)
|
||||||
|
{
|
||||||
|
char *tail_head;
|
||||||
|
char *_p0;
|
||||||
|
char *_p1;
|
||||||
|
|
||||||
|
_p1 = strstr(head, needle);
|
||||||
|
if (_p1 == NULL) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
_p1 = _p1 + 1;
|
||||||
|
_p0 = strchr(_p1, '\0');
|
||||||
|
|
||||||
|
tail_head = (char *)alloca((_p0 - _p1) + 1);
|
||||||
|
if (tail_head == NULL) {
|
||||||
|
perror("alloca");
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
memset(tail_head, 0, (_p0 - _p1) + 1);
|
||||||
|
memcpy(tail_head, _p1, (_p0 - _p1));
|
||||||
|
|
||||||
|
memset(head, 0, *head_len);
|
||||||
|
memcpy(head, string, string_len);
|
||||||
|
strncat(head, tail_head, (_p0 - _p1));
|
||||||
|
*head_len = string_len + (_p0 - _p1);
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *delete_head(char *head, int *head_len, const char *needle, int string)
|
||||||
|
{
|
||||||
|
char *temp_stack;
|
||||||
|
char *_p1, *_p2, *_p3;
|
||||||
|
_p1 = _p2 = _p3 = NULL;
|
||||||
|
int temp_stack_len;
|
||||||
|
|
||||||
|
_p1 = strstr(head, needle); // _p1指向head字符串中的"needle"字符处(needle字符串的第一个字符)
|
||||||
|
if (_p1 == NULL) {
|
||||||
|
//perror("_p1 HEAD NULL");
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
_p2 = strchr(_p1, string); // _p2指向head字符串中"string"字符到末尾中的'\0'
|
||||||
|
if (_p2 == NULL) {
|
||||||
|
//perror("_p2 HEAD NULL");
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
_p3 = strchr(_p1, '\0'); // _p3指向head字符串末尾的'\0'
|
||||||
|
if (_p3 == NULL) {
|
||||||
|
//perror("_p3 HEAD NULL");
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
temp_stack_len = (_p1 - head) + (_p3 - _p2);
|
||||||
|
temp_stack = (char *)alloca(temp_stack_len + 1); // 分配临时栈内存,长度是去除needle到string处
|
||||||
|
if (temp_stack == NULL) {
|
||||||
|
perror("alloca");
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
memset(temp_stack, 0, temp_stack_len + 1);
|
||||||
|
memmove(temp_stack, head, (_p1 - head) - 1);
|
||||||
|
strncat(temp_stack, _p2, _p3 - _p2);
|
||||||
|
|
||||||
|
memset(head, 0, *head_len);
|
||||||
|
*head_len = temp_stack_len;
|
||||||
|
return memmove(head, temp_stack, temp_stack_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *conf_handle_strrep(char *str, int *str_len, tcp * temp)
|
||||||
|
{
|
||||||
|
tcp *p = temp;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
if (p->strrep) {
|
||||||
|
str = replace(str, str_len, p->strrep_s, p->strrep_s_len, p->strrep_t, p->strrep_t_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *conf_handle_regrep(char *str, int *str_len, tcp * temp)
|
||||||
|
{
|
||||||
|
tcp *p = temp;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
if (p->regrep) {
|
||||||
|
str = regrep(str, str_len, p->regrep_s, p->regrep_t, p->regrep_t_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
char *request_head(conn_t * in, conf * configure)
|
char *request_head(conn_t * in, conf * configure)
|
||||||
{
|
{
|
||||||
|
char *result = NULL;
|
||||||
|
char *delim = ",";
|
||||||
|
char *saveptr = NULL;
|
||||||
|
char *incomplete_head = NULL;
|
||||||
|
int incomplete_head_len = 0;
|
||||||
|
int return_val = 0;
|
||||||
struct http_request *http_request;
|
struct http_request *http_request;
|
||||||
http_request = (struct http_request *)malloc(sizeof(struct http_request));
|
http_request = (struct http_request *)malloc(sizeof(struct http_request));
|
||||||
memset(http_request, 0, sizeof(struct http_request));
|
memset(http_request, 0, sizeof(struct http_request));
|
||||||
|
|
||||||
parse_request_head(in->incomplete_data, http_request);
|
parse_request_head(in->incomplete_data, http_request);
|
||||||
|
|
||||||
if (strncmp(in->incomplete_data, "CONNECT", 7) == 0) {
|
if ((return_val = strncmp(in->incomplete_data, "CONNECT", 7)) == 0) {
|
||||||
char *incomplete_head;
|
sslEncodeCode = configure->https_encode;
|
||||||
int incomplete_head_len;
|
|
||||||
char https_del_copy[configure->https_del_len * 2];
|
char https_del_copy[configure->https_del_len + 1];
|
||||||
char *result = NULL;
|
|
||||||
|
|
||||||
memset(remote_host, 0, CACHE_SIZE);
|
memset(remote_host, 0, CACHE_SIZE);
|
||||||
if (configure->https_port > 0)
|
if (configure->https_port > 0) {
|
||||||
remote_port = configure->https_port;
|
remote_port = configure->https_port;
|
||||||
if (configure->https_ip != NULL)
|
}
|
||||||
strcpy(remote_host, configure->https_ip);
|
if (configure->https_ip != NULL) {
|
||||||
|
memcpy(remote_host, configure->https_ip, configure->https_ip_len);
|
||||||
|
}
|
||||||
|
|
||||||
incomplete_head = (char *)malloc(sizeof(char) * (BUFFER_SIZE));
|
incomplete_head = (char *)malloc(sizeof(char) * (BUFFER_SIZE));
|
||||||
if (incomplete_head == NULL) {
|
if (incomplete_head == NULL) {
|
||||||
free(incomplete_head);
|
free(incomplete_head);
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
}
|
}
|
||||||
memset(incomplete_head, 0, sizeof(char) * (BUFFER_SIZE));
|
memset(incomplete_head, 0, sizeof(char) * (BUFFER_SIZE));
|
||||||
memcpy(incomplete_head, in->incomplete_data, strlen(in->incomplete_data));
|
memmove(incomplete_head, in->incomplete_data, in->incomplete_data_len);
|
||||||
memcpy(https_del_copy, configure->https_del, configure->https_del_len);
|
memmove(https_del_copy, configure->https_del, configure->https_del_len + 1);
|
||||||
|
|
||||||
result = strtok(https_del_copy, ",");
|
result = strtok_r(https_del_copy, delim, &saveptr);
|
||||||
while (result != NULL) {
|
while (result != NULL) {
|
||||||
delete_head(incomplete_head, result, '\n');
|
delete_head(incomplete_head, &in->incomplete_data_len, result, '\n');
|
||||||
result = strtok(NULL, ",");
|
result = strtok_r(NULL, delim, &saveptr);
|
||||||
}
|
}
|
||||||
splice_head(incomplete_head, "\n", configure->https_first);
|
|
||||||
incomplete_head_len = strlen(incomplete_head);
|
|
||||||
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, "\\b", 2, "\b", 1);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\v", 2, "\v", 1);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\f", 2, "\f", 1);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\a", 2, "\a", 1);
|
|
||||||
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, "[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, 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);
|
|
||||||
if (configure->https_strrep)
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, configure->https_strrep_aim, configure->https_strrep_aim_len, configure->https_strrep_obj, configure->https_strrep_obj_len);
|
|
||||||
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);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[host]", 6, http_request->host, http_request->host_len);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, http_request->port, http_request->port_len);
|
|
||||||
incomplete_head_len = strlen(incomplete_head); // 更新HTTPS HEADER长度
|
|
||||||
//printf("%s", incomplete_head); // 打印HTTPS HEADER
|
|
||||||
|
|
||||||
|
splice_head(incomplete_head, &in->incomplete_data_len, "\n", configure->https_first, configure->https_first_len);
|
||||||
|
|
||||||
|
incomplete_head_len = in->incomplete_data_len; // 更新HTTPS HEADER长度
|
||||||
|
incomplete_head = conf_handle_strrep(incomplete_head, &incomplete_head_len, https_head_strrep);
|
||||||
|
incomplete_head = conf_handle_regrep(incomplete_head, &incomplete_head_len, https_head_regrep);
|
||||||
|
|
||||||
|
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->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);
|
||||||
|
|
||||||
|
printf("%s", incomplete_head); // 打印HTTPS HEADER
|
||||||
|
|
||||||
char *new_incomplete_data;
|
char *new_incomplete_data;
|
||||||
new_incomplete_data = (char *)realloc(in->incomplete_data, incomplete_head_len + 1); // 更新incomplete_data堆内存
|
new_incomplete_data = (char *)realloc(in->incomplete_data, incomplete_head_len + 1);
|
||||||
if (new_incomplete_data == NULL) {
|
if (new_incomplete_data == NULL) {
|
||||||
|
free(in->incomplete_data);
|
||||||
perror("realloc");
|
perror("realloc");
|
||||||
return NULL;
|
return in->incomplete_data;
|
||||||
}
|
}
|
||||||
in->incomplete_data = new_incomplete_data;
|
in->incomplete_data = new_incomplete_data;
|
||||||
memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空incomplete_data数据
|
memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空incomplete_data数据
|
||||||
strcpy(in->incomplete_data, incomplete_head); // 更新incomplete_data数据
|
memmove(in->incomplete_data, incomplete_head, incomplete_head_len); // 更新incomplete_data数据
|
||||||
in->incomplete_data_len = strlen(in->incomplete_data); // 更新incomplete_data长度
|
in->incomplete_data_len = incomplete_head_len; // 更新incomplete_data长度
|
||||||
free(incomplete_head); // 释放incomplete_head内存
|
|
||||||
|
|
||||||
|
free(incomplete_head); // 释放incomplete_head内存
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(in->incomplete_data, "GET", 3) == 0 || strncmp(in->incomplete_data, "POST", 4) == 0) {
|
if (strncmp(in->incomplete_data, "GET", 3) == 0 || strncmp(in->incomplete_data, "POST", 4) == 0) {
|
||||||
char *incomplete_head;
|
sslEncodeCode = configure->http_encode;
|
||||||
int incomplete_head_len;
|
|
||||||
char http_del_copy[configure->http_del_len];
|
char http_del_copy[configure->http_del_len + 1];
|
||||||
char *result = NULL;
|
|
||||||
|
|
||||||
memset(remote_host, 0, CACHE_SIZE);
|
memset(remote_host, 0, CACHE_SIZE);
|
||||||
if (configure->http_port > 0)
|
if (configure->http_port > 0) {
|
||||||
remote_port = configure->http_port;
|
remote_port = configure->http_port;
|
||||||
if (configure->http_ip != NULL)
|
}
|
||||||
strcpy(remote_host, configure->http_ip);
|
if (configure->http_ip != NULL) {
|
||||||
|
memcpy(remote_host, configure->http_ip, configure->http_ip_len);
|
||||||
|
}
|
||||||
|
|
||||||
incomplete_head = (char *)malloc(sizeof(char) * (BUFFER_SIZE));
|
incomplete_head = (char *)malloc(sizeof(char) * (BUFFER_SIZE));
|
||||||
if (incomplete_head == NULL) {
|
if (incomplete_head == NULL) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
@ -556,57 +667,46 @@ char *request_head(conn_t * in, conf * configure)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(incomplete_head, 0, sizeof(char) * (BUFFER_SIZE));
|
memset(incomplete_head, 0, sizeof(char) * (BUFFER_SIZE));
|
||||||
memcpy(incomplete_head, in->incomplete_data, strlen(in->incomplete_data));
|
memmove(incomplete_head, in->incomplete_data, in->incomplete_data_len);
|
||||||
memcpy(http_del_copy, configure->http_del, configure->http_del_len);
|
memmove(http_del_copy, configure->http_del, configure->http_del_len + 1);
|
||||||
|
|
||||||
result = strtok(http_del_copy, ",");
|
result = strtok_r(http_del_copy, delim, &saveptr);
|
||||||
while (result != NULL) {
|
while (result != NULL) {
|
||||||
delete_head(incomplete_head, result, '\n');
|
delete_head(incomplete_head, &in->incomplete_data_len, result, '\n');
|
||||||
result = strtok(NULL, ",");
|
result = strtok_r(NULL, delim, &saveptr);
|
||||||
}
|
}
|
||||||
splice_head(incomplete_head, "\n", configure->http_first);
|
|
||||||
incomplete_head_len = strlen(incomplete_head);
|
splice_head(incomplete_head, &in->incomplete_data_len, "\n", configure->http_first, configure->http_first_len);
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\r", 2, "\r", 1);
|
incomplete_head_len = in->incomplete_data_len; // 更新HTTP HEADER长度
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\n", 2, "\n", 1);
|
incomplete_head = conf_handle_strrep(incomplete_head, &incomplete_head_len, http_head_strrep);
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\b", 2, "\b", 1);
|
incomplete_head = conf_handle_regrep(incomplete_head, &incomplete_head_len, http_head_regrep);
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\v", 2, "\v", 1);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "\\f", 2, "\f", 1);
|
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, "\\a", 2, "\a", 1);
|
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, "\\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, "[U]", 3, http_request->U, http_request->U_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, "[V]", 3, http_request->version, http_request->version_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, "[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, "[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, "[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);
|
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, "[port]", 6, http_request->port, http_request->port_len);
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len);
|
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len);
|
||||||
if (configure->http_strrep)
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, configure->http_strrep_aim, configure->http_strrep_aim_len, configure->http_strrep_obj, configure->http_strrep_obj_len);
|
|
||||||
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);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[host]", 6, http_request->host, http_request->host_len);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[port]", 6, http_request->port, http_request->port_len);
|
|
||||||
incomplete_head = replace(incomplete_head, &incomplete_head_len, "[H]", 3, http_request->H, http_request->H_len);
|
|
||||||
incomplete_head_len = strlen(incomplete_head); // 更新HTTP HEADER长度
|
|
||||||
//printf("%s", incomplete_head); // 打印HTTP HEADER
|
|
||||||
|
|
||||||
|
printf("%s", incomplete_head); // 打印HTTP HEADER
|
||||||
|
|
||||||
char *new_incomplete_data;
|
char *new_incomplete_data;
|
||||||
new_incomplete_data = (char *)realloc(in->incomplete_data, incomplete_head_len + 1); // 更新incomplete_data堆内存
|
new_incomplete_data = (char *)realloc(in->incomplete_data, incomplete_head_len + 1);
|
||||||
if (new_incomplete_data == NULL) {
|
if (new_incomplete_data == NULL) {
|
||||||
|
free(in->incomplete_data);
|
||||||
perror("realloc");
|
perror("realloc");
|
||||||
return NULL;
|
return in->incomplete_data;
|
||||||
}
|
}
|
||||||
in->incomplete_data = new_incomplete_data;
|
in->incomplete_data = new_incomplete_data;
|
||||||
memset(in->incomplete_data, 0, incomplete_head_len + 1); // 清空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数据
|
memmove(in->incomplete_data, incomplete_head, incomplete_head_len); // 更新incomplete_data数据
|
||||||
in->incomplete_data_len = strlen(in->incomplete_data); // 更新incomplete_data长度
|
in->incomplete_data_len = incomplete_head_len; // 更新incomplete_data长度
|
||||||
free(incomplete_head); // 释放incomplete_head内存
|
|
||||||
|
free(incomplete_head); // 释放incomplete_head内存
|
||||||
}
|
}
|
||||||
|
|
||||||
free_http_request(http_request);
|
free_http_request(http_request);
|
||||||
|
@ -8,18 +8,22 @@
|
|||||||
#include "http_proxy.h"
|
#include "http_proxy.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
|
#define HTTP_HEAD_HOST_CACHE_SIZE 1024
|
||||||
|
|
||||||
struct http_request {
|
struct http_request {
|
||||||
char *M, *U, *V;
|
char *method, *U, *version;
|
||||||
char *host, *port, *H;
|
char *host, *port, *H;
|
||||||
char *url, *uri;
|
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 host_len, port_len, H_len;
|
||||||
int url_len, uri_len;
|
int url_len, uri_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
|
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);
|
char *request_head(conn_t * in, conf * configure);
|
||||||
|
extern int8_t copy_new_mem(char *src, int src_len, char **dest);
|
||||||
|
extern void errors(const char *msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
761
httpdns.c
761
httpdns.c
@ -1,130 +1,184 @@
|
|||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include "httpdns.h"
|
#include "httpdns.h"
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
|
|
||||||
char http_rsp[HTTP_RSP_SIZE + 1];
|
#define DNS_MAX_CONCURRENT 512
|
||||||
struct sockaddr_in dst_addr;
|
#define DNS_REQUEST_MAX_SIZE 512+2 //2是TCPDNS头部用于指定dns的长度
|
||||||
char *host_value;
|
#define HTTP_RSP_SIZE 2048
|
||||||
int dnsListenFd = -1, dns_efd;
|
/*
|
||||||
unsigned int host_value_len;
|
缓存结构: (dns查询请求长度-2)(2字节) + dns原查询请求(删除2字节的dnsID) + dns回应长度(2字节) + dns回应
|
||||||
static int8_t encodeCode = 0;
|
*/
|
||||||
|
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;
|
FILE *cfp = NULL;
|
||||||
char *cachePath = NULL;
|
static struct dns_cache *cache = NULL;
|
||||||
struct dns_cache *cache, *cache_temp;
|
static int cache_using;
|
||||||
socklen_t addr_len = sizeof(dst_addr);
|
//子进程先写入缓存,再到父进程写入,否则可能导致缓存文件错乱
|
||||||
unsigned int cache_using, cacheLimit;
|
pid_t child_pid = 0;
|
||||||
dns_t dns_list[DNS_MAX_CONNECTION];
|
|
||||||
struct epoll_event evs[DNS_MAX_CONNECTION + 1], event;
|
|
||||||
|
|
||||||
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;
|
long file_size;
|
||||||
int fn;
|
int len, fl = 0;
|
||||||
|
|
||||||
fn = 0;
|
cache_temp = NULL;
|
||||||
cache = cache_temp = NULL;
|
|
||||||
cache_using = 0;
|
cache_using = 0;
|
||||||
if ((cfp = fopen(cachePath, "rb+")) == NULL) {
|
if ((cfp = fopen(httpdns.cachePath, "r+")) == NULL) {
|
||||||
//保持文件打开状态,防止切换uid后权限不足导致无法写入文件
|
//创建文件并设置权限
|
||||||
cfp = fopen(cachePath, "wb");
|
if ((cfp = fopen(httpdns.cachePath, "w")) != NULL) {
|
||||||
return cfp == NULL ? 1 : 0;
|
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);
|
fseek(cfp, 0, SEEK_END);
|
||||||
file_size = ftell(cfp);
|
file_size = ftell(cfp);
|
||||||
if ((buff = (char *)alloca(file_size)) == NULL) {
|
if ((buff = (char *)alloca(file_size)) == NULL)
|
||||||
fclose(cfp);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
rewind(cfp);
|
rewind(cfp);
|
||||||
if ((fn = fread(buff, file_size, 1, cfp)) < 0) {
|
if ((fl = fread(buff, file_size, 1, cfp)) != 1) ;
|
||||||
perror("fread");
|
fclose(cfp);
|
||||||
}
|
|
||||||
|
|
||||||
//读取缓存,一组缓存的内容为[ipDomain\0],其中ip占5字节
|
for (cache_ptr = buff; cache_ptr - buff < file_size; cache_ptr += len) {
|
||||||
for (answer = buff; answer - buff < file_size; answer = question + cache->question_len + 2) {
|
cache_temp = (struct dns_cache *)malloc(sizeof(struct dns_cache));
|
||||||
cache_temp = (struct dns_cache *)malloc(sizeof(*cache));
|
|
||||||
if (cache_temp == NULL)
|
if (cache_temp == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
cache_temp->next = cache;
|
cache_temp->next = cache;
|
||||||
cache = cache_temp;
|
cache = cache_temp;
|
||||||
cache_using++;
|
cache_using++;
|
||||||
cache->answer = strndup(answer, 5);
|
len = *(uint16_t *) cache_ptr + *(uint16_t *) (cache_ptr + *(uint16_t *) cache_ptr + 2) + 4;
|
||||||
question = answer + 5;
|
copy_new_mem(cache_ptr, len, &cache->dns_cache);
|
||||||
cache->question = strdup(question);
|
if (cache->dns_cache == NULL)
|
||||||
if (cache->question == NULL || cache->answer == NULL)
|
|
||||||
return 1;
|
return 1;
|
||||||
cache->question_len = strlen(question) - 1;
|
|
||||||
}
|
}
|
||||||
/* 删除重复记录 */
|
/* 删除重复记录 */
|
||||||
struct dns_cache *before, *after;
|
struct dns_cache *before, *after;
|
||||||
for (; cache_temp; cache_temp = cache_temp->next) {
|
for (; cache_temp; cache_temp = cache_temp->next) {
|
||||||
for (before = cache_temp; before && (after = before->next) != NULL; before = before->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;
|
before->next = after->next;
|
||||||
free(after->question);
|
free(after->dns_cache);
|
||||||
free(after->answer);
|
|
||||||
free(after);
|
free(after);
|
||||||
cache_using--;
|
cache_using--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(cfp);
|
chmod(httpdns.cachePath, S_IWOTH | S_IROTH | S_IWGRP | S_IRGRP | S_IWUSR | S_IRUSR);
|
||||||
cfp = fopen(cachePath, "wb");
|
|
||||||
return 0;
|
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) {
|
while (cache) {
|
||||||
fputs(cache->answer, cfp);
|
fwrite(cache->dns_cache, *(uint16_t *) cache->dns_cache + *(uint16_t *) (cache->dns_cache + *(uint16_t *) cache->dns_cache + 2) + 4, 1, cfp);
|
||||||
fputs(cache->question, cfp);
|
|
||||||
fputc('\0', cfp);
|
|
||||||
cache = cache->next;
|
cache = cache->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *cache_lookup(char *question, dns_t * dns)
|
static void dnsProxyStop(dns_t * dns)
|
||||||
|
{
|
||||||
|
epoll_ctl(dns_efd, EPOLL_CTL_DEL, dns->fd, NULL);
|
||||||
|
close(dns->fd);
|
||||||
|
if (httpdns.tcpDNS_mode == 0)
|
||||||
|
free(dns->out_request);
|
||||||
|
memset(((char *)dns) + DNS_REQUEST_MAX_SIZE + sizeof(struct sockaddr_in), 0, sizeof(dns_t) - DNS_REQUEST_MAX_SIZE + -sizeof(struct sockaddr_in));
|
||||||
|
dns->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 查询缓存 */
|
||||||
|
static uint8_t cache_lookup(dns_t * dns)
|
||||||
{
|
{
|
||||||
struct dns_cache *c;
|
struct dns_cache *c;
|
||||||
|
char *rsp;
|
||||||
|
|
||||||
for (c = cache; c; c = c->next) {
|
for (c = cache; c; c = c->next) {
|
||||||
if (strcmp(c->question, question) == 0) {
|
//不匹配dnsID
|
||||||
dns->host_len = c->question_len;
|
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) {
|
||||||
dns->query_type = 1;
|
rsp = c->dns_cache + *(uint16_t *) c->dns_cache + 2;
|
||||||
return c->answer;
|
*(uint16_t *) (rsp + 2) = *(uint16_t *) dns->dns_req; //设置dns id
|
||||||
|
sendto(global.dns_listen_fd, rsp + 2, *(uint16_t *) rsp, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_record(dns_t * dns)
|
/* 记录缓存 */
|
||||||
|
static void cache_record(char *request, uint16_t request_len, char *response, uint16_t response_len)
|
||||||
{
|
{
|
||||||
cache_temp = (struct dns_cache *)malloc(sizeof(*cache));
|
struct dns_cache *cache_temp;
|
||||||
|
|
||||||
|
cache_temp = (struct dns_cache *)malloc(sizeof(struct dns_cache));
|
||||||
if (cache_temp == NULL)
|
if (cache_temp == NULL)
|
||||||
return;
|
return;
|
||||||
cache_temp->question = strdup(dns->dns_req + 12);
|
cache_temp->dns_cache = (char *)malloc(request_len + response_len + 2);
|
||||||
if (cache_temp->question == NULL) {
|
if (cache_temp->dns_cache == NULL) {
|
||||||
free(cache_temp);
|
free(cache_temp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cache_temp->next = cache;
|
cache_temp->next = cache;
|
||||||
cache = cache_temp;
|
cache = cache_temp;
|
||||||
cache->question_len = dns->host_len;
|
//不缓存dnsid
|
||||||
cache->answer = dns->reply;
|
request += 2;
|
||||||
if (cacheLimit) {
|
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;
|
struct dns_cache *free_c;
|
||||||
int i;
|
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) {
|
for (free_c = cache_temp->next, cache_temp->next = NULL; free_c; free_c = cache_temp) {
|
||||||
cache_temp = free_c->next;
|
cache_temp = free_c->next;
|
||||||
|
free(free_c->dns_cache);
|
||||||
free(free_c);
|
free(free_c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,100 +186,69 @@ void cache_record(dns_t * dns)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int respond_client(dns_t * dns)
|
|
||||||
{
|
|
||||||
int write_len = sendto(dnsListenFd, dns->dns_req, dns->dns_rsp_len, 0, (struct sockaddr *)&dns->src_addr, sizeof(struct sockaddr_in));
|
|
||||||
if (write_len == dns->dns_rsp_len) {
|
|
||||||
dns->query_type = 0;
|
|
||||||
return 0;
|
|
||||||
} else if (write_len == -1)
|
|
||||||
return -1;
|
|
||||||
else {
|
|
||||||
dns->dns_rsp_len -= write_len;
|
|
||||||
memcpy(dns->dns_req, dns->dns_req + write_len, dns->dns_rsp_len);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void respond_clients()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < DNS_MAX_CONNECTION; i++) {
|
|
||||||
if (dns_list[i].wait_response_client) {
|
|
||||||
if (respond_client(&dns_list[i]) == 1)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
dns_list[i].wait_response_client = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event.events = EPOLLIN;
|
|
||||||
event.data.fd = dnsListenFd;
|
|
||||||
epoll_ctl(dns_efd, EPOLL_CTL_MOD, dnsListenFd, &event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 分析DNS请求 */
|
/* 分析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_req += 13; //跳到域名部分
|
||||||
dns->host_len = strlen(dns_req);
|
dns->host_len = strlen(dns_req);
|
||||||
//判断请求类型
|
dns->query_type = *(dns_req + 2 + dns->host_len);
|
||||||
switch ((dns->query_type = *(dns_req + 2 + dns->host_len))) {
|
//tcpdns不需要解析域名
|
||||||
//case 28: //查询ipv6地址
|
if (httpdns.tcpDNS_mode == 1)
|
||||||
//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;
|
return 0;
|
||||||
|
//httpdns只支持域名查询ipv4
|
||||||
default:
|
if (dns->query_type != 1 || (dns->host = strdup(dns_req)) == NULL)
|
||||||
dns->host = NULL;
|
|
||||||
return 1;
|
return 1;
|
||||||
|
for (len = *(--dns_req); dns_req[len + 1] != 0; len += dns_req[len]) {
|
||||||
|
//防止数组越界
|
||||||
|
if (len > dns->host_len) {
|
||||||
|
free(dns->host);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dns->host[len++] = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 建立DNS回应 */
|
/* 回应dns客户端 */
|
||||||
int build_dns_response(dns_t * dns)
|
static int8_t httpDNS_respond_client(dns_t * dns, char *rspIp)
|
||||||
{
|
{
|
||||||
|
static char rsp[DNS_REQUEST_MAX_SIZE + 16];
|
||||||
char *p;
|
char *p;
|
||||||
|
int rsp_len;
|
||||||
|
|
||||||
//18: 查询资源的前(12字节)后(6字节)部分
|
//18: 查询资源的前(12字节)后(6字节)部分
|
||||||
dns->dns_rsp_len = 18 + dns->host_len + (dns->reply ? 16 : 0);
|
rsp_len = 18 + dns->host_len + (rspIp ? 16 : 0);
|
||||||
if (dns->dns_rsp_len > DATA_SIZE) {
|
//判断是否超出缓冲大小
|
||||||
|
if (rsp_len > DNS_REQUEST_MAX_SIZE) {
|
||||||
dns->query_type = 0;
|
dns->query_type = 0;
|
||||||
return 1; //超出缓冲大小
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* dns ID */
|
||||||
|
memcpy(rsp, dns->dns_req, 2);
|
||||||
/* 问题数 */
|
/* 问题数 */
|
||||||
dns->dns_req[4] = 0;
|
rsp[4] = 0;
|
||||||
dns->dns_req[5] = 1;
|
rsp[5] = 1;
|
||||||
/* 资源记录数 */
|
/* 资源记录数 */
|
||||||
dns->dns_req[6] = 0;
|
rsp[6] = 0;
|
||||||
dns->dns_req[7] = 0;
|
rsp[7] = 0;
|
||||||
/* 授权资源记录数 */
|
/* 授权资源记录数 */
|
||||||
dns->dns_req[8] = 0;
|
rsp[8] = 0;
|
||||||
dns->dns_req[9] = 0;
|
rsp[9] = 0;
|
||||||
/* 额外资源记录数 */
|
/* 额外资源记录数 */
|
||||||
dns->dns_req[10] = 0;
|
rsp[10] = 0;
|
||||||
dns->dns_req[11] = 0;
|
rsp[11] = 0;
|
||||||
|
memcpy(rsp + 12, dns->dns_req + 12, dns->host_len + 6);
|
||||||
/* 如果有回应内容(资源记录) */
|
/* 如果有回应内容(资源记录) */
|
||||||
if (dns->reply) {
|
if (rspIp) {
|
||||||
p = dns->dns_req + 18 + dns->host_len;
|
p = rsp + 18 + dns->host_len;
|
||||||
/* 资源记录数+1 */
|
/* 资源记录数+1 */
|
||||||
dns->dns_req[7]++;
|
rsp[7]++;
|
||||||
/* 成功标志 */
|
/* 成功标志 */
|
||||||
dns->dns_req[2] = (char)133;
|
rsp[2] = (char)133;
|
||||||
dns->dns_req[3] = (char)128;
|
rsp[3] = (char)128;
|
||||||
/* 指向主机域名 */
|
/* 指向主机域名 */
|
||||||
p[0] = (char)192;
|
p[0] = (char)192;
|
||||||
p[1] = 12;
|
p[1] = 12;
|
||||||
@ -242,267 +265,341 @@ int build_dns_response(dns_t * dns)
|
|||||||
p[9] = 16;
|
p[9] = 16;
|
||||||
/* 回应长度 */
|
/* 回应长度 */
|
||||||
p[10] = 0;
|
p[10] = 0;
|
||||||
p[11] = 4; //reply中包含回应长度
|
p[11] = 4;
|
||||||
strcpy(p + 12, dns->reply);
|
memcpy(p + 12, rspIp, 4);
|
||||||
} else {
|
} else {
|
||||||
/* 失败标志 */
|
/* 失败标志 */
|
||||||
dns->dns_req[2] = (char)129;
|
rsp[2] = (char)129;
|
||||||
dns->dns_req[3] = (char)130;
|
rsp[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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//因为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;
|
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;
|
int write_len;
|
||||||
|
|
||||||
//puts("writing");
|
out->timer = 0;
|
||||||
//printf("%s\n", out->http_request);
|
if (httpdns.connect_request && out->sent_CONNECT_len < httpdns.connect_request_len) {
|
||||||
write_len = write(out->fd, out->http_request, out->http_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 == out->http_request_len) {
|
if (write_len == -1) {
|
||||||
//puts("write success");
|
dnsProxyStop(out);
|
||||||
free(out->http_request);
|
} else {
|
||||||
event.events = EPOLLIN | EPOLLET;
|
out->sent_CONNECT_len += write_len;
|
||||||
event.data.ptr = out;
|
if (out->sent_CONNECT_len == httpdns.connect_request_len) {
|
||||||
epoll_ctl(dns_efd, EPOLL_CTL_MOD, out->fd, &event);
|
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) {
|
} else if (write_len > 0) {
|
||||||
//puts("write a little");
|
out->out_request_len -= write_len;
|
||||||
out->http_request_len -= write_len;
|
memmove(out->out_request, out->out_request + write_len, out->out_request_len);
|
||||||
memcpy(out->http_request, out->http_request + write_len, out->http_request_len);
|
|
||||||
} else {
|
} else {
|
||||||
//puts("write error");
|
|
||||||
free(out->http_request);
|
|
||||||
epoll_ctl(dns_efd, EPOLL_CTL_DEL, out->fd, NULL);
|
epoll_ctl(dns_efd, EPOLL_CTL_DEL, out->fd, NULL);
|
||||||
close(out->fd);
|
close(out->fd);
|
||||||
out->query_type = 0;
|
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;
|
char *ip_ptr, *p, ip[4];
|
||||||
int len, i;
|
int i;
|
||||||
|
|
||||||
len = read(in->fd, http_rsp, HTTP_RSP_SIZE);
|
p = strstr(rsp, "\n\r");
|
||||||
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) {
|
if (p) {
|
||||||
//部分代理服务器使用长连接,第二次读取数据才读到域名的IP
|
|
||||||
if (p + 3 - http_rsp >= len)
|
|
||||||
return;
|
|
||||||
p += 3;
|
p += 3;
|
||||||
} else
|
rsp_len -= p - rsp;
|
||||||
p = http_rsp;
|
//部分代理服务器使用长连接,第二次读取数据才读到域名的IP
|
||||||
epoll_ctl(dns_efd, EPOLL_CTL_DEL, in->fd, NULL);
|
if (rsp_len <= 0)
|
||||||
close(in->fd);
|
return;
|
||||||
in->reply = (char *)malloc(5);
|
rsp = p;
|
||||||
if (in->reply == NULL)
|
}
|
||||||
goto error;
|
if (httpdns.encodeCode)
|
||||||
|
dataEncode(rsp, rsp_len, httpdns.encodeCode);
|
||||||
do {
|
do {
|
||||||
if (*p == '\n')
|
if (*rsp == '\n')
|
||||||
p++;
|
rsp++;
|
||||||
/* 匹配IP */
|
/* 匹配IP */
|
||||||
if (*p > 57 || *p < 49)
|
while ((*rsp > 57 || *rsp < 49) && *rsp != '\0')
|
||||||
continue;
|
rsp++;
|
||||||
for (i = 0, ip_ptr = p, p = strchr(ip_ptr, '.');; ip_ptr = p + 1, p = strchr(ip_ptr, '.')) {
|
for (i = 0, ip_ptr = rsp, rsp = strchr(ip_ptr, '.');; ip_ptr = rsp + 1, rsp = strchr(ip_ptr, '.')) {
|
||||||
if (i < 3) {
|
if (i < 3) {
|
||||||
if (p == NULL)
|
if (rsp == NULL) {
|
||||||
goto error;
|
httpDNS_respond_client(dns, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
//查找下一行
|
//查找下一行
|
||||||
if (p - ip_ptr > 3)
|
if (rsp - ip_ptr > 3)
|
||||||
break;
|
break;
|
||||||
in->reply[i++] = atoi(ip_ptr);
|
ip[i++] = atoi(ip_ptr);
|
||||||
} else {
|
} else {
|
||||||
in->reply[3] = atoi(ip_ptr);
|
ip[3] = atoi(ip_ptr);
|
||||||
in->reply[4] = 0;
|
httpDNS_respond_client(dns, ip);
|
||||||
build_dns_response(in);
|
|
||||||
cfp ? cache_record(in) : free(in->reply);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while ((p = strchr(p, '\n')) != NULL);
|
} while ((rsp = strchr(rsp, '\n')) != NULL);
|
||||||
|
|
||||||
error:
|
|
||||||
free(in->reply);
|
|
||||||
in->reply = NULL;
|
|
||||||
if (build_dns_response(in) == 1)
|
|
||||||
in->query_type = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
dns_t *dns;
|
||||||
|
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
for (i = 0; i < DNS_MAX_CONNECTION; i++)
|
for (i = 0; i < DNS_MAX_CONCURRENT; i++) {
|
||||||
if (dns_list[i].query_type == 0)
|
if (dns_list[i].query_type == 0) {
|
||||||
|
dns = &dns_list[i];
|
||||||
break;
|
break;
|
||||||
if (i == DNS_MAX_CONNECTION)
|
}
|
||||||
|
}
|
||||||
|
if (i == DNS_MAX_CONCURRENT)
|
||||||
return;
|
return;
|
||||||
dns = &dns_list[i];
|
len = recvfrom(global.dns_listen_fd, dns->dns_req, DNS_REQUEST_MAX_SIZE - 2, 0, (struct sockaddr *)&dns->src_addr, &addr_len);
|
||||||
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
|
//dns请求必须大于18
|
||||||
if (len <= 18)
|
if (len <= 18)
|
||||||
return;
|
return;
|
||||||
|
dns->dns_req_len = (uint16_t) len;
|
||||||
/* 查询缓存 */
|
/* 查询缓存 */
|
||||||
if (cachePath) {
|
if (cfp && cache_lookup(dns) == 0)
|
||||||
dns->reply = cache_lookup(dns->dns_req + 12, dns);
|
|
||||||
if (dns->reply != NULL) {
|
|
||||||
if (build_dns_response(dns) != 0)
|
|
||||||
dns->query_type = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parse_dns_request(dns->dns_req, dns) != 0) {
|
|
||||||
if (dns->host == NULL) {
|
|
||||||
if (build_dns_response(dns) != 0)
|
|
||||||
dns->query_type = 0;
|
|
||||||
} else
|
|
||||||
dns->query_type = 0;
|
|
||||||
return;
|
return;
|
||||||
|
if (create_outRequest(dns) != 0 || connectToDnsServer(dns) != 0) {
|
||||||
|
if (dns->out_request != dns->dns_req)
|
||||||
|
free(dns->out_request);
|
||||||
|
httpDNS_respond_client(dns, NULL);
|
||||||
}
|
}
|
||||||
dns->fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (dns->fd < 0) {
|
|
||||||
dns->query_type = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fcntl(dns->fd, F_SETFL, O_NONBLOCK);
|
|
||||||
if (connect(dns->fd, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) != 0 && errno != EINPROGRESS) {
|
|
||||||
close(dns->fd);
|
|
||||||
dns->query_type = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (encodeCode)
|
|
||||||
dataEncode(dns->host, strlen(dns->host));
|
|
||||||
/* "GET /d?dn=" + dns->host + " HTTP/1.0\r\nHost: " + host_value + "\r\n\r\n" */
|
|
||||||
dns->http_request = (char *)malloc(10 + strlen(dns->host) + 17 + host_value_len + 4 + 1);
|
|
||||||
free(dns->host);
|
|
||||||
if (dns->http_request == NULL) {
|
|
||||||
close(dns->fd);
|
|
||||||
dns->query_type = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//dns->http_request_len = sprintf(dns->http_request, "GET /d?dn=%s HTTP/1.0\r\nHost: %s\r\n\r\n", dns->host, host_value);
|
|
||||||
|
|
||||||
strcpy(dns->http_request, configure->http_req);
|
|
||||||
dns->http_request_len = strlen(dns->http_request);
|
|
||||||
int http_request_len = (int)dns->http_request_len;
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "[M]", 3, "GET", 3);
|
|
||||||
dns->host_len = strlen(dns->host);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "[D]", 3, dns->host, dns->host_len);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "[V]", 3, "HTTP/1.0", 8);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\r", 2, "\r", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\n", 2, "\n", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\b", 2, "\b", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\v", 2, "\v", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\f", 2, "\f", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\a", 2, "\a", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\t", 2, "\t", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\r", 2, "\r", 1);
|
|
||||||
dns->http_request = replace(dns->http_request, &http_request_len, "\\n", 2, "\n", 1);
|
|
||||||
dns->http_request_len = strlen(dns->http_request);
|
|
||||||
//printf("%s\n", dns->http_request);
|
|
||||||
|
|
||||||
event.events = EPOLLOUT | EPOLLERR | EPOLLET;
|
|
||||||
event.data.ptr = dns;
|
|
||||||
epoll_ctl(dns_efd, EPOLL_CTL_ADD, dns->fd, &event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *httpdns_loop(void *p)
|
static void httpRequest_init()
|
||||||
{
|
{
|
||||||
conf *configure = (conf *) p;
|
char dest[22];
|
||||||
int n;
|
uint16_t port;
|
||||||
|
|
||||||
fcntl(dnsListenFd, F_SETFL, O_NONBLOCK);
|
port = ntohs(httpdns.dst.sin_port);
|
||||||
dns_efd = epoll_create(DNS_MAX_CONNECTION + 1);
|
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) {
|
if (dns_efd < 0) {
|
||||||
perror("epoll_create");
|
perror("epoll_create");
|
||||||
return NULL;
|
exit(1);
|
||||||
}
|
}
|
||||||
event.data.fd = dnsListenFd;
|
fcntl(global.dns_listen_fd, F_SETFL, O_NONBLOCK);
|
||||||
event.events = EPOLLIN;
|
dns_ev.data.fd = global.dns_listen_fd;
|
||||||
epoll_ctl(dns_efd, EPOLL_CTL_ADD, dnsListenFd, &event);
|
dns_ev.events = EPOLLIN;
|
||||||
|
epoll_ctl(dns_efd, EPOLL_CTL_ADD, global.dns_listen_fd, &dns_ev);
|
||||||
memset(dns_list, 0, sizeof(dns_list));
|
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) {
|
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) {
|
while (n-- > 0) {
|
||||||
if (evs[n].data.fd == dnsListenFd) {
|
if (dns_evs[n].data.fd == global.dns_listen_fd) {
|
||||||
if (evs[n].events & EPOLLIN) {
|
new_client();
|
||||||
new_client(configure);
|
} else {
|
||||||
|
if (dns_evs[n].events & EPOLLIN) {
|
||||||
|
http_in((dns_t *) dns_evs[n].data.ptr);
|
||||||
}
|
}
|
||||||
if (evs[n].events & EPOLLOUT) {
|
if (dns_evs[n].events & EPOLLOUT) {
|
||||||
respond_clients();
|
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;
|
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;
|
|
||||||
}
|
}
|
||||||
|
62
httpdns.h
Normal file → Executable file
62
httpdns.h
Normal file → Executable file
@ -1,51 +1,25 @@
|
|||||||
#ifndef _HTTPDNS_
|
#ifndef HTTPDNS_H
|
||||||
#define _HTTPDNS_
|
#define HTTPDNS_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "main.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 "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函数的效率
|
struct httpdns {
|
||||||
#define DATA_SIZE 512
|
struct sockaddr_in dst;
|
||||||
#define HTTP_RSP_SIZE 1024
|
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;
|
||||||
typedef struct dns_connection {
|
unsigned encodeCode, //Host编码传输
|
||||||
char dns_req[DATA_SIZE];
|
httpsProxy_encodeCode, //CONNECT代理编码
|
||||||
struct sockaddr_in src_addr;
|
tcpDNS_mode:1; //判断是否开启TCPDNS
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern dns_t dns_list[DNS_MAX_CONNECTION];
|
extern void dns_timeout_check();
|
||||||
extern struct epoll_event evs[DNS_MAX_CONNECTION + 1], event;
|
extern void *dns_loop(void *nullPtr);
|
||||||
|
extern int8_t read_cache_file();
|
||||||
void *httpdns_loop(void *p);
|
extern void dns_init();
|
||||||
int httpdns_initialize(conf * configure);
|
extern struct httpdns httpdns;
|
||||||
|
extern pid_t child_pid;
|
||||||
|
extern FILE *cfp;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
438
httpudp.c
Executable file
438
httpudp.c
Executable file
@ -0,0 +1,438 @@
|
|||||||
|
/*
|
||||||
|
HTTPUDP模块代理UDP过程:
|
||||||
|
获取客户端UDP数据
|
||||||
|
向服务器发送一个http请求头
|
||||||
|
收到服务端回应后发送数据到服务端,内容为: UDP原始目标地址[struct in_addr](只有第一个数据包发送) + UDP长度[uint16_t] + UDP真实数据
|
||||||
|
服务端返回数据,数据内容为: UDP包的长度[uint16_t] + UDP真实数据
|
||||||
|
新建一个socket伪装原目标地址向客户端发送返回的数据(此功能需要root,否则部分UDP代理不上,例如QQ语音)
|
||||||
|
*/
|
||||||
|
#include "http_request.h"
|
||||||
|
#include "httpudp.h"
|
||||||
|
|
||||||
|
#define MAX_CLIENT_INFO 512
|
||||||
|
#define HTTP_RSP_SIZE 2048
|
||||||
|
#define CLIENT_BUFFER_SIZE 65535 //如果可以 尽量一次性读完数据
|
||||||
|
#define SERVER_BUFFER_SIZE 8192
|
||||||
|
|
||||||
|
typedef struct connection_info {
|
||||||
|
char client_data[CLIENT_BUFFER_SIZE + sizeof(struct sockaddr_in) + sizeof(uint16_t)];
|
||||||
|
struct sockaddr_in inaddr, toaddr;
|
||||||
|
struct connection_info *next;
|
||||||
|
char *rsp_data;
|
||||||
|
int client_data_len, client_data_sent_len, http_request_sent_len, rsp_data_len, rsp_data_sent_len, server_fd, responseClientFd, timer;
|
||||||
|
} info_t;
|
||||||
|
|
||||||
|
static info_t client_info_list[MAX_CLIENT_INFO];
|
||||||
|
static struct epoll_event udp_evs[MAX_CLIENT_INFO * 2 + 2], udp_ev;
|
||||||
|
struct httpudp udp;
|
||||||
|
static int udp_efd;
|
||||||
|
|
||||||
|
static void proxyStop(info_t * info)
|
||||||
|
{
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_DEL, info->server_fd, NULL);
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_DEL, info->responseClientFd, NULL);
|
||||||
|
close(info->server_fd);
|
||||||
|
close(info->responseClientFd);
|
||||||
|
free(info->rsp_data);
|
||||||
|
info->rsp_data = NULL;
|
||||||
|
do {
|
||||||
|
info->server_fd = info->responseClientFd = -1;
|
||||||
|
info->rsp_data_len = info->rsp_data_sent_len = info->client_data_sent_len = info->http_request_sent_len = 0;
|
||||||
|
} while ((info = info->next) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_timeout_check()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CLIENT_INFO; i++) {
|
||||||
|
if (client_info_list[i].server_fd > -1) {
|
||||||
|
if (client_info_list[i].timer >= global.timeout_m)
|
||||||
|
proxyStop(client_info_list + i);
|
||||||
|
else
|
||||||
|
client_info_list[i].timer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 创建udpfd回应客户端 */
|
||||||
|
static int createRspFd(info_t * client)
|
||||||
|
{
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
client->responseClientFd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (client->responseClientFd < 0)
|
||||||
|
return 1;
|
||||||
|
fcntl(client->responseClientFd, F_SETFL, O_NONBLOCK);
|
||||||
|
/*
|
||||||
|
以下函数不做返回值判断
|
||||||
|
因为有些UDP客户端不需要伪装源目标地址
|
||||||
|
*/
|
||||||
|
setsockopt(client->responseClientFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||||
|
setsockopt(client->responseClientFd, SOL_IP, IP_TRANSPARENT, &opt, sizeof(opt));
|
||||||
|
//切换root伪装源目标地址
|
||||||
|
if (-1 == seteuid(0))
|
||||||
|
perror("seteuid");
|
||||||
|
if (-1 == setegid(0))
|
||||||
|
perror("setegid");
|
||||||
|
bind(client->responseClientFd, (struct sockaddr *)&client->toaddr, sizeof(struct sockaddr_in));
|
||||||
|
//切换回用户设置的uid
|
||||||
|
if (-1 == setegid(global.uid))
|
||||||
|
perror("setegid");
|
||||||
|
if (-1 == seteuid(global.uid))
|
||||||
|
perror("seteuid");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 将服务端返回的数据发送到客户端 */
|
||||||
|
static int outputToClient(info_t * client)
|
||||||
|
{
|
||||||
|
char *dataPtr;
|
||||||
|
int write_len;
|
||||||
|
|
||||||
|
if (client->responseClientFd < 0 && createRspFd(client) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
client->timer = 0;
|
||||||
|
dataPtr = client->rsp_data;
|
||||||
|
//至少要有一个完整的udp包才返回客户端
|
||||||
|
while ((int)(*(uint16_t *) dataPtr + sizeof(uint16_t)) <= client->rsp_data_len) {
|
||||||
|
write_len = sendto(client->responseClientFd, dataPtr + sizeof(uint16_t) + client->rsp_data_sent_len, *(uint16_t *) dataPtr - client->rsp_data_sent_len, 0, (struct sockaddr *)&client->inaddr, sizeof(struct sockaddr_in));
|
||||||
|
//printf("rsp: [write_len:%d, dataLen:%u, sent:%u, total:%d]\n", write_len, *(uint16_t *)dataPtr, client->rsp_data_sent_len, client->rsp_data_len);
|
||||||
|
if (write_len < 0 && errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
client->rsp_data_sent_len += write_len;
|
||||||
|
if (write_len == 0 || write_len < 0) {
|
||||||
|
//perror("toClient write()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (write_len < *(uint16_t *) dataPtr) {
|
||||||
|
udp_ev.data.ptr = client;
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_ADD, client->responseClientFd, &udp_ev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dataPtr += write_len + sizeof(uint16_t);
|
||||||
|
client->rsp_data_len -= write_len + sizeof(uint16_t);
|
||||||
|
client->rsp_data_sent_len = 0;
|
||||||
|
}
|
||||||
|
//发送完已读取到的所有数据 释放内存
|
||||||
|
if (client->rsp_data_len == 0) {
|
||||||
|
free(client->rsp_data);
|
||||||
|
client->rsp_data = NULL;
|
||||||
|
udp_ev.data.ptr = client;
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLET;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_MOD, client->responseClientFd, &udp_ev);
|
||||||
|
}
|
||||||
|
//还有数据未返回给客户端,将未返回的数据复制到内存头
|
||||||
|
else if (dataPtr > client->rsp_data) {
|
||||||
|
memmove(client->rsp_data, dataPtr, client->rsp_data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 读取服务器的数据并返回给客户端 */
|
||||||
|
static void recvServer(info_t * in)
|
||||||
|
{
|
||||||
|
in->timer = 0;
|
||||||
|
//当条件成立时表示未接收https回应状态码
|
||||||
|
if (udp.http_request_len == in->http_request_sent_len) {
|
||||||
|
static char http_rsp[HTTP_RSP_SIZE];
|
||||||
|
int read_len;
|
||||||
|
do {
|
||||||
|
read_len = read(in->server_fd, http_rsp, HTTP_RSP_SIZE);
|
||||||
|
if (read_len == 0 || (read_len < 0 && errno != EAGAIN)) {
|
||||||
|
proxyStop(in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (read_len == HTTP_RSP_SIZE);
|
||||||
|
in->http_request_sent_len++; //不再接收http头
|
||||||
|
udp_ev.data.ptr = in;
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_MOD, in->server_fd, &udp_ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *new_data;
|
||||||
|
int read_len;
|
||||||
|
do {
|
||||||
|
new_data = (char *)realloc(in->rsp_data, in->rsp_data_len + SERVER_BUFFER_SIZE);
|
||||||
|
if (new_data == NULL) {
|
||||||
|
proxyStop(in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
in->rsp_data = new_data;
|
||||||
|
read_len = read(in->server_fd, in->rsp_data + in->rsp_data_len, SERVER_BUFFER_SIZE);
|
||||||
|
/* 判断是否关闭连接 */
|
||||||
|
if (read_len <= 0) {
|
||||||
|
if (read_len == 0 || errno != EAGAIN || in->rsp_data_len == 0) {
|
||||||
|
proxyStop(in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
read_len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (udp.httpsProxy_encodeCode)
|
||||||
|
dataEncode(in->rsp_data + in->rsp_data_len, read_len, udp.httpsProxy_encodeCode);
|
||||||
|
if (udp.encodeCode)
|
||||||
|
dataEncode(in->rsp_data + in->rsp_data_len, read_len, udp.encodeCode);
|
||||||
|
in->rsp_data_len += read_len;
|
||||||
|
} while (read_len == SERVER_BUFFER_SIZE);
|
||||||
|
outputToClient(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 向服务器发送数据 */
|
||||||
|
static int sendToServer(info_t * out)
|
||||||
|
{
|
||||||
|
info_t *send_info;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
out->timer = 0;
|
||||||
|
/* 发送http请求头到服务器 */
|
||||||
|
if (udp.http_request_len > out->http_request_sent_len) {
|
||||||
|
len = write(out->server_fd, udp.http_request + out->http_request_sent_len, udp.http_request_len - out->http_request_sent_len);
|
||||||
|
if (len <= 0) {
|
||||||
|
if (len == 0 || errno != EAGAIN)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
out->http_request_sent_len += len;
|
||||||
|
if (udp.http_request_len == out->http_request_sent_len) {
|
||||||
|
udp_ev.data.ptr = out;
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLET;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_MOD, out->server_fd, &udp_ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 发送UDP目标地址,UDP数据长度和UDP真实数据到服务器 */
|
||||||
|
for (send_info = out; send_info; send_info = send_info->next) {
|
||||||
|
if (send_info->client_data_len == send_info->client_data_sent_len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = write(out->server_fd, send_info->client_data + send_info->client_data_sent_len, send_info->client_data_len - send_info->client_data_sent_len);
|
||||||
|
//printf("server_fd: %d, write_len: %d, udp_len: %d, sent_le: %d\n", out->server_fd, len, send_info->client_data_len - send_info->client_data_sent_len, send_info->client_data_sent_len);
|
||||||
|
if (len <= 0) {
|
||||||
|
if (len == 0 || errno != EAGAIN)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
send_info->client_data_sent_len += len;
|
||||||
|
if (send_info->client_data_sent_len < send_info->client_data_len)
|
||||||
|
break;
|
||||||
|
if (send_info != out) {
|
||||||
|
//此结构体已用完
|
||||||
|
send_info->server_fd = -1;
|
||||||
|
send_info->client_data_sent_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (send_info == NULL) {
|
||||||
|
udp_ev.data.ptr = out;
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLET;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_MOD, out->server_fd, &udp_ev);
|
||||||
|
}
|
||||||
|
out->next = send_info;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void outEvent(info_t * out)
|
||||||
|
{
|
||||||
|
if (out->server_fd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((out->rsp_data && outputToClient(out) != 0) || sendToServer(out) != 0)
|
||||||
|
proxyStop(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int recvClient(info_t * client)
|
||||||
|
{
|
||||||
|
static char control[1024];
|
||||||
|
struct msghdr msg;
|
||||||
|
struct iovec io;
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
|
|
||||||
|
msg.msg_name = &client->inaddr;
|
||||||
|
msg.msg_namelen = sizeof(client->inaddr);
|
||||||
|
msg.msg_iov = &io;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
msg.msg_control = control;
|
||||||
|
msg.msg_controllen = sizeof(control);
|
||||||
|
io.iov_base = client->client_data + sizeof(struct sockaddr_in) + sizeof(uint16_t);
|
||||||
|
io.iov_len = CLIENT_BUFFER_SIZE;
|
||||||
|
client->client_data_len = recvmsg(global.udp_listen_fd, &msg, 0);
|
||||||
|
if (client->client_data_len <= 0) {
|
||||||
|
//perror("recvmsg()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* 取得客户端目标地址 */
|
||||||
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
|
||||||
|
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_ORIGDSTADDR && cmsg->cmsg_len >= CMSG_LEN(sizeof(client->toaddr))) {
|
||||||
|
memcpy(&client->toaddr, CMSG_DATA(cmsg), sizeof(client->toaddr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cmsg == NULL)
|
||||||
|
return 1;
|
||||||
|
/*
|
||||||
|
printf("src ip: [%s], port: [%d]\n", inet_ntoa(client->inaddr.sin_addr), ntohs(client->inaddr.sin_port));
|
||||||
|
printf("dst ip: [%s], port: [%d]\n", inet_ntoa(client->toaddr.sin_addr), ntohs(client->toaddr.sin_port));
|
||||||
|
*/
|
||||||
|
//printf("client len: %d\n", client->client_data_len);
|
||||||
|
//复制udp长度和原始目标地址
|
||||||
|
memcpy(client->client_data, &client->toaddr, sizeof(struct sockaddr_in));
|
||||||
|
memcpy(client->client_data + sizeof(struct sockaddr_in), &client->client_data_len, sizeof(uint16_t));
|
||||||
|
client->client_data_len += sizeof(uint16_t) + sizeof(struct sockaddr_in);
|
||||||
|
if (udp.encodeCode)
|
||||||
|
dataEncode(client->client_data, client->client_data_len, udp.encodeCode);
|
||||||
|
if (udp.httpsProxy_encodeCode)
|
||||||
|
dataEncode(client->client_data, client->client_data_len, udp.httpsProxy_encodeCode);
|
||||||
|
|
||||||
|
client->next = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connectToServer(info_t * info)
|
||||||
|
{
|
||||||
|
info->timer = 0;
|
||||||
|
info->server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (info->server_fd < 0)
|
||||||
|
return;
|
||||||
|
fcntl(info->server_fd, F_SETFL, O_NONBLOCK);
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||||
|
udp_ev.data.ptr = info;
|
||||||
|
if (epoll_ctl(udp_efd, EPOLL_CTL_ADD, info->server_fd, &udp_ev) != 0) {
|
||||||
|
close(info->server_fd);
|
||||||
|
info->server_fd = -1;
|
||||||
|
} else if (connect(info->server_fd, (struct sockaddr *)&udp.dst, sizeof(udp.dst)) != 0 && errno != EINPROGRESS) {
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_DEL, info->server_fd, NULL);
|
||||||
|
close(info->server_fd);
|
||||||
|
info->server_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 源地址跟目标地址一样的话,服务端需要同一个socket转发 */
|
||||||
|
static int margeClient(info_t * client)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CLIENT_INFO; i++) {
|
||||||
|
if (client != client_info_list + i && client_info_list[i].server_fd > -1 && memcmp(((char *)&client->toaddr) + 2, ((char *)&client_info_list[i].toaddr) + 2, 6) == 0 && memcmp(((char *)&client->inaddr) + 2, ((char *)&client_info_list[i].inaddr) + 2, 6) == 0) {
|
||||||
|
info_t *lastInfo;
|
||||||
|
for (lastInfo = client_info_list + i; lastInfo->next; lastInfo = lastInfo->next) ;
|
||||||
|
lastInfo->next = client;
|
||||||
|
client->server_fd = -2; //保证下次调用margeClient()不匹配到这个结构体 并且不被其他客户端连接使用
|
||||||
|
client->client_data_sent_len = sizeof(struct sockaddr_in); //不再发送UDP目标地址
|
||||||
|
//没有收到服务端回应前不发送UDP的数据
|
||||||
|
if (client_info_list[i].http_request_sent_len > udp.http_request_len) {
|
||||||
|
udp_ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||||
|
udp_ev.data.ptr = client_info_list + i;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_MOD, client_info_list[i].server_fd, &udp_ev);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void new_client()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CLIENT_INFO; i++) {
|
||||||
|
if (client_info_list[i].server_fd == -1) {
|
||||||
|
if (recvClient(client_info_list + i) == 0)
|
||||||
|
if (margeClient(client_info_list + i) != 0)
|
||||||
|
connectToServer(client_info_list + i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void http_udp_req_init()
|
||||||
|
{
|
||||||
|
char dest[22];
|
||||||
|
|
||||||
|
sprintf(dest, "%s:%u", inet_ntoa(udp.dst.sin_addr), ntohs(udp.dst.sin_port));
|
||||||
|
if (udp.http_request) {
|
||||||
|
udp.http_request_len = strlen(udp.http_request) + 2;
|
||||||
|
udp.http_request = (char *)realloc(udp.http_request, udp.http_request_len + 1);
|
||||||
|
if (udp.http_request == NULL)
|
||||||
|
errors("httpudp http request initializate failed.");
|
||||||
|
strcat(udp.http_request, "\r\n");
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[V]", 3, "HTTP/1.1", 8);
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[H]", 3, dest, strlen(dest));
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "\\0", 2, "\0", 1);
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[M]", 3, "CONNECT", 7);
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[url]", 5, "/", 1);
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[U]", 3, "/", 1);
|
||||||
|
} else { /* 默认使用CONNECT请求 */
|
||||||
|
if (https.encodeCode) {
|
||||||
|
dataEncode(dest, strlen(dest), https.encodeCode);
|
||||||
|
udp.httpsProxy_encodeCode = https.encodeCode;
|
||||||
|
}
|
||||||
|
udp.http_request_len = default_ssl_request_len;
|
||||||
|
copy_new_mem(default_ssl_request, default_ssl_request_len, &udp.http_request);
|
||||||
|
udp.http_request = replace(udp.http_request, &udp.http_request_len, "[H]", 3, dest, strlen(dest));
|
||||||
|
memcpy(&udp.dst, &https.dst, sizeof(udp.dst));
|
||||||
|
}
|
||||||
|
if (udp.http_request == NULL)
|
||||||
|
errors("out of memory.");
|
||||||
|
/* 保存原始生成的请求头,配合usr_hdr使用 */
|
||||||
|
if (saveHdrs) {
|
||||||
|
if (copy_new_mem(udp.http_request, udp.http_request_len, &udp.original_http_request) != 0)
|
||||||
|
errors("out of memory.");
|
||||||
|
udp.original_http_request_len = udp.http_request_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_init()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
//初始化http请求
|
||||||
|
http_udp_req_init();
|
||||||
|
//初始化结构体
|
||||||
|
memset(client_info_list, 0, sizeof(info_t) * MAX_CLIENT_INFO);
|
||||||
|
for (i = 0; i < MAX_CLIENT_INFO; i++)
|
||||||
|
client_info_list[i].server_fd = client_info_list[i].responseClientFd = -1;
|
||||||
|
//创建epoll fd
|
||||||
|
udp_efd = epoll_create(MAX_CLIENT_INFO * 2 + 1);
|
||||||
|
if (udp_efd < 0) {
|
||||||
|
perror("udp epoll_create()");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
//添加监听socket到epoll
|
||||||
|
fcntl(global.udp_listen_fd, F_SETFL, O_NONBLOCK);
|
||||||
|
udp_ev.data.fd = global.udp_listen_fd;
|
||||||
|
udp_ev.events = EPOLLIN;
|
||||||
|
epoll_ctl(udp_efd, EPOLL_CTL_ADD, global.udp_listen_fd, &udp_ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *udp_loop(void *nullPtr)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
n = epoll_wait(udp_efd, udp_evs, MAX_CLIENT_INFO * 2 + 1, -1);
|
||||||
|
while (n-- > 0) {
|
||||||
|
if (udp_evs[n].data.fd == global.udp_listen_fd) {
|
||||||
|
new_client();
|
||||||
|
} else {
|
||||||
|
if (udp_evs[n].events & EPOLLIN) {
|
||||||
|
recvServer((info_t *) udp_evs[n].data.ptr);
|
||||||
|
}
|
||||||
|
if (udp_evs[n].events & EPOLLOUT) {
|
||||||
|
outEvent((info_t *) udp_evs[n].data.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; //消除编译警告
|
||||||
|
}
|
33
httpudp.h
Executable file
33
httpudp.h
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef HTTPUDP_H
|
||||||
|
#define HTTPUDP_H
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/* 定义TPROXY模块需要的选项,有些编译器不带这些定义 */
|
||||||
|
#ifndef IP_TRANSPARENT
|
||||||
|
#define IP_TRANSPARENT 19
|
||||||
|
#endif
|
||||||
|
#ifndef IP_RECVORIGDSTADDR
|
||||||
|
#define IP_RECVORIGDSTADDR 20
|
||||||
|
#endif
|
||||||
|
#ifndef IP_ORIGDSTADDR
|
||||||
|
#define IP_ORIGDSTADDR 20
|
||||||
|
#endif
|
||||||
|
//默认使用HTTPS模块
|
||||||
|
//#define HTTPUDP_REQUEST "GET / HTTP/1.1\r\nHost: [H]\r\nConnection: Upgrade\r\nSec-WebSocket-Key: ChameleonProxy httpUDP Client\r\nSec-WebSocket-Version: "VERSION"\r\nUpgrade: websocket\r\nProxy-Connection: Keep-Alive\r\n\r\n"
|
||||||
|
|
||||||
|
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代理编码
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void udp_timeout_check();
|
||||||
|
extern void *udp_loop(void *nullPtr);
|
||||||
|
extern void udp_init();
|
||||||
|
|
||||||
|
extern struct httpudp udp;
|
||||||
|
|
||||||
|
#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
|
|
524
main.c
524
main.c
@ -1,52 +1,66 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "http_proxy.h"
|
#include "http_proxy.h"
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
#include "timeout.h"
|
|
||||||
#include "conf.h"
|
|
||||||
#include "kill.h"
|
|
||||||
#include "help.h"
|
|
||||||
#include "httpdns.h"
|
#include "httpdns.h"
|
||||||
|
#include "httpudp.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
#define SERVER_STOP 1
|
#define SERVER_TYPE_STOP 1
|
||||||
#define SERVER_RELOAD 2
|
#define SERVER_TYPE_RELOAD 2
|
||||||
#define SERVER_STATUS 3
|
#define SERVER_TYPE_STATUS 3
|
||||||
|
#define SERVICE_TYPE_STATUS_NOT_PRINT 4
|
||||||
|
|
||||||
|
struct global global;
|
||||||
|
struct tcp_mode http, https;
|
||||||
|
struct save_header *saveHdrs;
|
||||||
|
char *default_ssl_request;
|
||||||
|
int default_ssl_request_len;
|
||||||
|
uint16_t tcp_listen_port;
|
||||||
|
|
||||||
|
tcp *http_head_strrep;
|
||||||
|
tcp *http_head_regrep;
|
||||||
|
|
||||||
|
tcp *https_head_strrep;
|
||||||
|
tcp *https_head_regrep;
|
||||||
|
|
||||||
struct epoll_event ev, events[MAX_CONNECTION + 1];
|
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];
|
conn_t cts[MAX_CONNECTION];
|
||||||
int local_port;
|
|
||||||
char local_host[CACHE_SIZE];
|
char local_host[CACHE_SIZE];
|
||||||
int process;
|
|
||||||
|
|
||||||
int create_connection(char *remote_host, int remote_port)
|
static char help_information(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_in server_addr;
|
static const char name[] = "C";
|
||||||
struct hostent *server;
|
static const char subject[] = "Proxy Server";
|
||||||
int sock = -1;
|
static const struct {
|
||||||
server = NULL;
|
const char *email;
|
||||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
} author = {
|
||||||
perror("socket");
|
"AIXIAO@AIXIAO.ME",
|
||||||
return -1;
|
};
|
||||||
|
|
||||||
|
static const char usage[] = "Usage: [-?h] [-s signal] [-c filename]";
|
||||||
|
static const char *s_help[] = {
|
||||||
|
"",
|
||||||
|
"Options:",
|
||||||
|
" -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",
|
||||||
|
"",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
fprintf(stderr, "%s %s\n", name, subject);
|
||||||
|
fprintf(stderr, "Author: %s\n", author.email);
|
||||||
|
fprintf(stderr, "%s\n", usage);
|
||||||
|
|
||||||
|
int l;
|
||||||
|
for (l = 0; s_help[l]; l++) {
|
||||||
|
fprintf(stderr, "%s\n", s_help[l]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((server = gethostbyname(remote_host)) == NULL) {
|
BUILD("Compile、link.\n");
|
||||||
perror("gethostbyname");
|
|
||||||
errno = EFAULT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&server_addr, 0, sizeof(server_addr));
|
return 0;
|
||||||
server_addr.sin_family = AF_INET;
|
|
||||||
memmove(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length);
|
|
||||||
server_addr.sin_port = htons(remote_port);
|
|
||||||
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
|
||||||
perror("connect");
|
|
||||||
close(sock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
|
||||||
return sock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_server_socket(int port)
|
int create_server_socket(int port)
|
||||||
@ -70,7 +84,7 @@ int create_server_socket(int port)
|
|||||||
perror("bind");
|
perror("bind");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (listen(server_sock, 50) < 0) {
|
if (listen(server_sock, 500) < 0) {
|
||||||
perror("listen");
|
perror("listen");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -107,7 +121,7 @@ int create_server_socket6(int port)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(server_sock, 20) < 0) {
|
if (listen(server_sock, 500) < 0) {
|
||||||
perror("listen");
|
perror("listen");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -161,7 +175,7 @@ void accept_client6()
|
|||||||
epoll_ctl(epollfd, EPOLL_CTL_ADD, client->fd, &epollEvent);
|
epoll_ctl(epollfd, EPOLL_CTL_ADD, client->fd, &epollEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *http_proxy_loop(void *p)
|
void *tcp_loop(void *p)
|
||||||
{
|
{
|
||||||
conf *configure = (conf *) p;
|
conf *configure = (conf *) p;
|
||||||
int n;
|
int n;
|
||||||
@ -196,99 +210,56 @@ void *http_proxy_loop(void *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(epollfd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *start_server(conf * configure)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
pthread_t thread_id;
|
|
||||||
|
|
||||||
ev.events = EPOLLIN;
|
|
||||||
ev.data.fd = server_sock;
|
|
||||||
if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, server_sock, &ev)) {
|
|
||||||
perror("epoll_ctl");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ev.events = EPOLLIN;
|
|
||||||
ev.data.fd = server_sock6;
|
|
||||||
if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, server_sock6, &ev)) {
|
|
||||||
perror("epoll_ctl");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout_minute)
|
|
||||||
pthread_create(&thread_id, NULL, &tcp_timeout_check, NULL);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
n = epoll_wait(epollfd, events, MAX_CONNECTION, -1);
|
|
||||||
while (n-- > 0) {
|
|
||||||
if (events[n].data.fd == server_sock) {
|
|
||||||
accept_client();
|
|
||||||
} else if (events[n].data.fd == server_sock6) {
|
|
||||||
accept_client6();
|
|
||||||
} else {
|
|
||||||
if (events[n].events & EPOLLIN) {
|
|
||||||
tcp_in((conn_t *) events[n].data.ptr, configure);
|
|
||||||
}
|
|
||||||
if (events[n].events & EPOLLOUT) {
|
|
||||||
tcp_out((conn_t *) events[n].data.ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(epollfd);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_signal(int signal, char *process_name)
|
int process_signal(int signal, char *process_name)
|
||||||
{
|
{
|
||||||
char bufer[PATH_SIZE];
|
char bufer[CACHE_SIZE];
|
||||||
char comm[PATH_SIZE];
|
char comm[CACHE_SIZE];
|
||||||
char proc_comm_name[PATH_SIZE];
|
char proc_comm_name[CACHE_SIZE];
|
||||||
int number[PATH_SIZE] = { 0 };
|
|
||||||
int n = 0;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *ptr;
|
struct dirent *ptr;
|
||||||
|
pid_t self_pid;
|
||||||
|
|
||||||
|
self_pid = getpid();
|
||||||
dir = opendir("/proc");
|
dir = opendir("/proc");
|
||||||
bzero(bufer, 0);
|
bzero(bufer, 0);
|
||||||
bzero(comm, 0);
|
bzero(comm, 0);
|
||||||
bzero(proc_comm_name, 0);
|
bzero(proc_comm_name, 0);
|
||||||
while ((ptr = readdir(dir)) != NULL) {
|
while ((ptr = readdir(dir)) != NULL) {
|
||||||
if (ptr->d_type == DT_DIR && strcasecmp(ptr->d_name, ".") && strcasecmp(ptr->d_name, "..")) {
|
if (ptr->d_type != DT_DIR)
|
||||||
sprintf(comm, "/proc/%s/comm", ptr->d_name);
|
continue;
|
||||||
if (access(comm, F_OK) == 0) {
|
if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0 || atoi(ptr->d_name) == self_pid)
|
||||||
fp = fopen(comm, "r");
|
continue;
|
||||||
if (fgets(bufer, PATH_SIZE - 1, fp) == NULL) {
|
|
||||||
fclose(fp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sscanf(bufer, "%s", proc_comm_name);
|
|
||||||
if (!strcmp(process_name, proc_comm_name)) {
|
|
||||||
number[n] = atoi(ptr->d_name);
|
|
||||||
n += 1;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
sprintf(comm, "/proc/%s/comm", ptr->d_name);
|
||||||
|
if (access(comm, F_OK) == 0) {
|
||||||
|
fp = fopen(comm, "r");
|
||||||
|
if (fgets(bufer, CACHE_SIZE - 1, fp) == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sscanf(bufer, "%s", proc_comm_name);
|
||||||
|
if (!strcmp(process_name, proc_comm_name)) {
|
||||||
|
if (signal == SERVER_TYPE_STOP)
|
||||||
|
kill(atoi(ptr->d_name), SIGTERM);
|
||||||
|
else {
|
||||||
|
closedir(dir);
|
||||||
|
if (signal != SERVICE_TYPE_STATUS_NOT_PRINT)
|
||||||
|
printf("\t%d\n", atoi(ptr->d_name));;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
if (signal == SERVER_STATUS) { // 状态
|
if (signal == SERVER_TYPE_STATUS) ;
|
||||||
n -= 2; // 去除最后一个搜索时的本身进程和最后加一后未使用的
|
else if (signal == SERVICE_TYPE_STATUS_NOT_PRINT)
|
||||||
for (; n >= 0; n--) { // 依据数组从大到小的下标打印PID
|
return 1;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -316,14 +287,170 @@ void server_ini()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//while (process-- > 1 && fork() == 0);
|
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 (server_sock >= 0 || server_sock6 >= 0)
|
||||||
|
tcp_timeout_check(NULL);
|
||||||
|
if (global.dns_listen_fd >= 0)
|
||||||
|
dns_timeout_check();
|
||||||
|
if (global.udp_listen_fd >= 0)
|
||||||
|
udp_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));
|
||||||
|
memset(&https, 0, sizeof(https));
|
||||||
|
memset(&udp, 0, sizeof(udp));
|
||||||
|
saveHdrs = NULL;
|
||||||
|
httpdns.dst.sin_family = AF_INET;
|
||||||
|
udp.dst.sin_family = AF_INET;
|
||||||
|
global.tcp_listen_fd = global.dns_listen_fd = global.udp_listen_fd = global.uid = -1;
|
||||||
|
|
||||||
|
// httpdns module
|
||||||
|
global.dns_listen_fd = udp_listen((char *)"127.0.0.1", configure->dns_listen);
|
||||||
|
if ((p = strchr(configure->httpdns_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->httpdns_addr);
|
||||||
|
httpdns.http_req_len = configure->httpdns_http_req_len;
|
||||||
|
copy_new_mem(configure->httpdns_http_req, httpdns.http_req_len, &httpdns.http_req);
|
||||||
|
|
||||||
|
// httpudp module
|
||||||
|
global.udp_listen_fd = udp_listen((char *)"0.0.0.0", configure->udp_listen);
|
||||||
|
if ((p = strchr(configure->httpudp_addr, ':')) != NULL) {
|
||||||
|
*p = '\0';
|
||||||
|
udp.dst.sin_port = htons(atoi(p + 1));
|
||||||
|
} else {
|
||||||
|
udp.dst.sin_port = htons(80);
|
||||||
|
}
|
||||||
|
udp.dst.sin_addr.s_addr = inet_addr(configure->httpudp_addr);
|
||||||
|
udp.http_request_len = configure->httpudp_http_req_len;
|
||||||
|
copy_new_mem(configure->httpudp_http_req, udp.http_request_len, &udp.http_request);
|
||||||
|
|
||||||
|
// global module
|
||||||
|
server_sock = create_server_socket(configure->tcp_listen); // IPV4
|
||||||
|
server_sock6 = create_server_socket6(configure->tcp_listen); // IPV6
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (global.timeout_m)
|
||||||
|
pthread_create(&thread_id, NULL, &timeout_check, NULL);
|
||||||
|
|
||||||
|
if (server_sock >= 0)
|
||||||
|
{
|
||||||
|
if (global.dns_listen_fd >= 0) {
|
||||||
|
dns_init();
|
||||||
|
pthread_create(&thread_id, NULL, &dns_loop, NULL);
|
||||||
|
}
|
||||||
|
if (global.udp_listen_fd >= 0) {
|
||||||
|
udp_init();
|
||||||
|
//udp_loop(NULL);
|
||||||
|
pthread_create(&thread_id, NULL, &udp_loop, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&thread_id, NULL, &tcp_loop, (void *)configure) != 0)
|
||||||
|
perror("pthread_create");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global.dns_listen_fd >= 0)
|
||||||
|
{
|
||||||
|
dns_init();
|
||||||
|
if (global.udp_listen_fd >= 0)
|
||||||
|
{
|
||||||
|
udp_init();
|
||||||
|
pthread_create(&thread_id, NULL, &udp_loop, NULL);
|
||||||
|
}
|
||||||
|
dns_loop(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
udp_init();
|
||||||
|
udp_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, &tcp_loop, (void *)configure);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void _main(int argc, char *argv[])
|
void _main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int opt, i;
|
char *p = NULL;
|
||||||
char path[PATH_SIZE] = { 0 };
|
int longindex = 0;
|
||||||
char executable_filename[PATH_SIZE] = { 0 };
|
int opt;
|
||||||
|
char path[CACHE_SIZE] = { 0 };
|
||||||
|
char executable_filename[CACHE_SIZE] = { 0 };
|
||||||
(void)get_executable_path(path, executable_filename, sizeof(path));
|
(void)get_executable_path(path, executable_filename, sizeof(path));
|
||||||
char *inifile = "/CProxy.conf";
|
char *inifile = "/CProxy.conf";
|
||||||
struct rlimit rt;
|
struct rlimit rt;
|
||||||
@ -333,16 +460,7 @@ void _main(int argc, char *argv[])
|
|||||||
read_conf(inifile, configure);
|
read_conf(inifile, configure);
|
||||||
|
|
||||||
sslEncodeCode = 0; // 默认SSL不转码
|
sslEncodeCode = 0; // 默认SSL不转码
|
||||||
if (configure->sslencoding > 0) // 如果配置文件有sslencoding值,优先使用配置文件读取的值
|
|
||||||
sslEncodeCode = configure->sslencoding;
|
|
||||||
timeout_minute = 0; // 默认不超时
|
|
||||||
if (configure->timeout > 0) // 如果配置文件有值,优先使用配置文件读取的值
|
|
||||||
timeout_minute = configure->timeout;
|
|
||||||
process = 2; // 默认开启2个进程
|
|
||||||
if (configure->process > 0) // 如果配置文件有值,优先使用配置文件读取的值
|
|
||||||
process = configure->process;
|
|
||||||
|
|
||||||
int longindex = 0;
|
|
||||||
char optstring[] = ":l:f:t:p:c:e:s:h?";
|
char optstring[] = ":l:f:t:p:c:e:s:h?";
|
||||||
static struct option longopts[] = {
|
static struct option longopts[] = {
|
||||||
{ "local_address", required_argument, 0, 'l' },
|
{ "local_address", required_argument, 0, 'l' },
|
||||||
@ -356,9 +474,6 @@ void _main(int argc, char *argv[])
|
|||||||
{ "?", no_argument, 0, '?' },
|
{ "?", no_argument, 0, '?' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
char *p = NULL;
|
|
||||||
//char optstring[] = ":l:f:t:p:c:e:s:h?";
|
|
||||||
//while (-1 != (opt = getopt(argc, argv, optstring))) {
|
|
||||||
while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex))) {
|
while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex))) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'l':
|
case 'l':
|
||||||
@ -386,7 +501,12 @@ void _main(int argc, char *argv[])
|
|||||||
process = atoi(optarg);
|
process = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
|
free_tcp(&http_head_strrep);
|
||||||
|
free_tcp(&http_head_regrep);
|
||||||
|
free_tcp(&https_head_strrep);
|
||||||
|
free_tcp(&https_head_regrep);
|
||||||
free_conf(configure);
|
free_conf(configure);
|
||||||
|
memset(configure, 0, sizeof(struct CONF));
|
||||||
read_conf(optarg, configure);
|
read_conf(optarg, configure);
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
@ -395,13 +515,14 @@ void _main(int argc, char *argv[])
|
|||||||
case 's':
|
case 's':
|
||||||
if (strcasecmp(optarg, "stop") == 0 || strcasecmp(optarg, "quit") == 0) {
|
if (strcasecmp(optarg, "stop") == 0 || strcasecmp(optarg, "quit") == 0) {
|
||||||
free_conf(configure);
|
free_conf(configure);
|
||||||
exit(process_signal(SERVER_STOP, executable_filename));
|
exit(process_signal(SERVER_TYPE_STOP, executable_filename));
|
||||||
}
|
}
|
||||||
if (strcasecmp(optarg, "restart") == 0 || strcasecmp(optarg, "reload") == 0) {
|
if (strcasecmp(optarg, "restart") == 0 || strcasecmp(optarg, "reload") == 0) {
|
||||||
process_signal(SERVER_RELOAD, executable_filename);
|
process_signal(SERVER_TYPE_STOP, executable_filename);
|
||||||
|
while (process_signal(SERVICE_TYPE_STATUS_NOT_PRINT, executable_filename) == 0) ;
|
||||||
}
|
}
|
||||||
if (strcasecmp(optarg, "status") == 0)
|
if (strcasecmp(optarg, "status") == 0)
|
||||||
exit(process_signal(SERVER_STATUS, executable_filename));
|
exit(process_signal(SERVER_TYPE_STATUS, executable_filename));
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
@ -413,73 +534,102 @@ void _main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置每个进程允许打开的最大文件数
|
|
||||||
rt.rlim_max = rt.rlim_cur = MAX_CONNECTION * 2;
|
signal(SIGPIPE, SIG_IGN);
|
||||||
if (setrlimit(RLIMIT_NOFILE, &rt) == -1) {
|
#if DAEMON
|
||||||
|
// 守护进程
|
||||||
|
int nochdir = 1;
|
||||||
|
int noclose = 1;
|
||||||
|
int pid;
|
||||||
|
if ((pid = fork()) < 0) {
|
||||||
|
return;
|
||||||
|
} else if (0 != pid) {
|
||||||
|
free_tcp(&http_head_strrep);
|
||||||
|
free_tcp(&http_head_regrep);
|
||||||
|
free_tcp(&https_head_strrep);
|
||||||
|
free_tcp(&https_head_regrep);
|
||||||
|
free_conf(configure);
|
||||||
|
free(configure);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsid() < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGHUP, SIG_IGN);
|
||||||
|
if ((pid = fork()) < 0) {
|
||||||
|
return;
|
||||||
|
} else if (0 != pid) {
|
||||||
|
free_tcp(&http_head_strrep);
|
||||||
|
free_tcp(&http_head_regrep);
|
||||||
|
free_tcp(&https_head_strrep);
|
||||||
|
free_tcp(&https_head_regrep);
|
||||||
|
free_conf(configure);
|
||||||
|
free(configure);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == nochdir) {
|
||||||
|
chdir("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == noclose) {
|
||||||
|
freopen("/dev/null", "r", stdin);
|
||||||
|
freopen("/dev/null", "w", stdout);
|
||||||
|
freopen("/dev/null", "w", stderr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 反转链表,使读取的配置正序
|
||||||
|
http_head_strrep = local_reverse(http_head_strrep);
|
||||||
|
http_head_regrep = local_reverse(http_head_regrep);
|
||||||
|
|
||||||
|
https_head_strrep = local_reverse(https_head_strrep);
|
||||||
|
https_head_regrep = local_reverse(https_head_regrep);
|
||||||
|
|
||||||
|
/*
|
||||||
|
print_tcp(https_head_strrep);
|
||||||
|
print_tcp(https_head_regrep);
|
||||||
|
free_tcp(&https_head_strrep);
|
||||||
|
free_tcp(&https_head_regrep);
|
||||||
|
|
||||||
|
print_tcp(http_head_strrep);
|
||||||
|
print_tcp(http_head_regrep);
|
||||||
|
free_tcp(&http_head_strrep);
|
||||||
|
free_tcp(&http_head_regrep);
|
||||||
|
|
||||||
|
free_conf(configure);
|
||||||
|
free(configure);
|
||||||
|
exit(0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
rt.rlim_max = rt.rlim_cur = MAX_CONNECTION * 2; // 设置每个进程允许打开的最大文件数
|
||||||
|
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
|
||||||
perror("setrlimit");
|
perror("setrlimit");
|
||||||
}
|
initialize(configure);
|
||||||
|
|
||||||
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
|
if (setegid(configure->uid) == -1 || seteuid(configure->uid) == -1) // 设置uid
|
||||||
server_sock6 = create_server_socket6(configure->tcp6_listen); // IPV6
|
exit(1);
|
||||||
|
|
||||||
|
while (configure->process-- > 1 && (child_pid = fork()) == 0);
|
||||||
|
|
||||||
epollfd = epoll_create(MAX_CONNECTION);
|
epollfd = epoll_create(MAX_CONNECTION);
|
||||||
if (epollfd == -1) {
|
if (epollfd == -1) {
|
||||||
perror("epoll_create");
|
perror("epoll_create");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setegid(configure->uid) == -1 || seteuid(configure->uid) == -1) // 设置uid
|
thread_loop(configure);
|
||||||
exit(1);
|
|
||||||
/*
|
|
||||||
start_server(configure); // 单线程
|
|
||||||
httpdns_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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[], char **env)
|
int main(int argc, char *argv[], char **envp)
|
||||||
{
|
{
|
||||||
_main(argc, argv);
|
_main(argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
|
45
main.h
45
main.h
@ -24,17 +24,50 @@
|
|||||||
|
|
||||||
#define MAX_CONNECTION 1020
|
#define MAX_CONNECTION 1020
|
||||||
#define BUFFER_SIZE 8192
|
#define BUFFER_SIZE 8192
|
||||||
#define PATH_SIZE 270
|
|
||||||
#define CACHE_SIZE 270
|
#define CACHE_SIZE 270
|
||||||
#define HTTP_HEAD_CACHE_SIZE 1024
|
#define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0)
|
||||||
|
#define ERRDEBUG fprintf(stderr,"Error Occured at File: %s, Function: %s, Line: %d, Date: %s, Time: %s.\n", __FILE__, __FUNCTION__, __LINE__, __DATE__, __TIME__);
|
||||||
|
|
||||||
|
#define DAEMON 1
|
||||||
|
|
||||||
|
struct global {
|
||||||
|
int tcp_listen_fd, dns_listen_fd, udp_listen_fd, uid, procs, timeout_m;
|
||||||
|
unsigned mode:3, strict_modify:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct save_header {
|
||||||
|
struct save_header *next;
|
||||||
|
char *key, *value, *replace_string;
|
||||||
|
int key_len, value_len, replace_string_len, updateTime, timer;
|
||||||
|
unsigned notUpdate:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct modify {
|
||||||
|
char *first, *del_hdr, *src, *dest;
|
||||||
|
struct save_header *saveHdr;
|
||||||
|
struct modify *next;
|
||||||
|
int first_len, del_hdr_len, src_len, dest_len;
|
||||||
|
unsigned flag:3; //判断修改请求头的操作
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcp_mode {
|
||||||
|
struct sockaddr_in dst;
|
||||||
|
struct modify *m;
|
||||||
|
unsigned encodeCode, //wap_connect模式数据编码传输
|
||||||
|
uri_strict:1, http_only_get_post:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct global global;
|
||||||
|
extern struct tcp_mode https;
|
||||||
|
extern struct save_header *saveHdrs;
|
||||||
|
extern int default_ssl_request_len;
|
||||||
|
extern char *default_ssl_request;
|
||||||
|
|
||||||
extern int local_port;
|
|
||||||
extern char local_host[CACHE_SIZE];
|
extern char local_host[CACHE_SIZE];
|
||||||
extern int process;
|
extern int epollfd, local_port, process;
|
||||||
|
|
||||||
extern int epollfd;
|
|
||||||
extern struct epoll_event ev, events[MAX_CONNECTION + 1];
|
extern struct epoll_event ev, events[MAX_CONNECTION + 1];
|
||||||
int create_connection(char *remote_host, int remote_port);
|
int create_connection(char *remote_host, int remote_port);
|
||||||
int create_connection6(char *remote_host, int remote_port);
|
int create_connection6(char *remote_host, int remote_port);
|
||||||
|
extern uint16_t tcp_listen_port;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
22
timeout.c
22
timeout.c
@ -1,22 +0,0 @@
|
|||||||
#include "timeout.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "http_proxy.h"
|
|
||||||
|
|
||||||
int timeout_minute;
|
|
||||||
|
|
||||||
void *tcp_timeout_check(void *nullPtr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
sleep(60);
|
|
||||||
for (i = 0; i < MAX_CONNECTION; i += 2) {
|
|
||||||
if (cts[i].fd > -1) {
|
|
||||||
if (cts[i].timer >= timeout_minute) {
|
|
||||||
close_connection(cts + i);
|
|
||||||
} else
|
|
||||||
cts[i].timer++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef TIME_H
|
|
||||||
#define TIME_H
|
|
||||||
|
|
||||||
extern int timeout_minute;
|
|
||||||
void *tcp_timeout_check(void *nullPtr);
|
|
||||||
|
|
||||||
#endif
|
|
13
udpServer/Makefile
Executable file
13
udpServer/Makefile
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
CROSS_COMPILE ?=
|
||||||
|
CC := $(CROSS_COMPILE)gcc
|
||||||
|
STRIP := $(CROSS_COMPILE)strip
|
||||||
|
CFLAGS := -O2 -pthread -Wall
|
||||||
|
BIN := udpServer
|
||||||
|
|
||||||
|
all : udpServer.o
|
||||||
|
$(CC) $(CFLAGS) -o $(BIN) $^
|
||||||
|
$(STRIP) $(BIN)
|
||||||
|
-chmod a+x $(BIN)
|
||||||
|
|
||||||
|
clean :
|
||||||
|
rm -f *.o $(BIN)
|
553
udpServer/udpServer.c
Executable file
553
udpServer/udpServer.c
Executable file
@ -0,0 +1,553 @@
|
|||||||
|
/*
|
||||||
|
httpUDPServer代理UDP过程:
|
||||||
|
[接收客户端http请求并回应http请求] 这一步可有可无
|
||||||
|
接收客户端数据 格式为: UDP目标地址[steuct in_addr](只有第一个包有) + UDP数据长度[uint16_t] + UDP真实数据
|
||||||
|
发送UDP数据并接收UDP服务器回应的数据
|
||||||
|
将UDP服务器回应的UDP数据返回给客户端,格式: UDP数据长度[uint16_t] + UDP真实数据
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <linux/netfilter_ipv4.h>
|
||||||
|
|
||||||
|
#define WEB_SOCKET_RSP "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ChameleonProxy httpUDP Server\r\nVia: ChameleonProxy httpUDP Server\r\n\r\n"
|
||||||
|
#define HTTP_RSP "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Length: 999999999\r\nServer: ChameleonProxy httpUDP Server\r\n\r\n"
|
||||||
|
#define SSL_RSP "HTTP/1.1 200 Connection established\r\nConnection: Keep-Alive\r\nServer: ChameleonProxy httpUDP Server\r\n\r\n"
|
||||||
|
#define BUFFER_SIZE 4096+65535
|
||||||
|
#define DEFAULT_TIMEOUT_S 20
|
||||||
|
#define DEFAULT_THEAD_POOL_SIZE 30
|
||||||
|
#define HTTP_TYPE 0
|
||||||
|
#define OTHER_TYPE 1
|
||||||
|
|
||||||
|
struct clientData {
|
||||||
|
char buffer[BUFFER_SIZE+1], *client_data, *udpData;
|
||||||
|
struct sockaddr_in udpDst;
|
||||||
|
int client_data_len, clientfd, remote_udpfd;
|
||||||
|
uint16_t udpData_len;
|
||||||
|
unsigned sentRspHttpReq :1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clientData publicConn; //主线程设置该变量,子线程复制
|
||||||
|
pthread_cond_t thCond = PTHREAD_COND_INITIALIZER;
|
||||||
|
pthread_mutex_t thMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
pthread_t master_thId; //主线程的线程id
|
||||||
|
int listenfd = -1,
|
||||||
|
timeout_s = DEFAULT_TIMEOUT_S,
|
||||||
|
thread_pool_size = DEFAULT_THEAD_POOL_SIZE;
|
||||||
|
uint8_t encodeCode = 0;
|
||||||
|
|
||||||
|
void usage()
|
||||||
|
{
|
||||||
|
printf("httpudp server(0.3):\n"
|
||||||
|
"Author: CuteBi\n"
|
||||||
|
"E-mail: 915445800@qq.com\n"
|
||||||
|
" -l \033[20G listen port\n"
|
||||||
|
" -t \033[20G timeout(s) defaule is %d s\n"
|
||||||
|
" -w \033[20G worker proc\n"
|
||||||
|
" -p \033[20G thread pool size default is %d\n"
|
||||||
|
" -e \033[20G encode data code(128-255) default is 0\n"
|
||||||
|
" -u \033[20G set uid\n\n", DEFAULT_TIMEOUT_S, DEFAULT_THEAD_POOL_SIZE);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 对数据进行编码 */
|
||||||
|
void dataEncode(char *data, int data_len)
|
||||||
|
{
|
||||||
|
while (data_len-- > 0)
|
||||||
|
data[data_len] ^= encodeCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 判断请求类型 */
|
||||||
|
uint8_t request_type(char *req)
|
||||||
|
{
|
||||||
|
if (strncmp(req, "GET", 3) == 0 ||
|
||||||
|
strncmp(req, "POST", 4) == 0 ||
|
||||||
|
strncmp(req, "CONNECT", 7) == 0 ||
|
||||||
|
strncmp(req, "HEAD", 4) == 0 ||
|
||||||
|
strncmp(req, "PUT", 3) == 0 ||
|
||||||
|
strncmp(req, "OPTIONS", 7) == 0 ||
|
||||||
|
strncmp(req, "MOVE", 4) == 0 ||
|
||||||
|
strncmp(req, "COPY", 4) == 0 ||
|
||||||
|
strncmp(req, "TRACE", 5) == 0 ||
|
||||||
|
strncmp(req, "DELETE", 6) == 0 ||
|
||||||
|
strncmp(req, "LINK", 4) == 0 ||
|
||||||
|
strncmp(req, "UNLINK", 6) == 0 ||
|
||||||
|
strncmp(req, "PATCH", 5) == 0 ||
|
||||||
|
strncmp(req, "WRAPPED", 7) == 0)
|
||||||
|
return HTTP_TYPE;
|
||||||
|
else
|
||||||
|
return OTHER_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 回应HTTP请求 */
|
||||||
|
int rspHttpReq(struct clientData *client)
|
||||||
|
{
|
||||||
|
/* 回应CONNECT请求 */
|
||||||
|
if (strncmp(client->client_data, "CON", 3) == 0)
|
||||||
|
{
|
||||||
|
if (write(client->clientfd, SSL_RSP, sizeof(SSL_RSP) - 1) <= 0)
|
||||||
|
{
|
||||||
|
perror("ssl rsp write()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 回应WebSocket请求 */
|
||||||
|
else if (strstr(client->client_data, "websocket"))
|
||||||
|
{
|
||||||
|
if (write(client->clientfd, WEB_SOCKET_RSP, sizeof(WEB_SOCKET_RSP) - 1) <= 0)
|
||||||
|
{
|
||||||
|
perror("websocket rsp write()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 回应HTTP请求 */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (write(client->clientfd, HTTP_RSP, sizeof(HTTP_RSP) - 1) <= 0)
|
||||||
|
{
|
||||||
|
perror("http rsp write()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client->sentRspHttpReq = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 得到客户端数据中的udpDataLen dstAddr */
|
||||||
|
int parse_request(struct clientData *client)
|
||||||
|
{
|
||||||
|
char *headerEnd;
|
||||||
|
|
||||||
|
if (request_type(client->client_data) == OTHER_TYPE)
|
||||||
|
{
|
||||||
|
client->udpData = client->client_data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
headerEnd = strstr(client->client_data, "\n\r\n");
|
||||||
|
if (headerEnd == NULL)
|
||||||
|
{
|
||||||
|
//puts("headerEnd NULL.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*headerEnd = '\0';
|
||||||
|
if (client->sentRspHttpReq == 0 && rspHttpReq(client) != 0)
|
||||||
|
return 1;
|
||||||
|
*headerEnd = '\n';
|
||||||
|
client->udpData = headerEnd + 3;
|
||||||
|
}
|
||||||
|
if ((int)(client->client_data_len - (client->udpData - client->client_data) - sizeof(struct sockaddr_in) - sizeof(uint16_t)) <= 0)
|
||||||
|
return 1;
|
||||||
|
if (encodeCode)
|
||||||
|
dataEncode(client->udpData, (int)(client->client_data_len - (client->udpData - client->client_data)));
|
||||||
|
|
||||||
|
/* 复制UDP目标地址跟UDP长度 */
|
||||||
|
memcpy(&client->udpDst, client->udpData, sizeof(struct sockaddr_in));
|
||||||
|
memcpy(&(client->udpData_len), (uint16_t *)(client->udpData + sizeof(struct sockaddr_in)), sizeof(uint16_t));
|
||||||
|
client->udpData += sizeof(struct sockaddr_in);
|
||||||
|
//printf("len: [%u] dataLen: [%d], ip: [%s], port: [%d]\n", client->udpData_len, (int)(client->client_data_len - (client->udpData - client->client_data)), inet_ntoa(client->udpDst.sin_addr), ntohs(client->udpDst.sin_port));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int recvServer(struct clientData *server)
|
||||||
|
{
|
||||||
|
int read_len;
|
||||||
|
|
||||||
|
while ((read_len = recv(server->remote_udpfd, server->buffer + sizeof(uint16_t), BUFFER_SIZE - sizeof(uint16_t), MSG_DONTWAIT)) > 0)
|
||||||
|
{
|
||||||
|
//printf("%u: read remote: [%d]\n", pthread_self(), read_len);
|
||||||
|
memcpy(server->buffer, &read_len, sizeof(uint16_t));
|
||||||
|
//printf("server read_len: [%d], server->buffer: [%u]\n", read_len, *(uint16_t *)server->buffer);
|
||||||
|
read_len += sizeof(uint16_t);
|
||||||
|
if (encodeCode)
|
||||||
|
dataEncode(server->buffer, read_len);
|
||||||
|
if (write(server->clientfd, server->buffer, read_len) != read_len)
|
||||||
|
{
|
||||||
|
perror("write to client()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (read_len == 0 || errno != EAGAIN)
|
||||||
|
{
|
||||||
|
perror("server recv()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
发送客户端数据到服务器
|
||||||
|
发送失败或者发送完成返回null
|
||||||
|
未发送完成返回未发送的数据首地址
|
||||||
|
*/
|
||||||
|
char *sendServer(struct clientData *client)
|
||||||
|
{
|
||||||
|
char *dataPtr;
|
||||||
|
int write_len;
|
||||||
|
|
||||||
|
dataPtr = client->client_data;
|
||||||
|
//client->client_data_len > 1才能满意uint16_t这个类型的储存空间
|
||||||
|
while (client->client_data_len > 1 && (int)(*(uint16_t *)dataPtr + sizeof(uint16_t)) <= client->client_data_len)
|
||||||
|
{
|
||||||
|
if ((write_len = write(client->remote_udpfd, dataPtr+sizeof(uint16_t), *(uint16_t *)dataPtr)) != *(uint16_t *)dataPtr)
|
||||||
|
{
|
||||||
|
perror("write to remote()");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
//printf("%u, fd: %d, write_len: %d, client_data_len: %d\n", pthread_self(), client->remote_udpfd, write_len, client->client_data_len);
|
||||||
|
dataPtr += write_len + sizeof(uint16_t);
|
||||||
|
client->client_data_len -= write_len + sizeof(uint16_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return client->client_data_len > 0 ? dataPtr : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int recvClient(struct clientData *client)
|
||||||
|
{
|
||||||
|
char *new_data, *dataPtr;
|
||||||
|
int read_len;
|
||||||
|
|
||||||
|
do {
|
||||||
|
new_data = (char *)realloc(client->client_data, client->client_data_len + BUFFER_SIZE);
|
||||||
|
if (new_data == NULL)
|
||||||
|
return 1;
|
||||||
|
client->client_data = new_data;
|
||||||
|
read_len = recv(client->clientfd, client->client_data + client->client_data_len, BUFFER_SIZE, MSG_DONTWAIT);
|
||||||
|
printf("%lu: get client len: [%d]\n", pthread_self(), read_len);
|
||||||
|
if (read_len <= 0)
|
||||||
|
{
|
||||||
|
if (read_len == 0 || errno != EAGAIN)
|
||||||
|
{
|
||||||
|
perror("client read()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (encodeCode)
|
||||||
|
dataEncode(client->client_data + client->client_data_len, read_len);
|
||||||
|
client->client_data_len += read_len;
|
||||||
|
dataPtr = sendServer(client);
|
||||||
|
//write()发生错误
|
||||||
|
if (dataPtr == NULL && client->client_data_len > 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (client->client_data_len > 0)
|
||||||
|
{
|
||||||
|
memmove(client->client_data, dataPtr, client->client_data_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(client->client_data);
|
||||||
|
client->client_data = NULL;
|
||||||
|
client->client_data_len = 0;
|
||||||
|
}
|
||||||
|
} while (read_len == BUFFER_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forwardData(struct clientData *client)
|
||||||
|
{
|
||||||
|
struct pollfd pfds[2];
|
||||||
|
|
||||||
|
pfds[0].fd = client->remote_udpfd;
|
||||||
|
pfds[1].fd = client->clientfd;
|
||||||
|
pfds[0].events = pfds[1].events = POLLIN;
|
||||||
|
while (poll(pfds, 2, timeout_s*1000) > 0)
|
||||||
|
{
|
||||||
|
printf("a event %lu\n", pthread_self());
|
||||||
|
if (pfds[0].revents & POLLIN)
|
||||||
|
{
|
||||||
|
printf("recvServer %lu\n", pthread_self());
|
||||||
|
if (recvServer(client) != 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pfds[1].revents & POLLIN)
|
||||||
|
{
|
||||||
|
printf("recvServer %lu\n", pthread_self());
|
||||||
|
if (recvClient(client) != 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sendFirstData(struct clientData *client)
|
||||||
|
{
|
||||||
|
char *dataPtr;
|
||||||
|
|
||||||
|
printf("%lu: sendFirstData\n", pthread_self());
|
||||||
|
client->remote_udpfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (client->remote_udpfd < 0)
|
||||||
|
{
|
||||||
|
perror("socket()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
connect(client->remote_udpfd, (struct sockaddr *)&client->udpDst, sizeof(struct sockaddr_in));
|
||||||
|
client->client_data = client->udpData;
|
||||||
|
client->client_data_len = client->udpData_len + sizeof(uint16_t);
|
||||||
|
dataPtr = sendServer(client);
|
||||||
|
if (dataPtr == NULL)
|
||||||
|
{
|
||||||
|
if (client->client_data_len > 0)
|
||||||
|
return 1;
|
||||||
|
client->client_data = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client->client_data = (char *)malloc(client->client_data_len);
|
||||||
|
if (client->client_data == NULL)
|
||||||
|
return 1;
|
||||||
|
memcpy(client->client_data, dataPtr, client->client_data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%lu: sendFirstData end\n", pthread_self());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parseClient(struct clientData *client)
|
||||||
|
{
|
||||||
|
int read_len, count;
|
||||||
|
|
||||||
|
printf("%lu: parseClient\n", pthread_self());
|
||||||
|
count = 0;
|
||||||
|
client->client_data = client->buffer;
|
||||||
|
do {
|
||||||
|
//printf("%u: start read\n", pthread_self());
|
||||||
|
read_len = read(client->clientfd, client->client_data + client->client_data_len, BUFFER_SIZE - client->client_data_len);
|
||||||
|
//printf("%u: read_len = %d\n", pthread_self(), read_len);
|
||||||
|
if (read_len <= 0)
|
||||||
|
{
|
||||||
|
perror("parseClient read()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
client->client_data_len += read_len;
|
||||||
|
client->client_data[client->client_data_len] = '\0';
|
||||||
|
count++;
|
||||||
|
} while (parse_request(client) != 0 && count < 5);
|
||||||
|
|
||||||
|
//printf("%u: parseClient end\n", pthread_self());
|
||||||
|
return count == 5 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *new_connection(void *nullPtr)
|
||||||
|
{
|
||||||
|
#define NO_COPY_SIZE (BUFFER_SIZE + 1 + (sizeof(char *)<<1) + sizeof(struct sockaddr_in)) //struct clientData不需要全部复制
|
||||||
|
struct clientData client;
|
||||||
|
|
||||||
|
//printf("new_connection: %u\n", pthread_self())
|
||||||
|
memcpy((void *)(&client) + NO_COPY_SIZE, (void *)(&publicConn) + NO_COPY_SIZE, sizeof(struct clientData) - NO_COPY_SIZE);
|
||||||
|
pthread_kill(master_thId, SIGUSR1);
|
||||||
|
/* 读取客户端数据 */
|
||||||
|
if (parseClient(&client) == 0 && sendFirstData(&client) == 0)
|
||||||
|
forwardData(&client);
|
||||||
|
else
|
||||||
|
puts("parseClient() client error");
|
||||||
|
|
||||||
|
close(client.remote_udpfd);
|
||||||
|
close(client.clientfd);
|
||||||
|
if (client.client_data != client.buffer && client.client_data != client.udpData)
|
||||||
|
free(client.client_data);
|
||||||
|
|
||||||
|
//printf("new_connection end: %u\n", pthread_self());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int accept_client()
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
struct timeval tv = {timeout_s, 0};
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
|
||||||
|
publicConn.clientfd = accept(listenfd, (struct sockaddr *)&addr, &addr_len);
|
||||||
|
if (publicConn.clientfd < 0)
|
||||||
|
{
|
||||||
|
perror("accept()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
setsockopt(publicConn.clientfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *threadPool_waitTask(void *ptr)
|
||||||
|
{
|
||||||
|
int *isBusy;
|
||||||
|
|
||||||
|
isBusy = (int *)ptr;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&thCond, &thMutex);
|
||||||
|
pthread_mutex_unlock(&thMutex); //解锁,让其他线程可以并发
|
||||||
|
*isBusy = 1;
|
||||||
|
new_connection(NULL);
|
||||||
|
*isBusy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
pthread_t th_id;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
sigset_t sig;
|
||||||
|
int *th_isBusy, //线程执行繁忙值为1,空闲值为0
|
||||||
|
i, signum;
|
||||||
|
|
||||||
|
//初始化publicConn
|
||||||
|
memset(&publicConn, 0, sizeof(struct clientData));
|
||||||
|
publicConn.remote_udpfd = -1;
|
||||||
|
/* 创建线程池 */
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
|
th_isBusy = (int *)calloc(thread_pool_size, sizeof(int));
|
||||||
|
if (th_isBusy == NULL)
|
||||||
|
{
|
||||||
|
perror("calloc()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = 0; i < thread_pool_size; i++)
|
||||||
|
pthread_create(&th_id, &attr, &threadPool_waitTask, (void *)(th_isBusy + i));
|
||||||
|
/* 初始化信号设置,用于子线程告诉主线程内存已经拷贝完毕 */
|
||||||
|
sigemptyset(&sig);
|
||||||
|
sigaddset(&sig, SIGUSR1);
|
||||||
|
pthread_sigmask(SIG_BLOCK, &sig, NULL);
|
||||||
|
master_thId = pthread_self();
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (accept_client() != 0)
|
||||||
|
{
|
||||||
|
sleep(3);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* 如果线程池有空闲线程则调用空闲线程处理 */
|
||||||
|
for (i = 0; i < thread_pool_size; i++)
|
||||||
|
{
|
||||||
|
if (th_isBusy[i] == 0)
|
||||||
|
{
|
||||||
|
pthread_cond_signal(&thCond);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 线程池没有空闲线线程,创建新线程运行任务 */
|
||||||
|
if (i == thread_pool_size)
|
||||||
|
{
|
||||||
|
if (pthread_create(&th_id, &attr, &new_connection, NULL) != 0)
|
||||||
|
{
|
||||||
|
close(publicConn.clientfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sigwait(&sig, &signum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_listen(char *ip, int port)
|
||||||
|
{
|
||||||
|
int fd, optval = 1;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
perror("socket()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = inet_addr(ip);
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
perror("setsockopt()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
perror("bind()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (listen(fd, 500) != 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
perror("listen()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readCmd(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int opt, worker_proc;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "l:u:e:w:p:t:h")) != -1)
|
||||||
|
{
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 't':
|
||||||
|
timeout_s = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
encodeCode = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
listenfd = create_listen((char *)"0.0.0.0", atoi(optarg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
if (setgid(atoi(optarg)) || setuid(atoi(optarg)))
|
||||||
|
perror("setgid(or setuid)()");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'w':
|
||||||
|
worker_proc = atoi(optarg);
|
||||||
|
while (worker_proc-- > 1 && fork());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
thread_pool_size = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
readCmd(argc, argv);
|
||||||
|
if (listenfd < 0)
|
||||||
|
{
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (daemon(1, 1) == -1)
|
||||||
|
{
|
||||||
|
perror("daemon()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
loop();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user