opnsense / core

OPNsense GUI, API and systems backend
https://opnsense.org/
BSD 2-Clause "Simplified" License
3.24k stars 724 forks source link

firewall: Allow dynamic IPv6 prefixes in rules #3247

Closed klada closed 5 years ago

klada commented 5 years ago

Is your feature request related to a problem? Please describe.

Unfortunately many ISPs only hand out dynamic IPv6 prefixes. IPv6-enabled hosts/servers behind the firewall might have a static IPv6 interface address with a dynamic prefix part (e.g. assigned through ip tokens in Linux).

Right now it is impossible to add IPv6 firewall rules for individual hosts with dynamic prefixes.

Describe the solution you'd like

A trivial approach would be to match only the last 64 bits of an IPv6 address, thus ignoring the entire prefix. In Linux (with ip6tables) you can invert the network mask, so you ignore the prefix and only match the host part. This can be done like this:

ip6tables [...] -d ::192:168:20:1/0000:0000:0000:0000:ffff:ffff:ffff:ffff -o eth2 [...]
# or even sorter
ip6tables [...] -d ::192:168:20:1/!64  -o eth2 [...]

I think this is a very convenient approach which resolves most issues with changing prefixes in IPv6 firewall rules. I don't know if pf actually supports inverting the network mask, but if it does this would probably be the easiest way of supporting dynamic prefixes.

If the outbound interface could also be specified we wouldn't have to worry about address collision in situations where the host part is not unique across IPv6 subnets.

Describe alternatives you've considered

If matching the last 64 bits is not possible, a syntax like ${PREFIX_LAN}:192:168:20:1 for host aliases would probably also get the job done. The disadvantage would probably be that the aliases would need to be reloaded each time the tracked IPv6 address changes on the relevant interface.

AdSchellevis commented 5 years ago

I don't think pf has an option like this, at least not as far as I could find. It might be good to know how other vendors solve this, adding keywords like ${PREFIX_LAN}:192:168:20:1 usually causes more issues in the long run (for example in alias usage).

chaispaquichui commented 5 years ago

Dynamic ipv6 prefixes in the firewall is not the solution unfortunately. Almost everyone implement RFC7217 today (aka "stable privacy"), which mean the last 64 bits of the ipv6 address change when the host receives a new prefix.

There is no pretty solution for this problem.

There is a feature request to allow NPT rules to be dynamically updated when the upstream prefix changes

https://github.com/opnsense/core/issues/2544

With this feature, you could use ULA in the LAN. It also solves the multihoming problem

klada commented 5 years ago

Dynamic ipv6 prefixes in the firewall is not the solution unfortunately.

If you mean the clumsy ${PREFIX_LAN}:192:168:20:1 syntax, I agree. This was just a suggested workaround – I don't like it either.

The best thing would still be to simply match the last n bits of an IPv6 address. After thinking about this you could even include the static subnet id in the rule to make it a perfect match. The iptables equivalent (for subnet id 14) with a /56 prefix would be this:

ip6tables [...] -d ::0014:192:168:20:1/::00ff:ffff:ffff:ffff:ffff [...]
ip6tables [...] -d ::0014:192:168:20:1/!72 [...]

@AdSchellevis Are you sure pf does not support this? At least specifing a full mask like in the first line seems like the most basic feature of a firewall. The /!72 notation is just syntactic sugar.

Almost everyone implement RFC7217 today (aka "stable privacy"), which mean the last 64 bits of the ipv6 address change when the host receives a new prefix.

There is no pretty solution for this problem.

RFC 7217 is about opaque interface identifiers, which do not make sense for servers. For servers you want stable interface identifiers. And for stable identifiers there are two easy (and more or less pretty) solutions (sorry for being off-topic here, but it might explain why we need dynamic prefixes in firewall rules):

  1. Use DHCPv6 with a static host mapping for servers. When you are using DUID-LL then you can always assign the same IPv6 address to the host. This is already supported by OPNsense, even with dynamic prefixes. :tada:

  2. You can set a static IPv6 token, which results in a stable IPv6 address (Prefix + Token). In Linux with systemd-networkd all you need is this:

    [Network]
    DHCP=no
    IPv6AcceptRA=yes
    IPv6Token=::192:168:20:1

    This means the interface will pick up any prefix which is announced on the network and simply uses the specified token as the interface identifier. You can even still use privacy extensions if you really want to (for outbound communication), but again: we are talking about servers here.

I agree that NPTv6 (which ATM is still a draft only) can kind of work around the current firewall limitation, but it's still much more elegant (and desirable) to assign public IPv6 addresses to your servers. Especially since we live in times where many people are getting /56 prefixes from their ISPs.

AdSchellevis commented 5 years ago

@klada you can easily check on the machine what pf supports and what it doesn't man pf.conf should provide you with a comprehensive list of features supported. our ruleset is flushed to /tmp/rules.debug using pfctl -f /tmp/rules.debug you can reload with changes you like to test.

chaispaquichui commented 5 years ago

Klada, I know what static reservation and ipv6 token are but I don't understand why you are focusing on servers and ignoring all the other kind of hosts... For exemple, Android doesn't support (yet) DHCPv6 or the ipv6 token, the same for a lot of IoT crap.

Aside from bgp/ipv6 PI, NPT is the only solution who can provide easy multihoming and prefix independence no matter the kinf of hosts you have on your network. It's doesn't matter if it's only a draft, it's supported by Cisco, Juniper, Palo Alto, Linux and FreeBSD.

It's only my opinion but I think NPT will be massively used by the people who can't afford a BGP peering with their provider.

fichtner commented 5 years ago

Same as #2544 if we widen the scope. Please direct discussion there.