From 2336e77ac4b0412c84be5d790e0996b7b11f6747 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Fri, 29 Jun 2018 17:55:19 +0800 Subject: [PATCH 01/22] Signed-off-by: arraykeys@gmail.com --- CHANGELOG | 4 ++++ services/sps/sps.go | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a241863..08b0e1b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,8 @@ proxy更新日志 +v5.2 +1.修复了反向代理无法正常工作的问题. +2.修复了自定义加密导致HTTP(S)\SPS反向代理无法正常工作的问题. + v5.1 1.优化了kcp默认mtu配置,调整为450. 2.优化了HTTP(S)\SOCKS5代理智能判断,更加精确。 diff --git a/services/sps/sps.go b/services/sps/sps.go index 68591c7..60b6f29 100644 --- a/services/sps/sps.go +++ b/services/sps/sps.go @@ -17,6 +17,7 @@ import ( "github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils/conncrypt" + "github.com/snail007/goproxy/utils/sni" "github.com/snail007/goproxy/utils/socks" ) @@ -218,7 +219,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { bInConn.ReadByte() bInConn.UnreadByte() - n := 8 + n := 2048 if n > bInConn.Buffered() { n = bInConn.Buffered() } @@ -228,12 +229,12 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { (*inConn).Close() return } - + isSNI, _ := sni.ServerNameFromBytes(h) *inConn = bInConn address := "" var auth socks.Auth var forwardBytes []byte - //fmt.Printf("%v", header) + //fmt.Printf("%v", h) if utils.IsSocks5(h) { if *s.cfg.DisableSocks5 { (*inConn).Close() @@ -251,7 +252,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { } address = serverConn.Target() auth = serverConn.AuthData() - } else if utils.IsHTTP(h) { + } else if utils.IsHTTP(h) || isSNI != "" { if *s.cfg.DisableHTTP { (*inConn).Close() return From 0932aecff3c0a0e0ecf13cee6d02e29a5fcd7721 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Fri, 29 Jun 2018 18:54:24 +0800 Subject: [PATCH 02/22] Signed-off-by: arraykeys@gmail.com --- services/http/http.go | 5 ++--- utils/conncrypt/conncrypt.go | 4 ++-- utils/structs.go | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/services/http/http.go b/services/http/http.go index 16d41a3..51e7771 100644 --- a/services/http/http.go +++ b/services/http/http.go @@ -344,7 +344,6 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut Password: *s.cfg.ParentKey, }) } - outAddr := outConn.RemoteAddr().String() //outLocalAddr := outConn.LocalAddr().String() if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") { @@ -353,8 +352,8 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut } else { //https或者http,上级是代理,proxy需要转发 outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - //直连目标或上级非代理,清理HTTP头部的代理头信息 - if !useProxy || *s.cfg.ParentType == "ssh" { + //直连目标或上级非代理或非SNI,清理HTTP头部的代理头信息. + if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI { _, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf)) } else { _, err = outConn.Write(req.HeadBuf) diff --git a/utils/conncrypt/conncrypt.go b/utils/conncrypt/conncrypt.go index f3115e7..82641e8 100644 --- a/utils/conncrypt/conncrypt.go +++ b/utils/conncrypt/conncrypt.go @@ -12,8 +12,8 @@ import ( ) //Confg defaults -const DefaultIterations = 2048 -const DefaultKeySize = 32 //256bits +const DefaultIterations = 1024 +const DefaultKeySize = 24 //256bits var DefaultHashFunc = sha256.New var DefaultSalt = []byte(` (;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+ Date: Fri, 29 Jun 2018 18:55:18 +0800 Subject: [PATCH 03/22] Signed-off-by: arraykeys@gmail.com --- CHANGELOG | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 08b0e1b..ff0ce10 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,6 @@ proxy更新日志 v5.2 -1.修复了反向代理无法正常工作的问题. -2.修复了自定义加密导致HTTP(S)\SPS反向代理无法正常工作的问题. +1.修复了HTTP(S)\SPS反向代理无法正常工作的问题. v5.1 1.优化了kcp默认mtu配置,调整为450. From 05d2f16777b4c52613cfcb79112b81799391b703 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Fri, 29 Jun 2018 19:21:04 +0800 Subject: [PATCH 04/22] Signed-off-by: arraykeys@gmail.com --- services/http/http.go | 1 + services/socks/socks.go | 1 + services/sps/sps.go | 1 + 3 files changed, 3 insertions(+) diff --git a/services/http/http.go b/services/http/http.go index 51e7771..9159c7b 100644 --- a/services/http/http.go +++ b/services/http/http.go @@ -523,6 +523,7 @@ func (s *HTTP) Resolve(address string) string { ip, err := s.domainResolver.Resolve(address) if err != nil { s.log.Printf("dns error %s , ERR:%s", address, err) + return address } return ip } diff --git a/services/socks/socks.go b/services/socks/socks.go index b740966..9069447 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -804,6 +804,7 @@ func (s *Socks) Resolve(address string) string { ip, err := s.domainResolver.Resolve(address) if err != nil { s.log.Printf("dns error %s , ERR:%s", address, err) + return address } return ip } diff --git a/services/sps/sps.go b/services/sps/sps.go index 60b6f29..e3a7fdf 100644 --- a/services/sps/sps.go +++ b/services/sps/sps.go @@ -496,6 +496,7 @@ func (s *SPS) Resolve(address string) string { ip, err := s.domainResolver.Resolve(address) if err != nil { s.log.Printf("dns error %s , ERR:%s", address, err) + return address } return ip } From d84a4bec86b6490d1aa5d6a4acceb675e25f95c6 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Tue, 3 Jul 2018 17:35:05 +0800 Subject: [PATCH 05/22] Signed-off-by: arraykeys@gmail.com --- CHANGELOG | 1 + sdk/android-ios/dns.go | 2 +- services/http/http.go | 9 +++++---- services/socks/socks.go | 8 +++++--- utils/structs.go | 10 +++++----- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ff0ce10..a87ca95 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ proxy更新日志 v5.2 1.修复了HTTP(S)\SPS反向代理无法正常工作的问题. +2.优化了智能判断,减少不必要的DNS解析. v5.1 1.优化了kcp默认mtu配置,调整为450. diff --git a/sdk/android-ios/dns.go b/sdk/android-ios/dns.go index bb2dc4a..b08290d 100644 --- a/sdk/android-ios/dns.go +++ b/sdk/android-ios/dns.go @@ -76,7 +76,7 @@ func (s *DNS) InitService() (err error) { nil, &net.Dialer{ Timeout: 5 * time.Second, - KeepAlive: 5 * time.Second, + KeepAlive: 2 * time.Second, }, ) if err != nil { diff --git a/services/http/http.go b/services/http/http.go index 9159c7b..a1a14aa 100644 --- a/services/http/http.go +++ b/services/http/http.go @@ -277,10 +277,11 @@ func (s *HTTP) callback(inConn net.Conn) { } else if *s.cfg.Always { useProxy = true } else { - k := s.Resolve(address) - s.checker.Add(address, k) - //var n, m uint - useProxy, _, _ = s.checker.IsBlocked(k) + var isInMap bool + useProxy, isInMap, _, _ = s.checker.IsBlocked(address) + if !isInMap { + s.checker.Add(address, s.Resolve(address)) + } //s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m) } } diff --git a/services/socks/socks.go b/services/socks/socks.go index 9069447..0f762d3 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -562,9 +562,11 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque if utils.IsIternalIP(host, *s.cfg.Always) { useProxy = false } else { - k := s.Resolve(request.Addr()) - s.checker.Add(request.Addr(), k) - useProxy, _, _ = s.checker.IsBlocked(k) + var isInMap bool + useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr()) + if !isInMap { + s.checker.Add(request.Addr(), s.Resolve(request.Addr())) + } } if useProxy { outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) diff --git a/utils/structs.go b/utils/structs.go index d098240..62eec27 100644 --- a/utils/structs.go +++ b/utils/structs.go @@ -132,24 +132,24 @@ func (c *Checker) isNeedCheck(item CheckerItem) bool { } return true } -func (c *Checker) IsBlocked(address string) (blocked bool, failN, successN uint) { +func (c *Checker) IsBlocked(address string) (blocked, isInMap bool, failN, successN uint) { if c.domainIsInMap(address, true) { //log.Printf("%s in blocked ? true", address) - return true, 0, 0 + return true, true, 0, 0 } if c.domainIsInMap(address, false) { //log.Printf("%s in direct ? true", address) - return false, 0, 0 + return false, true, 0, 0 } _item, ok := c.data.Get(address) if !ok { //log.Printf("%s not in map, blocked true", address) - return true, 0, 0 + return true, false, 0, 0 } item := _item.(CheckerItem) - return item.FailCount >= item.SuccessCount, item.FailCount, item.SuccessCount + return item.FailCount >= item.SuccessCount, true, item.FailCount, item.SuccessCount } func (c *Checker) domainIsInMap(address string, blockedMap bool) bool { u, err := url.Parse("http://" + address) From 20c31b0c68969e133ead1393720602699853292b Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Tue, 3 Jul 2018 17:37:17 +0800 Subject: [PATCH 06/22] Signed-off-by: arraykeys@gmail.com --- README_ZH.md | 2 +- docs/old-release.md | 1 + install_auto.sh | 2 +- main.go | 2 +- release.sh | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README_ZH.md b/README_ZH.md index 07b2ebc..59a0aef 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -38,7 +38,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务 - ... -本页是v5.1手册,其他版本手册请点击[这里](docs/old-release.md)查看. +本页是v5.2手册,其他版本手册请点击[这里](docs/old-release.md)查看. ### 怎么找到组织? diff --git a/docs/old-release.md b/docs/old-release.md index aba1110..7204b03 100644 --- a/docs/old-release.md +++ b/docs/old-release.md @@ -1,5 +1,6 @@ # Old Versions of Proxy +- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1) - [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0) - [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9) - [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8) diff --git a/install_auto.sh b/install_auto.sh index 6f1723f..63b7672 100755 --- a/install_auto.sh +++ b/install_auto.sh @@ -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.1/proxy-linux-amd64.tar.gz +wget https://github.com/snail007/goproxy/releases/download/v5.2/proxy-linux-amd64.tar.gz # #install proxy tar zxvf proxy-linux-amd64.tar.gz diff --git a/main.go b/main.go index 66239c7..9d56bb9 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( "github.com/snail007/goproxy/services" ) -const APP_VERSION = "5.1" +const APP_VERSION = "5.2" func main() { err := initConfig() diff --git a/release.sh b/release.sh index 2c505c5..19c7481 100755 --- a/release.sh +++ b/release.sh @@ -1,5 +1,5 @@ #!/bin/bash -VER="5.1" +VER="5.2" RELEASE="release-${VER}" rm -rf .cert mkdir .cert From 846956a9fede2970594620ae8dbc47abf3b7b4bf Mon Sep 17 00:00:00 2001 From: arraykeys Date: Tue, 3 Jul 2018 21:38:35 +0800 Subject: [PATCH 07/22] no message --- utils/structs.go | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/utils/structs.go b/utils/structs.go index 62eec27..dfc0c90 100644 --- a/utils/structs.go +++ b/utils/structs.go @@ -33,15 +33,11 @@ type Checker struct { log *logger.Logger } type CheckerItem struct { - IsHTTPS bool - Method string - URL string Domain string - Host string - Data []byte + Address string SuccessCount uint FailCount uint - Key string + Lasttime int64 } //NewChecker args: @@ -101,7 +97,7 @@ func (c *Checker) start() { //log.Printf("check %s", item.Host) var conn net.Conn var err error - conn, err = ConnectHost(item.Host, c.timeout) + conn, err = ConnectHost(item.Address, c.timeout) if err == nil { conn.SetDeadline(time.Now().Add(time.Millisecond)) conn.Close() @@ -111,7 +107,8 @@ func (c *Checker) start() { } else { item.SuccessCount = item.SuccessCount + 1 } - c.data.Set(item.Host, item) + item.Lasttime = time.Now().Unix() + c.data.Set(item.Domain, item) } }(v.(CheckerItem)) } @@ -126,23 +123,28 @@ func (c *Checker) isNeedCheck(item CheckerItem) bool { var minCount uint = 5 if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount) || (item.FailCount >= minCount && item.SuccessCount > item.FailCount) || - c.domainIsInMap(item.Host, false) || - c.domainIsInMap(item.Host, true) { + c.domainIsInMap(item.Domain, false) || + c.domainIsInMap(item.Domain, true) || + time.Now().Unix()-item.Lasttime > 1800 { return false } return true } -func (c *Checker) IsBlocked(address string) (blocked, isInMap bool, failN, successN uint) { - if c.domainIsInMap(address, true) { +func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, successN uint) { + h, _, _ := net.SplitHostPort(domain) + if h != "" { + domain = h + } + if c.domainIsInMap(domain, true) { //log.Printf("%s in blocked ? true", address) return true, true, 0, 0 } - if c.domainIsInMap(address, false) { + if c.domainIsInMap(domain, false) { //log.Printf("%s in direct ? true", address) return false, true, 0, 0 } - _item, ok := c.data.Get(address) + _item, ok := c.data.Get(domain) if !ok { //log.Printf("%s not in map, blocked true", address) return true, false, 0, 0 @@ -174,16 +176,20 @@ func (c *Checker) domainIsInMap(address string, blockedMap bool) bool { } return false } -func (c *Checker) Add(key, address string) { - if c.domainIsInMap(key, false) || c.domainIsInMap(key, true) { +func (c *Checker) Add(domain, address string) { + h, _, _ := net.SplitHostPort(domain) + if h != "" { + domain = h + } + if c.domainIsInMap(domain, false) || c.domainIsInMap(domain, true) { return } var item CheckerItem item = CheckerItem{ - Host: address, - Key: key, + Domain: domain, + Address: address, } - c.data.SetIfAbsent(item.Host, item) + c.data.SetIfAbsent(item.Domain, item) } type BasicAuth struct { From bf72325fc0b3c4132003c87fd1af84026c280eb7 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Wed, 4 Jul 2018 17:44:24 +0800 Subject: [PATCH 08/22] Signed-off-by: arraykeys@gmail.com --- services/socks/socks.go | 180 +++++++++++++++++++++++++++++++++++----- utils/socks/client.go | 6 +- 2 files changed, 160 insertions(+), 26 deletions(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index 0f762d3..acf6a9d 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -3,10 +3,12 @@ package socks import ( "crypto/tls" "fmt" + "io" "io/ioutil" logger "log" "net" "runtime/debug" + "strconv" "strings" "time" @@ -59,27 +61,29 @@ type SocksArgs struct { ParentCompress *bool } type Socks struct { - cfg SocksArgs - checker utils.Checker - basicAuth utils.BasicAuth - sshClient *ssh.Client - lockChn chan bool - udpSC utils.ServerChannel - sc *utils.ServerChannel - domainResolver utils.DomainResolver - isStop bool - userConns utils.ConcurrentMap - log *logger.Logger + cfg SocksArgs + checker utils.Checker + basicAuth utils.BasicAuth + sshClient *ssh.Client + lockChn chan bool + udpSC utils.ServerChannel + sc *utils.ServerChannel + domainResolver utils.DomainResolver + isStop bool + userConns utils.ConcurrentMap + log *logger.Logger + udpRelatedPacketConns utils.ConcurrentMap } func NewSocks() services.Service { return &Socks{ - cfg: SocksArgs{}, - checker: utils.Checker{}, - basicAuth: utils.BasicAuth{}, - lockChn: make(chan bool, 1), - isStop: false, - userConns: utils.NewConcurrentMap(), + cfg: SocksArgs{}, + checker: utils.Checker{}, + basicAuth: utils.BasicAuth{}, + lockChn: make(chan bool, 1), + isStop: false, + userConns: utils.NewConcurrentMap(), + udpRelatedPacketConns: utils.NewConcurrentMap(), } } @@ -220,6 +224,9 @@ func (s *Socks) StopService() { for _, c := range s.userConns.Items() { (*c.(*net.Conn)).Close() } + for _, c := range s.udpRelatedPacketConns.Items() { + (*c.(*net.UDPConn)).Close() + } } func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) { s.log = log @@ -438,7 +445,9 @@ func (s *Socks) socksConnCallback(inConn net.Conn) { if err != nil { methodReq.Reply(socks.Method_NONE_ACCEPTABLE) utils.CloseConn(&inConn) - s.log.Printf("new methods request fail,ERR: %s", err) + if err != io.EOF { + s.log.Printf("new methods request fail,ERR: %s", err) + } return } @@ -531,10 +540,132 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque utils.CloseConn(inConn) return } + inconnRemoteAddr := (*inConn).RemoteAddr().String() + localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} + udpListener, err := net.ListenUDP("udp", localAddr) + if err != nil { + (*inConn).Close() + udpListener.Close() + s.log.Printf("udp bind fail , %s", err) + return + } host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) - _, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String()) - s.log.Printf("proxy udp on %s", net.JoinHostPort(host, port)) + _, port, _ := net.SplitHostPort(udpListener.LocalAddr().String()) + s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr) request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) + + s.userConns.Set(inconnRemoteAddr, inConn) + var outUDPConn *net.UDPConn + go func() { + buf := make([]byte, 1) + if _, err := (*inConn).Read(buf); err != nil { + laddr := "" + if outUDPConn != nil { + laddr = outUDPConn.LocalAddr().String() + } + s.log.Printf("udp related tcp conn disconnected , %s -> %s , %s", inconnRemoteAddr, laddr, err) + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + if outUDPConn != nil { + outUDPConn.Close() + } + } + }() + if *s.cfg.Parent != "" { + outconn, err := s.getOutConn(nil, nil, "", false) + if err != nil { + (*inConn).Close() + udpListener.Close() + s.log.Printf("connect fail , %s", err) + return + } + client := socks.NewClientConn(&outconn, "udp", "", time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) + if err = client.Handshake(); err != nil { + (*inConn).Close() + udpListener.Close() + s.log.Printf("handshake fail , %s", err) + } + outconnRemoteAddr := outconn.RemoteAddr().String() + outconnLocalAddr := outconn.LocalAddr().String() + s.userConns.Set(outconnLocalAddr, &outconn) + s.log.Printf("parent udp address %s", client.UDPAddr) + go func() { + buf := make([]byte, 1) + if _, err := outconn.Read(buf); err != nil { + s.log.Printf("udp parent net conn offline , %s", outconnRemoteAddr) + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(outconnLocalAddr) + } + }() + } else { + for { + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + n, srcAddr, err := udpListener.ReadFromUDP(buf) + if err != nil { + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + s.log.Printf("udp listener read fail , %s", err) + return + } + p := socks.NewPacketUDP() + err = p.Parse(buf[:n]) + if err != nil { + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + s.log.Printf("udp listener parse packet fail , %s , from : %s", err, srcAddr) + return + } + + port, _ := strconv.Atoi(p.Port()) + destAddr := &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port} + if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok { + outUDPConn, err = net.DialUDP("udp", localAddr, destAddr) + if err != nil { + s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) + continue + } + s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) + go func() { + //bind + for { + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + n, err := outUDPConn.Read(buf) + if err != nil { + s.udpRelatedPacketConns.Remove(srcAddr.String()) + s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) + if strings.Contains(err.Error(), "use of closed network connection") { + break + } + continue + } + rp := socks.NewPacketUDP() + rp.Build(srcAddr.String(), buf[:n]) + _, err = udpListener.WriteTo(rp.Bytes(), srcAddr) + if err != nil { + s.udpRelatedPacketConns.Remove(srcAddr.String()) + s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) + if strings.Contains(err.Error(), "use of closed network connection") { + break + } + } + } + }() + } else { + outUDPConn = v.(*net.UDPConn) + } + _, err = outUDPConn.Write(p.Data()) + if err != nil { + s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) + continue + } + } + } } func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { var outConn net.Conn @@ -554,7 +685,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque return } if *s.cfg.Always { - outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) + outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true) } else { if *s.cfg.Parent != "" { host, _, _ := net.SplitHostPort(request.Addr()) @@ -569,7 +700,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } } if useProxy { - outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) + outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true) } else { outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout) } @@ -609,7 +740,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } s.userConns.Set(inAddr, inConn) } -func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) { +func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake bool) (outConn net.Conn, err interface{}) { switch *s.cfg.ParentType { case "kcp": fallthrough @@ -637,6 +768,9 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n Password: *s.cfg.ParentKey, }) } + if !handshake { + return + } var buf = make([]byte, 1024) //var n int outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) diff --git a/utils/socks/client.go b/utils/socks/client.go index 619e3c7..7b06c1d 100644 --- a/utils/socks/client.go +++ b/utils/socks/client.go @@ -33,7 +33,7 @@ type ClientConn struct { timeout time.Duration addr string network string - udpAddr string + UDPAddr string } // SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address @@ -168,14 +168,14 @@ func (s *ClientConn) Handshake() error { } p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]}) //log.Printf("%v", p) - s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p)) + s.UDPAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p)) //log.Printf("%v", s.udpAddr) (*s.conn).SetDeadline(time.Time{}) return nil } func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) { - c, err := net.DialTimeout("udp", s.udpAddr, s.timeout) + c, err := net.DialTimeout("udp", s.UDPAddr, s.timeout) if err != nil { return } From eaf836eff33dca62d383d04101d8924b2e26217b Mon Sep 17 00:00:00 2001 From: arraykeys Date: Wed, 4 Jul 2018 21:43:30 +0800 Subject: [PATCH 09/22] no message --- services/socks/socks.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index acf6a9d..873a477 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -559,11 +559,11 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque go func() { buf := make([]byte, 1) if _, err := (*inConn).Read(buf); err != nil { - laddr := "" + raddr := "" if outUDPConn != nil { - laddr = outUDPConn.LocalAddr().String() + raddr = outUDPConn.RemoteAddr().String() } - s.log.Printf("udp related tcp conn disconnected , %s -> %s , %s", inconnRemoteAddr, laddr, err) + s.log.Printf("udp related tcp conn disconnected , %s -> %s", inconnRemoteAddr, raddr) (*inConn).Close() udpListener.Close() s.userConns.Remove(inconnRemoteAddr) @@ -646,13 +646,16 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } rp := socks.NewPacketUDP() rp.Build(srcAddr.String(), buf[:n]) - _, err = udpListener.WriteTo(rp.Bytes(), srcAddr) + d := rp.Bytes() + _, err = udpListener.WriteTo(d, srcAddr) if err != nil { s.udpRelatedPacketConns.Remove(srcAddr.String()) s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) if strings.Contains(err.Error(), "use of closed network connection") { break } + } else { + s.log.Printf("send udp data to local success , len %d, for : %s", len(d), srcAddr) } } }() @@ -663,6 +666,8 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque if err != nil { s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) continue + } else { + s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) } } } From 50886bd69a77533edf09db328941a25c159f77fa Mon Sep 17 00:00:00 2001 From: arraykeys Date: Wed, 4 Jul 2018 21:51:59 +0800 Subject: [PATCH 10/22] no message --- services/socks/socks.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index 873a477..d18490f 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -563,7 +563,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque if outUDPConn != nil { raddr = outUDPConn.RemoteAddr().String() } - s.log.Printf("udp related tcp conn disconnected , %s -> %s", inconnRemoteAddr, raddr) + s.log.Printf("udp related tcp conn disconnected with read , %s -> %s", inconnRemoteAddr, raddr) (*inConn).Close() udpListener.Close() s.userConns.Remove(inconnRemoteAddr) @@ -572,6 +572,25 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } } }() + go func() { + for { + if _, err := (*inConn).Write([]byte{0x00}); err != nil { + raddr := "" + if outUDPConn != nil { + raddr = outUDPConn.RemoteAddr().String() + } + s.log.Printf("udp related tcp conn disconnected with write , %s -> %s", inconnRemoteAddr, raddr) + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + if outUDPConn != nil { + outUDPConn.Close() + } + return + } + time.Sleep(time.Second * 5) + } + }() if *s.cfg.Parent != "" { outconn, err := s.getOutConn(nil, nil, "", false) if err != nil { From c20e19d74f1bddcc633036b4b5dbd0a54f673b10 Mon Sep 17 00:00:00 2001 From: arraykeys Date: Wed, 4 Jul 2018 23:58:09 +0800 Subject: [PATCH 11/22] no message --- services/socks/socks.go | 115 +++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index d18490f..d888618 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -553,39 +553,49 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque _, port, _ := net.SplitHostPort(udpListener.LocalAddr().String()) s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr) request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) - s.userConns.Set(inconnRemoteAddr, inConn) - var outUDPConn *net.UDPConn + var ( + outUDPConn *net.UDPConn + outconn net.Conn + outconnLocalAddr string + isClosedErr = func(err error) bool { + return err != nil && strings.Contains(err.Error(), "use of closed network connection") + } + ) + var clean = func(msg, err string) { + raddr := "" + if outUDPConn != nil { + raddr = outUDPConn.RemoteAddr().String() + outUDPConn.Close() + } + if msg != "" { + if raddr != "" { + s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr) + } else { + s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr) + } + } + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + if outconn != nil { + outconn.Close() + } + if outconnLocalAddr != "" { + s.userConns.Remove(outconnLocalAddr) + } + } + defer clean("", "") go func() { buf := make([]byte, 1) if _, err := (*inConn).Read(buf); err != nil { - raddr := "" - if outUDPConn != nil { - raddr = outUDPConn.RemoteAddr().String() - } - s.log.Printf("udp related tcp conn disconnected with read , %s -> %s", inconnRemoteAddr, raddr) - (*inConn).Close() - udpListener.Close() - s.userConns.Remove(inconnRemoteAddr) - if outUDPConn != nil { - outUDPConn.Close() - } + clean("udp related tcp conn disconnected with read", err.Error()) } }() go func() { for { if _, err := (*inConn).Write([]byte{0x00}); err != nil { - raddr := "" - if outUDPConn != nil { - raddr = outUDPConn.RemoteAddr().String() - } - s.log.Printf("udp related tcp conn disconnected with write , %s -> %s", inconnRemoteAddr, raddr) - (*inConn).Close() - udpListener.Close() - s.userConns.Remove(inconnRemoteAddr) - if outUDPConn != nil { - outUDPConn.Close() - } + clean("udp related tcp conn disconnected with write", err.Error()) return } time.Sleep(time.Second * 5) @@ -594,50 +604,43 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque if *s.cfg.Parent != "" { outconn, err := s.getOutConn(nil, nil, "", false) if err != nil { - (*inConn).Close() - udpListener.Close() - s.log.Printf("connect fail , %s", err) + clean("connnect fail", fmt.Sprintf("%s", err)) return } client := socks.NewClientConn(&outconn, "udp", "", time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) if err = client.Handshake(); err != nil { - (*inConn).Close() - udpListener.Close() - s.log.Printf("handshake fail , %s", err) + clean("handshake fail", fmt.Sprintf("%s", err)) + return } - outconnRemoteAddr := outconn.RemoteAddr().String() - outconnLocalAddr := outconn.LocalAddr().String() + //outconnRemoteAddr := outconn.RemoteAddr().String() + outconnLocalAddr = outconn.LocalAddr().String() s.userConns.Set(outconnLocalAddr, &outconn) - s.log.Printf("parent udp address %s", client.UDPAddr) go func() { buf := make([]byte, 1) if _, err := outconn.Read(buf); err != nil { - s.log.Printf("udp parent net conn offline , %s", outconnRemoteAddr) - (*inConn).Close() - udpListener.Close() - s.userConns.Remove(outconnLocalAddr) + clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err)) } }() + //forward to parent udp + s.log.Printf("parent udp address %s", client.UDPAddr) + } else { for { buf := utils.LeakyBuffer.Get() defer utils.LeakyBuffer.Put(buf) n, srcAddr, err := udpListener.ReadFromUDP(buf) if err != nil { - (*inConn).Close() - udpListener.Close() - s.userConns.Remove(inconnRemoteAddr) - s.log.Printf("udp listener read fail , %s", err) - return + s.log.Printf("udp listener read fail, %s", err.Error()) + if isClosedErr(err) { + return + } + continue } p := socks.NewPacketUDP() err = p.Parse(buf[:n]) if err != nil { - (*inConn).Close() - udpListener.Close() - s.userConns.Remove(inconnRemoteAddr) - s.log.Printf("udp listener parse packet fail , %s , from : %s", err, srcAddr) - return + s.log.Printf("udp listener parse packet fail, %s", err.Error()) + continue } port, _ := strconv.Atoi(p.Port()) @@ -650,16 +653,16 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) go func() { + defer s.udpRelatedPacketConns.Remove(srcAddr.String()) //bind + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) for { - buf := utils.LeakyBuffer.Get() - defer utils.LeakyBuffer.Put(buf) n, err := outUDPConn.Read(buf) if err != nil { - s.udpRelatedPacketConns.Remove(srcAddr.String()) s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) - if strings.Contains(err.Error(), "use of closed network connection") { - break + if isClosedErr(err) { + return } continue } @@ -670,9 +673,10 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque if err != nil { s.udpRelatedPacketConns.Remove(srcAddr.String()) s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) - if strings.Contains(err.Error(), "use of closed network connection") { - break + if isClosedErr(err) { + return } + continue } else { s.log.Printf("send udp data to local success , len %d, for : %s", len(d), srcAddr) } @@ -683,6 +687,9 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } _, err = outUDPConn.Write(p.Data()) if err != nil { + if isClosedErr(err) { + return + } s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) continue } else { From e92375f6a9c6cf44c7df259f0be5abc89f02b823 Mon Sep 17 00:00:00 2001 From: arraykeys Date: Thu, 5 Jul 2018 00:03:46 +0800 Subject: [PATCH 12/22] no message --- services/socks/socks.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index d888618..2fb4541 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -602,6 +602,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } }() if *s.cfg.Parent != "" { + //parent proxy outconn, err := s.getOutConn(nil, nil, "", false) if err != nil { clean("connnect fail", fmt.Sprintf("%s", err)) @@ -625,6 +626,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque s.log.Printf("parent udp address %s", client.UDPAddr) } else { + //local proxy for { buf := utils.LeakyBuffer.Get() defer utils.LeakyBuffer.Put(buf) @@ -652,9 +654,10 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque continue } s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) + go func() { defer s.udpRelatedPacketConns.Remove(srcAddr.String()) - //bind + //out->local io copy buf := utils.LeakyBuffer.Get() defer utils.LeakyBuffer.Put(buf) for { @@ -685,6 +688,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } else { outUDPConn = v.(*net.UDPConn) } + //local->out io copy _, err = outUDPConn.Write(p.Data()) if err != nil { if isClosedErr(err) { From cb8d0c0b4228f2eaf220e2382e7f586751f852ef Mon Sep 17 00:00:00 2001 From: arraykeys Date: Thu, 5 Jul 2018 01:03:37 +0800 Subject: [PATCH 13/22] no message --- services/socks/socks.go | 156 ++++++++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 62 deletions(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index 2fb4541..99427a9 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -561,6 +561,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque isClosedErr = func(err error) bool { return err != nil && strings.Contains(err.Error(), "use of closed network connection") } + destAddr *net.UDPAddr ) var clean = func(msg, err string) { raddr := "" @@ -601,7 +602,18 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque time.Sleep(time.Second * 5) } }() + useProxy := true if *s.cfg.Parent != "" { + dstHost, _, _ := net.SplitHostPort(request.Addr()) + if utils.IsIternalIP(dstHost, *s.cfg.Always) { + useProxy = false + } else { + var isInMap bool + useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr()) + if !isInMap { + s.checker.Add(request.Addr(), s.Resolve(request.Addr())) + } + } //parent proxy outconn, err := s.getOutConn(nil, nil, "", false) if err != nil { @@ -624,83 +636,103 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque }() //forward to parent udp s.log.Printf("parent udp address %s", client.UDPAddr) - + destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) } else { - //local proxy - for { - buf := utils.LeakyBuffer.Get() - defer utils.LeakyBuffer.Put(buf) - n, srcAddr, err := udpListener.ReadFromUDP(buf) + useProxy = false + } + s.log.Printf("use proxy %v , udp %s", useProxy, request.Addr()) + //relay + for { + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + n, srcAddr, err := udpListener.ReadFromUDP(buf) + if err != nil { + s.log.Printf("udp listener read fail, %s", err.Error()) + if isClosedErr(err) { + return + } + continue + } + p := socks.NewPacketUDP() + err = p.Parse(buf[:n]) + if err != nil { + s.log.Printf("udp listener parse packet fail, %s", err.Error()) + continue + } + + port, _ := strconv.Atoi(p.Port()) + + if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok { + if destAddr == nil { + destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port} + } + outUDPConn, err = net.DialUDP("udp", localAddr, destAddr) if err != nil { - s.log.Printf("udp listener read fail, %s", err.Error()) - if isClosedErr(err) { - return - } - continue - } - p := socks.NewPacketUDP() - err = p.Parse(buf[:n]) - if err != nil { - s.log.Printf("udp listener parse packet fail, %s", err.Error()) + s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) continue } + s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) - port, _ := strconv.Atoi(p.Port()) - destAddr := &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port} - if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok { - outUDPConn, err = net.DialUDP("udp", localAddr, destAddr) - if err != nil { - s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) - continue - } - s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) - - go func() { - defer s.udpRelatedPacketConns.Remove(srcAddr.String()) - //out->local io copy - buf := utils.LeakyBuffer.Get() - defer utils.LeakyBuffer.Put(buf) - for { - n, err := outUDPConn.Read(buf) - if err != nil { - s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) - if isClosedErr(err) { - return - } - continue + go func() { + defer s.udpRelatedPacketConns.Remove(srcAddr.String()) + //out->local io copy + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + for { + n, err := outUDPConn.Read(buf) + if err != nil { + s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) + if isClosedErr(err) { + return } + continue + } + + var dlen = n + if useProxy { + //forward to local + _, err = udpListener.WriteTo(buf[:n], srcAddr) + } else { rp := socks.NewPacketUDP() rp.Build(srcAddr.String(), buf[:n]) d := rp.Bytes() + dlen = len(d) _, err = udpListener.WriteTo(d, srcAddr) - if err != nil { - s.udpRelatedPacketConns.Remove(srcAddr.String()) - s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) - if isClosedErr(err) { - return - } - continue - } else { - s.log.Printf("send udp data to local success , len %d, for : %s", len(d), srcAddr) - } } - }() - } else { - outUDPConn = v.(*net.UDPConn) - } - //local->out io copy - _, err = outUDPConn.Write(p.Data()) - if err != nil { - if isClosedErr(err) { - return + + if err != nil { + s.udpRelatedPacketConns.Remove(srcAddr.String()) + s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) + if isClosedErr(err) { + return + } + continue + } else { + s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr) + } } - s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) - continue - } else { - s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) + }() + } else { + outUDPConn = v.(*net.UDPConn) + } + //local->out io copy + if useProxy { + //forward to parent + _, err = outUDPConn.Write(buf[:n]) + } else { + _, err = outUDPConn.Write(p.Data()) + } + if err != nil { + if isClosedErr(err) { + return } + s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) + continue + } else { + s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) } } + } func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { var outConn net.Conn From 3b49f17e019c0cebe41c20582c78bb8feac51ee5 Mon Sep 17 00:00:00 2001 From: arraykeys Date: Thu, 5 Jul 2018 01:56:18 +0800 Subject: [PATCH 14/22] no message --- utils/structs.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/utils/structs.go b/utils/structs.go index dfc0c90..079c6d5 100644 --- a/utils/structs.go +++ b/utils/structs.go @@ -97,17 +97,22 @@ func (c *Checker) start() { //log.Printf("check %s", item.Host) var conn net.Conn var err error + var now = time.Now().Unix() conn, err = ConnectHost(item.Address, c.timeout) if err == nil { conn.SetDeadline(time.Now().Add(time.Millisecond)) conn.Close() } + if now-item.Lasttime > 1800 { + item.FailCount = 0 + item.SuccessCount = 0 + } if err != nil { item.FailCount = item.FailCount + 1 } else { item.SuccessCount = item.SuccessCount + 1 } - item.Lasttime = time.Now().Unix() + item.Lasttime = now c.data.Set(item.Domain, item) } }(v.(CheckerItem)) @@ -121,11 +126,11 @@ func (c *Checker) start() { } func (c *Checker) isNeedCheck(item CheckerItem) bool { var minCount uint = 5 - if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount) || - (item.FailCount >= minCount && item.SuccessCount > item.FailCount) || + var now = time.Now().Unix() + if (item.SuccessCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) || + (item.FailCount >= minCount && item.SuccessCount > item.FailCount && now-item.Lasttime < 1800) || c.domainIsInMap(item.Domain, false) || - c.domainIsInMap(item.Domain, true) || - time.Now().Unix()-item.Lasttime > 1800 { + c.domainIsInMap(item.Domain, true) { return false } return true From 12dd591c58890579c4e1c5419ca698b340592ec2 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Thu, 5 Jul 2018 15:56:26 +0800 Subject: [PATCH 15/22] add fully socks5 UDP support Signed-off-by: arraykeys@gmail.com --- config.go | 2 - sdk/android-ios/sdk.go | 2 - services/socks/socks.go | 293 +++++++++++++--------------------------- utils/functions.go | 93 ------------- 4 files changed, 95 insertions(+), 295 deletions(-) diff --git a/config.go b/config.go index 7b633db..547f26f 100755 --- a/config.go +++ b/config.go @@ -198,8 +198,6 @@ func initConfig() (err error) { socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type ").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh") socksArgs.LocalType = socks.Flag("local-type", "local protocol type ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() - socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String() - socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String() socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String() socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() diff --git a/sdk/android-ios/sdk.go b/sdk/android-ios/sdk.go index 1033d62..db1882a 100644 --- a/sdk/android-ios/sdk.go +++ b/sdk/android-ios/sdk.go @@ -194,8 +194,6 @@ func Start(serviceID, serviceArgsStr string) (errStr string) { socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type ").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh") socksArgs.LocalType = socks.Flag("local-type", "local protocol type ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() - socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String() - socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String() socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String() socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() diff --git a/services/socks/socks.go b/services/socks/socks.go index 99427a9..4aa35d0 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -1,6 +1,7 @@ package socks import ( + "crypto/md5" "crypto/tls" "fmt" "io" @@ -15,7 +16,7 @@ import ( "github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/utils" - "github.com/snail007/goproxy/utils/aes" + goaes "github.com/snail007/goproxy/utils/aes" "github.com/snail007/goproxy/utils/conncrypt" "github.com/snail007/goproxy/utils/socks" "golang.org/x/crypto/ssh" @@ -50,8 +51,6 @@ type SocksArgs struct { AuthURLTimeout *int AuthURLRetry *int KCP kcpcfg.KCPConfigArgs - UDPParent *string - UDPLocal *string LocalIPS *[]string DNSAddress *string DNSTTL *int @@ -73,6 +72,8 @@ type Socks struct { userConns utils.ConcurrentMap log *logger.Logger udpRelatedPacketConns utils.ConcurrentMap + udpLocalKey []byte + udpParentKey []byte } func NewSocks() services.Service { @@ -107,17 +108,6 @@ func (s *Socks) CheckArgs() (err error) { err = fmt.Errorf("parent type unkown,use -T ") return } - host, _, e := net.SplitHostPort(*s.cfg.Parent) - if e != nil { - err = fmt.Errorf("parent format error : %s", e) - return - } - if *s.cfg.UDPParent == "" { - *s.cfg.UDPParent = net.JoinHostPort(host, "33090") - } - if strings.HasPrefix(*s.cfg.UDPParent, ":") { - *s.cfg.UDPParent = net.JoinHostPort(host, strings.TrimLeft(*s.cfg.UDPParent, ":")) - } if *s.cfg.ParentType == "ssh" { if *s.cfg.SSHUser == "" { err = fmt.Errorf("ssh user required") @@ -149,6 +139,9 @@ func (s *Socks) CheckArgs() (err error) { } } } + s.udpLocalKey = s.LocalUDPKey() + s.udpParentKey = s.ParentUDPKey() + //s.log.Printf("udpLocalKey : %v , udpParentKey : %v", s.udpLocalKey, s.udpParentKey) return } func (s *Socks) InitService() (err error) { @@ -190,14 +183,6 @@ func (s *Socks) InitService() (err error) { } if *s.cfg.ParentType == "ssh" { s.log.Printf("warn: socks udp not suppored for ssh") - } else { - s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal, s.log) - e := s.udpSC.ListenUDP(s.udpCallback) - if e != nil { - err = fmt.Errorf("init udp service fail, ERR: %s", e) - return - } - s.log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr()) } return } @@ -241,9 +226,6 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) { if *s.cfg.Parent != "" { s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) } - if *s.cfg.UDPParent != "" { - s.log.Printf("use socks udp parent %s", *s.cfg.UDPParent) - } sc := utils.NewServerChannelHost(*s.cfg.Local, s.log) if *s.cfg.LocalType == "tcp" { err = sc.ListenTCP(s.socksConnCallback) @@ -262,165 +244,7 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) { func (s *Socks) Clean() { s.StopService() } -func (s *Socks) UDPKey() []byte { - return s.cfg.KeyBytes[:32] -} -func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) { - rawB := b - var err error - if *s.cfg.LocalType == "tls" { - //decode b - rawB, err = goaes.Decrypt(s.UDPKey(), b) - if err != nil { - s.log.Printf("decrypt udp packet fail from %s", srcAddr.String()) - return - } - } - p, err := socks.ParseUDPPacket(rawB) - s.log.Printf("udp revecived:%v", len(p.Data())) - if err != nil { - s.log.Printf("parse udp packet fail, ERR:%s", err) - return - } - //防止死循环 - if s.IsDeadLoop((*localAddr).String(), p.Host()) { - s.log.Printf("dead loop detected , %s", p.Host()) - return - } - //s.log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port()) - if *s.cfg.Parent != "" { - //有上级代理,转发给上级 - if *s.cfg.ParentType == "tls" { - //encode b - rawB, err = goaes.Encrypt(s.UDPKey(), rawB) - if err != nil { - s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent) - return - } - } - parent := *s.cfg.UDPParent - if parent == "" { - parent = *s.cfg.Parent - } - dstAddr, err := net.ResolveUDPAddr("udp", s.Resolve(parent)) - if err != nil { - s.log.Printf("can't resolve address: %s", err) - return - } - clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} - conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) - if err != nil { - s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) - return - } - conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5))) - _, err = conn.Write(rawB) - conn.SetDeadline(time.Time{}) - s.log.Printf("udp request:%v", len(rawB)) - if err != nil { - s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) - conn.Close() - return - } - //s.log.Printf("send udp packet to %s success", dstAddr.String()) - buf := make([]byte, 10*1024) - conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - length, _, err := conn.ReadFromUDP(buf) - conn.SetDeadline(time.Time{}) - if err != nil { - s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) - conn.Close() - return - } - respBody := buf[0:length] - s.log.Printf("udp response:%v", len(respBody)) - //s.log.Printf("revecived udp packet from %s", dstAddr.String()) - if *s.cfg.ParentType == "tls" { - //decode b - respBody, err = goaes.Decrypt(s.UDPKey(), respBody) - if err != nil { - s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent) - conn.Close() - return - } - } - if *s.cfg.LocalType == "tls" { - d, err := goaes.Encrypt(s.UDPKey(), respBody) - if err != nil { - s.log.Printf("encrypt udp data fail from %s", dstAddr.String()) - conn.Close() - return - } - s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - s.udpSC.UDPListener.WriteToUDP(d, srcAddr) - s.udpSC.UDPListener.SetDeadline(time.Time{}) - s.log.Printf("udp reply:%v", len(d)) - d = nil - } else { - s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr) - s.udpSC.UDPListener.SetDeadline(time.Time{}) - s.log.Printf("udp reply:%v", len(respBody)) - } - - } else { - //本地代理 - dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(s.Resolve(p.Host()), p.Port())) - if err != nil { - s.log.Printf("can't resolve address: %s", err) - return - } - clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} - conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) - if err != nil { - s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) - return - } - conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3))) - _, err = conn.Write(p.Data()) - conn.SetDeadline(time.Time{}) - s.log.Printf("udp send:%v", len(p.Data())) - if err != nil { - s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) - conn.Close() - return - } - //s.log.Printf("send udp packet to %s success", dstAddr.String()) - buf := make([]byte, 10*1024) - conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - length, _, err := conn.ReadFromUDP(buf) - conn.SetDeadline(time.Time{}) - - if err != nil { - s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) - conn.Close() - return - } - respBody := buf[0:length] - //封装来自真实服务器的数据,返回给访问者 - respPacket := p.NewReply(respBody) - //s.log.Printf("revecived udp packet from %s", dstAddr.String()) - if *s.cfg.LocalType == "tls" { - d, err := goaes.Encrypt(s.UDPKey(), respPacket) - if err != nil { - s.log.Printf("encrypt udp data fail from %s", dstAddr.String()) - conn.Close() - return - } - s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - s.udpSC.UDPListener.WriteToUDP(d, srcAddr) - s.udpSC.UDPListener.SetDeadline(time.Time{}) - d = nil - } else { - s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) - s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr) - s.udpSC.UDPListener.SetDeadline(time.Time{}) - } - s.log.Printf("udp reply:%v", len(respPacket)) - } - -} func (s *Socks) socksConnCallback(inConn net.Conn) { defer func() { if err := recover(); err != nil { @@ -535,6 +359,36 @@ func (s *Socks) socksConnCallback(inConn net.Conn) { } } +func (s *Socks) ParentUDPKey() (key []byte) { + switch *s.cfg.ParentType { + case "tcp": + if *s.cfg.ParentKey != "" { + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey))) + return []byte(v)[:24] + } + case "tls": + return s.cfg.KeyBytes[:24] + case "kcp": + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) + return []byte(v)[:24] + } + return +} +func (s *Socks) LocalUDPKey() (key []byte) { + switch *s.cfg.LocalType { + case "tcp": + if *s.cfg.LocalKey != "" { + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey))) + return []byte(v)[:24] + } + case "tls": + return s.cfg.KeyBytes[:24] + case "kcp": + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) + return []byte(v)[:24] + } + return +} func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { if *s.cfg.ParentType == "ssh" { utils.CloseConn(inConn) @@ -589,16 +443,19 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque defer clean("", "") go func() { buf := make([]byte, 1) + (*inConn).SetReadDeadline(time.Time{}) if _, err := (*inConn).Read(buf); err != nil { clean("udp related tcp conn disconnected with read", err.Error()) } }() go func() { for { + (*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5)) if _, err := (*inConn).Write([]byte{0x00}); err != nil { clean("udp related tcp conn disconnected with write", err.Error()) return } + (*inConn).SetWriteDeadline(time.Time{}) time.Sleep(time.Second * 5) } }() @@ -614,13 +471,17 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque s.checker.Add(request.Addr(), s.Resolve(request.Addr())) } } + } else { + useProxy = false + } + if useProxy { //parent proxy outconn, err := s.getOutConn(nil, nil, "", false) if err != nil { clean("connnect fail", fmt.Sprintf("%s", err)) return } - client := socks.NewClientConn(&outconn, "udp", "", time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) + client := socks.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) if err = client.Handshake(); err != nil { clean("handshake fail", fmt.Sprintf("%s", err)) return @@ -630,17 +491,16 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque s.userConns.Set(outconnLocalAddr, &outconn) go func() { buf := make([]byte, 1) + outconn.SetReadDeadline(time.Time{}) if _, err := outconn.Read(buf); err != nil { clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err)) } }() //forward to parent udp - s.log.Printf("parent udp address %s", client.UDPAddr) + //s.log.Printf("parent udp address %s", client.UDPAddr) destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) - } else { - useProxy = false } - s.log.Printf("use proxy %v , udp %s", useProxy, request.Addr()) + s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr()) //relay for { buf := utils.LeakyBuffer.Get() @@ -654,7 +514,17 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque continue } p := socks.NewPacketUDP() - err = p.Parse(buf[:n]) + //convert data to raw + if len(s.udpLocalKey) > 0 { + var v []byte + v, err = goaes.Decrypt(s.udpLocalKey, buf[:n]) + if err == nil { + err = p.Parse(v) + } + } else { + err = p.Parse(buf[:n]) + } + //err = p.Parse(buf[:n]) if err != nil { s.log.Printf("udp listener parse packet fail, %s", err.Error()) continue @@ -672,7 +542,6 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque continue } s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) - go func() { defer s.udpRelatedPacketConns.Remove(srcAddr.String()) //out->local io copy @@ -688,16 +557,36 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque continue } - var dlen = n + //var dlen = n if useProxy { //forward to local - _, err = udpListener.WriteTo(buf[:n], srcAddr) + var v []byte + //convert parent data to raw + if len(s.udpParentKey) > 0 { + v, err = goaes.Decrypt(s.udpParentKey, buf[:n]) + if err != nil { + s.log.Printf("udp outconn parse packet fail, %s", err.Error()) + continue + } + } else { + v = buf[:n] + } + //now v is raw, try convert v to local + if len(s.udpLocalKey) > 0 { + v, _ = goaes.Encrypt(s.udpLocalKey, v) + } + _, err = udpListener.WriteTo(v, srcAddr) + // _, err = udpListener.WriteTo(buf[:n], srcAddr) } else { rp := socks.NewPacketUDP() rp.Build(srcAddr.String(), buf[:n]) - d := rp.Bytes() - dlen = len(d) - _, err = udpListener.WriteTo(d, srcAddr) + v := rp.Bytes() + //dlen = len(v) + //rp.Bytes() v is raw, try convert to local + if len(s.udpLocalKey) > 0 { + v, _ = goaes.Encrypt(s.udpLocalKey, v) + } + _, err = udpListener.WriteTo(v, srcAddr) } if err != nil { @@ -708,7 +597,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } continue } else { - s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr) + //s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr) } } }() @@ -718,7 +607,15 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque //local->out io copy if useProxy { //forward to parent - _, err = outUDPConn.Write(buf[:n]) + //p is raw, now convert it to parent + var v []byte + if len(s.udpParentKey) > 0 { + v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes()) + } else { + v = p.Bytes() + } + _, err = outUDPConn.Write(v) + // _, err = outUDPConn.Write(p.Bytes()) } else { _, err = outUDPConn.Write(p.Data()) } @@ -729,7 +626,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) continue } else { - s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) + //s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) } } diff --git a/utils/functions.go b/utils/functions.go index 29b4851..4d20b7c 100755 --- a/utils/functions.go +++ b/utils/functions.go @@ -17,7 +17,6 @@ import ( "net" "net/http" "os" - "os/exec" "github.com/snail007/goproxy/services/kcpcfg" @@ -209,98 +208,6 @@ func CloseConn(conn *net.Conn) { (*conn).Close() } } -func Keygen() (err error) { - CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"} - domainSubfixList := []string{".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".biz", ".info", ".pro", ".name", ".museum", ".coop", ".aero", ".xxx", ".idv", ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".eh", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".um", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".yu", ".yr", ".za", ".zm", ".zw"} - C := CList[int(RandInt(4))%len(CList)] - ST := RandString(int(RandInt(4) % 10)) - O := RandString(int(RandInt(4) % 10)) - CN := strings.ToLower(RandString(int(RandInt(4)%10)) + domainSubfixList[int(RandInt(4))%len(domainSubfixList)]) - //log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN) - var out []byte - if len(os.Args) == 3 && os.Args[2] == "ca" { - cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048") - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - fmt.Println(string(out)) - - cmdStr := fmt.Sprintf("openssl req -new -key ca.key -x509 -days 36500 -out ca.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, "*."+CN) - cmd = exec.Command("sh", "-c", cmdStr) - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - fmt.Println(string(out)) - } else if len(os.Args) == 5 && os.Args[2] == "ca" && os.Args[3] != "" && os.Args[4] != "" { - certBytes, _ := ioutil.ReadFile("ca.crt") - block, _ := pem.Decode(certBytes) - if block == nil || certBytes == nil { - panic("failed to parse ca certificate PEM") - } - x509Cert, _ := x509.ParseCertificate(block.Bytes) - if x509Cert == nil { - panic("failed to parse block") - } - name := os.Args[3] - days := os.Args[4] - cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048") - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - fmt.Println(string(out)) - - cmdStr := fmt.Sprintf("openssl req -new -key %s.key -out %s.csr -subj /C=%s/ST=%s/O=%s/CN=%s", name, name, C, ST, O, CN) - fmt.Printf("%s", cmdStr) - cmd = exec.Command("sh", "-c", cmdStr) - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - fmt.Println(string(out)) - - cmdStr = fmt.Sprintf("openssl x509 -req -days %s -in %s.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out %s.crt", days, name, name) - fmt.Printf("%s", cmdStr) - cmd = exec.Command("sh", "-c", cmdStr) - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - - fmt.Println(string(out)) - } else if len(os.Args) == 3 && os.Args[2] == "usage" { - fmt.Println(`proxy keygen //generate proxy.crt and proxy.key -proxy keygen ca //generate ca.crt and ca.key -proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sign it with 30 days - `) - } else if len(os.Args) == 2 { - cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048") - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - fmt.Println(string(out)) - - cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN) - cmd = exec.Command("sh", "-c", cmdStr) - out, err = cmd.CombinedOutput() - if err != nil { - logger.Printf("err:%s", err) - return - } - fmt.Println(string(out)) - } - - return -} func GetAllInterfaceAddr() ([]net.IP, error) { ifaces, err := net.Interfaces() From 6b4ee97f05177a92b2b6a6c0fc252a64eddee0ff Mon Sep 17 00:00:00 2001 From: arraykeys Date: Thu, 5 Jul 2018 20:18:12 +0800 Subject: [PATCH 16/22] no message --- README_ZH.md | 9 ++++++++- services/socks/socks.go | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README_ZH.md b/README_ZH.md index 59a0aef..d325b61 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -689,7 +689,14 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid `./proxy help client` ### **5.SOCKS5代理** -提示:SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证. +提示: + +SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证. + +***如果你的VPS是阿里云,腾讯云这种VPS,就是ifconfig看不见你的公网IP,只能看见内网IP,*** + +***那么需要加上`-g VPS公网IP`参数,SOCKS5代理的UDP功能才能正常工作。*** + #### **5.1.普通SOCKS5代理** `./proxy socks -t tcp -p "0.0.0.0:38080"` diff --git a/services/socks/socks.go b/services/socks/socks.go index 4aa35d0..b4c7933 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -405,7 +405,10 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) _, port, _ := net.SplitHostPort(udpListener.LocalAddr().String()) - s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr) + if len(*s.cfg.LocalIPS) > 0 { + host = (*s.cfg.LocalIPS)[0] + } + s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr) request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) s.userConns.Set(inconnRemoteAddr, inConn) var ( From f5d09b878b2ee974b888374e0603768e1efd80a5 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Fri, 6 Jul 2018 18:24:12 +0800 Subject: [PATCH 17/22] fix socks udp reply wrong dst addr Signed-off-by: arraykeys@gmail.com --- services/socks/socks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/socks/socks.go b/services/socks/socks.go index 4aa35d0..690fdaa 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -579,7 +579,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque // _, err = udpListener.WriteTo(buf[:n], srcAddr) } else { rp := socks.NewPacketUDP() - rp.Build(srcAddr.String(), buf[:n]) + rp.Build(destAddr.String(), buf[:n]) v := rp.Bytes() //dlen = len(v) //rp.Bytes() v is raw, try convert to local From 0226d2cde367956f15253c8aaf26821f2327df8d Mon Sep 17 00:00:00 2001 From: arraykeys Date: Sat, 7 Jul 2018 23:56:56 +0800 Subject: [PATCH 18/22] add sps : socks->udp support --- services/socks/socks.go | 277 ---------------------------------- services/socks/udp.go | 315 +++++++++++++++++++++++++++++++++++++++ services/sps/socksudp.go | 302 +++++++++++++++++++++++++++++++++++++ services/sps/sps.go | 43 ++++-- utils/socks/server.go | 64 +++++--- 5 files changed, 691 insertions(+), 310 deletions(-) create mode 100644 services/socks/udp.go create mode 100644 services/sps/socksudp.go diff --git a/services/socks/socks.go b/services/socks/socks.go index 6bae3ec..5020c50 100644 --- a/services/socks/socks.go +++ b/services/socks/socks.go @@ -1,7 +1,6 @@ package socks import ( - "crypto/md5" "crypto/tls" "fmt" "io" @@ -9,14 +8,12 @@ import ( logger "log" "net" "runtime/debug" - "strconv" "strings" "time" "github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/utils" - goaes "github.com/snail007/goproxy/utils/aes" "github.com/snail007/goproxy/utils/conncrypt" "github.com/snail007/goproxy/utils/socks" "golang.org/x/crypto/ssh" @@ -359,281 +356,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) { } } -func (s *Socks) ParentUDPKey() (key []byte) { - switch *s.cfg.ParentType { - case "tcp": - if *s.cfg.ParentKey != "" { - v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey))) - return []byte(v)[:24] - } - case "tls": - return s.cfg.KeyBytes[:24] - case "kcp": - v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) - return []byte(v)[:24] - } - return -} -func (s *Socks) LocalUDPKey() (key []byte) { - switch *s.cfg.LocalType { - case "tcp": - if *s.cfg.LocalKey != "" { - v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey))) - return []byte(v)[:24] - } - case "tls": - return s.cfg.KeyBytes[:24] - case "kcp": - v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) - return []byte(v)[:24] - } - return -} -func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { - if *s.cfg.ParentType == "ssh" { - utils.CloseConn(inConn) - return - } - inconnRemoteAddr := (*inConn).RemoteAddr().String() - localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} - udpListener, err := net.ListenUDP("udp", localAddr) - if err != nil { - (*inConn).Close() - udpListener.Close() - s.log.Printf("udp bind fail , %s", err) - return - } - host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) - _, port, _ := net.SplitHostPort(udpListener.LocalAddr().String()) - if len(*s.cfg.LocalIPS) > 0 { - host = (*s.cfg.LocalIPS)[0] - } - s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr) - request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) - s.userConns.Set(inconnRemoteAddr, inConn) - var ( - outUDPConn *net.UDPConn - outconn net.Conn - outconnLocalAddr string - isClosedErr = func(err error) bool { - return err != nil && strings.Contains(err.Error(), "use of closed network connection") - } - destAddr *net.UDPAddr - ) - var clean = func(msg, err string) { - raddr := "" - if outUDPConn != nil { - raddr = outUDPConn.RemoteAddr().String() - outUDPConn.Close() - } - if msg != "" { - if raddr != "" { - s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr) - } else { - s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr) - } - } - (*inConn).Close() - udpListener.Close() - s.userConns.Remove(inconnRemoteAddr) - if outconn != nil { - outconn.Close() - } - if outconnLocalAddr != "" { - s.userConns.Remove(outconnLocalAddr) - } - } - defer clean("", "") - go func() { - buf := make([]byte, 1) - (*inConn).SetReadDeadline(time.Time{}) - if _, err := (*inConn).Read(buf); err != nil { - clean("udp related tcp conn disconnected with read", err.Error()) - } - }() - go func() { - for { - (*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5)) - if _, err := (*inConn).Write([]byte{0x00}); err != nil { - clean("udp related tcp conn disconnected with write", err.Error()) - return - } - (*inConn).SetWriteDeadline(time.Time{}) - time.Sleep(time.Second * 5) - } - }() - useProxy := true - if *s.cfg.Parent != "" { - dstHost, _, _ := net.SplitHostPort(request.Addr()) - if utils.IsIternalIP(dstHost, *s.cfg.Always) { - useProxy = false - } else { - var isInMap bool - useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr()) - if !isInMap { - s.checker.Add(request.Addr(), s.Resolve(request.Addr())) - } - } - } else { - useProxy = false - } - if useProxy { - //parent proxy - outconn, err := s.getOutConn(nil, nil, "", false) - if err != nil { - clean("connnect fail", fmt.Sprintf("%s", err)) - return - } - client := socks.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) - if err = client.Handshake(); err != nil { - clean("handshake fail", fmt.Sprintf("%s", err)) - return - } - //outconnRemoteAddr := outconn.RemoteAddr().String() - outconnLocalAddr = outconn.LocalAddr().String() - s.userConns.Set(outconnLocalAddr, &outconn) - go func() { - buf := make([]byte, 1) - outconn.SetReadDeadline(time.Time{}) - if _, err := outconn.Read(buf); err != nil { - clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err)) - } - }() - //forward to parent udp - //s.log.Printf("parent udp address %s", client.UDPAddr) - destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) - } - s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr()) - //relay - for { - buf := utils.LeakyBuffer.Get() - defer utils.LeakyBuffer.Put(buf) - n, srcAddr, err := udpListener.ReadFromUDP(buf) - if err != nil { - s.log.Printf("udp listener read fail, %s", err.Error()) - if isClosedErr(err) { - return - } - continue - } - p := socks.NewPacketUDP() - //convert data to raw - if len(s.udpLocalKey) > 0 { - var v []byte - v, err = goaes.Decrypt(s.udpLocalKey, buf[:n]) - if err == nil { - err = p.Parse(v) - } - } else { - err = p.Parse(buf[:n]) - } - //err = p.Parse(buf[:n]) - if err != nil { - s.log.Printf("udp listener parse packet fail, %s", err.Error()) - continue - } - port, _ := strconv.Atoi(p.Port()) - - if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok { - if destAddr == nil { - destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port} - } - outUDPConn, err = net.DialUDP("udp", localAddr, destAddr) - if err != nil { - s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) - continue - } - s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) - go func() { - defer s.udpRelatedPacketConns.Remove(srcAddr.String()) - //out->local io copy - buf := utils.LeakyBuffer.Get() - defer utils.LeakyBuffer.Put(buf) - for { - n, err := outUDPConn.Read(buf) - if err != nil { - s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) - if isClosedErr(err) { - return - } - continue - } - - //var dlen = n - if useProxy { - //forward to local - var v []byte - //convert parent data to raw - if len(s.udpParentKey) > 0 { - v, err = goaes.Decrypt(s.udpParentKey, buf[:n]) - if err != nil { - s.log.Printf("udp outconn parse packet fail, %s", err.Error()) - continue - } - } else { - v = buf[:n] - } - //now v is raw, try convert v to local - if len(s.udpLocalKey) > 0 { - v, _ = goaes.Encrypt(s.udpLocalKey, v) - } - _, err = udpListener.WriteTo(v, srcAddr) - // _, err = udpListener.WriteTo(buf[:n], srcAddr) - } else { - rp := socks.NewPacketUDP() - rp.Build(destAddr.String(), buf[:n]) - v := rp.Bytes() - //dlen = len(v) - //rp.Bytes() v is raw, try convert to local - if len(s.udpLocalKey) > 0 { - v, _ = goaes.Encrypt(s.udpLocalKey, v) - } - _, err = udpListener.WriteTo(v, srcAddr) - } - - if err != nil { - s.udpRelatedPacketConns.Remove(srcAddr.String()) - s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) - if isClosedErr(err) { - return - } - continue - } else { - //s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr) - } - } - }() - } else { - outUDPConn = v.(*net.UDPConn) - } - //local->out io copy - if useProxy { - //forward to parent - //p is raw, now convert it to parent - var v []byte - if len(s.udpParentKey) > 0 { - v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes()) - } else { - v = p.Bytes() - } - _, err = outUDPConn.Write(v) - // _, err = outUDPConn.Write(p.Bytes()) - } else { - _, err = outUDPConn.Write(p.Data()) - } - if err != nil { - if isClosedErr(err) { - return - } - s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) - continue - } else { - //s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) - } - } - -} func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { var outConn net.Conn var err interface{} diff --git a/services/socks/udp.go b/services/socks/udp.go new file mode 100644 index 0000000..ad66a55 --- /dev/null +++ b/services/socks/udp.go @@ -0,0 +1,315 @@ +package socks + +import ( + "crypto/md5" + "fmt" + "net" + "runtime/debug" + "strconv" + "strings" + "time" + + "github.com/snail007/goproxy/utils" + goaes "github.com/snail007/goproxy/utils/aes" + "github.com/snail007/goproxy/utils/socks" +) + +func (s *Socks) ParentUDPKey() (key []byte) { + switch *s.cfg.ParentType { + case "tcp": + if *s.cfg.ParentKey != "" { + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey))) + return []byte(v)[:24] + } + case "tls": + return s.cfg.KeyBytes[:24] + case "kcp": + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) + return []byte(v)[:24] + } + return +} +func (s *Socks) LocalUDPKey() (key []byte) { + switch *s.cfg.LocalType { + case "tcp": + if *s.cfg.LocalKey != "" { + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey))) + return []byte(v)[:24] + } + case "tls": + return s.cfg.KeyBytes[:24] + case "kcp": + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) + return []byte(v)[:24] + } + return +} +func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + if *s.cfg.ParentType == "ssh" { + utils.CloseConn(inConn) + return + } + inconnRemoteAddr := (*inConn).RemoteAddr().String() + localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} + udpListener, err := net.ListenUDP("udp", localAddr) + if err != nil { + (*inConn).Close() + udpListener.Close() + s.log.Printf("udp bind fail , %s", err) + return + } + host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) + _, port, _ := net.SplitHostPort(udpListener.LocalAddr().String()) + if len(*s.cfg.LocalIPS) > 0 { + host = (*s.cfg.LocalIPS)[0] + } + s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr) + request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) + s.userConns.Set(inconnRemoteAddr, inConn) + var ( + outUDPConn *net.UDPConn + outconn net.Conn + outconnLocalAddr string + isClosedErr = func(err error) bool { + return err != nil && strings.Contains(err.Error(), "use of closed network connection") + } + destAddr *net.UDPAddr + ) + var clean = func(msg, err string) { + raddr := "" + if outUDPConn != nil { + raddr = outUDPConn.RemoteAddr().String() + outUDPConn.Close() + } + if msg != "" { + if raddr != "" { + s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr) + } else { + s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr) + } + } + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + if outconn != nil { + outconn.Close() + } + if outconnLocalAddr != "" { + s.userConns.Remove(outconnLocalAddr) + } + } + defer clean("", "") + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + buf := make([]byte, 1) + (*inConn).SetReadDeadline(time.Time{}) + if _, err := (*inConn).Read(buf); err != nil { + clean("udp related tcp conn disconnected with read", err.Error()) + } + }() + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + for { + (*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5)) + if _, err := (*inConn).Write([]byte{0x00}); err != nil { + clean("udp related tcp conn disconnected with write", err.Error()) + return + } + (*inConn).SetWriteDeadline(time.Time{}) + time.Sleep(time.Second * 5) + } + }() + useProxy := true + if *s.cfg.Parent != "" { + dstHost, _, _ := net.SplitHostPort(request.Addr()) + if utils.IsIternalIP(dstHost, *s.cfg.Always) { + useProxy = false + } else { + var isInMap bool + useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr()) + if !isInMap { + s.checker.Add(request.Addr(), s.Resolve(request.Addr())) + } + } + } else { + useProxy = false + } + if useProxy { + //parent proxy + outconn, err := s.getOutConn(nil, nil, "", false) + if err != nil { + clean("connnect fail", fmt.Sprintf("%s", err)) + return + } + client := socks.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) + if err = client.Handshake(); err != nil { + clean("handshake fail", fmt.Sprintf("%s", err)) + return + } + //outconnRemoteAddr := outconn.RemoteAddr().String() + outconnLocalAddr = outconn.LocalAddr().String() + s.userConns.Set(outconnLocalAddr, &outconn) + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + buf := make([]byte, 1) + outconn.SetReadDeadline(time.Time{}) + if _, err := outconn.Read(buf); err != nil { + clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err)) + } + }() + //forward to parent udp + //s.log.Printf("parent udp address %s", client.UDPAddr) + destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) + } + s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr()) + //relay + for { + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + n, srcAddr, err := udpListener.ReadFromUDP(buf) + if err != nil { + s.log.Printf("udp listener read fail, %s", err.Error()) + if isClosedErr(err) { + return + } + continue + } + p := socks.NewPacketUDP() + //convert data to raw + if len(s.udpLocalKey) > 0 { + var v []byte + v, err = goaes.Decrypt(s.udpLocalKey, buf[:n]) + if err == nil { + err = p.Parse(v) + } + } else { + err = p.Parse(buf[:n]) + } + //err = p.Parse(buf[:n]) + if err != nil { + s.log.Printf("udp listener parse packet fail, %s", err.Error()) + continue + } + + port, _ := strconv.Atoi(p.Port()) + + if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok { + if destAddr == nil { + destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port} + } + outUDPConn, err = net.DialUDP("udp", localAddr, destAddr) + if err != nil { + s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) + continue + } + s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + defer s.udpRelatedPacketConns.Remove(srcAddr.String()) + //out->local io copy + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + for { + n, err := outUDPConn.Read(buf) + if err != nil { + s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) + if isClosedErr(err) { + return + } + continue + } + //var dlen = n + if useProxy { + //forward to local + var v []byte + //convert parent data to raw + if len(s.udpParentKey) > 0 { + v, err = goaes.Decrypt(s.udpParentKey, buf[:n]) + if err != nil { + s.log.Printf("udp outconn parse packet fail, %s", err.Error()) + continue + } + } else { + v = buf[:n] + } + //now v is raw, try convert v to local + if len(s.udpLocalKey) > 0 { + v, _ = goaes.Encrypt(s.udpLocalKey, v) + } + _, err = udpListener.WriteTo(v, srcAddr) + // _, err = udpListener.WriteTo(buf[:n], srcAddr) + } else { + rp := socks.NewPacketUDP() + rp.Build(destAddr.String(), buf[:n]) + v := rp.Bytes() + //dlen = len(v) + //rp.Bytes() v is raw, try convert to local + if len(s.udpLocalKey) > 0 { + v, _ = goaes.Encrypt(s.udpLocalKey, v) + } + _, err = udpListener.WriteTo(v, srcAddr) + } + + if err != nil { + s.udpRelatedPacketConns.Remove(srcAddr.String()) + s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) + if isClosedErr(err) { + return + } + continue + } else { + //s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr) + } + } + }() + } else { + outUDPConn = v.(*net.UDPConn) + } + //local->out io copy + if useProxy { + //forward to parent + //p is raw, now convert it to parent + var v []byte + if len(s.udpParentKey) > 0 { + v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes()) + } else { + v = p.Bytes() + } + _, err = outUDPConn.Write(v) + // _, err = outUDPConn.Write(p.Bytes()) + } else { + _, err = outUDPConn.Write(p.Data()) + } + if err != nil { + if isClosedErr(err) { + return + } + s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) + continue + } else { + //s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) + } + } + +} diff --git a/services/sps/socksudp.go b/services/sps/socksudp.go new file mode 100644 index 0000000..6ab08f8 --- /dev/null +++ b/services/sps/socksudp.go @@ -0,0 +1,302 @@ +package sps + +import ( + "crypto/md5" + "fmt" + "net" + "runtime/debug" + "strconv" + "strings" + "time" + + "github.com/snail007/goproxy/utils" + goaes "github.com/snail007/goproxy/utils/aes" + "github.com/snail007/goproxy/utils/conncrypt" + "github.com/snail007/goproxy/utils/socks" +) + +func (s *SPS) ParentUDPKey() (key []byte) { + switch *s.cfg.ParentType { + case "tcp": + if *s.cfg.ParentKey != "" { + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey))) + return []byte(v)[:24] + } + case "tls": + return s.cfg.KeyBytes[:24] + case "kcp": + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) + return []byte(v)[:24] + } + return +} +func (s *SPS) LocalUDPKey() (key []byte) { + switch *s.cfg.LocalType { + case "tcp": + if *s.cfg.LocalKey != "" { + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey))) + return []byte(v)[:24] + } + case "tls": + return s.cfg.KeyBytes[:24] + case "kcp": + v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) + return []byte(v)[:24] + } + return +} +func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + if *s.cfg.ParentType == "ssh" { + utils.CloseConn(inConn) + return + } + inconnRemoteAddr := (*inConn).RemoteAddr().String() + localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} + udpListener := serverConn.UDPConnListener + s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr) + s.userConns.Set(inconnRemoteAddr, inConn) + var ( + outUDPConn *net.UDPConn + outconn net.Conn + outconnLocalAddr string + isClosedErr = func(err error) bool { + return err != nil && strings.Contains(err.Error(), "use of closed network connection") + } + destAddr *net.UDPAddr + ) + var clean = func(msg, err string) { + raddr := "" + if outUDPConn != nil { + raddr = outUDPConn.RemoteAddr().String() + outUDPConn.Close() + } + if msg != "" { + if raddr != "" { + s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr) + } else { + s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr) + } + } + (*inConn).Close() + udpListener.Close() + s.userConns.Remove(inconnRemoteAddr) + if outconn != nil { + outconn.Close() + } + if outconnLocalAddr != "" { + s.userConns.Remove(outconnLocalAddr) + } + } + defer clean("", "") + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp related client tcp conn read crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + buf := make([]byte, 1) + (*inConn).SetReadDeadline(time.Time{}) + if _, err := (*inConn).Read(buf); err != nil { + clean("udp related tcp conn disconnected with read", err.Error()) + } + }() + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp related client tcp conn write crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + for { + (*inConn).SetWriteDeadline(time.Now().Add(time.Second * 5)) + if _, err := (*inConn).Write([]byte{0x00}); err != nil { + clean("udp related tcp conn disconnected with write", err.Error()) + return + } + (*inConn).SetWriteDeadline(time.Time{}) + time.Sleep(time.Second * 5) + } + }() + //parent proxy + outconn, err := s.outPool.Get() + //outconn, err := s.GetParentConn(nil, nil, "", false) + if err != nil { + clean("connnect fail", fmt.Sprintf("%s", err)) + return + } + if *s.cfg.ParentCompress { + outconn = utils.NewCompConn(outconn) + } + if *s.cfg.ParentKey != "" { + outconn = conncrypt.New(outconn, &conncrypt.Config{ + Password: *s.cfg.ParentKey, + }) + } + + //client := socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) + + s.log.Printf("connect %s for udp", serverConn.Target()) + //socks client + var client *socks.ClientConn + auth := serverConn.AuthData() + if *s.cfg.ParentAuth != "" { + a := strings.Split(*s.cfg.ParentAuth, ":") + if len(a) != 2 { + err = fmt.Errorf("parent auth data format error") + return + } + client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil) + } else { + if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" { + client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil) + } else { + client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) + } + } + + if err = client.Handshake(); err != nil { + clean("handshake fail", fmt.Sprintf("%s", err)) + return + } + + //outconnRemoteAddr := outconn.RemoteAddr().String() + outconnLocalAddr = outconn.LocalAddr().String() + s.userConns.Set(outconnLocalAddr, &outconn) + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + buf := make([]byte, 1) + outconn.SetReadDeadline(time.Time{}) + if _, err := outconn.Read(buf); err != nil { + clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err)) + } + }() + //forward to parent udp + //s.log.Printf("parent udp address %s", client.UDPAddr) + destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) + //relay + for { + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + n, srcAddr, err := udpListener.ReadFromUDP(buf) + if err != nil { + s.log.Printf("udp listener read fail, %s", err.Error()) + if isClosedErr(err) { + return + } + continue + } + p := socks.NewPacketUDP() + //convert data to raw + if len(s.udpLocalKey) > 0 { + var v []byte + v, err = goaes.Decrypt(s.udpLocalKey, buf[:n]) + if err == nil { + err = p.Parse(v) + } + } else { + err = p.Parse(buf[:n]) + } + //err = p.Parse(buf[:n]) + if err != nil { + s.log.Printf("udp listener parse packet fail, %s", err.Error()) + continue + } + + port, _ := strconv.Atoi(p.Port()) + + if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok { + if destAddr == nil { + destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port} + } + outUDPConn, err = net.DialUDP("udp", localAddr, destAddr) + if err != nil { + s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) + continue + } + s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) + go func() { + defer func() { + if e := recover(); e != nil { + s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack())) + } + }() + defer s.udpRelatedPacketConns.Remove(srcAddr.String()) + //out->local io copy + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) + for { + n, err := outUDPConn.Read(buf) + if err != nil { + s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) + if isClosedErr(err) { + return + } + continue + } + + //var dlen = n + //forward to local + var v []byte + //convert parent data to raw + if len(s.udpParentKey) > 0 { + v, err = goaes.Decrypt(s.udpParentKey, buf[:n]) + if err != nil { + s.log.Printf("udp outconn parse packet fail, %s", err.Error()) + continue + } + } else { + v = buf[:n] + } + //now v is raw, try convert v to local + if len(s.udpLocalKey) > 0 { + v, _ = goaes.Encrypt(s.udpLocalKey, v) + } + _, err = udpListener.WriteTo(v, srcAddr) + // _, err = udpListener.WriteTo(buf[:n], srcAddr) + + if err != nil { + s.udpRelatedPacketConns.Remove(srcAddr.String()) + s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr) + if isClosedErr(err) { + return + } + continue + } else { + //s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr) + } + } + }() + } else { + outUDPConn = v.(*net.UDPConn) + } + //local->out io copy + //forward to parent + //p is raw, now convert it to parent + var v []byte + if len(s.udpParentKey) > 0 { + v, _ = goaes.Encrypt(s.udpParentKey, p.Bytes()) + } else { + v = p.Bytes() + } + _, err = outUDPConn.Write(v) + // _, err = outUDPConn.Write(p.Bytes()) + if err != nil { + if isClosedErr(err) { + return + } + s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) + continue + } else { + //s.log.Printf("send udp data to remote success , len %d, for : %s", len(p.Data()), srcAddr) + } + } + +} diff --git a/services/sps/sps.go b/services/sps/sps.go index e3a7fdf..8060987 100644 --- a/services/sps/sps.go +++ b/services/sps/sps.go @@ -53,22 +53,26 @@ type SPSArgs struct { DisableSocks5 *bool } type SPS struct { - outPool utils.OutConn - cfg SPSArgs - domainResolver utils.DomainResolver - basicAuth utils.BasicAuth - serverChannels []*utils.ServerChannel - userConns utils.ConcurrentMap - log *logger.Logger + outPool utils.OutConn + cfg SPSArgs + domainResolver utils.DomainResolver + basicAuth utils.BasicAuth + serverChannels []*utils.ServerChannel + userConns utils.ConcurrentMap + log *logger.Logger + udpRelatedPacketConns utils.ConcurrentMap + udpLocalKey []byte + udpParentKey []byte } func NewSPS() services.Service { return &SPS{ - outPool: utils.OutConn{}, - cfg: SPSArgs{}, - basicAuth: utils.BasicAuth{}, - serverChannels: []*utils.ServerChannel{}, - userConns: utils.NewConcurrentMap(), + outPool: utils.OutConn{}, + cfg: SPSArgs{}, + basicAuth: utils.BasicAuth{}, + serverChannels: []*utils.ServerChannel{}, + userConns: utils.NewConcurrentMap(), + udpRelatedPacketConns: utils.NewConcurrentMap(), } } func (s *SPS) CheckArgs() (err error) { @@ -93,6 +97,8 @@ func (s *SPS) CheckArgs() (err error) { } } } + s.udpLocalKey = s.LocalUDPKey() + s.udpParentKey = s.ParentUDPKey() return } func (s *SPS) InitService() (err error) { @@ -210,6 +216,11 @@ func (s *SPS) callback(inConn net.Conn) { } } func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { + enableUDP := *s.cfg.ParentServiceType == "socks" + udpIP, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) + if len(*s.cfg.LocalIPS) > 0 { + udpIP = (*s.cfg.LocalIPS)[0] + } bInConn := utils.NewBufferedConn(*inConn) //important //action read will regist read event to system, @@ -243,15 +254,19 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { //socks5 server var serverConn *socks.ServerConn if s.IsBasicAuth() { - serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", nil) + serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, enableUDP, udpIP, nil) } else { - serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", nil) + serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, enableUDP, udpIP, nil) } if err = serverConn.Handshake(); err != nil { return } address = serverConn.Target() auth = serverConn.AuthData() + if serverConn.IsUDP() { + s.proxyUDP(inConn, serverConn) + return + } } else if utils.IsHTTP(h) || isSNI != "" { if *s.cfg.DisableHTTP { (*inConn).Close() diff --git a/utils/socks/server.go b/utils/socks/server.go index 67f26bf..8808562 100644 --- a/utils/socks/server.go +++ b/utils/socks/server.go @@ -2,10 +2,11 @@ package socks import ( "fmt" - "github.com/snail007/goproxy/utils" "net" "strings" "time" + + "github.com/snail007/goproxy/utils" ) const ( @@ -54,26 +55,27 @@ type ServerConn struct { methods []uint8 method uint8 //request - cmd uint8 - reserve uint8 - addressType uint8 - dstAddr string - dstPort string - dstHost string - udpAddress string + cmd uint8 + reserve uint8 + addressType uint8 + dstAddr string + dstPort string + dstHost string + UDPConnListener *net.UDPConn + enableUDP bool + udpIP string } -func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn { - if udpAddress == "" { - udpAddress = "0.0.0.0:16666" - } +func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, enableUDP bool, udpHost string, header []byte) *ServerConn { + s := &ServerConn{ - conn: conn, - timeout: timeout, - auth: auth, - header: header, - ver: VERSION_V5, - udpAddress: udpAddress, + conn: conn, + timeout: timeout, + auth: auth, + header: header, + ver: VERSION_V5, + enableUDP: enableUDP, + udpIP: udpHost, } return s @@ -84,6 +86,12 @@ func (s *ServerConn) Close() { func (s *ServerConn) AuthData() Auth { return Auth{s.user, s.password} } +func (s *ServerConn) IsUDP() bool { + return s.cmd == CMD_ASSOCIATE +} +func (s *ServerConn) IsTCP() bool { + return s.cmd == CMD_CONNECT +} func (s *ServerConn) Method() uint8 { return s.method } @@ -205,11 +213,29 @@ func (s *ServerConn) Handshake() (err error) { return } case CMD_ASSOCIATE: - err = request.UDPReply(REP_SUCCESS, s.udpAddress) + if !s.enableUDP { + request.UDPReply(REP_UNKNOWN, "0.0.0.0:0") + if err != nil { + err = fmt.Errorf("UDPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err) + return + } + err = fmt.Errorf("cmd associate not supported, form: %s", remoteAddr) + return + } + a, _ := net.ResolveUDPAddr("udp", ":0") + s.UDPConnListener, err = net.ListenUDP("udp", a) + if err != nil { + request.UDPReply(REP_UNKNOWN, "0.0.0.0:0") + err = fmt.Errorf("udp bind fail,ERR: %s , for %s", err, remoteAddr) + return + } + _, port, _ := net.SplitHostPort(s.UDPConnListener.LocalAddr().String()) + err = request.UDPReply(REP_SUCCESS, net.JoinHostPort(s.udpIP, port)) if err != nil { err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err) return } + } //fill socks info From 1f655808c6b6ab72f1bb4a32a9b8a740acf11306 Mon Sep 17 00:00:00 2001 From: Wenhui Shen Date: Sun, 8 Jul 2018 19:52:46 +0800 Subject: [PATCH 19/22] bugfixed --- services/mux/mux_bridge.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/mux/mux_bridge.go b/services/mux/mux_bridge.go index e80b7c5..73ed365 100644 --- a/services/mux/mux_bridge.go +++ b/services/mux/mux_bridge.go @@ -88,7 +88,7 @@ func (s *MuxBridge) StopService() { (*(*s.sc).Listener).Close() } for _, g := range s.clientControlConns.Items() { - for _, session := range g.(utils.ConcurrentMap).Items() { + for _, session := range g.(*utils.ConcurrentMap).Items() { (session.(*smux.Session)).Close() } } From 04ef33880754cb8fa338df65fc7ad7bc1650b970 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Mon, 9 Jul 2018 16:32:04 +0800 Subject: [PATCH 20/22] add secure IP check for socks udp --- services/sps/socksudp.go | 16 ++++++++++------ utils/cert/cert.go | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/services/sps/socksudp.go b/services/sps/socksudp.go index 6ab08f8..e59c7d9 100644 --- a/services/sps/socksudp.go +++ b/services/sps/socksudp.go @@ -55,6 +55,7 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { utils.CloseConn(inConn) return } + srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String()) inconnRemoteAddr := (*inConn).RemoteAddr().String() localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} udpListener := serverConn.UDPConnListener @@ -137,8 +138,6 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { }) } - //client := socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil) - s.log.Printf("connect %s for udp", serverConn.Target()) //socks client var client *socks.ClientConn @@ -182,9 +181,9 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { //s.log.Printf("parent udp address %s", client.UDPAddr) destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) //relay + buf := utils.LeakyBuffer.Get() + defer utils.LeakyBuffer.Put(buf) for { - buf := utils.LeakyBuffer.Get() - defer utils.LeakyBuffer.Put(buf) n, srcAddr, err := udpListener.ReadFromUDP(buf) if err != nil { s.log.Printf("udp listener read fail, %s", err.Error()) @@ -193,6 +192,11 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { } continue } + srcIP0, _, _ := net.SplitHostPort(srcAddr.String()) + //IP not match drop it + if srcIP != srcIP0 { + continue + } p := socks.NewPacketUDP() //convert data to raw if len(s.udpLocalKey) > 0 { @@ -204,7 +208,6 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { } else { err = p.Parse(buf[:n]) } - //err = p.Parse(buf[:n]) if err != nil { s.log.Printf("udp listener parse packet fail, %s", err.Error()) continue @@ -233,7 +236,9 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { buf := utils.LeakyBuffer.Get() defer utils.LeakyBuffer.Put(buf) for { + outUDPConn.SetReadDeadline(time.Now().Add(time.Second * 5)) n, err := outUDPConn.Read(buf) + outUDPConn.SetReadDeadline(time.Time{}) if err != nil { s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr) if isClosedErr(err) { @@ -241,7 +246,6 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) { } continue } - //var dlen = n //forward to local var v []byte diff --git a/utils/cert/cert.go b/utils/cert/cert.go index 858f6e5..ac25ba5 100644 --- a/utils/cert/cert.go +++ b/utils/cert/cert.go @@ -73,7 +73,7 @@ func CreateSignCert(rootCa *x509.Certificate, rootKey *rsa.PrivateKey, domainOrI buf := x509.MarshalPKCS1PrivateKey(priKey) keyPem := &pem.Block{ - Type: "PRIVATE KEY", + Type: "RSA PRIVATE KEY", Bytes: buf, } keyBytes = pem.EncodeToMemory(keyPem) From 3a4a9a3a27047e7cbd3ee96d9571ca6eac8ee9ec Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Mon, 9 Jul 2018 16:41:48 +0800 Subject: [PATCH 21/22] a --- services/socks/udp.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/socks/udp.go b/services/socks/udp.go index ad66a55..ad71a01 100644 --- a/services/socks/udp.go +++ b/services/socks/udp.go @@ -54,6 +54,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque utils.CloseConn(inConn) return } + srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String()) inconnRemoteAddr := (*inConn).RemoteAddr().String() localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} udpListener, err := net.ListenUDP("udp", localAddr) @@ -191,6 +192,11 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque } continue } + srcIP0, _, _ := net.SplitHostPort(srcAddr.String()) + //IP not match drop it + if srcIP != srcIP0 { + continue + } p := socks.NewPacketUDP() //convert data to raw if len(s.udpLocalKey) > 0 { From 29e4cdf4e28f3af2bed91a00efc0db3cb51106b7 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Mon, 9 Jul 2018 17:22:10 +0800 Subject: [PATCH 22/22] v5.2 --- CHANGELOG | 1 + README.md | 50 ++++++++++++++++++------------------------------ README_ZH.md | 19 ++++++++++-------- utils/structs.go | 2 +- 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a87ca95..53d67bd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ proxy更新日志 v5.2 1.修复了HTTP(S)\SPS反向代理无法正常工作的问题. 2.优化了智能判断,减少不必要的DNS解析. +3.重构了SOCKS和SPS的UDP功能,基于UDP的游戏加速嗖嗖的. v5.1 1.优化了kcp默认mtu配置,调整为450. diff --git a/README.md b/README.md index 595f9bd..33648c0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,24 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox [![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) -[中文手册](/README_ZH.md) **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)** +**[中文手册](/README_ZH.md)** + +**[全平台图形界面版本](/gui/README.md)** + +**[全平台SDK](/sdk/README.md)** + + +### How to use the source code? + +Pull Request is welcomed. +Recommend go1.10.1. +`go get github.com/snail007/goproxy` +use command cd to enter your go SRC directory +then cd to enter `github.com/snail007/goproxy`. +Direct compilation:`go build -o proxy` +execution: `go run *.go` +`utils` is a toolkit, and `service` is a specific service class. + ### Features - chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy. @@ -37,27 +54,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox - ...   -This page is the v5.1 manual, and the other version of the manual can be checked by the following link. -- [v5.1 manual](https://github.com/snail007/goproxy/tree/v5.1) -- [v4.9 manual](https://github.com/snail007/goproxy/tree/v4.9) -- [v4.8 manual](https://github.com/snail007/goproxy/tree/v4.8) -- [v4.7 manual](https://github.com/snail007/goproxy/tree/v4.7) -- [v4.6 manual](https://github.com/snail007/goproxy/tree/v4.6) -- [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5) -- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4) -- [v4.3 manual](https://github.com/snail007/goproxy/tree/v4.3) -- [v4.2 manual](https://github.com/snail007/goproxy/tree/v4.2) -- [v4.0-4.1 manual](https://github.com/snail007/goproxy/tree/v4.1) -- [v3.9 manual](https://github.com/snail007/goproxy/tree/v3.9) -- [v3.8 manual](https://github.com/snail007/goproxy/tree/v3.8) -- [v3.6-v3.7 manual](https://github.com/snail007/goproxy/tree/v3.6) -- [v3.5 manual](https://github.com/snail007/goproxy/tree/v3.5) -- [v3.4 manual](https://github.com/snail007/goproxy/tree/v3.4) -- [v3.3 manual](https://github.com/snail007/goproxy/tree/v3.3) -- [v3.2 manual](https://github.com/snail007/goproxy/tree/v3.2) -- [v3.1 manual](https://github.com/snail007/goproxy/tree/v3.1) -- [v3.0 manual](https://github.com/snail007/goproxy/tree/v3.0) -- [v2.x manual](https://github.com/snail007/goproxy/tree/v2.2) +This page is the v5.2 manual, and the other version of the manual can be checked by the following [link](docs/old-release.md). ### How to find the organization? [Click to join the proxy group of gitter](https://gitter.im/go-proxy/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)   @@ -1088,15 +1085,6 @@ First, you need to clone the project to your account, and then modify the code o Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency. PR needs to explain what changes have been made and why you change them. -### How to use the source code? -Recommend go1.10.1. -`go get github.com/snail007/goproxy` -use command cd to enter your go SRC directory -then cd to enter `github.com/snail007/goproxy`. -Direct compilation:`go build -o proxy` -execution: `go run *.go` -`utils` is a toolkit, and `service` is a specific service class. - ### License Proxy is licensed under GPLv3 license. ### Contact diff --git a/README_ZH.md b/README_ZH.md index d325b61..6860b20 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -7,7 +7,17 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务 [![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) -**[English Manual](/README.md)** **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)** +**[English Manual](/README.md)** + +**[全平台图形界面版本](/gui/README.md)** + +**[全平台SDK](/sdk/README.md)** + +### 如何贡献代码(Pull Request)? + +欢迎加入一起发展壮大proxy.首先需要clone本项目到自己的帐号下面, +然后在dev分支上面修改代码,最后发Pull Request到goproxy项目的dev分支即可, +为了高效贡献代码,pr的时候需要说明做了什么变更,原因是什么. ### Features - 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理. @@ -1116,11 +1126,6 @@ fast3:`--nodelay=1 --interval=10 --resend=2 --nc=1` - http(s)代理增加pac支持? - 欢迎加群反馈... -### 如何贡献代码(Pull Request)? -首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码, -最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码, -pr的时候需要说明做了什么变更,原因是什么. - ### 如何使用源码? 建议go1.10.1. `go get github.com/snail007/goproxy` @@ -1140,5 +1145,3 @@ QQ交流群:189618940 如果proxy帮助你解决了很多问题,你可以通过下面的捐赠更好的支持proxy. - - diff --git a/utils/structs.go b/utils/structs.go index 079c6d5..06a1ead 100644 --- a/utils/structs.go +++ b/utils/structs.go @@ -156,7 +156,7 @@ func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, succes } item := _item.(CheckerItem) - return item.FailCount >= item.SuccessCount, true, item.FailCount, item.SuccessCount + return (item.FailCount >= item.SuccessCount) && (time.Now().Unix()-item.Lasttime < 1800), true, item.FailCount, item.SuccessCount } func (c *Checker) domainIsInMap(address string, blockedMap bool) bool { u, err := url.Parse("http://" + address)