Files
2026-07-09 11:20:33 +08:00

67 lines
1.5 KiB
Go

//go:build windows && (amd64 || 386)
package bridge
import (
"net/netip"
"sync"
"time"
)
// icmpTable records liveness of ICMP echo flows by (identifier, remote
// address). The identifier passes through untranslated — the dispatcher NAT
// already set it to the selector — and Windows ping.exe uses a constant
// identifier, so the remote address is needed to tell a bridged reply from the
// host's own ping.
type icmpTable struct {
access sync.Mutex
timeout time.Duration
active map[icmpFlowKey]time.Time
lastSweep time.Time
}
type icmpFlowKey struct {
identifier uint16
remote netip.Addr
}
func newICMPTable(timeout time.Duration) *icmpTable {
return &icmpTable{
timeout: timeout,
active: make(map[icmpFlowKey]time.Time),
}
}
func (t *icmpTable) register(identifier uint16, remote netip.Addr) {
now := time.Now()
key := icmpFlowKey{identifier: identifier, remote: remote}
t.access.Lock()
defer t.access.Unlock()
if now.Sub(t.lastSweep) >= t.timeout {
t.lastSweep = now
for flow, lastActive := range t.active {
if now.Sub(lastActive) >= t.timeout {
delete(t.active, flow)
}
}
}
t.active[key] = now
}
func (t *icmpTable) isActive(identifier uint16, remote netip.Addr) bool {
now := time.Now()
key := icmpFlowKey{identifier: identifier, remote: remote}
t.access.Lock()
defer t.access.Unlock()
lastActive, loaded := t.active[key]
if !loaded {
return false
}
if now.Sub(lastActive) >= t.timeout {
delete(t.active, key)
return false
}
t.active[key] = now
return true
}