net, wgengine/capture: encode NAT addresses in pcap stream
Signed-off-by: Tom DNetto <tom@tailscale.com>
This commit is contained in:
@@ -34,6 +34,14 @@ const (
|
||||
TCPECNBits TCPFlag = TCPECNEcho | TCPCWR
|
||||
)
|
||||
|
||||
// CaptureMeta contains metadata that is used when debugging.
|
||||
type CaptureMeta struct {
|
||||
DidSNAT bool // SNAT was performed & the address was updated.
|
||||
OriginalSrc netip.AddrPort // The source address before SNAT was performed.
|
||||
DidDNAT bool // DNAT was performed & the address was updated.
|
||||
OriginalDst netip.AddrPort // The destination address before DNAT was performed.
|
||||
}
|
||||
|
||||
// Parsed is a minimal decoding of a packet suitable for use in filters.
|
||||
type Parsed struct {
|
||||
// b is the byte buffer that this decodes.
|
||||
@@ -58,6 +66,9 @@ type Parsed struct {
|
||||
Dst netip.AddrPort
|
||||
// TCPFlags is the packet's TCP flag bits. Valid iff IPProto == TCP.
|
||||
TCPFlags TCPFlag
|
||||
|
||||
// CaptureMeta contains metadata that is used when debugging.
|
||||
CaptureMeta CaptureMeta
|
||||
}
|
||||
|
||||
func (p *Parsed) String() string {
|
||||
@@ -84,6 +95,7 @@ func (p *Parsed) String() string {
|
||||
// and shouldn't need any memory allocation.
|
||||
func (q *Parsed) Decode(b []byte) {
|
||||
q.b = b
|
||||
q.CaptureMeta = CaptureMeta{} // Clear any capture metadata if it exists.
|
||||
|
||||
if len(b) < 1 {
|
||||
q.IPVersion = 0
|
||||
@@ -447,6 +459,8 @@ func (q *Parsed) UpdateSrcAddr(src netip.Addr) {
|
||||
if q.IPVersion != 4 || src.Is6() {
|
||||
panic("UpdateSrcAddr: only IPv4 is supported")
|
||||
}
|
||||
q.CaptureMeta.DidSNAT = true
|
||||
q.CaptureMeta.OriginalSrc = q.Src
|
||||
|
||||
old := q.Src.Addr()
|
||||
q.Src = netip.AddrPortFrom(src, q.Src.Port())
|
||||
@@ -465,6 +479,9 @@ func (q *Parsed) UpdateDstAddr(dst netip.Addr) {
|
||||
panic("UpdateDstAddr: only IPv4 is supported")
|
||||
}
|
||||
|
||||
q.CaptureMeta.DidDNAT = true
|
||||
q.CaptureMeta.OriginalDst = q.Dst
|
||||
|
||||
old := q.Dst.Addr()
|
||||
q.Dst = netip.AddrPortFrom(dst, q.Dst.Port())
|
||||
|
||||
|
||||
+18
-15
@@ -713,6 +713,7 @@ func (t *Wrapper) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
|
||||
var buffsPos int
|
||||
p := parsedPacketPool.Get().(*packet.Parsed)
|
||||
defer parsedPacketPool.Put(p)
|
||||
captHook := t.captureHook.Load()
|
||||
for _, data := range res.data {
|
||||
p.Decode(data[res.dataOffset:])
|
||||
|
||||
@@ -722,8 +723,8 @@ func (t *Wrapper) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
if capt := t.captureHook.Load(); capt != nil {
|
||||
capt(capture.FromLocal, time.Now(), p.Buffer())
|
||||
if captHook != nil {
|
||||
captHook(capture.FromLocal, time.Now(), p.Buffer(), p.CaptureMeta)
|
||||
}
|
||||
if !t.disableFilter {
|
||||
response := t.filterPacketOutboundToWireGuard(p)
|
||||
@@ -788,9 +789,9 @@ func (t *Wrapper) injectedRead(res tunInjectedRead, buf []byte, offset int) (int
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (t *Wrapper) filterPacketInboundFromWireGuard(p *packet.Parsed) filter.Response {
|
||||
if capt := t.captureHook.Load(); capt != nil {
|
||||
capt(capture.FromPeer, time.Now(), p.Buffer())
|
||||
func (t *Wrapper) filterPacketInboundFromWireGuard(p *packet.Parsed, captHook capture.Callback) filter.Response {
|
||||
if captHook != nil {
|
||||
captHook(capture.FromPeer, time.Now(), p.Buffer(), p.CaptureMeta)
|
||||
}
|
||||
|
||||
if p.IPProto == ipproto.TSMP {
|
||||
@@ -892,11 +893,12 @@ func (t *Wrapper) Write(buffs [][]byte, offset int) (int, error) {
|
||||
i := 0
|
||||
p := parsedPacketPool.Get().(*packet.Parsed)
|
||||
defer parsedPacketPool.Put(p)
|
||||
captHook := t.captureHook.Load()
|
||||
for _, buff := range buffs {
|
||||
p.Decode(buff[offset:])
|
||||
t.dnatV4(p)
|
||||
if !t.disableFilter {
|
||||
if t.filterPacketInboundFromWireGuard(p) != filter.Accept {
|
||||
if t.filterPacketInboundFromWireGuard(p, captHook) != filter.Accept {
|
||||
metricPacketInDrop.Add(1)
|
||||
} else {
|
||||
buffs[i] = buff
|
||||
@@ -955,8 +957,9 @@ func (t *Wrapper) InjectInboundPacketBuffer(pkt stack.PacketBufferPtr) error {
|
||||
p := parsedPacketPool.Get().(*packet.Parsed)
|
||||
defer parsedPacketPool.Put(p)
|
||||
p.Decode(buf[PacketStartOffset:])
|
||||
if capt := t.captureHook.Load(); capt != nil {
|
||||
capt(capture.SynthesizedToLocal, time.Now(), p.Buffer())
|
||||
captHook := t.captureHook.Load()
|
||||
if captHook != nil {
|
||||
captHook(capture.SynthesizedToLocal, time.Now(), p.Buffer(), p.CaptureMeta)
|
||||
}
|
||||
t.dnatV4(p)
|
||||
|
||||
@@ -1048,22 +1051,22 @@ func (t *Wrapper) InjectOutbound(packet []byte) error {
|
||||
// InjectOutboundPacketBuffer logically behaves as InjectOutbound. It takes ownership of one
|
||||
// reference count on the packet, and the packet may be mutated. The packet refcount will be
|
||||
// decremented after the injected buffer has been read.
|
||||
func (t *Wrapper) InjectOutboundPacketBuffer(packet stack.PacketBufferPtr) error {
|
||||
size := packet.Size()
|
||||
func (t *Wrapper) InjectOutboundPacketBuffer(pkt stack.PacketBufferPtr) error {
|
||||
size := pkt.Size()
|
||||
if size > MaxPacketSize {
|
||||
packet.DecRef()
|
||||
pkt.DecRef()
|
||||
return errPacketTooBig
|
||||
}
|
||||
if size == 0 {
|
||||
packet.DecRef()
|
||||
pkt.DecRef()
|
||||
return nil
|
||||
}
|
||||
if capt := t.captureHook.Load(); capt != nil {
|
||||
b := packet.ToBuffer()
|
||||
capt(capture.SynthesizedToPeer, time.Now(), b.Flatten())
|
||||
b := pkt.ToBuffer()
|
||||
capt(capture.SynthesizedToPeer, time.Now(), b.Flatten(), packet.CaptureMeta{})
|
||||
}
|
||||
|
||||
t.injectOutbound(tunInjectedRead{packet: packet})
|
||||
t.injectOutbound(tunInjectedRead{packet: pkt})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -545,7 +545,7 @@ func TestPeerAPIBypass(t *testing.T) {
|
||||
tt.w.SetFilter(tt.filter)
|
||||
tt.w.disableTSMPRejected = true
|
||||
tt.w.logf = t.Logf
|
||||
if got := tt.w.filterPacketInboundFromWireGuard(p); got != tt.want {
|
||||
if got := tt.w.filterPacketInboundFromWireGuard(p, nil); got != tt.want {
|
||||
t.Errorf("got = %v; want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
@@ -575,7 +575,7 @@ func TestFilterDiscoLoop(t *testing.T) {
|
||||
|
||||
p := new(packet.Parsed)
|
||||
p.Decode(pkt)
|
||||
got := tw.filterPacketInboundFromWireGuard(p)
|
||||
got := tw.filterPacketInboundFromWireGuard(p, nil)
|
||||
if got != filter.DropSilently {
|
||||
t.Errorf("got %v; want DropSilently", got)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user