Contents
This HOWTO explains a quick and easy way to count network traffic (bytes sent over an interface) using only iptables.
It is here mainly because this way I can cut'n'paste it when I need it somewhere, myself. :-)
If you don't know what iptables, netfilter or Linux networking is, check out the iptables web site, especially an iptables tutorial which has in-depth explanations of all concepts. (Hint: all of this is only useful for Linux starting at Kernel version 2.4 or newer.)
A log file with the number of bytes transfered over some interface.
iptables automatically counts packages and bytes passing through each of its rules. It's easy to lose some bytes if there are rules matching more than one interface, so the following is added in front of all other rules. Feel free to do this for any other interface as well.
PPP=ppp0 iptables -N pppcount iptables -A INPUT -i $PPP -j pppcount iptables -A FORWARD -i $PPP -j pppcount iptables -A FORWARD -o $PPP -j pppcount iptables -A OUTPUT -o $PPP -j pppcount iptables -A pppcount
This trivial script logs all traffic passing through the "pppcount" rule and resets the count.
#!/bin/bash LOG=/var/log/traffic.log BYTES=`iptables -L pppcount -Z -vnx | tail -2 | head -1 | awk '{print $2}'` DATE=`date "+%Y-%m-%d %H:%M:%S"` echo $DATE $BYTES >> $LOG
The script is put into /etc/network/if-down.d and so is called whenever a network interface goes down.
It is safe to call that script at all times, not only if the interface goes down; if the interface did not see any traffic yet, it simply records 0 bytes. To make it less likely to lose traffic, it can also be called from anywhere related to network traffic (i.e., in your firewall setup script, at the beginning (before counts are reset); somewhere in /etc/ppp/ip-down.d, or wherever else).
Here is a perl script to evaluate the log file; it prints the traffic per day.
#!/usr/bin/perl my $log="/mnts/usbroot/var/log/dsltraffic.log"; open(LOG,$log) or die "$log: $!"; my %days; my %months; while (<LOG>) { if (m/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+) (\d+)$/) { $days{"$1$2$3"} += $7; $months{"$1$2"} += $7; } } close LOG; my $total=0; my $count=0; print "period : traffic per day/month | total traffic | avg/31 days\n"; foreach my $day (sort (keys %days,keys %months)) { if (exists($days{$day})) { my $traffic=$days{$day}; $total += $traffic; $count++; my $avg=$total/$count*31; printf "%-8s: %9.2f MB, %6.2f GB | %9.2f MB, %6.2f GB | %6.2f GB\n", $day, $traffic/1024/1024,$traffic/1024/1024/1024, $total/1024/1024,$total/1024/1024/1024, $avg/1024/1024/1024; } else { my $traffic=$months{$day}; printf "%-8s: %9.2f MB, %6.2f GB | |\n", $day, $traffic/1024/1024,$traffic/1024/1024/1024; } }
Example output:
period : traffic per day/month | total traffic | avg/31 days 200503 : 77.28 MB, 0.08 GB | | 20050327: 77.28 MB, 0.08 GB | 77.28 MB, 0.08 GB | 2.34 GB