munin-contrib/plugins/router/d-link-dir-655-router-stati...

251 lines
8.7 KiB
Ruby
Executable File

#!/usr/bin/env ruby
#
# Munin plugin for the D-link DIR-655 router
#
# This plugin can graph # of wifi clients, # of DHCP clients, collisions & errors for all network interfaces, dropped packets for all interfaces, and both transmit and receive rates for all interfaces of the router.
#
# Author: David Reitz
#
# 1. Copy script to a Linux server on your network.
# 2. Create symlink. (ln -s /path/to/dlink_dir655 /etc/munin/plugins/dlink_dir655)
# 3. Edit plugin configuration for this script (vi /etc/munin/plugin-conf.d/munin-node) and add:
# [dlink_dir655]
# host_name dir655
# env.router_password password
# env.router_ip_address 10.0.0.1
# 4. Edit munin configuration to point to itself to gather the data from your router (vi /etc/munin/munin-conf.d/munin) and add:
# [dir655]
# address 127.0.0.1
# use_node_name no
# 5. Modify the 'password' and 'router_path' variables below to reflect the correct password for the 'User' user on your D-link DIR-655 router and to reflect the correct IP address of your router (this *MUST* be on your local subnet/LAN).
#
# NOTICE 1: This is the first Ruby script I've written (as well as being my first Munin plugin), so I consider this a bit of a hack. Just letting you know ahead of time. :)
#
# NOTICE 2: I provide this script *as-is*. Use at your own risk! I thought other people may find this script useful/interesting but have no plans to support it for anyone else.
#
# Many thanks go to Clarke Brunsdon for his code listed at http://clarkebrunsdon.com/2010/12/the-dlink-dir-655-hash-changes/!!! This really helped me out!
#
# Original Implementation: 13 Jan 2011
gem 'mechanize'
require 'mechanize'
require 'digest/md5'
require 'nokogiri'
def output
nics = {}
nics['LAN'] = {}
nics['WAN'] = {}
nics['WLAN'] = {}
password = ENV['router_password'] || ''
router_path = ENV['router_ip_address'] || '10.0.0.1'
router_path = 'http://' + router_path
agent = Mechanize.new
x = agent.get(router_path)
salt = x.body.match(/salt = "(.*)"/)[1]
# pad the password to length 16
pad_size = (16 - password.length)
padded_password = password + "\x01" * pad_size
# pad it the rest of the way, length 64 for user
salted_password = salt + padded_password + ("\x01" * (63 - salt.length - padded_password.length)) + 'U'
login_hash = salt + Digest::MD5.hexdigest(salted_password)
# authenticate against the router using the hash that we just built
login_path = "#{router_path}/post_login.xml?hash=#{login_hash}"
x = agent.get(login_path)
# grab the statistics for all interfaces and parse it into a usable form
clients_xml = agent.get("#{router_path}/interface_stats.xml").body
doc = Nokogiri::XML(clients_xml.to_s)
doc.xpath('//interface').each do |interface|
children = interface.children
name = children.search('name')[0].text
nics[name]['packets_sent'] = children.search('packets_sent')[0].text
nics[name]['packets_received'] = children.search('packets_received')[0].text
nics[name]['tx_dropped'] = children.search('tx_dropped')[0].text
begin
nics[name]['tx_collisions'] = children.search('tx_collisions')[0].text
rescue Exception
nics[name]['tx_collisions'] = '0'
end
nics[name]['rx_dropped'] = children.search('rx_dropped')[0].text
nics[name]['rx_errors'] = children.search('rx_errors')[0].text
end
# get wifi associations and print out info for munin graph
puts 'multigraph clients'
clients_xml = agent.get("#{router_path}/wifi_assoc.xml").body
j = 0
doc = Nokogiri::XML(clients_xml.to_s)
doc.xpath('//assoc').each do |_assoc|
j += 1
end
puts 'wifi_assoc.value ' + j.to_s
# get dhcp clients and print out info for munin graph
clients_xml = agent.get("#{router_path}/dhcp_clients.xml").body
j = 0
doc = Nokogiri::XML(clients_xml.to_s)
doc.xpath('//client').each do |_client|
j += 1
end
puts 'dhcp_clients.value ' + j.to_s
puts 'multigraph uptime'
# get uptime of connection
clients_xml = agent.get("#{router_path}/wan_connection_status.xml").body
doc = Nokogiri::XML(clients_xml.to_s)
uptime = doc.children.search('wan_interface_up_time_0')[0].text
puts 'uptime.value ' + format('%.2f', (Float(uptime) / 86_400))
# graph overall interface packets transferred per interval
puts 'multigraph if_packets'
%w[LAN WAN WLAN].each do |i|
puts "#{i}_recv.value " + nics[i]['packets_received']
puts "#{i}_send.value " + nics[i]['packets_sent']
end
# graph overall interface dropped packets per interval
puts 'multigraph if_drop'
%w[LAN WAN WLAN].each do |i|
puts "#{i}_recv.value " + nics[i]['rx_dropped']
puts "#{i}_send.value " + nics[i]['tx_dropped']
end
# graph overall interface collisions & errors per interval
puts 'multigraph if_collerr'
%w[LAN WAN WLAN].each do |i|
puts "#{i}_coll.value " + nics[i]['tx_collisions']
puts "#{i}_err.value " + nics[i]['rx_errors']
end
# graph stats for each interface
%w[LAN WAN WLAN].each do |i|
puts "multigraph if_packets.#{i}"
puts 'send.value ' + nics[i]['packets_sent']
puts 'recv.value ' + nics[i]['packets_received']
puts "multigraph if_drop.#{i}"
puts 'send.value ' + nics[i]['tx_dropped']
puts 'recv.value ' + nics[i]['rx_dropped']
puts "multigraph if_collerr.#{i}"
puts 'coll.value ' + nics[i]['tx_collisions']
puts 'err.value ' + nics[i]['rx_errors']
end
end
def config
# build the configuration for graphs
puts 'multigraph if_packets'
puts 'graph_title D-Link DIR-655 interface traffic'
puts 'graph_category network'
puts 'graph_order LAN_recv LAN_send WAN_recv WAN_send WLAN_recv WLAN_send'
puts 'graph_vlabel packets in (-) / out (+) per ${graph_period}'
%w[LAN WAN WLAN].each do |i|
puts "#{i}_recv.type DERIVE"
puts "#{i}_recv.graph no"
puts "#{i}_recv.min 0"
puts "#{i}_send.label #{i}"
puts "#{i}_send.type DERIVE"
puts "#{i}_send.negative #{i}_recv"
puts "#{i}_send.min 0"
end
puts 'multigraph if_drop'
puts 'graph_title D-Link DIR-655 interface drops'
puts 'graph_category network'
puts 'graph_order LAN_recv LAN_send WAN_recv WAN_send WLAN_recv WLAN_send'
puts 'graph_vlabel packets / ${graph_period}'
%w[LAN WAN WLAN].each do |i|
puts "#{i}_recv.type DERIVE"
puts "#{i}_recv.graph no"
puts "#{i}_recv.min 0"
puts "#{i}_send.label #{i}"
puts "#{i}_send.type DERIVE"
puts "#{i}_send.negative #{i}_recv"
puts "#{i}_send.min 0"
end
puts 'multigraph if_collerr'
puts 'graph_title D-Link DIR-655 interface collisions & errors'
puts 'graph_category network'
puts 'graph_order LAN_coll LAN_err WAN_coll WAN_err WLAN_coll WLAN_coll'
puts 'graph_vlabel packets / ${graph_period}'
%w[LAN WAN WLAN].each do |i|
puts "#{i}_coll.label #{i} collisions"
puts "#{i}_coll.type DERIVE"
puts "#{i}_coll.min 0"
puts "#{i}_err.label #{i} errors"
puts "#{i}_err.type DERIVE"
puts "#{i}_err.min 0"
end
puts 'multigraph clients'
puts 'graph_title D-Link DIR-655 client information'
puts 'graph_category system'
puts 'graph_order dhcp_clients wifi_assoc'
puts 'graph_vlabel number of clients'
puts 'dhcp_clients.label DHCP clients'
puts 'dhcp_clients.type GAUGE'
puts 'dhcp_clients.min 0'
puts 'wifi_assoc.label wifi clients'
puts 'wifi_assoc.type GAUGE'
puts 'wifi_assoc.min 0'
puts 'multigraph uptime'
puts 'graph_title Uptime'
puts 'graph_vlabel uptime in days'
puts 'graph_category system'
puts 'uptime.label uptime'
puts 'uptime.draw AREA'
%w[LAN WAN WLAN].each do |i|
puts "multigraph if_packets.#{i}"
puts "graph_title D-Link DIR-655 #{i} traffic"
puts 'graph_category network'
puts 'graph_order recv send'
puts 'graph_vlabel packets in (-) / out (+) per ${graph_period}'
puts 'recv.label received'
puts 'recv.type DERIVE'
puts 'recv.graph no'
puts 'recv.min 0'
puts 'send.label packets/sec'
puts 'send.type DERIVE'
puts 'send.negative recv'
puts 'send.min 0'
puts "multigraph if_drop.#{i}"
puts "graph_title D-Link DIR-655 #{i} drops"
puts 'graph_category network'
puts 'graph_order recv send'
puts 'graph_vlabel packets / ${graph_period}'
puts 'recv.label RX packets dropped'
puts 'recv.type DERIVE'
puts 'recv.graph no'
puts 'recv.min 0'
puts 'send.label TX packets dropped'
puts 'send.type DERIVE'
puts 'send.negative recv'
puts 'send.min 0'
puts "multigraph if_collerr.#{i}"
puts "graph_title D-Link DIR-655 #{i} collisions & errors"
puts 'graph_category network'
puts 'graph_order coll err'
puts 'graph_vlabel packets / ${graph_period}'
puts 'coll.label collisions'
puts 'coll.type DERIVE'
puts 'coll.min 0'
puts 'err.label errors'
puts 'err.type DERIVE'
puts 'err.min 0'
end
end
# main
if (ARGV.length == 1) && (ARGV[0] == 'config')
config
else
output
end