Mac 下使用命令行模擬弱網環境

做音視頻開發,我們經常需要模擬弱網環境,觀察 app 在弱網下的表現,比如,丟包、延遲、抖動、限制帶寬條件等,Mac 系統有一個弱網工具 APP,叫做 “Network Link Conditioner ” ,支持可視化地完成弱網的模擬和配置,很好用,非常推薦你使用這個工具來完成弱網的模擬。


network.png


但是如果你期望使用命令行或者使用腳本來實現弱網環境的配置,就不得不研究一下它背後的原理了,本文就是介紹 Network Link Conditioner 背後使用的系統相關的命令和服務,教大家如何使用命令行完成弱網環境的配置


Mac OS X 10.10 以後,系統主要使用的是 `PF (Packet Filter, the BSD firewall)` `dummynet(the BSD traffic shaper)` 這兩個服務來模擬各種弱網環境。

dummynet

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

NAME
     dummynet -- traffic shaper, bandwidth manager and delay emulator

DESCRIPTION
     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.

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

HISTORY
     dummynet was initially implemented as a testing tool for TCP congestion
     control by Luigi Rizzo <[email protected]>, 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.

簡單來說,`dummynet` 是一個流量/帶寬/延時的控制工具,用戶可以使用 `dnctl` 命令來配置和與之交互。

dnctl

在線文檔:http://www.manpagez.com/man/8/dnctl/

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

NAME
     dnctl -- Traffic shaper control program

SYNOPSIS
     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

DESCRIPTION
     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.

簡單來說,`dnctl `是一個命令行工具,用於配製`dummynet`服務。

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

`dnctl`  提供了 2 種流量控制機制,一個是 pipe,一個是 queue,前者主要用於固定帶寬條件下的弱網模擬,後者則可以試驗不同 pipe 使如何搶佔和共享可用帶寬的。通常我們選擇前者來簡單地模擬弱網。

`config-options` 的種類特別多,弱網條件的配置基本上都在這裏了:

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.

綜上所述,我們來定義一個 pipe number id 爲 1,帶寬限制 100Kbit/s,delay 100ms,loss:50% 的弱網環境:

// 創建配置並顯示
$ 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

// 清空配置並顯示
$ sudo dnctl -q flush
$ sudo dnctl show

pf


我們再來看看另一個工具:`pf`,它是 Mac 系統的防火牆工具,我們利用它來把經過系統的流量轉到我們的弱網環境進行 filter 處理。


`pf` 主要使用配置文件保存防火牆規則,語法規範上比較嚴謹,cat /etc/pf.conf,可看到以下已有內容:

# 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.
#
# com.apple anchor point
#
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"

下面,我們需要來撰寫屬於我們自己的的規則。

1.  新建一個 pf.conf 文件

$ touch pf.conf

2.  添加路由規則

規則文檔:https://www.openbsd.org/faq/pf/filter.html

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]

詳細參數含義可以參考文檔,這裏簡單列出幾個關鍵的配置:

[direction]: 流量的方向,上行:out,下行:in
[proto protocol]:協議,tcp/udp/icmp 等
[from src_addr [port src_port]]:源 ip 和 port,默認可以使用 any
[to dst_addr [port dst_port]]:目標 ip 和 port,默認可以使用 any

這裏我們主要示例一下如何添加規則到我們上面創建的 dummynet  pipe 1

$ vi pf.conf

# 本示例的 “上行 + 下行” 都配置了弱網,也可以配置單向測測變化

# 測試 tcp,比如:curl www.baidu.com
dummynet in proto tcp from any to any pipe 1 
dummynet out proto tcp from any to any pipe 1

# 測試 udp,比如:音視頻通話
dummynet in proto udp from any to any pipe 1   
dummynet out proto udp from any to any pipe 1

# 測試 ping,比如:ping baidu.com
dummynet in proto icmp from any to any pipe 1
dummynet out proto icmp from any to any pipe 1

3.  啓動和加載 `PF` 配置


操作 `PF` 服務,需要藉助  `pfctl ` 命令。

# Mac 系統默認把 `PF` 服務關閉了,啓動 `PF` 服務
$ sudo pfctl -e

# 加載自定義防火牆規則
$ sudo pfctl -f pf.conf

# 恢復原始的防火牆規則
$ sudo pfctl -f /etc/pf.conf 

# 注意:使用 pfctl 命令會經常出現下面的 warning,沒有影響,忽略就好了。
"No ALTQ support in kernel"

小結


關於如何在 Mac 下使用命令行配置弱網環境就分享到這裏了,如有疑問的小夥伴歡迎來信 [email protected] 交流。另外,也歡迎大家關注我的新浪微博 @盧_俊 或者 微信公衆號 @Jhuster 獲取最新的文章和資訊。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章