Update UoT protocol

This commit is contained in:
世界 2023-03-15 12:55:24 +08:00
parent 448948d26d
commit 2cee5a24f6
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
4 changed files with 210 additions and 128 deletions

View file

@ -1,115 +0,0 @@
package uot
import (
"bufio"
"encoding/binary"
"io"
"net"
"sync"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
)
type ClientConn struct {
net.Conn
reader *bufio.Reader
writer *bufio.Writer
readAccess sync.Mutex
writeAccess sync.Mutex
}
func NewClientConn(conn net.Conn) *ClientConn {
return &ClientConn{
Conn: conn,
reader: bufio.NewReader(conn),
writer: bufio.NewWriter(conn),
}
}
func (c *ClientConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
c.readAccess.Lock()
defer c.readAccess.Unlock()
destination, err := AddrParser.ReadAddrPort(c.reader)
if err != nil {
return M.Socksaddr{}, err
}
var length uint16
err = binary.Read(c.reader, binary.BigEndian, &length)
if err != nil {
return M.Socksaddr{}, err
}
_, err = buffer.ReadFullFrom(c.reader, int(length))
if err != nil {
return M.Socksaddr{}, err
}
return destination, nil
}
func (c *ClientConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
c.writeAccess.Lock()
defer c.writeAccess.Unlock()
defer buffer.Release()
err := AddrParser.WriteAddrPort(c.writer, destination)
if err != nil {
return err
}
err = binary.Write(c.writer, binary.BigEndian, uint16(buffer.Len()))
if err != nil {
return err
}
_, err = c.writer.Write(buffer.Bytes())
if err != nil {
return err
}
return c.writer.Flush()
}
func (c *ClientConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
c.readAccess.Lock()
defer c.readAccess.Unlock()
addrPort, err := AddrParser.ReadAddrPort(c.reader)
if err != nil {
return 0, nil, err
}
var length uint16
err = binary.Read(c.reader, binary.BigEndian, &length)
if err != nil {
return 0, nil, err
}
if len(p) < int(length) {
return 0, nil, io.ErrShortBuffer
}
n, err = io.ReadFull(c.reader, p[:length])
if err != nil {
return 0, nil, err
}
addr = addrPort.UDPAddr()
return
}
func (c *ClientConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.writeAccess.Lock()
defer c.writeAccess.Unlock()
err = AddrParser.WriteAddrPort(c.writer, M.SocksaddrFromNet(addr))
if err != nil {
return
}
err = binary.Write(c.writer, binary.BigEndian, uint16(len(p)))
if err != nil {
return
}
_, err = c.writer.Write(p)
if err != nil {
return
}
err = c.writer.Flush()
if err != nil {
return
}
return len(p), nil
}

144
common/uot/conn.go Normal file
View file

@ -0,0 +1,144 @@
package uot
import (
"encoding/binary"
"io"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type Conn struct {
net.Conn
isConnect bool
destination M.Socksaddr
writer N.VectorisedWriter
}
func NewConn(conn net.Conn, isConnect bool, destination M.Socksaddr) *Conn {
uConn := &Conn{
Conn: conn,
isConnect: isConnect,
destination: destination,
}
uConn.writer, _ = bufio.CreateVectorisedWriter(conn)
return uConn
}
func (c *Conn) Read(p []byte) (n int, err error) {
n, _, err = c.ReadFrom(p)
return
}
func (c *Conn) Write(p []byte) (n int, err error) {
return c.WriteTo(p, c.destination)
}
func (c *Conn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
var destination M.Socksaddr
if c.isConnect {
destination = c.destination
} else {
destination, err = AddrParser.ReadAddrPort(c.Conn)
if err != nil {
return
}
}
var length uint16
err = binary.Read(c.Conn, binary.BigEndian, &length)
if err != nil {
return
}
if len(p) < int(length) {
err = E.Cause(io.ErrShortBuffer, "UoT read")
return
}
n, err = c.Conn.Read(p[:length])
if err == nil {
addr = destination.UDPAddr()
}
return
}
func (c *Conn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
destination := M.SocksaddrFromNet(addr)
var bufferLen int
if !c.isConnect {
bufferLen += AddrParser.AddrPortLen(destination)
}
bufferLen += 2
if c.writer == nil {
bufferLen += len(p)
}
_buffer := buf.StackNewSize(bufferLen)
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
if !c.isConnect {
common.Must(AddrParser.WriteAddrPort(buffer, destination))
}
common.Must(binary.Write(buffer, binary.BigEndian, uint16(len(p))))
if c.writer == nil {
common.Must1(buffer.Write(p))
return c.Conn.Write(buffer.Bytes())
}
err = c.writer.WriteVectorised([]*buf.Buffer{buffer, buf.As(p)})
if err == nil {
n = len(p)
}
return
}
func (c *Conn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
if c.isConnect {
destination = c.destination
} else {
destination, err = AddrParser.ReadAddrPort(c.Conn)
if err != nil {
return
}
}
var length uint16
err = binary.Read(c.Conn, binary.BigEndian, &length)
if err != nil {
return
}
_, err = buffer.ReadFullFrom(c.Conn, int(length))
if err != nil {
return M.Socksaddr{}, E.Cause(err, "UoT read")
}
return
}
func (c *Conn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
var headerLen int
if !c.isConnect {
headerLen += AddrParser.AddrPortLen(destination)
}
headerLen += 2
if c.writer == nil {
headerLen += buffer.Len()
}
_header := buf.StackNewSize(headerLen)
defer common.KeepAlive(_header)
header := common.Dup(_header)
defer header.Release()
if !c.isConnect {
common.Must(AddrParser.WriteAddrPort(header, destination))
}
common.Must(binary.Write(header, binary.BigEndian, uint16(buffer.Len())))
if c.writer == nil {
common.Must1(header.Write(buffer.Bytes()))
return common.Error(c.Conn.Write(header.Bytes()))
}
return c.writer.WriteVectorised([]*buf.Buffer{header, buffer})
}
func (c *Conn) Upstream() any {
return c.Conn
}

66
common/uot/protocol.go Normal file
View file

@ -0,0 +1,66 @@
package uot
import (
"encoding/binary"
"io"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
)
const (
Version = 2
MagicAddress = "sp.v2.udp-over-tcp.arpa"
LegacyMagicAddress = "sp.udp-over-tcp.arpa"
)
var AddrParser = M.NewSerializer(
M.AddressFamilyByte(0x00, M.AddressFamilyIPv4),
M.AddressFamilyByte(0x01, M.AddressFamilyIPv6),
M.AddressFamilyByte(0x02, M.AddressFamilyFqdn),
)
type Request struct {
IsConnect bool
Destination M.Socksaddr
}
func ReadRequest(reader io.Reader) (*Request, error) {
var version uint8
err := binary.Read(reader, binary.BigEndian, &version)
if err != nil {
return nil, err
}
if version != Version {
return nil, E.New("unsupported version: ", version)
}
var request Request
err = binary.Read(reader, binary.BigEndian, &request.IsConnect)
if err != nil {
return nil, err
}
request.Destination, err = M.SocksaddrSerializer.ReadAddrPort(reader)
if err != nil {
return nil, err
}
return &request, nil
}
func WriteRequest(writer io.Writer, request Request) error {
var requestLen int
requestLen += 1 // version
requestLen += 1 // isConnect
requestLen += M.SocksaddrSerializer.AddrPortLen(request.Destination)
_buffer := buf.StackNewSize(requestLen)
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
common.Must(
binary.Write(buffer, binary.BigEndian, uint8(Version)),
binary.Write(buffer, binary.BigEndian, request.IsConnect),
M.SocksaddrSerializer.WriteAddrPort(buffer, request.Destination),
)
return common.Error(writer.Write(buffer.Bytes()))
}

View file

@ -1,13 +0,0 @@
package uot
import (
M "github.com/sagernet/sing/common/metadata"
)
const UOTMagicAddress = "sp.udp-over-tcp.arpa"
var AddrParser = M.NewSerializer(
M.AddressFamilyByte(0x00, M.AddressFamilyIPv4),
M.AddressFamilyByte(0x01, M.AddressFamilyIPv6),
M.AddressFamilyByte(0x02, M.AddressFamilyFqdn),
)