【发布时间】:2018-06-13 06:54:27
【问题描述】:
我目前正在使用 Java 开发 VPN 服务器,至少尽可能使用 Java,并且我计划通过 tap 设备执行客户端数据包的路由。
目前,我可以将ethernet 帧写入tap 设备,并且可以通过tcpdump 观察这些数据包。但是,尽管我启用了 ip 转发并将MASQUERADE 规则添加到iptables,但它们并未通过eth0 路由。 (这个问题似乎与that 相同,只是网关接口是那里的真实接口,而在我的情况下是虚拟接口。)
ifconfig tap0的输出如下:
tap0 Link encap:Ethernet HWaddr 82:7d:95:39:71:a1
inet addr:10.1.0.1 Bcast:10.1.255.255 Mask:255.255.0.0
inet6 addr: fe80::807d:95ff:fe39:71a1/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:767 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:56838 (56.8 KB) TX bytes:0 (0.0 B)
ip link show tap0的输出如下:
12: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 82:7d:95:39:71:a1 brd ff:ff:ff:ff:ff:ff
这是我连接到水龙头设备的方法:
int helper_open(const char* dev_name, int tun_or_tap) {
struct ifreq ifr;
int fd;
if ((fd = open("/dev/net/tun", O_RDWR)) == -1) {
return -1;
}
memset(&ifr, 0, sizeof (ifr));
strncpy(ifr.ifr_name, dev_name, IFNAMSIZ);
ifr.ifr_flags = IFF_NO_PI;
if (tun_or_tap == DEVICE_TUN) {
ifr.ifr_flags |= IFF_TUN;
} else if (tun_or_tap == DEVICE_TAP) {
ifr.ifr_flags |= IFF_TAP;
} else {
return -2;
}
if (ioctl(fd, TUNSETIFF, (void *) &ifr) == -1) {
close(fd);
return -3;
}
return fd;
}
成功获取文件描述符后,通过write()调用写入设备是轻而易举的事。
我如何准备以太网帧如下:
public boolean sendIp(byte[] buffer, int start, int length) {
byte[] frame = new byte[length+14];
System.arraycopy(mac, 0, frame, 0, 6);
System.arraycopy(mac, 0, frame, 6, 2);
byte[] ip = IpUtils.getSourceIp(buffer, start).getAddress();
for (int i = 0; i < 4; i++) {
frame[8+i] = (byte) (0xFF & (ip[i] ^ mac[i+2]));
}
frame[12] = 0x08;
frame[13] = 0x00;
System.arraycopy(buffer, start, frame, 14, length);
try {
write(frame, 0, frame.length);
return true;
} catch (IOException e) {
logger.error("cannot send ip packet.", e);
return false;
}
}
mac 是tap 设备的 MAC 地址,我通过将 Tap 设备 MAC 的最后四个字节与我分配的虚拟 IP 进行异或运算来生成客户端的 MAC 地址。 (在我的测试中,客户端的 IP 是 10.1.0.2。)这样,它对所有参与者都是唯一的,也很容易处理 ARP/RARP 协议。
从ifconfig 输出的RX packets 字段可以看出,数据包在tap 设备中接收。此外,样本tcpdump -i tap0 -n 输出如下:
15:53:48.395082 IP 10.1.0.2.47132 > 216.58.208.34.443: Flags [S], seq 3162009985, win 65535, options [mss 1460,sackOK,TS val 4294939804 ecr 0,nop,wscale 6], length 0
15:53:49.396355 IP 10.1.0.2.39713 > 216.58.208.42.443: Flags [S], seq 2459164785, win 65535, options [mss 1460,sackOK,TS val 4294939905 ecr 0,nop,wscale 6], length 0
15:53:49.678691 IP 10.1.0.2.58306 > 194.177.210.54.123: NTPv3, Client, length 48
15:53:50.508132 IP 10.1.0.2.38112 > 172.217.22.110.443: Flags [S], seq 3132386571, win 65535, options [mss 1460,sackOK,TS val 4294940016 ecr 0,nop,wscale 6], length 0
15:53:51.519119 IP 10.1.0.2.37492 > 216.58.207.42.443: Flags [S], seq 3750738666, win 65535, options [mss 1460,sackOK,TS val 4294940117 ecr 0,nop,wscale 6], length 0
数据包被 tcpdump 正确解码,所以看来我正在成功准备以太网帧。 sysctl net.ipv4.ip_forward 表示启用了 ip 转发。那为什么不通过eth0路由呢?
iptables -L -n -v -t nat的输出:
Chain PREROUTING (policy ACCEPT 2436 packets, 132K bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 2436 packets, 132K bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 20 packets, 1462 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
20 1462 MASQUERADE all -- * eth0 0.0.0.0/0 0.0.0.0/0
和route -n的输出:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 173.212.233.1 0.0.0.0 UG 0 0 0 eth0
10.1.0.0 0.0.0.0 255.255.0.0 U 0 0 0 tap0
173.212.233.0 173.212.233.1 255.255.255.0 UG 0 0 0 eth0
173.212.233.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
非常感谢任何形式的帮助。
P.S:我正在 Ubuntu 16.04 上开发。
编辑:
为了确保数据包不会离开eth0,我在不同的终端上启动了tcpdump -i eth0 host 5.189.147.197 -n 和tcpdump -i tap0 host 5.189.147.197 -n,同时客户端尝试连接到5.189.147.197。我观察了tap0 接口上的流量,但没有观察eth0 接口上的流量。所以它们肯定不会被转发。
【问题讨论】:
-
你在 eth0 上看到了
tcpdump什么?他们根本就没有成功吗?过滤表(sudo iptables -L)的规则是什么? -
@user1794469 所有链都有
ACCEPT作为默认策略,没有其他规则。 -
@user1794469 因为回复没有回来,我以为他们根本没有到达
eth0,但让我确定一下。会更新。 -
@user1794469 请参阅编辑。很快,数据包不会出现在
eth0上。你知道发生了什么吗?这实际上是一个非常基本的路由问题。 -
也许比我更有知识的人可以插话,但我认为你需要将
tap0与eth0联系起来。以下是有关如何操作的信息:help.ubuntu.com/community/NetworkConnectionBridge