mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-07-22 21:00:38 +08:00
67 lines
1.5 KiB
Go
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
|
|
}
|