mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-26 11:11:01 +00:00
net/dns: add more of DNS manager for plan9, tests, plumb netmon/tun name around more
Change-Id: Ia542d7c69f3fbcd2571e2da8b04ad34ec0e2645d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
abb77602a4
commit
835c7e1e90
@ -748,6 +748,12 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
|
||||
return false, err
|
||||
}
|
||||
|
||||
if runtime.GOOS == "plan9" {
|
||||
// TODO(bradfitz): why don't we do this on all platforms?
|
||||
// We should. Doing it just on plan9 for now conservatively.
|
||||
sys.NetMon.Get().SetTailscaleInterfaceName(devName)
|
||||
}
|
||||
|
||||
r, err := router.New(logf, dev, sys.NetMon.Get(), sys.HealthTracker())
|
||||
if err != nil {
|
||||
dev.Close()
|
||||
|
@ -9,14 +9,18 @@ package dns
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"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) {
|
||||
@ -33,13 +37,113 @@ type plan9DNSManager struct {
|
||||
knobs *controlknobs.Knobs
|
||||
}
|
||||
|
||||
func (m *plan9DNSManager) SetDNS(c OSConfig) error {
|
||||
var buf bytes.Buffer
|
||||
bw := bufio.NewWriter(&buf)
|
||||
c.WriteToBufioWriter(bw)
|
||||
bw.Flush()
|
||||
// netNDBWithoutTailscale returns /net/ndb with any Tailscale
|
||||
// bits removed.
|
||||
func netNDBWithoutTailscale() ([]byte, error) {
|
||||
raw, err := os.ReadFile("/net/ndb")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return netNDBBytesWithoutTailscale(raw)
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
if len(added) == 0 || true {
|
||||
return buf.Bytes()
|
||||
}
|
||||
var ret bytes.Buffer
|
||||
for _, s := range added {
|
||||
ret.WriteString("#tailscaled-added-line: ")
|
||||
ret.WriteString(s)
|
||||
ret.WriteString("\n")
|
||||
}
|
||||
ret.WriteString("\n")
|
||||
ret.Write(buf.Bytes())
|
||||
return ret.Bytes()
|
||||
}
|
||||
|
||||
func (m *plan9DNSManager) SetDNS(c OSConfig) error {
|
||||
tsFree, err := netNDBWithoutTailscale()
|
||||
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, tsFree) {
|
||||
log.Printf("XXX need to write /net/ndb of %q", newBuf)
|
||||
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_WRONLY, 0); err == nil {
|
||||
defer f.Close()
|
||||
if _, err := io.WriteString(f, "refresh\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("XXX: TODO: plan9 SetDNS: %s", buf.Bytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
86
net/dns/manager_plan9_test.go
Normal file
86
net/dns/manager_plan9_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build plan9
|
||||
|
||||
package dns
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNetNDBBytesWithoutTailscale(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
raw: "",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "no-tailscale",
|
||||
raw: "# This is a comment\nip=10.0.2.15 ipmask=255.255.255.0 ipgw=10.0.2.2\n\tsys=gnot\n",
|
||||
want: "# This is a comment\nip=10.0.2.15 ipmask=255.255.255.0 ipgw=10.0.2.2\n\tsys=gnot\n",
|
||||
},
|
||||
{
|
||||
name: "remove-by-comments",
|
||||
raw: "# This is a comment\n#tailscaled-added-line: dns=100.100.100.100\nip=10.0.2.15 ipmask=255.255.255.0 ipgw=10.0.2.2\n\tdns=100.100.100.100\n\tsys=gnot\n",
|
||||
want: "# This is a comment\nip=10.0.2.15 ipmask=255.255.255.0 ipgw=10.0.2.2\n\tsys=gnot\n",
|
||||
},
|
||||
{
|
||||
name: "remove-by-ts.net",
|
||||
raw: "Some line\n\tdns=100.100.100.100 suffix=foo.ts.net\n\tfoo=bar\n",
|
||||
want: "Some line\n\tfoo=bar\n",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := netNDBBytesWithoutTailscale([]byte(tt.raw))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(got) != tt.want {
|
||||
t.Errorf("GOT:\n%s\n\nWANT:\n%s\n", string(got), tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetNDBSuffix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
raw: "",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "set",
|
||||
raw: "ip=10.0.2.15 ipmask=255.255.255.0 ipgw=10.0.2.2\n\tsys=gnot\n\tdns=100.100.100.100\n\n# foo\n",
|
||||
want: `#tailscaled-added-line: dns=100.100.100.100 suffix=foo.ts.net
|
||||
#tailscaled-added-line: dnsdomain=foo.ts.net
|
||||
|
||||
ip=10.0.2.15 ipmask=255.255.255.0 ipgw=10.0.2.2
|
||||
sys=gnot
|
||||
dns=100.100.100.100
|
||||
dns=100.100.100.100 suffix=foo.ts.net
|
||||
dnsdomain=foo.ts.net
|
||||
|
||||
# foo
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := setNDBSuffix([]byte(tt.raw), "foo.ts.net")
|
||||
if string(got) != tt.want {
|
||||
t.Errorf("wrong value\n GOT %q:\n%s\n\nWANT %q:\n%s\n", got, got, tt.want, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -491,7 +491,7 @@ func (m *Monitor) IsMajorChangeFrom(s1, s2 *State) bool {
|
||||
return true
|
||||
}
|
||||
for iname, i := range s1.Interface {
|
||||
if iname == m.tsIfName || iname == "/net/ipifc/2" {
|
||||
if iname == m.tsIfName {
|
||||
// Ignore changes in the Tailscale interface itself.
|
||||
continue
|
||||
}
|
||||
|
@ -454,9 +454,6 @@ func isTailscaleInterface(name string, ips []netip.Prefix) bool {
|
||||
// macOS NetworkExtensions and utun devices.
|
||||
return true
|
||||
}
|
||||
if runtime.GOOS == "plan9" && (hasTailscaleIP(ips) || name == "/net/ipifc/2") { // XXX fix; use tun name
|
||||
return true
|
||||
}
|
||||
return name == "Tailscale" || // as it is on Windows
|
||||
strings.HasPrefix(name, "tailscale") // TODO: use --tun flag value, etc; see TODO in method doc
|
||||
}
|
||||
@ -475,11 +472,11 @@ func getState(optTSInterfaceName string) (*State, error) {
|
||||
Interface: make(map[string]Interface),
|
||||
}
|
||||
if err := ForeachInterface(func(ni Interface, pfxs []netip.Prefix) {
|
||||
isTS := optTSInterfaceName != "" && ni.Name == optTSInterfaceName
|
||||
isTSInterfaceName := optTSInterfaceName != "" && ni.Name == optTSInterfaceName
|
||||
ifUp := ni.IsUp()
|
||||
s.Interface[ni.Name] = ni
|
||||
s.InterfaceIPs[ni.Name] = append(s.InterfaceIPs[ni.Name], pfxs...)
|
||||
if !ifUp || isTS || isTailscaleInterface(ni.Name, pfxs) {
|
||||
if !ifUp || isTSInterfaceName || isTailscaleInterface(ni.Name, pfxs) {
|
||||
return
|
||||
}
|
||||
for _, pfx := range pfxs {
|
||||
|
Loading…
x
Reference in New Issue
Block a user