From e9c3bcc2aa8ea200ecb47b25e9c8c6408bd427ba Mon Sep 17 00:00:00 2001 From: David Reitz Date: Mon, 17 Jan 2011 01:51:57 +0100 Subject: [PATCH] Initial version --- .../d-link-dir-655-router-statistics-plugin | 239 ++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100755 plugins/other/d-link-dir-655-router-statistics-plugin diff --git a/plugins/other/d-link-dir-655-router-statistics-plugin b/plugins/other/d-link-dir-655-router-statistics-plugin new file mode 100755 index 00000000..ce1a4b60 --- /dev/null +++ b/plugins/other/d-link-dir-655-router-statistics-plugin @@ -0,0 +1,239 @@ +#!/usr/bin/ruby -rauto_gem +# +# 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 = Hash.new + nics["LAN"] = Hash.new + nics["WAN"] = Hash.new + nics["WLAN"] = Hash.new + 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 pasword 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 + + # graph overall interface packets transferred per interval + puts "multigraph if_packets" + for i in [ "LAN", "WAN", "WLAN" ] do + 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" + for i in [ "LAN", "WAN", "WLAN" ] do + 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" + for i in [ "LAN", "WAN", "WLAN" ] do + puts "#{i}_coll.value " + nics[i]["tx_collisions"] + puts "#{i}_err.value " + nics[i]["rx_errors"] + end + + # graph stats for each interface + for i in [ "LAN", "WAN", "WLAN" ] do + 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}' + for i in [ "LAN", "WAN", "WLAN" ] do + puts "#{i}_recv.type COUNTER" + puts "#{i}_recv.graph no" + puts "#{i}_recv.min 0" + puts "#{i}_send.label #{i}" + puts "#{i}_send.type COUNTER" + 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}' + for i in [ "LAN", "WAN", "WLAN" ] do + puts "#{i}_recv.type COUNTER" + puts "#{i}_recv.graph no" + puts "#{i}_recv.min 0" + puts "#{i}_send.label #{i}" + puts "#{i}_send.type COUNTER" + 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}' + for i in [ "LAN", "WAN", "WLAN" ] do + puts "#{i}_coll.label #{i} collisions" + puts "#{i}_coll.type COUNTER" + puts "#{i}_coll.min 0" + puts "#{i}_err.label #{i} errors" + puts "#{i}_err.type COUNTER" + puts "#{i}_err.min 0" + end + + puts "multigraph clients" + puts "graph_title D-Link DIR-655 client information" + puts "graph_category network" + 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" + + for i in [ "LAN", "WAN", "WLAN" ] do + 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 COUNTER' + puts 'recv.graph no' + puts 'recv.min 0' + puts 'send.label packets/sec' + puts 'send.type COUNTER' + 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 COUNTER' + puts 'recv.graph no' + puts 'recv.min 0' + puts 'send.label TX packets dropped' + puts 'send.type COUNTER' + 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 COUNTER' + puts 'coll.min 0' + puts 'err.label errors' + puts 'err.type COUNTER' + puts 'err.min 0' + end +end + + +# main +if ARGV.length == 1 and ARGV[0] == 'config' + config() +else + output() +end