mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-03 10:31:59 +00:00
wgengine/router: dns: unify on *BSD, multimode on Linux, Magic DNS (#536)
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This commit is contained in:
committed by
GitHub
parent
6e8f0860af
commit
30bbbe9467
@@ -5,20 +5,14 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tailscale/wireguard-go/device"
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/atomicfile"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
@@ -31,6 +25,8 @@ type openbsdRouter struct {
|
||||
tunname string
|
||||
local netaddr.IPPrefix
|
||||
routes map[netaddr.IPPrefix]struct{}
|
||||
|
||||
dnsConfig DNSConfig
|
||||
}
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, _ *device.Device, tundev tun.Device) (Router, error) {
|
||||
@@ -159,112 +155,28 @@ func (r *openbsdRouter) Set(cfg *Config) error {
|
||||
r.local = localAddr
|
||||
r.routes = newRoutes
|
||||
|
||||
if err := r.replaceResolvConf(cfg.DNS, cfg.DNSDomains); err != nil {
|
||||
errq = fmt.Errorf("replacing resolv.conf failed: %v", err)
|
||||
if !r.dnsConfig.EquivalentTo(cfg.DNSConfig) {
|
||||
if err := dnsDirectUp(cfg.DNSConfig); err != nil {
|
||||
errq = fmt.Errorf("dns up: direct: %v", err)
|
||||
} else {
|
||||
r.dnsConfig = cfg.DNSConfig
|
||||
}
|
||||
}
|
||||
|
||||
return errq
|
||||
}
|
||||
|
||||
func (r *openbsdRouter) Close() error {
|
||||
out, err := cmd("ifconfig", r.tunname, "down").CombinedOutput()
|
||||
cleanup(r.logf, r.tunname)
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanup(logf logger.Logf, interfaceName string) {
|
||||
if err := dnsDirectDown(); err != nil {
|
||||
logf("dns down: direct: %v", err)
|
||||
}
|
||||
out, err := cmd("ifconfig", interfaceName, "down").CombinedOutput()
|
||||
if err != nil {
|
||||
r.logf("running ifconfig failed: %v\n%s", err, out)
|
||||
logf("ifconfig down: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
if err := r.restoreResolvConf(); err != nil {
|
||||
r.logf("failed to restore system resolv.conf: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
tsConf = "/etc/resolv.tailscale.conf"
|
||||
backupConf = "/etc/resolv.pre-tailscale-backup.conf"
|
||||
resolvConf = "/etc/resolv.conf"
|
||||
)
|
||||
|
||||
func (r *openbsdRouter) replaceResolvConf(servers []netaddr.IP, domains []string) error {
|
||||
if len(servers) == 0 {
|
||||
return r.restoreResolvConf()
|
||||
}
|
||||
|
||||
// Write the tsConf file.
|
||||
buf := new(bytes.Buffer)
|
||||
fmt.Fprintf(buf, "# resolv.conf(5) file generated by tailscale\n")
|
||||
fmt.Fprintf(buf, "# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN\n\n")
|
||||
for _, ns := range servers {
|
||||
fmt.Fprintf(buf, "nameserver %s\n", ns)
|
||||
}
|
||||
if len(domains) > 0 {
|
||||
fmt.Fprintf(buf, "search "+strings.Join(domains, " ")+"\n")
|
||||
}
|
||||
tf, err := ioutil.TempFile(filepath.Dir(tsConf), filepath.Base(tsConf)+".*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tempName := tf.Name()
|
||||
tf.Close()
|
||||
|
||||
if err := atomicfile.WriteFile(tempName, buf.Bytes(), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(tempName, tsConf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if linkPath, err := os.Readlink(resolvConf); err != nil {
|
||||
// Remove any old backup that may exist.
|
||||
os.Remove(backupConf)
|
||||
|
||||
// Backup the existing /etc/resolv.conf file.
|
||||
contents, err := ioutil.ReadFile(resolvConf)
|
||||
if os.IsNotExist(err) {
|
||||
// No existing /etc/resolv.conf file to backup.
|
||||
// Nothing to do.
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := atomicfile.WriteFile(backupConf, contents, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if linkPath != tsConf {
|
||||
// Backup the existing symlink.
|
||||
os.Remove(backupConf)
|
||||
if err := os.Symlink(linkPath, backupConf); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Nothing to do, resolvConf already points to tsConf.
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Remove(resolvConf)
|
||||
if err := os.Symlink(tsConf, resolvConf); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *openbsdRouter) restoreResolvConf() error {
|
||||
if _, err := os.Stat(backupConf); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil // No backup resolv.conf to restore.
|
||||
}
|
||||
return err
|
||||
}
|
||||
if ln, err := os.Readlink(resolvConf); err != nil {
|
||||
return err
|
||||
} else if ln != tsConf {
|
||||
return fmt.Errorf("resolv.conf is not a symlink to %s", tsConf)
|
||||
}
|
||||
if err := os.Rename(backupConf, resolvConf); err != nil {
|
||||
return err
|
||||
}
|
||||
os.Remove(tsConf) // Best effort removal.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user