OPNsense Forum

English Forums => Tutorials and FAQs => Topic started by: OPNenthu on May 08, 2025, 06:05:46 PM

Title: Stop IP leaks on WAN (and secure modem UI) without touching NAT
Post by: OPNenthu on May 08, 2025, 06:05:46 PM
I didn't see a similar topic in this section but only did a cursory title search with some keywords.  Apologies if this is covered elsewhere.

By default OPNsense filters private IP ranges on incoming connections.  My goal was to also filter outgoing connections as an added layer so that all private IPv4 and local IPv6 destinations would be rejected on WAN out, thus avoiding leaks.  This might also be prudent on shared ISP lines with neighbors.

In addition I wanted an alias for management clients, such as my PC/laptop, to have an exclusion so that those could continue to reach my leased cable modem UI.  In my case the modem is at 10.0.0.1 and I cannot change this, but I don't have any 10.x networks in OPNsense nor any static route to it.  I rely on Outbound NAT to reach the modem UI.  I suspect this is a common scenario for a lot of home internet users with basic setups.

Normally you'd have to put OPNsense into Manual NAT mode and add some translation rules because you cannot simply add a WAN rule with a "source" address to include your management PC/alias.  That field gets overwritten by NAT.  I wish to avoid this and leave it in the default Automatic NAT mode.  That way I don't have to worry about managing the NAT rules as interfaces and networks change over time.  Fortunately, pf/OPNsense support IP exclusions in alias tables and we can leverage this.  (Read more at OPNsense docs (https://docs.opnsense.org/manual/aliases.html#exclusions),  feature PR (https://github.com/opnsense/core/issues/4318),  'pf' handbook (https://docs.freebsd.org/en/books/handbook/firewalls/#pftut-tables)).

Disclaimer: You might have some more complicated routing setup that breaks with these instructions, so be sure to do your homework if this applies.  I tested with my Wireguard site-to-site setup and saw no issues there.


The procedure:

1) Create an Alias to specify your management PCs. I called it "management_clients".

This will be used in step 5.

(This one is optional as you may already be using a dedicated management network or can even use a trusted network (e.g. LAN) for this purpose.)

2) Create an Alias to specify your modem configuration IP.  I called it "modem_ui_address".

This will be used in step 5.

3) Create an Alias of type "Network group" to define RFC1918 private IPv4 ranges, excluding the modem management IP.

In order to use IP exclusions you have to use a nested alias, so it's really a combination of two aliases here into a final third one.

The first one is for the private IPv4 ranges.  You may already have one like this as it's commonly used in interface rules:

Name: IPv4_private_ranges
Type: Network(s)
Content: 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8
Description: RFC1918 private ranges

The second one is the exclusion (negated IP) of the modem or upstream device that you connect to over WAN.  This one also needs to be a "Network(s)" alias in order to combine with the previous one, so just give it a /32 notation if it's a single IP:

Name: modem_ui_exclusion
Type: Network(s)
Content: !10.0.0.1/32
Description: Inversion of modem MGMT IP

The "!" prefix is important here. Substitute whatever IP you need.

The final one is the combined alias:

Name: IPv4_dont_NAT
Type: Network group
Content: IPv4_private_ranges, modem_ui_exclusion
Description: Private IPv4 ranges to filter outbound

You can inspect the final alias in Firewall->Diagnostics->Aliases to confirm the exclusion IP is there sorted among the RFC1918 ranges.

nested_alias_with_IP_exclusion.png

3) Create an Alias of type "Network(s)" to define at least IPv6 ULA (fc00::/7) and link-local (fe80::/10) prefixes.  The latter shouldn't be routable but I like having it.

ipv6_pivate_alias.png

4) Add two respective WAN rules with direction "out" (post-NAT) to reject these destinations.

   *Important to use "reject" and not "block" here, so that LAN clients get notification and don't hang. RFC4193 (https://www.rfc-editor.org/rfc/rfc4193#section-4.3) for IPv6 ULA also recommends this.

WAN_rules.png

I made mine non-Quick rules to act as defaults on WAN, but you can keep them as Quick also.

5) Add a Floating interface rule to block all except the management hosts/network to reach the modem management IP.

Action: Block
Quick: checked
Interface: <none selected>
Direction: In
TCP/IP Version: IPv4
Protocol: TCP
Source invert: checked
Source: management_clients  (or network)
Destination: modem_ui_address
Destination port: HTTP
Description: Block all except MGMT hosts to modem UI

Clone and add an HTTPS rule if your modem uses it.

floating_rule.png

6) Test with some pings.  You should get timeouts on all private IP addresses which are not defined in OPNsense, except for the modem IP.

C:\>ping 10.1.2.3

Pinging 10.1.2.3 with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for 10.1.2.3:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

The firewall live view should reflect that these pings are dropped.  The "Source" address should be your WAN public IP, confirming that the rule was applied post-NAT.

For IPv6 you can ping a random ULA address (https://www.unique-local-ipv6.com/):

C:\>ping -6 [fd50:2e32:f043::]

Pinging fd50:2e32:f043:: with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for fd50:2e32:f043:::
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

In this case the "Source" IP in the FW logs will be your public IPv6 address (GUA) or a ULA if you have one configured on your local interface, as these aren't NAT-ed.  (Note: the intention is not to confirm filtering of ICMPv6 here, as that's generally frowned upon in IPv6.  This is just testing the rule.)

If you open a browser and try to navigate to these IPs you should not get stuck waiting.  You should get a "Connection Refused" error after a few seconds, confirming the Reject action on the WAN rules.

Finally test the modem admin UI is working.

7) Profit!

From now on you only need to update the management client and modem IPs in the respective aliases, if those change.  In summary those are:

Name: management_clients
Name: modem_ui_address
Name: modem_ui_exclusion
Title: Re: Stop IP leaks on WAN (and secure modem UI) without touching NAT
Post by: OPNenthu on May 08, 2025, 06:08:10 PM
I'm a little nervous to post this as it's not reviewed.  It's appreciated for the greybeards and others to point out the holes.
Title: Re: Stop IP leaks on WAN (and secure modem UI) without touching NAT
Post by: RamSense on May 08, 2025, 07:29:41 PM
thanks for sharing this. I have your WAN out rule reject IPv4_private_ranges added to firewall-rules-floating rules.
Is there a reason you have it at WAN instead floating?
And I have also added: 169.254.0.0/16
Title: Re: Stop IP leaks on WAN (and secure modem UI) without touching NAT
Post by: OPNenthu on May 08, 2025, 07:52:51 PM
Thanks for giving it a go. I don't see why the WAN rule can't be in floating.  My preference is to keep interface-specific rules on the interface and shared/common rules in Floating, but I'm open to new ideas about that.

Good call with 169.254.0.0/16.  I'd probably put it in the "IPv4_no_NAT" alias rather than the "IPv4_private_ranges" one.  I think it's kind of like the fe80::/10 range in that routers aren't supposed to forward packets from those, but who knows what a misbehaved one might do (?)
Title: Re: Stop IP leaks on WAN (and secure modem UI) without touching NAT
Post by: OPNenthu on May 08, 2025, 09:36:05 PM
Purely a pedantic cleanup, for those inclined.  I added one more alias for the IPv4 link-local range and renamed the IPv6 alias to "IPv6_local_ranges" rather than "IPv6_private_ranges" to be more accurate.

IPv4:
- IPv4_no_NAT:
  -- IPv4_private_ranges  (RFC1918)
  -- IPv4_local_ranges (RFC3927)

IPv6:
- IPv6_local_ranges (RFC4291, RFC4193)