IPv6 Traffic Rules work, but IPv4 Rules do not

First off, thanks in advance for the assistance! I am at a total loss. I feel like I am missing some small detail that lets this work properly and I've searched everwhere and watched every YT video I could find on the topic. This has been plaguing me for literally MONTHS now!

I can forward ports from WAN to LAN IPs all day long on IPv4. I can accept ports from WAN directly on the router (docker container published ports) on IPv6 and those work fine, too. However, the moment I attempt to reach an open port on the router on IPv4, no dice.

Since I can forward the exact same ports to an IP within the LAN (Port Forward), this would indicate this is not an ISP problem (AT&T 2.5GBit Fiber using IP Passthrough). I just can't get a normal accept directly on the router via IPv4 to work (Traffic Rules).

I have a docker container on the OWRT router running and publishing port 8443 (HTTPS). I can see this on IPv4 and IPv6 internally just fine on the LAN directly (port published correctly). I can see it outside across the WAN via IPv6 just fine (port accepted on IPv6 correctly). However, if only IPv4 is available to the external device as is the case with some ISPs, it can't reach 8443 via the WAN (long timeout, apparently dropped). Indeed, if I change the Rule to IPv4 only, no one can reach 8443 on the router via WAN anymore at all.

Masquerading is enabled on both IPv4 and IPv6; I'm not sure why one is working and the other isn't when both are in the accept rule.

config defaults
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

config zone 'lan'
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'
	list network 'OpenVPN'

config zone 'wan'
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option mtu_fix '1'
	option masq '1'
	option masq6 '1'
	list network 'wan'
	list network 'wan6'
	list network 'wanb'
	list network 'wanb6'

config zone 'docker'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	option name 'docker'
	list network 'docker'

config forwarding
	option src 'lan'
	option dest 'wan'

config forwarding
	option src 'docker'
	option dest 'lan'

config forwarding
	option src 'lan'
	option dest 'docker'

config forwarding
	option src 'docker'
	option dest 'wan'

config rule
	option name 'Allow-inbound-8443'
	option dest_port '8443'
	option target 'ACCEPT'
	option src 'wan'

Can anyone tell me why I can reach the docker container on the router over IPv6 but not IPv4? Again, if I configure as a redirect to a different server on my LAN, like this, it works:

config redirect
	option target 'DNAT'
	option name 'Forward-inbound-8443'
        option family 'ipv4'
        option src 'wan'
	option src_dport '8443'
	option dest 'lan'
        option dest_ip '10.10.0.2'
	option dest_port '8443'

It even works if I point from a different WAN port to the correct port on the LAN side like this (the router's LAN IP is 10.10.0.1), but this means a different port whether I'm inside or outside the network and is not suitable (plus the unnecessary flip to the LAN zone):

config redirect
	option target 'DNAT'
	option name 'Forward-8444-inbound-8443'
	option family 'ipv4'
        option src 'wan'
        option src_dport '8444'
	option dest 'lan'
	option dest_ip '10.10.0.1'
        option dest_port '8443'

What am I missing here? Why is OWRT not accepting specific port IPv4 traffic directly from the WAN side when it should be perfectly matching the Rule? With my luck, it's a simple checkbox somewhere. haha I'm presently accepting any and all theories anyone might have at this point.

Probably be helpful to see the contents of /etc/config/network and the whole firewall config.

It is just dport.
A connection on the wan interfaces on port 8443 should be redirected to lan on host foo with port bar....

Your connection does not come from a source with the source port 8443, but most likely with any port.

That was merely an example showing that a redirect from 8444 to 8443 does work, but this is not what I want.

Based on my understanding of the docs, this should work to allow WAN to reach a published port on the router itself. However, only IPv6 works. IPv4 does not:

config rule
	option name 'Allow-inbound-8443'
	option dest_port '8443'
	option target 'ACCEPT'
	option src 'wan'

Keep in mind that all the config in my OP was generated by LuCI. I didn't hand write it.

network:


config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix '[REDACTED]'
	option packet_steering '1'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'
	option promisc '1'
	option ip6segmentrouting '1'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ip6assign '60'
	list ipaddr '10.10.0.1/20'
	list dns '10.10.0.1'
	list ip6class 'local'

config interface 'wan'
	option device 'eth1'
	option proto 'static'
	list ipaddr '[REDACTED]'
	option gateway '[REDACTED]'
	list dns '10.10.0.1'
	option metric '10'
	option delegate '0'

config interface 'wan6'
	option device 'eth1'
	option proto 'static'
	list ip6addr '[REDACTED]'
	list ip6addr '[REDACTED]'
	option ip6gw '[REDACTED]'

config interface 'docker'
	option device 'docker0'
	option proto 'none'
	option auto '0'

config device
	option type 'bridge'
	option name 'docker0'

config interface 'wanb'
	option proto 'dhcp'
	option device 'eth2'
	option broadcast '1'
	option peerdns '0'
	option metric '20'
	option hostname '*'
	list dns '[REDACTED]'

config interface 'wanb6'
	option proto 'dhcpv6'
	option device 'eth2'
	option reqaddress 'try'
	option reqprefix 'auto'
	option metric '20'
	option norelease '1'

config device
	option name 'eth2'
	option ipv6 '1'

config device
	option name 'eth1'
	option ipv6 '1'

config interface 'OpenVPN'
	option proto 'none'
	option device 'tun0'
	option auto '0'
	list dns '[REDACTED]'

firewall:


config defaults
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'
	option flow_offloading '1'
	option flow_offloading_hw '1'

config zone 'lan'
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'
	list network 'OpenVPN'

config zone 'wan'
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option mtu_fix '1'
	option masq '1'
	option masq6 '1'
	list network 'wan'
	list network 'wan6'
	list network 'wanb'
	list network 'wanb6'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option family 'ipv4'
	option target 'ACCEPT'
	list icmp_type 'echo-request'
	option limit '1000/second'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'
	option limit '1000/second'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config zone 'docker'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	option name 'docker'
	list network 'docker'

config redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'Emby'
	option src 'wan'
	option src_dport '8920'
	option dest_ip '10.10.0.2'
	option dest_port '8920'

config redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'Octoprint'
	option family 'ipv4'
	list proto 'tcp'
	option src 'wan'
	option src_dport '61021'
	option dest_ip '10.10.0.21'
	option dest_port '80'

config forwarding
	option src 'docker'
	option dest 'lan'

config forwarding
	option src 'lan'
	option dest 'docker'

config forwarding
	option src 'docker'
	option dest 'wan'

config rule 'ovpn'
	option name 'Allow-OpenVPN'
	option src 'wan'
	option target 'ACCEPT'
	option proto 'udp'
	option dest_port '61194'

config rule
	option name 'Allow-Inbound-8443'
	option dest_port '8443'
	option target 'ACCEPT'
	option src 'wan'

Just to rule it out. Yeah nice pun.
What if you just for now configure 2 rule with family set to ipv4 and IPv6. Just to be explicit.
Did you also checked how the nft ruleset looks afterwards?

To add, you did not specify option proto I think it defaults to tcp and udp but maybe define the protocols you want?

list nft ruleset should show the result

I did try explicitly setting option family ipv4 and that didn't work.

In LuCI, selecting TCP and UDP together removes option proto which implies this is the default. I'll try manually specifying both in config, but I don't think it will have any effect.

But how does the rule look like in the end. Please post that otherwise we will poke in the dark for a longer time.

Is 8443 listening on WAN or 0.0.0.0 address?

netstat -nltp | grep 8443

Another common strategy is to use split horizon DNS. On the Internet your record lists of course a public address, but for queries from the local network a local network address is used in the response.
I'm not sure if dnsmasq is able to do so. But with bind9 it was and I think still is common practice.

Another troubleshooting step would be to add a trace on port 8443.

nft insert rule inet fw4 prerouting meta nfproto ipv4 tcp dport 8443 meta nftrace set 1

nft monitor trace

Test a connection and see how the trace output looks, then ctrl-c out of the monitor command. Restart the firewall to clear the temporary rule.

This will help prove if the firewall is dropping it or the docker is ignoring it.

root@router:~# nft monitor trace
trace id 9b708830 inet fw4 input packet: iif "eth1" ether saddr 00:…:46 ether daddr 94:…:0d ip saddr 150….93 ip daddr 24….74 ip dscp cs0 ip ecn not-ect ip ttl 56 ip id 37617 ip protocol tcp ip length 60 tcp sport 34412 tcp dport 8443 tcp flags == syn tcp window 62720 
trace id 9b708830 inet fw4 input rule meta nfproto ipv4 tcp dport 8443 meta nftrace set 1 (verdict continue)
trace id 9b708830 inet fw4 input rule tcp flags syn / fin,syn,rst,ack jump syn_flood comment "!fw4: Rate limit TCP syn packets" (verdict jump syn_flood)
trace id 9b708830 inet fw4 syn_flood verdict return 
trace id 9b708830 inet fw4 input rule iifname "eth1" jump input_wan comment "!fw4: Handle wan IPv4/IPv6 input traffic" (verdict jump input_wan)
trace id 9b708830 inet fw4 input_wan rule tcp dport 8443 counter packets 0 bytes 0 accept comment "!fw4: Test" (verdict accept)
netstat -nltp | grep 8443
tcp        0      0 0.0.0.0:8443            0.0.0.0:*               LISTEN      26814/docker-proxy
tcp        0      0 :::8443                 :::*                    LISTEN      26823/docker-proxy

And here's that trace. I don't know what to make of this, except that it ends up dropped at the end:

trace id eb7a24f7 inet fw4 prerouting packet: iif "eth1" ether saddr 0c:7c:28:xx:xx:xx ether daddr c0:74:2b:xx:xx:xx ip saddr [REDACTED] ip daddr 172.17.0.5 ip dscp cs0 ip ecn not-ect ip ttl 46 ip id 0 ip protocol tcp ip length 60 tcp sport 1735 tcp dport 8443 tcp flags == syn tcp window 65535 
trace id eb7a24f7 inet fw4 prerouting rule meta nfproto ipv4 tcp dport 8443 meta nftrace set 1 (verdict continue)
trace id eb7a24f7 inet fw4 prerouting verdict continue meta mark 0x00003f00 
trace id eb7a24f7 inet fw4 prerouting policy accept meta mark 0x00003f00 
trace id eb7a24f7 inet fw4 mangle_forward packet: iif "eth1" oif "docker0" ether saddr 0c:7c:28:xx:xx:xx ether daddr c0:74:2b:xx:xx:xx ip saddr [REDACTED] ip daddr 172.17.0.5 ip dscp cs0 ip ecn not-ect ip ttl 45 ip id 0 ip protocol tcp ip length 60 tcp sport 1735 tcp dport 8443 tcp flags == syn tcp window 65535 
trace id eb7a24f7 inet fw4 mangle_forward rule iifname { "eth1", "eth2" } tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 ingress MTU fixing" (verdict continue)
trace id eb7a24f7 inet fw4 mangle_forward verdict continue meta mark 0x00003f00 
trace id eb7a24f7 inet fw4 mangle_forward policy accept meta mark 0x00003f00 
trace id eb7a24f7 inet fw4 forward packet: iif "eth1" oif "docker0" ether saddr 0c:7c:28:xx:xx:xx ether daddr c0:74:2b:xx:xx:xx ip saddr [REDACTED] ip daddr 172.17.0.5 ip dscp cs0 ip ecn not-ect ip ttl 45 ip id 0 ip protocol tcp ip length 60 tcp sport 1735 tcp dport 8443 tcp flags == syn tcp window 65535 
trace id eb7a24f7 inet fw4 forward rule iifname { "eth1", "eth2" } jump forward_wan comment "!fw4: Handle wan IPv4/IPv6 forward traffic" (verdict jump forward_wan)
trace id eb7a24f7 inet fw4 forward_wan rule ct status dnat accept comment "!fw4: Accept port forwards" (verdict accept)
trace id eb7a24f7 ip filter FORWARD packet: iif "eth1" oif "docker0" ether saddr 0c:7c:28:xx:xx:xx ether daddr c0:74:2b:xx:xx:xx ip saddr [REDACTED] ip daddr 172.17.0.5 ip dscp cs0 ip ecn not-ect ip ttl 45 ip id 0 ip length 60 tcp sport 1735 tcp dport 8443 tcp flags == syn tcp window 65535 
trace id eb7a24f7 ip filter FORWARD rule counter packets 233483737 bytes 79802535248 jump DOCKER-USER (verdict jump DOCKER-USER)
trace id eb7a24f7 ip filter DOCKER-USER rule iifname "eth1" oifname "docker0" # xt_conntrack counter packets 5775 bytes 288736 # xt_REJECT (verdict drop)

So it is a docker block. Check the /etc/config/dockerd file for blocked_interfaces value. Might have wan interface blocked.

It's there. I suspect I should remove the line? How do I commit the changes from CLI? I tried uci commit dockerd (edit: and uci commit and fw3 restart) but I still see the DOCKER_USER rule in the ruleset.

To reset the docker rules too, you might have to run:

fw4 flush
fw4 start
/etc/init.d/dockerd restart

I don’t use docker, so not sure this will work. A reboot would be the last resort.

Yeah, restarting dockerd alone was not enough. I had to do as you suggest. I had to first flush and restart fw4 and then restart dockerd so it would rebuild its own chain.

All is working now on IPv4! Thank you so much for your assistance! Marking your mention of the blocked_interfaces value as the ultimate solution to my problem. I would have never found this without your help. Much appreciated!

I suppose it is interesting that your manual rule didn’t even come into play in the trace output. Docker adds enough of its own rules to complicate the setup.

Docker's rules were in the chain before my own rules prior to flushing, but now that I have flushed and rebuilt the ruleset, docker's rules are at the bottom of the chain.

I suspect this may be because I added/setup docker on my OPi5+ after my initial setup of the router...something in my early learning days of setup likely resulted in the docker chains being placed in the wrong place and superceeding my own rules. Since I was doing everything via LuCI back then pretty much exclusively, there's no telling where things got mucked up along the way.

Glad it is fixed, though! One little line...such is my luck. haha

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.