|
|
|
|
@ -35,6 +35,7 @@ import ( |
|
|
|
|
"tailscale.com/control/controlclient" |
|
|
|
|
"tailscale.com/derp" |
|
|
|
|
"tailscale.com/derp/derphttp" |
|
|
|
|
"tailscale.com/disco" |
|
|
|
|
"tailscale.com/ipn/ipnstate" |
|
|
|
|
"tailscale.com/net/dnscache" |
|
|
|
|
"tailscale.com/net/interfaces" |
|
|
|
|
@ -553,7 +554,7 @@ func (c *Conn) goDerpConnect(node int) { |
|
|
|
|
if node == 0 { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
go c.derpWriteChanOfAddr(&net.UDPAddr{IP: derpMagicIP, Port: node}, key.Public{}) |
|
|
|
|
go c.derpWriteChanOfAddr(netaddr.IPPort{IP: derpMagicIPAddr, Port: uint16(node)}, key.Public{}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// determineEndpoints returns the machine's endpoint addresses. It
|
|
|
|
|
@ -659,17 +660,25 @@ var logPacketDests, _ = strconv.ParseBool(os.Getenv("DEBUG_LOG_PACKET_DESTS")) |
|
|
|
|
const sprayPeriod = 3 * time.Second |
|
|
|
|
|
|
|
|
|
// appendDests appends to dsts the destinations that b should be
|
|
|
|
|
// written to in order to reach as. Some of the returned UDPAddrs may
|
|
|
|
|
// written to in order to reach as. Some of the returned IPPorts may
|
|
|
|
|
// be fake addrs representing DERP servers.
|
|
|
|
|
//
|
|
|
|
|
// It also returns as's current roamAddr, if any.
|
|
|
|
|
func (as *AddrSet) appendDests(dsts []*net.UDPAddr, b []byte) (_ []*net.UDPAddr, roamAddr *net.UDPAddr) { |
|
|
|
|
func (as *AddrSet) appendDests(dsts []netaddr.IPPort, b []byte) (_ []netaddr.IPPort, roamAddr netaddr.IPPort) { |
|
|
|
|
spray := shouldSprayPacket(b) // true for handshakes
|
|
|
|
|
now := as.timeNow() |
|
|
|
|
|
|
|
|
|
as.mu.Lock() |
|
|
|
|
defer as.mu.Unlock() |
|
|
|
|
|
|
|
|
|
// Some internal invariant checks.
|
|
|
|
|
if len(as.addrs) != len(as.ipPorts) { |
|
|
|
|
panic(fmt.Sprintf("lena %d != leni %d", len(as.addrs), len(as.ipPorts))) |
|
|
|
|
} |
|
|
|
|
if n1, n2 := as.roamAddr != nil, as.roamAddrStd != nil; n1 != n2 { |
|
|
|
|
panic(fmt.Sprintf("roamnil %v != roamstdnil %v", n1, n2)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Spray logic.
|
|
|
|
|
//
|
|
|
|
|
// After exchanging a handshake with a peer, we send some outbound
|
|
|
|
|
@ -702,17 +711,17 @@ func (as *AddrSet) appendDests(dsts []*net.UDPAddr, b []byte) (_ []*net.UDPAddr, |
|
|
|
|
switch { |
|
|
|
|
case spray: |
|
|
|
|
// This packet is being sprayed to all addresses.
|
|
|
|
|
for i := range as.addrs { |
|
|
|
|
dsts = append(dsts, &as.addrs[i]) |
|
|
|
|
for i := range as.ipPorts { |
|
|
|
|
dsts = append(dsts, as.ipPorts[i]) |
|
|
|
|
} |
|
|
|
|
if as.roamAddr != nil { |
|
|
|
|
dsts = append(dsts, as.roamAddr) |
|
|
|
|
dsts = append(dsts, *as.roamAddr) |
|
|
|
|
} |
|
|
|
|
case as.roamAddr != nil: |
|
|
|
|
// We have a roaming address, prefer it over other addrs.
|
|
|
|
|
// TODO(danderson): this is not correct, there's no reason
|
|
|
|
|
// roamAddr should be special like this.
|
|
|
|
|
dsts = append(dsts, as.roamAddr) |
|
|
|
|
dsts = append(dsts, *as.roamAddr) |
|
|
|
|
case as.curAddr != -1: |
|
|
|
|
if as.curAddr >= len(as.addrs) { |
|
|
|
|
as.Logf("[unexpected] magicsock bug: as.curAddr >= len(as.addrs): %d >= %d", as.curAddr, len(as.addrs)) |
|
|
|
|
@ -720,20 +729,23 @@ func (as *AddrSet) appendDests(dsts []*net.UDPAddr, b []byte) (_ []*net.UDPAddr, |
|
|
|
|
} |
|
|
|
|
// No roaming addr, but we've seen packets from a known peer
|
|
|
|
|
// addr, so keep using that one.
|
|
|
|
|
dsts = append(dsts, &as.addrs[as.curAddr]) |
|
|
|
|
dsts = append(dsts, as.ipPorts[as.curAddr]) |
|
|
|
|
default: |
|
|
|
|
// We know nothing about how to reach this peer, and we're not
|
|
|
|
|
// spraying. Use the first address in the array, which will
|
|
|
|
|
// usually be a DERP address that guarantees connectivity.
|
|
|
|
|
if len(as.addrs) > 0 { |
|
|
|
|
dsts = append(dsts, &as.addrs[0]) |
|
|
|
|
if len(as.ipPorts) > 0 { |
|
|
|
|
dsts = append(dsts, as.ipPorts[0]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if logPacketDests { |
|
|
|
|
as.Logf("spray=%v; roam=%v; dests=%v", spray, as.roamAddr, dsts) |
|
|
|
|
} |
|
|
|
|
return dsts, as.roamAddr |
|
|
|
|
if as.roamAddr != nil { |
|
|
|
|
roamAddr = *as.roamAddr |
|
|
|
|
} |
|
|
|
|
return dsts, roamAddr |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var errNoDestinations = errors.New("magicsock: no destinations") |
|
|
|
|
@ -751,12 +763,12 @@ func (c *Conn) Send(b []byte, ep conn.Endpoint) error { |
|
|
|
|
c.logf("magicsock: [unexpected] DERP BUG: attempting to send packet to DERP address %v", addr) |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
return c.sendUDP(addr, b) |
|
|
|
|
return c.sendUDPStd(addr, b) |
|
|
|
|
case *AddrSet: |
|
|
|
|
as = v |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var addrBuf [8]*net.UDPAddr |
|
|
|
|
var addrBuf [8]netaddr.IPPort |
|
|
|
|
dsts, roamAddr := as.appendDests(addrBuf[:0], b) |
|
|
|
|
|
|
|
|
|
if len(dsts) == 0 { |
|
|
|
|
@ -788,30 +800,39 @@ var errConnClosed = errors.New("Conn closed") |
|
|
|
|
|
|
|
|
|
var errDropDerpPacket = errors.New("too many DERP packets queued; dropping") |
|
|
|
|
|
|
|
|
|
// sendUDP sends UDP packet b to addr.
|
|
|
|
|
func (c *Conn) sendUDP(addr *net.UDPAddr, b []byte) error { |
|
|
|
|
if addr.IP.To4() != nil { |
|
|
|
|
_, err := c.pconn4.WriteTo(b, addr) |
|
|
|
|
// sendUDP sends UDP packet b to ipp.
|
|
|
|
|
func (c *Conn) sendUDP(ipp netaddr.IPPort, b []byte) error { |
|
|
|
|
addr := ipp.UDPAddr() // TOOD(bradfitz): add alloc-free netaddr.WriteTo helper
|
|
|
|
|
return c.sendUDPStd(addr, b) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Conn) sendUDPStd(addr *net.UDPAddr, b []byte) (err error) { |
|
|
|
|
switch { |
|
|
|
|
case addr.IP.To4() != nil: |
|
|
|
|
_, err = c.pconn4.WriteTo(b, addr) |
|
|
|
|
if err != nil && c.noV4.Get() { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if c.pconn6 != nil { |
|
|
|
|
_, err := c.pconn6.WriteTo(b, addr) |
|
|
|
|
case len(addr.IP) == net.IPv6len: |
|
|
|
|
if c.pconn6 == nil { |
|
|
|
|
// ignore IPv6 dest if we don't have an IPv6 address.
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
_, err = c.pconn6.WriteTo(b, addr) |
|
|
|
|
if err != nil && c.noV6.Get() { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
return err |
|
|
|
|
default: |
|
|
|
|
return errors.New("bogus sendUDPStd addr type") |
|
|
|
|
} |
|
|
|
|
return nil // ignore IPv6 dest if we don't have an IPv6 address.
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// sendAddr sends packet b to addr, which is either a real UDP address
|
|
|
|
|
// or a fake UDP address representing a DERP server (see derpmap.go).
|
|
|
|
|
// The provided public key identifies the recipient.
|
|
|
|
|
func (c *Conn) sendAddr(addr *net.UDPAddr, pubKey key.Public, b []byte) error { |
|
|
|
|
if !addr.IP.Equal(derpMagicIP) { |
|
|
|
|
func (c *Conn) sendAddr(addr netaddr.IPPort, pubKey key.Public, b []byte) error { |
|
|
|
|
if addr.IP != derpMagicIPAddr { |
|
|
|
|
return c.sendUDP(addr, b) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -857,11 +878,11 @@ var debugUseDerpRoute, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_ENABLE_DERP_ROU |
|
|
|
|
//
|
|
|
|
|
// If peer is non-zero, it can be used to find an active reverse
|
|
|
|
|
// path, without using addr.
|
|
|
|
|
func (c *Conn) derpWriteChanOfAddr(addr *net.UDPAddr, peer key.Public) chan<- derpWriteRequest { |
|
|
|
|
if !addr.IP.Equal(derpMagicIP) { |
|
|
|
|
func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.Public) chan<- derpWriteRequest { |
|
|
|
|
if addr.IP != derpMagicIPAddr { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
regionID := addr.Port |
|
|
|
|
regionID := int(addr.Port) |
|
|
|
|
|
|
|
|
|
c.mu.Lock() |
|
|
|
|
defer c.mu.Unlock() |
|
|
|
|
@ -964,7 +985,7 @@ func (c *Conn) derpWriteChanOfAddr(addr *net.UDPAddr, peer key.Public) chan<- de |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
go c.runDerpReader(ctx, addr, dc, wg, startGate) |
|
|
|
|
go c.runDerpWriter(ctx, addr, dc, ch, wg, startGate) |
|
|
|
|
go c.runDerpWriter(ctx, dc, ch, wg, startGate) |
|
|
|
|
|
|
|
|
|
return ad.writeCh |
|
|
|
|
} |
|
|
|
|
@ -1012,7 +1033,7 @@ func (c *Conn) setPeerLastDerpLocked(peer key.Public, regionID, homeID int) { |
|
|
|
|
// get at the packet contents they need to call copyBuf to copy it
|
|
|
|
|
// out, which also releases the buffer.
|
|
|
|
|
type derpReadResult struct { |
|
|
|
|
derpAddr *net.UDPAddr |
|
|
|
|
regionID int |
|
|
|
|
n int // length of data received
|
|
|
|
|
src key.Public // may be zero until server deployment if v2+
|
|
|
|
|
// copyBuf is called to copy the data to dst. It returns how
|
|
|
|
|
@ -1025,7 +1046,7 @@ var logDerpVerbose, _ = strconv.ParseBool(os.Getenv("DEBUG_DERP_VERBOSE")) |
|
|
|
|
|
|
|
|
|
// runDerpReader runs in a goroutine for the life of a DERP
|
|
|
|
|
// connection, handling received packets.
|
|
|
|
|
func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc *derphttp.Client, wg *syncs.WaitGroupChan, startGate <-chan struct{}) { |
|
|
|
|
func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netaddr.IPPort, dc *derphttp.Client, wg *syncs.WaitGroupChan, startGate <-chan struct{}) { |
|
|
|
|
defer wg.Decr() |
|
|
|
|
defer dc.Close() |
|
|
|
|
|
|
|
|
|
@ -1036,8 +1057,8 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
didCopy := make(chan struct{}, 1) |
|
|
|
|
|
|
|
|
|
res := derpReadResult{derpAddr: derpFakeAddr} |
|
|
|
|
regionID := int(derpFakeAddr.Port) |
|
|
|
|
res := derpReadResult{regionID: regionID} |
|
|
|
|
var pkt derp.ReceivedPacket |
|
|
|
|
res.copyBuf = func(dst []byte) int { |
|
|
|
|
n := copy(dst, pkt.Data) |
|
|
|
|
@ -1058,7 +1079,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc |
|
|
|
|
// Forget that all these peers have routes.
|
|
|
|
|
for peer := range peerPresent { |
|
|
|
|
delete(peerPresent, peer) |
|
|
|
|
c.removeDerpPeerRoute(peer, derpFakeAddr.Port, dc) |
|
|
|
|
c.removeDerpPeerRoute(peer, regionID, dc) |
|
|
|
|
} |
|
|
|
|
select { |
|
|
|
|
case <-ctx.Done(): |
|
|
|
|
@ -1066,7 +1087,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc |
|
|
|
|
default: |
|
|
|
|
} |
|
|
|
|
c.ReSTUN("derp-close") |
|
|
|
|
c.logf("magicsock: [%p] derp.Recv(derp-%d): %v", dc, derpFakeAddr.Port, err) |
|
|
|
|
c.logf("magicsock: [%p] derp.Recv(derp-%d): %v", dc, regionID, err) |
|
|
|
|
time.Sleep(250 * time.Millisecond) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
@ -1076,13 +1097,13 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc |
|
|
|
|
res.n = len(m.Data) |
|
|
|
|
res.src = m.Source |
|
|
|
|
if logDerpVerbose { |
|
|
|
|
c.logf("magicsock: got derp-%v packet: %q", derpFakeAddr, m.Data) |
|
|
|
|
c.logf("magicsock: got derp-%v packet: %q", regionID, m.Data) |
|
|
|
|
} |
|
|
|
|
// If this is a new sender we hadn't seen before, remember it and
|
|
|
|
|
// register a route for this peer.
|
|
|
|
|
if _, ok := peerPresent[m.Source]; !ok { |
|
|
|
|
peerPresent[m.Source] = true |
|
|
|
|
c.addDerpPeerRoute(m.Source, derpFakeAddr.Port, dc) |
|
|
|
|
c.addDerpPeerRoute(m.Source, regionID, dc) |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
// Ignore.
|
|
|
|
|
@ -1099,14 +1120,14 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr *net.UDPAddr, dc |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type derpWriteRequest struct { |
|
|
|
|
addr *net.UDPAddr |
|
|
|
|
addr netaddr.IPPort |
|
|
|
|
pubKey key.Public |
|
|
|
|
b []byte // copied; ownership passed to receiver
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// runDerpWriter runs in a goroutine for the life of a DERP
|
|
|
|
|
// connection, handling received packets.
|
|
|
|
|
func (c *Conn) runDerpWriter(ctx context.Context, derpFakeAddr *net.UDPAddr, dc *derphttp.Client, ch <-chan derpWriteRequest, wg *syncs.WaitGroupChan, startGate <-chan struct{}) { |
|
|
|
|
func (c *Conn) runDerpWriter(ctx context.Context, dc *derphttp.Client, ch <-chan derpWriteRequest, wg *syncs.WaitGroupChan, startGate <-chan struct{}) { |
|
|
|
|
defer wg.Decr() |
|
|
|
|
select { |
|
|
|
|
case <-startGate: |
|
|
|
|
@ -1185,7 +1206,6 @@ func (c *Conn) awaitUDP4(b []byte) { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addr.IP = addr.IP.To4() |
|
|
|
|
select { |
|
|
|
|
case c.udpRecvCh <- udpReadResult{n: n, addr: addr}: |
|
|
|
|
case <-c.donec(): |
|
|
|
|
@ -1200,12 +1220,13 @@ func (c *Conn) awaitUDP4(b []byte) { |
|
|
|
|
// per peer.
|
|
|
|
|
func wgRecvAddr(e conn.Endpoint, addr *net.UDPAddr) *net.UDPAddr { |
|
|
|
|
if de, ok := e.(*discoEndpoint); ok { |
|
|
|
|
return de.fakeWGAddr |
|
|
|
|
return de.fakeWGAddrStd |
|
|
|
|
} |
|
|
|
|
return addr |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Conn) ReceiveIPv4(b []byte) (n int, ep conn.Endpoint, addr *net.UDPAddr, err error) { |
|
|
|
|
Top: |
|
|
|
|
// First, process any buffered packet from earlier.
|
|
|
|
|
if addr := c.bufferedIPv4From; addr != nil { |
|
|
|
|
c.bufferedIPv4From = nil |
|
|
|
|
@ -1245,7 +1266,8 @@ func (c *Conn) ReceiveIPv4(b []byte) (n int, ep conn.Endpoint, addr *net.UDPAddr |
|
|
|
|
case <-c.donec(): |
|
|
|
|
return 0, nil, nil, errors.New("Conn closed") |
|
|
|
|
} |
|
|
|
|
n, addr = dm.n, dm.derpAddr |
|
|
|
|
var regionID int |
|
|
|
|
n, regionID = dm.n, dm.regionID |
|
|
|
|
ncopy := dm.copyBuf(b) |
|
|
|
|
if ncopy != n { |
|
|
|
|
err = fmt.Errorf("received DERP packet of length %d that's too big for WireGuard ReceiveIPv4 buf size %d", n, ncopy) |
|
|
|
|
@ -1253,6 +1275,11 @@ func (c *Conn) ReceiveIPv4(b []byte) (n int, ep conn.Endpoint, addr *net.UDPAddr |
|
|
|
|
return 0, nil, nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addr := netaddr.IPPort{IP: derpMagicIPAddr, Port: uint16(regionID)} |
|
|
|
|
if c.handleDiscoMessage(b[:n], addr.UDPAddr()) { |
|
|
|
|
goto Top |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.mu.Lock() |
|
|
|
|
if dk, ok := c.discoOfNode[tailcfg.NodeKey(dm.src)]; ok { |
|
|
|
|
discoEp = c.endpointOfDisco[dk] |
|
|
|
|
@ -1311,6 +1338,10 @@ func (c *Conn) ReceiveIPv6(b []byte) (int, conn.Endpoint, *net.UDPAddr, error) { |
|
|
|
|
c.stunReceiveFunc.Load().(func([]byte, *net.UDPAddr))(b[:n], addr) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if c.handleDiscoMessage(b[:n], addr) { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ep := c.findEndpoint(addr) |
|
|
|
|
return n, ep, wgRecvAddr(ep, addr), nil |
|
|
|
|
} |
|
|
|
|
@ -1324,8 +1355,11 @@ func (c *Conn) ReceiveIPv6(b []byte) (int, conn.Endpoint, *net.UDPAddr, error) { |
|
|
|
|
// * magic [6]byte
|
|
|
|
|
// * senderDiscoPubKey [32]byte
|
|
|
|
|
// * nonce [24]byte
|
|
|
|
|
// * naclbox of payload
|
|
|
|
|
func (c *Conn) handleDiscoMessage(msg []byte, addr *net.UDPAddr) bool { |
|
|
|
|
// * naclbox of payload (see tailscale.com/disco package for inner payload format)
|
|
|
|
|
//
|
|
|
|
|
// For messages received over DERP, the addr will be derpMagicIP (with
|
|
|
|
|
// port being the region)
|
|
|
|
|
func (c *Conn) handleDiscoMessage(msg []byte, src *net.UDPAddr) bool { |
|
|
|
|
const magic = "TS💬" |
|
|
|
|
const nonceLen = 24 |
|
|
|
|
const headerLen = len(magic) + len(tailcfg.DiscoKey{}) + nonceLen |
|
|
|
|
@ -1335,6 +1369,11 @@ func (c *Conn) handleDiscoMessage(msg []byte, addr *net.UDPAddr) bool { |
|
|
|
|
var sender tailcfg.DiscoKey |
|
|
|
|
copy(sender[:], msg[len(magic):]) |
|
|
|
|
|
|
|
|
|
srca, ok := netaddr.FromStdAddr(src.IP, src.Port, src.Zone) |
|
|
|
|
if !ok { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.mu.Lock() |
|
|
|
|
defer c.mu.Unlock() |
|
|
|
|
|
|
|
|
|
@ -1361,10 +1400,57 @@ func (c *Conn) handleDiscoMessage(msg []byte, addr *net.UDPAddr) bool { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.logf("magicsock: got disco message from %s: %x (%q)", senderNode.Key.ShortString(), payload, payload) |
|
|
|
|
dm, err := disco.Parse(payload) |
|
|
|
|
if err != nil { |
|
|
|
|
// Couldn't parse it, but it was inside a correctly
|
|
|
|
|
// signed box, so just ignore it, assuming it's from a
|
|
|
|
|
// newer version of Tailscale that we don't
|
|
|
|
|
// understand. Not even worth logging about, lest it
|
|
|
|
|
// be too spammy for old clients.
|
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch dm := dm.(type) { |
|
|
|
|
case *disco.Ping: |
|
|
|
|
c.handlePingLocked(dm, senderNode, sender, srca) |
|
|
|
|
case *disco.Pong: |
|
|
|
|
c.handlePongLocked(dm, senderNode, sender, srca) |
|
|
|
|
case disco.CallMeMaybe: |
|
|
|
|
if srca.IP != derpMagicIPAddr { |
|
|
|
|
// CallMeMaybe messages should only come via DERP.
|
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
c.handleCallMeMaybeLocked(senderNode, sender) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Conn) handlePongLocked(m *disco.Pong, n *tailcfg.Node, dk tailcfg.DiscoKey, from netaddr.IPPort) { |
|
|
|
|
c.logf("magicsock: disco: got pong from %s, tx=%x, disco=%x, src=%v (they saw %v)", n.Key.ShortString(), m.TxID, dk[:8], from, m.Src) |
|
|
|
|
// TODO: implement
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Conn) handlePingLocked(m *disco.Ping, n *tailcfg.Node, dk tailcfg.DiscoKey, from netaddr.IPPort) { |
|
|
|
|
c.logf("magicsock: disco: got ping from %s, tx=%x, disco=%x, src=%v", n.Key.ShortString(), m.TxID, dk[:8], from) |
|
|
|
|
// TODO: implement
|
|
|
|
|
reply := &disco.Pong{ |
|
|
|
|
TxID: m.TxID, |
|
|
|
|
Src: from, |
|
|
|
|
} |
|
|
|
|
go c.sendAddr(from, key.Public(n.Key), reply.AppendMarshal(nil)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// handleCallMeMaybeLocked is called when a discovery message arrives
|
|
|
|
|
// via DERP for us to send to a peer. The contract for use of this
|
|
|
|
|
// message is that the peer has already sent to us via UDP, so their
|
|
|
|
|
// stateful firewall should be open. Now we can Ping back and make it
|
|
|
|
|
// through.
|
|
|
|
|
func (c *Conn) handleCallMeMaybeLocked(n *tailcfg.Node, dk tailcfg.DiscoKey) { |
|
|
|
|
c.logf("magicsock: disco: got call-me-maybe packet from %s (disco=%x)", n.Key.ShortString, dk[:8]) |
|
|
|
|
// TODO: implement
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *Conn) sharedDiscoKeyLocked(k tailcfg.DiscoKey) *[32]byte { |
|
|
|
|
if v, ok := c.sharedDiscoKey[k]; ok { |
|
|
|
|
return v |
|
|
|
|
@ -1865,7 +1951,8 @@ type AddrSet struct { |
|
|
|
|
// this should hopefully never be used (or at least used
|
|
|
|
|
// rarely) in the case that all the components of Tailscale
|
|
|
|
|
// are correctly learning/sharing the network map details.
|
|
|
|
|
roamAddr *net.UDPAddr |
|
|
|
|
roamAddr *netaddr.IPPort |
|
|
|
|
roamAddrStd *net.UDPAddr |
|
|
|
|
|
|
|
|
|
// curAddr is an index into addrs of the highest-priority
|
|
|
|
|
// address a valid packet has been received from so far.
|
|
|
|
|
@ -1903,17 +1990,14 @@ func (as *AddrSet) timeNow() time.Time { |
|
|
|
|
return time.Now() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var noAddr = &net.UDPAddr{ |
|
|
|
|
IP: net.ParseIP("127.127.127.127"), |
|
|
|
|
Port: 127, |
|
|
|
|
} |
|
|
|
|
var noAddr, _ = netaddr.FromStdAddr(net.ParseIP("127.127.127.127"), 127, "") |
|
|
|
|
|
|
|
|
|
func (a *AddrSet) dst() *net.UDPAddr { |
|
|
|
|
func (a *AddrSet) dst() netaddr.IPPort { |
|
|
|
|
a.mu.Lock() |
|
|
|
|
defer a.mu.Unlock() |
|
|
|
|
|
|
|
|
|
if a.roamAddr != nil { |
|
|
|
|
return a.roamAddr |
|
|
|
|
return *a.roamAddr |
|
|
|
|
} |
|
|
|
|
if len(a.addrs) == 0 { |
|
|
|
|
return noAddr |
|
|
|
|
@ -1922,7 +2006,7 @@ func (a *AddrSet) dst() *net.UDPAddr { |
|
|
|
|
if i == -1 { |
|
|
|
|
i = 0 |
|
|
|
|
} |
|
|
|
|
return &a.addrs[i] |
|
|
|
|
return a.ipPorts[i] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// packUDPAddr packs a UDPAddr in the form wanted by WireGuard.
|
|
|
|
|
@ -1938,15 +2022,30 @@ func packUDPAddr(ua *net.UDPAddr) []byte { |
|
|
|
|
return b |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// packIPPort packs an IPPort into the form wanted by WireGuard.
|
|
|
|
|
func packIPPort(ua netaddr.IPPort) []byte { |
|
|
|
|
ip := ua.IP.Unmap() |
|
|
|
|
a := ip.As16() |
|
|
|
|
ipb := a[:] |
|
|
|
|
if ip.Is4() { |
|
|
|
|
ipb = ipb[12:] |
|
|
|
|
} |
|
|
|
|
b := make([]byte, 0, len(ipb)+2) |
|
|
|
|
b = append(b, ipb...) |
|
|
|
|
b = append(b, byte(ua.Port)) |
|
|
|
|
b = append(b, byte(ua.Port>>8)) |
|
|
|
|
return b |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (a *AddrSet) DstToBytes() []byte { |
|
|
|
|
return packUDPAddr(a.dst()) |
|
|
|
|
return packIPPort(a.dst()) |
|
|
|
|
} |
|
|
|
|
func (a *AddrSet) DstToString() string { |
|
|
|
|
dst := a.dst() |
|
|
|
|
return dst.String() |
|
|
|
|
} |
|
|
|
|
func (a *AddrSet) DstIP() net.IP { |
|
|
|
|
return a.dst().IP |
|
|
|
|
return a.dst().IP.IPAddr().IP // TODO: add netaddr accessor to cut an alloc here?
|
|
|
|
|
} |
|
|
|
|
func (a *AddrSet) SrcIP() net.IP { return nil } |
|
|
|
|
func (a *AddrSet) SrcToString() string { return "" } |
|
|
|
|
@ -1964,7 +2063,7 @@ func (a *AddrSet) UpdateDst(new *net.UDPAddr) error { |
|
|
|
|
a.mu.Lock() |
|
|
|
|
defer a.mu.Unlock() |
|
|
|
|
|
|
|
|
|
if a.roamAddr != nil && equalUDPAddr(new, a.roamAddr) { |
|
|
|
|
if a.roamAddrStd != nil && equalUDPAddr(new, a.roamAddrStd) { |
|
|
|
|
// Packet from the current roaming address, no logging.
|
|
|
|
|
// This is a hot path for established connections.
|
|
|
|
|
return nil |
|
|
|
|
@ -1975,6 +2074,11 @@ func (a *AddrSet) UpdateDst(new *net.UDPAddr) error { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
newa, ok := netaddr.FromStdAddr(new.IP, new.Port, new.Zone) |
|
|
|
|
if !ok { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
index := -1 |
|
|
|
|
for i := range a.addrs { |
|
|
|
|
if equalUDPAddr(new, &a.addrs[i]) { |
|
|
|
|
@ -1997,11 +2101,13 @@ func (a *AddrSet) UpdateDst(new *net.UDPAddr) error { |
|
|
|
|
} else { |
|
|
|
|
a.Logf("magicsock: rx %s from roaming address %s, replaces roaming address %s", pk, new, a.roamAddr) |
|
|
|
|
} |
|
|
|
|
a.roamAddr = new |
|
|
|
|
a.roamAddr = &newa |
|
|
|
|
a.roamAddrStd = new |
|
|
|
|
|
|
|
|
|
case a.roamAddr != nil: |
|
|
|
|
a.Logf("magicsock: rx %s from known %s (%d), replaces roaming address %s", pk, new, index, a.roamAddr) |
|
|
|
|
a.roamAddr = nil |
|
|
|
|
a.roamAddrStd = nil |
|
|
|
|
a.curAddr = index |
|
|
|
|
a.loggedLogPriMask = 0 |
|
|
|
|
|
|
|
|
|
@ -2037,7 +2143,7 @@ func (a *AddrSet) String() string { |
|
|
|
|
buf.WriteByte('[') |
|
|
|
|
if a.roamAddr != nil { |
|
|
|
|
buf.WriteString("roam:") |
|
|
|
|
sbPrintAddr(buf, *a.roamAddr) |
|
|
|
|
sbPrintAddr(buf, *a.roamAddrStd) |
|
|
|
|
} |
|
|
|
|
for i, addr := range a.addrs { |
|
|
|
|
if i > 0 || a.roamAddr != nil { |
|
|
|
|
@ -2325,7 +2431,7 @@ func (c *Conn) UpdateStatus(sb *ipnstate.StatusBuilder) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if as.roamAddr != nil { |
|
|
|
|
ps.CurAddr = udpAddrDebugString(*as.roamAddr) |
|
|
|
|
ps.CurAddr = udpAddrDebugString(*as.roamAddrStd) |
|
|
|
|
} |
|
|
|
|
sb.AddPeer(k, ps) |
|
|
|
|
} |
|
|
|
|
@ -2349,11 +2455,12 @@ type discoEndpoint struct { |
|
|
|
|
c *Conn |
|
|
|
|
publicKey key.Public // peer public key (for WireGuard + DERP)
|
|
|
|
|
discoKey tailcfg.DiscoKey // for discovery mesages
|
|
|
|
|
fakeWGAddr *net.UDPAddr // the UDPAddr we tell wireguard-go we're using
|
|
|
|
|
fakeWGAddr netaddr.IPPort // the UDP address we tell wireguard-go we're using
|
|
|
|
|
fakeWGAddrStd *net.UDPAddr // the *net.UDPAddr form of fakeWGAddr
|
|
|
|
|
wgEndpointHostPort string // string from CreateEndpoint: "<hex-discovery-key>.disco.tailscale:12345"
|
|
|
|
|
|
|
|
|
|
mu sync.Mutex // Lock ordering: Conn.mu, then discoEndpoint.mu
|
|
|
|
|
derpAddr *net.UDPAddr |
|
|
|
|
derpAddr netaddr.IPPort |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// initFakeUDPAddr populates fakeWGAddr with a globally unique fake UDPAddr.
|
|
|
|
|
@ -2364,11 +2471,11 @@ func (de *discoEndpoint) initFakeUDPAddr() { |
|
|
|
|
addr[0] = 0xfd |
|
|
|
|
addr[1] = 0x00 |
|
|
|
|
binary.BigEndian.PutUint64(addr[2:], uint64(reflect.ValueOf(de).Pointer())) |
|
|
|
|
ipp := netaddr.IPPort{ |
|
|
|
|
de.fakeWGAddr = netaddr.IPPort{ |
|
|
|
|
IP: netaddr.IPFrom16(addr), |
|
|
|
|
Port: 12345, |
|
|
|
|
} |
|
|
|
|
de.fakeWGAddr = ipp.UDPAddr() |
|
|
|
|
de.fakeWGAddrStd = de.fakeWGAddr.UDPAddr() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (de *discoEndpoint) Addrs() []wgcfg.Endpoint { |
|
|
|
|
@ -2391,7 +2498,7 @@ func (de *discoEndpoint) SrcToString() string { panic("unused") } // unused by w |
|
|
|
|
func (de *discoEndpoint) SrcIP() net.IP { panic("unused") } // unused by wireguard-go
|
|
|
|
|
func (de *discoEndpoint) DstToString() string { return de.wgEndpointHostPort } |
|
|
|
|
func (de *discoEndpoint) DstIP() net.IP { panic("unused") } |
|
|
|
|
func (de *discoEndpoint) DstToBytes() []byte { return de.fakeWGAddr.IP[:] } |
|
|
|
|
func (de *discoEndpoint) DstToBytes() []byte { return packIPPort(de.fakeWGAddr) } |
|
|
|
|
func (de *discoEndpoint) UpdateDst(addr *net.UDPAddr) error { |
|
|
|
|
// This is called ~per packet (and requiring a mutex acquisition inside wireguard-go).
|
|
|
|
|
// TODO(bradfitz): make that cheaper and/or remove it. We don't need it.
|
|
|
|
|
@ -2406,7 +2513,7 @@ func (de *discoEndpoint) send(b []byte) error { |
|
|
|
|
derpAddr := de.derpAddr |
|
|
|
|
de.mu.Unlock() |
|
|
|
|
|
|
|
|
|
if derpAddr == nil { |
|
|
|
|
if derpAddr.Port == 0 { |
|
|
|
|
return errors.New("no DERP addr") |
|
|
|
|
} |
|
|
|
|
return de.c.sendAddr(derpAddr, de.publicKey, b) |
|
|
|
|
@ -2421,12 +2528,9 @@ func (de *discoEndpoint) updateFromNode(n *tailcfg.Node) { |
|
|
|
|
defer de.mu.Unlock() |
|
|
|
|
|
|
|
|
|
if n.DERP == "" { |
|
|
|
|
de.derpAddr = nil |
|
|
|
|
de.derpAddr = netaddr.IPPort{} |
|
|
|
|
} else { |
|
|
|
|
// TODO: add ParseIPPort to netaddr package; only safe to use ResolveUDPAddr
|
|
|
|
|
// here because we know no DNS lookups are involved
|
|
|
|
|
ua, _ := net.ResolveUDPAddr("udp", n.DERP) |
|
|
|
|
de.derpAddr = ua |
|
|
|
|
de.derpAddr, _ = netaddr.ParseIPPort(n.DERP) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: parse all the endpoints, not just DERP
|
|
|
|
|
|