mirror of
https://github.com/wgtunnel/desktop.git
synced 2026-06-02 00:29:09 +02:00
fix: mitigate windows daemon bypass fw crashes with appID cache
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@ data class TunnelsUiState(
|
||||
|
||||
data class TunnelUiItem(val config: TunnelConfig, val status: TunnelStatus? = null) {
|
||||
val isRunning: Boolean
|
||||
get() = status?.state != TunnelState.DOWN && status != null
|
||||
get() = status?.state != TunnelState.DOWN && status?.state != TunnelState.STOPPING && status != null
|
||||
|
||||
val stateColor: Color
|
||||
get() = status?.state?.asColor() ?: TunnelState.DOWN.asColor()
|
||||
|
||||
@@ -9,16 +9,16 @@ require (
|
||||
github.com/cenkalti/backoff/v5 v5.0.3
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466
|
||||
github.com/google/nftables v0.3.0
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||
inet.af/wf v0.0.0-20221017222439-36129f591884
|
||||
tailscale.com v1.94.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/golibs v0.35.7 // indirect
|
||||
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0 // indirect
|
||||
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
@@ -28,7 +28,7 @@ require (
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20251125195548-87e1e737ad39 // indirect
|
||||
golang.org/x/mod v0.32.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/tools v0.41.0 // indirect
|
||||
|
||||
@@ -2,8 +2,8 @@ github.com/AdguardTeam/dnsproxy v0.78.2 h1:g+ba4vh72hAv9zIE+OPSEnu77utSKxIF6u2jN
|
||||
github.com/AdguardTeam/dnsproxy v0.78.2/go.mod h1:gwr+7Dc0e7QddQLC9JLGjL5NSKcqw0ESsNMRI5Q67Ps=
|
||||
github.com/AdguardTeam/golibs v0.35.7 h1:pTQpixUos7mALr3jqb0pigfrkiqPAX1hiYUi/yeBWiA=
|
||||
github.com/AdguardTeam/golibs v0.35.7/go.mod h1:meFdRqMtG/PLW6LD20MYAlcRbwAVowlbunHgE17xz9s=
|
||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A=
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0 h1:if6ZG2cuQmcP2TwSY+D0+8+xbPfoatufGlOQTMNkI9o=
|
||||
@@ -38,6 +38,8 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M=
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y=
|
||||
github.com/things-go/go-socks5 v0.1.0 h1:4f5dz0iMQ6cA4wseFmyLmCHmg3SWJTW92ndrKS6oERg=
|
||||
github.com/things-go/go-socks5 v0.1.0/go.mod h1:Riabiyu52kLsla0YmJqunt1c1JEl6iXSr4bRd7swFEA=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
@@ -58,8 +60,8 @@ golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
|
||||
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
|
||||
golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 h1:RMc8anw0hCPcg5CZYN2PEQ8nMwosk461R6vFwPrCFVg=
|
||||
golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms=
|
||||
golang.org/x/exp/typeparams v0.0.0-20251125195548-87e1e737ad39 h1:yzGKB4T4r1nFi65o7dQ96ERTfU2trk8Ige9aqqADqf4=
|
||||
golang.org/x/exp/typeparams v0.0.0-20251125195548-87e1e737ad39/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms=
|
||||
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
@@ -89,7 +91,5 @@ gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvs
|
||||
gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM=
|
||||
honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0 h1:5SXjd4ET5dYijLaf0O3aOenC0Z4ZafIWSpjUzsQaNho=
|
||||
honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0/go.mod h1:EPDDhEZqVHhWuPI5zPAsjU0U7v9xNIWjoOVyZ5ZcniQ=
|
||||
inet.af/wf v0.0.0-20221017222439-36129f591884 h1:zg9snq3Cpy50lWuVqDYM7AIRVTtU50y5WXETMFohW/Q=
|
||||
inet.af/wf v0.0.0-20221017222439-36129f591884/go.mod h1:bSAQ38BYbY68uwpasXOTZo22dKGy9SNvI6PZFeKomZE=
|
||||
tailscale.com v1.94.1 h1:0dAst/ozTuFkgmxZULc3oNwR9+qPIt5ucvzH7kaM0Jw=
|
||||
tailscale.com v1.94.1/go.mod h1:gLnVrEOP32GWvroaAHHGhjSGMPJ1i4DvqNwEg+Yuov4=
|
||||
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/amnezia-vpn/amneziawg-go/device"
|
||||
"github.com/tailscale/wf"
|
||||
"github.com/wgtunnel/desktop/tunnel/vpn/firewall"
|
||||
"golang.org/x/net/nettest"
|
||||
"golang.org/x/sys/windows"
|
||||
"inet.af/wf"
|
||||
"tailscale.com/net/netaddr"
|
||||
)
|
||||
|
||||
@@ -32,9 +32,8 @@ type WindowsFirewall struct {
|
||||
|
||||
iface string
|
||||
|
||||
luid uint64
|
||||
appID string
|
||||
|
||||
luid uint64
|
||||
appID string
|
||||
killSwitchEnabled atomic.Bool
|
||||
persistKillSwitch atomic.Bool
|
||||
|
||||
@@ -94,6 +93,11 @@ func New(logger *device.Logger) (firewall.Firewall, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// try to cache the app id once to prevent https://github.com/tailscale/wf/issues/25
|
||||
if err := f.cacheAppID(); err != nil {
|
||||
f.logger.Errorf("failed to cache daemon AppID: %v", err)
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
@@ -234,6 +238,22 @@ func (f *WindowsFirewall) IsEnabled() bool {
|
||||
return f.killSwitchEnabled.Load()
|
||||
}
|
||||
|
||||
func (f *WindowsFirewall) cacheAppID() error {
|
||||
currentFile, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
appID, err := wf.AppID(currentFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get app id for %q: %w", currentFile, err)
|
||||
}
|
||||
|
||||
f.appID = appID
|
||||
f.logger.Verbosef("Cached daemon AppID: %s (will never call wf.AppID again)", appID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *WindowsFirewall) RemoveTunnelRules() error {
|
||||
tunRulesCopy := make([]*wf.Rule, len(f.tunRules))
|
||||
copy(tunRulesCopy, f.tunRules)
|
||||
@@ -369,27 +389,26 @@ func (f *WindowsFirewall) Disable() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// permitDaemon allows the daemon process through firewall
|
||||
func (f *WindowsFirewall) permitDaemon(w weight) error {
|
||||
return f.addDaemonRule()
|
||||
}
|
||||
|
||||
currentFile, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
// addDaemonRule add the daemon bypass using the cached AppID
|
||||
func (f *WindowsFirewall) addDaemonRule() error {
|
||||
if f.appID == "" {
|
||||
return fmt.Errorf("AppID not cached")
|
||||
}
|
||||
|
||||
appID, err := wf.AppID(currentFile)
|
||||
f.logger.Verbosef("Adding bypass rule for %s", appID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get app id for %q: %w", currentFile, err)
|
||||
}
|
||||
conditions := []*wf.Match{
|
||||
{
|
||||
Field: wf.FieldALEAppID,
|
||||
Op: wf.MatchTypeEqual,
|
||||
Value: appID,
|
||||
},
|
||||
}
|
||||
_, err = f.addRules("unrestricted traffic for daemon", w, conditions, wf.ActionPermit, protocolAll, directionBoth)
|
||||
f.logger.Verbosef("Adding bypass rule for daemon (using cached AppID)")
|
||||
|
||||
conditions := []*wf.Match{{
|
||||
Field: wf.FieldALEAppID,
|
||||
Op: wf.MatchTypeEqual,
|
||||
Value: f.appID,
|
||||
}}
|
||||
|
||||
_, err := f.addRules("unrestricted traffic for daemon", weightDaemonTraffic,
|
||||
conditions, wf.ActionPermit, protocolAll, directionBoth)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user