diff --git a/README.md b/README.md index ef44689..7da36ca 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,6 @@ $ export TSDNS_DNSSERVER_PORT=2222 - Webhook endpoint allowing automatic refreshing of devices when a new device is added - LetsEncrypt DNS-01 Challenge integration - - Config based static records/aliases + - ~Config based static records/aliases~ - Simple web ui listing status - Status url for Prometheus or monitoring diff --git a/config.go b/config.go index 83cf469..8b0da56 100644 --- a/config.go +++ b/config.go @@ -40,6 +40,7 @@ func loadConfig() { viper.SetDefault("dns-server.port", 53) viper.SetDefault("tailscale.hostname", "tailscale-custom-domain-dns") viper.SetDefault("tailscale.ephemeral", false) + viper.SetDefault("aliases.subdomains", map[string]string{}) // Read the config configFile, err := os.Open(configPath) diff --git a/examples/tailscale-custom-domain-dns.toml b/examples/tailscale-custom-domain-dns.toml index 6fe2912..ccee1e1 100644 --- a/examples/tailscale-custom-domain-dns.toml +++ b/examples/tailscale-custom-domain-dns.toml @@ -60,3 +60,7 @@ interval = "1h" # Alias for the root domain without any subdomain # Example: root = "machine-one" root = "" + +[aliases.subdomains] +# Aliases for subdomains, they take the form of: +# alias = "existing-device-name" diff --git a/server/dns.go b/server/dns.go index b35a83a..0fd12cb 100644 --- a/server/dns.go +++ b/server/dns.go @@ -120,10 +120,12 @@ func makeHandler(readDevices chan ReadDevicesOp, host string) DnsHandler { // Get just the subdomain name from the request name := strings.ReplaceAll(question.Name, "."+host, "") + // Get possible aliases + aliases := viper.GetStringMapString("aliases.subdomains") + var rrs []dns.RR if question.Name == host { // If the hostname is bare, check for a root alias - if viper.IsSet("aliases.root") { name := viper.GetString("aliases.root") if device, ok := deviceMap[name]; ok { @@ -136,7 +138,22 @@ func makeHandler(readDevices chan ReadDevicesOp, host string) DnsHandler { m.Answer = rrs } } + } else if alias, ok := aliases[name]; ok { + // Respond with an alias + if device, ok := deviceMap[alias]; ok { + log. + Debug(). + Str("host", name). + Msgf(`Serving alias "%s" redirects to "%s"`, question.Name, alias) + + rrs = constructResponses(name, device, question, host) + m.Answer = rrs + } } else if device, ok := deviceMap[name]; ok { + log. + Debug(). + Msgf(`Serving normal response "%s"`, question.Name) + // Respond if a device with the hostname exists rrs = constructResponses(name, device, question, host) }