openvpn plugin: Add a plugin to read OpenVPN statistics.
authorDoug MacEachern <dougm@hyperic.com>
Sun, 21 Dec 2008 01:08:39 +0000 (17:08 -0800)
committerFlorian Forster <octo@huhu.verplant.org>
Thu, 1 Jan 2009 11:01:24 +0000 (12:01 +0100)
Simple but useful module for monitoring per-client openvpn traffic..

The plugin reads a statistics file maintained by OpenVPN. The location of the
statistics file is configurable.

Signed-off-by: Doug MacEachern <dougm@hyperic.com>
Signed-off-by: Florian Forster <octo@huhu.verplant.org>
README
configure.in
src/Makefile.am
src/collectd.conf.in
src/openvpn.c [new file with mode: 0644]

diff --git a/README b/README
index 5c9eed0..9b06f64 100644 (file)
--- a/README
+++ b/README
@@ -146,6 +146,10 @@ Features
       Read onewire sensors using the owcapu library of the owfs project.
       Please read in collectd.conf(5) why this plugin is experimental.
 
       Read onewire sensors using the owcapu library of the owfs project.
       Please read in collectd.conf(5) why this plugin is experimental.
 
+    - openvpn
+      RX and TX of each client in openvpn-status.log (status-version 2).
+      <http://openvpn.net/index.php/documentation/howto.html>
+
     - perl
       The perl plugin implements a Perl-interpreter into collectd. You can
       write your own plugins in Perl and return arbitrary values using this
     - perl
       The perl plugin implements a Perl-interpreter into collectd. You can
       write your own plugins in Perl and return arbitrary values using this
index 6b8571d..55ce936 100644 (file)
@@ -3008,6 +3008,7 @@ AC_PLUGIN([notify_email], [$with_libesmtp],    [Email notifier])
 AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
 AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
 AC_PLUGIN([onewire],     [$with_libowcapi],    [OneWire sensor statistics])
 AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
 AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
 AC_PLUGIN([onewire],     [$with_libowcapi],    [OneWire sensor statistics])
+AC_PLUGIN([openvpn],     [yes],                [OpenVPN client statistics])
 AC_PLUGIN([oracle],      [$with_oracle],       [Oracle plugin])
 AC_PLUGIN([perl],        [$plugin_perl],       [Embed a Perl interpreter])
 AC_PLUGIN([ping],        [$with_liboping],     [Network latency statistics])
 AC_PLUGIN([oracle],      [$with_oracle],       [Oracle plugin])
 AC_PLUGIN([perl],        [$plugin_perl],       [Embed a Perl interpreter])
 AC_PLUGIN([ping],        [$with_liboping],     [Network latency statistics])
@@ -3188,6 +3189,7 @@ Configuration:
     ntpd  . . . . . . . . $enable_ntpd
     nut . . . . . . . . . $enable_nut
     onewire . . . . . . . $enable_onewire
     ntpd  . . . . . . . . $enable_ntpd
     nut . . . . . . . . . $enable_nut
     onewire . . . . . . . $enable_onewire
+    openvpn . . . . . . . $enable_openvpn
     oracle  . . . . . . . $enable_oracle
     perl  . . . . . . . . $enable_perl
     ping  . . . . . . . . $enable_ping
     oracle  . . . . . . . $enable_oracle
     perl  . . . . . . . . $enable_perl
     ping  . . . . . . . . $enable_ping
index f5776d5..892ddea 100644 (file)
@@ -570,6 +570,15 @@ collectd_LDADD += "-dlopen" onewire.la
 collectd_DEPENDENCIES += onewire.la
 endif
 
 collectd_DEPENDENCIES += onewire.la
 endif
 
+if BUILD_PLUGIN_OPENVPN
+pkglib_LTLIBRARIES += openvpn.la
+openvpn_la_SOURCES = openvpn.c
+openvpn_la_CFLAGS = $(AM_CFLAGS)
+openvpn_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" openvpn.la
+collectd_DEPENDENCIES += openvpn.la
+endif
+
 if BUILD_PLUGIN_ORACLE
 pkglib_LTLIBRARIES += oracle.la
 oracle_la_SOURCES = oracle.c
 if BUILD_PLUGIN_ORACLE
 pkglib_LTLIBRARIES += oracle.la
 oracle_la_SOURCES = oracle.c
index 01017e3..0c27edc 100644 (file)
@@ -64,6 +64,7 @@ FQDNLookup   true
 @BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
 @BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
 @BUILD_PLUGIN_ONEWIRE_TRUE@LoadPlugin onewire
 @BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
 @BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
 @BUILD_PLUGIN_ONEWIRE_TRUE@LoadPlugin onewire
+@BUILD_PLUGIN_OPENVPN_TRUE@LoadPlugin openvpn
 @BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
 @BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
 @BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
 @BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
 @BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
 @BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
diff --git a/src/openvpn.c b/src/openvpn.c
new file mode 100644 (file)
index 0000000..16d4502
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+ * collectd - src/openvpn.c
+ * Copyright (C) 2008  Doug MacEachern
+ * Copyright (C) 2008  Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Doug MacEachern <dougm at hyperic.com>
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+static char *status_file = "/etc/openvpn/openvpn-status.log";
+
+static const char *config_keys[] =
+{
+       "StatusFile"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+/* copy-n-pasted from common.c - changed delim to "," */
+static int openvpn_strsplit (char *string, char **fields, size_t size)
+{
+        size_t i;
+        char *ptr;
+        char *saveptr;
+
+        i = 0;
+        ptr = string;
+        saveptr = NULL;
+        while ((fields[i] = strtok_r (ptr, ",", &saveptr)) != NULL)
+        {
+                ptr = NULL;
+                i++;
+
+                if (i >= size)
+                        break;
+        }
+
+        return (i);
+} /* int openvpn_strsplit */
+
+static void openvpn_submit (char *name, counter_t rx, counter_t tx)
+{
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].counter = rx;
+       values[1].counter = tx;
+
+       vl.values = values;
+       vl.values_len = STATIC_ARRAY_SIZE (values);
+       vl.time = time (NULL);
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
+       sstrncpy (vl.type_instance, name, sizeof (vl.type_instance));
+       sstrncpy (vl.type, "if_octets", sizeof (vl.type));
+
+       plugin_dispatch_values (&vl);
+} /* void openvpn_submit */
+
+static int openvpn_read (void)
+{
+       char *name;
+       counter_t rx, tx;
+       FILE *fh;
+       char buffer[1024];
+       char *fields[8];
+       const int max_fields = sizeof(fields)/sizeof(fields[0]);
+       int   fields_num;
+       static const char *prefix = "CLIENT_LIST,";
+
+       fh = fopen (status_file, "r");
+       if (fh == NULL)
+               return (-1);
+
+        /* status file is generated by openvpn/multi.c:multi_print_status()
+        * this plugin requires server.conf: "status-version 2"
+         * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c
+         */
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
+       {
+               if (strncmp(buffer, prefix, strlen(prefix)) != 0)
+               {
+                       continue;
+               }
+
+               fields_num = openvpn_strsplit (buffer, fields, max_fields);
+               if (fields_num != max_fields)
+               {
+                       continue;
+               }
+               name =      fields[1];  /* "Common Name" */
+               rx = atoll (fields[4]); /* "Bytes Received */
+               tx = atoll (fields[5]); /* "Bytes Sent" */
+               openvpn_submit (name, rx, tx);
+       }
+       fclose (fh);
+
+       return (0);
+} /* int openvpn_read */
+
+static int openvpn_config (const char *key, const char *value)
+{
+       if (strcasecmp ("StatusFile", key) == 0)
+       {
+               status_file = strdup(value);
+       }
+       else
+       {
+               return (-1);
+       }
+        return (0);
+} /* int openvpn_config */
+
+void module_register (void)
+{
+       plugin_register_config ("openvpn", openvpn_config,
+                               config_keys, config_keys_num);
+       plugin_register_read ("openvpn", openvpn_read);
+} /* void module_register */