Skip to content

Commit

Permalink
disco: move disco pcap helper to disco package
Browse files Browse the repository at this point in the history
Updates tailscale/corp#13464

Signed-off-by: David Anderson <[email protected]>
  • Loading branch information
danderson committed Jul 26, 2023
1 parent cde37f5 commit 9a76deb
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 42 deletions.
40 changes: 40 additions & 0 deletions disco/pcap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause

package disco

import (
"bytes"
"encoding/binary"
"net/netip"

"tailscale.com/tailcfg"
"tailscale.com/types/key"
)

// ToPCAPFrame marshals the bytes for a pcap record that describe a disco frame.
//
// Warning: Alloc garbage. Acceptable while capturing.
func ToPCAPFrame(src netip.AddrPort, derpNodeSrc key.NodePublic, payload []byte) []byte {
var (
b bytes.Buffer
flag uint8
)
b.Grow(128) // Most disco frames will probably be smaller than this.

if src.Addr() == tailcfg.DerpMagicIPAddr {
flag |= 0x01
}
b.WriteByte(flag) // 1b: flag

derpSrc := derpNodeSrc.Raw32()
b.Write(derpSrc[:]) // 32b: derp public key
binary.Write(&b, binary.LittleEndian, uint16(src.Port())) // 2b: port
addr, _ := src.Addr().MarshalBinary()
binary.Write(&b, binary.LittleEndian, uint16(len(addr))) // 2b: len(addr)
b.Write(addr) // Xb: addr
binary.Write(&b, binary.LittleEndian, uint16(len(payload))) // 2b: len(payload)
b.Write(payload) // Xb: payload

return b.Bytes()
}
2 changes: 2 additions & 0 deletions tailcfg/tailcfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -2351,6 +2351,8 @@ type PeerChange struct {
// Mnemonic: 3.3.40 are numbers above the keys D, E, R, P.
const DerpMagicIP = "127.3.3.40"

var DerpMagicIPAddr = netip.MustParseAddr(DerpMagicIP)

// EarlyNoise is the early payload that's sent over Noise but before the HTTP/2
// handshake when connecting to the coordination server.
//
Expand Down
2 changes: 1 addition & 1 deletion wgengine/magicsock/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ func (de *endpoint) handlePongConnLocked(m *disco.Pong, di *discoInfo, src netip
de.mu.Lock()
defer de.mu.Unlock()

isDerp := src.Addr() == derpMagicIPAddr
isDerp := src.Addr() == tailcfg.DerpMagicIPAddr

sp, ok := de.sentPing[m.TxID]
if !ok {
Expand Down
50 changes: 9 additions & 41 deletions wgengine/magicsock/magicsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ package magicsock

import (
"bufio"
"bytes"
"context"
crand "crypto/rand"
"encoding/binary"
"errors"
"fmt"
"hash/fnv"
Expand Down Expand Up @@ -357,8 +355,6 @@ func (c *Conn) addDerpPeerRoute(peer key.NodePublic, derpID int, dc *derphttp.Cl
mak.Set(&c.derpRoute, peer, derpRoute{derpID, dc})
}

var derpMagicIPAddr = netip.MustParseAddr(tailcfg.DerpMagicIP)

// activeDerp contains fields for an active DERP connection.
type activeDerp struct {
c *derphttp.Client
Expand Down Expand Up @@ -860,7 +856,7 @@ func (c *Conn) Ping(peer *tailcfg.Node, res *ipnstate.PingResult, cb func(*ipnst
// c.mu must be held
func (c *Conn) populateCLIPingResponseLocked(res *ipnstate.PingResult, latency time.Duration, ep netip.AddrPort) {
res.LatencySeconds = latency.Seconds()
if ep.Addr() != derpMagicIPAddr {
if ep.Addr() != tailcfg.DerpMagicIPAddr {
res.Endpoint = ep.String()
return
}
Expand Down Expand Up @@ -958,7 +954,7 @@ func (c *Conn) goDerpConnect(node int) {
if node == 0 {
return
}
go c.derpWriteChanOfAddr(netip.AddrPortFrom(derpMagicIPAddr, uint16(node)), key.NodePublic{})
go c.derpWriteChanOfAddr(netip.AddrPortFrom(tailcfg.DerpMagicIPAddr, uint16(node)), key.NodePublic{})
}

// determineEndpoints returns the machine's endpoint addresses. It
Expand Down Expand Up @@ -1232,7 +1228,7 @@ func (c *Conn) sendUDPStd(addr netip.AddrPort, b []byte) (sent bool, err error)
// IPv6 address when the local machine doesn't have IPv6 support
// returns (false, nil); it's not an error, but nothing was sent.
func (c *Conn) sendAddr(addr netip.AddrPort, pubKey key.NodePublic, b []byte) (sent bool, err error) {
if addr.Addr() != derpMagicIPAddr {
if addr.Addr() != tailcfg.DerpMagicIPAddr {
return c.sendUDP(addr, b)
}

Expand Down Expand Up @@ -1325,7 +1321,7 @@ func bufferedDerpWritesBeforeDrop() int {
// If peer is non-zero, it can be used to find an active reverse
// path, without using addr.
func (c *Conn) derpWriteChanOfAddr(addr netip.AddrPort, peer key.NodePublic) chan<- derpWriteRequest {
if addr.Addr() != derpMagicIPAddr {
if addr.Addr() != tailcfg.DerpMagicIPAddr {
return nil
}
regionID := int(addr.Port())
Expand Down Expand Up @@ -1839,7 +1835,7 @@ func (c *Conn) processDERPReadResult(dm derpReadResult, b []byte) (n int, ep *en
return 0, nil
}

ipp := netip.AddrPortFrom(derpMagicIPAddr, uint16(regionID))
ipp := netip.AddrPortFrom(tailcfg.DerpMagicIPAddr, uint16(regionID))
if c.handleDiscoMessage(b[:n], ipp, dm.src, discoRXPathDERP) {
return 0, nil
}
Expand Down Expand Up @@ -1886,7 +1882,7 @@ var debugIPv4DiscoPingPenalty = envknob.RegisterDuration("TS_DISCO_PONG_IPV4_DEL
// The dstKey should only be non-zero if the dstDisco key
// unambiguously maps to exactly one peer.
func (c *Conn) sendDiscoMessage(dst netip.AddrPort, dstKey key.NodePublic, dstDisco key.DiscoPublic, m disco.Message, logLevel discoLogLevel) (sent bool, err error) {
isDERP := dst.Addr() == derpMagicIPAddr
isDERP := dst.Addr() == tailcfg.DerpMagicIPAddr
if _, isPong := m.(*disco.Pong); isPong && !isDERP && dst.Addr().Is4() {
time.Sleep(debugIPv4DiscoPingPenalty())
}
Expand Down Expand Up @@ -1946,34 +1942,6 @@ func (c *Conn) sendDiscoMessage(dst netip.AddrPort, dstKey key.NodePublic, dstDi
return sent, err
}

// discoPcapFrame marshals the bytes for a pcap record that describe a
// disco frame.
//
// Warning: Alloc garbage. Acceptable while capturing.
func discoPcapFrame(src netip.AddrPort, derpNodeSrc key.NodePublic, payload []byte) []byte {
var (
b bytes.Buffer
flag uint8
)
b.Grow(128) // Most disco frames will probably be smaller than this.

if src.Addr() == derpMagicIPAddr {
flag |= 0x01
}
b.WriteByte(flag) // 1b: flag

derpSrc := derpNodeSrc.Raw32()
b.Write(derpSrc[:]) // 32b: derp public key
binary.Write(&b, binary.LittleEndian, uint16(src.Port())) // 2b: port
addr, _ := src.Addr().MarshalBinary()
binary.Write(&b, binary.LittleEndian, uint16(len(addr))) // 2b: len(addr)
b.Write(addr) // Xb: addr
binary.Write(&b, binary.LittleEndian, uint16(len(payload))) // 2b: len(payload)
b.Write(payload) // Xb: payload

return b.Bytes()
}

type discoRXPath string

const (
Expand Down Expand Up @@ -2063,7 +2031,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
// Emit information about the disco frame into the pcap stream
// if a capture hook is installed.
if cb := c.captureHook.Load(); cb != nil {
cb(capture.PathDisco, time.Now(), discoPcapFrame(src, derpNodeSrc, payload), packet.CaptureMeta{})
cb(capture.PathDisco, time.Now(), disco.ToPCAPFrame(src, derpNodeSrc, payload), packet.CaptureMeta{})
}

dm, err := disco.Parse(payload)
Expand All @@ -2080,7 +2048,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
return
}

isDERP := src.Addr() == derpMagicIPAddr
isDERP := src.Addr() == tailcfg.DerpMagicIPAddr
if isDERP {
metricRecvDiscoDERP.Add(1)
} else {
Expand Down Expand Up @@ -2178,7 +2146,7 @@ func (c *Conn) handlePingLocked(dm *disco.Ping, src netip.AddrPort, di *discoInf
likelyHeartBeat := src == di.lastPingFrom && time.Since(di.lastPingTime) < 5*time.Second
di.lastPingFrom = src
di.lastPingTime = time.Now()
isDerp := src.Addr() == derpMagicIPAddr
isDerp := src.Addr() == tailcfg.DerpMagicIPAddr

// If we can figure out with certainty which node key this disco
// message is for, eagerly update our IP<>node and disco<>node
Expand Down

0 comments on commit 9a76deb

Please sign in to comment.