Seiry

Seiry

Nat loopback issue in non-bridged dial-up openwrt

Introduction#

When I wanted to write this article, I suddenly felt that something was wrong. Why are all the articles I wrote on xlog about the Japanese internet?

Actually, I'm not good at computer network basics, which is a weak area in my field of knowledge. Whether it's a Japanese website or a network business, although I can do it, it's actually not my strong suit.

But this is both the reason and the result. Because I'm not good at it, I encounter "rare" problems, which are actually not problems for everyone else.

This is also a kind of discomfort paradox.

NAT Loopback#

NAT loopback, also known as hairpinning. The problem it solves is very simple, it's... it's... it's NAT loopback!

Assuming your public IPv4 is 1.2.3.4, and you have configured a port forwarding from 1.2.3.4:1000 to 192.168.1.2:1000, and your (one of them) router is 192.168.1.1. If you are inside the internal network, for example, with a /24 subnet, your network IP would be 192.168.1.200. At this time, if you try to access 1.2.3.4:1000, you will encounter a problem.

Usually, the router's port forwarding, backed by iptables, starts from the external (WAN) side and forwards to the internal (LAN) side. In other words, it listens on the WAN side, and any (external) IP requesting port 1000 will be forwarded to 192.168.1.2:1000.

Corresponding rule:

-A zone_wan_prerouting -p tcp -m tcp --dport 1000 -j DNAT --to-destination 192.168.1.2:1000

So here's the problem, what happens if you are not on the external network but on the internal network and try to access 1.2.3.4:1000? If no additional settings are made (but actually, in many cases, these additional settings are enabled by default), then just relying on this DNAT rule will not establish a connection. Because the entry chain is limited to the WAN side.

NAT Loopback?#

So, what is the problem mentioned above? NAT loopback?

If you don't know about this problem, then you won't be able to raise this problem.

Fortunately, technology has brought us new things. Today, we can use chatgpt to directly ask what our problem is.

Ask about the problem. Instead of asking how to solve it. Ask what the question is, instead of how to solve it.

This is a typical use of chatgpt for me. In the vast technical field, the traditional approach of searching and learning technology is like doing something in the air, it requires a lot of luck. You may have mastered six technologies, ABCEFG, but you can't connect them together. Many times, you can only try/accumulate HIGK aimlessly, but what you really lack is D. The productivity of large models is actually very limited, and there are still many unknown things that they cannot do at the moment, but this scenario is typical.

NAT Loopback!#

In modern router systems, NAT loopback has long been taken into consideration.

In OpenWrt, the underlying design for this is reflection.

You will get a rule like this:

-A zone_lan_prerouting -s 192.168.1.0/24 -d 192.168.0.3/32 -p tcp -m tcp --dport 1000 -m comment --comment "!fw3: 1000 (reflection)" -j DNAT --to-destination 192.168.1.2:1000

Note the words in the title, because it is a non-bridged environment, the WAN IP of OpenWrt here is 192.168.0.3.

Problem!#

In a bridged environment, directly dialing PPPoE in OpenWrt will not cause NAT loopback to fail. But in a non-bridged environment, that is, in the fiber modem router mode, it will.

The problem here is that OpenWrt's NAT loopback has actually had intermittent problems, combined with version fragmentation, in the noisy Internet, it is difficult to find out which error is causing your problem.

This directly leads to many problems and many answers, but everyone's plug is not compatible.

You will find various things, such as bugs in a certain version of OpenWrt, or configuring certain kernel flags, and many "correct" methods. Yes, but they can't solve your problem.

This problem cannot be solved by large models either. Not only can't they help, but they are also very good at causing trouble in this problem.

What they are best at is building a strawman argument.

The root cause of the problem is that this rule only sets 192.168.0.3 as the entry, but in fact, the entry should also include the public WAN.

-A zone_lan_prerouting -s 192.168.1.0/24 -d 192.168.0.3/32 -p tcp -m tcp --dport 1000 -m comment --comment "!fw3: 1000 (reflection)" -j DNAT --to-destination 192.168.1.2:1000

That is, an additional rule is needed:

-A zone_lan_prerouting -s 192.168.1.0/24 -d 1.2.3.4/32 -p tcp -m tcp --dport 1000 -j DNAT --to-destination 192.168.1.2:1000

If accessed from the LAN side to the public IP, it will be directly forwarded to the destination host.

But this is not elegant enough, right?

Done#

IP=$(curl -s 4.ipw.cn | grep -oE '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' | head -n 1)

iptables -t nat -A PREROUTING -s 192.168.1.0/24 -d $IP/32 -p tcp -m tcp --dport 1000 -j zone_wan_prerouting

So we can directly add a custom firewall rule, and if you are using nft, the large model can help you. In fact, these two lines were also written by chatgpt.

After obtaining the public IP, you can simply send the request back to zone_wan_prerouting, without duplicating the destination host.

In fact, it can be further simplified/more generic, but then it will be bound to OpenWrt's UCI, after all, there is also Padavan.

LAN=$(uci show network.lan.ipaddr | cut -d"'" -f2)
IP=$(curl -s 4.ipw.cn | grep -oE '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' | head -n 1)

iptables -t nat -A PREROUTING -s $LAN/24 -d $IP/32 -p tcp -m tcp --dport 1000 -j zone_wan_prerouting

Under Padavan, the handling is more elegant. There is no reflection, but instead:

-A PREROUTING -d 1.2.3.4/32 -j vserver
-A PREROUTING -d 192.168.0.1/32 -j vserver

Defining vserver as the external input chain.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.