udp: remove uottun and optimize udp implementation

This commit is contained in:
nadoo 2020-10-15 00:19:05 +08:00
parent 78e03d7fbf
commit d510ea45b0
19 changed files with 83 additions and 249 deletions

View File

@ -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.

View File

@ -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")

View File

@ -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://

View File

@ -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"

6
go.mod
View File

@ -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
)

12
go.sum
View File

@ -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=

View File

@ -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":

View File

@ -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

View File

@ -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 .

View File

@ -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)

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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")
}

View File

@ -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.

View File

@ -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
}

View File

@ -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.