mirror of
https://github.com/SagerNet/sing-mux.git
synced 2025-04-01 19:17:36 +03:00
238 lines
5.3 KiB
Go
238 lines
5.3 KiB
Go
package mux
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"io"
|
|
"math/rand"
|
|
"net"
|
|
|
|
"github.com/sagernet/sing/common"
|
|
"github.com/sagernet/sing/common/buf"
|
|
"github.com/sagernet/sing/common/bufio"
|
|
N "github.com/sagernet/sing/common/network"
|
|
"github.com/sagernet/sing/common/rw"
|
|
)
|
|
|
|
const kFirstPaddings = 16
|
|
|
|
type paddingConn struct {
|
|
N.ExtendedConn
|
|
writer N.VectorisedWriter
|
|
readPadding int
|
|
writePadding int
|
|
readRemaining int
|
|
paddingRemaining int
|
|
}
|
|
|
|
func newPaddingConn(conn net.Conn) net.Conn {
|
|
writer, isVectorised := bufio.CreateVectorisedWriter(conn)
|
|
if isVectorised {
|
|
return &vectorisedPaddingConn{
|
|
paddingConn{
|
|
ExtendedConn: bufio.NewExtendedConn(conn),
|
|
writer: bufio.NewVectorisedWriter(conn),
|
|
},
|
|
writer,
|
|
}
|
|
} else {
|
|
return &paddingConn{
|
|
ExtendedConn: bufio.NewExtendedConn(conn),
|
|
writer: bufio.NewVectorisedWriter(conn),
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *paddingConn) Read(p []byte) (n int, err error) {
|
|
if c.readRemaining > 0 {
|
|
if len(p) > c.readRemaining {
|
|
p = p[:c.readRemaining]
|
|
}
|
|
n, err = c.ExtendedConn.Read(p)
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.readRemaining -= n
|
|
return
|
|
}
|
|
if c.paddingRemaining > 0 {
|
|
err = rw.SkipN(c.ExtendedConn, c.paddingRemaining)
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.paddingRemaining = 0
|
|
}
|
|
if c.readPadding < kFirstPaddings {
|
|
var paddingHdr []byte
|
|
if len(p) >= 4 {
|
|
paddingHdr = p[:4]
|
|
} else {
|
|
paddingHdr = make([]byte, 4)
|
|
}
|
|
_, err = io.ReadFull(c.ExtendedConn, paddingHdr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
|
|
paddingLen := int(binary.BigEndian.Uint16(paddingHdr[2:]))
|
|
if len(p) > originalDataSize {
|
|
p = p[:originalDataSize]
|
|
}
|
|
n, err = c.ExtendedConn.Read(p)
|
|
if err != nil {
|
|
return
|
|
}
|
|
c.readPadding++
|
|
c.readRemaining = originalDataSize - n
|
|
c.paddingRemaining = paddingLen
|
|
return
|
|
}
|
|
return c.ExtendedConn.Read(p)
|
|
}
|
|
|
|
func (c *paddingConn) Write(p []byte) (n int, err error) {
|
|
for pLen := len(p); pLen > 0; {
|
|
var data []byte
|
|
if pLen > 65535 {
|
|
data = p[:65535]
|
|
p = p[65535:]
|
|
pLen -= 65535
|
|
} else {
|
|
data = p
|
|
pLen = 0
|
|
}
|
|
var writeN int
|
|
writeN, err = c.write(data)
|
|
n += writeN
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (c *paddingConn) write(p []byte) (n int, err error) {
|
|
if c.writePadding < kFirstPaddings {
|
|
paddingLen := 256 + rand.Intn(512)
|
|
buffer := buf.NewSize(4 + len(p) + paddingLen)
|
|
defer buffer.Release()
|
|
header := buffer.Extend(4)
|
|
binary.BigEndian.PutUint16(header[:2], uint16(len(p)))
|
|
binary.BigEndian.PutUint16(header[2:], uint16(paddingLen))
|
|
common.Must1(buffer.Write(p))
|
|
buffer.Extend(paddingLen)
|
|
_, err = c.ExtendedConn.Write(buffer.Bytes())
|
|
if err == nil {
|
|
n = len(p)
|
|
}
|
|
c.writePadding++
|
|
return
|
|
}
|
|
return c.ExtendedConn.Write(p)
|
|
}
|
|
|
|
func (c *paddingConn) ReadBuffer(buffer *buf.Buffer) error {
|
|
p := buffer.FreeBytes()
|
|
if c.readRemaining > 0 {
|
|
if len(p) > c.readRemaining {
|
|
p = p[:c.readRemaining]
|
|
}
|
|
n, err := c.ExtendedConn.Read(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.readRemaining -= n
|
|
buffer.Truncate(n)
|
|
return nil
|
|
}
|
|
if c.paddingRemaining > 0 {
|
|
err := rw.SkipN(c.ExtendedConn, c.paddingRemaining)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.paddingRemaining = 0
|
|
}
|
|
if c.readPadding < kFirstPaddings {
|
|
var paddingHdr []byte
|
|
if len(p) >= 4 {
|
|
paddingHdr = p[:4]
|
|
} else {
|
|
paddingHdr = make([]byte, 4)
|
|
}
|
|
_, err := io.ReadFull(c.ExtendedConn, paddingHdr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
|
|
paddingLen := int(binary.BigEndian.Uint16(paddingHdr[2:]))
|
|
|
|
if len(p) > originalDataSize {
|
|
p = p[:originalDataSize]
|
|
}
|
|
n, err := c.ExtendedConn.Read(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.readPadding++
|
|
c.readRemaining = originalDataSize - n
|
|
c.paddingRemaining = paddingLen
|
|
buffer.Truncate(n)
|
|
return nil
|
|
}
|
|
return c.ExtendedConn.ReadBuffer(buffer)
|
|
}
|
|
|
|
func (c *paddingConn) WriteBuffer(buffer *buf.Buffer) error {
|
|
if c.writePadding < kFirstPaddings {
|
|
bufferLen := buffer.Len()
|
|
if bufferLen > 65535 {
|
|
return common.Error(c.Write(buffer.Bytes()))
|
|
}
|
|
paddingLen := 256 + rand.Intn(512)
|
|
header := buffer.ExtendHeader(4)
|
|
binary.BigEndian.PutUint16(header[:2], uint16(bufferLen))
|
|
binary.BigEndian.PutUint16(header[2:], uint16(paddingLen))
|
|
buffer.Extend(paddingLen)
|
|
c.writePadding++
|
|
}
|
|
return c.ExtendedConn.WriteBuffer(buffer)
|
|
}
|
|
|
|
func (c *paddingConn) FrontHeadroom() int {
|
|
return 4 + 256 + 1024
|
|
}
|
|
|
|
func (c *paddingConn) Upstream() any {
|
|
return c.ExtendedConn
|
|
}
|
|
|
|
type vectorisedPaddingConn struct {
|
|
paddingConn
|
|
writer N.VectorisedWriter
|
|
}
|
|
|
|
func (c *vectorisedPaddingConn) WriteVectorised(buffers []*buf.Buffer) error {
|
|
if c.writePadding < kFirstPaddings {
|
|
bufferLen := buf.LenMulti(buffers)
|
|
if bufferLen > 65535 {
|
|
defer buf.ReleaseMulti(buffers)
|
|
for _, buffer := range buffers {
|
|
_, err := c.Write(buffer.Bytes())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
paddingLen := 256 + rand.Intn(512)
|
|
header := buf.NewSize(4)
|
|
common.Must(
|
|
binary.Write(header, binary.BigEndian, uint16(bufferLen)),
|
|
binary.Write(header, binary.BigEndian, uint16(paddingLen)),
|
|
)
|
|
c.writePadding++
|
|
padding := buf.NewSize(paddingLen)
|
|
padding.Extend(paddingLen)
|
|
buffers = append(append([]*buf.Buffer{header}, buffers...), padding)
|
|
}
|
|
return c.writer.WriteVectorised(buffers)
|
|
}
|