When running UFW and sing-box TUN simultaneously on a Linux bypass router, an easily misdiagnosed failure may occur: sing-box runs normally on the local machine, but LAN devices cannot access the Internet through the bypass router. Even if the TCP port that was blocked at the time is allowed, the problem may reappear after sing-box is restarted.
This article documents an actually observed cause and a fix pending regression validation. All examples use documentation-reserved addresses and do not correspond to a real network.
Environment and symptoms
- A Linux bypass router with the LAN interface
eth0and the address192.0.2.1(example only). - A downstream client,
192.0.2.20, using the bypass router as its IPv4 gateway. - The sing-box TUN interface is named
tun0, withauto_routeandauto_redirectenabled. - UFW denies unsolicited inbound traffic by default.
The key sing-box configuration is:
{
"type": "tun",
"interface_name": "tun0",
"auto_route": true,
"auto_redirect": true
}
Logs during the failure are similar to:
[UFW BLOCK] IN=eth0 OUT= SRC=192.0.2.20 DST=192.0.2.1 PROTO=TCP DPT=24461 SYN
DPT=24461 is only a dynamic port observed during one run, and it should not be hardcoded permanently in UFW. An empty OUT= indicates that the packet is entering the local machine’s INPUT path rather than merely traversing the FORWARD path.
Tracing NAT redirection
Check the sing-box listeners:
sudo ss -lntup | grep sing-box
Check nftables:
sudo nft -a list ruleset | grep -n -C 8 -E 'redirect|tproxy'
In the failure scenario, rules similar to the following can be seen:
meta l4proto tcp redirect to :24461
# 内部端口不允许直接连接
tcp dport 24461 ct status ! dnat reject with tcp reset
In other words, sing-box first redirects the destination TCP connection to a local listening port, and then UFW’s INPUT rules determine whether to allow it. Treating this type of traffic as ordinary FORWARD packets and allowing it will usually not eliminate the observed INPUT block.
Fix approach: Match DNAT connections rather than dynamic ports
For an explicitly trusted single downstream client, you can temporarily try:
sudo iptables -I ufw-before-input 1 \
-i eth0 \
-s 192.0.2.20/32 \
-d 192.0.2.1 \
-p tcp \
-m conntrack --ctstate DNAT \
-j ACCEPT
Be sure to replace the example IP address and interface with the actual values. DNAT is a valid virtual state for --ctstate; it is not valid for --ctstatus, which produces the error Bad ctstatus "DNAT".
This rule still has security boundaries: it matches qualifying DNAT TCP connections, not just connections created by sing-box. Therefore, the source and ingress interface should be restricted, and INPUT should not be allowed globally merely as a shortcut.
Validation
Run the following on the downstream device:
curl -4 -v --connect-timeout 5 https://www.cloudflare.com/
Observe the rule counters and block logs on the bypass router:
sudo iptables -L ufw-before-input -n -v --line-numbers
sudo journalctl -k --since '10 minutes ago' --grep='UFW BLOCK' --no-pager
Only if the counters increase, Internet connectivity is restored, and things continue to work after sing-box is restarted and the internal port changes can this method be considered suitable for the current deployment.
Persistence
After confirming that validation succeeded, create a backup first:
sudo cp -a /etc/ufw/before.rules /etc/ufw/before.rules.bak
sudo nano /etc/ufw/before.rules
In the *filter section, add the following after all chain definitions and before the existing ufw-before-input processing rules:
-A ufw-before-input -i eth0 -s 192.0.2.20/32 -d 192.0.2.1 -p tcp -m conntrack --ctstate DNAT -j ACCEPT
Check and reload:
sudo iptables-restore --test < /etc/ufw/before.rules
sudo ufw reload
To roll back, restore the file from the backup and run sudo ufw reload. Temporary test rules can also be removed using iptables -D with exactly the same matching arguments that were used when inserting the rule.
Precautions
- Do not use
ufw default allow routedor disable UFW entirely as a long-term solution. - This approach primarily addresses INPUT blocking after IPv4 TCP redirection; it is not a universal fix for all UDP, IPv6, or WireGuard failures.
- Access to other explicitly configured listening ports, such as those for APIs, DNS, or SOCKS, should continue to be restricted by source according to their actual use.
- Both UFW and sing-box may modify nftables. If the rule match counters increase but connections still fail, also check the hook priorities of other base chains and any subsequent drop rules.