diff --git a/Makefile b/Makefile index b4c6995..6ff3625 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,14 @@ CC=bear --append -- gcc CFLAGS= -g3 -Wall -Werror -all: proxy +all: proxlib -proxy: proxy.c - $(CC) $(CFLAGS) -o proxy.o -c proxy.c - $(CC) $(CFLAGS) -o proxy proxy.o +proxy: proxlib.c + $(CC) $(CFLAGS) -o proxlib.o -c proxlib.c + $(CC) $(CFLAGS) -o proxlib proxlib.o clean: - rm -f proxy *.o + rm -f proxlib *.o tar: - tar -cvzf proxy.tgz proxy.c structs.h README Makefile + tar -cvzf proxlib.tgz proxlib.c proxlib.h README Makefile diff --git a/README b/README index b552b51..5b058cd 100644 --- a/README +++ b/README @@ -1,8 +1,8 @@ -+==================+ -| CUSTOM PROXY | -+==================+ ++=============+ +| proxlib | ++=============+ - Proxy for HTTP/1.0 standard protocol + Proxy C library for HTTP/s protocol RFC: datatracker.ietf.org/doc/html/rfc1945 RES: cs.princeton.edu/courses/archive/spr13/cos461/assignments-proxy.html @@ -12,8 +12,16 @@ TECHNICALS - Parsing is done through a chain of regex expressions that verify - the format of received HTTP/1.0 messages. + Parsing is carried by a sub-library which I wrote named parslib. + +TODO + + * Connect with parslib + * Parse port out of Host header (default_value:80) + * Implement server message parsing + * Verify and search for memory leaks + * More testing, debugging, fixing + * Implement HTTPS with OpenSSL COMMITS diff --git a/proxlib b/proxlib new file mode 100755 index 0000000..0af840b Binary files /dev/null and b/proxlib differ diff --git a/proxy.c b/proxlib.c similarity index 74% rename from proxy.c rename to proxlib.c index f38815a..b59aa91 100644 --- a/proxy.c +++ b/proxlib.c @@ -8,8 +8,9 @@ #include #include #include -#include "structs.h" +#include "proxlib.h" +int on = 1; int debug = 1; struct request *clt_data; regex_t preg; @@ -20,13 +21,17 @@ int statem; int clt_sock = -1; int srv_sock = -1; char *clt_msg = NULL; -int clt_msg_len = 0; char *srv_msg = NULL; +int clt_msg_len = 0; int srv_msg_len = 0; void *extractsub(const char *msg, regmatch_t match) { + void *buf = NULL; int buflen = match.rm_eo - match.rm_so; - void *buf = (void *) calloc(1, buflen); + if (!buflen) + goto _return; + + buf = (void *) calloc(1, buflen); if (buf == NULL) goto _return; @@ -77,6 +82,37 @@ _err: return -1; } +int parse_host(char *buff) { + int ret; + + ret = regcomp(&preg, REGEX_HOST, REG_EXTENDED); + if (ret != 0) + goto _err; + + ret = regexec(&preg, buff, REGEX_MATCHN, pmatch, 0); + if (ret != 0) + goto _err; + + char *host_name = extractsub(buff, pmatch[1]); + if (!host_name) + goto _err; + + char *host_port = extractsub(buff, pmatch[2]); + if (!host_port) { + host_port = PROXY_DEF_PORT; + } + + clt_data->host_name = host_name; + clt_data->host_port = host_port; + + regfree(&preg); + return 0; + +_err: + regfree(&preg); + return -1; +} + int parse_title(char *msgbuff) { int ret; @@ -109,13 +145,18 @@ _err: } -void free_title() { +void free_host(void) { + free(clt_data->host_name); + free(clt_data->host_port); +} + +void free_title(void) { free(clt_data->method); free(clt_data->uri); free(clt_data->ver); } -void free_headers() { +void free_headers(void) { for (int i = 0; i < clt_data->header_num; i++) { struct header *header = &clt_data->headers[i]; free(header->key); @@ -124,12 +165,27 @@ void free_headers() { free(clt_data->headers); } -void free_message() { +void free_clt_data(void) { + free_host(); free_title(); free_headers(); free(clt_data); } +void free_srv_data(void) { + +} + +void free_msg_buffs(void) { + free(clt_msg); + free(srv_msg); +} + +void free_data(void) { + free_clt_data(); + free_srv_data(); +} + int parse_line(char *line, int line_count) { int ret = 0; @@ -157,19 +213,20 @@ char *getheader(char *key) { void do_err(void) { int statem_code = statem & (~STATEM_ERR); - fprintf(stderr, "[%d,%d,%d] Errored out!\n", statem, statem_code, STATEM_ERR); + fprintf(stderr, "[%d,%d,%d] Errored out!\n", statem, statem_code, + STATEM_ERR); } int do_fwd_clt(void) { int bytes = 0; int ret = 0; - do { - ret = send(clt_sock, srv_msg+bytes, srv_msg_len-bytes, 0); - if (ret < 0) - return -1; - + while (bytes < srv_msg_len) { + ret = write(clt_sock, srv_msg+bytes, srv_msg_len-bytes); + if (ret < 0) + return -1; + bytes += ret; - } while (bytes < srv_msg_len); + } return 0; } @@ -183,21 +240,21 @@ int do_prs_srv(void) { int do_rcv_srv(void) { int bytes = 0; int ret = 0; - do { - ret = recv(srv_sock, srv_msg+bytes, PROXY_MAX_MSGLEN-bytes, 0); + while (bytes < PROXY_MAX_MSGLEN) { + ret = recv(srv_sock, srv_msg+bytes, PROXY_MAX_MSGLEN-bytes, MSG_PEEK); if (ret < 0) - return -1; + return -1; if (!ret) break; + ret = recv(srv_sock, srv_msg+bytes, PROXY_MAX_MSGLEN-bytes, 0); - bytes += ret; - } while (bytes < sizeof(PROXY_MAX_MSGLEN)); + bytes += ret; + } srv_msg_len = bytes; - if (debug) { - fprintf(stdout, "[%d] Received server message: %s\n", statem, srv_msg); - } + if (debug) + fprintf(stdout, "[%d] Received server message of size %d bytes\n", statem, srv_msg_len); return 0; } @@ -207,6 +264,10 @@ int do_con_srv(void) { char *host = getheader("Host"); if (!host) return -1; + + ret = parse_host(host); + if (ret < 0) + return -1; struct addrinfo hints; struct addrinfo *res; @@ -215,11 +276,12 @@ int do_con_srv(void) { hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; - ret = getaddrinfo(host, "80", &hints, &res); + ret = getaddrinfo(clt_data->host_name, clt_data->host_port, &hints, &res); if (ret < 0) return -1; - ret = srv_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + ret = srv_sock = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); if (ret < 0) return -1; @@ -233,13 +295,13 @@ int do_con_srv(void) { int do_fwd_srv(void) { int bytes = 0; int ret = 0; - do { - ret = send(srv_sock, clt_msg+bytes, clt_msg_len-bytes, 0); - if (ret < 0) - return -1; + while (bytes < clt_msg_len) { + ret = write(srv_sock, clt_msg+bytes, clt_msg_len-bytes); + if (ret < 0) + return -1; - bytes += ret; - } while (bytes < clt_msg_len); + bytes += ret; + } return 0; } @@ -268,21 +330,22 @@ int do_prs_clt(void) { int do_rcv_clt(void) { int bytes = 0; int ret = 0; - do { - ret = recv(clt_sock, clt_msg+bytes, PROXY_MAX_MSGLEN-bytes, 0); + while (bytes < PROXY_MAX_MSGLEN) { + ret = recv(clt_sock, clt_msg+bytes, PROXY_MAX_MSGLEN-bytes, MSG_PEEK); if (ret < 0) return -1; if (!ret) break; + ret = recv(clt_sock, clt_msg+bytes, PROXY_MAX_MSGLEN-bytes, 0); + bytes += ret; - } while (bytes < sizeof(PROXY_MAX_MSGLEN)); + } clt_msg_len = bytes; - if (debug) { - fprintf(stdout, "[%d] Received client message: %s\n", statem, clt_msg); - } + if (debug) + fprintf(stdout, "[%d] Received client message of size %d bytes\n", statem, clt_msg_len); return 0; } @@ -304,6 +367,8 @@ int do_alloc(void) { } void do_clear(void) { + statem = STATEM_RCV_CLT; + memset(clt_msg, 0, PROXY_MAX_MSGLEN); memset(srv_msg, 0, PROXY_MAX_MSGLEN); memset(clt_data, 0, sizeof(struct request)); @@ -312,7 +377,7 @@ void do_clear(void) { srv_msg_len = 0; } -void dostatem() { +void do_statem() { int ret = do_alloc(); if (ret < 0) { do_err(); @@ -356,7 +421,6 @@ void dostatem() { } if (statem & STATEM_FWD_CLT) { - statem = STATEM_RCV_CLT; do_clear(); continue; } @@ -364,9 +428,8 @@ void dostatem() { statem <<= 1; } - free_message(); - free(clt_msg); - free(srv_msg); + free_msg_buffs(); + free_data(); } void dohelp() { @@ -382,38 +445,36 @@ void dohelp() { ); } -int doserver(void) { - int ret, server_socket; +int do_srv(void) { + int ret, proxy_sock; + struct sockaddr_in serv_addr; - ret = server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ret = proxy_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ret < 0) { fprintf(stderr, "Failed to create a socket to listen on\n"); return -1; } - int on = 1; - ret = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + ret = setsockopt(proxy_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (ret < 0) { fprintf(stderr, "Failed flagging server socket as reusable\n"); return -1; } - struct sockaddr_in serv_addr; - memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(PROXY_PORT); - ret = bind(server_socket, (struct sockaddr *) &serv_addr, + ret = bind(proxy_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (ret < 0) { fprintf(stderr, "Failed to bind to port %d\n", PROXY_PORT); return -1; } - ret = listen(server_socket, PROXY_CONN); + ret = listen(proxy_sock, PROXY_CONN); if (ret < 0) { fprintf(stderr, "Failed to listen on port %d\n", PROXY_PORT); return -1; @@ -422,12 +483,12 @@ int doserver(void) { fprintf(stdout, "Listening on port %d\n", PROXY_PORT); for (;;) { - struct sockaddr_in client_addr; - socklen_t client_addrlen = sizeof(client_addr); - int client_socket; + struct sockaddr_in new_clt_addr; + socklen_t new_clt_addr_len= sizeof(new_clt_addr); + int new_clt_sock; - ret = client_socket = accept(server_socket, (struct sockaddr *) - &client_addr, &client_addrlen); + ret = new_clt_sock = accept(proxy_sock, (struct sockaddr *) + &new_clt_addr, &new_clt_addr_len); if (ret < 0) { fprintf(stderr, "Failed to establish socket connection with" "client\n"); @@ -435,29 +496,27 @@ int doserver(void) { } ret = fork(); - switch (ret) { - case -1: + if (ret < 0) { fprintf(stderr, "[CLIENT SOCKET %d] Failed to fork child process" - "to handle the request\n", client_socket); + "to handle the request\n", new_clt_sock); return -1; - break; - case 0: - clt_sock = client_socket; + } + + if (!ret) { + clt_sock = new_clt_sock; statem = STATEM_RCV_CLT; - dostatem(); + do_statem(); return 0; - break; - default: - fprintf(stdout, "[PROGRAM] Successfully forked a new child process" - " with PID %d\n", ret); - break; } + + fprintf(stdout, "[PROGRAM] Successfully forked a new child process" + " with PID %d\n", ret); } return 0; } -int doclient(void) { +int do_clt(void) { int ret = 0; int client_socket; struct sockaddr_in serv_addr; @@ -510,11 +569,11 @@ int main(int argc, char *argv[]) { const char *mode = argv[1]; ret = strcmp(mode, SERVER_MODE); if (ret == 0) - return doserver(); + return do_srv(); ret = strcmp(mode, CLIENT_MODE); if (ret == 0) - return doclient(); + return do_clt(); fprintf(stderr, "Unknown proxy mode\n"); } diff --git a/structs.h b/proxlib.h similarity index 86% rename from structs.h rename to proxlib.h index ce2b0b6..61aeaea 100644 --- a/structs.h +++ b/proxlib.h @@ -9,11 +9,14 @@ #define PROXY_PORT 2020 #define PROXY_CONN 20 #define PROXY_MAX_MSGLEN 10000*1024 +#define PROXY_DEF_PORT "80" +#define PROXY_BASE_PORT 10 #define REGEX_MATCHN 4 #define REGEX_TITLE "^([A-Z]+)[ ]+([a-zA-Z0-9\\:/_.,-]+)"\ "[ ]+([a-zA-Z0-9_.,/-]+)[\n\r]*$" #define REGEX_HEADER "^([a-zA-Z0-9_-]*):[ \t]+([^\r\n]*)" +#define REGEX_HOST "^([a-zA-Z0-9_/,.-]+)(:[0-9]+)?$" #define CLIENT_MESSAGE "GET http://archive.0xdeadbeer.org/ HTTP/1.0\r\n\r\n"\ "Host: archive.0xdeadbeer.org\r\n"\ @@ -33,6 +36,9 @@ struct header { }; struct request { + char *host_name; + char *host_port; + char *method; char *uri; char *ver;