我有一个特定于iptables的问题。我在计算机上定义了以下网络接口:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether f8:ca:b8:5c:59:b5 brd ff:ff:ff:ff:ff:ff
inet 172.16.214.45/24 brd 172.16.214.255 scope global dynamic eno1
valid_lft 773635sec preferred_lft 773635sec
3: wlp3s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 80:00:0b:d7:a8:c5 brd ff:ff:ff:ff:ff:ff
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:bf:b2:fa:86 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
我有一个活动的docker容器正在ip 172.17.0.2上侦听(已连接到docker0接口)
我想做两件事:
我已经做到了,但是在环回接口上进行测试时它不起作用
iptables -t nat -I PREROUTING -i lo -d 127.0.0.1 -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443
$ curl https://localhost:8443
curl: (7) Failed to connect to localhost port 8443: Connection refused
$ curl -k https://172.17.0.2:8443
{
"paths": [
"/api"
]
}
有经验的iptables员工有任何迹象表明我在做什么错吗?
有两个问题(实际上是一个未问到的第三个问题,我将通过一个简单的,即使不是最好的解决方案也要解决,以防万一,以待彻底解决):
本地启动的数据包不转发(路由)。因此,这些数据包永远不会看到nat/PREROUTING
链。查看Netfilter和通用网络中的数据包流,以了解内核中数据包生命周期中发生的情况。本地数据包来自“本地进程”。
因此,除了对从“外部”到达的数据包nat/PREROUTING
执行“ DNAT
for ”规则外,它还应如下所示:
iptables -t nat -I PREROUTING -i eno1 -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443
您还必须使用nat/OUTPUT
链。输出时,其语法仅允许传出接口,因此将其更改为:
iptables -t nat -I OUTPUT -o lo -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443
最初的数据包和流将实际重新路由到另一个接口(我怀疑上一个链接的原理图中的“重新路由检查”可能未正确放置)。
这将适用于属于主机的任何IP(即172.16.214.45和172.17.0.1),但...
lo
接口外部看到IP范围127.0.0.0/8Linux内核具有特定的设置,可以防止将127.0.0.0/8范围内的任何IP路由到该lo
接口以外的任何其他位置,并且如果“尝试”使用其他接口,则丢弃任何此类数据包作为火星源,正确的是:远程系统(即使是容器)也不会接受源127.0.0.1和目标172.17.0.2的传入数据包,至少是因为它不知道在哪里答复。
因此,除了必须之外,还必须对数据包进行一个SNAT
(或简单的MASQUERADE
)处理DNAT
,这一次是在nat/POSTROUTING
遍历的链中进行的(请参见前面的示意图):
iptables -t nat -I POSTROUTING -s 127.0.0.1 -d 172.17.0.2 -j MASQUERADE
这仍然是不够的:顾名思义,nat/POSTROUTING
发生在路由之后(实际上是在之后发生的重新路由检查DNAT
),并且数据包已经作为火星源被丢弃。
对于像这样的特殊情况,可以通过按接口切换来覆盖localnet限制route_localnet
:
echo 1 > /proc/sys/net/ipv4/conf/docker0/route_localnet
现在,路由堆栈允许源为127.0.0.1的数据包通过,并且在通过虚拟线路连接到容器之前,根据先前的规则将其源数据更正为172.17.0.1:它可以工作。
您真的应该避免任何需要第二种情况的情况,因为这是不必要的复杂性:对于任何测试,使用属于主机而不是127.0.0.1的IP就足够了。同样,如果docker0
要删除并重新创建接口,则该route_localnet
设置将丢失,并且将其设置为默认值也不明智。
不会被问到,但是如果您在同一LAN中添加第二个系统(这里是一个容器),则lan到主机到相同lan重定向会出现问题(除非Docker已在网络级别处理此问题)。
nat/PREROUTING
我在答案开头写的规则仅处理eno1
接口。我添加了此-i eno1
限制是有原因的:如果没有此限制,则如果172.17.0.0/16网络中的其他容器尝试连接到例如172.16.214.45:8443(或172.17.0.1:8443),则该数据包将被重定向至172.17.0.2。然后172.17.0.2将直接答复源:另一个容器,并完全绕过主机及其NAT规则。该容器将看到来自未知来源的回复数据包,并拒绝它(使用TCP RST
)。因此,最好不要完全处理它,而要处理不好。Docker可能提供了直接将服务解析到另一个容器的IP /端口而不涉及主机的特定方法。
无论如何,如果有需要,有几种方法可以解决此问题,通常是权衡取舍,从简单的NAT(丢失源IP或必须将其转换为虚拟网络以进行记录)到复杂的网桥和/或路由器设置(可拦截)局域网通信。
这是一个简单的解决方案,其中的源使用SNAT编辑NETMAP
到虚拟网络10.17.0.0/16。一个简单的先决条件:10.17.0.0/16可能必须在主机上路由(即使未真正使用),也可以在默认路由(可能是这种情况),特定路由或在该虚拟网络中具有IP的主机上进行路由。这个目的。具有此IP的数据包仅存在于docker0
的网络内部。
-i eno1
从PREROUTING
上面的规则中删除后,添加此新规则:
iptables -t nat -I POSTROUTING -s 172.17.0.0/16 -d 172.17.0.0/16 -j NETMAP --to 10.17.0.0/16
现在,从LAN到同一LAN的重定向将起作用,目标容器的日志显示源IP在10.17.0.0/16范围内。
当然,也应避免发夹情况。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句