Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
133f004
Add IPv6 support to ACL manager, USP filter, and forwarder
lixmal Mar 24, 2026
780fd66
Fix review findings: v6 block rule, PMTUD, eBPF typed IP, tracer vali…
lixmal Mar 25, 2026
569244a
Merge branch 'client-ipv6-ssh-netflow' into client-ipv6-acl-usp
lixmal Mar 25, 2026
7fe417c
Merge branch 'client-ipv6-ssh-netflow' into client-ipv6-acl-usp
lixmal Mar 25, 2026
5e1cdd7
Fix localip bitmap aliasing and bench test indentation
lixmal Mar 25, 2026
aebf3ce
Merge branch 'client-ipv6-ssh-netflow' into client-ipv6-acl-usp
lixmal Mar 25, 2026
76414a1
Merge branch 'client-ipv6-ssh-netflow' into client-ipv6-acl-usp
lixmal Mar 26, 2026
fcf8c4b
Handle ICMP directly in forwarder, bypassing gVisor network layer
lixmal Mar 27, 2026
ed5cfa6
Fix CodeRabbit findings: fragment guard, v6 raw socket probe, v6 echo…
lixmal Mar 27, 2026
974ea1f
Merge remote-tracking branch 'origin/proto-ipv6-overlay' into client-…
lixmal Apr 7, 2026
01068dd
Merge remote-tracking branch 'origin/proto-ipv6-overlay' into client-…
lixmal Apr 7, 2026
b7c8c5b
Use raw socket for ICMPv6 echo when available, recompute checksum for…
lixmal Apr 8, 2026
5ccf521
Merge branch 'proto-ipv6-overlay' into client-ipv6-acl-usp
lixmal Apr 8, 2026
c3fb0f9
Add ICMPv6 echo ID/Seq to tracer packet builder and conntrack messages
lixmal Apr 8, 2026
dcd8562
Merge remote-tracking branch 'origin/proto-ipv6-overlay' into client-…
lixmal Apr 9, 2026
5063fea
[client] Add IPv6 routing, fake IPs, and DNS bind selection (#5706)
lixmal Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 62 additions & 21 deletions client/firewall/uspfilter/conntrack/icmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ const (
// ICMPCleanupInterval is how often we check for stale ICMP connections
ICMPCleanupInterval = 15 * time.Second

// MaxICMPPayloadLength is the maximum length of ICMP payload we consider for original packet info,
// which includes the IP header (20 bytes) and transport header (8 bytes)
MaxICMPPayloadLength = 28
// MaxICMPPayloadLength is the maximum length of ICMP payload we consider for original packet info.
// IPv4: 20-byte header + 8-byte transport = 28 bytes.
// IPv6: 40-byte header + 8-byte transport = 48 bytes.
MaxICMPPayloadLength = 48
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)

// ICMPConnKey uniquely identifies an ICMP connection
Expand Down Expand Up @@ -74,31 +75,63 @@ func (info ICMPInfo) String() string {
return info.TypeCode.String()
}

// isErrorMessage returns true if this ICMP type carries original packet info
// isErrorMessage returns true if this ICMP type carries original packet info.
// Covers both ICMPv4 and ICMPv6 error types. Without a family field we match
// both sets; type 3 overlaps (v4 DestUnreachable / v6 TimeExceeded) so it's
// kept as a literal.
func (info ICMPInfo) isErrorMessage() bool {
typ := info.TypeCode.Type()
return typ == 3 || // Destination Unreachable
typ == 5 || // Redirect
typ == 11 || // Time Exceeded
typ == 12 // Parameter Problem
// ICMPv4 error types
if typ == layers.ICMPv4TypeDestinationUnreachable ||
typ == layers.ICMPv4TypeRedirect ||
typ == layers.ICMPv4TypeTimeExceeded ||
typ == layers.ICMPv4TypeParameterProblem {
return true
}
// ICMPv6 error types (type 3 already matched above as v4 DestUnreachable)
if typ == layers.ICMPv6TypeDestinationUnreachable ||
typ == layers.ICMPv6TypePacketTooBig ||
typ == layers.ICMPv6TypeParameterProblem {
return true
}
return false
}

// parseOriginalPacket extracts info about the original packet from ICMP payload
func (info ICMPInfo) parseOriginalPacket() string {
if info.PayloadLen < MaxICMPPayloadLength {
if info.PayloadLen == 0 {
return ""
}

// TODO: handle IPv6
if version := (info.PayloadData[0] >> 4) & 0xF; version != 4 {
return ""
}
version := (info.PayloadData[0] >> 4) & 0xF

protocol := info.PayloadData[9]
srcIP := net.IP(info.PayloadData[12:16])
dstIP := net.IP(info.PayloadData[16:20])
var protocol uint8
var srcIP, dstIP net.IP
var transportData []byte

transportData := info.PayloadData[20:]
switch version {
case 4:
// 20-byte IPv4 header + 8-byte transport minimum
if info.PayloadLen < 28 {
return ""
}
protocol = info.PayloadData[9]
srcIP = net.IP(info.PayloadData[12:16])
dstIP = net.IP(info.PayloadData[16:20])
transportData = info.PayloadData[20:]
case 6:
// 40-byte IPv6 header + 8-byte transport minimum
if info.PayloadLen < 48 {
return ""
}
// Next Header field in IPv6 header
protocol = info.PayloadData[6]
srcIP = net.IP(info.PayloadData[8:24])
dstIP = net.IP(info.PayloadData[24:40])
transportData = info.PayloadData[40:]
default:
return ""
}

switch nftypes.Protocol(protocol) {
case nftypes.TCP:
Expand Down Expand Up @@ -247,9 +280,10 @@ func (t *ICMPTracker) track(
t.sendEvent(nftypes.TypeStart, conn, ruleId)
}

// IsValidInbound checks if an inbound ICMP Echo Reply matches a tracked request
// IsValidInbound checks if an inbound ICMP Echo Reply matches a tracked request.
// Accepts both ICMPv4 (type 0) and ICMPv6 (type 129) echo replies.
func (t *ICMPTracker) IsValidInbound(srcIP netip.Addr, dstIP netip.Addr, id uint16, icmpType uint8, size int) bool {
if icmpType != uint8(layers.ICMPv4TypeEchoReply) {
if icmpType != uint8(layers.ICMPv4TypeEchoReply) && icmpType != uint8(layers.ICMPv6TypeEchoReply) {
return false
}

Expand Down Expand Up @@ -301,6 +335,13 @@ func (t *ICMPTracker) cleanup() {
}
}

func icmpProtocolForAddr(ip netip.Addr) nftypes.Protocol {
if ip.Is6() {
return nftypes.ICMPv6
}
return nftypes.ICMP
}

// Close stops the cleanup routine and releases resources
func (t *ICMPTracker) Close() {
t.tickerCancel()
Expand All @@ -316,7 +357,7 @@ func (t *ICMPTracker) sendEvent(typ nftypes.Type, conn *ICMPConnTrack, ruleID []
Type: typ,
RuleID: ruleID,
Direction: conn.Direction,
Protocol: nftypes.ICMP, // TODO: adjust for IPv6/icmpv6
Protocol: icmpProtocolForAddr(conn.SourceIP),
SourceIP: conn.SourceIP,
DestIP: conn.DestIP,
ICMPType: conn.ICMPType,
Expand All @@ -334,7 +375,7 @@ func (t *ICMPTracker) sendStartEvent(direction nftypes.Direction, srcIP netip.Ad
Type: nftypes.TypeStart,
RuleID: ruleID,
Direction: direction,
Protocol: nftypes.ICMP,
Protocol: icmpProtocolForAddr(srcIP),
SourceIP: srcIP,
DestIP: dstIP,
ICMPType: typ,
Expand Down
Loading
Loading