From: Alan T. DeKok Date: Thu, 20 Oct 2022 16:08:27 +0000 (-0400) Subject: Track TLS sockets in the home server. X-Git-Tag: release_3_2_2~105 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a2c5bc5acc73f524374d3a7f2859d127af6a8abf;p=thirdparty%2Ffreeradius-server.git Track TLS sockets in the home server. So that when the home server is marked dead, we can clean up any blocked sockets. We don't yet have a timer to clean up blocked sockets when the home server is still alive. --- diff --git a/src/include/realms.h b/src/include/realms.h index b845840cd3..430fa2f9f0 100644 --- a/src/include/realms.h +++ b/src/include/realms.h @@ -136,6 +136,7 @@ typedef struct home_server { #ifdef WITH_TLS fr_tls_server_conf_t *tls; uint32_t connect_timeout; + rbtree_t *listeners; #endif #ifdef WITH_STATS diff --git a/src/main/listen.c b/src/main/listen.c index 84fde494d4..72b7cf06fb 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -2985,6 +2985,8 @@ static int _listener_free(rad_listen_t *this) #ifdef HAVE_PTHREAD_H pthread_mutex_destroy(&(sock->mutex)); #endif + + (void) rbtree_deletebydata(sock->home->listeners, this); } #endif /* WITH_TLS */ } @@ -3127,6 +3129,12 @@ rad_listen_t *proxy_new_listener(TALLOC_CTX *ctx, home_server_t *home, uint16_t listen_free(&this); return NULL; } + + if (!rbtree_insert(home->listeners, this)) { + ERROR("(TLS) Failed adding tracking informtion for proxy socket '%s'", buffer); + listen_free(&this); + return NULL; + } } /* @@ -3145,6 +3153,12 @@ rad_listen_t *proxy_new_listener(TALLOC_CTX *ctx, home_server_t *home, uint16_t this->recv = proxy_tls_recv; this->proxy_send = proxy_tls_send; + /* + * Make sure that this listener is associated with the home server. + * + * Since it's TCP+TLS, this socket can only be associated with one home server. + */ + #ifdef WITH_COA_TUNNEL if (home->recv_coa) { RADCLIENT *client; @@ -4063,6 +4077,8 @@ int listen_coa_find(REQUEST *request, char const *key) for (this = fr_hash_table_iter_init(coa_key->ht, &iter); this != NULL; this = fr_hash_table_iter_next(coa_key->ht, &iter)) { + if (this->blocked) continue; + if (this->dead) continue; if (!found) { diff --git a/src/main/process.c b/src/main/process.c index 45ebcd2dc5..2782b07e13 100644 --- a/src/main/process.c +++ b/src/main/process.c @@ -4133,6 +4133,33 @@ void revive_home_server(void *ctx) home->port); } +#ifdef WITH_TLS +static int eol_home_listener(void *ctx, UNUSED void *data) +{ + rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t); + + /* + * The socket isn't blocked, we can still use it. + * + * i.e. the home server is dead for a reason OTHER than + * "all available sockets are blocked". + * + * We can still ping the home server via sockets which + * are writable. + */ + if (!this->blocked) return 0; + + this->status = RAD_LISTEN_STATUS_EOL; + + FD_MUTEX_LOCK(&fd_mutex); + this->next = new_listeners; + new_listeners = this; + FD_MUTEX_UNLOCK(&fd_mutex); + + return 1; /* alway delete from this tree */ +} +#endif + void mark_home_server_dead(home_server_t *home, struct timeval *when, bool down) { int previous_state = home->state; @@ -4146,6 +4173,25 @@ void mark_home_server_dead(home_server_t *home, struct timeval *when, bool down) home->state = HOME_STATE_IS_DEAD; home_trigger(home, "home_server.dead"); +#ifdef WITH_TLS + /* + * If the home server is dead, then close all of the sockets associated with it. + * + * Note that the "EOL listener" code expects to _also_ + * delete the listeners. At which point we end up with a + * mutex locked twice, and bad things happen. The + * solution is to move the listeners to the global + * "waiting for update" list, and then notify ourselves + * that there are listeners waiting to be updated. + */ + if (home->listeners) { + ASSERT_MASTER; + + rbtree_walk(home->listeners, RBTREE_DELETE_ORDER, eol_home_listener, NULL); + radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD); + } +#endif + /* * Administratively down - don't do anything to bring it * up. @@ -5713,6 +5759,18 @@ static void event_new_fd(rad_listen_t *this) buffer, fr_strerror()); fr_exit(1); } + +#ifdef WITH_TLS + /* + * Remove this socket from the list of sockets assocated with this home server. + * + * This MUST be done with the proxy mutex locked! + */ + if (home->tls) { + (void) rbtree_deletebydata(sock->home->listeners, this); + } +#endif + PTHREAD_MUTEX_UNLOCK(&proxy_mutex); #ifdef WITH_COA_TUNNEL diff --git a/src/main/realms.c b/src/main/realms.c index 497c8991d1..3bc3b63829 100644 --- a/src/main/realms.c +++ b/src/main/realms.c @@ -743,6 +743,19 @@ bool realm_home_server_add(home_server_t *home) return true; } +#ifdef WITH_TLS +/* + * The listeners are always different. And we always look them up by *known* listener. And not "find me some random thing". + */ +static int listener_cmp(void const *one, void const *two) +{ + if (one < two) return -1; + if (one > two) return +1; + + return 0; +} +#endif + /** Alloc a new home server defined by a CONF_SECTION * * @param ctx to allocate home_server_t in. @@ -1112,6 +1125,9 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE if (rcode < 0) goto error; if (!home->connect_timeout || (home->connect_timeout > 30)) home->connect_timeout = 30; + + home->listeners = rbtree_create(home, listener_cmp, NULL, RBTREE_FLAG_LOCK); + if (!home->listeners) goto error; } #endif } /* end of parse home server */