experimental/windivert: P2.1+P2.2 with WinDivert NETWORK+SOCKET layers

WIP snapshot before pivot to sing-box+TUN. Reached:
- TCP redirect via streamdump pattern (swap+Outbound=0+reinject)
- SOCKET layer for SYN-stage flow detection (avoids FLOW Establish-too-late race)
- Lazy PID→name resolution (catches Update.exe inside procscan tick)
- UDP forward via SOCKS5 UDP ASSOCIATE relay + manual reinject
- Result: chat works, voice times out (Discord IP discovery / RTC handshake fails)

Reason for pivot: WinDivert NAT-reinject pattern has subtle layer-3
semantics issues that DLL-injection / TUN-based proxies sidestep
entirely. Going with embedded sing-box + wintun as the engine —
proven path for Discord voice through SOCKS5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 22:27:54 +03:00
parent 8ceb7775d7
commit 4074e68715
19 changed files with 2666 additions and 62 deletions
+64
View File
@@ -0,0 +1,64 @@
//go:build windows
package main
import (
"context"
"log"
"time"
"git.okcu.io/root/drover-go/internal/divert"
)
// runDebugFlow opens a WinDivert FLOW handle with the broadest possible
// filter ("tcp") and logs every flow-establish/delete event for up to
// 30 seconds. This is the simplest possible test that the FLOW layer
// is delivering events to our handle.
//
// If we see events here but our process-targeted handle in `proxy`
// stays silent, the bug is in our processId filter clause. If we see
// nothing here, the FLOW layer is broken on this machine.
func runDebugFlow(parent context.Context) error {
if _, err := divert.InstallDriver(); err != nil {
return err
}
ctx, cancel := context.WithTimeout(parent, 30*time.Second)
defer cancel()
log.Printf("debug-flow: opening FLOW handle with filter \"true\" (capture all flows)")
h, err := divert.OpenFlow("true")
if err != nil {
log.Printf("debug-flow: OpenFlow failed: %v", err)
return err
}
defer h.Close()
log.Printf("debug-flow: handle open, listening for 30s")
go func() {
<-ctx.Done()
_ = h.Close() // unblock RecvFlow
}()
count := 0
for {
ev, err := h.RecvFlow()
if err != nil {
if ctx.Err() != nil {
log.Printf("debug-flow: done — captured %d events in 30s", count)
return nil
}
log.Printf("debug-flow: RecvFlow err: %v", err)
return err
}
count++
log.Printf("debug-flow: event #%d est=%v pid=%d proto=%d %v:%d → %v:%d rawLocal=%x rawRemote=%x",
count, ev.Established, ev.ProcessID, ev.Protocol,
ev.SrcAddr, ev.SrcPort, ev.DstAddr, ev.DstPort,
ev.LocalRaw, ev.RemoteRaw)
if count >= 20 {
log.Printf("debug-flow: hit 20-event cap, stopping")
return nil
}
}
}