Add files via upload
This commit is contained in:
parent
a3832dda40
commit
5da52e4d2b
14
Makefile
Normal file
14
Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
OBJ := SpecialProxy
|
||||
CC := gcc
|
||||
CFLAGS := -O3 -Wall -pthread
|
||||
|
||||
all : main.o http.o dns.o
|
||||
$(CC) $(CFLAGS) $(DEFS) -o $(OBJ) $^
|
||||
strip $(OBJ)
|
||||
-chmod 777 $(OBJ) 2>&-
|
||||
|
||||
.c.o :
|
||||
$(CC) $(CFLAGS) $(DEFS) -c $<
|
||||
|
||||
clean :
|
||||
rm -f *.o
|
38
README.me
Normal file
38
README.me
Normal file
@ -0,0 +1,38 @@
|
||||
SpecialProxy
|
||||
======
|
||||
用epoll多路复用io写的一个HTTP代理,自带DNS解析
|
||||
|
||||
##### SpecialProxy有如下特性:
|
||||
1. 普通HTTP代理通过请求头首行的host或者Host头域字段获得目标主机,
|
||||
SpecialProxy不从首行获取目标主机,
|
||||
它可以自定义代理头域(默认是Host)。
|
||||
|
||||
2. 普通HTTP代理SSL代理是判断CONNECT请求方法,
|
||||
SpecialProxy可以通过自定义特定字符串进行SSL代理(默认是CONNECT)。
|
||||
|
||||
3. 普通HTTP代理如果遇到多个连续的HTTP请求头只重新拼接第一个请求头,
|
||||
SpecialProxy可以开启严格模式(-a参数),对所以请求头都重新拼接。
|
||||
|
||||
4. -L参数设置重定向到本地端口的头域,比如-L Local,
|
||||
然后请求头中含有Local: 443,代理会将请求发送到127.0.0.1:443
|
||||
|
||||
##### 启动参数:
|
||||
-l [监听ip:]监听端口 默认监听IP为 "0.0.0.0"
|
||||
-p 代理头域 默认为 "Host"
|
||||
-L 本地代理头域 默认为 "Local"
|
||||
-d DNS查询IP[:端口] 默认为 "114.114.114.114"
|
||||
-s SSL代理字符串 默认为 "CONNECT"
|
||||
-a 对所有HTTP请求重新拼接
|
||||
-h 显示帮助
|
||||
-w 工作进程数
|
||||
|
||||
##### BUG:
|
||||
好像有些连接不关闭,需要定时重启代理
|
||||
|
||||
##### 编译:
|
||||
~~~~~
|
||||
Linux/Android:
|
||||
make DEFS=-DXMEMCPY
|
||||
Android-ndk:
|
||||
ndk-build
|
||||
~~~~~
|
156
dns.c
Normal file
156
dns.c
Normal file
@ -0,0 +1,156 @@
|
||||
#include "dns.h"
|
||||
#include "http.h"
|
||||
|
||||
struct dns dns_list[MAX_CONNECTION / 2]; //一个客户端 + 一个服务端 占用一个dns结构体
|
||||
int dnsFd;
|
||||
|
||||
void read_dns_rsp()
|
||||
{
|
||||
static char rsp_data[512], *p, ips[16];
|
||||
static unsigned char *_p;
|
||||
static struct dns *dns;
|
||||
static conn_t *client;
|
||||
static int16_t len, dns_flag;
|
||||
|
||||
while ((len = read(dnsFd, rsp_data, BUFFER_SIZE)) > 11)
|
||||
{
|
||||
memcpy(&dns_flag, rsp_data, 2);
|
||||
dns = dns_list + dns_flag;
|
||||
client = cts + (dns_flag << 1);
|
||||
//判断是否是正常DNS回应,是否已关闭连接
|
||||
if (dns_flag > MAX_CONNECTION >> 1 || client->fd < 0)
|
||||
continue;
|
||||
if (dns->request_len + 12 > len || (unsigned char)rsp_data[3] != 128) //char只有7位可用,则正数最高为127
|
||||
{
|
||||
close_connection(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get ips */
|
||||
p = rsp_data + dns->request_len + 11;
|
||||
ips[0] = '\0';
|
||||
while (p - rsp_data + 4 <= len)
|
||||
{
|
||||
//type
|
||||
if (*(p - 8) != 1)
|
||||
{
|
||||
p += *p + 12;
|
||||
continue;
|
||||
}
|
||||
_p = (unsigned char *)p + 1;
|
||||
sprintf(ips, "%d.%d.%d.%d", _p[0], _p[1], _p[2], _p[3]);
|
||||
break;
|
||||
}
|
||||
if (ips[0])
|
||||
{
|
||||
//printf("ips %s\n", ips);
|
||||
if (connectionToServer(ips, client + 1) != 0)
|
||||
{
|
||||
close_connection(client);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
close_connection(client);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 完全发送返回0,发送部分返回1,出错返回-1 */
|
||||
static int8_t send_dns_req(struct dns *dns)
|
||||
{
|
||||
static int write_len;
|
||||
|
||||
write_len = write(dnsFd, dns->request + dns->sent_len, dns->request_len - dns->sent_len);
|
||||
if (write_len == dns->request_len - dns->sent_len)
|
||||
{
|
||||
dns->sent_len = dns->request_len;
|
||||
return 0;
|
||||
}
|
||||
else if (write_len >= 0)
|
||||
{
|
||||
dns->sent_len += write_len;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void dns_query()
|
||||
{
|
||||
static int16_t i, ret;
|
||||
|
||||
for (i = 0; i < MAX_CONNECTION >> 1; i++)
|
||||
{
|
||||
if (dns_list[i].request_len != dns_list[i].sent_len)
|
||||
{
|
||||
ret = send_dns_req(dns_list + i);
|
||||
if (ret == 1)
|
||||
break;
|
||||
else if (ret == -1)
|
||||
close_connection(cts + (i << 1));
|
||||
}
|
||||
}
|
||||
if (i == MAX_CONNECTION >> 1)
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
else
|
||||
ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
|
||||
ev.data.fd = dnsFd;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, dnsFd, &ev);
|
||||
}
|
||||
|
||||
int8_t build_dns_req(struct dns *dns, char *domain)
|
||||
{
|
||||
static char *p, *_p;
|
||||
static int8_t domain_size;
|
||||
|
||||
domain_size = strlen(domain);
|
||||
p = dns->request + 12;
|
||||
memcpy(p+1, domain, domain_size);
|
||||
*(p+1+domain_size) = 0;
|
||||
while ((_p = strchr(p+1, '.')) != NULL)
|
||||
{
|
||||
*p = _p - p - 1;
|
||||
p = _p;
|
||||
}
|
||||
*p = strlen(p+1);
|
||||
p = dns->request + 14 + domain_size;
|
||||
*p++ = 0;
|
||||
*p++ = 1;
|
||||
*p++ = 0;
|
||||
*p++ = 1;
|
||||
dns->request_len = p - dns->request;
|
||||
switch (send_dns_req(dns))
|
||||
{
|
||||
case 0:
|
||||
ev.data.fd = dnsFd;
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, dnsFd, &ev);
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
ev.data.fd = dnsFd;
|
||||
ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, dnsFd, &ev);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void dns_connect(struct sockaddr_in *dnsAddr)
|
||||
{
|
||||
dnsFd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (dnsFd < 0)
|
||||
{
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
connect(dnsFd, (struct sockaddr *)dnsAddr, sizeof(struct sockaddr_in));
|
||||
fcntl(dnsFd, F_SETFL, O_NONBLOCK);
|
||||
}
|
19
dns.h
Normal file
19
dns.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef DNS_H
|
||||
#define DNS_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
struct dns {
|
||||
char request[512]; //UDP的DNS请求不超512字节
|
||||
uint16_t request_len, sent_len;
|
||||
};
|
||||
|
||||
extern void dns_connect(struct sockaddr_in *dnsAddr);
|
||||
extern struct dns dns_list[MAX_CONNECTION / 2];
|
||||
extern int dnsFd;
|
||||
|
||||
extern int8_t build_dns_req(struct dns *dns, char *domain);
|
||||
extern void read_dns_rsp();
|
||||
extern void dns_query();
|
||||
|
||||
#endif
|
594
http.c
Normal file
594
http.c
Normal file
@ -0,0 +1,594 @@
|
||||
#include "http.h"
|
||||
#include "dns.h"
|
||||
|
||||
#define SSL_RSP "HTTP/1.1 200 Connection established\r\n\r\n"
|
||||
#define HTTP_TYPE 0
|
||||
#define OTHER_TYPE 1
|
||||
|
||||
conn_t cts[MAX_CONNECTION];
|
||||
char *local_header, *proxy_header, *ssl_proxy;
|
||||
int lisFd, proxy_header_len, local_header_len;
|
||||
uint8_t strict_spilce;
|
||||
|
||||
/*
|
||||
有时候由于程序代码原因glibc的memcpy不能src + len > dst,调试起来比较麻烦
|
||||
这个函数正是为了解决这样的问题,但是效率会比memcpy低
|
||||
*/
|
||||
#ifdef XMEMCPY
|
||||
typedef struct byte256 {char data[256];} byte256_t;
|
||||
typedef struct byte64 {char data[64];} byte64_t;
|
||||
typedef struct byte16 {char data[16];} byte16_t;
|
||||
static void xmemcpy(char *src, const char *dst, size_t len)
|
||||
{
|
||||
static byte256_t *to256, *from256;
|
||||
static byte64_t *to64, *from64;
|
||||
static byte16_t *to16, *from16;
|
||||
|
||||
to256 = (byte256_t *)src;
|
||||
from256 = (byte256_t *)dst;
|
||||
while (len >= sizeof(byte256_t))
|
||||
{
|
||||
*to256++ = *from256++;
|
||||
len -= sizeof(byte256_t);
|
||||
}
|
||||
to64 = (byte64_t *)to256;
|
||||
from64 = (byte64_t *)from256;
|
||||
while (len >= sizeof(byte64_t))
|
||||
{
|
||||
*to64++ = *from64++;
|
||||
len -= sizeof(byte64_t);
|
||||
}
|
||||
to16 = (byte16_t *)to64;
|
||||
from16 = (byte16_t *)from64;
|
||||
while (len >= sizeof(byte16_t))
|
||||
{
|
||||
*to16++ = *from16++;
|
||||
len -= sizeof(byte16_t);
|
||||
}
|
||||
src = (char *)to16;
|
||||
dst = (char *)from16;
|
||||
while (len--)
|
||||
*src++ = *dst++;
|
||||
}
|
||||
#else
|
||||
#define xmemcpy memcpy
|
||||
#endif
|
||||
|
||||
int8_t connectionToServer(char *ip, conn_t *server)
|
||||
{
|
||||
server->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server->fd < 0)
|
||||
return 1;
|
||||
fcntl(server->fd, F_SETFL, fcntl(server->fd, F_GETFL)|O_NONBLOCK);
|
||||
addr.sin_addr.s_addr = inet_addr(ip);
|
||||
addr.sin_port = htons(server->destPort);
|
||||
connect(server->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
ev.data.ptr = server;
|
||||
ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, server->fd, &ev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_connection(conn_t *conn)
|
||||
{
|
||||
epoll_ctl(efd, EPOLL_CTL_DEL, conn->fd, NULL);
|
||||
close(conn->fd);
|
||||
if ((conn - cts) & 1)
|
||||
{
|
||||
static char *server_data;
|
||||
|
||||
server_data = conn->ready_data;
|
||||
memset(conn, 0, sizeof(conn_t));
|
||||
conn->ready_data = server_data;
|
||||
conn-- ->fd = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
static struct dns *d;
|
||||
|
||||
d = dns_list + ((conn - cts) >> 1);
|
||||
d->request_len = d->sent_len = 0;
|
||||
free(conn->ready_data);
|
||||
free(conn->incomplete_data);
|
||||
memset(conn, 0, sizeof(conn_t));
|
||||
conn++ ->fd = -1;
|
||||
}
|
||||
if (conn->fd >= 0)
|
||||
close_connection(conn);
|
||||
}
|
||||
|
||||
|
||||
/* 判断请求类型 */
|
||||
static int8_t request_type(char *data)
|
||||
{
|
||||
if (strncmp(data, "GET", 3) == 0 ||
|
||||
strncmp(data, "POST", 4) == 0 ||
|
||||
strncmp(data, "CONNECT", 7) == 0 ||
|
||||
strncmp(data, "HEAD", 4) == 0 ||
|
||||
strncmp(data, "PUT", 3) == 0 ||
|
||||
strncmp(data, "OPTIONS", 7) == 0 ||
|
||||
strncmp(data, "MOVE", 4) == 0 ||
|
||||
strncmp(data, "COPY", 4) == 0 ||
|
||||
strncmp(data, "TRACE", 5) == 0 ||
|
||||
strncmp(data, "DELETE", 6) == 0 ||
|
||||
strncmp(data, "LINK", 4) == 0 ||
|
||||
strncmp(data, "UNLINK", 6) == 0 ||
|
||||
strncmp(data, "PATCH", 5) == 0 ||
|
||||
strncmp(data, "WRAPPED", 7) == 0)
|
||||
return HTTP_TYPE;
|
||||
return OTHER_TYPE;
|
||||
}
|
||||
|
||||
static char *read_data(conn_t *in, char *data, int *data_len)
|
||||
{
|
||||
static char *new_data;
|
||||
static int read_len;
|
||||
|
||||
do {
|
||||
new_data = (char *)realloc(data, *data_len + BUFFER_SIZE + 1);
|
||||
if (new_data == NULL)
|
||||
{
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
data = new_data;
|
||||
read_len = read(in->fd, data + *data_len, BUFFER_SIZE);
|
||||
/* 判断是否关闭连接 */
|
||||
if (read_len <= 0)
|
||||
{
|
||||
if (read_len == 0 || *data_len == 0 || errno != EAGAIN)
|
||||
{
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*data_len += read_len;
|
||||
} while (read_len == BUFFER_SIZE);
|
||||
*(data + *data_len) = '\0';
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static char *get_host(char *data)
|
||||
{
|
||||
static char *hostEnd, *host;
|
||||
|
||||
host = strstr(data, local_header);
|
||||
if (host != NULL)
|
||||
{
|
||||
static char *local_host;
|
||||
|
||||
host += local_header_len;
|
||||
while (*host == ' ')
|
||||
host++;
|
||||
for (hostEnd = host; *hostEnd < 58 && *hostEnd > 48; hostEnd++);
|
||||
//判断该头域是否正确使用
|
||||
if (hostEnd - host > 5 || *hostEnd != '\r')
|
||||
return NULL;
|
||||
local_host = (char *)malloc(16);
|
||||
if (local_host == NULL)
|
||||
return NULL;
|
||||
strcpy(local_host, "127.0.0.1:");
|
||||
strncpy(local_host + 10, host, hostEnd - host);
|
||||
local_host[10 + (hostEnd - host)] = '\0';
|
||||
puts(local_host);
|
||||
return local_host;
|
||||
}
|
||||
host= strstr(data, proxy_header);
|
||||
if (host == NULL)
|
||||
return NULL;
|
||||
host += proxy_header_len;
|
||||
while (*host == ' ')
|
||||
host++;
|
||||
hostEnd = strchr(host, '\r');
|
||||
if (hostEnd)
|
||||
return strndup(host, hostEnd - host);
|
||||
else
|
||||
return strdup(host);
|
||||
}
|
||||
|
||||
/* 删除请求头中的头域 */
|
||||
static void del_hdr(char *header, int *header_len)
|
||||
{
|
||||
static char *key_end, *line_begin, *line_end;
|
||||
static int key_len;
|
||||
|
||||
for (line_begin = strchr(header, '\n'); line_begin++ && *line_begin != '\r'; line_begin = line_end)
|
||||
{
|
||||
key_end = strchr(line_begin, ':');
|
||||
if (key_end == NULL)
|
||||
return;
|
||||
key_len = key_end - line_begin;
|
||||
line_end = strchr(key_end, '\n');
|
||||
if (strncasecmp(line_begin, "host", key_len) == 0 || strncmp(line_begin, local_header + 1, key_len) == 0 || strncmp(line_begin, proxy_header + 1, key_len) == 0)
|
||||
{
|
||||
if (line_end++)
|
||||
{
|
||||
xmemcpy(line_begin, line_end, *header_len - (line_end - header) + 1);
|
||||
(*header_len) -= line_end - line_begin;
|
||||
line_end = line_begin - 1; //新行前一个字符
|
||||
}
|
||||
else
|
||||
{
|
||||
*line_begin = '\0';
|
||||
*header_len = line_begin - header;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 构建新请求头 */
|
||||
static char *build_request(char *client_data, int *data_len, char *host)
|
||||
{
|
||||
static char *uri, *url, *p, *lf, *header, *new_data, *proxy_host;
|
||||
static int len;
|
||||
|
||||
del_hdr(client_data, data_len);
|
||||
header = client_data;
|
||||
proxy_host = host;
|
||||
do {
|
||||
/* 将完整url转换为uri */
|
||||
url = strchr(header, ' ');
|
||||
lf = strchr(header, '\n');
|
||||
if (url == NULL || lf == NULL || lf - 10 <= header)
|
||||
return client_data;
|
||||
if (url < lf && *(++url) != '/')
|
||||
{
|
||||
uri = strchr(url + 7, '/');
|
||||
p = lf - 10; //指向HTTP版本前面的空格
|
||||
if (uri != NULL && uri < p)
|
||||
{
|
||||
xmemcpy(url, uri, *data_len - (uri - client_data) + 1);
|
||||
*data_len -= uri - url;
|
||||
lf -= uri - url;
|
||||
}
|
||||
else
|
||||
{
|
||||
*url++ = '/';
|
||||
xmemcpy(url, p, *data_len - (p - client_data) + 1);
|
||||
*data_len -= p - url;
|
||||
lf -= p - url;
|
||||
}
|
||||
}
|
||||
|
||||
*data_len += strlen(proxy_host) + 8; //8为 "Host: " + "\r\n"的长度
|
||||
new_data = (char *)malloc(*data_len + 1);
|
||||
if (new_data == NULL)
|
||||
{
|
||||
if (proxy_host != host)
|
||||
free(proxy_host);
|
||||
free(client_data);
|
||||
return NULL;
|
||||
}
|
||||
/* 请求行后面添加Host行 */
|
||||
len = lf + 1 - client_data;
|
||||
memcpy(new_data, client_data, len); //复制请求行
|
||||
strcpy(new_data + len, "Host: ");
|
||||
strcpy(new_data + len + 6, proxy_host);
|
||||
len += strlen(proxy_host) + 6;
|
||||
new_data[len++] = '\r';
|
||||
new_data[len++] = '\n';
|
||||
//len += sprintf(new_data + len, "Host: %s\r\n", proxy_host);
|
||||
memcpy(new_data + len, lf + 1, *data_len - len + 1);
|
||||
free(client_data);
|
||||
if (proxy_host != host)
|
||||
free(proxy_host);
|
||||
if (strict_spilce == 0)
|
||||
return new_data;
|
||||
client_data = new_data;
|
||||
//如果请求头只有一个头域,则必须-1才能搜索到\n\r
|
||||
header = strstr(client_data + len - 1, "\n\r");
|
||||
//如果是连续的多个请求头,则全部修改
|
||||
if (header == NULL || request_type(header + 3) == OTHER_TYPE)
|
||||
return client_data;
|
||||
header += 3;
|
||||
proxy_host = get_host(header);
|
||||
if (proxy_host == NULL)
|
||||
proxy_host = host;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/* 解析Host */
|
||||
int8_t parse_host(conn_t *server, char *host)
|
||||
{
|
||||
static char *port, *p;
|
||||
|
||||
port = strchr(host, ':');
|
||||
if (port)
|
||||
{
|
||||
server->destPort = atoi(port+1);
|
||||
*port = '\0';
|
||||
}
|
||||
else
|
||||
server->destPort = 80; //默认80端口
|
||||
for (p = host; (*p > 47 && *p < 58) || *p == '.'; p++);
|
||||
if (*p == '\0')
|
||||
{
|
||||
if (connectionToServer(host, server) != 0)
|
||||
return 1;
|
||||
}
|
||||
else if (build_dns_req(dns_list + ((server - cts) >> 1), host) == -1)
|
||||
return 1;
|
||||
if (port)
|
||||
*port = ':';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 读取到的数据全部就绪,将incomplete_data复制到ready_data */
|
||||
static int8_t copy_data(conn_t *ct)
|
||||
{
|
||||
if (ct->ready_data)
|
||||
{
|
||||
static char *new_data;
|
||||
|
||||
new_data = (char *)realloc(ct->ready_data, ct->ready_data_len + ct->incomplete_data_len);
|
||||
if (new_data == NULL)
|
||||
return 1;
|
||||
ct->ready_data = new_data;
|
||||
memcpy(new_data + ct->ready_data_len, ct->incomplete_data, ct->incomplete_data_len);
|
||||
ct->ready_data_len += ct->incomplete_data_len;
|
||||
free(ct->incomplete_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
ct->ready_data = ct->incomplete_data;
|
||||
ct->ready_data_len = ct->incomplete_data_len;
|
||||
}
|
||||
ct->incomplete_data = NULL;
|
||||
ct->incomplete_data_len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void serverToClient(conn_t *server)
|
||||
{
|
||||
static conn_t *client;
|
||||
static int write_len;
|
||||
|
||||
client = server - 1;
|
||||
while ((server->ready_data_len = read(server->fd, server->ready_data, BUFFER_SIZE)) > 0)
|
||||
{
|
||||
write_len = write(client->fd, server->ready_data, server->ready_data_len);
|
||||
if (write_len == -1)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
close_connection(server);
|
||||
else
|
||||
server->sent_len = 0;
|
||||
return;
|
||||
}
|
||||
else if (write_len < server->ready_data_len)
|
||||
{
|
||||
server->sent_len = write_len;
|
||||
ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
|
||||
ev.data.ptr = client;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, client->fd, &ev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//判断服务端是否关闭连接
|
||||
if (server->ready_data_len == 0 || errno != EAGAIN)
|
||||
close_connection(server);
|
||||
else
|
||||
server->ready_data_len = server->sent_len = 0;
|
||||
}
|
||||
|
||||
void tcp_out(conn_t *to)
|
||||
{
|
||||
static conn_t *from;
|
||||
static int write_len;
|
||||
|
||||
if (to->fd == -1)
|
||||
return;
|
||||
else if ((to - cts) & 1)
|
||||
from = to - 1;
|
||||
else
|
||||
from = to + 1;
|
||||
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 ((from - cts) & 1)
|
||||
{
|
||||
serverToClient(from);
|
||||
if (from->fd >= 0 && from->ready_data_len == 0)
|
||||
{
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
ev.data.ptr = to;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, to->fd, &ev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
ev.data.ptr = to;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, to->fd, &ev);
|
||||
free(from->ready_data);
|
||||
from->ready_data = NULL;
|
||||
from->ready_data_len = 0;
|
||||
}
|
||||
}
|
||||
else if (write_len > 0)
|
||||
{
|
||||
from->sent_len += write_len;
|
||||
ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
|
||||
ev.data.ptr = to;
|
||||
epoll_ctl(efd, EPOLL_CTL_MOD, to->fd, &ev);
|
||||
}
|
||||
else if (errno != EAGAIN)
|
||||
{
|
||||
close_connection(to);
|
||||
}
|
||||
}
|
||||
|
||||
void tcp_in(conn_t *in)
|
||||
{
|
||||
static int write_len;
|
||||
static conn_t *server;
|
||||
static char *host, *headerEnd;
|
||||
|
||||
if (in->fd < 0)
|
||||
return;
|
||||
|
||||
//如果in - cts是奇数,那么是服务端触发事件
|
||||
if ((in - cts) & 1)
|
||||
{
|
||||
if (in->ready_data_len == 0)
|
||||
serverToClient(in);
|
||||
return;
|
||||
}
|
||||
|
||||
in->incomplete_data = read_data(in, in->incomplete_data, &in->incomplete_data_len);
|
||||
if (in->incomplete_data == NULL)
|
||||
{
|
||||
close_connection(in);
|
||||
return;
|
||||
}
|
||||
server = in + 1;
|
||||
if (request_type(in->incomplete_data) == 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;
|
||||
host = get_host(in->incomplete_data);
|
||||
if (host == NULL)
|
||||
{
|
||||
close_connection(in);
|
||||
return;
|
||||
}
|
||||
/* 第一次读取数据 */
|
||||
if (in->reread_data == 0)
|
||||
{
|
||||
in->reread_data = 1;
|
||||
if (parse_host(server, host) != 0)
|
||||
{
|
||||
free(host);
|
||||
close_connection(in);
|
||||
return;
|
||||
}
|
||||
if (strstr(in->incomplete_data, ssl_proxy))
|
||||
{
|
||||
write_len = write(in->fd, SSL_RSP, 39);
|
||||
if (write_len == 39)
|
||||
{
|
||||
;
|
||||
}
|
||||
else if (write_len > 0)
|
||||
{
|
||||
memcpy(server->ready_data, SSL_RSP + write_len, 39 - write_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(host);
|
||||
close_connection(in);
|
||||
return;
|
||||
}
|
||||
headerEnd += 3;
|
||||
if (headerEnd - in->incomplete_data < in->incomplete_data_len)
|
||||
{
|
||||
in->incomplete_data_len -= headerEnd - in->incomplete_data;
|
||||
xmemcpy(in->incomplete_data, headerEnd, in->incomplete_data_len + 1);
|
||||
if (request_type(in->incomplete_data) == OTHER_TYPE)
|
||||
{
|
||||
copy_data(in);
|
||||
free(host);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(in->incomplete_data);
|
||||
in->incomplete_data = NULL;
|
||||
in->incomplete_data_len = 0;
|
||||
free(host);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
in->incomplete_data = build_request(in->incomplete_data, &in->incomplete_data_len, host);
|
||||
free(host);
|
||||
if (in->incomplete_data == NULL || copy_data(in) != 0)
|
||||
{
|
||||
close_connection(in);
|
||||
return;
|
||||
}
|
||||
//数据处理完毕,可以发送
|
||||
handle_data_complete:
|
||||
//多次读取客户端数据,但是和服务端建立连接
|
||||
if (server->fd >= 0)
|
||||
tcp_out(server);
|
||||
}
|
||||
|
||||
void *accept_loop(void *ptr)
|
||||
{
|
||||
conn_t *client;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* 偶数为客户端,奇数为服务端 */
|
||||
for (client = cts; client - cts < MAX_CONNECTION; client += 2)
|
||||
if (client->fd < 0)
|
||||
break;
|
||||
if (client - cts >= MAX_CONNECTION)
|
||||
{
|
||||
sleep(3);
|
||||
continue;
|
||||
}
|
||||
client->fd = accept(lisFd, (struct sockaddr *)&addr, &addr_len);
|
||||
if (client->fd >= 0)
|
||||
{
|
||||
fcntl(client->fd, F_SETFL, fcntl(client->fd, F_GETFL)|O_NONBLOCK);
|
||||
ev.data.ptr = client;
|
||||
ev.events = EPOLLIN|EPOLLET;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, client->fd, &ev);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void create_listen(char *ip, int port)
|
||||
{
|
||||
int optval = 1;
|
||||
|
||||
if ((lisFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = inet_addr(ip);
|
||||
if (setsockopt(lisFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
|
||||
{
|
||||
perror("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
if (bind(lisFd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
|
||||
{
|
||||
perror("bind");
|
||||
exit(1);
|
||||
}
|
||||
if (listen(lisFd, 500) != 0)
|
||||
{
|
||||
perror("listen");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
25
http.h
Normal file
25
http.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
typedef struct tcp_connection {
|
||||
char *ready_data, *incomplete_data;
|
||||
int fd, ready_data_len, incomplete_data_len, sent_len;
|
||||
uint16_t destPort;
|
||||
unsigned reread_data :1;
|
||||
} conn_t;
|
||||
|
||||
extern void create_listen(char *ip, int port);
|
||||
extern void *accept_loop(void *ptr);
|
||||
extern void close_connection(conn_t *conn);
|
||||
extern int8_t connectionToServer(char *ip, conn_t *server);
|
||||
extern void tcp_in(conn_t *ct);
|
||||
extern void tcp_out(conn_t *ct);
|
||||
|
||||
extern conn_t cts[MAX_CONNECTION];
|
||||
extern char *local_header, *proxy_header, *ssl_proxy;
|
||||
extern int lisFd, local_header_len, proxy_header_len;
|
||||
extern uint8_t strict_spilce;
|
||||
|
||||
#endif
|
215
main.c
Normal file
215
main.c
Normal file
@ -0,0 +1,215 @@
|
||||
#include "main.h"
|
||||
#include "http.h"
|
||||
#include "dns.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#define VERSION "0.1"
|
||||
#define DEFAULT_DNS_IP "114.114.114.114"
|
||||
|
||||
struct epoll_event evs[MAX_CONNECTION + 2], ev;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
int efd;
|
||||
|
||||
static void usage()
|
||||
{
|
||||
puts("SpecialProxy(" VERSION "):\n"
|
||||
" -l [listenip:]listenport \033[35G default ip is 0.0.0.0\n"
|
||||
" -p proxy header \033[35G default is 'Host'\n"
|
||||
" -L local proxy header \033[35G default is 'Local'\n"
|
||||
" -d dns query address \033[35G default is " DEFAULT_DNS_IP "\n"
|
||||
" -s ssl proxy string \033[35G default is 'CONNECT'\n"
|
||||
" -a \033[35G all http requests repeat spilce\n"
|
||||
" -h display this infomaction\n"
|
||||
" -w worker process\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void server_loop()
|
||||
{
|
||||
pthread_t thread_id;
|
||||
int n;
|
||||
|
||||
//单独进程accept多进程并发环境下不会惊群
|
||||
pthread_create(&thread_id, NULL, accept_loop, NULL);
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = dnsFd;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, dnsFd, &ev);
|
||||
while (1)
|
||||
{
|
||||
n = epoll_wait(efd, evs, MAX_CONNECTION + 2, -1);
|
||||
while (n-- > 0)
|
||||
{
|
||||
if (evs[n].data.fd == dnsFd)
|
||||
{
|
||||
if (evs[n].events & EPOLLIN)
|
||||
read_dns_rsp();
|
||||
if (evs[n].events & EPOLLOUT)
|
||||
dns_query();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (evs[n].events & EPOLLIN)
|
||||
tcp_in((conn_t *)evs[n].data.ptr);
|
||||
if (evs[n].events & EPOLLOUT)
|
||||
tcp_out((conn_t *)evs[n].data.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void initializate(int argc, char **argv)
|
||||
{
|
||||
struct sockaddr_in dnsAddr;
|
||||
char *p;
|
||||
int opt, i, workers = 1;
|
||||
|
||||
addr_len = sizeof(addr);
|
||||
lisFd = -1;
|
||||
efd = epoll_create(MAX_CONNECTION + 2);
|
||||
if (efd < 0)
|
||||
{
|
||||
perror("epoll_create");
|
||||
exit(1);
|
||||
}
|
||||
dnsAddr.sin_family = addr.sin_family = AF_INET;
|
||||
//默认dns地址
|
||||
dnsAddr.sin_addr.s_addr = inet_addr(DEFAULT_DNS_IP);
|
||||
dnsAddr.sin_port = htons(53);
|
||||
dns_connect(&dnsAddr); //主进程中的fd
|
||||
strict_spilce = 0;
|
||||
local_header = NULL;
|
||||
ssl_proxy = (char *)"CONNECT";
|
||||
local_header = (char *)"\nLocal:";
|
||||
proxy_header = (char *)"\nHost:";
|
||||
proxy_header_len = strlen(proxy_header);
|
||||
local_header_len = strlen(local_header);
|
||||
/* 读取命令行参数 */
|
||||
while ((opt = getopt(argc, argv, "d:l:p:s:w:L:ah")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
p = strchr(optarg, ':');
|
||||
if (p)
|
||||
{
|
||||
*p = '\0';
|
||||
dnsAddr.sin_port = htons(atoi(p+1));
|
||||
}
|
||||
else
|
||||
{
|
||||
dnsAddr.sin_port = htons(53);
|
||||
}
|
||||
dnsAddr.sin_addr.s_addr = inet_addr(optarg);
|
||||
connect(dnsFd, (struct sockaddr *)&dnsAddr, sizeof(dnsAddr));
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
p = strchr(optarg, ':');
|
||||
if (p)
|
||||
{
|
||||
*p = '\0';
|
||||
create_listen(optarg, atoi(p+1));
|
||||
}
|
||||
else
|
||||
{
|
||||
create_listen((char *)"0.0.0.0", atoi(optarg));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
//假如选项值为 "Proxy", proxy_header设置为 "\nProxy:"
|
||||
proxy_header_len = strlen(optarg) + 2;
|
||||
if (optarg[proxy_header_len] == ':')
|
||||
optarg[proxy_header_len--] = '\0';
|
||||
proxy_header = (char *)malloc(proxy_header_len + 1);
|
||||
if (proxy_header == NULL)
|
||||
{
|
||||
fputs("out of memory.\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
sprintf(proxy_header, "\n%s:", optarg);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
local_header_len = strlen(optarg) + 2;
|
||||
if (optarg[local_header_len] == ':')
|
||||
optarg[local_header_len--] = '\0';
|
||||
local_header = (char *)malloc(local_header_len + 1);
|
||||
if (local_header == NULL)
|
||||
{
|
||||
fputs("out of memory.\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
sprintf(local_header, "\n%s:", optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
ssl_proxy = optarg;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
strict_spilce = 1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
workers = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lisFd < 0)
|
||||
{
|
||||
fputs("no listen address\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
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(dns_list, 0, sizeof(dns_list));
|
||||
for (i = MAX_CONNECTION / 2; i--; )
|
||||
{
|
||||
memcpy(dns_list[i].request, &i, sizeof(uint16_t));
|
||||
dns_list[i].request[2] = 1;
|
||||
dns_list[i].request[3] = 0;
|
||||
dns_list[i].request[4] = 0;
|
||||
dns_list[i].request[5] = 1;
|
||||
dns_list[i].request[6] = 0;
|
||||
dns_list[i].request[7] = 0;
|
||||
dns_list[i].request[8] = 0;
|
||||
dns_list[i].request[9] = 0;
|
||||
dns_list[i].request[10] = 0;
|
||||
dns_list[i].request[11] = 0;
|
||||
}
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
while (workers-- > 1 && fork() == 0)
|
||||
//子进程中的dnsFd必须重新申请,不然epoll监听可能读取到其他进程得到的数据
|
||||
dns_connect(&dnsAddr);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
initializate(argc, argv);
|
||||
//if (daemon(1, 1))
|
||||
if (daemon(1, 0))
|
||||
{
|
||||
perror("daemon");
|
||||
return 1;
|
||||
}
|
||||
server_loop();
|
||||
|
||||
return 0;
|
||||
}
|
27
main.h
Normal file
27
main.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <limits.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define BUFFER_SIZE 10240
|
||||
#define MAX_CONNECTION 1020
|
||||
|
||||
extern struct epoll_event evs[MAX_CONNECTION + 2], ev;
|
||||
extern struct sockaddr_in addr;
|
||||
extern socklen_t addr_len;
|
||||
extern int efd;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user