wgengine/router: move Tailscale's winipcfg additions into wgengine/router

Part of unforking our winipcfg-go and using upstream (#760), move our
additions into our repo. (We might upstream them later if upstream has
interest)

Originally these were:

@apenwarr: "Add ifc.SyncAddresses() and SyncRoutes()."
609dcf2df5

@bradfitz: "winipcfg: make Interface.AddRoutes do as much as possible, return combined error"
e9f93d53f3

@bradfitz: "prevent unnecessary Interface.SyncAddresses work; normalize IPNets in deltaNets"
decb9ee8e1
This commit is contained in:
Brad Fitzpatrick
2020-09-22 09:13:45 -07:00
parent 56a787fff8
commit 3528d28ed1
4 changed files with 359 additions and 4 deletions

View File

@ -5,8 +5,10 @@
package router
import (
"fmt"
"math/rand"
"net"
"strings"
"testing"
winipcfg "github.com/tailscale/winipcfg-go"
@ -95,3 +97,144 @@ func TestRouteLessConsistent(t *testing.T) {
}
}
}
func equalNetIPs(a, b []*net.IPNet) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if netCompare(*a[i], *b[i]) != 0 {
return false
}
}
return true
}
func ipnet4(ip string, bits int) *net.IPNet {
return &net.IPNet{
IP: net.ParseIP(ip),
Mask: net.CIDRMask(bits, 32),
}
}
// each cidr can end in "[4]" to mean To4 form.
func nets(cidrs ...string) (ret []*net.IPNet) {
for _, s := range cidrs {
to4 := strings.HasSuffix(s, "[4]")
if to4 {
s = strings.TrimSuffix(s, "[4]")
}
ip, ipNet, err := net.ParseCIDR(s)
if err != nil {
panic(fmt.Sprintf("Bogus CIDR %q in test", s))
}
if to4 {
ip = ip.To4()
}
ipNet.IP = ip
ret = append(ret, ipNet)
}
return
}
func TestDeltaNets(t *testing.T) {
tests := []struct {
a, b []*net.IPNet
wantAdd, wantDel []*net.IPNet
}{
{
a: nets("1.2.3.4/24", "1.2.3.4/31", "1.2.3.3/32", "10.0.1.1/32", "100.0.1.1/32"),
b: nets("10.0.1.1/32", "100.0.2.1/32", "1.2.3.3/32", "1.2.3.4/24"),
wantAdd: nets("100.0.2.1/32"),
wantDel: nets("1.2.3.4/31", "100.0.1.1/32"),
},
{
a: nets("fe80::99d0:ec2d:b2e7:536b/64", "100.84.36.11/32"),
b: nets("100.84.36.11/32"),
wantDel: nets("fe80::99d0:ec2d:b2e7:536b/64"),
},
{
a: nets("100.84.36.11/32", "fe80::99d0:ec2d:b2e7:536b/64"),
b: nets("100.84.36.11/32"),
wantDel: nets("fe80::99d0:ec2d:b2e7:536b/64"),
},
{
a: nets("100.84.36.11/32", "fe80::99d0:ec2d:b2e7:536b/64"),
b: nets("100.84.36.11/32[4]"),
wantDel: nets("fe80::99d0:ec2d:b2e7:536b/64"),
},
{
a: excludeIPv6LinkLocal(nets("100.84.36.11/32", "fe80::99d0:ec2d:b2e7:536b/64")),
b: nets("100.84.36.11/32"),
},
{
a: []*net.IPNet{
{
IP: net.ParseIP("1.2.3.4"),
Mask: net.IPMask{0xff, 0xff, 0xff, 0xff},
},
},
b: []*net.IPNet{
{
IP: net.ParseIP("1.2.3.4"),
Mask: net.IPMask{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
},
},
},
}
for i, tt := range tests {
add, del := deltaNets(tt.a, tt.b)
if !equalNetIPs(add, tt.wantAdd) {
t.Errorf("[%d] add:\n got: %v\n want: %v\n", i, add, tt.wantAdd)
}
if !equalNetIPs(del, tt.wantDel) {
t.Errorf("[%d] del:\n got: %v\n want: %v\n", i, del, tt.wantDel)
}
}
}
func equalRouteDatas(a, b []*winipcfg.RouteData) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if routeDataCompare(a[i], b[i]) != 0 {
return false
}
}
return true
}
func TestDeltaRouteData(t *testing.T) {
var h0 net.IP
h1 := net.ParseIP("99.99.99.99")
h2 := net.ParseIP("99.99.9.99")
a := []*winipcfg.RouteData{
{*ipnet4("1.2.3.4", 32), h0, 1},
{*ipnet4("1.2.3.4", 24), h1, 2},
{*ipnet4("1.2.3.4", 24), h2, 1},
{*ipnet4("1.2.3.5", 32), h0, 1},
}
b := []*winipcfg.RouteData{
{*ipnet4("1.2.3.5", 32), h0, 1},
{*ipnet4("1.2.3.4", 24), h1, 2},
{*ipnet4("1.2.3.4", 24), h2, 2},
}
add, del := deltaRouteData(a, b)
wantAdd := []*winipcfg.RouteData{
{*ipnet4("1.2.3.4", 24), h2, 2},
}
wantDel := []*winipcfg.RouteData{
{*ipnet4("1.2.3.4", 32), h0, 1},
{*ipnet4("1.2.3.4", 24), h2, 1},
}
if !equalRouteDatas(add, wantAdd) {
t.Errorf("add:\n got: %v\n want: %v\n", add, wantAdd)
}
if !equalRouteDatas(del, wantDel) {
t.Errorf("del:\n got: %v\n want: %v\n", del, wantDel)
}
}