mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-02 10:01:57 +00:00
wgengine/magicsock, tstest/natlab: start hooking up natlab to magicsock
Also adds ephemeral port support to natlab. Work in progress. Pairing with @danderson.
This commit is contained in:
@@ -49,6 +49,7 @@ import (
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/nettype"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/types/structs"
|
||||
"tailscale.com/version"
|
||||
@@ -82,6 +83,9 @@ type Conn struct {
|
||||
udpRecvCh chan udpReadResult
|
||||
derpRecvCh chan derpReadResult
|
||||
|
||||
// packetListener optionally specifies a test hook to open a PacketConn.
|
||||
packetListener nettype.PacketListener
|
||||
|
||||
// ============================================================
|
||||
mu sync.Mutex // guards all following fields
|
||||
|
||||
@@ -227,6 +231,10 @@ type Options struct {
|
||||
// IdleFunc optionally provides a func to return how long
|
||||
// it's been since a TUN packet was sent or received.
|
||||
IdleFunc func() time.Duration
|
||||
|
||||
// PacketListener optionally specifies how to create PacketConns.
|
||||
// It's meant for testing.
|
||||
PacketListener nettype.PacketListener
|
||||
}
|
||||
|
||||
func (o *Options) logf() logger.Logf {
|
||||
@@ -273,6 +281,7 @@ func NewConn(opts Options) (*Conn, error) {
|
||||
c.logf = opts.logf()
|
||||
c.epFunc = opts.endpointsFunc()
|
||||
c.idleFunc = opts.IdleFunc
|
||||
c.packetListener = opts.PacketListener
|
||||
|
||||
if err := c.initialBind(); err != nil {
|
||||
return nil, err
|
||||
@@ -2002,6 +2011,13 @@ func (c *Conn) initialBind() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) listenPacket(ctx context.Context, network, addr string) (net.PacketConn, error) {
|
||||
if c.packetListener != nil {
|
||||
return c.packetListener.ListenPacket(ctx, network, addr)
|
||||
}
|
||||
return netns.Listener().ListenPacket(ctx, network, addr)
|
||||
}
|
||||
|
||||
func (c *Conn) bind1(ruc **RebindingUDPConn, which string) error {
|
||||
host := ""
|
||||
if v, _ := strconv.ParseBool(os.Getenv("IN_TS_TEST")); v {
|
||||
@@ -2011,13 +2027,13 @@ func (c *Conn) bind1(ruc **RebindingUDPConn, which string) error {
|
||||
var err error
|
||||
listenCtx := context.Background() // unused without DNS name to resolve
|
||||
if c.pconnPort == 0 && DefaultPort != 0 {
|
||||
pc, err = netns.Listener().ListenPacket(listenCtx, which, fmt.Sprintf("%s:%d", host, DefaultPort))
|
||||
pc, err = c.listenPacket(listenCtx, which, fmt.Sprintf("%s:%d", host, DefaultPort))
|
||||
if err != nil {
|
||||
c.logf("magicsock: bind: default port %s/%v unavailable; picking random", which, DefaultPort)
|
||||
}
|
||||
}
|
||||
if pc == nil {
|
||||
pc, err = netns.Listener().ListenPacket(listenCtx, which, fmt.Sprintf("%s:%d", host, c.pconnPort))
|
||||
pc, err = c.listenPacket(listenCtx, which, fmt.Sprintf("%s:%d", host, c.pconnPort))
|
||||
}
|
||||
if err != nil {
|
||||
c.logf("magicsock: bind(%s/%v): %v", which, c.pconnPort, err)
|
||||
@@ -2026,7 +2042,7 @@ func (c *Conn) bind1(ruc **RebindingUDPConn, which string) error {
|
||||
if *ruc == nil {
|
||||
*ruc = new(RebindingUDPConn)
|
||||
}
|
||||
(*ruc).Reset(pc.(*net.UDPConn))
|
||||
(*ruc).Reset(pc)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2043,7 +2059,7 @@ func (c *Conn) Rebind() {
|
||||
if err := c.pconn4.pconn.Close(); err != nil {
|
||||
c.logf("magicsock: link change close failed: %v", err)
|
||||
}
|
||||
packetConn, err := netns.Listener().ListenPacket(listenCtx, "udp4", fmt.Sprintf("%s:%d", host, c.pconnPort))
|
||||
packetConn, err := c.listenPacket(listenCtx, "udp4", fmt.Sprintf("%s:%d", host, c.pconnPort))
|
||||
if err == nil {
|
||||
c.logf("magicsock: link change rebound port: %d", c.pconnPort)
|
||||
c.pconn4.pconn = packetConn.(*net.UDPConn)
|
||||
@@ -2054,7 +2070,7 @@ func (c *Conn) Rebind() {
|
||||
c.pconn4.mu.Unlock()
|
||||
}
|
||||
c.logf("magicsock: link change, binding new port")
|
||||
packetConn, err := netns.Listener().ListenPacket(listenCtx, "udp4", host+":0")
|
||||
packetConn, err := c.listenPacket(listenCtx, "udp4", host+":0")
|
||||
if err != nil {
|
||||
c.logf("magicsock: link change failed to bind new port: %v", err)
|
||||
return
|
||||
@@ -2481,10 +2497,10 @@ type RebindingUDPConn struct {
|
||||
ippCache ippCache
|
||||
|
||||
mu sync.Mutex
|
||||
pconn *net.UDPConn
|
||||
pconn net.PacketConn
|
||||
}
|
||||
|
||||
func (c *RebindingUDPConn) Reset(pconn *net.UDPConn) {
|
||||
func (c *RebindingUDPConn) Reset(pconn net.PacketConn) {
|
||||
c.mu.Lock()
|
||||
old := c.pconn
|
||||
c.pconn = pconn
|
||||
@@ -2539,7 +2555,7 @@ func (c *RebindingUDPConn) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
|
||||
pconn := c.pconn
|
||||
c.mu.Unlock()
|
||||
|
||||
n, err := pconn.WriteToUDP(b, addr)
|
||||
n, err := pconn.WriteTo(b, addr)
|
||||
if err != nil {
|
||||
c.mu.Lock()
|
||||
pconn2 := c.pconn
|
||||
|
||||
@@ -32,8 +32,10 @@ import (
|
||||
"tailscale.com/net/stun/stuntest"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tstest"
|
||||
"tailscale.com/tstest/natlab"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/nettype"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/tstun"
|
||||
)
|
||||
@@ -334,6 +336,16 @@ func makeNestable(t *testing.T) (logf logger.Logf, setT func(t *testing.T)) {
|
||||
}
|
||||
|
||||
func TestTwoDevicePing(t *testing.T) {
|
||||
t.Run("real", func(t *testing.T) {
|
||||
testTwoDevicePing(t, false)
|
||||
})
|
||||
t.Run("natlab", func(t *testing.T) {
|
||||
t.Skip("TODO: finish")
|
||||
testTwoDevicePing(t, true)
|
||||
})
|
||||
}
|
||||
|
||||
func testTwoDevicePing(t *testing.T, useNatlab bool) {
|
||||
tstest.PanicOnLog()
|
||||
rc := tstest.NewResourceCheck()
|
||||
defer rc.Assert(t)
|
||||
@@ -344,7 +356,28 @@ func TestTwoDevicePing(t *testing.T) {
|
||||
|
||||
derpServer, derpAddr, derpCleanupFn := runDERP(t, logf)
|
||||
defer derpCleanupFn()
|
||||
stunAddr, stunCleanupFn := stuntest.Serve(t)
|
||||
|
||||
packetConn := func(m *natlab.Machine) nettype.PacketListener {
|
||||
if m == nil {
|
||||
return nettype.Std{}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
var stunTestIP = "127.0.0.1"
|
||||
var stunMachine, machine1, machine2 *natlab.Machine
|
||||
if useNatlab {
|
||||
stunMachine = &natlab.Machine{Name: "stun"}
|
||||
machine1 = &natlab.Machine{Name: "machine1"}
|
||||
machine2 = &natlab.Machine{Name: "machine2"}
|
||||
internet := natlab.NewInternet()
|
||||
stunIf := stunMachine.Attach("eth0", internet)
|
||||
machine1.Attach("eth0", internet)
|
||||
machine2.Attach("eth0", internet)
|
||||
stunTestIP = stunIf.V4().String()
|
||||
}
|
||||
|
||||
stunAddr, stunCleanupFn := stuntest.ServeWithPacketListener(t, packetConn(stunMachine))
|
||||
defer stunCleanupFn()
|
||||
|
||||
derpMap := &tailcfg.DERPMap{
|
||||
@@ -361,6 +394,7 @@ func TestTwoDevicePing(t *testing.T) {
|
||||
IPv6: "none",
|
||||
STUNPort: stunAddr.Port,
|
||||
DERPTestPort: derpAddr.Port,
|
||||
STUNTestIP: stunTestIP,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -369,7 +403,8 @@ func TestTwoDevicePing(t *testing.T) {
|
||||
|
||||
epCh1 := make(chan []string, 16)
|
||||
conn1, err := NewConn(Options{
|
||||
Logf: logger.WithPrefix(logf, "conn1: "),
|
||||
Logf: logger.WithPrefix(logf, "conn1: "),
|
||||
PacketListener: packetConn(machine1),
|
||||
EndpointsFunc: func(eps []string) {
|
||||
epCh1 <- eps
|
||||
},
|
||||
@@ -383,7 +418,8 @@ func TestTwoDevicePing(t *testing.T) {
|
||||
|
||||
epCh2 := make(chan []string, 16)
|
||||
conn2, err := NewConn(Options{
|
||||
Logf: logger.WithPrefix(logf, "conn2: "),
|
||||
Logf: logger.WithPrefix(logf, "conn2: "),
|
||||
PacketListener: packetConn(machine2),
|
||||
EndpointsFunc: func(eps []string) {
|
||||
epCh2 <- eps
|
||||
},
|
||||
@@ -396,6 +432,14 @@ func TestTwoDevicePing(t *testing.T) {
|
||||
conn2.SetDERPMap(derpMap)
|
||||
|
||||
ports := []uint16{conn1.LocalPort(), conn2.LocalPort()}
|
||||
if useNatlab {
|
||||
// TODO: ...
|
||||
} else {
|
||||
addrs := []netaddr.IPPort{
|
||||
// netaddr.IPPort
|
||||
}
|
||||
_ = addrs
|
||||
}
|
||||
cfgs := makeConfigs(t, ports)
|
||||
|
||||
if err := conn1.SetPrivateKey(cfgs[0].PrivateKey); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user