#include "http.h" #include "dns.h" #include "timeout.h" #define SSL_RSP 270 #define SSL_RSP_CONNECT "HTTP/1.1 200 Connection established\r\nServer: SpecialProxy_CuteBi\r\nConnection: keep-alive\r\n\r\n" #define SSL_RSP_HTTP "HTTP/1.1 200 OK\r\nContent-length: 99999999\r\nServer: SpecialProxy_CuteBi\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: keep-alive\r\n\r\n" #define SSL_RSP_WEBSOCKET "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: SpecialProxy_CuteBi\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, ignore_host_before_count; uint8_t strict_spilce, sslEncodeCode; /* 对数据进行编码 */ static void dataEncode(char *data, int data_len) { if (sslEncodeCode) while (data_len-- > 0) data[data_len] ^= sslEncodeCode; } int8_t connectionToServer(in_addr_t ip, conn_t *server) { struct sockaddr_in addr; server->fd = socket(AF_INET, SOCK_STREAM, 0); if (server->fd < 0) return 1; fcntl(server->fd, F_SETFL, O_NONBLOCK); addr.sin_family = AF_INET; addr.sin_addr.s_addr = ip; addr.sin_port = htons(server->destPort); if (connect(server->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 && errno != EINPROGRESS) return 1; 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) { char *server_data; server_data = conn->ready_data; memset(conn, 0, sizeof(conn_t)); conn->ready_data = server_data; conn-- ->fd = -1; } else { 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) { 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); dataEncode(data, read_len); /* 判断是否关闭连接 */ 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) { char *hostEnd, *host; int i; host = strstr(data, local_header); if (host != NULL) { char *local_host; host += local_header_len; while (*host == ' ' || *host == '\t') 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:"); memcpy(local_host + 10, host, hostEnd - host); local_host[10 + (hostEnd - host)] = '\0'; return local_host; } host= strstr(data, proxy_header); if (host == NULL) return NULL; host += proxy_header_len; while (*host == ' ' || *host == '\t') host++; for (i = 0; i < ignore_host_before_count; i++) if (host[i] == '\0') //防止越界 break; host += i; hostEnd = strchr(host, '\r'); return hostEnd ? strndup(host, hostEnd - host) : strdup(host); } /* 删除请求头中的头域 */ static void del_hdr(char *header, int *header_len) { char *line_begin, *line_end; for (line_begin = strchr(header, '\n'); line_begin++ && *line_begin != '\r'; line_begin = line_end) { line_end = strchr(line_begin, '\n'); if (strncasecmp(line_begin, "host:", 5) == 0 || strncasecmp(line_begin, local_header + 1, local_header_len - 1) == 0 || strncasecmp(line_begin, proxy_header + 1, proxy_header_len - 1) == 0) { if (line_end++) { memmove(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) { char *uri, *url, *p, *lf, *header, *new_data, *proxy_host; int len; header = client_data; proxy_host = host; do { del_hdr(client_data, data_len); /* 将完整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) { memmove(url, uri, *data_len - (uri - client_data) + 1); *data_len -= uri - url; lf -= uri - url; } else { *url++ = '/'; memmove(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 */ static int8_t parse_host(conn_t *server, char *host) { 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(inet_addr(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) { //dataEncode(ct->incomplete_data, ct->incomplete_data_len); 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; } 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); 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(efd, 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; } /* ssl代理回应 */ static int respond_sslStatus(conn_t *in) { /* 可能客户端使用http请求伪装CONNECT代理 这时候即使fd是非阻塞也只需要判断返回值是否小于0 正常情况非阻塞也可以全部发送,懒得写代码了 */ char buffer[SSL_RSP]; if (memcmp(in->incomplete_data, "CON", 3) == 0) { memset(buffer, 0, SSL_RSP); memcpy(buffer, SSL_RSP_CONNECT, sizeof(SSL_RSP_CONNECT)-1); dataEncode(buffer, sizeof(SSL_RSP_CONNECT)-1); return (write(in->fd, buffer, sizeof(SSL_RSP_CONNECT)-1) <= 0); } else if (*in->incomplete_data == 'G' && (strstr(in->incomplete_data, "websocket") || strstr(in->incomplete_data, "WebSocket"))) { memset(buffer, 0, SSL_RSP); memcpy(buffer, SSL_RSP_WEBSOCKET, sizeof(SSL_RSP_WEBSOCKET)-1); return (write(in->fd, buffer, sizeof(SSL_RSP_WEBSOCKET)-1) <= 0); } memset(buffer, 0, SSL_RSP); memcpy(buffer, SSL_RSP_HTTP, sizeof(SSL_RSP_HTTP)-1); return (write(in->fd, SSL_RSP_HTTP, sizeof(SSL_RSP_HTTP)-1) <= 0); } void tcp_in(conn_t *in) { conn_t *server; char *host, *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; host = get_host(in->incomplete_data); if (host == NULL) { close_connection(in); return; } //dataEncode(host, strlen(host)); // 第一次读取数据 if (in->reread_data == 0) { // 打印HTTP HEAD //printf("%s", in->incomplete_data); in->reread_data = 1; if (parse_host(server, host) != 0) { free(host); close_connection(in); return; } if (strstr(in->incomplete_data, ssl_proxy)) { if (respond_sslStatus(in) != 0) { 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; memmove(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 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(efd, EPOLL_CTL_MOD, to->fd, &ev); } } 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 accept_client() { struct epoll_event epollEvent; struct sockaddr_in addr; conn_t *client; socklen_t addr_len = sizeof(addr); /* 偶数为客户端,奇数为服务端 */ for (client = cts; client - cts < MAX_CONNECTION; client += 2) if (client->fd < 0) break; if (client - cts >= MAX_CONNECTION) return; client->timer = (client+1)->timer = 0; client->fd = accept(lisFd, (struct sockaddr *)&addr, &addr_len); if (client->fd < 0) return; fcntl(client->fd, F_SETFL, O_NONBLOCK); epollEvent.events = EPOLLIN|EPOLLET; epollEvent.data.ptr = client; epoll_ctl(efd, EPOLL_CTL_ADD, client->fd, &epollEvent); } void create_listen(char *ip, int port) { struct sockaddr_in addr; int optval = 1; if ((lisFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } addr.sin_family = AF_INET; 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); } }