我正在设置一个本地 vpn 环境,我想通过虚拟网络接口在本地捕获流量,然后通过物理网络接口绑定套接字将它们转发到真实目的地。但是,设置 tun 虚拟网络接口后,我什至无法连接真实目的地。
我的测试机:Linux testing-VirtualBox 3.19.0-15-generic #15-Ubuntu SMP Thu Apr 16 23:32:37 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
首先,我成功创建了一个名为 tun0 的虚拟网络接口,如下所示:
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.2.1 P-t-P:192.168.2.1 Mask:255.0.0.0
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
为简洁起见,我只是将目标服务器的 ip 地址添加到路由表中: route add -host 45.113.192.102 dev tun0 路由表如下: 内核 IP 路由表
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 xxx.xx.xxx.xxx 0.0.0.0 UG 0 0 0 eth0
45.113.192.102 0.0.0.0 255.255.255.255 UH 0 0 0 tun0
xxx.xx.xxx.xxx 0.0.0.0 255.255.255.128 U 0 0 0 eth0
192.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 tun0
xxx.xx.xxx.xxx 是我的内部主机/网关 IP 地址。
最后,我创建了一个套接字并将套接字绑定到物理网络接口。我在这里使用 libuv,应该不管这个问题。
struct sockaddr_in remote_addr;
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = ntohs(443);
inet_pton(AF_INET, "45.113.192.102", &remote_addr.sin_addr);
uv_os_sock_t sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
std::cout << "ERROR--- create socket failed\n";
return -1;
}
int32_t r;
r = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "eth0", strlen("eth0"));
if (r != 0) {
std::cout << "setsockopt failed: " << errno;
return -1;
}
uv_tcp_init(g_uv_loop, &socket_handle);
r = uv_tcp_open(&socket_handle, sock);
uv_connect_t connect_req;
r = uv_tcp_connect(&connect_req, &socket_handle,
(struct sockaddr *) &remote_addr, _tcp_connect_cb);
我运行我的代码,发现我无法连接到“45.113.192.102”。我通过wireshark抓到流量,发现我的程序已经向“45.113.192.102”发送了SYN,“45.113.192.102”也回复了SYN,ACK。但是,在那之后似乎我的程序没有发送 ACK,导致连接失败。接下来,Client不断发送[TCP Spurious Retransmission] SYN,Server回复[TCP Retransmission] SYN,ACK。