github.com/kelleygo/clashcore@v1.0.2/transport/tuic/v5/server.go (about)

     1  package v5
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"net"
     8  	"sync"
     9  
    10  	"github.com/kelleygo/clashcore/adapter/inbound"
    11  	"github.com/kelleygo/clashcore/common/atomic"
    12  	N "github.com/kelleygo/clashcore/common/net"
    13  	C "github.com/kelleygo/clashcore/constant"
    14  	"github.com/kelleygo/clashcore/transport/socks5"
    15  	"github.com/kelleygo/clashcore/transport/tuic/common"
    16  
    17  	"github.com/gofrs/uuid/v5"
    18  	"github.com/metacubex/quic-go"
    19  	"github.com/puzpuzpuz/xsync/v3"
    20  )
    21  
    22  type ServerOption struct {
    23  	HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error
    24  	HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error
    25  
    26  	Users                 map[[16]byte]string
    27  	MaxUdpRelayPacketSize int
    28  }
    29  
    30  func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid uuid.UUID) common.ServerHandler {
    31  	return &serverHandler{
    32  		ServerOption: option,
    33  		quicConn:     quicConn,
    34  		uuid:         uuid,
    35  		authCh:       make(chan struct{}),
    36  		udpInputMap:  xsync.NewMapOf[uint16, *serverUDPInput](),
    37  	}
    38  }
    39  
    40  type serverHandler struct {
    41  	*ServerOption
    42  	quicConn quic.EarlyConnection
    43  	uuid     uuid.UUID
    44  
    45  	authCh   chan struct{}
    46  	authOk   atomic.Bool
    47  	authUUID atomic.TypedValue[string]
    48  	authOnce sync.Once
    49  
    50  	udpInputMap *xsync.MapOf[uint16, *serverUDPInput]
    51  }
    52  
    53  func (s *serverHandler) AuthOk() bool {
    54  	return s.authOk.Load()
    55  }
    56  
    57  func (s *serverHandler) HandleTimeout() {
    58  	s.authOnce.Do(func() {
    59  		_ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout")
    60  		s.authOk.Store(false)
    61  		close(s.authCh)
    62  	})
    63  }
    64  
    65  func (s *serverHandler) HandleMessage(message []byte) (err error) {
    66  	reader := bytes.NewBuffer(message)
    67  	commandHead, err := ReadCommandHead(reader)
    68  	if err != nil {
    69  		return
    70  	}
    71  	switch commandHead.TYPE {
    72  	case PacketType:
    73  		var packet Packet
    74  		packet, err = ReadPacketWithHead(commandHead, reader)
    75  		if err != nil {
    76  			return
    77  		}
    78  		return s.parsePacket(&packet, common.NATIVE)
    79  	case HeartbeatType:
    80  		var heartbeat Heartbeat
    81  		heartbeat, err = ReadHeartbeatWithHead(commandHead, reader)
    82  		if err != nil {
    83  			return
    84  		}
    85  		heartbeat.BytesLen()
    86  	}
    87  	return
    88  }
    89  
    90  func (s *serverHandler) parsePacket(packet *Packet, udpRelayMode common.UdpRelayMode) (err error) {
    91  	<-s.authCh
    92  	if !s.authOk.Load() {
    93  		return
    94  	}
    95  	var assocId uint16
    96  
    97  	assocId = packet.ASSOC_ID
    98  
    99  	input, _ := s.udpInputMap.LoadOrCompute(assocId, func() *serverUDPInput { return &serverUDPInput{} })
   100  	if input.writeClosed.Load() {
   101  		return nil
   102  	}
   103  	packetPtr := input.Feed(packet)
   104  	if packetPtr == nil {
   105  		return
   106  	}
   107  
   108  	pc := &quicStreamPacketConn{
   109  		connId:                assocId,
   110  		quicConn:              s.quicConn,
   111  		inputConn:             nil,
   112  		udpRelayMode:          udpRelayMode,
   113  		maxUdpRelayPacketSize: s.MaxUdpRelayPacketSize,
   114  		deferQuicConnFn:       nil,
   115  		closeDeferFn:          nil,
   116  		writeClosed:           &input.writeClosed,
   117  	}
   118  
   119  	return s.HandleUdpFn(packetPtr.ADDR.SocksAddr(), &serverUDPPacket{
   120  		pc:     pc,
   121  		packet: packetPtr,
   122  		rAddr:  N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn
   123  	}, inbound.WithInUser(s.authUUID.Load()))
   124  }
   125  
   126  func (s *serverHandler) HandleStream(conn *N.BufferedConn) (err error) {
   127  	connect, err := ReadConnect(conn)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	<-s.authCh
   132  	if !s.authOk.Load() {
   133  		return conn.Close()
   134  	}
   135  
   136  	err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr(), inbound.WithInUser(s.authUUID.Load()))
   137  	if err != nil {
   138  		_ = conn.Close()
   139  		return err
   140  	}
   141  	return
   142  }
   143  
   144  func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) {
   145  	commandHead, err := ReadCommandHead(reader)
   146  	if err != nil {
   147  		return
   148  	}
   149  	switch commandHead.TYPE {
   150  	case AuthenticateType:
   151  		var authenticate Authenticate
   152  		authenticate, err = ReadAuthenticateWithHead(commandHead, reader)
   153  		if err != nil {
   154  			return
   155  		}
   156  		authOk := false
   157  		var authUUID uuid.UUID
   158  		var token [32]byte
   159  		if password, ok := s.Users[authenticate.UUID]; ok {
   160  			token, err = GenToken(s.quicConn.ConnectionState(), authenticate.UUID, password)
   161  			if err != nil {
   162  				return
   163  			}
   164  			if token == authenticate.TOKEN {
   165  				authOk = true
   166  				authUUID = authenticate.UUID
   167  			}
   168  		}
   169  		s.authOnce.Do(func() {
   170  			if !authOk {
   171  				_ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed")
   172  			}
   173  			s.authOk.Store(authOk)
   174  			s.authUUID.Store(authUUID.String())
   175  			close(s.authCh)
   176  		})
   177  	case PacketType:
   178  		var packet Packet
   179  		packet, err = ReadPacketWithHead(commandHead, reader)
   180  		if err != nil {
   181  			return
   182  		}
   183  		return s.parsePacket(&packet, common.QUIC)
   184  	case DissociateType:
   185  		var disassociate Dissociate
   186  		disassociate, err = ReadDissociateWithHead(commandHead, reader)
   187  		if err != nil {
   188  			return
   189  		}
   190  		if input, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded {
   191  			input.writeClosed.Store(true)
   192  		}
   193  	}
   194  	return
   195  }
   196  
   197  type serverUDPInput struct {
   198  	writeClosed atomic.Bool
   199  	deFragger
   200  }
   201  
   202  type serverUDPPacket struct {
   203  	pc     *quicStreamPacketConn
   204  	packet *Packet
   205  	rAddr  net.Addr
   206  }
   207  
   208  func (s *serverUDPPacket) InAddr() net.Addr {
   209  	return s.pc.LocalAddr()
   210  }
   211  
   212  func (s *serverUDPPacket) LocalAddr() net.Addr {
   213  	return s.rAddr
   214  }
   215  
   216  func (s *serverUDPPacket) Data() []byte {
   217  	return s.packet.DATA
   218  }
   219  
   220  func (s *serverUDPPacket) WriteBack(b []byte, addr net.Addr) (n int, err error) {
   221  	return s.pc.WriteTo(b, addr)
   222  }
   223  
   224  func (s *serverUDPPacket) Drop() {
   225  	s.packet.DATA = nil
   226  }
   227  
   228  var _ C.UDPPacket = (*serverUDPPacket)(nil)
   229  var _ C.UDPPacketInAddr = (*serverUDPPacket)(nil)