我正在尝试在我的主机上设置透明代理网络。
真正的客户端和代理目标是容器,但在这个实验中,我使用 netns(网络命名空间)分隔的环境。
为了透明地将客户端流量重定向到代理,我使用策略路由。
Client (C) Proxy (P)
10.10.1.1/24 10.10.2.1/24
veth0 veth0
| |
veth pair veth pair
| |
-----------(HOST)--------------
client-veth0 proxy-veth0
10.10.1.2/24 10.10.2.2/24
| | 172.16.202.30
+-----------------+-------------- enp4s0 ---- INTERNET
# Policy Routing on Host
# [Client->Proxy]
# ip rule: from 10.10.1.0/24 iif client-veth0 lookup 100
# ip route: (100) default via 10.10.2.1 dev proxy-veth0
# [Proxy->Internet]
# ip route: (master) default via 172.16.202.1 dev enp4s0 proto static metric 100
# iptables: -t nat -A POSTROUTING -s 10.10.1.1/32 -o enp4s0 -j MASQUERADE
# [Internet->Proxy]
# ip rule: from all to 10.10.1.0/24 iif enp4s0 lookup 100
# ip route: (100) default via 10.10.2.1 dev proxy-veth0
# [Proxy->Client]
# ip rule: from all to 10.10.1.0/24 iif proxy-veth0 lookup 101
# ip route: (101) default via 10.10.1.1 dev client-veth0
问题是,当我从客户端 ping 8.8.8.8 时,在客户端 netns 中,源 IP 伪装不会发生。
iptables 伪装规则不匹配,默认为 ACCEPT 。我希望 enp4s0 上的 tcpdump 显示172.16.202.30 --> 8.8.8.8
,但它显示10.10.1.1 --> 8.8.8.8
,没有源 IP 伪装。
我在互联网线路上记录了 pcap 以澄清 SNAT 不会发生。client_to_goolge
从 enp4s0 之外的单独机器记录:
$ tcpdump -r client_to_google -n
reading from file client_to_google, link-type EN10MB (Ethernet)
23:35:40.852257 IP 10.10.1.1 > 8.8.8.8: ICMP echo request, id 14867, seq 1, length 64
23:35:41.865269 IP 10.10.1.1 > 8.8.8.8: ICMP echo request, id 14867, seq 2, length 64
当我检查 iptables mangle 表时,数据包按给定策略流动:
PREROUTING: client-veth0, 10.10.1.1 --> 8.8.8.8
POSTROUTING: proxy-veth0, 10.10.1.1 --> 8.8.8.8
PREROUTING: proxy-veth0, 10.10.1.1 --> 8.8.8.8
POSTROUTING: enp4s0, 10.10.1.1 --> 8.8.8.8
proxy-veth0
但是,当我在输出界面上更改伪装规则时,像这样iptables: -t nat -A POSTROUTING -s 10.10.10.1/32 -o proxy-veth0 -j MASQUERADE
,伪装发生了。即
10.10.2.2 --> 8.8.8.8
数据包被捕获。
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
...
11 0 0 MASQUERADE all -- * enp4s0 10.10.1.1 0.0.0.0/0
12 1 84 MASQUERADE all -- * proxy-veth0 10.10.1.1 0.0.0.0/0
上表显示规则#11enp4s0
输出条件未触发。在使用规则#11 进行多次测试后插入规则#12。规则 #12 表明proxy-veth0
输出条件确实触发了。enp4s0
主网卡和proxy-veth0
使用 iptables 的虚拟接口之间有什么区别吗?
任何意见将不胜感激,谢谢。
我必须假设透明代理充当路由器,至少对于 ICMP 而言,因此将路由回它来自的 ICMP 回显(veth0)。
发现问题
在重现您的设置并见证您的问题时,我使用iptables(旧版,可能与iptables-nft的版本略有不同)在主机上添加了一个TRACE(我还强制创建过滤表()它在痕迹中):
iptables -S
并且在内核日志中显示一个 ping(提示,如果主机不是实际的初始主机:)
sysctl -w net.netfilter.nf_log_all_netns=1
:同时,
conntrack -E
在主机上运行显示匹配:发生了什么:
由于这个conntrack的限制在过去阻碍了一些用例,比如你的,所以添加了一个附加功能:
连接区
它允许在某种程度上复制conntrack设施,包括 NAT 处理,但必须手动完成并匹配问题:这里是路由拓扑。
因此,从conntrack的角度来看,客户端 <-> 代理流量必须与其他流量分开。
我更希望将代理 <-> Internet 流量与通用主机流量分开,但这太难了,因为必须将区域分配给数据包的原始表只能看到非去 NAT 的流量,因此 Internet 回复将全部到达目的地 172.16.202.30)。无论如何,两者之间没有重复的流程,就像客户端 <-> 代理流程一样,所以这并不是真正需要的。
区域 0(0 表示没有特殊区域):通用主机流量以及代理 <-> 互联网流量。
没什么特别的,这是默认的。
区域 1:客户端 <-> 代理流量。使用
CT --zone
目标。这里的值是任意选择的,在这种情况下其他任何地方都不需要。正确的结果(我合并了两个工具的输出)现在是:
这里来自新流的单个第一个数据包会触发两次 iptables 的nat表,第一次没有效果。实际上conntrack认为有两个流,因为第一个流具有附加属性
zone=1
。这是正常的 iptables NAT 行为。现在用 tcpdump 进行测试,我使用了三个虚拟机,在每个虚拟机上我都设置了 SNAT 规则
vm1(10.10.1.1) ---> vm2(10.10.2.2) ---> vm3(1.2.3.4) (公共IP地址)
然后我尝试从 10.10.1.1 ping 8.8.8.8,在所有三台机器上运行 tcpdump,结果接下来是:在 vm2 10.10.1.1 ---> 8.8.8.8 在 vm3 10.10.2.2 ---> 8.8.8.8
理论上,如果我有 vm4,我会看到 1.2.3.4 ---> 8.8.8.8
你能显示你的代理配置吗?
鲍里斯