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)
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
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)
--------------------------------------------
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)
{
#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
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
#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)
{
}
}
#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))
#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
#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);
};
/*