From d510ea45b016ac4743ff158fd700ca7a3ed0ae16 Mon Sep 17 00:00:00 2001 From: nadoo <287492+nadoo@users.noreply.github.com> Date: Thu, 15 Oct 2020 00:19:05 +0800 Subject: [PATCH] udp: remove uottun and optimize udp implementation --- README.md | 6 +- config.go | 5 +- config/glider.conf.example | 3 - feature.go | 1 - go.mod | 6 +- go.sum | 12 ++-- proxy/direct.go | 4 -- proxy/socks/socks.go | 18 ++---- proxy/socks5/packet.go | 20 ++++--- proxy/socks5/server.go | 2 +- proxy/ss/client.go | 4 -- proxy/ss/packet.go | 15 +++-- proxy/ss/server.go | 42 +------------- proxy/trojan/packet.go | 23 +++++--- proxy/trojan/server.go | 6 +- proxy/uottun/uottun.go | 114 ------------------------------------- proxy/vless/client.go | 13 ++++- proxy/vless/packet.go | 10 +++- proxy/vless/server.go | 28 +++------ 19 files changed, 83 insertions(+), 249 deletions(-) delete mode 100644 proxy/uottun/uottun.go diff --git a/README.md b/README.md index 10ee179..496c124 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ we can set up local listeners as proxy servers, and forward requests to internet |simple-obfs | | |√| |transport client only |tcptun |√| | | |transport server only |udptun | |√| | |transport server only -|uottun | |√| | |transport server only |redir |√| | | |linux only |redir6 |√| | | |linux only(ipv6) |reject | | |√|√|reject all requests @@ -144,7 +143,7 @@ glider 0.12.0 usage: verbose mode Available schemes: - listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcptun udptun uottun tls unix kcp + listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcptun udptun tls unix kcp forward: reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tls ws unix kcp simple-obfs Socks5 scheme: @@ -299,9 +298,6 @@ Examples: ./glider -listen udptun://:53=8.8.8.8:53 -forward ss://method:pass@1.1.1.1:8443 -listen on :53 and forward all udp requests to 8.8.8.8:53 via remote ss server. - ./glider -listen uottun://:53=8.8.8.8:53 -forward ss://method:pass@1.1.1.1:8443 - -listen on :53 and forward all udp requests via udp over tcp tunnel. - ./glider -listen socks5://:1080 -listen http://:8080 -forward ss://method:pass@1.1.1.1:8443 -listen on :1080 as socks5 server, :8080 as http proxy server, forward all requests via remote ss server. diff --git a/config.go b/config.go index 59ada64..d713f3a 100644 --- a/config.go +++ b/config.go @@ -131,7 +131,7 @@ func usage() { fmt.Fprintf(w, "\n") fmt.Fprintf(w, "Available schemes:\n") - fmt.Fprintf(w, " listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcptun udptun uottun tls unix kcp\n") + fmt.Fprintf(w, " listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcptun udptun tls unix kcp\n") fmt.Fprintf(w, " forward: reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tls ws unix kcp simple-obfs\n") fmt.Fprintf(w, "\n") @@ -313,9 +313,6 @@ func usage() { fmt.Fprintf(w, " "+app+" -listen udptun://:53=8.8.8.8:53 -forward ss://method:pass@1.1.1.1:8443\n") fmt.Fprintf(w, " -listen on :53 and forward all udp requests to 8.8.8.8:53 via remote ss server.\n") fmt.Fprintf(w, "\n") - fmt.Fprintf(w, " "+app+" -listen uottun://:53=8.8.8.8:53 -forward ss://method:pass@1.1.1.1:8443\n") - fmt.Fprintf(w, " -listen on :53 and forward all udp requests via udp over tcp tunnel.\n") - fmt.Fprintf(w, "\n") fmt.Fprintf(w, " "+app+" -listen socks5://:1080 -listen http://:8080 -forward ss://method:pass@1.1.1.1:8443\n") fmt.Fprintf(w, " -listen on :1080 as socks5 server, :8080 as http proxy server, forward all requests via remote ss server.\n") fmt.Fprintf(w, "\n") diff --git a/config/glider.conf.example b/config/glider.conf.example index c1d3a16..71502d7 100644 --- a/config/glider.conf.example +++ b/config/glider.conf.example @@ -57,9 +57,6 @@ listen=socks5://:1080 # listen on 1083 as a udp tunnel, all requests to :1083 will be forward to 1.1.1.1:53 # listen=udptun://:1083=1.1.1.1:53 -# listen on 1084 as a udp over tcp tunnel, all requests to :1084 will be forward to 1.1.1.1:53 -# listen=uottun://:1084=1.1.1.1:53 - # http over tls (HTTPS proxy) # listen=tls://:443?cert=crtFilePath&key=keyFilePath,http:// diff --git a/feature.go b/feature.go index c14fda5..51f1b92 100644 --- a/feature.go +++ b/feature.go @@ -19,7 +19,6 @@ import ( _ "github.com/nadoo/glider/proxy/tls" _ "github.com/nadoo/glider/proxy/trojan" _ "github.com/nadoo/glider/proxy/udptun" - _ "github.com/nadoo/glider/proxy/uottun" _ "github.com/nadoo/glider/proxy/vless" _ "github.com/nadoo/glider/proxy/vmess" _ "github.com/nadoo/glider/proxy/ws" diff --git a/go.mod b/go.mod index f7a8796..2445378 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,10 @@ require ( github.com/nadoo/ipset v0.3.0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/xtaci/kcp-go/v5 v5.6.1 - golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 + golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee golang.org/x/net v0.0.0-20201010224723-4f7140c49acb // indirect - golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect - golang.org/x/tools v0.0.0-20201011145850-ed2f50202694 // indirect + golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc // indirect + golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect ) diff --git a/go.sum b/go.sum index 118fb82..5cb3ddb 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= @@ -167,8 +167,8 @@ golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc h1:HVFDs9bKvTxP6bh1Rj9MCSo+UmafQtI8ZWDPVwVk9g4= +golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -177,8 +177,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201011145850-ed2f50202694 h1:BANdcOVw3KTuUiyfDp7wrzCpkCe8UP3lowugJngxBTg= -golang.org/x/tools v0.0.0-20201011145850-ed2f50202694/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752 h1:2ntEwh02rqo2jSsrYmp4yKHHjh0CbXP3ZtSUetSB+q8= +golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= diff --git a/proxy/direct.go b/proxy/direct.go index 969283e..0d0f9d6 100644 --- a/proxy/direct.go +++ b/proxy/direct.go @@ -67,10 +67,6 @@ func (d *Direct) Dial(network, addr string) (c net.Conn, err error) { } func (d *Direct) dial(network, addr string, localIP net.IP) (net.Conn, error) { - if network == "uot" { - network = "udp" - } - var la net.Addr switch network { case "tcp": diff --git a/proxy/socks/socks.go b/proxy/socks/socks.go index 94d0655..09a6859 100644 --- a/proxy/socks/socks.go +++ b/proxy/socks/socks.go @@ -45,14 +45,14 @@ var Errors = []error{ errors.New("socks5UDPAssociate"), } -// Addr . +// Addr represents a SOCKS address as defined in RFC 1928 section 5. type Addr []byte // String serializes SOCKS address a to string form. func (a Addr) String() string { var host, port string - switch ATYP(a[0]) { // address type + switch a[0] { // address type case ATypDomain: host = string(a[2 : 2+int(a[1])]) port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1])) @@ -67,16 +67,6 @@ func (a Addr) String() string { return net.JoinHostPort(host, port) } -// UoT returns whether it is udp over tcp -func UoT(b byte) bool { - return b&0x8 == 0x8 -} - -// ATYP returns the address type -func ATYP(b byte) int { - return int(b &^ 0x8) -} - // ReadAddrBuf reads just enough bytes from r to get a valid Addr. func ReadAddrBuf(r io.Reader, b []byte) (Addr, error) { if len(b) < MaxAddrLen { @@ -87,7 +77,7 @@ func ReadAddrBuf(r io.Reader, b []byte) (Addr, error) { return nil, err } - switch ATYP(b[0]) { + switch b[0] { case ATypDomain: _, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length if err != nil { @@ -118,7 +108,7 @@ func SplitAddr(b []byte) Addr { return nil } - switch ATYP(b[0]) { + switch b[0] { case ATypDomain: if len(b) < 2 { return nil diff --git a/proxy/socks5/packet.go b/proxy/socks5/packet.go index 19e8169..604e942 100644 --- a/proxy/socks5/packet.go +++ b/proxy/socks5/packet.go @@ -4,7 +4,6 @@ import ( "errors" "net" - "github.com/nadoo/glider/log" "github.com/nadoo/glider/pool" "github.com/nadoo/glider/proxy/socks" ) @@ -40,7 +39,7 @@ func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHea if err, ok := err.(net.Error); ok && err.Timeout() { continue } - log.F("[socks5] dialudp udp associate end") + // log.F("[socks5] dialudp udp associate end") return } }() @@ -98,14 +97,19 @@ func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { return pc.PacketConn.WriteTo(b, addr) } - buf := pool.GetBuffer(3 + len(pc.tgtAddr) + len(b)) - defer pool.PutBuffer(buf) + buf := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(buf) - copy(buf, []byte{0, 0, 0}) - copy(buf[3:], pc.tgtAddr) - copy(buf[3+len(pc.tgtAddr):], b) + buf.Write([]byte{0, 0, 0}) + tgtLen, _ := buf.Write(pc.tgtAddr) + buf.Write(b) - return pc.PacketConn.WriteTo(buf, pc.writeAddr) + n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeAddr) + if n > tgtLen+3 { + return n - tgtLen - 3, err + } + + return 0, err } // Close . diff --git a/proxy/socks5/server.go b/proxy/socks5/server.go index b467653..7bfdb67 100644 --- a/proxy/socks5/server.go +++ b/proxy/socks5/server.go @@ -139,7 +139,7 @@ func (s *Socks5) ListenAndServeUDP() { nm.Delete(raddr.String()) }() - log.F("[socks5u] %s <-> %s", raddr, c.tgtAddr) + log.F("[socks5u] %s <-> %s via %s", raddr, c.tgtAddr, nextHop) } else { pc = v.(*PktConn) diff --git a/proxy/ss/client.go b/proxy/ss/client.go index 053bf1c..9cff975 100644 --- a/proxy/ss/client.go +++ b/proxy/ss/client.go @@ -29,10 +29,6 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) { return nil, errors.New("[ss] unable to parse address: " + addr) } - if network == "uot" { - target[0] = target[0] | 0x8 - } - c, err := s.dialer.Dial("tcp", s.addr) if err != nil { log.F("[ss] dial to %s error: %s", s.addr, err) diff --git a/proxy/ss/packet.go b/proxy/ss/packet.go index 9f66df3..88762f9 100644 --- a/proxy/ss/packet.go +++ b/proxy/ss/packet.go @@ -67,11 +67,16 @@ func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { return pc.PacketConn.WriteTo(b, addr) } - buf := pool.GetBuffer(len(pc.tgtAddr) + len(b)) - pool.PutBuffer(buf) + buf := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(buf) - copy(buf, pc.tgtAddr) - copy(buf[len(pc.tgtAddr):], b) + tgtLen, _ := buf.Write(pc.tgtAddr) + buf.Write(b) - return pc.PacketConn.WriteTo(buf, pc.writeAddr) + n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeAddr) + if n > tgtLen { + return n - tgtLen, err + } + + return 0, err } diff --git a/proxy/ss/server.go b/proxy/ss/server.go index d75953d..af01ce9 100644 --- a/proxy/ss/server.go +++ b/proxy/ss/server.go @@ -7,7 +7,6 @@ import ( "time" "github.com/nadoo/glider/log" - "github.com/nadoo/glider/pool" "github.com/nadoo/glider/proxy" "github.com/nadoo/glider/proxy/socks" ) @@ -60,45 +59,8 @@ func (s *SS) Serve(c net.Conn) { return } - dialer := s.proxy.NextDialer(tgt.String()) - - // udp over tcp? - uot := socks.UoT(tgt[0]) - if uot && dialer.Addr() == "DIRECT" { - rc, err := net.ListenPacket("udp", "") - if err != nil { - log.F("[ss] UDP remote listen error: %v", err) - } - defer rc.Close() - - buf := pool.GetBuffer(proxy.UDPBufSize) - defer pool.PutBuffer(buf) - - n, err := c.Read(buf) - if err != nil { - log.F("[ss] error in read: %s\n", err) - return - } - - tgtAddr, _ := net.ResolveUDPAddr("udp", tgt.String()) - rc.WriteTo(buf[:n], tgtAddr) - - n, _, err = rc.ReadFrom(buf) - if err != nil { - log.F("[ss] read error: %v", err) - } - - c.Write(buf[:n]) - - log.F("[ss] %s <-tcp-> %s - %s <-udp-> %s ", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt) - - return - } - network := "tcp" - if uot { - network = "udp" - } + dialer := s.proxy.NextDialer(tgt.String()) rc, err := dialer.Dial(network, tgt.String()) if err != nil { @@ -161,7 +123,7 @@ func (s *SS) ListenAndServeUDP() { nm.Delete(raddr.String()) }() - log.F("[ssu] %s <-> %s", raddr, c.tgtAddr) + log.F("[ssu] %s <-> %s via %s", raddr, c.tgtAddr, nextHop) } else { pc = v.(*PktConn) diff --git a/proxy/trojan/packet.go b/proxy/trojan/packet.go index da345ce..c3dc9af 100644 --- a/proxy/trojan/packet.go +++ b/proxy/trojan/packet.go @@ -7,7 +7,6 @@ import ( "net" "github.com/nadoo/glider/pool" - "github.com/nadoo/glider/proxy" "github.com/nadoo/glider/proxy/socks" ) @@ -36,14 +35,19 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, err } + if len(b) < 2 { + return 0, nil, errors.New("buf size is not enough") + } + // Length if _, err = io.ReadFull(pc.Conn, b[:2]); err != nil { return 0, nil, err } length := int(binary.BigEndian.Uint16(b[:2])) - if length > proxy.UDPBufSize { - return 0, nil, errors.New("packet invalid") + + if len(b) < length { + return 0, nil, errors.New("buf size is not enough") } // CRLF @@ -51,10 +55,6 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, err } - if len(b) < length { - return 0, nil, errors.New("buf size is not enough") - } - // Payload n, err := io.ReadFull(pc.Conn, b[:length]) if err != nil { @@ -70,10 +70,15 @@ func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { buf := pool.GetWriteBuffer() defer pool.PutWriteBuffer(buf) - buf.Write(pc.tgtAddr) + tgtLen, _ := buf.Write(pc.tgtAddr) binary.Write(buf, binary.BigEndian, uint16(len(b))) buf.WriteString("\r\n") buf.Write(b) - return pc.Write(buf.Bytes()) + n, err := pc.Write(buf.Bytes()) + if n > tgtLen+4 { + return n - tgtLen - 4, nil + } + + return 0, err } diff --git a/proxy/trojan/server.go b/proxy/trojan/server.go index e5a6802..712fbe4 100644 --- a/proxy/trojan/server.go +++ b/proxy/trojan/server.go @@ -193,7 +193,7 @@ func (s *Trojan) readHeader(r io.Reader) (byte, socks.Addr, error) { func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) { rc, err := net.ListenPacket("udp", "") if err != nil { - log.F("[trojan] UDP remote listen error: %v", err) + log.F("[trojan] UDP listen error: %v", err) return } defer rc.Close() @@ -212,13 +212,11 @@ func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) { for { n, _, err := pc.ReadFrom(buf) if err != nil { - log.F("[trojan] read error: %s\n", err) return } _, err = rc.WriteTo(buf[:n], tgtAddr) if err != nil { - log.F("[trojan] write rc error: %s\n", err) return } } @@ -232,14 +230,12 @@ func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) { for { n, _, err := rc.ReadFrom(buf) if err != nil { - log.F("[trojan] read rc error: %v", err) break } // WriteTo addr can be nil because the PktConn has it's own target, see packet.go _, err = pc.WriteTo(buf[:n], nil) if err != nil { - log.F("[trojan] write pc error: %v", err) break } } diff --git a/proxy/uottun/uottun.go b/proxy/uottun/uottun.go deleted file mode 100644 index cce2ccb..0000000 --- a/proxy/uottun/uottun.go +++ /dev/null @@ -1,114 +0,0 @@ -package uottun - -import ( - "errors" - "io/ioutil" - "net" - "net/url" - "strings" - "time" - - "github.com/nadoo/glider/log" - "github.com/nadoo/glider/proxy" -) - -// UoTTun is a base udp over tcp tunnel struct. -type UoTTun struct { - proxy proxy.Proxy - addr string - - raddr string -} - -func init() { - proxy.RegisterServer("uottun", NewUoTTunServer) -} - -// NewUoTTun returns a UoTTun proxy. -func NewUoTTun(s string, p proxy.Proxy) (*UoTTun, error) { - u, err := url.Parse(s) - if err != nil { - log.F("parse err: %s", err) - return nil, err - } - - addr := u.Host - d := strings.Split(addr, "=") - if len(d) < 2 { - return nil, errors.New("error in strings.Split") - } - - ut := &UoTTun{ - proxy: p, - addr: d[0], - raddr: d[1], - } - - return ut, nil -} - -// NewUoTTunServer returns a uot tunnel server. -func NewUoTTunServer(s string, p proxy.Proxy) (proxy.Server, error) { - return NewUoTTun(s, p) -} - -// ListenAndServe listen and serve on tcp. -func (s *UoTTun) ListenAndServe() { - c, err := net.ListenPacket("udp", s.addr) - if err != nil { - log.F("[uottun] failed to listen on %s: %v", s.addr, err) - return - } - defer c.Close() - - log.F("[uottun] listening UDP on %s", s.addr) - - buf := make([]byte, proxy.UDPBufSize) - - for { - n, clientAddr, err := c.ReadFrom(buf) - if err != nil { - log.F("[uottun] read error: %v", err) - continue - } - - rc, p, err := s.proxy.Dial("uot", s.raddr) - if err != nil { - log.F("[uottun] failed to connect to server %v: %v", s.raddr, err) - continue - } - - go func() { - // no remote forwarder, just a local udp forwarder - if urc, ok := rc.(*net.UDPConn); ok { - proxy.RelayUDP(c, clientAddr, urc, 2*time.Minute) - urc.Close() - return - } - - // remote forwarder, udp over tcp - // TODO: check here carefully, ReadAll allocates buffer and may leads to memory leak. - resp, err := ioutil.ReadAll(rc) - if err != nil { - log.F("[uottun] error in ioutil.ReadAll: %s\n", err) - return - } - rc.Close() - c.WriteTo(resp, clientAddr) - }() - - _, err = rc.Write(buf[:n]) - if err != nil { - log.F("[uottun] remote write error: %v", err) - continue - } - - log.F("[uottun] %s <-> %s via %s", clientAddr, s.raddr, p) - } -} - -// Serve is not allowed to be called directly. -func (s *UoTTun) Serve(c net.Conn) { - // TODO - log.F("[uottun] func Serve: can not be called directly") -} diff --git a/proxy/vless/client.go b/proxy/vless/client.go index 9d5aac3..9382ee7 100644 --- a/proxy/vless/client.go +++ b/proxy/vless/client.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "net" + "github.com/nadoo/glider/log" "github.com/nadoo/glider/pool" "github.com/nadoo/glider/proxy" ) @@ -35,12 +36,18 @@ func (s *VLess) Dial(network, addr string) (net.Conn, error) { // DialUDP connects to the given address via the proxy. func (s *VLess) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - c, err := s.Dial("udp", addr) + rc, err := s.dialer.Dial("tcp", s.addr) + if err != nil { + log.F("[vless]: dial to %s error: %s", s.addr, err) + return nil, nil, err + } + + c, err := NewClientConn(rc, s.uuid, network, addr) if err != nil { return nil, nil, err } - pkc := NewPktConn(c) - return pkc, nil, nil + + return NewPktConn(c), nil, nil } // ClientConn is a vless client connection. diff --git a/proxy/vless/packet.go b/proxy/vless/packet.go index 628e8e3..04c1bfa 100644 --- a/proxy/vless/packet.go +++ b/proxy/vless/packet.go @@ -18,6 +18,10 @@ func NewPktConn(c net.Conn) *PktConn { return &PktConn{Conn: c} } // ReadFrom implements the necessary function of net.PacketConn. // TODO: we know that we use it in proxy.RelayUDP and the length of b is enough, check it later. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { + if len(b) < 2 { + return 0, nil, errors.New("buf size is not enough") + } + // Length if _, err := io.ReadFull(pc.Conn, b[:2]); err != nil { return 0, nil, err @@ -41,5 +45,9 @@ func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { binary.Write(buf, binary.BigEndian, uint16(len(b))) buf.Write(b) - return pc.Write(buf.Bytes()) + n, err := pc.Write(buf.Bytes()) + if n > 2 { + return n - 2, err + } + return 0, err } diff --git a/proxy/vless/server.go b/proxy/vless/server.go index 19a8afc..7211e3c 100644 --- a/proxy/vless/server.go +++ b/proxy/vless/server.go @@ -2,7 +2,6 @@ package vless import ( "bytes" - "encoding/binary" "fmt" "io" "io/ioutil" @@ -52,6 +51,8 @@ func (s *VLess) Serve(c net.Conn) { headBuf := pool.GetWriteBuffer() defer pool.PutWriteBuffer(headBuf) + c = NewServerConn(c) + cmd, target, err := s.readHeader(io.TeeReader(c, headBuf)) if err != nil { log.F("[vless] verify header from %s error: %v", c.RemoteAddr(), err) @@ -82,7 +83,7 @@ func (s *VLess) Serve(c net.Conn) { log.F("[vless] %s <-> %s via %s", c.RemoteAddr(), target, dialer.Addr()) - if err = proxy.Relay(NewServerConn(c), rc); err != nil { + if err = proxy.Relay(c, rc); err != nil { log.F("[vless] %s <-> %s via %s, relay error: %v", c.RemoteAddr(), target, dialer.Addr(), err) // record remote conn failure only if !strings.Contains(err.Error(), s.addr) { @@ -161,7 +162,7 @@ func (s *VLess) readHeader(r io.Reader) (CmdType, string, error) { func (s *VLess) ServeUoT(c net.Conn, tgt string) { rc, err := net.ListenPacket("udp", "") if err != nil { - log.F("[vless] UDP remote listen error: %v", err) + log.F("[vless] UDP listen error: %v", err) return } defer rc.Close() @@ -172,26 +173,19 @@ func (s *VLess) ServeUoT(c net.Conn, tgt string) { return } + pc := NewPktConn(c) + go func() { buf := pool.GetBuffer(proxy.UDPBufSize) defer pool.PutBuffer(buf) for { - _, err := io.ReadFull(c, buf[:2]) + n, _, err := pc.ReadFrom(buf) if err != nil { - log.F("[vless] read c error: %s\n", err) - return - } - - length := binary.BigEndian.Uint16(buf[:2]) - n, err := io.ReadFull(c, buf[:length]) - if err != nil { - log.F("[vless] read payload error: %s\n", err) return } _, err = rc.WriteTo(buf[:n], tgtAddr) if err != nil { - log.F("[vless] write rc error: %s\n", err) return } } @@ -203,20 +197,16 @@ func (s *VLess) ServeUoT(c net.Conn, tgt string) { defer pool.PutBuffer(buf) for { - n, _, err := rc.ReadFrom(buf[2:]) + n, _, err := rc.ReadFrom(buf) if err != nil { - log.F("[vless] read rc error: %v", err) break } - binary.BigEndian.PutUint16(buf[:2], uint16(n)) - _, err = c.Write(buf[:2+n]) + _, err = pc.WriteTo(buf[:n], nil) if err != nil { - log.F("[vless] write c error: %v", err) break } } - } // ServerConn is a vless client connection.