在 Linux 上通过自定义 Tap 设备路由流量到互联网

在 Linux 上通过自定义 Tap 设备路由流量到互联网

我有一台正在使用 Tap 设备()的虚拟机,我的目标是使用我编写的在用户空间运行的自定义程序tap2过滤所有进出流量。tap2

我想到的拓扑结构将流量从我的进程监听帧的位置路由tap2tap1,并且任何允许前往目的地的帧都将通过使用传统 NAT 设置tap0进行连接的进程。enp0s25

                                  ┌─────────────────────────┐                                  
                                  │                         │                                  
                                  │                         │                                  
                                  │                         │                                  
                                  │Userspace filter process │                                  
                              ┌──▶│                         │───┐                              
                              │   │                         │   │                              
                              │   │                         │   │                              
┌────────┐        ┌────────┐  │   │                         │   │   ┌────────┐       ┌────────┐
│        │        │  tap1  │  │   └─────────────────────────┘   │   │  tap0  │       │        │
│  tap2  │───────▶│        │──┘                                 └──▶│        │──────▶│  enp0s25  │
│        │        │        │                                        │        │       │        │
└────────┘        └────────┘                                        └────────┘       └────────┘
┌────────┐                                                                                     
│        │                                                                                     
│   VM   │                                                                                     
│        │                                                                                     
└────────┘                                                                                     

我基本上停留在这个拓扑的第一部分。我有一个简单的python程序,它连接tap1并打印出它看到的任何帧:https://gist.github.com/shriphani/f98c212e0f4eb8d63ce3059a28509441

然后,我调出适当的设备:

tap1

sudo ip tuntap add tap1 mode tap user shriphani
sudo ip addr add 172.19.0.1/24 dev tap1
sudo ip link set tap1 up

tap2

sudo ip tuntap add tap2 mode tap user shriphani
sudo ip addr add 172.20.0.1/24 dev tap2
sudo ip link set tap2 up

接下来,我添加了从 tap2 到 tap1 的路线:

sudo ip route add 172.20.0.0/24 via dev tap1

这会导致以下错误消息:

RTNETLINK answers: File exists

这是路由表:

default via 192.168.1.1 dev enp0s25 proto dhcp src 192.168.1.16 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.19.0.0/24 dev tap1 proto kernel scope link src 172.19.0.1 linkdown
172.20.0.0/24 dev tap2 proto kernel scope link src 172.20.0.1
192.168.1.0/24 dev enp0s25 proto kernel scope link src 192.168.1.16
192.168.1.1 dev enp0s25 proto dhcp scope link src 192.168.1.16 metric 100

这更加奇怪,因为我在路由表中没有看到我要求的确切路线。

无论如何,我随后添加了以下iptables命令:

sudo iptables -A FORWARD -i tap2 -o tap1 -j ACCEPT
sudo iptables -t nat -A PREROUTING --in-interface tap2 -j DNAT --to-destination 172.19.0.2
sudo iptables -t nat -A POSTROUTING --out-interface tap1 -j MASQUERADE

我的理解是,我允许来自tap2-> 的流量tap1,将所有流量路由tap2tap1(到那个特定的IP地址 - 不确定是否正确),然后所有传出的流量tap1似乎都来自tap1(到目前为止我还没有传出的流量)。

当我运行附加到 的 Python 脚本tap1wget google.com从 VM 中运行它时,我看不到任何打印内容。从主机 ping tap IP 范围会导致脚本响应(即我ping 172.19.0.2在主机上执行此操作,脚本会打印一些内容)。

所以我对此设置有两个问题:

  1. 这种拓扑结构是否合理,或者是否有更简单的方法来实现我的目标
  2. 如果这是一个好的拓扑,我需要什么精确的规则集来强制来自 VM(tap2)的所有流量首先出现,tap1然后我可以将其发送出去。

非常感谢。任何帮助我都会很感激。

相关内容