glider/proxy/vless/client.go
2020-10-02 19:09:12 +08:00

95 lines
1.7 KiB
Go

package vless
import (
"encoding/binary"
"encoding/hex"
"errors"
"io"
"io/ioutil"
"net"
"strings"
"github.com/nadoo/glider/pool"
"github.com/nadoo/glider/proxy"
)
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
}
// 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
}
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
buf.WriteByte(Version) // ver
buf.Write(uuid[:]) // uuid
buf.WriteByte(0) // addLen
cmd := CmdTCP
if network == "udp" {
cmd = CmdUDP
}
buf.WriteByte(cmd) // 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 {
proxy.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
}