diff --git a/CHANGELOG b/CHANGELOG index d4c7c1e..f412d48 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,13 +1,13 @@ proxy更新日志 v4.7 -1.优化了bridge的日志,增加了client和server的掉线日志. -2.优化了sps读取http(s)代理响应的缓冲大小,同时优化了CONNECT请求, +1.增加了基于gomobile的sdk,对安卓/IOS提供SDK支持. +2.优化了bridge的日志,增加了client和server的掉线日志. +3.优化了sps读取http(s)代理响应的缓冲大小,同时优化了CONNECT请求, 避免了某些代理服务器返回过多数据导致不能正常通讯的问题. -3.去除了鸡肋连接池功能. -4.增加了gomobile sdk,对安卓/IOS提供支持. +4.去除了鸡肋连接池功能. 5.优化了所有服务代码,方便对sdk提供支持. - - +6.增加了SDK手册. +7.增加了GUI客户端(windows/web/android/ios)介绍主页. v4.6 1.sps,http(s),socks5,内网穿透都做了大量的超时优化处理,更加稳定. diff --git a/config.go b/config.go index 70f0a4a..229ae33 100755 --- a/config.go +++ b/config.go @@ -86,7 +86,6 @@ func initConfig() (err error) { httpArgs.Direct = http.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String() httpArgs.AuthFile = http.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String() httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() - httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() httpArgs.Local = http.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String() httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String() @@ -109,7 +108,6 @@ 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 ").Short('T').Enum("tls", "tcp", "udp", "kcp") tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") - tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() @@ -120,7 +118,6 @@ func initConfig() (err error) { udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int() udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type ").Short('T').Enum("tls", "tcp", "udp") - udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() diff --git a/sdk/README.md b/sdk/README.md new file mode 100644 index 0000000..899e048 --- /dev/null +++ b/sdk/README.md @@ -0,0 +1,77 @@ + +# Proxy SDK 使用说明 + +proxy使用gombile实现了一份go代码编译为android和ios平台下面可以直接调用的sdk类库, +基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具. + +### 下面分平台介绍SDK的用法 + +#### Android SDK + +[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/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 args="http -p :8080" +String err=Proxy.start(args) +if (err.isEmpty()){ + //启动失败 + System.out.println("start fail,error:"+err) +}else{ + //启动成功 +} +``` +#### 3.判断一个服务是否在运行 + +```java +String args="http -p :8080" +boolean isRunning=Proxy.isRunning(args)//这里传递http也可以,最终使用的就是args里面的第一个参数http +if(isRunning){ + //正在运行 +}else{ + //没有运行 +} +``` +#### 4.停止一个服务 + +```java +String args="http -p :8080" +Proxy.stop(args)//这里传递http也可以,最终使用的就是args里面的第一个参数http +//停止完毕 + +``` + + +### IOS-SDK使用实例 + +#### todo + + +### 关于服务 +proxy的服务有11种,分别是: + +```shell +http +socks +sps +tcp +udp +bridge +server +client +tbridge +tserver +tclient +``` +每个服务只能启动一个,如果相同的服务启动多次,那么之前的服务会被停掉,后面启动的服务覆盖之前的服务. +上面这些服务的具体使用方式和具体参数,可以参考[proxy手册](https://github.com/snail007/goproxy/blob/master/README_ZH.md) \ No newline at end of file diff --git a/sdk/release.sh b/sdk/release.sh index a30863f..463f2d3 100755 --- a/sdk/release.sh +++ b/sdk/release.sh @@ -1,41 +1,56 @@ #/bin/bash VER="v4.7" -rm -rf proxy-sdk-release-* +rm -rf android +rm -rf ios +mkdir android +mkdir ios + #arm -gomobile bind -v -target=android/arm -mkdir proxy-sdk-arm -mv sdk.aar proxy-sdk-arm/proxy-sdk-arm.aar -mv sdk-sources.jar proxy-sdk-arm/proxy-sdk-arm-sources.jar -tar zcfv proxy-sdk-arm-${VER}.tar.gz proxy-sdk-arm -rm -rf proxy-sdk-arm +gomobile bind -v -target=android/arm -javapkg=snail007 -ldflags="-s -w" +mkdir arm +mv proxy.aar arm/snail007.goproxy.sdk.aar +mv proxy-sources.jar arm/snail007.goproxy.sdk-sources.jar +tar zcfv sdk-arm-${VER}.tar.gz arm +mv sdk-arm-${VER}.tar.gz android +rm -rf arm + + #arm64 -gomobile bind -v -target=android/arm64 -mkdir proxy-sdk-arm64 -mv sdk.aar proxy-sdk-arm64/proxy-sdk-arm64.aar -mv sdk-sources.jar proxy-sdk-arm64/proxy-sdk-arm64-sources.jar -tar zcfv proxy-sdk-arm64-${VER}.tar.gz proxy-sdk-arm64 -rm -rf proxy-sdk-arm64 +gomobile bind -v -target=android/arm64 -javapkg=snail007 -ldflags="-s -w" +mkdir arm64 +mv proxy.aar arm64/snail007.goproxy.sdk.aar +mv proxy-sources.jar arm64/snail007.goproxy.sdk-sources.jar +tar zcfv sdk-arm64-${VER}.tar.gz arm64 +mv sdk-arm64-${VER}.tar.gz android +rm -rf arm64 + + #386 -gomobile bind -v -target=android/386 -mkdir proxy-sdk-386 -mv sdk.aar proxy-sdk-386/proxy-sdk-386.aar -mv sdk-sources.jar proxy-sdk-386/proxy-sdk-386-sources.jar -tar zcfv proxy-sdk-386-${VER}.tar.gz proxy-sdk-386 -rm -rf proxy-sdk-386 +gomobile bind -v -target=android/386 -javapkg=snail007 -ldflags="-s -w" +mkdir 386 +mv proxy.aar 386/snail007.goproxy.sdk.aar +mv proxy-sources.jar 386/snail007.goproxy.sdk-sources.jar +tar zcfv sdk-386-${VER}.tar.gz 386 +mv sdk-386-${VER}.tar.gz android +rm -rf 386 + #amd64 -gomobile bind -v -target=android/amd64 -mkdir proxy-sdk-amd64 -mv sdk.aar proxy-sdk-amd64/proxy-sdk-amd64.aar -mv sdk-sources.jar proxy-sdk-amd64/proxy-sdk-amd64-sources.jar -tar zcfv proxy-sdk-amd64-${VER}.tar.gz proxy-sdk-amd64 -rm -rf proxy-sdk-amd64 +gomobile bind -v -target=android/amd64 -javapkg=snail007 -ldflags="-s -w" +mkdir amd64 +mv proxy.aar amd64/snail007.goproxy.sdk.aar +mv proxy-sources.jar amd64/snail007.goproxy.sdk-sources.jar +tar zcfv sdk-amd64-${VER}.tar.gz amd64 +mv sdk-amd64-${VER}.tar.gz android +rm -rf amd64 + + #all-in-one -gomobile bind -v -target=android -mkdir proxy-sdk-all -mv sdk.aar proxy-sdk-all/proxy-sdk-all.aar -mv sdk-sources.jar proxy-sdk-all/proxy-sdk-all-sources.jar -tar zcfv proxy-sdk-all-${VER}.tar.gz proxy-sdk-all -rm -rf proxy-sdk-all -mkdir proxy-sdk-release-${VER} -mv *.tar.gz proxy-sdk-release-${VER} +gomobile bind -v -target=android -javapkg=snail007 -ldflags="-s -w" +mkdir all +mv proxy.aar all/snail007.goproxy.sdk.aar +mv proxy-sources.jar all/snail007.goproxy.sdk-sources.jar +tar zcfv sdk-all-${VER}.tar.gz all +mv sdk-all-${VER}.tar.gz android +rm -rf all + echo "done." diff --git a/sdk/sdk.go b/sdk/sdk.go index ee881f4..5048dad 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -1,13 +1,16 @@ -package sdk +package proxy import ( "crypto/sha1" "fmt" "log" + "net" "os" "snail007/proxy/services" "snail007/proxy/services/kcpcfg" + "strconv" "strings" + "time" kcp "github.com/xtaci/kcp-go" "golang.org/x/crypto/pbkdf2" @@ -15,8 +18,7 @@ import ( ) var ( - app *kingpin.Application - service *services.ServiceItem + app *kingpin.Application ) //Start argsStr: is the whole command line args string @@ -47,7 +49,7 @@ func Start(argsStr string) (errStr 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.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() @@ -79,7 +81,6 @@ func Start(argsStr string) (errStr 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.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() httpArgs.Local = http.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String() httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String() @@ -102,7 +103,6 @@ func Start(argsStr string) (errStr 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 ").Short('T').Enum("tls", "tcp", "udp", "kcp") tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") - tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() @@ -113,7 +113,6 @@ func Start(argsStr string) (errStr 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 ").Short('T').Enum("tls", "tcp", "udp") - udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() @@ -225,7 +224,11 @@ func Start(argsStr string) (errStr string) { 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() //parse args - args := strings.Fields(strings.Trim(argsStr, " ")) + _args := strings.Fields(strings.Trim(argsStr, " ")) + 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) @@ -323,16 +326,120 @@ func Start(argsStr string) (errStr string) { case "sps": services.Regist("sps", services.NewSPS(), spsArgs) } - - service, err = services.Run(serviceName) + _, err = services.Run(serviceName) if err != nil { return fmt.Sprintf("run service [%s] fail, ERR:%s", serviceName, err) } return } -func Stop() { - if service != nil && service.S != nil { - service.S.Clean() +func Stop(service string) { + s := getServiceName(service) + if s == "" { + return } + services.Stop(s) +} + +func IsRunning(service string) bool { + s := getServiceName(service) + if s == "" { + return false + } + srv := services.GetService(s) + if srv == nil { + return false + } + typ := "tcp" + addr := "" + route := "" + switch srv.Name { + case "http": + addr = *srv.Args.(services.HTTPArgs).Local + case "socks": + addr = *srv.Args.(services.SocksArgs).Local + case "sps": + addr = *srv.Args.(services.SPSArgs).Local + case "tcp": + addr = *srv.Args.(services.TCPArgs).Local + case "bridge": + addr = *srv.Args.(services.MuxBridgeArgs).Local + + case "tbridge": + addr = *srv.Args.(services.TunnelBridgeArgs).Local + case "server": + if len(*srv.Args.(services.MuxServerArgs).Route) > 0 { + route = (*srv.Args.(services.MuxServerArgs).Route)[0] + } + case "tserver": + if len(*srv.Args.(services.TunnelServerArgs).Route) > 0 { + route = (*srv.Args.(services.TunnelServerArgs).Route)[0] + } + case "client": + case "tclient": + case "udp": + typ = "udp" + } + if route != "" { + if strings.HasPrefix(route, "udp://") { + typ = "udp" + } + info := strings.TrimPrefix(route, "udp://") + info = strings.TrimPrefix(info, "tcp://") + _routeInfo := strings.Split(info, "@") + addr = _routeInfo[0] + } + a := strings.Split(addr, ",") + if len(a) > 0 { + return PortIsAlive(a[0], typ) == "" + } + return false +} + +func getServiceName(args string) string { + s := strings.Fields(strings.Trim(args, " \t")) + if len(s) == 0 { + return "" + } + return s[0] +} + +func PortIsAlive(address string, network ...string) string { + time.Sleep(time.Second) + n := "tcp" + if len(network) == 1 { + n = network[0] + } + if n == "tcp" { + conn, err := net.DialTimeout(n, address, time.Second) + if err != nil { + return fmt.Sprintf("connect %s is failed!,err:%v\n", address, err) + } + conn.Close() + } else { + ip, port, err := net.SplitHostPort(address) + if err != nil { + return err.Error() + } + portI, _ := strconv.Atoi(port) + dstAddr := &net.UDPAddr{IP: net.ParseIP(ip), Port: portI} + conn, err := net.DialUDP(n, &net.UDPAddr{IP: net.IPv4zero, Port: 0}, dstAddr) + if err != nil { + return err.Error() + } + conn.SetDeadline(time.Now().Add(time.Millisecond * 200)) + _, err = conn.Write([]byte{0x00}) + conn.SetDeadline(time.Now().Add(time.Millisecond * 200)) + b := make([]byte, 1) + _, err = conn.Read(b) + + if err != nil { + if strings.Contains(err.Error(), "refused") { + return err.Error() + } + } else { + conn.Close() + } + } + return "" } diff --git a/services/args.go b/services/args.go index 68ccb78..2f98140 100644 --- a/services/args.go +++ b/services/args.go @@ -111,7 +111,6 @@ type TCPArgs struct { ParentType *string LocalType *string Timeout *int - PoolSize *int CheckParentInterval *int KCP kcpcfg.KCPConfigArgs } @@ -139,7 +138,6 @@ type HTTPArgs struct { ParentType *string LocalType *string Timeout *int - PoolSize *int CheckParentInterval *int SSHKeyFile *string SSHKeyFileSalt *string @@ -161,7 +159,6 @@ type UDPArgs struct { Local *string ParentType *string Timeout *int - PoolSize *int CheckParentInterval *int } type SocksArgs struct { diff --git a/services/http.go b/services/http.go index c4da7fd..8d3c29e 100644 --- a/services/http.go +++ b/services/http.go @@ -25,6 +25,7 @@ type HTTP struct { domainResolver utils.DomainResolver isStop bool serverChannels []*utils.ServerChannel + userConns utils.ConcurrentMap } func NewHTTP() Service { @@ -36,6 +37,7 @@ func NewHTTP() Service { lockChn: make(chan bool, 1), isStop: false, serverChannels: []*utils.ServerChannel{}, + userConns: utils.NewConcurrentMap(), } } func (s *HTTP) CheckArgs() (err error) { @@ -139,7 +141,7 @@ func (s *HTTP) StopService() { if e != nil { log.Printf("stop http(s) service crashed,%s", e) } else { - log.Printf("service http(s) stoped,%s", e) + log.Printf("service http(s) stoped") } }() s.isStop = true @@ -230,7 +232,6 @@ func (s *HTTP) callback(inConn net.Conn) { log.Printf("use proxy : %v, %s", useProxy, address) err = s.OutToTCP(useProxy, address, &inConn, &req) - if err != nil { if *s.cfg.Parent == "" { log.Printf("connect to %s fail, ERR:%s", address, err) @@ -298,9 +299,13 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut utils.IoBind((*inConn), outConn, func(err interface{}) { log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host) + s.userConns.Remove(inAddr) }) log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host) - + if c, ok := s.userConns.Get(inAddr); ok { + (*c.(*net.Conn)).Close() + } + s.userConns.Set(inAddr, inConn) return } @@ -372,8 +377,6 @@ func (s *HTTP) InitOutConnPool() { s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, - *s.cfg.PoolSize, - *s.cfg.PoolSize*2, ) } } diff --git a/services/mux_bridge.go b/services/mux_bridge.go index e0f8fe7..8440d21 100644 --- a/services/mux_bridge.go +++ b/services/mux_bridge.go @@ -19,6 +19,7 @@ import ( type MuxBridge struct { cfg MuxBridgeArgs clientControlConns utils.ConcurrentMap + serverConns utils.ConcurrentMap router utils.ClientKeyRouter l *sync.Mutex isStop bool @@ -29,6 +30,7 @@ func NewMuxBridge() Service { b := &MuxBridge{ cfg: MuxBridgeArgs{}, clientControlConns: utils.NewConcurrentMap(), + serverConns: utils.NewConcurrentMap(), l: &sync.Mutex{}, isStop: false, } @@ -58,7 +60,7 @@ func (s *MuxBridge) StopService() { if e != nil { log.Printf("stop bridge service crashed,%s", e) } else { - log.Printf("service bridge stoped,%s", e) + log.Printf("service bridge stoped") } }() s.isStop = true @@ -70,6 +72,9 @@ func (s *MuxBridge) StopService() { (session.(*smux.Session)).Close() } } + for _, c := range s.serverConns.Items() { + (*c.(*net.Conn)).Close() + } } func (s *MuxBridge) Start(args interface{}) (err error) { s.cfg = args.(MuxBridgeArgs) @@ -116,6 +121,7 @@ func (s *MuxBridge) handler(inConn net.Conn) { 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{}) @@ -124,6 +130,10 @@ func (s *MuxBridge) handler(inConn net.Conn) { 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) @@ -138,6 +148,7 @@ func (s *MuxBridge) handler(inConn net.Conn) { if err != nil { session.Close() utils.CloseConn(&inConn) + s.serverConns.Remove(inAddr) log.Printf("server connection %s %s released", serverID, key) return } diff --git a/services/mux_client.go b/services/mux_client.go index b233598..1c8d772 100644 --- a/services/mux_client.go +++ b/services/mux_client.go @@ -56,7 +56,7 @@ func (s *MuxClient) StopService() { if e != nil { log.Printf("stop client service crashed,%s", e) } else { - log.Printf("service client stoped,%s", e) + log.Printf("service client stoped") } }() s.isStop = true diff --git a/services/mux_server.go b/services/mux_server.go index 27dde50..d5a4860 100644 --- a/services/mux_server.go +++ b/services/mux_server.go @@ -155,7 +155,7 @@ func (s *MuxServer) StopService() { if e != nil { log.Printf("stop server service crashed,%s", e) } else { - log.Printf("service server stoped,%s", e) + log.Printf("service server stoped") } }() s.isStop = true diff --git a/services/service.go b/services/service.go index 8131a68..4d06d40 100644 --- a/services/service.go +++ b/services/service.go @@ -18,13 +18,20 @@ type ServiceItem struct { var servicesMap = map[string]*ServiceItem{} func Regist(name string, s Service, args interface{}) { - + Stop(name) servicesMap[name] = &ServiceItem{ S: s, Args: args, Name: name, } } +func GetService(name string) *ServiceItem { + if s, ok := servicesMap[name]; ok && s.S != nil { + return s + } + return nil + +} func Stop(name string) { if s, ok := servicesMap[name]; ok && s.S != nil { s.S.Clean() diff --git a/services/socks.go b/services/socks.go index a79a6c7..e3ee6d2 100644 --- a/services/socks.go +++ b/services/socks.go @@ -26,6 +26,7 @@ type Socks struct { sc *utils.ServerChannel domainResolver utils.DomainResolver isStop bool + userConns utils.ConcurrentMap } func NewSocks() Service { @@ -35,6 +36,7 @@ func NewSocks() Service { basicAuth: utils.BasicAuth{}, lockChn: make(chan bool, 1), isStop: false, + userConns: utils.NewConcurrentMap(), } } @@ -147,7 +149,7 @@ func (s *Socks) StopService() { if e != nil { log.Printf("stop socks service crashed,%s", e) } else { - log.Printf("service socks stoped,%s", e) + log.Printf("service socks stoped") } }() s.isStop = true @@ -161,6 +163,9 @@ func (s *Socks) StopService() { if s.sc != nil && (*s.sc).Listener != nil { (*(*s.sc).Listener).Close() } + for _, c := range s.userConns.Items() { + (*c.(*net.Conn)).Close() + } } func (s *Socks) Start(args interface{}) (err error) { //start() @@ -526,6 +531,11 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque utils.IoBind(*inConn, outConn, func(err interface{}) { log.Printf("conn %s - %s released", inAddr, request.Addr()) }) + if c, ok := s.userConns.Get(inAddr); ok { + (*c.(*net.Conn)).Close() + s.userConns.Remove(inAddr) + } + s.userConns.Set(inAddr, inConn) } func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) { switch *s.cfg.ParentType { diff --git a/services/sps.go b/services/sps.go index ff02bfb..139ff88 100644 --- a/services/sps.go +++ b/services/sps.go @@ -22,6 +22,7 @@ type SPS struct { domainResolver utils.DomainResolver basicAuth utils.BasicAuth serverChannels []*utils.ServerChannel + userConns utils.ConcurrentMap } func NewSPS() Service { @@ -30,6 +31,7 @@ func NewSPS() Service { cfg: SPSArgs{}, basicAuth: utils.BasicAuth{}, serverChannels: []*utils.ServerChannel{}, + userConns: utils.NewConcurrentMap(), } } func (s *SPS) CheckArgs() (err error) { @@ -75,8 +77,6 @@ func (s *SPS) InitOutConnPool() { s.cfg.CertBytes, s.cfg.KeyBytes, nil, *s.cfg.Parent, *s.cfg.Timeout, - 0, - 0, ) } } @@ -87,7 +87,7 @@ func (s *SPS) StopService() { if e != nil { log.Printf("stop sps service crashed,%s", e) } else { - log.Printf("service sps stoped,%s", e) + log.Printf("service sps stoped") } }() for _, sc := range s.serverChannels { @@ -98,6 +98,9 @@ func (s *SPS) StopService() { (*sc.UDPListener).Close() } } + for _, c := range s.userConns.Items() { + (*c.(*net.Conn)).Close() + } } func (s *SPS) Start(args interface{}) (err error) { s.cfg = args.(SPSArgs) @@ -304,8 +307,13 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { outAddr := outConn.RemoteAddr().String() utils.IoBind((*inConn), outConn, func(err interface{}) { log.Printf("conn %s - %s released", inAddr, outAddr) + s.userConns.Remove(inAddr) }) log.Printf("conn %s - %s connected", inAddr, outAddr) + if c, ok := s.userConns.Get(inAddr); ok { + (*c.(*net.Conn)).Close() + } + s.userConns.Set(inAddr, &inConn) return } func (s *SPS) InitBasicAuth() (err error) { diff --git a/services/tcp.go b/services/tcp.go index 176d289..fde2849 100644 --- a/services/tcp.go +++ b/services/tcp.go @@ -14,17 +14,19 @@ import ( ) type TCP struct { - outPool utils.OutConn - cfg TCPArgs - sc *utils.ServerChannel - isStop bool + outPool utils.OutConn + cfg TCPArgs + sc *utils.ServerChannel + isStop bool + userConns utils.ConcurrentMap } func NewTCP() Service { return &TCP{ - outPool: utils.OutConn{}, - cfg: TCPArgs{}, - isStop: false, + outPool: utils.OutConn{}, + cfg: TCPArgs{}, + isStop: false, + userConns: utils.NewConcurrentMap(), } } func (s *TCP) CheckArgs() (err error) { @@ -54,7 +56,7 @@ func (s *TCP) StopService() { if e != nil { log.Printf("stop tcp service crashed,%s", e) } else { - log.Printf("service tcp stoped,%s", e) + log.Printf("service tcp stoped") } }() s.isStop = true @@ -64,6 +66,9 @@ func (s *TCP) StopService() { if s.sc.UDPListener != nil { (*s.sc.UDPListener).Close() } + for _, c := range s.userConns.Items() { + (*c.(*net.Conn)).Close() + } } func (s *TCP) Start(args interface{}) (err error) { s.cfg = args.(TCPArgs) @@ -134,14 +139,20 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) { //outLocalAddr := outConn.LocalAddr().String() utils.IoBind((*inConn), outConn, func(err interface{}) { log.Printf("conn %s - %s released", inAddr, outAddr) + s.userConns.Remove(inAddr) }) log.Printf("conn %s - %s connected", inAddr, outAddr) + if c, ok := s.userConns.Get(inAddr); ok { + (*c.(*net.Conn)).Close() + } + s.userConns.Set(inAddr, &inConn) return } func (s *TCP) OutToUDP(inConn *net.Conn) (err error) { log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr()) for { if s.isStop { + (*inConn).Close() return } srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn)) @@ -200,8 +211,6 @@ func (s *TCP) InitOutConnPool() { s.cfg.CertBytes, s.cfg.KeyBytes, nil, *s.cfg.Parent, *s.cfg.Timeout, - *s.cfg.PoolSize, - *s.cfg.PoolSize*2, ) } } diff --git a/services/tunnel_bridge.go b/services/tunnel_bridge.go index f9c6077..b3d4c7d 100644 --- a/services/tunnel_bridge.go +++ b/services/tunnel_bridge.go @@ -47,7 +47,7 @@ func (s *TunnelBridge) StopService() { if e != nil { log.Printf("stop tbridge service crashed,%s", e) } else { - log.Printf("service tbridge stoped,%s", e) + log.Printf("service tbridge stoped") } }() s.isStop = true diff --git a/services/tunnel_client.go b/services/tunnel_client.go index 4f0f51a..d7f9ed8 100644 --- a/services/tunnel_client.go +++ b/services/tunnel_client.go @@ -11,17 +11,17 @@ import ( ) type TunnelClient struct { - cfg TunnelClientArgs - // cm utils.ConnManager - ctrlConn net.Conn - isStop bool + cfg TunnelClientArgs + ctrlConn net.Conn + isStop bool + userConns utils.ConcurrentMap } func NewTunnelClient() Service { return &TunnelClient{ - cfg: TunnelClientArgs{}, - // cm: utils.NewConnManager(), - isStop: false, + cfg: TunnelClientArgs{}, + userConns: utils.NewConcurrentMap(), + isStop: false, } } @@ -49,13 +49,16 @@ func (s *TunnelClient) StopService() { if e != nil { log.Printf("stop tclient service crashed,%s", e) } else { - log.Printf("service tclient stoped,%s", e) + log.Printf("service tclient stoped") } }() s.isStop = true if s.ctrlConn != nil { s.ctrlConn.Close() } + for _, c := range s.userConns.Items() { + (*c.(*net.Conn)).Close() + } } func (s *TunnelClient) Start(args interface{}) (err error) { s.cfg = args.(TunnelClientArgs) @@ -139,6 +142,9 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) { // for { for { if s.isStop { + if inConn != nil { + inConn.Close() + } return } // s.cm.RemoveOne(*s.cfg.Key, ID) @@ -252,10 +258,14 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) { log.Printf("build connection error, err: %s", err) return } + inAddr := inConn.RemoteAddr().String() utils.IoBind(inConn, outConn, func(err interface{}) { log.Printf("conn %s released", ID) - // s.cm.RemoveOne(*s.cfg.Key, ID) + s.userConns.Remove(inAddr) }) - // s.cm.Add(*s.cfg.Key, ID, &inConn) + if c, ok := s.userConns.Get(inAddr); ok { + (*c.(*net.Conn)).Close() + } + s.userConns.Set(inAddr, &inConn) log.Printf("conn %s created", ID) } diff --git a/services/tunnel_server.go b/services/tunnel_server.go index d0dcc16..c82170f 100644 --- a/services/tunnel_server.go +++ b/services/tunnel_server.go @@ -14,11 +14,12 @@ import ( ) type TunnelServer struct { - cfg TunnelServerArgs - udpChn chan UDPItem - sc utils.ServerChannel - isStop bool - udpConn *net.Conn + cfg TunnelServerArgs + udpChn chan UDPItem + sc utils.ServerChannel + isStop bool + udpConn *net.Conn + userConns utils.ConcurrentMap } type TunnelServerManager struct { @@ -139,9 +140,10 @@ func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) { } func NewTunnelServer() Service { return &TunnelServer{ - cfg: TunnelServerArgs{}, - udpChn: make(chan UDPItem, 50000), - isStop: false, + cfg: TunnelServerArgs{}, + udpChn: make(chan UDPItem, 50000), + isStop: false, + userConns: utils.NewConcurrentMap(), } } @@ -157,7 +159,7 @@ func (s *TunnelServer) StopService() { if e != nil { log.Printf("stop server service crashed,%s", e) } else { - log.Printf("service server stoped,%s", e) + log.Printf("service server stoped") } }() s.isStop = true @@ -171,6 +173,9 @@ func (s *TunnelServer) StopService() { 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() @@ -230,12 +235,15 @@ func (s *TunnelServer) Start(args interface{}) (err error) { break } } + inAddr := inConn.RemoteAddr().String() utils.IoBind(inConn, outConn, func(err interface{}) { - // s.cfg.Mgr.cm.RemoveOne(s.cfg.Mgr.serverID, ID) + s.userConns.Remove(inAddr) log.Printf("%s conn %s released", *s.cfg.Key, ID) }) - //add conn - // s.cfg.Mgr.cm.Add(s.cfg.Mgr.serverID, ID, &inConn) + if c, ok := s.userConns.Get(inAddr); ok { + (*c.(*net.Conn)).Close() + } + s.userConns.Set(inAddr, &inConn) log.Printf("%s conn %s created", *s.cfg.Key, ID) }) if err != nil { diff --git a/services/udp.go b/services/udp.go index 09f6aeb..52bab39 100644 --- a/services/udp.go +++ b/services/udp.go @@ -59,7 +59,7 @@ func (s *UDP) StopService() { if e != nil { log.Printf("stop udp service crashed,%s", e) } else { - log.Printf("service udp stoped,%s", e) + log.Printf("service udp stoped") } }() s.isStop = true @@ -133,7 +133,7 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) { func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) { numLocal := crc32.ChecksumIEEE([]byte(localAddr.String())) numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String())) - mod := uint32(*s.cfg.PoolSize) + mod := uint32(10) if mod == 0 { mod = 10 } @@ -153,6 +153,7 @@ func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro log.Printf("conn %d created , local: %s", connKey, srcAddr.String()) for { if s.isStop { + conn.Close() return } srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn)) @@ -240,8 +241,6 @@ func (s *UDP) InitOutConnPool() { s.cfg.CertBytes, s.cfg.KeyBytes, nil, *s.cfg.Parent, *s.cfg.Timeout, - *s.cfg.PoolSize, - *s.cfg.PoolSize*2, ) } } diff --git a/utils/serve-channel.go b/utils/serve-channel.go index 596cede..8547441 100644 --- a/utils/serve-channel.go +++ b/utils/serve-channel.go @@ -24,7 +24,7 @@ func NewServerChannel(ip string, port int) ServerChannel { ip: ip, port: port, errAcceptHandler: func(err error) { - fmt.Printf("accept error , ERR:%s", err) + log.Printf("accept error , ERR:%s", err) }, } } diff --git a/utils/structs.go b/utils/structs.go index 6279530..30f6bc3 100644 --- a/utils/structs.go +++ b/utils/structs.go @@ -516,7 +516,7 @@ type OutConn struct { timeout int } -func NewOutConn(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutConn) { +func NewOutConn(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int) (op OutConn) { return OutConn{ dur: dur, typ: typ,