mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 09:25: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
|
- Periodical availability checking for forwarders
|
||||||
- Send requests from specific local ip/interface
|
- Send requests from specific local ip/interface
|
||||||
- Services:
|
- Services:
|
||||||
- dhcpd: a simple dhcp server
|
- dhcpd: a simple dhcp server that can detect existing dhcp server and avoid conflicts
|
||||||
|
|
||||||
## Protocols
|
## Protocols
|
||||||
<details>
|
<details>
|
||||||
@ -54,6 +54,7 @@ we can set up local listeners as proxy servers, and forward requests to internet
|
|||||||
|ssh | | |√| |client only
|
|ssh | | |√| |client only
|
||||||
|trojan | | |√|√|client only
|
|trojan | | |√|√|client only
|
||||||
|vmess | | |√| |client only
|
|vmess | | |√| |client only
|
||||||
|
|vless | | |√| |client only
|
||||||
|redir |√| | | |linux only
|
|redir |√| | | |linux only
|
||||||
|redir6 |√| | | |linux only(ipv6)
|
|redir6 |√| | | |linux only(ipv6)
|
||||||
|tls |√| |√| |transport client & server
|
|tls |√| |√| |transport client & server
|
||||||
@ -145,7 +146,7 @@ glider -h
|
|||||||
|
|
||||||
Available schemes:
|
Available schemes:
|
||||||
listen: mixed ss socks5 http redir redir6 tcptun udptun uottun tls unix kcp
|
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 scheme:
|
||||||
ss://method:pass@host:port
|
ss://method:pass@host:port
|
||||||
@ -168,6 +169,9 @@ SSH scheme:
|
|||||||
VMess scheme:
|
VMess scheme:
|
||||||
vmess://[security:]uuid@host:port?alterID=num
|
vmess://[security:]uuid@host:port?alterID=num
|
||||||
|
|
||||||
|
VLESS scheme:
|
||||||
|
vless://uuid@host:port
|
||||||
|
|
||||||
Trojan scheme:
|
Trojan scheme:
|
||||||
trojan://pass@host:port[?skipVerify=true]
|
trojan://pass@host:port[?skipVerify=true]
|
||||||
|
|
||||||
@ -361,9 +365,11 @@ glider -config CONFIGPATH -listen :8080 -verbose
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Builtin Service
|
## Service
|
||||||
|
|
||||||
|
Scheme:
|
||||||
|
service=SERVICE_NAME[,SERVICE_CONFIG]
|
||||||
|
|
||||||
scheme: service=SERVICE_NAME[,SERVICE_CONFIG]
|
|
||||||
- dhcpd(from v0.11.0):
|
- dhcpd(from v0.11.0):
|
||||||
- service=dhcpd,INTERFACE,START_IP,END_IP
|
- service=dhcpd,INTERFACE,START_IP,END_IP
|
||||||
- e.g., service=dhcpd,en0,192.168.254.100,192.168.254.199
|
- 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, "Available schemes:\n")
|
||||||
fmt.Fprintf(w, " listen: mixed ss socks5 http redir redir6 tcptun udptun uottun tls unix kcp\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, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "SS scheme:\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, " vmess://[security:]uuid@host:port?alterID=num\n")
|
||||||
fmt.Fprintf(w, "\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 scheme:\n")
|
||||||
fmt.Fprintf(w, " trojan://pass@host:port[?skipVerify=true]\n")
|
fmt.Fprintf(w, " trojan://pass@host:port[?skipVerify=true]\n")
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
@ -105,6 +105,9 @@ listen=socks5://:1080
|
|||||||
# trojan as forwarder
|
# trojan as forwarder
|
||||||
# forward=trojan://PASSWORD@1.1.1.1:8080[?skipVerify=true]
|
# 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
|
# vmess with none security
|
||||||
# forward=vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@1.1.1.1:443?alterID=2
|
# 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/trojan"
|
||||||
_ "github.com/nadoo/glider/proxy/udptun"
|
_ "github.com/nadoo/glider/proxy/udptun"
|
||||||
_ "github.com/nadoo/glider/proxy/uottun"
|
_ "github.com/nadoo/glider/proxy/uottun"
|
||||||
|
_ "github.com/nadoo/glider/proxy/vless"
|
||||||
_ "github.com/nadoo/glider/proxy/vmess"
|
_ "github.com/nadoo/glider/proxy/vmess"
|
||||||
_ "github.com/nadoo/glider/proxy/ws"
|
_ "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