Skip to content

Commit afc99a7

Browse files
修改了错误的项目名称
1 parent fbb1f48 commit afc99a7

File tree

3 files changed

+313
-1
lines changed

3 files changed

+313
-1
lines changed

README.md

+58
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,61 @@
22

33

44
通过系统调用的方式实现Windows系统的代理配置。
5+
6+
7+
修改自 C++项目,`sysproxy.exe`
8+
9+
- [Noisyfox/sysproxy](https://github.com/Noisyfox/sysproxy)
10+
11+
12+
## Quick Start
13+
14+
获取
15+
```
16+
go get -u github.com/Trisia/gosysproxy
17+
```
18+
19+
API
20+
```go
21+
// SetPAC 设置PAC代理模式
22+
// scriptLoc: 脚本地址,如: "http://127.0.0.1:7777/pac"
23+
func SetPAC(scriptLoc string)
24+
25+
// SetGlobalProxy 设置全局代理
26+
// proxyServer: 代理服务器host:port,例如: "127.0.0.1:7890"
27+
// bypass: 忽略代理列表,这些配置项开头的地址不进行代理
28+
func SetGlobalProxy(proxyServer string, bypasses ...string) error
29+
30+
// Off 关闭代理
31+
func Off() error
32+
33+
// Flush 更新系统配置使生效
34+
func Flush()
35+
```
36+
37+
## Demo
38+
39+
```go
40+
package main
41+
42+
import (
43+
"github.com/Trisia/gosysproxy"
44+
"time"
45+
)
46+
47+
func main() {
48+
// 设置全局代理
49+
err := gosysproxy.SetGlobalProxy("127.0.0.1:7890")
50+
if err{
51+
panic(err)
52+
}
53+
54+
time.Sleep(time.Second * 60)
55+
56+
err := gosysproxy.Off()
57+
if err{
58+
panic(err)
59+
}
60+
}
61+
62+
```

main.go

+207-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,212 @@
11
// +build windows
22

33
// windows系统代理配置
4-
package gosysporxy
4+
package gosysproxy
55

6+
import (
7+
"errors"
8+
"fmt"
9+
"math/big"
10+
"strings"
11+
"syscall"
12+
"unsafe"
13+
)
614

15+
var (
16+
wininet, _ = syscall.LoadLibrary("Wininet.dll")
17+
internetSetOption, _ = syscall.GetProcAddress(wininet, "InternetSetOptionW")
18+
)
19+
20+
const (
21+
_INTERNET_OPTION_PER_CONNECTION_OPTION = 75
22+
_INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95
23+
_INTERNET_OPTION_REFRESH = 37
24+
)
25+
26+
const (
27+
_PROXY_TYPE_DIRECT = 0x00000001 // direct to net
28+
_PROXY_TYPE_PROXY = 0x00000002 // via named proxy
29+
_PROXY_TYPE_AUTO_PROXY_URL = 0x00000004 // autoproxy URL
30+
_PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
31+
)
32+
33+
const (
34+
_INTERNET_PER_CONN_FLAGS = 1
35+
_INTERNET_PER_CONN_PROXY_SERVER = 2
36+
_INTERNET_PER_CONN_PROXY_BYPASS = 3
37+
_INTERNET_PER_CONN_AUTOCONFIG_URL = 4
38+
_INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5
39+
_INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6
40+
_INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7
41+
_INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8
42+
_INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9
43+
_INTERNET_PER_CONN_FLAGS_UI = 10
44+
)
45+
46+
type internetPerConnOptionList struct {
47+
dwSize uint32
48+
pszConnection *uint16
49+
dwOptionCount uint32
50+
dwOptionError uint32
51+
pOptions uintptr
52+
}
53+
54+
type internetPreConnOption struct {
55+
dwOption uint32
56+
value uint64
57+
}
58+
59+
// stringPtrAddr 获取C字符串(UTF16)的数组第一个位置的地址
60+
func stringPtrAddr(str string) (uint64, error) {
61+
scriptLocPtr, err := syscall.UTF16PtrFromString(str)
62+
if err != nil {
63+
return 0, err
64+
}
65+
n := new(big.Int)
66+
n.SetString(fmt.Sprintf("%x\n", scriptLocPtr), 16)
67+
return n.Uint64(), nil
68+
}
69+
70+
// newParam 创建参数序列容器
71+
// n: 参数数量
72+
func newParam(n int) internetPerConnOptionList {
73+
return internetPerConnOptionList{
74+
dwSize: 4,
75+
pszConnection: nil,
76+
dwOptionCount: uint32(n),
77+
dwOptionError: 0,
78+
pOptions: 0,
79+
}
80+
}
81+
82+
// SetPAC 设置PAC代理模式
83+
// scriptLoc: 脚本地址,如: "http://127.0.0.1:7777/pac"
84+
func SetPAC(scriptLoc string) error {
85+
if scriptLoc == "" {
86+
return errors.New("PAC脚本地址(scriptLoc)配置为空")
87+
}
88+
89+
scriptLocAddr, err := stringPtrAddr(scriptLoc)
90+
if err != nil {
91+
return err
92+
}
93+
94+
param := newParam(2)
95+
// 利用Golang数组地址空间连续模拟 malloc
96+
options := []internetPreConnOption{
97+
{dwOption: _INTERNET_PER_CONN_FLAGS, value: _PROXY_TYPE_AUTO_PROXY_URL | _PROXY_TYPE_DIRECT},
98+
{dwOption: _INTERNET_PER_CONN_AUTOCONFIG_URL, value: scriptLocAddr},
99+
}
100+
param.pOptions = uintptr(unsafe.Pointer(&options[0]))
101+
ret, _, infoPtr := syscall.Syscall6(internetSetOption,
102+
4,
103+
0,
104+
_INTERNET_OPTION_PER_CONNECTION_OPTION,
105+
uintptr(unsafe.Pointer(&param)),
106+
unsafe.Sizeof(param),
107+
0, 0)
108+
// fmt.Printf(">> Ret [%d] Setting options: %s\n", ret, info)
109+
if ret != 1 {
110+
return errors.New(fmt.Sprintf("%s", infoPtr))
111+
}
112+
113+
return Flush()
114+
}
115+
116+
// SetGlobalProxy 设置全局代理
117+
// proxyServer: 代理服务器host:port,例如: "127.0.0.1:7890"
118+
// bypass: 忽略代理列表,这些配置项开头的地址不进行代理
119+
func SetGlobalProxy(proxyServer string, bypasses ...string) error {
120+
if proxyServer == "" {
121+
return errors.New("代理服务器(proxyServer)配置为空")
122+
}
123+
124+
proxyServerPtrAddr, err := stringPtrAddr(proxyServer)
125+
if err != nil {
126+
return err
127+
}
128+
129+
var bypassBuilder strings.Builder
130+
// 地址过滤配置
131+
if bypasses != nil {
132+
for _, item := range bypasses {
133+
bypassBuilder.WriteString(item)
134+
bypassBuilder.WriteByte(';')
135+
}
136+
} else {
137+
bypassBuilder.WriteString("<local>")
138+
}
139+
bypassAddr, err := stringPtrAddr(bypassBuilder.String())
140+
if err != nil {
141+
return err
142+
}
143+
144+
param := newParam(3)
145+
options := []internetPreConnOption{
146+
{dwOption: _INTERNET_PER_CONN_FLAGS, value: _PROXY_TYPE_PROXY | _PROXY_TYPE_DIRECT},
147+
{dwOption: _INTERNET_PER_CONN_PROXY_SERVER, value: proxyServerPtrAddr},
148+
{dwOption: _INTERNET_PER_CONN_PROXY_BYPASS, value: bypassAddr},
149+
}
150+
param.pOptions = uintptr(unsafe.Pointer(&options[0]))
151+
ret, _, infoPtr := syscall.Syscall6(internetSetOption,
152+
4,
153+
0,
154+
_INTERNET_OPTION_PER_CONNECTION_OPTION,
155+
uintptr(unsafe.Pointer(&param)),
156+
unsafe.Sizeof(param),
157+
0, 0)
158+
// fmt.Printf(">> Ret [%d] Setting options: %s\n", ret, infoPtr)
159+
if ret != 1 {
160+
return errors.New(fmt.Sprintf("%s", infoPtr))
161+
}
162+
163+
return Flush()
164+
}
165+
166+
// Off 关闭代理
167+
func Off() error {
168+
param := newParam(1)
169+
option := internetPreConnOption{
170+
dwOption: _INTERNET_PER_CONN_FLAGS,
171+
//value: _PROXY_TYPE_AUTO_DETECT | _PROXY_TYPE_DIRECT}
172+
value: _PROXY_TYPE_DIRECT}
173+
param.pOptions = uintptr(unsafe.Pointer(&option))
174+
ret, _, infoPtr := syscall.Syscall6(internetSetOption,
175+
4,
176+
0,
177+
_INTERNET_OPTION_PER_CONNECTION_OPTION,
178+
uintptr(unsafe.Pointer(&param)),
179+
unsafe.Sizeof(param),
180+
0, 0)
181+
// fmt.Printf(">> Ret [%d] Setting options: %s\n", ret, info)
182+
if ret != 1 {
183+
return errors.New(fmt.Sprintf("%s", infoPtr))
184+
}
185+
return Flush()
186+
}
187+
188+
// Flush 更新系统配置使生效
189+
func Flush() error {
190+
ret, _, infoPtr := syscall.Syscall6(internetSetOption,
191+
4,
192+
0,
193+
_INTERNET_OPTION_PROXY_SETTINGS_CHANGED,
194+
0, 0,
195+
0, 0)
196+
// fmt.Println(">> Propagating changes:", fmt.Sprintf("%s", errno))
197+
if ret != 1 {
198+
return errors.New(fmt.Sprintf("%s", infoPtr))
199+
}
200+
201+
ret, _, infoPtr = syscall.Syscall6(internetSetOption,
202+
4,
203+
0,
204+
_INTERNET_OPTION_REFRESH,
205+
0, 0,
206+
0, 0)
207+
// fmt.Println(">> Refreshing:", errno)
208+
if ret != 1 {
209+
return errors.New(fmt.Sprintf("%s", infoPtr))
210+
}
211+
return nil
212+
}

main_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// +build windows
2+
3+
package gosysproxy
4+
5+
import "testing"
6+
7+
func TestFlush(t *testing.T) {
8+
err := Flush()
9+
if err != nil {
10+
t.Fatal(err)
11+
}
12+
}
13+
14+
func TestOff(t *testing.T) {
15+
err := Off()
16+
if err != nil {
17+
t.Fatal(err)
18+
}
19+
}
20+
21+
func TestSetPAC(t *testing.T) {
22+
err := SetPAC("http://127.0.0.1:7777/pac")
23+
if err != nil {
24+
t.Fatal(err)
25+
}
26+
}
27+
28+
func TestSetGlobalProxy(t *testing.T) {
29+
err := SetGlobalProxy("127.0.0.1:7890")
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
34+
err = Off()
35+
if err != nil {
36+
t.Fatal(err)
37+
}
38+
39+
err = SetGlobalProxy("127.0.0.1:7890", "foo", "bar")
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
44+
err = Off()
45+
if err != nil {
46+
t.Fatal(err)
47+
}
48+
}

0 commit comments

Comments
 (0)