mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-12 20:03:38 +00:00
175 lines
4.1 KiB
Go
175 lines
4.1 KiB
Go
package vless
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
|
|
"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"
|
|
)
|
|
|
|
type XUDPConn struct {
|
|
net.Conn
|
|
key []byte
|
|
destination M.Socksaddr
|
|
requestWritten bool
|
|
responseRead bool
|
|
}
|
|
|
|
func (c *XUDPConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|
return 0, nil, os.ErrInvalid
|
|
}
|
|
|
|
func (c *XUDPConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
|
start := buffer.Start()
|
|
if !c.responseRead {
|
|
err = ReadResponse(c.Conn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.responseRead = true
|
|
buffer.FullReset()
|
|
}
|
|
_, err = buffer.ReadFullFrom(c.Conn, 6)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var length uint16
|
|
err = binary.Read(buffer, binary.BigEndian, &length)
|
|
if err != nil {
|
|
return
|
|
}
|
|
header, err := buffer.ReadBytes(4)
|
|
if err != nil {
|
|
return
|
|
}
|
|
switch header[2] {
|
|
case 1:
|
|
// frame new
|
|
return M.Socksaddr{}, E.New("unexpected frame new")
|
|
case 2:
|
|
// frame keep
|
|
if length != 4 {
|
|
_, err = buffer.ReadFullFrom(c.Conn, int(length)-2)
|
|
if err != nil {
|
|
return
|
|
}
|
|
buffer.Advance(1)
|
|
destination, err = AddressSerializer.ReadAddrPort(buffer)
|
|
if err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
_, err = buffer.ReadFullFrom(c.Conn, 2)
|
|
if err != nil {
|
|
return
|
|
}
|
|
destination = c.destination
|
|
}
|
|
case 3:
|
|
// frame end
|
|
return M.Socksaddr{}, io.EOF
|
|
case 4:
|
|
// frame keep alive
|
|
default:
|
|
return M.Socksaddr{}, E.New("unexpected frame: ", buffer.Byte(2))
|
|
}
|
|
// option error
|
|
if header[3]&2 == 2 {
|
|
return M.Socksaddr{}, E.Cause(net.ErrClosed, "remote closed")
|
|
}
|
|
// option data
|
|
if header[3]&1 != 1 {
|
|
buffer.Resize(start, 0)
|
|
return c.ReadPacket(buffer)
|
|
} else {
|
|
err = binary.Read(buffer, binary.BigEndian, &length)
|
|
if err != nil {
|
|
return
|
|
}
|
|
buffer.Resize(start, 0)
|
|
_, err = buffer.ReadFullFrom(c.Conn, int(length))
|
|
return
|
|
}
|
|
}
|
|
|
|
func (c *XUDPConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|
destination := M.SocksaddrFromNet(addr)
|
|
headerLen := c.frontHeadroom(AddressSerializer.AddrPortLen(destination))
|
|
buffer := buf.NewSize(headerLen + len(p))
|
|
buffer.Advance(headerLen)
|
|
common.Must1(buffer.Write(p))
|
|
err = c.WritePacket(buffer, destination)
|
|
if err == nil {
|
|
n = len(p)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (c *XUDPConn) frontHeadroom(addrLen int) int {
|
|
if !c.requestWritten {
|
|
var headerLen int
|
|
headerLen += 1 // version
|
|
headerLen += 16 // uuid
|
|
headerLen += 1 // protobuf length
|
|
headerLen += 1 // command
|
|
headerLen += 2 // frame len
|
|
headerLen += 5 // frame header
|
|
headerLen += addrLen
|
|
headerLen += 2 // payload len
|
|
return headerLen
|
|
} else {
|
|
return 7 + addrLen + 2
|
|
}
|
|
}
|
|
|
|
func (c *XUDPConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
|
defer buffer.Release()
|
|
dataLen := buffer.Len()
|
|
addrLen := M.SocksaddrSerializer.AddrPortLen(destination)
|
|
if !c.requestWritten {
|
|
header := buf.With(buffer.ExtendHeader(c.frontHeadroom(addrLen)))
|
|
common.Must(
|
|
header.WriteByte(Version),
|
|
common.Error(header.Write(c.key)),
|
|
header.WriteByte(0),
|
|
header.WriteByte(CommandMux),
|
|
binary.Write(header, binary.BigEndian, uint16(5+addrLen)),
|
|
header.WriteByte(0),
|
|
header.WriteByte(0),
|
|
header.WriteByte(1), // frame type new
|
|
header.WriteByte(1), // option data
|
|
header.WriteByte(NetworkUDP),
|
|
AddressSerializer.WriteAddrPort(header, destination),
|
|
binary.Write(header, binary.BigEndian, uint16(dataLen)),
|
|
)
|
|
c.requestWritten = true
|
|
} else {
|
|
header := buffer.ExtendHeader(c.frontHeadroom(addrLen))
|
|
binary.BigEndian.PutUint16(header, uint16(5+addrLen))
|
|
header[2] = 0
|
|
header[3] = 0
|
|
header[4] = 2 // frame keep
|
|
header[5] = 1 // option data
|
|
header[6] = NetworkUDP
|
|
err := AddressSerializer.WriteAddrPort(buf.With(header[7:]), destination)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
binary.BigEndian.PutUint16(header[7+addrLen:], uint16(dataLen))
|
|
}
|
|
return common.Error(c.Conn.Write(buffer.Bytes()))
|
|
}
|
|
|
|
func (c *XUDPConn) FrontHeadroom() int {
|
|
return c.frontHeadroom(M.MaxSocksaddrLength)
|
|
}
|
|
|
|
func (c *XUDPConn) Upstream() any {
|
|
return c.Conn
|
|
}
|