From e0261c89420b47f7cee4a937b9ea46f13e326b72 Mon Sep 17 00:00:00 2001 From: aixiao Date: Thu, 7 Feb 2019 17:26:48 +0800 Subject: [PATCH] =?UTF-8?q?=09=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20Ma?= =?UTF-8?q?kefile=20=09=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20README.md?= =?UTF-8?q?=20=09=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20conf.c=20=09?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20conf.h=20=09=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=9A=20=20=20=20=20conf/cproxy.ini=20=09=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=9A=20=20=20=20=20cproxy.c=20=09=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=9A=20=20=20=20=20cproxy.h=20=09=E6=96=B0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=EF=BC=9A=20=20=20cproxy=5Fhelp.c=20=09?= =?UTF-8?q?=E6=96=B0=E6=96=87=E4=BB=B6=EF=BC=9A=20=20=20cproxy=5Fhelp.h=20?= =?UTF-8?q?=09=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20cproxy=5Frequest.c?= =?UTF-8?q?=20=09=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20cproxy=5Freques?= =?UTF-8?q?t.h=20=09=E4=BF=AE=E6=94=B9=EF=BC=9A=20=20=20=20=20log/cproxy.p?= =?UTF-8?q?id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 +- README.md | 5 +- conf.c | 5 +- conf.h | 1 + conf/cproxy.ini | 2 +- cproxy.c | 495 +++++++++++++++++------------------------------ cproxy.h | 90 +++++---- cproxy_help.c | 36 ++++ cproxy_help.h | 10 + cproxy_request.c | 264 ++++++++++++++++--------- cproxy_request.h | 1 + log/cproxy.pid | 2 +- 12 files changed, 463 insertions(+), 452 deletions(-) create mode 100644 cproxy_help.c create mode 100644 cproxy_help.h diff --git a/Makefile b/Makefile index 8ecd196..235b6d2 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,10 @@ CFLAGS = -g -Wall -Werror -I../iniparser/src -L../iniparser LIBS = -liniparser OBJ := cproxy -all: cproxy.o cproxy_request.o conf.o +all: cproxy.o conf.o cproxy_request.o cproxy_help.o $(CC) $(CFLAGS) -o $(OBJ) $^ $(LIBS) strip $(OBJ) - -chmod 755 $(OBJ) + -chmod a+x $(OBJ) .c.o: $(CC) $(CFLAGS) -c $< $(LIBS) diff --git a/README.md b/README.md index d06c7e5..c290a86 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # cproxy - 基于mproxy修改后的Android本地代理. - 可以修改非Http tunnel消息头(request). + Android本地二级代理. + 可以修改HTTP协议消息头(request). + 可以修改HTTP协议CONNECT方法消息头. # Build diff --git a/conf.c b/conf.c index d594e16..57450f4 100644 --- a/conf.c +++ b/conf.c @@ -1,6 +1,6 @@ #include "conf.h" -void read_conf(char *file, conf * p) +void read_conf(char *file, conf *p) { dictionary *ini = iniparser_load(file); @@ -101,7 +101,7 @@ err: iniparser_freedict(ini); } -void free_conf(conf * p) +void free_conf(conf *p) { free(p->server_pid_file); free(p->http_ip); @@ -111,3 +111,4 @@ void free_conf(conf * p) free(p->https_del); free(p->https_first); } + diff --git a/conf.h b/conf.h index 6d18001..3cac86a 100644 --- a/conf.h +++ b/conf.h @@ -5,3 +5,4 @@ #include "cproxy.h" #endif + diff --git a/conf/cproxy.ini b/conf/cproxy.ini index 58288b5..2037b43 100644 --- a/conf/cproxy.ini +++ b/conf/cproxy.ini @@ -12,4 +12,4 @@ http_first="[M] [U] [V]\r\n.aixiao.me\rx-online-host: [host]\r\nhost: iread.wo.c https_ip=10.0.0.172; https_port=80; https_del="Host"; -https_first="[M] [U] [V]\r\nHost: [host]\r\n"; +https_first="[M] [U]?wap.10010.com [V]\r\nHost: wap.10010.com:[port]\r\nX-Online-Host: [host]:[port]\r\n"; diff --git a/cproxy.c b/cproxy.c index 127707a..25c4c7c 100644 --- a/cproxy.c +++ b/cproxy.c @@ -1,151 +1,97 @@ #include "cproxy.h" -ssize_t readLine(int fd, void *buffer, size_t n) +char *read_data(int client_sock, char *data, int *data_len) { - ssize_t numRead; - size_t totRead; - char *buf; - char ch; + char *new_data; + int read_len; - if (n <= 0 || buffer == NULL) { - errno = EINVAL; - return -1; - } - - buf = buffer; - - totRead = 0; - for (;;) { - numRead = receive_data(fd, &ch, 1); - - if (numRead == -1) { - if (errno == EINTR) - continue; - else - return -1; // 未知错误 - - } else if (numRead == 0) { // EOF - if (totRead == 0) // No bytes read; return 0 - return 0; - else // Some bytes read; add '\0' - break; - - } else { - - if (totRead < n - 1) { // Discard > (n - 1) bytes - totRead++; - *buf++ = ch; + do { + new_data = (char *)realloc(data, *data_len + BUF_SIZE + 1); + if (new_data == NULL) { + free(data); + return NULL; + } + data = new_data; + read_len = read(client_sock, data + *data_len, BUF_SIZE); + if (read_len <= 0) { + if (read_len == 0 || *data_len == 0 || errno != EAGAIN) { + free(data); + return NULL; } - - if (ch == '\n') - break; - } - } - - *buf = '\0'; - return totRead; -} - -// 读取header -int read_header(int fd, void *buffer) -{ - memset(header_buffer, 0, MAX_HEADER_SIZE); - char line_buffer[2048]; - char *base_ptr = header_buffer; - - for (;;) { - memset(line_buffer, 0, 2048); - - int total_read = readLine(fd, line_buffer, 2048); - if (total_read <= 0) { - return -1; - } - // 防止header缓冲区蛮越界 - if (base_ptr + total_read - header_buffer <= MAX_HEADER_SIZE) { - strncpy(base_ptr, line_buffer, total_read); - base_ptr += total_read; - } else { - return -1; - } - - // 读到了空行,http头结束 - if (strcmp(line_buffer, "\r\n") == 0 || strcmp(line_buffer, "\n") == 0) { break; } + *data_len += read_len; + } while (read_len == BUF_SIZE); + *(data + *data_len) = '\0'; - } - return 0; - + return data; } -// 提取主机、端口 -int extract_host(char *header) +void servertoclient(int remote_sock, int client_sock, char *complete_data, int *len_complete_data) { - char *_p = strstr(header, "CONNECT"); // 在 CONNECT 方法中解析 隧道主机名称及端口号 - if (_p) { - char *_p1 = strchr(_p, ' '); - char *_p2 = strchr(_p1 + 1, ':'); - char *_p3 = strchr(_p1 + 1, ' '); + while ((*len_complete_data = read(remote_sock, complete_data, BUF_SIZE)) > 0) { + write(client_sock, complete_data, *len_complete_data); + } +} - if (_p2) { - char s_port[10]; - bzero(s_port, 10); - strncpy(remote_host, _p1 + 1, (int)(_p2 - _p1) - 1); - strncpy(s_port, _p2 + 1, (int)(_p3 - _p2) - 1); - remote_port = atoi(s_port); +void clienttoserver(int remote_sock, char *complete_data, int *len_complete_data) +{ + write(remote_sock, complete_data, *len_complete_data); + complete_data = NULL; + complete_data = 0; +} - } else { - strncpy(remote_host, _p1 + 1, (int)(_p3 - _p1) - 1); - remote_port = 80; +// 处理客户端的连接 +void handle_client(int client_sock, struct sockaddr_in client_addr, conf *configure) +{ + read_data(client_sock, header_buffer, &len_header_buffer); // 第一次读取客户端(浏览器)数据 + SIGN = request_type(header_buffer); // 获取请求消息类型 + extract_host(header_buffer); // 提取真实Host + replacement_http_head(header_buffer, remote_host, &remote_port, &SIGN, configure); + + //printf("%s", header_buffer); + //printf("%s\n", remote_host); + //printf("%d\n", remote_port); + + if ((remote_sock = create_connection(configure, SIGN)) < 0) { + return; + } + + if (fork() == 0) { + if (SIGN == HTTP_CONNECT) { + clienttoserver(remote_sock, header_buffer, &len_header_buffer); + forward_data(client_sock, remote_sock); + } else if (SIGN == HTTP_OTHERS || SIGN == HTTP) { + forward_header(remote_sock); //普通的http请求先转发header + forward_data(client_sock, remote_sock); } - - return 0; + exit(0); } - char *p = strstr(header, "Host:"); - if (!p) { - return -1; - } - char *p1 = strchr(p, '\n'); - if (!p1) { - return -1; + if (fork() == 0) { + if (SIGN == HTTP_CONNECT) { + servertoclient(remote_sock, client_sock, complete_data, &len_complete_data); + } else if (SIGN == HTTP_OTHERS || SIGN == HTTP) { + forward_data(remote_sock, client_sock); + } + exit(0); } - char *p2 = strchr(p + 5, ':'); // 5是指'Host:'的长度 - if (p2 && p2 < p1) { - int p_len = (int)(p1 - p2 - 1); - char s_port[p_len]; - strncpy(s_port, p2 + 1, p_len); - s_port[p_len] = '\0'; - remote_port = atoi(s_port); - - int h_len = (int)(p2 - p - 5 - 1); - strncpy(remote_host, p + 5 + 1, h_len); // Host: - remote_host[h_len] = '\0'; - } else { - int h_len = (int)(p1 - p - 5 - 1 - 1); - strncpy(remote_host, p + 5 + 1, h_len); - remote_host[h_len] = '\0'; - remote_port = 80; - } - - return 0; + close(client_sock); + close(remote_sock); } -// 响应隧道连接请求 -int send_tunnel_ok(int client_sock) +int send_data(int socket, char *buffer, int len) { - char *resp = "HTTP/1.1 200 Connection Established\r\n\r\n"; // 把字符串写入client_sock流 - int len = strlen(resp); - char buffer[len + 1]; - strcpy(buffer, resp); - if (send_data(client_sock, buffer, len) < 0) { - return -1; - } - return 0; + return send(socket, buffer, len, 0); +} + +int receive_data(int socket, char *buffer, int len) +{ + int n = recv(socket, buffer, len, 0); + return n; } -// 转发数据,读取source_sock流发送到destination_sock流 void forward_data(int source_sock, int destination_sock) { char buffer[BUF_SIZE]; @@ -157,134 +103,79 @@ void forward_data(int source_sock, int destination_sock) shutdown(source_sock, SHUT_RDWR); } -// 转发头字符串到destination_sock -void forward_header(int destination_sock) -{ - rewrite_header(); - int len = strlen(header_buffer); - send_data(destination_sock, header_buffer, len); -} - -// 代理中的完整URL转发前需改成 path 的形式 -void rewrite_header() -{ - char *p = strstr(header_buffer, "http://"); - char *p0 = strchr(p, '\0'); - char *p5 = strstr(header_buffer, "HTTP/"); // "HTTP/" 是协议标识 如 "HTTP/1.1" - int len = strlen(header_buffer); - if (p) { - char *p1 = strchr(p + 7, '/'); - if (p1 && (p5 > p1)) { - // 转换url到 path - memcpy(p, p1, (int)(p0 - p1)); - int l = len - (p1 - p); - header_buffer[l] = '\0'; - } else { - char *p2 = strchr(p, ' '); // GET http://3g.sina.com.cn HTTP/1.1 - memcpy(p + 1, p2, (int)(p0 - p2)); - *p = '/'; // url 没有路径使用根 - int l = len - (p2 - p) + 1; - header_buffer[l] = '\0'; - } - } - -} - -// 接收数据 -int receive_data(int socket, char *buffer, int len) -{ - int n = recv(socket, buffer, len, 0); - return n; -} - -// 发送数据 -int send_data(int socket, char *buffer, int len) -{ - return send(socket, buffer, len, 0); -} - -// 创建连接 -int create_connection() +int create_connection(conf * configure, int SIGN) { struct sockaddr_in server_addr; struct hostent *server; int sock; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - return -1; + return CLIENT_SOCKET_ERROR; } - if ((server = gethostbyname(remote_host)) == NULL) { - errno = EFAULT; - return -1; + + if (SIGN == HTTP_CONNECT) { + if ((server = gethostbyname(configure->https_ip)) == NULL) { + errno = EFAULT; + return CLIENT_RESOLVE_ERROR; + } + } else if (SIGN == HTTP_OTHERS || SIGN == HTTP) { + if ((server = gethostbyname(configure->http_ip)) == NULL) { + errno = EFAULT; + return CLIENT_RESOLVE_ERROR; + } } + memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); - server_addr.sin_port = htons(remote_port); + + if (SIGN == HTTP_CONNECT) { + server_addr.sin_port = htons(configure->https_port); + } else if (SIGN == HTTP_OTHERS || SIGN == HTTP) { + server_addr.sin_port = htons(configure->http_port); + } if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - return -1; + return CLIENT_CONNECT_ERROR; } return sock; } -// 处理客户端的连接 -void handle_client(int client_sock, struct sockaddr_in client_addr, conf *m) +int create_server_socket(int port) { - int HTTPS = 0; - read_header(client_sock, header_buffer); - extract_host(header_buffer); - replacement_http_head(header_buffer, remote_host, &remote_port, &HTTPS, m); + int server_sock, optval; + struct sockaddr_in server_addr; - printf("%s\n", remote_host); - printf("%d\n", remote_port); - printf("%d\n", HTTPS); - printf("%s", header_buffer); - - if ((remote_sock = create_connection()) < 0) { // 先创建连接 - return; + if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return SERVER_SOCKET_ERROR; } - if (fork() == 0) { // 创建子进程用于从客户端转发数据到远端socket接口 - if (HTTPS == 0) { - forward_header(remote_sock); //普通的http请求先转发header - forward_data(client_sock, remote_sock); - } else { - char buffer[BUF_SIZE]; - int n; - while ((n = read(client_sock, buffer, BUF_SIZE)) > 0) { - write(remote_sock, buffer, n); - } - } - if (HTTPS == 1) { - forward_header(remote_sock); //普通的http请求先转发header - forward_data(client_sock, remote_sock); - } else { - char buffer[BUF_SIZE]; - int n; - while ((n = read(client_sock, buffer, BUF_SIZE)) > 0) { - write(remote_sock, buffer, n); - } - } - exit(0); - } - if (fork() == 0) { // 创建子进程用于转发从远端socket接口过来的数据到客户端 - if (HTTPS == 1) { - send_tunnel_ok(client_sock); - } - forward_data(remote_sock, client_sock); - exit(0); + if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { + return SERVER_SETSOCKOPT_ERROR; } - close(remote_sock); - close(client_sock); + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) + != 0) { + return SERVER_BIND_ERROR; + } + + if (listen(server_sock, 20) < 0) { + return SERVER_LISTEN_ERROR; + } + + return server_sock; } // 守护 -int init_daemon(int nochdir, int noclose, conf * p) +int init_daemon(int nochdir, int noclose, conf * configure) { - FILE *fp = fopen(p->server_pid_file, "w"); + FILE *fp = fopen(configure->server_pid_file, "w"); int pid; if ((pid = fork()) < 0) { @@ -292,9 +183,9 @@ int init_daemon(int nochdir, int noclose, conf * p) } else if (0 != pid) { exit(0); } - //child 1 continues... + //child 1 continues... - //become session leader + //become session leader if (setsid() < 0) { return -1; } @@ -306,21 +197,13 @@ int init_daemon(int nochdir, int noclose, conf * p) fprintf(fp, "%d", pid); exit(0); } - //child 2 continues... + //child 2 continues... - //change working directory + //change working directory if (0 == nochdir) { chdir("/"); } - //close off file descriptors - /* - int i; - for (i = 0; i < 64; i++) { - close(i); - } - */ - - //redirect stdin,stdout,stderror to "/dev/null" + //redirect stdin,stdout,stderror to "/dev/null" if (0 == noclose) { open("/dev/null", O_RDONLY); open("/dev/null", O_RDWR); @@ -330,107 +213,81 @@ int init_daemon(int nochdir, int noclose, conf * p) return 0; } -// 判断pid文件存放目录 -void log_dir(conf *p) -{ - char *d = strchr(p->server_pid_file, '/'); - if (d != NULL) { - int l_d = p->len_server_pid_file - strlen(d); - char pid_dir[l_d]; - strncpy(pid_dir, p->server_pid_file, l_d - 1); - printf("%d\n", l_d); - printf("%s\n", pid_dir); - - if (access(pid_dir, F_OK) != 0) { - printf("Pid File Can Not Open To Write\n"); - errno = 0; - mkdir("log", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - perror("mkdir"); - } - } -} - +// 处理僵尸进程 void sigchld_handler(int signal) { while (waitpid(-1, NULL, WNOHANG) > 0) ; } -// 主函数 +void server_loop(conf * configure) +{ + struct sockaddr_in client_addr; + socklen_t addrlen = sizeof(client_addr); + + while (1) { + client_sock = + accept(server_sock, (struct sockaddr *)&client_addr, &addrlen); + + if (fork() == 0) { // 创建子进程处理客户端连接请求 + handle_client(client_sock, client_addr, configure); + close(client_sock); + exit(0); + } + } + + close(server_sock); +} + +void start_server(conf * configure) +{ + signal(SIGCHLD, sigchld_handler); // 防止子进程变成僵尸进程 + + if ((server_sock = create_server_socket(local_port)) < 0) { + exit(server_sock); + } + + server_loop(configure); +} + int _main(int argc, char *argv[]) { + //初始化全局变量 + header_buffer = (char *)malloc(BUF_SIZE); + len_header_buffer = strlen(header_buffer); + + complete_data = (char *)malloc(BUF_SIZES); + len_complete_data = strlen(complete_data); + char *inifile = "conf/cproxy.ini"; - conf *m = (struct CONF *)malloc(sizeof(struct CONF)); - read_conf(inifile, m); - int PORT = m->server_port; -/* - printf("%d\n", m->server_port); - printf("%s\n", m->server_pid_file); - printf("%s\n", m->http_ip); - printf("%d\n", m->http_port); - printf("%s\n", m->http_del); - printf("%s\n", m->http_first); - printf("%s\n", m->https_ip); - printf("%d\n", m->https_port); - printf("%s\n", m->https_del); - printf("%s\n", m->https_first); -*/ + conf *configure = (struct CONF *)malloc(sizeof(struct CONF)); + read_conf(inifile, configure); + + local_port = configure->server_port; int opt; - char optstrs[] = ":l:d"; + char optstrs[] = ":l:dh"; while (-1 != (opt = getopt(argc, argv, optstrs))) { switch (opt) { case 'l': - PORT = atoi(optarg); + local_port = atoi(optarg); break; - case 'd':{ - init_daemon(1, 1, m); - } + case 'd': + init_daemon(1, 1, configure); + break; + case 'h': + help_information(); + exit(0); break; default: ; } } - header_buffer = (char *)malloc(MAX_HEADER_SIZE); - - signal(SIGCHLD, sigchld_handler); // 防止子进程变成僵尸进程 - - int server_sock, optval; - struct sockaddr_in server_addr; - if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - return -1; - } - if (setsockopt - (server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { - return -1; - } - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(PORT); - server_addr.sin_addr.s_addr = INADDR_ANY; - if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) - != 0) { - return -1; - } - if (listen(server_sock, 17) < 0) { - return -1; - } - - struct sockaddr_in clnt_addr; - socklen_t clnt_addr_size = sizeof(clnt_addr); - while (1) { - int client_socket = accept(server_sock, (struct sockaddr *)&clnt_addr, - &clnt_addr_size); - - if (fork() == 0) { // 创建子进程处理客户端连接请求 - close(server_sock); - handle_client(client_socket, clnt_addr, m); - exit(0); - } - close(client_socket); - } - free(header_buffer); // 收回内存 - free_conf(m); + start_server(configure); + free_conf(configure); + free(complete_data); + free(header_buffer); + return 0; } int main(int argc, char *argv[]) diff --git a/cproxy.h b/cproxy.h index 58f229f..8eaa9a9 100644 --- a/cproxy.h +++ b/cproxy.h @@ -14,60 +14,74 @@ #include #include #include - #include #include #include -#include -#include "iniparser.h" -#define LOG(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0) #define BUF_SIZE 8192 -#define MAX_HEADER_SIZE 8192 +#define BUF_SIZES 1024 -typedef struct CONF { - int server_port; // server module - char *server_pid_file; - - int http_port; // http module - char *http_ip, *http_del, *http_first; - - int https_port; // https module - char *https_ip, *https_del, *https_first; - - int len_server_pid_file; // length - int len_http_ip, len_http_del, len_http_first; - int len_https_ip, len_https_del, len_https_first; -} conf; - -void read_conf(char *file, conf * p); -void free_conf(conf * p); +#define SERVER_SOCKET_ERROR -1 +#define SERVER_SETSOCKOPT_ERROR -2 +#define SERVER_BIND_ERROR -3 +#define SERVER_LISTEN_ERROR -4 +#define CLIENT_SOCKET_ERROR -5 +#define CLIENT_RESOLVE_ERROR -6 +#define CLIENT_CONNECT_ERROR -7 char remote_host[128]; int remote_port; int local_port; + int server_sock; int client_sock; int remote_sock; -char *header_buffer; -ssize_t readLine(int fd, void *buffer, size_t n); -int read_header(int fd, void *buffer); -void extract_server_path(const char *header, char *output); -int extract_host(char *header); -int send_tunnel_ok(int client_sock); -void hand_cproxy_info_req(int sock, char *header_buffer); +char *header_buffer; +int len_header_buffer; +char *complete_data; +int len_complete_data; + +int SIGN; + +// 配置文件结构 +typedef struct CONF { + int server_port; // server module + char *server_pid_file; + + int http_port; // http module + char *http_ip, *http_del, *http_first; + + int https_port; // https module + char *https_ip, *https_del, *https_first; + + int len_server_pid_file; // length + int len_http_ip, len_http_del, len_http_first; + int len_https_ip, len_https_del, len_https_first; +} conf; + +// 请求类型 +#define OTHER 1 +#define HTTP 2 +#define HTTP_OTHERS 3 +#define HTTP_CONNECT 4 + +void read_conf(char *file, conf *p); +void free_conf(conf * p); + +void server_loop(conf * configure); +void handle_client(int client_sock, struct sockaddr_in client_addr, conf *configure); void forward_data(int source_sock, int destination_sock); +int send_data(int socket, char *buffer, int len); +int receive_data(int socket, char *buffer, int len); + +int create_connection(conf * configure, int SIGN); +int _main(int argc, char *argv[]); +int extract_host(char *header); +int replacement_http_head(char *header_buffer, char *remote_host, int *remote_port, int *SIGN, conf *p); +uint8_t request_type(char *req); void forward_header(int destination_sock); void rewrite_header(); -int receive_data(int socket, char *buffer, int len); -int send_data(int socket, char *buffer, int len); -int create_connection(); -void handle_client(int client_sock, struct sockaddr_in client_addr, conf * p); -int init_daemon(int nochdir, int noclose, conf *p); -void sigchld_handler(int signal); -int _main(int argc, char *argv[]); -int replacement_http_head(char *header_buffer, char *remote_host, - int *remote_port, int *HTTPS, conf * p); +char help_information(void); #endif diff --git a/cproxy_help.c b/cproxy_help.c new file mode 100644 index 0000000..3e961f9 --- /dev/null +++ b/cproxy_help.c @@ -0,0 +1,36 @@ +#include "cproxy_help.h" + +char help_information(void) +{ + static const char name[] = "cproxy"; + static const char subject[] = "proxy server"; + + static const struct { + const char *a, *b, *c, *d; + } author = { + "aixiao@aixiao.me", "aixiao", "Author:", "Email :",}; + static const char usage[] = + "usage: [-d] [-h]"; + + static const char *s_help[] = { + " -h: help information", + " -d: daemon", + "", + 0 + }; + + fprintf(stderr, "%s %s\n", name, subject); + fprintf(stderr, "%s %s\n", author.c, author.b); + fprintf(stderr, "%s %s\n", author.d, author.a); + fprintf(stderr, "%s %s\n", name, usage); + + int l; + for (l = 0; s_help[l]; l++) { + fprintf(stderr, "%s\n", s_help[l]); + } + + BUILD("Compile、link.\n"); + + return 0; +} + diff --git a/cproxy_help.h b/cproxy_help.h new file mode 100644 index 0000000..3c8dcfb --- /dev/null +++ b/cproxy_help.h @@ -0,0 +1,10 @@ +#ifndef CPROXY_HELP +#define CPROXY_HELP + +#include +#include "cproxy.h" + +#define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0) + +#endif + diff --git a/cproxy_request.c b/cproxy_request.c index 2ab9967..7e4f163 100644 --- a/cproxy_request.c +++ b/cproxy_request.c @@ -1,11 +1,9 @@ #include "cproxy_request.h" -void *memmem(const void *haystack, size_t haystacklen, const void *needle, - size_t needlelen); +void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); // 字符串替换 -char *replace(char *replace_memory, int *replace_memory_len, const char *src, - const int src_len, const char *dest, const int dest_len) +char *replace(char *replace_memory, int *replace_memory_len, const char *src, const int src_len, const char *dest, const int dest_len) { if (!replace_memory || !src || !dest) return replace_memory; @@ -64,14 +62,14 @@ char *replace(char *replace_memory, int *replace_memory_len, const char *src, // 删除单个字符 void del_chr(char *s, char ch) { - char *t = s; //目标指针先指向原串头 - while (*s != '\0') //遍历字符串s + char *t = s; // 目标指针先指向原串头 + while (*s != '\0') // 遍历字符串s { - if (*s != ch) //如果当前字符不是要删除的,则保存到目标串中 + if (*s != ch) // 如果当前字符不是要删除的,则保存到目标串中 *t++ = *s; - s++; //检查下一个字符 + s++; // 检查下一个字符 } - *t = '\0'; //置目标串结束符。 + *t = '\0'; // 置目标串结束符。 } // strncpy()封装 @@ -90,42 +88,145 @@ char *strncpy_(char *dest, const char *src, size_t n) } } -// 删除字符串header_buffer中第一位到ch处,并拼接str,ch必须存在. -char *splice_head(char *header_buffer, const char *ch, char *str) +uint8_t request_type(char *req) { - int len_http_first = strlen(str); - char *p1 = strstr(header_buffer, ch); - p1 = p1 + 1; - - char *s = (char *)malloc(len_http_first + strlen(p1) + 1); - strcpy(s, str); // 拼接 - return strcat(s, p1); + if (strncmp(req, "GET", 3) == 0 || strncmp(req, "POST", 4) == 0) + return HTTP; + else if (strncmp(req, "CONNECT", 7) == 0) + return HTTP_CONNECT; + else if (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_OTHERS; + else + return OTHER; } -// 删除字符串header_buffer中ch到str处,ch为空返回原字符串. -char *delete_header(char *header_buffer, const char *ch, int str) +int extract_host(char *header) +{ + char *_p = strstr(header, "CONNECT"); // 在 CONNECT 方法中解析 隧道主机名称及端口号 + if (_p) { + char *_p1 = strchr(_p, ' '); + char *_p2 = strchr(_p1 + 1, ':'); + char *_p3 = strchr(_p1 + 1, ' '); + + if (_p2) { + char s_port[10]; + bzero(s_port, 10); + strncpy(remote_host, _p1 + 1, (int)(_p2 - _p1) - 1); + strncpy(s_port, _p2 + 1, (int)(_p3 - _p2) - 1); + remote_port = atoi(s_port); + + } else { + strncpy(remote_host, _p1 + 1, (int)(_p3 - _p1) - 1); + remote_port = 80; + } + return 0; + } + + char *p = strstr(header, "Host:"); + if (!p) { + return -1; + } + char *p1 = strchr(p, '\n'); + if (!p1) { + return -1; + } + + char *p2 = strchr(p + 5, ':'); // 5是指'Host:'的长度 + if (p2 && p2 < p1) { + int p_len = (int)(p1 - p2 - 1); + char s_port[p_len]; + strncpy(s_port, p2 + 1, p_len); + s_port[p_len] = '\0'; + remote_port = atoi(s_port); + + int h_len = (int)(p2 - p - 5 - 1); + strncpy(remote_host, p + 5 + 1, h_len); // Host: + remote_host[h_len] = '\0'; + } else { + int h_len = (int)(p1 - p - 5 - 1 - 1); + strncpy(remote_host, p + 5 + 1, h_len); + remote_host[h_len] = '\0'; + remote_port = 80; + } + + return 0; +} + +// 转发头字符串到destination_sock +void forward_header(int destination_sock) +{ + rewrite_header(); + int len = strlen(header_buffer); + send_data(destination_sock, header_buffer, len); +} + +// 代理中的完整URL转发前需改成 path 的形式 +void rewrite_header() +{ + char *p = strstr(header_buffer, "http://"); + char *p0 = strchr(p, '\0'); + char *p5 = strstr(header_buffer, "HTTP/"); // "HTTP/" 是协议标识 如 "HTTP/1.1" + int len = strlen(header_buffer); + if (p) { + char *p1 = strchr(p + 7, '/'); + if (p1 && (p5 > p1)) { + // 转换url到 path + memcpy(p, p1, (int)(p0 - p1)); + int l = len - (p1 - p); + header_buffer[l] = '\0'; + } else { + char *p2 = strchr(p, ' '); // GET http://3g.sina.com.cn HTTP/1.1 + memcpy(p + 1, p2, (int)(p0 - p2)); + *p = '/'; // url 没有路径使用根 + int l = len - (p2 - p) + 1; + header_buffer[l] = '\0'; + } + } +} + +// 删除字符串header_buffer中第一位到character处,并拼接string,character必须存在.(string替换第一个字符到character处) +char *splice_head(char *header_buffer, const char *character, char *string) +{ + int len_first = strlen(string); + char *p1 = strstr(header_buffer, character); + p1 = p1 + 1; + char new_string[len_first + strlen(p1) + 1]; + strcpy(new_string, string); // 拼接 + return strcat(new_string, p1); +} + +// 删除字符串header_buffer中character到string处,character为空返回原字符串. +char *delete_header(char *header_buffer, const char *character, int string) { int len_header_buffer = strlen(header_buffer); - char *p1 = strstr(header_buffer, ch); + char *p1 = strstr(header_buffer, character); if (p1 == NULL) { return header_buffer; } - char *p2 = strchr(p1, str); + char *p2 = strchr(p1, string); int l = len_header_buffer - strlen(p1); header_buffer[l] = '\0'; return strcat(header_buffer, p2 + 1); } -int replacement_http_head(char *header_buffer, char *remote_host, - int *remote_port, int *HTTPS, conf *p) +int replacement_http_head(char *header_buffer, char *remote_host, int *remote_port, int *SIGN, conf * p) { char *http_firsts = (char *)malloc(strlen(p->http_first) + 1); strcpy(http_firsts, p->http_first); // 拷贝http_first char *https_firsts = (char *)malloc(strlen(p->https_first) + 1); strcpy(https_firsts, p->https_first); // 拷贝https_first - char *header_buffers = (char *)malloc(strlen(header_buffer) + 1); // 拷贝原字符串 - strcpy(header_buffers, header_buffer); + char *header_buffer_backup = (char *)malloc(strlen(header_buffer) + 1); // 拷贝原字符串 + strcpy(header_buffer_backup, header_buffer); char *new_http_del = malloc(strlen(p->http_del) + 1); // 拷贝http_del strcpy(new_http_del, p->http_del); @@ -133,25 +234,19 @@ int replacement_http_head(char *header_buffer, char *remote_host, char *new_https_del = malloc(strlen(p->https_del) + 1); // // 拷贝https_del strcpy(new_https_del, p->https_del); - char *con = strstr(header_buffers, "CONNECT"); // 判断是否是http 隧道请求 - if (con == NULL) { + if (*SIGN == HTTP) { char *result = NULL; result = strtok(new_http_del, ","); while (result != NULL) { - delete_header(header_buffers, result, '\n'); + delete_header(header_buffer_backup, result, '\n'); result = strtok(NULL, ","); } - //delete_header(header_buffers, "Host", '\n'); // 删除HOST,改变原字符串 - char *new_header_buffer = (char *) - malloc(strlen(splice_head(header_buffers, "\n", http_firsts)) + 1); - strcpy(new_header_buffer, - splice_head(header_buffers, "\n", http_firsts)); - char *p2 = strstr(header_buffers, "\n"); + char *p2 = strstr(header_buffer_backup, "\n"); p2 = p2 + 1; - int len_http_head = strlen(header_buffers) - strlen(p2); + int len_http_head = strlen(header_buffer_backup) - strlen(p2); char *HTTP_HEAD = (char *)malloc(len_http_head + 1); //http头第一行 - strncpy_(HTTP_HEAD, header_buffers, len_http_head); + strncpy_(HTTP_HEAD, header_buffer_backup, len_http_head); // M char *p3 = strstr(HTTP_HEAD, " "); @@ -176,56 +271,49 @@ int replacement_http_head(char *header_buffer, char *remote_host, char *V = (char *)malloc(l); strcpy(V, p4); //printf("%s", V); + + char *new_header_buffer = (char *)malloc(strlen(splice_head(header_buffer_backup, "\n", http_firsts)) + 1); + //char *new_header_buffer = (char *)malloc(BUF_SIZES); + strcpy(new_header_buffer, splice_head(header_buffer_backup, "\n", http_firsts)); int len = strlen(new_header_buffer); int len_m = strlen(M); - new_header_buffer = - replace(new_header_buffer, &len, "[M]", 3, M, len_m); - len = strlen(new_header_buffer); int len_u = strlen(U); - new_header_buffer = - replace(new_header_buffer, &len, "[U]", 3, U, len_u); - len = strlen(new_header_buffer); int len_v = strlen(V); - new_header_buffer = - replace(new_header_buffer, &len, "[V]", 3, V, len_v); - len = strlen(new_header_buffer); int len_remote_host = strlen(remote_host); - new_header_buffer = - replace(new_header_buffer, &len, "[host]", 6, remote_host, - len_remote_host); - len = strlen(new_header_buffer); + + new_header_buffer = replace(new_header_buffer, &len, "[M]", 3, M, len_m); + new_header_buffer = replace(new_header_buffer, &len, "[U]", 3, U, len_u); + new_header_buffer = replace(new_header_buffer, &len, "[V]", 3, V, len_v); + new_header_buffer = replace(new_header_buffer, &len, "[host]", 6, remote_host, len_remote_host); new_header_buffer = replace(new_header_buffer, &len, "\\r", 2, "\r", 1); - len = strlen(new_header_buffer); new_header_buffer = replace(new_header_buffer, &len, "\\n", 2, "\n", 1); - stpcpy(remote_host, p->http_ip); - *remote_port = p->http_port; + //stpcpy(p->http_ip, remote_host); + //p->http_port = *remote_port; memset(header_buffer, 0, strlen(header_buffer)); strcpy(header_buffer, new_header_buffer); + len_header_buffer = strlen(header_buffer); + free(HTTP_HEAD); free(M); free(U); free(V); free(new_header_buffer); - *HTTPS = 0; - } else { + + } else if (*SIGN == HTTP_CONNECT) { char *result = NULL; result = strtok(new_https_del, ","); while (result != NULL) { - delete_header(header_buffers, result, '\n'); + delete_header(header_buffer_backup, result, '\n'); result = strtok(NULL, ","); } - //delete_header(header_buffers, "Host", '\n'); // 删除HOST,改变原字符串 - //delete_header(header_buffers, "x-online-host", '\n'); // 删除HOST,改变原字符串 - char *new_header_buffer = (char *)malloc(strlen(splice_head(header_buffers, "\n", https_firsts)) + 1); - strcpy(new_header_buffer, splice_head(header_buffers, "\n", https_firsts)); - char *p2 = strstr(header_buffers, "\n"); + char *p2 = strstr(header_buffer_backup, "\n"); p2 = p2 + 1; - int len_https_head = strlen(header_buffers) - strlen(p2); - char *HTTPS_HEAD = (char *)malloc(len_https_head + 1); //http头第一行 - strncpy_(HTTPS_HEAD, header_buffers, len_https_head); + int len_https_head = strlen(header_buffer_backup) - strlen(p2); + char *HTTPS_HEAD = (char *)malloc(len_https_head + 1); //https头第一行 + strncpy_(HTTPS_HEAD, header_buffer_backup, len_https_head); // M char *p3 = strstr(HTTPS_HEAD, " "); @@ -244,51 +332,53 @@ int replacement_http_head(char *header_buffer, char *remote_host, // V p4 = p4 + 1; - del_chr(p4, '\r'); - del_chr(p4, '\n'); + //del_chr(p4, '\r'); + //del_chr(p4, '\n'); l = strlen(p4); char *V = (char *)malloc(l); - strcpy(V, p4); + strncpy_(V, p4, 8); //printf("%s", V); + + char *new_header_buffer = (char *) malloc(strlen(splice_head(header_buffer_backup, "\n", https_firsts)) + 1); + //char *new_header_buffer = (char *) malloc(BUF_SIZES); + strcpy(new_header_buffer, splice_head(header_buffer_backup, "\n", https_firsts)); int len = strlen(new_header_buffer); int len_m = strlen(M); - new_header_buffer = - replace(new_header_buffer, &len, "[M]", 3, M, len_m); - len = strlen(new_header_buffer); int len_u = strlen(U); - new_header_buffer = - replace(new_header_buffer, &len, "[U]", 3, U, len_u); - len = strlen(new_header_buffer); int len_v = strlen(V); - new_header_buffer = - replace(new_header_buffer, &len, "[V]", 3, V, len_v); - len = strlen(new_header_buffer); int len_remote_host = strlen(remote_host); - new_header_buffer = - replace(new_header_buffer, &len, "[host]", 6, remote_host, - len_remote_host); - len = strlen(new_header_buffer); + new_header_buffer = replace(new_header_buffer, &len, "[M]", 3, M, len_m); + new_header_buffer = replace(new_header_buffer, &len, "[U]", 3, U, len_u); + new_header_buffer = replace(new_header_buffer, &len, "[V]", 3, V, len_v); + new_header_buffer = replace(new_header_buffer, &len, "[host]", 6, remote_host, len_remote_host); + + char port_num[9]; + sprintf(port_num, "%d", *remote_port); + int len_remote_port = strlen(port_num); + new_header_buffer = replace(new_header_buffer, &len, "[port]", 6, port_num, len_remote_port); + new_header_buffer = replace(new_header_buffer, &len, "\\r", 2, "\r", 1); - len = strlen(new_header_buffer); new_header_buffer = replace(new_header_buffer, &len, "\\n", 2, "\n", 1); - //stpcpy(remote_host, p->https_ip); - //*remote_port = p->https_port; + //stpcpy(p->https_ip, remote_host); // 走真实IP非代理 + //p->https_port = *remote_port; memset(header_buffer, 0, strlen(header_buffer)); - strcpy(header_buffer, new_header_buffer); + memcpy(header_buffer, new_header_buffer, strlen(new_header_buffer)); + len_header_buffer = strlen(header_buffer); free(HTTPS_HEAD); free(M); free(U); free(V); free(new_header_buffer); - *HTTPS = 1; + } + free(http_firsts); free(https_firsts); free(new_http_del); free(new_https_del); - free(header_buffers); - return *HTTPS; + free(header_buffer_backup); + return 1; } diff --git a/cproxy_request.h b/cproxy_request.h index c69fb89..6e47650 100644 --- a/cproxy_request.h +++ b/cproxy_request.h @@ -7,3 +7,4 @@ #include "cproxy.h" #endif + diff --git a/log/cproxy.pid b/log/cproxy.pid index cfdc48c..0863c8e 100644 --- a/log/cproxy.pid +++ b/log/cproxy.pid @@ -1 +1 @@ -3006 \ No newline at end of file +22338 \ No newline at end of file