netsat -tupn
这是我的 Debian Jessie 服务器上的输出:
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 10.0.0.12:445 10.0.0.20:49729 ESTABLISHED 26277/smbd
tcp 0 0 10.0.0.12:443 10.0.0.21:44162 ESTABLISHED 1400/nginx: worker
tcp 0 0 10.0.0.12:445 10.0.0.21:46650 ESTABLISHED 23039/smbd
tcp 0 0 10.0.0.12:443 10.0.0.20:54584 ESTABLISHED 1400/nginx: worker
tcp 0 0 10.0.0.12:139 10.0.0.225:10425 ESTABLISHED 23701/smbd
tcp 0 0 10.0.0.12:445 10.0.0.217:49179 ESTABLISHED 21535/smbd
tcp 0 0 10.0.0.12:445 10.0.0.217:49178 ESTABLISHED 21534/smbd
tcp 0 0 10.0.0.12:445 10.0.0.20:64636 ESTABLISHED 21470/smbd
tcp 0 0 10.0.0.12:443 10.0.0.21:44198 ESTABLISHED 1400/nginx: worker
tcp 0 0 10.0.0.12:2049 10.0.0.16:752 ESTABLISHED -
tcp 0 0 10.0.0.12:222 10.0.0.21:55514 ESTABLISHED 23111/sshd: redacted
tcp6 0 0 10.0.0.12:4243 10.0.0.20:64702 ESTABLISHED 31307/java
tcp6 0 0 10.0.0.12:48932 162.222.40.93:443 ESTABLISHED 31307/java
tcp6 0 0 10.0.0.12:49093 216.17.8.47:443 ESTABLISHED 31307/java
PID 31307 是崩溃计划备份引擎,Java版本1.7.0_45
。这两个非 RFC1918 IPv4 地址是 CrashPlan 的服务器,也是10.0.0.20:64702
我运行客户端的计算机。
为什么最后三个连接显示为 tcp6,即使它们是 IPv4 地址?
答案1
发生这种情况是因为默认情况下,AF_INET6 套接字实际上适用于 IPv4 和 IPv6。看第 3.7 节 - 与 RFC 3493 的 IPv4 节点的兼容性 - IPv6 的基本套接字接口扩展
下面是一个可以产生这种情况的简短代码示例:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define TEST_PORT 5555
#define xstr(s) str(s)
#define str(x) #x
int main (int argc, char **argv)
{
int v6server;
int v4client;
int rc;
struct sockaddr_in6 s6addr = {
.sin6_family = AF_INET6,
.sin6_flowinfo = 0,
.sin6_port = htons(TEST_PORT),
.sin6_addr = in6addr_any
};
struct sockaddr_in c4addr = {
.sin_family = AF_INET,
.sin_port = htons(TEST_PORT),
.sin_addr = inet_addr("127.0.0.1")
};
// Open an IPv6 listener
v6server = socket(AF_INET6, SOCK_STREAM, 0);
if (v6server < 0) perror("socket()");
rc = bind(v6server, (struct sockaddr *)&s6addr, sizeof(s6addr));
if (rc != 0) perror("bind()");
rc = listen(v6server, 0);
if (rc != 0) perror("listen()");
// Connect to the listener with an IPv4 socket
v4client = socket(AF_INET, SOCK_STREAM, 0);
if (v4client < 0) perror("socket()");
rc = connect(v4client, (struct sockaddr *)&c4addr, sizeof(c4addr));
if (rc != 0) perror("connect()");
// inspect open sockets
system("netstat -tan | grep " xstr(TEST_PORT));
close(v4client);
close(v6server);
}
我的 Ubuntu 机器上的输出是:
$ make v4v6
cc v4v6.c -o v4v6
$ ./v4v6
tcp 0 0 127.0.0.1:46518 127.0.0.1:5555 ESTABLISHED
tcp6 0 0 :::5555 :::* LISTEN
tcp6 0 0 127.0.0.1:5555 127.0.0.1:46518 ESTABLISHED
$
- 该
tcp6 LISTEN
条目用于侦听端口 5555 的套接字。请注意,它是 AF_INET6 套接字,因此它将接受 IPv4 和 IPv6 传入连接。 - 该
tcp ESTABLISHED
条目是将 AF_INET4 套接字连接到侦听器(活动连接)的结果。 - 该
tcp6 ESTABLISHED
条目用于从侦听器套接字生成的被动连接。它显示为tcp6
,因为它是从tcp6
侦听器生成的;然而,它代表来自 IPv4 的连接。
值得注意的是以下几点:
- 此行为对于 AF_INET6 套接字来说是特殊的。 AF_INET (IPv4) 套接字根本不能也不会处理任何 IPv6 内容。
- 此行为可能会被覆盖IPV6_V6ONLY 套接字选项。设置此选项将导致套接字仅有的处理 IPv6 并且不允许任何 IPv4。