vless: added udp support

This commit is contained in:
nadoo 2020-10-02 19:09:12 +08:00
parent bc68535dcd
commit b323a62ce6
10 changed files with 97 additions and 34 deletions

View File

@ -377,7 +377,7 @@ glider -config CONFIGPATH -listen :8080 -verbose
## Customize Build
You can customize and build glider by yourself if you want a smaller binary.
You can customize and build glider if you want a smaller binary.
1. Clone the source code:
```bash
@ -385,8 +385,8 @@ You can customize and build glider by yourself if you want a smaller binary.
```
2. Customize features:
```open `feature.go` & `feature_linux.go`, comment out the packages you don't need```
```bash
open `feature.go` & `feature_linux.go`, comment out the packages you don't need
// _ "github.com/nadoo/glider/proxy/kcp"
```

4
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.5.17
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 // indirect
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c // indirect
golang.org/x/tools v0.0.0-20201002055958-0d28ed0cbe40 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
)

8
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-20200930160638-afb6bcd081ae h1:duLSQW+DZ5MsXKX7kc4rXlq6/mmxz4G6ewJuBPlhRe0=
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977 h1:yH6opeNE+0SY+7pXT4gclZUoKHogXeC2EvOSHGOMGPU=
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977/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=
@ -173,8 +173,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-20201001104356-43ebab892c4c h1:9BSeO6440XJVa2mxIcRAndAol4g4g2KflCVGcHx9Yu8=
golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201002055958-0d28ed0cbe40 h1:ErPN1Z9An7dXc56pRUCKgWJkjYzc3hE+y15ky9E8qxU=
golang.org/x/tools v0.0.0-20201002055958-0d28ed0cbe40/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

@ -172,14 +172,14 @@ func (s *SS) Serve(c net.Conn) {
func (s *SS) ListenAndServeUDP() {
lc, err := net.ListenPacket("udp", s.addr)
if err != nil {
log.F("[ss-udp] failed to listen on %s: %v", s.addr, err)
log.F("[ssu] failed to listen on %s: %v", s.addr, err)
return
}
defer lc.Close()
lc = s.PacketConn(lc)
log.F("[ss-udp] listening UDP on %s", s.addr)
log.F("[ssu] listening UDP on %s", s.addr)
var nm sync.Map
buf := make([]byte, proxy.UDPBufSize)
@ -189,7 +189,7 @@ func (s *SS) ListenAndServeUDP() {
n, raddr, err := c.ReadFrom(buf)
if err != nil {
log.F("[ss-udp] remote read error: %v", err)
log.F("[ssu] remote read error: %v", err)
continue
}
@ -198,7 +198,7 @@ func (s *SS) ListenAndServeUDP() {
if !ok && v == nil {
lpc, nextHop, err := s.proxy.DialUDP("udp", c.tgtAddr.String())
if err != nil {
log.F("[ss-udp] remote dial error: %v", err)
log.F("[ssu] remote dial error: %v", err)
continue
}
@ -211,7 +211,7 @@ func (s *SS) ListenAndServeUDP() {
nm.Delete(raddr.String())
}()
log.F("[ss-udp] %s <-> %s", raddr, c.tgtAddr)
log.F("[ssu] %s <-> %s", raddr, c.tgtAddr)
} else {
pc = v.(*PktConn)
@ -219,11 +219,11 @@ func (s *SS) ListenAndServeUDP() {
_, err = pc.WriteTo(buf[:n], pc.writeAddr)
if err != nil {
log.F("[ss-udp] remote write error: %v", err)
log.F("[ssu] remote write error: %v", err)
continue
}
// log.F("[ss-udp] %s <-> %s", raddr, c.tgtAddr)
// log.F("[ssu] %s <-> %s", raddr, c.tgtAddr)
}
}

View File

@ -28,6 +28,7 @@ func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn {
}
// 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) {
// ATYP, DST.ADDR, DST.PORT
_, err := socks.ReadAddr(pc.Conn)
@ -50,6 +51,10 @@ 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 {
@ -69,5 +74,6 @@ func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.WriteString("\r\n")
buf.Write(b)
return pc.Write(buf.Bytes())
}

View File

@ -27,8 +27,8 @@ type Conn struct {
rcved bool
}
// NewConn returns a new vless client conn.
func NewConn(c net.Conn, uuid [16]byte, target string) (*Conn, error) {
// ClientConn returns a new vless client conn.
func ClientConn(c net.Conn, uuid [16]byte, network, target string) (*Conn, error) {
atyp, addr, port, err := ParseAddr(target)
if err != nil {
return nil, err
@ -40,7 +40,12 @@ func NewConn(c net.Conn, uuid [16]byte, target string) (*Conn, error) {
buf.WriteByte(Version) // ver
buf.Write(uuid[:]) // uuid
buf.WriteByte(0) // addLen
buf.WriteByte(CmdTCP) // cmd
cmd := CmdTCP
if network == "udp" {
cmd = CmdUDP
}
buf.WriteByte(cmd) // cmd
// target
err = binary.Write(buf, binary.BigEndian, uint16(port)) // port

53
proxy/vless/packet.go Normal file
View File

@ -0,0 +1,53 @@
package vless
import (
"encoding/binary"
"errors"
"io"
"net"
"github.com/nadoo/glider/pool"
)
// PktConn .
type PktConn struct {
net.Conn
}
// NewPktConn returns a PktConn.
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) {
// Length
if _, err := io.ReadFull(pc.Conn, b[:2]); err != nil {
return 0, nil, err
}
length := int(binary.BigEndian.Uint16(b[:2]))
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 {
return 0, nil, err
}
return n, nil, nil
}
// WriteTo implements the necessary function of net.PacketConn.
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.Write(b)
return pc.Write(buf.Bytes())
}

View File

@ -1,7 +1,6 @@
package vless
import (
"errors"
"net"
"net/url"
@ -60,10 +59,15 @@ func (s *VLess) Dial(network, addr string) (net.Conn, error) {
if err != nil {
return nil, err
}
return NewConn(rc, s.uuid, addr)
return ClientConn(rc, s.uuid, network, addr)
}
// DialUDP connects to the given address via the proxy.
func (s *VLess) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
return nil, nil, errors.New("vless client does not support udp now")
c, err := s.Dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c)
return pkc, nil, nil
}

View File

@ -14,8 +14,9 @@ import (
"strings"
"time"
"github.com/nadoo/glider/pool"
"golang.org/x/crypto/chacha20poly1305"
"github.com/nadoo/glider/pool"
)
// Request Options

View File

@ -226,9 +226,8 @@ func checkWebSite(fwdr *Forwarder, website string, timeout time.Duration, buf []
rc, err := fwdr.Dial("tcp", website)
if err != nil {
log.F("[check] %s(%d) -> %s, FAILED. error in dial: %s", fwdr.Addr(), fwdr.Priority(), website, err)
fwdr.Disable()
log.F("[check] %s(%d) -> %s, FAILED. error in dial: %s", fwdr.Addr(), fwdr.Priority(),
website, err)
return false
}
defer rc.Close()
@ -239,24 +238,21 @@ func checkWebSite(fwdr *Forwarder, website string, timeout time.Duration, buf []
_, err = io.WriteString(rc, "GET / HTTP/1.0\r\n\r\n")
if err != nil {
log.F("[check] %s(%d) -> %s, FAILED. error in write: %s", fwdr.Addr(), fwdr.Priority(), website, err)
fwdr.Disable()
log.F("[check] %s(%d) -> %s, FAILED. error in write: %s", fwdr.Addr(), fwdr.Priority(),
website, err)
return false
}
_, err = io.ReadFull(rc, buf)
if err != nil {
log.F("[check] %s(%d) -> %s, FAILED. error in read: %s", fwdr.Addr(), fwdr.Priority(), website, err)
fwdr.Disable()
log.F("[check] %s(%d) -> %s, FAILED. error in read: %s", fwdr.Addr(), fwdr.Priority(),
website, err)
return false
}
if !bytes.Equal([]byte("HTTP"), buf) {
log.F("[check] %s(%d) -> %s, FAILED. server response: %s", fwdr.Addr(), fwdr.Priority(), website, buf)
fwdr.Disable()
log.F("[check] %s(%d) -> %s, FAILED. server response: %s", fwdr.Addr(), fwdr.Priority(),
website, buf)
return false
}
@ -264,15 +260,13 @@ func checkWebSite(fwdr *Forwarder, website string, timeout time.Duration, buf []
fwdr.SetLatency(int64(readTime))
if readTime > timeout {
log.F("[check] %s(%d) -> %s, FAILED. check timeout: %s", fwdr.Addr(), fwdr.Priority(), website, readTime)
fwdr.Disable()
log.F("[check] %s(%d) -> %s, FAILED. check timeout: %s", fwdr.Addr(), fwdr.Priority(),
website, readTime)
return false
}
log.F("[check] %s(%d) -> %s, SUCCESS. elapsed time: %s", fwdr.Addr(), fwdr.Priority(), website, readTime)
fwdr.Enable()
log.F("[check] %s(%d) -> %s, SUCCESS. connect time: %s", fwdr.Addr(), fwdr.Priority(),
website, readTime)
return true
}