From 2544f20bdfeb351ec017445a121fbbc8259210d5 Mon Sep 17 00:00:00 2001 From: Oleg Oshmyan Date: Sat, 9 Sep 2017 00:25:30 +0300 Subject: [PATCH] sslh-select: support forking for particular protocols To keep the code simple, use the same event loop in the child process as in the parent process but close all irrelevant file descriptors. --- probe.c | 20 ++++++++++---------- probe.h | 1 + sslh-main.c | 6 ++++-- sslh-select.c | 20 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/probe.c b/probe.c index 9b4a63e..ed05f50 100644 --- a/probe.c +++ b/probe.c @@ -45,16 +45,16 @@ static int is_true(const char *p, int len, struct proto* proto) { return 1; } /* Table of protocols that have a built-in probe */ static struct proto builtins[] = { - /* description service saddr log_level keepalive probe */ - { "ssh", "sshd", NULL, 1, 0, is_ssh_protocol}, - { "openvpn", NULL, NULL, 1, 0, is_openvpn_protocol }, - { "tinc", NULL, NULL, 1, 0, is_tinc_protocol }, - { "xmpp", NULL, NULL, 1, 0, is_xmpp_protocol }, - { "http", NULL, NULL, 1, 0, is_http_protocol }, - { "ssl", NULL, NULL, 1, 0, is_tls_protocol }, - { "tls", NULL, NULL, 1, 0, is_tls_protocol }, - { "adb", NULL, NULL, 1, 0, is_adb_protocol }, - { "anyprot", NULL, NULL, 1, 0, is_true } + /* description service saddr log_level keepalive fork probe */ + { "ssh", "sshd", NULL, 1, 0, 1, is_ssh_protocol}, + { "openvpn", NULL, NULL, 1, 0, 1, is_openvpn_protocol }, + { "tinc", NULL, NULL, 1, 0, 1, is_tinc_protocol }, + { "xmpp", NULL, NULL, 1, 0, 0, is_xmpp_protocol }, + { "http", NULL, NULL, 1, 0, 0, is_http_protocol }, + { "ssl", NULL, NULL, 1, 0, 0, is_tls_protocol }, + { "tls", NULL, NULL, 1, 0, 0, is_tls_protocol }, + { "adb", NULL, NULL, 1, 0, 0, is_adb_protocol }, + { "anyprot", NULL, NULL, 1, 0, 0, is_true } }; static struct proto *protocols; diff --git a/probe.h b/probe.h index 8c576a2..2476542 100644 --- a/probe.h +++ b/probe.h @@ -24,6 +24,7 @@ struct proto { * 1: Log incoming connection */ int keepalive; /* 0: No keepalive ; 1: Set Keepalive for this connection */ + int fork; /* 0: Connection can run within shared process ; 1: Separate process required for this connection */ /* function to probe that protocol; parameters are buffer and length * containing the data to probe, and a pointer to the protocol structure */ diff --git a/sslh-main.c b/sslh-main.c index e2a4e34..2af35b8 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -123,14 +123,15 @@ static void printsettings(void) for (p = get_first_protocol(); p; p = p->next) { fprintf(stderr, - "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s]\n", + "%s addr: %s. libwrap service: %s log_level: %d family %d %d [%s] [%s]\n", p->description, sprintaddr(buf, sizeof(buf), p->saddr), p->service, p->log_level, p->saddr->ai_family, p->saddr->ai_addr->sa_family, - p->keepalive ? "keepalive" : ""); + p->keepalive ? "keepalive" : "", + p->fork ? "fork" : ""); } fprintf(stderr, "listening on:\n"); for (a = addr_listen; a; a = a->ai_next) { @@ -307,6 +308,7 @@ static int config_protocols(config_t *config, struct proto **prots) p->description = name; config_setting_lookup_string(prot, "service", &(p->service)); config_setting_lookup_bool(prot, "keepalive", &p->keepalive); + config_setting_lookup_bool(prot, "fork", &p->fork); if (config_setting_lookup_int(prot, "log_level", &p->log_level) == CONFIG_FALSE) { p->log_level = 1; diff --git a/sslh-select.c b/sslh-select.c index db05645..de1cb03 100644 --- a/sslh-select.c +++ b/sslh-select.c @@ -27,6 +27,8 @@ const char* server_type = "sslh-select"; +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + /* cnx_num_alloc is the number of connection to allocate at once (at start-up, * and then every time we get too many simultaneous connections: e.g. start * with 100 slots, then if we get more than 100 connections allocate another @@ -319,6 +321,24 @@ void main_loop(int listen_sockets[], int num_addr_listen) check_access_rights(in_socket, cnx[i].proto->service)) { tidy_connection(&cnx[i], &fds_r, &fds_w); res = -1; + } else if (cnx[i].proto->fork) { + if (!fork()) { + struct connection *cnx_i = &cnx[i]; + for (i = 0; i < num_addr_listen; i++) { + FD_CLR(listen_sockets[i], &fds_r); + close(listen_sockets[i]); + } + num_addr_listen = 0; + for (i = 0; i < num_cnx; i++) + if (&cnx[i] != cnx_i) + tidy_connection(&cnx[i], &fds_r, &fds_w); + num_probing = 0; + res = connect_queue(cnx_i, &fds_r, &fds_w); + max_fd = MAX(cnx_i->q[0].fd, cnx_i->q[1].fd) + 1; + } else { + tidy_connection(&cnx[i], &fds_r, &fds_w); + res = -1; + } } else { res = connect_queue(&cnx[i], &fds_r, &fds_w); }