mirror of
https://github.com/fosrl/gerbil.git
synced 2026-02-07 21:46:40 +00:00
Rebuild sessions
This commit is contained in:
140
relay/relay.go
140
relay/relay.go
@@ -64,6 +64,17 @@ type WireGuardSession struct {
|
|||||||
LastSeen time.Time
|
LastSeen time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type for tracking bidirectional communication patterns to rebuild sessions
|
||||||
|
type CommunicationPattern struct {
|
||||||
|
FromClient *net.UDPAddr // The client address
|
||||||
|
ToDestination *net.UDPAddr // The destination address
|
||||||
|
ClientIndex uint32 // The receiver index seen from client
|
||||||
|
DestIndex uint32 // The receiver index seen from destination
|
||||||
|
LastFromClient time.Time // Last packet from client to destination
|
||||||
|
LastFromDest time.Time // Last packet from destination to client
|
||||||
|
PacketCount int // Number of packets observed
|
||||||
|
}
|
||||||
|
|
||||||
type InitialMappings struct {
|
type InitialMappings struct {
|
||||||
Mappings map[string]ProxyMapping `json:"mappings"` // key is "ip:port"
|
Mappings map[string]ProxyMapping `json:"mappings"` // key is "ip:port"
|
||||||
}
|
}
|
||||||
@@ -105,6 +116,9 @@ type UDPProxyServer struct {
|
|||||||
// Session tracking for WireGuard peers
|
// Session tracking for WireGuard peers
|
||||||
// Key format: "senderIndex:receiverIndex"
|
// Key format: "senderIndex:receiverIndex"
|
||||||
wgSessions sync.Map
|
wgSessions sync.Map
|
||||||
|
// Communication pattern tracking for rebuilding sessions
|
||||||
|
// Key format: "clientIP:clientPort-destIP:destPort"
|
||||||
|
commPatterns sync.Map
|
||||||
// ReachableAt is the URL where this server can be reached
|
// ReachableAt is the URL where this server can be reached
|
||||||
ReachableAt string
|
ReachableAt string
|
||||||
}
|
}
|
||||||
@@ -156,6 +170,9 @@ func (s *UDPProxyServer) Start() error {
|
|||||||
// Start the proxy mapping cleanup routine
|
// Start the proxy mapping cleanup routine
|
||||||
go s.cleanupIdleProxyMappings()
|
go s.cleanupIdleProxyMappings()
|
||||||
|
|
||||||
|
// Start the communication pattern cleanup routine
|
||||||
|
go s.cleanupIdleCommunicationPatterns()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +462,9 @@ func (s *UDPProxyServer) handleWireGuardPacket(packet []byte, remoteAddr *net.UD
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track communication pattern for session rebuilding
|
||||||
|
s.trackCommunicationPattern(remoteAddr, destAddr, receiverIndex, true)
|
||||||
|
|
||||||
_, err = conn.Write(packet)
|
_, err = conn.Write(packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug("Failed to forward transport data: %v", err)
|
logger.Debug("Failed to forward transport data: %v", err)
|
||||||
@@ -465,6 +485,9 @@ func (s *UDPProxyServer) handleWireGuardPacket(packet []byte, remoteAddr *net.UD
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track communication pattern for session rebuilding
|
||||||
|
s.trackCommunicationPattern(remoteAddr, destAddr, receiverIndex, true)
|
||||||
|
|
||||||
_, err = conn.Write(packet)
|
_, err = conn.Write(packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug("Failed to forward transport data: %v", err)
|
logger.Debug("Failed to forward transport data: %v", err)
|
||||||
@@ -548,6 +571,9 @@ func (s *UDPProxyServer) handleResponses(conn *net.UDPConn, destAddr *net.UDPAdd
|
|||||||
LastSeen: time.Now(),
|
LastSeen: time.Now(),
|
||||||
})
|
})
|
||||||
logger.Debug("Stored session mapping: %s -> %s", sessionKey, destAddr.String())
|
logger.Debug("Stored session mapping: %s -> %s", sessionKey, destAddr.String())
|
||||||
|
} else if ok && buffer[0] == WireGuardMessageTypeTransportData {
|
||||||
|
// Track communication pattern for session rebuilding (reverse direction)
|
||||||
|
s.trackCommunicationPattern(destAddr, remoteAddr, receiverIndex, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -823,3 +849,117 @@ func (s *UDPProxyServer) UpdateDestinationInMappings(oldDest, newDest PeerDestin
|
|||||||
|
|
||||||
return updatedCount
|
return updatedCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trackCommunicationPattern tracks bidirectional communication patterns to rebuild sessions
|
||||||
|
func (s *UDPProxyServer) trackCommunicationPattern(fromAddr, toAddr *net.UDPAddr, receiverIndex uint32, fromClient bool) {
|
||||||
|
var clientAddr, destAddr *net.UDPAddr
|
||||||
|
var clientIndex, destIndex uint32
|
||||||
|
|
||||||
|
if fromClient {
|
||||||
|
clientAddr = fromAddr
|
||||||
|
destAddr = toAddr
|
||||||
|
clientIndex = receiverIndex
|
||||||
|
destIndex = 0 // We don't know the destination index yet
|
||||||
|
} else {
|
||||||
|
clientAddr = toAddr
|
||||||
|
destAddr = fromAddr
|
||||||
|
clientIndex = 0 // We don't know the client index yet
|
||||||
|
destIndex = receiverIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
patternKey := fmt.Sprintf("%s-%s", clientAddr.String(), destAddr.String())
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
if existingPattern, ok := s.commPatterns.Load(patternKey); ok {
|
||||||
|
pattern := existingPattern.(*CommunicationPattern)
|
||||||
|
|
||||||
|
// Update the pattern
|
||||||
|
if fromClient {
|
||||||
|
pattern.LastFromClient = now
|
||||||
|
if pattern.ClientIndex == 0 {
|
||||||
|
pattern.ClientIndex = clientIndex
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pattern.LastFromDest = now
|
||||||
|
if pattern.DestIndex == 0 {
|
||||||
|
pattern.DestIndex = destIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern.PacketCount++
|
||||||
|
s.commPatterns.Store(patternKey, pattern)
|
||||||
|
|
||||||
|
// Check if we have bidirectional communication and can rebuild a session
|
||||||
|
s.tryRebuildSession(pattern)
|
||||||
|
} else {
|
||||||
|
// Create new pattern
|
||||||
|
pattern := &CommunicationPattern{
|
||||||
|
FromClient: clientAddr,
|
||||||
|
ToDestination: destAddr,
|
||||||
|
ClientIndex: clientIndex,
|
||||||
|
DestIndex: destIndex,
|
||||||
|
PacketCount: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if fromClient {
|
||||||
|
pattern.LastFromClient = now
|
||||||
|
} else {
|
||||||
|
pattern.LastFromDest = now
|
||||||
|
}
|
||||||
|
|
||||||
|
s.commPatterns.Store(patternKey, pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryRebuildSession attempts to rebuild a WireGuard session from communication patterns
|
||||||
|
func (s *UDPProxyServer) tryRebuildSession(pattern *CommunicationPattern) {
|
||||||
|
// Check if we have bidirectional communication within a reasonable time window
|
||||||
|
timeDiff := pattern.LastFromClient.Sub(pattern.LastFromDest)
|
||||||
|
if timeDiff < 0 {
|
||||||
|
timeDiff = -timeDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only rebuild if we have recent bidirectional communication and both indices
|
||||||
|
if timeDiff < 30*time.Second && pattern.ClientIndex != 0 && pattern.DestIndex != 0 && pattern.PacketCount >= 4 {
|
||||||
|
// Create session mapping: client's index maps to destination
|
||||||
|
sessionKey := fmt.Sprintf("%d:%d", pattern.DestIndex, pattern.ClientIndex)
|
||||||
|
|
||||||
|
// Check if we already have this session
|
||||||
|
if _, exists := s.wgSessions.Load(sessionKey); !exists {
|
||||||
|
session := &WireGuardSession{
|
||||||
|
ReceiverIndex: pattern.DestIndex,
|
||||||
|
SenderIndex: pattern.ClientIndex,
|
||||||
|
DestAddr: pattern.ToDestination,
|
||||||
|
LastSeen: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
s.wgSessions.Store(sessionKey, session)
|
||||||
|
logger.Info("Rebuilt WireGuard session from communication pattern: %s -> %s (packets: %d)",
|
||||||
|
sessionKey, pattern.ToDestination.String(), pattern.PacketCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupIdleCommunicationPatterns periodically removes idle communication patterns
|
||||||
|
func (s *UDPProxyServer) cleanupIdleCommunicationPatterns() {
|
||||||
|
ticker := time.NewTicker(10 * time.Minute)
|
||||||
|
for range ticker.C {
|
||||||
|
now := time.Now()
|
||||||
|
s.commPatterns.Range(func(key, value interface{}) bool {
|
||||||
|
pattern := value.(*CommunicationPattern)
|
||||||
|
|
||||||
|
// Get the most recent activity
|
||||||
|
lastActivity := pattern.LastFromClient
|
||||||
|
if pattern.LastFromDest.After(lastActivity) {
|
||||||
|
lastActivity = pattern.LastFromDest
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove patterns that haven't had activity in 20 minutes
|
||||||
|
if now.Sub(lastActivity) > 20*time.Minute {
|
||||||
|
s.commPatterns.Delete(key)
|
||||||
|
logger.Debug("Removed idle communication pattern: %s", key)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user