I have created a NAT port forward from one of my interfaces to a special DNS service listening on loopback on port 5053.
Port Forward Rule:
Interface: LAB
Protocol: TCP/UDP
Destination: LAB Address
Destination Port: DNS(53)
Redirect Target IP: 127.0.0.1
Redirect Target Port: 5053
Reflection: Disable
When a packet comes in on the interface address (LAB), the firewall correctly forwards it from LAB_IP:53 -> 127.0.0.1:5053, and the DNS service sees the request. However the response from OPNsense to the client will come from LAB_IP:5053 and not LAB_IP:53.
Since the client sent the packet to port 53, it expects a response from port 53, but instead gets a response from port 5053, which it discards.
This only happens with UDP traffic forwarded to the loopback interface. If I test with TCP forwarded to loopback, the source port is updated correctly. It also works if I forward UDP to non-loopback IPs. I have verified this behavior with packet captures running on both OPNsense and the client.
Why would the source port for responses not be set correctly for UDP traffic on the loopback interface? Is there a setting I may have missed, or is this a bug?
Thanks.
https://labzilla.io/blog/force-dns-pihole
You're missing the "NAT Rule 3: Prevent clients from giving unexpected source errors" part.
It's not identical setup but the principle is the same, need to adjust to your IPs.
Thanks for the suggestion.
I tried creating the outbound NAT rule as suggested in the article, but it does not seem to have any effect on the UDP responses from OPNsense to the client.
I have attached a screenshot of the outing NAT rule. Does it look correct with the different IPs?
Does anything different need to be done to make it take effect on packets from a loopback interface in response to an incoming forwarded request?
You need to bind that DNS service to 127.0.0.1:5053 only. Otherwise it will always try to answer via a matching directly connected interface.
Amazing, that was the problem.
Changing the DNS service that is listening on port 5053 to bind to "127.0.0.1" and "::1" instead of "0.0.0.0" and "::" allows the src port for UDP and TCP traffic to be correct! No outbound NAT rules needed.
However, now there appears to be another issue. If I update the port forward rule to also support IPv6, it seems to have no effect. It continues to work for the IPv4 LAB_IP, but if I have a client query the IPv6 LAB_IP, it times out.
As far as I can tell I set the NAT port forward to work the same for IPv4 and IPv6.
Port Forward Rule:
Interface: LAB
Version: IPv4+IPv6
Protocol: TCP/UDP
Destination: This Firewall
Destination Port: DNS(53)
Redirect Target IP: Alias(loopback[127.0.0.1,::1])
Redirect Target Port: 5053
Reflection: Disable
All other local and internet IPv6 traffic works normally.
Does something need to be done to "NAT Port Forward" for this port on the IPv6 address?
Try a separate rule for IPv6 with ::1 as the redirect target. Not sure if it will work, but I am pretty confident a combined rule for port forwarding won't. I'm lazy, I use only IPv4 for DNS. ;) All devices are dual stack, anyway.
Unfortunately even ad a separate rule just for IPv6, it does not work.
Unlike when IPv4 was not working, the DNS service does not see any requests over IPv6. IT is listening on IPv6 (if queried directly on OPNsense to [::1]:5053 it works as expected, but the NAT port forward is not forwarding any of the incoming packets.