165 lines
4 KiB
Go
165 lines
4 KiB
Go
|
package ieproxy
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
"sync"
|
||
|
"unsafe"
|
||
|
|
||
|
"golang.org/x/sys/windows/registry"
|
||
|
)
|
||
|
|
||
|
type regeditValues struct {
|
||
|
ProxyServer string
|
||
|
ProxyOverride string
|
||
|
ProxyEnable uint64
|
||
|
AutoConfigURL string
|
||
|
}
|
||
|
|
||
|
var once sync.Once
|
||
|
var windowsProxyConf ProxyConf
|
||
|
|
||
|
// GetConf retrieves the proxy configuration from the Windows Regedit
|
||
|
func getConf() ProxyConf {
|
||
|
once.Do(writeConf)
|
||
|
return windowsProxyConf
|
||
|
}
|
||
|
|
||
|
func writeConf() {
|
||
|
var (
|
||
|
cfg *tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG
|
||
|
err error
|
||
|
)
|
||
|
|
||
|
if cfg, err = getUserConfigFromWindowsSyscall(); err != nil {
|
||
|
regedit, _ := readRegedit() // If the syscall fails, backup to manual detection.
|
||
|
windowsProxyConf = parseRegedit(regedit)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
defer globalFreeWrapper(cfg.lpszProxy)
|
||
|
defer globalFreeWrapper(cfg.lpszProxyBypass)
|
||
|
defer globalFreeWrapper(cfg.lpszAutoConfigUrl)
|
||
|
|
||
|
windowsProxyConf = ProxyConf{
|
||
|
Static: StaticProxyConf{
|
||
|
Active: cfg.lpszProxy != nil,
|
||
|
},
|
||
|
Automatic: ProxyScriptConf{
|
||
|
Active: cfg.lpszAutoConfigUrl != nil || cfg.fAutoDetect,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
if windowsProxyConf.Static.Active {
|
||
|
protocol := make(map[string]string)
|
||
|
for _, s := range strings.Split(StringFromUTF16Ptr(cfg.lpszProxy), ";") {
|
||
|
s = strings.TrimSpace(s)
|
||
|
if s == "" {
|
||
|
continue
|
||
|
}
|
||
|
pair := strings.SplitN(s, "=", 2)
|
||
|
if len(pair) > 1 {
|
||
|
protocol[pair[0]] = pair[1]
|
||
|
} else {
|
||
|
protocol[""] = pair[0]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
windowsProxyConf.Static.Protocols = protocol
|
||
|
if cfg.lpszProxyBypass != nil {
|
||
|
windowsProxyConf.Static.NoProxy = strings.Replace(StringFromUTF16Ptr(cfg.lpszProxyBypass), ";", ",", -1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if windowsProxyConf.Automatic.Active {
|
||
|
windowsProxyConf.Automatic.PreConfiguredURL = StringFromUTF16Ptr(cfg.lpszAutoConfigUrl)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func getUserConfigFromWindowsSyscall() (*tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG, error) {
|
||
|
handle, _, err := winHttpOpen.Call(0, 0, 0, 0, 0)
|
||
|
if handle == 0 {
|
||
|
return &tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG{}, err
|
||
|
}
|
||
|
defer winHttpCloseHandle.Call(handle)
|
||
|
|
||
|
config := new(tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG)
|
||
|
|
||
|
ret, _, err := winHttpGetIEProxyConfigForCurrentUser.Call(uintptr(unsafe.Pointer(config)))
|
||
|
if ret > 0 {
|
||
|
err = nil
|
||
|
}
|
||
|
|
||
|
return config, err
|
||
|
}
|
||
|
|
||
|
// OverrideEnvWithStaticProxy writes new values to the
|
||
|
// http_proxy, https_proxy and no_proxy environment variables.
|
||
|
// The values are taken from the Windows Regedit (should be called in init() function)
|
||
|
func overrideEnvWithStaticProxy(conf ProxyConf, setenv envSetter) {
|
||
|
if conf.Static.Active {
|
||
|
for _, scheme := range []string{"http", "https"} {
|
||
|
url := mapFallback(scheme, "", conf.Static.Protocols)
|
||
|
setenv(scheme+"_proxy", url)
|
||
|
}
|
||
|
if conf.Static.NoProxy != "" {
|
||
|
setenv("no_proxy", conf.Static.NoProxy)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func parseRegedit(regedit regeditValues) ProxyConf {
|
||
|
protocol := make(map[string]string)
|
||
|
for _, s := range strings.Split(regedit.ProxyServer, ";") {
|
||
|
if s == "" {
|
||
|
continue
|
||
|
}
|
||
|
pair := strings.SplitN(s, "=", 2)
|
||
|
if len(pair) > 1 {
|
||
|
protocol[pair[0]] = pair[1]
|
||
|
} else {
|
||
|
protocol[""] = pair[0]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ProxyConf{
|
||
|
Static: StaticProxyConf{
|
||
|
Active: regedit.ProxyEnable > 0,
|
||
|
Protocols: protocol,
|
||
|
NoProxy: strings.Replace(regedit.ProxyOverride, ";", ",", -1), // to match linux style
|
||
|
},
|
||
|
Automatic: ProxyScriptConf{
|
||
|
Active: regedit.AutoConfigURL != "",
|
||
|
PreConfiguredURL: regedit.AutoConfigURL,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func readRegedit() (values regeditValues, err error) {
|
||
|
k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
defer k.Close()
|
||
|
|
||
|
values.ProxyServer, _, err = k.GetStringValue("ProxyServer")
|
||
|
if err != nil && err != registry.ErrNotExist {
|
||
|
return
|
||
|
}
|
||
|
values.ProxyOverride, _, err = k.GetStringValue("ProxyOverride")
|
||
|
if err != nil && err != registry.ErrNotExist {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
values.ProxyEnable, _, err = k.GetIntegerValue("ProxyEnable")
|
||
|
if err != nil && err != registry.ErrNotExist {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
values.AutoConfigURL, _, err = k.GetStringValue("AutoConfigURL")
|
||
|
if err != nil && err != registry.ErrNotExist {
|
||
|
return
|
||
|
}
|
||
|
err = nil
|
||
|
return
|
||
|
}
|