Merge branch 'snail007-dev' into dev

This commit is contained in:
yc
2018-04-24 19:53:43 +08:00
72 changed files with 3932 additions and 1488 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ proxy
*.exe *.exe
*.exe~ *.exe~
.* .*
!.gitignore
release-* release-*
proxy.crt proxy.crt
proxy.key proxy.key

View File

@ -1,4 +1,47 @@
proxy更新日志 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 v4.3
1.优化了参数keygen生成证书逻辑避免证书出现特征。 1.优化了参数keygen生成证书逻辑避免证书出现特征。
2.http(s)和socks代理增加了--dns-address和--dns-ttl参数。 2.http(s)和socks代理增加了--dns-address和--dns-ttl参数。

142
Godeps/Godeps.json generated
View File

@ -1,41 +1,80 @@
{ {
"ImportPath": "snail007/proxy", "ImportPath": "snail007/proxy",
"GoVersion": "go1.8", "GoVersion": "go1.9",
"GodepVersion": "v79", "GodepVersion": "v80",
"Packages": [ "Packages": [
"./..." "./..."
], ],
"Deps": [ "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", "ImportPath": "github.com/golang/snappy",
"Rev": "553a641470496b2327abcac10b36396bd98e45c9" "Rev": "553a641470496b2327abcac10b36396bd98e45c9"
}, },
{ {
"ImportPath": "github.com/miekg/dns", "ImportPath": "github.com/miekg/dns",
"Comment": "v1.0.4", "Comment": "v1.0.4-1-g40b5202",
"Rev": "5364553f1ee9cddc7ac8b62dce148309c386695b" "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", "ImportPath": "github.com/pkg/errors",
"Comment": "v0.8.0-6-g602255c", "Comment": "v0.8.0-6-g602255c",
"Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9" "Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9"
}, },
{
"ImportPath": "github.com/templexxx/cpufeat",
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
},
{ {
"ImportPath": "github.com/templexxx/reedsolomon", "ImportPath": "github.com/templexxx/reedsolomon",
"Comment": "0.1.1-4-g7092926", "Comment": "0.1.1-4-g7092926",
@ -51,16 +90,6 @@
"Comment": "v1.0.1-3-g9d99fac", "Comment": "v1.0.1-3-g9d99fac",
"Rev": "9d99face20b0dd300b7db50b3f69758de41c096a" "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", "ImportPath": "golang.org/x/crypto/blowfish",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
@ -69,34 +98,10 @@
"ImportPath": "golang.org/x/crypto/cast5", "ImportPath": "golang.org/x/crypto/cast5",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "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", "ImportPath": "golang.org/x/crypto/salsa20",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "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", "ImportPath": "golang.org/x/crypto/tea",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
@ -110,33 +115,28 @@
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
}, },
{ {
"ImportPath": "golang.org/x/net/bpf", "ImportPath": "github.com/templexxx/cpufeat",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec" "Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
}, },
{ {
"ImportPath": "golang.org/x/net/internal/iana", "ImportPath": "golang.org/x/crypto/salsa20/salsa",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
}, },
{ {
"ImportPath": "golang.org/x/net/internal/socket", "ImportPath": "golang.org/x/crypto/curve25519",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
}, },
{ {
"ImportPath": "golang.org/x/net/ipv4", "ImportPath": "github.com/alecthomas/template",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec" "Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
}, },
{ {
"ImportPath": "golang.org/x/net/ipv6", "ImportPath": "github.com/alecthomas/units",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec" "Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
}, },
{ {
"ImportPath": "golang.org/x/time/rate", "ImportPath": "github.com/alecthomas/template/parse",
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7" "Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
},
{
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
"Comment": "v2.2.5",
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
} }
] ]
} }

View File

@ -298,13 +298,13 @@ Local HTTP (S) proxy use 28080 port,excute:
#### **1.8.KCP protocol transmission** #### **1.8.KCP protocol transmission**
![1.8](/docs/images/http-kcp.png) ![1.8](/docs/images/http-kcp.png)
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) 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) 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. 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** #### **1.9.HTTP reverse proxy**
![1.9](/docs/images/fxdl.png) ![1.9](/docs/images/fxdl.png)
@ -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. If there is no -a or -F or --auth-url parameters, it means to turn off the authentication.
#### **5.8.KCP protocol transmission** #### **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) 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) 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. 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** #### **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. 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 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** #### **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. 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. 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 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** #### **6.4.Chain style connection**
![6.4](/docs/images/sps-tls.png) ![6.4](/docs/images/sps-tls.png)

View File

@ -23,7 +23,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- 集成外部APIHTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成可以方便的通过外部系统控制代理用户 - 集成外部APIHTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成可以方便的通过外部系统控制代理用户
- 反向代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站. - 反向代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站.
- 透明HTTP(S)代理,配合iptables,在网关直接把出去的80,443方向的流量转发到proxy,就能实现无感知的智能路由器代理. - 透明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? ### Why need these?
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务. - 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的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.3手册](https://github.com/snail007/goproxy/tree/v4.3)
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2) - [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2)
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1) - [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.9 HTTP(S)反向代理](#19-https反向代理)
- [1.10 HTTP(S)透明代理](#110-https透明代理) - [1.10 HTTP(S)透明代理](#110-https透明代理)
- [1.11 自定义DNS](#111-自定义dns) - [1.11 自定义DNS](#111-自定义dns)
- [1.12 查看帮助](#112-查看帮助) - [1.12 自定义加密](#112-自定义加密)
- [1.13 压缩传输](#113-压缩传输)
- [1.14 查看帮助](#114-查看帮助)
- [2. TCP代理](#2tcp代理) - [2. TCP代理](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理) - [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理) - [2.2 普通二级TCP代理](#22普通二级tcp代理)
@ -118,14 +125,22 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [5.7 认证](#57认证) - [5.7 认证](#57认证)
- [5.8 KCP协议传输](#58kcp协议传输) - [5.8 KCP协议传输](#58kcp协议传输)
- [5.9 自定义DNS](#59自定义dns) - [5.9 自定义DNS](#59自定义dns)
- [5.10 查看帮助](#510查看帮助) - [5.10 自定义加密](#510-自定义加密)
- [5.11 压缩传输](#511-压缩传输)
- [5.12 查看帮助](#512查看帮助)
- [6. 代理协议转换](#6代理协议转换) - [6. 代理协议转换](#6代理协议转换)
- [6.1 功能介绍](#61-功能介绍) - [6.1 功能介绍](#61-功能介绍)
- [6.2 HTTP(S)转HTTP(S)+SOCKS5](#62-https转httpssocks5) - [6.2 HTTP(S)转HTTP(S)+SOCKS5](#62-https转httpssocks5)
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5) - [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
- [6.4 链式连接](#64-链式连接) - [6.4 链式连接](#64-链式连接)
- [6.5 监听多个端口](#65-监听多个端口) - [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 ### Fast Start
提示:所有操作需要root权限. 提示:所有操作需要root权限.
@ -143,7 +158,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
下载地址:https://github.com/snail007/goproxy/releases 下载地址:https://github.com/snail007/goproxy/releases
```shell ```shell
cd /root/proxy/ 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.下载自动安装脚本** #### **2.下载自动安装脚本**
```shell ```shell
@ -184,7 +199,8 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
在linux上并安装了openssl命令可以直接通过下面的命令生成证书和key文件. 在linux上并安装了openssl命令可以直接通过下面的命令生成证书和key文件.
`./proxy keygen` `./proxy keygen`
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。 默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
更多用法:`proxy keygen usage`
### **后台运行** ### **后台运行**
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行. 默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可. 如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
@ -204,20 +220,19 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
`./proxy http -g "23.23.23.23"` `./proxy http -g "23.23.23.23"`
### **1.HTTP代理** ### **1.HTTP代理**
#### **1.1.普通HTTP代理** #### **1.1.普通一级HTTP代理**
![1.1](/docs/images/1.1.jpg) ![1.1](/docs/images/http-1.png)
`./proxy http -t tcp -p "0.0.0.0:38080"` `./proxy http -t tcp -p "0.0.0.0:38080"`
#### **1.2.普通二级HTTP代理** #### **1.2.普通二级HTTP代理**
![1.2](/docs/images/http-2.png)
使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080` 使用本地端口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" ` `./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,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理. 我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如: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` `./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二级代理(加密)** #### **1.3.HTTP二级代理(加密)**
![1.3](/docs/images/http-tls-2.png)
一级HTTP代理(VPS,IP:22.22.22.22) 一级HTTP代理(VPS,IP:22.22.22.22)
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key` `./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上网。 然后设置你的windos系统中需要通过代理上网的程序的代理为http模式地址为127.0.0.1端口为8080,程序即可通过加密通道通过vps上网。
#### **1.4.HTTP三级代理(加密)** #### **1.4.HTTP三级代理(加密)**
![1.3](/docs/images/http-tls-3.png)
一级HTTP代理VPS_01,IP:22.22.22.22 一级HTTP代理VPS_01,IP:22.22.22.22
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key` `./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
二级HTTP代理VPS_02,IP:33.33.33.33 二级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` `./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中转** #### **1.7.HTTP(S)通过SSH中转**
![1.7](/docs/images/http-ssh-1.png)
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址. 说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
假设有:vps 假设有:vps
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo - 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"` `./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
#### **1.8.KCP协议传输** #### **1.8.KCP协议传输**
KCP协议需要-B参数设置一个密码用于加密解密数据 ![1.8](/docs/images/http-kcp.png)
KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
一级HTTP代理(VPS,IP:22.22.22.22) 一级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) 二级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协议传输. 那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
#### **1.9 HTTP(S)反向代理** #### **1.9 HTTP(S)反向代理**
![1.9](/docs/images/fxdl.png)
proxy不仅支持在其他软件里面通过设置代理的方式,为其他软件提供代理服务,而且支持直接把请求的网站域名解析到proxy监听的ip上,然后proxy监听80和443端口,那么proxy就会自动为你代理访问需要访问的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 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)透明代理** #### **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` `./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` `./proxy help http`
### **2.TCP代理** ### **2.TCP代理**
#### **2.1.普通一级TCP代理** #### **2.1.普通一级TCP代理**
![2.1](/docs/images/2.1.png) ![2.1](/docs/images/tcp-1.png)
本地执行: 本地执行:
`./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22"` `./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22"`
那么访问本地33080端口就是访问192.168.22.33的22端口. 那么访问本地33080端口就是访问192.168.22.33的22端口.
#### **2.2.普通二级TCP代理** #### **2.2.普通二级TCP代理**
![2.2](/docs/images/2.2.png) ![2.2](/docs/images/tcp-2.png)
VPS(IP:22.22.22.33)执行: VPS(IP:22.22.22.33)执行:
`./proxy tcp -p ":33080" -T tcp -P "127.0.0.1:8080"` `./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端口. 那么访问本地23080端口就是访问22.22.22.33的8080端口.
#### **2.3.普通三级TCP代理** #### **2.3.普通三级TCP代理**
![2.3](/docs/images/tcp-3.png)
一级TCP代理VPS_01,IP:22.22.22.22 一级TCP代理VPS_01,IP:22.22.22.22
`./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080"` `./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080"`
二级TCP代理VPS_02,IP:33.33.33.33 二级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端口. 那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
#### **2.4.加密二级TCP代理** #### **2.4.加密二级TCP代理**
![2.4](/docs/images/tcp-tls-2.png)
VPS(IP:22.22.22.33)执行: 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` `./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端口. 那么访问本地23080端口就是通过加密TCP隧道访问22.22.22.33的8080端口.
#### **2.5.加密三级TCP代理** #### **2.5.加密三级TCP代理**
![2.5](/docs/images/tcp-tls-3.png)
一级TCP代理VPS_01,IP:22.22.22.22 一级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 二级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代理(本地) 三级TCP代理(本地)
`./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key` `./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端口. 那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
@ -403,11 +471,13 @@ VPS(IP:22.22.22.33)执行:
### **3.UDP代理** ### **3.UDP代理**
#### **3.1.普通一级UDP代理** #### **3.1.普通一级UDP代理**
![3.1](/docs/images/udp-1.png)
本地执行: 本地执行:
`./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"` `./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"`
那么访问本地UDP:5353端口就是访问8.8.8.8的UDP:53端口. 那么访问本地UDP:5353端口就是访问8.8.8.8的UDP:53端口.
#### **3.2.普通二级UDP代理** #### **3.2.普通二级UDP代理**
![3.2](/docs/images/udp-2.png)
VPS(IP:22.22.22.33)执行: VPS(IP:22.22.22.33)执行:
`./proxy tcp -p ":33080" -T udp -P "8.8.8.8:53"` `./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端口. 那么访问本地UDP:5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
#### **3.3.普通三级UDP代理** #### **3.3.普通三级UDP代理**
![3.3](/docs/images/udp-3.png)
一级TCP代理VPS_01,IP:22.22.22.22 一级TCP代理VPS_01,IP:22.22.22.22
`./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"` `./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"`
二级TCP代理VPS_02,IP:33.33.33.33 二级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端口. 那么访问本地5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的53端口.
#### **3.4.加密二级UDP代理** #### **3.4.加密二级UDP代理**
![3.4](/docs/images/udp-tls-2.png)
VPS(IP:22.22.22.33)执行: 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` `./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端口. 那么访问本地UDP:5353端口就是通过加密TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
#### **3.5.加密三级UDP代理** #### **3.5.加密三级UDP代理**
![3.5](/docs/images/udp-tls-3.png)
一级TCP代理VPS_01,IP:22.22.22.22 一级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 二级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代理(本地) 三级TCP代理(本地)
`./proxy udp -p ":5353" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key` `./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端口. 那么访问本地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"` `./proxy socks -t tcp -p "0.0.0.0:38080"`
#### **5.2.普通二级SOCKS5代理** #### **5.2.普通二级SOCKS5代理**
![5.2](/docs/images/5.2.png) ![5.2](/docs/images/socks-2.png)
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080` 使用本地端口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" ` `./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` `./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二级代理(加密)** #### **5.3.SOCKS二级代理(加密)**
![5.3](/docs/images/socks-tls-2.png)
一级SOCKS代理(VPS,IP:22.22.22.22) 一级SOCKS代理(VPS,IP:22.22.22.22)
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key` `./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上网。 然后设置你的windos系统中需要通过代理上网的程序的代理为socks5模式地址为127.0.0.1端口为8080,程序即可通过加密通道通过vps上网。
#### **5.4.SOCKS三级代理(加密)** #### **5.4.SOCKS三级代理(加密)**
![5.4](/docs/images/socks-tls-3.png)
一级SOCKS代理VPS_01,IP:22.22.22.22 一级SOCKS代理VPS_01,IP:22.22.22.22
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key` `./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
二级SOCKS代理VPS_02,IP:33.33.33.33 二级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` `./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中转** #### **5.6.SOCKS通过SSH中转**
![5.6](/docs/images/socks-ssh.png)
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址. 说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
假设有:vps 假设有:vps
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo - 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参数,就是关闭认证. 如果没有-a或-F或--auth-url参数,就是关闭认证.
#### **5.8.KCP协议传输** #### **5.8.KCP协议传输**
KCP协议需要-B参数设置一个密码用于加密解密数据 KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
一级HTTP代理(VPS,IP:22.22.22.22) 一级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) 二级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协议传输. 那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
#### **5.9.自定义DNS** #### **5.9.自定义DNS**
@ -673,13 +749,64 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
比如: 比如:
`./proxy socks -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300` `./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` `./proxy help socks`
### **6.代理协议转换** ### **6.代理协议转换**
#### **6.1 功能介绍** #### **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** #### **6.2 HTTP(S)转HTTP(S)+SOCKS5**
假设已经存在一个普通的http(s)代理127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。 假设已经存在一个普通的http(s)代理127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
@ -692,7 +819,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
假设已经存在一个kcp的http(s)代理密码是demo123127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。 假设已经存在一个kcp的http(s)代理密码是demo123127.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** #### **6.3 SOCKS5转HTTP(S)+SOCKS5**
假设已经存在一个普通的socks5代理127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。 假设已经存在一个普通的socks5代理127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
@ -705,9 +832,10 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
假设已经存在一个kcp的socks5代理密码是demo123127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。 假设已经存在一个kcp的socks5代理密码是demo123127.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 链式连接**
![6.4](/docs/images/sps-tls.png)
上面提过多个sps结点可以层级连接构建加密通道假设有如下vps和家里的pc电脑。 上面提过多个sps结点可以层级连接构建加密通道假设有如下vps和家里的pc电脑。
vps012.2.2.2 vps012.2.2.2
vps023.3.3.3 vps023.3.3.3
@ -730,22 +858,157 @@ vps023.3.3.3
一般情况下监听一个端口就可以不过如果作为反向代理需要同时监听80和443两个端口那么-p参数是支持的 一般情况下监听一个端口就可以不过如果作为反向代理需要同时监听80和443两个端口那么-p参数是支持的
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。 格式是:`-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` `./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 ### TODO
- http,socks代理多个上级负载均衡? - http,socks代理多个上级负载均衡?
- http(s)代理增加pac支持? - http(s)代理增加pac支持?
- 欢迎加群反馈... - 欢迎加群反馈...
### 如何使用源码? ### 如何使用源码?
建议go1.8.5,不保证>=1.9能用. 建议go1.8.5,不保证>=1.9能用.
cd进入你的go src目录,新建文件夹snail007, cd进入你的go src目录,新建文件夹snail007,
cd进入snail007,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可. cd进入snail007,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
编译直接:go build 编译直接:go build
运行: go run *.go 运行: go run *.go
utils是工具包,service是具体的每个服务类. utils是工具包,service是具体的每个服务类.
### License ### License
Proxy is licensed under GPLv3 license. Proxy is licensed under GPLv3 license.

125
config.go
View File

@ -2,14 +2,18 @@ package main
import ( import (
"bufio" "bufio"
"crypto/sha1"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"snail007/proxy/services" "snail007/proxy/services"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils" "snail007/proxy/utils"
"time" "time"
kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@ -40,6 +44,7 @@ func initConfig() (err error) {
udpArgs := services.UDPArgs{} udpArgs := services.UDPArgs{}
socksArgs := services.SocksArgs{} socksArgs := services.SocksArgs{}
spsArgs := services.SPSArgs{} spsArgs := services.SPSArgs{}
kcpArgs := kcpcfg.KCPConfigArgs{}
//build srvice args //build srvice args
app = kingpin.New("proxy", "happy with proxy") app = kingpin.New("proxy", "happy with proxy")
app.Author("snail").Version(APP_VERSION) 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() 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() forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String() 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#########
http := app.Command("http", "proxy on http mode") 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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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#########
tcp := app.Command("tcp", "proxy on tcp mode") 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.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.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.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.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.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#########
udp := app.Command("udp", "proxy on udp mode") 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.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.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.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.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() udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########mux-server######### //########mux-server#########
muxServer := app.Command("server", "proxy on mux server mode") 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.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.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.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.IsUDP = muxServer.Flag("udp", "proxy on udp mux server mode").Default("false").Bool()
muxServerArgs.Key = muxServer.Flag("k", "client key").Default("default").String() 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.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######### //########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode") 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.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.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.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.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######### //########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode") 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.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.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.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######### //########tunnel-server#########
tunnelServer := app.Command("tserver", "proxy on tunnel server mode") 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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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)######### //########socks+http(s)#########
sps := app.Command("sps", "proxy on socks+http(s) mode") 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.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.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.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.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.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.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.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.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.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.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 //parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) 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 flags := log.Ldate
if *debug { if *debug {
flags |= log.Lshortfile | log.Lmicroseconds flags |= log.Lshortfile | log.Lmicroseconds

BIN
docs/images/fxdl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/images/http-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/images/http-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/images/http-kcp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/http-ssh-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/images/http-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/http-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/images/socks-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/images/socks-ssh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/images/socks-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/images/socks-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/sps-tls.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/images/tcp-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/images/tcp-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/images/tcp-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/images/tcp-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/images/tcp-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/udp-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/images/udp-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/images/udp-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/images/udp-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/images/udp-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
fi fi
mkdir /tmp/proxy mkdir /tmp/proxy
cd /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 # #install proxy
tar zxvf proxy-linux-amd64.tar.gz tar zxvf proxy-linux-amd64.tar.gz

View File

@ -8,7 +8,7 @@ import (
"syscall" "syscall"
) )
const APP_VERSION = "4.4" const APP_VERSION = "4.7"
func main() { func main() {
err := initConfig() err := initConfig()

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VER="4.4" VER="4.7"
RELEASE="release-${VER}" RELEASE="release-${VER}"
rm -rf .cert rm -rf .cert
mkdir .cert mkdir .cert

259
sdk/README.md Normal file
View 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
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-android/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-android.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-android/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-android/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-android.svg?style=plastic)](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
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-ios/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-ios.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-ios/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-ios/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-ios.svg?style=plastic)](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
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-windows/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-windows.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-windows/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-windows/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-windows.svg?style=plastic)](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
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-linux/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-linux.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-linux/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-linux/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-linux.svg?style=plastic)](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
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-mac/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-mac.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-mac/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-mac/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-mac.svg?style=plastic)](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
View File

@ -0,0 +1,7 @@
*.jar
*.aar
*.tar.gz
ios
android
Proxy.framework

View 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
View 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
View 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
View File

@ -0,0 +1,6 @@
proxy-sdk.dll
proxy-sdk.h
proxy-sdk.so
proxy-sdk.a
*.tar.gz
test.c

Binary file not shown.

View 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."

View 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."

View 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
View 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() {
}

View File

@ -1,6 +1,10 @@
package services 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") // 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() // 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 { type MuxServerArgs struct {
Parent *string Parent *string
CertFile *string ParentType *string
KeyFile *string CertFile *string
CertBytes []byte KeyFile *string
KeyBytes []byte CertBytes []byte
Local *string KeyBytes []byte
IsUDP *bool Local *string
Key *string IsUDP *bool
Remote *string Key *string
Timeout *int Remote *string
Route *[]string Timeout *int
Mgr *MuxServerManager Route *[]string
IsCompress *bool Mgr *MuxServerManager
IsCompress *bool
SessionCount *int
KCP kcpcfg.KCPConfigArgs
} }
type MuxClientArgs struct { type MuxClientArgs struct {
Parent *string Parent *string
CertFile *string ParentType *string
KeyFile *string CertFile *string
CertBytes []byte KeyFile *string
KeyBytes []byte CertBytes []byte
Key *string KeyBytes []byte
Timeout *int Key *string
IsCompress *bool Timeout *int
IsCompress *bool
SessionCount *int
KCP kcpcfg.KCPConfigArgs
} }
type MuxBridgeArgs struct { type MuxBridgeArgs struct {
Parent *string
CertFile *string CertFile *string
KeyFile *string KeyFile *string
CertBytes []byte CertBytes []byte
KeyBytes []byte KeyBytes []byte
Local *string Local *string
LocalType *string
Timeout *int Timeout *int
IsCompress *bool IsCompress *bool
KCP kcpcfg.KCPConfigArgs
} }
type TunnelServerArgs struct { type TunnelServerArgs struct {
Parent *string Parent *string
@ -100,16 +111,16 @@ type TCPArgs struct {
ParentType *string ParentType *string
LocalType *string LocalType *string
Timeout *int Timeout *int
PoolSize *int
CheckParentInterval *int CheckParentInterval *int
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
} }
type HTTPArgs struct { type HTTPArgs struct {
Parent *string Parent *string
CertFile *string CertFile *string
KeyFile *string KeyFile *string
CaCertFile *string
CaCertBytes []byte
CertBytes []byte CertBytes []byte
KeyBytes []byte KeyBytes []byte
Local *string Local *string
@ -127,7 +138,6 @@ type HTTPArgs struct {
ParentType *string ParentType *string
LocalType *string LocalType *string
Timeout *int Timeout *int
PoolSize *int
CheckParentInterval *int CheckParentInterval *int
SSHKeyFile *string SSHKeyFile *string
SSHKeyFileSalt *string SSHKeyFileSalt *string
@ -135,11 +145,14 @@ type HTTPArgs struct {
SSHUser *string SSHUser *string
SSHKeyBytes []byte SSHKeyBytes []byte
SSHAuthMethod ssh.AuthMethod SSHAuthMethod ssh.AuthMethod
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
LocalIPS *[]string LocalIPS *[]string
DNSAddress *string DNSAddress *string
DNSTTL *int DNSTTL *int
LocalKey *string
ParentKey *string
LocalCompress *bool
ParentCompress *bool
} }
type UDPArgs struct { type UDPArgs struct {
Parent *string Parent *string
@ -150,7 +163,6 @@ type UDPArgs struct {
Local *string Local *string
ParentType *string ParentType *string
Timeout *int Timeout *int
PoolSize *int
CheckParentInterval *int CheckParentInterval *int
} }
type SocksArgs struct { type SocksArgs struct {
@ -160,6 +172,8 @@ type SocksArgs struct {
LocalType *string LocalType *string
CertFile *string CertFile *string
KeyFile *string KeyFile *string
CaCertFile *string
CaCertBytes []byte
CertBytes []byte CertBytes []byte
KeyBytes []byte KeyBytes []byte
SSHKeyFile *string SSHKeyFile *string
@ -179,29 +193,45 @@ type SocksArgs struct {
AuthURLOkCode *int AuthURLOkCode *int
AuthURLTimeout *int AuthURLTimeout *int
AuthURLRetry *int AuthURLRetry *int
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
UDPParent *string UDPParent *string
UDPLocal *string UDPLocal *string
LocalIPS *[]string LocalIPS *[]string
DNSAddress *string DNSAddress *string
DNSTTL *int DNSTTL *int
LocalKey *string
ParentKey *string
LocalCompress *bool
ParentCompress *bool
} }
type SPSArgs struct { type SPSArgs struct {
Parent *string Parent *string
CertFile *string CertFile *string
KeyFile *string KeyFile *string
CaCertFile *string
CaCertBytes []byte
CertBytes []byte CertBytes []byte
KeyBytes []byte KeyBytes []byte
Local *string Local *string
ParentType *string ParentType *string
LocalType *string LocalType *string
Timeout *int Timeout *int
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
ParentServiceType *string ParentServiceType *string
DNSAddress *string DNSAddress *string
DNSTTL *int 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 { func (a *SPSArgs) Protocol() string {

View File

@ -8,6 +8,7 @@ import (
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/utils" "snail007/proxy/utils"
"snail007/proxy/utils/conncrypt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -16,38 +17,56 @@ import (
) )
type HTTP struct { type HTTP struct {
outPool utils.OutPool outPool utils.OutConn
cfg HTTPArgs cfg HTTPArgs
checker utils.Checker checker utils.Checker
basicAuth utils.BasicAuth basicAuth utils.BasicAuth
sshClient *ssh.Client sshClient *ssh.Client
lockChn chan bool lockChn chan bool
domainResolver utils.DomainResolver domainResolver utils.DomainResolver
isStop bool
serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap
} }
func NewHTTP() Service { func NewHTTP() Service {
return &HTTP{ return &HTTP{
outPool: utils.OutPool{}, outPool: utils.OutConn{},
cfg: HTTPArgs{}, cfg: HTTPArgs{},
checker: utils.Checker{}, checker: utils.Checker{},
basicAuth: utils.BasicAuth{}, basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1), lockChn: make(chan bool, 1),
isStop: false,
serverChannels: []*utils.ServerChannel{},
userConns: utils.NewConcurrentMap(),
} }
} }
func (s *HTTP) CheckArgs() { func (s *HTTP) CheckArgs() (err error) {
var err error
if *s.cfg.Parent != "" && *s.cfg.ParentType == "" { 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" { 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.ParentType == "ssh" {
if *s.cfg.SSHUser == "" { if *s.cfg.SSHUser == "" {
log.Fatalf("ssh user required") err = fmt.Errorf("ssh user required")
return
} }
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" { 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 != "" { if *s.cfg.SSHPassword != "" {
@ -56,7 +75,8 @@ func (s *HTTP) CheckArgs() {
var SSHSigner ssh.Signer var SSHSigner ssh.Signer
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile) s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
if err != nil { 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 != "" { if *s.cfg.SSHKeyFileSalt != "" {
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*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) SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
} }
if err != nil { 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) s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
} }
} }
return
} }
func (s *HTTP) InitService() { func (s *HTTP) InitService() (err error) {
s.InitBasicAuth() s.InitBasicAuth()
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) 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) (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
err := s.ConnectSSH() err = s.ConnectSSH()
if err != nil { if err != nil {
log.Fatalf("init service fail, ERR: %s", err) err = fmt.Errorf("init service fail, ERR: %s", err)
return
} }
go func() { go func() {
//循环检查ssh网络连通性 //循环检查ssh网络连通性
for { for {
if s.isStop {
return
}
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2) conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
if err == nil { if err == nil {
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write([]byte{0}) _, err = conn.Write([]byte{0})
conn.SetDeadline(time.Time{})
} }
if err != nil { if err != nil {
if s.sshClient != nil { if s.sshClient != nil {
@ -106,20 +134,43 @@ func (s *HTTP) InitService() {
} }
}() }()
} }
return
} }
func (s *HTTP) StopService() { func (s *HTTP) StopService() {
if s.outPool.Pool != nil { defer func() {
s.outPool.Pool.ReleaseAll() 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) { func (s *HTTP) Start(args interface{}) (err error) {
s.cfg = args.(HTTPArgs) s.cfg = args.(HTTPArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
return
}
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitOutConnPool() s.InitOutConnPool()
} }
s.InitService() if err = s.InitService(); err != nil {
return
}
for _, addr := range strings.Split(*s.cfg.Local, ",") { for _, addr := range strings.Split(*s.cfg.Local, ",") {
if addr != "" { if addr != "" {
host, port, _ := net.SplitHostPort(addr) host, port, _ := net.SplitHostPort(addr)
@ -128,14 +179,15 @@ func (s *HTTP) Start(args interface{}) (err error) {
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_TLS { } 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 { } 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 { if err != nil {
return return
} }
log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr()) log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
s.serverChannels = append(s.serverChannels, &sc)
} }
} }
return 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())) 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 err interface{}
var req utils.HTTPRequest var req utils.HTTPRequest
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth) 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) log.Printf("use proxy : %v, %s", useProxy, address)
err = s.OutToTCP(useProxy, address, &inConn, &req) err = s.OutToTCP(useProxy, address, &inConn, &req)
if err != nil { if err != nil {
if *s.cfg.Parent == "" { if *s.cfg.Parent == "" {
log.Printf("connect to %s fail, ERR:%s", address, err) 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 return
} }
var outConn net.Conn var outConn net.Conn
var _outConn interface{}
tryCount := 0 tryCount := 0
maxTryCount := 5 maxTryCount := 5
for { for {
if s.isStop {
return
}
if useProxy { if useProxy {
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
outConn, err = s.getSSHConn(address) outConn, err = s.getSSHConn(address)
} else { } else {
//log.Printf("%v", s.outPool) // log.Printf("%v", s.outPool)
_outConn, err = s.outPool.Pool.Get() outConn, err = s.outPool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
}
} }
} else { } else {
outConn, err = utils.ConnectHost(s.Resolve(address), *s.cfg.Timeout) 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) utils.CloseConn(inConn)
return 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() outAddr := outConn.RemoteAddr().String()
//outLocalAddr := outConn.LocalAddr().String() //outLocalAddr := outConn.LocalAddr().String()
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") { if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标 //https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
err = req.HTTPSReply() err = req.HTTPSReply()
} else { } else {
//https或者http,上级是代理,proxy需要转发 //https或者http,上级是代理,proxy需要转发
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(req.HeadBuf) _, err = outConn.Write(req.HeadBuf)
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("write to %s , err:%s", *s.cfg.Parent, err) log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) 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{}) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host) 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) 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 return
} }
@ -260,7 +331,7 @@ func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err interface{}) {
maxTryCount := 1 maxTryCount := 1
tryCount := 0 tryCount := 0
RETRY: RETRY:
if tryCount >= maxTryCount { if tryCount >= maxTryCount || s.isStop {
return return
} }
wait := make(chan bool, 1) 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 { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte, //dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int //parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutConn(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
*s.cfg.KCPMethod, s.cfg.KCP,
*s.cfg.KCPKey, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
s.cfg.CertBytes, s.cfg.KeyBytes,
s.Resolve(*s.cfg.Parent), s.Resolve(*s.cfg.Parent),
*s.cfg.Timeout, *s.cfg.Timeout,
*s.cfg.PoolSize,
*s.cfg.PoolSize*2,
) )
} }
} }

24
services/kcpcfg/args.go Normal file
View 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
}

View File

@ -2,11 +2,15 @@ package services
import ( import (
"bufio" "bufio"
"fmt"
"io" "io"
"log" "log"
"math/rand"
"net" "net"
"snail007/proxy/utils" "snail007/proxy/utils"
"strconv" "strconv"
"strings"
"sync"
"time" "time"
"github.com/xtaci/smux" "github.com/xtaci/smux"
@ -15,108 +19,207 @@ import (
type MuxBridge struct { type MuxBridge struct {
cfg MuxBridgeArgs cfg MuxBridgeArgs
clientControlConns utils.ConcurrentMap clientControlConns utils.ConcurrentMap
serverConns utils.ConcurrentMap
router utils.ClientKeyRouter router utils.ClientKeyRouter
l *sync.Mutex
isStop bool
sc *utils.ServerChannel
} }
func NewMuxBridge() Service { func NewMuxBridge() Service {
b := &MuxBridge{ b := &MuxBridge{
cfg: MuxBridgeArgs{}, cfg: MuxBridgeArgs{},
clientControlConns: utils.NewConcurrentMap(), clientControlConns: utils.NewConcurrentMap(),
serverConns: utils.NewConcurrentMap(),
l: &sync.Mutex{},
isStop: false,
} }
b.router = utils.NewClientKeyRouter(&b.clientControlConns, 50000) b.router = utils.NewClientKeyRouter(&b.clientControlConns, 50000)
return b 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 == "" { 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() { 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) { func (s *MuxBridge) Start(args interface{}) (err error) {
s.cfg = args.(MuxBridgeArgs) s.cfg = args.(MuxBridgeArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
}
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p)
if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) { err = sc.ListenTCP(s.handler)
reader := bufio.NewReader(inConn) } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
var err error } else if *s.cfg.LocalType == TYPE_KCP {
var connType uint8 err = sc.ListenKCP(s.cfg.KCP, s.handler)
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 err != nil { if err != nil {
return 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 return
} }
func (s *MuxBridge) Clean() { func (s *MuxBridge) Clean() {
s.StopService() 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) { func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
try := 20 try := 20
for { for {
if s.isStop {
return
}
try-- try--
if try == 0 { if try == 0 {
break break
@ -124,19 +227,35 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
if key == "*" { if key == "*" {
key = s.router.GetKey() key = s.router.GetKey()
} }
session, ok := s.clientControlConns.Get(key) _group, ok := s.clientControlConns.Get(key)
if !ok { 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) time.Sleep(time.Second * 3)
continue 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() stream, err := session.(*smux.Session).OpenStream()
session.(*smux.Session).SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err) log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
log.Printf("%s server %s stream created", key, serverID) log.Printf("stream %s -> %s created", serverID, key)
die1 := make(chan bool, 1) die1 := make(chan bool, 1)
die2 := make(chan bool, 1) die2 := make(chan bool, 1)
go func() { go func() {

View File

@ -2,6 +2,7 @@ package services
import ( import (
"crypto/tls" "crypto/tls"
"fmt"
"io" "io"
"log" "log"
"net" "net"
@ -13,98 +14,177 @@ import (
) )
type MuxClient struct { type MuxClient struct {
cfg MuxClientArgs cfg MuxClientArgs
isStop bool
sessions utils.ConcurrentMap
} }
func NewMuxClient() Service { func NewMuxClient() Service {
return &MuxClient{ 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 != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) log.Printf("use tls parent %s", *s.cfg.Parent)
} else { } else {
log.Fatalf("parent required") err = fmt.Errorf("parent required")
return
} }
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { 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() { 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) { func (s *MuxClient) Start(args interface{}) (err error) {
s.cfg = args.(MuxClientArgs) s.cfg = args.(MuxClientArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
log.Printf("proxy on mux client mode, compress %v", *s.cfg.IsCompress) }
for { if err = s.InitService(); err != nil {
var _conn tls.Conn return
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes) }
if err != nil { log.Printf("client started")
log.Printf("connection err: %s, retrying...", err) count := 1
time.Sleep(time.Second * 3) if *s.cfg.SessionCount > 0 {
continue count = *s.cfg.SessionCount
} }
conn := net.Conn(&_conn) for i := 1; i <= count; i++ {
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, *s.cfg.Key)) key := fmt.Sprintf("worker[%d]", i)
if err != nil { log.Printf("session %s started", key)
conn.Close() go func(i int) {
log.Printf("connection err: %s, retrying...", err) defer func() {
time.Sleep(time.Second * 3) e := recover()
continue if e != nil {
} log.Printf("session worker crashed: %s", e)
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)
} }
}() }()
} 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() { func (s *MuxClient) Clean() {
s.StopService() 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) { func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
for { for {
if s.isStop {
return
}
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
srcAddr, body, err := utils.ReadUDPPacket(inConn) srcAddr, body, err := utils.ReadUDPPacket(inConn)
inConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("udp packet revecived fail, err: %s", err) log.Printf("udp packet revecived fail, err: %s", err)
log.Printf("connection %s released", ID) log.Printf("connection %s released", ID)
@ -112,7 +192,15 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
break break
} else { } else {
//log.Printf("udp packet revecived:%s,%v", srcAddr, body) //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))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write(body) _, err = conn.Write(body)
conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 1024) buf := make([]byte, 1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
return return
@ -147,7 +238,9 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
respBody := buf[0:length] respBody := buf[0:length]
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody) //log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
bs := utils.UDPPacket(srcAddr, respBody) bs := utils.UDPPacket(srcAddr, respBody)
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = (*inConn).Write(bs) _, err = (*inConn).Write(bs)
(*inConn).SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("send udp response fail ,ERR:%s", err) log.Printf("send udp response fail ,ERR:%s", err)
inConn.Close() inConn.Close()
@ -160,6 +253,9 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
var outConn net.Conn var outConn net.Conn
i := 0 i := 0
for { for {
if s.isStop {
return
}
i++ i++
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout) outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
if err == nil || i == 3 { if err == nil || i == 3 {

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"math/rand"
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/utils" "snail007/proxy/utils"
@ -17,18 +18,20 @@ import (
) )
type MuxServer struct { type MuxServer struct {
cfg MuxServerArgs cfg MuxServerArgs
udpChn chan MuxUDPItem udpChn chan MuxUDPItem
sc utils.ServerChannel sc utils.ServerChannel
session *smux.Session sessions utils.ConcurrentMap
lockChn chan bool lockChn chan bool
isStop bool
udpConn *net.Conn
} }
type MuxServerManager struct { type MuxServerManager struct {
cfg MuxServerArgs cfg MuxServerArgs
udpChn chan MuxUDPItem udpChn chan MuxUDPItem
sc utils.ServerChannel
serverID string serverID string
servers []*Service
} }
func NewMuxServerManager() Service { func NewMuxServerManager() Service {
@ -36,18 +39,25 @@ func NewMuxServerManager() Service {
cfg: MuxServerArgs{}, cfg: MuxServerArgs{},
udpChn: make(chan MuxUDPItem, 50000), udpChn: make(chan MuxUDPItem, 50000),
serverID: utils.Uniqueid(), serverID: utils.Uniqueid(),
servers: []*Service{},
} }
} }
func (s *MuxServerManager) Start(args interface{}) (err error) { func (s *MuxServerManager) Start(args interface{}) (err error) {
s.cfg = args.(MuxServerArgs) s.cfg = args.(MuxServerArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
return
}
if *s.cfg.Parent != "" { 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 { } 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("server id: %s", s.serverID)
//log.Printf("route:%v", *s.cfg.Route) //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) remote = fmt.Sprintf("127.0.0.1%s", remote)
} }
err = server.Start(MuxServerArgs{ err = server.Start(MuxServerArgs{
CertBytes: s.cfg.CertBytes, CertBytes: s.cfg.CertBytes,
KeyBytes: s.cfg.KeyBytes, KeyBytes: s.cfg.KeyBytes,
Parent: s.cfg.Parent, Parent: s.cfg.Parent,
CertFile: s.cfg.CertFile, CertFile: s.cfg.CertFile,
KeyFile: s.cfg.KeyFile, KeyFile: s.cfg.KeyFile,
Local: &local, Local: &local,
IsUDP: &IsUDP, IsUDP: &IsUDP,
Remote: &remote, Remote: &remote,
Key: &KEY, Key: &KEY,
Timeout: s.cfg.Timeout, Timeout: s.cfg.Timeout,
Mgr: s, Mgr: s,
IsCompress: s.cfg.IsCompress, IsCompress: s.cfg.IsCompress,
SessionCount: s.cfg.SessionCount,
KCP: s.cfg.KCP,
ParentType: s.cfg.ParentType,
}) })
if err != nil { if err != nil {
return return
} }
s.servers = append(s.servers, &server)
} }
return return
} }
@ -98,21 +112,34 @@ func (s *MuxServerManager) Clean() {
s.StopService() s.StopService()
} }
func (s *MuxServerManager) StopService() { func (s *MuxServerManager) StopService() {
} for _, server := range s.servers {
func (s *MuxServerManager) CheckArgs() { (*server).Clean()
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
} }
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 { func NewMuxServer() Service {
return &MuxServer{ return &MuxServer{
cfg: MuxServerArgs{}, cfg: MuxServerArgs{},
udpChn: make(chan MuxUDPItem, 50000), udpChn: make(chan MuxUDPItem, 50000),
lockChn: make(chan bool, 1), lockChn: make(chan bool, 1),
sessions: utils.NewConcurrentMap(),
isStop: false,
} }
} }
@ -122,19 +149,49 @@ type MuxUDPItem struct {
srcAddr *net.UDPAddr srcAddr *net.UDPAddr
} }
func (s *MuxServer) InitService() { func (s *MuxServer) StopService() {
s.UDPConnDeamon() defer func() {
} e := recover()
func (s *MuxServer) CheckArgs() { if e != nil {
if *s.cfg.Remote == "" { log.Printf("stop server service crashed,%s", e)
log.Fatalf("remote required") } 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) { func (s *MuxServer) Start(args interface{}) (err error) {
s.cfg = args.(MuxServerArgs) s.cfg = args.(MuxServerArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
}
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p) s.sc = utils.NewServerChannel(host, p)
@ -149,7 +206,7 @@ func (s *MuxServer) Start(args interface{}) (err error) {
if err != nil { if err != nil {
return return
} }
log.Printf("proxy on udp mux server mode %s", (*s.sc.UDPListener).LocalAddr()) log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr())
} else { } else {
err = s.sc.ListenTCP(func(inConn net.Conn) { err = s.sc.ListenTCP(func(inConn net.Conn) {
defer func() { defer func() {
@ -160,6 +217,9 @@ func (s *MuxServer) Start(args interface{}) (err error) {
var outConn net.Conn var outConn net.Conn
var ID string var ID string
for { for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn() outConn, ID, err = s.GetOutConn()
if err != nil { if err != nil {
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
@ -198,15 +258,19 @@ func (s *MuxServer) Start(args interface{}) (err error) {
if err != nil { if err != nil {
return 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 return
} }
func (s *MuxServer) Clean() { func (s *MuxServer) Clean() {
s.StopService()
} }
func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) { 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 { if err != nil {
log.Printf("connection err: %s", err) log.Printf("connection err: %s", err)
return return
@ -216,7 +280,9 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
remoteAddr = "udp:" + *s.cfg.Remote remoteAddr = "udp:" + *s.cfg.Remote
} }
ID = utils.Uniqueid() 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)) _, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("write stream data err: %s ,retrying...", err) log.Printf("write stream data err: %s ,retrying...", err)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
@ -224,7 +290,7 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
} }
return return
} }
func (s *MuxServer) GetConn() (conn net.Conn, err error) { func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
select { select {
case s.lockChn <- true: case s.lockChn <- true:
default: default:
@ -234,34 +300,66 @@ func (s *MuxServer) GetConn() (conn net.Conn, err error) {
defer func() { defer func() {
<-s.lockChn <-s.lockChn
}() }()
if s.session == nil { var session *smux.Session
var _conn tls.Conn _session, ok := s.sessions.Get(index)
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes) if !ok {
var c net.Conn
c, err = s.getParentConn()
if err != nil { if err != nil {
s.session = nil
return 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)) _, err = c.Write(utils.BuildPacket(CONN_SERVER, *s.cfg.Key, s.cfg.Mgr.serverID))
c.SetDeadline(time.Time{})
if err != nil { if err != nil {
c.Close() c.Close()
s.session = nil
return return
} }
if err == nil { if err == nil {
s.session, err = smux.Client(c, nil) session, err = smux.Client(c, nil)
if err != nil { if err != nil {
s.session = nil
return 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 { if err != nil {
s.session.Close() session.Close()
s.session = nil 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 return
} }
func (s *MuxServer) UDPConnDeamon() { func (s *MuxServer) UDPConnDeamon() {
@ -275,10 +373,19 @@ func (s *MuxServer) UDPConnDeamon() {
var ID string var ID string
var err error var err error
for { for {
if s.isStop {
return
}
item := <-s.udpChn item := <-s.udpChn
RETRY: RETRY:
if s.isStop {
return
}
if outConn == nil { if outConn == nil {
for { for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn() outConn, ID, err = s.GetOutConn()
if err != nil { if err != nil {
outConn = nil outConn = nil
@ -288,11 +395,17 @@ func (s *MuxServer) UDPConnDeamon() {
continue continue
} else { } else {
go func(outConn net.Conn, ID string) { go func(outConn net.Conn, ID string) {
go func() { if s.udpConn != nil {
// outConn.Close() (*s.udpConn).Close()
}() }
s.udpConn = &outConn
for { for {
if s.isStop {
return
}
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn) srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body) log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
log.Printf("UDP deamon connection %s exited", ID) log.Printf("UDP deamon connection %s exited", ID)
@ -306,7 +419,9 @@ func (s *MuxServer) UDPConnDeamon() {
} }
port, _ := strconv.Atoi(_srcAddr[1]) port, _ := strconv.Atoi(_srcAddr[1])
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port} 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) _, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
s.sc.UDPListener.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err) log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
continue continue

View File

@ -2,7 +2,6 @@ package services
import ( import (
"fmt" "fmt"
"log"
"runtime/debug" "runtime/debug"
) )
@ -19,33 +18,43 @@ type ServiceItem struct {
var servicesMap = map[string]*ServiceItem{} var servicesMap = map[string]*ServiceItem{}
func Regist(name string, s Service, args interface{}) { func Regist(name string, s Service, args interface{}) {
Stop(name)
servicesMap[name] = &ServiceItem{ servicesMap[name] = &ServiceItem{
S: s, S: s,
Args: args, Args: args,
Name: name, 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) { func Run(name string, args ...interface{}) (service *ServiceItem, err error) {
service, ok := servicesMap[name] service, ok := servicesMap[name]
if ok { if ok {
go func() { defer func() {
defer func() { e := recover()
err := recover() if e != nil {
if err != nil { err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
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)
} }
}() }()
} if len(args) == 1 {
if !ok { 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) err = fmt.Errorf("service %s not found", name)
} }
return return

View File

@ -9,6 +9,7 @@ import (
"runtime/debug" "runtime/debug"
"snail007/proxy/utils" "snail007/proxy/utils"
"snail007/proxy/utils/aes" "snail007/proxy/utils/aes"
"snail007/proxy/utils/conncrypt"
"snail007/proxy/utils/socks" "snail007/proxy/utils/socks"
"strings" "strings"
"time" "time"
@ -23,7 +24,10 @@ type Socks struct {
sshClient *ssh.Client sshClient *ssh.Client
lockChn chan bool lockChn chan bool
udpSC utils.ServerChannel udpSC utils.ServerChannel
sc *utils.ServerChannel
domainResolver utils.DomainResolver domainResolver utils.DomainResolver
isStop bool
userConns utils.ConcurrentMap
} }
func NewSocks() Service { func NewSocks() Service {
@ -32,27 +36,39 @@ func NewSocks() Service {
checker: utils.Checker{}, checker: utils.Checker{},
basicAuth: utils.BasicAuth{}, basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1), lockChn: make(chan bool, 1),
isStop: false,
userConns: utils.NewConcurrentMap(),
} }
} }
func (s *Socks) CheckArgs() { func (s *Socks) CheckArgs() (err error) {
var err error
if *s.cfg.LocalType == "tls" { if *s.cfg.LocalType == "tls" || (*s.cfg.Parent != "" && *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
}
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.Parent != "" {
if *s.cfg.ParentType == "" { if *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.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
if *s.cfg.SSHUser == "" { if *s.cfg.SSHUser == "" {
log.Fatalf("ssh user required") err = fmt.Errorf("ssh user required")
return
} }
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" { 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 != "" { if *s.cfg.SSHPassword != "" {
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword) s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
@ -60,7 +76,8 @@ func (s *Socks) CheckArgs() {
var SSHSigner ssh.Signer var SSHSigner ssh.Signer
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile) s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
if err != nil { 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 != "" { if *s.cfg.SSHKeyFileSalt != "" {
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*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) SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
} }
if err != nil { 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) s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
} }
} }
} }
return
} }
func (s *Socks) InitService() { func (s *Socks) InitService() (err error) {
s.InitBasicAuth() s.InitBasicAuth()
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) (*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) s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
err := s.ConnectSSH() e := s.ConnectSSH()
if err != nil { if e != nil {
log.Fatalf("init service fail, ERR: %s", err) err = fmt.Errorf("init service fail, ERR: %s", e)
return
} }
go func() { go func() {
//循环检查ssh网络连通性 //循环检查ssh网络连通性
for { for {
if s.isStop {
return
}
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2) conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
if err == nil { if err == nil {
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write([]byte{0}) _, err = conn.Write([]byte{0})
conn.SetDeadline(time.Time{})
} }
if err != nil { if err != nil {
if s.sshClient != nil { if s.sshClient != nil {
@ -111,26 +135,48 @@ func (s *Socks) InitService() {
log.Println("warn: socks udp not suppored for ssh") log.Println("warn: socks udp not suppored for ssh")
} else { } else {
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal) s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal)
err := s.udpSC.ListenUDP(s.udpCallback) e := s.udpSC.ListenUDP(s.udpCallback)
if err != nil { if e != nil {
log.Fatalf("init udp service fail, ERR: %s", err) err = fmt.Errorf("init udp service fail, ERR: %s", e)
return
} }
log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr()) log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
} }
return
} }
func (s *Socks) StopService() { 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 { if s.sshClient != nil {
s.sshClient.Close() s.sshClient.Close()
} }
if s.udpSC.UDPListener != nil { if s.udpSC.UDPListener != nil {
s.udpSC.UDPListener.Close() 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) { func (s *Socks) Start(args interface{}) (err error) {
//start() //start()
s.cfg = args.(SocksArgs) s.cfg = args.(SocksArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
}
if err = s.InitService(); err != nil {
s.InitService()
}
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *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 { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.socksConnCallback) err = sc.ListenTCP(s.socksConnCallback)
} else if *s.cfg.LocalType == TYPE_TLS { } 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 { } 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 { if err != nil {
return return
} }
s.sc = &sc
log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr()) log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
return 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))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
_, err = conn.Write(rawB) _, err = conn.Write(rawB)
conn.SetDeadline(time.Time{})
log.Printf("udp request:%v", len(rawB)) log.Printf("udp request:%v", len(rawB))
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) 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()) //log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 10*1024) buf := make([]byte, 10*1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close() conn.Close()
@ -238,10 +288,14 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
conn.Close() conn.Close()
return return
} }
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(d, srcAddr) s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
log.Printf("udp reply:%v", len(d)) log.Printf("udp reply:%v", len(d))
} else { } else {
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr) s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
log.Printf("udp reply:%v", len(respBody)) 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))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
_, err = conn.Write(p.Data()) _, err = conn.Write(p.Data())
conn.SetDeadline(time.Time{})
log.Printf("udp send:%v", len(p.Data())) log.Printf("udp send:%v", len(p.Data()))
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) 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()) //log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 10*1024) buf := make([]byte, 10*1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close() conn.Close()
@ -285,9 +343,13 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
conn.Close() conn.Close()
return return
} }
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(d, srcAddr) s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
} else { } else {
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr) s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{})
} }
log.Printf("udp reply:%v", len(respPacket)) log.Printf("udp reply:%v", len(respPacket))
} }
@ -300,6 +362,14 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
inConn.Close() 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 //method select request
@ -359,9 +429,15 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
//auth //auth
_addr := strings.Split(inConn.RemoteAddr().String(), ":") _addr := strings.Split(inConn.RemoteAddr().String(), ":")
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") { 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.Write([]byte{0x01, 0x00})
inConn.SetDeadline(time.Time{})
} else { } else {
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
inConn.Write([]byte{0x01, 0x01}) inConn.Write([]byte{0x01, 0x01})
inConn.SetDeadline(time.Time{})
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
return return
} }
@ -415,6 +491,9 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
return return
} }
for { for {
if s.isStop {
return
}
if *s.cfg.Always { if *s.cfg.Always {
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
} else { } else {
@ -451,6 +530,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
request.TCPReply(socks.REP_NETWOR_UNREACHABLE) request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
return return
} }
log.Printf("use proxy %v : %s", useProxy, request.Addr()) log.Printf("use proxy %v : %s", useProxy, request.Addr())
request.TCPReply(socks.REP_SUCCESS) 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{}) { utils.IoBind(*inConn, outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, request.Addr()) 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{}) { func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
switch *s.cfg.ParentType { switch *s.cfg.ParentType {
@ -471,10 +556,10 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
case "tcp": case "tcp":
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
var _outConn tls.Conn 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) outConn = net.Conn(&_outConn)
} else if *s.cfg.ParentType == "kcp" { } 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 { } else {
outConn, err = utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout) 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) err = fmt.Errorf("connect fail,%s", err)
return 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 buf = make([]byte, 1024)
//var n int //var n int
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(methodBytes) _, err = outConn.Write(methodBytes)
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
err = fmt.Errorf("write method fail,%s", err) err = fmt.Errorf("write method fail,%s", err)
return return
} }
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Read(buf) _, err = outConn.Read(buf)
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
err = fmt.Errorf("read method reply fail,%s", err) err = fmt.Errorf("read method reply fail,%s", err)
return return
} }
//resp := buf[:n] //resp := buf[:n]
//log.Printf("resp:%v", resp) //log.Printf("resp:%v", resp)
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(reqBytes) _, err = outConn.Write(reqBytes)
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
err = fmt.Errorf("write req detail fail,%s", err) err = fmt.Errorf("write req detail fail,%s", err)
return return
} }
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Read(buf) _, err = outConn.Read(buf)
outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
err = fmt.Errorf("read req reply fail,%s", err) err = fmt.Errorf("read req reply fail,%s", err)
return return
@ -514,7 +614,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
maxTryCount := 1 maxTryCount := 1
tryCount := 0 tryCount := 0
RETRY: RETRY:
if tryCount >= maxTryCount { if tryCount >= maxTryCount || s.isStop {
return return
} }
wait := make(chan bool, 1) wait := make(chan bool, 1)

View File

@ -2,72 +2,116 @@ package services
import ( import (
"bytes" "bytes"
"encoding/base64"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/utils" "snail007/proxy/utils"
"snail007/proxy/utils/conncrypt"
"snail007/proxy/utils/socks" "snail007/proxy/utils/socks"
"strconv" "strconv"
"strings" "strings"
"time"
) )
type SPS struct { type SPS struct {
outPool utils.OutPool outPool utils.OutConn
cfg SPSArgs cfg SPSArgs
domainResolver utils.DomainResolver domainResolver utils.DomainResolver
basicAuth utils.BasicAuth
serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap
} }
func NewSPS() Service { func NewSPS() Service {
return &SPS{ return &SPS{
outPool: utils.OutPool{}, outPool: utils.OutConn{},
cfg: SPSArgs{}, 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 == "" { 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 == "" { 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 { 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() s.InitOutConnPool()
if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
}
err = s.InitBasicAuth()
return
} }
func (s *SPS) InitOutConnPool() { func (s *SPS) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte, //dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int //parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutConn(
0, 0,
*s.cfg.ParentType, *s.cfg.ParentType,
*s.cfg.KCPMethod, s.cfg.KCP,
*s.cfg.KCPKey, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,
0,
0,
) )
} }
} }
func (s *SPS) StopService() { func (s *SPS) StopService() {
if s.outPool.Pool != nil { defer func() {
s.outPool.Pool.ReleaseAll() 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) { func (s *SPS) Start(args interface{}) (err error) {
s.cfg = args.(SPSArgs) 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) 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, ",") { for _, addr := range strings.Split(*s.cfg.Local, ",") {
if addr != "" { if addr != "" {
host, port, _ := net.SplitHostPort(*s.cfg.Local) 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 { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_TLS { } 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 { } 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 { if err != nil {
return return
} }
log.Printf("%s http(s)+socks proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr()) log.Printf("%s http(s)+socks proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
s.serverChannels = append(s.serverChannels, &sc)
} }
} }
return 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())) 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 var err error
switch *s.cfg.ParentType { switch *s.cfg.ParentType {
case TYPE_KCP: case TYPE_KCP:
@ -110,7 +163,7 @@ func (s *SPS) callback(inConn net.Conn) {
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType) err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
} }
if err != nil { 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) utils.CloseConn(&inConn)
} }
} }
@ -124,51 +177,32 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
return return
} }
address := "" address := ""
var auth socks.Auth
var forwardBytes []byte var forwardBytes []byte
//fmt.Printf("%v", header) //fmt.Printf("%v", header)
if header[0] == socks.VERSION_V5 { if header[0] == socks.VERSION_V5 {
//socks //socks5 server
methodReq, e := socks.NewMethodsRequest(*inConn, header) var serverConn *socks.ServerConn
if e != nil { if s.IsBasicAuth() {
log.Printf("new method request err:%s", e) serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header)
utils.CloseConn(inConn) } else {
err = e.(error) serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header)
}
if err = serverConn.Handshake(); err != nil {
return return
} }
if !methodReq.Select(socks.Method_NO_AUTH) { address = serverConn.Target()
methodReq.Reply(socks.Method_NONE_ACCEPTABLE) auth = serverConn.AuthData()
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)
} else if bytes.IndexByte(header, '\n') != -1 { } else if bytes.IndexByte(header, '\n') != -1 {
//http //http
var request utils.HTTPRequest 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 { if err != nil {
log.Printf("new http request fail,ERR: %s", err) log.Printf("new http request fail,ERR: %s", err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
@ -182,6 +216,17 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
forwardBytes = request.HeadBuf forwardBytes = request.HeadBuf
} }
address = request.Host 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 { } else {
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header)) log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
utils.CloseConn(inConn) utils.CloseConn(inConn)
@ -190,22 +235,56 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
} }
//connect to parent //connect to parent
var outConn net.Conn var outConn net.Conn
var _outConn interface{} outConn, err = s.outPool.Get()
_outConn, err = s.outPool.Pool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
}
if err != nil { if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err) log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return 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 //ask parent for connect to target address
if *s.cfg.ParentServiceType == "http" { if *s.cfg.ParentServiceType == "http" {
//http parent //http parent
fmt.Fprintf(outConn, "CONNECT %s HTTP/1.1\r\n", address) pb := new(bytes.Buffer)
reply := make([]byte, 100) pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
n, err = outConn.Read(reply) //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 { if err != nil {
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err) log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
@ -215,53 +294,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
//log.Printf("reply: %s", string(reply[:n])) //log.Printf("reply: %s", string(reply[:n]))
} else { } else {
log.Printf("connect %s", address) log.Printf("connect %s", address)
//socks parent //socks client
//send auth type var clientConn *socks.ClientConn
_, err = outConn.Write([]byte{0x05, 0x01, 0x00}) if *s.cfg.ParentAuth != "" {
if err != nil { a := strings.Split(*s.cfg.ParentAuth, ":")
log.Printf("write method to %s fail, err:%s", *s.cfg.Parent, err) if len(a) != 2 {
utils.CloseConn(inConn) err = fmt.Errorf("parent auth data format error")
utils.CloseConn(&outConn) 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 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. //forward client data to target,if necessary.
if len(forwardBytes) > 0 { if len(forwardBytes) > 0 {
@ -272,10 +323,43 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
outAddr := outConn.RemoteAddr().String() outAddr := outConn.RemoteAddr().String()
utils.IoBind((*inConn), outConn, func(err interface{}) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, outAddr) log.Printf("conn %s - %s released", inAddr, outAddr)
s.userConns.Remove(inAddr)
}) })
log.Printf("conn %s - %s connected", inAddr, outAddr) 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 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) { func (s *SPS) buildRequest(address string) (buf []byte, err error) {
host, portStr, err := net.SplitHostPort(address) host, portStr, err := net.SplitHostPort(address)
if err != nil { if err != nil {

View File

@ -14,41 +14,71 @@ import (
) )
type TCP struct { type TCP struct {
outPool utils.OutPool outPool utils.OutConn
cfg TCPArgs cfg TCPArgs
sc *utils.ServerChannel
isStop bool
userConns utils.ConcurrentMap
} }
func NewTCP() Service { func NewTCP() Service {
return &TCP{ return &TCP{
outPool: utils.OutPool{}, outPool: utils.OutConn{},
cfg: TCPArgs{}, cfg: TCPArgs{},
isStop: false,
userConns: utils.NewConcurrentMap(),
} }
} }
func (s *TCP) CheckArgs() { func (s *TCP) CheckArgs() (err error) {
if *s.cfg.Parent == "" { 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 == "" { 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 { 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() s.InitOutConnPool()
return
} }
func (s *TCP) StopService() { func (s *TCP) StopService() {
if s.outPool.Pool != nil { defer func() {
s.outPool.Pool.ReleaseAll() 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) { func (s *TCP) Start(args interface{}) (err error) {
s.cfg = args.(TCPArgs) 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) log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitService()
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p)
@ -56,14 +86,15 @@ func (s *TCP) Start(args interface{}) (err error) {
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_TLS { } 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 { } 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 { if err != nil {
return return
} }
log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr()) log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
s.sc = &sc
return return
} }
@ -96,11 +127,7 @@ func (s *TCP) callback(inConn net.Conn) {
} }
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) { func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
var outConn net.Conn var outConn net.Conn
var _outConn interface{} outConn, err = s.outPool.Get()
_outConn, err = s.outPool.Pool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
}
if err != nil { if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err) log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
@ -112,13 +139,22 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
//outLocalAddr := outConn.LocalAddr().String() //outLocalAddr := outConn.LocalAddr().String()
utils.IoBind((*inConn), outConn, func(err interface{}) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, outAddr) log.Printf("conn %s - %s released", inAddr, outAddr)
s.userConns.Remove(inAddr)
}) })
log.Printf("conn %s - %s connected", inAddr, outAddr) 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 return
} }
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) { func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr()) log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
for { for {
if s.isStop {
(*inConn).Close()
return
}
srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn)) srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn))
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
//log.Printf("connection %s released", srcAddr) //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 { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte, //dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int //parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutConn(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
*s.cfg.KCPMethod, s.cfg.KCP,
*s.cfg.KCPKey, s.cfg.CertBytes, s.cfg.KeyBytes, nil,
s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,
*s.cfg.PoolSize,
*s.cfg.PoolSize*2,
) )
} }
} }

View File

@ -1,12 +1,15 @@
package services package services
import ( import (
"bufio" "bytes"
"fmt"
"log" "log"
"net" "net"
"snail007/proxy/utils" "snail007/proxy/utils"
"strconv" "strconv"
"time" "time"
"github.com/xtaci/smux"
) )
type ServerConn struct { type ServerConn struct {
@ -17,8 +20,7 @@ type TunnelBridge struct {
cfg TunnelBridgeArgs cfg TunnelBridgeArgs
serverConns utils.ConcurrentMap serverConns utils.ConcurrentMap
clientControlConns utils.ConcurrentMap clientControlConns utils.ConcurrentMap
// cmServer utils.ConnManager isStop bool
// cmClient utils.ConnManager
} }
func NewTunnelBridge() Service { func NewTunnelBridge() Service {
@ -26,213 +28,51 @@ func NewTunnelBridge() Service {
cfg: TunnelBridgeArgs{}, cfg: TunnelBridgeArgs{},
serverConns: utils.NewConcurrentMap(), serverConns: utils.NewConcurrentMap(),
clientControlConns: utils.NewConcurrentMap(), clientControlConns: utils.NewConcurrentMap(),
// cmServer: utils.NewConnManager(), isStop: false,
// cmClient: utils.NewConnManager(),
} }
} }
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 == "" { 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() { 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) { func (s *TunnelBridge) Start(args interface{}) (err error) {
s.cfg = args.(TunnelBridgeArgs) s.cfg = args.(TunnelBridgeArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
}
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p)
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) { err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
//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)
}
})
if err != nil { if err != nil {
return return
} }
@ -242,3 +82,111 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
func (s *TunnelBridge) Clean() { func (s *TunnelBridge) Clean() {
s.StopService() 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)
}
}

View File

@ -8,106 +8,74 @@ import (
"net" "net"
"snail007/proxy/utils" "snail007/proxy/utils"
"time" "time"
"github.com/xtaci/smux"
) )
type TunnelClient struct { type TunnelClient struct {
cfg TunnelClientArgs cfg TunnelClientArgs
// cm utils.ConnManager ctrlConn net.Conn
ctrlConn net.Conn isStop bool
userConns utils.ConcurrentMap
} }
func NewTunnelClient() Service { func NewTunnelClient() Service {
return &TunnelClient{ return &TunnelClient{
cfg: TunnelClientArgs{}, cfg: TunnelClientArgs{},
// cm: utils.NewConnManager(), userConns: utils.NewConcurrentMap(),
isStop: false,
} }
} }
func (s *TunnelClient) InitService() { func (s *TunnelClient) InitService() (err error) {
// s.InitHeartbeatDeamon() return
} }
// func (s *TunnelClient) InitHeartbeatDeamon() { func (s *TunnelClient) CheckArgs() (err error) {
// 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() {
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) log.Printf("use tls parent %s", *s.cfg.Parent)
} else { } else {
log.Fatalf("parent required") err = fmt.Errorf("parent required")
return
} }
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { 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() { 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) { func (s *TunnelClient) Start(args interface{}) (err error) {
s.cfg = args.(TunnelClientArgs) s.cfg = args.(TunnelClientArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
}
if err = s.InitService(); err != nil {
return
}
log.Printf("proxy on tunnel client mode") log.Printf("proxy on tunnel client mode")
for { for {
//close all conn if s.isStop {
// s.cm.Remove(*s.cfg.Key) return
}
if s.ctrlConn != nil { if s.ctrlConn != nil {
s.ctrlConn.Close() s.ctrlConn.Close()
} }
@ -122,6 +90,9 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
continue continue
} }
for { for {
if s.isStop {
return
}
var ID, clientLocalAddr, serverID string var ID, clientLocalAddr, serverID string
err = utils.ReadPacketData(s.ctrlConn, &ID, &clientLocalAddr, &serverID) err = utils.ReadPacketData(s.ctrlConn, &ID, &clientLocalAddr, &serverID)
if err != nil { 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) { func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn 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 { if err == nil {
conn = net.Conn(&_conn) 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 return
} }
@ -172,6 +160,12 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
var err error var err error
// for { // for {
for { for {
if s.isStop {
if inConn != nil {
inConn.Close()
}
return
}
// s.cm.RemoveOne(*s.cfg.Key, ID) // s.cm.RemoveOne(*s.cfg.Key, ID)
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID) inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil { if err != nil {
@ -187,6 +181,9 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
log.Printf("conn %s created", ID) log.Printf("conn %s created", ID)
for { for {
if s.isStop {
return
}
srcAddr, body, err := utils.ReadUDPPacket(inConn) srcAddr, body, err := utils.ReadUDPPacket(inConn)
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
log.Printf("connection %s released", ID) log.Printf("connection %s released", ID)
@ -243,6 +240,9 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
var inConn, outConn net.Conn var inConn, outConn net.Conn
var err error var err error
for { for {
if s.isStop {
return
}
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID) inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
@ -256,6 +256,9 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
i := 0 i := 0
for { for {
if s.isStop {
return
}
i++ i++
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout) outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
if err == nil || i == 3 { 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) log.Printf("build connection error, err: %s", err)
return return
} }
inAddr := inConn.RemoteAddr().String()
utils.IoBind(inConn, outConn, func(err interface{}) { utils.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("conn %s released", ID) 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) log.Printf("conn %s created", ID)
} }

View File

@ -11,20 +11,24 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/xtaci/smux"
) )
type TunnelServer struct { type TunnelServer struct {
cfg TunnelServerArgs cfg TunnelServerArgs
udpChn chan UDPItem udpChn chan UDPItem
sc utils.ServerChannel sc utils.ServerChannel
isStop bool
udpConn *net.Conn
userConns utils.ConcurrentMap
} }
type TunnelServerManager struct { type TunnelServerManager struct {
cfg TunnelServerArgs cfg TunnelServerArgs
udpChn chan UDPItem udpChn chan UDPItem
sc utils.ServerChannel
serverID string serverID string
// cm utils.ConnManager servers []*Service
} }
func NewTunnelServerManager() Service { func NewTunnelServerManager() Service {
@ -32,19 +36,24 @@ func NewTunnelServerManager() Service {
cfg: TunnelServerArgs{}, cfg: TunnelServerArgs{},
udpChn: make(chan UDPItem, 50000), udpChn: make(chan UDPItem, 50000),
serverID: utils.Uniqueid(), serverID: utils.Uniqueid(),
// cm: utils.NewConnManager(), servers: []*Service{},
} }
} }
func (s *TunnelServerManager) Start(args interface{}) (err error) { func (s *TunnelServerManager) Start(args interface{}) (err error) {
s.cfg = args.(TunnelServerArgs) s.cfg = args.(TunnelServerArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
return
}
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) log.Printf("use tls parent %s", *s.cfg.Parent)
} else { } 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("server id: %s", s.serverID)
//log.Printf("route:%v", *s.cfg.Route) //log.Printf("route:%v", *s.cfg.Route)
@ -84,6 +93,7 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
if err != nil { if err != nil {
return return
} }
s.servers = append(s.servers, &server)
} }
return return
} }
@ -91,72 +101,22 @@ func (s *TunnelServerManager) Clean() {
s.StopService() s.StopService()
} }
func (s *TunnelServerManager) StopService() { func (s *TunnelServerManager) StopService() {
// s.cm.RemoveAll() for _, server := range s.servers {
} (*server).Clean()
func (s *TunnelServerManager) CheckArgs() {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
} }
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
} }
func (s *TunnelServerManager) InitService() { func (s *TunnelServerManager) CheckArgs() (err error) {
// s.InitHeartbeatDeamon() 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) { func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn() outConn, err = s.GetConn()
if err != nil { 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) { func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn 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 { if err == nil {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
} }
@ -182,8 +142,10 @@ func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
} }
func NewTunnelServer() Service { func NewTunnelServer() Service {
return &TunnelServer{ return &TunnelServer{
cfg: TunnelServerArgs{}, cfg: TunnelServerArgs{},
udpChn: make(chan UDPItem, 50000), udpChn: make(chan UDPItem, 50000),
isStop: false,
userConns: utils.NewConcurrentMap(),
} }
} }
@ -193,19 +155,50 @@ type UDPItem struct {
srcAddr *net.UDPAddr srcAddr *net.UDPAddr
} }
func (s *TunnelServer) InitService() { func (s *TunnelServer) StopService() {
s.UDPConnDeamon() defer func() {
} e := recover()
func (s *TunnelServer) CheckArgs() { if e != nil {
if *s.cfg.Remote == "" { log.Printf("stop server service crashed,%s", e)
log.Fatalf("remote required") } 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) { func (s *TunnelServer) Start(args interface{}) (err error) {
s.cfg = args.(TunnelServerArgs) s.cfg = args.(TunnelServerArgs)
s.CheckArgs() if err = s.CheckArgs(); err != nil {
s.InitService() return
}
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p) s.sc = utils.NewServerChannel(host, p)
@ -231,6 +224,9 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
var outConn net.Conn var outConn net.Conn
var ID string var ID string
for { for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn(CONN_SERVER) outConn, ID, err = s.GetOutConn(CONN_SERVER)
if err != nil { if err != nil {
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
@ -241,12 +237,15 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
break break
} }
} }
inAddr := inConn.RemoteAddr().String()
utils.IoBind(inConn, outConn, func(err interface{}) { 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) log.Printf("%s conn %s released", *s.cfg.Key, ID)
}) })
//add conn if c, ok := s.userConns.Get(inAddr); ok {
// s.cfg.Mgr.cm.Add(s.cfg.Mgr.serverID, ID, &inConn) (*c.(*net.Conn)).Close()
}
s.userConns.Set(inAddr, &inConn)
log.Printf("%s conn %s created", *s.cfg.Key, ID) log.Printf("%s conn %s created", *s.cfg.Key, ID)
}) })
if err != nil { 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) { func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn 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 { if err == nil {
conn = net.Conn(&_conn) 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 return
} }
@ -299,10 +315,19 @@ func (s *TunnelServer) UDPConnDeamon() {
// var cmdChn = make(chan bool, 1000) // var cmdChn = make(chan bool, 1000)
var err error var err error
for { for {
if s.isStop {
return
}
item := <-s.udpChn item := <-s.udpChn
RETRY: RETRY:
if s.isStop {
return
}
if outConn == nil { if outConn == nil {
for { for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn(CONN_SERVER) outConn, ID, err = s.GetOutConn(CONN_SERVER)
if err != nil { if err != nil {
// cmdChn <- true // cmdChn <- true
@ -313,11 +338,14 @@ func (s *TunnelServer) UDPConnDeamon() {
continue continue
} else { } else {
go func(outConn net.Conn, ID string) { go func(outConn net.Conn, ID string) {
go func() { if s.udpConn != nil {
// <-cmdChn (*s.udpConn).Close()
// outConn.Close() }
}() s.udpConn = &outConn
for { for {
if s.isStop {
return
}
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn) srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
log.Printf("UDP deamon connection %s exited", ID) log.Printf("UDP deamon connection %s exited", ID)

View File

@ -8,6 +8,7 @@ import (
"log" "log"
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils" "snail007/proxy/utils"
"strconv" "strconv"
"strings" "strings"
@ -16,44 +17,68 @@ import (
type UDP struct { type UDP struct {
p utils.ConcurrentMap p utils.ConcurrentMap
outPool utils.OutPool outPool utils.OutConn
cfg UDPArgs cfg UDPArgs
sc *utils.ServerChannel sc *utils.ServerChannel
isStop bool
} }
func NewUDP() Service { func NewUDP() Service {
return &UDP{ return &UDP{
outPool: utils.OutPool{}, outPool: utils.OutConn{},
p: utils.NewConcurrentMap(), p: utils.NewConcurrentMap(),
isStop: false,
} }
} }
func (s *UDP) CheckArgs() { func (s *UDP) CheckArgs() (err error) {
if *s.cfg.Parent == "" { 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 == "" { 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" { 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 { if *s.cfg.ParentType != TYPE_UDP {
s.InitOutConnPool() s.InitOutConnPool()
} }
return
} }
func (s *UDP) StopService() { func (s *UDP) StopService() {
if s.outPool.Pool != nil { defer func() {
s.outPool.Pool.ReleaseAll() 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) { func (s *UDP) Start(args interface{}) (err error) {
s.cfg = args.(UDPArgs) 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) 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) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) 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) isNew = !s.p.Has(connKey)
var _conn interface{} var _conn interface{}
if isNew { if isNew {
_conn, err = s.outPool.Pool.Get() _conn, err = s.outPool.Get()
if err != nil { if err != nil {
return nil, false, err 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) { func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
numLocal := crc32.ChecksumIEEE([]byte(localAddr.String())) numLocal := crc32.ChecksumIEEE([]byte(localAddr.String()))
numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String())) numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String()))
mod := uint32(*s.cfg.PoolSize) mod := uint32(10)
if mod == 0 { if mod == 0 {
mod = 10 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()) log.Printf("conn %d created , local: %s", connKey, srcAddr.String())
for { for {
if s.isStop {
conn.Close()
return
}
srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn)) srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn))
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
//log.Printf("connection %d released", connKey) //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 { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP {
//dur int, isTLS bool, certBytes, keyBytes []byte, //dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int //parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutConn(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
"", "", kcpcfg.KCPConfigArgs{},
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CertBytes, s.cfg.KeyBytes, nil,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,
*s.cfg.PoolSize,
*s.cfg.PoolSize*2,
) )
} }
} }

View 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)
}

View File

@ -18,6 +18,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"snail007/proxy/services/kcpcfg"
"golang.org/x/crypto/pbkdf2" "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, ":") h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1]) 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) { func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
conf, err := getRequestTlsConfig(certBytes, keyBytes) conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
if err != nil { if err != nil {
return return
} }
@ -102,8 +103,24 @@ func TlsConnect(host string, port, timeout int, certBytes, keyBytes []byte) (con
} }
return *tls.Client(_conn, conf), err return *tls.Client(_conn, conf), err
} }
func getRequestTlsConfig(certBytes, keyBytes []byte) (conf *tls.Config, err error) { func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
block, _ := pem.Decode(certBytes)
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 { if block == nil {
panic("failed to parse certificate PEM") panic("failed to parse certificate PEM")
} }
@ -111,34 +128,24 @@ func getRequestTlsConfig(certBytes, keyBytes []byte) (conf *tls.Config, err erro
if x509Cert == nil { if x509Cert == nil {
panic("failed to parse block") 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{ conf = &tls.Config{
RootCAs: serverCertPool, RootCAs: serverCertPool,
Certificates: []tls.Certificate{cert}, Certificates: []tls.Certificate{cert},
InsecureSkipVerify: false, InsecureSkipVerify: true,
ServerName: x509Cert.Subject.CommonName, ServerName: x509Cert.Subject.CommonName,
// VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// opts := x509.VerifyOptions{ opts := x509.VerifyOptions{
// Roots: serverCertPool, Roots: serverCertPool,
// } }
// for _, rawCert := range rawCerts { for _, rawCert := range rawCerts {
// cert, _ := x509.ParseCertificate(rawCert) cert, _ := x509.ParseCertificate(rawCert)
// _, err := cert.Verify(opts) _, err := cert.Verify(opts)
// if err != nil { if err != nil {
// return err return err
// } }
// } }
// return nil return nil
// }, },
} }
return 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) conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
return return
} }
func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) { func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.Conn, err error) {
kcpconn, err := kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3) kcpconn, err := kcp.DialWithOptions(hostAndPort, config.Block, *config.DataShard, *config.ParityShard)
if err != nil { if err != nil {
return return
} }
kcpconn.SetNoDelay(1, 10, 2, 1) kcpconn.SetStreamMode(true)
kcpconn.SetWindowSize(1024, 1024) kcpconn.SetWriteDelay(true)
kcpconn.SetMtu(1400) kcpconn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
kcpconn.SetACKNoDelay(false) kcpconn.SetMtu(*config.MTU)
return kcpconn, err 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) func ListenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
if block == nil {
panic("failed to parse certificate PEM")
}
x509Cert, _ := x509.ParseCertificate(block.Bytes)
if x509Cert == nil {
panic("failed to parse block")
}
var cert tls.Certificate var cert tls.Certificate
cert, err = tls.X509KeyPair(certBytes, keyBytes) cert, err = tls.X509KeyPair(certBytes, keyBytes)
if err != nil { if err != nil {
return return
} }
clientCertPool := x509.NewCertPool() clientCertPool := x509.NewCertPool()
ok := clientCertPool.AppendCertsFromPEM(certBytes) caBytes := certBytes
if caCertBytes != nil {
caBytes = caCertBytes
}
ok := clientCertPool.AppendCertsFromPEM(caBytes)
if !ok { if !ok {
err = errors.New("failed to parse root certificate") 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, ClientCAs: clientCertPool,
Certificates: []tls.Certificate{cert}, Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert, 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) _ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
if err == nil { if err == nil {
@ -238,27 +233,95 @@ func CloseConn(conn *net.Conn) {
} }
} }
func Keygen() (err error) { 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"} 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"} 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)] C := CList[int(RandInt(4))%len(CList)]
ST := RandString(int(RandInt(4) % 10)) ST := RandString(int(RandInt(4) % 10))
O := 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)]) 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) //log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN)
cmd = exec.Command("sh", "-c", cmdStr) var out []byte
out, err = cmd.CombinedOutput() if len(os.Args) == 3 && os.Args[2] == "ca" {
if err != nil { cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
log.Printf("err:%s", err) out, err = cmd.CombinedOutput()
return 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 return
} }
func GetAllInterfaceAddr() ([]net.IP, error) { func GetAllInterfaceAddr() ([]net.IP, error) {
@ -461,15 +524,15 @@ func SubBytes(bytes []byte, start, end int) []byte {
} }
return bytes[start:end] return bytes[start:end]
} }
func TlsBytes(cert, key string) (certBytes, keyBytes []byte) { func TlsBytes(cert, key string) (certBytes, keyBytes []byte, err error) {
certBytes, err := ioutil.ReadFile(cert) certBytes, err = ioutil.ReadFile(cert)
if err != nil { if err != nil {
log.Fatalf("err : %s", err) err = fmt.Errorf("err : %s", err)
return return
} }
keyBytes, err = ioutil.ReadFile(key) keyBytes, err = ioutil.ReadFile(key)
if err != nil { if err != nil {
log.Fatalf("err : %s", err) err = fmt.Errorf("err : %s", err)
return return
} }
return return

View File

@ -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)
}

View File

@ -5,6 +5,7 @@ import (
"log" "log"
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/services/kcpcfg"
"strconv" "strconv"
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
@ -23,7 +24,7 @@ func NewServerChannel(ip string, port int) ServerChannel {
ip: ip, ip: ip,
port: port, port: port,
errAcceptHandler: func(err error) { 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)) { func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
sc.errAcceptHandler = fn sc.errAcceptHandler = fn
} }
func (sc *ServerChannel) ListenTls(certBytes, keyBytes []byte, fn func(conn net.Conn)) (err error) { 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) sc.Listener, err = ListenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
if err == nil { if err == nil {
go func() { go func() {
defer func() { defer func() {
@ -138,11 +139,23 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
} }
return return
} }
func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (err error) { func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn)) (err error) {
var l net.Listener lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
l, err = kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), GetKCPBlock(method, key), 10, 3)
if err == nil { 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() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
@ -150,8 +163,8 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (
} }
}() }()
for { for {
var conn net.Conn //var conn net.Conn
conn, err = (*sc.Listener).Accept() conn, err := lis.AcceptKCP()
if err == nil { if err == nil {
go func() { go func() {
defer 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())) 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 { } else {
sc.errAcceptHandler(err) sc.errAcceptHandler(err)

253
utils/socks/client.go Normal file
View 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
View 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
}

View File

@ -3,44 +3,13 @@ package socks
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"net" "net"
"strconv" "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 { type Request struct {
ver uint8 ver uint8
cmd uint8 cmd uint8
@ -57,7 +26,7 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
var b = make([]byte, 1024) var b = make([]byte, 1024)
var n int var n int
req = Request{rw: rw} req = Request{rw: rw}
if len(header) == 1 { if header != nil && len(header) == 1 && len(header[0]) > 1 {
b = header[0] b = header[0]
n = len(header[0]) n = len(header[0])
} else { } else {
@ -71,7 +40,6 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
req.cmd = uint8(b[1]) req.cmd = uint8(b[1])
req.reserve = uint8(b[2]) req.reserve = uint8(b[2])
req.addressType = uint8(b[3]) req.addressType = uint8(b[3])
if b[0] != 0x5 { if b[0] != 0x5 {
err = fmt.Errorf("sosck version supported") err = fmt.Errorf("sosck version supported")
req.TCPReply(REP_REQ_FAIL) 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[4], ipv6[5], ipv6[6], ipv6[7],
ipv6[8], ipv6[9], ipv6[10], ipv6[11], ipv6[8], ipv6[9], ipv6[10], ipv6[11],
) )
if ipv6 != nil && "0000000000255255" != zeroiIPv6 { if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 {
atyp = ATYP_IPV6 atyp = ATYP_IPV6
ipb = ip.To16() ipb = ip.To16()
} }
@ -165,7 +133,7 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
s.rw = &r s.rw = &r
var buf = make([]byte, 300) var buf = make([]byte, 300)
var n int var n int
if len(header) == 1 { if header != nil && len(header) == 1 && len(header[0]) > 1 {
buf = header[0] buf = header[0]
n = len(header[0]) n = len(header[0])
} else { } else {
@ -182,7 +150,6 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
err = fmt.Errorf("socks methods data length error") err = fmt.Errorf("socks methods data length error")
return return
} }
s.ver = buf[0] s.ver = buf[0]
s.methodsCount = buf[1] s.methodsCount = buf[1]
s.methods = buf[2:n] s.methods = buf[2:n]
@ -195,6 +162,9 @@ func (s *MethodsRequest) Version() uint8 {
func (s *MethodsRequest) MethodsCount() uint8 { func (s *MethodsRequest) MethodsCount() uint8 {
return s.methodsCount return s.methodsCount
} }
func (s *MethodsRequest) Methods() []uint8 {
return s.methods
}
func (s *MethodsRequest) Select(method uint8) bool { func (s *MethodsRequest) Select(method uint8) bool {
for _, m := range s.methods { for _, m := range s.methods {
if m == method { if m == method {
@ -211,17 +181,6 @@ func (s *MethodsRequest) Bytes() []byte {
return s.bytes 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) { func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
p = UDPPacket{} p = UDPPacket{}
p.frag = uint8(b[2]) p.frag = uint8(b[2])
@ -249,6 +208,18 @@ func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
p.header = b[:portIndex+2] p.header = b[:portIndex+2]
return 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 { func (s *UDPPacket) Header() []byte {
return s.header return s.header
} }
@ -268,3 +239,104 @@ func (s *UDPPacket) Port() string {
func (s *UDPPacket) Data() []byte { func (s *UDPPacket) Data() []byte {
return s.data 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
}

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"encoding/base64" "encoding/base64"
"encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -12,11 +11,13 @@ import (
"log" "log"
"net" "net"
"net/url" "net/url"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils/sni" "snail007/proxy/utils/sni"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/golang/snappy"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -26,6 +27,7 @@ type Checker struct {
directMap ConcurrentMap directMap ConcurrentMap
interval int64 interval int64
timeout int timeout int
isStop bool
} }
type CheckerItem struct { type CheckerItem struct {
IsHTTPS bool IsHTTPS bool
@ -46,6 +48,7 @@ func NewChecker(timeout int, interval int64, blockedFile, directFile string) Che
data: NewConcurrentMap(), data: NewConcurrentMap(),
interval: interval, interval: interval,
timeout: timeout, timeout: timeout,
isStop: false,
} }
ch.blockedMap = ch.loadMap(blockedFile) ch.blockedMap = ch.loadMap(blockedFile)
ch.directMap = ch.loadMap(directFile) ch.directMap = ch.loadMap(directFile)
@ -79,6 +82,9 @@ func (c *Checker) loadMap(f string) (dataMap ConcurrentMap) {
} }
return return
} }
func (c *Checker) Stop() {
c.isStop = true
}
func (c *Checker) start() { func (c *Checker) start() {
go func() { go func() {
//log.Printf("checker started") //log.Printf("checker started")
@ -105,6 +111,9 @@ func (c *Checker) start() {
}(v.(CheckerItem)) }(v.(CheckerItem))
} }
time.Sleep(time.Second * time.Duration(c.interval)) 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 { } else {
err = fmt.Errorf("token error") 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 { if err != nil && tryCount < ba.authRetry {
log.Print(err) log.Print(err)
@ -315,7 +328,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
req = HTTPRequest{ req = HTTPRequest{
conn: inConn, conn: inConn,
} }
if len(header) == 1 { if header != nil && len(header) == 1 && len(header[0]) > 1 {
buf = header[0] buf = header[0]
n = len(header[0]) n = len(header[0])
} else { } else {
@ -400,17 +413,13 @@ func (req *HTTPRequest) IsHTTPS() bool {
return req.Method == "CONNECT" 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)) // log.Printf("request :%s", string(req.HeadBuf))
code := "407"
authorization := req.getHeader("Proxy-Authorization") authorization := req.getHeader("Proxy-Authorization")
// if authorization == "" {
// authorization = req.getHeader("Authorization") authorization = strings.Trim(authorization, " \r\n\t")
// code = "401"
// }
if authorization == "" { 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) CloseConn(req.conn)
err = errors.New("require auth header data") err = errors.New("require auth header data")
return return
@ -428,6 +437,10 @@ func (req *HTTPRequest) BasicAuth() (err error) {
CloseConn(req.conn) CloseConn(req.conn)
return return
} }
basicInfo = string(user)
return
}
func (req *HTTPRequest) BasicAuth() (err error) {
addr := strings.Split((*req.conn).RemoteAddr().String(), ":") addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
URL := "" URL := ""
if req.IsHTTPS() { if req.IsHTTPS() {
@ -435,10 +448,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
} else { } else {
URL = req.getHTTPURL() URL = req.getHTTPURL()
} }
user, err := req.GetAuthDataStr()
if err != nil {
return
}
authOk := (*req.basicAuth).Check(string(user), addr[0], URL) authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
//log.Printf("auth %s,%v", string(user), authOk) //log.Printf("auth %s,%v", string(user), authOk)
if !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) CloseConn(req.conn)
err = fmt.Errorf("basic auth fail") err = fmt.Errorf("basic auth fail")
return return
@ -488,243 +505,44 @@ func (req *HTTPRequest) addPortIfNot() (newHost string) {
return return
} }
type OutPool struct { type OutConn struct {
Pool ConnPool dur int
dur int typ string
typ string certBytes []byte
certBytes []byte keyBytes []byte
keyBytes []byte caCertBytes []byte
kcpMethod string kcp kcpcfg.KCPConfigArgs
kcpKey string address string
address string timeout int
timeout int
} }
func NewOutPool(dur int, typ, kcpMethod, kcpKey string, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) { func NewOutConn(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int) (op OutConn) {
op = OutPool{ return OutConn{
dur: dur, dur: dur,
typ: typ, typ: typ,
certBytes: certBytes, certBytes: certBytes,
keyBytes: keyBytes, keyBytes: keyBytes,
kcpMethod: kcpMethod, caCertBytes: caCertBytes,
kcpKey: kcpKey, kcp: kcp,
address: address, address: address,
timeout: timeout, 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" { if op.typ == "tls" {
var _conn tls.Conn 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 { if err == nil {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
} }
} else if op.typ == "kcp" { } else if op.typ == "kcp" {
conn, err = ConnectKCPHost(op.address, op.kcpMethod, op.kcpKey) conn, err = ConnectKCPHost(op.address, op.kcp)
} else { } else {
conn, err = ConnectHost(op.address, op.timeout) conn, err = ConnectHost(op.address, op.timeout)
} }
return 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 { type ConnManager struct {
pool ConcurrentMap pool ConcurrentMap
l *sync.Mutex 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) 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
View 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
View File

@ -0,0 +1,4 @@
*.6
tags
test.out
a.out

24
vendor/github.com/pkg/errors/.gitignore generated vendored Executable file
View 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
View 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
View 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
View 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
View 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
View 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