Skip to content

Commit c9e908d

Browse files
committed
no message
1 parent eacd200 commit c9e908d

13 files changed

+331
-329
lines changed

README.md

+31-53
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,29 @@ golang proxy, HTTP/HTTPS proxy server, HTTP/HTTPS 代理服务器
33

44
命令行:
55
-----------------------------------
6-
-addr string
7-
代理服务器地 (format "0.0.0.0:8080")
8-
-dataBufioSize int
9-
代理数据交换缓冲区大小,单位字节 (default 10240)
10-
-disableCompression
11-
禁止传送数据时候进行压缩 (default false)
12-
-disableKeepAlives
13-
禁止长连接 (default false)
14-
-expectContinueTimeout int
15-
http1.1过度到http2的等待超时,单位毫秒 (default 1000)
16-
-idleConnTimeout int
17-
空闲连接超时时,单位毫秒 (default 0)
18-
-keepAlive int
19-
保持连接心跳检测超时,单位毫秒 (default 30000)
20-
-linkPosterior
21-
支持连接式代理,如:http://111.222.333.444:8080/https://www.baidu.com/abc/file.zip
22-
-log string
23-
日志文件(默认留空在控制台显示日志) (format "./vproxy.txt")
24-
-logLevel int
25-
日志级别,0)不记录 1)客户端IP 2)认证 3)访问的Host地址 4)路径 5)请求 6)响应 7)错误 (default 0)
26-
-maxIdleConns int
27-
保持空闲连接(TCP)数量 (default 500)
28-
-maxIdleConnsPerHost int
29-
保持空闲连接(Host)数量 (default 500)
30-
-maxResponseHeaderBytes int
31-
读取服务器发来的文件标头大小限制 (default 0)
32-
-proxy string
33-
代理服务器的上级代理IP地址 (format "http://11.22.33.44:8888" or "socks5://admin:[email protected]:1080")
34-
-pwd string
35-
密码
36-
-responseHeaderTimeout int
37-
读取服务器发来的文件标头超时,单位毫秒 (default 0)
38-
-timeout int
39-
转发连接请求超时,单位毫秒 (default 300000)
40-
-tlsHandshakeTimeout int
41-
SSL握手超时,单位毫秒 (default 10000)
42-
-user string
43-
用户名
6+
-addr string
7+
代理服务器地 (format "0.0.0.0:8080")
8+
-dataBufioSize int
9+
代理数据交换缓冲区大小,单位字节 (default 10240)
10+
-idleConnTimeout int
11+
空闲连接超时时,单位毫秒 (default 0)
12+
-linkPosterior
13+
支持连接式代理,如:http://111.222.333.444:8080/https://www.baidu.com/abc/file.zip
14+
-log string
15+
日志文件(默认留空在控制台显示日志) (format "./vproxy.txt")
16+
-logLevel int
17+
日志级别,0)不记录 1)客户端IP 2)认证 3)访问的Host地址 4)路径 5)请求 6)响应 7)错误 (default 0)
18+
-proxy string
19+
代理服务器的上级代理IP地址 (format "http://11.22.33.44:8888" or "socks5://admin:[email protected]:1080")
20+
-pwd string
21+
密码
22+
-timeout int
23+
转发连接请求超时,单位毫秒 (default 300000)
24+
-user string
25+
用户名
4426

4527
命令行例子:vproxy -addr 0.0.0.0:8080
4628

47-
4829
列表:
4930
-----------------------------------
5031
```go
@@ -58,23 +39,20 @@ const
5839
Response // 响应
5940
Error // 错误
6041
)
61-
type Config struct { // 配置
62-
LinkPosterior bool // 支持连接后面的,如:http://192.168.2.31/http://www.baidu.com/
63-
DataBufioSize int // 缓冲区大小
64-
Auth func(username, password string) bool // 认证
65-
Timeout time.Duration // 转发连接请求超时
66-
Deadline time.Time // 转发连接请求超时
67-
}
42+
6843
type Proxy struct { // 代理
69-
*Config // 配置
70-
Addr string // 代理IP地址
71-
Server http.Server // 服务器
72-
Transport http.RoundTripper // 代理
73-
ErrorLogLevel LogLevel // 日志级别
74-
ErrorLog *log.Logger // 日志
44+
LinkPosterior bool // 支持连接后面的,如:http://192.168.2.31/http://www.baidu.com/
45+
DataBufioSize int // 缓冲区大小
46+
Auth func(username, password string) bool // 认证
47+
Addr string // 代理IP地址
48+
Server http.Server // 服务器
49+
DialContext func(ctx context.Context, network, address string) (net.Conn, error) // 拨号
50+
ErrorLog *log.Logger // 日志
51+
ErrorLogLevel LogLevel // 日志级别
7552
}
7653
func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) // 处理
77-
func (p *Proxy) ListenAndServ() error // 监听
54+
func (p *Proxy) ListenAndServe() error // 监听
7855
func (p *Proxy) Serve(l net.Listener) error // 监听
7956
func (p *Proxy) Close() error // 关闭代理
57+
8058
```

cmd/build.bat

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1+
cd /D ./main
2+
set GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,https://gocenter.io,https://proxy.golang.org,https://goproxy.io,https://athens.azurefd.net,direct
3+
set GOSUMDB=sum.golang.org
4+
15
set GOOS=windows
26
set GOARCH=amd64
3-
go build -o ./bin/vproxy-win-amd64.exe -ldflags="-s -w" ./main/main.go
7+
go build -o ../bin/vproxy-win-amd64.exe -ldflags="-s -w"
8+
49
set GOOS=linux
510
set GOARCH=amd64
6-
go build -o ./bin/vproxy-linux-amd64 -ldflags="-s -w" ./main/main.go
11+
go build -o ../bin/vproxy-linux-amd64 -ldflags="-s -w"
712
set GOARCH=386
8-
go build -o ./bin/vproxy-linux-386 -ldflags="-s -w" ./main/main.go
13+
go build -o ../bin/vproxy-linux-386 -ldflags="-s -w"
914
set GOARCH=arm
1015
set GOARM=7
11-
go build -o ./bin/vproxy-linux-armv7 -ldflags="-s -w" ./main/main.go
16+
go build -o ../bin/vproxy-linux-armv7 -ldflags="-s -w"
1217
set GOARCH=arm64
13-
go build -o ./bin/vproxy-linux-arm64 -ldflags="-s -w" ./main/main.go
18+
go build -o ../bin/vproxy-linux-arm64 -ldflags="-s -w"
1419
set GOARCH=mips
15-
go build -o ./bin/vproxy-linux-mips -ldflags="-s -w" ./main/main.go
20+
go build -o ../bin/vproxy-linux-mips -ldflags="-s -w"
1621

17-
upx -9 ./bin/*
22+
upx -9 ../bin/*

cmd/main/go.mod.bak

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module main
2+
3+
go 1.15
4+
5+
replace github.com/456vv/vsocks5 => ../../../vsocks5
6+
7+
replace github.com/456vv/vproxy => ../../../vproxy
8+

cmd/main/main.go

+153-44
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package main
22

33
import (
44
"github.com/456vv/vproxy"
5+
"github.com/456vv/vsocks5"
6+
"github.com/456vv/vconn"
7+
"golang.org/x/crypto/ssh"
58
"net"
69
"net/http"
7-
//"crypto/tls"
810
"net/url"
911
"time"
1012
"flag"
@@ -13,6 +15,9 @@ import (
1315
"io"
1416
"os"
1517
"context"
18+
"bytes"
19+
"errors"
20+
"encoding/base64"
1621
)
1722

1823
var (
@@ -22,18 +27,9 @@ var (
2227
flogLevel = flag.Int("logLevel", 0, "日志级别,0)不记录 1)客户端IP 2)认证 3)访问的Host地址 4)路径 5)请求 6)响应 7)错误 (default 0)")
2328
faddr = flag.String("addr", "", "代理服务器地 (format \"0.0.0.0:8080\")")
2429
fproxy = flag.String("proxy", "", "代理服务器的上级代理IP地址 (format \"http://11.22.33.44:8888\" or \"socks5://admin:[email protected]:1080\")")
25-
fmaxIdleConns = flag.Int("maxIdleConns", 500, "保持空闲连接(TCP)数量")
26-
fmaxIdleConnsPerHost = flag.Int("maxIdleConnsPerHost", 500, "保持空闲连接(Host)数量")
27-
fdisableKeepAlives = flag.Bool("disableKeepAlives", false, "禁止长连接 (default false)")
28-
fdisableCompression = flag.Bool("disableCompression", false, "禁止传送数据时候进行压缩 (default false)")
29-
ftlsHandshakeTimeout = flag.Int64("tlsHandshakeTimeout", 10000, "SSL握手超时,单位毫秒")
3030
fidleConnTimeout = flag.Int64("idleConnTimeout", 0, "空闲连接超时时,单位毫秒 (default 0)")
31-
fexpectContinueTimeout = flag.Int64("expectContinueTimeout", 1000, "http1.1过度到http2的等待超时,单位毫秒")
32-
fresponseHeaderTimeout = flag.Int64("responseHeaderTimeout", 0, "读取服务器发来的文件标头超时,单位毫秒 (default 0)")
33-
fmaxResponseHeaderBytes = flag.Int64("maxResponseHeaderBytes", 0, "读取服务器发来的文件标头大小限制 (default 0)")
3431
fdataBufioSize = flag.Int("dataBufioSize", 1024*10, "代理数据交换缓冲区大小,单位字节")
3532
ftimeout = flag.Int64("timeout", 300000, "转发连接请求超时,单位毫秒")
36-
fkeepAlive = flag.Int64("keepAlive", 30000, "保持连接心跳检测超时,单位毫秒")
3733
flinkPosterior = flag.Bool("linkPosterior", false, "支持连接式代理,如:http://111.222.333.444:8080/https://www.baidu.com/abc/file.zip")
3834
)
3935

@@ -53,50 +49,144 @@ func main(){
5349
}
5450
out = file
5551
}
52+
5653
p := &vproxy.Proxy{
57-
Config : &vproxy.Config{
58-
LinkPosterior: *flinkPosterior,
59-
DataBufioSize: *fdataBufioSize,
60-
Timeout: time.Duration(*ftimeout) * time.Millisecond,
61-
KeepAlive: time.Duration(*fkeepAlive) * time.Millisecond,
62-
},
54+
LinkPosterior: *flinkPosterior,
55+
DataBufioSize: *fdataBufioSize,
6356
Addr : *faddr,
64-
Transport : &http.Transport{
65-
DisableKeepAlives: *fdisableKeepAlives,
66-
DisableCompression: *fdisableCompression,
67-
MaxIdleConns: *fmaxIdleConns,
68-
MaxIdleConnsPerHost: *fmaxIdleConnsPerHost,
69-
IdleConnTimeout: time.Duration(*fidleConnTimeout) * time.Millisecond,
70-
ResponseHeaderTimeout: time.Duration(*fresponseHeaderTimeout) * time.Millisecond,
71-
MaxResponseHeaderBytes: *fmaxResponseHeaderBytes,
72-
TLSHandshakeTimeout: time.Duration(*ftlsHandshakeTimeout) * time.Millisecond,
73-
ExpectContinueTimeout: time.Duration(*fexpectContinueTimeout) * time.Millisecond,
74-
},
7557
ErrorLogLevel: vproxy.LogLevel(*flogLevel),
7658
}
7759
p.ErrorLog = log.New(out, "", log.Lshortfile|log.LstdFlags)
7860
if *fuser != "" {
79-
p.Config.Auth = func(username, password string) bool {
61+
p.Auth = func(username, password string) bool {
8062
return username == *fuser && password == *fpwd
8163
}
8264
}
83-
84-
if tr, ok := p.Transport.(*http.Transport); ok && *fproxy != "" {
85-
dialer := &net.Dialer{
86-
Timeout: p.Config.Timeout,
87-
KeepAlive: p.Config.KeepAlive,
88-
DualStack: true,
65+
66+
tr := http.DefaultTransport.(*http.Transport)
67+
tr.IdleConnTimeout=time.Duration(*fidleConnTimeout) * time.Millisecond
68+
dialer := &net.Dialer{
69+
Timeout: time.Duration(*ftimeout) * time.Millisecond,
70+
DualStack: true,
71+
}
72+
p.DialContext=dialer.DialContext
73+
74+
if *fproxy != "" {
75+
purl, err := url.Parse(*fproxy)
76+
if err != nil {
77+
fmt.Println("上级代理格式错误:", err)
78+
return
8979
}
90-
tr.Proxy = func(r *http.Request) (*url.URL, error){
91-
return url.Parse(*fproxy)
92-
}
93-
tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error){
94-
ctx, cancel := context.WithTimeout(ctx, p.Config.Timeout)
95-
defer cancel()
96-
return dialer.DialContext(ctx, network, addr)
97-
}
98-
}
99-
80+
var puser, ppwd string
81+
if purl.User != nil {
82+
puser = purl.User.Username()
83+
ppwd, _ = purl.User.Password()
84+
}
85+
86+
switch purl.Scheme {
87+
case "ssh":
88+
config := &ssh.ClientConfig{
89+
User: puser,
90+
Auth: []ssh.AuthMethod{
91+
ssh.Password(ppwd),
92+
},
93+
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
94+
log.Println(hostname, remote, key)
95+
return nil
96+
},
97+
HostKeyAlgorithms: []string{
98+
ssh.KeyAlgoRSA,
99+
ssh.KeyAlgoDSA,
100+
ssh.KeyAlgoECDSA256,
101+
ssh.KeyAlgoECDSA384,
102+
ssh.KeyAlgoECDSA521,
103+
ssh.KeyAlgoED25519,
104+
},
105+
Timeout: 5 * time.Second,
106+
}
107+
108+
sshConn, client, err := sshDial("tcp", purl.Host, config)
109+
if err != nil {
110+
fmt.Println("代理拨号错误: ", err)
111+
return
112+
}
113+
defer func(){
114+
client.Close()
115+
}()
116+
117+
//connectProxy
118+
p.DialContext = func(ctx context.Context, network, address string) (net.Conn, error){
119+
if cn, ok := sshConn.(vconn.CloseNotifier); ok {
120+
select {
121+
case <-cn.CloseNotify():
122+
sshConn, client, err = sshDial("tcp", purl.Host, config)
123+
if err != nil {
124+
return nil, err
125+
}
126+
default:
127+
}
128+
}
129+
130+
return client.Dial(network, address)
131+
}
132+
133+
//httpProxy
134+
tr.DialContext=p.DialContext
135+
case "https","http":
136+
//httpProxy
137+
tr.Proxy = func(r *http.Request) (*url.URL, error){
138+
return purl, nil
139+
}
140+
141+
//connectProxy
142+
p.DialContext = func(ctx context.Context, network, address string) (net.Conn, error){
143+
pconn, err := dialer.Dial(network, purl.Host)
144+
if err != nil {
145+
return nil, err
146+
}
147+
148+
if purl.Scheme == "http" {
149+
return pconn, err
150+
}
151+
152+
var pauth string
153+
if puser != "" {
154+
pauth = "\nProxy-Authorization: Basic " +basicAuth(puser, ppwd)
155+
}
156+
pconn.Write([]byte(fmt.Sprintf("CONNECT %[1]s HTTP/1.1\r\nHost: %[1]s%s\r\n\r\n", address, pauth)))
157+
158+
p := make([]byte, 1024)
159+
n, err := pconn.Read(p)
160+
if err != nil {
161+
return nil, err
162+
}
163+
if bytes.Compare([]byte("HTTP/1.1 200 Connection established"), p[:n]) != 0 {
164+
pconn.Close()
165+
return nil, errors.New("https proxy not support")
166+
}
167+
return pconn, err
168+
}
169+
case "socks5":
170+
//httpProxy
171+
tr.Proxy = func(r *http.Request) (*url.URL, error){
172+
return purl, nil
173+
}
174+
175+
//connectProxy
176+
s5Client := &vsocks5.Client{
177+
Username: puser,
178+
Password: ppwd,
179+
Server: purl.Host,
180+
}
181+
p.DialContext = func(ctx context.Context, network, address string) (net.Conn, error){
182+
return s5Client.Dial(network, address)
183+
}
184+
default:
185+
fmt.Printf("暂时不支持 %s 协议代理!\n", purl.Scheme)
186+
return
187+
}
188+
}
189+
100190
defer p.Close()
101191
err := p.ListenAndServe()
102192
if err != nil {
@@ -105,3 +195,22 @@ func main(){
105195

106196

107197
}
198+
func sshDial(network, addr string, config *ssh.ClientConfig) (net.Conn, *ssh.Client, error){
199+
conn, err := net.DialTimeout(network, addr, config.Timeout)
200+
if err != nil {
201+
return nil, nil, err
202+
}
203+
204+
conn = vconn.NewConn(conn)
205+
c, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
206+
if err != nil {
207+
return nil, nil, err
208+
}
209+
210+
return conn, ssh.NewClient(c, chans, reqs), nil
211+
}
212+
213+
func basicAuth(username, password string) string {
214+
auth := username + ":" + password
215+
return base64.StdEncoding.EncodeToString([]byte(auth))
216+
}

0 commit comments

Comments
 (0)