mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
vless: added vless support
This commit is contained in:
parent
02220387e9
commit
c01c2d1839
14
README.md
14
README.md
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
61
proxy/vless/addr.go
Normal 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
88
proxy/vless/client.go
Normal 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
69
proxy/vless/vless.go
Normal 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")
|
||||
}
|
Loading…
Reference in New Issue
Block a user