Files
navi/internal/sysproxy/windows.go
T

157 lines
3.5 KiB
Go

//go:build windows
package sysproxy
import (
"fmt"
"os/exec"
"strings"
"syscall"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
)
const (
internetOptionSettingsChanged = 39
internetOptionRefresh = 37
)
type windowsController struct {
enabled bool
hadProxy bool
oldEnable uint64
oldServer string
oldOverride string
}
func newPlatform() Controller {
return &windowsController{}
}
func (c *windowsController) Enabled() bool { return c.enabled }
func (c *windowsController) Enable(httpHostPort string) error {
if httpHostPort == "" {
return fmt.Errorf("sysproxy: empty http proxy address")
}
key, err := registry.OpenKey(registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Internet Settings`,
registry.QUERY_VALUE|registry.SET_VALUE)
if err != nil {
return fmt.Errorf("sysproxy: open registry: %w", err)
}
defer key.Close()
if !c.enabled {
c.oldEnable, _, _ = key.GetIntegerValue("ProxyEnable")
c.oldServer, _, _ = key.GetStringValue("ProxyServer")
c.oldOverride, _, _ = key.GetStringValue("ProxyOverride")
c.hadProxy = true
}
override := strings.Join([]string{
"localhost",
"127.*",
"10.*",
"172.16.*",
"172.17.*",
"172.18.*",
"172.19.*",
"172.20.*",
"172.21.*",
"172.22.*",
"172.23.*",
"172.24.*",
"172.25.*",
"172.26.*",
"172.27.*",
"172.28.*",
"172.29.*",
"172.30.*",
"172.31.*",
"192.168.*",
"<local>",
}, ";")
if err := key.SetDWordValue("ProxyEnable", 1); err != nil {
return err
}
if err := key.SetStringValue("ProxyServer", httpHostPort); err != nil {
return err
}
if err := key.SetStringValue("ProxyOverride", override); err != nil {
return err
}
if err := notifyInternetSettingsChanged(); err != nil {
return err
}
_ = setWinHTTPProxy(httpHostPort)
c.enabled = true
return nil
}
func (c *windowsController) Disable() error {
if !c.enabled {
return nil
}
key, err := registry.OpenKey(registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Internet Settings`,
registry.QUERY_VALUE|registry.SET_VALUE)
if err != nil {
return err
}
defer key.Close()
if c.hadProxy {
_ = key.SetDWordValue("ProxyEnable", uint32(c.oldEnable))
if c.oldServer != "" {
_ = key.SetStringValue("ProxyServer", c.oldServer)
} else {
_ = key.DeleteValue("ProxyServer")
}
if c.oldOverride != "" {
_ = key.SetStringValue("ProxyOverride", c.oldOverride)
}
} else {
_ = key.SetDWordValue("ProxyEnable", 0)
}
_ = notifyInternetSettingsChanged()
_ = resetWinHTTPProxy()
c.enabled = false
return nil
}
func notifyInternetSettingsChanged() error {
wininet := windows.NewLazySystemDLL("wininet.dll")
proc := wininet.NewProc("InternetSetOptionW")
r1, _, err := proc.Call(0, uintptr(internetOptionSettingsChanged), 0, 0)
if r1 == 0 {
return fmt.Errorf("InternetSetOption(SETTINGS_CHANGED): %w", err)
}
r1, _, err = proc.Call(0, uintptr(internetOptionRefresh), 0, 0)
if r1 == 0 {
return fmt.Errorf("InternetSetOption(REFRESH): %w", err)
}
return nil
}
func setWinHTTPProxy(httpHostPort string) error {
cmd := exec.Command("netsh", "winhttp", "set", "proxy", httpHostPort,
"bypass-list=localhost;127.*;10.*;192.168.*;<local>")
const createNoWindow = 0x08000000
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: createNoWindow}
return cmd.Run()
}
func resetWinHTTPProxy() error {
cmd := exec.Command("netsh", "winhttp", "reset", "proxy")
const createNoWindow = 0x08000000
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: createNoWindow}
return cmd.Run()
}