Upstream wireguard-go added an EgressProvider hook to StdNetBind (egress
anchoring for TUN auto-redirect): EgressProvider interface, egressProvider
field, SetEgressProvider, plus egress branches in Open/Send/Close and a
standardEndpoint cast hoist in Send. sing-box's endpoint-listen refactor
now calls StdNetBind.SetEgressProvider, so our AWG2 fork (which was one
wireguard-go revision behind) failed to build.
Applied the upstream delta to conn/bind_std.go verbatim, then re-applied
SPEC 026: gate BOTH reserved-clear sites behind hasReserved() —
- main receiveIP path (msg.N > 3 && s.hasReserved()) [existing]
- NEW egress receive path (dataLength > 3 && s.hasReserved())
Upstream's egress hook re-introduced an UNCONDITIONAL common.ClearArray(
bufs[0][1:4]) — the exact anti-pattern SPEC 026 fixed. Gating it keeps a
small-padding AmneziaWG magic (bytes 1-3) intact when no WARP reserved
value is set, and STILL fires for WARP-over-egress: the egress bind is
only created on the isUDPListener path, where SetReservedForEndpoint is
called for every peer, so hasReserved() is true in that scenario. Verified:
WARP egress unaffected, AWG magic survives, conn tests green.
reservedForEndpoint is populated before receive goroutines start and never
mutated after (same lock-free invariant SPEC 026 already relies on).