1#!/usr/local/bin/perl -w
2
3=head1 NAME
4
5openvpn_multi - Plugin for monitoring OpenVPN users traffic
6
7=head1 CONFIGURATION
8
9  [openvpn_multi]
10    user root
11    env.statusfile /var/log/openvpn.status
12
13=head1 AUTHOR
14
15Copyright 2013 Pierre Schweitzer <pierre@reactos.org>
16
17=head1 LICENSE
18
19GNU GPL v2 or any later version
20
21=head1 MAGIC MARKERS
22
23 #%# family=auto
24 #%# capabilities=autoconf
25
26=cut
27
28use strict;
29use Munin::Common::Defaults;
30use Munin::Plugin;
31
32my $statusfile = ($ENV{'statusfile'} || '/var/log/openvpn.status');
33
34sub config {
35	open FILE, $statusfile or die $!;
36
37	print "multigraph openvpn_users\n";
38	print "graph_title OpenVPN traffic\n";
39	print "graph_args --base 1024 --lower-limit 0\n";
40	print "graph_vlabel Bytes Out (-) / In (+) per \${graph_period}\n";
41	print "graph_category network\n";
42	print "in.label recv\n";
43	print "in.type DERIVE\n";
44	print "in.min 0\n";
45	print "in.graph no\n";
46	print "in.cdef in,1,*\n";
47	print "out.label Bps\n";
48	print "out.type DERIVE\n";
49	print "out.min 0\n";
50	print "out.negative in\n";
51	print "out.cdef out,1,*\n";
52
53	while (<FILE>) {
54		next if ($_ =~ /CLIENT LIST/ || $_ =~ /Updated/ || $_ =~ /Common Name/ || $_ =~ /^UNDEF,/);
55		last if ($_ =~ /ROUTING TABLE/);
56
57		# client,IP:port,in,out,D M N hour Y
58		my @values = split(',', $_);
59		my $name = $values[0];
60		my $fieldname = clean_fieldname($name);
61
62		print "multigraph openvpn_users.$fieldname\n";
63		print "graph_title OpenVPN traffic for $name\n";
64		print "graph_args --base 1024 --lower-limit 0\n";
65		print "graph_vlabel Bytes Out (-) / In (+) per \${graph_period}\n";
66		print "graph_category network\n";
67		print "in.label recv\n";
68		print "in.type DERIVE\n";
69		print "in.min 0\n";
70		print "in.graph no\n";
71		print "in.cdef in,1,*\n";
72		print "out.label Bps\n";
73		print "out.type DERIVE\n";
74		print "out.min 0\n";
75		print "out.negative in\n";
76		print "out.cdef out,1,*\n";
77	}
78	close FILE;
79
80	exit 0;
81}
82
83sub autoconf {
84	if (-e $statusfile) {
85		print "yes\n";
86	} else {
87		print "no\n";
88	}
89	exit 0;
90}
91
92sub report {
93	my %in;
94	my %out;
95	my $tot_in = 0;
96	my $tot_out = 0;
97
98	my %previous_state = restore_state();
99	my %new_state;
100
101	open FILE, $statusfile or die $!;
102	while (<FILE>) {
103		next if ($_ =~ /CLIENT LIST/ || $_ =~ /Updated/ || $_ =~ /Common Name/ || $_ =~ /^UNDEF,/);
104		last if ($_ =~ /ROUTING TABLE/);
105
106		# client,IP:port,in,out,D M N hour Y
107		my @values = split(',', $_);
108		my $name = $values[0];
109
110		my $in = 0;
111		my $out = 0;
112		if (exists $previous_state{$name."_in"} && exists $previous_state{$name."_out"}) {
113			my $old_in = $previous_state{$name."_in"};
114			my $old_out = $previous_state{$name."_out"};
115			if ($old_in <= $values[2] && $old_out <= $values[3]) {
116				$in = $values[2] - $old_in;
117				$out = $values[3] - $old_out;
118			}
119		}
120
121		$in{$name} = $in;
122		$out{$name} = $out;
123		$tot_in += $in;
124		$tot_out += $out;
125
126		$new_state{$name."_in"} = $values[2];
127		$new_state{$name."_out"} = $values[3];
128	}
129	close FILE;
130
131	print "multigraph openvpn_users\n";
132	if (exists $previous_state{"total.in"} && exists $previous_state{"total.out"}) {
133		my $old_tot_in = $previous_state{"total.in"};
134		my $old_tot_out = $previous_state{"total.out"};
135		if ($old_tot_in <= $tot_in && $old_tot_out <= $tot_out) {
136			print "in.value $tot_in\n";
137			print "out.value $tot_out\n";
138		} else {
139			print "in.value 0\n";
140			print "out.value 0\n";
141		}
142	}  else {
143		print "in.value 0\n";
144		print "out.value 0\n";
145	}
146
147	$new_state{"total.in"} = $tot_in;
148	$new_state{"total.out"} = $tot_out;
149
150	save_state(%new_state);
151
152	for my $name (keys %in) {
153		my $in = $in{$name};
154		my $out = $out{$name};
155		my $fieldname = clean_fieldname($name);
156
157		print "multigraph openvpn_users.$fieldname\n";
158		print "in.value $in\n";
159		print "out.value $out\n";
160	}
161
162	exit 0;
163}
164
165if ($ARGV[0]) {
166	my $arg = $ARGV[0];
167	my %funcs = (
168		config   => \&config,
169		autoconf => \&autoconf,
170	);
171
172	if (exists $funcs{$arg}) {
173		$funcs{$arg}->();
174	} else {
175		die "Unknown argument '$arg'\n";
176	}
177} else {
178	report();
179}
180