Created
July 8, 2022 08:52
-
-
Save majek/ae3f85666b977ef0155059b4a57e1ea6 to your computer and use it in GitHub Desktop.
Bash script to selectively slow down traffic to given IP's - using tc netem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
set -u | |
set -o pipefail | |
IFACE="lo" | |
LATENCY=200 | |
CLEAN="" | |
IPS=() | |
for i in "$@"; do | |
case $i in | |
--help) | |
cat <<EOF | |
Usage: | |
./slow_network.sh [--clean] [--iface=IFACE] [--latency=LATENCYMS] [ADDRESS]... | |
Cleans and sets a tc (traffic control) policy on a given IFACE, adding | |
latency on traffic going to specific IP addresses. The script first | |
cleans up existing tc policy, and sets up a simple netem/u32 | |
configuration. | |
By default the IFACE=lo and LATENCYMS=200. IFACE can also be set to a | |
"default" string which will cause the script to resolve the default | |
gateway and use the appropriate interface. | |
When ADDRESSES are not given over command line, they are read from | |
stdin until EOF. | |
The --clean option just clears the tc config. | |
Example: | |
$ sudo ./slow_network.sh --interface=default 1.1.1.1 8.8.8.8 | |
[ ] Setting tc on enx381428a758c2, latency 200 ms | |
$ ping -nc2 1.1.1.1 | |
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. | |
64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=201 ms | |
64 bytes from 1.1.1.1: icmp_seq=2 ttl=64 time=201 ms | |
If IFACE is lo, then the LATENCY might be doubled since both ingress | |
and egress go via tc:: | |
$ sudo ./slow_network.sh --latency=100 ::1 127.0.0.1 | |
[ ] Setting tc on lo, latency 100 ms | |
$ ping -nc2 127.0.0.1 | |
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. | |
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=200 ms | |
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=200 ms | |
You can give the script a hostname to resolve: | |
$ sudo ./slow_network.sh --iface=default speed.cloudflare.com | |
[ ] Setting tc on enxf6beece96820, latency 200 ms | |
- 104.18.47.225 | |
- 172.64.156.31 | |
- 2606:4700:440e::6812:2fe1 | |
- 2606:4700:440e::ac40:9c1f | |
EOF | |
exit 1 | |
;; | |
--clean|--clear) | |
CLEAN="yes" | |
shift # past argument with no value | |
;; | |
-i=*|--interface=*|--iface=*) | |
IFACE="${i#*=}" | |
shift | |
;; | |
-l=*|--latency=*) | |
LATENCY="${i#*=}" | |
shift | |
;; | |
-*|--*) | |
echo "Unknown option $i" | |
exit 1 | |
;; | |
*) | |
IPS[${#IPS[@]}]="$i" | |
shift | |
;; | |
esac | |
done | |
if [ "$IFACE" == "default" ]; then | |
IFACE=`ip r show default|awk '/default/ {print $5}'|head -n1` | |
fi | |
if [ "$CLEAN" == "yes" ]; then | |
echo "[ ] Cleaning up tc on $IFACE" | |
tc qdisc del dev $IFACE root | |
exit 0 | |
fi | |
echo "[ ] Setting tc on $IFACE, latency $LATENCY ms" | |
tc qdisc del dev $IFACE root || true | |
tc qdisc add dev $IFACE root handle 1: prio bands 2 priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | |
tc qdisc add dev $IFACE parent 1:1 handle 2: fq_codel | |
tc qdisc add dev $IFACE parent 1:2 handle 3: netem delay ${LATENCY}ms | |
if [ "${#IPS[@]}" -gt "0" ]; then | |
for LINE in "${IPS[@]}"; do | |
echo $LINE | |
done | |
else | |
while read LINE; do | |
echo $LINE | |
done | |
fi | while read IP; do | |
echo $IP | \ | |
python3 -c "import socket as s;print('\n'.join(x[4][0] for x in s.getaddrinfo(input(), 0, 0,s.SOCK_STREAM)))" \ | |
| while read XIP; do | |
echo " - $XIP" | |
if [[ "$XIP" =~ .*":".* ]]; then | |
tc filter add dev $IFACE protocol ipv6 parent 1: u32 match ip6 dst $XIP flowid 1:2 | |
else | |
tc filter add dev $IFACE protocol ip parent 1: prio 1 u32 match ip dst $XIP flowid 1:2 | |
fi | |
done | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment