Starting with a 127.0.0.1 filter points at the wrong layer
When IPv4 traffic uses Passwall but IPv6 traffic exits directly or fails, do not begin by treating 127.0.0.1 as an IPv6 filter target. 127.0.0.1 is IPv4 loopback; IPv6 loopback is ::1. Separate whether DNS returns AAAA, whether IPv6 transparent proxying is enabled, and whether client IPv6 packets enter Passwall’s nftables chains.
The LuCI option Filter Proxy Host IPv6 filters IPv6 DNS answers for proxy targets. It is not the same switch as proxying every IPv6 flow. The official code stores the former as filter_proxy_ipv6 and controls transparent IPv6 proxying separately with ipv6_tproxy.
Scope verified for this guide
This procedure was reviewed on 2026-08-08 against Passwall’s official repository at commit a2989df1868c517cc330aa007e1b9987683d0535. The LuCI definitions, runtime script, and nftables rule-generation path were compared directly. The failure was not reproduced on a physical OpenWrt router, so confirm device-specific package versions and runtime output with the commands below.
SOURCE_COMMIT=a2989df1868c517cc330aa007e1b9987683d0535
FILTER_PROXY_IPV6=global.filter_proxy_ipv6
PROXY_IPV6=global_forwarding.ipv6_tproxy
NFT_TABLE='inet passwall'
IPV6_CHAINS='PSW_MANGLE_V6 PSW_OUTPUT_MANGLE_V6'
At this commit, global.lua defines filter_proxy_ipv6 as a DNS-tab option. app.sh can restrict the remote DNS query strategy toward IPv4 when it is enabled, while transparent proxy activation is read from the separate ipv6_tproxy value. nftables.sh creates IPv6 chains and sets under inet passwall when IPv6 proxy conditions are enabled.
Capture four layers before changing anything
| Layer | Value to inspect | Decision rule |
|---|---|---|
| Address and route | LAN/WAN IPv6 addresses and default route | No default route indicates native IPv6 failure, not bypass |
| DNS | A/AAAA answers from router DNS and DoH use | No AAAA means traffic cannot reach an IPv6 TProxy rule |
| Passwall UCI | filter_proxy_ipv6, ipv6_tproxy, proxy mode |
Confirm DNS-filter and traffic-TProxy intent separately |
| Firewall | inet passwall, IPv6 chains, counters |
Separate a missing chain from packets that never reach it |
| Client | IPv4 and IPv6 result for the same destination | Compare address-family egress and failure time |
ubus call system board
opkg list-installed | grep -E 'passwall|firewall4|nftables|iptables'
uci -q show passwall | grep -E 'filter_proxy_ipv6|ipv6_tproxy|tcp_proxy_mode|udp_proxy_mode|dns_mode'
ip -6 addr show
ip -6 route show table all
logread -e passwall
The output can contain node addresses and credentials. Do not publish it unchanged. Before sharing uci -q show passwall, remove server, UUID, password, and token values.
Separate DNS filtering from IPv6 TProxy
- When the goal is to suppress proxy-target AAAA answers:
filter_proxy_ipv6applies to DNS paths managed by Passwall. A browser or application using its own DoH can bypass router dnsmasq, so a saved toggle does not prove that AAAA disappeared. - When the goal is to proxy IPv6:
ipv6_tproxyand the selected node must support IPv6/TProxy. DNS may return AAAA, but without an IPv6 proxy chain the connection can leave through the native IPv6 route. - When the goal is to disable IPv6: do not treat one Passwall option as a LAN-wide IPv6 kill switch. Align OpenWrt WAN6, RA/DHCPv6, and firewall policy, and do not break the network by dropping all ICMPv6.
nslookup example.com 127.0.0.1
command -v nft
nft list tables
nft -a list table inet passwall
nft -a list chain inet passwall PSW_MANGLE_V6
nft -a list chain inet passwall PSW_OUTPUT_MANGLE_V6
If inet passwall does not exist, inspect Passwall startup failure and the selected firewall backend first. If the table exists but PSW_MANGLE_V6 does not, check ipv6_tproxy, node support, and startup logs. If chains and rules exist but counters do not move, determine whether client packets use a different interface, zone, or policy path.
ip6tables alone can hide the real rules on fw4
Current OpenWrt defaults use the fw4/nftables firewall family. An ip6tables command may still exist through compatibility packages, but when Passwall generated rules under inet passwall, the output of ip6tables -L alone cannot prove that rules are missing. Inspect installed packages and the actual table first.
An older build or legacy backend can instead use Passwall’s iptables.sh path. Do not apply an nft command copied from another release. Choose the inspection tool from the installed version, the firewall4 package, and the backend shown in startup logs.
Safe correction sequence
- Save current configuration and rules first. Copy them to a management computer if they must survive a reboot instead of relying on
/tmp. - Choose one objective: suppress proxy-target AAAA, send IPv6 traffic through TProxy, or disable IPv6 on the LAN. These are different changes.
- Change only one relevant LuCI option and record the previous value before Apply. If editing UCI directly, print the exact section before using an assumed index.
- Restart Passwall only and inspect the first error. Do not flush the whole firewall or leave an arbitrary permanent rule.
- Measure DNS answers, IPv6 route,
inet passwallcounters, and client IPv4/IPv6 requests again in the same order.
cp /etc/config/passwall /tmp/passwall.before
nft list ruleset > /tmp/nft.before
ip -6 route show table all > /tmp/route6.before
/etc/init.d/passwall restart
logread -e passwall
nft -a list table inet passwall
Distinguish client bypass from IPv6 failure
nslookup example.com <ROUTER_LAN_IP>
curl -4 -I https://example.com/
curl -6 -I https://example.com/
ip -6 route get 2001:4860:4860::8888
If curl -6 fails and there is no IPv6 default route, that is not evidence of Passwall bypass. If both curl -4 and curl -6 succeed but public egress or policy outcome differs, compare the path by address family. A CDN can legitimately return different destination addresses, so correlate source egress, Passwall counters, and logs.
Verification and rollback
Success is not a saved LuCI toggle. DNS answers, inet passwall IPv6 counters, and the real client path must agree with the intended policy. Reboot once and confirm that the table and routes are recreated.
If the failure expands, restore the saved file and restart Passwall. A manually inserted nft rule can disappear on service restart and should not remain as the solution. If IPv6 is still broken after restoration, separate WAN6, RA/DHCPv6, and fw4 zone behavior as a non-Passwall incident.
cp /tmp/passwall.before /etc/config/passwall
/etc/init.d/passwall restart
logread -e passwall
nft -a list table inet passwall
Related guides
Official code and verification scope
- Passwall global.lua at reviewed commit – definition of the filter_proxy_ipv6 LuCI option
- Passwall app.sh at reviewed commit – separate runtime reads for filter_proxy_ipv6 and ipv6_tproxy
- Passwall nftables.sh at reviewed commit – generation of inet passwall, IPv6 sets, and chains
- OpenWrt firewall4 source repository – fw4 and nftables firewall implementation