Httpudp support, fixed error reading httpdns "http_req".
This commit is contained in:
parent
9aa4d19547
commit
40df4da8b8
12
CProxy.conf
12
CProxy.conf
@ -1,14 +1,15 @@
|
|||||||
global {
|
global {
|
||||||
uid=3004;
|
uid=3004;
|
||||||
process=2;
|
process=2;
|
||||||
timeout=1;
|
timeout=7;
|
||||||
encode=128;
|
encode=128;
|
||||||
tcp_listen=0124;
|
tcp_listen=0124;
|
||||||
dns_listen=0126;
|
dns_listen=0126;
|
||||||
|
udp_listen = 10010;
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
http_ip="2408:8221:9916:15e0:3cf9:3d8d:64ac:b880";
|
http_ip="47.240.75.93";
|
||||||
http_port=127;
|
http_port=127;
|
||||||
http_del="Host";
|
http_del="Host";
|
||||||
http_first="[M] http://[host][U] [V]\r\nHost: [H]\r\n";
|
http_first="[M] http://[host][U] [V]\r\nHost: [H]\r\n";
|
||||||
@ -17,7 +18,7 @@ http {
|
|||||||
}
|
}
|
||||||
|
|
||||||
https {
|
https {
|
||||||
https_ip="127.0.0.1";
|
https_ip="47.240.75.93";
|
||||||
https_port=127;
|
https_port=127;
|
||||||
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]\r\n";
|
||||||
@ -29,3 +30,8 @@ httpdns {
|
|||||||
addr = 119.29.29.29:80;
|
addr = 119.29.29.29:80;
|
||||||
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n";
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpudp {
|
||||||
|
addr = 47.240.75.93:10010;
|
||||||
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n";
|
||||||
|
}
|
||||||
|
@ -1,34 +1,39 @@
|
|||||||
global {
|
global {
|
||||||
uid=3004;
|
uid=3004;
|
||||||
process=2;
|
process=2;
|
||||||
timeout=60;
|
timeout=7;
|
||||||
sslencoding=128;
|
encode=128;
|
||||||
tcp_listen=0124;
|
tcp_listen=0124;
|
||||||
tcp6_listen=0124;
|
dns_listen=0126;
|
||||||
dns_listen=0125;
|
udp_listen = 10010;
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
http_ip=cproxy.aixiao.me;
|
http_ip="47.240.75.93";
|
||||||
http_port=124;
|
http_port=127;
|
||||||
http_del="x-online-host,X-Online-Host,host,Host";
|
http_del="Host";
|
||||||
http_first="[M] [U] [V]\r\nHost: [H]\r\n";
|
http_first="[M] http://[host][U] [V]\r\nHost: [H]\r\n";
|
||||||
//strrep="Windows NT 10.0->Linux";
|
//strrep="Windows NT 10.0->Linux";
|
||||||
//regrep="Host*.+?->Host: hu60.cn:443";
|
//regrep="Host:*.+?->Host: [host]:80";
|
||||||
}
|
}
|
||||||
|
|
||||||
https {
|
https {
|
||||||
https_ip=cproxy.aixiao.me;
|
https_ip="47.240.75.93";
|
||||||
https_port=124;
|
https_port=127;
|
||||||
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]\r\n";
|
||||||
strrep="Windows NT 10.0->Linux";
|
//strrep="Windows NT 10.0->Linux";
|
||||||
//regrep="Host*.+?->Host: hu60.cn:443";
|
//regrep="Host*.+?->host: [host]:443";
|
||||||
}
|
}
|
||||||
|
|
||||||
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
httpudp {
|
||||||
|
addr = 47.240.75.93:10010;
|
||||||
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,3 +73,10 @@ httpdns 模块关键字: [M], [D], [V], \r, \n, \v, \f, \b, \t, \a.
|
|||||||
addr=119.29.29.29:80; //HTTPDNS服务器IP
|
addr=119.29.29.29:80; //HTTPDNS服务器IP
|
||||||
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n"; //自定义HTTPDNS请求头
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n"; //自定义HTTPDNS请求头
|
||||||
|
|
||||||
|
httpudp模块
|
||||||
|
httpudp 模块关键字: [M], [U], [V], [H].
|
||||||
|
默认 [M] 为 CONNECT
|
||||||
|
默认 [V] 为 HTTP/1.1
|
||||||
|
addr=47.240.75.93:10010; //HTTPUDP服务器IP
|
||||||
|
http_req = "[M] [U] [V]\r\nHost: [H]\r\n\r\n"; //自定义HTTPUDP请求头
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -5,7 +5,7 @@ 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 help.o
|
all: main.o http_proxy.o http_request.o httpdns.o httpudp.o conf.o help.o
|
||||||
$(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS)
|
$(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS)
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
可以修改HTTP协议消息头(request).
|
可以修改HTTP协议消息头(request).
|
||||||
可以修改HTTP协议CONNECT方法消息头.
|
可以修改HTTP协议CONNECT方法消息头.
|
||||||
可以修改HTTP协议GET方法消息头.
|
可以修改HTTP协议GET方法消息头.
|
||||||
支持IPV4/IPV6.
|
httptcp支持IPV4/IPV6.
|
||||||
|
支持httpdns、httpudp代理
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
55
conf.c
55
conf.c
@ -207,6 +207,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');
|
||||||
@ -381,20 +383,49 @@ static void parse_httpdns_module(char *content, conf * p)
|
|||||||
memset(p->addr, 0, val_begin_len);
|
memset(p->addr, 0, val_begin_len);
|
||||||
memcpy(p->addr, val_begin, val_begin_len);
|
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;
|
//val_begin_len = strlen(val_begin) + 1;
|
||||||
p->http_req = (char *)malloc(val_begin_len);
|
val_begin_len = val_end - val_begin;
|
||||||
|
p->http_req = (char *)malloc(val_begin_len + 1);
|
||||||
memset(p->http_req, 0, val_begin_len);
|
memset(p->http_req, 0, val_begin_len);
|
||||||
memcpy(p->http_req, val_begin, val_begin_len);
|
memcpy(p->http_req, val_begin, val_begin_len);
|
||||||
p->http_req_len = 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;
|
||||||
|
int val_begin_len;
|
||||||
|
|
||||||
|
while ((lineEnd = set_var_val_lineEnd2(content, &var, &val_begin, &val_end)) != NULL) {
|
||||||
|
if (strcasecmp(var, "addr") == 0) {
|
||||||
|
val_begin_len = strlen(val_begin) + 1;
|
||||||
|
p->httpudp_addr = (char *)malloc(val_begin_len);
|
||||||
|
memset(p->httpudp_addr, 0, val_begin_len);
|
||||||
|
memcpy(p->httpudp_addr, val_begin, val_begin_len);
|
||||||
|
} else if (strcasecmp(var, "http_req") == 0) {
|
||||||
|
//val_begin_len = strlen(val_begin) + 1;
|
||||||
|
val_begin_len = val_end - val_begin;
|
||||||
|
p->httpudp_http_req = (char *)malloc(val_begin_len + 1);
|
||||||
|
memset(p->httpudp_http_req, 0, val_begin_len);
|
||||||
|
memcpy(p->httpudp_http_req, val_begin, val_begin_len);
|
||||||
|
p->httpudp_http_req_len = val_begin_len;
|
||||||
|
} 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)
|
||||||
@ -414,6 +445,7 @@ void free_conf(conf * p)
|
|||||||
if (p->http_regrep_obj)
|
if (p->http_regrep_obj)
|
||||||
free(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)
|
||||||
@ -433,19 +465,28 @@ void free_conf(conf * p)
|
|||||||
if (p->https_regrep_obj)
|
if (p->https_regrep_obj)
|
||||||
free(p->https_regrep_obj);
|
free(p->https_regrep_obj);
|
||||||
|
|
||||||
|
// httpdns module
|
||||||
if (p->addr)
|
if (p->addr)
|
||||||
free(p->addr);
|
free(p->addr);
|
||||||
if (p->http_req) {
|
if (p->http_req) {
|
||||||
bzero(p->http_req, 0);
|
|
||||||
p->http_req_len = 0;
|
p->http_req_len = 0;
|
||||||
free(p->http_req);
|
free(p->http_req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// httpudp module
|
||||||
|
if(p->httpudp_addr)
|
||||||
|
free(p->httpudp_addr);
|
||||||
|
if (p->httpudp_http_req) {
|
||||||
|
p->httpudp_http_req_len = 0;
|
||||||
|
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;
|
||||||
|
|
||||||
@ -489,4 +530,10 @@ void read_conf(char *filename, conf * configure)
|
|||||||
else
|
else
|
||||||
parse_httpdns_module(httpdns_content, configure);
|
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);
|
||||||
}
|
}
|
||||||
|
9
conf.h
9
conf.h
@ -18,6 +18,7 @@ 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;
|
||||||
@ -45,11 +46,17 @@ typedef struct CONF {
|
|||||||
char *https_regrep_aim, *https_regrep_obj;
|
char *https_regrep_aim, *https_regrep_obj;
|
||||||
int https_regrep_aim_len, https_regrep_obj_len;
|
int https_regrep_aim_len, https_regrep_obj_len;
|
||||||
|
|
||||||
// http dns_listen
|
// httpdns module
|
||||||
char *addr;
|
char *addr;
|
||||||
char *http_req;
|
char *http_req;
|
||||||
int http_req_len;
|
int http_req_len;
|
||||||
int encode;
|
int encode;
|
||||||
|
|
||||||
|
// httpudp module
|
||||||
|
char *httpudp_addr;
|
||||||
|
char *httpudp_http_req;
|
||||||
|
int httpudp_http_req_len;
|
||||||
|
int httpudp_encode;
|
||||||
} conf;
|
} conf;
|
||||||
|
|
||||||
char *strncpy_(char *dest, const char *src, size_t n);
|
char *strncpy_(char *dest, const char *src, size_t n);
|
||||||
|
17
http_proxy.c
17
http_proxy.c
@ -4,6 +4,7 @@
|
|||||||
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, unsigned code)
|
void dataEncode(char *data, int data_len, unsigned code)
|
||||||
@ -12,6 +13,22 @@ void dataEncode(char *data, int data_len, unsigned code)
|
|||||||
data[data_len] ^= code;
|
data[data_len] ^= code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
char *new_data;
|
char *new_data;
|
||||||
|
@ -24,5 +24,7 @@ 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);
|
||||||
extern void dataEncode(char *data, int data_len, unsigned code);
|
extern void dataEncode(char *data, int data_len, unsigned code);
|
||||||
|
extern int timeout_minute;
|
||||||
|
void *tcp_timeout_check(void *nullPtr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
#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)
|
int8_t copy_new_mem(char *src, int src_len, char **dest)
|
||||||
{
|
{
|
||||||
*dest = (char *)malloc(src_len + 1);
|
*dest = (char *)malloc(src_len + 1);
|
||||||
|
@ -22,5 +22,6 @@ void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_
|
|||||||
extern 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 int8_t copy_new_mem(char *src, int src_len, char **dest);
|
||||||
|
extern void errors(const char *msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
434
httpudp.c
Executable file
434
httpudp.c
Executable file
@ -0,0 +1,434 @@
|
|||||||
|
/*
|
||||||
|
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伪装源目标地址
|
||||||
|
seteuid(0);
|
||||||
|
setegid(0);
|
||||||
|
bind(client->responseClientFd, (struct sockaddr *)&client->toaddr, sizeof(struct sockaddr_in));
|
||||||
|
//切换回用户设置的uid
|
||||||
|
setegid(global.uid);
|
||||||
|
seteuid(global.uid);
|
||||||
|
|
||||||
|
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
|
58
main.c
58
main.c
@ -2,7 +2,7 @@
|
|||||||
#include "http_proxy.h"
|
#include "http_proxy.h"
|
||||||
#include "http_request.h"
|
#include "http_request.h"
|
||||||
#include "httpdns.h"
|
#include "httpdns.h"
|
||||||
#include "timeout.h"
|
#include "httpudp.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
|
||||||
@ -10,9 +10,15 @@
|
|||||||
#define SERVER_RELOAD 2
|
#define SERVER_RELOAD 2
|
||||||
#define SERVER_STATUS 3
|
#define SERVER_STATUS 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct global global;
|
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;
|
uint16_t tcp_listen_port;
|
||||||
struct httpudp udp;
|
|
||||||
struct epoll_event ev, events[MAX_CONNECTION + 1];
|
struct epoll_event ev, events[MAX_CONNECTION + 1];
|
||||||
int epollfd, server_sock, server_sock6, local_port, process;
|
int epollfd, server_sock, server_sock6, local_port, process;
|
||||||
conn_t cts[MAX_CONNECTION];
|
conn_t cts[MAX_CONNECTION];
|
||||||
@ -291,7 +297,8 @@ int process_signal(int signal, char *process_name)
|
|||||||
if (signal == SERVER_STOP || signal == SERVER_RELOAD) { // 关闭
|
if (signal == SERVER_STOP || signal == SERVER_RELOAD) { // 关闭
|
||||||
n -= 2;
|
n -= 2;
|
||||||
for (; n >= 0; n--) {
|
for (; n >= 0; n--) {
|
||||||
kill(number[n], SIGTERM);
|
//kill(number[n], SIGTERM);
|
||||||
|
kill(number[n], SIGKILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,8 +358,12 @@ void *timeout_check(void *nullPtr)
|
|||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
sleep(60);
|
sleep(60);
|
||||||
|
if (server_sock >= 0 || server_sock6 >= 0)
|
||||||
|
tcp_timeout_check(NULL);
|
||||||
if (global.dns_listen_fd >= 0)
|
if (global.dns_listen_fd >= 0)
|
||||||
dns_timeout_check();
|
dns_timeout_check();
|
||||||
|
if (global.udp_listen_fd >= 0)
|
||||||
|
udp_timeout_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -377,8 +388,14 @@ void initialize(conf * configure)
|
|||||||
|
|
||||||
memset(&global, 0, sizeof(global));
|
memset(&global, 0, sizeof(global));
|
||||||
memset(&httpdns, 0, sizeof(httpdns));
|
memset(&httpdns, 0, sizeof(httpdns));
|
||||||
|
memset(&https, 0, sizeof(https));
|
||||||
|
memset(&udp, 0, sizeof(udp));
|
||||||
|
saveHdrs = NULL;
|
||||||
httpdns.dst.sin_family = AF_INET;
|
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;
|
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);
|
global.dns_listen_fd = udp_listen((char *)"127.0.0.1", configure->dns_listen);
|
||||||
if ((p = strchr(configure->addr, ':')) != NULL) {
|
if ((p = strchr(configure->addr, ':')) != NULL) {
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
@ -390,6 +407,19 @@ void initialize(conf * configure)
|
|||||||
httpdns.http_req_len = configure->http_req_len;
|
httpdns.http_req_len = configure->http_req_len;
|
||||||
copy_new_mem(configure->http_req, httpdns.http_req_len, &httpdns.http_req);
|
copy_new_mem(configure->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_sock = create_server_socket(configure->tcp_listen); // IPV4
|
||||||
server_sock6 = create_server_socket6(configure->tcp_listen); // IPV6
|
server_sock6 = create_server_socket6(configure->tcp_listen); // IPV6
|
||||||
epollfd = epoll_create(MAX_CONNECTION);
|
epollfd = epoll_create(MAX_CONNECTION);
|
||||||
@ -409,18 +439,29 @@ void thread_loop(conf * configure)
|
|||||||
if (pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) != 0) {
|
if (pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) != 0) {
|
||||||
printf("block sigpipe error\n");
|
printf("block sigpipe error\n");
|
||||||
}
|
}
|
||||||
if (timeout_minute)
|
//if (timeout_minute)
|
||||||
pthread_create(&thread_id, NULL, &tcp_timeout_check, NULL);
|
// pthread_create(&thread_id, NULL, &tcp_timeout_check, NULL);
|
||||||
if (pthread_create(&thread_id, NULL, &http_proxy_loop, (void *)configure) != 0)
|
|
||||||
perror("pthread_create");
|
|
||||||
if (global.timeout_m)
|
if (global.timeout_m)
|
||||||
pthread_create(&thread_id, NULL, &timeout_check, NULL);
|
pthread_create(&thread_id, NULL, &timeout_check, NULL);
|
||||||
|
|
||||||
|
if (pthread_create(&thread_id, NULL, &http_proxy_loop, (void *)configure) != 0)
|
||||||
|
perror("pthread_create");
|
||||||
|
|
||||||
if (global.dns_listen_fd >= 0) {
|
if (global.dns_listen_fd >= 0) {
|
||||||
dns_init();
|
dns_init();
|
||||||
dns_loop(NULL);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_join(thread_id, NULL);
|
pthread_join(thread_id, NULL);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
|
|
||||||
|
|
||||||
/* 线程分离
|
/* 线程分离
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
@ -528,6 +569,7 @@ void _main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
server_ini(); // 守护进程
|
server_ini(); // 守护进程
|
||||||
|
|
||||||
// 设置每个进程允许打开的最大文件数
|
// 设置每个进程允许打开的最大文件数
|
||||||
|
38
main.h
38
main.h
@ -22,6 +22,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
|
||||||
#define MAX_CONNECTION 1020
|
#define MAX_CONNECTION 1020
|
||||||
#define BUFFER_SIZE 8192
|
#define BUFFER_SIZE 8192
|
||||||
#define PATH_SIZE 270
|
#define PATH_SIZE 270
|
||||||
@ -29,26 +30,45 @@
|
|||||||
#define HTTP_HEAD_CACHE_SIZE 1024
|
#define HTTP_HEAD_CACHE_SIZE 1024
|
||||||
#define ERRDEBUG fprintf(stderr,"Error Occured at File: %s, Function: %s, Line: %d, Date: %s, Time: %s.\n", __FILE__, __FUNCTION__, __LINE__, __DATE__, __TIME__);
|
#define ERRDEBUG fprintf(stderr,"Error Occured at File: %s, Function: %s, Line: %d, Date: %s, Time: %s.\n", __FILE__, __FUNCTION__, __LINE__, __DATE__, __TIME__);
|
||||||
|
|
||||||
struct httpudp {
|
|
||||||
struct sockaddr_in dst;
|
|
||||||
char *http_request, *original_http_request; //original_http_request为初始化生成的请求头,用来配合use_hdr语法
|
|
||||||
int http_request_len, original_http_request_len;
|
|
||||||
unsigned encodeCode, //数据编码传输
|
|
||||||
httpsProxy_encodeCode; //CONNECT代理编码
|
|
||||||
};
|
|
||||||
|
|
||||||
struct global {
|
struct global {
|
||||||
int tcp_listen_fd, dns_listen_fd, udp_listen_fd, uid, procs, timeout_m;
|
int tcp_listen_fd, dns_listen_fd, udp_listen_fd, uid, procs, timeout_m;
|
||||||
unsigned mode:3, strict_modify:1;
|
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 char local_host[CACHE_SIZE];
|
extern char local_host[CACHE_SIZE];
|
||||||
extern int epollfd, local_port, process;
|
extern int epollfd, local_port, process;
|
||||||
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 struct global global;
|
|
||||||
extern uint16_t tcp_listen_port;
|
extern uint16_t tcp_listen_port;
|
||||||
extern struct httpudp udp;
|
|
||||||
|
|
||||||
#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(10);
|
|
||||||
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