从LAN内部访问DNAT的Web服务器


12

我有一个带有路由器的小型网络,该路由器可维护与Internet,服务器和本地网络中某些工作站的连接。

网络图

可以从Internet访问服务器,并且在路由器iptables中设置了多个DNAT条目,如下所示:

-A PREROUTING -i ppp0 -p tcp -m multiport --dports 22,25,80,443 -j DNAT --to-destination 192.168.2.10

外部数据包通过ppp0接口到达路由器,内部数据包从接口到达br-lan,实际上包括交换机和WLAN适配器。问题是,尽管外部访问可以正常进行,但是尝试通过DNS解析的外部IP(分配给ppp0)从LAN内部访问服务器失败。

我能够发明的唯一解决方案是在/etc/hosts指向内部IP的路由器指向中添加静态条目,但是由于没有通配符(并且我至少为该系统分配了三个顶级域,所以不计算数十个子域),这非常脆弱而且容易失败。你能提出更好的建议吗?

我只发现了这个问题,但不是很有帮助。

如果相关,路由器将运行带有dnsmasq的OpenWRT 10.03 Kamikaze。


什么版本的OpenWRT?
Corey S.

@Corey 10.03稳定,但这与openwrt本身无关,不是吗?
whitequark 2010年

Answers:


3

令我惊讶的是,将近8年之后,没有人解释过如何使用OpenWRT中默认使用的UCI配置系统正确执行此操作。

史蒂文·星期一的回答是正确的,但是它iptables直接使用命令,它比UCI配置系统低一层,如果可能的话,最好不要被大多数OpenWRT用户使用。

通过其公共IP /端口组合从UCI中的另一台内部主机访问内部服务器的正确方法是,启用reflection文件中每个特定DNAT目标下的配置选项/etc/config/firewall。此行为在此处记录

例如:

config redirect option target 'DNAT' option src 'wan' option dest 'lan' option proto 'tcp' option src_dport '44322' option dest_ip '192.168.5.22' option dest_port '443' option name 'apache HTTPS server' option reflection '1'

注意:根据指示的OpenWRT文档,reflection默认情况下启用。在我的测试中,情况并非如此。


15

我删除了原来的答案,因为我不确定它是正确的。从那以后,我花了一些时间建立一个虚拟机虚拟网络来模拟所讨论的网络。这是一组适用于我的防火墙规则(iptables-save格式nat仅适用于表):

-A PREROUTING -d 89.179.245.232/32 -p tcp -m multiport --dports 22,25,80,443 -j DNAT --to-destination 192.168.2.10
-A POSTROUTING -s 192.168.2.0/24 -o ppp0 -j MASQUERADE
-A POSTROUTING -s 192.168.2.0/24 -d 192.168.2.10/32 -p tcp -m multiport --dports 22,25,80,443 -j MASQUERADE

第一条POSTROUTING规则是与LAN共享Internet连接的直接方法。为了完整起见,我把它留在那里。

PREROUTING规则和第二个POSTROUTING规则一起建立了适当的NAT,因此,无论连接是来自外部还是内部,都可以通过外部IP地址与服务器建立连接。当LAN上的客户端通过外部IP地址连接到服务器时,服务器会将连接视为来自路由器的内部IP地址(192.168.2.1)。

有趣的是,事实证明,第二个POSTROUTING规则也有几个变体也可以使用。如果将目标更改为-j SNAT --to-source 192.168.2.1,效果(并不奇怪)与:相同MASQUERADE:服务器将来自本地LAN客户端的连接视为源自路由器的内部 IP地址。另一方面,如果将目标更改为-j SNAT --to-source 89.179.245.232,则NAT仍然有效,但是这次服务器将来自本地LAN客户端的连接视为源自路由器的外部 IP地址(89.179.245.232)。

最后,请注意原来的PREROUTING/ DNAT规则-i ppp0不起作用,因为该规则永远不会匹配来自LAN客户端的数据包(因为这些数据包不会通过ppp0接口进入路由器)。可以通过PREROUTING仅为内部LAN客户端添加第二条规则来使其工作,但这是不雅的(IMO),并且仍然需要显式引用外部IP地址。

现在,即使在详细介绍了“发夹式NAT”(或“ NAT环回”或“ NAT反射”,或任何喜欢称呼它的解决方案)解决方案之后,我仍然相信水平分割DNS解决方案- -将外部客户端解析为外部IP,将内部客户端解析为内部IP-将是更明智的选择。为什么?因为了解DNS的人比了解NAT的人更多,因此构建良好系统的很大一部分是选择使用可维护的部分。与奥秘的NAT设置(当然是IMO)相比,DNS设置更易于理解,并因此得到正确维护。


效果很好,非常感谢!我同意DNS设置会更好,但是您不能使用它将同一外部IP上的不同端口转发到LAN上的其他计算机。无论如何,我是唯一会维护此设置的人,所以很好。
whitequark 2010年

我很高兴听到这为您工作!
史蒂文

什么是“ IMO”?国际流星组织www.imo.net?
乔纳森·科玛

@ macmadness86 IMO ==在我看来
史蒂文(Steven)

3

常见的解决方案是将内部主机指向本地DNS服务器,该服务器为这些主机名返回正确的“内部”地址。

另一个解决方案(我们在Cisco防火墙上使用的解决方案)是在防火墙上重写与这些地址相对应的DNS响应。我认为目前没有用于Linux的工具可以做到这一点。

您应该能够在网关上配置路由以执行正确的操作。您可能需要配置服务器以了解其外部映射的IP地址(例如,通过将其分配给虚拟接口)。通过这种配置,从一个内部系统到另一个内部系统的通信(使用其“外部”地址)将通过路由器。


嗯 那么,您是否建议将外部IP添加到服务器的接口,然后配置路由器,以便它将所有数据包转发到从LAN内部到该服务器的外部IP?有趣的是,我会尽快对其进行测试。
whitequark 2010年

您可以建议配置吗?我尝试了以下方法:ip rule add to 89.179.245.232 dev br-lan table 10; ip route add 89.179.245.232 via 192.168.2.10 dev br-lan table 10,但它不起作用。
whitequark 2010年

路由表10中有什么?在内部服务器上,您可能希望它们在其主接口上同时具有本地192.168.xx地址(用于本地通信)和公用地址(作为别名)。
larsks 2010年

2

要求执行的操作被称为NAT Loopback,它要求您添加SNAT规则,以便从LAN到服务器的数据包将通过路由器返回:

-A POSTROUTING -p tcp -s 192.168.2.0/24 -d 192.168.2.10 -m multiport --dports 22,25,80,443 -j SNAT --to-source 89.179.245.232

可悲的是,这行不通。我最初错过了相关-i ppp0规则中的选项,因为该选项是由其他链处理的。此规则将阻止路由来自LAN的数据包(如果启用该功能,则数据包将来自错误的源并被拒绝)。
whitequark 2010年

你试过了吗?它只会影响来自您局域网的数据包,这些数据包将通过这些非常特定的端口到达您的服务器IP。
SiegeX

是的,我做到了。(我也尝试更改第一条规则)。例如,dig将数据包发送到192.168.2.1#53,然后从192.168.2.10#53收到意外答复,无论您的规则是否存在。
whitequark 2010年

0

Larsks关于托管内部版本的namespace \ domain的评论通常是我过去处理此问题的方式。当然,您需要在内部使用DNS服务器来执行此操作。


是的,我写过我正在使用dnsmasq。关于设置自动替换有什么想法?
whitequark 2010年

我对OpenWRT和神风队一无所知,但基于我正在阅读的内容-如果将以下内容添加到/etc/dnsmasq.conf“ cname = ext-hostname.domain.com,int-hostname.domain.com”,该怎么办?
CurtM 2010年

好吧,据我所能确定的,dnsmasq cname不支持掩码,因此由于子域数而不适用于我。
whitequark 2010年

0

我想出了以下解决方案,以允许我的来宾网络连接到从WAN转发到LAN网络的端口。该脚本位于我的“网络->防火墙->自定义规则”部分:

# lookup the public IP (DDNS resolves to this)
wanip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}')

# Guest network to LAN
# srcname is the guest network name, this needs to match for iptables
srcname=guest
# CIDR notation of guest and lan networks
srcnet=192.168.15.0/24
tgtnet=192.168.10.0/24
# router (openwrt) IP on lan network
tgtrouter=192.168.10.1
# host on lan network where ports are normally forwarded
tgthost=192.168.10.5
# ports to forward as a list or range
tcpports=8080,9090
udpports=12345

prechain=prerouting_${srcname}_rule
postchain=postrouting_${srcname}_rule

# reset the tables to prevent duplicate rules
iptables -t nat -F ${prechain}
iptables -t nat -F ${postchain}

iptables -t nat -A ${prechain} -s ${srcnet} -d ${wanip}/32 -p tcp -m tcp -m multiport --dports ${tcpports} -m comment --comment "${srcname} NAT reflection TCP DNAT" -j DNAT --to-destination ${tgthost}
iptables -t nat -A ${postchain} -s ${srcnet} -d ${tgthost}/32 -p tcp -m tcp -m multiport --dports ${tcpports} -m comment --comment "${srcname} NAT reflection TCP SNAT" -j SNAT --to-source ${tgtrouter}
iptables -t nat -A ${prechain} -s ${srcnet} -d ${wanip}/32 -p udp -m udp -m multiport --dports ${udpports} -m comment --comment "${srcname} NAT reflection UDP DNAT" -j DNAT --to-destination ${tgthost}
iptables -t nat -A ${postchain} -s ${srcnet} -d ${tgthost}/32 -p udp -m udp -m multiport --dports ${udpports} -m comment --comment "${srcname} NAT reflection UDP SNAT" -j SNAT --to-source ${tgtrouter}

为了支持重新启动,我需要在openwrt上的ssh命令行中运行以下命令(否则,我认为存在竞争条件,其中添加了一些规则,然后在重新启动期间刷新了这些规则):

uci set firewall.@include[0].reload="1"
uci commit firewall

NAT反射是为LAN网络内与其自身(而不是与其他网络)的连接设置的,如果您已创建多个接口来隔离通信。我尝试从Web界面配置转发规则,但这会将所有流量发送到从来宾网络到该LAN主机的端口。以上仅拦截对WAN IP的请求,而不是所有网络流量。

可以使用内部DNS代替它,但前提是所有端口转发都仅进入单个主机。如果您有多个主机在其中转发不同的端口,则可以将不同端口的规则重复到不同的tgthostIP和端口。


当前的内核中有conntrackmatch模块。解决此问题所需要做的就是使用这样的单一规则:iptables -t nat -A POSTROUTING --dst <lan-net> ! --src <lan-gw-ip> -m conntrack --ctstate DNAT --ctorigdst <wan-gw-ip> -j MASQUERADE
Anton Danilov,

@AntonDanilov很好,我喜欢。我使用的规则基于OpenWRT中已有的反射NAT规则,用于来自同一子网的连接。除了在conntrack可用之前可能写过之外,不确定是否有其他原因。
BMitch
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.