<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/11885">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Pau Espin Pedrol: Looks good to me, but someone else must approve
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add OpenVPN status helper example from corresponding ticket<br><br>Change-Id: I912d943cdc7024e3ddd92e0a122ac2dd4fbf0a18<br>Related: SYS#2655<br>---<br>A contrib/openvpn-status-export.pl<br>1 file changed, 124 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/contrib/openvpn-status-export.pl b/contrib/openvpn-status-export.pl</span><br><span>new file mode 100755</span><br><span>index 0000000..c227a8f</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/openvpn-status-export.pl</span><br><span>@@ -0,0 +1,124 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/perl -w</span><br><span style="color: hsl(120, 100%, 40%);">+use strict;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Script to export the OpenVPN daemon status information (which clients</span><br><span style="color: hsl(120, 100%, 40%);">+# are connected from where) as a JSON file that can be served via HTTP.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2015 by sysmocom - s.f.m.c. GmbH, All rights reserved.</span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Harald Welte</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+use JSON;</span><br><span style="color: hsl(120, 100%, 40%);">+use Linux::Inotify2;</span><br><span style="color: hsl(120, 100%, 40%);">+use Net::Netmask;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+my $OPENVPN_STATE_FILE = "/var/tmp/openvpn.status";</span><br><span style="color: hsl(120, 100%, 40%);">+my $JSON_OUTPUT_FILE = "/var/www/openvpn/status.json";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+my $srcip_table = {</span><br><span style="color: hsl(120, 100%, 40%);">+     'Destination 1' => [</span><br><span style="color: hsl(120, 100%, 40%);">+               '127.0.0.0/8',</span><br><span style="color: hsl(120, 100%, 40%);">+                ],</span><br><span style="color: hsl(120, 100%, 40%);">+    'Peer 2' => [</span><br><span style="color: hsl(120, 100%, 40%);">+              '8.8.0.0/16', '1.2.3.0/18',</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%);">+my %netblocks;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+sub read_netmask_table($)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      my ($t) = @_;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       foreach my $k (keys %$t) {</span><br><span style="color: hsl(120, 100%, 40%);">+            my $table = {};</span><br><span style="color: hsl(120, 100%, 40%);">+               foreach my $net (@{$$t{$k}}) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        my $block = new Net::Netmask($net);</span><br><span style="color: hsl(120, 100%, 40%);">+                   $block->storeNetblock($table);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             $netblocks{$k} = $table;</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%);">+sub classify_srcip($)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      my ($ip) = @_;</span><br><span style="color: hsl(120, 100%, 40%);">+        foreach my $k (%netblocks) {</span><br><span style="color: hsl(120, 100%, 40%);">+          my $block = findNetblock($ip, $netblocks{$k});</span><br><span style="color: hsl(120, 100%, 40%);">+                if ($block) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 return $k;</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 undef;</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%);">+# read the openvpn.status file and parse it, return hash reference to</span><br><span style="color: hsl(120, 100%, 40%);">+# its contents.</span><br><span style="color: hsl(120, 100%, 40%);">+sub get_openvpn_clients($)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     my ($fname) = @_;</span><br><span style="color: hsl(120, 100%, 40%);">+     my $state = 'init';</span><br><span style="color: hsl(120, 100%, 40%);">+   my $href;</span><br><span style="color: hsl(120, 100%, 40%);">+     my @clients;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        $$href{version} = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        open(INFILE, "<", $fname);</span><br><span style="color: hsl(120, 100%, 40%);">+       while (my $line = <INFILE>) {</span><br><span style="color: hsl(120, 100%, 40%);">+           chomp($line);</span><br><span style="color: hsl(120, 100%, 40%);">+         if ($line =~ /^OpenVPN CLIENT LIST$/) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       $state = 'client_list';</span><br><span style="color: hsl(120, 100%, 40%);">+               } elsif ($line =~ /^ROUTING\ TABLE$/) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       $state = 'routing_table';</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if ($state eq 'client_list') {</span><br><span style="color: hsl(120, 100%, 40%);">+                                my %cl;</span><br><span style="color: hsl(120, 100%, 40%);">+                               if ($line =~ /^Updated,(.*)/) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       $$href{updated} = $1;</span><br><span style="color: hsl(120, 100%, 40%);">+                         } elsif ($line =~ /^(\S+),([0-9\.]+)\:(\d+),(\d+),(\d+),(.*)$/) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     $cl{name} = $1;</span><br><span style="color: hsl(120, 100%, 40%);">+                                       $cl{srcip} = $2;</span><br><span style="color: hsl(120, 100%, 40%);">+                                      $cl{operator} = classify_srcip($2);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   $cl{srcport} = $3 + 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                                        $cl{bytes_rx} = $4 + 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                                       $cl{bytes_tx} = $5 + 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                                       $cl{connected_since} = $6;</span><br><span style="color: hsl(120, 100%, 40%);">+                                    push(@clients, \%cl);</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%);">+     close(INFILE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      $$href{clients} = \@clients;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return $href;</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%);">+# inotify handler to re-parse/convert openvpn.status on any change</span><br><span style="color: hsl(120, 100%, 40%);">+sub status_in_handler</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      my $e = shift;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      # read/parse openvpn.status</span><br><span style="color: hsl(120, 100%, 40%);">+   my $cl = get_openvpn_clients($e->fullname);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      # write result to file</span><br><span style="color: hsl(120, 100%, 40%);">+        open(OUTFILE, ">", $JSON_OUTPUT_FILE);</span><br><span style="color: hsl(120, 100%, 40%);">+   print(OUTFILE to_json($cl, { pretty => 1 }));</span><br><span style="color: hsl(120, 100%, 40%);">+      close(OUTFILE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     # also print it to console for debugging</span><br><span style="color: hsl(120, 100%, 40%);">+      print(to_json($cl, { pretty => 1 }));</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%);">+# main</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+read_netmask_table($srcip_table);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+my $inotify = new Linux::Inotify2 or die("Can't create inotify object: $!");</span><br><span style="color: hsl(120, 100%, 40%);">+$inotify->watch($OPENVPN_STATE_FILE, IN_MODIFY, \&status_in_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# endless loop, wait for inotify enents</span><br><span style="color: hsl(120, 100%, 40%);">+1 while $inotify->poll;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/11885">change 11885</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/11885"/><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: merged </div>
<div style="display:none"> Gerrit-Change-Id: I912d943cdc7024e3ddd92e0a122ac2dd4fbf0a18 </div>
<div style="display:none"> Gerrit-Change-Number: 11885 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Max <msuraev@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Pau Espin Pedrol <pespin@sysmocom.de> </div>