sing-box/transport/vless/client.go
2022-09-12 21:59:27 +08:00

145 lines
3 KiB
Go

package vless
import (
"encoding/binary"
"io"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
"github.com/gofrs/uuid"
)
type Client struct {
key []byte
}
func NewClient(userId string) (*Client, error) {
user := uuid.FromStringOrNil(userId)
if user == uuid.Nil {
user = uuid.NewV5(user, userId)
}
return &Client{key: user.Bytes()}, nil
}
func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) *Conn {
return &Conn{Conn: conn, key: c.key, destination: destination}
}
func (c *Client) DialPacketConn(conn net.Conn, destination M.Socksaddr) *PacketConn {
return &PacketConn{Conn: conn, key: c.key, destination: destination}
}
func (c *Client) DialXUDPPacketConn(conn net.Conn, destination M.Socksaddr) *XUDPConn {
return &XUDPConn{Conn: conn, key: c.key, destination: destination}
}
type Conn struct {
net.Conn
key []byte
destination M.Socksaddr
requestWritten bool
responseRead bool
}
func (c *Conn) Read(b []byte) (n int, err error) {
if !c.responseRead {
err = ReadResponse(c.Conn)
if err != nil {
return
}
c.responseRead = true
}
return c.Conn.Read(b)
}
func (c *Conn) Write(b []byte) (n int, err error) {
if !c.requestWritten {
err = WriteRequest(c.Conn, Request{c.key, CommandTCP, c.destination}, b)
if err == nil {
n = len(b)
}
c.requestWritten = true
return
}
return c.Conn.Write(b)
}
func (c *Conn) Upstream() any {
return c.Conn
}
type PacketConn struct {
net.Conn
key []byte
destination M.Socksaddr
requestWritten bool
responseRead bool
}
func (c *PacketConn) Read(b []byte) (n int, err error) {
if !c.responseRead {
err = ReadResponse(c.Conn)
if err != nil {
return
}
c.responseRead = true
}
var length uint16
err = binary.Read(c.Conn, binary.BigEndian, &length)
if err != nil {
return
}
if cap(b) < int(length) {
return 0, io.ErrShortBuffer
}
return io.ReadFull(c.Conn, b[:length])
}
func (c *PacketConn) Write(b []byte) (n int, err error) {
if !c.requestWritten {
err = WritePacketRequest(c.Conn, Request{c.key, CommandUDP, c.destination}, b)
if err == nil {
n = len(b)
}
c.requestWritten = true
return
}
err = binary.Write(c.Conn, binary.BigEndian, uint16(len(b)))
if err != nil {
return
}
return c.Conn.Write(b)
}
func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
dataLen := buffer.Len()
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(dataLen))
if !c.requestWritten {
err := WritePacketRequest(c.Conn, Request{c.key, CommandUDP, c.destination}, buffer.Bytes())
c.requestWritten = true
return err
}
return common.Error(c.Conn.Write(buffer.Bytes()))
}
func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
n, err = c.Read(p)
return
}
func (c *PacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return c.Write(p)
}
func (c *PacketConn) FrontHeadroom() int {
return 2
}
func (c *PacketConn) Upstream() any {
return c.Conn
}