Munin plugin for Shorewall accounting
I wrote this little script to monitor traffic on various machines at work. We use Shorewall to set up all the netfilter rules, traffic shaping, etc. It also makes it easy to set up rules to monitor traffic for different types of traffic.
We use Munin to track all sorts of things over time. The script below is a Munin plugin that will create a graph with one data series for each of the chains defined in your shorewall accounting file.
Put this script into /etc/munin/plugins and call it something like shorewall_accounting, and then add this in /etc/munin/plugin-conf.d/munin-node:
[shorewall_accounting]
user root
The name in between the square brackets should match the name of the file you saved the script in. The script needs to run as root in order to get access to iptables.
Edit Jan 20, 2006: Some minor bugfixes to the script have now been included. The shorewall accounting chains are now output in alphabetical order, and the regexp has been fixed to catch very large numbers.
#!/usr/bin/python # shorewall_accounting # A munin plugin for tracking traffic as recorded by shorewall accounting rules # Written by Chris AtLee <chris@atlee.ca> # Released under the GPL v2 import sys, commands, re accountingLineExp = re.compile(r"^\s*\d+\s+(\d+)\s+(\w+).*$") def getBytesByChain(): status, output = commands.getstatusoutput("shorewall -x show accounting") if status != 0: raise OSError("Error running command (%s)[%i]: %s" % (trafficCmd, status, output)) chains = {} for line in output.split("\n"): m = accountingLineExp.match(line) if m is not None: target = m.group(2) bytes = int(m.group(1)) if target in chains: chains[target] += bytes else: chains[target] = bytes retval = [] chainNames = chains.keys() chainNames.sort() for name in chainNames: retval.append((name, chains[name])) return retval if len(sys.argv) > 1: if sys.argv[1] == "autoconf": print "yes" sys.exit(0) elif sys.argv[1] == "config": print "graph_title Shorewall accounting" print "graph_category network" print "graph_vlabel bits per ${graph_period}" for chain,bytes in getBytesByChain(): print "%s.min 0" % chain print "%s.type DERIVE" % chain print "%s.label %s" % (chain, chain) print "%s.cdef %s,8,*" % (chain, chain) sys.exit(0) for chain, bytes in getBytesByChain(): print "%s.value %i" % (chain, bytes)

Bah! I finally remember to go grab my moustache pic from the Christmas dinner so that I include in as a historical artifact and your gallery isn’t working. What kind of techhead are you?
Wah!
Stupid web hosting changed the permissions on all my files. Should be ok now
[code]
#!/usr/bin/python
# shorewall_accounting
# A munin plugin for tracking traffic as recorded by shorewall accounting rules
# Written by Chris AtLee
# Released under the GPL v2
import sys, commands, re
accountingLineExp = re.compile(r"^\s*\d+[KMG]*\s+(\d+)([KMGT]*)\s+(\w+).*$")
def getBytesByChain():
trafficCmd = "shorewall"
status, output = commands.getstatusoutput("/sbin/shorewall show accounting 2>/dev/null")
if status != 0:
raise OSError("Error running command (%s)[%i]: %s" % (trafficCmd, status, output))
chains = {}
for line in output.split("\n"):
m = accountingLineExp.match(line)
if m is not None:
target = m.group(3)
bytes = int(m.group(1))
if m.group(2) == "K":
bytes *= 1024
elif m.group(2) == "M":
bytes *= 1024 * 1024
elif m.group(2) == "G":
bytes *= 1024 * 1024 * 1024
elif m.group(2) == "T":
bytes *= 1024 * 1024 * 1024 * 1024
if target in chains:
chains[target] += bytes
else:
chains[target] = bytes
# else:
# print "IGNORED LINE %s" % ( line)
retval = []
chainNames = chains.keys()
chainNames.sort()
for name in chainNames:
retval.append((name, chains[name]))
return retval
if len(sys.argv) > 1:
if sys.argv[1] == "autoconf":
print "yes"
sys.exit(0)
elif sys.argv[1] == "config":
print "graph_title Shorewall accounting"
print "graph_category network"
print "graph_vlabel bits per ${graph_period}"
for chain,bytes in getBytesByChain():
print "%s.min 0" % chain
print "%s.type DERIVE" % chain
print "%s.label %s" % (chain, chain)
print "%s.cdef %s,8,*" % (chain, chain)
sys.exit(0)
for chain, bytes in getBytesByChain():
print "%s.value %i" % (chain, bytes)
[/code]
Absolutely beautiful solution! It’s exactly what I was looking for. Thanks!
[...] copied the code from the website and fixed up all quote characters and other html issues, saved it to [...]