internal/divert: filter expression builder
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:
@@ -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 ")
|
||||
}
|
||||
Reference in New Issue
Block a user