github.com/metacubex/mihomo@v1.18.5/transport/vless/vision/conn.go (about)

     1  package vision
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/subtle"
     6  	gotls "crypto/tls"
     7  	"encoding/binary"
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  
    12  	"github.com/metacubex/mihomo/common/buf"
    13  	N "github.com/metacubex/mihomo/common/net"
    14  	"github.com/metacubex/mihomo/log"
    15  
    16  	"github.com/gofrs/uuid/v5"
    17  	utls "github.com/sagernet/utls"
    18  )
    19  
    20  var (
    21  	_ N.ExtendedConn = (*Conn)(nil)
    22  )
    23  
    24  type Conn struct {
    25  	net.Conn
    26  	N.ExtendedReader
    27  	N.ExtendedWriter
    28  	upstream net.Conn
    29  	userUUID *uuid.UUID
    30  
    31  	tlsConn  net.Conn
    32  	input    *bytes.Reader
    33  	rawInput *bytes.Buffer
    34  
    35  	needHandshake              bool
    36  	packetsToFilter            int
    37  	isTLS                      bool
    38  	isTLS12orAbove             bool
    39  	enableXTLS                 bool
    40  	cipher                     uint16
    41  	remainingServerHello       uint16
    42  	readRemainingContent       int
    43  	readRemainingPadding       int
    44  	readProcess                bool
    45  	readFilterUUID             bool
    46  	readLastCommand            byte
    47  	writeFilterApplicationData bool
    48  	writeDirect                bool
    49  }
    50  
    51  func (vc *Conn) Read(b []byte) (int, error) {
    52  	if vc.readProcess {
    53  		buffer := buf.With(b)
    54  		err := vc.ReadBuffer(buffer)
    55  		return buffer.Len(), err
    56  	}
    57  	return vc.ExtendedReader.Read(b)
    58  }
    59  
    60  func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
    61  	toRead := buffer.FreeBytes()
    62  	if vc.readRemainingContent > 0 {
    63  		if vc.readRemainingContent < buffer.FreeLen() {
    64  			toRead = toRead[:vc.readRemainingContent]
    65  		}
    66  		n, err := vc.ExtendedReader.Read(toRead)
    67  		buffer.Truncate(n)
    68  		vc.readRemainingContent -= n
    69  		vc.FilterTLS(toRead)
    70  		return err
    71  	}
    72  	if vc.readRemainingPadding > 0 {
    73  		_, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding))
    74  		if err != nil {
    75  			return err
    76  		}
    77  		vc.readRemainingPadding = 0
    78  	}
    79  	if vc.readProcess {
    80  		switch vc.readLastCommand {
    81  		case commandPaddingContinue:
    82  			//if vc.isTLS || vc.packetsToFilter > 0 {
    83  			headerUUIDLen := 0
    84  			if vc.readFilterUUID {
    85  				headerUUIDLen = uuid.Size
    86  			}
    87  			var header []byte
    88  			if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need {
    89  				header = make([]byte, need)
    90  			} else {
    91  				header = buffer.FreeBytes()[:need]
    92  			}
    93  			_, err := io.ReadFull(vc.ExtendedReader, header)
    94  			if err != nil {
    95  				return err
    96  			}
    97  			if vc.readFilterUUID {
    98  				vc.readFilterUUID = false
    99  				if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 {
   100  					err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
   101  						uuid.FromBytesOrNil(header[:uuid.Size]).String())
   102  					log.Errorln(err.Error())
   103  					return err
   104  				}
   105  				header = header[uuid.Size:]
   106  			}
   107  			vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[3:]))
   108  			vc.readRemainingContent = int(binary.BigEndian.Uint16(header[1:]))
   109  			vc.readLastCommand = header[0]
   110  			log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d",
   111  				vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding)
   112  			return vc.ReadBuffer(buffer)
   113  			//}
   114  		case commandPaddingEnd:
   115  			vc.readProcess = false
   116  			return vc.ReadBuffer(buffer)
   117  		case commandPaddingDirect:
   118  			needReturn := false
   119  			if vc.input != nil {
   120  				_, err := buffer.ReadFrom(vc.input)
   121  				if err != nil {
   122  					return err
   123  				}
   124  				if vc.input.Len() == 0 {
   125  					needReturn = true
   126  					vc.input = nil
   127  				} else { // buffer is full
   128  					return nil
   129  				}
   130  			}
   131  			if vc.rawInput != nil {
   132  				_, err := buffer.ReadFrom(vc.rawInput)
   133  				if err != nil {
   134  					return err
   135  				}
   136  				needReturn = true
   137  				if vc.rawInput.Len() == 0 {
   138  					vc.rawInput = nil
   139  				}
   140  			}
   141  			if vc.input == nil && vc.rawInput == nil {
   142  				vc.readProcess = false
   143  				vc.ExtendedReader = N.NewExtendedReader(vc.Conn)
   144  				log.Debugln("XTLS Vision direct read start")
   145  			}
   146  			if needReturn {
   147  				return nil
   148  			}
   149  		default:
   150  			err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand)
   151  			log.Debugln(err.Error())
   152  			return err
   153  		}
   154  	}
   155  	return vc.ExtendedReader.ReadBuffer(buffer)
   156  }
   157  
   158  func (vc *Conn) Write(p []byte) (int, error) {
   159  	if vc.writeFilterApplicationData {
   160  		return N.WriteBuffer(vc, buf.As(p))
   161  	}
   162  	return vc.ExtendedWriter.Write(p)
   163  }
   164  
   165  func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
   166  	if vc.needHandshake {
   167  		vc.needHandshake = false
   168  		if buffer.IsEmpty() {
   169  			ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, false)
   170  		} else {
   171  			vc.FilterTLS(buffer.Bytes())
   172  			ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS)
   173  		}
   174  		err = vc.ExtendedWriter.WriteBuffer(buffer)
   175  		if err != nil {
   176  			buffer.Release()
   177  			return err
   178  		}
   179  		switch underlying := vc.tlsConn.(type) {
   180  		case *gotls.Conn:
   181  			if underlying.ConnectionState().Version != gotls.VersionTLS13 {
   182  				buffer.Release()
   183  				return ErrNotTLS13
   184  			}
   185  		case *utls.UConn:
   186  			if underlying.ConnectionState().Version != utls.VersionTLS13 {
   187  				buffer.Release()
   188  				return ErrNotTLS13
   189  			}
   190  		}
   191  		vc.tlsConn = nil
   192  		return nil
   193  	}
   194  
   195  	if vc.writeFilterApplicationData {
   196  		buffer2 := ReshapeBuffer(buffer)
   197  		defer buffer2.Release()
   198  		vc.FilterTLS(buffer.Bytes())
   199  		command := commandPaddingContinue
   200  		if !vc.isTLS {
   201  			command = commandPaddingEnd
   202  
   203  			// disable XTLS
   204  			//vc.readProcess = false
   205  			vc.writeFilterApplicationData = false
   206  			vc.packetsToFilter = 0
   207  		} else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
   208  			command = commandPaddingEnd
   209  			if vc.enableXTLS {
   210  				command = commandPaddingDirect
   211  				vc.writeDirect = true
   212  			}
   213  			vc.writeFilterApplicationData = false
   214  		}
   215  		ApplyPadding(buffer, command, nil, vc.isTLS)
   216  		err = vc.ExtendedWriter.WriteBuffer(buffer)
   217  		if err != nil {
   218  			return err
   219  		}
   220  		if vc.writeDirect {
   221  			vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
   222  			log.Debugln("XTLS Vision direct write start")
   223  			//time.Sleep(5 * time.Millisecond)
   224  		}
   225  		if buffer2 != nil {
   226  			if vc.writeDirect || !vc.isTLS {
   227  				return vc.ExtendedWriter.WriteBuffer(buffer2)
   228  			}
   229  			vc.FilterTLS(buffer2.Bytes())
   230  			command = commandPaddingContinue
   231  			if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
   232  				command = commandPaddingEnd
   233  				if vc.enableXTLS {
   234  					command = commandPaddingDirect
   235  					vc.writeDirect = true
   236  				}
   237  				vc.writeFilterApplicationData = false
   238  			}
   239  			ApplyPadding(buffer2, command, nil, vc.isTLS)
   240  			err = vc.ExtendedWriter.WriteBuffer(buffer2)
   241  			if vc.writeDirect {
   242  				vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
   243  				log.Debugln("XTLS Vision direct write start")
   244  				//time.Sleep(10 * time.Millisecond)
   245  			}
   246  		}
   247  		return err
   248  	}
   249  	/*if vc.writeDirect {
   250  		log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len())
   251  	}*/
   252  	return vc.ExtendedWriter.WriteBuffer(buffer)
   253  }
   254  
   255  func (vc *Conn) FrontHeadroom() int {
   256  	if vc.readFilterUUID {
   257  		return PaddingHeaderLen
   258  	}
   259  	return PaddingHeaderLen - uuid.Size
   260  }
   261  
   262  func (vc *Conn) RearHeadroom() int {
   263  	return 500 + 900
   264  }
   265  
   266  func (vc *Conn) NeedHandshake() bool {
   267  	return vc.needHandshake
   268  }
   269  
   270  func (vc *Conn) Upstream() any {
   271  	if vc.writeDirect ||
   272  		vc.readLastCommand == commandPaddingDirect {
   273  		return vc.Conn
   274  	}
   275  	return vc.upstream
   276  }
   277  
   278  func (vc *Conn) ReaderPossiblyReplaceable() bool {
   279  	return vc.readProcess
   280  }
   281  
   282  func (vc *Conn) ReaderReplaceable() bool {
   283  	if !vc.readProcess &&
   284  		vc.readLastCommand == commandPaddingDirect {
   285  		return true
   286  	}
   287  	return false
   288  }
   289  
   290  func (vc *Conn) WriterPossiblyReplaceable() bool {
   291  	return vc.writeFilterApplicationData
   292  }
   293  
   294  func (vc *Conn) WriterReplaceable() bool {
   295  	if vc.writeDirect {
   296  		return true
   297  	}
   298  	return false
   299  }