#!/usr/bin/perl # -*- cperl -*- =head1 NAME TG585v7_ - Munin plugin to monitor the stats of a Thomson TG585 v7. =head1 APPLICABLE SYSTEMS Any system with access to a Thomson TG585 v7 ADSL router. Requires perl and either WWW::Mechanize or Net::Telnet. =head1 CONFIGURATION The plugin needs HTML access to the router. If you can get to http://YOUR_ROUTER/, and are greeting with a page titled "THOMSON TG585 v7", then you can probably use this plugin. This is a wildcard plugin, so you will need to create symlinks to this plugin (or create copies if your filesystem doesn't support linking). Links should be of the form: TG585v7__ where "" is one of "bandwidth", "power", "errors" or "uptime" (thus you probably want 4 symlinks in total. In addition, you may set the following environment variables: =over 4 =item user The username to login to the router as (Default: Administrator) =item pass The password to login to the router with (Default: Blank) =item mode How to connect to the router. Should be either C or C. (Default: C). =back =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf =head1 BUGS Please report bugs to L. =head1 AUTHOR Darac Marjal =head1 VERSION 2.0 =head1 CHANGELOG =over 4 =item 1.0 =over 4 =item * First release =back =item 2.0 =over 4 =item * Allowed connectiosndn via telnet, for when the webpage is unavailable. =back =back =head1 LICENSE GPL =cut use strict; use warnings; use lib $ENV{'MUNIN_LIBDIR'}; use Munin::Plugin; # Get configuration from environment my $USER = $ENV{user} || 'Administrator'; my $PASS = $ENV{pass} || ''; my $ACCESS_MODE = $ENV{mode} || 'telnet'; my $MUNIN_DEBUG = $ENV{MUNIN_DEBUG} || 0; my $ret; if ( $ACCESS_MODE eq 'http' and !eval "require WWW::Mechanize;" ) { $ret = "Could not load WWW::Mechanize"; } if ( $ACCESS_MODE eq 'telnet' and !eval "require Net::Telnet;" ) { $ret = "Could not load Net::Telnet"; } print "# Access Mode is: $ACCESS_MODE\n" if $MUNIN_DEBUG; if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) { if ($ret) { print "no ($ret)\n"; } else { print "yes\n"; } exit 0; } if ( defined $ARGV[0] and $ARGV[0] eq "suggest" ) { print join " ", sort qw(bandwidth power errors uptime firewall ids atm conntrack dhcpclient dhcprelay dhcpserver dns igmphost igmpproxy protoip prototcp protoudp protoicmp), "\n"; exit 0; } our @name_fields = split /_/, $0; if ( scalar @name_fields == 3 ) { if ( $name_fields[1] eq '' or $name_fields[2] eq '' ) { print "Misconfigured symlink. See Documentation\n"; exit 1; } } else { print "Misconfigured symlink. See Documentation\n"; exit 1; } my $host = $name_fields[1]; my $mode = $name_fields[2]; if ( defined $ARGV[0] and $ARGV[0] eq "config" ) { if ($ret) { print $ret; exit 1; } print "host_name $host\n" unless $host eq 'localhost'; if ( $mode eq 'bandwidth' ) { print <new(); $mech->credentials( $USER, $PASS ); if ( $mode eq 'bandwidth' or $mode eq 'power' or $mode eq 'errors' ) { print "# Fetching http://$host/cgi/b/dsl/dt/?be=0&l0=1&l1=0\n" if $MUNIN_DEBUG; $mech->get("http://$host/cgi/b/dsl/dt/?be=0&l0=1&l1=0"); } elsif ( $mode eq 'uptime' ) { print "# Fetching http://$host/cgi/b/bb/?be=0&l0=2&l1=-1\n" if $MUNIN_DEBUG; $mech->get("http://$host/cgi/b/bb/?be=0&l0=2&l1=-1"); } if ( $mech->success() ) { my $page = $mech->content; if ( $mode eq 'bandwidth' ) { $page =~ m{Bandwidth \(Up/Down\).*]+>([\d,\.]+) / ([\d,\.]+)}; my $upBW = $1; my $downBW = $2; $upBW =~ s/,//; $downBW =~ s/,//; print "down.value $downBW\n"; print "up.value $upBW\n"; } elsif ( $mode eq 'power' ) { $page =~ m{Output Power.*]+>([\d,\.]+) / ([\d,\.]+)}; my $upOUT = $1; my $downOUT = $2; $upOUT =~ s/,//; $downOUT =~ s/,//; $page =~ m{Line Attenuation.*]+>([\d,\.]+) / ([\d,\.]+)}; my $upLINE = $1; my $downLINE = $2; $upLINE =~ s/,//; $downLINE =~ s/,//; $page =~ m{SN Margin.*]+>([\d,\.]+) / ([\d,\.]+)}; my $upSN = $1; my $downSN = $2; $upSN =~ s/,//; $downSN =~ s/,//; print "downout.value $downOUT\n"; print "upout.value $upOUT\n"; print "downline.value $downLINE\n"; print "upline.value $upLINE\n"; print "downsn.value $downSN\n"; print "upsn.value $upSN\n"; } elsif ( $mode eq 'errors' ) { $page =~ m{FEC Errors.*]+>([\d,\.]+) / ([\d,\.]+)}; my $upFEC = $1; my $downFEC = $2; $upFEC =~ s/,//g; $downFEC =~ s/,//g; $page =~ m{CRC Errors.*]+>([\d,\.]+) / ([\d,\.]+)}; my $upCRC = $1; my $downCRC = $2; $upCRC =~ s/,//g; $downCRC =~ s/,//g; $page =~ m{HEC Errors.*]+>([\d,\.]+) / ([\d,\.]+)}; my $upHEC = $1; my $downHEC = $2; $upHEC =~ s/,//g; $downHEC =~ s/,//g; print "downFEC.value $downFEC\n"; print "upFEC.value $upFEC\n"; print "downCRC.value $downCRC\n"; print "upCRC.value $upCRC\n"; print "downHEC.value $downHEC\n"; print "upHEC.value $upHEC\n"; } elsif ( $mode eq 'uptime' ) { my ( $DSLRaw, $DSLUp, $iNetRaw, $iNetUp, $BoxRaw, $BoxUp ); if ( $page =~ m{Uptime:.*]+>(.*)}g ) { $DSLRaw = $1; $DSLUp = Uptime2Days($DSLRaw); } else { $DSLUp = 'U'; } if ( $page =~ m{Uptime:.*]+>(.*)}g ) { $iNetRaw = $1; $iNetUp = Uptime2Days($iNetRaw); } else { $iNetUp = 'U'; } print "# Fetching http://$host/cgi/b/cfg/ov/?be=0&l0=1&l1=1\n" if $MUNIN_DEBUG; $mech->get("http://$host/cgi/b/cfg/ov/?be=0&l0=1&l1=1"); $page = $mech->content; if ( $page =~ m{Time Since Power-on:.*]+>(.*)} ) { $BoxRaw = $1; $BoxUp = Uptime2Days($BoxRaw); } else { $BoxUp = 'U'; } print "Box.value $BoxUp\n"; print "Box.extinfo $BoxRaw\n"; print "DSL.value $DSLUp\n"; print "DSL.extinfo $DSLRaw\n"; print "iNet.value $iNetUp\n"; print "iNet.extinfo $iNetRaw\n"; } else { print "Don't know how to graph $mode\n"; exit 1; } exit 0; } } else { our $telnet; sub TelnetError { my $errmsg = shift; my %parts = ( 'atm' => [qw(RXCells RxErrors RxOctets TxCells TxErrors TxOctets)], 'bandwidth' => [qw(down downrate up uprate)], 'conntrack' => [qw(Active closing expected halfopen ICMP idle loose mcast non TCP TCPclosing TCPestablished TCPopen UDP)], 'dhcpclient' => [qw(ACKs Corrupted DECLINEs DISCOVERs failures INFORMs NAKs OFFERs Other RELEASEs REPLIES REQUESTs)], 'dhcprelay' => [qw(badc bogusg bogusr clientp corrupta missinga missingc packets serverp)], 'dhcpserver' => [qw(ACKs BOOTP Corrupted DECLINE DISCOVER dropped failures INFORM NAKs OFFERs Other RELEASE REQUEST)], 'dns' => [qw(corrupted discard external forwarded negative resolved spoofed spurious unknown)], 'errors' => [qw(downCRC downFEC downHEC upCRC upFEC upHEC)], 'firewall' => [qw(DroppedForward DroppedInput DroppedOutput ParsedForward ParsedInput ParsedOutput)], 'ids' => [qw(Active Collisions New Recycled Searches)], 'igmphost' => [qw(badchecksum badqueries badttl failing invalidmembership norouter receivedforour reportsreceived reportstransmitted toolong toosmall v1membershipq v2membershipq v3membershipq v3membershipr)], 'igmpproxy' => [qw(badchecksum badleavereports badqueries badreports badttl election igmpleavereports mrdadvertise mrdbad mrdsolicits mrdterminate noroute queriesfail toolong tooshort v1queriesr v1queriess v1reportsr v2queriesr v2queriess v2reportsr v3queriesr v3queriess v3reportsr)], 'power' => [qw(downline downout downsn upline upout upsn)], 'protoicmp' => [qw(echor echorepr echoreps echos errorsr errorss maskr maskrepr maskreps masks paramr params quenchr quenchs redirectr redirects timeexceedr timeexceeds timestampr timestamprepr timestampreps timestamps unreachabler unreachables)], 'protoip' => [qw(droppedfrags forwarded fragerrs fragged fragments fwderrors herrors hostdrop hostfwd hostrec noroute reassembled reserrors totfrags)], 'prototcp' => [qw(accepts attempts drops errors established received retransmitted transmitted)], 'protoudp' => [qw(dropped errors received transmitted)], 'uptime' => [qw(Box DSL iNet)] ); foreach ( @{$parts{$mode}} ) { print "$_.value U\n"; print "$_.extinfo $errmsg\n"; } print "# Sending \"exit\"\n" if $MUNIN_DEBUG; if ( defined $telnet ) { $telnet->errmode('return'); $telnet->print('exit'); $telnet->close; } exit 1; } print "# Connecting to $host:23...\n" if $MUNIN_DEBUG; $telnet = new Net::Telnet( Host => $host, Prompt => '/{.*}.*=>$/', ErrMode => \&TelnetError, Timeout => 10 ); print "# Logging in...\n" if $MUNIN_DEBUG; $telnet->login( Name => $USER, Password => $PASS ); if ( $mode eq 'bandwidth' ) { print "# Sending \"xdsl info expand enabled\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'xdsl info expand enabled' ); foreach (@lines) { if (/Payload rate .*:\s+(\d+)\s+(\d+)/) { print "down.value $1\n"; print "up.value $2\n"; } } print "# Sending \"ip iflist\"\n" if $MUNIN_DEBUG; @lines = $telnet->cmd( String => 'ip iflist' ); foreach (@lines) { if (/.*wan\s+\d+\s+(\d+)\s+(\d+)/) { print "downrate.value $1\n"; print "uprate.value $2\n"; } } } elsif ( $mode eq 'power' ) { print "# Sending \"xdsl info expand enabled\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'xdsl info expand enabled' ); foreach (@lines) { if (/Attenuation.*:\s+([0-9\.]+)\s+([0-9\.]+)/) { print "downline.value $1\n"; print "upline.value $2\n"; } elsif (/Margins.*:\s+([0-9\.]+)\s+([0-9\.]+)/) { print "downsn.value $1\n"; print "upsn.value $2\n"; } elsif (/Output power.*:\s+([0-9\.]+)\s+([0-9\.]+)/) { print "downout.value $1\n"; print "upout.value $2\n"; } } } elsif ( $mode eq 'errors' ) { print "# Sending \"xdsl info expand enabled\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'xdsl info expand enabled' ); my $state = 0; foreach (@lines) { if (/G.997.1 Statistics \(Current\)/) { $state = 1; } elsif (/G.997.1 Statistics \(last/) { $state = 0; } if ( $state == 1 and /Code Violation.*:\s+(\d+)/ ) { print "downCRC.value $1\n"; print "upCRC.value U\n"; } elsif ( $state == 1 and /FEC.*:\s+(\d+)/ ) { print "downFEC.value $1\n"; print "upFEC.value U\n"; } elsif ( $state == 1 and /HEC violation.*:\s+(\d+)\s+(\d+)/ ) { print "downHEC.value $1\n"; print "upHEC.value $2\n"; } } } elsif ( $mode eq 'uptime' ) { my ( $DSLRaw, $DSLUp, $iNetRaw, $iNetUp, $BoxRaw, $BoxUp ); $DSLUp = 'U'; $iNetUp = 'U'; $BoxUp = 'U'; print "# Sending \"xdsl info expand enabled\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'xdsl info expand enabled' ); foreach (@lines) { if (/Up time.*:\s+(.*)$/) { $DSLRaw = $1; $DSLUp = Uptime2Days($DSLRaw); } } print "# Sending \"system settime\"\n" if $MUNIN_DEBUG; @lines = $telnet->cmd( String => 'system settime' ); foreach (@lines) { if (/uptime = (.*)$/) { $BoxRaw = $1; $BoxUp = Uptime2Days($BoxRaw); } } print "# Sending \"ppp iflist\"\n" if $MUNIN_DEBUG; @lines = $telnet->cmd( String => 'ppp iflist' ); foreach (@lines) { if (/\[(\d+:\d+:\d+)\]/) { $iNetRaw = $1; $iNetUp = Uptime2Days("0 days, $iNetRaw"); } } print "Box.value $BoxUp\n"; print "Box.extinfo $BoxRaw\n"; print "DSL.value $DSLUp\n"; print "DSL.extinfo $DSLRaw\n"; print "iNet.value $iNetUp\n"; print "iNet.extinfo $iNetRaw\n"; } elsif ( $mode eq 'firewall' ) { my ( $PI, $PO, $PF, $DI, $DO, $DF ) = ( 'U', 'U', 'U', 'U', 'U', 'U' ); print "# Sending \"firewall debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'firewall debug stats' ); foreach (@lines) { $PI = $1 if (/Packets parsed in hook sink\s+:\s+(\d+)/); $PO = $1 if (/Packets parsed in hook source\s+:\s+(\d+)/); $PF = $1 if (/Packets parsed in hook forward\s+:\s+(\d+)/); $DI = $1 if (/Packets dropped in hook sink\s+:\s+(\d+)/); $DO = $1 if (/Packets dropped in hook source\s+:\s+(\d+)/); $DF = $1 if (/Packets dropped in hook forward\s+:\s+(\d+)/); } print "ParsedInput.value $PI\n"; print "ParsedOutput.value $PO\n"; print "ParsedForward.value $PF\n"; print "DroppedInput.value $DI\n"; print "DroppedOutput.value $DO\n"; print "DroppedForward.value $DF\n"; } elsif ( $mode eq 'ids' ) { my ( $Active, $Recycled, $Searches, $New, $Collisions ) = ( 'U', 'U', 'U', 'U', 'U' ); print "# Sending \"ids pattern stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'ids pattern stats' ); foreach (@lines) { $Active = $1 if (/number of active patterns\s+:\s+(\d+)/); $Recycled = $1 if (/number of recycled patterns\s+:\s+(\d+)/); $Searches = $1 if (/number of pattern searches\s+:\s+(\d+)/); $New = $1 if (/number of new patterns\s+:\s+(\d+)/); $Collisions = $1 if (/number of hash collisions\s+:\s+(\d+)/); } print "Active.value $Active\n"; print "Recycled.value $Recycled\n"; print "Searches.value $Searches\n"; print "New.value $New\n"; print "Collisions.value $Collisions\n"; } elsif ( $mode eq 'atm' ) { my ( $RxO, $RxC, $RxE, $TxO, $TxC, $TxE ) = ( 'U', 'U', 'U', 'U', 'U', 'U' ); print "# Sending \"atm debug gstats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'atm debug gstats' ); foreach (@lines) { $RxO = $1 if (/received octets\s+=\s+(\d+)/); $RxC = $1 if (/received cells\s+=\s+(\d+)/); $RxE = $1 if (/errors on the input\s+=\s+(\d+)/); $TxO = $1 if (/transmitted octets\s+=\s+(\d+)/); $TxC = $1 if (/transmitted cells\s+=\s+(\d+)/); $TxE = $1 if (/errors on output\s+=\s+(\d+)/); } print "RxOctets.value $RxO\n"; print "RxCells.value $RxC\n"; print "RxErrors.value $RxE\n"; print "TxOctets.value $TxO\n"; print "TxCells.value $TxC\n"; print "TxErrors.value $TxE\n"; } elsif ( $mode eq 'conntrack' ) { print "# Sending \"connection stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'connection stats' ); foreach (@lines) { if (/^Number of (.*) connections\s+:\s+(\d+)/) { my $field = $1; my $value = $2; $field =~ s/\s+//g; $field = 'non' if ( $field eq "nonTCP/UDP/ICMP" ); print "$field.value $value\n"; } } } elsif ( $mode eq 'dhcpclient' ) { print "# Sending \"dhcp client debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'dhcp client debug stats' ); foreach (@lines) { chomp; print "# Got '$_'\n" if $MUNIN_DEBUG; if ( /(Corrupted) packet recv\s+:\s+(\d+)/ or /(\S+)\s+recv\s+:\s+(\d+)/ or /(\S+)\s+sent\s+:\s+(\d+)/ or /Pure BOOTP (REPLIES)\s+:\s+(\d+)/ or /(Other) message types\s+:\s+(\d+)/ or /Packet\s+sent (failures)\s+:\s+(\d+)/ ) { print "$1.value $2\n"; } } } elsif ( $mode eq 'dhcprelay' ) { print "# Sending \"dhcp relay debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'dhcp relay debug stats' ); foreach (@lines) { if (/(\S+\s+\S).*:\s+(\d+)/) { my $field = $1; my $value = $2; $field =~ s/\s+//g; $field = lc $field; print "$field.value $value\n"; } } } elsif ( $mode eq 'dhcpserver' ) { print "# Sending \"dhcp server debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'dhcp server debug stats' ); foreach (@lines) { print "# Got '$_'\n" if $MUNIN_DEBUG; if ( /(Corrupted) packet recv\s+:\s+(\d+)/ or /^(\S+)\s+:\s+(\d+)/ or /Pure (BOOTP) REQUESTS\s+:\s+(\d+)/ or /(Other) message types\s+:\s+(\d+)/ or /(\S+) sent\s+:\s+(\d+)/ or /Packet sent (failures)\s+:\s+(\d+)/ or /Relay agent options (dropped)\s+:\s+(\d+)/ ) { print "$1.value $2\n"; } } } elsif ( $mode eq 'dns' ) { print "# Sending \"dns server debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'dns server debug stats' ); my @kw = qw(corrupted resolved negative forwarded external spoofed discard spurious unknown); foreach (@lines) { foreach my $kw (@kw) { if (/$kw.*:\s+(\d+)/i) { print "$kw.value $1\n"; } } } } elsif ( $mode eq 'igmphost' ) { print "# Sending \"igmp host debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'igmp host debug stats' ); my @kw = qw(toosmall toolong badchecksum badttl norouter v1membershipq v2membershipq v3membershipq badqueries failing reportsreceived invalidmembership receivedforour reportstransmitted v3membershipr); foreach (@lines) { chomp; print "# Got '$_'\n" if $MUNIN_DEBUG; if (/(.*)\s+:\s+(\d+)/) { my $field = lc $1; my $value = $2; $field =~ s/\s+//g; foreach my $kw (@kw) { if ( $field =~ /$kw/ ) { print "$kw.value $value\n"; } } } } } elsif ( $mode eq 'igmpproxy' ) { print "# Sending \"igmp proxy debug stats\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'igmp proxy debug stats' ); my @kw = qw(tooshort toolong badchecksum badttl noroute v1queriesr v2queriesr v3queriesr badqueries queriesfail v1reportsr v2reportsr v3reportsr badreports igmpleavereports badleavereports v1queriess v2queriess v3queriess election mrdsolicits mrdbad mrdadvertise mrdterminate); foreach (@lines) { chomp; print "# Got '$_'\n" if $MUNIN_DEBUG; if (/(.*)\s*:\s+(\d+)/) { my $field = lc $1; my $value = $2; $field =~ s/\s+//g; foreach my $kw (@kw) { if ( $field =~ /$kw/ ) { print "$kw.value $value\n"; } } } } } elsif ( $mode eq 'protoip' ) { print "# Sending \"ip debug stats proto=ip\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'ip debug stats proto=ip' ); my %kws = ( herrors => 'IP header errors', forwarded => 'Datagrams forwarded', fwderrors => 'Datagram forwarding errors', reserrors => 'Datagram forwarding resource errors', noroute => 'Datagram dropped due to no route', fragments => 'Total Fragments received', droppedfrags => 'Fragments dropped due to resources or timeouts', reassembled => 'Datagrams reassembled', hostrec => 'Host datagrams received', hostfwd => 'Host datagrams forwarded', hostdrop => 'Host datagrams dropped due to unknown proto', fragged => 'Datagrams fragmented successfully', fragerrs => 'Datagram fragmentation errors', totfrags => 'Total Datagram fragments created successfully' ); foreach (@lines) { chomp; print "# Got '$_'\n" if $MUNIN_DEBUG; if (/(.*)\s+:\s+(\d+)/) { my $field = $1; my $value = $2; foreach my $kw ( keys %kws ) { if ( $field =~ /$kws{$kw}/ ) { print "$kw.value $value\n"; } } } } } elsif ( $mode eq 'prototcp' ) { print "# Sending \"ip debug stats proto=tcp\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'ip debug stats proto=tcp' ); my @kw = qw(attempts accepts drops established received transmitted retransmitted errors); foreach (@lines) { chomp; print "# Got '$_'\n" if $MUNIN_DEBUG; foreach my $kw (@kw) { if (/\b$kw\b.*:\s+(\d+)/) { print "$kw.value $1\n"; } } } } elsif ( $mode eq 'protoudp' ) { print "# Sending \"ip debug stats proto=udp\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'ip debug stats proto=udp' ); my @kw = qw(received transmitted dropped errors); foreach (@lines) { foreach my $kw (@kw) { if (/$kw.*:\s+(\d+)/) { print "$kw.value $1\n"; } } } } elsif ( $mode eq 'protoicmp' ) { print "# Sending \"ip debug stats proto=icmp\"\n" if $MUNIN_DEBUG; my @lines = $telnet->cmd( String => 'ip debug stats proto=icmp' ); my %kws = ( errors => 'packet errors', unreachable => 'destination unreachable', timeexceed => 'time exceeded', param => 'param problem', quench => 'source quench', redirect => 'redirect', echo => 'echo', echorep => 'echo reply', timestamp => 'timestamp request', timestamprep => 'timestamp reply', mask => 'mask request', maskrep => 'mask reply' ); my $sentrecv = 'U'; foreach (@lines) { chomp; print "# Got '$_'\n" if $MUNIN_DEBUG; if (/Total ICMP datagrams received/) { print "# SentRecv => r\n" if $MUNIN_DEBUG; $sentrecv = 'r'; next; } if (/Total ICMP datagrams transmitted/) { print "# SentRecv => s\n" if $MUNIN_DEBUG; $sentrecv = 's'; next; } if (/ICMP\s+(.*)\s+:\s+(\d+)/) { my $field = $1; my $value = $2; foreach my $kw ( keys %kws ) { if ( $field =~ /^\s*$kws{$kw}\s*$/ ) { print "${kw}${sentrecv}.value $value\n"; } } } } } print "# Sending \"exit\"\n" if $MUNIN_DEBUG; $telnet->print('exit'); $telnet->close; exit 0; }