Ipv6

netcat 在發送到 UDP IPv6 多播時產生 EINVAL

  • August 16, 2021

我在 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套接字選項。這是通過-bnetcat 選項實現的。假設您實際上在網路 192.168.0.0/24(不是 /16)中,那就是:

nc -b -u 192.168.0.255 7777

請注意,廣播不是多播。


關於問題。整個ff02::/16範圍都在鏈路本地多播範圍內。對於此範圍,只有當介面關聯到地址時,地址才是完整的(這就是為什麼它是連結本地範圍的原因)。此範圍內的有效地址不能是 only ff02::777:777:777。假設 LAN 介面被呼叫eth0ff02::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用於整數)。

引用自:https://unix.stackexchange.com/questions/656582