It seems that dual stack sockets are not supported by some operating systems. I am looking for a reliable approach to detect if this feature is supported or not. My current suggestion (not tested yet) is checking the returned value of setsockopt to turn off IPV6_V6ONLY when I try to put the socket into dual stack mode. Do you think this works or there is a better solution?
似乎某些操作系统不支持双堆栈套接字。我正在寻找一种可靠的方法来检测是否支持此功能。我当前的建议(尚未测试)是在我尝试将套接字置于双堆栈模式时检查setsockopt的返回值以关闭IPV6_V6ONLY。你认为这有效还是有更好的解决方案?
Thanks
1 个解决方案
#1
One approach that comes to my mind is to attempt to create an IPv6-only UDP socket and connect it to an IPv4-mapped address. This will not produce any actual network traffic, but by looking at the behavior of the code and the resulting local address assigned to the socket, you can figure out if the socket is actually IPv6-only.
我想到的一种方法是尝试创建仅支持IPv6的UDP套接字并将其连接到IPv4映射地址。这不会产生任何实际的网络流量,但通过查看代码的行为和分配给套接字的结果本地地址,您可以确定套接字是否实际上是仅IPv6。
Here is Python code demonstrating the idea. This can be directly mapped to equivalent C code performing the same sequence of system calls:
这是演示这个想法的Python代码。这可以直接映射到执行相同系统调用序列的等效C代码:
import socket
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
s.connect(('::ffff:169.254.1.1', 53))
print s.getsockname()
Possible outcomes:
-
setsockopt
fails due to theIPV6_V6ONLY
option not being supported. -
connect
fails due to socket being IPv6-only and connect recognizing that you are not allowed to bind such a socket to an IPv4-mapped address. -
connect
fails with no route to host. If that case you are left in the dark, because you don't know if it was looking for an IPv4 route or an IPv6 route, and you'd have to attempt connecting to other addresses to figure out which was the case. -
getsockname
returns an IPv4-mapped address, which meansIPV6_V6ONLY
and the socket is not IPv6-only. -
getsockname
returns an IPv6 address other than an IPv4-mapped address, which means the socket is IPv6-only and the code path used by connect had no clue that an IPv4-mapped address was somehow special.
由于不支持IPV6_V6ONLY选项,setsockopt失败。
由于套接字仅为IPv6,因此连接失败,并且连接时认识到不允许将此类套接字绑定到IPv4映射地址。
连接失败,没有到主机的路由。如果遇到这种情况,你就会陷入黑暗,因为你不知道它是在寻找IPv4路由还是IPv6路由,而你必须尝试连接到其他地址才能弄清楚是哪种情况。
getsockname返回IPv4映射地址,这意味着IPV6_V6ONLY,并且套接字不是仅IPv6。
getsockname返回除IPv4映射地址以外的IPv6地址,这意味着套接字是仅IPv6的,并且connect使用的代码路径不知道IPv4映射地址在某种程度上是特殊的。
I would consider it impossible to predict what quirks you could come across on various operating systems. But I am quite confident that the sequence of socket API calls I suggest would reveal any such quirks. So you'd have to test it on the target OS relevant to you to see how they each behave, and it may turn out a simplified version of the tests would be sufficient.
我认为无法预测各种操作系统会遇到什么怪癖。但我相信我建议的套接字API调用序列会揭示任何这样的怪癖。因此,您必须在与您相关的目标操作系统上测试它,以了解它们各自的行为方式,并且可能会产生简化版本的测试就足够了。
#1
One approach that comes to my mind is to attempt to create an IPv6-only UDP socket and connect it to an IPv4-mapped address. This will not produce any actual network traffic, but by looking at the behavior of the code and the resulting local address assigned to the socket, you can figure out if the socket is actually IPv6-only.
我想到的一种方法是尝试创建仅支持IPv6的UDP套接字并将其连接到IPv4映射地址。这不会产生任何实际的网络流量,但通过查看代码的行为和分配给套接字的结果本地地址,您可以确定套接字是否实际上是仅IPv6。
Here is Python code demonstrating the idea. This can be directly mapped to equivalent C code performing the same sequence of system calls:
这是演示这个想法的Python代码。这可以直接映射到执行相同系统调用序列的等效C代码:
import socket
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
s.connect(('::ffff:169.254.1.1', 53))
print s.getsockname()
Possible outcomes:
-
setsockopt
fails due to theIPV6_V6ONLY
option not being supported. -
connect
fails due to socket being IPv6-only and connect recognizing that you are not allowed to bind such a socket to an IPv4-mapped address. -
connect
fails with no route to host. If that case you are left in the dark, because you don't know if it was looking for an IPv4 route or an IPv6 route, and you'd have to attempt connecting to other addresses to figure out which was the case. -
getsockname
returns an IPv4-mapped address, which meansIPV6_V6ONLY
and the socket is not IPv6-only. -
getsockname
returns an IPv6 address other than an IPv4-mapped address, which means the socket is IPv6-only and the code path used by connect had no clue that an IPv4-mapped address was somehow special.
由于不支持IPV6_V6ONLY选项,setsockopt失败。
由于套接字仅为IPv6,因此连接失败,并且连接时认识到不允许将此类套接字绑定到IPv4映射地址。
连接失败,没有到主机的路由。如果遇到这种情况,你就会陷入黑暗,因为你不知道它是在寻找IPv4路由还是IPv6路由,而你必须尝试连接到其他地址才能弄清楚是哪种情况。
getsockname返回IPv4映射地址,这意味着IPV6_V6ONLY,并且套接字不是仅IPv6。
getsockname返回除IPv4映射地址以外的IPv6地址,这意味着套接字是仅IPv6的,并且connect使用的代码路径不知道IPv4映射地址在某种程度上是特殊的。
I would consider it impossible to predict what quirks you could come across on various operating systems. But I am quite confident that the sequence of socket API calls I suggest would reveal any such quirks. So you'd have to test it on the target OS relevant to you to see how they each behave, and it may turn out a simplified version of the tests would be sufficient.
我认为无法预测各种操作系统会遇到什么怪癖。但我相信我建议的套接字API调用序列会揭示任何这样的怪癖。因此,您必须在与您相关的目标操作系统上测试它,以了解它们各自的行为方式,并且可能会产生简化版本的测试就足够了。