diff --git a/net/interfaces/interfaces.go b/net/interfaces/interfaces.go index 3ef95c657..ab72cc4db 100644 --- a/net/interfaces/interfaces.go +++ b/net/interfaces/interfaces.go @@ -177,6 +177,9 @@ type State struct { // HTTPProxy is the HTTP proxy to use. HTTPProxy string + + // PAC is the URL to the Proxy Autoconfig URL, if applicable. + PAC string } func (s *State) Equal(s2 *State) bool { @@ -197,6 +200,9 @@ func (s *State) RemoveTailscaleInterfaces() { } } +// getPAC, if non-nil, returns the current PAC file URL. +var getPAC func() string + // GetState returns the state of all the current machine's network interfaces. // // It does not set the returned State.IsExpensive. The caller can populate that. @@ -222,6 +228,9 @@ func GetState() (*State, error) { if u, err := tshttpproxy.ProxyFromEnvironment(req); err == nil && u != nil { s.HTTPProxy = u.String() } + if getPAC != nil { + s.PAC = getPAC() + } return s, nil } diff --git a/net/interfaces/interfaces_windows.go b/net/interfaces/interfaces_windows.go index 8f672eb73..6a8052389 100644 --- a/net/interfaces/interfaces_windows.go +++ b/net/interfaces/interfaces_windows.go @@ -6,11 +6,14 @@ import ( "fmt" + "log" "os/exec" "syscall" + "unsafe" "github.com/tailscale/winipcfg-go" "go4.org/mem" + "golang.org/x/sys/windows" "inet.af/netaddr" "tailscale.com/tsconst" "tailscale.com/util/lineread" @@ -18,6 +21,7 @@ func init() { likelyHomeRouterIP = likelyHomeRouterIPWindows + getPAC = getPACWindows } /* @@ -148,3 +152,32 @@ func DefaultRouteInterface() (string, error) { } return fmt.Sprintf("%s (%s)", iface.FriendlyName, iface.Description), nil } + +var ( + winHTTP = windows.NewLazySystemDLL("winhttp.dll") + detectAutoProxyConfigURL = winHTTP.NewProc("WinHttpDetectAutoProxyConfigUrl") + + kernel32 = windows.NewLazySystemDLL("kernel32.dll") + globalFree = kernel32.NewProc("GlobalFree") +) + +const ( + winHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001 + winHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002 +) + +func getPACWindows() string { + var res *uint16 + r, _, err := detectAutoProxyConfigURL.Call( + winHTTP_AUTO_DETECT_TYPE_DHCP|winHTTP_AUTO_DETECT_TYPE_DNS_A, + uintptr(unsafe.Pointer(&res)), + ) + var got string + if res != nil { + got = windows.UTF16PtrToString(res) + globalFree.Call(uintptr(unsafe.Pointer(res))) + } else { + log.Printf("getPACWindows: r=%v, err=%#v", r, err) + } + return got +}