mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-26 03:01:02 +00:00
tstest/integration/vms: test DNS configuration
This uses a neat little tool to dump the output of DNS queries to standard out. This is the first end-to-end test of DNS that runs against actual linux systems. The /etc/resolv.conf test may look superflous, however this will help for correlating system state if one of the DNS tests fails. Signed-off-by: Christine Dodrill <xe@tailscale.com>
This commit is contained in:
parent
00b3c1c042
commit
0b9e938152
@ -43,6 +43,7 @@ type Server struct {
|
|||||||
DERPMap *tailcfg.DERPMap // nil means to use prod DERP map
|
DERPMap *tailcfg.DERPMap // nil means to use prod DERP map
|
||||||
RequireAuth bool
|
RequireAuth bool
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
DNSConfig *tailcfg.DNSConfig // nil means no DNS config
|
||||||
|
|
||||||
// ExplicitBaseURL or HTTPTestServer must be set.
|
// ExplicitBaseURL or HTTPTestServer must be set.
|
||||||
ExplicitBaseURL string // e.g. "http://127.0.0.1:1234" with no trailing URL
|
ExplicitBaseURL string // e.g. "http://127.0.0.1:1234" with no trailing URL
|
||||||
@ -453,6 +454,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey tail
|
|||||||
MachineAuthorized: machineAuthorized,
|
MachineAuthorized: machineAuthorized,
|
||||||
Addresses: allowedIPs,
|
Addresses: allowedIPs,
|
||||||
AllowedIPs: allowedIPs,
|
AllowedIPs: allowedIPs,
|
||||||
|
Hostinfo: *req.Hostinfo,
|
||||||
}
|
}
|
||||||
requireAuth := s.RequireAuth
|
requireAuth := s.RequireAuth
|
||||||
if requireAuth && s.nodeKeyAuthed[req.NodeKey] {
|
if requireAuth && s.nodeKeyAuthed[req.NodeKey] {
|
||||||
@ -691,6 +693,7 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse,
|
|||||||
Debug: &tailcfg.Debug{
|
Debug: &tailcfg.Debug{
|
||||||
DisableUPnP: "true",
|
DisableUPnP: "true",
|
||||||
},
|
},
|
||||||
|
DNSConfig: s.DNSConfig,
|
||||||
}
|
}
|
||||||
for _, p := range s.AllNodes() {
|
for _, p := range s.AllNodes() {
|
||||||
if p.StableID != node.StableID {
|
if p.StableID != node.StableID {
|
||||||
|
55
tstest/integration/vms/dns_tester.go
Normal file
55
tstest/integration/vms/dns_tester.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2021 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 ignore
|
||||||
|
|
||||||
|
// Command dns_tester exists in order to perform tests of our DNS
|
||||||
|
// configuration stack. This was written because the state of DNS
|
||||||
|
// in our target environments is so diverse that we need a little tool
|
||||||
|
// to do this test for us.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
target := flag.Arg(0)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
errCount := 0
|
||||||
|
wait := 25 * time.Millisecond
|
||||||
|
for range make([]struct{}, 5) {
|
||||||
|
err := lookup(ctx, target)
|
||||||
|
if err != nil {
|
||||||
|
errCount++
|
||||||
|
time.Sleep(wait)
|
||||||
|
wait = wait * 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup(ctx context.Context, target string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
hosts, err := net.LookupHost(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(os.Stdout).Encode(hosts)
|
||||||
|
return nil
|
||||||
|
}
|
@ -26,8 +26,10 @@ import (
|
|||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/tstest/integration"
|
"tailscale.com/tstest/integration"
|
||||||
"tailscale.com/tstest/integration/testcontrol"
|
"tailscale.com/tstest/integration/testcontrol"
|
||||||
|
"tailscale.com/types/dnstype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Harness struct {
|
type Harness struct {
|
||||||
@ -55,7 +57,17 @@ func newHarness(t *testing.T) *Harness {
|
|||||||
})
|
})
|
||||||
t.Logf("host:port: %s", ln.Addr())
|
t.Logf("host:port: %s", ln.Addr())
|
||||||
|
|
||||||
cs := &testcontrol.Server{}
|
cs := &testcontrol.Server{
|
||||||
|
DNSConfig: &tailcfg.DNSConfig{
|
||||||
|
// TODO: this is wrong.
|
||||||
|
// It is also only one of many configurations.
|
||||||
|
// Figure out how to scale it up.
|
||||||
|
Resolvers: []dnstype.Resolver{{Addr: "100.100.100.100"}, {Addr: "8.8.8.8"}},
|
||||||
|
Domains: []string{"record"},
|
||||||
|
Proxied: true,
|
||||||
|
ExtraRecords: []tailcfg.DNSRecord{{Name: "extratest.record", Type: "A", Value: "1.2.3.4"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
derpMap := integration.RunDERPAndSTUN(t, t.Logf, bindHost)
|
derpMap := integration.RunDERPAndSTUN(t, t.Logf, bindHost)
|
||||||
cs.DERPMap = derpMap
|
cs.DERPMap = derpMap
|
||||||
|
@ -624,6 +624,48 @@ func (h *Harness) testDistro(t *testing.T, d Distro, ipm ipMapping) {
|
|||||||
t.Fatalf("wanted %q from vm, got: %q", securePassword, msg)
|
t.Fatalf("wanted %q from vm, got: %q", securePassword, msg)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("dns-test", func(t *testing.T) {
|
||||||
|
t.Run("etc-resolv-conf", func(t *testing.T) {
|
||||||
|
sess := getSession(t, cli)
|
||||||
|
sess.Stdout = logger.FuncWriter(t.Logf)
|
||||||
|
sess.Stderr = logger.FuncWriter(t.Errorf)
|
||||||
|
if err := sess.Run("cat /etc/resolv.conf"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't get working directory: %v", err)
|
||||||
|
}
|
||||||
|
dir := t.TempDir()
|
||||||
|
run(t, cwd, "go", "build", "-o", filepath.Join(dir, "dns_tester"), "./dns_tester.go")
|
||||||
|
|
||||||
|
sftpCli, err := sftp.NewClient(cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't connect over sftp to copy binaries: %v", err)
|
||||||
|
}
|
||||||
|
defer sftpCli.Close()
|
||||||
|
|
||||||
|
copyFile(t, sftpCli, filepath.Join(dir, "dns_tester"), "/dns_tester")
|
||||||
|
|
||||||
|
for _, record := range []string{"extratest.record", "extratest"} {
|
||||||
|
t.Run(record, func(t *testing.T) {
|
||||||
|
sess := getSession(t, cli)
|
||||||
|
sess.Stderr = logger.FuncWriter(t.Errorf)
|
||||||
|
msg, err := sess.Output("/dns_tester " + record)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = bytes.TrimSpace(msg)
|
||||||
|
if want := []byte("1.2.3.4"); !bytes.Contains(msg, want) {
|
||||||
|
t.Fatalf("got: %q, want: %q", msg, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestCommands(t *testing.T, timeout time.Duration, cli *ssh.Client, batch []expect.Batcher) {
|
func runTestCommands(t *testing.T, timeout time.Duration, cli *ssh.Client, batch []expect.Batcher) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user