CProxy/http_proxy.c
2022-07-13 11:33:56 +08:00

423 lines
12 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "http_proxy.h"
#include "main.h"
int sslEncodeCode;
int remote_port;
char remote_host[CACHE_SIZE];
int timeout_minute;
/* 对数据进行编码 */
void dataEncode(char *data, int data_len, unsigned code)
{
while (data_len-- > 0)
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) {
printf("关闭连接\n");
close_connection(cts + i);
} else
cts[i].timer++;
}
}
return NULL;
}
static char *read_data(conn_t * in, char *data, int *data_len)
{
char *new_data;
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;
}
void close_connection(conn_t * conn)
{
epoll_ctl(epollfd, EPOLL_CTL_DEL, conn->fd, NULL);
close(conn->fd);
if ((conn - cts) & 1) {
char *server_data;
server_data = conn->ready_data;
memset(conn, 0, sizeof(conn_t));
conn->ready_data = server_data;
conn--->fd = -1;
} else {
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 void serverToClient(conn_t * server)
{
conn_t *client;
int write_len;
client = server - 1;
while ((server->ready_data_len = read(server->fd, server->ready_data, BUFFER_SIZE)) > 0) {
dataEncode(server->ready_data, server->ready_data_len, sslEncodeCode);
write_len = write(client->fd, server->ready_data, server->ready_data_len);
if (write_len <= 0) {
if (write_len == 0 || 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(epollfd, EPOLL_CTL_MOD, client->fd, &ev);
return;
}
if (server->ready_data_len < BUFFER_SIZE)
break;
}
//判断是否关闭连接
if (server->ready_data_len == 0 || (server->ready_data_len == -1 && errno != EAGAIN))
close_connection(server);
else
server->ready_data_len = server->sent_len = 0;
}
void clientToserver(conn_t * in)
{
int write_len;
conn_t *remote;
remote = in + 1;
write_len = write(remote->fd, in->ready_data, in->ready_data_len);
if (write_len == in->ready_data_len) {
in->ready_data_len = 0;
in->ready_data = NULL;
} else {
close_connection(remote);
}
return;
}
// 判断请求类型
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;
}
// Check for valid IPv4 or Iv6 string. Returns AF_INET for IPv4, AF_INET6 for IPv6
int check_ipversion(char *address)
{
struct in6_addr bindaddr;
if (inet_pton(AF_INET, address, &bindaddr) == 1) {
return AF_INET;
} else {
if (inet_pton(AF_INET6, address, &bindaddr) == 1) {
return AF_INET6;
}
}
return 0;
}
int create_connection6(char *remote_host, int remote_port)
{
struct addrinfo hints;
int sock;
int validfamily = 0;
char portstr[CACHE_SIZE];
memset(&hints, 0x00, sizeof(hints));
hints.ai_flags = AI_NUMERICSERV; // numeric service number, not resolve
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
sprintf(portstr, "%d", remote_port);
// check for numeric IP to specify IPv6 or IPv4 socket
if ((validfamily = check_ipversion(remote_host)) != 0) {
hints.ai_family = validfamily;
hints.ai_flags |= AI_NUMERICHOST;
}
/*
struct addrinfo *res = NULL;
if (getaddrinfo(remote_host, portstr, &hints, &res) != 0) {
errno = EFAULT;
perror("getaddrinfo");
return -1;
}
if ((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
perror("socket");
return -1;
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
perror("connect");
return -1;
}
if (res != NULL)
freeaddrinfo(res);
*/
//通用sockaddr_storage结构体
struct sockaddr_storage remote_addr;
memset(&remote_addr, 0, sizeof(struct sockaddr_storage));
if (validfamily == AF_INET) {
struct sockaddr_in *addr_v4 = (struct sockaddr_in *)&remote_addr;
addr_v4->sin_family = AF_INET;
addr_v4->sin_port = htons(remote_port);
inet_aton(remote_host, &(addr_v4->sin_addr));
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
}
else
{
struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)&remote_addr;
addr_v6->sin6_family = AF_INET6;
addr_v6->sin6_port = htons(remote_port);
inet_pton(AF_INET6, remote_host, &(addr_v6->sin6_addr));
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
}
if (connect(sock, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_storage)) < 0)
{
perror("connect");
return -1;
}
/*
//普通方法
if (validfamily == AF_INET) {
struct sockaddr_in remote_addr;
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(remote_port);
remote_addr.sin_addr.s_addr = inet_addr(remote_host);
if ((sock = socket(validfamily, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
if (connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) < 0) {
perror("connect");
return -1;
}
return sock;
} else {
struct sockaddr_in6 remote_addr;
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin6_family = AF_INET6;
remote_addr.sin6_port = htons(remote_port);
inet_pton(AF_INET6, remote_host, &(remote_addr.sin6_addr));
if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
if (connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) < 0) {
perror("connect");
return -1;
}
return sock;
}
*/
return sock;
}
/* 读取到的数据全部就绪将incomplete_data复制到ready_data */
static int8_t copy_data(conn_t * ct)
{
dataEncode(ct->incomplete_data, ct->incomplete_data_len, sslEncodeCode);
if (ct->ready_data) {
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;
}
void tcp_in(conn_t * in, conf * configure)
{
conn_t *server;
char *headerEnd;
if (in->fd < 0)
return;
//如果in - cts是奇数那么是服务端触发事件
if ((in - cts) & 1) {
in->timer = (in - 1)->timer = 0;
if (in->ready_data_len <= 0)
serverToClient(in);
return;
}
in->timer = (in + 1)->timer = 0;
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;
server->request_type = in->request_type = request_type(in->incomplete_data);
if (in->request_type == OTHER_TYPE) {
//如果是第一次读取数据并且不是HTTP请求的关闭连接。复制数据失败的也关闭连接
if (in->reread_data == 0 || copy_data(in) != 0) {
close_connection(in);
return;
}
goto handle_data_complete;
}
headerEnd = strstr(in->incomplete_data, "\n\r");
//请求头不完整,等待下次读取
if (headerEnd == NULL)
return;
if (in->reread_data == 0) {
in->reread_data = 1;
in->incomplete_data = request_head(in, configure);
server->fd = create_connection6(remote_host, remote_port);
if (server->fd < 0) {
printf("remote->fd ERROR!\n");
close_connection(in);
return;
}
fcntl(server->fd, F_SETFL, O_NONBLOCK);
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.data.ptr = server;
epoll_ctl(epollfd, EPOLL_CTL_ADD, server->fd, &ev);
}
if (in->incomplete_data == NULL || copy_data(in) != 0) {
close_connection(server);
return;
}
// 数据处理完毕,可以发送
handle_data_complete:
// 这个判断是防止 多次读取客户端数据,但是没有和服务端建立连接,导致报错
if (server->fd >= 0)
tcp_out(server);
}
void tcp_out(conn_t * to)
{
conn_t *from;
int write_len;
if (to->fd == -1)
return;
else if ((to - cts) & 1)
from = to - 1;
else
from = to + 1;
from->timer = to->timer = 0;
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(epollfd, EPOLL_CTL_MOD, to->fd, &ev);
}
} else {
ev.events = EPOLLIN | EPOLLET;
ev.data.ptr = to;
epoll_ctl(epollfd, 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(epollfd, EPOLL_CTL_MOD, to->fd, &ev);
} else if (errno != EAGAIN) {
close_connection(to);
}
}