mihomo/transport/tuic/v4/server.go

302 lines
6.4 KiB
Go
Raw Normal View History

2023-06-12 17:44:22 +08:00
package v4
2022-11-28 17:09:25 +08:00
import (
"bufio"
"bytes"
"context"
"crypto/tls"
"fmt"
2022-11-28 17:09:25 +08:00
"net"
"sync"
"sync/atomic"
2022-11-28 17:09:25 +08:00
"time"
2023-06-12 17:44:22 +08:00
"github.com/Dreamacro/clash/adapter/inbound"
2022-11-28 17:09:25 +08:00
N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/pool"
2023-03-05 11:00:14 +08:00
"github.com/Dreamacro/clash/common/utils"
2022-11-28 17:09:25 +08:00
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
2023-06-12 17:44:22 +08:00
"github.com/Dreamacro/clash/transport/tuic/common"
2023-03-05 11:00:14 +08:00
2023-04-09 15:40:17 +08:00
"github.com/gofrs/uuid/v5"
2023-03-05 11:00:14 +08:00
"github.com/metacubex/quic-go"
2022-11-28 17:09:25 +08:00
)
type ServerOption struct {
2023-06-12 17:44:22 +08: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 17:09:25 +08:00
TlsConfig *tls.Config
QuicConfig *quic.Config
Tokens [][32]byte
CongestionController string
AuthenticationTimeout time.Duration
MaxUdpRelayPacketSize int
}
type Server struct {
*ServerOption
2023-06-03 16:45:35 +08:00
listener *quic.EarlyListener
2022-11-28 17:09:25 +08:00
}
func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) {
listener, err := quic.ListenEarly(pc, option.TlsConfig, option.QuicConfig)
if err != nil {
return nil, err
}
return &Server{
ServerOption: option,
listener: listener,
}, err
}
func (s *Server) Serve() error {
for {
conn, err := s.listener.Accept(context.Background())
if err != nil {
return err
}
2023-06-12 17:44:22 +08:00
common.SetCongestionController(conn, s.CongestionController)
2022-11-28 17:09:25 +08:00
h := &serverHandler{
Server: s,
quicConn: conn,
2023-03-15 10:10:03 +08:00
uuid: utils.NewUUIDV4(),
2022-11-28 17:09:25 +08:00
authCh: make(chan struct{}),
}
go h.handle()
}
}
func (s *Server) Close() error {
return s.listener.Close()
}
type serverHandler struct {
*Server
quicConn quic.EarlyConnection
2022-11-28 17:09:25 +08:00
uuid uuid.UUID
authCh chan struct{}
authOk bool
authOnce sync.Once
udpInputMap sync.Map
2022-11-28 17:09:25 +08:00
}
func (s *serverHandler) handle() {
go func() {
_ = s.handleUniStream()
}()
go func() {
_ = s.handleStream()
}()
go func() {
_ = s.handleMessage()
}()
2023-06-01 16:25:02 +08:00
<-s.quicConn.HandshakeComplete()
time.AfterFunc(s.AuthenticationTimeout, func() {
s.authOnce.Do(func() {
_ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout")
s.authOk = false
close(s.authCh)
})
})
2022-11-28 17:09:25 +08:00
}
func (s *serverHandler) handleMessage() (err error) {
for {
var message []byte
message, err = s.quicConn.ReceiveMessage()
if err != nil {
return err
}
go func() (err error) {
buffer := bytes.NewBuffer(message)
packet, err := ReadPacket(buffer)
if err != nil {
return
}
return s.parsePacket(packet, "native")
}()
}
}
func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err error) {
<-s.authCh
if !s.authOk {
return
}
var assocId uint32
assocId = packet.ASSOC_ID
v, _ := s.udpInputMap.LoadOrStore(assocId, &atomic.Bool{})
writeClosed := v.(*atomic.Bool)
if writeClosed.Load() {
return nil
}
2022-11-28 17:09:25 +08:00
pc := &quicStreamPacketConn{
connId: assocId,
quicConn: s.quicConn,
inputConn: nil,
udpRelayMode: udpRelayMode,
maxUdpRelayPacketSize: s.MaxUdpRelayPacketSize,
deferQuicConnFn: nil,
closeDeferFn: nil,
writeClosed: writeClosed,
2022-11-28 17:09:25 +08:00
}
return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{
2022-11-28 17:09:25 +08:00
pc: pc,
packet: &packet,
rAddr: N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn
2022-11-28 17:09:25 +08:00
})
}
func (s *serverHandler) handleStream() (err error) {
for {
var quicStream quic.Stream
quicStream, err = s.quicConn.AcceptStream(context.Background())
if err != nil {
return err
}
go func() (err error) {
2023-06-12 17:44:22 +08:00
stream := common.NewQuicStreamConn(
quicStream,
s.quicConn.LocalAddr(),
s.quicConn.RemoteAddr(),
nil,
)
2022-11-28 17:09:25 +08:00
conn := N.NewBufferedConn(stream)
connect, err := ReadConnect(conn)
if err != nil {
return err
}
<-s.authCh
if !s.authOk {
return conn.Close()
}
buf := pool.GetBuffer()
defer pool.PutBuffer(buf)
err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr())
2022-11-28 17:09:25 +08:00
if err != nil {
err = NewResponseFailed().WriteTo(buf)
2022-11-29 00:42:26 +08:00
defer conn.Close()
} else {
err = NewResponseSucceed().WriteTo(buf)
2022-11-28 17:09:25 +08:00
}
if err != nil {
_ = conn.Close()
return err
}
_, err = buf.WriteTo(stream)
if err != nil {
_ = conn.Close()
return err
}
return
}()
}
}
func (s *serverHandler) handleUniStream() (err error) {
for {
var stream quic.ReceiveStream
stream, err = s.quicConn.AcceptUniStream(context.Background())
if err != nil {
return err
}
go func() (err error) {
defer func() {
stream.CancelRead(0)
}()
reader := bufio.NewReader(stream)
commandHead, err := ReadCommandHead(reader)
if err != nil {
return
}
switch commandHead.TYPE {
case AuthenticateType:
var authenticate Authenticate
authenticate, err = ReadAuthenticateWithHead(commandHead, reader)
if err != nil {
return
}
2023-06-12 17:44:22 +08:00
authOk := false
2022-11-28 17:09:25 +08:00
for _, tkn := range s.Tokens {
if authenticate.TKN == tkn {
2023-06-12 17:44:22 +08:00
authOk = true
2022-11-28 17:09:25 +08:00
break
}
}
s.authOnce.Do(func() {
2023-06-12 17:44:22 +08:00
if !authOk {
_ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed")
2022-11-28 17:09:25 +08:00
}
2023-06-12 17:44:22 +08:00
s.authOk = authOk
2022-11-28 17:09:25 +08:00
close(s.authCh)
})
case PacketType:
var packet Packet
packet, err = ReadPacketWithHead(commandHead, reader)
if err != nil {
return
}
return s.parsePacket(packet, "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 {
writeClosed := v.(*atomic.Bool)
writeClosed.Store(true)
}
case HeartbeatType:
var heartbeat Heartbeat
heartbeat, err = ReadHeartbeatWithHead(commandHead, reader)
if err != nil {
return
}
heartbeat.BytesLen()
2022-11-28 17:09:25 +08:00
}
return
}()
}
}
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)