<p>Max has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/12763">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add OpenVPN probe<br><br>This adds support for OpenVPN status probe which uses OpenVPN's<br>management interface (configured via 'management 127.0.0.1 1234' in<br>OpenVPN's config).<br><br>The output looks as follows:<br>...<br>  OpenVPN<br>    127.0.0.1:1234<br>      status: CONNECTED<br>      tunnel: 10.8.0.15<br>      remote: 144.76.43.77:1194<br>    localhost:4242<br>      status: management interface incompatible<br>    127.0.0.1:4444<br>      status: management interface unavailable<br>...<br><br>We show tunnel's IP (if available) as well as remote (OpenVPN server<br>itself) address/port in addition to general connection status. If<br>management interface is unavailable it's reported as such. If we've<br>managed to establish connection with a given management interface but<br>are unable to obtain expected information than we report this<br>incompatibility as well.<br><br>Related: SYS#2655<br>Change-Id: I4493e19b9a09dcebd289457eacd1719f7f8cc31c<br>---<br>M src/Makefile.am<br>M src/osysmon.h<br>M src/osysmon_main.c<br>A src/osysmon_openvpn.c<br>4 files changed, 307 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-sysmon refs/changes/63/12763/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index e38b70e..f9b79f2 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -29,6 +29,7 @@</span><br><span> </span><br><span> osmo_sysmon_LDADD = $(LDADD) \</span><br><span>        $(LIBOSMOVTY_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(LIBOSMONETIF_LIBS) \</span><br><span>       $(LIBMNL_LIBS) \</span><br><span>     $(LIBOPING_LIBS) \</span><br><span>   $(NULL)</span><br><span>@@ -40,6 +41,7 @@</span><br><span>  osysmon_rtnl.c \</span><br><span>     osysmon_file.c \</span><br><span>     osysmon_ping.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      osysmon_openvpn.c \</span><br><span>  osysmon_main.c \</span><br><span>     $(NULL)</span><br><span> </span><br><span>diff --git a/src/osysmon.h b/src/osysmon.h</span><br><span>index df8bf8d..2f82c47 100644</span><br><span>--- a/src/osysmon.h</span><br><span>+++ b/src/osysmon.h</span><br><span>@@ -15,6 +15,8 @@</span><br><span>     struct rtnl_client_state *rcs;</span><br><span>       /* list of 'struct ctrl client' */</span><br><span>   struct llist_head ctrl_clients;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* list of 'struct openvpn_client' */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head openvpn_clients;</span><br><span>   /* list of 'struct netdev' */</span><br><span>        struct llist_head netdevs;</span><br><span>   /* list of 'struct osysmon_file' */</span><br><span>@@ -30,6 +32,7 @@</span><br><span>      CTRL_CLIENT_NODE = _LAST_OSMOVTY_NODE + 1,</span><br><span>   CTRL_CLIENT_GETVAR_NODE,</span><br><span>     NETDEV_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+  OPENVPN_NODE,</span><br><span>        PING_NODE,</span><br><span> };</span><br><span> </span><br><span>@@ -48,5 +51,8 @@</span><br><span> int osysmon_ping_init();</span><br><span> int osysmon_ping_poll(struct value_node *parent);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int osysmon_openvpn_init();</span><br><span style="color: hsl(120, 100%, 40%);">+int osysmon_openvpn_poll(struct value_node *parent);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int osysmon_file_init();</span><br><span> int osysmon_file_poll(struct value_node *parent);</span><br><span>diff --git a/src/osysmon_main.c b/src/osysmon_main.c</span><br><span>index eb4f50b..6d72786 100644</span><br><span>--- a/src/osysmon_main.c</span><br><span>+++ b/src/osysmon_main.c</span><br><span>@@ -199,6 +199,7 @@</span><br><span> </span><br><span>   g_oss = talloc_zero(NULL, struct osysmon_state);</span><br><span>     INIT_LLIST_HEAD(&g_oss->ctrl_clients);</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&g_oss->openvpn_clients);</span><br><span>     INIT_LLIST_HEAD(&g_oss->netdevs);</span><br><span>     INIT_LLIST_HEAD(&g_oss->files);</span><br><span> </span><br><span>@@ -206,6 +207,7 @@</span><br><span>     handle_options(argc, argv);</span><br><span>  osysmon_sysinfo_init();</span><br><span>      osysmon_ctrl_init();</span><br><span style="color: hsl(120, 100%, 40%);">+  osysmon_openvpn_init();</span><br><span>      osysmon_rtnl_init();</span><br><span>         ping_init = osysmon_ping_init();</span><br><span>     osysmon_file_init();</span><br><span>@@ -239,9 +241,11 @@</span><br><span>                  osysmon_ping_poll(root);</span><br><span> </span><br><span>                 osysmon_file_poll(root);</span><br><span style="color: hsl(120, 100%, 40%);">+              osysmon_openvpn_poll(root);</span><br><span> </span><br><span>              display_update(root);</span><br><span>                value_node_del(root);</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_select_main(0);</span><br><span>                 sleep(1);</span><br><span>    }</span><br><span> </span><br><span>diff --git a/src/osysmon_openvpn.c b/src/osysmon_openvpn.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6edb143</span><br><span>--- /dev/null</span><br><span>+++ b/src/osysmon_openvpn.c</span><br><span>@@ -0,0 +1,295 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Simple Osmocom System Monitor (osysmon): Support for OpenVPN monitoring */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2019 by sysmocom - s.f.m.c. GmbH.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Max Suraev</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ *  it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ *  the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ *  (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ *  GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ *  along with this program; if not, write to the Free Software</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  MA  02110-1301, USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <ctype.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/command.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/stream.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osysmon.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "client.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "value_node.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Data model</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* max number of csv in response */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAX_RESP_COMPONENTS 6</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* a single OpenVPN management interface client */</span><br><span style="color: hsl(120, 100%, 40%);">+struct openvpn_client {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* links to osysmon.openvpn_clients */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct host_cfg *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_stream_cli *mgmt;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* fields below are parsed from response to 'state' command on mgmt interface */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct host_cfg *rem_cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+     char *tun_ip;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool connected;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *parse_state(const struct msgb *msg, struct openvpn_client *vpn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char tmp[128];</span><br><span style="color: hsl(120, 100%, 40%);">+        char *tok;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *m = msgb_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (msgb_length(msg) > 128)</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "[%s] received message too long (%d > %u), truncating...\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     get_authority(NULL, vpn->cfg), msgb_length(msg), 128);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (msgb_length(msg) > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!isdigit(m[0])) /* skip OpenVPN greetings and alike */</span><br><span style="color: hsl(120, 100%, 40%);">+                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "[%s] received message is empty, ignoring...\n", get_authority(NULL, vpn->cfg));</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy(tmp, m, OSMO_MIN(sizeof(tmp) - 1, msgb_length(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+  tmp[sizeof(tmp) - 1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (tok = strtok(tmp, ","); tok && i < MAX_RESP_COMPONENTS; tok = strtok(NULL, ",")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (tok)</span><br><span style="color: hsl(120, 100%, 40%);">+                      switch (i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        case 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                               update_name(vpn->rem_cfg, tok);</span><br><span style="color: hsl(120, 100%, 40%);">+                            break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        case 3:</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_talloc_replace_string(vpn->rem_cfg, &vpn->tun_ip, tok);</span><br><span style="color: hsl(120, 100%, 40%);">+                                break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        case 4:</span><br><span style="color: hsl(120, 100%, 40%);">+                               update_host(vpn->rem_cfg, tok);</span><br><span style="color: hsl(120, 100%, 40%);">+                            break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        case 5:</span><br><span style="color: hsl(120, 100%, 40%);">+                               vpn->rem_cfg->remote_port = atoi(tok);</span><br><span style="color: hsl(120, 100%, 40%);">+                          break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct openvpn_client *openvpn_client_find(const struct osysmon_state *os, const char *host, uint16_t port)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct openvpn_client *vpn;</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(vpn, &os->openvpn_clients, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (match_config(vpn->cfg, host, MATCH_HOST) && vpn->cfg->remote_port == port)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return vpn;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int connect_cb(struct osmo_stream_cli *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct openvpn_client *vpn = osmo_stream_cli_get_data(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        update_name(vpn->rem_cfg, "management interface incompatible");</span><br><span style="color: hsl(120, 100%, 40%);">+  vpn->connected = true; /* FIXME: there's no callback for lost connection to drop this flag */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int read_cb(struct osmo_stream_cli *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int bytes;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct openvpn_client *vpn = osmo_stream_cli_get_data(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = msgb_alloc(1024, "OpenVPN");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (msg == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+            fprintf(stderr, "[%s] unable to allocate message in callback\n", get_authority(NULL, vpn->cfg));</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bytes = osmo_stream_cli_recv(conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (bytes < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           fprintf(stderr, "[%s] unable to receive message in callback\n", get_authority(NULL, vpn->cfg));</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   parse_state(msg, vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool openvpn_client_create(struct osysmon_state *os, const char *name, const char *host, uint16_t port)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct openvpn_client *vpn = openvpn_client_find(os, host, port);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (vpn)</span><br><span style="color: hsl(120, 100%, 40%);">+              return true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        vpn = talloc_zero(os, struct openvpn_client);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!vpn)</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       vpn->connected = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  vpn->cfg = make_config(vpn, name, host, port);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!vpn->cfg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           talloc_free(vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vpn->rem_cfg = make_config(vpn, "management interface unavailable", NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!vpn->cfg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           talloc_free(vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vpn->mgmt = make_tcp_client(vpn->cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!vpn->mgmt)</span><br><span style="color: hsl(120, 100%, 40%);">+    {//FIXME: log error via same macro as ctrl client?</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+             fprintf(stderr, "OpenVPN: ERROR: failed to create TCP client for %s:%u\n", host, port);</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Wait for 1 minute before attempting to reconnect to management interface */</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_stream_cli_set_reconnect_timeout(vpn->mgmt, 60); /* FIXME: this seems to be ignored by libosmo-netif */</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_stream_cli_set_read_cb(vpn->mgmt, read_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_stream_cli_set_connect_cb(vpn->mgmt, connect_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_stream_cli_open(vpn->mgmt) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "OpenVPN: ERROR: failed to connect to %s:%u\n", host, port);</span><br><span style="color: hsl(120, 100%, 40%);">+                talloc_free(vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_stream_cli_set_data(vpn->mgmt, vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_add_tail(&vpn->list, &os->openvpn_clients);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void openvpn_client_destroy(struct openvpn_client *vpn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!vpn)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_stream_cli_destroy(vpn->mgmt);</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_del(&vpn->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * VTY</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define OPENVPN_STR "Configure OpenVPN management interface address\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_openvpn, cfg_openvpn_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "openvpn HOST <1-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+      OPENVPN_STR "Name of the host to connect to\n" "Management interface port\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t port = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!openvpn_client_create(g_oss, "OpenVPN", argv[0], port)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Failed to create OpenVPN client for %s:%u%s", argv[0], port, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_no_openvpn, cfg_no_openvpn_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no openvpn HOST <1-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR OPENVPN_STR "Name of the host to connect to\n" "Management interface port\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t port = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct openvpn_client *vpn = openvpn_client_find(g_oss, argv[0], port);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!vpn) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "OpenVPN client %s:%u doesn't exist%s", argv[0], port, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   openvpn_client_destroy(vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Runtime Code</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int openvpn_client_poll(struct openvpn_client *vpn, struct value_node *parent)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char *remote = get_authority(parent, vpn->rem_cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct value_node *vn_host = value_node_find_or_add(parent, get_authority(parent, vpn->cfg));</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg = msgb_alloc(128, "state");</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           value_node_add(vn_host, "msgb", "memory allocation failure");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (vpn->rem_cfg->name)</span><br><span style="color: hsl(120, 100%, 40%);">+         value_node_add(vn_host, "status", vpn->rem_cfg->name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (vpn->tun_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+           value_node_add(vn_host, "tunnel", vpn->tun_ip);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (remote)</span><br><span style="color: hsl(120, 100%, 40%);">+           value_node_add(vn_host, "remote", remote);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* FIXME: there's no way to check client state so this might be triggered even while it's reconnecting */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (vpn->connected) { /* re-trigger state command */</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_printf(msg, "state\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_stream_cli_send(vpn->mgmt, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* called once on startup before config file parsing */</span><br><span style="color: hsl(120, 100%, 40%);">+int osysmon_openvpn_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(CONFIG_NODE, &cfg_openvpn_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(CONFIG_NODE, &cfg_no_openvpn_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* called periodically */</span><br><span style="color: hsl(120, 100%, 40%);">+int osysmon_openvpn_poll(struct value_node *parent)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct value_node *vn_vpn;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (llist_count(&g_oss->openvpn_clients)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct openvpn_client *vpn;</span><br><span style="color: hsl(120, 100%, 40%);">+           vn_vpn = value_node_add(parent, "OpenVPN", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           llist_for_each_entry(vpn, &g_oss->openvpn_clients, list)</span><br><span style="color: hsl(120, 100%, 40%);">+                       openvpn_client_poll(vpn, vn_vpn);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12763">change 12763</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/12763"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-sysmon </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I4493e19b9a09dcebd289457eacd1719f7f8cc31c </div>
<div style="display:none"> Gerrit-Change-Number: 12763 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Max <msuraev@sysmocom.de> </div>