proxy: refactor and implement simple state machine
This commit is contained in:
parent
d61315d438
commit
4fc6665e44
274
proxy.c
274
proxy.c
|
@ -11,10 +11,16 @@
|
||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
|
|
||||||
int debug = 1;
|
int debug = 1;
|
||||||
struct http_msg *child_msg;
|
struct request *child_msg;
|
||||||
regex_t preg;
|
regex_t preg;
|
||||||
regmatch_t pmatch[REGEX_MATCHN];
|
regmatch_t pmatch[REGEX_MATCHN];
|
||||||
int par_line = 0;
|
|
||||||
|
int statem;
|
||||||
|
|
||||||
|
int clt_sock = -1;
|
||||||
|
int srv_sock = -1;
|
||||||
|
char *clt_msg = NULL;
|
||||||
|
char *srv_msg = NULL;
|
||||||
|
|
||||||
void *extractsub(const char *msg, regmatch_t match) {
|
void *extractsub(const char *msg, regmatch_t match) {
|
||||||
int buflen = match.rm_eo - match.rm_so;
|
int buflen = match.rm_eo - match.rm_so;
|
||||||
|
@ -37,7 +43,7 @@ int parse_header(char *msgbuff) {
|
||||||
|
|
||||||
ret = regexec(&preg, msgbuff, REGEX_MATCHN, pmatch, 0);
|
ret = regexec(&preg, msgbuff, REGEX_MATCHN, pmatch, 0);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto _err;
|
goto _ok;
|
||||||
|
|
||||||
char *key = extractsub(msgbuff, pmatch[1]);
|
char *key = extractsub(msgbuff, pmatch[1]);
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
|
@ -60,6 +66,8 @@ int parse_header(char *msgbuff) {
|
||||||
|
|
||||||
child_msg->headers[last_index] = new_header;
|
child_msg->headers[last_index] = new_header;
|
||||||
|
|
||||||
|
_ok:
|
||||||
|
|
||||||
regfree(&preg);
|
regfree(&preg);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -146,159 +154,179 @@ char *getheader(char *key) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *doforward(char *host, char *msgbuff) {
|
void do_err(void) {
|
||||||
|
int statem_code = statem & (~STATEM_ERR);
|
||||||
|
fprintf(stderr, "[%d,%d,%d] Errored out!\n", statem, statem_code, STATEM_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_fwd_clt(void) {
|
||||||
|
int bytes = 0;
|
||||||
|
do {
|
||||||
|
bytes += send(clt_sock, srv_msg+bytes, PROXY_MAX_MSGLEN-bytes, 0);
|
||||||
|
} while (bytes < PROXY_MAX_MSGLEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add parsing ability
|
||||||
|
int do_prs_srv(void) {
|
||||||
|
int ret = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_rcv_srv(void) {
|
||||||
|
int ret = recv(srv_sock, srv_msg, PROXY_MAX_MSGLEN, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
fprintf(stdout, "[%d] Received server message: %s\n", statem, clt_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int con_srv(void) {
|
||||||
|
int ret;
|
||||||
|
char *host = getheader("Host");
|
||||||
|
if (!host)
|
||||||
|
return -1;
|
||||||
|
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
int client_socket;
|
|
||||||
int ret;
|
|
||||||
char *host_response = NULL;
|
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_family = AF_INET;
|
hints.ai_family = AF_INET;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
ret = getaddrinfo(host, "80", &hints, &res);
|
ret = getaddrinfo(host, "80", &hints, &res);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
fprintf(stderr, "Failed to determine host '%s'\n", host);
|
return -1;
|
||||||
goto _return;
|
|
||||||
|
ret = srv_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = connect(srv_sock, res->ai_addr, res->ai_addrlen);
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = client_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
int do_fwd_srv(void) {
|
||||||
if (ret < 0) {
|
int ret = 0;
|
||||||
fprintf(stderr, "Failed to create a client socket\n");
|
if (srv_sock < 0)
|
||||||
goto _return;
|
ret = con_srv();
|
||||||
}
|
|
||||||
|
|
||||||
ret = connect(client_socket, res->ai_addr, res->ai_addrlen);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
return -1;
|
||||||
fprintf(stderr, "Failed to connect to destination host '%s'\n", host);
|
|
||||||
goto _return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
do {
|
do {
|
||||||
bytes += send(client_socket, msgbuff+bytes,
|
bytes += send(srv_sock, clt_msg+bytes, PROXY_MAX_MSGLEN-bytes, 0);
|
||||||
PROXY_MAX_MSGLEN-bytes, 0);
|
|
||||||
} while (bytes < PROXY_MAX_MSGLEN);
|
} while (bytes < PROXY_MAX_MSGLEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
host_response = (char *) calloc(1, PROXY_MAX_MSGLEN);
|
|
||||||
if (host_response == NULL) {
|
|
||||||
fprintf(stderr, "Not enough dynamic memory\n");
|
|
||||||
goto _free_sock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*bytes = 0;
|
int do_prs_clt(void) {
|
||||||
while (bytes < PROXY_MAX_MSGLEN) {
|
|
||||||
fprintf(stdout, "bytes 2 -> %d\n", bytes);
|
|
||||||
int new_bytes = recv(client_socket, host_response+bytes, PROXY_MAX_MSGLEN-bytes, 0);
|
|
||||||
bytes += new_bytes;
|
|
||||||
|
|
||||||
fprintf(stdout, "New bytes -> %d, bytes -> %d\n", new_bytes, bytes);
|
|
||||||
|
|
||||||
if (!new_bytes)
|
|
||||||
break;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
recv(client_socket, host_response, PROXY_MAX_MSGLEN, 0);
|
|
||||||
|
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
fprintf(stdout, "RECEIVED %s\n", host_response);
|
|
||||||
}
|
|
||||||
|
|
||||||
_free_sock:
|
|
||||||
close(client_socket);
|
|
||||||
|
|
||||||
_return:
|
|
||||||
return host_response;
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_request(int sockfd) {
|
|
||||||
int ret;
|
int ret;
|
||||||
|
int ln_cnt = 0;
|
||||||
|
|
||||||
char *msgbuff = (char *) calloc(1, PROXY_MAX_MSGLEN);
|
char *ln = strdup(clt_msg);
|
||||||
if (msgbuff == NULL) {
|
if (!ln)
|
||||||
fprintf(stderr, "Not enough dynamic memory\n");
|
return -1;
|
||||||
goto end_sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = recv(sockfd, msgbuff, PROXY_MAX_MSGLEN, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Failed to receive data from client\n");
|
|
||||||
goto end_sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare structs
|
|
||||||
child_msg = (struct http_msg *) calloc(1, sizeof(struct http_msg));
|
|
||||||
if (child_msg == NULL) {
|
|
||||||
fprintf(stderr, "Failed to allocate memory for client structs\n");
|
|
||||||
goto end_sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
fprintf(stdout, "Received buffer: %s\n", msgbuff);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ln = strdup(msgbuff);
|
|
||||||
if (!ln) {
|
|
||||||
fprintf(stderr, "Not enough dynamic memory\n");
|
|
||||||
goto free_msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
ln = strtok(ln, "\n");
|
ln = strtok(ln, "\n");
|
||||||
while (ln) {
|
while (ln) {
|
||||||
parse_line(ln, par_line);
|
ret = parse_line(ln, ln_cnt);
|
||||||
par_line++;
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ln_cnt++;
|
||||||
ln = strtok(NULL, "\n");
|
ln = strtok(NULL, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// logic
|
return 0;
|
||||||
fprintf(stdout,
|
|
||||||
"=====PARSE=RESULTS=====\n"
|
|
||||||
" * Method value: '%s'\n"
|
|
||||||
" * URI value: '%s'\n"
|
|
||||||
" * Version value: '%s'\n"
|
|
||||||
" * Number of headers: %d\n"
|
|
||||||
" * Headers:\n",
|
|
||||||
child_msg->method,
|
|
||||||
child_msg->uri,
|
|
||||||
child_msg->ver,
|
|
||||||
child_msg->header_num
|
|
||||||
);
|
|
||||||
for (int i = 0; i < child_msg->header_num; i++) {
|
|
||||||
struct header *hdr = &child_msg->headers[i];
|
|
||||||
fprintf(stdout, " * Key: '%s', Value: '%s'\n", hdr->key, hdr->value);
|
|
||||||
}
|
|
||||||
fprintf(stdout, "=====PARSE=RESULTS=====\n");
|
|
||||||
|
|
||||||
char *host = getheader("Host");
|
|
||||||
|
|
||||||
char *response = doforward(host, msgbuff);
|
|
||||||
if (debug) {
|
|
||||||
fprintf(stdout, "Response from host '%s': %s\n", host, response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reply to client
|
int do_rcv_clt(void) {
|
||||||
int bytes = 0;
|
int ret;
|
||||||
do {
|
ret = recv(clt_sock, clt_msg, PROXY_MAX_MSGLEN, 0);
|
||||||
bytes += send(sockfd, response+bytes,
|
if (ret < 0)
|
||||||
PROXY_MAX_MSGLEN-bytes, 0);
|
return -1;
|
||||||
} while (bytes < PROXY_MAX_MSGLEN);
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
fprintf(stdout, "Sent response from host '%s' to client. Totaling %d bytes of transfer\n", host, bytes);
|
fprintf(stdout, "[%d] Received client message: %s\n", statem, clt_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(response);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
free_message();
|
int do_alloc(void) {
|
||||||
|
clt_msg = (char *) calloc(1, PROXY_MAX_MSGLEN);
|
||||||
|
if (!clt_msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
free_msg:
|
srv_msg = (char *) calloc(1, PROXY_MAX_MSGLEN);
|
||||||
free(msgbuff);
|
if (!srv_msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
end_sock:
|
child_msg = (struct request *) calloc(1, sizeof(struct request));
|
||||||
close(sockfd);
|
if (!child_msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dostatem() {
|
||||||
|
int ret = do_alloc();
|
||||||
|
if (ret < 0) {
|
||||||
|
do_err();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int counter = 0; counter < MAX_BOUND; counter++) {
|
||||||
|
switch (statem & (~STATEM_ERR)) {
|
||||||
|
case STATEM_RCV_CLT:
|
||||||
|
ret = do_rcv_clt();
|
||||||
|
break;
|
||||||
|
case STATEM_PRS_CLT:
|
||||||
|
ret = do_prs_clt();
|
||||||
|
break;
|
||||||
|
case STATEM_FWD_SRV:
|
||||||
|
ret = do_fwd_srv();
|
||||||
|
break;
|
||||||
|
case STATEM_RCV_SRV:
|
||||||
|
ret = do_rcv_srv();
|
||||||
|
break;
|
||||||
|
case STATEM_PRS_SRV:
|
||||||
|
ret = do_prs_srv();
|
||||||
|
break;
|
||||||
|
case STATEM_FWD_CLT:
|
||||||
|
ret = do_fwd_clt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
statem |= STATEM_ERR;
|
||||||
|
|
||||||
|
if (statem & STATEM_ERR) {
|
||||||
|
do_err();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statem & STATEM_FWD_CLT) {
|
||||||
|
statem = STATEM_RCV_CLT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
statem <<= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dohelp() {
|
void dohelp() {
|
||||||
|
@ -374,7 +402,9 @@ int doserver(void) {
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
handle_request(client_socket);
|
clt_sock = client_socket;
|
||||||
|
statem = STATEM_RCV_CLT;
|
||||||
|
dostatem();
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
12
structs.h
12
structs.h
|
@ -1,6 +1,8 @@
|
||||||
#ifndef STRUCTS_H
|
#ifndef STRUCTS_H
|
||||||
#define STRUCTS_H
|
#define STRUCTS_H
|
||||||
|
|
||||||
|
#define MAX_BOUND 100
|
||||||
|
|
||||||
#define SERVER_MODE "server"
|
#define SERVER_MODE "server"
|
||||||
#define CLIENT_MODE "client"
|
#define CLIENT_MODE "client"
|
||||||
|
|
||||||
|
@ -18,12 +20,20 @@
|
||||||
"Host: google.com\n"\
|
"Host: google.com\n"\
|
||||||
"Authorization: Bearer ffja2439gjawgjgojserg\n"
|
"Authorization: Bearer ffja2439gjawgjgojserg\n"
|
||||||
|
|
||||||
|
#define STATEM_RCV_CLT 0b00000001
|
||||||
|
#define STATEM_PRS_CLT 0b00000010
|
||||||
|
#define STATEM_FWD_SRV 0b00000100
|
||||||
|
#define STATEM_RCV_SRV 0b00001000
|
||||||
|
#define STATEM_PRS_SRV 0b00010000
|
||||||
|
#define STATEM_FWD_CLT 0b00100000
|
||||||
|
#define STATEM_ERR 0b10000000
|
||||||
|
|
||||||
struct header {
|
struct header {
|
||||||
char *key;
|
char *key;
|
||||||
char *value;
|
char *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct http_msg {
|
struct request {
|
||||||
char *method;
|
char *method;
|
||||||
char *uri;
|
char *uri;
|
||||||
char *ver;
|
char *ver;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user