#!/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 network\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 network\n"; # print "graph_printf %3.0lf\n"; print "in.label in\n"; print "in.type DERIVE\n"; print "in.draw AREA\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 bps\n"; print "out.type DERIVE\n"; print "out.negative in\n"; print "out.draw AREA\n"; print "out.colour COLOUR18\n"; print "out.cdef out,8,*\n"; print "out.min 0\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+(\S+)$|) { $name = $1; $name =~ s/\-/_/; $tables{$name}->{"name"} = $name; 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