I have a DNS service (pihole, 192.168.53.2) running on a Raspberry Pi. My DHCP service tells connected devices where the DNS server is, but some ignore it and connect directly to 8.8.8.8. Is it possible to capture this traffic from the Mikrotik router and forward it to the Raspberry Pi so it responds correctly without causing any problems?
That's right, after thinking about it I understand, but these rules don't work for me. The request reaches the server (192.168.53.2) and it seems to respond, but the computer in this test case, my own PC, never receives the response.
I think the problem is that my PC is rejecting the response because it's coming from 192.168.53.2 instead of 8.8.8.8
This is usually the reason why it doesn't work. When you have the condition listed in the export like this, then that condition will never successfully match and the whole DSTNAT rule will never match. Because it only matches when the port is an empty string. But the port is an whole number and will never be equal to "".
You should properly clear the src-port condition. If using WinBox, use these buttons:
It's working now, but PiHole shows that the requests are being made by the router, which is messing up my PiHole statistics. I'll see what I can do. Thanks.
Yes, if you want the Pi-hole to see the real IP source address of the clients, it's best that you put pihole in its own subnet. It's doesn't have to be in a separate VLAN. You can keep it in the same VLAN as the client devices but:
Under /ip address add another address in another /24 subnet to the interface, for example 192.168.54.1/24 besides the existing 192.168.53.1/24 entry.
On Pi-hole configure static address to be 192.168.54.2/24 gateway 192.168.54.1.
On Pi-hole make sure it accepts connections from other subnets (at least from 192.168.53.0/24).
Update the two DSTNAT rules above to use 192.168.54.2 instead of 192.168.53.2.
Then you don't need the hairpin-NAT rule anymore (or you can keep it but change to dst-address=192.168.54.0/24 src-address=192.168.54.0/24). And Pi-hole will see the correct source IP addresses of the clients instead of 192.168.53.1.
Yes, and currently in the same subnet 192.168.53.0/24. That's why the Hairpin-NAT was needed (otherwise it won't work after DSTNAT kicks in, like you could observe).
But the Hairpin-NAT rule then causes the source address information to be lost (it's a SRCNAT rule) and Pi-hole now only sees 192.168.53.1 as source of the requests.
To workaround that while still keeping Pi-hole and the client devices in the same VLAN is what I wrote in the previous post (add an extra address entry to the VLAN interface and put only Pi-hole in that subnet, Pi-hole is still in the same original VLAN, it just has an IP address in the 192.168.54.0/24 range).
You can assign multiple subnets to a single interface.
Client 192.168.53.30 wants to send DNS request to 8.8.8.8 port 53 UDP. The packet has src-address=192.168.53.30 and dst-address=8.8.8.8.
Your DSTNAT rule rewrites the destination address, the packet now has a dst-address=192.168.53.2.
Packet is forwarded to Pi-hole. Pi-hole sees that packet has src-address=192.168.53.30
Pi-hole processes the request and responds. The response packet uses the previous source address as destination.
Pi-hole needs to send a packet with src-address=192.168.53.2 and dst-address=192.168.53.30 (the original src-address).
Pi-hole sees that the destination is in its subnet, so it uses ARP and send the packet directly on Layer 2, bypassing the router completely.
Packet arrives at the 192.168.53.30 device. Device sees a packet with src-address=192.168.53.2.
This is something it didn't expect at all, because it was expecting a response from Google, with src-address=8.8.8.8.
Response is dropped, client never gets the response to the request.
In this case when the Hairpin-NAT rule is added, it forces the source address of the original packet to be changed from src-address=192.168.53.30 to 192.168.53.1. Pi-hole receives this packet. When it sends the response, it sends that to 192.168.53.1 which is the router.
The router can match this packet to the previous SRCNAT action (the Hairpin-NAT) and knows how to undo the NAT-ing. It will rewrite the destination of the response packet to 192.168.53.30 and the source to 8.8.8.8, then forwards the packet to the client. Client will accept this packet because it was expected.
This helps the client get the response. But if you look at the Pi-hole side, Pi-hole now only sees 192.168.53.1 as src-address of the packets.
My proposed solution above will put the clients and Pi-hole in separate subnets. The request when arriving at Pi-hole has dst-address=192.168.53.30 but Pi-hole is at 192.168.54.2. When Pi-hole responds, it will see that the address is not in its subnet, it will not send the response directly on Layer 2, but will use the gateway as intermediate, which is the router.
The router will then be able to undo the NAT-ing correctly.
A side note for case if Pi-hole was running in container (or for any other Hairpin-NAT case to container), there is no need to create masquerade rule for dst-nat to VETH IP on same subnet, response packets will be always sent over gateway because VETH is not L2 interface.
Could you explain that better? In my case, Pihole and other services are running on Docker, which is why I've postponed testing until I have more time.
I captured packets for DNS request to 8.8.8.8 to resolve www.google.com (dig @8.8.8.8 www.google.com) from client IP 192.168.100.21 on wifi1 interface. Pi-hole is running in container with veth1 interfce IP 192.168.100.5, both interfaces are assigned to ports of same LAN bridge. There are two dst-nat rules related to this:
DNS address list contains my local DNS servers IPs (192.168.100.1, 192.168.100.5, 192.168.100.7) and ALLOW_DNS list has IP list which are allowed to query external DNS servers (IP 192.168.100.21 is not in that list).
Only NAT masquerade rule I have is from defconf for WAN and it is not related to this flow:
Now what is interesting are 2 last packets with same MAC addresses (src of veth and dst of wifi client) but with different src IP (and client has expected src address in last packet), which rule does that translation even there is no masquerade rule in this flow?
Did you do the capture on the router? Then from 177 -> 178 is conntrack undoing the DSTNAT, it just performs the reverse of what happens when DSTNAT kicks in between 173 -> 174.