net/netns: add functionality to bind outgoing sockets based on route table

When turned on via environment variable (off by default), this will use
the BSD routing APIs to query what interface index a socket should be
bound to, rather than binding to the default interface in all cases.

Updates #5719
Updates #5940

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
Change-Id: Ib4c919471f377b7a08cd3413f8e8caacb29fee0b
This commit is contained in:
Andrew Dunham
2023-01-25 13:17:40 -05:00
parent 7439bc7ba6
commit 2703d6916f
5 changed files with 247 additions and 3 deletions

View File

@@ -0,0 +1,85 @@
// Copyright (c) 2023 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 netns
import (
"testing"
"tailscale.com/net/interfaces"
)
func TestGetInterfaceIndex(t *testing.T) {
oldVal := bindToInterfaceByRoute.Load()
t.Cleanup(func() { bindToInterfaceByRoute.Store(oldVal) })
bindToInterfaceByRoute.Store(true)
tests := []struct {
name string
addr string
err string
}{
{
name: "IP_and_port",
addr: "8.8.8.8:53",
},
{
name: "bare_ip",
addr: "8.8.8.8",
},
{
name: "invalid",
addr: "!!!!!",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
idx, err := getInterfaceIndex(t.Logf, tc.addr)
if err != nil {
if tc.err == "" {
t.Fatalf("got unexpected error: %v", err)
}
if errstr := err.Error(); errstr != tc.err {
t.Errorf("expected error %q, got %q", errstr, tc.err)
}
} else {
t.Logf("getInterfaceIndex(%q) = %d", tc.addr, idx)
if tc.err != "" {
t.Fatalf("wanted error %q", tc.err)
}
if idx < 0 {
t.Fatalf("got invalid index %d", idx)
}
}
})
}
t.Run("NoTailscale", func(t *testing.T) {
_, tsif, err := interfaces.Tailscale()
if err != nil {
t.Fatal(err)
}
if tsif == nil {
t.Skip("no tailscale interface on this machine")
}
defaultIdx, err := interfaces.DefaultRouteInterfaceIndex()
if err != nil {
t.Fatal(err)
}
idx, err := getInterfaceIndex(t.Logf, "100.100.100.100:53")
if err != nil {
t.Fatal(err)
}
t.Logf("tailscaleIdx=%d defaultIdx=%d idx=%d", tsif.Index, defaultIdx, idx)
if idx == tsif.Index {
t.Fatalf("got idx=%d; wanted not Tailscale interface", idx)
} else if idx != defaultIdx {
t.Fatalf("got idx=%d, want %d", idx, defaultIdx)
}
})
}