DNS Hairpin Rule for Pi-Hole

Started by spetrillo, August 16, 2021, 11:07:23 PM

Previous topic - Next topic
Hello all,

I have read many posts and many other documents on how to force all DNS requests to Pi-Hole. Is there a defacto way to ensure those devices that bypass DHCP DNS server to force them to Pi-Hole, which is my DHCP DNS server?

Thanks,
Steve

This should probably help: https://labzilla.io/blog/force-dns-pihole

I've implemented mine slightly differently, particularly in the port forward rules. My setup also deals with IPv6 and I use tagging on the rules so the outbound NAT only applies to those packets that are redirected. Otherwise the pihole sees everything as coming from OPNsense.

If the link doesn't work for you I can post my config at some point.

Curious what you mean by tagging.  Would you mind sharing your config?  TIA!

On the port forward rule, in the "Set local tag" option I put a tag (in my case the text "forward"; doesn't matter what it is).

On the outbound NAT rule, in the "Match local tag" option I put the same tag.

So any packet that the port forward acts on will be tagged, meaning that the outbound NAT rule will apply to it. If the packet is not tagged, the outbound NAT rule won't apply.

I should have a chance to post the config in the next couple of days.

OK, so here is my config.

Background:

- I have a LAN interface and several VLANs on OPNsense
- I have an interface group called ALL_LOCAL which groups the LAN and those VLANs together
- My Pi-hole is on a separate box that also runs unbound as a recursive resolver. It is on the LAN
- Pi-hole listens on 192.168.1.10 and fdfd:2553:8868:1:63df:78ab:5e7e:68ee
- The Pi-hole IPs are handed out as DNS servers by DHCP and RA
- The idea is that all DNS for my network is handled by Pi-hole and unbound

Aliases:

pihole_local_ips: 192.168.1.10, fdfd:2553:8868:1:e142:6fe1:5e7e:68ee
pihole_ips: 192.168.1.10, fdfd:2553:8868:1:e142:6fe1:5e7e:68ee, 2503:7310:39ab:7c01:6fe1:5e7e:f997:3b3d

(Not my real GUA of course)

I have two aliases because one is used for local clients to access Pi-hole/unbound, and the other is used for Pi-hole/unbound to access the internet (hence the GUA).

Firewall rules:

There are no firewall rules to configure if you have the default "allow LAN to any" rule. Otherwise there would need to be a rule on LAN (given Pi-hole/unbound is on the LAN) to allow Pi-hole/unbound to access the internet:

   Action: Pass
   Quick: Checked
   Interface: LAN
   Direction: in
   TCP/IP Version: IPv4+IPv6
   Protocol: TCP/UDP
   Source / Invert: Unchecked
   Source: pihole_ips
   Destination / Invert: Unchecked
   Destination: any
   Destination port range: DNS

Port forward:

   Interface: ALL_LOCAL
   TCP/IP Version: IPv4+IPv6
   Protocol: TCP/UDP
   Source invert: Checked
   Source address: pihole_ips
   Source port: any
   Destination invert: Checked
   Destination address: pihole_local_ips
   Destination port: DNS
   Redirect target IP: pihole_local_ips
   Redirect target port: DNS
   Set local tag: forward
   Filter rule association: Make sure this is NOT set to None or Pass (that is, you want a firewall rule created)

Note that this port forward creates a firewall rule that allows all local clients to access the pihole_local_ips. This is created on the ALL_LOCAL group.

Outbound NAT:

   Interface: LAN
   TCP/IP Version: IPv4
   Protocol: TCP/UDP
   Source invert: Unchecked
   Source address: ALL_LOCAL net
   Source port: any
   Destination invert: Unchecked
   Destination address: pihole_local_ips
   Destination port: DNS
   Translation / target: Interface address
   Match local tag: forward

   Interface: LAN
   TCP/IP Version: IPv6
   Protocol: TCP/UDP
   Source invert: Unchecked
   Source address: ALL_LOCAL net
   Source port: any
   Destination invert: Unchecked
   Destination address: pihole_local_ips
   Destination port: DNS
   Translation / target: Interface address
   Match local tag: forward

It's very kind of you to share. In my setup the pi-hole sees the clients as they are, not as all from OPN. It made me curious to compare with yours.
In your setup is it OPNS DFCP service dishing out the IPs or is it unbound on the PI-Hole.?

OPNsense provides DHCP. unbound is not a DHCP server.

Interesting that the outbound NAT rule didn't impact you in the same way. Not sure why you have a different experience - it seems logical to me that if you source NAT all packets going to the Pi-hole, then they will also show the OPNsense IP as their source when arriving at Pi-hole. The only exception is where clients are on the same subnet and are already using Pi-hole - then they wouldn't be routed through OPNsense anyway because they would just be dealt with on L2. In my case the vast majority of my clients are not on the LAN subnet, and so are routed through OPNsense.

Thanks Greelan

I was a little lost on your outbound NAT rule for the LAN before you shared the config.  Seems this is needed, other wise the response traffic from pi-hole would leave and try to head directly back to the SRC IP of the clients, which would be an asymmetrical route, and probably dropped by them I would imagine since that's not where they sent the query to.

I think I've spotted the difference in our setups now Greelan. If I read correctly you are running unbound outside OPN.
In my setup OPN also provides DHCP to clients and gives them the pi-hole ip address as the DNS server. So all clients do name resolution against the pi-hole on standard port 53. The pi-hole in turn has OPN's ip address as the upstream resolver also on port 53.
On OPN I run Unbound and my custom configuration pushes the received queries from pi-hole onto Stubby for DoT.
That is DNS go: clients -> pi-hole @53 -> OPN @53 -> Stubby @8053. That is normal client DNS traffic. No tagging is necessary.
And the firewall rules I have on OPN are to catch only those rogue clients not respecting that and have their hardcoded dns servers or any misconfigured client. This is the port forward rule.
Additionally my outbound rule is  to prevent hardcoded DNS clients from giving unexpected source error after DNS is  redirected to PiHole, if I understand correctly.

Hello,
I have implemented this hairpin approach for DNS requests successfully for IPv4. The problem is that it does not work for IPv6. The setup for Ipv6 is identical as for IPv4. The pihole address is an ULA address fd00::2:115 which is  working like a charm. So nslookup google.com fd00::2:115 works fine. However, as soon as I want to get around pihole nslookup google.com 2001:4860:4860::8844 I receive a timeout. In the log I can see that the request was redirected to pihole, but I receive no response.

Does anyone have an idea how to solve this issue? In the firewall log I can see no blocks or anything.

Hello,
Ipv6 is really strange. I have tracked the issue down to some problem in Opnsene.
nslookup google.com 2001:4860:4860::8844
successfully leads to a request originating from Opnsense (fd00::1) at the local pihole DNS server (fd00::2:115). The Firewall log at opnsense reports the redirect and tcpdump at the DNS server correctly reports:

12:13:57.142437 IP6 fd00::1.49895 > pi.hole.domain: 18686+ A? google.com. (28)
12:13:57.142994 IP6 pi.hole.domain > fd00::1.49895: 18686 1/0/0 A 142.250.185.206 (44)


The problem is, that somehow Opnsenese does not forward this response to the requesting device. Unfortunatelly I have no idea how to track that issue? By the way, the forward works fine for IPv4:
nslookup google.de 9.9.9.9
results at the DNS server in

12:58:45.175356 IP 192.168.2.2.11493 > pi.hole.domain: 53828+ AAAA? google.de. (27)
12:58:45.252237 IP pi.hole.domain > 192.168.2.2.11493: 53828 1/0/0 AAAA 2a00:1450:4001:82f::2003 (55)

and the DNS reponse is immediatelly provided at the requesting device.

January 24, 2022, 12:10:20 AM #11 Last Edit: January 24, 2022, 12:18:44 AM by stefan21
Quote from: Greelan on August 20, 2021, 01:55:22 PM
OK, so here is my config.

Background:

- I have a LAN interface and several VLANs on OPNsense
- I have an interface group called ALL_LOCAL which groups the LAN and those VLANs together
- My Pi-hole is on a separate box that also runs unbound as a recursive resolver. It is on the LAN
- Pi-hole listens on 192.168.1.10 and fdfd:2553:8868:1:63df:78ab:5e7e:68ee
- The Pi-hole IPs are handed out as DNS servers by DHCP and RA
- The idea is that all DNS for my network is handled by Pi-hole and unbound

Aliases:

Good evening,

and thank you for sharing your approach.

I do have a slightly different network config. The OPNSense does not act as a DHCP, this job is doing a NethServer. I'd like to implement the pihole in the LAN. Therefore I have a few questions:

a) would your setup work also in my scenario (pointing the DNS from the NethServer to the IP of the pihole)?

b) in OPNSense System: Settings: General: do I have to enter the IP of the pihole?

c) I assume in OPNSense Services: Unbound DNS: General: this one should be disabled?

Thank's for any hints.

regards,
stefan


My thoughts:

a) Should do. Your separate DHCP server will just hand out of the pihole IP as DNS server rather than OPNsense doing that job.

b) Yes, if you want OPNsense to use the pihole for DNS resolution too.

c) Correct, if you don't need unbound on OPNsense providing any DNS services in your network.

@Greelan

Thank you for your feedback and time in this. I'll try it out and let you know.

regards,
stefan

Hmm, something's not quite correct. From the pi-hole log (which is spilling rapidly):

dnsmasq[2705]: query[NS] . from 192.168.52.1
Jan 24 14:35:03 dnsmasq[2705]: forwarded . to 127.0.0.1
Jan 24 14:35:03 dnsmasq[2705]: reply error is REFUSED

and

Jan 24 14:32:36 dnsmasq[2705]: query[A] 2.0.de.pool.ntp.org from 192.168.52.1
Jan 24 14:32:36 dnsmasq[2705]: forwarded 2.0.de.pool.ntp.org to 127.0.0.1
Jan 24 14:32:36 dnsmasq[2705]: reply error is REFUSED

The OPNSense is configured for using chrony - the query to de.pool.ntp.org must come from some client. Unbound in OPNSense is turned off. All DNS are pointing to the pi-hole.

However the pi-hole is blocking requests and filtering is up.

Any thoughts?