Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
This commit is contained in:
@ -3,6 +3,9 @@ v3.2
|
|||||||
1.内网穿透功能server端-r参数增加了协议和key设置.
|
1.内网穿透功能server端-r参数增加了协议和key设置.
|
||||||
2.手册增加了对-r参数的详细说明.
|
2.手册增加了对-r参数的详细说明.
|
||||||
3.修复了普通模式也检查证书文件的bug.
|
3.修复了普通模式也检查证书文件的bug.
|
||||||
|
4.增加了Socks5支持,目前只支持TCP协议,不支持UDP协议.
|
||||||
|
5.Socks5上级代理支持ssh中转,linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
|
6.http(s)代理增加了ssh中转支持,linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
|
|
||||||
v3.1
|
v3.1
|
||||||
1.优化了内网穿透功能,bridge,client和server只需要启动一个即可。
|
1.优化了内网穿透功能,bridge,client和server只需要启动一个即可。
|
||||||
|
|||||||
80
README.md
80
README.md
@ -11,8 +11,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp代理服务器,支
|
|||||||
- 智能HTTP代理,会自动判断访问的网站是否屏蔽,如果被屏蔽那么就会使用上级代理(前提是配置了上级代理)访问网站;如果访问的网站没有被屏蔽,为了加速访问,代理会直接访问网站,不使用上级代理.
|
- 智能HTTP代理,会自动判断访问的网站是否屏蔽,如果被屏蔽那么就会使用上级代理(前提是配置了上级代理)访问网站;如果访问的网站没有被屏蔽,为了加速访问,代理会直接访问网站,不使用上级代理.
|
||||||
- 域名黑白名单,更加自由的控制网站的访问方式。
|
- 域名黑白名单,更加自由的控制网站的访问方式。
|
||||||
- 跨平台性,无论你是widows,linux,还是mac,甚至是树莓派,都可以很好的运行proxy.
|
- 跨平台性,无论你是widows,linux,还是mac,甚至是树莓派,都可以很好的运行proxy.
|
||||||
- 多协议支持,支持HTTP,TCP,UDP,Websocket代理.
|
- 多协议支持,支持HTTP(S),TCP,UDP,Websocket,SOCKS5代理.
|
||||||
- 支持内网穿透,协议支持TCP和UDP.
|
- 支持内网穿透,协议支持TCP和UDP.
|
||||||
|
- HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
|
|
||||||
### Why need these?
|
### Why need these?
|
||||||
- 当由于安全因素或者限制,我们不能顺畅的访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道,顺畅的访问我们的服务.
|
- 当由于安全因素或者限制,我们不能顺畅的访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道,顺畅的访问我们的服务.
|
||||||
@ -24,7 +25,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp代理服务器,支
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
### 手册目录
|
### 手册目录
|
||||||
本页是最新v3.1手册,其他版本手册请点击下面链接查看.
|
本页是最新v3.2手册,其他版本手册请点击下面链接查看.
|
||||||
|
- [v3.1手册](https://github.com/snail007/goproxy/tree/v3.1)
|
||||||
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0)
|
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0)
|
||||||
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2)
|
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2)
|
||||||
|
|
||||||
@ -91,8 +93,9 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
|||||||
**1.2.普通二级HTTP代理**
|
**1.2.普通二级HTTP代理**
|
||||||
使用本地端口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可以关闭连接池,0就是连接池大小,0为关闭.
|
默认关闭了连接池,如果要加快访问速度,-L可以开启连接池,10就是连接池大小,0为关闭,
|
||||||
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -L 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`
|
||||||
|
|
||||||
@ -129,7 +132,19 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
|||||||
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级HTTP代理.通过--always可以使全部HTTP代理流量强制走上级HTTP代理.
|
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级HTTP代理.通过--always可以使全部HTTP代理流量强制走上级HTTP代理.
|
||||||
`./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.查看帮助**
|
**1.7.HTTP(S)通过SSH中转**
|
||||||
|
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
|
||||||
|
假设有:vps
|
||||||
|
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
|
||||||
|
- 用户user的ssh私钥名称是user.key
|
||||||
|
***1.7.1 ssh用户名和密码的方式***
|
||||||
|
本地HTTP(S)代理28080端口,执行:
|
||||||
|
`./proxy http -T ssh -P "2.2.2.2:22" -u user -A demo -t tcp -p ":28080"`
|
||||||
|
***1.7.2 ssh用户名和密钥的方式***
|
||||||
|
本地HTTP(S)代理28080端口,执行:
|
||||||
|
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||||
|
|
||||||
|
**1.8.查看帮助**
|
||||||
`./proxy help http`
|
`./proxy help http`
|
||||||
|
|
||||||
|
|
||||||
@ -352,9 +367,62 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
`./proxy help tserver`
|
`./proxy help tserver`
|
||||||
`./proxy help tserver`
|
`./proxy help tserver`
|
||||||
|
|
||||||
|
### 5.SOCKS5代理
|
||||||
|
提示:SOCKS5代理,只支持TCP协议,不支持UDP协议,不支持用户名密码认证.
|
||||||
|
**5.1.普通SOCKS5代理**
|
||||||
|
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
||||||
|
|
||||||
|
**5.2.普通二级SOCKS5代理**
|
||||||
|
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080`
|
||||||
|
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||||
|
我们还可以指定网站域名的黑白名单文件,一行一个域名,怕匹配规则是最右批评匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
||||||
|
`./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||||
|
|
||||||
|
**5.3.SOCKS二级代理(加密)**
|
||||||
|
一级SOCKS代理(VPS,IP:22.22.22.22)
|
||||||
|
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
二级SOCKS代理(本地Linux)
|
||||||
|
`./proxy socks -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
那么访问本地的8080端口就是访问VPS上面的代理端口38080.
|
||||||
|
|
||||||
|
二级SOCKS代理(本地windows)
|
||||||
|
`./proxy.exe socks -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
然后设置你的windos系统中,需要通过代理上网的程序的代理为socks5模式,地址为:127.0.0.1,端口为:8080,程序即可通过加密通道通过vps上网。
|
||||||
|
|
||||||
|
**5.4.SOCKS三级代理(加密)**
|
||||||
|
一级SOCKS代理VPS_01,IP:22.22.22.22
|
||||||
|
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||||
|
二级SOCKS代理VPS_02,IP:33.33.33.33
|
||||||
|
`./proxy socks -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
三级SOCKS代理(本地)
|
||||||
|
`./proxy socks -t tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||||
|
那么访问本地的8080端口就是访问一级SOCKS代理上面的代理端口38080.
|
||||||
|
|
||||||
|
**5.5.SOCKS代理流量强制走上级SOCKS代理**
|
||||||
|
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级SOCKS代理.通过--always可以使全部SOCKS代理流量强制走上级SOCKS代理.
|
||||||
|
`./proxy socks --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
**5.6.SOCKS通过SSH中转**
|
||||||
|
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
|
||||||
|
假设有:vps
|
||||||
|
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
|
||||||
|
- 用户user的ssh私钥名称是user.key
|
||||||
|
***5.6.1 ssh用户名和密码的方式***
|
||||||
|
本地SOCKS5代理28080端口,执行:
|
||||||
|
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -A demo -t tcp -p ":28080"`
|
||||||
|
***5.6.2 ssh用户名和密钥的方式***
|
||||||
|
本地SOCKS5代理28080端口,执行:
|
||||||
|
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||||
|
|
||||||
|
那么访问本地的28080端口就是通过VPS访问目标地址.
|
||||||
|
|
||||||
|
**5.7.查看帮助**
|
||||||
|
`./proxy help socks`
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- socks5代理支持.
|
- SOCKS5增加用户名密码认证
|
||||||
|
|
||||||
### 如何使用源码?
|
### 如何使用源码?
|
||||||
cd进入你的go src目录,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
|
cd进入你的go src目录,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
|
||||||
编译直接:go build
|
编译直接:go build
|
||||||
|
|||||||
86
config.go
86
config.go
@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"proxy/services"
|
"proxy/services"
|
||||||
@ -24,7 +23,7 @@ func initConfig() (err error) {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args := services.Args{}
|
|
||||||
//define args
|
//define args
|
||||||
tcpArgs := services.TCPArgs{}
|
tcpArgs := services.TCPArgs{}
|
||||||
httpArgs := services.HTTPArgs{}
|
httpArgs := services.HTTPArgs{}
|
||||||
@ -32,18 +31,18 @@ func initConfig() (err error) {
|
|||||||
tunnelClientArgs := services.TunnelClientArgs{}
|
tunnelClientArgs := services.TunnelClientArgs{}
|
||||||
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
||||||
udpArgs := services.UDPArgs{}
|
udpArgs := services.UDPArgs{}
|
||||||
|
socksArgs := services.SocksArgs{}
|
||||||
//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)
|
||||||
args.Parent = app.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
|
||||||
certTLS := app.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
|
||||||
keyTLS := app.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
|
||||||
|
|
||||||
//########http#########
|
//########http#########
|
||||||
http := app.Command("http", "proxy on http mode")
|
http := app.Command("http", "proxy on http mode")
|
||||||
httpArgs.LocalType = http.Flag("local-type", "parent protocol type <tls|tcp>").Default("tcp").Short('t').Enum("tls", "tcp")
|
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp>").Short('T').Enum("tls", "tcp")
|
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>").Default("tcp").Short('t').Enum("tls", "tcp")
|
||||||
|
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp|ssh>").Short('T').Enum("tls", "tcp", "ssh")
|
||||||
httpArgs.Always = http.Flag("always", "always use parent proxy").Default("false").Bool()
|
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.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.HTTPTimeout = http.Flag("http-timeout", "check domain if blocked , http request timeout milliseconds when connect to host").Default("3000").Int()
|
||||||
@ -55,9 +54,16 @@ func initConfig() (err error) {
|
|||||||
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.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").Short('p').Default(":33080").String()
|
httpArgs.Local = http.Flag("local", "local ip:port to listen").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()
|
||||||
|
|
||||||
//########tcp#########
|
//########tcp#########
|
||||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
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('t').Default("2000").Int()
|
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('t').Default("2000").Int()
|
||||||
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
|
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
|
||||||
tcpArgs.IsTLS = tcp.Flag("tls", "proxy on tls mode").Default("false").Bool()
|
tcpArgs.IsTLS = tcp.Flag("tls", "proxy on tls mode").Default("false").Bool()
|
||||||
@ -67,6 +73,9 @@ func initConfig() (err error) {
|
|||||||
|
|
||||||
//########udp#########
|
//########udp#########
|
||||||
udp := app.Command("udp", "proxy on udp mode")
|
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.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.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
||||||
@ -75,6 +84,9 @@ func initConfig() (err error) {
|
|||||||
|
|
||||||
//########tunnel-server#########
|
//########tunnel-server#########
|
||||||
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
|
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.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.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
|
||||||
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
|
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
|
||||||
@ -82,35 +94,39 @@ func initConfig() (err error) {
|
|||||||
|
|
||||||
//########tunnel-client#########
|
//########tunnel-client#########
|
||||||
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
|
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.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()
|
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
|
||||||
|
|
||||||
//########tunnel-bridge#########
|
//########tunnel-bridge#########
|
||||||
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
|
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.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()
|
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|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "ssh")
|
||||||
|
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp>").Default("tcp").Short('t').Enum("tls", "tcp")
|
||||||
|
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").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("2000").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()
|
||||||
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
|
||||||
if *httpArgs.ParentType == "tls" ||
|
|
||||||
*tcpArgs.ParentType == "tls" ||
|
|
||||||
*udpArgs.ParentType == "tls" ||
|
|
||||||
*httpArgs.LocalType == "tls" ||
|
|
||||||
*tcpArgs.IsTLS ||
|
|
||||||
serviceName == "tserver" ||
|
|
||||||
serviceName == "tclient" ||
|
|
||||||
serviceName == "tbridge" {
|
|
||||||
args.CertBytes, args.KeyBytes = tlsBytes(*certTLS, *keyTLS)
|
|
||||||
}
|
|
||||||
|
|
||||||
//common args
|
|
||||||
httpArgs.Args = args
|
|
||||||
tcpArgs.Args = args
|
|
||||||
udpArgs.Args = args
|
|
||||||
tunnelBridgeArgs.Args = args
|
|
||||||
tunnelClientArgs.Args = args
|
|
||||||
tunnelServerArgs.Args = args
|
|
||||||
|
|
||||||
poster()
|
poster()
|
||||||
//regist services and run service
|
//regist services and run service
|
||||||
services.Regist("http", services.NewHTTP(), httpArgs)
|
services.Regist("http", services.NewHTTP(), httpArgs)
|
||||||
@ -119,9 +135,10 @@ func initConfig() (err error) {
|
|||||||
services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs)
|
services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs)
|
||||||
services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs)
|
services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs)
|
||||||
services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs)
|
services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs)
|
||||||
|
services.Regist("socks", services.NewSocks(), socksArgs)
|
||||||
service, err = services.Run(serviceName)
|
service, err = services.Run(serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("run service [%s] fail, ERR:%s", service, err)
|
log.Fatalf("run service [%s] fail, ERR:%s", serviceName, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -138,16 +155,3 @@ func poster() {
|
|||||||
|
|
||||||
v%s`+" by snail , blog : http://www.host900.com/\n\n", APP_VERSION)
|
v%s`+" by snail , blog : http://www.host900.com/\n\n", APP_VERSION)
|
||||||
}
|
}
|
||||||
func tlsBytes(cert, key string) (certBytes, keyBytes []byte) {
|
|
||||||
certBytes, err := ioutil.ReadFile(cert)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("err : %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keyBytes, err = ioutil.ReadFile(key)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("err : %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
|
import "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()
|
||||||
|
|
||||||
@ -13,13 +15,12 @@ const (
|
|||||||
CONN_CLIENT = uint8(3)
|
CONN_CLIENT = uint8(3)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Args struct {
|
type TunnelServerArgs struct {
|
||||||
Parent *string
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
CertBytes []byte
|
CertBytes []byte
|
||||||
KeyBytes []byte
|
KeyBytes []byte
|
||||||
}
|
|
||||||
type TunnelServerArgs struct {
|
|
||||||
Args
|
|
||||||
Local *string
|
Local *string
|
||||||
IsUDP *bool
|
IsUDP *bool
|
||||||
Key *string
|
Key *string
|
||||||
@ -28,17 +29,29 @@ type TunnelServerArgs struct {
|
|||||||
Route *[]string
|
Route *[]string
|
||||||
}
|
}
|
||||||
type TunnelClientArgs struct {
|
type TunnelClientArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Key *string
|
Key *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
}
|
}
|
||||||
type TunnelBridgeArgs struct {
|
type TunnelBridgeArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
}
|
}
|
||||||
type TCPArgs struct {
|
type TCPArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
IsTLS *bool
|
IsTLS *bool
|
||||||
@ -48,7 +61,11 @@ type TCPArgs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HTTPArgs struct {
|
type HTTPArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
Always *bool
|
Always *bool
|
||||||
HTTPTimeout *int
|
HTTPTimeout *int
|
||||||
@ -62,15 +79,46 @@ type HTTPArgs struct {
|
|||||||
Timeout *int
|
Timeout *int
|
||||||
PoolSize *int
|
PoolSize *int
|
||||||
CheckParentInterval *int
|
CheckParentInterval *int
|
||||||
|
SSHKeyFile *string
|
||||||
|
SSHKeyFileSalt *string
|
||||||
|
SSHPassword *string
|
||||||
|
SSHUser *string
|
||||||
|
SSHKeyBytes []byte
|
||||||
|
SSHAuthMethod ssh.AuthMethod
|
||||||
}
|
}
|
||||||
type UDPArgs struct {
|
type UDPArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
PoolSize *int
|
PoolSize *int
|
||||||
CheckParentInterval *int
|
CheckParentInterval *int
|
||||||
}
|
}
|
||||||
|
type SocksArgs struct {
|
||||||
|
Parent *string
|
||||||
|
ParentType *string
|
||||||
|
Local *string
|
||||||
|
LocalType *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
SSHKeyFile *string
|
||||||
|
SSHKeyFileSalt *string
|
||||||
|
SSHPassword *string
|
||||||
|
SSHUser *string
|
||||||
|
SSHKeyBytes []byte
|
||||||
|
SSHAuthMethod ssh.AuthMethod
|
||||||
|
Timeout *int
|
||||||
|
Always *bool
|
||||||
|
Interval *int
|
||||||
|
Blocked *string
|
||||||
|
Direct *string
|
||||||
|
}
|
||||||
|
|
||||||
func (a *TCPArgs) Protocol() string {
|
func (a *TCPArgs) Protocol() string {
|
||||||
if *a.IsTLS {
|
if *a.IsTLS {
|
||||||
|
|||||||
@ -3,11 +3,15 @@ package services
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"proxy/utils"
|
"proxy/utils"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
@ -15,6 +19,7 @@ type HTTP struct {
|
|||||||
cfg HTTPArgs
|
cfg HTTPArgs
|
||||||
checker utils.Checker
|
checker utils.Checker
|
||||||
basicAuth utils.BasicAuth
|
basicAuth utils.BasicAuth
|
||||||
|
sshClient *ssh.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTP() Service {
|
func NewHTTP() Service {
|
||||||
@ -26,15 +31,52 @@ func NewHTTP() Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) CheckArgs() {
|
func (s *HTTP) CheckArgs() {
|
||||||
|
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>")
|
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
if *s.cfg.SSHUser == "" {
|
||||||
|
log.Fatalf("ssh user required")
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
|
||||||
|
log.Fatalf("ssh password or key required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *s.cfg.SSHPassword != "" {
|
||||||
|
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
|
||||||
|
} else {
|
||||||
|
var SSHSigner ssh.Signer
|
||||||
|
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("read key file ERR: %s", err)
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFileSalt != "" {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
|
||||||
|
} else {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("parse ssh private key fail,ERR: %s", err)
|
||||||
|
}
|
||||||
|
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) InitService() {
|
func (s *HTTP) InitService() {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
err := s.ConnectSSH()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("init service fail, ERR: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) StopService() {
|
func (s *HTTP) StopService() {
|
||||||
if s.outPool.Pool != nil {
|
if s.outPool.Pool != nil {
|
||||||
@ -99,8 +141,9 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
//log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
//log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
||||||
}
|
}
|
||||||
log.Printf("use proxy : %v, %s", useProxy, address)
|
log.Printf("use proxy : %v, %s", useProxy, address)
|
||||||
//os.Exit(0)
|
|
||||||
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)
|
||||||
@ -122,10 +165,14 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
var _outConn interface{}
|
var _outConn interface{}
|
||||||
if useProxy {
|
if useProxy {
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
outConn, err = s.getSSHConn(address)
|
||||||
|
} else {
|
||||||
_outConn, err = s.outPool.Pool.Get()
|
_outConn, err = s.outPool.Pool.Get()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
outConn = _outConn.(net.Conn)
|
outConn = _outConn.(net.Conn)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
outConn, err = utils.ConnectHost(address, *s.cfg.Timeout)
|
outConn, err = utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
}
|
}
|
||||||
@ -138,20 +185,61 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
outAddr := outConn.RemoteAddr().String()
|
outAddr := outConn.RemoteAddr().String()
|
||||||
outLocalAddr := outConn.LocalAddr().String()
|
outLocalAddr := outConn.LocalAddr().String()
|
||||||
|
|
||||||
if req.IsHTTPS() && !useProxy {
|
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||||
req.HTTPSReply()
|
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
|
||||||
|
err = req.HTTPSReply()
|
||||||
} else {
|
} else {
|
||||||
outConn.Write(req.HeadBuf)
|
//https或者http,上级是代理,proxy需要转发
|
||||||
|
_, err = outConn.Write(req.HeadBuf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
utils.IoBind((*inConn), outConn, func(err error) {
|
utils.IoBind((*inConn), outConn, func(err error) {
|
||||||
log.Printf("conn %s - %s - %s - %s released [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
log.Printf("conn %s - %s - %s - %s released [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
}, func(n int, d bool) {}, 0)
|
}, func(n int, d bool) {}, 0)
|
||||||
log.Printf("conn %s - %s - %s - %s connected [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
log.Printf("conn %s - %s - %s - %s connected [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *HTTP) OutToUDP(inConn *net.Conn) (err error) {
|
|
||||||
|
func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err error) {
|
||||||
|
maxTryCount := 1
|
||||||
|
tryCount := 0
|
||||||
|
RETRY:
|
||||||
|
if tryCount >= maxTryCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
outConn, err = s.sshClient.Dial("tcp", host)
|
||||||
|
//log.Printf("s.sshClient.Dial, host:%s)", host)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
||||||
|
s.sshClient.Close()
|
||||||
|
e := s.ConnectSSH()
|
||||||
|
if e == nil {
|
||||||
|
tryCount++
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
goto RETRY
|
||||||
|
} else {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *HTTP) ConnectSSH() (err error) {
|
||||||
|
config := ssh.ClientConfig{
|
||||||
|
User: *s.cfg.SSHUser,
|
||||||
|
Auth: []ssh.AuthMethod{s.cfg.SSHAuthMethod},
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.sshClient, err = ssh.Dial("tcp", *s.cfg.Parent, &config)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *HTTP) InitOutConnPool() {
|
func (s *HTTP) InitOutConnPool() {
|
||||||
|
|||||||
303
services/socks.go
Normal file
303
services/socks.go
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"proxy/utils"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Socks struct {
|
||||||
|
cfg SocksArgs
|
||||||
|
checker utils.Checker
|
||||||
|
basicAuth utils.BasicAuth
|
||||||
|
sshClient *ssh.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSocks() Service {
|
||||||
|
return &Socks{
|
||||||
|
cfg: SocksArgs{},
|
||||||
|
checker: utils.Checker{},
|
||||||
|
basicAuth: utils.BasicAuth{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks) CheckArgs() {
|
||||||
|
var err error
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
if *s.cfg.ParentType == "" {
|
||||||
|
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh>")
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
if *s.cfg.SSHUser == "" {
|
||||||
|
log.Fatalf("ssh user required")
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
|
||||||
|
log.Fatalf("ssh password or key required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *s.cfg.SSHPassword != "" {
|
||||||
|
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
|
||||||
|
} else {
|
||||||
|
var SSHSigner ssh.Signer
|
||||||
|
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("read key file ERR: %s", err)
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFileSalt != "" {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
|
||||||
|
} else {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("parse ssh private key fail,ERR: %s", err)
|
||||||
|
}
|
||||||
|
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *Socks) InitService() {
|
||||||
|
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
err := s.ConnectSSH()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("init service fail, ERR: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *Socks) StopService() {
|
||||||
|
if s.sshClient != nil {
|
||||||
|
s.sshClient.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *Socks) Start(args interface{}) (err error) {
|
||||||
|
//start()
|
||||||
|
s.cfg = args.(SocksArgs)
|
||||||
|
s.CheckArgs()
|
||||||
|
s.InitService()
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
|
}
|
||||||
|
sc := utils.NewServerChannelHost(*s.cfg.Local)
|
||||||
|
if *s.cfg.LocalType == TYPE_TCP {
|
||||||
|
err = sc.ListenTCP(s.callback)
|
||||||
|
} else {
|
||||||
|
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) Clean() {
|
||||||
|
s.StopService()
|
||||||
|
}
|
||||||
|
func (s *Socks) callback(inConn net.Conn) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
//log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
}()
|
||||||
|
var outConn net.Conn
|
||||||
|
defer utils.CloseConn(&outConn)
|
||||||
|
|
||||||
|
var b [1024]byte
|
||||||
|
n, err := inConn.Read(b[:])
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
log.Printf("read request data fail,ERR: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqBytes = b[:n]
|
||||||
|
//log.Printf("% x", b[:n])
|
||||||
|
|
||||||
|
//reply
|
||||||
|
n, err = inConn.Write([]byte{0x05, 0x00})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("reply answer data fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//read answer
|
||||||
|
n, err = inConn.Read(b[:])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read answer data fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var headBytes = b[:n]
|
||||||
|
// log.Printf("% x", b[:n])
|
||||||
|
var addr string
|
||||||
|
switch b[3] {
|
||||||
|
case 0x01:
|
||||||
|
sip := sockIP{}
|
||||||
|
if err := binary.Read(bytes.NewReader(b[4:n]), binary.BigEndian, &sip); err != nil {
|
||||||
|
log.Printf("read ip fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr = sip.toAddr()
|
||||||
|
case 0x03:
|
||||||
|
host := string(b[5 : n-2])
|
||||||
|
var port uint16
|
||||||
|
err = binary.Read(bytes.NewReader(b[n-2:n]), binary.BigEndian, &port)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read domain fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr = fmt.Sprintf("%s:%d", host, port)
|
||||||
|
}
|
||||||
|
useProxy := true
|
||||||
|
if *s.cfg.Always {
|
||||||
|
outConn, err = s.getOutConn(reqBytes, headBytes, addr)
|
||||||
|
} else {
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
s.checker.Add(addr, true, "", "", nil)
|
||||||
|
useProxy, _, _ = s.checker.IsBlocked(addr)
|
||||||
|
if useProxy {
|
||||||
|
outConn, err = s.getOutConn(reqBytes, headBytes, addr)
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(addr, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(addr, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("get out conn fail,%s", err)
|
||||||
|
inConn.Write([]byte{0x05, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("use proxy %v : %s", useProxy, addr)
|
||||||
|
|
||||||
|
inConn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||||
|
|
||||||
|
inAddr := inConn.RemoteAddr().String()
|
||||||
|
inLocalAddr := inConn.LocalAddr().String()
|
||||||
|
|
||||||
|
log.Printf("conn %s - %s connected [%s]", inAddr, inLocalAddr, addr)
|
||||||
|
// utils.IoBind(outConn, inConn, func(err error) {
|
||||||
|
// log.Printf("conn %s - %s released [%s]", inAddr, inLocalAddr, addr)
|
||||||
|
|
||||||
|
// }, func(i int, b bool) {}, 0)
|
||||||
|
var bind = func() (err interface{}) {
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
if err = recover(); err != nil {
|
||||||
|
log.Printf("bind crashed %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
if err = recover(); err != nil {
|
||||||
|
log.Printf("bind crashed %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
_, err = io.Copy(outConn, inConn)
|
||||||
|
}()
|
||||||
|
_, err = io.Copy(inConn, outConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bind()
|
||||||
|
log.Printf("conn %s - %s released [%s]", inAddr, inLocalAddr, addr)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
}
|
||||||
|
func (s *Socks) getOutConn(reqBytes, headBytes []byte, host string) (outConn net.Conn, err error) {
|
||||||
|
switch *s.cfg.ParentType {
|
||||||
|
case "tls":
|
||||||
|
fallthrough
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
var _outConn tls.Conn
|
||||||
|
_outConn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||||
|
outConn = net.Conn(&_outConn)
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buf = make([]byte, 1024)
|
||||||
|
//var n int
|
||||||
|
_, err = outConn.Write(reqBytes)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = outConn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//resp := buf[:n]
|
||||||
|
//log.Printf("resp:%v", resp)
|
||||||
|
|
||||||
|
outConn.Write(headBytes)
|
||||||
|
_, err = outConn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//result := buf[:n]
|
||||||
|
//log.Printf("result:%v", result)
|
||||||
|
|
||||||
|
case "ssh":
|
||||||
|
maxTryCount := 1
|
||||||
|
tryCount := 0
|
||||||
|
RETRY:
|
||||||
|
if tryCount >= maxTryCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
outConn, err = s.sshClient.Dial("tcp", host)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
||||||
|
s.sshClient.Close()
|
||||||
|
e := s.ConnectSSH()
|
||||||
|
if e == nil {
|
||||||
|
tryCount++
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
goto RETRY
|
||||||
|
} else {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) ConnectSSH() (err error) {
|
||||||
|
config := ssh.ClientConfig{
|
||||||
|
User: *s.cfg.SSHUser,
|
||||||
|
Auth: []ssh.AuthMethod{s.cfg.SSHAuthMethod},
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.sshClient, err = ssh.Dial("tcp", *s.cfg.Parent, &config)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type sockIP struct {
|
||||||
|
A, B, C, D byte
|
||||||
|
PORT uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip sockIP) toAddr() string {
|
||||||
|
return fmt.Sprintf("%d.%d.%d.%d:%d", ip.A, ip.B, ip.C, ip.D, ip.PORT)
|
||||||
|
}
|
||||||
@ -31,6 +31,9 @@ func (s *TCP) CheckArgs() {
|
|||||||
if *s.cfg.ParentType == "" {
|
if *s.cfg.ParentType == "" {
|
||||||
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" || *s.cfg.IsTLS {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *TCP) InitService() {
|
func (s *TCP) InitService() {
|
||||||
s.InitOutConnPool()
|
s.InitOutConnPool()
|
||||||
|
|||||||
@ -33,10 +33,10 @@ func (s *TunnelBridge) InitService() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
func (s *TunnelBridge) CheckArgs() {
|
func (s *TunnelBridge) CheckArgs() {
|
||||||
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
log.Fatalf("cert and key file required")
|
log.Fatalf("cert and key file required")
|
||||||
}
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
}
|
}
|
||||||
func (s *TunnelBridge) StopService() {
|
func (s *TunnelBridge) StopService() {
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,10 @@ func (s *TunnelClient) CheckArgs() {
|
|||||||
} else {
|
} else {
|
||||||
log.Fatalf("parent required")
|
log.Fatalf("parent required")
|
||||||
}
|
}
|
||||||
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
log.Fatalf("cert and key file required")
|
log.Fatalf("cert and key file required")
|
||||||
}
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
}
|
}
|
||||||
func (s *TunnelClient) StopService() {
|
func (s *TunnelClient) StopService() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,7 +61,9 @@ func (s *TunnelServerManager) 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(TunnelServerArgs{
|
err = server.Start(TunnelServerArgs{
|
||||||
Args: s.cfg.Args,
|
CertBytes: s.cfg.CertBytes,
|
||||||
|
KeyBytes: s.cfg.KeyBytes,
|
||||||
|
Parent: s.cfg.Parent,
|
||||||
Local: &local,
|
Local: &local,
|
||||||
IsUDP: &IsUDP,
|
IsUDP: &IsUDP,
|
||||||
Remote: &remote,
|
Remote: &remote,
|
||||||
@ -97,9 +99,10 @@ func (s *TunnelServer) CheckArgs() {
|
|||||||
if *s.cfg.Remote == "" {
|
if *s.cfg.Remote == "" {
|
||||||
log.Fatalf("remote required")
|
log.Fatalf("remote required")
|
||||||
}
|
}
|
||||||
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
log.Fatalf("cert and key file required")
|
log.Fatalf("cert and key file required")
|
||||||
}
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
}
|
}
|
||||||
func (s *TunnelServer) StopService() {
|
func (s *TunnelServer) StopService() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,9 @@ func (s *UDP) CheckArgs() {
|
|||||||
if *s.cfg.ParentType == "" {
|
if *s.cfg.ParentType == "" {
|
||||||
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *UDP) InitService() {
|
func (s *UDP) InitService() {
|
||||||
if *s.cfg.ParentType != TYPE_UDP {
|
if *s.cfg.ParentType != TYPE_UDP {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
@ -311,6 +312,19 @@ func Uniqueid() string {
|
|||||||
s := fmt.Sprintf("%d", src.Int63())
|
s := fmt.Sprintf("%d", src.Int63())
|
||||||
return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
|
return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
|
||||||
}
|
}
|
||||||
|
func TlsBytes(cert, key string) (certBytes, keyBytes []byte) {
|
||||||
|
certBytes, err := ioutil.ReadFile(cert)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err : %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
keyBytes, err = ioutil.ReadFile(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err : %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// type sockaddr struct {
|
// type sockaddr struct {
|
||||||
// family uint16
|
// family uint16
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerChannel struct {
|
type ServerChannel struct {
|
||||||
@ -24,6 +25,17 @@ func NewServerChannel(ip string, port int) ServerChannel {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func NewServerChannelHost(host string) ServerChannel {
|
||||||
|
h, port, _ := net.SplitHostPort(host)
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
return ServerChannel{
|
||||||
|
ip: h,
|
||||||
|
port: p,
|
||||||
|
errAcceptHandler: func(err error) {
|
||||||
|
log.Printf("accept error , ERR:%s", err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
||||||
sc.errAcceptHandler = fn
|
sc.errAcceptHandler = fn
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user