#!/usr/bin/env bash # Subscribe the current host to black.local's LAN DNS. # # Why this exists: # black.local (10.0.0.11) runs dnsmasq with `address=/black.local/10.0.0.11` # — a wildcard rule that resolves every *.black.local hostname to black's # LAN IP. The DNS server is already reachable because DHCP hands 10.0.0.11 # out as one of the assigned DNS servers. The piece still missing on # Linux hosts with mDNS disabled is a **resolver routing-domain policy** # that tells systemd-resolved "forward *.black.local queries to my DNS # servers instead of treating them as mDNS / refusing them." # # macOS handles this natively via /etc/resolver/black.local. Linux needs # a drop-in file for systemd-resolved. # # What this does (idempotent — safe to re-run): # * Linux + systemd-resolved: writes # /etc/systemd/resolved.conf.d/black-local.conf # with `Domains=~black.local` + `DNS=10.0.0.11`, then reloads resolved. # * macOS: writes # /etc/resolver/black.local # with `nameserver 10.0.0.11` so the macOS resolver routes black.local # lookups to dnsmasq. No daemon reload needed. # * Windows / BSD / other: prints a manual remediation hint. # # Verify after running: # getent hosts mc.next.black.local # Linux # scutil --dns | grep -A2 black.local # macOS # curl -sk https://mc.next.black.local/ -o /dev/null -w '%{http_code}\n' # # Usage: # bash scripts/lan/subscribe-black-dns.sh # locally # ssh 'bash -s' < scripts/lan/subscribe-black-dns.sh # remote # # Re-run any time after black.local's IP or DNS-server layout changes. set -euo pipefail readonly BLACK_IP='10.0.0.11' readonly BLACK_DOMAIN='black.local' readonly RESOLVED_DROP_IN='/etc/systemd/resolved.conf.d/black-local.conf' readonly MACOS_RESOLVER_FILE='/etc/resolver/black.local' log() { printf '\033[0;34m[subscribe-black-dns]\033[0m %s\n' "$*"; } ok() { printf '\033[0;32m[subscribe-black-dns] ✓\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[subscribe-black-dns] !\033[0m %s\n' "$*"; } fail() { printf '\033[0;31m[subscribe-black-dns] ✗\033[0m %s\n' "$*" >&2; exit 1; } probe_dns() { # Return 0 if `mc.next.black.local` resolves via the host's normal # resolver path. macOS's /etc/resolver/ mechanism isn't visible to # NSS-based tools (getent / host / nslookup in some configs), so on # Darwin we have to use dscacheutil which IS aware of it. case "$(uname -s)" in Darwin) dscacheutil -q host -a name mc.next.black.local 2>/dev/null \ | grep -q "^ip_address: " ;; *) getent hosts mc.next.black.local >/dev/null 2>&1 \ || host mc.next.black.local >/dev/null 2>&1 ;; esac } configure_linux_systemd_resolved() { if ! command -v systemctl >/dev/null 2>&1; then fail "systemctl not found — this script's Linux branch assumes systemd." fi if ! systemctl is-active --quiet systemd-resolved; then warn "systemd-resolved is not active; skipping routing-domain drop-in." warn "Configure your resolver manually: point *.${BLACK_DOMAIN} at ${BLACK_IP}." return 0 fi local payload payload="$(cat </dev/null log "reloading systemd-resolved" sudo systemctl reload systemd-resolved ok "systemd-resolved reloaded" fi } configure_macos_resolver() { local payload="nameserver ${BLACK_IP}" if [ -f "$MACOS_RESOLVER_FILE" ] && grep -qx "$payload" "$MACOS_RESOLVER_FILE"; then ok "already subscribed (${MACOS_RESOLVER_FILE} up to date)" return 0 fi log "writing ${MACOS_RESOLVER_FILE}" sudo mkdir -p "$(dirname "$MACOS_RESOLVER_FILE")" printf '%s\n' "$payload" | sudo tee "$MACOS_RESOLVER_FILE" >/dev/null ok "macOS resolver file installed (no daemon reload needed)" } verify() { if probe_dns; then ok "mc.next.black.local resolves via this host's resolver" else warn "mc.next.black.local still doesn't resolve — check that black (${BLACK_IP}) is reachable:" warn " ping -c 1 ${BLACK_IP}" warn " dig @${BLACK_IP} mc.${BLACK_DOMAIN}" fi } main() { log "host: $(hostname) · OS: $(uname -s)" case "$(uname -s)" in Linux) configure_linux_systemd_resolved ;; Darwin) configure_macos_resolver ;; *) fail "Unsupported OS: $(uname -s). Route *.${BLACK_DOMAIN} to ${BLACK_IP} via your resolver of choice." ;; esac verify } main "$@"