mirror of
https://github.com/bolucat/Archive.git
synced 2025-12-24 13:28:37 +08:00
Update On Thu Aug 14 20:41:00 CEST 2025
This commit is contained in:
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
tls "github.com/3andne/restls-client-go"
|
||||
tls "github.com/metacubex/restls-client-go"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"net/netip"
|
||||
"strconv"
|
||||
|
||||
"github.com/metacubex/blake3"
|
||||
"github.com/metacubex/quic-go"
|
||||
"lukechampine.com/blake3"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/transport/socks5"
|
||||
|
||||
@@ -105,26 +105,20 @@ func (vc *Conn) sendRequest(p []byte) bool {
|
||||
}
|
||||
}
|
||||
|
||||
var buffer *buf.Buffer
|
||||
if vc.IsXTLSVisionEnabled() {
|
||||
buffer = buf.New()
|
||||
defer buffer.Release()
|
||||
} else {
|
||||
requestLen := 1 // protocol version
|
||||
requestLen += 16 // UUID
|
||||
requestLen += 1 // addons length
|
||||
requestLen += len(addonsBytes)
|
||||
requestLen += 1 // command
|
||||
if !vc.dst.Mux {
|
||||
requestLen += 2 // port
|
||||
requestLen += 1 // addr type
|
||||
requestLen += len(vc.dst.Addr)
|
||||
}
|
||||
requestLen += len(p)
|
||||
|
||||
buffer = buf.NewSize(requestLen)
|
||||
defer buffer.Release()
|
||||
requestLen := 1 // protocol version
|
||||
requestLen += 16 // UUID
|
||||
requestLen += 1 // addons length
|
||||
requestLen += len(addonsBytes)
|
||||
requestLen += 1 // command
|
||||
if !vc.dst.Mux {
|
||||
requestLen += 2 // port
|
||||
requestLen += 1 // addr type
|
||||
requestLen += len(vc.dst.Addr)
|
||||
}
|
||||
requestLen += len(p)
|
||||
|
||||
buffer := buf.NewSize(requestLen)
|
||||
defer buffer.Release()
|
||||
|
||||
buf.Must(
|
||||
buffer.WriteByte(Version), // protocol version
|
||||
@@ -182,10 +176,6 @@ func (vc *Conn) NeedHandshake() bool {
|
||||
return vc.needHandshake
|
||||
}
|
||||
|
||||
func (vc *Conn) IsXTLSVisionEnabled() bool {
|
||||
return vc.addons != nil && vc.addons.Flow == XRV
|
||||
}
|
||||
|
||||
// newConn return a Conn instance
|
||||
func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) {
|
||||
c := &Conn{
|
||||
|
||||
@@ -4,11 +4,13 @@ import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -36,13 +38,12 @@ func init() {
|
||||
|
||||
type ClientInstance struct {
|
||||
sync.RWMutex
|
||||
nfsEKey *mlkem.EncapsulationKey768
|
||||
nfsEKeyBytes []byte
|
||||
xor uint32
|
||||
minutes time.Duration
|
||||
expire time.Time
|
||||
baseKey []byte
|
||||
ticket []byte
|
||||
nfsEKey *mlkem.EncapsulationKey768
|
||||
xorKey []byte
|
||||
minutes time.Duration
|
||||
expire time.Time
|
||||
baseKey []byte
|
||||
ticket []byte
|
||||
}
|
||||
|
||||
type ClientConn struct {
|
||||
@@ -59,10 +60,17 @@ type ClientConn struct {
|
||||
}
|
||||
|
||||
func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) {
|
||||
if i.nfsEKey != nil {
|
||||
err = errors.New("already initialized")
|
||||
return
|
||||
}
|
||||
i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if xor > 0 {
|
||||
i.nfsEKeyBytes = nfsEKeyBytes
|
||||
i.xor = xor
|
||||
xorKey := sha256.Sum256(nfsEKeyBytes)
|
||||
i.xorKey = xorKey[:]
|
||||
}
|
||||
i.minutes = minutes
|
||||
return
|
||||
@@ -72,8 +80,8 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
if i.nfsEKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
if i.xor > 0 {
|
||||
conn = NewXorConn(conn, i.nfsEKeyBytes)
|
||||
if i.xorKey != nil {
|
||||
conn = NewXorConn(conn, i.xorKey)
|
||||
}
|
||||
c := &ClientConn{Conn: conn}
|
||||
|
||||
@@ -107,16 +115,16 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
if _, err := c.Conn.Write(clientHello); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// client can send more padding / NFS AEAD messages if needed
|
||||
// client can send more paddings / NFS AEAD messages if needed
|
||||
|
||||
_, t, l, err := ReadAndDecodeHeader(c.Conn)
|
||||
_, t, l, err := ReadAndDiscardPaddings(c.Conn) // allow paddings before server hello
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t != 1 {
|
||||
return nil, fmt.Errorf("unexpected type %v, expect random hello", t)
|
||||
}
|
||||
|
||||
peerRandomHello := make([]byte, 1088+21)
|
||||
if l != len(peerRandomHello) {
|
||||
return nil, fmt.Errorf("unexpected length %v for random hello", l)
|
||||
@@ -193,27 +201,9 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
if c.peerAead == nil {
|
||||
var t byte
|
||||
var l int
|
||||
var err error
|
||||
if c.instance == nil { // from 1-RTT
|
||||
for {
|
||||
if _, t, l, err = ReadAndDecodeHeader(c.Conn); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if t != 23 {
|
||||
break
|
||||
}
|
||||
if _, err := io.ReadFull(c.Conn, make([]byte, l)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
h := make([]byte, 5)
|
||||
if _, err := io.ReadFull(c.Conn, h); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if t, l, err = DecodeHeader(h); err != nil {
|
||||
_, t, l, err := ReadAndDiscardPaddings(c.Conn) // allow paddings before random hello
|
||||
if err != nil {
|
||||
if c.instance != nil && strings.HasPrefix(err.Error(), "invalid header: ") { // 0-RTT's 0-RTT
|
||||
c.instance.Lock()
|
||||
if bytes.Equal(c.ticket, c.instance.ticket) {
|
||||
c.instance.expire = time.Now() // expired
|
||||
@@ -221,6 +211,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
||||
c.instance.Unlock()
|
||||
return 0, errors.New("new handshake needed")
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
if t != 0 {
|
||||
return 0, fmt.Errorf("unexpected type %v, expect server random", t)
|
||||
|
||||
@@ -45,10 +45,10 @@ func DecodeHeader(h []byte) (t byte, l int, err error) {
|
||||
} else if h[0] == 1 && h[1] == 1 && h[2] == 1 {
|
||||
t = 1
|
||||
} else {
|
||||
h = nil
|
||||
l = 0
|
||||
}
|
||||
if h == nil || l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
||||
err = fmt.Errorf("invalid header: %v", h[:5])
|
||||
if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
||||
err = fmt.Errorf("invalid header: %v", h[:5]) // DO NOT CHANGE: relied by client's Read()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -62,6 +62,17 @@ func ReadAndDecodeHeader(conn net.Conn) (h []byte, t byte, l int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ReadAndDiscardPaddings(conn net.Conn) (h []byte, t byte, l int, err error) {
|
||||
for {
|
||||
if h, t, l, err = ReadAndDecodeHeader(conn); err != nil || t != 23 {
|
||||
return
|
||||
}
|
||||
if _, err = io.ReadFull(conn, make([]byte, l)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewAead(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
||||
key := make([]byte, 32)
|
||||
hkdf.New(sha256.New, secret, salt, info).Read(key)
|
||||
|
||||
@@ -9,4 +9,6 @@
|
||||
// https://github.com/XTLS/Xray-core/commit/1720be168fa069332c418503d30341fc6e01df7f
|
||||
// https://github.com/XTLS/Xray-core/commit/0fd7691d6b28e05922d7a5a9313d97745a51ea63
|
||||
// https://github.com/XTLS/Xray-core/commit/09cc92c61d9067e0d65c1cae9124664ecfc78f43
|
||||
// https://github.com/XTLS/Xray-core/commit/2807ee432a1fbeb301815647189eacd650b12a8b
|
||||
// https://github.com/XTLS/Xray-core/commit/bfe4820f2f086daf639b1957eb23dc13c843cad1
|
||||
package encryption
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -23,12 +24,11 @@ type ServerSession struct {
|
||||
|
||||
type ServerInstance struct {
|
||||
sync.RWMutex
|
||||
nfsDKey *mlkem.DecapsulationKey768
|
||||
nfsEKeyBytes []byte
|
||||
xor uint32
|
||||
minutes time.Duration
|
||||
sessions map[[21]byte]*ServerSession
|
||||
closed bool
|
||||
nfsDKey *mlkem.DecapsulationKey768
|
||||
xorKey []byte
|
||||
minutes time.Duration
|
||||
sessions map[[21]byte]*ServerSession
|
||||
closed bool
|
||||
}
|
||||
|
||||
type ServerConn struct {
|
||||
@@ -45,10 +45,17 @@ type ServerConn struct {
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Duration) (err error) {
|
||||
if i.nfsDKey != nil {
|
||||
err = errors.New("already initialized")
|
||||
return
|
||||
}
|
||||
i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if xor > 0 {
|
||||
i.nfsEKeyBytes = i.nfsDKey.EncapsulationKey().Bytes()
|
||||
i.xor = xor
|
||||
xorKey := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
i.xorKey = xorKey[:]
|
||||
}
|
||||
if minutes > 0 {
|
||||
i.minutes = minutes
|
||||
@@ -85,18 +92,15 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
if i.nfsDKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
if i.xor > 0 {
|
||||
conn = NewXorConn(conn, i.nfsEKeyBytes)
|
||||
if i.xorKey != nil {
|
||||
conn = NewXorConn(conn, i.xorKey)
|
||||
}
|
||||
c := &ServerConn{Conn: conn}
|
||||
|
||||
_, t, l, err := ReadAndDecodeHeader(c.Conn)
|
||||
_, t, l, err := ReadAndDiscardPaddings(c.Conn) // allow paddings before client/ticket hello
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t == 23 {
|
||||
return nil, errors.New("unexpected data")
|
||||
}
|
||||
|
||||
if t == 0 {
|
||||
if i.minutes == 0 {
|
||||
@@ -113,9 +117,13 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
s := i.sessions[[21]byte(peerTicketHello)]
|
||||
i.RUnlock()
|
||||
if s == nil {
|
||||
noise := make([]byte, randBetween(100, 1000))
|
||||
rand.Read(noise)
|
||||
c.Conn.Write(noise) // make client do new handshake
|
||||
noises := make([]byte, randBetween(100, 1000))
|
||||
var err error
|
||||
for err == nil {
|
||||
rand.Read(noises)
|
||||
_, _, err = DecodeHeader(noises)
|
||||
}
|
||||
c.Conn.Write(noises) // make client do new handshake
|
||||
return nil, errors.New("expired ticket")
|
||||
}
|
||||
if _, replay := s.randoms.LoadOrStore([32]byte(peerTicketHello[21:]), true); replay {
|
||||
@@ -165,7 +173,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
if _, err := c.Conn.Write(serverHello); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// server can send more padding / PFS AEAD messages if needed
|
||||
// server can send more paddings / PFS AEAD messages if needed
|
||||
|
||||
if i.minutes > 0 {
|
||||
i.Lock()
|
||||
@@ -185,20 +193,10 @@ func (c *ServerConn) Read(b []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
if c.peerAead == nil {
|
||||
if c.peerRandom == nil { // from 1-RTT
|
||||
var t byte
|
||||
var l int
|
||||
var err error
|
||||
for {
|
||||
if _, t, l, err = ReadAndDecodeHeader(c.Conn); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if t != 23 {
|
||||
break
|
||||
}
|
||||
if _, err := io.ReadFull(c.Conn, make([]byte, l)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if c.peerRandom == nil { // 1-RTT's 0-RTT
|
||||
_, t, l, err := ReadAndDiscardPaddings(c.Conn) // allow paddings before ticket hello
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if t != 0 {
|
||||
return 0, fmt.Errorf("unexpected type %v, expect ticket hello", t)
|
||||
|
||||
@@ -18,11 +18,11 @@ type XorConn struct {
|
||||
}
|
||||
|
||||
func NewXorConn(conn net.Conn, key []byte) *XorConn {
|
||||
return &XorConn{Conn: conn, key: key[:16]}
|
||||
return &XorConn{Conn: conn, key: key}
|
||||
//chacha20.NewUnauthenticatedCipher()
|
||||
}
|
||||
|
||||
func (c *XorConn) Write(b []byte) (int, error) { // two records at most
|
||||
func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
@@ -34,10 +34,10 @@ func (c *XorConn) Write(b []byte) (int, error) { // two records at most
|
||||
c.ctr = cipher.NewCTR(block, iv)
|
||||
}
|
||||
t, l, _ := DecodeHeader(b)
|
||||
if t != 23 {
|
||||
l += 10 // 5+l+5
|
||||
} else {
|
||||
if t == 23 { // single 23
|
||||
l = 5
|
||||
} else { // 1/0 + 23, or noises only
|
||||
l += 10
|
||||
}
|
||||
c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b
|
||||
if iv != nil {
|
||||
@@ -73,8 +73,8 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
return len(b), nil
|
||||
}
|
||||
c.peerCtr.XORKeyStream(b, b)
|
||||
if c.isHeader {
|
||||
if t, _, _ := DecodeHeader(b); t == 23 { // always 5-bytes
|
||||
if c.isHeader { // always 5-bytes
|
||||
if t, _, _ := DecodeHeader(b); t == 23 {
|
||||
c.skipNext = true
|
||||
} else {
|
||||
c.isHeader = false
|
||||
|
||||
@@ -3,7 +3,6 @@ package vision
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
gotls "crypto/tls"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -12,7 +11,6 @@ import (
|
||||
|
||||
"github.com/metacubex/mihomo/common/buf"
|
||||
N "github.com/metacubex/mihomo/common/net"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
@@ -181,17 +179,10 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
|
||||
buffer.Release()
|
||||
return err
|
||||
}
|
||||
switch underlying := vc.tlsConn.(type) {
|
||||
case *gotls.Conn:
|
||||
if underlying.ConnectionState().Version != gotls.VersionTLS13 {
|
||||
buffer.Release()
|
||||
return ErrNotTLS13
|
||||
}
|
||||
case *tlsC.UConn:
|
||||
if underlying.ConnectionState().Version != tlsC.VersionTLS13 {
|
||||
buffer.Release()
|
||||
return ErrNotTLS13
|
||||
}
|
||||
err = vc.checkTLSVersion()
|
||||
if err != nil {
|
||||
buffer.Release()
|
||||
return err
|
||||
}
|
||||
vc.tlsConn = nil
|
||||
return nil
|
||||
|
||||
@@ -67,3 +67,21 @@ func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) {
|
||||
c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset))
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (vc *Conn) checkTLSVersion() error {
|
||||
switch underlying := vc.tlsConn.(type) {
|
||||
case *gotls.Conn:
|
||||
if underlying.ConnectionState().Version != gotls.VersionTLS13 {
|
||||
return ErrNotTLS13
|
||||
}
|
||||
case *tlsC.Conn:
|
||||
if underlying.ConnectionState().Version != tlsC.VersionTLS13 {
|
||||
return ErrNotTLS13
|
||||
}
|
||||
case *tlsC.UConn:
|
||||
if underlying.ConnectionState().Version != tlsC.VersionTLS13 {
|
||||
return ErrNotTLS13
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user