Files
XTLS_Xray-core/transport/internet/finalmask/finalmask.go
T

423 lines
10 KiB
Go

package finalmask
import (
"context"
"fmt"
"slices"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
)
type Dialer struct {
DialTCP func(net.Destination) (net.Conn, error)
DialUDP func(net.Destination) (net.Conn, error)
}
type ListenConfig struct {
Listen func(net.Addr) (net.Listener, error)
ListenPacket func(net.Addr) (net.PacketConn, error)
}
type TCPMask interface {
WrapConnClient(net.Conn, *net.Destination, *Dialer) (net.Conn, error)
WrapConnServer(net.Conn) (net.Conn, error)
// Listen(net.Listener) (net.Listener, error)
}
type UDPMask interface {
WrapPacketConnClient(net.PacketConn, *net.Destination, *Dialer) (net.PacketConn, error)
WrapPacketConnServer(net.PacketConn, net.Addr, *ListenConfig) (net.PacketConn, error)
}
type FinalMask struct {
tcpMasks []TCPMask
udpMasks []UDPMask
dialTCP func(context.Context, net.Destination) (net.Conn, error)
listen func(context.Context, net.Addr) (net.Listener, error)
dialUDP func(context.Context, net.Destination) (net.PacketConn, net.Addr, error)
listenPacket func(context.Context, net.Addr) (net.PacketConn, error)
}
func NewFinalMask(tcpMasks []TCPMask, udpMasks []UDPMask, dialTCP func(context.Context, net.Destination) (net.Conn, error), listen func(context.Context, net.Addr) (net.Listener, error), dialUDP func(context.Context, net.Destination) (net.PacketConn, net.Addr, error), listenPacket func(context.Context, net.Addr) (net.PacketConn, error)) *FinalMask {
slices.Reverse(tcpMasks)
slices.Reverse(udpMasks)
return &FinalMask{
tcpMasks: tcpMasks,
udpMasks: udpMasks,
dialTCP: dialTCP,
dialUDP: dialUDP,
listen: listen,
listenPacket: listenPacket,
}
}
func (fm *FinalMask) DialTCP(ctx context.Context, dest net.Destination) (net.Conn, error) {
if len(fm.tcpMasks) == 0 {
return fm.dialTCP(ctx, dest)
}
for i := range fm.tcpMasks {
if i > 0 {
if _, ok := fm.tcpMasks[i].(interface{ HandleDial() }); ok {
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.tcpMasks[i])
}
}
}
var conn net.Conn
var err error
if _, ok := fm.tcpMasks[0].(interface{ HandleDial() }); !ok {
conn, err = fm.dialTCP(ctx, dest)
if err != nil {
return nil, err
}
}
dialer := &Dialer{
DialTCP: func(dest net.Destination) (net.Conn, error) {
return fm.dialTCP(ctx, dest)
},
DialUDP: func(dest net.Destination) (net.Conn, error) {
conn, addr, err := fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, err
},
}
for i := range fm.tcpMasks {
var newConn net.Conn
newConn, err = fm.tcpMasks[i].WrapConnClient(conn, &dest, dialer)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
return conn, nil
}
func (fm *FinalMask) Listen(ctx context.Context, addr net.Addr) (net.Listener, error) {
if len(fm.tcpMasks) == 0 {
return fm.listen(ctx, addr)
}
off := 0
listener, err := fm.listen(ctx, addr)
if err != nil {
return nil, err
}
for i := range fm.tcpMasks {
if _, ok := fm.tcpMasks[i].(interface {
Listen(net.Listener) (net.Listener, error)
}); ok {
if i-off == 0 {
l, err := fm.tcpMasks[i].(interface {
Listen(net.Listener) (net.Listener, error)
}).Listen(listener)
if err != nil {
listener.Close()
return nil, err
}
listener = l
} else {
l, err := fm.tcpMasks[i].(interface {
Listen(net.Listener) (net.Listener, error)
}).Listen(&TCPListener{Listener: listener, tcpMasks: fm.tcpMasks[off:i]})
if err != nil {
listener.Close()
return nil, err
}
listener = l
}
off = i + 1
}
}
if off < len(fm.tcpMasks) {
return &TCPListener{Listener: listener, tcpMasks: fm.tcpMasks[off:]}, nil
}
return listener, nil
}
func (fm *FinalMask) DialUDP(ctx context.Context, dest net.Destination) (net.Conn, error) {
if len(fm.udpMasks) == 0 {
conn, addr, err := fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, nil
}
for i := range fm.udpMasks {
if i > 0 {
if _, ok := fm.udpMasks[i].(interface{ HandleDial() }); ok {
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.udpMasks[i])
}
}
}
var conn net.PacketConn
var addr net.Addr
var err error
if _, ok := fm.udpMasks[0].(interface{ HandleDial() }); !ok {
conn, addr, err = fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
}
dialer := &Dialer{
DialTCP: func(dest net.Destination) (net.Conn, error) {
return fm.dialTCP(ctx, dest)
},
DialUDP: func(dest net.Destination) (net.Conn, error) {
conn, addr, err := fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, err
},
}
var sizes []int
var conns []net.PacketConn
for i := range fm.udpMasks {
var newConn net.PacketConn
if _, ok := fm.udpMasks[i].(interface{ HeaderConn() }); ok {
newConn, err = fm.udpMasks[i].WrapPacketConnClient(nil, nil, nil)
if err != nil {
_ = conn.Close()
return nil, err
}
sizes = append(sizes, newConn.(interface{ Size() int }).Size())
conns = append(conns, newConn)
} else {
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
newConn, err = fm.udpMasks[i].WrapPacketConnClient(conn, &dest, dialer)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
}
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
if addr == nil {
addr = &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, nil
}
func (fm *FinalMask) ListenPacket(ctx context.Context, addr net.Addr) (net.PacketConn, error) {
if len(fm.udpMasks) == 0 {
return fm.listenPacket(ctx, addr)
}
for i := range fm.udpMasks {
if i > 0 {
if _, ok := fm.udpMasks[i].(interface{ HandleListen() }); ok {
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.udpMasks[i])
}
}
}
var conn net.PacketConn
var err error
if _, ok := fm.udpMasks[0].(interface{ HandleListen() }); !ok {
conn, err = fm.listenPacket(ctx, addr)
if err != nil {
return nil, err
}
}
lc := &ListenConfig{
Listen: func(addr net.Addr) (net.Listener, error) { return fm.listen(ctx, addr) },
ListenPacket: func(addr net.Addr) (net.PacketConn, error) { return fm.listenPacket(ctx, addr) },
}
var sizes []int
var conns []net.PacketConn
for i := range fm.udpMasks {
var newConn net.PacketConn
if _, ok := fm.udpMasks[i].(interface{ HeaderConn() }); ok {
newConn, err = fm.udpMasks[i].WrapPacketConnServer(nil, nil, nil)
if err != nil {
_ = conn.Close()
return nil, err
}
sizes = append(sizes, newConn.(interface{ Size() int }).Size())
conns = append(conns, newConn)
} else {
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
newConn, err = fm.udpMasks[i].WrapPacketConnServer(conn, addr, lc)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
}
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
return conn, nil
}
const (
UDPSize = 4096
)
type PacketConnWrapper struct {
net.PacketConn
udpAddr net.Addr
}
func (c *PacketConnWrapper) RemoteAddr() net.Addr {
return c.udpAddr
}
func (c *PacketConnWrapper) Read(b []byte) (n int, err error) {
n, _, err = c.PacketConn.ReadFrom(b)
return
}
func (c *PacketConnWrapper) Write(b []byte) (n int, err error) {
return c.PacketConn.WriteTo(b, c.udpAddr)
}
type headerManagerConn struct {
net.PacketConn
sizes []int
conns []net.PacketConn
}
func (c *headerManagerConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
b := p
if len(b) < UDPSize {
buf := buf.New()
buf.Resize(0, UDPSize)
b = buf.Bytes()
defer buf.Release()
}
for {
n, addr, err = c.PacketConn.ReadFrom(b)
if err != nil {
return n, addr, err
}
buf := b[:n]
sum := 0
for _, size := range c.sizes {
sum += size
}
if n < sum {
errors.LogError(context.Background(), "[mask] drop packet from ", addr, " with size ", n)
continue
}
for i := range c.conns {
n, _, err = c.conns[i].ReadFrom(buf)
if err != nil {
errors.LogErrorInner(context.Background(), err, "[mask] drop packet from ", addr, " with size ", n)
break
}
buf = buf[c.sizes[i] : n+c.sizes[i]]
}
if err != nil {
continue
}
return copy(p, buf), addr, nil
}
}
func (c *headerManagerConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
buf := buf.New()
buf.Resize(0, UDPSize)
b := buf.Bytes()
defer buf.Release()
sum := 0
for _, size := range c.sizes {
sum += size
}
if sum+len(p) > UDPSize {
errors.LogError(context.Background(), "[mask] drop packet to ", addr, " with size ", len(p))
return 0, nil
}
n = copy(b[sum:], p)
for i := len(c.conns) - 1; i >= 0; i-- {
n, err = c.conns[i].WriteTo(b[sum-c.sizes[i]:n+sum], nil)
if err != nil {
errors.LogErrorInner(context.Background(), err, "[mask] drop packet to ", addr, " with size ", len(p))
return 0, nil
}
sum -= c.sizes[i]
}
if n > UDPSize {
errors.LogError(context.Background(), "[mask] drop packet to ", addr, " with size ", len(p))
return 0, nil
}
_, err = c.PacketConn.WriteTo(b[:n], addr)
if err != nil {
return 0, err
}
return len(p), nil
}
type TCPListener struct {
net.Listener
tcpMasks []TCPMask
}
func (l *TCPListener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return conn, err
}
for i := range l.tcpMasks {
var newConn net.Conn
newConn, err = l.tcpMasks[i].WrapConnServer(conn)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
return conn, nil
}
type TcpMaskConn interface {
TcpMaskConn()
RawConn() net.Conn
Splice() bool
}
func UnwrapTcpMask(conn net.Conn) net.Conn {
for {
if v, ok := conn.(TcpMaskConn); ok {
if !v.Splice() {
return conn
}
conn = v.RawConn()
} else {
return conn
}
}
}