pivot: replace WinDivert engine with embedded sing-box + wintun
After 5+ hours of WinDivert NETWORK-layer NAT-rewrite debugging
(streamdump pattern, SOCKET-layer SYN preemption, lazy PID resolution,
UDP ASSOCIATE relay + manual reinject), Discord voice still wouldn't
connect. The fundamental issue is that WinDivert reinjected UDP
packets don't always reach connect()-bound application sockets — the
demux happens at a layer above the reinject point.
dvp/force-proxy avoids this entirely via DLL injection (above the
kernel demux). We avoid it the other way: embed sing-box, let it run
TUN inbound + per-process routing rule + SOCKS5 outbound. TUN packets
are read by sing-box from kernel as a normal flow; the application
socket sees a normal flow back. No reinject hairpin, no SYN race, no
spoofing concerns.
What this commit does:
- Drops internal/divert, internal/engine, internal/redirect,
internal/socks5, internal/procscan, plus cmd/drover/{proxy,
debugflow}_*.go subcommands (all WinDivert-only).
- Adds internal/sboxrun — embed sing-box.exe (1.12.25) + wintun.dll
(0.14.1) via //go:embed, install to %PROGRAMDATA%\Drover\sboxrun\
with SHA256 verify, generate JSON config from form, spawn as
subprocess, manage lifecycle.
- Wires sboxrun into internal/gui/app.go: StartEngine/StopEngine
now call sboxrun.Engine instead of windivert engine.
- Fixes Wails binding: StartEngine(cfg) now passes the form config
(was zero-arg, hit ProxyHost-required validation silently).
Manual test: Discord chat + voice work end-to-end through mihomo
upstream. Yandex Music / svchost / etc continue direct via
process_name routing rule.
Binary grew from 12 MB → 49 MB (37 MB sing-box embedded), but ships
fully self-contained. AV-friendly: wintun is Microsoft-signed, no
DLL injection.
WinDivert work preserved on experimental/windivert branch in case we
ever want to come back to that path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
//go:build !windows
|
||||
|
||||
package sboxrun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Status — duplicate of the Windows-side enum so call sites compile.
|
||||
type Status string
|
||||
|
||||
const (
|
||||
StatusIdle Status = "idle"
|
||||
StatusStarting Status = "starting"
|
||||
StatusActive Status = "active"
|
||||
StatusFailed Status = "failed"
|
||||
)
|
||||
|
||||
// Engine stub for non-Windows builds.
|
||||
type Engine struct{}
|
||||
|
||||
// New returns an error on non-Windows: sing-box + wintun + WFP-based
|
||||
// per-process routing only make sense on Windows.
|
||||
func New(_ Config) (*Engine, error) {
|
||||
return nil, errors.New("sboxrun is Windows-only")
|
||||
}
|
||||
|
||||
func (e *Engine) Start(_ context.Context) error { return errors.New("sboxrun is Windows-only") }
|
||||
func (e *Engine) Stop() error { return nil }
|
||||
func (e *Engine) Status() Status { return StatusIdle }
|
||||
func (e *Engine) LastError() error { return nil }
|
||||
func (e *Engine) LogPath() string { return "" }
|
||||
func (e *Engine) ConfigPath() string { return "" }
|
||||
|
||||
// AssetPaths stub.
|
||||
type AssetPaths struct {
|
||||
SingBoxExe string
|
||||
WintunDLL string
|
||||
WorkDir string
|
||||
ConfigPath string
|
||||
LogPath string
|
||||
}
|
||||
|
||||
// InstallAssets stub.
|
||||
func InstallAssets() (*AssetPaths, error) {
|
||||
return nil, errors.New("sboxrun is Windows-only")
|
||||
}
|
||||
Reference in New Issue
Block a user