-
-
Notifications
You must be signed in to change notification settings - Fork 538
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[client] Add stateful userspace firewall and remove egress filters (#…
…3093) - Add stateful firewall functionality for UDP/TCP/ICMP in userspace firewalll - Removes all egress drop rules/filters, still needs refactoring so we don't add output rules to any chains/filters. - on Linux, if the OUTPUT policy is DROP then we don't do anything about it (no extra allow rules). This is up to the user, if they don't want anything leaving their machine they'll have to manage these rules explicitly.
- Loading branch information
Showing
16 changed files
with
3,099 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
// common.go | ||
package conntrack | ||
|
||
import ( | ||
"net" | ||
"sync" | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
// BaseConnTrack provides common fields and locking for all connection types | ||
type BaseConnTrack struct { | ||
sync.RWMutex | ||
SourceIP net.IP | ||
DestIP net.IP | ||
SourcePort uint16 | ||
DestPort uint16 | ||
lastSeen atomic.Int64 // Unix nano for atomic access | ||
established atomic.Bool | ||
} | ||
|
||
// these small methods will be inlined by the compiler | ||
|
||
// UpdateLastSeen safely updates the last seen timestamp | ||
func (b *BaseConnTrack) UpdateLastSeen() { | ||
b.lastSeen.Store(time.Now().UnixNano()) | ||
} | ||
|
||
// IsEstablished safely checks if connection is established | ||
func (b *BaseConnTrack) IsEstablished() bool { | ||
return b.established.Load() | ||
} | ||
|
||
// SetEstablished safely sets the established state | ||
func (b *BaseConnTrack) SetEstablished(state bool) { | ||
b.established.Store(state) | ||
} | ||
|
||
// GetLastSeen safely gets the last seen timestamp | ||
func (b *BaseConnTrack) GetLastSeen() time.Time { | ||
return time.Unix(0, b.lastSeen.Load()) | ||
} | ||
|
||
// timeoutExceeded checks if the connection has exceeded the given timeout | ||
func (b *BaseConnTrack) timeoutExceeded(timeout time.Duration) bool { | ||
lastSeen := time.Unix(0, b.lastSeen.Load()) | ||
return time.Since(lastSeen) > timeout | ||
} | ||
|
||
// IPAddr is a fixed-size IP address to avoid allocations | ||
type IPAddr [16]byte | ||
|
||
// MakeIPAddr creates an IPAddr from net.IP | ||
func MakeIPAddr(ip net.IP) (addr IPAddr) { | ||
// Optimization: check for v4 first as it's more common | ||
if ip4 := ip.To4(); ip4 != nil { | ||
copy(addr[12:], ip4) | ||
} else { | ||
copy(addr[:], ip.To16()) | ||
} | ||
return addr | ||
} | ||
|
||
// ConnKey uniquely identifies a connection | ||
type ConnKey struct { | ||
SrcIP IPAddr | ||
DstIP IPAddr | ||
SrcPort uint16 | ||
DstPort uint16 | ||
} | ||
|
||
// makeConnKey creates a connection key | ||
func makeConnKey(srcIP net.IP, dstIP net.IP, srcPort uint16, dstPort uint16) ConnKey { | ||
return ConnKey{ | ||
SrcIP: MakeIPAddr(srcIP), | ||
DstIP: MakeIPAddr(dstIP), | ||
SrcPort: srcPort, | ||
DstPort: dstPort, | ||
} | ||
} | ||
|
||
// ValidateIPs checks if IPs match without allocation | ||
func ValidateIPs(connIP IPAddr, pktIP net.IP) bool { | ||
if ip4 := pktIP.To4(); ip4 != nil { | ||
// Compare IPv4 addresses (last 4 bytes) | ||
for i := 0; i < 4; i++ { | ||
if connIP[12+i] != ip4[i] { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
// Compare full IPv6 addresses | ||
ip6 := pktIP.To16() | ||
for i := 0; i < 16; i++ { | ||
if connIP[i] != ip6[i] { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// PreallocatedIPs is a pool of IP byte slices to reduce allocations | ||
type PreallocatedIPs struct { | ||
sync.Pool | ||
} | ||
|
||
// NewPreallocatedIPs creates a new IP pool | ||
func NewPreallocatedIPs() *PreallocatedIPs { | ||
return &PreallocatedIPs{ | ||
Pool: sync.Pool{ | ||
New: func() interface{} { | ||
ip := make(net.IP, 16) | ||
return &ip | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// Get retrieves an IP from the pool | ||
func (p *PreallocatedIPs) Get() net.IP { | ||
return *p.Pool.Get().(*net.IP) | ||
} | ||
|
||
// Put returns an IP to the pool | ||
func (p *PreallocatedIPs) Put(ip net.IP) { | ||
p.Pool.Put(&ip) | ||
} | ||
|
||
// copyIP copies an IP address efficiently | ||
func copyIP(dst, src net.IP) { | ||
if len(src) == 16 { | ||
copy(dst, src) | ||
} else { | ||
// Handle IPv4 | ||
copy(dst[12:], src.To4()) | ||
} | ||
} |
Oops, something went wrong.