wgengine/router/dns: create
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>dshynkev/dns-refactor
parent
1f923124bf
commit
d923a3d5ee
|
@ -2,23 +2,29 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package router
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSConfig is the subset of Config that contains DNS parameters.
|
// Config is the subset of router.Config that contains DNS parameters.
|
||||||
type DNSConfig struct {
|
type DNSConfig struct {
|
||||||
// Nameservers are the IP addresses of the nameservers to use.
|
// Nameservers are the IP addresses of the nameservers to use.
|
||||||
Nameservers []netaddr.IP
|
Nameservers []netaddr.IP
|
||||||
// Domains are the search domains to use.
|
// Domains are the search domains to use.
|
||||||
Domains []string
|
Domains []string
|
||||||
|
// PerDomain indicates whether it is preferred to use Nameservers
|
||||||
|
// only for queries for subdomains of Domains.
|
||||||
|
//
|
||||||
|
// Note that Nameservers may still be applied to all queries
|
||||||
|
// if the selected configuration mode does not support per-domain settings.
|
||||||
|
PerDomain bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// EquivalentTo determines whether its argument and receiver
|
// EquivalentTo determines whether its argument and receiver
|
||||||
// represent equivalent DNS configurations (then DNS reconfig is a no-op).
|
// represent equivalent DNS configurations (then DNS reconfig is a no-op).
|
||||||
func (lhs DNSConfig) EquivalentTo(rhs DNSConfig) bool {
|
func (lhs Config) EquivalentTo(rhs Config) bool {
|
||||||
if len(lhs.Nameservers) != len(rhs.Nameservers) {
|
if len(lhs.Nameservers) != len(rhs.Nameservers) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -27,6 +33,10 @@ func (lhs DNSConfig) EquivalentTo(rhs DNSConfig) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lhs.PerDomain != rhs.PerDomain {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// With how we perform resolution order shouldn't matter,
|
// With how we perform resolution order shouldn't matter,
|
||||||
// but it is unlikely that we will encounter different orders.
|
// but it is unlikely that we will encounter different orders.
|
||||||
for i, server := range lhs.Nameservers {
|
for i, server := range lhs.Nameservers {
|
||||||
|
@ -35,6 +45,7 @@ func (lhs DNSConfig) EquivalentTo(rhs DNSConfig) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The order of domains, on the other hand, is significant.
|
||||||
for i, domain := range lhs.Domains {
|
for i, domain := range lhs.Domains {
|
||||||
if rhs.Domains[i] != domain {
|
if rhs.Domains[i] != domain {
|
||||||
return false
|
return false
|
|
@ -25,8 +25,8 @@ const (
|
||||||
resolvConf = "/etc/resolv.conf"
|
resolvConf = "/etc/resolv.conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dnsWriteConfig writes DNS configuration in resolv.conf format to the given writer.
|
// writeResolvConf writes DNS configuration in resolv.conf format to the given writer.
|
||||||
func dnsWriteConfig(w io.Writer, servers []netaddr.IP, domains []string) {
|
func writeResolvConf(w io.Writer, servers []netaddr.IP, domains []string) {
|
||||||
io.WriteString(w, "# resolv.conf(5) file generated by tailscale\n")
|
io.WriteString(w, "# resolv.conf(5) file generated by tailscale\n")
|
||||||
io.WriteString(w, "# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN\n\n")
|
io.WriteString(w, "# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN\n\n")
|
||||||
for _, ns := range servers {
|
for _, ns := range servers {
|
||||||
|
@ -44,8 +44,8 @@ func dnsWriteConfig(w io.Writer, servers []netaddr.IP, domains []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dnsReadConfig reads DNS configuration from /etc/resolv.conf.
|
// readResolvConf reads DNS configuration from /etc/resolv.conf.
|
||||||
func dnsReadConfig() (DNSConfig, error) {
|
func readResolvConf() (DNSConfig, error) {
|
||||||
var config DNSConfig
|
var config DNSConfig
|
||||||
|
|
||||||
f, err := os.Open("/etc/resolv.conf")
|
f, err := os.Open("/etc/resolv.conf")
|
||||||
|
@ -89,7 +89,7 @@ func dnsReadConfig() (DNSConfig, error) {
|
||||||
func dnsDirectUp(config DNSConfig) error {
|
func dnsDirectUp(config DNSConfig) error {
|
||||||
// Write the tsConf file.
|
// Write the tsConf file.
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
dnsWriteConfig(buf, config.Nameservers, config.Domains)
|
writeResolvConf(buf, config.Nameservers, config.Domains)
|
||||||
if err := atomicfile.WriteFile(tsConf, buf.Bytes(), 0644); err != nil {
|
if err := atomicfile.WriteFile(tsConf, buf.Bytes(), 0644); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tailscale.com/types/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setTimeout is the time interval within which Manager.Set should complete.
|
||||||
|
//
|
||||||
|
// This is particularly useful because certain conditions can cause indefinite hangs
|
||||||
|
// (such as improper dbus auth followed by contextless dbus.Object.Call).
|
||||||
|
// Such operations should be wrapped in a timeout context.
|
||||||
|
const setTimeout = time.Second
|
||||||
|
|
||||||
|
type managerImpl interface {
|
||||||
|
Set(Config) error
|
||||||
|
Get() Config
|
||||||
|
Reset() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Manager struct {
|
||||||
|
impl managerImpl
|
||||||
|
oldConfig Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewManager(logf logger.Logf, interfaceName string) *Manager {
|
||||||
|
return &Manager{
|
||||||
|
impl: newManager(logf, interfaceName),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) Up(config Config) error {
|
||||||
|
if len(config.Nameservers) == 0 {
|
||||||
|
return m.impl.Down()
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.EquivalentTo(m.oldConfig) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := m.impl.Up(config)
|
||||||
|
if err == nil {
|
||||||
|
m.oldConfig = config
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) Down() error {
|
||||||
|
return m.impl.Down()
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/tailscale/wireguard-go/tun"
|
"github.com/tailscale/wireguard-go/tun"
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/wgengine/router/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Router is responsible for managing the system network stack.
|
// Router is responsible for managing the system network stack.
|
||||||
|
@ -72,7 +73,7 @@ type Config struct {
|
||||||
LocalAddrs []netaddr.IPPrefix
|
LocalAddrs []netaddr.IPPrefix
|
||||||
Routes []netaddr.IPPrefix // routes to point into the Tailscale interface
|
Routes []netaddr.IPPrefix // routes to point into the Tailscale interface
|
||||||
|
|
||||||
DNSConfig
|
DNS dns.Config
|
||||||
|
|
||||||
// Linux-only things below, ignored on other platforms.
|
// Linux-only things below, ignored on other platforms.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue