mirror of https://github.com/tailscale/tailscale/
ipn: fix netmap change tracking and dns map generation (#609)
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>pull/613/head
parent
3e3c24b8f6
commit
c7582dc234
@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
// Code generated by tailscale.com/cmd/cloner -type Persist; DO NOT EDIT.
|
||||
|
||||
package controlclient
|
||||
|
||||
import ()
|
||||
|
||||
// Clone makes a deep copy of Persist.
|
||||
// The result aliases no memory with the original.
|
||||
func (src *Persist) Clone() *Persist {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dst := new(Persist)
|
||||
*dst = *src
|
||||
return dst
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
// 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.
|
||||
|
||||
package tsdns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
// Map is all the data Resolver needs to resolve DNS queries within the Tailscale network.
|
||||
type Map struct {
|
||||
// nameToIP is a mapping of Tailscale domain names to their IP addresses.
|
||||
// For example, monitoring.tailscale.us -> 100.64.0.1.
|
||||
nameToIP map[string]netaddr.IP
|
||||
// names are the keys of nameToIP in sorted order.
|
||||
names []string
|
||||
}
|
||||
|
||||
// NewMap returns a new Map with name to address mapping given by nameToIP.
|
||||
func NewMap(nameToIP map[string]netaddr.IP) *Map {
|
||||
names := make([]string, 0, len(nameToIP))
|
||||
for name := range nameToIP {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
return &Map{
|
||||
nameToIP: nameToIP,
|
||||
names: names,
|
||||
}
|
||||
}
|
||||
|
||||
func printSingleNameIP(buf *strings.Builder, name string, ip netaddr.IP) {
|
||||
// Output width is exactly 80 columns.
|
||||
fmt.Fprintf(buf, "%s\t%s\n", name, ip)
|
||||
}
|
||||
|
||||
func (m *Map) Pretty() string {
|
||||
buf := new(strings.Builder)
|
||||
for _, name := range m.names {
|
||||
printSingleNameIP(buf, name, m.nameToIP[name])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (m *Map) PrettyDiffFrom(old *Map) string {
|
||||
var (
|
||||
oldNameToIP map[string]netaddr.IP
|
||||
newNameToIP map[string]netaddr.IP
|
||||
oldNames []string
|
||||
newNames []string
|
||||
)
|
||||
if old != nil {
|
||||
oldNameToIP = old.nameToIP
|
||||
oldNames = old.names
|
||||
}
|
||||
if m != nil {
|
||||
newNameToIP = m.nameToIP
|
||||
newNames = m.names
|
||||
}
|
||||
|
||||
buf := new(strings.Builder)
|
||||
|
||||
for len(oldNames) > 0 && len(newNames) > 0 {
|
||||
var name string
|
||||
|
||||
newName, oldName := newNames[0], oldNames[0]
|
||||
switch {
|
||||
case oldName < newName:
|
||||
name = oldName
|
||||
oldNames = oldNames[1:]
|
||||
case oldName > newName:
|
||||
name = newName
|
||||
newNames = newNames[1:]
|
||||
case oldNames[0] == newNames[0]:
|
||||
name = oldNames[0]
|
||||
oldNames = oldNames[1:]
|
||||
newNames = newNames[1:]
|
||||
}
|
||||
|
||||
ipOld, inOld := oldNameToIP[name]
|
||||
ipNew, inNew := newNameToIP[name]
|
||||
switch {
|
||||
case !inOld:
|
||||
buf.WriteByte('+')
|
||||
printSingleNameIP(buf, name, ipNew)
|
||||
case !inNew:
|
||||
buf.WriteByte('-')
|
||||
printSingleNameIP(buf, name, ipOld)
|
||||
case ipOld != ipNew:
|
||||
buf.WriteByte('-')
|
||||
printSingleNameIP(buf, name, ipOld)
|
||||
buf.WriteByte('+')
|
||||
printSingleNameIP(buf, name, ipNew)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range oldNames {
|
||||
if _, ok := newNameToIP[name]; !ok {
|
||||
buf.WriteByte('-')
|
||||
printSingleNameIP(buf, name, oldNameToIP[name])
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range newNames {
|
||||
if _, ok := oldNameToIP[name]; !ok {
|
||||
buf.WriteByte('+')
|
||||
printSingleNameIP(buf, name, newNameToIP[name])
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
// 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.
|
||||
|
||||
package tsdns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
func TestPretty(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
dmap *Map
|
||||
want string
|
||||
}{
|
||||
{"empty", NewMap(nil), ""},
|
||||
{
|
||||
"single",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"hello.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
}),
|
||||
"hello.ipn.dev\t100.101.102.103\n",
|
||||
},
|
||||
{
|
||||
"multiple",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.domain": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test2.sub.domain": netaddr.IPv4(100, 99, 9, 1),
|
||||
}),
|
||||
"test1.domain\t100.101.102.103\ntest2.sub.domain\t100.99.9.1\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.dmap.Pretty()
|
||||
if tt.want != got {
|
||||
t.Errorf("want %v; got %v", tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrettyDiffFrom(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
map1 *Map
|
||||
map2 *Map
|
||||
want string
|
||||
}{
|
||||
{
|
||||
"from_empty",
|
||||
nil,
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
}),
|
||||
"+test1.ipn.dev\t100.101.102.103\n+test2.ipn.dev\t100.103.102.101\n",
|
||||
},
|
||||
{
|
||||
"equal",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
}),
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
}),
|
||||
"",
|
||||
},
|
||||
{
|
||||
"changed_ip",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
}),
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 104, 102, 101),
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
}),
|
||||
"-test2.ipn.dev\t100.103.102.101\n+test2.ipn.dev\t100.104.102.101\n",
|
||||
},
|
||||
{
|
||||
"new_domain",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
}),
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test3.ipn.dev": netaddr.IPv4(100, 105, 106, 107),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
}),
|
||||
"+test3.ipn.dev\t100.105.106.107\n",
|
||||
},
|
||||
{
|
||||
"gone_domain",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
}),
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
}),
|
||||
"-test2.ipn.dev\t100.103.102.101\n",
|
||||
},
|
||||
{
|
||||
"mixed",
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 101, 102, 103),
|
||||
"test4.ipn.dev": netaddr.IPv4(100, 107, 106, 105),
|
||||
"test5.ipn.dev": netaddr.IPv4(100, 64, 1, 1),
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 103, 102, 101),
|
||||
}),
|
||||
NewMap(map[string]netaddr.IP{
|
||||
"test2.ipn.dev": netaddr.IPv4(100, 104, 102, 101),
|
||||
"test1.ipn.dev": netaddr.IPv4(100, 100, 101, 102),
|
||||
"test3.ipn.dev": netaddr.IPv4(100, 64, 1, 1),
|
||||
}),
|
||||
"-test1.ipn.dev\t100.101.102.103\n+test1.ipn.dev\t100.100.101.102\n" +
|
||||
"-test2.ipn.dev\t100.103.102.101\n+test2.ipn.dev\t100.104.102.101\n" +
|
||||
"+test3.ipn.dev\t100.64.1.1\n-test4.ipn.dev\t100.107.106.105\n-test5.ipn.dev\t100.64.1.1\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.map2.PrettyDiffFrom(tt.map1)
|
||||
if tt.want != got {
|
||||
t.Errorf("want %v; got %v", tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue