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>
| ... | ... |
@@ -10,6 +10,11 @@ instead: https://github.com/OpenVPN/openvpn/issues |
| 10 | 10 |
|
| 11 | 11 |
New features |
| 12 | 12 |
------------ |
| 13 |
+New management commands to enumerate and list remote entries |
|
| 14 |
+ Use ``remote-entry-count`` and ``remote-entry-get`` |
|
| 15 |
+ commands from the management interface to get the number of |
|
| 16 |
+ remote entries and the entries themselves. |
|
| 17 |
+ |
|
| 13 | 18 |
Keying Material Exporters (RFC 5705) based key generation |
| 14 | 19 |
As part of the cipher negotiation OpenVPN will automatically prefer |
| 15 | 20 |
the RFC5705 based key material generation to the current custom |
| ... | ... |
@@ -785,6 +785,66 @@ Immediately kill a client instance by CID. |
| 785 | 785 |
CID -- client ID. See documentation for ">CLIENT:" notification for more |
| 786 | 786 |
info. |
| 787 | 787 |
|
| 788 |
+COMMAND -- remote-entry-count (OpenVPN 2.6+ management version > 3) |
|
| 789 |
+------------------------------------------------------------------- |
|
| 790 |
+ |
|
| 791 |
+Retrieve available number of remote host/port entries |
|
| 792 |
+ |
|
| 793 |
+Example: |
|
| 794 |
+ |
|
| 795 |
+ Management interface client sends: |
|
| 796 |
+ |
|
| 797 |
+ remote-entry-count |
|
| 798 |
+ |
|
| 799 |
+ OpenVPN daemon responds with |
|
| 800 |
+ |
|
| 801 |
+ 5 |
|
| 802 |
+ END |
|
| 803 |
+ |
|
| 804 |
+COMMAND -- remote-entry-get (OpenVPN 2.6+ management version > 3) |
|
| 805 |
+------------------------------------------------------------------ |
|
| 806 |
+ |
|
| 807 |
+ remote-entry-get <start> [<end>] |
|
| 808 |
+ |
|
| 809 |
+Retrieve remote entry (host, port and protocol) for index |
|
| 810 |
+<start> or indices from <start> to <end>+1. Alternatively |
|
| 811 |
+<start> = "all" retrieves all remote entries. |
|
| 812 |
+ |
|
| 813 |
+Example 1: |
|
| 814 |
+ |
|
| 815 |
+ Management interface client sends: |
|
| 816 |
+ |
|
| 817 |
+ remote-entry-get 1 |
|
| 818 |
+ |
|
| 819 |
+ OpenVPN daemon responds with |
|
| 820 |
+ |
|
| 821 |
+ 1,vpn.example.com,1194,udp |
|
| 822 |
+ END |
|
| 823 |
+ |
|
| 824 |
+Example 2: |
|
| 825 |
+ |
|
| 826 |
+ Management interface client sends: |
|
| 827 |
+ |
|
| 828 |
+ remote-entry-get 1 3 |
|
| 829 |
+ |
|
| 830 |
+ OpenVPN daemon responds with |
|
| 831 |
+ |
|
| 832 |
+ 1,vpn.example.com,1194,udp |
|
| 833 |
+ 2,vpn.example.net,443,tcp-client |
|
| 834 |
+ END |
|
| 835 |
+ |
|
| 836 |
+Example 3: |
|
| 837 |
+ Management interface client sends: |
|
| 838 |
+ |
|
| 839 |
+ remote-entry-get all |
|
| 840 |
+ |
|
| 841 |
+ OpenVPN daemon with 3 connection entries responds with |
|
| 842 |
+ |
|
| 843 |
+ 1,vpn.example.com,1194,udp |
|
| 844 |
+ 2,vpn.example.com,443,tcp-client |
|
| 845 |
+ 3,vpn.example.net,443,udp |
|
| 846 |
+ END |
|
| 847 |
+ |
|
| 788 | 848 |
COMMAND -- remote (OpenVPN AS 2.1.5/OpenVPN 2.3 or higher) |
| 789 | 849 |
-------------------------------------------- |
| 790 | 850 |
|
| ... | ... |
@@ -329,6 +329,48 @@ management_callback_send_cc_message(void *arg, |
| 329 | 329 |
return status; |
| 330 | 330 |
} |
| 331 | 331 |
|
| 332 |
+static unsigned int |
|
| 333 |
+management_callback_remote_entry_count(void *arg) |
|
| 334 |
+{
|
|
| 335 |
+ assert(arg); |
|
| 336 |
+ struct context *c = (struct context *) arg; |
|
| 337 |
+ struct connection_list *l = c->options.connection_list; |
|
| 338 |
+ |
|
| 339 |
+ return l->len; |
|
| 340 |
+} |
|
| 341 |
+ |
|
| 342 |
+static bool |
|
| 343 |
+management_callback_remote_entry_get(void *arg, unsigned int index, char **remote) |
|
| 344 |
+{
|
|
| 345 |
+ assert(arg); |
|
| 346 |
+ assert(remote); |
|
| 347 |
+ |
|
| 348 |
+ struct context *c = (struct context *) arg; |
|
| 349 |
+ struct connection_list *l = c->options.connection_list; |
|
| 350 |
+ bool ret = true; |
|
| 351 |
+ |
|
| 352 |
+ if (index < l->len) |
|
| 353 |
+ {
|
|
| 354 |
+ struct connection_entry *ce = l->array[index]; |
|
| 355 |
+ const char *proto = proto2ascii(ce->proto, ce->af, false); |
|
| 356 |
+ |
|
| 357 |
+ /* space for output including 2 commas and a nul */ |
|
| 358 |
+ int len = strlen(ce->remote) + strlen(ce->remote_port) + strlen(proto) + 2 + 1; |
|
| 359 |
+ char *out = malloc(len); |
|
| 360 |
+ check_malloc_return(out); |
|
| 361 |
+ |
|
| 362 |
+ openvpn_snprintf(out, len, "%s,%s,%s", ce->remote, ce->remote_port, proto); |
|
| 363 |
+ *remote = out; |
|
| 364 |
+ } |
|
| 365 |
+ else |
|
| 366 |
+ {
|
|
| 367 |
+ ret = false; |
|
| 368 |
+ msg(M_WARN, "Out of bounds index in management query for remote entry: index = %u", index); |
|
| 369 |
+ } |
|
| 370 |
+ |
|
| 371 |
+ return ret; |
|
| 372 |
+} |
|
| 373 |
+ |
|
| 332 | 374 |
static bool |
| 333 | 375 |
management_callback_remote_cmd(void *arg, const char **p) |
| 334 | 376 |
{
|
| ... | ... |
@@ -4085,6 +4127,8 @@ init_management_callback_p2p(struct context *c) |
| 4085 | 4085 |
#ifdef TARGET_ANDROID |
| 4086 | 4086 |
cb.network_change = management_callback_network_change; |
| 4087 | 4087 |
#endif |
| 4088 |
+ cb.remote_entry_count = management_callback_remote_entry_count; |
|
| 4089 |
+ cb.remote_entry_get = management_callback_remote_entry_get; |
|
| 4088 | 4090 |
management_set_callback(management, &cb); |
| 4089 | 4091 |
} |
| 4090 | 4092 |
#endif |
| ... | ... |
@@ -96,6 +96,8 @@ man_help(void) |
| 96 | 96 |
msg(M_CLIENT, "net : (Windows only) Show network info and routing table."); |
| 97 | 97 |
msg(M_CLIENT, "password type p : Enter password p for a queried OpenVPN password."); |
| 98 | 98 |
msg(M_CLIENT, "remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP."); |
| 99 |
+ msg(M_CLIENT, "remote-entry-count : Get number of available remote entries."); |
|
| 100 |
+ msg(M_CLIENT, "remote-entry-get i|all [j]: Get remote entry at index = i to to j-1 or all."); |
|
| 99 | 101 |
msg(M_CLIENT, "proxy type [host port flags] : Enter dynamic proxy server info."); |
| 100 | 102 |
msg(M_CLIENT, "pid : Show process ID of the current OpenVPN process."); |
| 101 | 103 |
#ifdef ENABLE_PKCS11 |
| ... | ... |
@@ -842,6 +844,63 @@ man_pkcs11_id_get(struct management *man, const int index) |
| 842 | 842 |
#endif /* ifdef ENABLE_PKCS11 */ |
| 843 | 843 |
|
| 844 | 844 |
static void |
| 845 |
+man_remote_entry_count(struct management *man) |
|
| 846 |
+{
|
|
| 847 |
+ unsigned count = 0; |
|
| 848 |
+ if (man->persist.callback.remote_entry_count) |
|
| 849 |
+ {
|
|
| 850 |
+ count = (*man->persist.callback.remote_entry_count)(man->persist.callback.arg); |
|
| 851 |
+ msg(M_CLIENT, "%u", count); |
|
| 852 |
+ msg(M_CLIENT, "END"); |
|
| 853 |
+ } |
|
| 854 |
+ else |
|
| 855 |
+ {
|
|
| 856 |
+ msg(M_CLIENT, "ERROR: The remote-entry-count command is not supported by the current daemon mode"); |
|
| 857 |
+ } |
|
| 858 |
+} |
|
| 859 |
+ |
|
| 860 |
+#define min(a, b) ((a) < (b) ? (a) : (b)) |
|
| 861 |
+ |
|
| 862 |
+static void |
|
| 863 |
+man_remote_entry_get(struct management *man, const char *p1, const char *p2) |
|
| 864 |
+{
|
|
| 865 |
+ ASSERT(p1); |
|
| 866 |
+ |
|
| 867 |
+ if (man->persist.callback.remote_entry_get |
|
| 868 |
+ && man->persist.callback.remote_entry_count) |
|
| 869 |
+ {
|
|
| 870 |
+ bool res; |
|
| 871 |
+ unsigned int from, to; |
|
| 872 |
+ unsigned int count = (*man->persist.callback.remote_entry_count)(man->persist.callback.arg); |
|
| 873 |
+ |
|
| 874 |
+ from = (unsigned int) atoi(p1); |
|
| 875 |
+ to = p2 ? (unsigned int) atoi(p2) : from + 1; |
|
| 876 |
+ |
|
| 877 |
+ if (!strcmp(p1, "all")) |
|
| 878 |
+ {
|
|
| 879 |
+ from = 0; |
|
| 880 |
+ to = count; |
|
| 881 |
+ } |
|
| 882 |
+ |
|
| 883 |
+ for (unsigned int i = from; i < min(to, count); i++) |
|
| 884 |
+ {
|
|
| 885 |
+ char *remote = NULL; |
|
| 886 |
+ res = (*man->persist.callback.remote_entry_get)(man->persist.callback.arg, i, &remote); |
|
| 887 |
+ if (res && remote) |
|
| 888 |
+ {
|
|
| 889 |
+ msg(M_CLIENT, "%u,%s", i, remote); |
|
| 890 |
+ } |
|
| 891 |
+ free(remote); |
|
| 892 |
+ } |
|
| 893 |
+ msg(M_CLIENT, "END"); |
|
| 894 |
+ } |
|
| 895 |
+ else |
|
| 896 |
+ {
|
|
| 897 |
+ msg(M_CLIENT, "ERROR: The remote-entry command is not supported by the current daemon mode"); |
|
| 898 |
+ } |
|
| 899 |
+} |
|
| 900 |
+ |
|
| 901 |
+static void |
|
| 845 | 902 |
man_hold(struct management *man, const char *cmd) |
| 846 | 903 |
{
|
| 847 | 904 |
if (cmd) |
| ... | ... |
@@ -1563,6 +1622,17 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha |
| 1563 | 1563 |
} |
| 1564 | 1564 |
} |
| 1565 | 1565 |
#endif |
| 1566 |
+ else if (streq(p[0], "remote-entry-count")) |
|
| 1567 |
+ {
|
|
| 1568 |
+ man_remote_entry_count(man); |
|
| 1569 |
+ } |
|
| 1570 |
+ else if (streq(p[0], "remote-entry-get")) |
|
| 1571 |
+ {
|
|
| 1572 |
+ if (man_need(man, p, 1, MN_AT_LEAST)) |
|
| 1573 |
+ {
|
|
| 1574 |
+ man_remote_entry_get(man, p[1], p[2]); |
|
| 1575 |
+ } |
|
| 1576 |
+ } |
|
| 1566 | 1577 |
else if (streq(p[0], "proxy")) |
| 1567 | 1578 |
{
|
| 1568 | 1579 |
if (man_need(man, p, 1, MN_AT_LEAST)) |
| ... | ... |
@@ -31,7 +31,7 @@ |
| 31 | 31 |
#include "socket.h" |
| 32 | 32 |
#include "mroute.h" |
| 33 | 33 |
|
| 34 |
-#define MANAGEMENT_VERSION 3 |
|
| 34 |
+#define MANAGEMENT_VERSION 4 |
|
| 35 | 35 |
#define MANAGEMENT_N_PASSWORD_RETRIES 3 |
| 36 | 36 |
#define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE 100 |
| 37 | 37 |
#define MANAGEMENT_ECHO_BUFFER_SIZE 100 |
| ... | ... |
@@ -181,6 +181,8 @@ struct management_callback |
| 181 | 181 |
#ifdef TARGET_ANDROID |
| 182 | 182 |
int (*network_change)(void *arg, bool samenetwork); |
| 183 | 183 |
#endif |
| 184 |
+ unsigned int (*remote_entry_count)(void *arg); |
|
| 185 |
+ bool (*remote_entry_get)(void *arg, unsigned int index, char **remote); |
|
| 184 | 186 |
}; |
| 185 | 187 |
|
| 186 | 188 |
/* |