From 18b00b5d8d3ee98fa0f6539e78b5a980551f5922 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Tue, 19 Oct 2021 20:51:43 +0200 Subject: [PATCH 1/4] Add support for Split DNS (implements #179) --- app.go | 4 +++- cmd/headscale/cli/utils.go | 27 +++++++++++++++++++++++++++ docs/DNS.md | 36 +++++++++++++++++++++--------------- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/app.go b/app.go index 864ae16a..0576e7f2 100644 --- a/app.go +++ b/app.go @@ -113,7 +113,9 @@ func NewHeadscale(cfg Config) (*Headscale, error) { if err != nil { return nil, err } - h.cfg.DNSConfig.Routes = make(map[string][]dnstype.Resolver) + if h.cfg.DNSConfig.Routes == nil { // we might have routes already from Split DNS + h.cfg.DNSConfig.Routes = make(map[string][]dnstype.Resolver) + } for _, d := range magicDNSDomains { h.cfg.DNSConfig.Routes[d.WithoutTrailingDot()] = nil } diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index 95555e94..7b7d84ad 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -104,6 +104,33 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) { dnsConfig.Nameservers = nameservers dnsConfig.Resolvers = resolvers } + + if viper.IsSet("dns_config.restricted_nameservers") { + if len(dnsConfig.Nameservers) > 0 { + dnsConfig.Routes = make(map[string][]dnstype.Resolver) + restrictedDNS := viper.GetStringMapStringSlice("dns_config.restricted_nameservers") + for domain, resNameservers := range restrictedDNS { + resResolvers := make([]dnstype.Resolver, len(resNameservers)) + for index, nameserverStr := range resNameservers { + nameserver, err := netaddr.ParseIP(nameserverStr) + if err != nil { + log.Error(). + Str("func", "getDNSConfig"). + Err(err). + Msgf("Could not parse restricted nameserver IP: %s", nameserverStr) + } + resResolvers[index] = dnstype.Resolver{ + Addr: nameserver.String(), + } + } + dnsConfig.Routes[domain] = resResolvers + } + } else { + log.Warn(). + Msg("Warning: dns_config.restricted_nameservers is set, but no nameservers are configured. Ignoring restricted_nameservers.") + } + } + if viper.IsSet("dns_config.domains") { dnsConfig.Domains = viper.GetStringSlice("dns_config.domains") } diff --git a/docs/DNS.md b/docs/DNS.md index 85bf9f44..948f3c79 100644 --- a/docs/DNS.md +++ b/docs/DNS.md @@ -11,23 +11,29 @@ Long story short, you can define the DNS servers you want to use in your tailnet ## Configuration reference -The setup is done via the `config.json` file, under the `dns_config` key. +The setup is done via the `config.yaml` file, under the `dns_config` key. -```json -{ - "server_url": "http://127.0.0.1:8001", - "listen_addr": "0.0.0.0:8001", - "private_key_path": "private.key", - //... - "dns_config": { - "nameservers": ["1.1.1.1", "8.8.8.8"], - "domains": [], - "magic_dns": true, - "base_domain": "example.com" - } -} +```yaml +server_url: http://127.0.0.1:8001 +listen_addr: 0.0.0.0:8001 +private_key_path: private.key +dns_config: + nameservers: + - 1.1.1.1 + - 8.8.8.8 + restricted_nameservers: + foo.bar.com: + - 1.1.1.1 + darp.headscale.net: + - 1.1.1.1 + - 8.8.8.8 + domains: [] + magic_dns: true + base_domain: example.com ``` + - `nameservers`: The list of DNS servers to use. - `domains`: Search domains to inject. - `magic_dns`: Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). Only works if there is at least a nameserver defined. -- `base_domain`: Defines the base domain to create the hostnames for MagicDNS. `base_domain` must be a FQDNs, without the trailing dot. The FQDN of the hosts will be `hostname.namespace.base_domain` (e.g., _myhost.mynamespace.example.com_). \ No newline at end of file +- `base_domain`: Defines the base domain to create the hostnames for MagicDNS. `base_domain` must be a FQDNs, without the trailing dot. The FQDN of the hosts will be `hostname.namespace.base_domain` (e.g., _myhost.mynamespace.example.com_). +- `restricted_nameservers`: Also known as Split DNS (see https://tailscale.com/kb/1054/dns/), list of search domains and the DNS you want to use for them. \ No newline at end of file From 41c5a0ddf56637c582098f220c06bb3180ef8799 Mon Sep 17 00:00:00 2001 From: Juan Font Date: Wed, 20 Oct 2021 09:35:56 +0200 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: Kristoffer Dalby --- app.go | 3 ++- cmd/headscale/cli/utils.go | 10 +++++----- docs/DNS.md | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app.go b/app.go index 0576e7f2..66e2a306 100644 --- a/app.go +++ b/app.go @@ -113,7 +113,8 @@ func NewHeadscale(cfg Config) (*Headscale, error) { if err != nil { return nil, err } - if h.cfg.DNSConfig.Routes == nil { // we might have routes already from Split DNS + // we might have routes already from Split DNS + if h.cfg.DNSConfig.Routes == nil { h.cfg.DNSConfig.Routes = make(map[string][]dnstype.Resolver) } for _, d := range magicDNSDomains { diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index 7b7d84ad..52c8d043 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -109,9 +109,9 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) { if len(dnsConfig.Nameservers) > 0 { dnsConfig.Routes = make(map[string][]dnstype.Resolver) restrictedDNS := viper.GetStringMapStringSlice("dns_config.restricted_nameservers") - for domain, resNameservers := range restrictedDNS { - resResolvers := make([]dnstype.Resolver, len(resNameservers)) - for index, nameserverStr := range resNameservers { + for domain, restrictedNameservers := range restrictedDNS { + restrictedResolvers := make([]dnstype.Resolver, len(restrictedNameservers)) + for index, nameserverStr := range restrictedNameservers { nameserver, err := netaddr.ParseIP(nameserverStr) if err != nil { log.Error(). @@ -119,11 +119,11 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) { Err(err). Msgf("Could not parse restricted nameserver IP: %s", nameserverStr) } - resResolvers[index] = dnstype.Resolver{ + restrictedResolvers[index] = dnstype.Resolver{ Addr: nameserver.String(), } } - dnsConfig.Routes[domain] = resResolvers + dnsConfig.Routes[domain] = restrictedResolvers } } else { log.Warn(). diff --git a/docs/DNS.md b/docs/DNS.md index 948f3c79..10f99b79 100644 --- a/docs/DNS.md +++ b/docs/DNS.md @@ -36,4 +36,4 @@ dns_config: - `domains`: Search domains to inject. - `magic_dns`: Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). Only works if there is at least a nameserver defined. - `base_domain`: Defines the base domain to create the hostnames for MagicDNS. `base_domain` must be a FQDNs, without the trailing dot. The FQDN of the hosts will be `hostname.namespace.base_domain` (e.g., _myhost.mynamespace.example.com_). -- `restricted_nameservers`: Also known as Split DNS (see https://tailscale.com/kb/1054/dns/), list of search domains and the DNS you want to use for them. \ No newline at end of file +- `restricted_nameservers`: Split DNS (see https://tailscale.com/kb/1054/dns/), list of search domains and the DNS to query for each one. \ No newline at end of file From 5159b6d08586e3b28f448b57495433f9a27e9a48 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Wed, 20 Oct 2021 23:10:59 +0200 Subject: [PATCH 3/4] Trying to fix arm64 --- .goreleaser.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index f7355104..7c5e853b 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -60,6 +60,9 @@ builds: - linux goarch: - arm64 + env: + - CGO_ENABLED=1 + - CC=aarch64-linux-gnu-gcc-9 main: ./cmd/headscale/headscale.go mod_timestamp: '{{ .CommitTimestamp }}' ldflags: From fb569b04832cb8c54dbc4d20e681697f7c48a6d3 Mon Sep 17 00:00:00 2001 From: Juan Font Alonso Date: Thu, 21 Oct 2021 17:47:10 +0200 Subject: [PATCH 4/4] Fixed ARM64 compiler name --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 7c5e853b..ad4fea70 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -62,7 +62,7 @@ builds: - arm64 env: - CGO_ENABLED=1 - - CC=aarch64-linux-gnu-gcc-9 + - CC=aarch64-linux-gnu-gcc main: ./cmd/headscale/headscale.go mod_timestamp: '{{ .CommitTimestamp }}' ldflags: