mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	Add support for NextDNS resolver
This commit is contained in:
		
							parent
							
								
									c0884f94b8
								
							
						
					
					
						commit
						6d3ede1367
					
				@ -27,6 +27,7 @@
 | 
				
			|||||||
- Fix some DNS config issues [#660](https://github.com/juanfont/headscale/issues/660)
 | 
					- Fix some DNS config issues [#660](https://github.com/juanfont/headscale/issues/660)
 | 
				
			||||||
- Make it possible to disable TS2019 with build flag [#928](https://github.com/juanfont/headscale/pull/928)
 | 
					- Make it possible to disable TS2019 with build flag [#928](https://github.com/juanfont/headscale/pull/928)
 | 
				
			||||||
- Fix OIDC registration issues [#960](https://github.com/juanfont/headscale/pull/960) and [#971](https://github.com/juanfont/headscale/pull/971)
 | 
					- Fix OIDC registration issues [#960](https://github.com/juanfont/headscale/pull/960) and [#971](https://github.com/juanfont/headscale/pull/971)
 | 
				
			||||||
 | 
					- Add support for specifying NextDNS DNS-over-HTTPS resolver [#940](https://github.com/juanfont/headscale/pull/940)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.16.4 (2022-08-21)
 | 
					## 0.16.4 (2022-08-21)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -214,6 +214,18 @@ dns_config:
 | 
				
			|||||||
  nameservers:
 | 
					  nameservers:
 | 
				
			||||||
    - 1.1.1.1
 | 
					    - 1.1.1.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # NextDNS (see https://tailscale.com/kb/1218/nextdns/).
 | 
				
			||||||
 | 
					  # "abc123" is example NextDNS ID, replace with yours.
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # With metadata sharing:
 | 
				
			||||||
 | 
					  # nameservers:
 | 
				
			||||||
 | 
					  #   - https://dns.nextdns.io/abc123
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # Without metadata sharing:
 | 
				
			||||||
 | 
					  # nameservers:
 | 
				
			||||||
 | 
					  #   - 2a07:a8c0::ab:c123
 | 
				
			||||||
 | 
					  #   - 2a07:a8c1::ab:c123
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Split DNS (see https://tailscale.com/kb/1054/dns/),
 | 
					  # Split DNS (see https://tailscale.com/kb/1054/dns/),
 | 
				
			||||||
  # list of search domains and the DNS to query for each one.
 | 
					  # list of search domains and the DNS to query for each one.
 | 
				
			||||||
  #
 | 
					  #
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								config.go
									
									
									
									
									
								
							@ -383,10 +383,21 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) {
 | 
				
			|||||||
		if viper.IsSet("dns_config.nameservers") {
 | 
							if viper.IsSet("dns_config.nameservers") {
 | 
				
			||||||
			nameserversStr := viper.GetStringSlice("dns_config.nameservers")
 | 
								nameserversStr := viper.GetStringSlice("dns_config.nameservers")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			nameservers := make([]netip.Addr, len(nameserversStr))
 | 
								nameservers := []netip.Addr{}
 | 
				
			||||||
			resolvers := make([]*dnstype.Resolver, len(nameserversStr))
 | 
								resolvers := []*dnstype.Resolver{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for index, nameserverStr := range nameserversStr {
 | 
								for _, nameserverStr := range nameserversStr {
 | 
				
			||||||
 | 
									// Search for explicit DNS-over-HTTPS resolvers
 | 
				
			||||||
 | 
									if strings.HasPrefix(nameserverStr, "https://") {
 | 
				
			||||||
 | 
										resolvers = append(resolvers, &dnstype.Resolver{
 | 
				
			||||||
 | 
											Addr: nameserverStr,
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// This nameserver can not be parsed as an IP address
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Parse nameserver as a regular IP
 | 
				
			||||||
				nameserver, err := netip.ParseAddr(nameserverStr)
 | 
									nameserver, err := netip.ParseAddr(nameserverStr)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					log.Error().
 | 
										log.Error().
 | 
				
			||||||
@ -395,10 +406,10 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) {
 | 
				
			|||||||
						Msgf("Could not parse nameserver IP: %s", nameserverStr)
 | 
											Msgf("Could not parse nameserver IP: %s", nameserverStr)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				nameservers[index] = nameserver
 | 
									nameservers = append(nameservers, nameserver)
 | 
				
			||||||
				resolvers[index] = &dnstype.Resolver{
 | 
									resolvers = append(resolvers, &dnstype.Resolver{
 | 
				
			||||||
					Addr: nameserver.String(),
 | 
										Addr: nameserver.String(),
 | 
				
			||||||
				}
 | 
									})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			dnsConfig.Nameservers = nameservers
 | 
								dnsConfig.Nameservers = nameservers
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								dns.go
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								dns.go
									
									
									
									
									
								
							@ -3,11 +3,13 @@ package headscale
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/netip"
 | 
						"net/netip"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mapset "github.com/deckarep/golang-set/v2"
 | 
						mapset "github.com/deckarep/golang-set/v2"
 | 
				
			||||||
	"go4.org/netipx"
 | 
						"go4.org/netipx"
 | 
				
			||||||
	"tailscale.com/tailcfg"
 | 
						"tailscale.com/tailcfg"
 | 
				
			||||||
 | 
						"tailscale.com/types/dnstype"
 | 
				
			||||||
	"tailscale.com/util/dnsname"
 | 
						"tailscale.com/util/dnsname"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -20,6 +22,10 @@ const (
 | 
				
			|||||||
	ipv6AddressLength = 128
 | 
						ipv6AddressLength = 128
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						nextDNSDoHPrefix = "https://dns.nextdns.io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// generateMagicDNSRootDomains generates a list of DNS entries to be included in `Routes` in `MapResponse`.
 | 
					// generateMagicDNSRootDomains generates a list of DNS entries to be included in `Routes` in `MapResponse`.
 | 
				
			||||||
// This list of reverse DNS entries instructs the OS on what subnets and domains the Tailscale embedded DNS
 | 
					// This list of reverse DNS entries instructs the OS on what subnets and domains the Tailscale embedded DNS
 | 
				
			||||||
// server (listening in 100.100.100.100 udp/53) should be used for.
 | 
					// server (listening in 100.100.100.100 udp/53) should be used for.
 | 
				
			||||||
@ -152,16 +158,39 @@ func generateIPv6DNSRootDomain(ipPrefix netip.Prefix) []dnsname.FQDN {
 | 
				
			|||||||
	return fqdns
 | 
						return fqdns
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// If any nextdns DoH resolvers are present in the list of resolvers it will
 | 
				
			||||||
 | 
					// take metadata from the machine metadata and instruct tailscale to add it
 | 
				
			||||||
 | 
					// to the requests. This makes it possible to identify from which device the
 | 
				
			||||||
 | 
					// requests come in the NextDNS dashboard.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This will produce a resolver like:
 | 
				
			||||||
 | 
					// `https://dns.nextdns.io/<nextdns-id>?device_name=node-name&device_model=linux&device_ip=100.64.0.1`
 | 
				
			||||||
 | 
					func addNextDNSMetadata(resolvers []*dnstype.Resolver, machine Machine) {
 | 
				
			||||||
 | 
						for _, resolver := range resolvers {
 | 
				
			||||||
 | 
							if strings.HasPrefix(resolver.Addr, nextDNSDoHPrefix) {
 | 
				
			||||||
 | 
								attrs := url.Values{
 | 
				
			||||||
 | 
									"device_name":  []string{machine.Hostname},
 | 
				
			||||||
 | 
									"device_model": []string{machine.HostInfo.OS},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if len(machine.IPAddresses) > 0 {
 | 
				
			||||||
 | 
									attrs.Add("device_ip", machine.IPAddresses[0].String())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								resolver.Addr = fmt.Sprintf("%s?%s", resolver.Addr, attrs.Encode())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getMapResponseDNSConfig(
 | 
					func getMapResponseDNSConfig(
 | 
				
			||||||
	dnsConfigOrig *tailcfg.DNSConfig,
 | 
						dnsConfigOrig *tailcfg.DNSConfig,
 | 
				
			||||||
	baseDomain string,
 | 
						baseDomain string,
 | 
				
			||||||
	machine Machine,
 | 
						machine Machine,
 | 
				
			||||||
	peers Machines,
 | 
						peers Machines,
 | 
				
			||||||
) *tailcfg.DNSConfig {
 | 
					) *tailcfg.DNSConfig {
 | 
				
			||||||
	var dnsConfig *tailcfg.DNSConfig
 | 
						var dnsConfig *tailcfg.DNSConfig = dnsConfigOrig.Clone()
 | 
				
			||||||
	if dnsConfigOrig != nil && dnsConfigOrig.Proxied { // if MagicDNS is enabled
 | 
						if dnsConfigOrig != nil && dnsConfigOrig.Proxied { // if MagicDNS is enabled
 | 
				
			||||||
		// Only inject the Search Domain of the current namespace - shared nodes should use their full FQDN
 | 
							// Only inject the Search Domain of the current namespace - shared nodes should use their full FQDN
 | 
				
			||||||
		dnsConfig = dnsConfigOrig.Clone()
 | 
					 | 
				
			||||||
		dnsConfig.Domains = append(
 | 
							dnsConfig.Domains = append(
 | 
				
			||||||
			dnsConfig.Domains,
 | 
								dnsConfig.Domains,
 | 
				
			||||||
			fmt.Sprintf(
 | 
								fmt.Sprintf(
 | 
				
			||||||
@ -184,5 +213,7 @@ func getMapResponseDNSConfig(
 | 
				
			|||||||
		dnsConfig = dnsConfigOrig
 | 
							dnsConfig = dnsConfigOrig
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addNextDNSMetadata(dnsConfig.Resolvers, machine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dnsConfig
 | 
						return dnsConfig
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user