# dnsmasq — LAN wildcard DNS ## Summary Provides name resolution for guest laptops so `*.ulicraft.local` resolves to the Docker host. Replaces the homelab's AdGuard (dropped for the LAN party). Image: `jpillora/dnsmasq` (dnsmasq wrapped in webproc, optional web UI on :8080). Config is a **file**, not env-driven — `/etc/dnsmasq.conf`, standard dnsmasq format. Rendered from a template by `tooling/render-config.sh`. Only guest laptops point their DNS here. Stack-internal resolution is handled by Docker network aliases on Caddy (see `02-caddy.md`), so dnsmasq is not on the critical path for the server's own services. ## Config template `dnsmasq/dnsmasq.conf.tmpl`: ``` # wildcard: every *.ulicraft.local → host LAN IP address=/${BASE_DOMAIN}/${HOST_LAN_IP} # upstream optional; party is offline so may be omitted no-resolv ``` ### Air-gap spoof records (see 11) For full client air-gap, this file also spoofs the real upstream hosts → our Caddy mirror (`piston-meta`/`piston-data`/`libraries.minecraft.net`/ `maven.neoforged.net`/`resources.download.minecraft.net`/`meta.prismlauncher.org`). Full list + rationale in `11-full-airgap-mirror.md`. Keep in sync with the capture step. Auth hosts (session/textures/api.mojang) are NOT spoofed — drasl handles those via authlib-injector. ## Gotcha — port 53 conflict Linux Docker hosts usually run `systemd-resolved` bound to `:53`. Publishing `53:53` will fail with `address already in use`. Resolve by one of: - Bind dnsmasq only to the LAN IP: publish `${HOST_LAN_IP}:53:53/udp` (+tcp) - Or disable resolved's stub listener (`DNSStubListener=no`) and restart resolved ## Gotcha — `.local` / mDNS See overview. Avahi may shortcut `*.local` to multicast before hitting dnsmasq. Test on a macOS client early; if broken, switch `BASE_DOMAIN` to `.lan`. ## Tasks - [ ] Add `dnsmasq` service to `docker-compose.yml` (`jpillora/dnsmasq`) - [ ] Create `dnsmasq/dnsmasq.conf.tmpl` with wildcard `address=` line - [ ] Wire `render-config.sh` to emit `dnsmasq/dnsmasq.conf` (gitignored) - [ ] Decide port-53 strategy (bind to `HOST_LAN_IP` vs disable resolved stub) - [ ] Publish `53/udp` + `53/tcp`; mount rendered conf read-only - [ ] Optionally expose webproc UI (8080) behind Caddy as `dns.ulicraft.local` - [ ] Document guest DNS setting (set DNS server = `HOST_LAN_IP`) - [ ] Verify `*.local` resolves on Windows + macOS + Linux guests (mDNS check) - [ ] Add air-gap spoof `address=` records (see 11) once capture confirms the host list