Merge branch 'dev'

This commit is contained in:
arraykeys@gmail.com
2018-08-30 16:10:28 +08:00
18 changed files with 428 additions and 105 deletions

View File

@ -1,4 +1,12 @@
proxy更新日志
v5.4
1.优化了获取本地IP信息导致CPU过高的问题.
2.所有服务都增加了--nolog参数,可以关闭日志输出,节省CPU.
3.优化sdk,支持并发启动/关闭操作.
4.修复了多连接版本的内网穿透,tserver连接不能正确释放的bug.
5.内网穿透增加了client/tclient和server/tserver使用代理连接bridge/tbridge的功能,详细内容参考手册.
6.TCP端口映射(TCP代理)增加了使用代理连接上级的功能,详细内容参考手册.
v5.3
1.优化了socks_client握手端口判断,避免了sstap测试UDP失败的问题.

View File

@ -48,7 +48,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- ...
本页是v5.3手册,其他版本手册请点击[这里](docs/old-release.md)查看.
本页是v5.4手册,其他版本手册请点击[这里](docs/old-release.md)查看.
### 怎么找到组织?
@ -87,14 +87,15 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [1.12 自定义加密](#112-自定义加密)
- [1.13 压缩传输](#113-压缩传输)
- [1.14 查看帮助](#114-查看帮助)
- [2. TCP代理](#2tcp代理)
- [2. TCP代理(端口映射)](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
- [2.3 普通三级TCP代理](#23普通三级tcp代理)
- [2.4 加密二级TCP代理](#24加密二级tcp代理)
- [2.5 加密三级TCP代理](#25加密三级tcp代理)
- [2.6 查看帮助](#26查看帮助)
- [3. UDP代理](#3udp代理)
- [2.6 通过代理连接上级](#26通过代理连接上级)
- [2.7 查看帮助](#27查看帮助)
- [3. UDP代理(端口映射)](#3udp代理)
- [3.1 普通一级UDP代理](#31普通一级udp代理)
- [3.2 普通二级UDP代理](#32普通二级udp代理)
- [3.3 普通三级UDP代理](#33普通三级udp代理)
@ -109,7 +110,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [4.5 高级用法一](#45高级用法一)
- [4.6 高级用法一](#46高级用法二)
- [4.7 server的-r参数](#47server的-r参数)
- [4.8 查看帮助](#48查看帮助)
- [4.8 server和client通过代理连接bridge](#48server和client通过代理连接bridge)
- [4.9 查看帮助](#49查看帮助)
- [5. SOCKS5代理](#5socks5代理)
- [5.1 普通SOCKS5代理](#51普通socks5代理)
- [5.2 普通二级SOCKS5代理](#52普通二级socks5代理)
@ -159,7 +161,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
下载地址:https://github.com/snail007/goproxy/releases
```shell
cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v5.3/proxy-linux-amd64.tar.gz
wget https://github.com/snail007/goproxy/releases/download/v5.4/proxy-linux-amd64.tar.gz
```
#### **2.下载自动安装脚本**
```shell
@ -506,7 +508,27 @@ VPS(IP:22.22.22.33)执行:
`./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端口.
#### **2.6.查看帮助**
#### **2.6.通过代理连接上级**
有时候proxy所在的网络不能直接访问外网,需要通过一个https或者socks5代理才能上网,那么这个时候
-J参数就可以帮助你让proxy的tcp端口映射的时候通过https或者socks5代理去连接上级-P,将外部端口映射到本地.
-J参数格式如下:
https代理写法:
代理需要认证,用户名:username 密码:password
https://username:password@host:port
代理不需要认证
https://host:port
socks5代理写法:
代理需要认证,用户名:username 密码:password
socks5://username:password@host:port
代理不需要认证
socks5://host:port
host:代理的IP或者域名
port:代理的端口
#### **2.7.查看帮助**
`./proxy help tcp`
### **3.UDP代理**
@ -693,7 +715,27 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
4.7.3.LOCAL_IP为空默认是:`0.0.0.0`,CLIENT_LOCAL_HOST为空默认是:`127.0.0.1`;
#### **4.8.查看帮助**
#### **4.8.server和client通过代理连接bridge**
有时候server或者client所在的网络不能直接访问外网,需要通过一个https或者socks5代理才能上网,那么这个时候
-J参数就可以帮助你让server或者client通过https或者socks5代理去连接bridge.
-J参数格式如下:
https代理写法:
代理需要认证,用户名:username 密码:password
https://username:password@host:port
代理不需要认证
https://host:port
socks5代理写法:
代理需要认证,用户名:username 密码:password
socks5://username:password@host:port
代理不需要认证
socks5://host:port
host:代理的IP或者域名
port:代理的端口
#### **4.9.查看帮助**
`./proxy help bridge`
`./proxy help server`
`./proxy help client`

View File

@ -4,6 +4,7 @@ import (
"bufio"
"crypto/sha1"
"fmt"
"io/ioutil"
logger "log"
"os"
"os/exec"
@ -62,6 +63,7 @@ func initConfig() (err error) {
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String()
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
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")
@ -122,8 +124,8 @@ func initConfig() (err error) {
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
tcpArgs.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.Jumper = tcp.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########udp#########
udp := app.Command("udp", "proxy on udp mode")
@ -147,6 +149,7 @@ func initConfig() (err error) {
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()
muxServerArgs.Jumper = muxServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode")
@ -158,6 +161,7 @@ func initConfig() (err error) {
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()
muxClientArgs.Jumper = muxClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
@ -176,6 +180,7 @@ func initConfig() (err error) {
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()
tunnelServerArgs.Jumper = tunnelServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-client#########
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
@ -184,6 +189,7 @@ func initConfig() (err error) {
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()
tunnelClientArgs.Jumper = tunnelClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-bridge#########
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
@ -352,7 +358,9 @@ func initConfig() (err error) {
}
log.SetFlags(flags)
if *logfile != "" {
if *nolog {
log.SetOutput(ioutil.Discard)
} else if *logfile != "" {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if e != nil {
log.Fatal(e)

View File

@ -1,5 +1,6 @@
# Old Versions of Proxy
- [v5.3手册](https://github.com/snail007/goproxy/tree/v5.3)
- [v5.2手册](https://github.com/snail007/goproxy/tree/v5.2)
- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1)
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0)

View File

@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
fi
mkdir /tmp/proxy
cd /tmp/proxy
wget https://github.com/snail007/goproxy/releases/download/v5.3/proxy-linux-amd64.tar.gz
wget https://github.com/snail007/goproxy/releases/download/v5.4/proxy-linux-amd64.tar.gz
# #install proxy
tar zxvf proxy-linux-amd64.tar.gz

View File

@ -9,7 +9,7 @@ import (
"github.com/snail007/goproxy/services"
)
const APP_VERSION = "5.3"
const APP_VERSION = "5.4"
func main() {
err := initConfig()

View File

@ -1,5 +1,5 @@
#!/bin/bash
VER="5.3"
VER="5.4"
RELEASE="release-${VER}"
rm -rf .cert
mkdir .cert
@ -60,12 +60,12 @@ CGO_ENABLED=0 GOOS=plan9 GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/pr
#solaris
CGO_ENABLED=0 GOOS=solaris GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked
#windows
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-H=windowsgui" -o proxy-wingui.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe proxy-wingui.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-H=windowsgui" -o proxy-wingui.exe
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe proxy-wingui.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-H=windowsgui" -o proxy-noconsole.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe proxy-noconsole.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-H=windowsgui" -o proxy-noconsole.exe
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe proxy-noconsole.exe direct blocked .cert/proxy.crt .cert/proxy.key
rm -rf proxy proxy.exe proxy-wingui.exe .cert
rm -rf proxy proxy.exe proxy-noconsole.exe .cert
#todo
#1.release.sh VER="xxx"

View File

@ -1,4 +1,7 @@
SDK更新日志
v5.4
1.去掉了无用参数
v5.3
1.增加了支持日志输出回调的方法:

View File

@ -3,6 +3,7 @@ package proxy
import (
"crypto/sha1"
"fmt"
"io/ioutil"
logger "log"
"os"
"path"
@ -77,6 +78,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
app.Author("snail").Version(SDK_VERSION)
debug := app.Flag("debug", "debug log output").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String()
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
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")
@ -137,8 +139,8 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
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()
tcpArgs.Jumper = tcp.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########udp#########
udp := app.Command("udp", "proxy on udp mode")
@ -162,6 +164,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
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()
muxServerArgs.Jumper = muxServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode")
@ -173,6 +176,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
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()
muxClientArgs.Jumper = muxClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
@ -191,6 +195,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
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()
tunnelServerArgs.Jumper = tunnelServer.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-client#########
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
@ -199,6 +204,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
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()
tunnelClientArgs.Jumper = tunnelClient.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
//########tunnel-bridge#########
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
@ -357,7 +363,9 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
log.SetFlags(flags)
if loggerCallback == nil {
if *logfile != "" {
if *nolog {
log.SetOutput(ioutil.Discard)
} else if *logfile != "" {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if e != nil {
log.Fatal(e)

View File

@ -12,6 +12,7 @@ import (
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
)
@ -28,12 +29,14 @@ type MuxClientArgs struct {
IsCompress *bool
SessionCount *int
KCP kcpcfg.KCPConfigArgs
Jumper *string
}
type MuxClient struct {
cfg MuxClientArgs
isStop bool
sessions utils.ConcurrentMap
log *logger.Logger
jumper *jumper.Jumper
}
func NewMuxClient() services.Service {
@ -65,6 +68,19 @@ func (s *MuxClient) CheckArgs() (err error) {
return
}
}
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return
}
func (s *MuxClient) StopService() {
@ -182,15 +198,32 @@ func (s *MuxClient) Clean() {
}
func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" {
if s.jumper == nil {
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 {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
}
} else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else {
if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
}
return
}

View File

@ -15,6 +15,7 @@ import (
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"github.com/golang/snappy"
//"github.com/xtaci/smux"
@ -38,6 +39,7 @@ type MuxServerArgs struct {
IsCompress *bool
SessionCount *int
KCP kcpcfg.KCPConfigArgs
Jumper *string
}
type MuxUDPItem struct {
@ -121,6 +123,7 @@ func (s *MuxServerManager) Start(args interface{}, log *logger.Logger) (err erro
SessionCount: s.cfg.SessionCount,
KCP: s.cfg.KCP,
ParentType: s.cfg.ParentType,
Jumper: s.cfg.Jumper,
}, log)
if err != nil {
@ -164,6 +167,7 @@ type MuxServer struct {
isStop bool
udpConn *net.Conn
log *logger.Logger
jumper *jumper.Jumper
}
func NewMuxServer() services.Service {
@ -208,6 +212,19 @@ func (s *MuxServer) CheckArgs() (err error) {
err = fmt.Errorf("remote required")
return
}
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return
}
@ -378,15 +395,32 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
}
func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" {
if s.jumper == nil {
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 {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
}
} else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else {
if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
}
return
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
logger "log"
"runtime/debug"
"sync"
)
type Service interface {
@ -17,31 +18,31 @@ type ServiceItem struct {
Log *logger.Logger
}
var servicesMap = map[string]*ServiceItem{}
var servicesMap = sync.Map{}
func Regist(name string, s Service, args interface{}, log *logger.Logger) {
Stop(name)
servicesMap[name] = &ServiceItem{
servicesMap.Store(name, &ServiceItem{
S: s,
Args: args,
Name: name,
Log: log,
}
})
}
func GetService(name string) *ServiceItem {
if s, ok := servicesMap[name]; ok && s.S != nil {
return s
if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil {
return s.(*ServiceItem)
}
return nil
}
func Stop(name string) {
if s, ok := servicesMap[name]; ok && s.S != nil {
s.S.Clean()
if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil {
s.(*ServiceItem).S.Clean()
}
}
func Run(name string, args interface{}) (service *ServiceItem, err error) {
service, ok := servicesMap[name]
_service, ok := servicesMap.Load(name)
if ok {
defer func() {
e := recover()
@ -49,6 +50,7 @@ func Run(name string, args interface{}) (service *ServiceItem, err error) {
err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
}
}()
service = _service.(*ServiceItem)
if args != nil {
err = service.S.Start(args, service.Log)
} else {

View File

@ -2,6 +2,7 @@ package tcp
import (
"bufio"
"crypto/tls"
"fmt"
"io"
logger "log"
@ -12,6 +13,7 @@ import (
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"strconv"
)
@ -26,22 +28,21 @@ type TCPArgs struct {
ParentType *string
LocalType *string
Timeout *int
CheckParentInterval *int
KCP kcpcfg.KCPConfigArgs
Jumper *string
}
type TCP struct {
outPool utils.OutConn
cfg TCPArgs
sc *utils.ServerChannel
isStop bool
userConns utils.ConcurrentMap
log *logger.Logger
jumper *jumper.Jumper
}
func NewTCP() services.Service {
return &TCP{
outPool: utils.OutConn{},
cfg: TCPArgs{},
isStop: false,
userConns: utils.NewConcurrentMap(),
@ -62,10 +63,23 @@ func (s *TCP) CheckArgs() (err error) {
return
}
}
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return
}
func (s *TCP) InitService() (err error) {
s.InitOutConnPool()
return
}
func (s *TCP) StopService() {
@ -146,7 +160,7 @@ func (s *TCP) callback(inConn net.Conn) {
}
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
var outConn net.Conn
outConn, err = s.outPool.Get()
outConn, err = s.GetParentConn()
if err != nil {
s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn)
@ -219,17 +233,34 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
return
}
func (s *TCP) InitOutConnPool() {
if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" || *s.cfg.ParentType == "kcp" {
//dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutConn(
*s.cfg.CheckParentInterval,
*s.cfg.ParentType,
s.cfg.KCP,
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
*s.cfg.Parent,
*s.cfg.Timeout,
)
func (s *TCP) GetParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" {
if s.jumper == nil {
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 {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
}
} else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else {
if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
}
return
}

View File

@ -30,7 +30,6 @@ type TunnelBridgeArgs struct {
KeyBytes []byte
Local *string
Timeout *int
Mux *bool
}
type ServerConn struct {
//ClientLocalAddr string //tcp:2.2.22:333@ID

View File

@ -11,6 +11,7 @@ import (
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
)
@ -28,7 +29,7 @@ type TunnelClientArgs struct {
KeyBytes []byte
Key *string
Timeout *int
Mux *bool
Jumper *string
}
type TunnelClient struct {
cfg TunnelClientArgs
@ -36,6 +37,7 @@ type TunnelClient struct {
isStop bool
userConns utils.ConcurrentMap
log *logger.Logger
jumper *jumper.Jumper
}
func NewTunnelClient() services.Service {
@ -62,6 +64,18 @@ func (s *TunnelClient) CheckArgs() (err error) {
return
}
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
if *s.cfg.Jumper != "" {
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return
}
func (s *TunnelClient) StopService() {
@ -151,10 +165,24 @@ func (s *TunnelClient) GetInConn(typ uint8, data ...string) (outConn net.Conn, e
return
}
func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
if s.jumper == nil {
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 {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
}
if err == nil {
c, e := smux.Client(conn, &smux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,

View File

@ -14,6 +14,7 @@ import (
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
@ -32,7 +33,7 @@ type TunnelServerArgs struct {
Timeout *int
Route *[]string
Mgr *TunnelServerManager
Mux *bool
Jumper *string
}
type UDPItem struct {
packet *[]byte
@ -105,6 +106,7 @@ func (s *TunnelServerManager) Start(args interface{}, log *logger.Logger) (err e
Key: &KEY,
Timeout: s.cfg.Timeout,
Mgr: s,
Jumper: s.cfg.Jumper,
}, log)
if err != nil {
@ -134,30 +136,6 @@ func (s *TunnelServerManager) InitService() (err error) {
return
}
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn()
if err != nil {
s.log.Printf("connection err: %s", err)
return
}
ID = s.serverID
_, err = outConn.Write(utils.BuildPacket(typ, s.serverID))
if err != nil {
s.log.Printf("write connection data err: %s ,retrying...", err)
utils.CloseConn(&outConn)
return
}
return
}
func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
var _conn tls.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err == nil {
conn = net.Conn(&_conn)
}
return
}
type TunnelServer struct {
cfg TunnelServerArgs
udpChn chan UDPItem
@ -166,6 +144,7 @@ type TunnelServer struct {
udpConn *net.Conn
userConns utils.ConcurrentMap
log *logger.Logger
jumper *jumper.Jumper
}
func NewTunnelServer() services.Service {
@ -210,6 +189,15 @@ func (s *TunnelServer) CheckArgs() (err error) {
err = fmt.Errorf("remote required")
return
}
if *s.cfg.Jumper != "" {
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return
}
@ -301,11 +289,26 @@ func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err e
return
}
func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
var dconn net.Conn
if s.jumper == nil {
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)
c, e := smux.Client(conn, &smux.Config{
dconn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
dconn = net.Conn(tls.Client(_c, conf))
}
}
if err == nil {
sess, e := smux.Client(dconn, &smux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 9 * time.Second,
@ -316,14 +319,30 @@ func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
if e != nil {
s.log.Printf("new mux client conn error,ERR:%s", e)
err = e
dconn.Close()
return
}
conn, e = c.OpenStream()
conn, e = sess.OpenStream()
if e != nil {
s.log.Printf("mux client conn open stream error,ERR:%s", e)
err = e
dconn.Close()
return
}
go func() {
defer func() {
_ = recover()
}()
timer := time.NewTicker(time.Second * 3)
for {
<-timer.C
if sess.NumStreams() == 0 {
sess.Close()
timer.Stop()
return
}
}
}()
}
return
}

View File

@ -22,15 +22,14 @@ import (
"golang.org/x/crypto/pbkdf2"
"context"
"strconv"
"strings"
"time"
"context"
"github.com/snail007/goproxy/utils/id"
kcp "github.com/xtaci/kcp-go"
)
func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
@ -109,6 +108,9 @@ func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes
}
return *tls.Client(_conn, conf), err
}
func TlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
return getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
}
func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
var cert tls.Certificate
@ -210,8 +212,13 @@ func CloseConn(conn *net.Conn) {
(*conn).Close()
}
}
func GetAllInterfaceAddr() ([]net.IP, error) {
var allInterfaceAddrCache []net.IP
func GetAllInterfaceAddr() ([]net.IP, error) {
if allInterfaceAddrCache != nil {
return allInterfaceAddrCache, nil
}
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
@ -252,6 +259,7 @@ func GetAllInterfaceAddr() ([]net.IP, error) {
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
}
//only need first
allInterfaceAddrCache = addresses
return addresses, nil
}
func UDPPacket(srcAddr string, packet []byte) []byte {
@ -635,7 +643,6 @@ func InsertProxyHeaders(head []byte, headers string) []byte {
// return
// }
/*
net.LookupIP may cause deadlock in windows
https://github.com/golang/go/issues/24178

100
utils/jumper/jumper.go Normal file
View File

@ -0,0 +1,100 @@
package jumper
import (
"bytes"
"encoding/base64"
"fmt"
"net"
"net/url"
"time"
"golang.org/x/net/proxy"
)
type Jumper struct {
proxyURL *url.URL
timeout time.Duration
}
type socks5Dialer struct {
timeout time.Duration
}
func (s socks5Dialer) Dial(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, s.timeout)
}
func New(proxyURL string, timeout time.Duration) (j Jumper, err error) {
u, err := url.Parse(proxyURL)
if err != nil {
return
}
j = Jumper{
proxyURL: u,
timeout: timeout,
}
return
}
func (j *Jumper) Dial(address string, timeout time.Duration) (conn net.Conn, err error) {
switch j.proxyURL.Scheme {
case "https":
return j.dialHTTPS(address, timeout)
case "socks5":
return j.dialSOCKS5(address, timeout)
default:
return nil, fmt.Errorf("unkown scheme of %s", j.proxyURL.String())
}
}
func (j *Jumper) dialHTTPS(address string, timeout time.Duration) (conn net.Conn, err error) {
conn, err = net.DialTimeout("tcp", j.proxyURL.Host, timeout)
if err != nil {
return
}
pb := new(bytes.Buffer)
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", address)))
pb.WriteString("Proxy-Connection: Keep-Alive\r\n")
if j.proxyURL.User != nil {
p, _ := j.proxyURL.User.Password()
u := fmt.Sprintf("%s:%s", j.proxyURL.User.Username(), p)
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
}
pb.Write([]byte("\r\n"))
_, err = conn.Write(pb.Bytes())
if err != nil {
conn.Close()
conn = nil
err = fmt.Errorf("error connecting to proxy: %s", err)
return
}
reply := make([]byte, 1024)
conn.SetDeadline(time.Now().Add(timeout))
n, err := conn.Read(reply)
conn.SetDeadline(time.Time{})
if err != nil {
err = fmt.Errorf("error read reply from proxy: %s", err)
conn.Close()
conn = nil
return
}
if bytes.Index(reply[:n], []byte("200")) == -1 {
err = fmt.Errorf("error greeting to proxy, response: %s", string(reply[:n]))
conn.Close()
conn = nil
return
}
return
}
func (j *Jumper) dialSOCKS5(address string, timeout time.Duration) (conn net.Conn, err error) {
auth := &proxy.Auth{}
if j.proxyURL.User != nil {
auth.User = j.proxyURL.User.Username()
auth.Password, _ = j.proxyURL.User.Password()
} else {
auth = nil
}
dialSocksProxy, err := proxy.SOCKS5("tcp", j.proxyURL.Host, auth, socks5Dialer{timeout: timeout})
if err != nil {
err = fmt.Errorf("error connecting to proxy: %s", err)
return
}
return dialSocksProxy.Dial("tcp", address)
}