Describe the Bug you encountered
WARNING: I admit, I prepared this issue using AI (Gemini 3.1 Pro Preview) and manual editing, but this is a real problem that I encountered personally and tried to solve myself. I didn't have the necessary knowledge of packet routing and the nuances of FakeDNS and I know this is my fault. My apologies if this issue seems more like an ai-slop. I'm not definitely sure about correctness of all conclusions but the proposed solution (in Other Information section) worked for me.
When Localhost Proxy and FakeDNS are both enabled, the OpenWrt router itself cannot connect to proxied domains (xray shunt with direct node as default and only several selected geosites in proxy rule).
The DNS request works, and FakeDNS returns an IP (like 198.18.x.x). However, the HTTP connection hangs forever. Traffic from LAN clients works perfectly. Only the router itself fails to connect.
This happens because the Linux kernel lacks a local route for the FakeDNS IP pool. When a local program tries to connect to 198.18.x.x, the kernel sends the packet to the WAN interface first. The packet gets the public WAN Source IP. Then, the firewall OUTPUT chain redirects the packet to the loopback interface. The kernel sees a WAN Source IP arriving on the loopback interface and drops it as a spoofed packet.
Steps to reproduce this Bug
- Ensure you already have a vpn node (vless+reality in my case), default node set to shunt, shunt default rule is direct connection and another rule exists with one or more domain/geosite filled in (in my case, geosite:youtube is in this list), with FakeDNS enabled for this rule and for FakeDNS main switch as well.
- Open Passwall2 settings.
- Enable Localhost Proxy.
- Apply settings and wait for Passwall2 to start.
- Connect to the router via SSH.
- Run:
curl -I -v -4 https://www.youtube.com
- The terminal will hang forever and the connection will fail.
What you want to implement
Passwall2 should automatically add local routes for the FakeDNS IP pools to the loopback interface.
It should run these commands in the background when FakeDNS and Localhost Proxy are enabled:
ip route add local 198.18.0.0/16 dev lo
ip -6 route add local fc00::/18 dev lo
This will force the kernel to use 127.0.0.1 as the Source IP for local FakeDNS traffic. The firewall OUTPUT chain will then process the packets correctly without the kernel dropping them.
Log information
Xray-core log shows the FakeDNS resolution works, but the TCP connection never reaches Xray:
...
2026/04/05 10:36:04.589256 [Debug] [2238148529] proxy/dokodemo: processing connection from: 127.0.0.1:59050
2026/04/05 10:36:04.589313 [Info] [2238148529] proxy/dokodemo: received request for 127.0.0.1:59050
2026/04/05 10:36:04.589336 [Info] [2238148529] app/dispatcher: taking detour [dns-out] for [udp:0.0.0.0:15353]
2026/04/05 10:36:04.589355 [Info] [2238148529] proxy/dns: handling DNS traffic to udp:127.0.0.1:15354
2026/04/05 10:36:04.589393 from 127.0.0.1:59050 accepted udp:0.0.0.0:15353 [dns-in -> dns-out]
2026/04/05 10:36:04.589847 [Info] app/dns: FakeDNS got answer: www.youtube.com -> [198.18.115.199]
2026/04/05 10:36:04.591523 [Debug] [70149023] proxy/dokodemo: processing connection from: 127.0.0.1:46822
2026/04/05 10:36:04.591582 [Info] [70149023] proxy/dokodemo: received request for 127.0.0.1:46822
2026/04/05 10:36:04.591606 [Info] [70149023] app/dispatcher: taking detour [dns-out] for [udp:0.0.0.0:15353]
2026/04/05 10:36:04.591627 [Info] [70149023] proxy/dns: handling DNS traffic to udp:127.0.0.1:15354
2026/04/05 10:36:04.591660 from 127.0.0.1:46822 accepted udp:0.0.0.0:15353 [dns-in -> dns-out]
2026/04/05 10:36:04.592154 [Info] app/dns: FakeDNS got answer: www.youtube.com -> [[fc00::19d:5d35:73c8]]
(No further TCP connection logs appear because the kernel dropped the packet).
...
Screenshot
N/A
System related information
Xiaomi Mi Router AX3000T
OpenWrt 25.12.2 r32802-f505120278 / LuCI openwrt-25.12 branch 26.094.61984~16167c7
Linux kernel 6.12.74
Passwall2 26.4.5
Xray-core 26.3.27
dnsmasq-full 2.91-r2
PPPoE wan connection
Other Information
I confirmed this routing issue is the exact cause.
If I run this command manually via SSH:
ip route add local 198.18.0.0/16 dev lo
The issue is fixed immediately. The curl command completes instantly and the router itself is successfully proxied through Xray FakeDNS. Passwall2 just needs to automate adding and removing these local routes.
Describe the Bug you encountered
WARNING: I admit, I prepared this issue using AI (Gemini 3.1 Pro Preview) and manual editing, but this is a real problem that I encountered personally and tried to solve myself. I didn't have the necessary knowledge of packet routing and the nuances of FakeDNS and I know this is my fault. My apologies if this issue seems more like an ai-slop. I'm not definitely sure about correctness of all conclusions but the proposed solution (in Other Information section) worked for me.
When Localhost Proxy and FakeDNS are both enabled, the OpenWrt router itself cannot connect to proxied domains (xray shunt with direct node as default and only several selected geosites in proxy rule).
The DNS request works, and FakeDNS returns an IP (like 198.18.x.x). However, the HTTP connection hangs forever. Traffic from LAN clients works perfectly. Only the router itself fails to connect.
This happens because the Linux kernel lacks a local route for the FakeDNS IP pool. When a local program tries to connect to 198.18.x.x, the kernel sends the packet to the WAN interface first. The packet gets the public WAN Source IP. Then, the firewall OUTPUT chain redirects the packet to the loopback interface. The kernel sees a WAN Source IP arriving on the loopback interface and drops it as a spoofed packet.
Steps to reproduce this Bug
curl -I -v -4 https://www.youtube.comWhat you want to implement
Passwall2 should automatically add local routes for the FakeDNS IP pools to the loopback interface.
It should run these commands in the background when FakeDNS and Localhost Proxy are enabled:
This will force the kernel to use 127.0.0.1 as the Source IP for local FakeDNS traffic. The firewall OUTPUT chain will then process the packets correctly without the kernel dropping them.
Log information
Xray-core log shows the FakeDNS resolution works, but the TCP connection never reaches Xray:
Screenshot
N/A
System related information
Xiaomi Mi Router AX3000T
OpenWrt 25.12.2 r32802-f505120278 / LuCI openwrt-25.12 branch 26.094.61984~16167c7
Linux kernel 6.12.74
Passwall2 26.4.5
Xray-core 26.3.27
dnsmasq-full 2.91-r2
PPPoE wan connection
Other Information
I confirmed this routing issue is the exact cause.
If I run this command manually via SSH:
ip route add local 198.18.0.0/16 dev loThe issue is fixed immediately. The curl command completes instantly and the router itself is successfully proxied through Xray FakeDNS. Passwall2 just needs to automate adding and removing these local routes.