]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Track TLS sockets in the home server.
authorAlan T. DeKok <aland@freeradius.org>
Thu, 20 Oct 2022 16:08:27 +0000 (12:08 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 20 Oct 2022 17:47:32 +0000 (13:47 -0400)
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.

src/include/realms.h
src/main/listen.c
src/main/process.c
src/main/realms.c

index b845840cd3537f1814db618e31614b4f004f94c4..430fa2f9f01182b9decca1f6b46edac73dbfe646 100644 (file)
@@ -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
index 84fde494d4b3a3e63d329712036a2dcad1243e41..72b7cf06fb4545eda520978ed9947543787a709e 100644 (file)
@@ -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) {
index 45ebcd2dc59a5d763dc9a9a505ead777d2a3d713..2782b07e1333fc9ab2a987dfa38b75c23c8efbaa 100644 (file)
@@ -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
index 497c8991d1eeb0514986e80196dd7a60ae0e05e8..3bc3b6382940cca96410b4c5d8fc8b98965fe502 100644 (file)
@@ -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 */