Hi,
I've created a patch to Stunnel that reloads all accepting connections from the config file. This will not work for privileged ports in the current implementation. Test at your own risk :)
Feedback welcome.
Best regards, Matthew
diff -urb stunnel-orig/stunnel-4.20/src/stunnel.c stunnel-4.20/src/stunnel.c --- stunnel-orig/stunnel-4.20/src/stunnel.c 2006-11-30 15:47:45.000000000 -0500 +++ stunnel-4.20/src/stunnel.c 2006-12-12 03:34:36.000000000 -0500 @@ -53,12 +53,12 @@ #endif
int volatile num_clients=0; /* Current number of clients */ +int volatile conf_updated=0; /* Conf updated ? */
/* Functions */
#ifndef USE_WIN32 int main(int argc, char* argv[]) { /* execution begins here 8-) */ - main_initialize(argc>1 ? argv[1] : NULL, argc>2 ? argv[2] : NULL);
signal(SIGPIPE, SIG_IGN); /* avoid 'broken pipe' signal */ @@ -78,12 +78,17 @@ } #endif
+char *cfg_arg1 = NULL; +char *cfg_arg2 = NULL; + void main_initialize(char *arg1, char *arg2) { ssl_init(); /* initialize SSL library */ sthreads_init(); /* initialize critical sections & SSL callbacks */ parse_config(arg1, arg2); log_open(); stunnel_info(0); + cfg_arg1 = arg1; + cfg_arg2 = arg2; }
void main_execute(void) { @@ -105,6 +110,7 @@ SOCKADDR_UNION addr; s_poll_set fds; LOCAL_OPTIONS *opt; + int i; get_limits(); s_poll_zero(&fds); #if !defined(USE_WIN32) && !defined(USE_OS2) @@ -173,6 +179,42 @@ accept_connection(opt);
} + if(conf_updated) { + for(i=0; i<fds.nfds; i++) + close(fds.ufds[i].fd); + + /* re-bind local ports */ + for(opt=local_options.next; opt; opt=opt->next) { + if(!opt->option.accept) /* no need to bind this service */ + continue; + memcpy(&addr, &opt->local_addr.addr[0], sizeof(SOCKADDR_UNION)); + if((opt->fd=socket(addr.sa.sa_family, SOCK_STREAM, 0))<0) { + sockerror("local socket"); + exit(1); + } + if(alloc_fd(opt->fd)) + exit(1); + if(set_socket_options(opt->fd, 0)<0) + exit(1); + s_ntop(opt->local_address, &addr); + if(bind(opt->fd, &addr.sa, addr_len(addr))) { + s_log(LOG_ERR, "Error binding %s to %s", + opt->servname, opt->local_address); + sockerror("bind"); + exit(1); + } + s_log(LOG_DEBUG, "%s bound to %s", opt->servname, opt->local_address); + if(listen(opt->fd, 5)) { + sockerror("listen"); + exit(1); + } +#ifdef FD_CLOEXEC + fcntl(opt->fd, F_SETFD, FD_CLOEXEC); /* close socket in child execvp */ +#endif + s_poll_add(&fds, opt->fd, 1, 0); + } + conf_updated = 0; + } } s_log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)"); } @@ -413,9 +455,16 @@ }
static void signal_handler(int sig) { /* signal handler */ + if((sig==SIGHUP) && local_options.next) { /* only in service mode */ + s_log(LOG_NOTICE, "Re-reading configuration"); + parse_config(cfg_arg1, cfg_arg2); + conf_updated = 1; + } + else { s_log(sig==SIGTERM ? LOG_NOTICE : LOG_ERR, "Received signal %d; terminating", sig); exit(3); + } } #endif /* !defined USE_WIN32 */