2023-08-17
I run a fair bit of OpenBSD in my home network. At this time, my firewall setup runs a chain of Unbound (with RPZ to block ads) to NSD (to maintain my internal domain hosts) to dnscrypt_proxy (to send my recursive queries to external hosts).
The unbound portion of this work is kinda clunky and homegrown. It was essentially trying to emulate a pihole setup that I didn’t want to dedicate hardware or an OpenBSD vmm to.
This page describes an incremental move away from that approach: I start by implementing pihole and forwarding everything to my router DNS service; since pihole will block everything that unbound would block, unbound will thus serve to either do local name resolution for my internal domain (lan.ckure.com) or send to the recursive upstream resolvers via dnscrypt_proxy.
I decided to execute the pihole/pihole-latest container via a project. I’m not sure if that’s the best approach. But it was pretty straightforward, except that binding pihole to the “host” network wasn’t working. I looked at several things to solve a couple of issues:
Ultimately, I settled on IPTables forwarding of DNS traffic into the Docker network.
With that said, here are the key components of my working setup:
version: "3"
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
ports:
- "53:53/tcp"
- "53:53/udp"
# - "67:67/udp" # Only required if you are using Pi-hole as your DHCP server
- "843:80/tcp"
environment:
TZ: 'America/New_York'
WEBPASSWORD: ...
PIHOLE_DNS_: $InternalDnsIp # eg. '192.168.1.254'
REV_SERVER: "true"
REV_SERVER_DOMAIN: $MyInternalDomain # eg. 'lan.ckure.com'
REV_SERVER_TARGET: $InternalDnsIp # eg. '192.168.1.254'; you need this if you have an internal domain for your hosts
REV_SERVER_CIDR: $MyLanSubnet # eg. '192.168.1.0/16'; you use this to tell pihole which subnet to send to REV_SERVER_TARGET for local DNS resolution
# Volumes store your data between container upgrades
volumes:
- './etc-pihole:/etc/pihole'
- './etc-dnsmasq.d:/etc/dnsmasq.d'
# cap_add:
# - NET_ADMIN # Required if you are using Pi-hole as your DHCP server, else not needed
restart: unless-stopped
In order to get past the container NAT and expose the 192.168.1.0/16 client IP addresses / reverse name lookups in pihole’s “Client” view, I need to add some IP tables rules. To do that, we run a scheduled task on boot:
Control Panel > Task Scheduler
Create a new user-defined script
Use the following script to forward 53/udp and 53/tcp past the Docker NAT
#!/bin/bash
currentAttempt=0
totalAttempts=10
delay=3
while [ $currentAttempt -lt $totalAttempts ]
do
currentAttempt=$(( $currentAttempt + 1 ))
echo “Attempt $currentAttempt of $totalAttempts…"
result=$(iptables-save)
if [[ $result =~ “-A DOCKER -i docker0 -j RETURN” ]]; then
echo “Docker rules found! Modifying…"
iptables -t nat -A PREROUTING -p tcp –dport 53 -m addrtype –dst-type LOCAL -j DOCKER
iptables -t nat -A PREROUTING -p udp –dport 53 -m addrtype –dst-type LOCAL -j DOCKER
echo “Done!"
break
fi
echo “Docker rules not found! Sleeping for $delay seconds…”
sleep $delay
done