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
# 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)