Firewalld as router for IPv6

I’m using one machine with openSUSE as a router for IPv4 for many years. Some time ago I tried to add IPv6 and I was not successful. At least it was possible to get from internal network to the outside, but it was not possible to get any traffic from outside to internal servers. After upgrade to to 15.6, it’s not even possible to get from the internal network outside. I’ve created some policy that helped forwarding IPv4 traffic, but it doesn’t seem to affect IPv6.

What would I like to achieve:

  • Traffic from internal zone is forwarded to external
  • Traffic from extternal is forwarded to internal for specific addresses and ports

Is this possible with firewalld or do I have to ditch it and create some nftables rules on my own?

Yes, it is possible. Describe your network topology, show your firewalld configuration.

There are 3 interfaces

  • eth0 pointing to internet
  • eth1 pointing to internal network
  • wg0 wireguard, also considered internal network, IPv4 only

There is mail server and web server in the internal network, that need to be accessible form the outside, which is done via port forwarding in IPv4, but they should be accessible directly in IPv6.

firewall-cmd --list-all-zones

block
  target: %%REJECT%%
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: 
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

dmz
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: ssh
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

docker (active)
  target: ACCEPT
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: docker0
  sources: 
  services: 
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

drop
  target: DROP
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: 
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

external (default, active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: eth0
  sources: 
  services: 
  ports: 51820/udp
  protocols: 
  forward: no
  masquerade: yes
  forward-ports: 
	port=80:proto=tcp:toport=:toaddr=10.20.0.6
	port=443:proto=tcp:toport=:toaddr=10.20.0.6
	port=25:proto=tcp:toport=:toaddr=10.20.0.4
	port=587:proto=tcp:toport=:toaddr=10.20.0.4
	port=993:proto=tcp:toport=:toaddr=10.20.0.4
  source-ports: 
  icmp-blocks: 
  rich rules: 

home
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

internal (active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: eth1 tun0 wg0
  sources: 
  services: dhcp dhcpv6 dhcpv6-client mdns ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

public
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: 
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

trusted
  target: ACCEPT
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: 
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

work
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: ssh
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

firewall-cmd --list-all-policies

allow-host-ipv6 (active)
  priority: -15000
  target: CONTINUE
  ingress-zones: ANY
  egress-zones: HOST
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
	rule family="ipv6" icmp-type name="neighbour-advertisement" accept
	rule family="ipv6" icmp-type name="neighbour-solicitation" accept
	rule family="ipv6" icmp-type name="router-advertisement" accept
	rule family="ipv6" icmp-type name="redirect" accept

test (active)
  priority: -1
  target: ACCEPT
  ingress-zones: internal external
  egress-zones: ANY
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

And what exactly does not work? And does it start to work when you stop firewalld?

This should work. Assuming kernel decides to forward these packets in the first place. It should also allow unrestricted IPv4 forwarding. Does it?

Show the output of

ip -6 a
ip -6 r

from both your router and your end-host as well as example of a command failing “to get from the internal network outside”.

Does your end host have its own firewall?

In 15.5 internal was able to reach internet, but it was not possible to reach internal servers from internet (but ping worked). In 15.6 nothing is forwarded. I’d rather not show IPv6 addresses, if not completely necessary.

When firewall is off, neither IPv4 nor IPv6 is forwarded.

Then it has nothing to do with firewalld. Show

grep . /proc/sys/net/ipv6/conf/*/forwarding

on your router.

Shouldn’t that be stopped in external zone? How should policy look like for IPv4 to allow internal out and block external?

/proc/sys/net/ipv6/conf/all/forwarding:0
/proc/sys/net/ipv6/conf/default/forwarding:0
/proc/sys/net/ipv6/conf/eth0/forwarding:1
/proc/sys/net/ipv6/conf/eth1/forwarding:1
/proc/sys/net/ipv6/conf/lo/forwarding:0
/proc/sys/net/ipv6/conf/wg0/forwarding:0

Please, use preformatted text when pasting computer output. Anyway, this is incorrect. The only option to enable IPv6 forwarding is /proc/sys/net/ipv6/conf/all/forwarding. Per-interface forwarding does something different.

Yeah, that changed stuff. Question is why it was off, because I have it on in /etc/sysctl.conf.

But now traffic is unrestricted both ways.

So the policy ACCEPT should only have ingress internal and there should be another of external with REJECT and explicitly allowing specific IPv6 addresses and ports?

I got it now, thanks for your help.

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