我的 DNS 包含 ServerA 的两条记录:
- 其 IPv4 地址为 10.25.46.130 的 A 记录
- 带有 IPv6 地址的 AAAA 记录:fda8:6c3:ce53:a890::55
我无法得到我的简单客户端.java程序(来源在本文末尾)在 Windows 服务器上列出 IPv6 地址服务器A使用InetAddress.getAllByName()
,即使在使用配置JVM时也是如此-Djava.net.preferIPv6Addresses=true
。
在启用 IPv6 的 Linux 服务器上运行相同的测试成功。
配置详细信息:
- Windows:Server 2019 标准版 (10.0.17763)
- Java:OpenJDK 11.0.5+
Windows 服务器上的输出ipconfig
显示 IPv6 似乎已启用:
> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet:
Connection-specific DNS Suffix . :
IPv4 Address. . . . . . . . . . . : 10.25.0.214
Subnet Mask . . . . . . . . . . . : X.X.X.X
Default Gateway . . . . . . . . . : X.X.X.X
Ethernet adapter Ethernet 2:
Connection-specific DNS Suffix . : fr.company.com
IPv6 Address. . . . . . . . . . . : fda8:6c3:ce53:a890::3
Link-local IPv6 Address . . . . . : X.X.X.X::X
Default Gateway . . . . . . . . . : X.X.X.X::X
nslookup
Windows 服务器的输出是预期的输出:
> nslookup ServerA
Server: dns.fr.company.com
Address: X.X.X.X
Non-authoritative answer:
Name: ServerA.fr.company.com
Addresses: fda8:6c3:ce53:a890::55
10.25.46.130
我能够ping -6 ServerA
从 Windows 服务器成功运行:
> ping -6 ServerA
Pinging ServerA.fr.company.com [fda8:6c3:ce53:a890::55] with 32 bytes of data:
Reply from fda8:6c3:ce53:a890::55: time<1ms
Reply from fda8:6c3:ce53:a890::55: time<1ms
以下是预期输出从启用 IPv6 的 Linux 服务器运行:
# IPv4 (default)
$ java SimpleClient.java ServerA 12345
preferIPv6Addresses: null
InetAddress.getByName()
ServerA/10.25.46.130
InetAddress.getAllByName()
ServerA/10.25.46.130
ServerA/fda8:6c3:ce53:a890:0:0:0:55
# IPv6
$ java -Djava.net.preferIPv6Addresses=true SimpleClient.java ServerA 12345
preferIPv6Addresses: true
InetAddress.getByName()
ServerA/fda8:6c3:ce53:a890:0:0:0:55
InetAddress.getAllByName()
ServerA/fda8:6c3:ce53:a890:0:0:0:55
ServerA/10.25.46.130
相同的测试在 Windows 服务器上失败:
# IPv4 (default)
> java SimpleClient.java ServerA 12345
preferIPv6Addresses: null
InetAddress.getByName()
ServerA/10.25.46.130
InetAddress.getAllByName()
ServerA/10.25.46.130
# IPv6
> java -Djava.net.preferIPv6Addresses=true SimpleClient.java ServerA 12345
preferIPv6Addresses: true
InetAddress.getByName()
ServerA/10.25.46.130
InetAddress.getAllByName()
ServerA/10.25.46.130
在 Windows 服务器上,对的调用InetAddress.getAllByName()
仅返回单个 IPv4 地址,而不是像在启用了 Linux IPv6 的服务器上预期的那样同时返回 IPv4 和 IPv6 地址。
我可以在禁用 IPv6(grub 和内核设置)的 Linux 服务器上重现相同的行为:
# IPv4 (default)
$ java SimpleClient.java ServerA 12345
preferIPv6Addresses: null
InetAddress.getByName()
ServerA/10.25.46.130
InetAddress.getAllByName()
ServerA/10.25.46.130
# IPv6
$ java -Djava.net.preferIPv6Addresses=true SimpleClient.java ServerA 12345
preferIPv6Addresses: true
InetAddress.getByName()
ServerA/10.25.46.130
InetAddress.getAllByName()
ServerA/10.25.46.130
通过这些测试,我得出结论,Windows 服务器的 IPv6 配置某处有问题,但我不知道是什么问题。
我尝试过的一些笔记和东西:
- 手动添加 IPv6 地址服务器A在C:\Windows\System32\drivers\etc\hosts导致程序列出 IPv6 地址,但仅此一个。
- 我没有
DisabledComponents
在注册表中找到该路径的键Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters
以下是代码示例客户端.java:
import java.net.Socket;
import java.net.UnknownHostException;
import java.net.InetAddress;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.IOException;
public class SimpleClient {
public static void main(String[] args) {
if (args.length < 2) return;
String hostname = args[0];
System.out.println("preferIPv6Addresses: " + System.getProperty("java.net.preferIPv6Addresses"));
try {
System.out.println("InetAddress.getByName()");
System.out.println(InetAddress.getByName(hostname));
InetAddress[] addresses = InetAddress.getAllByName(hostname);
System.out.println("InetAddress.getAllByName()");
for (InetAddress address : addresses) {
System.out.println(address);
}
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
}
int port = Integer.parseInt(args[1]);
try (Socket socket = new Socket(hostname, port)) {
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
System.out.println(reader.readLine());
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
有人可以提示一下 Windows 服务器配置可能出了什么问题吗?
谢谢。
编辑1:
正如评论中提到的,我也使用 Python 重现了这个问题socket.getaddrinfo()
:
- Windows 服务器(无AF_INET6)
>>> socket.getaddrinfo("serverA", 12345)
[(<AddressFamily.AF_INET: 2>, 0, 0, '', ('10.25.46.130', 12345))]
- Linux 服务器(两者皆AF_INET6和AF_INET)
>>> socket.getaddrinfo("serverA", 12345)
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('10.25.46.130', 12345)),
(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_DGRAM: 2>, 17, '', ('10.25.46.130', 12345)),
(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_RAW: 3>, 0, '', ('10.25.46.130', 12345)),
(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('fda8:6c3:ce53:a890::55', 12345, 0, 0)),
(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_DGRAM: 2>, 17, '', ('fda8:6c3:ce53:a890::55', 12345, 0, 0)),
(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_RAW: 3>, 0, '', ('fda8:6c3:ce53:a890::55', 12345, 0, 0))]
答案1
答案来自评论中的@user1686,指出IPv4和IPv6在不同的接口上是分开的。
看来我们的 IT 部门为 Windows 服务器配备了两个接口,每个 IP 堆栈专用一个:
- 以太网(IPv4)
- 以太网4(IPv6)
我禁用了 Windows 服务器上的所有额外接口,只保留了“以太网“ 一:
我在“以太网” 通过复制粘贴“以太网 4”:
所结果的ipconfig显示同时具有 IPv4 和 IPv6 的单个接口:
> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet:
Connection-specific DNS Suffix . :
IPv6 Address. . . . . . . . . . . : fda8:6c3:ce53:a890::3
Link-local IPv6 Address . . . . . : fe80::8d10:5083:9a0:9ab8%16
IPv4 Address. . . . . . . . . . . : 10.25.0.214
Subnet Mask . . . . . . . . . . . : Z.Z.Z.Z
Default Gateway . . . . . . . . . : Y:Y:Y:Y::T
X.X.X.X
重新配置后,测试运行正常,并列出了服务器 A 的 IPv4 和 IPv6 地址:
# IPv4
> C:\jdk11.0.8\bin\java SimpleClient.java serverA 12345
preferIPv6Addresses: null
InetAddress.getByName()
serverA/10.25.46.130
InetAddress.getAllByName()
serverA/10.25.46.130
serverA/fda8:6c3:ce53:a890:0:0:0:55
# IPv6
> C:\jdk11.0.8\bin\java -Djava.net.preferIPv6Addresses=true SimpleClient.java serverA 12345
preferIPv6Addresses: true
InetAddress.getByName()
serverA/fda8:6c3:ce53:a890:0:0:0:55
InetAddress.getAllByName()
serverA/fda8:6c3:ce53:a890:0:0:0:55
serverA/10.25.46.130
因此,尝试在不同的接口上隔离 IP 堆栈似乎是不是一个好主意。