Skip to content

Commit

Permalink
sysproxy: update impl
Browse files Browse the repository at this point in the history
  • Loading branch information
5aaee9 committed Mar 10, 2024
1 parent ba3b1c8 commit 6b74563
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 90 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ module github.com/5aaee9/utils
go 1.20

require (
github.com/pkg/errors v0.9.1
github.com/samber/do v1.6.0
github.com/stretchr/testify v1.8.4
golang.org/x/sys v0.18.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/samber/do v1.6.0 h1:Jy/N++BXINDB6lAx5wBlbpHlUdl0FKpLWgGEV9YWqaU=
github.com/samber/do v1.6.0/go.mod h1:DWqBvumy8dyb2vEnYZE7D7zaVEB64J45B0NjTlY/M4k=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
161 changes: 72 additions & 89 deletions pkgs/proxy/sysproxy/sysproxy_windows.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package sysproxy

import (
"errors"
"fmt"
"math/big"
"os"
"syscall"
"unsafe"

"golang.org/x/sys/windows"
)

type WindowsSystemProxy struct{}
Expand All @@ -17,129 +17,112 @@ func NewSystemProxy() SystemProxy {
var _ SystemProxy = (*WindowsSystemProxy)(nil)

var (
wininet, _ = syscall.LoadLibrary("Wininet.dll")
internetSetOption, _ = syscall.GetProcAddress(wininet, "InternetSetOptionW")
modwininet = windows.NewLazySystemDLL("wininet.dll")
procInternetSetOptionW = modwininet.NewProc("InternetSetOptionW")
)

const (
internetOptionPerConnectionOption = 75
internetOptionProxySettingsChanged = 95
internetOptionSettingsChanged = 39
internetOptionRefresh = 37
internetOptionProxySettingsChanged = 95
)

const (
proxyTypeDirect = 0x00000001 // direct to net
proxyTypeProxy = 0x00000002 // via named proxy
internetPerConnFlags = 1
internetPerConnProxyServer = 2
internetPerConnProxyBypass = 3
internetPerConnAutoconfigUrl = 4
internetPerConnAutodiscoveryFlags = 5
internetPerConnAutoconfigSecondaryUrl = 6
internetPerConnAutoconfigReloadDelayMins = 7
internetPerConnAutoconfigLastDetectTime = 8
internetPerConnAutoconfigLastDetectUrl = 9
internetPerConnFlagsUi = 10
internetOptionProxyUsername = 43
internetOptionProxyPassword = 44
)

const (
internetPerConnFlags = 1
internetPerConnProxyServer = 2
proxyTypeDirect = 1
proxyTypeProxy = 2
proxyTypeAutoProxyUrl = 4
proxyTypeAutoDetect = 8
)

type internetPerConnOptionList struct {
dwSize uint32
pszConnection *uint16
pszConnection uintptr
dwOptionCount uint32
dwOptionError uint32
pOptions uintptr
}

type internetPreConnOption struct {
type internetPerConnOption struct {
dwOption uint32
value uint64
}

func stringPtrAddr(str string) (uint64, error) {
scriptLocPtr, err := syscall.UTF16PtrFromString(str)
if err != nil {
return 0, err
func internetSetOption(option uintptr, lpBuffer uintptr, dwBufferSize uintptr) error {
r0, _, err := syscall.SyscallN(procInternetSetOptionW.Addr(), 0, option, lpBuffer, dwBufferSize)
if r0 != 1 {
return err
}
n := new(big.Int)
n.SetString(fmt.Sprintf("%x\n", scriptLocPtr), 16)
return n.Uint64(), nil
return nil
}

func newParam(n int) internetPerConnOptionList {
return internetPerConnOptionList{
dwSize: 4,
pszConnection: nil,
dwOptionCount: uint32(n),
dwOptionError: 0,
pOptions: 0,
func setOptions(options ...internetPerConnOption) error {
var optionList internetPerConnOptionList
optionList.dwSize = uint32(unsafe.Sizeof(optionList))
optionList.dwOptionCount = uint32(len(options))
optionList.dwOptionError = 0
optionList.pOptions = uintptr(unsafe.Pointer(&options[0]))
err := internetSetOption(internetOptionPerConnectionOption, uintptr(unsafe.Pointer(&optionList)), uintptr(optionList.dwSize))
if err != nil {
return os.NewSyscallError("InternetSetOption(PerConnectionOption)", err)
}
}

func (p *WindowsSystemProxy) TurnOn(addrport string) error {
proxyServerPtrAddr, err := stringPtrAddr(addrport)
err = internetSetOption(internetOptionSettingsChanged, 0, 0)
if err != nil {
return err
return os.NewSyscallError("InternetSetOption(SettingsChanged)", err)
}

param := newParam(2)
options := []internetPreConnOption{
{dwOption: internetPerConnFlags, value: proxyTypeProxy | proxyTypeDirect},
{dwOption: internetPerConnProxyServer, value: proxyServerPtrAddr},
err = internetSetOption(internetOptionProxySettingsChanged, 0, 0)
if err != nil {
return os.NewSyscallError("InternetSetOption(ProxySettingsChanged)", err)
}

param.pOptions = uintptr(unsafe.Pointer(&options[0]))
ret, _, infoPtr := syscall.SyscallN(internetSetOption,
4,
0,
internetOptionPerConnectionOption,
uintptr(unsafe.Pointer(&param)),
unsafe.Sizeof(param),
0, 0)

if ret != 1 {
return errors.New(fmt.Sprintf("%s", infoPtr))
err = internetSetOption(internetOptionRefresh, 0, 0)
if err != nil {
return os.NewSyscallError("InternetSetOption(Refresh)", err)
}

return p.Flush()
return nil
}
func (p *WindowsSystemProxy) TurnOff() error {
param := newParam(1)
option := internetPreConnOption{
dwOption: internetPerConnFlags,
//value: _PROXY_TYPE_AUTO_DETECT | _PROXY_TYPE_DIRECT}
value: proxyTypeDirect}
param.pOptions = uintptr(unsafe.Pointer(&option))
ret, _, infoPtr := syscall.SyscallN(internetSetOption,
4,
0,
internetOptionPerConnectionOption,
uintptr(unsafe.Pointer(&param)),
unsafe.Sizeof(param),
0, 0)

if ret != 1 {
return errors.New(fmt.Sprintf("%s", infoPtr))
}

return p.Flush()
func ClearSystemProxy() error {
var flagsOption internetPerConnOption
flagsOption.dwOption = internetPerConnFlags
*((*uint32)(unsafe.Pointer(&flagsOption.value))) = proxyTypeDirect | proxyTypeAutoDetect
return setOptions(flagsOption)
}

func (p *WindowsSystemProxy) Flush() error {
ret, _, infoPtr := syscall.SyscallN(internetSetOption,
4,
0,
internetOptionProxySettingsChanged,
0, 0,
0, 0)

if ret != 1 {
return errors.New(fmt.Sprintf("%s", infoPtr))
func SetSystemProxy(proxy string, bypass string) error {
var flagsOption internetPerConnOption
flagsOption.dwOption = internetPerConnFlags
*((*uint32)(unsafe.Pointer(&flagsOption.value))) = proxyTypeProxy | proxyTypeDirect
var proxyOption internetPerConnOption
proxyOption.dwOption = internetPerConnProxyServer
*((*uintptr)(unsafe.Pointer(&proxyOption.value))) = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(proxy)))
if bypass == "" {
return setOptions(flagsOption, proxyOption)
}
var bypassOption internetPerConnOption
bypassOption.dwOption = internetPerConnProxyBypass
*((*uintptr)(unsafe.Pointer(&bypassOption.value))) = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(bypass)))
return setOptions(flagsOption, proxyOption, bypassOption)
}

ret, _, infoPtr = syscall.SyscallN(internetSetOption,
4,
0,
internetOptionRefresh,
0, 0,
0, 0)
func (p *WindowsSystemProxy) TurnOn(addrport string) error {
return SetSystemProxy(addrport, "")
}

if ret != 1 {
return errors.New(fmt.Sprintf("%s", infoPtr))
}
return nil
func (p *WindowsSystemProxy) TurnOff() error {
return ClearSystemProxy()
}

0 comments on commit 6b74563

Please sign in to comment.