1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2026-06-22 10:49:58 -04:00
Files
v2fly/transport/internet/tlsmirror/server/client_conn.go
Xiaokang Wang (Shelikhoo) b1ef737d48 Add TLSMirror looks like TLS censorship resistant transport protocol as a developer preview transport (#3437)
* Add tlsmirror server processing routine

* Add tlsmirror server processing routine: generated

* Add tlsmirror server handshake capture

* it runs version~

* add draining copy for handshake

* refactor out base tls mirror connection

* tls mirror server side base

* add random field extraction

* add tls like encryption

* add tls like encryption (generated)

* add server side implementation for tlsmirror

* apply coding style: tlsmirror

* fix typo in mirrortls mirror crypto

* add client initial implementation for tls mirror

* add traffic generator implementation for tlsmirror

* add client processing of traffic generator originated traffic

* add embedded traffic generator support to mirrortls client

* override security setting of traffic generator if appropriate

* override security setting of traffic generator if appropriate

* apply request wait time for traffic generator

* add unsafe keyword required for linkname

* fix outbound manager registration for traffic ingress at tlsmirror client

* initial works at sticking packets together

* fix traffic generator's traffic goto logic

* fix get client and server random

* fix applying primary key

* fix log error handling for handshake random retrieval

* fix nonce generation and key derivation logic

* fix: add readPipe channel to client and server connection handlers

* fix: use detached context for persistent mirror TLS dialer

* fix: ensure proper closure of connections on context cancellation

* fix: proper detection of traffic generator originated connection

wait for connection ready before sending payload

* fix coding style
2025-07-03 11:33:16 +01:00

165 lines
4.0 KiB
Go

package server
import (
"bytes"
"context"
gonet "net"
"time"
"github.com/v2fly/v2ray-core/v5/common/net"
"github.com/v2fly/v2ray-core/v5/transport/internet"
"github.com/v2fly/v2ray-core/v5/transport/internet/tlsmirror"
"github.com/v2fly/v2ray-core/v5/transport/internet/tlsmirror/mirrorcommon"
"github.com/v2fly/v2ray-core/v5/transport/internet/tlsmirror/mirrorcrypto"
)
type clientConnState struct {
ctx context.Context
done context.CancelFunc
handler internet.ConnHandler
mirrorConn tlsmirror.InsertableTLSConn
localAddr net.Addr
remoteAddr net.Addr
activated bool
decryptor *mirrorcrypto.Decryptor
encryptor *mirrorcrypto.Encryptor
primaryKey []byte
readPipe chan []byte
readBuffer *bytes.Buffer
protocolVersion [2]byte
}
func (s *clientConnState) GetConnectionContext() context.Context {
return s.ctx
}
func (s *clientConnState) Read(b []byte) (n int, err error) {
if s.readBuffer != nil {
n, _ = s.readBuffer.Read(b)
if n > 0 {
return n, nil
}
s.readBuffer = nil
}
select {
case <-s.ctx.Done():
return 0, s.ctx.Err()
case data := <-s.readPipe:
s.readBuffer = bytes.NewBuffer(data)
n, err = s.readBuffer.Read(b)
if err != nil {
return 0, err
}
return n, nil
}
}
func (s *clientConnState) Write(b []byte) (n int, err error) {
err = s.WriteMessage(b)
if err != nil {
return 0, err
}
n = len(b)
return n, nil
}
func (s *clientConnState) Close() error {
s.done()
return nil
}
func (s *clientConnState) LocalAddr() gonet.Addr {
return s.remoteAddr
}
func (s *clientConnState) RemoteAddr() gonet.Addr {
return s.remoteAddr
}
func (s *clientConnState) SetDeadline(t time.Time) error {
return nil
}
func (s *clientConnState) SetReadDeadline(t time.Time) error {
return nil
}
func (s *clientConnState) SetWriteDeadline(t time.Time) error {
return nil
}
func (s *clientConnState) onC2SMessage(message *tlsmirror.TLSRecord) (drop bool, ok error) {
if message.RecordType == mirrorcommon.TLSRecord_RecordType_application_data {
if s.decryptor == nil {
clientRandom, serverRandom, err := s.mirrorConn.GetHandshakeRandom()
if err != nil {
newError("failed to get handshake random").Base(err).AtWarning().WriteToLog()
return false, nil
}
{
encryptionKey, nonceMask, err := mirrorcrypto.DeriveEncryptionKey(s.primaryKey, clientRandom, serverRandom, ":s2c")
if err != nil {
newError("failed to derive C2S encryption key").Base(err).AtWarning().WriteToLog()
return false, nil
}
s.decryptor = mirrorcrypto.NewDecryptor(encryptionKey, nonceMask)
}
{
encryptionKey, nonceMask, err := mirrorcrypto.DeriveEncryptionKey(s.primaryKey, clientRandom, serverRandom, ":c2s")
if err != nil {
newError("failed to derive S2C encryption key").Base(err).AtWarning().WriteToLog()
return false, nil
}
s.encryptor = mirrorcrypto.NewEncryptor(encryptionKey, nonceMask)
}
s.protocolVersion = message.LegacyProtocolVersion
if !s.activated {
s.handler(s)
s.activated = true
}
}
}
return false, ok
}
func (s *clientConnState) onS2CMessage(message *tlsmirror.TLSRecord) (drop bool, ok error) {
if message.RecordType == mirrorcommon.TLSRecord_RecordType_application_data {
if s.encryptor == nil {
return false, nil
}
buffer := make([]byte, 0, len(message.Fragment)-s.encryptor.NonceSize())
buffer, err := s.decryptor.Open(buffer, message.Fragment)
if err != nil {
return false, nil
}
s.readPipe <- buffer
return true, nil
}
return false, ok
}
func (s *clientConnState) WriteMessage(message []byte) error {
buffer := make([]byte, 0, len(message)+s.encryptor.NonceSize())
buffer, err := s.encryptor.Seal(buffer, message)
if err != nil {
return newError("failed to encrypt message").Base(err)
}
record := tlsmirror.TLSRecord{
RecordType: mirrorcommon.TLSRecord_RecordType_application_data,
LegacyProtocolVersion: s.protocolVersion,
RecordLength: uint16(len(buffer)),
Fragment: buffer,
}
return s.mirrorConn.InsertC2SMessage(&record)
}