My suggestion is the following script that will get the data of incoming and outgoing traffic from ifconfig interface-name
and will compare the sum with a predefined limit value. This action will be repeated every 5 seconds (for example).
When the amount of the traffic (income+outcome) becomes equal or greater than the limit, the script will disable the target interface and exit. The maximum discrepancy between the actual value at which the interface will be disabled and the limit value will be equal to 5s
x MaxSpeed
.
The script can be executed by Cron job. So you will be able to set different job for each day of the week, etc. Additionally when the limit is reached you can run the script manually with an additional amount of traffic.
The script name should be traffic-watch
, otherwise you should change its 5th line. My suggestion is to place it in /usr/local/bin
, thus it will be available as shell command. Don't forget to make it executable: chmod +x /usr/local/bin/traffic-watch
.
The script should be executed as root (sudo
). It creates a log file: /tmp/traffic-watch-interface-name.log
, where you can check the last action. The script has two input variables:
$1
=$LIMIT
- the value of the traffic limit in MB - the default value is 400
.
$2
=$IFACE
- the name of the target network interface - the default value is eth0
.
If you want to override these values during the execution of the script, use these formats:
traffic-watch "250" "enp0s25"
traffic-watch "250"
traffic-watch "" "enp0s25"
Use 'traffic-watch' with 'crontab'. If you want to run the script every morning at 6:30
, open root's Crontab (sudo crontab -e
) and add this line:
30 6 * * * /usr/local/bin/traffic-watch 2>/dev/null
Use 'traffic-watch' manually. To run the script as root and push it into the background we shall use sudo -b
:
sudo -b traffic-watch "150" 2>/dev/null
The content of the script 'traffic-watch' is:
#!/bin/bash
# Initialize
[ -z "${1}" ] && LIMIT="400" || LIMIT="$1" # Set the total traffic daily limit in MB
[ -z "${2}" ] && IFACE="eth0" || IFACE="$2" # Set the name of the target interface
LOG="/tmp/traffic-watch-$IFACE.log" # Set the log file name
LANG=C # Set envvar $LANG to `C` due to grep, awk, etc.
IPPT='[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' # Set IP address match pattern #IPPT='[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
NIC="$(/sbin/ethtool -i "$IFACE" | awk 'FS=": " {print $2; exit}')" # Get the $IFACE (NIC) driver
# Function: Get the current traffic
get_traffic(){
RX="$(/sbin/ifconfig "$IFACE" | grep -Po "RX bytes:[0-9]+" | sed 's/RX bytes://')" # Get the incoming traffic
TX="$(/sbin/ifconfig "$IFACE" | grep -Po "TX bytes:[0-9]+" | sed 's/TX bytes://')" # Get the outgoing traffic
XB=$(( RX + TX )) # Calculate the total traffic
XM=$(( XB / ( 1000 * 1000 ) )) # Convert the total traffic in MB
}
# Functions: Disable the interface
interface_down(){ /sbin/ifconfig "$IFACE" down 2>/dev/null && exit; }
# Function: Reset the traffic and enable the interface
reset_traffic_interface_up(){ /sbin/modprobe -r "$NIC" 2>/dev/null && /sbin/modprobe "$NIC" 2>/dev/null && /sbin/ifconfig "$IFACE" up 2>/dev/null; }
# Function: Get the IP address
get_ip(){ /sbin/ifconfig "$IFACE" 2>/dev/null | grep -Po "${IPPT}" | head -1; }
# --- The main program ---
reset_traffic_interface_up
# Wait until the IP address is obtained
until [[ "$(get_ip)" =~ ${IPPT} ]]; do sleep 1; done
# While the interface has IP address == while it is up; check if it is up on every 5 seconds (the `time` of the cycle is about 75 ms)
while [[ "$(get_ip)" =~ ${IPPT} ]]; do
get_traffic
# Start logging
printf '\n%s\n\nI-face:\t%s\nDriver:\t%s\nIP:\t%s\n' "$(date)" "$IFACE" "$NIC" "$(get_ip)" > "$LOG"
printf '\nRX:\t%s\nTX:\t%s\nXB:\t%s\nXM:\t%s\n' "$RX" "$TX" "$XB" "$XM" >> "$LOG"
if (( XM >= LIMIT )); then
printf '\nThe daily limit of %s MB was reached.' "$LIMIT" >> "$LOG"
printf ' The interface %s was disabled!\n\n' "$IFACE" >> "$LOG"
interface_down
else
printf '\n%s MB remains on %s.\n\n' "$(( LIMIT - XM ))" "$IFACE" >> "$LOG"
fi
# Debug: cat "$LOG"
sleep 5 ## *Adjust this value* ##
done; interface_down
Notes:
Disable the script when you update and upgrade the system! The lack of internet could be cause of broken packages.
It is a good idea to attempt to kill the previous instance of the script (just in case its limit is not reached) before run a new:
sudo pkill traffic-watch
sudo -b traffic-watch "150" 2>/dev/null
29 6 * * * /usr/bin/pkill traffic-watch 2>/dev/null
30 6 * * * /usr/local/bin/traffic-watch 2>/dev/null
Probably 2>/dev/null
is not obligatory, because, I think all, errors are redirected to /dev/null
by the script itself.
To check the remaining traffic remotely you can use this command:
ssh user@host.or.ip tail -n3 /tmp/traffic-watch-eth0.log
Thanks to @Dessert for this idea! (Replace eth0
with the actual interface in use.)
To get back your network interface UP: First ise ifconfig -a
to find its name. Then sudo ifconfig INTERFACE up
.
This script could be recreated to work with iptables
instead ofifconfig - up/down
. This will be a powerful solution.
The script is available as GitHub repository at: https://github.com/pa4080/traffic-watch
Another script, based on the current, that only will get the traffic for a period of time is provided here: How to get the current network traffic via the commandline in a simple format.
References:
eth2
or through some other interface? I mean - is it okay to disable this interface programmatically when the daily limit is reached. – pa4080 Oct 10 '17 at 10:00ifconfig
. I will write an answer, soon as I can. – pa4080 Oct 10 '17 at 10:58