mihomo/transport/vless/conn.go

129 lines
2.3 KiB
Go
Raw Normal View History

2021-07-01 22:49:29 +08:00
package vless
import (
"bytes"
"encoding/binary"
"errors"
2021-07-06 23:55:34 +08:00
"fmt"
2021-07-01 22:49:29 +08:00
"io"
"net"
"github.com/gofrs/uuid"
2021-07-06 23:55:34 +08:00
xtls "github.com/xtls/go"
"google.golang.org/protobuf/proto"
2021-07-01 22:49:29 +08:00
)
type Conn struct {
net.Conn
2021-07-06 23:55:34 +08:00
dst *DstAddr
id *uuid.UUID
addons *Addons
2021-07-01 22:49:29 +08:00
received bool
}
func (vc *Conn) Read(b []byte) (int, error) {
if vc.received {
return vc.Conn.Read(b)
}
if err := vc.recvResponse(); err != nil {
return 0, err
}
vc.received = true
return vc.Conn.Read(b)
}
func (vc *Conn) sendRequest() error {
buf := &bytes.Buffer{}
buf.WriteByte(Version) // protocol version
buf.Write(vc.id.Bytes()) // 16 bytes of uuid
2021-07-06 23:55:34 +08:00
if vc.addons != nil {
bytes, err := proto.Marshal(vc.addons)
if err != nil {
return err
}
buf.WriteByte(byte(len(bytes)))
buf.Write(bytes)
} else {
buf.WriteByte(0) // addon data length. 0 means no addon data
}
2021-07-01 22:49:29 +08:00
// command
if vc.dst.UDP {
buf.WriteByte(CommandUDP)
} else {
buf.WriteByte(CommandTCP)
}
// Port AddrType Addr
binary.Write(buf, binary.BigEndian, uint16(vc.dst.Port))
buf.WriteByte(vc.dst.AddrType)
buf.Write(vc.dst.Addr)
_, err := vc.Conn.Write(buf.Bytes())
return err
}
func (vc *Conn) recvResponse() error {
var err error
buf := make([]byte, 1)
_, err = io.ReadFull(vc.Conn, buf)
if err != nil {
return err
}
if buf[0] != Version {
return errors.New("unexpected response version")
}
_, err = io.ReadFull(vc.Conn, buf)
if err != nil {
return err
}
length := int64(buf[0])
if length != 0 { // addon data length > 0
2021-10-15 14:11:14 +08:00
io.CopyN(io.Discard, vc.Conn, length) // just discard
2021-07-01 22:49:29 +08:00
}
return nil
}
// newConn return a Conn instance
2021-07-06 23:55:34 +08:00
func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) {
2021-07-01 22:49:29 +08:00
c := &Conn{
Conn: conn,
2021-07-06 23:55:34 +08:00
id: client.uuid,
2021-07-01 22:49:29 +08:00
dst: dst,
}
2021-07-06 23:55:34 +08:00
if !dst.UDP && client.Addons != nil {
switch client.Addons.Flow {
case XRO, XRD, XRS:
if xtlsConn, ok := conn.(*xtls.Conn); ok {
xtlsConn.RPRX = true
xtlsConn.SHOW = client.XTLSShow
xtlsConn.MARK = "XTLS"
if client.Addons.Flow == XRS {
client.Addons.Flow = XRD
}
if client.Addons.Flow == XRD {
xtlsConn.DirectMode = true
}
c.addons = client.Addons
} else {
return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow)
}
}
}
2021-07-01 22:49:29 +08:00
if err := c.sendRequest(); err != nil {
return nil, err
}
return c, nil
}