Upstream acceptLoop treats any Accept error as terminal and silently
returns, leaving the stack alive but every new TCP SYN NAT-rewritten onto
a dead port (instant RST) until a full restart. When the listener fd is
closed out from under the stack (a stray close on a reused fd number from
another runtime in the same process), all new TCP dies forever while
UDP/QUIC/DNS keep working.
- System.Close() now marks a deliberate shutdown first; acceptLoop still
exits quietly on it.
- Any other Accept error is logged (the errno names the killer path),
the listener is recreated on the same address, the forwarder port is
republished atomically, and the loop keeps serving.
- If the rebind fails, the loop logs an error and gives up - no worse
than upstream.
- acceptRecoveries counter is kept as telemetry.
tcpPort/tcpPort6 become atomic (written by the heal path, read from the
tunLoop dispatch/NAT path); listener replacement is serialized against
Close() with a mutex.
Unconnected raw ICMP sockets receive every ICMP packet arriving at the
host, so any ICMP traffic refreshed the read deadline of every flow and
stale flows (with their raw sockets and goroutines) accumulated forever,
making per-ping cost grow linearly with uptime.
Expire flows based on their own activity only, and on Linux attach a
classic BPF ident filter to each raw socket so other flows' packets are
dropped in the kernel instead of waking every flow.
Unconnected raw ICMP sockets receive every ICMP packet arriving at the
host, so any ICMP traffic refreshed the read deadline of every flow and
stale flows (with their raw sockets and goroutines) were only reclaimed
by LRU eviction while processing all host ICMP traffic in the meantime.
Expire flows based on their own activity only, and on Linux attach a
classic BPF ident filter to each raw socket so other flows' packets are
dropped in the kernel instead of waking every flow.
When To() is 255.255.255.255 / ffff:...:ffff, Next() is invalid. Using
From() as the end key duplicated the start element and caused EEXIST.
Omit the end element so the half-open interval covers through max.
FixesSagerNet/sing-box#4316