#!/usr/bin/perl -w # # tor-bandwidth-usage - munin plugin to monitor Tor traffic # # To use this plugin you need the following: # o Enable accounting on torrc configuration file (even if you dont want to limit bandwidth usage, # just put a huge value for on AccountingMax) # example: # AccountingStart day 12:00 # AccountingMax 100 GB # o Enable CookieAuthentication (CookieAuthentication 1 in torrc) or define a HashedControlPassword # o Add something like the following to /etc/munin/plugin-conf.d/munin-node: # [tor-bandwidth-usage] # user debian-tor # env.cookiefile /var/run/tor/control.authcookie # # # tested with Tor releases: 0.2.1.28, 0.2.1.29, 0.2.2.35 # # Author: tazoi , based on a plugin by Ævar Arnfjörð Bjarmason # # Parameters understood (defined in file /etc/munin/plugin-conf.d/munin-node or in environment) # host - Change which host to graph (default localhost) # port - Change which port to connect to (default 9051) # password - Plain-text control channel password (see torrc # HashedControlPassword parameter) # cookiefile - Name of the file containing the control channel cookie # (see torrc CookieAuthentication parameter) # # Using HashedControlPassword authentication has the problem that you # must include the plain-text password in the munin config file. To # have any effect, that file shouldn't be world-readable. # # If you're using CookieAuthentication, you should run this plugin as # a user which has read access to the tor datafiles. Also note that # bugs in versions up to and including 0.1.1.20 prevent # CookieAuthentication from working. # # Usage: place in /etc/munin/plugins (or link it there using ln -s) # #%# family=contrib #%# capabilities=autoconf use strict; use feature ':5.10'; use IO::Socket::INET; use Munin::Plugin; # Config my $address = $ENV{host} || "localhost"; my $port = $ENV{port} || 9051; # Don't edit below this line sub Authenticate { my ($socket) = @_; my $authline = "AUTHENTICATE"; if (defined($ENV{cookiefile})) { if (open(COOKIE, "<$ENV{cookiefile}")) { my $cookie; binmode COOKIE; $authline .= " "; while (read(COOKIE, $cookie, 32)) { foreach my $byte (unpack "C*", $cookie) { $authline .= sprintf "%02x", $byte; } } close COOKIE; } } elsif (defined($ENV{password})) { $authline .= ' "' . $ENV{password} . '"'; } say $socket "$authline"; my $replyline = <$socket>; if (substr($replyline, 0, 1) != '2') { $replyline =~ s/\s*$//; return "Failed to authenticate: $replyline"; } return; } if ($ARGV[0] and $ARGV[0] eq "autoconf") { # Try to connect to the daemon my $socket = IO::Socket::INET->new("$address:$port") or my $failed = 1; if ($failed) { say "no (failed to connect to $address port $port)"; exit 1; } my $msg = Authenticate($socket); if (defined($msg)) { say $socket "QUIT"; close($socket); say "no ($msg)"; exit 1; } say $socket "QUIT"; close($socket); say "yes"; exit 0; } if ($ARGV[0] and $ARGV[0] eq "config") { say "graph_order down up"; say "graph_title Tor traffic"; say "graph_args --base 1000"; say "graph_vlabel bits in (-) / out (+) per \${graph_period}"; say "graph_category network"; say "graph_info This graph shows the traffic through this Tor node."; say "down.label received"; say "down.type DERIVE"; say 'down.graph no'; say "down.cdef down,8,*"; say "down.min 0"; say "up.label b/s"; say "up.type DERIVE"; say "up.negative down"; say "up.cdef up,8,*"; say "up.min 0"; exit 0; } my $socket = IO::Socket::INET->new("$address:$port") or die("Couldn't connect to $address port $port: $!"); my $msg = Authenticate($socket); if (defined($msg)) { say $socket "QUIT"; close($socket); die "$msg\n"; } say $socket "GETINFO accounting/bytes"; my $down = 0; my $up = 0; my $replyline = <$socket>; chomp($replyline); if ($replyline =~ /^250-accounting\/bytes=(\d+)\s(\d+)/) { $down = $1; $up = $2; } else { die "Failed to get accounting info: $replyline\n"; } say $socket "QUIT"; close($socket); say "down.value $down"; say "up.value $up"; exit 0;