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:
Brad Fitzpatrick
2020-07-10 14:26:04 -07:00
parent edcbb5394e
commit 6c74065053
9 changed files with 186 additions and 36 deletions

View File

@@ -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