From ec033efbbcbd3c1bdfa432e50475dd75c8e29fed Mon Sep 17 00:00:00 2001 From: yrutschle Date: Tue, 26 Oct 2021 21:45:44 +0200 Subject: [PATCH] refactor more code from sslh-select to processes.c --- Makefile | 13 +++-- processes.c | 130 ++++++++++++++++++++++++++++++++++++------------- processes.h | 21 +++++--- sslh-select.c | 103 +++++++++++---------------------------- udp-listener.h | 1 + 5 files changed, 148 insertions(+), 120 deletions(-) diff --git a/Makefile b/Makefile index 6ddc454..45aba8c 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ CC ?= gcc CFLAGS ?=-Wall -DLIBPCRE -g $(CFLAGS_COV) LIBS=-lm -lpcre2-8 -OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o udp-listener.o collection.o gap.o +OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o udp-listener.o collection.o gap.o processes.o CONDITIONAL_TARGETS= @@ -70,21 +70,26 @@ all: sslh $(MAN) echosrv $(CONDITIONAL_TARGETS) version.h: ./genver.sh >version.h -sslh: sslh-fork sslh-select +sslh: sslh-fork sslh-select # sslh-ev $(OBJS): version.h common.h collection.h sslh-conf.h gap.h sslh-conf.c sslh-conf.h: sslhconf.cfg conf2struct sslhconf.cfg -sslh-fork: version.h $(OBJS) sslh-fork.o Makefile - $(CC) $(CFLAGS) $(LDFLAGS) -o sslh-fork sslh-fork.o $(OBJS) $(LIBS) +FORK_OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o udp-listener.o collection.o gap.o +sslh-fork: version.h sslh-fork.o Makefile $(FORK_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o sslh-fork sslh-fork.o $(FORK_OBJS) $(LIBS) #strip sslh-fork sslh-select: version.h $(OBJS) sslh-select.o Makefile $(CC) $(CFLAGS) $(LDFLAGS) -o sslh-select sslh-select.o $(OBJS) $(LIBS) #strip sslh-select +sslh-ev: version.h $(OBJS) sslh-ev.o Makefile + $(CC) $(CFLAGS) $(LDFLAGS) -o sslh-ev sslh-ev.o $(OBJS) $(LIBS) + #strip sslh-select + systemd-sslh-generator: systemd-sslh-generator.o $(CC) $(CFLAGS) $(LDFLAGS) -o systemd-sslh-generator systemd-sslh-generator.o -lconfig diff --git a/processes.c b/processes.c index adeeecc..31b198c 100644 --- a/processes.c +++ b/processes.c @@ -20,7 +20,9 @@ */ +#include "udp-listener.h" #include "processes.h" +#include "probe.h" #include "log.h" /* Removes cnx from probing list */ @@ -36,6 +38,65 @@ void add_probing_cnx(struct loop_info* fd_info, struct connection* cnx) fd_info->num_probing++; } +/* Returns the queue index that contains the specified file descriptor */ +static int active_queue(struct connection* cnx, int fd) +{ + if (cnx->q[0].fd == fd) return 0; + if (cnx->q[1].fd == fd) return 1; + + print_message(msg_int_error, "file descriptor %d not found in connection object\n", fd); + return -1; +} + +int tidy_connection(struct connection *cnx, struct loop_info* fd_info) +{ + int i; + + for (i = 0; i < 2; i++) { + if (cnx->q[i].fd != -1) { + print_message(msg_fd, "closing fd %d\n", cnx->q[i].fd); + + watchers_del_read(fd_info->watchers, cnx->q[i].fd); + watchers_del_write(fd_info->watchers, cnx->q[i].fd); + close(cnx->q[i].fd); + if (cnx->q[i].deferred_data) + free(cnx->q[i].deferred_data); + } + } + collection_remove_cnx(fd_info->collection, cnx); + return 0; +} + + +/* shovels data from active fd to the other + returns after one socket closed or operation would block + */ +static void shovel(struct connection *cnx, int active_fd, struct loop_info* fd_info) +{ + struct queue *read_q, *write_q; + + read_q = &cnx->q[active_fd]; + write_q = &cnx->q[1-active_fd]; + + print_message(msg_fd, "activity on fd%d\n", read_q->fd); + + switch(fd2fd(write_q, read_q)) { + case -1: + case FD_CNXCLOSED: + tidy_connection(cnx, fd_info); + break; + + case FD_STALLED: + watchers_add_write(fd_info->watchers, write_q->fd); + watchers_del_read(fd_info->watchers, read_q->fd); + break; + + default: /* Nothing */ + break; + } +} + + /* Process a connection that is active in read */ static void tcp_read_process(struct loop_info* fd_info, int fd) @@ -107,8 +168,8 @@ void cnx_write_process(struct loop_info* fd_info, int fd) /* If no deferred data is left, stop monitoring the fd * for write, and restart monitoring the other one for reads*/ if (!cnx->q[queue].deferred_data_size) { - watchers_del_write(&fd_info->watchers, cnx->q[queue].fd); - watchers_add_read(&fd_info->watchers, cnx->q[1-queue].fd); + watchers_del_write(fd_info->watchers, cnx->q[queue].fd); + watchers_add_read(fd_info->watchers, cnx->q[1-queue].fd); } } } @@ -145,7 +206,7 @@ static struct connection* accept_new_connection(int listen_socket, struct cnx_co * (For UDP, this means all traffic coming from remote clients) * Returns new file descriptor, or -1 * */ -void cnx_accept_process(struct loop_info* fd_info, struct listen_endpoint* listen_socket) +int cnx_accept_process(struct loop_info* fd_info, struct listen_endpoint* listen_socket) { int fd = listen_socket->socketfd; int type = listen_socket->type; @@ -163,50 +224,22 @@ void cnx_accept_process(struct loop_info* fd_info, struct listen_endpoint* liste break; case SOCK_DGRAM: - new_fd = udp_c2s_forward(fd, fd_info->collection, fd_info->watchers.max_fd); + new_fd = udp_c2s_forward(fd, fd_info->collection, watchers_maxfd(fd_info->watchers)); print_message(msg_fd, "new_fd %d\n", new_fd); if (new_fd == -1) - return; + return -1; break; default: print_message(msg_int_error, "Inconsistent cnx type: %d\n", type); exit(1); - return; } - watchers_add_read(&fd_info->watchers, new_fd); + watchers_add_read(fd_info->watchers, new_fd); + return new_fd; } -/* shovels data from active fd to the other - returns after one socket closed or operation would block - */ -static void shovel(struct connection *cnx, int active_fd, struct loop_info* fd_info) -{ - struct queue *read_q, *write_q; - - read_q = &cnx->q[active_fd]; - write_q = &cnx->q[1-active_fd]; - - print_message(msg_fd, "activity on fd%d\n", read_q->fd); - - switch(fd2fd(write_q, read_q)) { - case -1: - case FD_CNXCLOSED: - tidy_connection(cnx, fd_info); - break; - - case FD_STALLED: - watchers_add_write(&fd_info->watchers, write_q->fd); - watchers_del_read(&fd_info->watchers, read_q->fd); - break; - - default: /* Nothing */ - break; - } -} - /* shovels data from one fd to the other and vice-versa returns after one socket closed */ @@ -293,6 +326,33 @@ static void connect_proxy(struct connection *cnx) } +/* Connect queue 1 of connection to SSL; returns new file descriptor */ +static int connect_queue(struct connection* cnx, + struct loop_info* fd_info) +{ + struct queue *q = &cnx->q[1]; + + q->fd = connect_addr(cnx, cnx->q[0].fd, NON_BLOCKING); + if (q->fd != -1) { + log_connection(NULL, cnx); + flush_deferred(q); + if (q->deferred_data) { + /* + FD_SET(q->fd, &fd_info->watchers->fds_w); + FD_CLR(cnx->q[0].fd, &fd_info->watchers->fds_r); */ + watchers_add_write(fd_info->watchers, q->fd); + watchers_del_read(fd_info->watchers, cnx->q[0].fd); + } + /* FD_SET(q->fd, &fd_info->watchers->fds_r); */ + watchers_add_read(fd_info->watchers, q->fd); + collection_add_fd(fd_info->collection, cnx, q->fd); + return q->fd; + } else { + tidy_connection(cnx, fd_info); + return -1; + } +} + /* Process read activity on a socket in probe state * IN/OUT cnx: connection data, updated if connected diff --git a/processes.h b/processes.h index 845988c..295972b 100644 --- a/processes.h +++ b/processes.h @@ -1,14 +1,13 @@ #ifndef PROCESSES_H #define PROCESSES_H -#ifndef WATCHERS_TYPE_DEFINED -#error Define watchers type before including processes.h -#endif - #include "common.h" #include "collection.h" #include "gap.h" +/* Provided by event loop, sslh-ev or sslh-select, for implementation-dependant + * data */ +typedef struct watchers watchers; /* Global state for a loop */ struct loop_info { @@ -17,7 +16,7 @@ struct loop_info { * select() */ gap_array* probing_list; /* Pointers to cnx that are in probing mode */ - watchers watchers; + watchers* watchers; cnx_collection* collection; /* Collection of connections linked to this loop */ @@ -26,10 +25,20 @@ struct loop_info { void cnx_read_process(struct loop_info* fd_info, int fd); void cnx_write_process(struct loop_info* fd_info, int fd); -void cnx_accept_process(struct loop_info* fd_info, struct listen_endpoint* listen_socket); +int cnx_accept_process(struct loop_info* fd_info, struct listen_endpoint* listen_socket); void probing_read_process(struct connection* cnx, struct loop_info* fd_info); void remove_probing_cnx(struct loop_info* fd_info, struct connection* cnx); void add_probing_cnx(struct loop_info* fd_info, struct connection* cnx); +int tidy_connection(struct connection *cnx, struct loop_info* fd_info); + + +/* These must be declared in the loop handler, sslh-ev or sslh-select */ +void watchers_init(watchers** w); +void watchers_add_read(watchers* w, int fd); +void watchers_del_read(watchers* w, int fd); +void watchers_add_write(watchers* w, int fd); +void watchers_del_write(watchers* w, int fd); +int watchers_maxfd(watchers* w); #endif diff --git a/sslh-select.c b/sslh-select.c index 3a1bb24..33240bb 100644 --- a/sslh-select.c +++ b/sslh-select.c @@ -42,18 +42,19 @@ const char* server_type = "sslh-select"; /* watcher type for a select() loop */ -typedef struct watchers { +struct watchers { fd_set fds_r, fds_w; /* reference fd sets (used to init working copies) */ int max_fd; /* Highest fd number to pass to select() */ -} watchers; +}; #define WATCHERS_TYPE_DEFINED /* To notify processes.h */ #include "processes.h" -void watchers_init(watchers* w) +void watchers_init(watchers** w) { - FD_ZERO(&w->fds_r); - FD_ZERO(&w->fds_w); + *w = malloc(sizeof(**w)); + FD_ZERO(&(*w)->fds_r); + FD_ZERO(&(*w)->fds_w); } void watchers_add_read(watchers* w, int fd) @@ -79,32 +80,22 @@ void watchers_del_write(watchers* w, int fd) { FD_CLR(fd, &w->fds_w); } + +/* To remove after moving UDP lookups to hash table */ +int watchers_maxfd(watchers* w) +{ + return w->max_fd; +} + /* /end watchers */ -static int tidy_connection(struct connection *cnx, struct loop_info* fd_info) -{ - int i; - - for (i = 0; i < 2; i++) { - if (cnx->q[i].fd != -1) { - print_message(msg_fd, "closing fd %d\n", cnx->q[i].fd); - - watchers_del_read(&fd_info->watchers, cnx->q[i].fd); - watchers_del_write(&fd_info->watchers, cnx->q[i].fd); - close(cnx->q[i].fd); - if (cnx->q[i].deferred_data) - free(cnx->q[i].deferred_data); - } - } - collection_remove_cnx(fd_info->collection, cnx); - return 0; -} - /* if fd becomes higher than FD_SETSIZE, things won't work so well with FD_SET * and FD_CLR. Need to drop connections if we go above that limit */ +#warning strange things will happen if more than FD_SETSIZE descriptors are used +/* This test is currently not done */ static int fd_is_in_range(int fd) { if (fd >= FD_SETSIZE) { print_message(msg_system_error, "too many open file descriptor to monitor them all -- dropping connection\n"); @@ -115,40 +106,6 @@ static int fd_is_in_range(int fd) { -/* Connect queue 1 of connection to SSL; returns new file descriptor */ -static int connect_queue(struct connection* cnx, - struct loop_info* fd_info) -{ - struct queue *q = &cnx->q[1]; - - q->fd = connect_addr(cnx, cnx->q[0].fd, NON_BLOCKING); - if ((q->fd != -1) && fd_is_in_range(q->fd)) { - log_connection(NULL, cnx); - flush_deferred(q); - if (q->deferred_data) { - FD_SET(q->fd, &fd_info->watchers.fds_w); - FD_CLR(cnx->q[0].fd, &fd_info->watchers.fds_r); - } - FD_SET(q->fd, &fd_info->watchers.fds_r); - collection_add_fd(fd_info->collection, cnx, q->fd); - return q->fd; - } else { - tidy_connection(cnx, fd_info); - return -1; - } -} - - -/* Returns the queue index that contains the specified file descriptor */ -int active_queue(struct connection* cnx, int fd) -{ - if (cnx->q[0].fd == fd) return 0; - if (cnx->q[1].fd == fd) return 1; - - print_message(msg_int_error, "file descriptor %d not found in connection object\n", fd); - return -1; -} - /* Check all connections to see if a UDP connections has timed out, then free @@ -164,10 +121,10 @@ static void udp_timeouts(struct loop_info* fd_info) time_t next_timeout = INT_MAX; - for (int i = 0; i < fd_info->watchers.max_fd; i++) { + for (int i = 0; i < fd_info->watchers->max_fd; i++) { /* if it's either in read or write set, there is a connection * behind that file descriptor */ - if (FD_ISSET(i, &fd_info->watchers.fds_r) || FD_ISSET(i, &fd_info->watchers.fds_w)) { + if (FD_ISSET(i, &fd_info->watchers->fds_r) || FD_ISSET(i, &fd_info->watchers->fds_w)) { struct connection* cnx = collection_get_cnx_from_fd(fd_info->collection, i); if (cnx) { time_t timeout = udp_timeout(cnx); @@ -175,8 +132,8 @@ static void udp_timeouts(struct loop_info* fd_info) if (cnx && (timeout <= now)) { print_message(msg_fd, "timed out UDP %d\n", cnx->target_sock); close(cnx->target_sock); - watchers_del_read(&fd_info->watchers, i); - watchers_del_write(&fd_info->watchers, i); + watchers_del_read(fd_info->watchers, i); + watchers_del_write(fd_info->watchers, i); collection_remove_cnx(fd_info->collection, cnx); } else { if (timeout < next_timeout) next_timeout = timeout; @@ -216,23 +173,23 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) watchers_init(&fd_info.watchers); for (i = 0; i < num_addr_listen; i++) { - watchers_add_read(&fd_info.watchers, listen_sockets[i].socketfd); + watchers_add_read(fd_info.watchers, listen_sockets[i].socketfd); set_nonblock(listen_sockets[i].socketfd); } - fd_info.collection = collection_init(fd_info.watchers.max_fd); + fd_info.collection = collection_init(fd_info.watchers->max_fd); while (1) { memset(&tv, 0, sizeof(tv)); tv.tv_sec = cfg.timeout; - memcpy(&readfds, &fd_info.watchers.fds_r, sizeof(readfds)); - memcpy(&writefds, &fd_info.watchers.fds_w, sizeof(writefds)); + memcpy(&readfds, &fd_info.watchers->fds_r, sizeof(readfds)); + memcpy(&writefds, &fd_info.watchers->fds_w, sizeof(writefds)); print_message(msg_fd, "selecting... max_fd=%d num_probing=%d\n", - fd_info.watchers.max_fd, fd_info.num_probing); - res = select(fd_info.watchers.max_fd, &readfds, &writefds, + fd_info.watchers->max_fd, fd_info.num_probing); + res = select(fd_info.watchers->max_fd, &readfds, &writefds, NULL, fd_info.num_probing ? &tv : NULL); if (res < 0) perror("select"); @@ -246,17 +203,13 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) if (FD_ISSET(listen_sockets[i].socketfd, &readfds)) { cnx_accept_process(&fd_info, &listen_sockets[i]); - if (!fd_is_in_range(0 /*TODO: retrieve fd */ )) { - /* TODO: drop the connection */ - } - /* don't also process it as a read socket */ FD_CLR(listen_sockets[i].socketfd, &readfds); } } /* Check all sockets for write activity */ - for (i = 0; i < fd_info.watchers.max_fd; i++) { + for (i = 0; i < fd_info.watchers->max_fd; i++) { if (FD_ISSET(i, &writefds)) { cnx_write_process(&fd_info, i); } @@ -278,11 +231,11 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) } /* Check all sockets for read activity */ - for (i = 0; i < fd_info.watchers.max_fd; i++) { + for (i = 0; i < fd_info.watchers->max_fd; i++) { /* Check if it's active AND currently monitored (if a connection * died, it gets tidied, which closes both sockets, but readfs does * not know about that */ - if (FD_ISSET(i, &readfds) && FD_ISSET(i, &fd_info.watchers.fds_r)) { + if (FD_ISSET(i, &readfds) && FD_ISSET(i, &fd_info.watchers->fds_r)) { cnx_read_process(&fd_info, i); } } diff --git a/udp-listener.h b/udp-listener.h index 7b44f10..9439846 100644 --- a/udp-listener.h +++ b/udp-listener.h @@ -2,6 +2,7 @@ #define UDPLISTENER_H #include "collection.h" +#include "common.h" /* UDP listener: upon incoming packet, find where it should go * This is run in its own process and never returns.