]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Add remote-count and remote-entry query via management
authorSelva Nair <selva.nair@gmail.com>
Tue, 7 Sep 2021 22:31:24 +0000 (18:31 -0400)
committerGert Doering <gert@greenie.muc.de>
Tue, 27 Dec 2022 08:30:20 +0000 (09:30 +0100)
Selecting the remote host via the management interface
(management-query-remote) provides a restrictive user
experience as there is no easy way to tabulate all available
remote entries and show a list to the user to choose from.
Fix that.

Two new commands for querying the management interface are added:
(i) remote-entry-count : returns the number of remotes specified
    in the config file. Example result:
       10
       END

(ii) remote-entry-get i [j]: returns the remote entry at index i
     in the form index,host,port,protocol. Or, if j is present
     all entries from index i to j-1 are returned, one per line.

     Example result for i = 2:
        2,ovpn.example.com,1194,udp
        END
     Example result for i = 2, j = 4
        2,ovpn.example.com,1194,udp
        3,ovpn.example.com,443,tcp-client
        END

     remote-entry-get all: returns all remote entries.

v2: use independent callback functions for the two commands
v3: return results as 0 or more lines terminated by END, as done
    for all other similar commands. v1 was fashioned after
    pkcs11-id-count and pkcs11-id-get which uses a format not
    consistent with the rest of the management commands.

See also management-notes.txt

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <20210907223126.8440-1-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg22815.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(cherry picked from commit 125263804701f9e62a5a27587e4ea6afdb21f54d)

Changes.rst
doc/management-notes.txt
src/openvpn/init.c
src/openvpn/manage.c
src/openvpn/manage.h

index 2fb2777d79ffe9c8d7b9b0da8d325fefbb7f08a2..4be3d665b517903b4a9fd66068682f977e28aac0 100644 (file)
@@ -46,6 +46,11 @@ instead: https://github.com/OpenVPN/openvpn/issues
 
 New features
 ------------
+New management commands to enumerate and list remote entries
+    Use ``remote-entry-count`` and ``remote-entry-get``
+    commands from the management interface to get the number of
+    remote entries and the entries themselves.
+
 Keying Material Exporters (RFC 5705) based key generation
     As part of the cipher negotiation OpenVPN will automatically prefer
     the RFC5705 based key material generation to the current custom
index 7bb10c24c1c123e319c6fd91a8c27e235651282c..60d46d64d55a7072fec708a2f5e10ba81642eb05 100644 (file)
@@ -785,6 +785,66 @@ Immediately kill a client instance by CID.
 CID -- client ID.  See documentation for ">CLIENT:" notification for more
 info.
 
+COMMAND -- remote-entry-count (OpenVPN 2.6+ management version > 3)
+-------------------------------------------------------------------
+
+Retrieve available number of remote host/port entries
+
+Example:
+
+  Management interface client sends:
+
+    remote-entry-count
+
+  OpenVPN daemon responds with
+
+  5
+  END
+
+COMMAND -- remote-entry-get (OpenVPN 2.6+ management version > 3)
+------------------------------------------------------------------
+
+  remote-entry-get <start> [<end>]
+
+Retrieve remote entry (host, port and protocol) for index
+<start> or indices from <start> to <end>+1. Alternatively
+<start> = "all" retrieves all remote entries.
+
+Example 1:
+
+  Management interface client sends:
+
+    remote-entry-get 1
+
+  OpenVPN daemon responds with
+
+  1,vpn.example.com,1194,udp
+  END
+
+Example 2:
+
+  Management interface client sends:
+
+    remote-entry-get 1 3
+
+  OpenVPN daemon responds with
+
+    1,vpn.example.com,1194,udp
+    2,vpn.example.net,443,tcp-client
+    END
+
+Example 3:
+  Management interface client sends:
+
+    remote-entry-get all
+
+  OpenVPN daemon with 3 connection entries responds with
+
+    1,vpn.example.com,1194,udp
+    2,vpn.example.com,443,tcp-client
+    3,vpn.example.net,443,udp
+    END
+
 COMMAND -- remote  (OpenVPN AS 2.1.5/OpenVPN 2.3 or higher)
 --------------------------------------------
 
index 3380ed9e64f270b21e272e540ff9924fc99c1e2e..f63422ffc55bf290060bd2f068707d942946dbb6 100644 (file)
@@ -329,6 +329,48 @@ management_callback_send_cc_message(void *arg,
     return status;
 }
 
+static unsigned int
+management_callback_remote_entry_count(void *arg)
+{
+    assert(arg);
+    struct context *c = (struct context *) arg;
+    struct connection_list *l = c->options.connection_list;
+
+    return l->len;
+}
+
+static bool
+management_callback_remote_entry_get(void *arg, unsigned int index, char **remote)
+{
+    assert(arg);
+    assert(remote);
+
+    struct context *c = (struct context *) arg;
+    struct connection_list *l = c->options.connection_list;
+    bool ret = true;
+
+    if (index < l->len)
+    {
+        struct connection_entry *ce = l->array[index];
+        const char *proto = proto2ascii(ce->proto, ce->af, false);
+
+        /* space for output including 2 commas and a nul */
+        int len = strlen(ce->remote) + strlen(ce->remote_port) + strlen(proto) + 2 + 1;
+        char *out = malloc(len);
+        check_malloc_return(out);
+
+        openvpn_snprintf(out, len, "%s,%s,%s", ce->remote, ce->remote_port, proto);
+        *remote = out;
+    }
+    else
+    {
+        ret = false;
+        msg(M_WARN, "Out of bounds index in management query for remote entry: index = %u", index);
+    }
+
+    return ret;
+}
+
 static bool
 management_callback_remote_cmd(void *arg, const char **p)
 {
@@ -4085,6 +4127,8 @@ init_management_callback_p2p(struct context *c)
 #ifdef TARGET_ANDROID
         cb.network_change = management_callback_network_change;
 #endif
+        cb.remote_entry_count = management_callback_remote_entry_count;
+        cb.remote_entry_get = management_callback_remote_entry_get;
         management_set_callback(management, &cb);
     }
 #endif
index 5465b7e9bc084a1d277bdab8fcd4a76e15ce69e5..aedd9ca8baf82592b37e00f97d230a3bfa413df6 100644 (file)
@@ -96,6 +96,8 @@ man_help(void)
     msg(M_CLIENT, "net                    : (Windows only) Show network info and routing table.");
     msg(M_CLIENT, "password type p        : Enter password p for a queried OpenVPN password.");
     msg(M_CLIENT, "remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP.");
+    msg(M_CLIENT, "remote-entry-count     : Get number of available remote entries.");
+    msg(M_CLIENT, "remote-entry-get  i|all [j]: Get remote entry at index = i to to j-1 or all.");
     msg(M_CLIENT, "proxy type [host port flags] : Enter dynamic proxy server info.");
     msg(M_CLIENT, "pid                    : Show process ID of the current OpenVPN process.");
 #ifdef ENABLE_PKCS11
@@ -841,6 +843,63 @@ man_pkcs11_id_get(struct management *man, const int index)
 
 #endif /* ifdef ENABLE_PKCS11 */
 
+static void
+man_remote_entry_count(struct management *man)
+{
+    unsigned count = 0;
+    if (man->persist.callback.remote_entry_count)
+    {
+        count = (*man->persist.callback.remote_entry_count)(man->persist.callback.arg);
+        msg(M_CLIENT, "%u", count);
+        msg(M_CLIENT, "END");
+    }
+    else
+    {
+        msg(M_CLIENT, "ERROR: The remote-entry-count command is not supported by the current daemon mode");
+    }
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static void
+man_remote_entry_get(struct management *man, const char *p1, const char *p2)
+{
+    ASSERT(p1);
+
+    if (man->persist.callback.remote_entry_get
+        && man->persist.callback.remote_entry_count)
+    {
+        bool res;
+        unsigned int from, to;
+        unsigned int count = (*man->persist.callback.remote_entry_count)(man->persist.callback.arg);
+
+        from = (unsigned int) atoi(p1);
+        to = p2 ? (unsigned int) atoi(p2) : from + 1;
+
+        if (!strcmp(p1, "all"))
+        {
+            from = 0;
+            to = count;
+        }
+
+        for (unsigned int i = from; i < min(to, count); i++)
+        {
+            char *remote = NULL;
+            res = (*man->persist.callback.remote_entry_get)(man->persist.callback.arg, i, &remote);
+            if (res && remote)
+            {
+                msg(M_CLIENT, "%u,%s", i, remote);
+            }
+            free(remote);
+        }
+        msg(M_CLIENT, "END");
+    }
+    else
+    {
+        msg(M_CLIENT, "ERROR: The remote-entry command is not supported by the current daemon mode");
+    }
+}
+
 static void
 man_hold(struct management *man, const char *cmd)
 {
@@ -1563,6 +1622,17 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha
         }
     }
 #endif
+    else if (streq(p[0], "remote-entry-count"))
+    {
+        man_remote_entry_count(man);
+    }
+    else if (streq(p[0], "remote-entry-get"))
+    {
+        if (man_need(man, p, 1, MN_AT_LEAST))
+        {
+            man_remote_entry_get(man, p[1], p[2]);
+        }
+    }
     else if (streq(p[0], "proxy"))
     {
         if (man_need(man, p, 1, MN_AT_LEAST))
index 30291e42b93ee9bc5c6f0a30720cc6dad5e69c84..b98cc06180d4f09a8fd5cd9ab38d1b9de87765da 100644 (file)
@@ -31,7 +31,7 @@
 #include "socket.h"
 #include "mroute.h"
 
-#define MANAGEMENT_VERSION                      3
+#define MANAGEMENT_VERSION                      4
 #define MANAGEMENT_N_PASSWORD_RETRIES           3
 #define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE   100
 #define MANAGEMENT_ECHO_BUFFER_SIZE           100
@@ -181,6 +181,8 @@ struct management_callback
 #ifdef TARGET_ANDROID
     int (*network_change)(void *arg, bool samenetwork);
 #endif
+    unsigned int (*remote_entry_count)(void *arg);
+    bool (*remote_entry_get)(void *arg, unsigned int index, char **remote);
 };
 
 /*