From eb1b303d56cd577c6c56e22cbb403a4470cd2920 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Wed, 10 Feb 2016 22:57:16 +0000 Subject: [PATCH] ircd: support restarting ssld processes Add REHASH SSLD (admins only) that starts new sslds and marks the existing ones as inactive until all their clients disconnect. Very useful whenever the SSL library has a vulnerability because new connections can use a new version of the library without disconnecting existing clients/servers. Add STATS S (admins only) to list ssld processes, status, and client count. --- help/opers/rehash | 1 + help/opers/stats | 1 + include/sslproc.h | 8 ++++++++ ircd/sslproc.c | 50 +++++++++++++++++++++++++++++++++++++++++----- modules/m_rehash.c | 11 ++++++++++ modules/m_stats.c | 22 ++++++++++++++++++++ 6 files changed, 88 insertions(+), 5 deletions(-) diff --git a/help/opers/rehash b/help/opers/rehash index 2226499d..a8c062a4 100644 --- a/help/opers/rehash +++ b/help/opers/rehash @@ -11,6 +11,7 @@ ircd.conf file. NICKDELAY - Clears delayed nicks OMOTD - Re-reads Oper MOTD file REJECTCACHE - Clears the reject cache + SSLD - Restarts the ssld processes TDLINES - Clears temporary D Lines THROTTLES - Clears throttled IP addresses TKLINES - Clears temporary K Lines diff --git a/help/opers/stats b/help/opers/stats index fb7bb347..c109b9da 100644 --- a/help/opers/stats +++ b/help/opers/stats @@ -32,6 +32,7 @@ X f - Shows File Descriptors * q - Shows temporary and global resv'd nicks and channels * Q - Shows resv'd nicks and channels * r - Shows resource usage by ircd +X S - Shows ssld processes * t - Shows generic server stats * U - Shows shared blocks (Old U: lines) u - Shows server uptime diff --git a/include/sslproc.h b/include/sslproc.h index 838bff75..b152d7eb 100644 --- a/include/sslproc.h +++ b/include/sslproc.h @@ -27,7 +27,14 @@ struct _ssl_ctl; typedef struct _ssl_ctl ssl_ctl_t; +enum ssld_status { + SSLD_ACTIVE, + SSLD_SHUTDOWN, + SSLD_DEAD, +}; + void init_ssld(void); +void restart_ssld(void); int start_ssldaemon(int count, const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, const char *ssl_cipher_list); ssl_ctl_t *start_ssld_accept(rb_fde_t *sslF, rb_fde_t *plainF, uint32_t id); ssl_ctl_t *start_ssld_connect(rb_fde_t *sslF, rb_fde_t *plainF, uint32_t id); @@ -35,6 +42,7 @@ void start_zlib_session(void *data); void send_new_ssl_certs(const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, const char *ssl_cipher_list); void ssld_decrement_clicount(ssl_ctl_t *ctl); int get_ssld_count(void); +void ssld_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum ssld_status status), void *data); #endif diff --git a/ircd/sslproc.c b/ircd/sslproc.c index 3b4be1a8..4fad6dc4 100644 --- a/ircd/sslproc.c +++ b/ircd/sslproc.c @@ -66,6 +66,7 @@ struct _ssl_ctl pid_t pid; rb_dlink_list readq; rb_dlink_list writeq; + uint8_t shutdown; uint8_t dead; }; @@ -150,6 +151,31 @@ static time_t last_spin; static int ssld_wait = 0; +void +restart_ssld(void) +{ + rb_dlink_node *ptr, *next; + ssl_ctl_t *ctl; + + RB_DLINK_FOREACH_SAFE(ptr, next, ssl_daemons.head) + { + ctl = ptr->data; + if(ctl->dead) + continue; + if(ctl->shutdown) + continue; + ctl->shutdown = 1; + ssld_count--; + if(!ctl->cli_count) + { + rb_kill(ctl->pid, SIGKILL); + free_ssl_daemon(ctl); + } + } + + start_ssldaemon(ServerInfo.ssld_count, ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list); +} + static void ssl_killall(void) { @@ -161,8 +187,11 @@ ssl_killall(void) if(ctl->dead) continue; ctl->dead = 1; - ssld_count--; + if(!ctl->shutdown) + ssld_count--; rb_kill(ctl->pid, SIGKILL); + if(!ctl->cli_count) + free_ssl_daemon(ctl); } } @@ -173,11 +202,15 @@ ssl_dead(ssl_ctl_t * ctl) return; ctl->dead = 1; - ssld_count--; rb_kill(ctl->pid, SIGKILL); /* make sure the process is really gone */ - ilog(L_MAIN, "ssld helper died - attempting to restart"); - sendto_realops_snomask(SNO_GENERAL, L_ALL, "ssld helper died - attempting to restart"); - start_ssldaemon(1, ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list); + + if(!ctl->shutdown) + { + ssld_count--; + ilog(L_MAIN, "ssld helper died - attempting to restart"); + sendto_realops_snomask(SNO_GENERAL, L_ALL, "ssld helper died - attempting to restart"); + start_ssldaemon(1, ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list); + } } static void @@ -541,6 +574,8 @@ which_ssld(void) ctl = ptr->data; if(ctl->dead) continue; + if(ctl->shutdown) + continue; if(lowest == NULL) { lowest = ctl; @@ -737,6 +772,11 @@ ssld_decrement_clicount(ssl_ctl_t * ctl) return; ctl->cli_count--; + if(ctl->shutdown && !ctl->cli_count) + { + ctl->dead = 1; + rb_kill(ctl->pid, SIGKILL); + } if(ctl->dead && !ctl->cli_count) { free_ssl_daemon(ctl); diff --git a/modules/m_rehash.c b/modules/m_rehash.c index 005ef352..dae84c2c 100644 --- a/modules/m_rehash.c +++ b/modules/m_rehash.c @@ -44,6 +44,7 @@ #include "hash.h" #include "cache.h" #include "irc_radixtree.h" +#include "sslproc.h" static int mo_rehash(struct Client *, struct Client *, int, const char **); static int me_rehash(struct Client *, struct Client *, int, const char **); @@ -85,6 +86,15 @@ rehash_dns(struct Client *source_p) restart_authd(); } +static void +rehash_ssld(struct Client *source_p) +{ + sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s is restarting ssld", + get_oper_name(source_p)); + + restart_ssld(); +} + static void rehash_motd(struct Client *source_p) { @@ -276,6 +286,7 @@ static struct hash_commands rehash_commands[] = { {"BANS", rehash_bans_loc }, {"DNS", rehash_dns }, + {"SSLD", rehash_ssld }, {"MOTD", rehash_motd }, {"OMOTD", rehash_omotd }, {"TKLINES", rehash_tklines }, diff --git a/modules/m_stats.c b/modules/m_stats.c index 21631e15..4fccb5e9 100644 --- a/modules/m_stats.c +++ b/modules/m_stats.c @@ -49,6 +49,7 @@ #include "reject.h" #include "whowas.h" #include "irc_radixtree.h" +#include "sslproc.h" static int m_stats (struct Client *, struct Client *, int, const char **); @@ -109,6 +110,7 @@ static void stats_operedup(struct Client *); static void stats_ports(struct Client *); static void stats_tresv(struct Client *); static void stats_resv(struct Client *); +static void stats_ssld(struct Client *); static void stats_usage(struct Client *); static void stats_tstats(struct Client *); static void stats_uptime(struct Client *); @@ -162,6 +164,8 @@ static struct StatsStruct stats_cmd_table[] = { {'Q', stats_resv, 1, 0, }, {'r', stats_usage, 1, 0, }, {'R', stats_usage, 1, 0, }, + {'s', stats_ssld, 1, 1, }, + {'S', stats_ssld, 1, 1, }, {'t', stats_tstats, 1, 0, }, {'T', stats_tstats, 1, 0, }, {'u', stats_uptime, 0, 0, }, @@ -884,6 +888,24 @@ stats_resv(struct Client *source_p) } } +static void +stats_ssld_foreach(void *data, pid_t pid, int cli_count, enum ssld_status status) +{ + struct Client *source_p = data; + + sendto_one_numeric(source_p, RPL_STATSDEBUG, + "S :%u %c %u", + pid, + status == SSLD_DEAD ? 'D' : (status == SSLD_SHUTDOWN ? 'S' : 'A'), + cli_count); +} + +static void +stats_ssld(struct Client *source_p) +{ + ssld_foreach_info(stats_ssld_foreach, source_p); +} + static void stats_usage (struct Client *source_p) {