Files
v2ray_simple/tlsLayer/shadow.go
e1732a364fed e841d258b1 修订shadowTls代码;取消shadowTls的readv, 添加writev
经过思考,readv应该不会有什么性能提升,因为需要解析数据并重新分包;
通过实现writev,可以将从tcp流readv得到的数据写入,配合readv得到性能提升
2022-12-27 09:09:51 +08:00

304 lines
6.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package tlsLayer
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
"go.uber.org/zap"
)
//https://www.ihcblog.com/a-better-tls-obfs-proxy/
//https://github.com/ihciah/shadow-tls/blob/master/docs/protocol-cn.md
func getShadowTlsPasswordFromExtra(extra map[string]any) string {
if len(extra) > 0 {
if thing := extra["shadowtls_password"]; thing != nil {
if str, ok := thing.(string); ok {
return str
}
}
}
return ""
}
// 转发并判断tls1握手结束后直接返回
func shadowTls1(servername string, clientConn net.Conn) (err error) {
var fakeConn net.Conn
fakeConn, err = net.Dial("tcp", servername+":443")
if err != nil {
if ce := utils.CanLogErr("Failed shadowTls server fake dial server "); ce != nil {
ce.Write(zap.Error(err))
}
return
}
if ce := utils.CanLogDebug("shadowTls ready to fake "); ce != nil {
ce.Write()
}
var e1, e2 error
finish1 := make(chan struct{})
go func() {
e1 = CopyTls12Handshake(true, fakeConn, clientConn)
if ce := utils.CanLogDebug("shadowTls copy client end"); ce != nil {
ce.Write(zap.Error(e1))
}
close(finish1)
}()
e2 = CopyTls12Handshake(false, clientConn, fakeConn)
if ce := utils.CanLogDebug("shadowTls copy server end"); ce != nil {
ce.Write(
zap.Error(e2),
)
}
<-finish1
if e1 != nil || e2 != nil {
e := utils.Errs{List: []utils.ErrsItem{
{Index: 1, E: e1},
{Index: 2, E: e2},
}}
return e
}
if ce := utils.CanLogDebug("shadowTls fake ok "); ce != nil {
ce.Write()
}
return
}
// 握手成功后返回 *FakeAppDataConn
func shadowTls2(servername string, clientConn net.Conn, password string) (result net.Conn, err error) {
var fakeConn net.Conn
fakeConn, err = net.Dial("tcp", servername+":443")
if err != nil {
if ce := utils.CanLogErr("Failed shadowTls2 server fake dial server "); ce != nil {
ce.Write(zap.Error(err))
}
return
}
if ce := utils.CanLogDebug("shadowTls2 ready to fake "); ce != nil {
ce.Write()
}
hashW := utils.NewHashWriter(clientConn, []byte(password))
go io.Copy(hashW, fakeConn)
var firstPayload *bytes.Buffer
firstPayload, err = shadowCopyHandshakeClientToFake(fakeConn, clientConn, hashW)
if err == nil {
fakeConn.Close()
if ce := utils.CanLogDebug("shadowTls2 fake ok!"); ce != nil {
ce.Write()
}
realconn := &FakeAppDataConn{
Conn: clientConn,
OptionalReader: firstPayload,
OptionalReaderRemainLen: firstPayload.Len(),
}
return realconn, nil
} else if err == utils.ErrFailed {
if ce := utils.CanLogWarn("shadowTls2 fake failed!"); ce != nil {
ce.Write()
}
hashW.StopHashing()
go io.Copy(fakeConn, clientConn)
return nil, errors.New("not real shadowTlsClient, fallback")
}
return nil, err
}
// 根据shadowTls v2的方式它一定会返回一个 firstPayload
func shadowCopyHandshakeClientToFake(fakeConn, clientConn net.Conn, hashW *utils.HashWriter) (*bytes.Buffer, error) {
var header [5]byte
step := 0
var applicationDataCount int
var firstPayload *bytes.Buffer
for {
if ce := utils.CanLogDebug("shadowTls2 copy "); ce != nil {
ce.Write(zap.Int("step", step))
}
netLayer.SetCommonReadTimeout(clientConn)
_, err := io.ReadFull(clientConn, header[:])
netLayer.PersistConn(clientConn)
if err != nil {
if firstPayload != nil {
utils.PutBuf(firstPayload)
}
return nil, utils.ErrInErr{ErrDetail: err, ErrDesc: "shadowTls2, io.ReadFull err"}
}
contentType := header[0]
length := binary.BigEndian.Uint16(header[3:])
if ce := utils.CanLogDebug("shadowTls2 copy "); ce != nil {
ce.Write(zap.Int("step", step),
zap.Uint8("contentType", contentType),
zap.Uint16("length", length),
)
}
if contentType == 23 {
if firstPayload == nil {
firstPayload = utils.GetBuf()
}
netLayer.SetCommonReadTimeout(clientConn)
_, err = io.Copy(firstPayload, io.LimitReader(clientConn, int64(length)))
netLayer.PersistRead(clientConn)
if err != nil {
utils.PutBuf(firstPayload)
return nil, utils.ErrInErr{ErrDetail: err, ErrDesc: "shadowTls2, copy err1"}
}
if hashW.Written() && length >= 8 {
checksum := hashW.Sum()
first8 := firstPayload.Bytes()[:8]
if ce := utils.CanLogDebug("shadowTls2 check "); ce != nil {
ce.Write(zap.Int("step", step),
zap.String("checksum", fmt.Sprintf("%v", checksum)),
zap.String("real8", fmt.Sprintf("%v", first8)),
)
}
if bytes.Equal(first8, checksum) {
firstPayload.Next(8)
return firstPayload, nil
}
}
netLayer.SetCommonWriteTimeout(fakeConn)
_, err = io.Copy(fakeConn, io.MultiReader(bytes.NewReader(header[:]), firstPayload))
netLayer.PersistWrite(fakeConn)
if err != nil {
utils.PutBuf(firstPayload)
return nil, utils.ErrInErr{ErrDetail: err, ErrDesc: "shadowTls2, copy err2"}
}
firstPayload.Reset()
applicationDataCount++
} else {
netLayer.SetCommonReadTimeout(clientConn)
netLayer.SetCommonWriteTimeout(fakeConn)
_, err = io.Copy(fakeConn, io.MultiReader(bytes.NewReader(header[:]), io.LimitReader(clientConn, int64(length))))
netLayer.PersistRead(clientConn)
netLayer.PersistWrite(fakeConn)
if err != nil {
if firstPayload != nil {
utils.PutBuf(firstPayload)
}
return nil, utils.ErrInErr{ErrDetail: err, ErrDesc: "shadowTls2, copy err3"}
}
}
const maxAppDataCount = 3
if applicationDataCount > maxAppDataCount {
utils.PutBuf(firstPayload)
return nil, utils.ErrFailed
}
step++
if step > 8 {
if firstPayload != nil {
utils.PutBuf(firstPayload)
}
return nil, errors.New("shadowTls2 copy loop > 8, maybe under attack")
}
}
}
// 第一次写时写入一个hash其余直接使用 FakeAppDataConn. 实现 utils.MultiWriter
type shadowClientConn struct {
*FakeAppDataConn
sum []byte
}
func (c *shadowClientConn) Write(p []byte) (n int, err error) {
if c.sum != nil {
sum := c.sum
c.sum = nil
buf := utils.GetBuf()
if ce := utils.CanLogDebug("write hash"); ce != nil {
ce.Write(zap.Any("sum", fmt.Sprintf("%v", sum)))
}
buf.Write(sum)
buf.Write(p)
_, err = c.FakeAppDataConn.Write(buf.Bytes())
utils.PutBuf(buf)
if err == nil {
n = len(p)
}
return
}
return c.FakeAppDataConn.Write(p)
}
func (c *shadowClientConn) WriteBuffers(bss [][]byte) (int64, error) {
if c.sum != nil {
sum := c.sum
c.sum = nil
result, dup := utils.MergeBuffersWithPrefix(sum, bss)
allDataLen := len(result) - len(sum)
_, err := c.FakeAppDataConn.Write(result)
if dup {
utils.PutPacket(result)
}
if err != nil {
return 0, err
}
return int64(allDataLen), nil
}
return c.FakeAppDataConn.WriteBuffers(bss)
}