From c3d019284d5c6691c7e5b2c8f5e4ba57569f162f Mon Sep 17 00:00:00 2001 From: yrutschle Date: Sat, 24 Apr 2021 10:31:41 +0200 Subject: [PATCH] made echosrv independant from common.o and with its own configuration --- Makefile | 9 ++- echosrv.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++-- echosrv.cfg | 37 +++++++++++++ 3 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 echosrv.cfg diff --git a/Makefile b/Makefile index 5bc6d8f..57a9fc2 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ sslh: sslh-fork sslh-select $(OBJS): version.h common.h collection.h sslh-conf.h gap.h -sslh-conf.c: sslhconf.cfg +sslh-conf.c sslh-conf.h: sslhconf.cfg conf2struct sslhconf.cfg sslh-fork: version.h $(OBJS) sslh-fork.o Makefile @@ -94,8 +94,11 @@ sslh-select: version.h $(OBJS) sslh-select.o Makefile systemd-sslh-generator: systemd-sslh-generator.o $(CC) $(CFLAGS) $(LDFLAGS) -o systemd-sslh-generator systemd-sslh-generator.o -lconfig -echosrv: version.h $(OBJS) echosrv.o - $(CC) $(CFLAGS) $(LDFLAGS) -o echosrv echosrv.o sslh-conf.o probe.o common.o tls.o argtable3.o $(LIBS) +echosrv-conf.c echosrv-conf.h: echosrv.cfg + conf2struct echosrv.cfg + +echosrv: version.h echosrv-conf.c echosrv.o echosrv-conf.o argtable3.o + $(CC) $(CFLAGS) $(LDFLAGS) -o echosrv echosrv.o echosrv-conf.o argtable3.o $(LIBS) $(MAN): sslh.pod Makefile pod2man --section=8 --release=$(VERSION) --center=" " sslh.pod | gzip -9 - > $(MAN) diff --git a/echosrv.c b/echosrv.c index 7529fb1..3ab71a1 100644 --- a/echosrv.c +++ b/echosrv.c @@ -27,9 +27,13 @@ #include #include #include +#include +#define cfg sslhcfg #include "common.h" -#include "sslh-conf.h" +#undef cfg + +#include "echosrv-conf.h" /* Added to make the code compilable under CYGWIN * */ @@ -37,7 +41,24 @@ #define SA_NOCLDWAIT 0 #endif -const char* server_type = "echsrv"; /* keep setup_syslog happy */ +struct echocfg_item cfg; + +void check_res_dump(int res, struct addrinfo *addr, char* syscall) +{ + char buf[NI_MAXHOST]; + + if (res == -1) { + if (addr) + fprintf(stderr, "error %s:%s: %s\n", + sprintaddr(buf, sizeof(buf), addr), + syscall, + strerror(errno)); + else + fprintf(stderr, "Dying just because\n"); + + exit(1); + } +} void start_echo(int fd) { @@ -80,7 +101,7 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) while (1) { in_socket = accept(listen_sockets[i].socketfd, 0, 0); - if (cfg.verbose) fprintf(stderr, "accepted fd %d\n", in_socket); + CHECK_RES_DIE(in_socket, "accept"); if (!fork()) { @@ -95,6 +116,132 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) wait(NULL); } +/* Following is a number of utility functions copied from common.c: linking + * against common.o directly means echosrv has to work with sslh config struct, + * which makes it all too awkward */ + +/* simplified from common.c */ +char* sprintaddr(char* buf, size_t size, struct addrinfo *a) +{ + char host[NI_MAXHOST], serv[NI_MAXSERV]; + int res; + + res = getnameinfo(a->ai_addr, a->ai_addrlen, + host, sizeof(host), + serv, sizeof(serv), + 0 ); + + if (res) { + /* Name resolution failed: do it numerically instead */ + res = getnameinfo(a->ai_addr, a->ai_addrlen, + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); + /* should not fail but... */ + if (res) { + strcpy(host, "?"); + strcpy(serv, "?"); + } + } + + snprintf(buf, size, "%s:%s", host, serv); + + return buf; +} + + +/* simplified from common.c */ +int listen_single_addr(struct addrinfo* addr, int keepalive, int udp) +{ + struct sockaddr_storage *saddr; + int sockfd, one, res; + + saddr = (struct sockaddr_storage*)addr->ai_addr; + + sockfd = socket(saddr->ss_family, udp ? SOCK_DGRAM : SOCK_STREAM, 0); + check_res_dump(sockfd, addr, "socket"); + + one = 1; + res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)); + check_res_dump(res, addr, "setsockopt(SO_REUSEADDR)"); + + if (addr->ai_addr->sa_family == AF_INET6) { + res = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)); + check_res_dump(res, addr, "setsockopt(IPV6_V6ONLY)"); + } + + res = bind(sockfd, addr->ai_addr, addr->ai_addrlen); + check_res_dump(res, addr, "bind"); + + if (!udp) { + res = listen (sockfd, 50); + check_res_dump(res, addr, "listen"); + } + + return sockfd; +} + +/* simplified from common.c */ +int resolve_split_name(struct addrinfo **out, char* host, char* serv) +{ + struct addrinfo hint; + char *end; + int res; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + + /* If it is a RFC-Compliant IPv6 address ("[1234::12]:443"), remove brackets + * around IP address */ + if (host[0] == '[') { + end = strrchr(host, ']'); + if (!end) { + fprintf(stderr, "%s: no closing bracket in IPv6 address?\n", host); + return -1; + } + host++; /* skip first bracket */ + *end = 0; /* remove last bracket */ + } + + res = getaddrinfo(host, serv, &hint, out); + + if (res) + fprintf(stderr, "%s `%s:%s'\n", gai_strerror(res), host, serv); + return res; +} + +int start_listen_sockets(struct listen_endpoint *sockfd[]) +{ + struct addrinfo *addr, *start_addr; + char buf[NI_MAXHOST]; + int i, res; + int num_addr = 0, keepalive = 0, udp = 0; + + *sockfd = NULL; + + fprintf(stderr, "Listening to:\n"); + + for (i = 0; i < cfg.listen_len; i++) { + udp = cfg.udp; + + + res = resolve_split_name(&start_addr, cfg.listen[i].host, cfg.listen[i].port); + if (res) exit(4); + + for (addr = start_addr; addr; addr = addr->ai_next) { + num_addr++; + *sockfd = realloc(*sockfd, num_addr * sizeof(*sockfd)); + (*sockfd)[num_addr-1].socketfd = listen_single_addr(addr, keepalive, udp); + (*sockfd)[num_addr-1].type = udp ? SOCK_DGRAM : SOCK_STREAM; + fprintf(stderr, "%d:\t%s\n", (*sockfd)[num_addr-1].socketfd, sprintaddr(buf, sizeof(buf), addr)); + } + freeaddrinfo(start_addr); + } + + return num_addr; +} + int main(int argc, char *argv[]) { @@ -105,10 +252,10 @@ int main(int argc, char *argv[]) struct listen_endpoint *listen_sockets; memset(&cfg, 0, sizeof(cfg)); - if (sslhcfg_cl_parse(argc, argv, &cfg)) + if (echocfg_cl_parse(argc, argv, &cfg)) exit(1); - sslhcfg_fprint(stdout, &cfg, 0); + echocfg_fprint(stdout, &cfg, 0); num_addr_listen = start_listen_sockets(&listen_sockets); diff --git a/echosrv.cfg b/echosrv.cfg new file mode 100644 index 0000000..4ff5dac --- /dev/null +++ b/echosrv.cfg @@ -0,0 +1,37 @@ +# conf2struct for echosrv + +header: "echosrv-conf.h"; +parser: "echosrv-conf.c"; + +printer: true; + +conffile_option: ("F", "config"); + +config: { + name: "echocfg", + type: "list", + items: ( + {name: "udp", type: "bool"; default: false; }, + {name: "prefix", type: "string"; }, + { name: "listen", + type: "list", + items: ( + { name: "host"; type: "string"; var: true; }, + { name: "port"; type: "string"; var: true; } + ) + } + ) +} + + +cl_groups: ( + { name: "listen"; pattern: "(.+):(\w+)"; description: "Listen on host:port"; + short: "p"; argdesc: ""; + list: "listen"; + # no override, this just adds to the list (and thus can be specified several times) + targets: ( + { path: "host"; value: "$1" }, + { path: "port"; value: "$2" } + ); + } +)