Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 780b271

Browse files
fix(vpn): fail early if wintun.dll is not present (cherry-pick #16707) (#16738)
Cherry-picked fix(vpn): fail early if wintun.dll is not present (#16707) Prevents the VPN startup from hanging for 5 minutes due to a startup backoff if `wintun.dll` cannot be loaded. Because the `wintun` package doesn't expose an easy `Load() error` method for us, the only way for us to force it to load (without unwanted side effects) is through `wintun.Version()` which doesn't return an error message. So, we call that function so the `wintun` package loads the DLL and configures the logging properly, then we try to load the DLL ourselves. `LoadLibraryEx` will not load the library multiple times and returns a reference to the existing library. Closes coder/coder-desktop-windows#24 Co-authored-by: Dean Sheather <[email protected]>
1 parent 34740bc commit 780b271

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

vpn/tun_windows.go

+31-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ import (
2525
"github.com/coder/retry"
2626
)
2727

28-
const tunName = "Coder"
28+
const (
29+
tunName = "Coder"
30+
tunGUID = "{0ed1515d-04a4-4c46-abae-11ad07cf0e6d}"
31+
32+
wintunDLL = "wintun.dll"
33+
)
2934

3035
func GetNetworkingStack(t *Tunnel, _ *StartRequest, logger slog.Logger) (NetworkStack, error) {
3136
// Initialize COM process-wide so Tailscale can make calls to the windows
@@ -44,12 +49,35 @@ func GetNetworkingStack(t *Tunnel, _ *StartRequest, logger slog.Logger) (Network
4449

4550
// Set the name and GUID for the TUN interface.
4651
tun.WintunTunnelType = tunName
47-
guid, err := windows.GUIDFromString("{0ed1515d-04a4-4c46-abae-11ad07cf0e6d}")
52+
guid, err := windows.GUIDFromString(tunGUID)
4853
if err != nil {
49-
panic(err)
54+
return NetworkStack{}, xerrors.Errorf("could not parse GUID %q: %w", tunGUID, err)
5055
}
5156
tun.WintunStaticRequestedGUID = &guid
5257

58+
// Ensure wintun.dll is available, and fail early if it's not to avoid
59+
// hanging for 5 minutes in tstunNewWithWindowsRetries.
60+
//
61+
// First, we call wintun.Version() to make the wintun package attempt to
62+
// load wintun.dll. This allows the wintun package to set the logging
63+
// callback in the DLL before we load it ourselves.
64+
_ = wintun.Version()
65+
66+
// Then, we try to load wintun.dll ourselves so we get a better error
67+
// message if there was a problem. This call matches the wintun package, so
68+
// we're loading it in the same way.
69+
//
70+
// Note: this leaks the handle to wintun.dll, but since it's already loaded
71+
// it wouldn't be freed anyways.
72+
const (
73+
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200
74+
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
75+
)
76+
_, err = windows.LoadLibraryEx(wintunDLL, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR|LOAD_LIBRARY_SEARCH_SYSTEM32)
77+
if err != nil {
78+
return NetworkStack{}, xerrors.Errorf("could not load %q, it should be in the same directory as the executable (in Coder Desktop, this should have been installed automatically): %w", wintunDLL, err)
79+
}
80+
5381
tunDev, tunName, err := tstunNewWithWindowsRetries(tailnet.Logger(logger.Named("net.tun.device")), tunName)
5482
if err != nil {
5583
return NetworkStack{}, xerrors.Errorf("create tun device: %w", err)

0 commit comments

Comments
 (0)