ieproxy_windows.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package ieproxy
  2. import (
  3. "strings"
  4. "sync"
  5. "unsafe"
  6. "golang.org/x/sys/windows/registry"
  7. )
  8. type regeditValues struct {
  9. ProxyServer string
  10. ProxyOverride string
  11. ProxyEnable uint64
  12. AutoConfigURL string
  13. }
  14. var once sync.Once
  15. var windowsProxyConf ProxyConf
  16. // GetConf retrieves the proxy configuration from the Windows Regedit
  17. func getConf() ProxyConf {
  18. once.Do(writeConf)
  19. return windowsProxyConf
  20. }
  21. func writeConf() {
  22. var (
  23. cfg *tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG
  24. err error
  25. )
  26. if cfg, err = getUserConfigFromWindowsSyscall(); err != nil {
  27. regedit, _ := readRegedit() // If the syscall fails, backup to manual detection.
  28. windowsProxyConf = parseRegedit(regedit)
  29. return
  30. }
  31. defer globalFreeWrapper(cfg.lpszProxy)
  32. defer globalFreeWrapper(cfg.lpszProxyBypass)
  33. defer globalFreeWrapper(cfg.lpszAutoConfigUrl)
  34. windowsProxyConf = ProxyConf{
  35. Static: StaticProxyConf{
  36. Active: cfg.lpszProxy != nil,
  37. },
  38. Automatic: ProxyScriptConf{
  39. Active: cfg.lpszAutoConfigUrl != nil || cfg.fAutoDetect,
  40. },
  41. }
  42. if windowsProxyConf.Static.Active {
  43. protocol := make(map[string]string)
  44. for _, s := range strings.Split(StringFromUTF16Ptr(cfg.lpszProxy), ";") {
  45. s = strings.TrimSpace(s)
  46. if s == "" {
  47. continue
  48. }
  49. pair := strings.SplitN(s, "=", 2)
  50. if len(pair) > 1 {
  51. protocol[pair[0]] = pair[1]
  52. } else {
  53. protocol[""] = pair[0]
  54. }
  55. }
  56. windowsProxyConf.Static.Protocols = protocol
  57. if cfg.lpszProxyBypass != nil {
  58. windowsProxyConf.Static.NoProxy = strings.Replace(StringFromUTF16Ptr(cfg.lpszProxyBypass), ";", ",", -1)
  59. }
  60. }
  61. if windowsProxyConf.Automatic.Active {
  62. windowsProxyConf.Automatic.PreConfiguredURL = StringFromUTF16Ptr(cfg.lpszAutoConfigUrl)
  63. }
  64. }
  65. func getUserConfigFromWindowsSyscall() (*tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG, error) {
  66. handle, _, err := winHttpOpen.Call(0, 0, 0, 0, 0)
  67. if handle == 0 {
  68. return &tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG{}, err
  69. }
  70. defer winHttpCloseHandle.Call(handle)
  71. config := new(tWINHTTP_CURRENT_USER_IE_PROXY_CONFIG)
  72. ret, _, err := winHttpGetIEProxyConfigForCurrentUser.Call(uintptr(unsafe.Pointer(config)))
  73. if ret > 0 {
  74. err = nil
  75. }
  76. return config, err
  77. }
  78. // OverrideEnvWithStaticProxy writes new values to the
  79. // http_proxy, https_proxy and no_proxy environment variables.
  80. // The values are taken from the Windows Regedit (should be called in init() function)
  81. func overrideEnvWithStaticProxy(conf ProxyConf, setenv envSetter) {
  82. if conf.Static.Active {
  83. for _, scheme := range []string{"http", "https"} {
  84. url := mapFallback(scheme, "", conf.Static.Protocols)
  85. setenv(scheme+"_proxy", url)
  86. }
  87. if conf.Static.NoProxy != "" {
  88. setenv("no_proxy", conf.Static.NoProxy)
  89. }
  90. }
  91. }
  92. func parseRegedit(regedit regeditValues) ProxyConf {
  93. protocol := make(map[string]string)
  94. for _, s := range strings.Split(regedit.ProxyServer, ";") {
  95. if s == "" {
  96. continue
  97. }
  98. pair := strings.SplitN(s, "=", 2)
  99. if len(pair) > 1 {
  100. protocol[pair[0]] = pair[1]
  101. } else {
  102. protocol[""] = pair[0]
  103. }
  104. }
  105. return ProxyConf{
  106. Static: StaticProxyConf{
  107. Active: regedit.ProxyEnable > 0,
  108. Protocols: protocol,
  109. NoProxy: strings.Replace(regedit.ProxyOverride, ";", ",", -1), // to match linux style
  110. },
  111. Automatic: ProxyScriptConf{
  112. Active: regedit.AutoConfigURL != "",
  113. PreConfiguredURL: regedit.AutoConfigURL,
  114. },
  115. }
  116. }
  117. func readRegedit() (values regeditValues, err error) {
  118. k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE)
  119. if err != nil {
  120. return
  121. }
  122. defer k.Close()
  123. values.ProxyServer, _, err = k.GetStringValue("ProxyServer")
  124. if err != nil && err != registry.ErrNotExist {
  125. return
  126. }
  127. values.ProxyOverride, _, err = k.GetStringValue("ProxyOverride")
  128. if err != nil && err != registry.ErrNotExist {
  129. return
  130. }
  131. values.ProxyEnable, _, err = k.GetIntegerValue("ProxyEnable")
  132. if err != nil && err != registry.ErrNotExist {
  133. return
  134. }
  135. values.AutoConfigURL, _, err = k.GetStringValue("AutoConfigURL")
  136. if err != nil && err != registry.ErrNotExist {
  137. return
  138. }
  139. err = nil
  140. return
  141. }