]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Improve shuffling algorithm of connection list
authorShuji Furukawa <shujifurukawa1213@gmail.com>
Mon, 18 Nov 2024 14:20:20 +0000 (23:20 +0900)
committerGert Doering <gert@greenie.muc.de>
Sun, 29 Dec 2024 12:22:34 +0000 (13:22 +0100)
This patch implements the Fisher-Yates shuffle algorithm to ensure that all
permutations of the connection target list are generated with equal
probability, eliminating biases present in the previous shuffling method. In
the Fisher-Yates algorithm, there's only one way to obtain each permutation
through a series of element swaps, so all permutations occur with equal
probability in theory.

Signed-off-by: Shuji Furukawa <shujifurukawa1213@gmail.com>
Acked-by: Antonio Quartulli <antonio@openvpn.net>
Message-Id: <20241118142019.31045-1-shujifurukawa1213@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg29837.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/init.c

index 7145495cefafdc30701f51ef647c9a57372af295..a23cb24779743a3ae952805e643f44924c594c4f 100644 (file)
@@ -467,7 +467,15 @@ ce_management_query_remote(struct context *c)
 #endif /* ENABLE_MANAGEMENT */
 
 /*
- * Initialize and possibly randomize connection list.
+ * Initialize and possibly randomize the connection list.
+ *
+ * Applies the Fisher-Yates shuffle algorithm to ensure all permutations
+ * are equally probable, thereby eliminating shuffling bias.
+ *
+ * The algorithm randomly selects an element from the unshuffled portion
+ * and places it at position i. There's only one way to obtain each
+ * permutation through these swaps. This guarantees that each permutation
+ * occurs with equal probability in theory.
  */
 static void
 init_connection_list(struct context *c)
@@ -478,9 +486,9 @@ init_connection_list(struct context *c)
     if (c->options.remote_random)
     {
         int i;
-        for (i = 0; i < l->len; ++i)
+        for (i = l->len - 1; i > 0; --i)
         {
-            const int j = get_random() % l->len;
+            const int j = get_random() % (i + 1);
             if (i != j)
             {
                 struct connection_entry *tmp;