tstest/natlab/vnet: capture network wan/lan interfaces

Updates #13038

Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
Maisem Ali
2024-08-08 21:29:09 -07:00
committed by Maisem Ali
parent 7aec8d4e6b
commit 10c2bee9e1
3 changed files with 123 additions and 52 deletions

View File

@@ -404,13 +404,15 @@ type portMapping struct {
}
type network struct {
s *Server
mac MAC
portmap bool
wanIP netip.Addr
lanIP netip.Prefix // with host bits set (e.g. 192.168.2.1/24)
nodesByIP map[netip.Addr]*node
logf func(format string, args ...any)
s *Server
mac MAC
portmap bool
lanInterfaceID int
wanInterfaceID int
wanIP netip.Addr
lanIP netip.Prefix // with host bits set (e.g. 192.168.2.1/24)
nodesByIP map[netip.Addr]*node
logf func(format string, args ...any)
ns *stack.Stack
linkEP *channel.Endpoint
@@ -445,10 +447,10 @@ func (n *network) MACOfIP(ip netip.Addr) (_ MAC, ok bool) {
}
type node struct {
mac MAC
id int
net *network
lanIP netip.Addr // must be in net.lanIP prefix + unique in net
mac MAC
interfaceID int
net *network
lanIP netip.Addr // must be in net.lanIP prefix + unique in net
}
type derpServer struct {
@@ -570,9 +572,7 @@ func New(c *Config) (*Server, error) {
func (s *Server) Close() {
if shutdown := s.shuttingDown.Swap(true); !shutdown {
s.shutdownCancel()
if s.pcapWriter != nil {
s.pcapWriter.Close()
}
s.pcapWriter.Close()
}
s.wg.Wait()
}
@@ -647,17 +647,12 @@ func (s *Server) ServeUnixConn(uc *net.UnixConn, proto Protocol) {
if err := bw.Flush(); err != nil {
log.Printf("Flush: %v", err)
}
if s.pcapWriter != nil {
ci := gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(pkt),
Length: len(pkt),
}
if srcNode != nil {
ci.InterfaceIndex = srcNode.id
}
must.Do(s.pcapWriter.WritePacket(ci, pkt))
}
must.Do(s.pcapWriter.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(pkt),
Length: len(pkt),
InterfaceIndex: srcNode.interfaceID,
}, pkt))
}
buf := make([]byte, 16<<10)
@@ -717,17 +712,12 @@ func (s *Server) ServeUnixConn(uc *net.UnixConn, proto Protocol) {
continue
}
}
if s.pcapWriter != nil {
ci := gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(packetRaw),
Length: len(packetRaw),
}
if srcNode != nil {
ci.InterfaceIndex = srcNode.id
}
must.Do(s.pcapWriter.WritePacket(ci, packetRaw))
}
must.Do(s.pcapWriter.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(packetRaw),
Length: len(packetRaw),
InterfaceIndex: srcNode.interfaceID,
}, packetRaw))
netw.HandleEthernetPacket(ep)
}
}
@@ -825,12 +815,34 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
// LAN IP here and wrapped in an ethernet layer and delivered
// to the network.
func (n *network) HandleUDPPacket(p UDPPacket) {
buf, err := n.serializedUDPPacket(p.Src, p.Dst, p.Payload, nil)
if err != nil {
n.logf("serializing UDP packet: %v", err)
return
}
n.s.pcapWriter.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(buf),
Length: len(buf),
InterfaceIndex: n.wanInterfaceID,
}, buf)
dst := n.doNATIn(p.Src, p.Dst)
if !dst.IsValid() {
n.logf("Warning: NAT dropped packet; no mapping for %v=>%v", p.Src, p.Dst)
return
}
p.Dst = dst
buf, err = n.serializedUDPPacket(p.Src, p.Dst, p.Payload, nil)
if err != nil {
n.logf("serializing UDP packet: %v", err)
return
}
n.s.pcapWriter.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(buf),
Length: len(buf),
InterfaceIndex: n.lanInterfaceID,
}, buf)
n.WriteUDPPacketNoNAT(p)
}
@@ -853,6 +865,20 @@ func (n *network) WriteUDPPacketNoNAT(p UDPPacket) {
DstMAC: node.mac.HWAddr(),
EthernetType: layers.EthernetTypeIPv4,
}
ethRaw, err := n.serializedUDPPacket(src, dst, p.Payload, eth)
if err != nil {
n.logf("serializing UDP packet: %v", err)
return
}
n.writeEth(ethRaw)
}
// serializedUDPPacket serializes a UDP packet with the given source and
// destination IP:port pairs, and payload.
//
// If eth is non-nil, it will be used as the Ethernet layer, otherwise the
// Ethernet layer will be omitted from the serialization.
func (n *network) serializedUDPPacket(src, dst netip.AddrPort, payload []byte, eth *layers.Ethernet) ([]byte, error) {
ip := &layers.IPv4{
Version: 4,
TTL: 64,
@@ -868,12 +894,14 @@ func (n *network) WriteUDPPacketNoNAT(p UDPPacket) {
buffer := gopacket.NewSerializeBuffer()
options := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
if err := gopacket.SerializeLayers(buffer, options, eth, ip, udp, gopacket.Payload(p.Payload)); err != nil {
n.logf("serializing UDP: %v", err)
return
layers := []gopacket.SerializableLayer{eth, ip, udp, gopacket.Payload(payload)}
if eth == nil {
layers = layers[1:]
}
ethRaw := buffer.Bytes()
n.writeEth(ethRaw)
if err := gopacket.SerializeLayers(buffer, options, layers...); err != nil {
return nil, fmt.Errorf("serializing UDP: %v", err)
}
return buffer.Bytes(), nil
}
// HandleEthernetIPv4PacketForRouter handles an IPv4 packet that is
@@ -931,10 +959,30 @@ func (n *network) HandleEthernetIPv4PacketForRouter(ep EthernetPacket) {
if toForward && isUDP {
src := netip.AddrPortFrom(srcIP, uint16(udp.SrcPort))
dst := netip.AddrPortFrom(dstIP, uint16(udp.DstPort))
src0 := src
buf, err := n.serializedUDPPacket(src, dst, udp.Payload, nil)
if err != nil {
n.logf("serializing UDP packet: %v", err)
return
}
n.s.pcapWriter.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(buf),
Length: len(buf),
InterfaceIndex: n.lanInterfaceID,
}, buf)
src = n.doNATOut(src, dst)
_ = src0
//log.Printf("XXX UDP out %v=>%v to %v", src0, src, dst)
buf, err = n.serializedUDPPacket(src, dst, udp.Payload, nil)
if err != nil {
n.logf("serializing UDP packet: %v", err)
return
}
n.s.pcapWriter.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
CaptureLength: len(buf),
Length: len(buf),
InterfaceIndex: n.wanInterfaceID,
}, buf)
n.s.routeUDPPacket(UDPPacket{
Src: src,