我有一个服务在某个 X 端口上的“localhost”地址上运行。不幸的是,我无法将地址更改为“0.0.0.0”以公开该服务。
我可以使用 iptables 在内部将请求从外部重定向到环回/本地主机接口吗?重定向将是 0.0.0.0:X -> localhost:X
谢谢
答案1
由于OP没有提到防火墙的存在,并且为了简单起见,我假设事先没有iptables设置存在:允许任何流量。
DNAT可用于nat/预路由将目标 IP 更改为 127.0.0.1,如下所示(重定向 UDP 端口 5555 的示例):
# iptables -t nat -A PREROUTING -p udp --dport 5555 -j DNAT --to-destination 127.0.0.1
但虽然这对于任何 DNAT 目标到 127.0.0.0/8 范围之外的系统任何本地 IP 地址来说已经足够了。对于将目标更改为 127.0.0.0/8 内的 IP 地址的特定情况,这还不够。
必须切换一种特殊设置才能使其正常工作。假设系统的网络接口被称为以太网0这个命令会做到这一点:
# sysctl -w net.ipv4.conf.eth0.route_localnet=1
详细解释见后文。
(可选)特别是如果侦听 127.0.0.1 的应用程序不需要 127.0.0.0/8 之外的源 IP,您还可以更改自然/输入链与网络地址转换。对目标和源进行 NAT 会严重限制并发连接的数量,因此您应该仅在需要时才执行此操作,并且您将不再在日志中获取实际源:
# iptables -t nat -A INPUT -d 127.0.0.1 -m state --ctstate DNAT -j SNAT --to-source 127.0.0.1
关于使用的详细解释route_localnet
=1
为了在下面更彻底地说明问题,我将假设:主机的网络接口是以太网0,在此接口上设置的 IP 地址为 192.0.2.100/24,正在接收来自客户端 192.0.2.200 的流量,但route_localnet
尚未启用。
必须看一看Netfilter 和通用网络中的数据包流(点击查看完整尺寸):
检查事情发生的顺序:
客户端从 192.0.2.200 发送数据包到 192.0.2.100(UDP 目标端口 5555)
nat/预路由发生
目的地更改为 127.0.0.1(随后将使用相应的 conntrack 条目来恢复回复的此更改)
路由堆栈处理到达的数据包以太网0源地址为 192.0.2.200,目标地址为 127.0.0.1。
路由堆栈认为此数据包无效,因为 127.0.0.1 永远不会出现在
lo
环回接口之外。数据包被丢弃。可以通过以下方式检查
ip route get
:# ip route get 127.0.0.1 from 192.0.2.200 iif eth0 RTNETLINK answers: Invalid argument
除此之外,如果要激活内核火星日志(
sysctl -w net.ipv4.conf.eth0.log_martians=1
) ,DNAT 时收到的每个数据包都会记录此信息iptables上面的规则正在起作用:[728538.240893] IPv4: martian destination 127.0.0.1 from 192.0.2.200, dev eth0
在极少数需要这样做的情况下,内核有一个特定的切换来放松这种行为,就像这个特定的情况一样,我们知道数据包中出现 127.0.0.1 的原因是 DNAT 规则:route_localnet
:
route_localnet - BOOLEAN Do not consider loopback addresses as martian source or destination while routing. This enables the use of 127/8 for local routing purposes. default FALSE
在以太网0:
# sysctl -w net.ipv4.conf.eth0.route_localnet=1
现在,前面的ip route get
命令给出了:
# ip route get 127.0.0.1 from 192.0.2.200 iif eth0
local 127.0.0.1 from 192.0.2.200 dev lo
cache <local> iif eth0
不再掉落了。
这也将以相反的方式放宽相同的限制:作为第一步,回复数据包将遍历路由决策,前被 netfilter 取消 DNAT,因此也会被丢弃。之前和之后的路线route_localnet
设置为 1:
前:
# ip route get 192.0.2.200 from 127.0.0.1
RTNETLINK answers: Invalid argument
后:
# ip route get 192.0.2.200 from 127.0.0.1
192.0.2.200 from 127.0.0.1 dev eth0 uid 0
cache
答案2
是的,这是可能的。
以下命令序列应该可以做到这一点:
INTERFACE_IP="192.168.0.1" # IP address of the external interface (e.g. eth0)
INTERFACE_PORT="80" # external port to forward
LOCAL_IP="127.0.0.1" # internal ip address to forward to
LOCAL_PORT="8080" # internal port to forward to
/usr/sbin/iptables -t nat -A PREROUTING -d $INTERFACE_IP --dport $INTERFACE_PORT -j DNAT --to-destination $LOCAL_IP:$LOCAL_PORT
或者稍微不那么动态:
/usr/sbin/iptables -t nat -A PREROUTING -d 192.168.0.1 --dport 80 -j DNAT --to-destination 127.0.0.1:8080
如果目标端口 (:8080) 与传入端口相同,则可以省略。
请注意,您的 iptables 中的其他规则可能会给该规则带来问题!