diff --git a/plugins/network/pf_tables_ b/plugins/network/pf_tables_ new file mode 100644 index 00000000..3e98903f --- /dev/null +++ b/plugins/network/pf_tables_ @@ -0,0 +1,252 @@ +#!/usr/bin/perl -w +# -*- perl -*- + +=head1 NAME + +pf_tables : Munin plugin to monitor pf tables. +Inout: bandwidth usage for table +Addresses: number of entries in table + + +=head1 APPLICABLE SYSTEMS + +Should work on any BSD that has pf(4). + +Examples: + +=over + +=item pf_tables_inout_tablename + +=item pf_tables_addresses_authenticated + +=item pf_tables_addresses_badboys + + +=head1 CONFIGURATION + +[pf_tables_*] +user root + +=head1 INTERPRETATION + +The plugin simply runs the pfctl -sTables -vvv command and counts the number of +Addresses and InBytes/OutBytes in each table. + +=head1 BUGS + +Only tested extensively on FreeBSD. + +=head1 MAGIC MARKERS + + #%# family=auto + #%# capabilities=autoconf suggest + +=head1 VERSION + + $Id$ + +=head1 AUTHOR + +Copyright (C) 2015. + +Original version by Luc Duchosal (at) arcantel (dot) ch. +Created by Luc Duchosal, 2015 + +=head1 LICENSE + +BSD + +=cut + + +use strict; +use Munin::Plugin; + +$0 =~ /pf_tables_(addresses|inout)_(.+)$/; +my $name = $2; +my $operation = $1; + +if ( defined($ARGV[0])) { + if ($ARGV[0] eq 'autoconf') { + print "yes\n"; + exit 0; + } + + if ($ARGV[0] eq "config") { + + if (!defined($name)) { + print "Unknown table\n"; + exit 0; + } + + if (!defined($operation)) { + print "Unknown operation\n"; + exit 0; + } + + if ($operation =~ m/addresses/) { + + print "graph_title Connected users ($name)\n"; + print "graph_args --base 1000 -l 0\n"; + print "graph_vlabel Users\n"; + print "graph_scale no\n"; + print "graph_category pf\n"; + print "graph_printf %3.0lf\n"; + + print "users.label users\n"; + print "users.draw AREASTACK\n"; + print "users.colour 00C000\n"; + foreach my $field (qw(users)) { + print_thresholds($field); + } + } + + if ($operation =~ m/inout/) { + + print "graph_title Network bandwidth ($name)\n"; + print "graph_args --base 1024 -l 0\n"; + print "graph_vlabel Bandwidth\n"; + print "graph_scale yes\n"; + print "graph_category pf\n"; +# print "graph_printf %3.0lf\n"; + + print "in.label in\n"; + print "in.type DERIVE\n"; + print "in.draw AREASTACK\n"; + print "in.colour C00000\n"; + print "in.cdef in,8,*\n"; + print "in.min 0\n"; + print "in.graph no\n"; + print "out.label out\n"; + print "out.type DERIVE\n"; + print "out.negative in\n"; + print "out.draw AREASTACK\n"; + print "out.colour 0000C0\n"; + print "out.cdef out,8,*\n"; + print "out.min 0\n"; + print "out.graph no\n"; + + foreach my $field (qw(in out)) { + print_thresholds($field); + } + + } + exit 0; + } + + if ($ARGV[0] eq "suggest") { + my %tables = &tables(); + foreach my $key (keys(%tables)) { + print "addresses_$key\n"; + print "inout_$key\n"; + } + exit 0; + } + +} + +if (!defined($name)) { + print "Usage: pf_tables_addresses_tablename or pf_tables_inout_tablename\n"; + exit 1; +} + +my %tables = &tables(); +if (!exists $tables{$name}) { + print "Unknown table name $name\n"; + exit 2; +} + +if ($operation =~ m/addresses/) { + my $users = $tables{$name}->{"addresses"}; + print "users.value $users\n"; +} + +if ($operation =~ m/inout/) { + my $in = $tables{$name}->{"inpassbytes"}; + my $out = $tables{$name}->{"outpassbytes"}; + print "in.value $in\n"; + print "out.value $out\n"; +} + + +sub tables { + + # # pfctl -s Tables -vv + # -pa-r-- auth + # Addresses: 0 + # Cleared: Fri Sep 18 17:34:42 2015 + # References: [ Anchors: 0 Rules: 14 ] + # Evaluations: [ NoMatch: 43624 Match: 788 ] + # In/Block: [ Packets: 0 Bytes: 0 ] + # In/Pass: [ Packets: 30908 Bytes: 2704516 ] + # In/XPass: [ Packets: 124 Bytes: 7897 ] + # Out/Block: [ Packets: 0 Bytes: 0 ] + # Out/Pass: [ Packets: 30288 Bytes: 26313114 ] + # Out/XPass: [ Packets: 89 Bytes: 21166 ] + + my $output = `/sbin/pfctl -s Tables -vv 2> /dev/null`; + my %tables; + my $name; + + foreach (split(/\n/, $output)) { + + if (m|^[cpairhC\-]{7}\s+(\w+)$|) { + $name = $1; + $tables{$name}->{"name"} = $1; + next; + } + + if (m|Addresses:\s+([0-9]+)$|) { + $tables{$name}->{"addresses"} = $1; + next; + } + + if (m|Cleared:\s+(.+)$|) { + $tables{$name}->{"cleared"} = $1; + next; + } + + if (m|In/Block:\s+\[\s+Packets:\s+([0-9]+)\s+Bytes:\s+([0-9]+)\s+\]$|) { + $tables{$name}->{"inblockpackets"} = $1; + $tables{$name}->{"inblockbytes"} = $2; + next; + } + + if (m|In/Pass:\s+\[\s+Packets:\s+([0-9]+)\s+Bytes:\s+([0-9]+)\s+\]$|) { + $tables{$name}->{"inpasspackets"} = $1; + $tables{$name}->{"inpassbytes"} = $2; + next; + } + + if (m|In/XPass:\s+\[\s+Packets:\s+([0-9]+)\s+Bytes:\s+([0-9]+)\s+\]$|) { + $tables{$name}->{"inxpasspackets"} = $1; + $tables{$name}->{"inxpassbytes"} = $2; + next; + } + + if (m|Out/Block:\s+\[\s+Packets:\s+([0-9]+)\s+Bytes:\s+([0-9]+)\s+\]$|) { + $tables{$name}->{"outblockpackets"} = $1; + $tables{$name}->{"outblockbytes"} = $2; + next; + } + + if (m|Out/Pass:\s+\[\s+Packets:\s+([0-9]+)\s+Bytes:\s+([0-9]+)\s+\]$|) { + $tables{$name}->{"outpasspackets"} = $1; + $tables{$name}->{"outpassbytes"} = $2; + next; + } + + if (m|Out/XPass:\s+\[\s+Packets:\s+([0-9]+)\s+Bytes:\s+([0-9]+)\s+\]$|) { + $tables{$name}->{"outxpasspackets"} = $1; + $tables{$name}->{"outxpassbytes"} = $2; + next; + } + + } + + return %tables; + +} + +# vim:syntax=perl