New quota shell script with the ability to save quota to local file. iptables-mod-quota2 is needed.
#!/bin/sh
folder=/mnt/mmcblk0p2/openwrt/var/log # A persistent folder to save remaining quota value.
default_quota=30 # Default quota in GB
quota_file=/proc/net/xt_quota/unlimited_plan
DEV_LTE=eth1 # Interface name of LTE dongle
[ -d "$folder" ] || mkdir -p $folder
alias ipt='iptables'
check_environment(){
# Detect if xt_quota2 module is installed
[ -z "$(opkg info iptables-mod-quota2|grep installed)" ] && echo "xt_quota2 module is not installed." && opkg update && opkg install iptables-mod-quota2
# Detect if xt_quota2 module is loaded
[ -z "$(lsmod|grep xt_quota2)" ] && echo "xt_quota2 module is not loaded" && modprobe xt_quota2
}
set_quota(){
echo -n $((${1} * 1024 * 1024 * 1024)) > ${folder}/quota.log
echo -n $((${1} * 1024 * 1024 * 1024)) > $quota_file
}
remain_quota(){
[ -s "$folder/quota.log" ] || set_quota $default_quota
cat ${folder}/quota.log
}
current_remain_quota(){
local remain=$(cat /proc/net/xt_quota/unlimited_plan)
echo $(($remain / 1024 / 1024)) MB
}
del_iptables_rule(){
ipt -F UNLIMITED_PLAN_LIMIT
for chain_name in forwarding_rule input_rule output_rule
do
while true
do
line=$(ipt -L $chain_name|sed -e '1,2d'|grep -n UNLIMITED_PLAN_LIMIT|head -1|cut -d : -f 1 2>/dev/null)
[ -n "$(echo $line|grep -E ^[[:digit:]]+$)" ] && ipt -D $chain_name $line || break
done
done
ipt -X UNLIMITED_PLAN_LIMIT
}
set_iptables_rule(){
# ipt -t mangle -A PREROUTING -j CONNMARK --restore-mark
# ipt -t mangle -A POSTROUTING -j CONNMARK --restore-mark
ipt -N UNLIMITED_PLAN_LIMIT
# After limit is reached, reject all traffic.
ipt -I UNLIMITED_PLAN_LIMIT -m quota2 --name unlimited_plan ! --quota $(remain_quota) -j REJECT
ipt -I forwarding_rule -i $DEV_LTE -j UNLIMITED_PLAN_LIMIT
ipt -I forwarding_rule -o $DEV_LTE -j UNLIMITED_PLAN_LIMIT
ipt -I input_rule -i $DEV_LTE -j UNLIMITED_PLAN_LIMIT
ipt -I output_rule -o $DEV_LTE -j UNLIMITED_PLAN_LIMIT
}
save_quota(){
[ -r "$quota_file" ] && local last_used=$(($(cat $quota_file 2>/dev/null) - $(remain_quota)))
local remain=$(($(remain_quota) + ${last_used:-"0"}))
if [ $remain -ge 0 ]; then
echo -n ${remain} > ${folder}/quota.log
else
echo -n 0 > ${folder}/quota.log
fi
}
case $1 in
remain)
remain_quota
;;
cremain)
current_remain_quota
;;
set)
set_quota ${2:-"$default_quota"}
;;
save)
save_quota
;;
start)
del_iptables_rule
set_iptables_rule
;;
stop)
save_quota
del_iptables_rule
;;
reload)
save_quota
del_iptables_rule
set_iptables_rule
;;
*)
check_environment
set_quota ${1:-"$default_quota"}
del_iptables_rule
set_iptables_rule
;;
esac
exit 0
/etc/crontabs/root
# Save remaining quota to local file
*/10 * * * * /mnt/mmcblk0p2/openwrt/usr/sbin/quota.sh save &
# Log remaining quota every hour
0 */1 * * * logger -t "quota" "Remaining Quota: $(/mnt/mmcblk0p2/openwrt/usr/sbin/quota.sh cremain)" &
# Reset the quota monthly
0 0 1 * * /mnt/mmcblk0p2/openwrt/usr/sbin/quota.sh set 30 &
/etc/firewall.user
/mnt/mmcblk0p2/openwrt/usr/sbin/quota.sh start
/etc/init.d/firewall
restart() {
/mnt/mmcblk0p2/openwrt/usr/sbin/quota.sh save
fw3 restart
}
How to use
- quota.sh 30 # Set a 30GB traffic limit, check the router environment, and start counting
- quota.sh set 30 # Set a 30GB traffic limit, and reset the counter of xt_quota2.
- quota.sh save # Save the current remaining quota data to the local in order to avoid the loss caused by a sudden shutdown of the router
- quota.sh start # Set iptables rules
- quota.sh stop # Delete iptables rules
- quota.sh reload # Reload iptables rules
- quota.sh cremain # Output remaining quota in MB