Skip to content

Instantly share code, notes, and snippets.

@JamesWatling
Created May 29, 2025 18:03
Show Gist options
  • Select an option

  • Save JamesWatling/8fedc1103cac7f461e43ef0d27dddb3d to your computer and use it in GitHub Desktop.

Select an option

Save JamesWatling/8fedc1103cac7f461e43ef0d27dddb3d to your computer and use it in GitHub Desktop.
Mac OSX simulate poor network conditions

πŸ“‘ simulate-network

A simple macOS utility to simulate different network conditions (e.g. 3G, 4G, edge, wifi) for all TCP and UDP traffic. Useful for testing how your app behaves under degraded or limited network environments.


βœ… Features

  • Simulate bandwidth throttling, latency, and packet loss
  • Affects all TCP and UDP traffic (including WebRTC)
  • Easy reset to return to normal
  • macOS-native using pfctl and dnctl

πŸ”§ Requirements

  • macOS with pfctl and dnctl (usually built-in)
  • Root access (sudo)
  • Bash shell (bash >= 3)

πŸš€ Usage

# Make the script executable
chmod +x simulate-network

# Simulate a 3G network with 1% packet loss
sudo ./simulate-network 3g --loss 1

# Simulate wifi conditions (default delay and bandwidth)
sudo ./simulate-network wifi

# Reset all simulation and restore normal network behavior
sudo ./simulate-network reset

🌐 Supported Presets

Speed Bandwidth Latency
edge 240 Kbit/s 400 ms
3g 750 Kbit/s 200 ms
4g 4000 Kbit/s 80 ms
wifi 30000 Kbit/s 20 ms

⚠️ Limitations

  • Jitter is not supported on macOS's dnctl (it will be ignored with a warning)
  • Only one simulation can be active at a time
  • Must be run with sudo

πŸ“ Files

  • simulate-network – the Bash script
  • README.md – this file

🧼 Cleanup

Always run the following to restore your system to a normal state after testing:

sudo ./simulate-network reset
#!/usr/bin/env bash
# -------- Bootstrap: force Bash --------
if [ -z "$BASH_VERSION" ]; then
exec /usr/bin/env bash "$0" "$@"
fi
set -e
DEFAULT_INTERFACE="en0"
TMP_PF_CONF="/tmp/pf.conf.simnet"
print_usage() {
echo "Usage: $0 [speed] [--loss %] [--jitter ms]"
echo " $0 reset"
echo ""
echo "Speeds: edge, 3g, 4g, wifi"
}
require_root() {
if [ "$EUID" -ne 0 ]; then
echo "Please run as root (e.g. sudo $0 ...)"
exit 1
fi
}
list_interfaces() {
echo "Available network interfaces:"
ifconfig | awk '/flags=/{gsub(":", "", $1); iface=$1} /status: /{print " - " iface ": " $2}' \
| sed "s/^ - $DEFAULT_INTERFACE/ * $DEFAULT_INTERFACE/"
echo ""
}
reset_network() {
echo "Resetting network simulation..."
sudo pfctl -d
sudo dnctl flush
echo "βœ… Network simulation reset."
exit 0
}
# -------- Parse Arguments --------
if [ "$1" == "reset" ]; then
require_root
reset_network
fi
if [ $# -lt 1 ]; then
print_usage
exit 1
fi
SPEED=$1
shift
# Default values
LOSS=0
JITTER=0
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
--loss)
LOSS="$2"
shift; shift
;;
--jitter)
JITTER="$2"
shift; shift
;;
*)
echo "Unknown option: $key"
print_usage
exit 1
;;
esac
done
# Map speed to bandwidth/delay
case "$SPEED" in
edge)
BW=240
DELAY=400
;;
3g)
BW=750
DELAY=200
;;
4g)
BW=4000
DELAY=80
;;
wifi)
BW=30000
DELAY=20
;;
*)
echo "Invalid speed: $SPEED"
print_usage
exit 1
;;
esac
# -------- Apply Network Simulation --------
require_root
list_interfaces
echo "Using interface: $DEFAULT_INTERFACE"
echo "Setting network simulation:"
echo " Speed: $SPEED ($BW Kbit/s, $DELAY ms)"
echo " Loss: $LOSS%"
if [ "$JITTER" -gt 0 ]; then
echo "⚠️ Warning: 'jitter' is not supported by macOS dummynet and will be ignored."
fi
sudo dnctl flush
sudo dnctl pipe 1 config bw ${BW}Kbit/s delay ${DELAY}ms plr $(awk "BEGIN {print $LOSS / 100}")
sudo dnctl pipe 2 config bw ${BW}Kbit/s delay ${DELAY}ms plr $(awk "BEGIN {print $LOSS / 100}")
cat <<EOF > $TMP_PF_CONF
dummynet in quick on $DEFAULT_INTERFACE proto { tcp udp } from any to any pipe 1
dummynet out quick on $DEFAULT_INTERFACE proto { tcp udp } from any to any pipe 2
EOF
sudo pfctl -f $TMP_PF_CONF
sudo pfctl -e
echo "βœ… Network simulation applied."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment