0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-20 03:52:28 +02:00

Add remote-count and remote-entry query via management

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>
This commit is contained in:
Selva Nair 2021-09-07 18:31:24 -04:00 committed by Gert Doering
parent 8516b4b366
commit 1252638047
5 changed files with 182 additions and 1 deletions

View File

@ -10,6 +10,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

View 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)
--------------------------------------------

View 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

View 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))

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