Java 如何伪装tap接口流量
我目前正在用Java开发一个VPN服务器,至少要用Java开发尽可能多的VPN服务器,并且我计划通过Java 如何伪装tap接口流量,java,c,linux,vpn,iptables,Java,C,Linux,Vpn,Iptables,我目前正在用Java开发一个VPN服务器,至少要用Java开发尽可能多的VPN服务器,并且我计划通过tap设备执行客户端数据包的路由 目前,我能够将以太网帧写入轻触设备,并且可以通过tcpdump观察这些数据包。但是,它们不会通过eth0路由,尽管我启用了ip转发,并在iptables中添加了MASQUERADE规则。(这个问题似乎与相同,只是网关接口是一个真实的接口,在我的情况下是一个虚拟接口。) ifconfig tap0的输出如下: tap0 Link encap:Etherne
tap
设备执行客户端数据包的路由
目前,我能够将以太网
帧写入轻触
设备,并且可以通过tcpdump
观察这些数据包。但是,它们不会通过eth0
路由,尽管我启用了ip转发,并在iptables
中添加了MASQUERADE
规则。(这个问题似乎与相同,只是网关接口是一个真实的接口,在我的情况下是一个虚拟接口。)
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)
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
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;
}
}
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
ip link show 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)
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
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;
}
}
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
成功获取文件描述符后,通过write()
调用写入设备是很简单的
我如何准备以太网帧,如下所示:
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)
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
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;
}
}
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
并输出路由-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
非常感谢您的任何帮助
附言:我正在Ubuntu 16.04上开发
编辑:
为了确保数据包不会离开eth0
,我在不同的终端上启动了tcpdump-I eth0主机5.189.147.197-n
和tcpdump-I tap0主机5.189.147.197-n
,同时客户端试图连接到5.189.147.197
。我在tap0
界面上观察到流量,但在eth0
界面上没有观察到流量。所以它们肯定不会被转发。一如既往,原因很简单:在注入数据包时,我错误地计算了IP报头中的校验和。也就是说,我忘了在添加后翻转位。我真丢脸
我不会删除整个问题,因为它可能会帮助人们开发类似的应用程序
要检查校验和是否正常,您可以在更详细的模式下运行tcpdump
,即包括一些-v
参数。我使用tcpdump-i tap0-n-X-s0-vvv
来观察数据包的内容。这对我帮助很大
关于user1794469建议的桥接选项,您需要在eth0
子网中具有可分配给客户端的额外IP,因为桥接使客户端看起来像一个新的参与者(没有任何NAT)加入子网。但是,我的VPS有一个单独的IP分配给它,并且它不在NAT后面,所以没有DHCP等。这就是为什么我需要有自己的NAT。现在它可以完美地工作。你看到eth0上的tcpdump
有什么吗?它们根本就不存在吗?过滤表(sudo iptables-L
)上的规则是什么?@user1794469所有链都将接受
作为默认策略,并且没有其他规则。@user1794469由于响应不会返回,我认为它们根本不会到达eth0
,但让我确定一下。将更新。@user1794469请查看编辑。很快,数据包不会出现在eth0
上。您知道吗你知道发生了什么吗?实际上这是一个非常基本的路由问题。也许有比我更了解的人可以插话,但我认为你需要将tap0
与eth0
连接起来。以下是有关如何: