musl 的 DNS reolsver 支援 TCP fallback

Facebook 上看到這篇:

剛好想起前陣子在 Hacker News 上看到「Musl 1.2.4 adds TCP DNS fallback (openwall.com)」這個消息,裡面的連結是今年五月 musl 1.2.4 的出版公告:「musl 1.2.4 released」(話說 openwall 網站似乎有擋 HiNet 的 IP,我是走第四台網路看的,或是參考 Internet Archive 上面的連結)。

musl 1.2.4 一個很重要的改變是在 DNS resolver 上支援了 TCP fallback (也就是支援 DNS over TCP),這改善了長久以來在 container 裡面使用 Alpine Linux 偶而會因為 DNS 遇到沒有照標準做的 server 而中雷的問題:

This release adds TCP fallback to the DNS stub resolver, fixing the longstanding inability to query large DNS records and incompatibility with recursive nameservers that don't give partial results in truncated UDP responses. It also makes a number of other bug fixes and improvements in DNS and related functionality, including making both the modern and legacy API results differentiate between NODATA and NxDomain conditions so that the caller can handle them differently.

查了一下對應的標準,跑去問 ChatGPT 的 GPT-4:

但 ChatGPT 引用的東西都不能直接當作是實際的文字,只能當作一個起點去找。實際翻 RFC 1035 可以翻到:

Messages carried by UDP are restricted to 512 bytes (not counting the IP or UDP headers). Longer messages are truncated and the TC bit is set in the header.

所以的確在 UDP response 的規範是 512 bytes,要取得完整的資料只能往 TCP 查詢。而 musl 有了這個 TCP fallback 總算是補掉了 Alpine Linux 的一個大坑。

而 musl 1.2.4 則是在 Alpine Linux 3.18 才開始使用:「Alpine 3.18.0 released」。

musl libc 1.2.4 – now with TCP fallback in DNS resolver

所以回到開頭,提到 Alpine Linux 3.16 還是有問題的人,是應該會遇到問題沒錯,因為 3.16 的 musl 本來就沒 TCP fallback?遇到不標準的 DNS server 的確是會噴...

Anyway,Alpine Linux 的 DNS 問題應該會變成過去式...

Netflix 單機 800Gbps 伺服器所使用的最佳化技巧

Hacker News 上看到 Netflix 的人丟出來的投影片,試著了解 Netflix 的 Open Connect Appliances 裡與 FreeBSD 相關的最佳化技巧對於效能的影響:「The “other” FreeBSD optimizations used by Netflix to serve video at 800Gb/s from a single server」。

看起來這邊的分析是先基於 400Gbps 的版本,可以跑到 375Gbps (53% CPU),接著在上面拔掉各種最佳化的設定,看看會掉多少流量。這邊可以參考先前在「Netflix 在單機服務 400Gbps 的影音流量」提到的資料。

投影片上的第一章是 sendfile 與 kTLS 相關的最佳化,這邊可以看出來都是重要的項目,隨便關掉一個就會掉很多 capacity:

  • Disable kTLS (and async sendfile) + nginx aio:40Gbps (100% CPU)
  • Disable kTLS (and async sendfile) + nginx thread pools:90Gbps (90% CPU)
  • Disable sendfile (but use kTLS):75Gbps (80% CPU)
  • Disable sendfile (but use NIC kTLS):95Gbps (80% CPU)
  • Enable Sendfile & kTLS, but disable ISA-L crypto:180Gbps (80% CPU)
  • Enable Sendfile & kTLS:240Gbps (80% CPU)

第二章是 virtual memory,UMA VM Page Cache 這邊看起來最明顯,SF_NOCACHE 也是個重要的項目:

  • Disable UMA VM Page Cache:60Gbps (95% CPU)
  • Disable VM Batch Queues:280Gbps (95% CPU)
  • Disable SF_NOCACHE:120Gbps (55% CPU)

另外第二章特別提到了一個之前沒有用到的 optimization,是把 arm64 上面的 4KB Pages 變成 16KB Pages,這帶動了些許的效能提昇,並且降低了 CPU 使用率:

345Gb/s @ 80% CPU -> 368Gb/s @ 66% CPU

第三章是 network stack,看起來 TSO 帶來的效益也是很高:

  • Disable TCP Large Receive Offload:330Gbps (65% CPU)
  • Disable RSS accelerated LRO:365Gbps (70% CPU)
  • TSO Disabled:180Gbps (85% CPU)
  • Disable TSO and LRO:170Gbps (85% CPU)

最後面則是有提到從 400Gbps 到 800Gbps 還多做了那些事情,最後是達到 731Gbps。

用的機器是 Dell PowerEdge R7525,這是一台 2U 的機器啊...

網頁大小 14KB 與 15KB 的速度差異

Hacker News 上看到「Why your website should be under 14kB in size」這篇,對應的討論在「A 14kb page can load much faster than a 15kb page (endtimes.dev)」,在講網頁大小 14KB/15KB 的速度差異比 15KB/16KB 大很多的問題:

What is surprising is that a 14kB page can load much faster than a 15kB page — maybe 612ms faster — while the difference between a 15kB and a 16kB page is trivial.

原因是 TCP slow start 造成的:

This is because of the TCP slow start algorithm.

而網頁這邊 TCP slow start 目前大多數的實做都是 10 packets 後發動:

Most web servers TCP slow start algorithm starts by sending 10 TCP packets.

然後再組合 1500 bytes/packet 以及 overhead,就差不多是 14KB 了:

The maximum size of a TCP packet is 1500 bytes.

This this maximum is not set by the TCP specification, it comes from the ethernet standard

Each TCP packet uses 40 bytes in its header — 16 bytes for IP and an additional 24 bytes for TCP

That leaves 1460 bytes per TCP packet. 10 x 1460 = 14600 bytes or roughly 14kB!

然後 HTTP/3 也可以看到類似的設計 (出自「QUIC Loss Detection and Congestion Control」:

Sending multiple packets into the network without any delay between them creates a packet burst that might cause short-term congestion and losses. Implementations MUST either use pacing or limit such bursts to the initial congestion window, which is recommended to be the minimum of 10 * max_datagram_size and max(2* max_datagram_size, 14720)), where max_datagram_size is the current maximum size of a datagram for the connection, not including UDP or IP overhead.

算是一個小知識... 但對於現在肥滋滋的網頁效果來說就沒辦法了,而且考慮到大一點的網站會在一個 TCP 連線裡面可能會傳很多 request,其實早就超過 TCP slow start 的門檻了。

TCP 標準被整理到 RFC 9293

看到「RFC 9293: Transmission Control Protocol (TCP)」這篇,主要是把本來分散在各個 RFC 的文件 (從 RFC 793 開始) 全部整理成一份,另外把一些已知的勘誤表放進來:

This document specifies the Transmission Control Protocol (TCP). TCP is an important transport-layer protocol in the Internet protocol stack, and it has continuously evolved over decades of use and growth of the Internet. Over this time, a number of changes have been made to TCP as it was specified in RFC 793, though these have only been documented in a piecemeal fashion. This document collects and brings those changes together with the protocol specification from RFC 793. This document obsoletes RFC 793, as well as RFCs 879, 2873, 6093, 6429, 6528, and 6691 that updated parts of RFC 793. It updates RFCs 1011 and 1122, and it should be considered as a replacement for the portions of those documents dealing with TCP requirements. It also updates RFC 5961 by adding a small clarification in reset handling while in the SYN-RECEIVED state. The TCP header control bits from RFC 793 have also been updated based on RFC 3168.

然後淘汰掉 (obselete) 一卡車 RFC 文件 XD

翻資料發現 2014 的時候 HTTP/1.1 被幹過一次類似的事情,不過是反過來被拆開:「HTTP/1.1 的更新」,這次把 RFC 2616 幹掉分成 RFC 7230RFC 7235

然後今年因為 HTTP 的關係又被幹了一次,這次 HTTP/1.1 又被整回來變成一份文件,但是把裡面的一些概念拆開:「HTTP 標準的翻新」。

其中 RFC 9110 定義 HTTP Semantics,RFC 9111 定義 HTTP Caching,然後 RFC 9112RFC 9113 拿來定義了 HTTP/1.1 與 HTTP/2,另外先把 HTTP/3 的號碼保留下來的 RFC 9114

不斷 refactor 以及加新功能的文件...

DOS 下的 TCP/IP 程式組

Hacker News 上看到「mTCP: TCP/IP applications for DOS PCs (brutman.com)」這個有趣的東西,在 DOS 環境下的 TCP/IP 程式組,原網站在「TCP/IP applications for your PC compatible retro-computers」這邊。

不過我覺得比較神奇的是,他的測試環境是真的包括一堆老機器跟網卡耶 XDDD

裡面提到的 NE1000ISA 界面的卡,這樣聽起來保養的都還不錯...

Tor 0.4.7.7 支援 congestion control

Tor 首度在協定內支援了 congestion control:「Congestion Control Arrives in Tor 0.4.7-stable!」。

這個新功能會帶來效能的提昇:

Tor has released 0.4.7.7, the first stable Tor release with support for congestion control. Congestion control will eliminate the speed limit of current Tor, as well as reduce latency by minimizing queue lengths at relays. It will result in significant performance improvements in Tor, as well as increased utilization of our network capacity.

之所以沒有辦法直接利用 packet loss 的方式讓 TCP network stack 直接判斷 congestion control,是因為這樣會產生 side channel:

Crucially, we rejected mechanisms to provide congestion control by allowing packet drops, due to the ability to introduce end-to-end side channels in the packet drop pattern.

所以 Tor 得自己實做 congestion control 演算法,選擇的演算法是結合了 Vegas 的 Tor-Vegas,可以看到在實驗中,德國與香港的 exit node 效率大幅提昇:

另外也因為 0.4.7.7 也出來一個禮拜了,也可以看到 Advertised Bandwidth (算是 Tor network 觀察到的 bandwidth) 開始成長:

另外一個重要的點是 UDP 的支援計畫,看起來在這次改善後也比較有可行性了:

The astute reader will note that we rejected datagram transports. However, this does not mean that Tor will never carry UDP traffic. On the contrary, congestion control deployment means that queue delay and latency will be much more stable and predictable. This will enable us to carry UDP without packet drops in the network, and only drop UDP at the edges, when the congestion window becomes full. We are hopeful that this new behavior will match what existing UDP protocols expect, allowing their use over Tor.

用 iptables 擋特定國家的封包

這兩天發現 ubuntu-20.04.3-live-server-amd64.iso 這個 BitTorrent 的 ISO image 有大量來自 CN 的連線在狂抓,導致整個上傳頻寬都被吃滿:

沒想到第一次用 iptables 的 xt_geoip 居然是這個用途... 主要是參考「GeoIP Blocking Ubuntu 20.04LTS」這邊的方法,不過因為我的 rtorrent 是跑在 Docker 裡面的,有另外要注意的地方。

首先是安裝軟體,這邊要裝 xtables-addons-commonlibtext-csv-xs-perl

sudo apt install -y libtext-csv-xs-perl xtables-addons-common

再來是建立目錄,並且下載一包 GeoIP 的資料 (從 DBIP 下載) 並且轉成 xt_geoip 可以用的格式:

sudo mkdir /usr/share/xt_geoip
cd /usr/share/xt_geoip
sudo /usr/lib/xtables-addons/xt_geoip_dl
sudo /usr/bin/perl /usr/lib/xtables-addons/xt_geoip_build

然後就是加到 iptables 的條件裡面了,我加到兩個地方,一個是 INPUT chain,另外一個是 DOCKER-USER chain (參考「Docker and iptables」這邊的說明),假設你是用 port 6991 的話就這樣加:

sudo iptables -I INPUT -p tcp -m geoip --source-country CN -m tcp --dport 6991 -j DROP
sudo iptables -I DOCKER-USER -p tcp -m geoip --source-country CN -m tcp --dport 6991 -j DROP

然後可以考慮每個禮拜更新一次資料庫。

另外在找資料的時候發現「Free updated GeoIP legacy databases」這邊有人放出 MaxMind 的版本,不過免費版的應該都差不多,這邊就用 xtables-addons-common 內預設的。

弄完以後就正常多了...

Amazon EC2 的網路效能

前一篇「在 AWS 上面的 OpenVPN Server 效能」最後的問題就是 EC2 instance 本身的網路效能,畢竟是公司要用的,還是實際測一下數字,之後有人接手的時候也比較清楚是怎麼選這個大小的...

這邊拿的是 AWSap-southeast-1 (Singapore) 的 EC2 測試,直接在同一個 subnet 裡面開兩台一樣的機器跑 iperf 測試。

機器開機後會先跑這串指令 (除了安裝 iperf 的指令,其他的是出自我自己 wiki 上的 Ubuntu 這頁),然後再重開機:

sudo fallocate -l 512M /swapfile; sudo chmod 600 /swapfile; sudo mkswap /swapfile; sudo swapon /swapfile; echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab; echo -e "net.core.default_qdisc=fq\nnet.ipv4.tcp_congestion_control=bbr" | sudo tee /etc/sysctl.d/99-tcp.conf; sudo sysctl -p /etc/sysctl.d/99-tcp.conf; sudo apt update; sudo apt dist-upgrade -y; sudo apt install -y apache2-utils apt-transport-https build-essential curl dnsutils dstat git jq locales moreutils most mtr-tiny net-tools p7zip-full pigz prometheus-node-exporter rsync sharutils software-properties-common sysstat unrar unzip vim-nox wget zsh zsh-syntax-highlighting zstd; sudo apt install -y iperf; sudo apt clean

接下來就是一台跑 iperf -s,另外一台跑 iperf -c 10.x.x.x -i 1 -t 3600 讓他跑一個小時看結果了。

我都有跑 tmux 再連到這些機器上,這樣可以捲回去看每一秒的傳輸速度,就可以看出來變化了,不過這邊還是簡單的只列出最高速度 (burstable) 與穩定輸出的速度 (baseline):

EC2 instance Baseline Burstable vCPU RAM Pricing (USD$)
c6g.medium 500Mbps 10Gbps 1 2GB 0.0392
c6g.large 750Mbps 5Gbps (claimed 10Gbps) 2 4GB 0.0784
c6g.xlarge 1.25Gbps 10Gbps 4 8GB 0.1568
t4g.small 125Mbps 5Gbps 2 2GB 0.0212
t4g.medium 255Mbps 5Gbps 2 4GB 0.0424
t4g.large 510Mbps 5Gbps 2 8GB 0.0848
t4g.xlarge 1Gbps 5Gbps 4 16GB 0.1696

這邊沒列出來的是 burstable 可以持續的時間,但這跟你機器吃的網路資源有關,我就決定只用 baseline 來做決策了,這樣可能會多花一點錢,但會少很多麻煩。

另外這次在處理的過程有被同事提醒各種 bandwidth overhead,所以就順便查了一下資料:

  • OpenVPN 本身的 overhead 大約是 5% (跑 UDP 的時候):「OpenVPN performance」。
  • SSH 也有些 overhead,大約是 6% (把來回的封包都算進去):「What is the overhead of SSH compared to telnet?」。
  • rsync 的部份鐵定也有 overhead,但這邊就沒找到現成的文章有統計過了。
  • 另外我自己之前做實驗發現 TCP BBR 的 retransmission algorithm 還蠻激進的,會有 10% packet loss,改用預設的 CUBIC 會好很多,大約 1% 到 2% 左右。

綜合這些測試,我自己抓了 35% 的 overhead 來推估,最後是用 c6g.large 來養 VPN server。750Mbps 的實際流量大約可以包進 550Mbps 的原始流量,大約是 68MB/sec。

不過新加坡與印尼之間的 internet bandwidth 好像還是不太夠,有時候深夜跑也跑不滿... 不過之後 VPN 上的 client 會愈來愈多,應該是不需要降...

Mitmproxy 7 支援 TLS over TCP 的分析了

Hacker News 首頁上看到 Mitmproxy 7 的消息:「Mitmproxy 7」。

比較重要的功能應該就是可以針對任意的 TLS 連線攔截分析了:

不過像是 STARTTLS 這類先在 plaintext 溝通,然後送出指令進入 TLS 的方式,目前就還沒支援:

Opportunistic TLS (STARTTLS) is not supported yet, but regular TCP-over-TLS just works!

另外是可以分析 WebSocket 內的傳輸資料:

應該是跑個 pip install -U mitmproxy 就可以升級了... (如果先前是用 pip 安裝的話)

HP 印表機的 Port 與 Prometheus...

Twitter 上看到這個,HP 印表機的 Port 9100 跟 Prometheus 撞到,再加上 mistype,於是就出事了:

找了一下 HP 的文件,「HP Jetdirect Print Servers - HP Jetdirect Port Numbers for TCP/IP (UDP) Connections」:

9100 TCP port is used for printing. Port numbers 9101 and 9102 are for parallel ports 2 and 3 on the three-port HP Jetdirect external print servers.

翻了一下「Service Name and Transport Protocol Port Number Registry」這邊,看起來 HP 在很久前就登記了 9100/tcp 與 9100/udp...

不過這沒有誰對誰錯的問題,只是很好笑:Printer 在收到不認識的指令時會直接當做 text 印出來,加上 Prometheus 的 HTTP request 打進去...