My favorites | Sign in
Project Hosting will be READ-ONLY Thursday at 3:00pm UTC for up to 3 hours for network maintenance.
Project Home Downloads Wiki Issues Source
Repository:
Checkout   Browse   Changes   Clones    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#!/bin/sh
#
# Traffic logging tool for OpenWRT-based routers
#
# Created by Emmanuel Brucy (e.brucy AT qut.edu.au)
#
# Based on work from Fredrik Erlandsson (erlis AT linux.nu)
# Based on traff_graph script by twist - http://wiki.openwrt.org/RrdTrafficWatch
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

LAN_IFACE=$(nvram get lan_ifname)

lock()
{
while [ -f /tmp/wrtbwmon.lock ]; do
if [ ! -d /proc/$(cat /tmp/wrtbwmon.lock) ]; then
echo "WARNING : Lockfile detected but process $(cat /tmp/wrtbwmon.lock) does not exist !"
rm -f /tmp/wrtbwmon.lock
fi
sleep 1
done
echo $$ > /tmp/wrtbwmon.lock
}

unlock()
{
rm -f /tmp/wrtbwmon.lock
}

case ${1} in

"setup" )

#Create the RRDIPT CHAIN (it doesn't matter if it already exists).
iptables -N RRDIPT 2> /dev/null

#Add the RRDIPT CHAIN to the FORWARD chain (if non existing).
iptables -L FORWARD --line-numbers -n | grep "RRDIPT" | grep "1" > /dev/null
if [ $? -ne 0 ]; then
iptables -L FORWARD -n | grep "RRDIPT" > /dev/null
if [ $? -eq 0 ]; then
echo "DEBUG : iptables chain misplaced, recreating it..."
iptables -D FORWARD -j RRDIPT
fi
iptables -I FORWARD -j RRDIPT
fi

#For each host in the ARP table
grep ${LAN_IFACE} /proc/net/arp | while read IP TYPE FLAGS MAC MASK IFACE
do
#Add iptable rules (if non existing).
iptables -nL RRDIPT | grep "${IP} " > /dev/null
if [ $? -ne 0 ]; then
iptables -I RRDIPT -d ${IP} -j RETURN
iptables -I RRDIPT -s ${IP} -j RETURN
fi
done
;;

"update" )
[ -z "${2}" ] && echo "ERROR : Missing argument 2" && exit 1

# Uncomment this line if you want to abort if database not found
# [ -f "${2}" ] || exit 1

lock

#Read and reset counters
iptables -L RRDIPT -vnxZ -t filter > /tmp/traffic_$$.tmp

grep -v "0x0" /proc/net/arp | while read IP TYPE FLAGS MAC MASK IFACE
do
#Add new data to the graph. Count in Kbs to deal with 16 bits signed values (up to 2G only)
#Have to use temporary files because of crappy busybox shell
echo 0 > /tmp/in_$$.tmp
echo 0 > /tmp/out_$$.tmp
grep ${IP} /tmp/traffic_$$.tmp | while read PKTS BYTES TARGET PROT OPT IFIN IFOUT SRC DST
do
[ "${DST}" = "${IP}" ] && echo $((${BYTES}/1000)) > /tmp/in_$$.tmp
[ "${SRC}" = "${IP}" ] && echo $((${BYTES}/1000)) > /tmp/out_$$.tmp
done
IN=$(cat /tmp/in_$$.tmp)
OUT=$(cat /tmp/out_$$.tmp)

if [ ${IN} -gt 0 -o ${OUT} -gt 0 ]; then
echo "DEBUG : New traffic for ${MAC} since last update : ${IN}k:${OUT}k"

LINE=$(grep ${MAC} ${2})
if [ -z "${LINE}" ]; then
echo "DEBUG : ${MAC} is a new host !"
PEAKUSAGE_IN=0
PEAKUSAGE_OUT=0
OFFPEAKUSAGE_IN=0
OFFPEAKUSAGE_OUT=0
else
PEAKUSAGE_IN=$(echo ${LINE} | cut -f3 -s -d, )
PEAKUSAGE_OUT=$(echo ${LINE} | cut -f4 -s -d, )
OFFPEAKUSAGE_IN=$(echo ${LINE} | cut -f5 -s -d, )
OFFPEAKUSAGE_OUT=$(echo ${LINE} | cut -f6 -s -d, )
fi

if [ "${3}" = "offpeak" ]; then
OFFPEAKUSAGE_IN=$((${OFFPEAKUSAGE_IN}+${IN}))
OFFPEAKUSAGE_OUT=$((${OFFPEAKUSAGE_OUT}+${OUT}))
else
PEAKUSAGE_IN=$((${PEAKUSAGE_IN}+${IN}))
PEAKUSAGE_OUT=$((${PEAKUSAGE_OUT}+${OUT}))
fi

grep -v "${MAC}" ${2} > /tmp/db_$$.tmp
mv /tmp/db_$$.tmp ${2}
echo ${MAC},${IP},${PEAKUSAGE_IN},${PEAKUSAGE_OUT},${OFFPEAKUSAGE_IN},${OFFPEAKUSAGE_OUT},$(date "+%s") >> ${2}
fi
done

#Free some memory
rm -f /tmp/*_$$.tmp
unlock
;;

"publish" )

[ -z "${2}" ] && echo "ERROR : Missing argument 2" && exit 1
[ -z "${3}" ] && echo "ERROR : Missing argument 3" && exit 1

USERSFILE="/etc/dnsmasq.conf"
[ -f "${USERSFILE}" ] || USERSFILE="/tmp/dnsmasq.conf"
[ -z "${4}" ] || USERSFILE=${4}
[ -f "${USERSFILE}" ] || USERSFILE="/dev/null"

# create HTML page
echo "<html><head><title>Traffic</title><script type=\"text/javascript\">" > ${3}
echo "function getSize(size) {" >> ${3}
echo "var prefix=new Array(\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\");var base=1000;" >> ${3}
echo "var pos=0;while(size>base){size/=base;pos++;}if(pos>2)precision=1000;else precision=1;" >> ${3}
echo "return(Math.round(size*precision)/precision)+' '+prefix[pos];}" >> ${3}
echo "</script></head><body><h1>Total Usage :</h1>" >> ${3}
echo "<table border="1"><tr bgcolor=silver><th>User</th><th>Peak download</th><th>Peak upload</th><th>Offpeak download</th><th>Offpeak upload</th><th>Last seen</th></tr>" >> ${3}
echo "<script type=\"text/javascript\">" >> ${3}

echo "var values = new Array(" >> ${3}
lock
cat ${2} | while IFS=, read MAC IP PEAKUSAGE_IN PEAKUSAGE_OUT OFFPEAKUSAGE_IN OFFPEAKUSAGE_OUT LASTSEEN
do
echo "new Array(" >> ${3}
USER=$(grep "${MAC}" "${USERSFILE}" | cut -f2 -s -d, )
[ -z "$USER" ] && USER=${MAC}
echo "\"${USER}\",${PEAKUSAGE_IN}000,${PEAKUSAGE_OUT}000,${OFFPEAKUSAGE_IN}000,${OFFPEAKUSAGE_OUT}000,${LASTSEEN}000)," >> ${3}
done
unlock
echo "0);" >> ${3}

echo "var dv = new Array();for (i=0;i<values.length-1;i++){found=0;for(j=i+1;j<values.length-1;j++){if(values[i][0]==values[j][0]){" >> ${3}
echo "values[j][1]+=values[i][1];values[j][2]+=values[i][2];values[j][3]+=values[i][3];values[j][4]+=values[i][4];values[j][5]=Math.max(values[i][5],values[j][5]);found=1;break;" >> ${3}
echo "}}if(found==0){dv.push(values[i]);}}dv.sort(function(a,b){return a[1]-b[1]});" >> ${3}

echo "for (i=0; i < dv.length; i++) {document.write(\"<tr><td>\");" >> ${3}
echo "document.write(dv[i][0]);document.write(\"</td><td>\");" >> ${3}
echo "document.write(getSize(dv[i][1]));document.write(\"</td><td>\");" >> ${3}
echo "document.write(getSize(dv[i][2]));document.write(\"</td><td>\");" >> ${3}
echo "document.write(getSize(dv[i][3]));document.write(\"</td><td>\");" >> ${3}
echo "document.write(getSize(dv[i][4]));document.write(\"</td><td>\");" >> ${3}
echo "document.write(new Date(dv[i][5]));document.write(\"</td></tr>\");" >> ${3}
echo "}</script></table>" >> ${3}
echo "<br /><small>This page was generated on `date`</small>" 2>&1 >> ${3}
echo "</body></html>" >> ${3}

#Free some memory
rm -f /tmp/*_$$.tmp
;;

*)
echo "Usage : $0 {setup|update|publish} [options...]"
echo "Options : "
echo " $0 setup"
echo " $0 update database_file [offpeak]"
echo " $0 publish database_file path_of_html_report [user_file]"
echo "Examples : "
echo " $0 setup"
echo " $0 update /tmp/usage.db offpeak"
echo " $0 publish /tmp/usage.db /www/user/usage.htm /jffs/users.txt"
echo "Note : [user_file] is an optional file to match users with their MAC address"
echo " Its format is : 00:MA:CA:DD:RE:SS,username , with one entry per line"
exit
;;
esac

Change log

cc0e0b3fa1e4 by emmanuel.brucy on Jul 2, 2010   Diff
Fixed error messages in Update, let the
browser sort the table in the report.
Go to: 
Sign in to write a code review

Older revisions

acb963e7a40d by emmanuel.brucy on Feb 3, 2010   Diff
Fixed typo USERSFILE / USERFILE in
command line arg parsing
208263bdb483 by emmanuel.brucy on Jan 8, 2010   Diff
Put back dnsmasq patch overwritten on
previous commit
81279a6d8b58 by emmanuel.brucy on Jan 8, 2010   Diff
Javascript-based report, generation is
very fast now
All revisions of this file

File info

Size: 7469 bytes, 199 lines
Powered by Google Project Hosting