Merge remote-tracking branch 'origin/Alpha' into dev-restls
This commit is contained in:
@ -20,6 +20,7 @@ import (
|
||||
"github.com/Dreamacro/clash/common/buf"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
@ -189,7 +190,7 @@ func (g *Conn) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *TransportWrap {
|
||||
func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap {
|
||||
wrap := TransportWrap{}
|
||||
|
||||
dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
@ -201,20 +202,37 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *T
|
||||
wrap.remoteAddr = pconn.RemoteAddr()
|
||||
|
||||
if len(Fingerprint) != 0 {
|
||||
if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists {
|
||||
utlsConn := tlsC.UClient(pconn, cfg, fingerprint)
|
||||
if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil {
|
||||
if realityConfig == nil {
|
||||
if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists {
|
||||
utlsConn := tlsC.UClient(pconn, cfg, fingerprint)
|
||||
if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
}
|
||||
state := utlsConn.(*tlsC.UConn).ConnectionState()
|
||||
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
||||
utlsConn.Close()
|
||||
return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
|
||||
}
|
||||
return utlsConn, nil
|
||||
}
|
||||
} else {
|
||||
realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, cfg, realityConfig)
|
||||
if err != nil {
|
||||
pconn.Close()
|
||||
return nil, err
|
||||
}
|
||||
state := utlsConn.(*tlsC.UConn).ConnectionState()
|
||||
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
||||
utlsConn.Close()
|
||||
return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
|
||||
}
|
||||
return utlsConn, nil
|
||||
//state := realityConn.(*utls.UConn).ConnectionState()
|
||||
//if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
||||
// realityConn.Close()
|
||||
// return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
|
||||
//}
|
||||
return realityConn, nil
|
||||
}
|
||||
}
|
||||
if realityConfig != nil {
|
||||
return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
|
||||
}
|
||||
|
||||
conn := tls.Client(pconn, cfg)
|
||||
if err := conn.HandshakeContext(ctx); err != nil {
|
||||
@ -274,11 +292,11 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config) (net.Conn, error) {
|
||||
func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) {
|
||||
dialFn := func(network, addr string) (net.Conn, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint)
|
||||
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig)
|
||||
return StreamGunWithTransport(transport, cfg)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
"github.com/Dreamacro/clash/transport/vless"
|
||||
"github.com/Dreamacro/clash/transport/vmess"
|
||||
|
||||
xtls "github.com/xtls/go"
|
||||
)
|
||||
|
||||
@ -54,6 +55,7 @@ type Option struct {
|
||||
Flow string
|
||||
FlowShow bool
|
||||
ClientFingerprint string
|
||||
Reality *tlsC.RealityConfig
|
||||
}
|
||||
|
||||
type WebsocketOption struct {
|
||||
@ -117,16 +119,24 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
|
||||
}
|
||||
|
||||
if len(t.option.ClientFingerprint) != 0 {
|
||||
utlsConn, valid := vmess.GetUtlsConnWithClientFingerprint(conn, t.option.ClientFingerprint, tlsConfig)
|
||||
if valid {
|
||||
if t.option.Reality == nil {
|
||||
utlsConn, valid := vmess.GetUTLSConn(conn, t.option.ClientFingerprint, tlsConfig)
|
||||
if valid {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx)
|
||||
return utlsConn, err
|
||||
}
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx)
|
||||
return utlsConn, err
|
||||
|
||||
return tlsC.GetRealityConn(ctx, conn, t.option.ClientFingerprint, tlsConfig, t.option.Reality)
|
||||
}
|
||||
}
|
||||
if t.option.Reality != nil {
|
||||
return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
|
||||
}
|
||||
|
||||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
|
||||
|
@ -200,7 +200,7 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err
|
||||
}
|
||||
|
||||
func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if len(p) > q.maxUdpRelayPacketSize {
|
||||
if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize {
|
||||
return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.maxUdpRelayPacketSize)
|
||||
}
|
||||
if q.closed {
|
||||
@ -215,7 +215,6 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro
|
||||
q.deferQuicConnFn(q.quicConn, err)
|
||||
}()
|
||||
}
|
||||
addr.String()
|
||||
buf := pool.GetBuffer()
|
||||
defer pool.PutBuffer(buf)
|
||||
addrPort, err := netip.ParseAddrPort(addr.String())
|
||||
@ -239,7 +238,8 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro
|
||||
return
|
||||
}
|
||||
default: // native
|
||||
err = q.quicConn.SendMessage(buf.Bytes())
|
||||
data := buf.Bytes()
|
||||
err = q.quicConn.SendMessage(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -250,7 +250,29 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro
|
||||
}
|
||||
|
||||
func (q *quicStreamPacketConn) LocalAddr() net.Addr {
|
||||
return q.quicConn.LocalAddr()
|
||||
addr := q.quicConn.LocalAddr()
|
||||
if q.inputConn != nil { // client
|
||||
return &packetAddr{addrStr: q.quicConn.LocalAddr().String(), connId: q.connId, rawAddr: addr}
|
||||
}
|
||||
return addr // server
|
||||
}
|
||||
|
||||
var _ net.PacketConn = &quicStreamPacketConn{}
|
||||
|
||||
type packetAddr struct {
|
||||
addrStr string
|
||||
connId uint32
|
||||
rawAddr net.Addr
|
||||
}
|
||||
|
||||
func (a packetAddr) Network() string {
|
||||
return "tuic"
|
||||
}
|
||||
|
||||
func (a packetAddr) String() string {
|
||||
return fmt.Sprintf("%s-%d", a.addrStr, a.connId)
|
||||
}
|
||||
|
||||
func (a packetAddr) RawAddr() net.Addr {
|
||||
return a.rawAddr
|
||||
}
|
||||
|
@ -114,9 +114,6 @@ func NewAuthenticate(TKN [32]byte) Authenticate {
|
||||
|
||||
func ReadAuthenticateWithHead(head CommandHead, reader BufferedReader) (c Authenticate, err error) {
|
||||
c.CommandHead = head
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c.CommandHead.TYPE != AuthenticateType {
|
||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||
return
|
||||
@ -170,9 +167,6 @@ func NewConnect(ADDR Address) Connect {
|
||||
|
||||
func ReadConnectWithHead(head CommandHead, reader BufferedReader) (c Connect, err error) {
|
||||
c.CommandHead = head
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c.CommandHead.TYPE != ConnectType {
|
||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||
return
|
||||
@ -228,9 +222,6 @@ func NewPacket(ASSOC_ID uint32, LEN uint16, ADDR Address, DATA []byte) Packet {
|
||||
|
||||
func ReadPacketWithHead(head CommandHead, reader BufferedReader) (c Packet, err error) {
|
||||
c.CommandHead = head
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c.CommandHead.TYPE != PacketType {
|
||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||
return
|
||||
@ -305,9 +296,6 @@ func NewDissociate(ASSOC_ID uint32) Dissociate {
|
||||
|
||||
func ReadDissociateWithHead(head CommandHead, reader BufferedReader) (c Dissociate, err error) {
|
||||
c.CommandHead = head
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c.CommandHead.TYPE != DissociateType {
|
||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||
return
|
||||
@ -476,15 +464,17 @@ func NewAddress(metadata *C.Metadata) Address {
|
||||
|
||||
func NewAddressAddrPort(addrPort netip.AddrPort) Address {
|
||||
var addrType byte
|
||||
if addrPort.Addr().Is4() {
|
||||
port := addrPort.Port()
|
||||
addr := addrPort.Addr().Unmap()
|
||||
if addr.Is4() {
|
||||
addrType = AtypIPv4
|
||||
} else {
|
||||
addrType = AtypIPv6
|
||||
}
|
||||
return Address{
|
||||
TYPE: addrType,
|
||||
ADDR: addrPort.Addr().AsSlice(),
|
||||
PORT: addrPort.Port(),
|
||||
ADDR: addr.AsSlice(),
|
||||
PORT: port,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@ -76,7 +75,7 @@ func (s *Server) Close() error {
|
||||
|
||||
type serverHandler struct {
|
||||
*Server
|
||||
quicConn quic.Connection
|
||||
quicConn quic.EarlyConnection
|
||||
uuid uuid.UUID
|
||||
|
||||
authCh chan struct{}
|
||||
@ -87,13 +86,6 @@ type serverHandler struct {
|
||||
}
|
||||
|
||||
func (s *serverHandler) handle() {
|
||||
time.AfterFunc(s.AuthenticationTimeout, func() {
|
||||
s.authOnce.Do(func() {
|
||||
_ = s.quicConn.CloseWithError(AuthenticationTimeout, "")
|
||||
s.authOk = false
|
||||
close(s.authCh)
|
||||
})
|
||||
})
|
||||
go func() {
|
||||
_ = s.handleUniStream()
|
||||
}()
|
||||
@ -103,6 +95,15 @@ func (s *serverHandler) handle() {
|
||||
go func() {
|
||||
_ = s.handleMessage()
|
||||
}()
|
||||
|
||||
<-s.quicConn.HandshakeComplete().Done()
|
||||
time.AfterFunc(s.AuthenticationTimeout, func() {
|
||||
s.authOnce.Do(func() {
|
||||
_ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout")
|
||||
s.authOk = false
|
||||
close(s.authCh)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *serverHandler) handleMessage() (err error) {
|
||||
@ -152,14 +153,10 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err err
|
||||
return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{
|
||||
pc: pc,
|
||||
packet: &packet,
|
||||
rAddr: s.genServerAssocIdAddr(assocId, s.quicConn.RemoteAddr()),
|
||||
rAddr: &packetAddr{addrStr: "tuic-" + s.uuid.String(), connId: assocId, rawAddr: s.quicConn.RemoteAddr()},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *serverHandler) genServerAssocIdAddr(assocId uint32, addr net.Addr) net.Addr {
|
||||
return &ServerAssocIdAddr{assocId: fmt.Sprintf("tuic-%s-%d", s.uuid.String(), assocId), addr: addr}
|
||||
}
|
||||
|
||||
func (s *serverHandler) handleStream() (err error) {
|
||||
for {
|
||||
var quicStream quic.Stream
|
||||
@ -239,7 +236,7 @@ func (s *serverHandler) handleUniStream() (err error) {
|
||||
}
|
||||
s.authOnce.Do(func() {
|
||||
if !ok {
|
||||
_ = s.quicConn.CloseWithError(AuthenticationFailed, "")
|
||||
_ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed")
|
||||
}
|
||||
s.authOk = ok
|
||||
close(s.authCh)
|
||||
@ -274,23 +271,6 @@ func (s *serverHandler) handleUniStream() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
type ServerAssocIdAddr struct {
|
||||
assocId string
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
func (a ServerAssocIdAddr) Network() string {
|
||||
return "ServerAssocIdAddr"
|
||||
}
|
||||
|
||||
func (a ServerAssocIdAddr) String() string {
|
||||
return a.assocId
|
||||
}
|
||||
|
||||
func (a ServerAssocIdAddr) RawAddr() net.Addr {
|
||||
return a.addr
|
||||
}
|
||||
|
||||
type serverUDPPacket struct {
|
||||
pc *quicStreamPacketConn
|
||||
packet *Packet
|
||||
|
@ -3,6 +3,7 @@ package vless
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/Dreamacro/clash/common/buf"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
@ -21,16 +22,15 @@ const (
|
||||
func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) {
|
||||
contentLen := int32(len(p))
|
||||
var paddingLen int32
|
||||
if contentLen < 900 && paddingTLS {
|
||||
log.Debugln("long padding")
|
||||
paddingLen = fastrand.Int31n(500) + 900 - contentLen
|
||||
} else {
|
||||
paddingLen = fastrand.Int31n(256)
|
||||
if contentLen < 900 {
|
||||
if paddingTLS {
|
||||
//log.Debugln("long padding")
|
||||
paddingLen = fastrand.Int31n(500) + 900 - contentLen
|
||||
} else {
|
||||
paddingLen = fastrand.Int31n(256)
|
||||
}
|
||||
}
|
||||
if paddingLen > buf.BufferSize-21-contentLen {
|
||||
paddingLen = buf.BufferSize - 21 - contentLen
|
||||
}
|
||||
if userUUID != nil { // unnecessary, but keep the same with Xray
|
||||
if userUUID != nil {
|
||||
buffer.Write(userUUID.Bytes())
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid
|
||||
binary.BigEndian.PutUint16(buffer.Extend(2), uint16(contentLen))
|
||||
binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen))
|
||||
buffer.Write(p)
|
||||
|
||||
buffer.Extend(int(paddingLen))
|
||||
log.Debugln("XTLS Vision write padding1: command=%v, payloadLen=%v, paddingLen=%v", command, contentLen, paddingLen)
|
||||
}
|
||||
@ -45,21 +46,22 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid
|
||||
func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) {
|
||||
contentLen := int32(buffer.Len())
|
||||
var paddingLen int32
|
||||
if contentLen < 900 && paddingTLS {
|
||||
log.Debugln("long padding")
|
||||
paddingLen = fastrand.Int31n(500) + 900 - contentLen
|
||||
} else {
|
||||
paddingLen = fastrand.Int31n(256)
|
||||
}
|
||||
if paddingLen > buf.BufferSize-21-contentLen {
|
||||
paddingLen = buf.BufferSize - 21 - contentLen
|
||||
if contentLen < 900 {
|
||||
if paddingTLS {
|
||||
//log.Debugln("long padding")
|
||||
paddingLen = fastrand.Int31n(500) + 900 - contentLen
|
||||
} else {
|
||||
paddingLen = fastrand.Int31n(256)
|
||||
}
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen))
|
||||
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen))
|
||||
buffer.ExtendHeader(1)[0] = command
|
||||
if userUUID != nil { // unnecessary, but keep the same with Xray
|
||||
if userUUID != nil {
|
||||
copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes())
|
||||
}
|
||||
|
||||
buffer.Extend(int(paddingLen))
|
||||
log.Debugln("XTLS Vision write padding2: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package vmess
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
@ -15,6 +16,7 @@ type TLSConfig struct {
|
||||
FingerPrint string
|
||||
ClientFingerprint string
|
||||
NextProtos []string
|
||||
Reality *tlsC.RealityConfig
|
||||
}
|
||||
|
||||
func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
||||
@ -34,15 +36,25 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
||||
}
|
||||
|
||||
if len(cfg.ClientFingerprint) != 0 {
|
||||
utlsConn, valid := GetUtlsConnWithClientFingerprint(conn, cfg.ClientFingerprint, tlsConfig)
|
||||
if valid {
|
||||
if cfg.Reality == nil {
|
||||
utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig)
|
||||
if valid {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx)
|
||||
return utlsConn, err
|
||||
}
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx)
|
||||
return utlsConn, err
|
||||
return tlsC.GetRealityConn(ctx, conn, cfg.ClientFingerprint, tlsConfig, cfg.Reality)
|
||||
}
|
||||
}
|
||||
if cfg.Reality != nil {
|
||||
return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
|
||||
}
|
||||
|
||||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
@ -52,7 +64,7 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
||||
return tlsConn, err
|
||||
}
|
||||
|
||||
func GetUtlsConnWithClientFingerprint(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) {
|
||||
func GetUTLSConn(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) {
|
||||
|
||||
if fingerprint, exists := tlsC.GetFingerprint(ClientFingerprint); exists {
|
||||
utlsConn := tlsC.UClient(conn, tlsConfig, fingerprint)
|
||||
|
Reference in New Issue
Block a user