2009-12-25 16:51:48 +01:00
|
|
|
#!/usr/bin/perl -w
|
|
|
|
#
|
|
|
|
# Munin plugin to monitor Tor routers
|
|
|
|
#
|
|
|
|
# Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>, based on a plugin by Ge van Geldorp <ge@gse.nl>
|
|
|
|
#
|
|
|
|
# Parameters understood:
|
|
|
|
#
|
|
|
|
# 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
|
2014-12-05 00:37:42 +01:00
|
|
|
# up to and including 0.1.1.20 prevent CookieAuthentication from working.
|
2009-12-25 16:51:48 +01:00
|
|
|
#
|
|
|
|
# Usage: place in /etc/munin/node.d/ (or link it there using ln -s)
|
|
|
|
#
|
|
|
|
# Parameters understood:
|
|
|
|
# config (required)
|
|
|
|
# autoconf (optional - used by munin-config)
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Magic markers - optional - used by installation scripts and
|
|
|
|
# munin-config:
|
|
|
|
#
|
|
|
|
#%# family=contrib
|
|
|
|
#%# capabilities=autoconf
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use IO::Socket::INET;
|
|
|
|
|
|
|
|
# Config
|
|
|
|
our $address = $ENV{host} || "localhost"; # Default: localhost
|
|
|
|
our $port = $ENV{port} || 9051; # Default: 9051
|
|
|
|
|
|
|
|
# Don't edit below this line
|
|
|
|
|
|
|
|
sub Authenticate
|
|
|
|
{
|
|
|
|
my ($socket) = @_;
|
|
|
|
my $authline = "AUTHENTICATE";
|
|
|
|
if (defined($ENV{cookiefile})) {
|
|
|
|
if (open(COOKIE, "<$ENV{cookiefile}")) {
|
|
|
|
binmode COOKIE;
|
|
|
|
my $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} . '"';
|
|
|
|
}
|
|
|
|
print $socket "$authline\r\n";
|
|
|
|
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) {
|
|
|
|
print "no (failed to connect to $address port $port)\n";
|
2018-09-16 04:01:57 +02:00
|
|
|
exit 0;
|
2009-12-25 16:51:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
my $msg = Authenticate($socket);
|
|
|
|
if (defined($msg)) {
|
|
|
|
print $socket "QUIT\r\n";
|
|
|
|
close($socket);
|
|
|
|
print "no ($msg)\n";
|
2018-09-16 04:01:57 +02:00
|
|
|
exit 0;
|
2009-12-25 16:51:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
print $socket "QUIT\r\n";
|
|
|
|
close($socket);
|
|
|
|
print "yes\n";
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($ARGV[0] and $ARGV[0] eq "config") {
|
|
|
|
print "graph_title Routers\n";
|
|
|
|
print "graph_args -l 0\n";
|
|
|
|
print "graph_vlabel routers\n";
|
2017-02-23 20:45:01 +01:00
|
|
|
print "graph_category network\n";
|
2009-12-25 16:51:48 +01:00
|
|
|
print "graph_info This graph shows the number of known Tor ORs.\n";
|
|
|
|
|
|
|
|
print "ors.label routers\n";
|
|
|
|
print "ors.type GAUGE\n";
|
|
|
|
print "ors.info The number of known Tor ORs (onion routers)\n";
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
print $socket "QUIT\r\n";
|
|
|
|
close($socket);
|
|
|
|
die "$msg\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
print $socket "GETINFO ns/all\r\n";
|
|
|
|
my $replyline = <$socket>;
|
|
|
|
if (substr($replyline, 0, 1) != '2') {
|
|
|
|
print $socket "QUIT\r\n";
|
|
|
|
close($socket);
|
|
|
|
$replyline =~ s/\s*$//;
|
|
|
|
die "Failed to get orconn-status info: $replyline\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
my $count;
|
|
|
|
while (! (($replyline = <$socket>) =~ /^\.\s*$/)) {
|
|
|
|
my @reply = split(/\s+/, $replyline);
|
|
|
|
$count++ if $reply[0] eq 'r';
|
|
|
|
}
|
|
|
|
$replyline = <$socket>;
|
|
|
|
if (substr($replyline, 0, 1) != '2') {
|
|
|
|
print $socket "QUIT\r\n";
|
|
|
|
close($socket);
|
|
|
|
$replyline =~ s/\s*$//;
|
|
|
|
die "Failed to authenticate: $replyline\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
print $socket "QUIT\r\n";
|
|
|
|
close($socket);
|
|
|
|
|
|
|
|
print "ors.value $count\n";
|
|
|
|
|
|
|
|
exit 0;
|
|
|
|
|
|
|
|
# vim:syntax=perl
|