Implementing Bandwidth Throttling for SSH Sessions: Traffic Control Methods


2 views

While SSH is primarily designed for secure remote access, its tunneling capabilities (-D SOCKS proxy) often lead to uncontrolled bandwidth consumption. When multiple users utilize SSH tunnels for browsing or file transfers, it can saturate server bandwidth without proper traffic shaping.

The most effective method is using Linux's built-in traffic control system. This example limits all SSH traffic to 200Kbps:

tc qdisc add dev eth0 root handle 1: htb default 10
tc class add dev eth0 parent 1: classid 1:10 htb rate 200kbit ceil 200kbit
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10

For more granular control, trickle works as a userspace bandwidth shaper:

LD_PRELOAD=/usr/lib/trickle/trickle.so trickle -d 200 -u 200 ssh user@example.com

This approach is particularly useful when you want to limit bandwidth for specific connections rather than all SSH traffic.

For systems without tc, iptables can provide basic rate limiting:

iptables -A OUTPUT -p tcp --sport 22 -m limit --limit 200kb/s -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j DROP

While OpenSSH doesn't have built-in bandwidth limiting, these parameters can indirectly help:

# /etc/ssh/sshd_config
ClientAliveInterval 60
TCPKeepAlive no
Compression delayed

After implementation, verify the restrictions using iftop or nethogs:

iftop -f 'port 22'
nethogs -t sshd

While SSH is primarily designed for secure terminal access, many administrators use its tunneling capabilities (-D for SOCKS proxy, -L/-R for port forwarding) for various network operations. Unlike SCP which has built-in bandwidth limiting (-l flag), OpenSSH lacks native traffic shaping capabilities. This becomes problematic when:

  • Running bulk transfers via SSH tunnels
  • Sharing server resources among multiple users
  • Preventing SSH from saturating network links

Option 1: Using tc (Traffic Control)

The most robust method uses Linux's built-in traffic shaping tools. Create a script (/usr/local/bin/limit_ssh.sh):

#!/bin/bash
# Limit SSH to 200Kbit/s per connection
TC="/sbin/tc"
INTERFACE="eth0"
RATE="200kbit"
BURST="10kb"
LATENCY="50ms"

# Create HTB queue discipline
$TC qdisc add dev $INTERFACE root handle 1: htb default 30
$TC class add dev $INTERFACE parent 1: classid 1:1 htb rate 1000mbit
$TC class add dev $INTERFACE parent 1:1 classid 1:10 htb rate $RATE ceil $RATE burst $BURST

# Filter SSH traffic (port 22)
$TC filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10
$TC filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip sport 22 0xffff flowid 1:10

Option 2: Trickle Userspace Bandwidth Shaper

For per-process limiting without root access:

# Install trickle
sudo apt-get install trickle

# Limit ssh command
trickle -s -u 200 -d 200 ssh user@example.com -D 1080

Option 3: Firewall-Based Limiting (iptables)

# Limit SSH traffic to 200Kb/s
iptables -A OUTPUT -p tcp --sport 22 -m limit --limit 200kb/s -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j DROP

# For incoming SSH (adjust interface)
iptables -A INPUT -i eth0 -p tcp --dport 22 -m limit --limit 200kb/s -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 22 -j DROP

For systems with multiple concurrent SSH users, combine tc with cgroups:

# Create cgroup
cgcreate -g net_cls:ssh_limited

# Set class ID (matches tc filter)
echo 0x10010 > /sys/fs/cgroup/net_cls/ssh_limited/net_cls.classid

# Apply to SSH processes
cgclassify -g net_cls:ssh_limited $(pgrep sshd)

# Add matching tc filter
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 10: cgroup

Check your bandwidth limits with:

# For tc
tc -s qdisc ls dev eth0
tc -s class ls dev eth0

# For real-time monitoring
iftop -f 'port 22'
nethogs eth0 -t

Remember to persist these rules across reboots by adding them to /etc/rc.local or creating systemd services.