Outbound Nat Rewrite - how to monitor in logs?

Started by allebone, May 20, 2021, 09:52:28 PM

Previous topic - Next topic
Ah hang on. I am confusing myself. Don't you need a port forward in this scenario (with an outbound NAT simply to deal with source address errors)?

I haven't implemented this myself yet but have disabled rules set up ready for testing when I get the chance. Will post them later FYI

Yup give it a go. I believe what I am asking is impossible. You cannot know the destination ip (eg: 8.8.8.8) the client attempted to access that was then redirected. Its simply not logged.

Sorry about the confusion in my earlier posts - I shouldn't try to exercise and troubleshoot on the forum at the same time!

Attached are the draft rules I have set up (can't test until I don't have people on the network, in case DNS breaks!). Note that ALL_LOCAL is an interface group that includes all of my local networks/VLANs.

First is a port forward rule (destination NAT) that redirects to the pi-hole any DNS request from a local host that is not the pi-hole and that is not already destined for the pi-hole.

Second are outbound NAT rules (source NAT) to fix any source address errors as a result of the redirection.

Finally, my filter rules. The second rule in this screenshot is automatically created by the port forward. The first rule is to ensure that the pi-hole itself is able to access external DNS servers.

If logging is enabled on the port forward, does that not give the original destination IP in the logs? If not, then I agree that this functionality probably doesn't exist currently.

Yes these rules are almost identical to what I have setup. Logging is enabled on the first rule in your example for me as well. I dont believe its possible, and instead I think the information is lost at this point in time.

June 25, 2021, 02:19:35 PM #34 Last Edit: June 25, 2021, 02:21:27 PM by allebone
The other think that makes me think its impossible is that the very first thing processed in

cat /tmp/rules.debug

Ie the Nat rewrite rules listed first in that file. Since its done first, anything that happens after is happening after the rewrite and so logging later on is not going to help. There would need to be a logging mechanism that processes before the (current) very first rule processed which does not exist :(

I finally implemented my rules but in the end disabled the outbound NAT rules, because they basically meant that the Pi-hole saw every DNS request as coming from the router. There is no way AFAIK to distinguish for the outbound NAT rules between packets that have been port forwarded and packets that are going to the Pi-hole normally, because by the time the outbound NAT rules apply the packets have already been destination NATed.

On the processing order I actually don't agree that the order in rules.debug is the order they are applied. My understanding is that destination NAT occurs first, then the filter rules, and then source NAT. The issue here is simply that OPNsense does not log the original destination IP in the port forward logs. Presumably it could with a code change, because OPNsense has the information when it applies the port forward.

Actually, just had a thought about distinguishing packets - by setting a local tag on the port forward and matching that on the outbound NAT. That could actually work...

June 26, 2021, 04:35:05 AM #37 Last Edit: June 26, 2021, 05:52:27 AM by Greelan
Nope, the tag doesn't seem to work. This behaviour is really hard to figure out lol

Edit: the tag does actually work. It just had a syntax error when I originally tried it (for some reason I can't figure out)

I came across this thread attempting to achieve the same goal as OP: redirecting all DNS traffic to a specific address, but logging the original destination address before network translation took place.  I've tried various combinations of enabling firewall/NAT logging and setting local tags, but have not been successful so far.  Now that I've done some digging into the matter, I understand why it's not as straightforward as you might think it would be.

It's been established (and confirmed by franco) that OPNsense processes NAT and firewall rules in the same order as pfSense.  I.e. the pfSense documentation on this matter is relevant in OPNsense and, most importantly, NAT occurs before firewall rules.  Meaning that address translation occurs first and any subsequent firewall rules (and associated logging) occurs on the translated address.  So there is no opportunity to log any details about the pre-NAT'ed traffic, including the original destination address.

That's not to say obtaining this information is impossible.  Searching for prior art on the subject, I came across these projects
OPNsense's firewall logs (`/var/log/filter/filter_yyyymmdd.log`) are generated by `/usr/local/sbin/filterlog`.  When `pf` processes a packet that matches a rule with the `log` flag set, it makes it available on the `pflog0` interface.  `filterlog` then reads the packet, parses out various properties, then writes out logging information in a defined format.  It's possible there's scope to extend parsing to extract pre-NAT destination address and port information.  If it were possible, it's likely only one step of many required to expose the information through the web interface.  I.e modifying views, updating the API, etc.

The above is based purely on my limited understanding of OPNsense and FreeBSD internals gained from poking around the source.  I'd really appreciate if someone more knowledgeable could let me know if I'm on the right track.  Better yet, if would be great if one of the developers could chime in on the feasibility of my speculative implementation.

June 27, 2021, 11:22:54 AM #39 Last Edit: June 27, 2021, 11:40:10 AM by Greelan
Nice analysis, good work. Confirms my thinking that code changes could definitely address the logging.

The pfSense docs seem a little inconsistent on the rule processing order. The first section refers to outbound NAT being processed first, but then the examples given show it near the end. The latter makes more sense to me, and is also consistent with the fact that a local tag set on my port forward is picked up by my outbound NAT rule. If the outbound NAT rule was processed first, that presumably could not happen.

It seems this thread has a corresponding issue on GitHub.  If it's likely to get the devs' attention, I'm happy for for my write-up to be echoed over there.

Only issue is that the problem is misdescribed - it is not outbound NAT that is the issue, it is the port forward. Outbound NAT is source NAT, whereas the issue of concern is destination NAT (ie port forward)

Quote from: Greelan on June 27, 2021, 01:30:11 PM
Only issue is that the problem is misdescribed - it is not outbound NAT that is the issue, it is the port forward. Outbound NAT is source NAT, whereas the issue of concern is destination NAT (ie port forward)

I raised the issue to the best of my ability at the time on github. A lot more info has come through on this thread since then. Just trying my best man :)

Wasn't a criticism, just pointing out that for it to get the right attention it should be updated. GH has an edit function [emoji14]

I think I have updated it to what you might consider adequate?