update readme
1
.gitignore
vendored
@ -2,6 +2,7 @@ proxy
|
||||
*.exe
|
||||
*.exe~
|
||||
.*
|
||||
!.gitignore
|
||||
release-*
|
||||
proxy.crt
|
||||
proxy.key
|
||||
|
||||
43
CHANGELOG
@ -1,4 +1,47 @@
|
||||
proxy更新日志
|
||||
v4.7
|
||||
1.增加了基于gomobile的sdk,对安卓/IOS提供SDK支持.
|
||||
2.优化了bridge的日志,增加了client和server的掉线日志.
|
||||
3.优化了sps读取http(s)代理响应的缓冲大小,同时优化了CONNECT请求,
|
||||
避免了某些代理服务器返回过多数据导致不能正常通讯的问题.
|
||||
4.去除了鸡肋连接池功能.
|
||||
5.优化了所有服务代码,方便对sdk提供支持.
|
||||
6.增加了SDK手册.
|
||||
7.增加了GUI客户端(windows/web/android/ios)介绍主页.
|
||||
8.SPS\HTTP(s)\Socks代理增加了自定义加密传输,只需要通过参数-z和-Z设置一个密码即可.
|
||||
9.SPS\HTTP(s)\Socks代理增加了压缩传输,只需要通过参数-m和-M设置即可.
|
||||
10.手册增加了SPS\HTTP(s)\Socks自定义加密的使用示例.
|
||||
11.手册增加了SPS\HTTP(s)\Socks压缩传输的使用示例.
|
||||
12.优化了多链接版本的内网穿透,融合了多链接和smux的优点,即能够拥有大的吞吐量,
|
||||
同时又具备mux的心跳机制保证了链接的稳定性.
|
||||
13.手册增加了大量配图.
|
||||
|
||||
v4.6
|
||||
1.sps,http(s),socks5,内网穿透都做了大量的超时优化处理,更加稳定.
|
||||
2.sps增加了强大的树形级联认证支持,可以轻松构建你的认证代理网络.
|
||||
3.手册增加了6.6对sps认证功能的介绍.
|
||||
|
||||
|
||||
v4.5
|
||||
1.优化了mux内网穿透连接管理逻辑,增强了稳定性.
|
||||
2.mux内网穿透增加了tcp和kcp协议支持,之前是tls,现在支持三种协议tcp,tls,kcp.
|
||||
3.keygen参数增加了用法: proxy keygen usage.
|
||||
4.http(s)/socks5代理,tls增加了自签名证书支持.
|
||||
5.建议升级.
|
||||
v4.4
|
||||
1.增加了协议转换sps功能,代理协议转换使用的是sps子命令(socks+https的缩写),
|
||||
sps本身不提供代理功能,只是接受代理请求"转换并转发"给已经存在的http(s)代理
|
||||
或者socks5代理;sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口
|
||||
同时支持http(s)和socks5代理,而且http(s)代理支持正向代理和反向代理(SNI),转
|
||||
换后的SOCKS5代理不支持UDP功能;另外对于已经存在的http(s)代理或者socks5代理,
|
||||
支持tls、tcp、kcp三种模式,支持链式连接,也就是可以多个sps结点层级连接构建
|
||||
加密通道。
|
||||
2.增加了对KCP传输参数的配置,多达17个参数可以自由的配置对kcp传输效率调优。
|
||||
3.内网穿透功能,server和client增加了--session-count参数,可以设置server每个
|
||||
监听端口到bridge打开的session数量,可以设置client到bridge打开的session数量,
|
||||
之前都是1个,现在性能提升N倍,N就是你自己设置的--session-count,这个参数很大
|
||||
程度上解决了多路复用的拥塞问题,v4.4开始默认10个。
|
||||
|
||||
v4.3
|
||||
1.优化了参数keygen生成证书逻辑,避免证书出现特征。
|
||||
2.http(s)和socks代理增加了--dns-address和--dns-ttl参数。
|
||||
|
||||
142
Godeps/Godeps.json
generated
@ -1,41 +1,80 @@
|
||||
{
|
||||
"ImportPath": "snail007/proxy",
|
||||
"GoVersion": "go1.8",
|
||||
"GodepVersion": "v79",
|
||||
"GoVersion": "go1.9",
|
||||
"GodepVersion": "v80",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/template",
|
||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/template/parse",
|
||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/units",
|
||||
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/snappy",
|
||||
"Rev": "553a641470496b2327abcac10b36396bd98e45c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/dns",
|
||||
"Comment": "v1.0.4",
|
||||
"Rev": "5364553f1ee9cddc7ac8b62dce148309c386695b"
|
||||
"Comment": "v1.0.4-1-g40b5202",
|
||||
"Rev": "40b520211179dbf7eaafaa7fe1ffaa1b7d929ee0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/xtaci/kcp-go",
|
||||
"Comment": "v3.19-6-g21da33a",
|
||||
"Rev": "21da33a6696d67c1bffb3c954366499d613097a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/xtaci/smux",
|
||||
"Comment": "v1.0.6",
|
||||
"Rev": "ebec7ef2574b42a7088cd7751176483e0a27d458"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ssh",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/time/rate",
|
||||
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
|
||||
"Comment": "v2.2.5",
|
||||
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ed25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/ipv4",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/ipv6",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/bpf",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/internal/iana",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/internal/socket",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pkg/errors",
|
||||
"Comment": "v0.8.0-6-g602255c",
|
||||
"Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/templexxx/cpufeat",
|
||||
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/templexxx/reedsolomon",
|
||||
"Comment": "0.1.1-4-g7092926",
|
||||
@ -51,16 +90,6 @@
|
||||
"Comment": "v1.0.1-3-g9d99fac",
|
||||
"Rev": "9d99face20b0dd300b7db50b3f69758de41c096a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/xtaci/kcp-go",
|
||||
"Comment": "v3.19-6-g21da33a",
|
||||
"Rev": "21da33a6696d67c1bffb3c954366499d613097a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/xtaci/smux",
|
||||
"Comment": "v1.0.6",
|
||||
"Rev": "ebec7ef2574b42a7088cd7751176483e0a27d458"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
@ -69,34 +98,10 @@
|
||||
"ImportPath": "golang.org/x/crypto/cast5",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ed25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/salsa20",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ssh",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/tea",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
@ -110,33 +115,28 @@
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/bpf",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
"ImportPath": "github.com/templexxx/cpufeat",
|
||||
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/internal/iana",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/internal/socket",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/ipv4",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
"ImportPath": "github.com/alecthomas/template",
|
||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/ipv6",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
"ImportPath": "github.com/alecthomas/units",
|
||||
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/time/rate",
|
||||
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
|
||||
"Comment": "v2.2.5",
|
||||
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
|
||||
"ImportPath": "github.com/alecthomas/template/parse",
|
||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
16
README.md
@ -298,13 +298,13 @@ Local HTTP (S) proxy use 28080 port,excute:
|
||||
|
||||
#### **1.8.KCP protocol transmission**
|
||||

|
||||
The KCP protocol requires a -B parameter to set a password which can encrypt and decrypt data.
|
||||
The KCP protocol requires a --kcp-key parameter to set a password which can encrypt and decrypt data.
|
||||
|
||||
Http first level proxy(VPS,IP:22.22.22.22)
|
||||
`./proxy http -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy http -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
Http second level proxy(os is Linux)
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
Then access to the local 8080 port is access to the proxy's port 38080 on the VPS, and the data is transmitted through the KCP protocol.
|
||||
#### **1.9.HTTP reverse proxy**
|
||||

|
||||
@ -729,13 +729,13 @@ ip: user's IP, for example: 192.168.1.200
|
||||
If there is no -a or -F or --auth-url parameters, it means to turn off the authentication.
|
||||
|
||||
#### **5.8.KCP protocol transmission**
|
||||
The KCP protocol requires a -B parameter which can set a password to encrypt and decrypt data.
|
||||
The KCP protocol requires a --kcp-key parameter which can set a password to encrypt and decrypt data.
|
||||
|
||||
HTTP first level proxy(VPS,IP:22.22.22.22)
|
||||
`./proxy socks -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy socks -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
HTTP two level proxy(local os is Linux)
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
Then access to the local 8080 port is access to the proxy port 38080 on the VPS, and the data is transmitted through the KCP protocol.
|
||||
|
||||
#### **5.9.Custom DNS**
|
||||
@ -805,7 +805,7 @@ command:
|
||||
|
||||
Suppose there is a KCP HTTP (s) proxy (password: demo123): 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080.
|
||||
command:
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.3.SOCKS5 to HTTP(S) + SOCKS5**
|
||||
Suppose there is a common Socks5 proxy: 127.0.0.1:8080, now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time, and the local port after transformation is 18080.
|
||||
@ -818,7 +818,7 @@ command:
|
||||
|
||||
Suppose there is a KCP Socks5 proxy (password: demo123): 127.0.0.1:8080, now we turn it into a common proxy that support HTTP (s) and Socks5 at the same time, and the local port after transformation is 18080.
|
||||
command:
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.4.Chain style connection**
|
||||

|
||||
|
||||
351
README_ZH.md
@ -23,7 +23,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- 集成外部API,HTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成,可以方便的通过外部系统控制代理用户.
|
||||
- 反向代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站.
|
||||
- 透明HTTP(S)代理,配合iptables,在网关直接把出去的80,443方向的流量转发到proxy,就能实现无感知的智能路由器代理.
|
||||
- 协议转换,可以把已经存在的HTTP(S)或SOCKS5代理转换为一个端口同时支持HTTP(S)和SOCKS5代理,转换后的SOCKS5代理不支持UDP功能。
|
||||
- 协议转换,可以把已经存在的HTTP(S)或SOCKS5代理转换为一个端口同时支持HTTP(S)和SOCKS5代理,转换后的SOCKS5代理不支持UDP功能,同时支持强大的级联认证功能。
|
||||
- 自定义底层加密传输,http(s)\sps\socks代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可。
|
||||
- 底层压缩高效传输,http(s)\sps\socks代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在加密之后还可以对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的。
|
||||
|
||||
### Why need these?
|
||||
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
||||
@ -35,7 +37,10 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- ...
|
||||
|
||||
|
||||
本页是v4.4手册,其他版本手册请点击下面链接查看.
|
||||
本页是v4.7手册,其他版本手册请点击下面链接查看.
|
||||
- [v4.6手册](https://github.com/snail007/goproxy/tree/v4.6)
|
||||
- [v4.5手册](https://github.com/snail007/goproxy/tree/v4.5)
|
||||
- [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4)
|
||||
- [v4.3手册](https://github.com/snail007/goproxy/tree/v4.3)
|
||||
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2)
|
||||
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1)
|
||||
@ -82,7 +87,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- [1.9 HTTP(S)反向代理](#19-https反向代理)
|
||||
- [1.10 HTTP(S)透明代理](#110-https透明代理)
|
||||
- [1.11 自定义DNS](#111-自定义dns)
|
||||
- [1.12 查看帮助](#112-查看帮助)
|
||||
- [1.12 自定义加密](#112-自定义加密)
|
||||
- [1.13 压缩传输](#113-压缩传输)
|
||||
- [1.14 查看帮助](#114-查看帮助)
|
||||
- [2. TCP代理](#2tcp代理)
|
||||
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
|
||||
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
|
||||
@ -118,14 +125,22 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- [5.7 认证](#57认证)
|
||||
- [5.8 KCP协议传输](#58kcp协议传输)
|
||||
- [5.9 自定义DNS](#59自定义dns)
|
||||
- [5.10 查看帮助](#510查看帮助)
|
||||
- [5.10 自定义加密](#510-自定义加密)
|
||||
- [5.11 压缩传输](#511-压缩传输)
|
||||
- [5.12 查看帮助](#512查看帮助)
|
||||
- [6. 代理协议转换](#6代理协议转换)
|
||||
- [6.1 功能介绍](#61-功能介绍)
|
||||
- [6.2 HTTP(S)转HTTP(S)+SOCKS5](#62-https转httpssocks5)
|
||||
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
||||
- [6.4 链式连接](#64-链式连接)
|
||||
- [6.5 监听多个端口](#65-监听多个端口)
|
||||
- [6.6 查看帮助](#66-查看帮助)
|
||||
- [6.6 认证功能](#66-认证功能)
|
||||
- [6.7 自定义加密](#67-自定义加密)
|
||||
- [6.8 压缩传输](#68-压缩传输)
|
||||
- [6.9 查看帮助](#69-查看帮助)
|
||||
- [7. KCP配置](#7kcp配置)
|
||||
- [7.1 配置介绍](#71-配置介绍)
|
||||
- [7.2 详细配置](#72-详细配置)
|
||||
|
||||
### Fast Start
|
||||
提示:所有操作需要root权限.
|
||||
@ -143,7 +158,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
|
||||
下载地址:https://github.com/snail007/goproxy/releases
|
||||
```shell
|
||||
cd /root/proxy/
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.4/proxy-linux-amd64.tar.gz
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.7/proxy-linux-amd64.tar.gz
|
||||
```
|
||||
#### **2.下载自动安装脚本**
|
||||
```shell
|
||||
@ -184,7 +199,8 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
||||
在linux上并安装了openssl命令,可以直接通过下面的命令生成证书和key文件.
|
||||
`./proxy keygen`
|
||||
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
|
||||
|
||||
更多用法:`proxy keygen usage`。
|
||||
|
||||
### **后台运行**
|
||||
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
|
||||
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
|
||||
@ -204,20 +220,19 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
|
||||
`./proxy http -g "23.23.23.23"`
|
||||
|
||||
### **1.HTTP代理**
|
||||
#### **1.1.普通HTTP代理**
|
||||

|
||||
#### **1.1.普通一级HTTP代理**
|
||||

|
||||
`./proxy http -t tcp -p "0.0.0.0:38080"`
|
||||
|
||||
#### **1.2.普通二级HTTP代理**
|
||||

|
||||
使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080`
|
||||
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||
默认关闭了连接池,如果要加快访问速度,-L可以开启连接池,10就是连接池大小,0为关闭,
|
||||
开启连接池在网络不好的情况下,稳定不是很好.
|
||||
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -L 10`
|
||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
||||
`./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||
|
||||
#### **1.3.HTTP二级代理(加密)**
|
||||

|
||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||
|
||||
@ -230,6 +245,7 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
|
||||
然后设置你的windos系统中,需要通过代理上网的程序的代理为http模式,地址为:127.0.0.1,端口为:8080,程序即可通过加密通道通过vps上网。
|
||||
|
||||
#### **1.4.HTTP三级代理(加密)**
|
||||

|
||||
一级HTTP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||
二级HTTP代理VPS_02,IP:33.33.33.33
|
||||
@ -265,6 +281,7 @@ target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.c
|
||||
`./proxy http --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
|
||||
#### **1.7.HTTP(S)通过SSH中转**
|
||||

|
||||
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
|
||||
假设有:vps
|
||||
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
|
||||
@ -278,16 +295,18 @@ target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.c
|
||||
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||
|
||||
#### **1.8.KCP协议传输**
|
||||
KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||

|
||||
KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
|
||||
|
||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||
`./proxy http -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy http -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
二级HTTP代理(本地Linux)
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
|
||||
|
||||
#### **1.9 HTTP(S)反向代理**
|
||||
#### **1.9 HTTP(S)反向代理**
|
||||

|
||||
proxy不仅支持在其他软件里面通过设置代理的方式,为其他软件提供代理服务,而且支持直接把请求的网站域名解析到proxy监听的ip上,然后proxy监听80和443端口,那么proxy就会自动为你代理访问需要访问的HTTP(S)网站.
|
||||
|
||||
使用方式:
|
||||
@ -300,7 +319,7 @@ proxy不仅支持在其他软件里面通过设置代理的方式,为其他软
|
||||
`./proxy http -t tcp -p :80,:443 -T tls -P "2.2.2.2:33080" -C proxy.crt -K proxy.key`
|
||||
|
||||
注意:
|
||||
proxy所在的服务器的DNS解析结果不能受到自定义的解析影响,不然就死循环了.
|
||||
proxy所在的服务器的DNS解析结果不能受到自定义的解析影响,不然就死循环了,proxy代理最好指定`--dns 8.8.8.8`参数.
|
||||
|
||||
#### **1.10 HTTP(S)透明代理**
|
||||
该模式需要具有一定的网络基础,相关概念不懂的请自行搜索解决.
|
||||
@ -353,19 +372,65 @@ iptables -t nat -A OUTPUT -p tcp -j PROXY
|
||||
比如:
|
||||
`./proxy http -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300`
|
||||
|
||||
#### **1.12 查看帮助**
|
||||
#### **1.12 自定义加密**
|
||||
proxy的http(s)代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义
|
||||
加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可,
|
||||
加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
|
||||
自定义加密要求两端都是proxy才可以,下面分别用二级,三级为例:
|
||||
|
||||
**二级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy http -t tcp -z demo_password -p :7777`
|
||||
本地二级执行:
|
||||
`proxy http -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||
|
||||
|
||||
**三级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy http -t tcp -z demo_password -p :7777`
|
||||
二级vps(ip:3.3.3.3)上执行:
|
||||
`proxy http -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
|
||||
本地三级执行:
|
||||
`proxy http -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||
|
||||
#### **1.13 压缩传输**
|
||||
proxy的http(s)代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以对数据进行压缩,
|
||||
也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,一部分是本地(-m)是否压缩传输,
|
||||
一部分是与上级(-M)传输是否压缩.
|
||||
压缩要求两端都是proxy才可以,压缩也在一定程度上保护了(加密)数据,下面分别用二级,三级为例:
|
||||
|
||||
**二级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy http -t tcp -m -p :7777`
|
||||
本地二级执行:
|
||||
`proxy http -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||
|
||||
|
||||
**三级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy http -t tcp -m -p :7777`
|
||||
二级vps(ip:3.3.3.3)上执行:
|
||||
`proxy http -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
|
||||
本地三级执行:
|
||||
`proxy http -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||
|
||||
#### **1.14 查看帮助**
|
||||
`./proxy help http`
|
||||
|
||||
### **2.TCP代理**
|
||||
|
||||
#### **2.1.普通一级TCP代理**
|
||||

|
||||

|
||||
本地执行:
|
||||
`./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22"`
|
||||
那么访问本地33080端口就是访问192.168.22.33的22端口.
|
||||
|
||||
#### **2.2.普通二级TCP代理**
|
||||

|
||||

|
||||
VPS(IP:22.22.22.33)执行:
|
||||
`./proxy tcp -p ":33080" -T tcp -P "127.0.0.1:8080"`
|
||||
本地执行:
|
||||
@ -373,6 +438,7 @@ VPS(IP:22.22.22.33)执行:
|
||||
那么访问本地23080端口就是访问22.22.22.33的8080端口.
|
||||
|
||||
#### **2.3.普通三级TCP代理**
|
||||

|
||||
一级TCP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080"`
|
||||
二级TCP代理VPS_02,IP:33.33.33.33
|
||||
@ -382,17 +448,19 @@ VPS(IP:22.22.22.33)执行:
|
||||
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
||||
|
||||
#### **2.4.加密二级TCP代理**
|
||||

|
||||
VPS(IP:22.22.22.33)执行:
|
||||
`./proxy tcp -t tcp -p ":33080" -T tcp -P "127.0.0.1:8080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":33080" -T tcp -P "127.0.0.1:8080" -C proxy.crt -K proxy.key`
|
||||
本地执行:
|
||||
`./proxy tcp -p ":23080" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地23080端口就是通过加密TCP隧道访问22.22.22.33的8080端口.
|
||||
|
||||
#### **2.5.加密三级TCP代理**
|
||||

|
||||
一级TCP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy tcp -t tcp -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
|
||||
二级TCP代理VPS_02,IP:33.33.33.33
|
||||
`./proxy tcp -t tcp -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
三级TCP代理(本地)
|
||||
`./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
||||
@ -403,11 +471,13 @@ VPS(IP:22.22.22.33)执行:
|
||||
### **3.UDP代理**
|
||||
|
||||
#### **3.1.普通一级UDP代理**
|
||||

|
||||
本地执行:
|
||||
`./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"`
|
||||
那么访问本地UDP:5353端口就是访问8.8.8.8的UDP:53端口.
|
||||
|
||||
#### **3.2.普通二级UDP代理**
|
||||

|
||||
VPS(IP:22.22.22.33)执行:
|
||||
`./proxy tcp -p ":33080" -T udp -P "8.8.8.8:53"`
|
||||
本地执行:
|
||||
@ -415,6 +485,7 @@ VPS(IP:22.22.22.33)执行:
|
||||
那么访问本地UDP:5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
||||
|
||||
#### **3.3.普通三级UDP代理**
|
||||

|
||||
一级TCP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"`
|
||||
二级TCP代理VPS_02,IP:33.33.33.33
|
||||
@ -424,17 +495,19 @@ VPS(IP:22.22.22.33)执行:
|
||||
那么访问本地5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的53端口.
|
||||
|
||||
#### **3.4.加密二级UDP代理**
|
||||

|
||||
VPS(IP:22.22.22.33)执行:
|
||||
`./proxy tcp -t tcp -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
本地执行:
|
||||
`./proxy udp -p ":5353" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地UDP:5353端口就是通过加密TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
||||
|
||||
#### **3.5.加密三级UDP代理**
|
||||

|
||||
一级TCP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy tcp -t tcp -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
二级TCP代理VPS_02,IP:33.33.33.33
|
||||
`./proxy tcp -t tcp -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
三级TCP代理(本地)
|
||||
`./proxy udp -p ":5353" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地5353端口就是通过加密TCP隧道,通过VPS_01访问8.8.8.8的53端口.
|
||||
@ -590,13 +663,14 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
||||
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
||||
|
||||
#### **5.2.普通二级SOCKS5代理**
|
||||

|
||||

|
||||
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080`
|
||||
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理;如果域名即在黑名单又在白名单中,那么黑名单起作用.
|
||||
`./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||
|
||||
#### **5.3.SOCKS二级代理(加密)**
|
||||

|
||||
一级SOCKS代理(VPS,IP:22.22.22.22)
|
||||
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||
|
||||
@ -609,6 +683,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
||||
然后设置你的windos系统中,需要通过代理上网的程序的代理为socks5模式,地址为:127.0.0.1,端口为:8080,程序即可通过加密通道通过vps上网。
|
||||
|
||||
#### **5.4.SOCKS三级代理(加密)**
|
||||

|
||||
一级SOCKS代理VPS_01,IP:22.22.22.22
|
||||
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||
二级SOCKS代理VPS_02,IP:33.33.33.33
|
||||
@ -622,6 +697,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
||||
`./proxy socks --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
|
||||
#### **5.6.SOCKS通过SSH中转**
|
||||

|
||||
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
|
||||
假设有:vps
|
||||
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
|
||||
@ -658,13 +734,13 @@ ip:用户的IP,比如:192.168.1.200
|
||||
如果没有-a或-F或--auth-url参数,就是关闭认证.
|
||||
|
||||
#### **5.8.KCP协议传输**
|
||||
KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
|
||||
|
||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||
`./proxy socks -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy socks -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
二级HTTP代理(本地Linux)
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
|
||||
|
||||
#### **5.9.自定义DNS**
|
||||
@ -673,13 +749,64 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
比如:
|
||||
`./proxy socks -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300`
|
||||
|
||||
#### **5.10.查看帮助**
|
||||
#### **5.10 自定义加密**
|
||||
proxy的socks代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可,
|
||||
加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
|
||||
|
||||
自定义加密要求两端都是proxy才可以.
|
||||
|
||||
下面分别用二级,三级为例:
|
||||
|
||||
**二级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy socks -t tcp -z demo_password -p :7777`
|
||||
本地二级执行:
|
||||
`proxy socks -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||
|
||||
|
||||
**三级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy socks -t tcp -z demo_password -p :7777`
|
||||
二级vps(ip:3.3.3.3)上执行:
|
||||
`proxy socks -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
|
||||
本地三级执行:
|
||||
`proxy socks -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||
|
||||
#### **5.11 压缩传输**
|
||||
proxy的socks代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以
|
||||
对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,
|
||||
一部分是本地(-m)是否压缩传输,一部分是与上级(-M)传输是否压缩.
|
||||
|
||||
压缩要求两端都是proxy才可以,压缩也在一定程度上保护了(加密)数据.
|
||||
|
||||
下面分别用二级,三级为例:
|
||||
|
||||
**二级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy socks -t tcp -m -p :7777`
|
||||
本地二级执行:
|
||||
`proxy socks -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||
|
||||
|
||||
**三级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy socks -t tcp -m -p :7777`
|
||||
二级vps(ip:3.3.3.3)上执行:
|
||||
`proxy socks -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
|
||||
本地三级执行:
|
||||
`proxy socks -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||
|
||||
#### **5.12.查看帮助**
|
||||
`./proxy help socks`
|
||||
|
||||
### **6.代理协议转换**
|
||||
|
||||
#### **6.1 功能介绍**
|
||||
代理协议转换使用的是sps子命令(socks+https的缩写),sps本身不提供代理功能,只是接受代理请求"转换并转发"给已经存在的http(s)代理或者socks5代理;sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口同时支持http(s)和socks5代理,而且http(s)代理支持正向代理和反向代理(SNI),转换后的SOCKS5代理不支持UDP功能;另外对于已经存在的http(s)代理或者socks5代理,支持tls、tcp、kcp三种模式,支持链式连接,也就是可以多个sps结点层级连接构建加密通道;。
|
||||
代理协议转换使用的是sps子命令(socks+https的缩写),sps本身不提供代理功能,只是接受代理请求"转换并转发"给已经存在的http(s)代理或者socks5代理;sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口同时支持http(s)和socks5代理,而且http(s)代理支持正向代理和反向代理(SNI),转换后的SOCKS5代理不支持UDP功能;另外对于已经存在的http(s)代理或者socks5代理,支持tls、tcp、kcp三种模式,支持链式连接,也就是可以多个sps结点层级连接构建加密通道。
|
||||
|
||||
#### **6.2 HTTP(S)转HTTP(S)+SOCKS5**
|
||||
假设已经存在一个普通的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
@ -692,7 +819,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
|
||||
假设已经存在一个kcp的http(s)代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
命令如下:
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.3 SOCKS5转HTTP(S)+SOCKS5**
|
||||
假设已经存在一个普通的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
@ -705,9 +832,10 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
|
||||
假设已经存在一个kcp的socks5代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
命令如下:
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.4 链式连接**
|
||||
#### **6.4 链式连接**
|
||||

|
||||
上面提过多个sps结点可以层级连接构建加密通道,假设有如下vps和家里的pc电脑。
|
||||
vps01:2.2.2.2
|
||||
vps02:3.3.3.3
|
||||
@ -730,22 +858,157 @@ vps02:3.3.3.3
|
||||
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
||||
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
||||
|
||||
#### **6.6 查看帮助**
|
||||
#### **6.6 认证功能**
|
||||
sps支持http(s)\socks5代理认证,可以级联认证,有四个重要的信息:
|
||||
1:用户发送认证信息`user-auth`。
|
||||
2:设置的本地认证信息`local-auth`。
|
||||
3:设置的连接上级使用的认证信息`parent-auth`。
|
||||
4:最终发送给上级的认证信息`auth-info-to-parent`。
|
||||
他们的情况关系如下:
|
||||
|
||||
| user-auth | local-auth | parent-auth | auth-info-to-paren
|
||||
| ------ | ------ | ------ | ------
|
||||
| 有/没有 | 有 | 有 | 来自parent-auth
|
||||
| 有/没有 | 没有 | 有 | 来自parent-auth
|
||||
| 有/没有 | 有 | 没有 | 无
|
||||
| 没有 | 没有 | 没有 | 无
|
||||
| 有 | 没有 | 没有 | 来自user-auth
|
||||
|
||||
对于sps代理我们可以进行用户名密码认证,认证的用户名和密码可以在命令行指定
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||
多个用户,重复-a参数即可.
|
||||
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -F auth-file.txt`
|
||||
|
||||
如果上级有认证,下级可以通过-A参数设置认证信息,比如:
|
||||
上级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||
下级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -A "user1:pass1" -t tcp -p ":33080" `
|
||||
|
||||
另外,sps代理,本地认证集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
|
||||
然后有用户连接的时候,proxy会GET方式请求这url,带上下面四个参数,如果返回HTTP状态码204,代表认证成功
|
||||
其它情况认为认证失败.
|
||||
比如:
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
|
||||
带上user,pass,ip,target四个参数:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
|
||||
user:用户名
|
||||
pass:密码
|
||||
ip:用户的IP,比如:192.168.1.200
|
||||
target:如果客户端是http(s)代理请求,这里代表的是请求的完整url,其它情况为空.
|
||||
|
||||
如果没有-a或-F或--auth-url参数,就是关闭本地认证.
|
||||
如果没有-A参数,连接上级不使用认证.
|
||||
|
||||
|
||||
#### **6.7 自定义加密**
|
||||
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
|
||||
自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义
|
||||
一个密码即可,加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
|
||||
|
||||
自定义加密要求两端都是proxy才可以.
|
||||
|
||||
下面分别用二级,三级为例:
|
||||
|
||||
假设已经存在一个http(s)代理:`6.6.6.6:6666`
|
||||
|
||||
**二级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy sps -S http -T tcp -P 6.6.6.6:6666 -t tcp -z demo_password -p :7777`
|
||||
本地二级执行:
|
||||
`proxy sps -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||
|
||||
|
||||
**三级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy sps -S http -T tcp -P 6.6.6.6:6666 -t tcp -z demo_password -p :7777`
|
||||
二级vps(ip:3.3.3.3)上执行:
|
||||
`proxy sps -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
|
||||
本地三级执行:
|
||||
`proxy sps -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||
|
||||
#### **6.8 压缩传输**
|
||||
proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以
|
||||
对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,
|
||||
一部分是本地(-m)是否压缩传输,一部分是与上级(-M)传输是否压缩.
|
||||
|
||||
压缩要求两端都是proxy才可以,压缩也在一定程度上保护了(加密)数据.
|
||||
|
||||
下面分别用二级,三级为例:
|
||||
|
||||
**二级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy sps -t tcp -m -p :7777`
|
||||
本地二级执行:
|
||||
`proxy sps -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||
|
||||
|
||||
**三级实例**
|
||||
一级vps(ip:2.2.2.2)上执行:
|
||||
`proxy sps -t tcp -m -p :7777`
|
||||
二级vps(ip:3.3.3.3)上执行:
|
||||
`proxy sps -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
|
||||
本地三级执行:
|
||||
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||
|
||||
|
||||
#### **6.9 查看帮助**
|
||||
`./proxy help sps`
|
||||
|
||||
### **7.KCP配置**
|
||||
|
||||
#### **7.1 配置介绍**
|
||||
proxy的很多功能都支持kcp协议,凡是使用了kcp协议的功能都支持这里介绍的配置参数。
|
||||
所以这里统一对KCP配置参数进行介绍。
|
||||
|
||||
#### **7.2 详细配置**
|
||||
所有的KCP配置参数共有17个,你可以都不用设置,他们都有默认值,如果为了或者最好的效果,
|
||||
就需要自己根据自己根据网络情况对参数进行配置。由于kcp配置很复杂需要一定的网络基础知识,
|
||||
如果想获得kcp参数更详细的配置和解说,请自行搜索。每个参数的命令行名称以及默认值和简单的功能说明如下:
|
||||
```
|
||||
--kcp-key="secrect" pre-shared secret between client and server
|
||||
--kcp-method="aes" encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish,
|
||||
twofish, cast5, 3des, tea, xtea, xor, sm4, none
|
||||
--kcp-mode="fast" profiles: fast3, fast2, fast, normal, manual
|
||||
--kcp-mtu=1350 set maximum transmission unit for UDP packets
|
||||
--kcp-sndwnd=1024 set send window size(num of packets)
|
||||
--kcp-rcvwnd=1024 set receive window size(num of packets)
|
||||
--kcp-ds=10 set reed-solomon erasure coding - datashard
|
||||
--kcp-ps=3 set reed-solomon erasure coding - parityshard
|
||||
--kcp-dscp=0 set DSCP(6bit)
|
||||
--kcp-nocomp disable compression
|
||||
--kcp-acknodelay be carefull! flush ack immediately when a packet is received
|
||||
--kcp-nodelay=0 be carefull!
|
||||
--kcp-interval=50 be carefull!
|
||||
--kcp-resend=0 be carefull!
|
||||
--kcp-nc=0 be carefull! no congestion
|
||||
--kcp-sockbuf=4194304 be carefull!
|
||||
--kcp-keepalive=10 be carefull!
|
||||
```
|
||||
提示:
|
||||
参数:--kcp-mode中的四种fast3, fast2, fast, normal模式,
|
||||
相当于设置了下面四个参数:
|
||||
normal:`--nodelay=0 --interval=40 --resend=2 --nc=1`
|
||||
fast :`--nodelay=0 --interval=30 --resend=2 --nc=1`
|
||||
fast2:`--nodelay=1 --interval=20 --resend=2 --nc=1`
|
||||
fast3:`--nodelay=1 --interval=10 --resend=2 --nc=1`
|
||||
|
||||
### TODO
|
||||
- http,socks代理多个上级负载均衡?
|
||||
- http(s)代理增加pac支持?
|
||||
- 欢迎加群反馈...
|
||||
|
||||
### 如何使用源码?
|
||||
建议go1.8.5,不保证>=1.9能用.
|
||||
cd进入你的go src目录,新建文件夹snail007,
|
||||
cd进入snail007,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
|
||||
编译直接:go build
|
||||
运行: go run *.go
|
||||
utils是工具包,service是具体的每个服务类.
|
||||
### 如何使用源码?
|
||||
建议go1.8.5,不保证>=1.9能用.
|
||||
cd进入你的go src目录,新建文件夹snail007,
|
||||
cd进入snail007,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
|
||||
编译直接:go build
|
||||
运行: go run *.go
|
||||
utils是工具包,service是具体的每个服务类.
|
||||
|
||||
### License
|
||||
Proxy is licensed under GPLv3 license.
|
||||
|
||||
125
config.go
@ -2,14 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"snail007/proxy/services"
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
"snail007/proxy/utils"
|
||||
"time"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
@ -40,6 +44,7 @@ func initConfig() (err error) {
|
||||
udpArgs := services.UDPArgs{}
|
||||
socksArgs := services.SocksArgs{}
|
||||
spsArgs := services.SPSArgs{}
|
||||
kcpArgs := kcpcfg.KCPConfigArgs{}
|
||||
//build srvice args
|
||||
app = kingpin.New("proxy", "happy with proxy")
|
||||
app.Author("snail").Version(APP_VERSION)
|
||||
@ -47,10 +52,28 @@ func initConfig() (err error) {
|
||||
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
|
||||
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
|
||||
logfile := app.Flag("log", "log file path").Default("").String()
|
||||
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
|
||||
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
|
||||
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").Enum("fast3", "fast2", "fast", "normal", "manual")
|
||||
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
|
||||
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
|
||||
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
|
||||
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
|
||||
kcpArgs.ParityShard = app.Flag("kcp-ps", "set reed-solomon erasure coding - parityshard").Default("3").Int()
|
||||
kcpArgs.DSCP = app.Flag("kcp-dscp", "set DSCP(6bit)").Default("0").Int()
|
||||
kcpArgs.NoComp = app.Flag("kcp-nocomp", "disable compression").Default("false").Bool()
|
||||
kcpArgs.AckNodelay = app.Flag("kcp-acknodelay", "be carefull! flush ack immediately when a packet is received").Default("true").Bool()
|
||||
kcpArgs.NoDelay = app.Flag("kcp-nodelay", "be carefull!").Default("0").Int()
|
||||
kcpArgs.Interval = app.Flag("kcp-interval", "be carefull!").Default("50").Int()
|
||||
kcpArgs.Resend = app.Flag("kcp-resend", "be carefull!").Default("0").Int()
|
||||
kcpArgs.NoCongestion = app.Flag("kcp-nc", "be carefull! no congestion").Default("0").Int()
|
||||
kcpArgs.SockBuf = app.Flag("kcp-sockbuf", "be carefull!").Default("4194304").Int()
|
||||
kcpArgs.KeepAlive = app.Flag("kcp-keepalive", "be carefull!").Default("10").Int()
|
||||
|
||||
//########http#########
|
||||
http := app.Command("http", "proxy on http mode")
|
||||
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
httpArgs.CaCertFile = http.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
httpArgs.CertFile = http.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
httpArgs.KeyFile = http.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
httpArgs.LocalType = http.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
@ -63,15 +86,12 @@ func initConfig() (err error) {
|
||||
httpArgs.Direct = http.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
||||
httpArgs.AuthFile = http.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||
httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||
httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
||||
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||
httpArgs.Local = http.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
||||
httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||
httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||
httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
|
||||
httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
|
||||
httpArgs.KCPKey = http.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
|
||||
httpArgs.KCPMethod = http.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||
httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||
httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||
httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||
@ -79,6 +99,10 @@ func initConfig() (err error) {
|
||||
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
|
||||
httpArgs.DNSAddress = http.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
httpArgs.DNSTTL = http.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
httpArgs.LocalKey = http.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########tcp#########
|
||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
@ -88,11 +112,8 @@ func initConfig() (err error) {
|
||||
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
||||
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
|
||||
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
||||
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
tcpArgs.KCPKey = tcp.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
|
||||
tcpArgs.KCPMethod = tcp.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||
|
||||
//########udp#########
|
||||
udp := app.Command("udp", "proxy on udp mode")
|
||||
@ -101,36 +122,40 @@ func initConfig() (err error) {
|
||||
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
|
||||
udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
|
||||
udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
||||
udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||
udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
|
||||
//########mux-server#########
|
||||
muxServer := app.Command("server", "proxy on mux server mode")
|
||||
muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
|
||||
muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxServerArgs.IsUDP = muxServer.Flag("udp", "proxy on udp mux server mode").Default("false").Bool()
|
||||
muxServerArgs.Key = muxServer.Flag("k", "client key").Default("default").String()
|
||||
muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
||||
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp mode").Default("false").Bool()
|
||||
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
|
||||
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
|
||||
|
||||
//########mux-client#########
|
||||
muxClient := app.Command("client", "proxy on mux client mode")
|
||||
muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
|
||||
muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String()
|
||||
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp mode").Default("false").Bool()
|
||||
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
|
||||
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
|
||||
|
||||
//########mux-bridge#########
|
||||
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
|
||||
muxBridgeArgs.CertFile = muxBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tls").Short('t').Enum("tls", "tcp", "kcp")
|
||||
|
||||
//########tunnel-server#########
|
||||
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
|
||||
@ -166,6 +191,7 @@ func initConfig() (err error) {
|
||||
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
|
||||
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
|
||||
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
socksArgs.SSHUser = socks.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||
socksArgs.SSHKeyFile = socks.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||
@ -178,8 +204,6 @@ func initConfig() (err error) {
|
||||
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
||||
socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||
socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||
socksArgs.KCPKey = socks.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
|
||||
socksArgs.KCPMethod = socks.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||
socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||
socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||
@ -187,23 +211,92 @@ func initConfig() (err error) {
|
||||
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########socks+http(s)#########
|
||||
sps := app.Command("sps", "proxy on socks+http(s) mode")
|
||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
spsArgs.CaCertFile = sps.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
spsArgs.Timeout = sps.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int()
|
||||
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
||||
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
||||
spsArgs.KCPKey = sps.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
|
||||
spsArgs.KCPMethod = sps.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||
spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||
spsArgs.LocalIPS = sps.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||
spsArgs.AuthURL = sps.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||
spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||
spsArgs.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||
spsArgs.LocalKey = sps.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//parse args
|
||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
|
||||
//set kcp config
|
||||
|
||||
switch *kcpArgs.Mode {
|
||||
case "normal":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 40, 2, 1
|
||||
case "fast":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 30, 2, 1
|
||||
case "fast2":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 20, 2, 1
|
||||
case "fast3":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 10, 2, 1
|
||||
}
|
||||
pass := pbkdf2.Key([]byte(*kcpArgs.Key), []byte("snail007-goproxy"), 4096, 32, sha1.New)
|
||||
|
||||
switch *kcpArgs.Crypt {
|
||||
case "sm4":
|
||||
kcpArgs.Block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
kcpArgs.Block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||
case "xor":
|
||||
kcpArgs.Block, _ = kcp.NewSimpleXORBlockCrypt(pass)
|
||||
case "none":
|
||||
kcpArgs.Block, _ = kcp.NewNoneBlockCrypt(pass)
|
||||
case "aes-128":
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:16])
|
||||
case "aes-192":
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:24])
|
||||
case "blowfish":
|
||||
kcpArgs.Block, _ = kcp.NewBlowfishBlockCrypt(pass)
|
||||
case "twofish":
|
||||
kcpArgs.Block, _ = kcp.NewTwofishBlockCrypt(pass)
|
||||
case "cast5":
|
||||
kcpArgs.Block, _ = kcp.NewCast5BlockCrypt(pass[:16])
|
||||
case "3des":
|
||||
kcpArgs.Block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
|
||||
case "xtea":
|
||||
kcpArgs.Block, _ = kcp.NewXTEABlockCrypt(pass[:16])
|
||||
case "salsa20":
|
||||
kcpArgs.Block, _ = kcp.NewSalsa20BlockCrypt(pass)
|
||||
default:
|
||||
*kcpArgs.Crypt = "aes"
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass)
|
||||
}
|
||||
//attach kcp config
|
||||
tcpArgs.KCP = kcpArgs
|
||||
httpArgs.KCP = kcpArgs
|
||||
socksArgs.KCP = kcpArgs
|
||||
spsArgs.KCP = kcpArgs
|
||||
muxBridgeArgs.KCP = kcpArgs
|
||||
muxServerArgs.KCP = kcpArgs
|
||||
muxClientArgs.KCP = kcpArgs
|
||||
|
||||
flags := log.Ldate
|
||||
if *debug {
|
||||
flags |= log.Lshortfile | log.Lmicroseconds
|
||||
|
||||
BIN
docs/images/fxdl.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/images/http-1.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/images/http-2.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/images/http-kcp.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/images/http-ssh-1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/images/http-tls-2.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/images/http-tls-3.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/images/socks-2.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/images/socks-ssh.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/images/socks-tls-2.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/images/socks-tls-3.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/images/sps-tls.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/images/tcp-1.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/images/tcp-2.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/images/tcp-3.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/images/tcp-tls-2.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/images/tcp-tls-3.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/images/udp-1.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/images/udp-2.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
docs/images/udp-3.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/images/udp-tls-2.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/images/udp-tls-3.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
|
||||
fi
|
||||
mkdir /tmp/proxy
|
||||
cd /tmp/proxy
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.4/proxy-linux-amd64.tar.gz
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.7/proxy-linux-amd64.tar.gz
|
||||
|
||||
# #install proxy
|
||||
tar zxvf proxy-linux-amd64.tar.gz
|
||||
|
||||
2
main.go
@ -8,7 +8,7 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const APP_VERSION = "4.4"
|
||||
const APP_VERSION = "4.7"
|
||||
|
||||
func main() {
|
||||
err := initConfig()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER="4.4"
|
||||
VER="4.7"
|
||||
RELEASE="release-${VER}"
|
||||
rm -rf .cert
|
||||
mkdir .cert
|
||||
|
||||
259
sdk/README.md
Normal file
@ -0,0 +1,259 @@
|
||||
|
||||
# Proxy SDK 使用说明
|
||||
|
||||
支持以下平台:
|
||||
- Android,`.arr`库
|
||||
- IOS,`.framework`库
|
||||
- Windows,`.dll`库
|
||||
- Linux,`.so`库
|
||||
- MacOS,`.dylib`库
|
||||
|
||||
proxy使用gombile实现了一份go代码编译为android和ios平台下面可以直接调用的sdk类库,
|
||||
另外还为linux和windows提供sdk支持,基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具。
|
||||
|
||||
# 下面分平台介绍SDK的用法
|
||||
|
||||
## Android SDK
|
||||
|
||||
[](https://github.com/snail007/goproxy-sdk-android/) []() [](https://github.com/snail007/goproxy-sdk-android/releases) [](https://github.com/snail007/goproxy-sdk-android/releases)
|
||||
|
||||
[点击下载Android-SDK](https://github.com/snail007/goproxy-sdk-android/releases)
|
||||
在Android系统提供的sdk形式是一个后缀为.aar的类库文件,开发的时候只需要把arr类库文件引入android项目即可.
|
||||
|
||||
### Android-SDK使用实例
|
||||
|
||||
#### 1.导入包
|
||||
|
||||
```java
|
||||
import snail007.proxy.Porxy
|
||||
```
|
||||
|
||||
#### 2.启动一个服务
|
||||
|
||||
```java
|
||||
String serviceID="http01";//这里serviceID是自定义的唯一标识字符串,保证每个启动的服务不一样即可
|
||||
String serviceArgs="http -p :8080";
|
||||
String err=Proxy.start(serviceID,serviceArgs);
|
||||
if (!err.isEmpty()){
|
||||
//启动失败
|
||||
System.out.println("start fail,error:"+err);
|
||||
}else{
|
||||
//启动成功
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.停止一个服务
|
||||
|
||||
```java
|
||||
String serviceID="http01";
|
||||
Proxy.stop(serviceID);
|
||||
//停止完毕
|
||||
|
||||
```
|
||||
|
||||
## IOS SDK
|
||||
|
||||
[](https://github.com/snail007/goproxy-sdk-ios/) []() [](https://github.com/snail007/goproxy-sdk-ios/releases) [](https://github.com/snail007/goproxy-sdk-ios/releases)
|
||||
|
||||
[点击下载IOS-SDK](https://github.com/snail007/goproxy-sdk-ios/releases)
|
||||
在IOS系统提供的sdk形式是一个后缀为.framework的类库文件夹,开发的时候只需要把类库文件引入项目,然后调用方法即可.
|
||||
|
||||
### IOS-SDK使用实例
|
||||
|
||||
#### 导入包
|
||||
|
||||
```objc
|
||||
#import <Proxy/Proxy.objc.h>
|
||||
```
|
||||
|
||||
#### 2.启动一个服务
|
||||
|
||||
```objc
|
||||
-(IBAction)doStart:(id)sender
|
||||
{
|
||||
//这里serviceID是自定义的唯一标识字符串,保证每个启动的服务不一样
|
||||
NSString *serviceID = @"http01";
|
||||
NSString *serviceArgs = @"http -p :8080";
|
||||
NSString *error = ProxyStart(serviceID,serviceArgs);
|
||||
|
||||
if (error != nil && error.length > 0)
|
||||
{
|
||||
NSLog(@"start error %@",error);
|
||||
}else{
|
||||
NSLog(@"启动成功");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.停止一个服务
|
||||
|
||||
```objc
|
||||
-(IBAction)doStop:(id)sender
|
||||
{
|
||||
NSString *serviceID = @"http01";
|
||||
ProxyStop(serviceID);
|
||||
//停止完毕
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Windows SDK
|
||||
[](https://github.com/snail007/goproxy-sdk-windows/) []() [](https://github.com/snail007/goproxy-sdk-windows/releases) [](https://github.com/snail007/goproxy-sdk-windows/releases)
|
||||
|
||||
[点击下载Windows-SDK](https://github.com/snail007/goproxy-sdk-windows/releases)
|
||||
在Windows系统提供的sdk形式是一个后缀为.dll的类库文件,开发的时候只需要把dll类库文件加载,然后调用方法即可.
|
||||
|
||||
### Windows-SDK使用实例
|
||||
C++示例,不需要包含头文件,只需要加载proxy-sdk.dll即可,ieshims.dll需要和proxy-sdk.dll在一起。
|
||||
作者:[yjbdsky](https://github.com/yjbdsky)
|
||||
|
||||
```cpp
|
||||
#include <stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include <string.h>
|
||||
#include<pthread.h>
|
||||
#include<Windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef char *(*GOSTART)(char *s);
|
||||
typedef char *(*GOSTOP)(char *s);
|
||||
typedef int(*GOISRUN)(char *s);
|
||||
HMODULE GODLL = LoadLibrary("proxy-sdk.dll");
|
||||
|
||||
char * Start(char * p0,char * p1)
|
||||
{
|
||||
if (GODLL != NULL)
|
||||
{
|
||||
GOSTART gostart = *(GOSTART)(GetProcAddress(GODLL, "Start"));
|
||||
if (gostart != NULL){
|
||||
printf("%s:%s\n",p0, p1);
|
||||
char *ret = gostart(p0,p1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return "Cannot Find dll";
|
||||
}
|
||||
char * Stop(char * p)
|
||||
{
|
||||
if (GODLL != NULL)
|
||||
{
|
||||
GOSTOP gostop = *(GOSTOP)(GetProcAddress(GODLL, "Stop"));
|
||||
if (gostop != NULL){
|
||||
printf("%s\n", p);
|
||||
char *ret = gostop(p);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return "Cannot Find dll";
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
//这里p0是自定义的唯一标识字符串,保证每个启动的服务不一样
|
||||
char *p0 = "http01";
|
||||
char *p1 = "http -t tcp -p :38080";
|
||||
printf("This is demo application.\n");
|
||||
//启动服务,返回空字符串说明启动成功;返回非空字符串说明启动失败,返回的字符串是错误原因
|
||||
printf("start result %s\n", Start(p0,p1));
|
||||
//停止服务,没有返回值
|
||||
Stop(p0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
C++示例2,请移步:[GoProxyForC](https://github.com/SuperPowerLF2/GoProxyForC)
|
||||
|
||||
## Linux SDK
|
||||
[](https://github.com/snail007/goproxy-sdk-linux/) []() [](https://github.com/snail007/goproxy-sdk-linux/releases) [](https://github.com/snail007/goproxy-sdk-linux/releases)
|
||||
|
||||
[点击下载Linux-SDK](https://github.com/snail007/goproxy-sdk-linux/releases)
|
||||
在Linux系统提供的sdk形式是一个后缀为.so的类库文件,开发的时候只需要把so类库加载,调用方法即可.
|
||||
|
||||
### Linux-SDK使用实例
|
||||
Linux下面使用的sdk是so文件即libproxy-sdk.so,下面写一个简单的C程序示例,调用so库里面的方法.
|
||||
|
||||
`vi test-proxy.c`
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "libproxy-sdk.h"
|
||||
|
||||
int main() {
|
||||
printf("This is demo application.\n");
|
||||
//这里p0是自定义的唯一标识字符串,保证每个启动的服务不一样
|
||||
char *p0 = "http01";
|
||||
char *p1 = "http -t tcp -p :38080";
|
||||
//启动服务,返回空字符串说明启动成功;返回非空字符串说明启动失败,返回的字符串是错误原因
|
||||
printf("start result %s\n",Start(p0,p1));
|
||||
//停止服务,没有返回值
|
||||
Stop(p0);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
#### 编译test-proxy.c ####
|
||||
`export LD_LIBRARY_PATH=./ && gcc -o test-proxy test.c libproxy-sdk.so`
|
||||
|
||||
#### 执行 ####
|
||||
`./test-proxy`
|
||||
|
||||
## MacOS SDK
|
||||
[](https://github.com/snail007/goproxy-sdk-mac/) []() [](https://github.com/snail007/goproxy-sdk-mac/releases) [](https://github.com/snail007/goproxy-sdk-mac/releases)
|
||||
|
||||
[点击下载MacOS-SDK](https://github.com/snail007/goproxy-sdk-mac/releases)
|
||||
在MacOS系统提供的sdk形式是一个后缀为.dylib的类库文件,开发的时候只需要把so类库加载,调用方法即可.
|
||||
|
||||
### MacOS-SDK使用实例
|
||||
MacOS下面使用的sdk是dylib文件即libproxy-sdk.dylib,下面写一个简单的Obj-C程序示例,调用dylib库里面的方法.
|
||||
|
||||
```objc
|
||||
#import "libproxy-sdk.h"
|
||||
-(IBAction)doStart:(id)sender
|
||||
{
|
||||
char *result = Start("http01", "http -t tcp -p :38080");
|
||||
|
||||
if (result)
|
||||
{
|
||||
printf("started");
|
||||
}else{
|
||||
printf("not started");
|
||||
}
|
||||
|
||||
}
|
||||
-(IBAction)doStop:(id)sender
|
||||
{
|
||||
Stop("http01");
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### 关于服务
|
||||
proxy的服务有11种,分别是:
|
||||
|
||||
```shell
|
||||
http
|
||||
socks
|
||||
sps
|
||||
tcp
|
||||
udp
|
||||
bridge
|
||||
server
|
||||
client
|
||||
tbridge
|
||||
tserver
|
||||
tclient
|
||||
```
|
||||
服务启动时,如果存在正在运行的相同ID的服务,那么之前的服务会被停掉,后面启动的服务覆盖之前的服务.
|
||||
所以要保证每次启动服务的时候,第一个ID参数唯一.
|
||||
上面这些服务的具体使用方式和具体参数,可以参考[proxy手册](https://github.com/snail007/goproxy/blob/master/README_ZH.md)
|
||||
sdk里面的服务不支持手册里面的:--daemon和--forever参数.
|
||||
|
||||
|
||||
7
sdk/android-ios/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
*.jar
|
||||
*.aar
|
||||
*.tar.gz
|
||||
ios
|
||||
android
|
||||
Proxy.framework
|
||||
|
||||
15
sdk/android-ios/release_android.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
rm -rf sdk-android-*.tar.gz
|
||||
rm -rf android
|
||||
mkdir android
|
||||
|
||||
#android
|
||||
gomobile bind -v -target=android -javapkg=snail007 -ldflags="-s -w"
|
||||
mv proxy.aar android/snail007.goproxy.sdk.aar
|
||||
mv proxy-sources.jar android/snail007.goproxy.sdk-sources.jar
|
||||
cp ../README.md android
|
||||
tar zcfv sdk-android-${VER}.tar.gz android
|
||||
rm -rf android
|
||||
|
||||
echo "done."
|
||||
14
sdk/android-ios/release_ios.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
rm -rf sdk-ios-*.tar.gz
|
||||
rm -rf ios
|
||||
mkdir ios
|
||||
|
||||
#ios XCode required
|
||||
gomobile bind -v -target=ios -ldflags="-s -w"
|
||||
mv Proxy.framework ios
|
||||
cp ../README.md ios
|
||||
tar zcfv sdk-ios-${VER}.tar.gz ios
|
||||
rm -rf ios
|
||||
|
||||
echo "done."
|
||||
351
sdk/android-ios/sdk.go
Normal file
@ -0,0 +1,351 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"snail007/proxy/services"
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
"strings"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
app *kingpin.Application
|
||||
)
|
||||
|
||||
//Start
|
||||
//serviceID : is service identify id,different service's id should be difference
|
||||
//serviceArgsStr: is the whole command line args string
|
||||
//such as :
|
||||
//1."http -t tcp -p :8989"
|
||||
//2."socks -t tcp -p :8989"
|
||||
//and so on.
|
||||
//if an error occured , errStr will be the error reason
|
||||
//if start success, errStr is empty.
|
||||
func Start(serviceID, serviceArgsStr string) (errStr string) {
|
||||
//define args
|
||||
tcpArgs := services.TCPArgs{}
|
||||
httpArgs := services.HTTPArgs{}
|
||||
tunnelServerArgs := services.TunnelServerArgs{}
|
||||
tunnelClientArgs := services.TunnelClientArgs{}
|
||||
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
||||
muxServerArgs := services.MuxServerArgs{}
|
||||
muxClientArgs := services.MuxClientArgs{}
|
||||
muxBridgeArgs := services.MuxBridgeArgs{}
|
||||
udpArgs := services.UDPArgs{}
|
||||
socksArgs := services.SocksArgs{}
|
||||
spsArgs := services.SPSArgs{}
|
||||
kcpArgs := kcpcfg.KCPConfigArgs{}
|
||||
//build srvice args
|
||||
app = kingpin.New("proxy", "happy with proxy")
|
||||
app.Author("snail").Version("4.7")
|
||||
debug := app.Flag("debug", "debug log output").Default("false").Bool()
|
||||
logfile := app.Flag("log", "log file path").Default("").String()
|
||||
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
|
||||
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
|
||||
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual")
|
||||
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
|
||||
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
|
||||
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
|
||||
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
|
||||
kcpArgs.ParityShard = app.Flag("kcp-ps", "set reed-solomon erasure coding - parityshard").Default("3").Int()
|
||||
kcpArgs.DSCP = app.Flag("kcp-dscp", "set DSCP(6bit)").Default("0").Int()
|
||||
kcpArgs.NoComp = app.Flag("kcp-nocomp", "disable compression").Default("false").Bool()
|
||||
kcpArgs.AckNodelay = app.Flag("kcp-acknodelay", "be carefull! flush ack immediately when a packet is received").Default("true").Bool()
|
||||
kcpArgs.NoDelay = app.Flag("kcp-nodelay", "be carefull!").Default("0").Int()
|
||||
kcpArgs.Interval = app.Flag("kcp-interval", "be carefull!").Default("50").Int()
|
||||
kcpArgs.Resend = app.Flag("kcp-resend", "be carefull!").Default("0").Int()
|
||||
kcpArgs.NoCongestion = app.Flag("kcp-nc", "be carefull! no congestion").Default("0").Int()
|
||||
kcpArgs.SockBuf = app.Flag("kcp-sockbuf", "be carefull!").Default("4194304").Int()
|
||||
kcpArgs.KeepAlive = app.Flag("kcp-keepalive", "be carefull!").Default("10").Int()
|
||||
|
||||
//########http#########
|
||||
http := app.Command("http", "proxy on http mode")
|
||||
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
httpArgs.CaCertFile = http.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
httpArgs.CertFile = http.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
httpArgs.KeyFile = http.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
httpArgs.LocalType = http.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp|ssh|kcp>").Short('T').Enum("tls", "tcp", "ssh", "kcp")
|
||||
httpArgs.Always = http.Flag("always", "always use parent proxy").Default("false").Bool()
|
||||
httpArgs.Timeout = http.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
|
||||
httpArgs.HTTPTimeout = http.Flag("http-timeout", "check domain if blocked , http request timeout milliseconds when connect to host").Default("3000").Int()
|
||||
httpArgs.Interval = http.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
|
||||
httpArgs.Blocked = http.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
|
||||
httpArgs.Direct = http.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
||||
httpArgs.AuthFile = http.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||
httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||
httpArgs.Local = http.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
||||
httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||
httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||
httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
|
||||
httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
|
||||
httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||
httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||
httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||
httpArgs.AuthURLOkCode = http.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
|
||||
httpArgs.DNSAddress = http.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
httpArgs.DNSTTL = http.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
httpArgs.LocalKey = http.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########tcp#########
|
||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
||||
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
|
||||
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
|
||||
//########udp#########
|
||||
udp := app.Command("udp", "proxy on udp mode")
|
||||
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
udpArgs.CertFile = udp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
|
||||
udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
|
||||
udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||
udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
|
||||
//########mux-server#########
|
||||
muxServer := app.Command("server", "proxy on mux server mode")
|
||||
muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
|
||||
muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxServerArgs.IsUDP = muxServer.Flag("udp", "proxy on udp mux server mode").Default("false").Bool()
|
||||
muxServerArgs.Key = muxServer.Flag("k", "client key").Default("default").String()
|
||||
muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
||||
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
|
||||
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
|
||||
|
||||
//########mux-client#########
|
||||
muxClient := app.Command("client", "proxy on mux client mode")
|
||||
muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
|
||||
muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String()
|
||||
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
|
||||
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
|
||||
|
||||
//########mux-bridge#########
|
||||
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
|
||||
muxBridgeArgs.CertFile = muxBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tls").Short('t').Enum("tls", "tcp", "kcp")
|
||||
|
||||
//########tunnel-server#########
|
||||
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
|
||||
tunnelServerArgs.Parent = tunnelServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
tunnelServerArgs.CertFile = tunnelServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
tunnelServerArgs.KeyFile = tunnelServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
tunnelServerArgs.Timeout = tunnelServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
|
||||
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
|
||||
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
||||
|
||||
//########tunnel-client#########
|
||||
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
|
||||
tunnelClientArgs.Parent = tunnelClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
tunnelClientArgs.CertFile = tunnelClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
|
||||
|
||||
//########tunnel-bridge#########
|
||||
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
|
||||
tunnelBridgeArgs.CertFile = tunnelBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
tunnelBridgeArgs.KeyFile = tunnelBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
|
||||
//########ssh#########
|
||||
socks := app.Command("socks", "proxy on ssh mode")
|
||||
socksArgs.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').String()
|
||||
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
||||
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
|
||||
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
|
||||
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
socksArgs.SSHUser = socks.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||
socksArgs.SSHKeyFile = socks.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||
socksArgs.SSHKeyFileSalt = socks.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
|
||||
socksArgs.SSHPassword = socks.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
|
||||
socksArgs.Always = socks.Flag("always", "always use parent proxy").Default("false").Bool()
|
||||
socksArgs.Timeout = socks.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("5000").Int()
|
||||
socksArgs.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
|
||||
socksArgs.Blocked = socks.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
|
||||
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
||||
socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||
socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||
socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||
socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||
socksArgs.AuthURLOkCode = socks.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########socks+http(s)#########
|
||||
sps := app.Command("sps", "proxy on socks+http(s) mode")
|
||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
spsArgs.CaCertFile = sps.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
spsArgs.Timeout = sps.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int()
|
||||
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
||||
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||
spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||
spsArgs.LocalIPS = sps.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||
spsArgs.AuthURL = sps.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||
spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||
spsArgs.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||
spsArgs.LocalKey = sps.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//parse args
|
||||
_args := strings.Fields(strings.Trim(serviceArgsStr, " "))
|
||||
args := []string{}
|
||||
for _, a := range _args {
|
||||
args = append(args, strings.Trim(a, "\""))
|
||||
}
|
||||
serviceName, err := app.Parse(args)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("parse args fail,err: %s", err)
|
||||
}
|
||||
//set kcp config
|
||||
|
||||
switch *kcpArgs.Mode {
|
||||
case "normal":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 40, 2, 1
|
||||
case "fast":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 30, 2, 1
|
||||
case "fast2":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 20, 2, 1
|
||||
case "fast3":
|
||||
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 10, 2, 1
|
||||
}
|
||||
pass := pbkdf2.Key([]byte(*kcpArgs.Key), []byte("snail007-goproxy"), 4096, 32, sha1.New)
|
||||
|
||||
switch *kcpArgs.Crypt {
|
||||
case "sm4":
|
||||
kcpArgs.Block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
kcpArgs.Block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||
case "xor":
|
||||
kcpArgs.Block, _ = kcp.NewSimpleXORBlockCrypt(pass)
|
||||
case "none":
|
||||
kcpArgs.Block, _ = kcp.NewNoneBlockCrypt(pass)
|
||||
case "aes-128":
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:16])
|
||||
case "aes-192":
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:24])
|
||||
case "blowfish":
|
||||
kcpArgs.Block, _ = kcp.NewBlowfishBlockCrypt(pass)
|
||||
case "twofish":
|
||||
kcpArgs.Block, _ = kcp.NewTwofishBlockCrypt(pass)
|
||||
case "cast5":
|
||||
kcpArgs.Block, _ = kcp.NewCast5BlockCrypt(pass[:16])
|
||||
case "3des":
|
||||
kcpArgs.Block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
|
||||
case "xtea":
|
||||
kcpArgs.Block, _ = kcp.NewXTEABlockCrypt(pass[:16])
|
||||
case "salsa20":
|
||||
kcpArgs.Block, _ = kcp.NewSalsa20BlockCrypt(pass)
|
||||
default:
|
||||
*kcpArgs.Crypt = "aes"
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass)
|
||||
}
|
||||
//attach kcp config
|
||||
tcpArgs.KCP = kcpArgs
|
||||
httpArgs.KCP = kcpArgs
|
||||
socksArgs.KCP = kcpArgs
|
||||
spsArgs.KCP = kcpArgs
|
||||
muxBridgeArgs.KCP = kcpArgs
|
||||
muxServerArgs.KCP = kcpArgs
|
||||
muxClientArgs.KCP = kcpArgs
|
||||
|
||||
flags := log.Ldate
|
||||
if *debug {
|
||||
flags |= log.Lshortfile | log.Lmicroseconds
|
||||
} else {
|
||||
flags |= log.Ltime
|
||||
}
|
||||
log.SetFlags(flags)
|
||||
|
||||
if *logfile != "" {
|
||||
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||
if e != nil {
|
||||
log.Fatal(e)
|
||||
}
|
||||
log.SetOutput(f)
|
||||
}
|
||||
|
||||
//regist services and run service
|
||||
switch serviceName {
|
||||
case "http":
|
||||
services.Regist(serviceID, services.NewHTTP(), httpArgs)
|
||||
case "tcp":
|
||||
services.Regist(serviceID, services.NewTCP(), tcpArgs)
|
||||
case "udp":
|
||||
services.Regist(serviceID, services.NewUDP(), udpArgs)
|
||||
case "tserver":
|
||||
services.Regist(serviceID, services.NewTunnelServerManager(), tunnelServerArgs)
|
||||
case "tclient":
|
||||
services.Regist(serviceID, services.NewTunnelClient(), tunnelClientArgs)
|
||||
case "tbridge":
|
||||
services.Regist(serviceID, services.NewTunnelBridge(), tunnelBridgeArgs)
|
||||
case "server":
|
||||
services.Regist(serviceID, services.NewMuxServerManager(), muxServerArgs)
|
||||
case "client":
|
||||
services.Regist(serviceID, services.NewMuxClient(), muxClientArgs)
|
||||
case "bridge":
|
||||
services.Regist(serviceID, services.NewMuxBridge(), muxBridgeArgs)
|
||||
case "socks":
|
||||
services.Regist(serviceID, services.NewSocks(), socksArgs)
|
||||
case "sps":
|
||||
services.Regist(serviceID, services.NewSPS(), spsArgs)
|
||||
}
|
||||
_, err = services.Run(serviceID)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("run service [%s:%s] fail, ERR:%s", serviceID, serviceName, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Stop(serviceID string) {
|
||||
services.Stop(serviceID)
|
||||
}
|
||||
6
sdk/windows-linux/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
proxy-sdk.dll
|
||||
proxy-sdk.h
|
||||
proxy-sdk.so
|
||||
proxy-sdk.a
|
||||
*.tar.gz
|
||||
test.c
|
||||
BIN
sdk/windows-linux/ieshims.dll
Normal file
24
sdk/windows-linux/release_linux.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
|
||||
rm -rf sdk-linux-*.tar.gz
|
||||
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
|
||||
|
||||
#linux 32bit
|
||||
CGO_ENABLED=1 GOARCH=386 GOOS=linux go build -buildmode=c-archive -ldflags "-s -w" -o libproxy-sdk.a sdk.go
|
||||
CGO_ENABLED=1 GOARCH=386 GOOS=linux go build -buildmode=c-shared -ldflags "-s -w" -o libproxy-sdk.so sdk.go
|
||||
cp ../README.md .
|
||||
tar zcf sdk-linux-32bit-${VER}.tar.gz README.md libproxy-sdk.so libproxy-sdk.a libproxy-sdk.h
|
||||
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
|
||||
|
||||
#linux 64bit
|
||||
CGO_ENABLED=1 GOARCH=amd64 GOOS=linux go build -buildmode=c-archive -ldflags "-s -w" -o libproxy-sdk.a sdk.go
|
||||
CGO_ENABLED=1 GOARCH=amd64 GOOS=linux go build -buildmode=c-shared -ldflags "-s -w" -o libproxy-sdk.so sdk.go
|
||||
cp ../README.md .
|
||||
tar zcf sdk-linux-64bit-${VER}.tar.gz README.md libproxy-sdk.so libproxy-sdk.a libproxy-sdk.h
|
||||
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
|
||||
|
||||
echo "done."
|
||||
|
||||
|
||||
|
||||
13
sdk/windows-linux/release_mac.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
|
||||
rm -rf *.tar.gz
|
||||
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
|
||||
|
||||
#mac , macos required
|
||||
CGO_ENABLED=1 GOARCH=amd64 GOOS=darwin go build -buildmode=c-shared -ldflags "-s -w" -o libproxy-sdk.dylib sdk.go
|
||||
cp ../README.md .
|
||||
tar zcf sdk-mac-${VER}.tar.gz README.md libproxy-sdk.dylib libproxy-sdk.h
|
||||
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
|
||||
|
||||
echo "done."
|
||||
28
sdk/windows-linux/release_windows.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
|
||||
sudo rm /usr/local/go
|
||||
sudo ln -s /usr/local/go1.10.1 /usr/local/go
|
||||
rm -rf sdk-windows-*.tar.gz
|
||||
rm -rf README.md proxy-sdk.h proxy-sdk.dll
|
||||
|
||||
#windows 64bit
|
||||
#apt-get install gcc-multilib
|
||||
#apt-get install gcc-mingw-w64
|
||||
|
||||
#windows 64bit
|
||||
CC=x86_64-w64-mingw32-gcc GOARCH=amd64 CGO_ENABLED=1 GOOS=windows go build -buildmode=c-shared -ldflags "-s -w" -o proxy-sdk.dll sdk.go
|
||||
cp ../README.md .
|
||||
tar zcf sdk-windows-64bit-${VER}.tar.gz README.md proxy-sdk.dll proxy-sdk.h ieshims.dll
|
||||
rm -rf README.md proxy-sdk.h proxy-sdk.dll
|
||||
|
||||
#windows 32bit
|
||||
CC=i686-w64-mingw32-gcc-win32 GOARCH=386 CGO_ENABLED=1 GOOS=windows go build -buildmode=c-shared -ldflags "-s -w" -o proxy-sdk.dll sdk.go
|
||||
cp ../README.md .
|
||||
tar zcf sdk-windows-32bit-${VER}.tar.gz README.md proxy-sdk.dll proxy-sdk.h ieshims.dll
|
||||
rm -rf README.md proxy-sdk.h proxy-sdk.dll
|
||||
|
||||
sudo rm /usr/local/go
|
||||
sudo ln -s /usr/local/go1.8.5 /usr/local/go
|
||||
|
||||
echo "done."
|
||||
19
sdk/windows-linux/sdk.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
sdk "snail007/proxy/sdk/android-ios"
|
||||
)
|
||||
|
||||
//export Start
|
||||
func Start(serviceID *C.char,serviceArgsStr *C.char) (errStr *C.char) {
|
||||
return C.CString(sdk.Start(C.GoString(serviceID),C.GoString(serviceArgsStr)))
|
||||
}
|
||||
|
||||
//export Stop
|
||||
func Stop(serviceID *C.char) {
|
||||
sdk.Stop(C.GoString(serviceID))
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
package services
|
||||
|
||||
import "golang.org/x/crypto/ssh"
|
||||
import (
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
// t := tcp.Flag("tcp-timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
|
||||
@ -21,39 +25,46 @@ const (
|
||||
)
|
||||
|
||||
type MuxServerArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
IsUDP *bool
|
||||
Key *string
|
||||
Remote *string
|
||||
Timeout *int
|
||||
Route *[]string
|
||||
Mgr *MuxServerManager
|
||||
IsCompress *bool
|
||||
Parent *string
|
||||
ParentType *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
IsUDP *bool
|
||||
Key *string
|
||||
Remote *string
|
||||
Timeout *int
|
||||
Route *[]string
|
||||
Mgr *MuxServerManager
|
||||
IsCompress *bool
|
||||
SessionCount *int
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
type MuxClientArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Key *string
|
||||
Timeout *int
|
||||
IsCompress *bool
|
||||
Parent *string
|
||||
ParentType *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Key *string
|
||||
Timeout *int
|
||||
IsCompress *bool
|
||||
SessionCount *int
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
type MuxBridgeArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
LocalType *string
|
||||
Timeout *int
|
||||
IsCompress *bool
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
type TunnelServerArgs struct {
|
||||
Parent *string
|
||||
@ -100,16 +111,16 @@ type TCPArgs struct {
|
||||
ParentType *string
|
||||
LocalType *string
|
||||
Timeout *int
|
||||
PoolSize *int
|
||||
CheckParentInterval *int
|
||||
KCPMethod *string
|
||||
KCPKey *string
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
|
||||
type HTTPArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CaCertFile *string
|
||||
CaCertBytes []byte
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
@ -127,7 +138,6 @@ type HTTPArgs struct {
|
||||
ParentType *string
|
||||
LocalType *string
|
||||
Timeout *int
|
||||
PoolSize *int
|
||||
CheckParentInterval *int
|
||||
SSHKeyFile *string
|
||||
SSHKeyFileSalt *string
|
||||
@ -135,11 +145,14 @@ type HTTPArgs struct {
|
||||
SSHUser *string
|
||||
SSHKeyBytes []byte
|
||||
SSHAuthMethod ssh.AuthMethod
|
||||
KCPMethod *string
|
||||
KCPKey *string
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
LocalIPS *[]string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
LocalKey *string
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
}
|
||||
type UDPArgs struct {
|
||||
Parent *string
|
||||
@ -150,7 +163,6 @@ type UDPArgs struct {
|
||||
Local *string
|
||||
ParentType *string
|
||||
Timeout *int
|
||||
PoolSize *int
|
||||
CheckParentInterval *int
|
||||
}
|
||||
type SocksArgs struct {
|
||||
@ -160,6 +172,8 @@ type SocksArgs struct {
|
||||
LocalType *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CaCertFile *string
|
||||
CaCertBytes []byte
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
SSHKeyFile *string
|
||||
@ -179,29 +193,45 @@ type SocksArgs struct {
|
||||
AuthURLOkCode *int
|
||||
AuthURLTimeout *int
|
||||
AuthURLRetry *int
|
||||
KCPMethod *string
|
||||
KCPKey *string
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
UDPParent *string
|
||||
UDPLocal *string
|
||||
LocalIPS *[]string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
LocalKey *string
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
}
|
||||
type SPSArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CaCertFile *string
|
||||
CaCertBytes []byte
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
ParentType *string
|
||||
LocalType *string
|
||||
Timeout *int
|
||||
KCPMethod *string
|
||||
KCPKey *string
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
ParentServiceType *string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
AuthFile *string
|
||||
Auth *[]string
|
||||
AuthURL *string
|
||||
AuthURLOkCode *int
|
||||
AuthURLTimeout *int
|
||||
AuthURLRetry *int
|
||||
LocalIPS *[]string
|
||||
ParentAuth *string
|
||||
LocalKey *string
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
}
|
||||
|
||||
func (a *SPSArgs) Protocol() string {
|
||||
|
||||
146
services/http.go
@ -8,6 +8,7 @@ import (
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
"snail007/proxy/utils/conncrypt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -16,38 +17,56 @@ import (
|
||||
)
|
||||
|
||||
type HTTP struct {
|
||||
outPool utils.OutPool
|
||||
outPool utils.OutConn
|
||||
cfg HTTPArgs
|
||||
checker utils.Checker
|
||||
basicAuth utils.BasicAuth
|
||||
sshClient *ssh.Client
|
||||
lockChn chan bool
|
||||
domainResolver utils.DomainResolver
|
||||
isStop bool
|
||||
serverChannels []*utils.ServerChannel
|
||||
userConns utils.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewHTTP() Service {
|
||||
return &HTTP{
|
||||
outPool: utils.OutPool{},
|
||||
cfg: HTTPArgs{},
|
||||
checker: utils.Checker{},
|
||||
basicAuth: utils.BasicAuth{},
|
||||
lockChn: make(chan bool, 1),
|
||||
outPool: utils.OutConn{},
|
||||
cfg: HTTPArgs{},
|
||||
checker: utils.Checker{},
|
||||
basicAuth: utils.BasicAuth{},
|
||||
lockChn: make(chan bool, 1),
|
||||
isStop: false,
|
||||
serverChannels: []*utils.ServerChannel{},
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
func (s *HTTP) CheckArgs() {
|
||||
var err error
|
||||
func (s *HTTP) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent != "" && *s.cfg.ParentType == "" {
|
||||
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read ca file error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
if *s.cfg.SSHUser == "" {
|
||||
log.Fatalf("ssh user required")
|
||||
err = fmt.Errorf("ssh user required")
|
||||
return
|
||||
}
|
||||
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
|
||||
log.Fatalf("ssh password or key required")
|
||||
err = fmt.Errorf("ssh password or key required")
|
||||
return
|
||||
}
|
||||
|
||||
if *s.cfg.SSHPassword != "" {
|
||||
@ -56,7 +75,8 @@ func (s *HTTP) CheckArgs() {
|
||||
var SSHSigner ssh.Signer
|
||||
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
|
||||
if err != nil {
|
||||
log.Fatalf("read key file ERR: %s", err)
|
||||
err = fmt.Errorf("read key file ERR: %s", err)
|
||||
return
|
||||
}
|
||||
if *s.cfg.SSHKeyFileSalt != "" {
|
||||
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
|
||||
@ -64,13 +84,15 @@ func (s *HTTP) CheckArgs() {
|
||||
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("parse ssh private key fail,ERR: %s", err)
|
||||
err = fmt.Errorf("parse ssh private key fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *HTTP) InitService() {
|
||||
func (s *HTTP) InitService() (err error) {
|
||||
s.InitBasicAuth()
|
||||
if *s.cfg.Parent != "" {
|
||||
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||
@ -79,16 +101,22 @@ func (s *HTTP) InitService() {
|
||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||
}
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
err := s.ConnectSSH()
|
||||
err = s.ConnectSSH()
|
||||
if err != nil {
|
||||
log.Fatalf("init service fail, ERR: %s", err)
|
||||
err = fmt.Errorf("init service fail, ERR: %s", err)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
//循环检查ssh网络连通性
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
||||
if err == nil {
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write([]byte{0})
|
||||
conn.SetDeadline(time.Time{})
|
||||
}
|
||||
if err != nil {
|
||||
if s.sshClient != nil {
|
||||
@ -106,20 +134,43 @@ func (s *HTTP) InitService() {
|
||||
}
|
||||
}()
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *HTTP) StopService() {
|
||||
if s.outPool.Pool != nil {
|
||||
s.outPool.Pool.ReleaseAll()
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop http(s) service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service http(s) stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
s.checker.Stop()
|
||||
if s.sshClient != nil {
|
||||
s.sshClient.Close()
|
||||
}
|
||||
for _, sc := range s.serverChannels {
|
||||
if sc.Listener != nil && *sc.Listener != nil {
|
||||
(*sc.Listener).Close()
|
||||
}
|
||||
if sc.UDPListener != nil {
|
||||
(*sc.UDPListener).Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
func (s *HTTP) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(HTTPArgs)
|
||||
s.CheckArgs()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
s.InitOutConnPool()
|
||||
}
|
||||
s.InitService()
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
for _, addr := range strings.Split(*s.cfg.Local, ",") {
|
||||
if addr != "" {
|
||||
host, port, _ := net.SplitHostPort(addr)
|
||||
@ -128,14 +179,15 @@ func (s *HTTP) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||
s.serverChannels = append(s.serverChannels, &sc)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -150,6 +202,14 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if *s.cfg.LocalCompress {
|
||||
inConn = utils.NewCompConn(inConn)
|
||||
}
|
||||
if *s.cfg.LocalKey != "" {
|
||||
inConn = conncrypt.New(inConn, &conncrypt.Config{
|
||||
Password: *s.cfg.LocalKey,
|
||||
})
|
||||
}
|
||||
var err interface{}
|
||||
var req utils.HTTPRequest
|
||||
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth)
|
||||
@ -181,7 +241,6 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
log.Printf("use proxy : %v, %s", useProxy, address)
|
||||
|
||||
err = s.OutToTCP(useProxy, address, &inConn, &req)
|
||||
|
||||
if err != nil {
|
||||
if *s.cfg.Parent == "" {
|
||||
log.Printf("connect to %s fail, ERR:%s", address, err)
|
||||
@ -201,19 +260,18 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
return
|
||||
}
|
||||
var outConn net.Conn
|
||||
var _outConn interface{}
|
||||
tryCount := 0
|
||||
maxTryCount := 5
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if useProxy {
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
outConn, err = s.getSSHConn(address)
|
||||
} else {
|
||||
//log.Printf("%v", s.outPool)
|
||||
_outConn, err = s.outPool.Pool.Get()
|
||||
if err == nil {
|
||||
outConn = _outConn.(net.Conn)
|
||||
}
|
||||
// log.Printf("%v", s.outPool)
|
||||
outConn, err = s.outPool.Get()
|
||||
}
|
||||
} else {
|
||||
outConn, err = utils.ConnectHost(s.Resolve(address), *s.cfg.Timeout)
|
||||
@ -231,16 +289,25 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentCompress {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
//outLocalAddr := outConn.LocalAddr().String()
|
||||
|
||||
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
|
||||
err = req.HTTPSReply()
|
||||
} else {
|
||||
//https或者http,上级是代理,proxy需要转发
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(req.HeadBuf)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -250,9 +317,13 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
|
||||
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
||||
log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
|
||||
s.userConns.Remove(inAddr)
|
||||
})
|
||||
log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
|
||||
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, inConn)
|
||||
return
|
||||
}
|
||||
|
||||
@ -260,7 +331,7 @@ func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err interface{}) {
|
||||
maxTryCount := 1
|
||||
tryCount := 0
|
||||
RETRY:
|
||||
if tryCount >= maxTryCount {
|
||||
if tryCount >= maxTryCount || s.isStop {
|
||||
return
|
||||
}
|
||||
wait := make(chan bool, 1)
|
||||
@ -317,16 +388,13 @@ func (s *HTTP) InitOutConnPool() {
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
||||
//parent string, timeout int, InitialCap int, MaxCap int
|
||||
s.outPool = utils.NewOutPool(
|
||||
s.outPool = utils.NewOutConn(
|
||||
*s.cfg.CheckParentInterval,
|
||||
*s.cfg.ParentType,
|
||||
*s.cfg.KCPMethod,
|
||||
*s.cfg.KCPKey,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.KCP,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
|
||||
s.Resolve(*s.cfg.Parent),
|
||||
*s.cfg.Timeout,
|
||||
*s.cfg.PoolSize,
|
||||
*s.cfg.PoolSize*2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
24
services/kcpcfg/args.go
Normal file
@ -0,0 +1,24 @@
|
||||
package kcpcfg
|
||||
|
||||
import kcp "github.com/xtaci/kcp-go"
|
||||
|
||||
type KCPConfigArgs struct {
|
||||
Key *string
|
||||
Crypt *string
|
||||
Mode *string
|
||||
MTU *int
|
||||
SndWnd *int
|
||||
RcvWnd *int
|
||||
DataShard *int
|
||||
ParityShard *int
|
||||
DSCP *int
|
||||
NoComp *bool
|
||||
AckNodelay *bool
|
||||
NoDelay *int
|
||||
Interval *int
|
||||
Resend *int
|
||||
NoCongestion *int
|
||||
SockBuf *int
|
||||
KeepAlive *int
|
||||
Block kcp.BlockCrypt
|
||||
}
|
||||
@ -2,11 +2,15 @@ package services
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"snail007/proxy/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
@ -15,108 +19,207 @@ import (
|
||||
type MuxBridge struct {
|
||||
cfg MuxBridgeArgs
|
||||
clientControlConns utils.ConcurrentMap
|
||||
serverConns utils.ConcurrentMap
|
||||
router utils.ClientKeyRouter
|
||||
l *sync.Mutex
|
||||
isStop bool
|
||||
sc *utils.ServerChannel
|
||||
}
|
||||
|
||||
func NewMuxBridge() Service {
|
||||
b := &MuxBridge{
|
||||
cfg: MuxBridgeArgs{},
|
||||
clientControlConns: utils.NewConcurrentMap(),
|
||||
serverConns: utils.NewConcurrentMap(),
|
||||
l: &sync.Mutex{},
|
||||
isStop: false,
|
||||
}
|
||||
b.router = utils.NewClientKeyRouter(&b.clientControlConns, 50000)
|
||||
return b
|
||||
}
|
||||
|
||||
func (s *MuxBridge) InitService() {
|
||||
|
||||
func (s *MuxBridge) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
func (s *MuxBridge) CheckArgs() {
|
||||
func (s *MuxBridge) CheckArgs() (err error) {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
err = fmt.Errorf("cert and key file required")
|
||||
return
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.LocalType == TYPE_TLS {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxBridge) StopService() {
|
||||
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop bridge service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service bridge stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
if s.sc != nil && (*s.sc).Listener != nil {
|
||||
(*(*s.sc).Listener).Close()
|
||||
}
|
||||
for _, g := range s.clientControlConns.Items() {
|
||||
for _, session := range g.(utils.ConcurrentMap).Items() {
|
||||
(session.(*smux.Session)).Close()
|
||||
}
|
||||
}
|
||||
for _, c := range s.serverConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
}
|
||||
func (s *MuxBridge) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(MuxBridgeArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) {
|
||||
reader := bufio.NewReader(inConn)
|
||||
|
||||
var err error
|
||||
var connType uint8
|
||||
var key string
|
||||
err = utils.ReadPacket(reader, &connType, &key)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
case CONN_SERVER:
|
||||
var serverID string
|
||||
err = utils.ReadPacketData(reader, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("server connection %s %s connected", serverID, key)
|
||||
session, err := smux.Server(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("server session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
session.Close()
|
||||
utils.CloseConn(&inConn)
|
||||
return
|
||||
}
|
||||
go s.callback(stream, serverID, key)
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
|
||||
log.Printf("client connection %s connected", key)
|
||||
session, err := smux.Client(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
s.clientControlConns.Set(key, session)
|
||||
go func() {
|
||||
for {
|
||||
if session.IsClosed() {
|
||||
s.clientControlConns.Remove(key)
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
//log.Printf("set client session,key: %s", key)
|
||||
}
|
||||
|
||||
})
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.handler)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.handler)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on mux bridge mode %s", (*sc.Listener).Addr())
|
||||
s.sc = &sc
|
||||
log.Printf("%s bridge on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||
return
|
||||
}
|
||||
func (s *MuxBridge) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
reader := bufio.NewReader(inConn)
|
||||
|
||||
var err error
|
||||
var connType uint8
|
||||
var key string
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
err = utils.ReadPacket(reader, &connType, &key)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
case CONN_SERVER:
|
||||
var serverID string
|
||||
inAddr := inConn.RemoteAddr().String()
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
err = utils.ReadPacketData(reader, &serverID)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("server connection %s %s connected", serverID, key)
|
||||
if c, ok := s.serverConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.serverConns.Set(inAddr, &inConn)
|
||||
session, err := smux.Server(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("server session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
session.Close()
|
||||
utils.CloseConn(&inConn)
|
||||
s.serverConns.Remove(inAddr)
|
||||
log.Printf("server connection %s %s released", serverID, key)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
log.Printf("bridge callback crashed,err: %s", e)
|
||||
}
|
||||
}()
|
||||
s.callback(stream, serverID, key)
|
||||
}()
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
log.Printf("client connection %s connected", key)
|
||||
session, err := smux.Client(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
keyInfo := strings.Split(key, "-")
|
||||
if len(keyInfo) != 2 {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client key format error,key:%s", key)
|
||||
return
|
||||
}
|
||||
groupKey := keyInfo[0]
|
||||
index := keyInfo[1]
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
if !s.clientControlConns.Has(groupKey) {
|
||||
item := utils.NewConcurrentMap()
|
||||
s.clientControlConns.Set(groupKey, &item)
|
||||
}
|
||||
_group, _ := s.clientControlConns.Get(groupKey)
|
||||
group := _group.(*utils.ConcurrentMap)
|
||||
if v, ok := group.Get(index); ok {
|
||||
v.(*smux.Session).Close()
|
||||
}
|
||||
group.Set(index, session)
|
||||
// s.clientControlConns.Set(key, session)
|
||||
go func() {
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if session.IsClosed() {
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
|
||||
group.Remove(index)
|
||||
log.Printf("client connection %s released", key)
|
||||
}
|
||||
if group.IsEmpty() {
|
||||
s.clientControlConns.Remove(groupKey)
|
||||
}
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
//log.Printf("set client session,key: %s", key)
|
||||
}
|
||||
|
||||
}
|
||||
func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||
try := 20
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
try--
|
||||
if try == 0 {
|
||||
break
|
||||
@ -124,19 +227,35 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||
if key == "*" {
|
||||
key = s.router.GetKey()
|
||||
}
|
||||
session, ok := s.clientControlConns.Get(key)
|
||||
_group, ok := s.clientControlConns.Get(key)
|
||||
if !ok {
|
||||
log.Printf("client %s session not exists for server stream %s", key, serverID)
|
||||
log.Printf("client %s session not exists for server stream %s, retrying...", key, serverID)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
group := _group.(*utils.ConcurrentMap)
|
||||
keys := group.Keys()
|
||||
keysLen := len(keys)
|
||||
i := 0
|
||||
if keysLen > 0 {
|
||||
i = rand.Intn(keysLen)
|
||||
} else {
|
||||
log.Printf("client %s session empty for server stream %s, retrying...", key, serverID)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
index := keys[i]
|
||||
log.Printf("select client : %s-%s", key, index)
|
||||
session, _ := group.Get(index)
|
||||
session.(*smux.Session).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
stream, err := session.(*smux.Session).OpenStream()
|
||||
session.(*smux.Session).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
} else {
|
||||
log.Printf("%s server %s stream created", key, serverID)
|
||||
log.Printf("stream %s -> %s created", serverID, key)
|
||||
die1 := make(chan bool, 1)
|
||||
die2 := make(chan bool, 1)
|
||||
go func() {
|
||||
|
||||
@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@ -13,98 +14,177 @@ import (
|
||||
)
|
||||
|
||||
type MuxClient struct {
|
||||
cfg MuxClientArgs
|
||||
cfg MuxClientArgs
|
||||
isStop bool
|
||||
sessions utils.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewMuxClient() Service {
|
||||
return &MuxClient{
|
||||
cfg: MuxClientArgs{},
|
||||
cfg: MuxClientArgs{},
|
||||
isStop: false,
|
||||
sessions: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MuxClient) InitService() {
|
||||
|
||||
func (s *MuxClient) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *MuxClient) CheckArgs() {
|
||||
func (s *MuxClient) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
} else {
|
||||
log.Fatalf("parent required")
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
}
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
err = fmt.Errorf("cert and key file required")
|
||||
return
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxClient) StopService() {
|
||||
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop client service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service client stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
for _, sess := range s.sessions.Items() {
|
||||
sess.(*smux.Session).Close()
|
||||
}
|
||||
}
|
||||
func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(MuxClientArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
log.Printf("proxy on mux client mode, compress %v", *s.cfg.IsCompress)
|
||||
for {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
conn := net.Conn(&_conn)
|
||||
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, *s.cfg.Key))
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
session, err := smux.Server(conn, nil)
|
||||
if err != nil {
|
||||
log.Printf("session err: %s, retrying...", err)
|
||||
conn.Close()
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
for {
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
log.Printf("accept stream err: %s, retrying...", err)
|
||||
session.Close()
|
||||
time.Sleep(time.Second * 3)
|
||||
break
|
||||
}
|
||||
go func() {
|
||||
var ID, clientLocalAddr, serverID string
|
||||
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read stream signal err: %s", err)
|
||||
stream.Close()
|
||||
return
|
||||
}
|
||||
log.Printf("signal revecived,server %s stream %s %s", serverID, ID, clientLocalAddr)
|
||||
protocol := clientLocalAddr[:3]
|
||||
localAddr := clientLocalAddr[4:]
|
||||
if protocol == "udp" {
|
||||
s.ServeUDP(stream, localAddr, ID)
|
||||
} else {
|
||||
s.ServeConn(stream, localAddr, ID)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("client started")
|
||||
count := 1
|
||||
if *s.cfg.SessionCount > 0 {
|
||||
count = *s.cfg.SessionCount
|
||||
}
|
||||
for i := 1; i <= count; i++ {
|
||||
key := fmt.Sprintf("worker[%d]", i)
|
||||
log.Printf("session %s started", key)
|
||||
go func(i int) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("session worker crashed: %s", e)
|
||||
}
|
||||
}()
|
||||
}
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
conn, err := s.getParentConn()
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, fmt.Sprintf("%s-%d", *s.cfg.Key, i)))
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
session, err := smux.Server(conn, nil)
|
||||
if err != nil {
|
||||
log.Printf("session err: %s, retrying...", err)
|
||||
conn.Close()
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
if _sess, ok := s.sessions.Get(key); ok {
|
||||
_sess.(*smux.Session).Close()
|
||||
}
|
||||
s.sessions.Set(key, session)
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
log.Printf("accept stream err: %s, retrying...", err)
|
||||
session.Close()
|
||||
time.Sleep(time.Second * 3)
|
||||
break
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stream handler crashed: %s", e)
|
||||
}
|
||||
}()
|
||||
var ID, clientLocalAddr, serverID string
|
||||
stream.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
||||
stream.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read stream signal err: %s", err)
|
||||
stream.Close()
|
||||
return
|
||||
}
|
||||
log.Printf("worker[%d] signal revecived,server %s stream %s %s", i, serverID, ID, clientLocalAddr)
|
||||
protocol := clientLocalAddr[:3]
|
||||
localAddr := clientLocalAddr[4:]
|
||||
if protocol == "udp" {
|
||||
s.ServeUDP(stream, localAddr, ID)
|
||||
} else {
|
||||
s.ServeConn(stream, localAddr, ID)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
func (s *MuxClient) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
|
||||
func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
} else if *s.cfg.ParentType == "kcp" {
|
||||
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
|
||||
} else {
|
||||
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
||||
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("udp packet revecived fail, err: %s", err)
|
||||
log.Printf("connection %s released", ID)
|
||||
@ -112,7 +192,15 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
||||
break
|
||||
} else {
|
||||
//log.Printf("udp packet revecived:%s,%v", srcAddr, body)
|
||||
go s.processUDPPacket(inConn, srcAddr, localAddr, body)
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
log.Printf("client processUDPPacket crashed,err: %s", e)
|
||||
}
|
||||
}()
|
||||
s.processUDPPacket(inConn, srcAddr, localAddr, body)
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -133,13 +221,16 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(body)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 1024)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
@ -147,7 +238,9 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
|
||||
respBody := buf[0:length]
|
||||
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||
bs := utils.UDPPacket(srcAddr, respBody)
|
||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = (*inConn).Write(bs)
|
||||
(*inConn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("send udp response fail ,ERR:%s", err)
|
||||
inConn.Close()
|
||||
@ -160,6 +253,9 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
|
||||
var outConn net.Conn
|
||||
i := 0
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
i++
|
||||
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
|
||||
if err == nil || i == 3 {
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
@ -17,18 +18,20 @@ import (
|
||||
)
|
||||
|
||||
type MuxServer struct {
|
||||
cfg MuxServerArgs
|
||||
udpChn chan MuxUDPItem
|
||||
sc utils.ServerChannel
|
||||
session *smux.Session
|
||||
lockChn chan bool
|
||||
cfg MuxServerArgs
|
||||
udpChn chan MuxUDPItem
|
||||
sc utils.ServerChannel
|
||||
sessions utils.ConcurrentMap
|
||||
lockChn chan bool
|
||||
isStop bool
|
||||
udpConn *net.Conn
|
||||
}
|
||||
|
||||
type MuxServerManager struct {
|
||||
cfg MuxServerArgs
|
||||
udpChn chan MuxUDPItem
|
||||
sc utils.ServerChannel
|
||||
serverID string
|
||||
servers []*Service
|
||||
}
|
||||
|
||||
func NewMuxServerManager() Service {
|
||||
@ -36,18 +39,25 @@ func NewMuxServerManager() Service {
|
||||
cfg: MuxServerArgs{},
|
||||
udpChn: make(chan MuxUDPItem, 50000),
|
||||
serverID: utils.Uniqueid(),
|
||||
servers: []*Service{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(MuxServerArgs)
|
||||
s.CheckArgs()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
} else {
|
||||
log.Fatalf("parent required")
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
}
|
||||
|
||||
s.InitService()
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("server id: %s", s.serverID)
|
||||
//log.Printf("route:%v", *s.cfg.Route)
|
||||
@ -74,23 +84,27 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
remote = fmt.Sprintf("127.0.0.1%s", remote)
|
||||
}
|
||||
err = server.Start(MuxServerArgs{
|
||||
CertBytes: s.cfg.CertBytes,
|
||||
KeyBytes: s.cfg.KeyBytes,
|
||||
Parent: s.cfg.Parent,
|
||||
CertFile: s.cfg.CertFile,
|
||||
KeyFile: s.cfg.KeyFile,
|
||||
Local: &local,
|
||||
IsUDP: &IsUDP,
|
||||
Remote: &remote,
|
||||
Key: &KEY,
|
||||
Timeout: s.cfg.Timeout,
|
||||
Mgr: s,
|
||||
IsCompress: s.cfg.IsCompress,
|
||||
CertBytes: s.cfg.CertBytes,
|
||||
KeyBytes: s.cfg.KeyBytes,
|
||||
Parent: s.cfg.Parent,
|
||||
CertFile: s.cfg.CertFile,
|
||||
KeyFile: s.cfg.KeyFile,
|
||||
Local: &local,
|
||||
IsUDP: &IsUDP,
|
||||
Remote: &remote,
|
||||
Key: &KEY,
|
||||
Timeout: s.cfg.Timeout,
|
||||
Mgr: s,
|
||||
IsCompress: s.cfg.IsCompress,
|
||||
SessionCount: s.cfg.SessionCount,
|
||||
KCP: s.cfg.KCP,
|
||||
ParentType: s.cfg.ParentType,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.servers = append(s.servers, &server)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -98,21 +112,34 @@ func (s *MuxServerManager) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
func (s *MuxServerManager) StopService() {
|
||||
}
|
||||
func (s *MuxServerManager) CheckArgs() {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
for _, server := range s.servers {
|
||||
(*server).Clean()
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
}
|
||||
func (s *MuxServerManager) InitService() {
|
||||
func (s *MuxServerManager) CheckArgs() (err error) {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
err = fmt.Errorf("cert and key file required")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxServerManager) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func NewMuxServer() Service {
|
||||
return &MuxServer{
|
||||
cfg: MuxServerArgs{},
|
||||
udpChn: make(chan MuxUDPItem, 50000),
|
||||
lockChn: make(chan bool, 1),
|
||||
cfg: MuxServerArgs{},
|
||||
udpChn: make(chan MuxUDPItem, 50000),
|
||||
lockChn: make(chan bool, 1),
|
||||
sessions: utils.NewConcurrentMap(),
|
||||
isStop: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,19 +149,49 @@ type MuxUDPItem struct {
|
||||
srcAddr *net.UDPAddr
|
||||
}
|
||||
|
||||
func (s *MuxServer) InitService() {
|
||||
s.UDPConnDeamon()
|
||||
}
|
||||
func (s *MuxServer) CheckArgs() {
|
||||
if *s.cfg.Remote == "" {
|
||||
log.Fatalf("remote required")
|
||||
func (s *MuxServer) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop server service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service server stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
for _, sess := range s.sessions.Items() {
|
||||
sess.(*smux.Session).Close()
|
||||
}
|
||||
if s.sc.Listener != nil {
|
||||
(*s.sc.Listener).Close()
|
||||
}
|
||||
if s.sc.UDPListener != nil {
|
||||
(*s.sc.UDPListener).Close()
|
||||
}
|
||||
if s.udpConn != nil {
|
||||
(*s.udpConn).Close()
|
||||
}
|
||||
}
|
||||
func (s *MuxServer) InitService() (err error) {
|
||||
s.UDPConnDeamon()
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) CheckArgs() (err error) {
|
||||
if *s.cfg.Remote == "" {
|
||||
err = fmt.Errorf("remote required")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(MuxServerArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
s.sc = utils.NewServerChannel(host, p)
|
||||
@ -149,7 +206,7 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on udp mux server mode %s", (*s.sc.UDPListener).LocalAddr())
|
||||
log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr())
|
||||
} else {
|
||||
err = s.sc.ListenTCP(func(inConn net.Conn) {
|
||||
defer func() {
|
||||
@ -160,6 +217,9 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
var outConn net.Conn
|
||||
var ID string
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
outConn, ID, err = s.GetOutConn()
|
||||
if err != nil {
|
||||
utils.CloseConn(&outConn)
|
||||
@ -198,15 +258,19 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on mux server mode %s, compress %v", (*s.sc.Listener).Addr(), *s.cfg.IsCompress)
|
||||
log.Printf("server on %s", (*s.sc.Listener).Addr())
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) Clean() {
|
||||
|
||||
s.StopService()
|
||||
}
|
||||
func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||
outConn, err = s.GetConn()
|
||||
i := 1
|
||||
if *s.cfg.SessionCount > 0 {
|
||||
i = rand.Intn(*s.cfg.SessionCount)
|
||||
}
|
||||
outConn, err = s.GetConn(fmt.Sprintf("%d", i))
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s", err)
|
||||
return
|
||||
@ -216,7 +280,9 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||
remoteAddr = "udp:" + *s.cfg.Remote
|
||||
}
|
||||
ID = utils.Uniqueid()
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("write stream data err: %s ,retrying...", err)
|
||||
utils.CloseConn(&outConn)
|
||||
@ -224,7 +290,7 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) GetConn() (conn net.Conn, err error) {
|
||||
func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
||||
select {
|
||||
case s.lockChn <- true:
|
||||
default:
|
||||
@ -234,34 +300,66 @@ func (s *MuxServer) GetConn() (conn net.Conn, err error) {
|
||||
defer func() {
|
||||
<-s.lockChn
|
||||
}()
|
||||
if s.session == nil {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
var session *smux.Session
|
||||
_session, ok := s.sessions.Get(index)
|
||||
if !ok {
|
||||
var c net.Conn
|
||||
c, err = s.getParentConn()
|
||||
if err != nil {
|
||||
s.session = nil
|
||||
return
|
||||
}
|
||||
c := net.Conn(&_conn)
|
||||
c.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = c.Write(utils.BuildPacket(CONN_SERVER, *s.cfg.Key, s.cfg.Mgr.serverID))
|
||||
c.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
c.Close()
|
||||
s.session = nil
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
s.session, err = smux.Client(c, nil)
|
||||
session, err = smux.Client(c, nil)
|
||||
if err != nil {
|
||||
s.session = nil
|
||||
return
|
||||
}
|
||||
}
|
||||
if _sess, ok := s.sessions.Get(index); ok {
|
||||
_sess.(*smux.Session).Close()
|
||||
}
|
||||
s.sessions.Set(index, session)
|
||||
log.Printf("session[%s] created", index)
|
||||
go func() {
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if session.IsClosed() {
|
||||
s.sessions.Remove(index)
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
session = _session.(*smux.Session)
|
||||
}
|
||||
conn, err = s.session.OpenStream()
|
||||
conn, err = session.OpenStream()
|
||||
if err != nil {
|
||||
s.session.Close()
|
||||
s.session = nil
|
||||
session.Close()
|
||||
s.sessions.Remove(index)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
} else if *s.cfg.ParentType == "kcp" {
|
||||
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
|
||||
} else {
|
||||
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) UDPConnDeamon() {
|
||||
@ -275,10 +373,19 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
var ID string
|
||||
var err error
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
item := <-s.udpChn
|
||||
RETRY:
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if outConn == nil {
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
outConn, ID, err = s.GetOutConn()
|
||||
if err != nil {
|
||||
outConn = nil
|
||||
@ -288,11 +395,17 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
continue
|
||||
} else {
|
||||
go func(outConn net.Conn, ID string) {
|
||||
go func() {
|
||||
// outConn.Close()
|
||||
}()
|
||||
if s.udpConn != nil {
|
||||
(*s.udpConn).Close()
|
||||
}
|
||||
s.udpConn = &outConn
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
||||
log.Printf("UDP deamon connection %s exited", ID)
|
||||
@ -306,7 +419,9 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
}
|
||||
port, _ := strconv.Atoi(_srcAddr[1])
|
||||
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||
s.sc.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||
s.sc.UDPListener.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
||||
continue
|
||||
|
||||
@ -2,7 +2,6 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
@ -19,33 +18,43 @@ type ServiceItem struct {
|
||||
var servicesMap = map[string]*ServiceItem{}
|
||||
|
||||
func Regist(name string, s Service, args interface{}) {
|
||||
Stop(name)
|
||||
servicesMap[name] = &ServiceItem{
|
||||
S: s,
|
||||
Args: args,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
func GetService(name string) *ServiceItem {
|
||||
if s, ok := servicesMap[name]; ok && s.S != nil {
|
||||
return s
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
func Stop(name string) {
|
||||
if s, ok := servicesMap[name]; ok && s.S != nil {
|
||||
s.S.Clean()
|
||||
}
|
||||
}
|
||||
func Run(name string, args ...interface{}) (service *ServiceItem, err error) {
|
||||
service, ok := servicesMap[name]
|
||||
if ok {
|
||||
go func() {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
log.Fatalf("%s servcie crashed, ERR: %s\ntrace:%s", name, err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if len(args) == 1 {
|
||||
err = service.S.Start(args[0])
|
||||
} else {
|
||||
err = service.S.Start(service.Args)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("%s servcie fail, ERR: %s", name, err)
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
}
|
||||
if !ok {
|
||||
if len(args) == 1 {
|
||||
err = service.S.Start(args[0])
|
||||
} else {
|
||||
err = service.S.Start(service.Args)
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s servcie fail, ERR: %s", name, err)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("service %s not found", name)
|
||||
}
|
||||
return
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
"snail007/proxy/utils/aes"
|
||||
"snail007/proxy/utils/conncrypt"
|
||||
"snail007/proxy/utils/socks"
|
||||
"strings"
|
||||
"time"
|
||||
@ -23,7 +24,10 @@ type Socks struct {
|
||||
sshClient *ssh.Client
|
||||
lockChn chan bool
|
||||
udpSC utils.ServerChannel
|
||||
sc *utils.ServerChannel
|
||||
domainResolver utils.DomainResolver
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewSocks() Service {
|
||||
@ -32,27 +36,39 @@ func NewSocks() Service {
|
||||
checker: utils.Checker{},
|
||||
basicAuth: utils.BasicAuth{},
|
||||
lockChn: make(chan bool, 1),
|
||||
isStop: false,
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socks) CheckArgs() {
|
||||
var err error
|
||||
if *s.cfg.LocalType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
func (s *Socks) CheckArgs() (err error) {
|
||||
|
||||
if *s.cfg.LocalType == "tls" || (*s.cfg.Parent != "" && *s.cfg.ParentType == "tls") {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read ca file error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
if *s.cfg.ParentType == "" {
|
||||
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
if *s.cfg.SSHUser == "" {
|
||||
log.Fatalf("ssh user required")
|
||||
err = fmt.Errorf("ssh user required")
|
||||
return
|
||||
}
|
||||
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
|
||||
log.Fatalf("ssh password or key required")
|
||||
err = fmt.Errorf("ssh password or key required")
|
||||
return
|
||||
}
|
||||
if *s.cfg.SSHPassword != "" {
|
||||
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
|
||||
@ -60,7 +76,8 @@ func (s *Socks) CheckArgs() {
|
||||
var SSHSigner ssh.Signer
|
||||
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
|
||||
if err != nil {
|
||||
log.Fatalf("read key file ERR: %s", err)
|
||||
err = fmt.Errorf("read key file ERR: %s", err)
|
||||
return
|
||||
}
|
||||
if *s.cfg.SSHKeyFileSalt != "" {
|
||||
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
|
||||
@ -68,31 +85,38 @@ func (s *Socks) CheckArgs() {
|
||||
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("parse ssh private key fail,ERR: %s", err)
|
||||
err = fmt.Errorf("parse ssh private key fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
func (s *Socks) InitService() {
|
||||
func (s *Socks) InitService() (err error) {
|
||||
s.InitBasicAuth()
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||
}
|
||||
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
err := s.ConnectSSH()
|
||||
if err != nil {
|
||||
log.Fatalf("init service fail, ERR: %s", err)
|
||||
e := s.ConnectSSH()
|
||||
if e != nil {
|
||||
err = fmt.Errorf("init service fail, ERR: %s", e)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
//循环检查ssh网络连通性
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
||||
if err == nil {
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write([]byte{0})
|
||||
conn.SetDeadline(time.Time{})
|
||||
}
|
||||
if err != nil {
|
||||
if s.sshClient != nil {
|
||||
@ -111,26 +135,48 @@ func (s *Socks) InitService() {
|
||||
log.Println("warn: socks udp not suppored for ssh")
|
||||
} else {
|
||||
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal)
|
||||
err := s.udpSC.ListenUDP(s.udpCallback)
|
||||
if err != nil {
|
||||
log.Fatalf("init udp service fail, ERR: %s", err)
|
||||
e := s.udpSC.ListenUDP(s.udpCallback)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("init udp service fail, ERR: %s", e)
|
||||
return
|
||||
}
|
||||
log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *Socks) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop socks service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service socks stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
s.checker.Stop()
|
||||
if s.sshClient != nil {
|
||||
s.sshClient.Close()
|
||||
}
|
||||
if s.udpSC.UDPListener != nil {
|
||||
s.udpSC.UDPListener.Close()
|
||||
}
|
||||
if s.sc != nil && (*s.sc).Listener != nil {
|
||||
(*(*s.sc).Listener).Close()
|
||||
}
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
}
|
||||
func (s *Socks) Start(args interface{}) (err error) {
|
||||
//start()
|
||||
s.cfg = args.(SocksArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
s.InitService()
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
}
|
||||
@ -138,13 +184,14 @@ func (s *Socks) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.socksConnCallback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.socksConnCallback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.socksConnCallback)
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.sc = &sc
|
||||
log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||
return
|
||||
}
|
||||
@ -204,6 +251,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
|
||||
_, err = conn.Write(rawB)
|
||||
conn.SetDeadline(time.Time{})
|
||||
log.Printf("udp request:%v", len(rawB))
|
||||
if err != nil {
|
||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
@ -213,7 +261,9 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
|
||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 10*1024)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
conn.Close()
|
||||
@ -238,10 +288,14 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
log.Printf("udp reply:%v", len(d))
|
||||
} else {
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
log.Printf("udp reply:%v", len(respBody))
|
||||
}
|
||||
|
||||
@ -260,6 +314,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
|
||||
_, err = conn.Write(p.Data())
|
||||
conn.SetDeadline(time.Time{})
|
||||
log.Printf("udp send:%v", len(p.Data()))
|
||||
if err != nil {
|
||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
@ -268,7 +323,10 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 10*1024)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
conn.Close()
|
||||
@ -285,9 +343,13 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
} else {
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
}
|
||||
log.Printf("udp reply:%v", len(respPacket))
|
||||
}
|
||||
@ -300,6 +362,14 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
inConn.Close()
|
||||
}
|
||||
}()
|
||||
if *s.cfg.LocalCompress {
|
||||
inConn = utils.NewCompConn(inConn)
|
||||
}
|
||||
if *s.cfg.LocalKey != "" {
|
||||
inConn = conncrypt.New(inConn, &conncrypt.Config{
|
||||
Password: *s.cfg.LocalKey,
|
||||
})
|
||||
}
|
||||
//协商开始
|
||||
|
||||
//method select request
|
||||
@ -359,9 +429,15 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
//auth
|
||||
_addr := strings.Split(inConn.RemoteAddr().String(), ":")
|
||||
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
inConn.Write([]byte{0x01, 0x00})
|
||||
inConn.SetDeadline(time.Time{})
|
||||
|
||||
} else {
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
inConn.Write([]byte{0x01, 0x01})
|
||||
inConn.SetDeadline(time.Time{})
|
||||
|
||||
utils.CloseConn(&inConn)
|
||||
return
|
||||
}
|
||||
@ -415,6 +491,9 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
return
|
||||
}
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if *s.cfg.Always {
|
||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
||||
} else {
|
||||
@ -451,6 +530,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("use proxy %v : %s", useProxy, request.Addr())
|
||||
|
||||
request.TCPReply(socks.REP_SUCCESS)
|
||||
@ -461,6 +541,11 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
utils.IoBind(*inConn, outConn, func(err interface{}) {
|
||||
log.Printf("conn %s - %s released", inAddr, request.Addr())
|
||||
})
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
s.userConns.Remove(inAddr)
|
||||
}
|
||||
s.userConns.Set(inAddr, inConn)
|
||||
}
|
||||
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
|
||||
switch *s.cfg.ParentType {
|
||||
@ -471,10 +556,10 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
case "tcp":
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
var _outConn tls.Conn
|
||||
_outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
outConn = net.Conn(&_outConn)
|
||||
} else if *s.cfg.ParentType == "kcp" {
|
||||
outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), *s.cfg.KCPMethod, *s.cfg.KCPKey)
|
||||
outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), s.cfg.KCP)
|
||||
} else {
|
||||
outConn, err = utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout)
|
||||
}
|
||||
@ -482,27 +567,42 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
err = fmt.Errorf("connect fail,%s", err)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentCompress {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
var buf = make([]byte, 1024)
|
||||
//var n int
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(methodBytes)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("write method fail,%s", err)
|
||||
return
|
||||
}
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Read(buf)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read method reply fail,%s", err)
|
||||
return
|
||||
}
|
||||
//resp := buf[:n]
|
||||
//log.Printf("resp:%v", resp)
|
||||
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(reqBytes)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("write req detail fail,%s", err)
|
||||
return
|
||||
}
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Read(buf)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read req reply fail,%s", err)
|
||||
return
|
||||
@ -514,7 +614,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
maxTryCount := 1
|
||||
tryCount := 0
|
||||
RETRY:
|
||||
if tryCount >= maxTryCount {
|
||||
if tryCount >= maxTryCount || s.isStop {
|
||||
return
|
||||
}
|
||||
wait := make(chan bool, 1)
|
||||
|
||||
308
services/sps.go
@ -2,72 +2,116 @@ package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
"snail007/proxy/utils/conncrypt"
|
||||
"snail007/proxy/utils/socks"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SPS struct {
|
||||
outPool utils.OutPool
|
||||
outPool utils.OutConn
|
||||
cfg SPSArgs
|
||||
domainResolver utils.DomainResolver
|
||||
basicAuth utils.BasicAuth
|
||||
serverChannels []*utils.ServerChannel
|
||||
userConns utils.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewSPS() Service {
|
||||
return &SPS{
|
||||
outPool: utils.OutPool{},
|
||||
cfg: SPSArgs{},
|
||||
outPool: utils.OutConn{},
|
||||
cfg: SPSArgs{},
|
||||
basicAuth: utils.BasicAuth{},
|
||||
serverChannels: []*utils.ServerChannel{},
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
func (s *SPS) CheckArgs() {
|
||||
func (s *SPS) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent == "" {
|
||||
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
||||
err = fmt.Errorf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "" {
|
||||
log.Fatalf("parent type unkown,use -T <tls|tcp|kcp>")
|
||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp>")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read ca file error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitService() {
|
||||
func (s *SPS) InitService() (err error) {
|
||||
s.InitOutConnPool()
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||
}
|
||||
err = s.InitBasicAuth()
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitOutConnPool() {
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
||||
//parent string, timeout int, InitialCap int, MaxCap int
|
||||
s.outPool = utils.NewOutPool(
|
||||
s.outPool = utils.NewOutConn(
|
||||
0,
|
||||
*s.cfg.ParentType,
|
||||
*s.cfg.KCPMethod,
|
||||
*s.cfg.KCPKey,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.KCP,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
|
||||
*s.cfg.Parent,
|
||||
*s.cfg.Timeout,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SPS) StopService() {
|
||||
if s.outPool.Pool != nil {
|
||||
s.outPool.Pool.ReleaseAll()
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop sps service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service sps stoped")
|
||||
}
|
||||
}()
|
||||
for _, sc := range s.serverChannels {
|
||||
if sc.Listener != nil && *sc.Listener != nil {
|
||||
(*sc.Listener).Close()
|
||||
}
|
||||
if sc.UDPListener != nil {
|
||||
(*sc.UDPListener).Close()
|
||||
}
|
||||
}
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
}
|
||||
func (s *SPS) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(SPSArgs)
|
||||
s.CheckArgs()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("use %s %s parent %s", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent)
|
||||
s.InitService()
|
||||
|
||||
for _, addr := range strings.Split(*s.cfg.Local, ",") {
|
||||
if addr != "" {
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
@ -76,14 +120,15 @@ func (s *SPS) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("%s http(s)+socks proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
|
||||
s.serverChannels = append(s.serverChannels, &sc)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -98,6 +143,14 @@ func (s *SPS) callback(inConn net.Conn) {
|
||||
log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if *s.cfg.LocalCompress {
|
||||
inConn = utils.NewCompConn(inConn)
|
||||
}
|
||||
if *s.cfg.LocalKey != "" {
|
||||
inConn = conncrypt.New(inConn, &conncrypt.Config{
|
||||
Password: *s.cfg.LocalKey,
|
||||
})
|
||||
}
|
||||
var err error
|
||||
switch *s.cfg.ParentType {
|
||||
case TYPE_KCP:
|
||||
@ -110,7 +163,7 @@ func (s *SPS) callback(inConn net.Conn) {
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr())
|
||||
utils.CloseConn(&inConn)
|
||||
}
|
||||
}
|
||||
@ -124,51 +177,32 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
return
|
||||
}
|
||||
address := ""
|
||||
var auth socks.Auth
|
||||
var forwardBytes []byte
|
||||
//fmt.Printf("%v", header)
|
||||
if header[0] == socks.VERSION_V5 {
|
||||
//socks
|
||||
methodReq, e := socks.NewMethodsRequest(*inConn, header)
|
||||
if e != nil {
|
||||
log.Printf("new method request err:%s", e)
|
||||
utils.CloseConn(inConn)
|
||||
err = e.(error)
|
||||
//socks5 server
|
||||
var serverConn *socks.ServerConn
|
||||
if s.IsBasicAuth() {
|
||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header)
|
||||
} else {
|
||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header)
|
||||
}
|
||||
if err = serverConn.Handshake(); err != nil {
|
||||
return
|
||||
}
|
||||
if !methodReq.Select(socks.Method_NO_AUTH) {
|
||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||
utils.CloseConn(inConn)
|
||||
log.Printf("none method found : Method_NO_AUTH")
|
||||
return
|
||||
}
|
||||
//method select reply
|
||||
err = methodReq.Reply(socks.Method_NO_AUTH)
|
||||
if err != nil {
|
||||
log.Printf("reply answer data fail,ERR: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
//request detail
|
||||
request, e := socks.NewRequest(*inConn)
|
||||
if e != nil {
|
||||
log.Printf("read request data fail,ERR: %s", e)
|
||||
utils.CloseConn(inConn)
|
||||
err = e.(error)
|
||||
return
|
||||
}
|
||||
if request.CMD() != socks.CMD_CONNECT {
|
||||
//只支持tcp
|
||||
request.TCPReply(socks.REP_UNKNOWN)
|
||||
utils.CloseConn(inConn)
|
||||
err = errors.New("cmd not supported")
|
||||
return
|
||||
}
|
||||
address = request.Addr()
|
||||
request.TCPReply(socks.REP_SUCCESS)
|
||||
address = serverConn.Target()
|
||||
auth = serverConn.AuthData()
|
||||
} else if bytes.IndexByte(header, '\n') != -1 {
|
||||
//http
|
||||
var request utils.HTTPRequest
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
if s.IsBasicAuth() {
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header)
|
||||
} else {
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||
}
|
||||
(*inConn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("new http request fail,ERR: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -182,6 +216,17 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
forwardBytes = request.HeadBuf
|
||||
}
|
||||
address = request.Host
|
||||
var userpass string
|
||||
if s.IsBasicAuth() {
|
||||
userpass, err = request.GetAuthDataStr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userpassA := strings.Split(userpass, ":")
|
||||
if len(userpassA) == 2 {
|
||||
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
||||
utils.CloseConn(inConn)
|
||||
@ -190,22 +235,56 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
}
|
||||
//connect to parent
|
||||
var outConn net.Conn
|
||||
var _outConn interface{}
|
||||
_outConn, err = s.outPool.Pool.Get()
|
||||
if err == nil {
|
||||
outConn = _outConn.(net.Conn)
|
||||
}
|
||||
outConn, err = s.outPool.Get()
|
||||
if err != nil {
|
||||
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentCompress {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
//ask parent for connect to target address
|
||||
if *s.cfg.ParentServiceType == "http" {
|
||||
//http parent
|
||||
fmt.Fprintf(outConn, "CONNECT %s HTTP/1.1\r\n", address)
|
||||
reply := make([]byte, 100)
|
||||
n, err = outConn.Read(reply)
|
||||
pb := new(bytes.Buffer)
|
||||
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
|
||||
//Proxy-Authorization:\r\n
|
||||
u := ""
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
if len(a) != 2 {
|
||||
err = fmt.Errorf("parent auth data format error")
|
||||
return
|
||||
}
|
||||
u = fmt.Sprintf("%s:%s", a[0], a[1])
|
||||
} else {
|
||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||
u = fmt.Sprintf("%s:%s", auth.User, auth.Password)
|
||||
}
|
||||
}
|
||||
if u != "" {
|
||||
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization:Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
|
||||
}
|
||||
pb.Write([]byte("\r\n"))
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(pb.Bytes())
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
reply := make([]byte, 1024)
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Read(reply)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -215,53 +294,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
//log.Printf("reply: %s", string(reply[:n]))
|
||||
} else {
|
||||
log.Printf("connect %s", address)
|
||||
//socks parent
|
||||
//send auth type
|
||||
_, err = outConn.Write([]byte{0x05, 0x01, 0x00})
|
||||
if err != nil {
|
||||
log.Printf("write method to %s fail, err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
//socks client
|
||||
var clientConn *socks.ClientConn
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
if len(a) != 2 {
|
||||
err = fmt.Errorf("parent auth data format error")
|
||||
return
|
||||
}
|
||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, header)
|
||||
} else {
|
||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, header)
|
||||
} else {
|
||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, header)
|
||||
}
|
||||
}
|
||||
if err = clientConn.Handshake(); err != nil {
|
||||
return
|
||||
}
|
||||
//read reply
|
||||
reply := make([]byte, 512)
|
||||
n, err = outConn.Read(reply)
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//log.Printf("method reply %v", reply[:n])
|
||||
|
||||
//build request
|
||||
buf, err = s.buildRequest(address)
|
||||
if err != nil {
|
||||
log.Printf("build request to %s fail , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//send address request
|
||||
_, err = outConn.Write(buf)
|
||||
if err != nil {
|
||||
log.Printf("write request to %s fail, err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//read reply
|
||||
reply = make([]byte, 512)
|
||||
n, err = outConn.Read(reply)
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
|
||||
//log.Printf("request reply %v", reply[:n])
|
||||
}
|
||||
//forward client data to target,if necessary.
|
||||
if len(forwardBytes) > 0 {
|
||||
@ -272,10 +323,43 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
||||
log.Printf("conn %s - %s released", inAddr, outAddr)
|
||||
s.userConns.Remove(inAddr)
|
||||
})
|
||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitBasicAuth() (err error) {
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||
} else {
|
||||
s.basicAuth = utils.NewBasicAuth(nil)
|
||||
}
|
||||
if *s.cfg.AuthURL != "" {
|
||||
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
}
|
||||
if *s.cfg.AuthFile != "" {
|
||||
var n = 0
|
||||
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
|
||||
}
|
||||
if len(*s.cfg.Auth) > 0 {
|
||||
n := s.basicAuth.Add(*s.cfg.Auth)
|
||||
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *SPS) IsBasicAuth() bool {
|
||||
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||
}
|
||||
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
||||
host, portStr, err := net.SplitHostPort(address)
|
||||
if err != nil {
|
||||
|
||||
@ -14,41 +14,71 @@ import (
|
||||
)
|
||||
|
||||
type TCP struct {
|
||||
outPool utils.OutPool
|
||||
cfg TCPArgs
|
||||
outPool utils.OutConn
|
||||
cfg TCPArgs
|
||||
sc *utils.ServerChannel
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewTCP() Service {
|
||||
return &TCP{
|
||||
outPool: utils.OutPool{},
|
||||
cfg: TCPArgs{},
|
||||
outPool: utils.OutConn{},
|
||||
cfg: TCPArgs{},
|
||||
isStop: false,
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
func (s *TCP) CheckArgs() {
|
||||
func (s *TCP) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent == "" {
|
||||
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
||||
err = fmt.Errorf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "" {
|
||||
log.Fatalf("parent type unkown,use -T <tls|tcp|kcp|udp>")
|
||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp|udp>")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *TCP) InitService() {
|
||||
func (s *TCP) InitService() (err error) {
|
||||
s.InitOutConnPool()
|
||||
return
|
||||
}
|
||||
func (s *TCP) StopService() {
|
||||
if s.outPool.Pool != nil {
|
||||
s.outPool.Pool.ReleaseAll()
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop tcp service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service tcp stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
if s.sc.Listener != nil && *s.sc.Listener != nil {
|
||||
(*s.sc.Listener).Close()
|
||||
}
|
||||
if s.sc.UDPListener != nil {
|
||||
(*s.sc.UDPListener).Close()
|
||||
}
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
}
|
||||
func (s *TCP) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(TCPArgs)
|
||||
s.CheckArgs()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
s.InitService()
|
||||
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
@ -56,14 +86,15 @@ func (s *TCP) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
|
||||
s.sc = &sc
|
||||
return
|
||||
}
|
||||
|
||||
@ -96,11 +127,7 @@ func (s *TCP) callback(inConn net.Conn) {
|
||||
}
|
||||
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
||||
var outConn net.Conn
|
||||
var _outConn interface{}
|
||||
_outConn, err = s.outPool.Pool.Get()
|
||||
if err == nil {
|
||||
outConn = _outConn.(net.Conn)
|
||||
}
|
||||
outConn, err = s.outPool.Get()
|
||||
if err != nil {
|
||||
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -112,13 +139,22 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
||||
//outLocalAddr := outConn.LocalAddr().String()
|
||||
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
||||
log.Printf("conn %s - %s released", inAddr, outAddr)
|
||||
s.userConns.Remove(inAddr)
|
||||
})
|
||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
return
|
||||
}
|
||||
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
|
||||
log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
|
||||
for {
|
||||
if s.isStop {
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn))
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
//log.Printf("connection %s released", srcAddr)
|
||||
@ -168,16 +204,13 @@ func (s *TCP) InitOutConnPool() {
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
||||
//parent string, timeout int, InitialCap int, MaxCap int
|
||||
s.outPool = utils.NewOutPool(
|
||||
s.outPool = utils.NewOutConn(
|
||||
*s.cfg.CheckParentInterval,
|
||||
*s.cfg.ParentType,
|
||||
*s.cfg.KCPMethod,
|
||||
*s.cfg.KCPKey,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.KCP,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
|
||||
*s.cfg.Parent,
|
||||
*s.cfg.Timeout,
|
||||
*s.cfg.PoolSize,
|
||||
*s.cfg.PoolSize*2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"snail007/proxy/utils"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
)
|
||||
|
||||
type ServerConn struct {
|
||||
@ -17,8 +20,7 @@ type TunnelBridge struct {
|
||||
cfg TunnelBridgeArgs
|
||||
serverConns utils.ConcurrentMap
|
||||
clientControlConns utils.ConcurrentMap
|
||||
// cmServer utils.ConnManager
|
||||
// cmClient utils.ConnManager
|
||||
isStop bool
|
||||
}
|
||||
|
||||
func NewTunnelBridge() Service {
|
||||
@ -26,213 +28,51 @@ func NewTunnelBridge() Service {
|
||||
cfg: TunnelBridgeArgs{},
|
||||
serverConns: utils.NewConcurrentMap(),
|
||||
clientControlConns: utils.NewConcurrentMap(),
|
||||
// cmServer: utils.NewConnManager(),
|
||||
// cmClient: utils.NewConnManager(),
|
||||
isStop: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TunnelBridge) InitService() {
|
||||
|
||||
func (s *TunnelBridge) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
func (s *TunnelBridge) CheckArgs() {
|
||||
func (s *TunnelBridge) CheckArgs() (err error) {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
err = fmt.Errorf("cert and key file required")
|
||||
return
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
return
|
||||
}
|
||||
func (s *TunnelBridge) StopService() {
|
||||
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop tbridge service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service tbridge stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
for _, sess := range s.clientControlConns.Items() {
|
||||
(*sess.(*net.Conn)).Close()
|
||||
}
|
||||
for _, sess := range s.serverConns.Items() {
|
||||
(*sess.(ServerConn).Conn).Close()
|
||||
}
|
||||
}
|
||||
func (s *TunnelBridge) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(TunnelBridgeArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) {
|
||||
//log.Printf("connection from %s ", inConn.RemoteAddr())
|
||||
|
||||
reader := bufio.NewReader(inConn)
|
||||
var err error
|
||||
var connType uint8
|
||||
err = utils.ReadPacket(reader, &connType)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
case CONN_SERVER:
|
||||
var key, ID, clientLocalAddr, serverID string
|
||||
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
|
||||
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
|
||||
|
||||
//addr := clientLocalAddr + "@" + ID
|
||||
s.serverConns.Set(ID, ServerConn{
|
||||
Conn: &inConn,
|
||||
})
|
||||
for {
|
||||
item, ok := s.clientControlConns.Get(key)
|
||||
if !ok {
|
||||
log.Printf("client %s control conn not exists", key)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
(*item.(*net.Conn)).SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||
_, err := (*item.(*net.Conn)).Write(packet)
|
||||
(*item.(*net.Conn)).SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
} else {
|
||||
// s.cmServer.Add(serverID, ID, &inConn)
|
||||
break
|
||||
}
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
var key, ID, serverID string
|
||||
err = utils.ReadPacketData(reader, &key, &ID, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
|
||||
|
||||
serverConnItem, ok := s.serverConns.Get(ID)
|
||||
if !ok {
|
||||
inConn.Close()
|
||||
log.Printf("server conn %s exists", ID)
|
||||
return
|
||||
}
|
||||
serverConn := serverConnItem.(ServerConn).Conn
|
||||
utils.IoBind(*serverConn, inConn, func(err interface{}) {
|
||||
s.serverConns.Remove(ID)
|
||||
// s.cmClient.RemoveOne(key, ID)
|
||||
// s.cmServer.RemoveOne(serverID, ID)
|
||||
log.Printf("conn %s released", ID)
|
||||
})
|
||||
// s.cmClient.Add(key, ID, &inConn)
|
||||
log.Printf("conn %s created", ID)
|
||||
|
||||
case CONN_CLIENT_CONTROL:
|
||||
var key string
|
||||
err = utils.ReadPacketData(reader, &key)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("client control connection, key: %s", key)
|
||||
if s.clientControlConns.Has(key) {
|
||||
item, _ := s.clientControlConns.Get(key)
|
||||
(*item.(*net.Conn)).Close()
|
||||
}
|
||||
s.clientControlConns.Set(key, &inConn)
|
||||
log.Printf("set client %s control conn", key)
|
||||
|
||||
// case CONN_SERVER_HEARBEAT:
|
||||
// var serverID string
|
||||
// err = utils.ReadPacketData(reader, &serverID)
|
||||
// if err != nil {
|
||||
// log.Printf("read error,ERR:%s", err)
|
||||
// return
|
||||
// }
|
||||
// log.Printf("server heartbeat connection, id: %s", serverID)
|
||||
// writeDie := make(chan bool)
|
||||
// readDie := make(chan bool)
|
||||
// go func() {
|
||||
// for {
|
||||
// inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||
// _, err = inConn.Write([]byte{0x00})
|
||||
// inConn.SetWriteDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("server heartbeat connection write err %s", err)
|
||||
// break
|
||||
// }
|
||||
// time.Sleep(time.Second * 3)
|
||||
// }
|
||||
// close(writeDie)
|
||||
// }()
|
||||
// go func() {
|
||||
// for {
|
||||
// signal := make([]byte, 1)
|
||||
// inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
|
||||
// _, err := inConn.Read(signal)
|
||||
// inConn.SetReadDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("server heartbeat connection read err: %s", err)
|
||||
// break
|
||||
// } else {
|
||||
// // log.Printf("heartbeat from server ,id:%s", serverID)
|
||||
// }
|
||||
// }
|
||||
// close(readDie)
|
||||
// }()
|
||||
// select {
|
||||
// case <-readDie:
|
||||
// case <-writeDie:
|
||||
// }
|
||||
// utils.CloseConn(&inConn)
|
||||
// s.cmServer.Remove(serverID)
|
||||
// log.Printf("server heartbeat conn %s released", serverID)
|
||||
// case CONN_CLIENT_HEARBEAT:
|
||||
// var clientID string
|
||||
// err = utils.ReadPacketData(reader, &clientID)
|
||||
// if err != nil {
|
||||
// log.Printf("read error,ERR:%s", err)
|
||||
// return
|
||||
// }
|
||||
// log.Printf("client heartbeat connection, id: %s", clientID)
|
||||
// writeDie := make(chan bool)
|
||||
// readDie := make(chan bool)
|
||||
// go func() {
|
||||
// for {
|
||||
// inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||
// _, err = inConn.Write([]byte{0x00})
|
||||
// inConn.SetWriteDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("client heartbeat connection write err %s", err)
|
||||
// break
|
||||
// }
|
||||
// time.Sleep(time.Second * 3)
|
||||
// }
|
||||
// close(writeDie)
|
||||
// }()
|
||||
// go func() {
|
||||
// for {
|
||||
// signal := make([]byte, 1)
|
||||
// inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
|
||||
// _, err := inConn.Read(signal)
|
||||
// inConn.SetReadDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("client control connection read err: %s", err)
|
||||
// break
|
||||
// } else {
|
||||
// // log.Printf("heartbeat from client ,id:%s", clientID)
|
||||
// }
|
||||
// }
|
||||
// close(readDie)
|
||||
// }()
|
||||
// select {
|
||||
// case <-readDie:
|
||||
// case <-writeDie:
|
||||
// }
|
||||
// utils.CloseConn(&inConn)
|
||||
// s.cmClient.Remove(clientID)
|
||||
// if s.clientControlConns.Has(clientID) {
|
||||
// item, _ := s.clientControlConns.Get(clientID)
|
||||
// (*item.(*net.Conn)).Close()
|
||||
// }
|
||||
// s.clientControlConns.Remove(clientID)
|
||||
// log.Printf("client heartbeat conn %s released", clientID)
|
||||
}
|
||||
})
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -242,3 +82,111 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
|
||||
func (s *TunnelBridge) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
var err error
|
||||
//log.Printf("connection from %s ", inConn.RemoteAddr())
|
||||
sess, err := smux.Server(inConn, &smux.Config{
|
||||
KeepAliveInterval: 10 * time.Second,
|
||||
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
|
||||
MaxFrameSize: 4096,
|
||||
MaxReceiveBuffer: 4194304,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("new mux server conn error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
inConn, err = sess.AcceptStream()
|
||||
if err != nil {
|
||||
log.Printf("mux server conn accept error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
var buf = make([]byte, 1024)
|
||||
n, _ := inConn.Read(buf)
|
||||
reader := bytes.NewReader(buf[:n])
|
||||
//reader := bufio.NewReader(inConn)
|
||||
|
||||
var connType uint8
|
||||
err = utils.ReadPacket(reader, &connType)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
case CONN_SERVER:
|
||||
var key, ID, clientLocalAddr, serverID string
|
||||
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
|
||||
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
|
||||
|
||||
//addr := clientLocalAddr + "@" + ID
|
||||
s.serverConns.Set(ID, ServerConn{
|
||||
Conn: &inConn,
|
||||
})
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
item, ok := s.clientControlConns.Get(key)
|
||||
if !ok {
|
||||
log.Printf("client %s control conn not exists", key)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
(*item.(*net.Conn)).SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||
_, err := (*item.(*net.Conn)).Write(packet)
|
||||
(*item.(*net.Conn)).SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
} else {
|
||||
// s.cmServer.Add(serverID, ID, &inConn)
|
||||
break
|
||||
}
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
var key, ID, serverID string
|
||||
err = utils.ReadPacketData(reader, &key, &ID, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
|
||||
|
||||
serverConnItem, ok := s.serverConns.Get(ID)
|
||||
if !ok {
|
||||
inConn.Close()
|
||||
log.Printf("server conn %s exists", ID)
|
||||
return
|
||||
}
|
||||
serverConn := serverConnItem.(ServerConn).Conn
|
||||
utils.IoBind(*serverConn, inConn, func(err interface{}) {
|
||||
s.serverConns.Remove(ID)
|
||||
// s.cmClient.RemoveOne(key, ID)
|
||||
// s.cmServer.RemoveOne(serverID, ID)
|
||||
log.Printf("conn %s released", ID)
|
||||
})
|
||||
// s.cmClient.Add(key, ID, &inConn)
|
||||
log.Printf("conn %s created", ID)
|
||||
|
||||
case CONN_CLIENT_CONTROL:
|
||||
var key string
|
||||
err = utils.ReadPacketData(reader, &key)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("client control connection, key: %s", key)
|
||||
if s.clientControlConns.Has(key) {
|
||||
item, _ := s.clientControlConns.Get(key)
|
||||
(*item.(*net.Conn)).Close()
|
||||
}
|
||||
s.clientControlConns.Set(key, &inConn)
|
||||
log.Printf("set client %s control conn", key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,106 +8,74 @@ import (
|
||||
"net"
|
||||
"snail007/proxy/utils"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
)
|
||||
|
||||
type TunnelClient struct {
|
||||
cfg TunnelClientArgs
|
||||
// cm utils.ConnManager
|
||||
ctrlConn net.Conn
|
||||
cfg TunnelClientArgs
|
||||
ctrlConn net.Conn
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewTunnelClient() Service {
|
||||
return &TunnelClient{
|
||||
cfg: TunnelClientArgs{},
|
||||
// cm: utils.NewConnManager(),
|
||||
cfg: TunnelClientArgs{},
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
isStop: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TunnelClient) InitService() {
|
||||
// s.InitHeartbeatDeamon()
|
||||
func (s *TunnelClient) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// func (s *TunnelClient) InitHeartbeatDeamon() {
|
||||
// log.Printf("heartbeat started")
|
||||
// go func() {
|
||||
// var heartbeatConn net.Conn
|
||||
// var ID = *s.cfg.Key
|
||||
// for {
|
||||
|
||||
// //close all connection
|
||||
// s.cm.RemoveAll()
|
||||
// if s.ctrlConn != nil {
|
||||
// s.ctrlConn.Close()
|
||||
// }
|
||||
// utils.CloseConn(&heartbeatConn)
|
||||
// heartbeatConn, err := s.GetInConn(CONN_CLIENT_HEARBEAT, ID)
|
||||
// if err != nil {
|
||||
// log.Printf("heartbeat connection err: %s, retrying...", err)
|
||||
// time.Sleep(time.Second * 3)
|
||||
// utils.CloseConn(&heartbeatConn)
|
||||
// continue
|
||||
// }
|
||||
// log.Printf("heartbeat connection created,id:%s", ID)
|
||||
// writeDie := make(chan bool)
|
||||
// readDie := make(chan bool)
|
||||
// go func() {
|
||||
// for {
|
||||
// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||
// _, err = heartbeatConn.Write([]byte{0x00})
|
||||
// heartbeatConn.SetWriteDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("heartbeat connection write err %s", err)
|
||||
// break
|
||||
// }
|
||||
// time.Sleep(time.Second * 3)
|
||||
// }
|
||||
// close(writeDie)
|
||||
// }()
|
||||
// go func() {
|
||||
// for {
|
||||
// signal := make([]byte, 1)
|
||||
// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
|
||||
// _, err := heartbeatConn.Read(signal)
|
||||
// heartbeatConn.SetReadDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("heartbeat connection read err: %s", err)
|
||||
// break
|
||||
// } else {
|
||||
// //log.Printf("heartbeat from bridge")
|
||||
// }
|
||||
// }
|
||||
// close(readDie)
|
||||
// }()
|
||||
// select {
|
||||
// case <-readDie:
|
||||
// case <-writeDie:
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// }
|
||||
func (s *TunnelClient) CheckArgs() {
|
||||
func (s *TunnelClient) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
} else {
|
||||
log.Fatalf("parent required")
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
}
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
err = fmt.Errorf("cert and key file required")
|
||||
return
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
return
|
||||
}
|
||||
func (s *TunnelClient) StopService() {
|
||||
// s.cm.RemoveAll()
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop tclient service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service tclient stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
if s.ctrlConn != nil {
|
||||
s.ctrlConn.Close()
|
||||
}
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
}
|
||||
func (s *TunnelClient) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(TunnelClientArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on tunnel client mode")
|
||||
|
||||
for {
|
||||
//close all conn
|
||||
// s.cm.Remove(*s.cfg.Key)
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if s.ctrlConn != nil {
|
||||
s.ctrlConn.Close()
|
||||
}
|
||||
@ -122,6 +90,9 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
|
||||
continue
|
||||
}
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
var ID, clientLocalAddr, serverID string
|
||||
err = utils.ReadPacketData(s.ctrlConn, &ID, &clientLocalAddr, &serverID)
|
||||
if err != nil {
|
||||
@ -161,9 +132,26 @@ func (s *TunnelClient) GetInConn(typ uint8, data ...string) (outConn net.Conn, e
|
||||
}
|
||||
func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
c, e := smux.Client(conn, &smux.Config{
|
||||
KeepAliveInterval: 10 * time.Second,
|
||||
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
|
||||
MaxFrameSize: 4096,
|
||||
MaxReceiveBuffer: 4194304,
|
||||
})
|
||||
if e != nil {
|
||||
log.Printf("new mux client conn error,ERR:%s", e)
|
||||
err = e
|
||||
return
|
||||
}
|
||||
conn, e = c.OpenStream()
|
||||
if e != nil {
|
||||
log.Printf("mux client conn open stream error,ERR:%s", e)
|
||||
err = e
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -172,6 +160,12 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||
var err error
|
||||
// for {
|
||||
for {
|
||||
if s.isStop {
|
||||
if inConn != nil {
|
||||
inConn.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
// s.cm.RemoveOne(*s.cfg.Key, ID)
|
||||
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
|
||||
if err != nil {
|
||||
@ -187,6 +181,9 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||
log.Printf("conn %s created", ID)
|
||||
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
log.Printf("connection %s released", ID)
|
||||
@ -243,6 +240,9 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
|
||||
var inConn, outConn net.Conn
|
||||
var err error
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
@ -256,6 +256,9 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
|
||||
|
||||
i := 0
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
i++
|
||||
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
|
||||
if err == nil || i == 3 {
|
||||
@ -274,10 +277,14 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
|
||||
log.Printf("build connection error, err: %s", err)
|
||||
return
|
||||
}
|
||||
inAddr := inConn.RemoteAddr().String()
|
||||
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||
log.Printf("conn %s released", ID)
|
||||
// s.cm.RemoveOne(*s.cfg.Key, ID)
|
||||
s.userConns.Remove(inAddr)
|
||||
})
|
||||
// s.cm.Add(*s.cfg.Key, ID, &inConn)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
log.Printf("conn %s created", ID)
|
||||
}
|
||||
|
||||
@ -11,20 +11,24 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
)
|
||||
|
||||
type TunnelServer struct {
|
||||
cfg TunnelServerArgs
|
||||
udpChn chan UDPItem
|
||||
sc utils.ServerChannel
|
||||
cfg TunnelServerArgs
|
||||
udpChn chan UDPItem
|
||||
sc utils.ServerChannel
|
||||
isStop bool
|
||||
udpConn *net.Conn
|
||||
userConns utils.ConcurrentMap
|
||||
}
|
||||
|
||||
type TunnelServerManager struct {
|
||||
cfg TunnelServerArgs
|
||||
udpChn chan UDPItem
|
||||
sc utils.ServerChannel
|
||||
serverID string
|
||||
// cm utils.ConnManager
|
||||
servers []*Service
|
||||
}
|
||||
|
||||
func NewTunnelServerManager() Service {
|
||||
@ -32,19 +36,24 @@ func NewTunnelServerManager() Service {
|
||||
cfg: TunnelServerArgs{},
|
||||
udpChn: make(chan UDPItem, 50000),
|
||||
serverID: utils.Uniqueid(),
|
||||
// cm: utils.NewConnManager(),
|
||||
servers: []*Service{},
|
||||
}
|
||||
}
|
||||
func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(TunnelServerArgs)
|
||||
s.CheckArgs()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
} else {
|
||||
log.Fatalf("parent required")
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
}
|
||||
|
||||
s.InitService()
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("server id: %s", s.serverID)
|
||||
//log.Printf("route:%v", *s.cfg.Route)
|
||||
@ -84,6 +93,7 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.servers = append(s.servers, &server)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -91,72 +101,22 @@ func (s *TunnelServerManager) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
func (s *TunnelServerManager) StopService() {
|
||||
// s.cm.RemoveAll()
|
||||
}
|
||||
func (s *TunnelServerManager) CheckArgs() {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
for _, server := range s.servers {
|
||||
(*server).Clean()
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
}
|
||||
func (s *TunnelServerManager) InitService() {
|
||||
// s.InitHeartbeatDeamon()
|
||||
func (s *TunnelServerManager) CheckArgs() (err error) {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
err = fmt.Errorf("cert and key file required")
|
||||
return
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
return
|
||||
}
|
||||
func (s *TunnelServerManager) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// func (s *TunnelServerManager) InitHeartbeatDeamon() {
|
||||
// log.Printf("heartbeat started")
|
||||
// go func() {
|
||||
// var heartbeatConn net.Conn
|
||||
// var ID string
|
||||
// for {
|
||||
// //close all connection
|
||||
// s.cm.Remove(ID)
|
||||
// utils.CloseConn(&heartbeatConn)
|
||||
// heartbeatConn, ID, err := s.GetOutConn(CONN_SERVER_HEARBEAT)
|
||||
// if err != nil {
|
||||
// log.Printf("heartbeat connection err: %s, retrying...", err)
|
||||
// time.Sleep(time.Second * 3)
|
||||
// utils.CloseConn(&heartbeatConn)
|
||||
// continue
|
||||
// }
|
||||
// log.Printf("heartbeat connection created,id:%s", ID)
|
||||
// writeDie := make(chan bool)
|
||||
// readDie := make(chan bool)
|
||||
// go func() {
|
||||
// for {
|
||||
// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||
// _, err = heartbeatConn.Write([]byte{0x00})
|
||||
// heartbeatConn.SetWriteDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("heartbeat connection write err %s", err)
|
||||
// break
|
||||
// }
|
||||
// time.Sleep(time.Second * 3)
|
||||
// }
|
||||
// close(writeDie)
|
||||
// }()
|
||||
// go func() {
|
||||
// for {
|
||||
// signal := make([]byte, 1)
|
||||
// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
|
||||
// _, err := heartbeatConn.Read(signal)
|
||||
// heartbeatConn.SetReadDeadline(time.Time{})
|
||||
// if err != nil {
|
||||
// log.Printf("heartbeat connection read err: %s", err)
|
||||
// break
|
||||
// } else {
|
||||
// // log.Printf("heartbeat from bridge")
|
||||
// }
|
||||
// }
|
||||
// close(readDie)
|
||||
// }()
|
||||
// select {
|
||||
// case <-readDie:
|
||||
// case <-writeDie:
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// }
|
||||
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
|
||||
outConn, err = s.GetConn()
|
||||
if err != nil {
|
||||
@ -174,7 +134,7 @@ func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string
|
||||
}
|
||||
func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
@ -182,8 +142,10 @@ func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
|
||||
}
|
||||
func NewTunnelServer() Service {
|
||||
return &TunnelServer{
|
||||
cfg: TunnelServerArgs{},
|
||||
udpChn: make(chan UDPItem, 50000),
|
||||
cfg: TunnelServerArgs{},
|
||||
udpChn: make(chan UDPItem, 50000),
|
||||
isStop: false,
|
||||
userConns: utils.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,19 +155,50 @@ type UDPItem struct {
|
||||
srcAddr *net.UDPAddr
|
||||
}
|
||||
|
||||
func (s *TunnelServer) InitService() {
|
||||
s.UDPConnDeamon()
|
||||
}
|
||||
func (s *TunnelServer) CheckArgs() {
|
||||
if *s.cfg.Remote == "" {
|
||||
log.Fatalf("remote required")
|
||||
func (s *TunnelServer) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop server service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service server stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
|
||||
if s.sc.Listener != nil {
|
||||
(*s.sc.Listener).Close()
|
||||
}
|
||||
if s.sc.UDPListener != nil {
|
||||
(*s.sc.UDPListener).Close()
|
||||
}
|
||||
if s.udpConn != nil {
|
||||
(*s.udpConn).Close()
|
||||
}
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
}
|
||||
func (s *TunnelServer) InitService() (err error) {
|
||||
s.UDPConnDeamon()
|
||||
return
|
||||
}
|
||||
func (s *TunnelServer) CheckArgs() (err error) {
|
||||
if *s.cfg.Remote == "" {
|
||||
err = fmt.Errorf("remote required")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(TunnelServerArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
s.sc = utils.NewServerChannel(host, p)
|
||||
@ -231,6 +224,9 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
var outConn net.Conn
|
||||
var ID string
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
outConn, ID, err = s.GetOutConn(CONN_SERVER)
|
||||
if err != nil {
|
||||
utils.CloseConn(&outConn)
|
||||
@ -241,12 +237,15 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
inAddr := inConn.RemoteAddr().String()
|
||||
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||
// s.cfg.Mgr.cm.RemoveOne(s.cfg.Mgr.serverID, ID)
|
||||
s.userConns.Remove(inAddr)
|
||||
log.Printf("%s conn %s released", *s.cfg.Key, ID)
|
||||
})
|
||||
//add conn
|
||||
// s.cfg.Mgr.cm.Add(s.cfg.Mgr.serverID, ID, &inConn)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
log.Printf("%s conn %s created", *s.cfg.Key, ID)
|
||||
})
|
||||
if err != nil {
|
||||
@ -280,9 +279,26 @@ func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err e
|
||||
}
|
||||
func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
c, e := smux.Client(conn, &smux.Config{
|
||||
KeepAliveInterval: 10 * time.Second,
|
||||
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
|
||||
MaxFrameSize: 4096,
|
||||
MaxReceiveBuffer: 4194304,
|
||||
})
|
||||
if e != nil {
|
||||
log.Printf("new mux client conn error,ERR:%s", e)
|
||||
err = e
|
||||
return
|
||||
}
|
||||
conn, e = c.OpenStream()
|
||||
if e != nil {
|
||||
log.Printf("mux client conn open stream error,ERR:%s", e)
|
||||
err = e
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -299,10 +315,19 @@ func (s *TunnelServer) UDPConnDeamon() {
|
||||
// var cmdChn = make(chan bool, 1000)
|
||||
var err error
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
item := <-s.udpChn
|
||||
RETRY:
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
if outConn == nil {
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
outConn, ID, err = s.GetOutConn(CONN_SERVER)
|
||||
if err != nil {
|
||||
// cmdChn <- true
|
||||
@ -313,11 +338,14 @@ func (s *TunnelServer) UDPConnDeamon() {
|
||||
continue
|
||||
} else {
|
||||
go func(outConn net.Conn, ID string) {
|
||||
go func() {
|
||||
// <-cmdChn
|
||||
// outConn.Close()
|
||||
}()
|
||||
if s.udpConn != nil {
|
||||
(*s.udpConn).Close()
|
||||
}
|
||||
s.udpConn = &outConn
|
||||
for {
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
log.Printf("UDP deamon connection %s exited", ID)
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
"snail007/proxy/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -16,44 +17,68 @@ import (
|
||||
|
||||
type UDP struct {
|
||||
p utils.ConcurrentMap
|
||||
outPool utils.OutPool
|
||||
outPool utils.OutConn
|
||||
cfg UDPArgs
|
||||
sc *utils.ServerChannel
|
||||
isStop bool
|
||||
}
|
||||
|
||||
func NewUDP() Service {
|
||||
return &UDP{
|
||||
outPool: utils.OutPool{},
|
||||
outPool: utils.OutConn{},
|
||||
p: utils.NewConcurrentMap(),
|
||||
isStop: false,
|
||||
}
|
||||
}
|
||||
func (s *UDP) CheckArgs() {
|
||||
func (s *UDP) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent == "" {
|
||||
log.Fatalf("parent required for udp %s", *s.cfg.Local)
|
||||
err = fmt.Errorf("parent required for udp %s", *s.cfg.Local)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "" {
|
||||
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp>")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *UDP) InitService() {
|
||||
func (s *UDP) InitService() (err error) {
|
||||
if *s.cfg.ParentType != TYPE_UDP {
|
||||
s.InitOutConnPool()
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *UDP) StopService() {
|
||||
if s.outPool.Pool != nil {
|
||||
s.outPool.Pool.ReleaseAll()
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop udp service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service udp stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
if s.sc.Listener != nil && *s.sc.Listener != nil {
|
||||
(*s.sc.Listener).Close()
|
||||
}
|
||||
if s.sc.UDPListener != nil {
|
||||
(*s.sc.UDPListener).Close()
|
||||
}
|
||||
}
|
||||
func (s *UDP) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(UDPArgs)
|
||||
s.CheckArgs()
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
s.InitService()
|
||||
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
@ -94,7 +119,7 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
|
||||
isNew = !s.p.Has(connKey)
|
||||
var _conn interface{}
|
||||
if isNew {
|
||||
_conn, err = s.outPool.Pool.Get()
|
||||
_conn, err = s.outPool.Get()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
@ -108,7 +133,7 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
|
||||
func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
|
||||
numLocal := crc32.ChecksumIEEE([]byte(localAddr.String()))
|
||||
numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String()))
|
||||
mod := uint32(*s.cfg.PoolSize)
|
||||
mod := uint32(10)
|
||||
if mod == 0 {
|
||||
mod = 10
|
||||
}
|
||||
@ -127,6 +152,10 @@ func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro
|
||||
}()
|
||||
log.Printf("conn %d created , local: %s", connKey, srcAddr.String())
|
||||
for {
|
||||
if s.isStop {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn))
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
//log.Printf("connection %d released", connKey)
|
||||
@ -205,15 +234,13 @@ func (s *UDP) InitOutConnPool() {
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP {
|
||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
||||
//parent string, timeout int, InitialCap int, MaxCap int
|
||||
s.outPool = utils.NewOutPool(
|
||||
s.outPool = utils.NewOutConn(
|
||||
*s.cfg.CheckParentInterval,
|
||||
*s.cfg.ParentType,
|
||||
"", "",
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
kcpcfg.KCPConfigArgs{},
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
|
||||
*s.cfg.Parent,
|
||||
*s.cfg.Timeout,
|
||||
*s.cfg.PoolSize,
|
||||
*s.cfg.PoolSize*2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
95
utils/conncrypt/conncrypt.go
Normal file
@ -0,0 +1,95 @@
|
||||
package conncrypt
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
//Confg defaults
|
||||
const DefaultIterations = 2048
|
||||
const DefaultKeySize = 32 //256bits
|
||||
var DefaultHashFunc = sha256.New
|
||||
var DefaultSalt = []byte(`
|
||||
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
||||
Ao<:>SOd,6acYKY_ec+(x"R";\'4&fTAVu92GVA-wxBptOTM^2,iP5%)wnhW
|
||||
hwk=]Snsgymt!3gbP2pe=J//}1a?lp9ej=&TB!C_V(cT2?z8wyoL_-13fd[]
|
||||
`) //salt must be predefined in order to derive the same key
|
||||
|
||||
//Config stores the PBKDF2 key generation parameters
|
||||
type Config struct {
|
||||
Password string
|
||||
Salt []byte
|
||||
Iterations int
|
||||
KeySize int
|
||||
HashFunc func() hash.Hash
|
||||
}
|
||||
|
||||
//New creates an AES encrypted net.Conn by generating
|
||||
//a key using PBKDF2 with the provided configuration
|
||||
func New(conn net.Conn, c *Config) net.Conn {
|
||||
//set defaults
|
||||
if len(c.Salt) == 0 {
|
||||
c.Salt = DefaultSalt
|
||||
}
|
||||
if c.Iterations == 0 {
|
||||
c.Iterations = DefaultIterations
|
||||
}
|
||||
if c.KeySize != 16 && c.KeySize != 24 && c.KeySize != 32 {
|
||||
c.KeySize = DefaultKeySize
|
||||
}
|
||||
if c.HashFunc == nil {
|
||||
c.HashFunc = DefaultHashFunc
|
||||
}
|
||||
|
||||
//generate key
|
||||
key := pbkdf2.Key([]byte(c.Password), c.Salt, c.Iterations, c.KeySize, c.HashFunc)
|
||||
|
||||
// could use scrypt, but it's a bit slow...
|
||||
// dk, err := scrypt.Key([]byte(c.Password), c.Salt, 16384, 8, 1, 32)
|
||||
|
||||
//key will be always be the correct size so this will never error
|
||||
conn, _ = NewFromKey(conn, key)
|
||||
return conn
|
||||
}
|
||||
|
||||
//NewFromKey creates an AES encrypted net.Conn using the provided key
|
||||
func NewFromKey(conn net.Conn, key []byte) (net.Conn, error) {
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//hash(key) -> read IV
|
||||
riv := DefaultHashFunc().Sum(key)
|
||||
rstream := cipher.NewCFBDecrypter(block, riv[:aes.BlockSize])
|
||||
reader := &cipher.StreamReader{S: rstream, R: conn}
|
||||
//hash(read IV) -> write IV
|
||||
wiv := DefaultHashFunc().Sum(riv)
|
||||
wstream := cipher.NewCFBEncrypter(block, wiv[:aes.BlockSize])
|
||||
writer := &cipher.StreamWriter{S: wstream, W: conn}
|
||||
|
||||
return &cryptoConn{
|
||||
Conn: conn,
|
||||
r: reader,
|
||||
w: writer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type cryptoConn struct {
|
||||
net.Conn
|
||||
r io.Reader
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
//replace read and write methods
|
||||
func (c *cryptoConn) Read(p []byte) (int, error) {
|
||||
return c.r.Read(p)
|
||||
}
|
||||
func (c *cryptoConn) Write(p []byte) (int, error) {
|
||||
return c.w.Write(p)
|
||||
}
|
||||
@ -18,6 +18,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
@ -85,14 +86,14 @@ func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
func TlsConnectHost(host string, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) {
|
||||
func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
|
||||
h := strings.Split(host, ":")
|
||||
port, _ := strconv.Atoi(h[1])
|
||||
return TlsConnect(h[0], port, timeout, certBytes, keyBytes)
|
||||
return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes)
|
||||
}
|
||||
|
||||
func TlsConnect(host string, port, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) {
|
||||
conf, err := getRequestTlsConfig(certBytes, keyBytes)
|
||||
func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
|
||||
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -102,8 +103,24 @@ func TlsConnect(host string, port, timeout int, certBytes, keyBytes []byte) (con
|
||||
}
|
||||
return *tls.Client(_conn, conf), err
|
||||
}
|
||||
func getRequestTlsConfig(certBytes, keyBytes []byte) (conf *tls.Config, err error) {
|
||||
block, _ := pem.Decode(certBytes)
|
||||
func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
|
||||
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverCertPool := x509.NewCertPool()
|
||||
caBytes := certBytes
|
||||
if caCertBytes != nil {
|
||||
caBytes = caCertBytes
|
||||
|
||||
}
|
||||
ok := serverCertPool.AppendCertsFromPEM(caBytes)
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
block, _ := pem.Decode(caBytes)
|
||||
if block == nil {
|
||||
panic("failed to parse certificate PEM")
|
||||
}
|
||||
@ -111,34 +128,24 @@ func getRequestTlsConfig(certBytes, keyBytes []byte) (conf *tls.Config, err erro
|
||||
if x509Cert == nil {
|
||||
panic("failed to parse block")
|
||||
}
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverCertPool := x509.NewCertPool()
|
||||
ok := serverCertPool.AppendCertsFromPEM(certBytes)
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
conf = &tls.Config{
|
||||
RootCAs: serverCertPool,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: false,
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: x509Cert.Subject.CommonName,
|
||||
// VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// opts := x509.VerifyOptions{
|
||||
// Roots: serverCertPool,
|
||||
// }
|
||||
// for _, rawCert := range rawCerts {
|
||||
// cert, _ := x509.ParseCertificate(rawCert)
|
||||
// _, err := cert.Verify(opts)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// },
|
||||
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: serverCertPool,
|
||||
}
|
||||
for _, rawCert := range rawCerts {
|
||||
cert, _ := x509.ParseCertificate(rawCert)
|
||||
_, err := cert.Verify(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -147,33 +154,36 @@ func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
|
||||
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
|
||||
return
|
||||
}
|
||||
func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) {
|
||||
kcpconn, err := kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3)
|
||||
func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.Conn, err error) {
|
||||
kcpconn, err := kcp.DialWithOptions(hostAndPort, config.Block, *config.DataShard, *config.ParityShard)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
kcpconn.SetNoDelay(1, 10, 2, 1)
|
||||
kcpconn.SetWindowSize(1024, 1024)
|
||||
kcpconn.SetMtu(1400)
|
||||
kcpconn.SetACKNoDelay(false)
|
||||
return kcpconn, err
|
||||
kcpconn.SetStreamMode(true)
|
||||
kcpconn.SetWriteDelay(true)
|
||||
kcpconn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
|
||||
kcpconn.SetMtu(*config.MTU)
|
||||
kcpconn.SetWindowSize(*config.SndWnd, *config.RcvWnd)
|
||||
kcpconn.SetACKNoDelay(*config.AckNodelay)
|
||||
if *config.NoComp {
|
||||
return kcpconn, err
|
||||
}
|
||||
return NewCompStream(kcpconn), err
|
||||
}
|
||||
func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) {
|
||||
block, _ := pem.Decode(certBytes)
|
||||
if block == nil {
|
||||
panic("failed to parse certificate PEM")
|
||||
}
|
||||
x509Cert, _ := x509.ParseCertificate(block.Bytes)
|
||||
if x509Cert == nil {
|
||||
panic("failed to parse block")
|
||||
}
|
||||
|
||||
func ListenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
|
||||
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
clientCertPool := x509.NewCertPool()
|
||||
ok := clientCertPool.AppendCertsFromPEM(certBytes)
|
||||
caBytes := certBytes
|
||||
if caCertBytes != nil {
|
||||
caBytes = caCertBytes
|
||||
}
|
||||
ok := clientCertPool.AppendCertsFromPEM(caBytes)
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
@ -181,21 +191,6 @@ func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listene
|
||||
ClientCAs: clientCertPool,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ServerName: x509Cert.Subject.CommonName,
|
||||
// VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// opts := x509.VerifyOptions{
|
||||
// Roots: clientCertPool,
|
||||
// }
|
||||
// for _, rawCert := range rawCerts {
|
||||
// cert, _ := x509.ParseCertificate(rawCert)
|
||||
// _, err := cert.Verify(opts)
|
||||
// fmt.Println("SERVER ERR:", err)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// },
|
||||
}
|
||||
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
|
||||
if err == nil {
|
||||
@ -238,27 +233,95 @@ func CloseConn(conn *net.Conn) {
|
||||
}
|
||||
}
|
||||
func Keygen() (err error) {
|
||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"}
|
||||
domainSubfixList := []string{".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".biz", ".info", ".pro", ".name", ".museum", ".coop", ".aero", ".xxx", ".idv", ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".eh", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".um", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".yu", ".yr", ".za", ".zm", ".zw"}
|
||||
C := CList[int(RandInt(4))%len(CList)]
|
||||
ST := RandString(int(RandInt(4) % 10))
|
||||
O := RandString(int(RandInt(4) % 10))
|
||||
CN := strings.ToLower(RandString(int(RandInt(4)%10)) + domainSubfixList[int(RandInt(4))%len(domainSubfixList)])
|
||||
cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN)
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
//log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN)
|
||||
var out []byte
|
||||
if len(os.Args) == 3 && os.Args[2] == "ca" {
|
||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
cmdStr := fmt.Sprintf("openssl req -new -key ca.key -x509 -days 36500 -out ca.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, "*."+CN)
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
} else if len(os.Args) == 5 && os.Args[2] == "ca" && os.Args[3] != "" && os.Args[4] != "" {
|
||||
certBytes, _ := ioutil.ReadFile("ca.crt")
|
||||
block, _ := pem.Decode(certBytes)
|
||||
if block == nil || certBytes == nil {
|
||||
panic("failed to parse ca certificate PEM")
|
||||
}
|
||||
x509Cert, _ := x509.ParseCertificate(block.Bytes)
|
||||
if x509Cert == nil {
|
||||
panic("failed to parse block")
|
||||
}
|
||||
name := os.Args[3]
|
||||
days := os.Args[4]
|
||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
cmdStr := fmt.Sprintf("openssl req -new -key %s.key -out %s.csr -subj /C=%s/ST=%s/O=%s/CN=%s", name, name, C, ST, O, CN)
|
||||
fmt.Printf("%s", cmdStr)
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
cmdStr = fmt.Sprintf("openssl x509 -req -days %s -in %s.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out %s.crt", days, name, name)
|
||||
fmt.Printf("%s", cmdStr)
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
} else if len(os.Args) == 3 && os.Args[2] == "usage" {
|
||||
fmt.Println(`proxy keygen //generate proxy.crt and proxy.key
|
||||
proxy keygen ca //generate ca.crt and ca.key
|
||||
proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sign it with 30 days
|
||||
`)
|
||||
} else if len(os.Args) == 2 {
|
||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN)
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
return
|
||||
}
|
||||
func GetAllInterfaceAddr() ([]net.IP, error) {
|
||||
@ -461,15 +524,15 @@ func SubBytes(bytes []byte, start, end int) []byte {
|
||||
}
|
||||
return bytes[start:end]
|
||||
}
|
||||
func TlsBytes(cert, key string) (certBytes, keyBytes []byte) {
|
||||
certBytes, err := ioutil.ReadFile(cert)
|
||||
func TlsBytes(cert, key string) (certBytes, keyBytes []byte, err error) {
|
||||
certBytes, err = ioutil.ReadFile(cert)
|
||||
if err != nil {
|
||||
log.Fatalf("err : %s", err)
|
||||
err = fmt.Errorf("err : %s", err)
|
||||
return
|
||||
}
|
||||
keyBytes, err = ioutil.ReadFile(key)
|
||||
if err != nil {
|
||||
log.Fatalf("err : %s", err)
|
||||
err = fmt.Errorf("err : %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
145
utils/pool.go
@ -1,145 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
//ConnPool to use
|
||||
type ConnPool interface {
|
||||
Get() (conn interface{}, err error)
|
||||
Put(conn interface{})
|
||||
ReleaseAll()
|
||||
Len() (length int)
|
||||
}
|
||||
type poolConfig struct {
|
||||
Factory func() (interface{}, error)
|
||||
IsActive func(interface{}) bool
|
||||
Release func(interface{})
|
||||
InitialCap int
|
||||
MaxCap int
|
||||
}
|
||||
|
||||
func NewConnPool(poolConfig poolConfig) (pool ConnPool, err error) {
|
||||
p := netPool{
|
||||
config: poolConfig,
|
||||
conns: make(chan interface{}, poolConfig.MaxCap),
|
||||
lock: &sync.Mutex{},
|
||||
}
|
||||
//log.Printf("pool MaxCap:%d", poolConfig.MaxCap)
|
||||
if poolConfig.MaxCap > 0 {
|
||||
err = p.initAutoFill(false)
|
||||
if err == nil {
|
||||
p.initAutoFill(true)
|
||||
}
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
type netPool struct {
|
||||
conns chan interface{}
|
||||
lock *sync.Mutex
|
||||
config poolConfig
|
||||
}
|
||||
|
||||
func (p *netPool) initAutoFill(async bool) (err error) {
|
||||
var worker = func() (err error) {
|
||||
for {
|
||||
//log.Printf("pool fill: %v , len: %d", p.Len() <= p.config.InitialCap/2, p.Len())
|
||||
if p.Len() <= p.config.InitialCap/2 {
|
||||
p.lock.Lock()
|
||||
errN := 0
|
||||
for i := 0; i < p.config.InitialCap; i++ {
|
||||
c, err := p.config.Factory()
|
||||
if err != nil {
|
||||
errN++
|
||||
if async {
|
||||
continue
|
||||
} else {
|
||||
p.lock.Unlock()
|
||||
return err
|
||||
}
|
||||
}
|
||||
select {
|
||||
case p.conns <- c:
|
||||
default:
|
||||
p.config.Release(c)
|
||||
break
|
||||
}
|
||||
if p.Len() >= p.config.InitialCap {
|
||||
break
|
||||
}
|
||||
}
|
||||
if errN > 0 {
|
||||
log.Printf("fill conn pool fail , ERRN:%d", errN)
|
||||
}
|
||||
p.lock.Unlock()
|
||||
}
|
||||
if !async {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
}
|
||||
if async {
|
||||
go worker()
|
||||
} else {
|
||||
err = worker()
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (p *netPool) Get() (conn interface{}, err error) {
|
||||
// defer func() {
|
||||
// log.Printf("pool len : %d", p.Len())
|
||||
// }()
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
// for {
|
||||
select {
|
||||
case conn = <-p.conns:
|
||||
if p.config.IsActive(conn) {
|
||||
return
|
||||
}
|
||||
p.config.Release(conn)
|
||||
default:
|
||||
conn, err = p.config.Factory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
// }
|
||||
return
|
||||
}
|
||||
|
||||
func (p *netPool) Put(conn interface{}) {
|
||||
if conn == nil {
|
||||
return
|
||||
}
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
if !p.config.IsActive(conn) {
|
||||
p.config.Release(conn)
|
||||
}
|
||||
select {
|
||||
case p.conns <- conn:
|
||||
default:
|
||||
p.config.Release(conn)
|
||||
}
|
||||
}
|
||||
func (p *netPool) ReleaseAll() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
close(p.conns)
|
||||
for c := range p.conns {
|
||||
p.config.Release(c)
|
||||
}
|
||||
p.conns = make(chan interface{}, p.config.InitialCap)
|
||||
|
||||
}
|
||||
func (p *netPool) Len() (length int) {
|
||||
return len(p.conns)
|
||||
}
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
"strconv"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
@ -23,7 +24,7 @@ func NewServerChannel(ip string, port int) ServerChannel {
|
||||
ip: ip,
|
||||
port: port,
|
||||
errAcceptHandler: func(err error) {
|
||||
fmt.Printf("accept error , ERR:%s", err)
|
||||
log.Printf("accept error , ERR:%s", err)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -41,8 +42,8 @@ func NewServerChannelHost(host string) ServerChannel {
|
||||
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
||||
sc.errAcceptHandler = fn
|
||||
}
|
||||
func (sc *ServerChannel) ListenTls(certBytes, keyBytes []byte, fn func(conn net.Conn)) (err error) {
|
||||
sc.Listener, err = ListenTls(sc.ip, sc.port, certBytes, keyBytes)
|
||||
func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) {
|
||||
sc.Listener, err = ListenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
|
||||
if err == nil {
|
||||
go func() {
|
||||
defer func() {
|
||||
@ -138,11 +139,23 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
||||
}
|
||||
return
|
||||
}
|
||||
func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (err error) {
|
||||
var l net.Listener
|
||||
l, err = kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), GetKCPBlock(method, key), 10, 3)
|
||||
func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn)) (err error) {
|
||||
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
|
||||
if err == nil {
|
||||
sc.Listener = &l
|
||||
if err = lis.SetDSCP(*config.DSCP); err != nil {
|
||||
log.Println("SetDSCP:", err)
|
||||
return
|
||||
}
|
||||
if err = lis.SetReadBuffer(*config.SockBuf); err != nil {
|
||||
log.Println("SetReadBuffer:", err)
|
||||
return
|
||||
}
|
||||
if err = lis.SetWriteBuffer(*config.SockBuf); err != nil {
|
||||
log.Println("SetWriteBuffer:", err)
|
||||
return
|
||||
}
|
||||
sc.Listener = new(net.Listener)
|
||||
*sc.Listener = lis
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
@ -150,8 +163,8 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (
|
||||
}
|
||||
}()
|
||||
for {
|
||||
var conn net.Conn
|
||||
conn, err = (*sc.Listener).Accept()
|
||||
//var conn net.Conn
|
||||
conn, err := lis.AcceptKCP()
|
||||
if err == nil {
|
||||
go func() {
|
||||
defer func() {
|
||||
@ -159,7 +172,18 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (
|
||||
log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
fn(conn)
|
||||
conn.SetStreamMode(true)
|
||||
conn.SetWriteDelay(true)
|
||||
conn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
|
||||
conn.SetMtu(*config.MTU)
|
||||
conn.SetWindowSize(*config.SndWnd, *config.RcvWnd)
|
||||
conn.SetACKNoDelay(*config.AckNodelay)
|
||||
if *config.NoComp {
|
||||
fn(conn)
|
||||
} else {
|
||||
cconn := NewCompStream(conn)
|
||||
fn(cconn)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
sc.errAcceptHandler(err)
|
||||
|
||||
253
utils/socks/client.go
Normal file
@ -0,0 +1,253 @@
|
||||
package socks
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var socks5Errors = []string{
|
||||
"",
|
||||
"general failure",
|
||||
"connection forbidden",
|
||||
"network unreachable",
|
||||
"host unreachable",
|
||||
"connection refused",
|
||||
"TTL expired",
|
||||
"command not supported",
|
||||
"address type not supported",
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
User, Password string
|
||||
}
|
||||
type ClientConn struct {
|
||||
user string
|
||||
password string
|
||||
conn *net.Conn
|
||||
header []byte
|
||||
timeout time.Duration
|
||||
addr string
|
||||
network string
|
||||
udpAddr string
|
||||
}
|
||||
|
||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
||||
// with an optional username and password. See RFC 1928 and RFC 1929.
|
||||
// target must be a canonical address with a host and port.
|
||||
// network : tcp udp
|
||||
func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration, auth *Auth, header []byte) *ClientConn {
|
||||
s := &ClientConn{
|
||||
conn: conn,
|
||||
network: network,
|
||||
timeout: timeout,
|
||||
}
|
||||
if auth != nil {
|
||||
s.user = auth.User
|
||||
s.password = auth.Password
|
||||
}
|
||||
if header != nil && len(header) > 0 {
|
||||
s.header = header
|
||||
}
|
||||
if network == "udp" && target == "" {
|
||||
target = "0.0.0.0:1"
|
||||
}
|
||||
s.addr = target
|
||||
return s
|
||||
}
|
||||
|
||||
// connect takes an existing connection to a socks5 proxy server,
|
||||
// and commands the server to extend that connection to target,
|
||||
// which must be a canonical address with a host and port.
|
||||
func (s *ClientConn) Handshake() error {
|
||||
host, portStr, err := net.SplitHostPort(s.addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return errors.New("proxy: failed to parse port number: " + portStr)
|
||||
}
|
||||
if port < 1 || port > 0xffff {
|
||||
return errors.New("proxy: port number out of range: " + portStr)
|
||||
}
|
||||
|
||||
if err := s.handshake(host); err != nil {
|
||||
return err
|
||||
}
|
||||
buf := []byte{}
|
||||
if s.network == "tcp" {
|
||||
buf = append(buf, VERSION_V5, CMD_CONNECT, 0 /* reserved */)
|
||||
|
||||
} else {
|
||||
buf = append(buf, VERSION_V5, CMD_ASSOCIATE, 0 /* reserved */)
|
||||
}
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
buf = append(buf, ATYP_IPV4)
|
||||
ip = ip4
|
||||
} else {
|
||||
buf = append(buf, ATYP_IPV6)
|
||||
}
|
||||
buf = append(buf, ip...)
|
||||
} else {
|
||||
if len(host) > 255 {
|
||||
return errors.New("proxy: destination host name too long: " + host)
|
||||
}
|
||||
buf = append(buf, ATYP_DOMAIN)
|
||||
buf = append(buf, byte(len(host)))
|
||||
buf = append(buf, host...)
|
||||
}
|
||||
buf = append(buf, byte(port>>8), byte(port))
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := (*s.conn).Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:4]); err != nil {
|
||||
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
failure := "unknown error"
|
||||
if int(buf[1]) < len(socks5Errors) {
|
||||
failure = socks5Errors[buf[1]]
|
||||
}
|
||||
|
||||
if len(failure) > 0 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
|
||||
}
|
||||
|
||||
bytesToDiscard := 0
|
||||
switch buf[3] {
|
||||
case ATYP_IPV4:
|
||||
bytesToDiscard = net.IPv4len
|
||||
case ATYP_IPV6:
|
||||
bytesToDiscard = net.IPv6len
|
||||
case ATYP_DOMAIN:
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
_, err := io.ReadFull((*s.conn), buf[:1])
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
bytesToDiscard = int(buf[0])
|
||||
default:
|
||||
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
|
||||
}
|
||||
|
||||
if cap(buf) < bytesToDiscard {
|
||||
buf = make([]byte, bytesToDiscard)
|
||||
} else {
|
||||
buf = buf[:bytesToDiscard]
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf); err != nil {
|
||||
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
var ip net.IP
|
||||
ip = buf
|
||||
ipStr := ""
|
||||
if bytesToDiscard == net.IPv4len || bytesToDiscard == net.IPv6len {
|
||||
if ipv4 := ip.To4(); ipv4 != nil {
|
||||
ipStr = ipv4.String()
|
||||
} else {
|
||||
ipStr = ip.To16().String()
|
||||
}
|
||||
}
|
||||
//log.Printf("%v", ipStr)
|
||||
// Also need to discard the port number
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
|
||||
//log.Printf("%v", p)
|
||||
s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
|
||||
//log.Printf("%v", s.udpAddr)
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
return nil
|
||||
}
|
||||
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
|
||||
|
||||
c, err := net.DialTimeout("udp", s.udpAddr, s.timeout)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn := c.(*net.UDPConn)
|
||||
|
||||
p := NewPacketUDP()
|
||||
p.Build(addr, data)
|
||||
conn.SetDeadline(time.Now().Add(s.timeout))
|
||||
conn.Write(p.Bytes())
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
conn.SetDeadline(time.Now().Add(s.timeout))
|
||||
n, _, err := conn.ReadFrom(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
respData = buf[:n]
|
||||
return
|
||||
}
|
||||
func (s *ClientConn) handshake(host string) error {
|
||||
|
||||
// the size here is just an estimate
|
||||
buf := make([]byte, 0, 6+len(host))
|
||||
|
||||
buf = append(buf, VERSION_V5)
|
||||
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
|
||||
buf = append(buf, 2 /* num auth methods */, Method_NO_AUTH, Method_USER_PASS)
|
||||
} else {
|
||||
buf = append(buf, 1 /* num auth methods */, Method_NO_AUTH)
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := (*s.conn).Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
|
||||
if buf[0] != 5 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
if buf[1] == 0xff {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
|
||||
}
|
||||
|
||||
// See RFC 1929
|
||||
if buf[1] == Method_USER_PASS {
|
||||
buf = buf[:0]
|
||||
buf = append(buf, 1 /* password protocol version */)
|
||||
buf = append(buf, uint8(len(s.user)))
|
||||
buf = append(buf, s.user...)
|
||||
buf = append(buf, uint8(len(s.password)))
|
||||
buf = append(buf, s.password...)
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := (*s.conn).Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if buf[1] != 0 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
226
utils/socks/server.go
Normal file
@ -0,0 +1,226 @@
|
||||
package socks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"snail007/proxy/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Method_NO_AUTH = uint8(0x00)
|
||||
Method_GSSAPI = uint8(0x01)
|
||||
Method_USER_PASS = uint8(0x02)
|
||||
Method_IANA = uint8(0x7F)
|
||||
Method_RESVERVE = uint8(0x80)
|
||||
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
||||
VERSION_V5 = uint8(0x05)
|
||||
CMD_CONNECT = uint8(0x01)
|
||||
CMD_BIND = uint8(0x02)
|
||||
CMD_ASSOCIATE = uint8(0x03)
|
||||
ATYP_IPV4 = uint8(0x01)
|
||||
ATYP_DOMAIN = uint8(0x03)
|
||||
ATYP_IPV6 = uint8(0x04)
|
||||
REP_SUCCESS = uint8(0x00)
|
||||
REP_REQ_FAIL = uint8(0x01)
|
||||
REP_RULE_FORBIDDEN = uint8(0x02)
|
||||
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
||||
REP_HOST_UNREACHABLE = uint8(0x04)
|
||||
REP_CONNECTION_REFUSED = uint8(0x05)
|
||||
REP_TTL_TIMEOUT = uint8(0x06)
|
||||
REP_CMD_UNSUPPORTED = uint8(0x07)
|
||||
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
||||
REP_UNKNOWN = uint8(0x09)
|
||||
RSV = uint8(0x00)
|
||||
)
|
||||
|
||||
var (
|
||||
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
||||
ZERO_PORT = []byte{0x00, 0x00}
|
||||
)
|
||||
|
||||
type ServerConn struct {
|
||||
target string
|
||||
user string
|
||||
password string
|
||||
conn *net.Conn
|
||||
timeout time.Duration
|
||||
auth *utils.BasicAuth
|
||||
header []byte
|
||||
ver uint8
|
||||
//method
|
||||
methodsCount uint8
|
||||
methods []uint8
|
||||
method uint8
|
||||
//request
|
||||
cmd uint8
|
||||
reserve uint8
|
||||
addressType uint8
|
||||
dstAddr string
|
||||
dstPort string
|
||||
dstHost string
|
||||
udpAddress string
|
||||
}
|
||||
|
||||
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn {
|
||||
if udpAddress == "" {
|
||||
udpAddress = "0.0.0.0:16666"
|
||||
}
|
||||
s := &ServerConn{
|
||||
conn: conn,
|
||||
timeout: timeout,
|
||||
auth: auth,
|
||||
header: header,
|
||||
ver: VERSION_V5,
|
||||
udpAddress: udpAddress,
|
||||
}
|
||||
return s
|
||||
|
||||
}
|
||||
func (s *ServerConn) Close() {
|
||||
utils.CloseConn(s.conn)
|
||||
}
|
||||
func (s *ServerConn) AuthData() Auth {
|
||||
return Auth{s.user, s.password}
|
||||
}
|
||||
func (s *ServerConn) Method() uint8 {
|
||||
return s.method
|
||||
}
|
||||
func (s *ServerConn) Target() string {
|
||||
return s.target
|
||||
}
|
||||
func (s *ServerConn) Handshake() (err error) {
|
||||
remoteAddr := (*s.conn).RemoteAddr()
|
||||
//协商开始
|
||||
//method select request
|
||||
var methodReq MethodsRequest
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
|
||||
methodReq, e := NewMethodsRequest((*s.conn), s.header)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
||||
return
|
||||
}
|
||||
//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
|
||||
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
|
||||
// if !methodReq.Select(Method_NO_AUTH) {
|
||||
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
// methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
// (*s.conn).SetReadDeadline(time.Time{})
|
||||
// err = fmt.Errorf("none method found : Method_NO_AUTH")
|
||||
// return
|
||||
// }
|
||||
s.method = Method_NO_AUTH
|
||||
//method select reply
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
err = methodReq.Reply(Method_NO_AUTH)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reply answer data fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
// err = fmt.Errorf("% x", methodReq.Bytes())
|
||||
} else {
|
||||
//auth
|
||||
if !methodReq.Select(Method_USER_PASS) {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("none method found : Method_USER_PASS")
|
||||
return
|
||||
}
|
||||
s.method = Method_USER_PASS
|
||||
//method reply need auth
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
err = methodReq.Reply(Method_USER_PASS)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reply answer data fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
//read auth
|
||||
buf := make([]byte, 500)
|
||||
var n int
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
n, err = (*s.conn).Read(buf)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read auth info fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
r := buf[:n]
|
||||
s.user = string(r[2 : r[1]+2])
|
||||
s.password = string(r[2+r[1]+1:])
|
||||
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
|
||||
//auth
|
||||
_addr := strings.Split(remoteAddr.String(), ":")
|
||||
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x00})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("answer auth success to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x01})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("answer auth fail to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("auth fail from %s", remoteAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
//request detail
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
request, e := NewRequest(*s.conn)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
err = fmt.Errorf("read request data fail,ERR: %s", e)
|
||||
return
|
||||
}
|
||||
//协商结束
|
||||
|
||||
switch request.CMD() {
|
||||
case CMD_BIND:
|
||||
err = request.TCPReply(REP_UNKNOWN)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("TCPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("cmd bind not supported, form: %s", remoteAddr)
|
||||
return
|
||||
case CMD_CONNECT:
|
||||
err = request.TCPReply(REP_SUCCESS)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("TCPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
case CMD_ASSOCIATE:
|
||||
err = request.UDPReply(REP_SUCCESS, s.udpAddress)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//fill socks info
|
||||
s.target = request.Addr()
|
||||
s.methodsCount = methodReq.MethodsCount()
|
||||
s.methods = methodReq.Methods()
|
||||
s.cmd = request.CMD()
|
||||
s.reserve = request.reserve
|
||||
s.addressType = request.addressType
|
||||
s.dstAddr = request.dstAddr
|
||||
s.dstHost = request.dstHost
|
||||
s.dstPort = request.dstPort
|
||||
return
|
||||
}
|
||||
@ -3,44 +3,13 @@ package socks
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
Method_NO_AUTH = uint8(0x00)
|
||||
Method_GSSAPI = uint8(0x01)
|
||||
Method_USER_PASS = uint8(0x02)
|
||||
Method_IANA = uint8(0x7F)
|
||||
Method_RESVERVE = uint8(0x80)
|
||||
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
||||
VERSION_V5 = uint8(0x05)
|
||||
CMD_CONNECT = uint8(0x01)
|
||||
CMD_BIND = uint8(0x02)
|
||||
CMD_ASSOCIATE = uint8(0x03)
|
||||
ATYP_IPV4 = uint8(0x01)
|
||||
ATYP_DOMAIN = uint8(0x03)
|
||||
ATYP_IPV6 = uint8(0x04)
|
||||
REP_SUCCESS = uint8(0x00)
|
||||
REP_REQ_FAIL = uint8(0x01)
|
||||
REP_RULE_FORBIDDEN = uint8(0x02)
|
||||
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
||||
REP_HOST_UNREACHABLE = uint8(0x04)
|
||||
REP_CONNECTION_REFUSED = uint8(0x05)
|
||||
REP_TTL_TIMEOUT = uint8(0x06)
|
||||
REP_CMD_UNSUPPORTED = uint8(0x07)
|
||||
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
||||
REP_UNKNOWN = uint8(0x09)
|
||||
RSV = uint8(0x00)
|
||||
)
|
||||
|
||||
var (
|
||||
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
||||
ZERO_PORT = []byte{0x00, 0x00}
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
ver uint8
|
||||
cmd uint8
|
||||
@ -57,7 +26,7 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
|
||||
var b = make([]byte, 1024)
|
||||
var n int
|
||||
req = Request{rw: rw}
|
||||
if len(header) == 1 {
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
b = header[0]
|
||||
n = len(header[0])
|
||||
} else {
|
||||
@ -71,7 +40,6 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
|
||||
req.cmd = uint8(b[1])
|
||||
req.reserve = uint8(b[2])
|
||||
req.addressType = uint8(b[3])
|
||||
|
||||
if b[0] != 0x5 {
|
||||
err = fmt.Errorf("sosck version supported")
|
||||
req.TCPReply(REP_REQ_FAIL)
|
||||
@ -129,7 +97,7 @@ func (s *Request) NewReply(rep uint8, addr string) []byte {
|
||||
ipv6[4], ipv6[5], ipv6[6], ipv6[7],
|
||||
ipv6[8], ipv6[9], ipv6[10], ipv6[11],
|
||||
)
|
||||
if ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
||||
if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
||||
atyp = ATYP_IPV6
|
||||
ipb = ip.To16()
|
||||
}
|
||||
@ -165,7 +133,7 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
|
||||
s.rw = &r
|
||||
var buf = make([]byte, 300)
|
||||
var n int
|
||||
if len(header) == 1 {
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
buf = header[0]
|
||||
n = len(header[0])
|
||||
} else {
|
||||
@ -182,7 +150,6 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
|
||||
err = fmt.Errorf("socks methods data length error")
|
||||
return
|
||||
}
|
||||
|
||||
s.ver = buf[0]
|
||||
s.methodsCount = buf[1]
|
||||
s.methods = buf[2:n]
|
||||
@ -195,6 +162,9 @@ func (s *MethodsRequest) Version() uint8 {
|
||||
func (s *MethodsRequest) MethodsCount() uint8 {
|
||||
return s.methodsCount
|
||||
}
|
||||
func (s *MethodsRequest) Methods() []uint8 {
|
||||
return s.methods
|
||||
}
|
||||
func (s *MethodsRequest) Select(method uint8) bool {
|
||||
for _, m := range s.methods {
|
||||
if m == method {
|
||||
@ -211,17 +181,6 @@ func (s *MethodsRequest) Bytes() []byte {
|
||||
return s.bytes
|
||||
}
|
||||
|
||||
type UDPPacket struct {
|
||||
rsv uint16
|
||||
frag uint8
|
||||
atype uint8
|
||||
dstHost string
|
||||
dstPort string
|
||||
data []byte
|
||||
header []byte
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
||||
p = UDPPacket{}
|
||||
p.frag = uint8(b[2])
|
||||
@ -249,6 +208,18 @@ func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
||||
p.header = b[:portIndex+2]
|
||||
return
|
||||
}
|
||||
|
||||
type UDPPacket struct {
|
||||
rsv uint16
|
||||
frag uint8
|
||||
atype uint8
|
||||
dstHost string
|
||||
dstPort string
|
||||
data []byte
|
||||
header []byte
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func (s *UDPPacket) Header() []byte {
|
||||
return s.header
|
||||
}
|
||||
@ -268,3 +239,104 @@ func (s *UDPPacket) Port() string {
|
||||
func (s *UDPPacket) Data() []byte {
|
||||
return s.data
|
||||
}
|
||||
|
||||
type PacketUDP struct {
|
||||
rsv uint16
|
||||
frag uint8
|
||||
atype uint8
|
||||
dstHost string
|
||||
dstPort string
|
||||
data []byte
|
||||
}
|
||||
|
||||
func NewPacketUDP() (p PacketUDP) {
|
||||
return PacketUDP{}
|
||||
}
|
||||
func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
|
||||
host, port, err := net.SplitHostPort(destAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.rsv = 0
|
||||
p.frag = 0
|
||||
p.dstHost = host
|
||||
p.dstPort = port
|
||||
p.atype = ATYP_IPV4
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
p.atype = ATYP_IPV4
|
||||
ip = ip4
|
||||
} else {
|
||||
p.atype = ATYP_IPV6
|
||||
}
|
||||
} else {
|
||||
if len(host) > 255 {
|
||||
err = errors.New("proxy: destination host name too long: " + host)
|
||||
return
|
||||
}
|
||||
p.atype = ATYP_DOMAIN
|
||||
}
|
||||
p.data = data
|
||||
|
||||
return
|
||||
}
|
||||
func (p *PacketUDP) Parse(b []byte) (err error) {
|
||||
p.frag = uint8(b[2])
|
||||
if p.frag != 0 {
|
||||
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
||||
return
|
||||
}
|
||||
portIndex := 0
|
||||
p.atype = b[3]
|
||||
switch p.atype {
|
||||
case ATYP_IPV4: //IP V4
|
||||
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
||||
portIndex = 8
|
||||
case ATYP_DOMAIN: //域名
|
||||
domainLen := uint8(b[4])
|
||||
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
||||
portIndex = int(5 + domainLen)
|
||||
case ATYP_IPV6: //IP V6
|
||||
p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
|
||||
portIndex = 20
|
||||
}
|
||||
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
|
||||
p.data = b[portIndex+2:]
|
||||
return
|
||||
}
|
||||
func (p *PacketUDP) Header() []byte {
|
||||
header := new(bytes.Buffer)
|
||||
header.Write([]byte{0x00, 0x00, p.frag, p.atype})
|
||||
if p.atype == ATYP_IPV4 {
|
||||
ip := net.ParseIP(p.dstHost)
|
||||
header.Write(ip.To4())
|
||||
} else if p.atype == ATYP_IPV6 {
|
||||
ip := net.ParseIP(p.dstHost)
|
||||
header.Write(ip.To16())
|
||||
} else if p.atype == ATYP_DOMAIN {
|
||||
hBytes := []byte(p.dstHost)
|
||||
header.WriteByte(byte(len(hBytes)))
|
||||
header.Write(hBytes)
|
||||
}
|
||||
port, _ := strconv.ParseUint(p.dstPort, 10, 64)
|
||||
portBytes := new(bytes.Buffer)
|
||||
binary.Write(portBytes, binary.BigEndian, port)
|
||||
header.Write(portBytes.Bytes()[portBytes.Len()-2:])
|
||||
return header.Bytes()
|
||||
}
|
||||
func (p *PacketUDP) Bytes() []byte {
|
||||
packBytes := new(bytes.Buffer)
|
||||
packBytes.Write(p.Header())
|
||||
packBytes.Write(p.data)
|
||||
return packBytes.Bytes()
|
||||
}
|
||||
func (p *PacketUDP) Host() string {
|
||||
return p.dstHost
|
||||
}
|
||||
|
||||
func (p *PacketUDP) Port() string {
|
||||
return p.dstPort
|
||||
}
|
||||
func (p *PacketUDP) Data() []byte {
|
||||
return p.data
|
||||
}
|
||||
|
||||
334
utils/structs.go
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -12,11 +11,13 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"snail007/proxy/services/kcpcfg"
|
||||
"snail007/proxy/utils/sni"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@ -26,6 +27,7 @@ type Checker struct {
|
||||
directMap ConcurrentMap
|
||||
interval int64
|
||||
timeout int
|
||||
isStop bool
|
||||
}
|
||||
type CheckerItem struct {
|
||||
IsHTTPS bool
|
||||
@ -46,6 +48,7 @@ func NewChecker(timeout int, interval int64, blockedFile, directFile string) Che
|
||||
data: NewConcurrentMap(),
|
||||
interval: interval,
|
||||
timeout: timeout,
|
||||
isStop: false,
|
||||
}
|
||||
ch.blockedMap = ch.loadMap(blockedFile)
|
||||
ch.directMap = ch.loadMap(directFile)
|
||||
@ -79,6 +82,9 @@ func (c *Checker) loadMap(f string) (dataMap ConcurrentMap) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (c *Checker) Stop() {
|
||||
c.isStop = true
|
||||
}
|
||||
func (c *Checker) start() {
|
||||
go func() {
|
||||
//log.Printf("checker started")
|
||||
@ -105,6 +111,9 @@ func (c *Checker) start() {
|
||||
}(v.(CheckerItem))
|
||||
}
|
||||
time.Sleep(time.Second * time.Duration(c.interval))
|
||||
if c.isStop {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -278,7 +287,11 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
|
||||
} else {
|
||||
err = fmt.Errorf("token error")
|
||||
}
|
||||
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, string(body))
|
||||
b := string(body)
|
||||
if len(b) > 50 {
|
||||
b = b[:50]
|
||||
}
|
||||
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b)
|
||||
}
|
||||
if err != nil && tryCount < ba.authRetry {
|
||||
log.Print(err)
|
||||
@ -315,7 +328,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
||||
req = HTTPRequest{
|
||||
conn: inConn,
|
||||
}
|
||||
if len(header) == 1 {
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
buf = header[0]
|
||||
n = len(header[0])
|
||||
} else {
|
||||
@ -400,17 +413,13 @@ func (req *HTTPRequest) IsHTTPS() bool {
|
||||
return req.Method == "CONNECT"
|
||||
}
|
||||
|
||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
|
||||
func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
|
||||
// log.Printf("request :%s", string(req.HeadBuf))
|
||||
code := "407"
|
||||
authorization := req.getHeader("Proxy-Authorization")
|
||||
// if authorization == "" {
|
||||
// authorization = req.getHeader("Authorization")
|
||||
// code = "401"
|
||||
// }
|
||||
|
||||
authorization = strings.Trim(authorization, " \r\n\t")
|
||||
if authorization == "" {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", code)
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", "407")
|
||||
CloseConn(req.conn)
|
||||
err = errors.New("require auth header data")
|
||||
return
|
||||
@ -428,6 +437,10 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
CloseConn(req.conn)
|
||||
return
|
||||
}
|
||||
basicInfo = string(user)
|
||||
return
|
||||
}
|
||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
||||
URL := ""
|
||||
if req.IsHTTPS() {
|
||||
@ -435,10 +448,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
} else {
|
||||
URL = req.getHTTPURL()
|
||||
}
|
||||
user, err := req.GetAuthDataStr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
||||
//log.Printf("auth %s,%v", string(user), authOk)
|
||||
if !authOk {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", code)
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", "407")
|
||||
CloseConn(req.conn)
|
||||
err = fmt.Errorf("basic auth fail")
|
||||
return
|
||||
@ -488,243 +505,44 @@ func (req *HTTPRequest) addPortIfNot() (newHost string) {
|
||||
return
|
||||
}
|
||||
|
||||
type OutPool struct {
|
||||
Pool ConnPool
|
||||
dur int
|
||||
typ string
|
||||
certBytes []byte
|
||||
keyBytes []byte
|
||||
kcpMethod string
|
||||
kcpKey string
|
||||
address string
|
||||
timeout int
|
||||
type OutConn struct {
|
||||
dur int
|
||||
typ string
|
||||
certBytes []byte
|
||||
keyBytes []byte
|
||||
caCertBytes []byte
|
||||
kcp kcpcfg.KCPConfigArgs
|
||||
address string
|
||||
timeout int
|
||||
}
|
||||
|
||||
func NewOutPool(dur int, typ, kcpMethod, kcpKey string, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) {
|
||||
op = OutPool{
|
||||
dur: dur,
|
||||
typ: typ,
|
||||
certBytes: certBytes,
|
||||
keyBytes: keyBytes,
|
||||
kcpMethod: kcpMethod,
|
||||
kcpKey: kcpKey,
|
||||
address: address,
|
||||
timeout: timeout,
|
||||
func NewOutConn(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int) (op OutConn) {
|
||||
return OutConn{
|
||||
dur: dur,
|
||||
typ: typ,
|
||||
certBytes: certBytes,
|
||||
keyBytes: keyBytes,
|
||||
caCertBytes: caCertBytes,
|
||||
kcp: kcp,
|
||||
address: address,
|
||||
timeout: timeout,
|
||||
}
|
||||
var err error
|
||||
op.Pool, err = NewConnPool(poolConfig{
|
||||
IsActive: func(conn interface{}) bool { return true },
|
||||
Release: func(conn interface{}) {
|
||||
if conn != nil {
|
||||
conn.(net.Conn).SetDeadline(time.Now().Add(time.Millisecond))
|
||||
conn.(net.Conn).Close()
|
||||
// log.Println("conn released")
|
||||
}
|
||||
},
|
||||
InitialCap: InitialCap,
|
||||
MaxCap: MaxCap,
|
||||
Factory: func() (conn interface{}, err error) {
|
||||
conn, err = op.getConn()
|
||||
return
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("init conn pool fail ,%s", err)
|
||||
} else {
|
||||
if InitialCap > 0 {
|
||||
log.Printf("init conn pool success")
|
||||
op.initPoolDeamon()
|
||||
} else {
|
||||
log.Printf("conn pool closed")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (op *OutPool) getConn() (conn interface{}, err error) {
|
||||
func (op *OutConn) Get() (conn net.Conn, err error) {
|
||||
if op.typ == "tls" {
|
||||
var _conn tls.Conn
|
||||
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes)
|
||||
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes, op.caCertBytes)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
} else if op.typ == "kcp" {
|
||||
conn, err = ConnectKCPHost(op.address, op.kcpMethod, op.kcpKey)
|
||||
conn, err = ConnectKCPHost(op.address, op.kcp)
|
||||
} else {
|
||||
conn, err = ConnectHost(op.address, op.timeout)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (op *OutPool) initPoolDeamon() {
|
||||
go func() {
|
||||
if op.dur <= 0 {
|
||||
return
|
||||
}
|
||||
log.Printf("pool deamon started")
|
||||
for {
|
||||
time.Sleep(time.Second * time.Duration(op.dur))
|
||||
conn, err := op.getConn()
|
||||
if err != nil {
|
||||
log.Printf("pool deamon err %s , release pool", err)
|
||||
op.Pool.ReleaseAll()
|
||||
} else {
|
||||
conn.(net.Conn).SetDeadline(time.Now().Add(time.Millisecond))
|
||||
conn.(net.Conn).Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
type HeartbeatData struct {
|
||||
Data []byte
|
||||
N int
|
||||
Error error
|
||||
}
|
||||
type HeartbeatReadWriter struct {
|
||||
conn *net.Conn
|
||||
// rchn chan HeartbeatData
|
||||
l *sync.Mutex
|
||||
dur int
|
||||
errHandler func(err error, hb *HeartbeatReadWriter)
|
||||
once *sync.Once
|
||||
datachn chan byte
|
||||
// rbuf bytes.Buffer
|
||||
// signal chan bool
|
||||
rerrchn chan error
|
||||
}
|
||||
|
||||
func NewHeartbeatReadWriter(conn *net.Conn, dur int, fn func(err error, hb *HeartbeatReadWriter)) (hrw HeartbeatReadWriter) {
|
||||
hrw = HeartbeatReadWriter{
|
||||
conn: conn,
|
||||
l: &sync.Mutex{},
|
||||
dur: dur,
|
||||
// rchn: make(chan HeartbeatData, 10000),
|
||||
// signal: make(chan bool, 1),
|
||||
errHandler: fn,
|
||||
datachn: make(chan byte, 4*1024),
|
||||
once: &sync.Once{},
|
||||
rerrchn: make(chan error, 1),
|
||||
// rbuf: bytes.Buffer{},
|
||||
}
|
||||
hrw.heartbeat()
|
||||
hrw.reader()
|
||||
return
|
||||
}
|
||||
|
||||
func (rw *HeartbeatReadWriter) Close() {
|
||||
CloseConn(rw.conn)
|
||||
}
|
||||
func (rw *HeartbeatReadWriter) reader() {
|
||||
go func() {
|
||||
//log.Printf("heartbeat read started")
|
||||
for {
|
||||
n, data, err := rw.read()
|
||||
if n == -1 {
|
||||
continue
|
||||
}
|
||||
//log.Printf("n:%d , data:%s ,err:%s", n, string(data), err)
|
||||
if err == nil {
|
||||
//fmt.Printf("write data %s\n", string(data))
|
||||
for _, b := range data {
|
||||
rw.datachn <- b
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
//log.Printf("heartbeat reader err: %s", err)
|
||||
select {
|
||||
case rw.rerrchn <- err:
|
||||
default:
|
||||
}
|
||||
rw.once.Do(func() {
|
||||
rw.errHandler(err, rw)
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
//log.Printf("heartbeat read exited")
|
||||
}()
|
||||
}
|
||||
func (rw *HeartbeatReadWriter) read() (n int, data []byte, err error) {
|
||||
var typ uint8
|
||||
err = binary.Read((*rw.conn), binary.LittleEndian, &typ)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if typ == 0 {
|
||||
// log.Printf("heartbeat revecived")
|
||||
n = -1
|
||||
return
|
||||
}
|
||||
var dataLength uint32
|
||||
binary.Read((*rw.conn), binary.LittleEndian, &dataLength)
|
||||
_data := make([]byte, dataLength)
|
||||
// log.Printf("dataLength:%d , data:%s", dataLength, string(data))
|
||||
n, err = (*rw.conn).Read(_data)
|
||||
//log.Printf("n:%d , data:%s ,err:%s", n, string(data), err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if uint32(n) != dataLength {
|
||||
err = fmt.Errorf("read short data body")
|
||||
return
|
||||
}
|
||||
data = _data[:n]
|
||||
return
|
||||
}
|
||||
func (rw *HeartbeatReadWriter) heartbeat() {
|
||||
go func() {
|
||||
//log.Printf("heartbeat started")
|
||||
for {
|
||||
if rw.conn == nil || *rw.conn == nil {
|
||||
//log.Printf("heartbeat err: conn nil")
|
||||
break
|
||||
}
|
||||
rw.l.Lock()
|
||||
_, err := (*rw.conn).Write([]byte{0})
|
||||
rw.l.Unlock()
|
||||
if err != nil {
|
||||
//log.Printf("heartbeat err: %s", err)
|
||||
rw.once.Do(func() {
|
||||
rw.errHandler(err, rw)
|
||||
})
|
||||
break
|
||||
} else {
|
||||
// log.Printf("heartbeat send ok")
|
||||
}
|
||||
time.Sleep(time.Second * time.Duration(rw.dur))
|
||||
}
|
||||
//log.Printf("heartbeat exited")
|
||||
}()
|
||||
}
|
||||
func (rw *HeartbeatReadWriter) Read(p []byte) (n int, err error) {
|
||||
data := make([]byte, cap(p))
|
||||
for i := 0; i < cap(p); i++ {
|
||||
data[i] = <-rw.datachn
|
||||
n++
|
||||
//fmt.Printf("read %d %v\n", i, data[:n])
|
||||
if len(rw.datachn) == 0 {
|
||||
n = i + 1
|
||||
copy(p, data[:n])
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (rw *HeartbeatReadWriter) Write(p []byte) (n int, err error) {
|
||||
defer rw.l.Unlock()
|
||||
rw.l.Lock()
|
||||
pkg := new(bytes.Buffer)
|
||||
binary.Write(pkg, binary.LittleEndian, uint8(1))
|
||||
binary.Write(pkg, binary.LittleEndian, uint32(len(p)))
|
||||
binary.Write(pkg, binary.LittleEndian, p)
|
||||
bs := pkg.Bytes()
|
||||
n, err = (*rw.conn).Write(bs)
|
||||
if err == nil {
|
||||
n = len(p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type ConnManager struct {
|
||||
pool ConcurrentMap
|
||||
l *sync.Mutex
|
||||
@ -924,3 +742,53 @@ func (a *DomainResolver) PrintData() {
|
||||
fmt.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt)
|
||||
}
|
||||
}
|
||||
func NewCompStream(conn net.Conn) *CompStream {
|
||||
c := new(CompStream)
|
||||
c.conn = conn
|
||||
c.w = snappy.NewBufferedWriter(conn)
|
||||
c.r = snappy.NewReader(conn)
|
||||
return c
|
||||
}
|
||||
func NewCompConn(conn net.Conn) net.Conn {
|
||||
c := CompStream{}
|
||||
c.conn = conn
|
||||
c.w = snappy.NewBufferedWriter(conn)
|
||||
c.r = snappy.NewReader(conn)
|
||||
return &c
|
||||
}
|
||||
|
||||
type CompStream struct {
|
||||
net.Conn
|
||||
conn net.Conn
|
||||
w *snappy.Writer
|
||||
r *snappy.Reader
|
||||
}
|
||||
|
||||
func (c *CompStream) Read(p []byte) (n int, err error) {
|
||||
return c.r.Read(p)
|
||||
}
|
||||
|
||||
func (c *CompStream) Write(p []byte) (n int, err error) {
|
||||
n, err = c.w.Write(p)
|
||||
err = c.w.Flush()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *CompStream) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
func (c *CompStream) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
func (c *CompStream) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
func (c *CompStream) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
func (c *CompStream) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
func (c *CompStream) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
16
vendor/github.com/golang/snappy/.gitignore
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
cmd/snappytool/snappytool
|
||||
testdata/bench
|
||||
|
||||
# These explicitly listed benchmark data files are for an obsolete version of
|
||||
# snappy_test.go.
|
||||
testdata/alice29.txt
|
||||
testdata/asyoulik.txt
|
||||
testdata/fireworks.jpeg
|
||||
testdata/geo.protodata
|
||||
testdata/html
|
||||
testdata/html_x_4
|
||||
testdata/kppkn.gtb
|
||||
testdata/lcet10.txt
|
||||
testdata/paper-100k.pdf
|
||||
testdata/plrabn12.txt
|
||||
testdata/urls.10K
|
||||
4
vendor/github.com/miekg/dns/.gitignore
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.6
|
||||
tags
|
||||
test.out
|
||||
a.out
|
||||
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
Executable file
@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
14
vendor/github.com/templexxx/cpufeat/.gitignore
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
40
vendor/github.com/templexxx/reedsolomon/.gitignore
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
/.idea
|
||||
/backup
|
||||
/loopunroll/
|
||||
cpu.out
|
||||
mathtool/galois/
|
||||
mathtool/matrix/
|
||||
mem.out
|
||||
/examples/
|
||||
/.DS_Store
|
||||
/mathtool/cntinverse
|
||||
/invert
|
||||
/bakcup
|
||||
/buf.svg
|
||||
*.svg
|
||||
*.out
|
||||
/escape
|
||||
18
vendor/github.com/templexxx/xor/.gitignore
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
/backup/
|
||||
/backup2/
|
||||
/.idea
|
||||
/backup3/
|
||||
24
vendor/github.com/xtaci/kcp-go/.gitignore
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
24
vendor/github.com/xtaci/smux/.gitignore
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||