mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-08-05 05:15:18 +03:00
Add OpenVPN, TrustTunnel, Sudoku, inbound managers. Fixes
This commit is contained in:
165
transport/sudoku/uot.go
Normal file
165
transport/sudoku/uot.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package sudoku
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
)
|
||||
|
||||
const (
|
||||
maxUoTPayload = 64 * 1024
|
||||
)
|
||||
|
||||
// WriteDatagram sends a single UDP datagram frame over a reliable stream.
|
||||
func WriteDatagram(w io.Writer, addr string, payload []byte) error {
|
||||
addrBuf, err := EncodeAddress(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode address: %w", err)
|
||||
}
|
||||
|
||||
if addrLen := len(addrBuf); addrLen == 0 || addrLen > maxUoTPayload {
|
||||
return fmt.Errorf("address too long: %d", len(addrBuf))
|
||||
}
|
||||
if payloadLen := len(payload); payloadLen > maxUoTPayload {
|
||||
return fmt.Errorf("payload too large: %d", payloadLen)
|
||||
}
|
||||
|
||||
var header [4]byte
|
||||
binary.BigEndian.PutUint16(header[:2], uint16(len(addrBuf)))
|
||||
binary.BigEndian.PutUint16(header[2:], uint16(len(payload)))
|
||||
|
||||
return writeAllChunks(w, header[:], addrBuf, payload)
|
||||
}
|
||||
|
||||
// ReadDatagram parses a single UDP datagram frame from the reliable stream.
|
||||
func ReadDatagram(r io.Reader) (string, []byte, error) {
|
||||
addr, payloadLen, err := readDatagramHeaderAndAddress(r)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
payload := make([]byte, payloadLen)
|
||||
if _, err := io.ReadFull(r, payload); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return addr, payload, nil
|
||||
}
|
||||
|
||||
// UoTPacketConn adapts a net.Conn with the Sudoku UoT framing to net.PacketConn.
|
||||
type UoTPacketConn struct {
|
||||
conn net.Conn
|
||||
writeMu sync.Mutex
|
||||
}
|
||||
|
||||
func NewUoTPacketConn(conn net.Conn) *UoTPacketConn {
|
||||
return &UoTPacketConn{conn: conn}
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) ReadFrom(p []byte) (int, net.Addr, error) {
|
||||
for {
|
||||
addrStr, payloadLen, err := readDatagramHeaderAndAddress(c.conn)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
udpAddr, err := parseDatagramUDPAddr(addrStr)
|
||||
if payloadLen > len(p) {
|
||||
if discardErr := discardBytes(c.conn, payloadLen); discardErr != nil {
|
||||
return 0, nil, discardErr
|
||||
}
|
||||
return 0, nil, io.ErrShortBuffer
|
||||
}
|
||||
if err != nil {
|
||||
if discardErr := discardBytes(c.conn, payloadLen); discardErr != nil {
|
||||
return 0, nil, discardErr
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, err := io.ReadFull(c.conn, p[:payloadLen]); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return payloadLen, udpAddr, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) WriteTo(p []byte, addr net.Addr) (int, error) {
|
||||
if addr == nil {
|
||||
return 0, errors.New("address is nil")
|
||||
}
|
||||
c.writeMu.Lock()
|
||||
defer c.writeMu.Unlock()
|
||||
if err := WriteDatagram(c.conn, addr.String(), p); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *UoTPacketConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func readDatagramHeaderAndAddress(r io.Reader) (string, int, error) {
|
||||
var header [4]byte
|
||||
if _, err := io.ReadFull(r, header[:]); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
addrLen := int(binary.BigEndian.Uint16(header[:2]))
|
||||
payloadLen := int(binary.BigEndian.Uint16(header[2:]))
|
||||
if addrLen <= 0 || addrLen > maxUoTPayload {
|
||||
return "", 0, fmt.Errorf("invalid address length: %d", addrLen)
|
||||
}
|
||||
if payloadLen < 0 || payloadLen > maxUoTPayload {
|
||||
return "", 0, fmt.Errorf("invalid payload length: %d", payloadLen)
|
||||
}
|
||||
|
||||
addrBuf := make([]byte, addrLen)
|
||||
if _, err := io.ReadFull(r, addrBuf); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
addr, err := DecodeAddress(bytes.NewReader(addrBuf))
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("decode address: %w", err)
|
||||
}
|
||||
return addr, payloadLen, nil
|
||||
}
|
||||
|
||||
func parseDatagramUDPAddr(addr string) (*net.UDPAddr, error) {
|
||||
addrPort, err := netip.ParseAddrPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return net.UDPAddrFromAddrPort(netip.AddrPortFrom(addrPort.Addr().Unmap(), addrPort.Port())), nil
|
||||
}
|
||||
|
||||
func discardBytes(r io.Reader, n int) error {
|
||||
if n <= 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := io.CopyN(io.Discard, r, int64(n))
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user