clash/transport/tuic/v5/server.go

230 lines
5.2 KiB
Go
Raw Normal View History

2023-06-12 09:44:22 +00:00
package v5
2022-11-28 09:09:25 +00:00
import (
"bufio"
"bytes"
"fmt"
2022-11-28 09:09:25 +00:00
"net"
"sync"
2023-06-12 09:44:22 +00:00
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/atomic"
2022-11-28 09:09:25 +00:00
N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
2023-06-12 09:44:22 +00:00
"github.com/Dreamacro/clash/transport/tuic/common"
2023-03-05 03:00:14 +00:00
2023-04-09 07:40:17 +00:00
"github.com/gofrs/uuid/v5"
2023-03-05 03:00:14 +00:00
"github.com/metacubex/quic-go"
2022-11-28 09:09:25 +00:00
)
type ServerOption struct {
2023-06-12 09:44:22 +00:00
HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error
HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error
2022-11-28 09:09:25 +00:00
2023-06-12 09:44:22 +00:00
Users map[[16]byte]string
2022-11-28 09:09:25 +00:00
MaxUdpRelayPacketSize int
}
func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid uuid.UUID) common.ServerHandler {
return &serverHandler{
2022-11-28 09:09:25 +00:00
ServerOption: option,
quicConn: quicConn,
uuid: uuid,
authCh: make(chan struct{}),
2022-11-28 09:09:25 +00:00
}
}
type serverHandler struct {
*ServerOption
quicConn quic.EarlyConnection
2022-11-28 09:09:25 +00:00
uuid uuid.UUID
authCh chan struct{}
authOk atomic.Bool
authUUID atomic.TypedValue[string]
2022-11-28 09:09:25 +00:00
authOnce sync.Once
udpInputMap sync.Map
2022-11-28 09:09:25 +00:00
}
func (s *serverHandler) AuthOk() bool {
return s.authOk.Load()
}
func (s *serverHandler) HandleTimeout() {
s.authOnce.Do(func() {
_ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout")
s.authOk.Store(false)
close(s.authCh)
})
2022-11-28 09:09:25 +00:00
}
func (s *serverHandler) HandleMessage(message []byte) (err error) {
reader := bytes.NewBuffer(message)
commandHead, err := ReadCommandHead(reader)
if err != nil {
return
}
switch commandHead.TYPE {
case PacketType:
var packet Packet
packet, err = ReadPacketWithHead(commandHead, reader)
2022-11-28 09:09:25 +00:00
if err != nil {
return
2022-11-28 09:09:25 +00:00
}
return s.parsePacket(packet, common.NATIVE)
case HeartbeatType:
var heartbeat Heartbeat
heartbeat, err = ReadHeartbeatWithHead(commandHead, reader)
if err != nil {
return
}
heartbeat.BytesLen()
2022-11-28 09:09:25 +00:00
}
return
2022-11-28 09:09:25 +00:00
}
func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) {
2022-11-28 09:09:25 +00:00
<-s.authCh
if !s.authOk.Load() {
2022-11-28 09:09:25 +00:00
return
}
2023-06-12 09:44:22 +00:00
var assocId uint16
2022-11-28 09:09:25 +00:00
assocId = packet.ASSOC_ID
2023-06-12 09:44:22 +00:00
v, _ := s.udpInputMap.LoadOrStore(assocId, &serverUDPInput{})
input := v.(*serverUDPInput)
if input.writeClosed.Load() {
return nil
}
2023-06-12 09:44:22 +00:00
packetPtr := input.Feed(packet)
if packetPtr == nil {
return
}
2022-11-28 09:09:25 +00:00
pc := &quicStreamPacketConn{
connId: assocId,
quicConn: s.quicConn,
inputConn: nil,
udpRelayMode: udpRelayMode,
maxUdpRelayPacketSize: s.MaxUdpRelayPacketSize,
deferQuicConnFn: nil,
closeDeferFn: nil,
2023-06-12 09:44:22 +00:00
writeClosed: &input.writeClosed,
2022-11-28 09:09:25 +00:00
}
2023-06-12 09:44:22 +00:00
return s.HandleUdpFn(packetPtr.ADDR.SocksAddr(), &serverUDPPacket{
2022-11-28 09:09:25 +00:00
pc: pc,
2023-06-12 09:44:22 +00:00
packet: packetPtr,
rAddr: N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn
}, inbound.WithInUser(s.authUUID.Load()))
2022-11-28 09:09:25 +00:00
}
func (s *serverHandler) HandleStream(conn *N.BufferedConn) (err error) {
connect, err := ReadConnect(conn)
if err != nil {
return err
}
<-s.authCh
if !s.authOk.Load() {
return conn.Close()
}
2022-11-28 09:09:25 +00:00
err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr(), inbound.WithInUser(s.authUUID.Load()))
if err != nil {
_ = conn.Close()
return err
2022-11-28 09:09:25 +00:00
}
return
2022-11-28 09:09:25 +00:00
}
func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) {
commandHead, err := ReadCommandHead(reader)
if err != nil {
return
}
switch commandHead.TYPE {
case AuthenticateType:
var authenticate Authenticate
authenticate, err = ReadAuthenticateWithHead(commandHead, reader)
2022-11-28 09:09:25 +00:00
if err != nil {
return
2022-11-28 09:09:25 +00:00
}
authOk := false
var authUUID uuid.UUID
var token [32]byte
if password, ok := s.Users[authenticate.UUID]; ok {
token, err = GenToken(s.quicConn.ConnectionState(), authenticate.UUID, password)
2022-11-28 09:09:25 +00:00
if err != nil {
return
}
if token == authenticate.TOKEN {
authOk = true
authUUID = authenticate.UUID
2022-11-28 09:09:25 +00:00
}
}
s.authOnce.Do(func() {
if !authOk {
_ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed")
}
s.authOk.Store(authOk)
s.authUUID.Store(authUUID.String())
close(s.authCh)
})
case PacketType:
var packet Packet
packet, err = ReadPacketWithHead(commandHead, reader)
if err != nil {
2022-11-28 09:09:25 +00:00
return
}
return s.parsePacket(packet, common.QUIC)
case DissociateType:
var disassociate Dissociate
disassociate, err = ReadDissociateWithHead(commandHead, reader)
if err != nil {
return
}
if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded {
input := v.(*serverUDPInput)
input.writeClosed.Store(true)
}
2022-11-28 09:09:25 +00:00
}
return
2022-11-28 09:09:25 +00:00
}
2023-06-12 09:44:22 +00:00
type serverUDPInput struct {
writeClosed atomic.Bool
deFragger
}
2022-11-28 09:09:25 +00:00
type serverUDPPacket struct {
pc *quicStreamPacketConn
packet *Packet
rAddr net.Addr
}
func (s *serverUDPPacket) InAddr() net.Addr {
return s.pc.LocalAddr()
}
func (s *serverUDPPacket) LocalAddr() net.Addr {
return s.rAddr
}
func (s *serverUDPPacket) Data() []byte {
return s.packet.DATA
}
func (s *serverUDPPacket) WriteBack(b []byte, addr net.Addr) (n int, err error) {
return s.pc.WriteTo(b, addr)
}
func (s *serverUDPPacket) Drop() {
s.packet.DATA = nil
}
var _ C.UDPPacket = (*serverUDPPacket)(nil)
var _ C.UDPPacketInAddr = (*serverUDPPacket)(nil)