internal/divert: filter expression builder
Build / test (push) Failing after 32s
Build / build-windows (push) Has been skipped

Pure-Go assembly of the WinDivert filter clause. Empty PID list →
"false" (captures nothing — used during Discord-not-running window).
Non-IPv4 upstream → 0.0.0.0 fallback (caller should validate; the
builder degrades gracefully rather than panicking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 19:41:53 +03:00
parent 736c3ecfc7
commit 223c7f5886
2 changed files with 134 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
package divert
import (
"fmt"
"net"
"strings"
)
// FilterParams collects the inputs needed to build a WinDivert filter
// expression for Drover's outbound capture.
type FilterParams struct {
// TargetPIDs is the set of PIDs whose outbound traffic should be
// captured (e.g. Discord variants). When empty, the resulting
// filter is "false" — captures nothing — which is the right
// behaviour while procscan reports zero Discord processes.
TargetPIDs []uint32
// OwnPID is drover.exe's own PID. Excluded from capture so our
// SOCKS5 traffic to the upstream proxy doesn't get re-captured.
OwnPID uint32
// UpstreamIP is the resolved IPv4 of the upstream SOCKS5 proxy.
// Excluded from capture as a second line of defence against
// self-loops. If unparseable, "0.0.0.0" is substituted (caller
// should validate before calling).
UpstreamIP string
}
// BuildFilter returns a WinDivert filter expression string suitable
// for WinDivertOpen. The expression captures only outbound IPv4 TCP/UDP
// from the listed PIDs, excluding our own process and the upstream
// proxy's IP.
func BuildFilter(p FilterParams) string {
if len(p.TargetPIDs) == 0 {
return "false"
}
upstream := p.UpstreamIP
if net.ParseIP(upstream).To4() == nil {
upstream = "0.0.0.0"
}
pidClauses := make([]string, len(p.TargetPIDs))
for i, pid := range p.TargetPIDs {
pidClauses[i] = fmt.Sprintf("processId == %d", pid)
}
pidClause := "(" + strings.Join(pidClauses, " or ") + ")"
parts := []string{
"outbound",
"(tcp or udp)",
"ip",
pidClause,
fmt.Sprintf("processId != %d", p.OwnPID),
fmt.Sprintf("ip.DstAddr != %s", upstream),
"not (ip.DstAddr >= 224.0.0.0 and ip.DstAddr <= 239.255.255.255)",
"not (ip.DstAddr >= 127.0.0.0 and ip.DstAddr <= 127.255.255.255)",
"not (ip.DstAddr >= 169.254.0.0 and ip.DstAddr <= 169.254.255.255)",
}
return strings.Join(parts, " and ")
}