前言
同事最近被問說「為什麼 NLB 啟用 dualstack 後,從位於同 AZ 內的 EC2 使用 curl -6
去拜訪,永遠都是拜訪同 subnet 的 NLB 節點?」
這問題一直可以復現,也很確定 dig 出來的結果會有 round robin,但若從 VPC 外的 IPv6 網路測試就沒有這個問題,因此我跟其他同事們便好奇地去找原因。
過程
嘗試使用 strace 去查看,發現這段後
openat(AT_FDCWD, "/lib64/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
過沒多久就是連線了,中途沒看到什麼可疑的地方。
connect(5, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "2600:dddd:baf:cccc:d700:bbbb:aac7:aaaa", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
因此猜測有可能是 curl 對於地址有偏好,我跑去 curl 的 GitHub 搜尋對 DNS
等資訊搜尋看看有沒有可疑的程式碼,但只看到使用 Curl_dns_entry
結構儲存,沒看到取得 DNS 對應 IP 地址後有什麼特殊的排序、偏好設定。
接著跟另一名資深 Linux 組 H 同事去 Stack Overflow 找答案,找到有些人是問 source IP preference 的問題,底下有人留言提到 RFC 3484, 標題寫著 “Default Address Selection for Internet Protocol version 6 (IPv6)”,看了一下目錄有 “Destination Address Selection”,看來很明顯就是這份文件了。不過寫這篇文章時發現 RFC 6724 取代了 RFC 3484。
原因
當有多個 IPv6 地址可以選擇時,會先將其做各種偏好規則排序,分別有:
- Rule 1: Avoid unusable destinations
- Rule 2: Prefer matching scope
- Rule 3: Avoid deprecated addresses
- Rule 4: Prefer home addresses
- Rule 5: Prefer matching label
- Rule 6: Prefer higher precedence
- Rule 7: Prefer native transport
- Rule 8: Prefer smaller scope
- Rule 9: Use longest matching prefix
- Rule 10: Otherwise, leave the order unchanged
其中第 6 條讓網管人員可以根據喜好自定義偏好 prefix,根據 glibc 實作 Precedence 資訊是儲存在 /etc/gai.conf 當中,因此沒設定通常就沒有。
Amazon Linux 2 預設是沒有的,因此我們往下看到較可能的規則應該是第 9 條,這就是網路路由中常見的 Longest Prefix Matching (LPM) 規則,根據 AWS 的 IPv6 定址規則,同個 subnet 會有相同的 /64
前綴,因此解釋了該名同事的問題。
後記
- 網路組同事 L 在 glibc 中找到 Rule 9 的實作
- 網路組同事 T 提到 Windows 也有實作
- 查到有前輩發表 RFC 3484 读后感,不想看 RFC 的人推薦看看這篇
comments powered by Disqus