netcat 在發送到 UDP IPv6 多播時產生 EINVAL
我在 Fedora 上使用 netcat 來測試 IPv6 UDP 多播地址。命令是
echo hi | nc -6 -u ff02::777:777:777 7777
netcat 響應,“無效的參數。”
執行 strace 產量
connect(3, {sa_family=AF_INET6, sin6_port=htons(7777), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "ff02::777:777:777", &sin6_addr), sin6_scope_id=0}, 28) = -1 EINVAL
執行類似的命令但沒有 IPv6,
echo hi | nc -u 192.168.255.255 7777
工作得很好。
初步說明:您的 IPv4 網路未設置為 192.168.0.0/16 但很可能設置為 192.168.0.0/24 或任何其他 /24 範圍:192.168.255.255 因此不是廣播,否則
echo hi | nc -u 192.168.255.255 7777
會失敗。對於廣播,IPv6 不支持但僅 IPv4 支持,應用程序必須使用SO_BROADCAST
套接字選項。這是通過-b
netcat 選項實現的。假設您實際上在網路 192.168.0.0/24(不是 /16)中,那就是:nc -b -u 192.168.0.255 7777
請注意,廣播不是多播。
關於問題。整個
ff02::/16
範圍都在鏈路本地多播範圍內。對於此範圍,只有當介面關聯到地址時,地址才是完整的(這就是為什麼它是連結本地範圍的原因)。此範圍內的有效地址不能是 onlyff02::777:777:777
。假設 LAN 介面被呼叫eth0
,ff02::777:777:777%eth0
是一個有效的地址,如RFC 4007中所定義:nc -6 -u ff02::777:777:777%eth0 7777
這可能是由庫而不是
nc
命令本身自動處理的。使用不需要介面的範圍通常會失敗,因為介面不應該是地址的一部分。如果您不想需要該介面,請不要使用連結本地(或節點本地)範圍。切換到不需要指定介面即可工作的站點本地:ff05:
nc -6 -u ff05::777:777:777 7777
在 Linux 上,可以看到這兩個命令的區別
ss
:$ ss -aun dport == 7777 State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 [2001:db8:900d:cafe:0:1:2:3]:58092 [ff05::777:777:777]:7777 ESTAB 0 0 [fe80::8c5f:87ff:fe50:d08a]%eth0:60937 [ff02::777:777:777]:7777
由於eth0上提供了一個全域地址,並且它不是本地連結範圍,因此選擇此地址作為源地址。對於連結本地範圍的地址,套接字綁定到介面。對於 Linux 案例,請參閱此 Q/A 以了解與發送時(和未使用的
IPV6_MULTICAST_IF
)介面選擇相關的其他警告:如何設置首選 IPv6 介面最後一點:您應該考慮切換到socat ,它的功能比netcat多得多,包括加入IPv4 的多播組。雖然它支持 IPv6,但它不直接支持 IPv6 多播,但可以
setsockopt(2)
對不受支持的功能使用任意呼叫,包括處理 IPv6 多播。這仍然比不支持接收先前netcat命令發出的多播流量的netcat好。因此,對於socat,這是一個至少在具有 amd64 (x86_64) 架構的 Linux 上有效的範例,並且可能在使用適當的替換 (for
IPV6_ADD_MEMBERSHIP
/IPV6_JOIN_GROUP
) 更改下面的值 20 之後可能在其他 nix 上工作,使用 rawsetsockopt(2)
選項來啟用接收多播索引為 2 的介面( lo之後的第一個介面)上的流量,由第一個netcat*命令發送:socat udp6-recv:7777,setsockopt-listen=41:20:xff020000000000000000077707770777i2 -
該選項將使用以下方式解碼
strace
:setsockopt(5, SOL_IPV6, IPV6_ADD_MEMBERSHIP, {inet_pton(AF_INET6, "ff02::777:777:777", &ipv6mr_multiaddr), ipv6mr_interface=if_nametoindex("eth0")}, 20) = 0
用於傳遞任意套接字選項的所謂“dalan”格式在此處用於ipv6_mreq結構:一個 IPv6 地址(
x
用於任意十六進制值,此處為 IPv6 地址的 16 個字節)後跟一個介面索引(i
用於整數)。