Archived
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m30s
NixOS's dnsmasq module defaults resolveLocalQueries to true, which adds 127.0.0.1 to networking.nameservers and binds dnsmasq to listen-address=127.0.0.1. This made the host route all its own DNS through dnsmasq, which had no-resolv=true and no upstream for anything outside the tailnet domain — so every non-tailscale DNS query from the host itself (including SSSD resolving the IPA server FQDN after the IPA client module was added) failed. Setting resolveLocalQueries=false limits dnsmasq to its intended role: a forwarding proxy reachable on the LAN interface for IPA's conditional forwarder. The host uses domainControllerIp directly (already set in networking.nameservers in host.nix). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
61 lines
2.9 KiB
Nix
61 lines
2.9 KiB
Nix
{ vars, ... }:
|
|
|
|
{
|
|
# Run dnsmasq on the LAN interface as a forwarding-only resolver for
|
|
# *.ts.net (Tailscale MagicDNS names). FreeIPA's bind-dyndb-ldap
|
|
# cannot reach 100.100.100.100 (Tailscale's internal resolver) directly
|
|
# because the DC is not a Tailscale node. This host IS a Tailscale node
|
|
# and can reach 100.100.100.100 via its tailscale0 interface, so it
|
|
# acts as an intermediary: FreeIPA has a conditional forward zone for
|
|
# ts.net pointing here (vars.tailscaleRouterIp), and this dnsmasq
|
|
# instance forwards those queries onward to Tailscale's resolver.
|
|
#
|
|
# Configure FreeIPA once after deploying this host:
|
|
# kinit admin
|
|
# ipa dnsforwardzone-add ${vars.tailnetDomain} \
|
|
# --forwarder=${vars.tailscaleRouterIp} \
|
|
# --forward-policy=only
|
|
# Note: IPA refuses to shadow ts.net (a real public TLD); use the
|
|
# tailnet-specific subdomain (vars.tailnetDomain) instead.
|
|
services.dnsmasq = {
|
|
enable = true;
|
|
# NixOS's dnsmasq module defaults resolveLocalQueries to true, which adds
|
|
# 127.0.0.1 to networking.nameservers and makes dnsmasq bind to
|
|
# listen-address=127.0.0.1. This instance is not the host's local
|
|
# resolver — it only serves IPA's conditional forwarder for tailnet names.
|
|
# The host uses domainControllerIp directly (networking.nameservers in
|
|
# host.nix). Without this, all host DNS goes through dnsmasq, which has
|
|
# no upstream for general queries (no-resolv=true), breaking resolution.
|
|
resolveLocalQueries = false;
|
|
settings = {
|
|
# Listen only on the LAN interface — not tailscale0 or loopback.
|
|
# bind-interfaces prevents dnsmasq from binding to 0.0.0.0 and
|
|
# then filtering by interface later; combined with `interface` this
|
|
# ensures it genuinely listens only on eth0.
|
|
bind-interfaces = true;
|
|
interface = [ vars.lxcLanInterface ];
|
|
|
|
# Forward-only: no local /etc/hosts or /etc/resolv.conf reading,
|
|
# no negative caching of NXDOMAIN for names this instance doesn't
|
|
# serve. All ts.net queries come from FreeIPA's conditional forwarder
|
|
# and must be answered by Tailscale's resolver.
|
|
no-hosts = true;
|
|
no-resolv = true;
|
|
|
|
# Tailscale's internal "Quad100" resolver — reachable from any
|
|
# Tailscale node via the tailscale0 interface. Scoped to the
|
|
# specific tailnet subdomain (vars.tailnetDomain) rather than
|
|
# all of ts.net: FreeIPA refuses to shadow ts.net (a real public
|
|
# TLD with DNSimple nameservers) so the conditional forward zone
|
|
# in FreeIPA must use the tailnet-specific subdomain instead:
|
|
# ipa dnsforwardzone-add ${vars.tailnetDomain} \
|
|
# --forwarder=${vars.tailscaleRouterIp} \
|
|
# --forward-policy=only
|
|
server = [ "/${vars.tailnetDomain}/100.100.100.100" ];
|
|
};
|
|
};
|
|
|
|
networking.firewall.allowedUDPPorts = [ 53 ];
|
|
networking.firewall.allowedTCPPorts = [ 53 ];
|
|
}
|