我正在编写一个小型 VPN 服务器,其中对于某个 ip 地址,我通过一个http proxy
.
当前设置
- TUN 接口在 10.0.2.0/24 启动并运行
iptables 配置
iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -j MASQUERADE
VPN逻辑
- 当我收到一个发往某个地址的 IP 数据包时,比如说
1.2.3.4
,我将它的目标地址127.0.0.1
和目标端口更新为12345
。 TCP
我重新计算和IP
层的校验和
代码
- 我使用gopackets解析 IP 层和 TCP 层
- 更新目的端口和IP地址
- 在应用层创建一个 NAT 条目,以便我可以将响应数据包中的
source_ip
and改回source_port
// Code to receive packet from tun interface
pkt := gopacket.NewPacket(packet, layers.LayerTypeIPv4, gopacket.DecodeOptions{
NoCopy: true,
Lazy: false,
})
if ntPkt := pkt.NetworkLayer().(*layers.IPv4); ntPkt != nil {
var err error
if tPkt := pkt.TransportLayer().(*layers.TCP); tPkt != nil {
// Adding NAT entry
h.nLock.RLock()
hash := fmt.Sprintf("%s:%d", waterutil.IPv4Source(packet).String(), waterutil.IPv4SourcePort(packet))
if _, ok := h.natTable[hash]; !ok {
h.nLock.RUnlock()
h.nLock.Lock()
h.natTable[hash] = net.TCPAddr{IP: waterutil.IPv4Destination(packet), Port: int(waterutil.IPv4DestinationPort(packet))}
h.nLock.Unlock()
} else {
h.nLock.RUnlock()
}
buf := gopacket.NewSerializeBuffer()
ntPkt.DstIP = h.proxyIP
tPkt.DstPort = layers.TCPPort(h.proxyPort)
tPkt.SetNetworkLayerForChecksum(ntPkt)
err = gopacket.SerializeLayers(buf, h.opts,
ntPkt,
tPkt)
if err != nil {
logger.E("Error while serializing, skipping the changes", err)
return nil
}
copy(packet, buf.Bytes())
}
}
// Code to write packet onto tun interface
预期产出
- 来自的流量
tun0
将被转发到eth0
(即使我不添加该 iptable 条目,默认路由也会做同样的事情) eth0
将知道 lo 地址,因此会将数据包转发到环回地址,并最终转发到在 localhost 上运行的代理
实际输出
- 数据包在中间丢失
tshark -i tun0
显示数据包从tun0
2419 279.256438200 10.0.2.3 ? 127.0.0.1 TCP 60 [TCP Retransmission] 47129 ? 12345 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=550203836 TSecr=0 WS=256
- 但既不显示
lo
也不eth0
显示--dport 12345 的相应条目。