mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-07 08:44:38 +00:00

all: clean up logging noise Change-Id: Id7a777b5697fb63cf8690fe971e1ece97427f678 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
182 lines
4.4 KiB
Go
182 lines
4.4 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// TODO: man 6 ndb | grep -e 'suffix.*same line'
|
|
// to detect Russ's https://9fans.topicbox.com/groups/9fans/T9c9d81b5801a0820/ndb-suffix-specific-dns-changes
|
|
|
|
package dns
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"net/netip"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"tailscale.com/control/controlknobs"
|
|
"tailscale.com/health"
|
|
"tailscale.com/types/logger"
|
|
"tailscale.com/util/set"
|
|
)
|
|
|
|
func NewOSConfigurator(logf logger.Logf, ht *health.Tracker, knobs *controlknobs.Knobs, interfaceName string) (OSConfigurator, error) {
|
|
return &plan9DNSManager{
|
|
logf: logf,
|
|
ht: ht,
|
|
knobs: knobs,
|
|
}, nil
|
|
}
|
|
|
|
type plan9DNSManager struct {
|
|
logf logger.Logf
|
|
ht *health.Tracker
|
|
knobs *controlknobs.Knobs
|
|
}
|
|
|
|
// netNDBBytesWithoutTailscale returns raw (the contents of /net/ndb) with any
|
|
// Tailscale bits removed.
|
|
func netNDBBytesWithoutTailscale(raw []byte) ([]byte, error) {
|
|
var ret bytes.Buffer
|
|
bs := bufio.NewScanner(bytes.NewReader(raw))
|
|
removeLine := set.Set[string]{}
|
|
for bs.Scan() {
|
|
t := bs.Text()
|
|
if rest, ok := strings.CutPrefix(t, "#tailscaled-added-line:"); ok {
|
|
removeLine.Add(strings.TrimSpace(rest))
|
|
continue
|
|
}
|
|
trimmed := strings.TrimSpace(t)
|
|
if removeLine.Contains(trimmed) {
|
|
removeLine.Delete(trimmed)
|
|
continue
|
|
}
|
|
|
|
// Also remove any DNS line referencing *.ts.net. This is
|
|
// Tailscale-specific (and won't work with, say, Headscale), but
|
|
// the Headscale case will be covered by the #tailscaled-added-line
|
|
// logic above, assuming the user didn't delete those comments.
|
|
if (strings.HasPrefix(trimmed, "dns=") || strings.Contains(trimmed, "dnsdomain=")) &&
|
|
strings.HasSuffix(trimmed, ".ts.net") {
|
|
continue
|
|
}
|
|
|
|
ret.WriteString(t)
|
|
ret.WriteByte('\n')
|
|
}
|
|
return ret.Bytes(), bs.Err()
|
|
}
|
|
|
|
// setNDBSuffix adds lines to tsFree (the contents of /net/ndb already cleaned
|
|
// of Tailscale-added lines) to add the optional DNS search domain (e.g.
|
|
// "foo.ts.net") and DNS server to it.
|
|
func setNDBSuffix(tsFree []byte, suffix string) []byte {
|
|
suffix = strings.TrimSuffix(suffix, ".")
|
|
if suffix == "" {
|
|
return tsFree
|
|
}
|
|
var buf bytes.Buffer
|
|
bs := bufio.NewScanner(bytes.NewReader(tsFree))
|
|
var added []string
|
|
addLine := func(s string) {
|
|
added = append(added, strings.TrimSpace(s))
|
|
buf.WriteString(s)
|
|
}
|
|
for bs.Scan() {
|
|
buf.Write(bs.Bytes())
|
|
buf.WriteByte('\n')
|
|
|
|
t := bs.Text()
|
|
if suffix != "" && len(added) == 0 && strings.HasPrefix(t, "\tdns=") {
|
|
addLine(fmt.Sprintf("\tdns=100.100.100.100 suffix=%s\n", suffix))
|
|
addLine(fmt.Sprintf("\tdnsdomain=%s\n", suffix))
|
|
}
|
|
}
|
|
bufTrim := bytes.TrimLeftFunc(buf.Bytes(), unicode.IsSpace)
|
|
if len(added) == 0 {
|
|
return bufTrim
|
|
}
|
|
var ret bytes.Buffer
|
|
for _, s := range added {
|
|
ret.WriteString("#tailscaled-added-line: ")
|
|
ret.WriteString(s)
|
|
ret.WriteString("\n")
|
|
}
|
|
ret.WriteString("\n")
|
|
ret.Write(bufTrim)
|
|
return ret.Bytes()
|
|
}
|
|
|
|
func (m *plan9DNSManager) SetDNS(c OSConfig) error {
|
|
ndbOnDisk, err := os.ReadFile("/net/ndb")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tsFree, err := netNDBBytesWithoutTailscale(ndbOnDisk)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var suffix string
|
|
if len(c.SearchDomains) > 0 {
|
|
suffix = string(c.SearchDomains[0])
|
|
}
|
|
|
|
newBuf := setNDBSuffix(tsFree, suffix)
|
|
if !bytes.Equal(newBuf, ndbOnDisk) {
|
|
if err := os.WriteFile("/net/ndb", newBuf, 0644); err != nil {
|
|
return fmt.Errorf("writing /net/ndb: %w", err)
|
|
}
|
|
if f, err := os.OpenFile("/net/dns", os.O_RDWR, 0); err == nil {
|
|
if _, err := io.WriteString(f, "refresh\n"); err != nil {
|
|
f.Close()
|
|
return fmt.Errorf("/net/dns refresh write: %w", err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
return fmt.Errorf("/net/dns refresh close: %w", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *plan9DNSManager) SupportsSplitDNS() bool { return false }
|
|
|
|
func (m *plan9DNSManager) Close() error {
|
|
// TODO(bradfitz): remove the Tailscale bits from /net/ndb ideally
|
|
return nil
|
|
}
|
|
|
|
var dnsRegex = regexp.MustCompile(`\bdns=(\d+\.\d+\.\d+\.\d+)\b`)
|
|
|
|
func (m *plan9DNSManager) GetBaseConfig() (OSConfig, error) {
|
|
var oc OSConfig
|
|
f, err := os.Open("/net/ndb")
|
|
if err != nil {
|
|
return oc, err
|
|
}
|
|
defer f.Close()
|
|
bs := bufio.NewScanner(f)
|
|
for bs.Scan() {
|
|
m := dnsRegex.FindSubmatch(bs.Bytes())
|
|
if m == nil {
|
|
continue
|
|
}
|
|
addr, err := netip.ParseAddr(string(m[1]))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
oc.Nameservers = append(oc.Nameservers, addr)
|
|
}
|
|
if err := bs.Err(); err != nil {
|
|
return oc, err
|
|
}
|
|
|
|
return oc, nil
|
|
}
|