sshd
has no features that limit the bandwidth used by a given ssh connection, so scp or sftp transfers can consume as much bandwidth as the underlying connection can support. If this connection is shared, this might be undesirable – one transfer will always be trying to saturate the pipe, forcing other communications to contend for bandwidth. Conveniently, the OpenBSD ipfw
firewall includes a traffic shaping filter named dummynet which can used to simulate a wide variety of network conditions, including artificially limiting the bandwidth for traffic matching a given ipfw rule. This can be leveraged to limit bandwidth for external ssh connections.
I ran into two issues when trying to get this working:
- Confusingly the ipfw manpage still suggests that the
ipfw
command can be used to configure dummynet. In reality, all it can now do is create a dummynet pipe;dnctl
is used to configure the pipe once created. - The dummynet kernel module is neither compiled into the kernel nor loaded by default.
The below script incorporates solutions to both the above challenges, defines the rules necessary to base-configure ipfw, and adds a 10Mbit/s bandwidth limit for outgoing ssh connections:
#!/bin/csh
ipfw -q -f flush
# since we have dynamic rules later in the set (those with keep-state), adding this here reduces rule-scanning once a dynamic rule is created
ipfw -q add 00100 check-state
# must always allow unfettered comms on the loopback address
ipfw -q add 00001 allow all from any to any via lo0
# Load the dummynet kernel model
kldload dummynet
# Use dummynet to create a virtual pipe between any local address and any external address, applied only for outgoing traffic
ipfw -q add 00102 pipe 1 ip from me to any out
# Set the maximum bandwith for the pipe I have defined
dnctl pipe 1 config bw 10Mbit/s
Note that the above only limits bandwidth. If you have needs to limit access by IP (ranges), then further ipfw rules will be required.
With the above put into a file named, say, /usr/local/etc/ipfw_rules.sh and set executable by root, the following two lines need to be added to /etc/rc.conf to start the firewall at boot time and install the rules:
firewall_enable=”yes”
firewall_script=”/usr/local/etc/ipfw_rules.sh”