mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-30 05:25:35 +00:00
85 lines
2.5 KiB
Go
85 lines
2.5 KiB
Go
|
// 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.
|
||
|
|
||
|
// +build linux freebsd
|
||
|
|
||
|
package router
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
)
|
||
|
|
||
|
// resolvconfIsActive indicates whether the system appears to be using resolvconf.
|
||
|
// If this is true, then dnsManualUp should be avoided:
|
||
|
// resolvconf has exclusive ownership of /etc/resolv.conf.
|
||
|
func resolvconfIsActive() bool {
|
||
|
// Sanity-check first: if there is no resolvconf binary, then this is fruitless.
|
||
|
//
|
||
|
// However, this binary may be a shim like the one systemd-resolved provides.
|
||
|
// Such a shim may not behave as expected: in particular, systemd-resolved
|
||
|
// does not seem to respect the exclusive mode -x, saying:
|
||
|
// -x Send DNS traffic preferably over this interface
|
||
|
// whereas e.g. openresolv sends DNS traffix _exclusively_ over that interface,
|
||
|
// or not at all (in case of another exclusive-mode request later in time).
|
||
|
//
|
||
|
// Moreover, resolvconf may be installed but unused, in which case we should
|
||
|
// not use it either, lest we clobber existing configuration.
|
||
|
//
|
||
|
// To handle all the above correctly, we scan the comments in /etc/resolv.conf
|
||
|
// to ensure that it was generated by a resolvconf implementation.
|
||
|
_, err := exec.LookPath("resolvconf")
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
f, err := os.Open("/etc/resolv.conf")
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
scanner := bufio.NewScanner(f)
|
||
|
for scanner.Scan() {
|
||
|
line := scanner.Bytes()
|
||
|
// Look for the word "resolvconf" until comments end.
|
||
|
if len(line) > 0 && line[0] != '#' {
|
||
|
return false
|
||
|
}
|
||
|
if bytes.Contains(line, []byte("resolvconf")) {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// dnsResolvconfUp invokes the resolvconf binary to associate
|
||
|
// the given DNS configuration the Tailscale interface.
|
||
|
func dnsResolvconfUp(config DNSConfig, interfaceName string) error {
|
||
|
stdin := new(bytes.Buffer)
|
||
|
dnsWriteConfig(stdin, config.Nameservers, config.Domains) // dns_direct.go
|
||
|
|
||
|
cmd := exec.Command("resolvconf", "-m", "0", "-x", "-a", interfaceName+".inet")
|
||
|
cmd.Stdin = stdin
|
||
|
out, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("running %s: %s", cmd, out)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// dnsResolvconfDown undoes the action of dnsResolvconfUp.
|
||
|
func dnsResolvconfDown(interfaceName string) error {
|
||
|
cmd := exec.Command("resolvconf", "-f", "-d", interfaceName+".inet")
|
||
|
out, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("running %s: %s", cmd, out)
|
||
|
}
|
||
|
return nil
|
||
|
}
|