mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-10 09:45:08 +00:00
net, wgengine/capture: encode NAT addresses in pcap stream
Signed-off-by: Tom DNetto <tom@tailscale.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
_ "embed"
|
||||
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/util/set"
|
||||
)
|
||||
|
||||
@@ -26,7 +27,7 @@ var DissectorLua string
|
||||
// Such callbacks must not take ownership of the
|
||||
// provided data slice: it may only copy out of it
|
||||
// within the lifetime of the function.
|
||||
type Callback func(Path, time.Time, []byte)
|
||||
type Callback func(Path, time.Time, []byte, packet.CaptureMeta)
|
||||
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() any {
|
||||
@@ -159,24 +160,50 @@ func (s *Sink) WaitCh() <-chan struct{} {
|
||||
return s.ctx.Done()
|
||||
}
|
||||
|
||||
func customDataLen(meta packet.CaptureMeta) int {
|
||||
length := 4
|
||||
if meta.DidSNAT {
|
||||
length += meta.OriginalSrc.Addr().BitLen() / 8
|
||||
}
|
||||
if meta.DidDNAT {
|
||||
length += meta.OriginalDst.Addr().BitLen() / 8
|
||||
}
|
||||
return length
|
||||
}
|
||||
|
||||
// LogPacket is called to insert a packet into the capture.
|
||||
//
|
||||
// This function does not take ownership of the provided data slice.
|
||||
func (s *Sink) LogPacket(path Path, when time.Time, data []byte) {
|
||||
func (s *Sink) LogPacket(path Path, when time.Time, data []byte, meta packet.CaptureMeta) {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
extraLen := customDataLen(meta)
|
||||
b := bufferPool.Get().(*bytes.Buffer)
|
||||
b.Reset()
|
||||
b.Grow(16 + 2 + len(data)) // 16b pcap header + 2b custom data + len
|
||||
b.Grow(16 + extraLen + len(data)) // 16b pcap header + len(metadata) + len(payload)
|
||||
defer bufferPool.Put(b)
|
||||
|
||||
writePktHeader(b, when, len(data)+2)
|
||||
writePktHeader(b, when, len(data)+extraLen)
|
||||
|
||||
// Custom tailscale debugging data
|
||||
binary.Write(b, binary.LittleEndian, uint16(path))
|
||||
if meta.DidSNAT {
|
||||
binary.Write(b, binary.LittleEndian, uint8(meta.OriginalSrc.Addr().BitLen()/8))
|
||||
b.Write(meta.OriginalSrc.Addr().AsSlice())
|
||||
} else {
|
||||
binary.Write(b, binary.LittleEndian, uint8(0)) // SNAT addr len == 0
|
||||
}
|
||||
if meta.DidDNAT {
|
||||
binary.Write(b, binary.LittleEndian, uint8(meta.OriginalDst.Addr().BitLen()/8))
|
||||
b.Write(meta.OriginalDst.Addr().AsSlice())
|
||||
} else {
|
||||
binary.Write(b, binary.LittleEndian, uint8(0)) // DNAT addr len == 0
|
||||
}
|
||||
|
||||
b.Write(data)
|
||||
|
||||
s.mu.Lock()
|
||||
|
@@ -4,7 +4,11 @@ end
|
||||
|
||||
tsdebug_ll = Proto("tsdebug", "Tailscale debug")
|
||||
PATH = ProtoField.string("tsdebug.PATH","PATH", base.ASCII)
|
||||
tsdebug_ll.fields = {PATH}
|
||||
SNAT_IP_4 = ProtoField.ipv4("tsdebug.SNAT_IP_4", "Pre-NAT Source IPv4 address")
|
||||
SNAT_IP_6 = ProtoField.ipv4("tsdebug.SNAT_IP_6", "Pre-NAT Source IPv6 address")
|
||||
DNAT_IP_4 = ProtoField.ipv4("tsdebug.DNAT_IP_4", "Pre-NAT Dest IPv4 address")
|
||||
DNAT_IP_6 = ProtoField.ipv4("tsdebug.DNAT_IP_6", "Pre-NAT Dest IPv6 address")
|
||||
tsdebug_ll.fields = {PATH, SNAT_IP_4, SNAT_IP_6, DNAT_IP_4, DNAT_IP_6}
|
||||
|
||||
function tsdebug_ll.dissector(buffer, pinfo, tree)
|
||||
pinfo.cols.protocol = tsdebug_ll.name
|
||||
@@ -14,14 +18,28 @@ function tsdebug_ll.dissector(buffer, pinfo, tree)
|
||||
|
||||
-- -- Get path UINT16
|
||||
local path_id = buffer:range(offset, 2):le_uint()
|
||||
if path_id == 0 then subtree:add(PATH, "FromLocal")
|
||||
elseif path_id == 1 then subtree:add(PATH, "FromPeer")
|
||||
elseif path_id == 2 then subtree:add(PATH, "Synthesized (Inbound / ToLocal)")
|
||||
elseif path_id == 3 then subtree:add(PATH, "Synthesized (Outbound / ToPeer)")
|
||||
if path_id == 0 then subtree:add(PATH, "FromLocal")
|
||||
elseif path_id == 1 then subtree:add(PATH, "FromPeer")
|
||||
elseif path_id == 2 then subtree:add(PATH, "Synthesized (Inbound / ToLocal)")
|
||||
elseif path_id == 3 then subtree:add(PATH, "Synthesized (Outbound / ToPeer)")
|
||||
elseif path_id == 254 then subtree:add(PATH, "Disco frame")
|
||||
end
|
||||
offset = offset + 2
|
||||
|
||||
-- -- Get SNAT address
|
||||
local snat_addr_len = buffer:range(offset, 1):le_uint()
|
||||
if snat_addr_len == 4 then subtree:add(SNAT_IP_4, buffer:range(offset + 1, snat_addr_len))
|
||||
elseif snat_addr_len > 0 then subtree:add(SNAT_IP_6, buffer:range(offset + 1, snat_addr_len))
|
||||
end
|
||||
offset = offset + 1 + snat_addr_len
|
||||
|
||||
-- -- Get DNAT address
|
||||
local dnat_addr_len = buffer:range(offset, 1):le_uint()
|
||||
if dnat_addr_len == 4 then subtree:add(DNAT_IP_4, buffer:range(offset + 1, dnat_addr_len))
|
||||
elseif dnat_addr_len > 0 then subtree:add(DNAT_IP_6, buffer:range(offset + 1, dnat_addr_len))
|
||||
end
|
||||
offset = offset + 1 + dnat_addr_len
|
||||
|
||||
-- -- Handover rest of data to lower-level dissector
|
||||
local data_buffer = buffer:range(offset, packet_length-offset):tvb()
|
||||
if path_id == 254 then
|
||||
|
Reference in New Issue
Block a user