Simulate weak network environment using command line under Mac

Keywords: Programming network sudo Mac firewall

For audio and video development, we often need to simulate the weak network environment and observe the performance of APP under the weak network, such as packet loss, delay, jitter, bandwidth restriction, etc. Mac system has a weak network tool APP, called Network Link Conditioner, which supports the visualization of the simulation and configuration of the weak network. It is very useful, and it is highly recommended that you use this tool to complete the weak network.Simulation.

But if you expect to use the command line or script to configure a weak network environment, you will have to look at the principles behind it. This article introduces the system-related commands and services behind Network Link Conditioner and shows you how to configure a weak network environment using the command line.

After Mac OS X 10.10, the system mainly used two services `PF (Packet Filter, the BSD firewall)` and `dummynet (the BSD traffic shaper)` to simulate various weak network environments.


DUMMYNET(4)              BSD Kernel Interfaces Manual              DUMMYNET(4)

     dummynet -- traffic shaper, bandwidth manager and delay emulator

     dummynet is a system facility that permits the control of traffic going
     through the various network interfaces, by applying bandwidth and queue
     size limitations, implementing different scheduling and queue management
     policies, and emulating delays and losses.

     The user interface for dummynet is implemented by the dnctl program, so
     the reader is referred to the dnctl(8) manpage for a complete description
     of the capabilities of dummynet and on how to use it.

     dnctl(8), setsockopt(2), bridge(4), ip(4), sysctl(8)

     dummynet was initially implemented as a testing tool for TCP congestion
     control by Luigi Rizzo <>, as described on ACM Computer
     Communication Review, Jan.97 issue.  Later it has been then modified to
     work at the ip and bridging level, integrated with the IPFW packet fil-
     ter, and extended to support multiple queueing and scheduling policies.

Simply put, `dummynet'is a traffic/bandwidth/delay control tool that users can configure and interact with using the `dnctl` command.


Online Documentation:

DNCTL(8)                  BSD System Manager's Manual                 DNCTL(8)

     dnctl -- Traffic shaper control program

     dnctl [-anqs] {list | show}
     dnctl [-f | -q] flush
     dnctl [-q] {delete} [number ...]
     dnctl {pipe | queue} number config config-options
     dnctl [-s [field]] {pipe | queue} {delete | list | show} [number ...]
     dnctl [-nq] [-p preproc [preproc-flags]] pathname

     The dnctl utility is the user interface for controlling the dummynet(4)
     traffic shaper.

     dummynet operates by first using a packet filter to classify packets and
     divide them into flows, using any match pattern that can be used in dnctl
     rules.  Depending on local policies, a flow can contain packets for a
     single TCP connection, or from/to a given host, or entire subnet, or a
     protocol type, etc.

Simply put, `dnctl'is a command line tool for configuring `dummynet' services.

$ dnctl {pipe | queue} number config config-options

`dnctl` provides two traffic control mechanisms, one is a pipe, the other is a queue, which is mainly used for weak network simulation under fixed bandwidth conditions, and the other is to test how different pipes can preempt and share available bandwidth.Usually we choose the former to simulate weak networks simply.

`config-options` has a particularly wide variety of configurations, and the configuration of weak network conditions is basically here:

The following parameters can be configured for a pipe:

bw bandwidth
    Bandwidth, measured in [K|M]{bit/s|Byte/s}.
    A value of 0 (default) means unlimited bandwidth.

delay ms-delay
    Propagation delay, measured in milliseconds.

plr packet-loss-rate
    a floating-point number between 0 and 1, with 0 meaning no loss, 1 meaning 100% loss.

queue {slots | sizeKbytes}
    Queue size, in slots or KBytes.  Default value is 50 slots, which
    is the typical queue size for Ethernet devices.

To sum up, we define a weak network environment with a pipe number id of 1, bandwidth limit of 100Kbit/s, delay of 100ms, loss:50%:

//Create configuration and display
$ sudo dnctl pipe 1 config bw 100Kbit/s delay 100 plr 0.5
$ sudo dnctl show

00001: 100.000 Kbit/s 100 ms 50 sl.plr 0.500000 0 queues (1 buckets) droptail
    mask: 0x00 0x00000000/0x0000 -> 0x00000000/0x0000

//Empty configuration and display
$ sudo dnctl -q flush
$ sudo dnctl show


Let's look at another tool: `pf', which is the firewall tool for Mac systems and is used to filter traffic through the system into our weak network environment.

`pf` Mainly uses configuration files to save firewall rules, with stricter syntax specifications, cat/etc/pf.conf, you can see the following:

# This file contains the main ruleset, which gets automatically loaded
# at startup.  PF will not be automatically enabled, however.  Instead,
# each component which utilizes PF is responsible for enabling and disabling
# PF via -E and -X as documented in pfctl(8).  That will ensure that PF
# is disabled only when the last enable reference is released.
# Care must be taken to ensure that the main ruleset does not get flushed,
# as the nested anchors rely on the anchor point defined here. In addition,
# to the anchors loaded by this file, some system services would dynamically
# insert anchors into the main ruleset. These anchors will be added only when
# the system service is used and would removed on termination of the service.
# See pf.conf(5) for syntax.
# anchor point
scrub-anchor "*"
nat-anchor "*"
rdr-anchor "*"
dummynet-anchor "*"
anchor "*"
load anchor "" from "/etc/pf.anchors/"

Next, we need to write our own rules.

1. Create a new pf.conf file

$ touch pf.conf

2. Add routing rules

Rule document:

action [direction] [log] [quick] [on interface] [af] [proto protocol]
       [from src_addr [port src_port]] [to dst_addr [port dst_port]]
       [flags tcp_flags] [state]

Detailed parameter meanings can be referenced in the documentation, which outlines a few key configurations:

[direction]: direction of flow, up: out, down: in
 [proto protocol]: protocol, tcp/udp/icmp, etc.
[from src_addr [port src_port]: source ip and port, any can be used by default
 [to dst_addr [port dst_port]: Target ip and port, any can be used by default

Here's our main example of how to add rules to the dummynet pipe 1 we created above

$ vi pf.conf

#The "Up + Down" examples in this example are both configured with a weak network or can also be configured to measure change in one way

#Testing tcp, such as curl
dummynet in proto tcp from any to any pipe 1 
dummynet out proto tcp from any to any pipe 1

#Testing udp, such as audio-video calls
dummynet in proto udp from any to any pipe 1   
dummynet out proto udp from any to any pipe 1

#Test ping, for example: Ping
dummynet in proto icmp from any to any pipe 1
dummynet out proto icmp from any to any pipe 1

3. Start and Load `PF`Configuration

Operating on the `PF` service requires the help of the `pfctl ` command.

#Mac system shuts down `PF` service by default and starts `PF` service
$ sudo pfctl -e

#Load custom firewall rules
$ sudo pfctl -f pf.conf

#Restore original firewall rules
$ sudo pfctl -f /etc/pf.conf 

#Note: The following warning often appears with the pfctl command. It has no effect, just ignore it.
"No ALTQ support in kernel"


Here's how to configure a weak network environment on the Mac using the command line. If you have questions, please write to addition, you are welcome to pay attention to my Sina Weibo @Lu_Jun Or WeChat Public Number @Jhuster to get the latest articles and information.

Posted by bugsuperstar37 on Sun, 02 Feb 2020 10:19:02 -0800