mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-04 20:37:40 +03:00
Update UoT protocol
This commit is contained in:
parent
448948d26d
commit
2cee5a24f6
4 changed files with 210 additions and 128 deletions
|
@ -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
144
common/uot/conn.go
Normal 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
66
common/uot/protocol.go
Normal 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()))
|
||||
}
|
|
@ -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),
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue