vless: added vless support

This commit is contained in:
nadoo 2020-10-01 20:59:45 +08:00
parent 02220387e9
commit c01c2d1839
7 changed files with 237 additions and 5 deletions

View File

@ -37,7 +37,7 @@ we can set up local listeners as proxy servers, and forward requests to internet
- Periodical availability checking for forwarders
- Send requests from specific local ip/interface
- Services:
- dhcpd: a simple dhcp server
- dhcpd: a simple dhcp server that can detect existing dhcp server and avoid conflicts
## Protocols
<details>
@ -54,6 +54,7 @@ we can set up local listeners as proxy servers, and forward requests to internet
|ssh | | |√| |client only
|trojan | | |√|√|client only
|vmess | | |√| |client only
|vless | | |√| |client only
|redir |√| | | |linux only
|redir6 |√| | | |linux only(ipv6)
|tls |√| |√| |transport client & server
@ -145,7 +146,7 @@ glider -h
Available schemes:
listen: mixed ss socks5 http redir redir6 tcptun udptun uottun tls unix kcp
forward: reject ss socks4 socks5 http ssr ssh vmess trojan tls ws unix kcp simple-obfs
forward: reject ss socks4 socks5 http ssr ssh vmess vless trojan tls ws unix kcp simple-obfs
SS scheme:
ss://method:pass@host:port
@ -168,6 +169,9 @@ SSH scheme:
VMess scheme:
vmess://[security:]uuid@host:port?alterID=num
VLESS scheme:
vless://uuid@host:port
Trojan scheme:
trojan://pass@host:port[?skipVerify=true]
@ -361,9 +365,11 @@ glider -config CONFIGPATH -listen :8080 -verbose
</details>
## Builtin Service
## Service
Scheme:
service=SERVICE_NAME[,SERVICE_CONFIG]
scheme: service=SERVICE_NAME[,SERVICE_CONFIG]
- dhcpd(from v0.11.0):
- service=dhcpd,INTERFACE,START_IP,END_IP
- e.g., service=dhcpd,en0,192.168.254.100,192.168.254.199

View File

@ -127,7 +127,7 @@ func usage() {
fmt.Fprintf(w, "Available schemes:\n")
fmt.Fprintf(w, " listen: mixed ss socks5 http redir redir6 tcptun udptun uottun tls unix kcp\n")
fmt.Fprintf(w, " forward: reject ss socks4 socks5 http ssr ssh vmess trojan tls ws unix kcp simple-obfs\n")
fmt.Fprintf(w, " forward: reject ss socks4 socks5 http ssr ssh vmess vless trojan tls ws unix kcp simple-obfs\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "SS scheme:\n")
@ -156,6 +156,10 @@ func usage() {
fmt.Fprintf(w, " vmess://[security:]uuid@host:port?alterID=num\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "VLESS scheme:\n")
fmt.Fprintf(w, " vless://uuid@host:port\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Trojan scheme:\n")
fmt.Fprintf(w, " trojan://pass@host:port[?skipVerify=true]\n")
fmt.Fprintf(w, "\n")

View File

@ -105,6 +105,9 @@ listen=socks5://:1080
# trojan as forwarder
# forward=trojan://PASSWORD@1.1.1.1:8080[?skipVerify=true]
# vless forwarder
# forward=vless://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@1.1.1.1:443
# vmess with none security
# forward=vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@1.1.1.1:443?alterID=2

View File

@ -20,6 +20,7 @@ import (
_ "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"
)

61
proxy/vless/addr.go Normal file
View File

@ -0,0 +1,61 @@
package vless
import (
"net"
"strconv"
)
// Atyp is vless addr type.
type Atyp byte
// Atyp
const (
AtypErr Atyp = 0
AtypIP4 Atyp = 1
AtypDomain Atyp = 2
AtypIP6 Atyp = 3
)
// Addr is vless addr.
type Addr []byte
// Port is vless addr port.
type Port uint16
// ParseAddr parses the address in string s.
func ParseAddr(s string) (Atyp, Addr, Port, error) {
var atyp Atyp
var addr Addr
host, port, err := net.SplitHostPort(s)
if err != nil {
return 0, nil, 0, err
}
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
addr = make([]byte, net.IPv4len)
atyp = AtypIP4
copy(addr[:], ip4)
} else {
addr = make([]byte, net.IPv6len)
atyp = AtypIP6
copy(addr[:], ip)
}
} else {
if len(host) > 255 {
return 0, nil, 0, err
}
addr = make([]byte, 1+len(host))
atyp = AtypDomain
addr[0] = byte(len(host))
copy(addr[1:], host)
}
portnum, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return 0, nil, 0, err
}
return atyp, addr, Port(portnum), err
}

88
proxy/vless/client.go Normal file
View File

@ -0,0 +1,88 @@
package vless
import (
"encoding/binary"
"encoding/hex"
"errors"
"io"
"io/ioutil"
"net"
"strings"
"github.com/nadoo/glider/common/pool"
)
const Version byte = 0
// CMD types.
const (
CmdTCP byte = 1
CmdUDP byte = 2
)
// Conn is a vless client connection.
type Conn struct {
net.Conn
rcved bool
}
// NewConn returns a new vless client conn.
func NewConn(c net.Conn, uuid [16]byte, target string) (*Conn, error) {
atyp, addr, port, err := ParseAddr(target)
if err != nil {
return nil, err
}
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
buf.WriteByte(Version) // ver
buf.Write(uuid[:]) // uuid
buf.WriteByte(0) // addinfo
buf.WriteByte(CmdTCP) // cmd
// target
err = binary.Write(buf, binary.BigEndian, uint16(port)) // port
if err != nil {
return nil, err
}
buf.WriteByte(byte(atyp)) // atyp
buf.Write(addr) //addr
_, err = c.Write(buf.Bytes())
return &Conn{Conn: c}, err
}
func (c *Conn) Read(b []byte) (n int, err error) {
if !c.rcved {
buf := pool.GetBuffer(2)
defer pool.PutBuffer(buf)
n, err = io.ReadFull(c.Conn, buf)
if err != nil {
return
}
if buf[0] != Version {
return n, errors.New("version not supported")
}
if addLen := int64(buf[1]); addLen != 0 {
io.CopyN(ioutil.Discard, c.Conn, addLen)
}
c.rcved = true
}
return c.Conn.Read(b)
}
// StrToUUID converts string to uuid.
// s fomat: "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
func StrToUUID(s string) (uuid [16]byte, err error) {
b := []byte(strings.Replace(s, "-", "", -1))
if len(b) != 32 {
return uuid, errors.New("invalid UUID: " + s)
}
_, err = hex.Decode(uuid[:], b)
return
}

69
proxy/vless/vless.go Normal file
View File

@ -0,0 +1,69 @@
package vless
import (
"errors"
"net"
"net/url"
"github.com/nadoo/glider/proxy"
)
// VLess struct.
type VLess struct {
dialer proxy.Dialer
addr string
uuid [16]byte
}
func init() {
proxy.RegisterDialer("vless", NewVLessDialer)
}
// NewVLess returns a vless proxy.
func NewVLess(s string, d proxy.Dialer) (*VLess, error) {
u, err := url.Parse(s)
if err != nil {
return nil, err
}
addr := u.Host
uuid, err := StrToUUID(u.User.Username())
if err != nil {
return nil, err
}
p := &VLess{
dialer: d,
addr: addr,
uuid: uuid,
}
return p, nil
}
// NewVLessDialer returns a vless proxy dialer.
func NewVLessDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
return NewVLess(s, dialer)
}
// Addr returns forwarder's address.
func (s *VLess) Addr() string {
if s.addr == "" {
return s.dialer.Addr()
}
return s.addr
}
// Dial connects to the address addr on the network net via the proxy.
func (s *VLess) Dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
return nil, err
}
return NewConn(rc, s.uuid, 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")
}