Fix: trojan/vmess grpc broken
This commit is contained in:
parent
cc96187f58
commit
3d5a0d9f73
1 changed files with 57 additions and 35 deletions
|
@ -4,6 +4,7 @@
|
||||||
package gun
|
package gun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -15,14 +16,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidLength = errors.New("invalid length")
|
ErrInvalidLength = errors.New("invalid length")
|
||||||
|
ErrSmallBuffer = errors.New("buffer too small")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -42,9 +42,8 @@ type Conn struct {
|
||||||
once sync.Once
|
once sync.Once
|
||||||
close *atomic.Bool
|
close *atomic.Bool
|
||||||
err error
|
err error
|
||||||
|
remain int
|
||||||
buf []byte
|
br *bufio.Reader
|
||||||
offset int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -73,53 +72,76 @@ func (g *Conn) Read(b []byte) (n int, err error) {
|
||||||
return 0, g.err
|
return 0, g.err
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.buf != nil {
|
if g.br != nil {
|
||||||
n = copy(b, g.buf[g.offset:])
|
remain := g.br.Buffered()
|
||||||
g.offset += n
|
if len(b) < remain {
|
||||||
if g.offset == len(g.buf) {
|
remain = len(b)
|
||||||
g.offset = 0
|
|
||||||
g.buf = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n, err = g.br.Read(b[:remain])
|
||||||
|
if g.br.Buffered() == 0 {
|
||||||
|
g.br = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if g.remain != 0 {
|
||||||
|
size := g.remain
|
||||||
|
if len(b) < size {
|
||||||
|
size = len(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = g.response.Body.Read(b[:size])
|
||||||
|
g.remain -= n
|
||||||
return
|
return
|
||||||
} else if g.response == nil {
|
} else if g.response == nil {
|
||||||
return 0, net.ErrClosed
|
return 0, net.ErrClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, 5)
|
// 0x00 grpclength(uint32) 0x0A uleb128 payload
|
||||||
|
buf := make([]byte, 6)
|
||||||
_, err = io.ReadFull(g.response.Body, buf)
|
_, err = io.ReadFull(g.response.Body, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
grpcPayloadLen := binary.BigEndian.Uint32(buf[1:])
|
|
||||||
if grpcPayloadLen > pool.RelayBufferSize {
|
|
||||||
return 0, ErrInvalidLength
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = pool.Get(int(grpcPayloadLen))
|
br := bufio.NewReaderSize(g.response.Body, 16)
|
||||||
_, err = io.ReadFull(g.response.Body, buf)
|
protobufPayloadLen, err := binary.ReadUvarint(br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pool.Put(buf)
|
|
||||||
return 0, io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
protobufPayloadLen, protobufLengthLen := decodeUleb128(buf[1:])
|
|
||||||
if protobufLengthLen == 0 {
|
|
||||||
pool.Put(buf)
|
|
||||||
return 0, ErrInvalidLength
|
|
||||||
}
|
|
||||||
if grpcPayloadLen != uint32(protobufPayloadLen)+uint32(protobufLengthLen)+1 {
|
|
||||||
pool.Put(buf)
|
|
||||||
return 0, ErrInvalidLength
|
return 0, ErrInvalidLength
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b) >= int(grpcPayloadLen)-1-int(protobufLengthLen) {
|
bufferedSize := br.Buffered()
|
||||||
n = copy(b, buf[1+protobufLengthLen:])
|
if len(b) < bufferedSize {
|
||||||
pool.Put(buf)
|
n, err = br.Read(b)
|
||||||
|
g.br = br
|
||||||
|
g.remain = int(protobufPayloadLen) - n - g.br.Buffered()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n = copy(b, buf[1+protobufLengthLen:])
|
|
||||||
g.offset = n + 1 + int(protobufLengthLen)
|
_, err = br.Read(b[:bufferedSize])
|
||||||
g.buf = buf
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := int(protobufPayloadLen)
|
||||||
|
if len(b) < int(protobufPayloadLen) {
|
||||||
|
offset = len(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset == bufferedSize {
|
||||||
|
return bufferedSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = io.ReadFull(g.response.Body, b[bufferedSize:offset])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remain := int(protobufPayloadLen) - offset
|
||||||
|
if remain > 0 {
|
||||||
|
g.remain = remain
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Conn) Write(b []byte) (n int, err error) {
|
func (g *Conn) Write(b []byte) (n int, err error) {
|
||||||
|
|
Loading…
Reference in a new issue