mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
ssr: a little modification to use buffer pool
This commit is contained in:
parent
b3940e4b77
commit
7c92aca331
7
go.mod
7
go.mod
@ -4,6 +4,9 @@ go 1.15
|
||||
|
||||
require (
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
|
||||
github.com/dgryski/go-camellia v0.0.0-20191119043421-69a8a13fb23d
|
||||
github.com/dgryski/go-idea v0.0.0-20170306091226-d2fb45a411fb
|
||||
github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152
|
||||
github.com/insomniacslk/dhcp v0.0.0-20200922210017-67c425063dca
|
||||
github.com/mzz2017/shadowsocksR v1.0.0
|
||||
github.com/nadoo/conflag v0.2.3
|
||||
@ -11,8 +14,8 @@ require (
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||
golang.org/x/net v0.0.0-20201026091529-146b70c837a4 // indirect
|
||||
golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1 // indirect
|
||||
golang.org/x/net v0.0.0-20201027133719-8eef5233e2a1 // indirect
|
||||
golang.org/x/sys v0.0.0-20201027140754-0fcbb8f4928c // indirect
|
||||
golang.org/x/tools v0.0.0-20201026223136-e84cfc6dd5ca // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
)
|
||||
|
8
go.sum
8
go.sum
@ -129,8 +129,8 @@ golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs=
|
||||
golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201027133719-8eef5233e2a1 h1:IEhJ99VWSYpHIxjlbu3DQyHegGPnQYAv0IaCX9KHyG0=
|
||||
golang.org/x/net v0.0.0-20201027133719-8eef5233e2a1/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -154,8 +154,8 @@ golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1 h1:/DtoiOYKoQCcIFXQjz07RnWNPRCbqmSXSpgEzhC9ZHM=
|
||||
golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201027140754-0fcbb8f4928c h1:2+jF2APAgFgXJnYOQGDGGiRvvEo6OhqZGQf46n9xgEw=
|
||||
golang.org/x/sys v0.0.0-20201027140754-0fcbb8f4928c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
342
proxy/ssr/internal/cipher.go
Normal file
342
proxy/ssr/internal/cipher.go
Normal file
@ -0,0 +1,342 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/md5"
|
||||
"crypto/rc4"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/rand"
|
||||
|
||||
"github.com/aead/chacha20"
|
||||
"github.com/dgryski/go-camellia"
|
||||
"github.com/dgryski/go-idea"
|
||||
"github.com/dgryski/go-rc2"
|
||||
"github.com/mzz2017/shadowsocksR/tools"
|
||||
"golang.org/x/crypto/blowfish"
|
||||
"golang.org/x/crypto/cast5"
|
||||
"golang.org/x/crypto/salsa20/salsa"
|
||||
|
||||
"github.com/nadoo/glider/pool"
|
||||
)
|
||||
|
||||
var errEmptyPassword = errors.New("empty key")
|
||||
|
||||
type DecOrEnc int
|
||||
|
||||
const (
|
||||
Decrypt DecOrEnc = iota
|
||||
Encrypt
|
||||
)
|
||||
|
||||
func newCTRStream(block cipher.Block, err error, key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cipher.NewCTR(block, iv), nil
|
||||
}
|
||||
|
||||
func newAESCTRStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
return newCTRStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newOFBStream(block cipher.Block, err error, key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cipher.NewCTR(block, iv), nil
|
||||
}
|
||||
|
||||
func newAESOFBStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
return newOFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newCFBStream(block cipher.Block, err error, key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if doe == Encrypt {
|
||||
return cipher.NewCFBEncrypter(block, iv), nil
|
||||
} else {
|
||||
return cipher.NewCFBDecrypter(block, iv), nil
|
||||
}
|
||||
}
|
||||
|
||||
func newAESCFBStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newDESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newBlowFishStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := blowfish.NewCipher(key)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newCast5Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := cast5.NewCipher(key)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newRC4MD5Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
h := md5.New()
|
||||
h.Write(key)
|
||||
h.Write(iv)
|
||||
rc4key := h.Sum(nil)
|
||||
|
||||
return rc4.NewCipher(rc4key)
|
||||
}
|
||||
|
||||
func newChaCha20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
return chacha20.NewCipher(iv, key)
|
||||
}
|
||||
|
||||
func newChacha20IETFStream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
return chacha20.NewCipher(iv, key)
|
||||
}
|
||||
|
||||
type salsaStreamCipher struct {
|
||||
nonce [8]byte
|
||||
key [32]byte
|
||||
counter int
|
||||
}
|
||||
|
||||
func (c *salsaStreamCipher) XORKeyStream(dst, src []byte) {
|
||||
var buf []byte
|
||||
padLen := c.counter % 64
|
||||
dataSize := len(src) + padLen
|
||||
if cap(dst) >= dataSize {
|
||||
buf = dst[:dataSize]
|
||||
// nadoo: comment out codes here to use pool buffer
|
||||
// modify start -->
|
||||
// } else if leakybuf.GlobalLeakyBufSize >= dataSize {
|
||||
// buf = leakybuf.GlobalLeakyBuf.Get()
|
||||
// defer leakybuf.GlobalLeakyBuf.Put(buf)
|
||||
// buf = buf[:dataSize]
|
||||
// } else {
|
||||
// buf = make([]byte, dataSize)
|
||||
// }
|
||||
} else {
|
||||
buf = pool.GetBuffer(dataSize)
|
||||
defer pool.PutBuffer(buf)
|
||||
}
|
||||
// --> modify end
|
||||
|
||||
var subNonce [16]byte
|
||||
copy(subNonce[:], c.nonce[:])
|
||||
binary.LittleEndian.PutUint64(subNonce[len(c.nonce):], uint64(c.counter/64))
|
||||
|
||||
// It's difficult to avoid data copy here. src or dst maybe slice from
|
||||
// Conn.Read/Write, which can't have padding.
|
||||
copy(buf[padLen:], src[:])
|
||||
salsa.XORKeyStream(buf, buf, &subNonce, &c.key)
|
||||
copy(dst, buf[padLen:])
|
||||
|
||||
c.counter += len(src)
|
||||
}
|
||||
|
||||
func newSalsa20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||
var c salsaStreamCipher
|
||||
copy(c.nonce[:], iv[:8])
|
||||
copy(c.key[:], key[:32])
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func newCamelliaStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := camellia.New(key)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newIdeaStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := idea.NewCipher(key)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newRC2Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
block, err := rc2.New(key, 16)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
func newRC4Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
return rc4.NewCipher(key)
|
||||
}
|
||||
|
||||
func newSeedStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
// TODO: SEED block cipher implementation is required
|
||||
block, err := rc2.New(key, 16)
|
||||
return newCFBStream(block, err, key, iv, doe)
|
||||
}
|
||||
|
||||
type NoneStream struct {
|
||||
cipher.Stream
|
||||
}
|
||||
|
||||
func (*NoneStream) XORKeyStream(dst, src []byte) {
|
||||
copy(dst, src)
|
||||
}
|
||||
|
||||
func newNoneStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||
return new(NoneStream), nil
|
||||
}
|
||||
|
||||
type cipherInfo struct {
|
||||
keyLen int
|
||||
ivLen int
|
||||
newStream func(key, iv []byte, doe DecOrEnc) (cipher.Stream, error)
|
||||
}
|
||||
|
||||
var streamCipherMethod = map[string]*cipherInfo{
|
||||
"aes-128-cfb": {16, 16, newAESCFBStream},
|
||||
"aes-192-cfb": {24, 16, newAESCFBStream},
|
||||
"aes-256-cfb": {32, 16, newAESCFBStream},
|
||||
"aes-128-ctr": {16, 16, newAESCTRStream},
|
||||
"aes-192-ctr": {24, 16, newAESCTRStream},
|
||||
"aes-256-ctr": {32, 16, newAESCTRStream},
|
||||
"aes-128-ofb": {16, 16, newAESOFBStream},
|
||||
"aes-192-ofb": {24, 16, newAESOFBStream},
|
||||
"aes-256-ofb": {32, 16, newAESOFBStream},
|
||||
"des-cfb": {8, 8, newDESStream},
|
||||
"bf-cfb": {16, 8, newBlowFishStream},
|
||||
"cast5-cfb": {16, 8, newCast5Stream},
|
||||
"rc4-md5": {16, 16, newRC4MD5Stream},
|
||||
"rc4-md5-6": {16, 6, newRC4MD5Stream},
|
||||
"chacha20": {32, 8, newChaCha20Stream},
|
||||
"chacha20-ietf": {32, 12, newChacha20IETFStream},
|
||||
"salsa20": {32, 8, newSalsa20Stream},
|
||||
"camellia-128-cfb": {16, 16, newCamelliaStream},
|
||||
"camellia-192-cfb": {24, 16, newCamelliaStream},
|
||||
"camellia-256-cfb": {32, 16, newCamelliaStream},
|
||||
"idea-cfb": {16, 8, newIdeaStream},
|
||||
"rc2-cfb": {16, 8, newRC2Stream},
|
||||
"seed-cfb": {16, 8, newSeedStream},
|
||||
"rc4": {16, 0, newRC4Stream},
|
||||
"none": {16, 0, newNoneStream},
|
||||
}
|
||||
|
||||
func CheckCipherMethod(method string) error {
|
||||
if method == "" {
|
||||
method = "rc4-md5"
|
||||
}
|
||||
_, ok := streamCipherMethod[method]
|
||||
if !ok {
|
||||
return errors.New("Unsupported encryption method: " + method)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type StreamCipher struct {
|
||||
enc cipher.Stream
|
||||
dec cipher.Stream
|
||||
key []byte
|
||||
info *cipherInfo
|
||||
iv []byte
|
||||
}
|
||||
|
||||
// NewStreamCipher creates a cipher that can be used in Dial() etc.
|
||||
// Use cipher.Copy() to create a new cipher with the same method and password
|
||||
// to avoid the cost of repeated cipher initialization.
|
||||
func NewStreamCipher(method, password string) (c *StreamCipher, err error) {
|
||||
if password == "" {
|
||||
return nil, errEmptyPassword
|
||||
}
|
||||
if method == "" {
|
||||
method = "rc4-md5"
|
||||
}
|
||||
mi, ok := streamCipherMethod[method]
|
||||
if !ok {
|
||||
return nil, errors.New("Unsupported encryption method: " + method)
|
||||
}
|
||||
|
||||
key := tools.EVPBytesToKey(password, mi.keyLen)
|
||||
|
||||
c = &StreamCipher{key: key, info: mi}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *StreamCipher) EncryptInited() bool {
|
||||
return c.enc != nil
|
||||
}
|
||||
|
||||
func (c *StreamCipher) DecryptInited() bool {
|
||||
return c.dec != nil
|
||||
}
|
||||
|
||||
// Initializes the block cipher with CFB mode, returns IV.
|
||||
func (c *StreamCipher) InitEncrypt() (iv []byte, err error) {
|
||||
if c.iv == nil {
|
||||
iv = make([]byte, c.info.ivLen)
|
||||
rand.Read(iv)
|
||||
c.iv = iv
|
||||
} else {
|
||||
iv = c.iv
|
||||
}
|
||||
c.enc, err = c.info.newStream(c.key, iv, Encrypt)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *StreamCipher) InitDecrypt(iv []byte) (err error) {
|
||||
c.dec, err = c.info.newStream(c.key, iv, Decrypt)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *StreamCipher) Encrypt(dst, src []byte) {
|
||||
c.enc.XORKeyStream(dst, src)
|
||||
}
|
||||
|
||||
func (c *StreamCipher) Decrypt(dst, src []byte) {
|
||||
c.dec.XORKeyStream(dst, src)
|
||||
}
|
||||
|
||||
// Copy creates a new cipher at it's initial state.
|
||||
func (c *StreamCipher) Copy() *StreamCipher {
|
||||
// This optimization maybe not necessary. But without this function, we
|
||||
// need to maintain a table cache for newTableCipher and use lock to
|
||||
// protect concurrent access to that cache.
|
||||
|
||||
// AES and DES ciphers does not return specific types, so it's difficult
|
||||
// to create copy. But their initialization time is less than 4000ns on my
|
||||
// 2.26 GHz Intel Core 2 Duo processor. So no need to worry.
|
||||
|
||||
// Currently, blow-fish and cast5 initialization cost is an order of
|
||||
// magnitude slower than other ciphers. (I'm not sure whether this is
|
||||
// because the current implementation is not highly optimized, or this is
|
||||
// the nature of the algorithm.)
|
||||
|
||||
nc := *c
|
||||
nc.enc = nil
|
||||
nc.dec = nil
|
||||
return &nc
|
||||
}
|
||||
|
||||
func (c *StreamCipher) Key() []byte {
|
||||
return c.key
|
||||
}
|
||||
|
||||
func (c *StreamCipher) IV() []byte {
|
||||
return c.iv
|
||||
}
|
||||
|
||||
func (c *StreamCipher) SetIV(iv []byte) {
|
||||
c.iv = iv
|
||||
}
|
||||
|
||||
func (c *StreamCipher) SetKey(key []byte) {
|
||||
c.key = key
|
||||
}
|
||||
|
||||
func (c *StreamCipher) InfoIVLen() int {
|
||||
return c.info.ivLen
|
||||
}
|
||||
|
||||
func (c *StreamCipher) InfoKeyLen() int {
|
||||
return c.info.keyLen
|
||||
}
|
242
proxy/ssr/internal/client.go
Normal file
242
proxy/ssr/internal/client.go
Normal file
@ -0,0 +1,242 @@
|
||||
// source from https://github.com/v2rayA/shadowsocksR
|
||||
// just copy here to use the builtin buffer pool.
|
||||
// as this protocol hasn't been maintained since 2017, it doesn't deserve our research to rewrite it.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/mzz2017/shadowsocksR/obfs"
|
||||
"github.com/mzz2017/shadowsocksR/protocol"
|
||||
|
||||
"github.com/nadoo/glider/pool"
|
||||
)
|
||||
|
||||
const bufSize = 16 << 10
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// SSTCPConn the struct that override the net.Conn methods
|
||||
type SSTCPConn struct {
|
||||
net.Conn
|
||||
*StreamCipher
|
||||
IObfs obfs.IObfs
|
||||
IProtocol protocol.IProtocol
|
||||
readBuf []byte
|
||||
underPostdecryptBuf *bytes.Buffer
|
||||
readIndex uint64
|
||||
decryptedBuf *bytes.Buffer
|
||||
writeBuf []byte
|
||||
lastReadError error
|
||||
}
|
||||
|
||||
func NewSSTCPConn(c net.Conn, cipher *StreamCipher) *SSTCPConn {
|
||||
return &SSTCPConn{
|
||||
Conn: c,
|
||||
StreamCipher: cipher,
|
||||
readBuf: pool.GetBuffer(bufSize),
|
||||
decryptedBuf: pool.GetWriteBuffer(),
|
||||
underPostdecryptBuf: pool.GetWriteBuffer(),
|
||||
writeBuf: pool.GetBuffer(bufSize),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) Close() error {
|
||||
pool.PutBuffer(c.readBuf)
|
||||
pool.PutWriteBuffer(c.decryptedBuf)
|
||||
pool.PutWriteBuffer(c.underPostdecryptBuf)
|
||||
pool.PutBuffer(c.writeBuf)
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) GetIv() (iv []byte) {
|
||||
iv = make([]byte, len(c.IV()))
|
||||
copy(iv, c.IV())
|
||||
return
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) GetKey() (key []byte) {
|
||||
key = make([]byte, len(c.Key()))
|
||||
copy(key, c.Key())
|
||||
return
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) initEncryptor(b []byte) (iv []byte, err error) {
|
||||
if !c.EncryptInited() {
|
||||
iv, err = c.InitEncrypt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
overhead := c.IObfs.GetOverhead() + c.IProtocol.GetOverhead()
|
||||
// should initialize obfs/protocol now, because iv is ready now
|
||||
obfsServerInfo := c.IObfs.GetServerInfo()
|
||||
obfsServerInfo.SetHeadLen(b, 30)
|
||||
obfsServerInfo.IV, obfsServerInfo.IVLen = c.IV(), c.InfoIVLen()
|
||||
obfsServerInfo.Key, obfsServerInfo.KeyLen = c.Key(), c.InfoKeyLen()
|
||||
obfsServerInfo.Overhead = overhead
|
||||
c.IObfs.SetServerInfo(obfsServerInfo)
|
||||
|
||||
protocolServerInfo := c.IProtocol.GetServerInfo()
|
||||
protocolServerInfo.SetHeadLen(b, 30)
|
||||
protocolServerInfo.IV, protocolServerInfo.IVLen = c.IV(), c.InfoIVLen()
|
||||
protocolServerInfo.Key, protocolServerInfo.KeyLen = c.Key(), c.InfoKeyLen()
|
||||
protocolServerInfo.Overhead = overhead
|
||||
c.IProtocol.SetServerInfo(protocolServerInfo)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) Read(b []byte) (n int, err error) {
|
||||
for {
|
||||
n, err = c.doRead(b)
|
||||
if b == nil || n != 0 || err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) doRead(b []byte) (n int, err error) {
|
||||
if c.decryptedBuf.Len() > 0 {
|
||||
return c.decryptedBuf.Read(b)
|
||||
}
|
||||
n, err = c.Conn.Read(c.readBuf)
|
||||
if n == 0 || err != nil {
|
||||
return n, err
|
||||
}
|
||||
decodedData, needSendBack, err := c.IObfs.Decode(c.readBuf[:n])
|
||||
if err != nil {
|
||||
//log.Println(c.Conn.LocalAddr().String(), c.IObfs.(*obfs.tls12TicketAuth).handshakeStatus, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
//do send back
|
||||
if needSendBack {
|
||||
c.Write(nil)
|
||||
//log.Println("sendBack")
|
||||
return 0, nil
|
||||
}
|
||||
//log.Println(len(decodedData), needSendBack, err, n)
|
||||
if len(decodedData) == 0 {
|
||||
//log.Println(string(c.readBuf[:200]))
|
||||
}
|
||||
decodedDataLen := len(decodedData)
|
||||
if decodedDataLen == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if !c.DecryptInited() {
|
||||
|
||||
if len(decodedData) < c.InfoIVLen() {
|
||||
return 0, errors.New(fmt.Sprintf("invalid ivLen:%v, actual length:%v", c.InfoIVLen(), len(decodedData)))
|
||||
}
|
||||
iv := decodedData[0:c.InfoIVLen()]
|
||||
if err = c.InitDecrypt(iv); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(c.IV()) == 0 {
|
||||
c.SetIV(iv)
|
||||
}
|
||||
decodedDataLen -= c.InfoIVLen()
|
||||
if decodedDataLen <= 0 {
|
||||
return 0, nil
|
||||
}
|
||||
decodedData = decodedData[c.InfoIVLen():]
|
||||
}
|
||||
|
||||
// nadoo: comment out codes here to use pool buffer
|
||||
// modify start -->
|
||||
// buf := make([]byte, decodedDataLen)
|
||||
// // decrypt decodedData and save it to buf
|
||||
// c.Decrypt(buf, decodedData)
|
||||
// // append buf to c.underPostdecryptBuf
|
||||
// c.underPostdecryptBuf.Write(buf)
|
||||
// // and read it to buf immediately
|
||||
// buf = c.underPostdecryptBuf.Bytes()
|
||||
|
||||
buf1 := pool.GetBuffer(decodedDataLen)
|
||||
defer pool.PutBuffer(buf1)
|
||||
|
||||
c.Decrypt(buf1, decodedData)
|
||||
c.underPostdecryptBuf.Write(buf1)
|
||||
buf := c.underPostdecryptBuf.Bytes()
|
||||
// --> modify end
|
||||
|
||||
postDecryptedData, length, err := c.IProtocol.PostDecrypt(buf)
|
||||
if err != nil {
|
||||
c.underPostdecryptBuf.Reset()
|
||||
//log.Println(string(decodebytes))
|
||||
//log.Println("err", err)
|
||||
return 0, err
|
||||
}
|
||||
if length == 0 {
|
||||
// not enough to postDecrypt
|
||||
return 0, nil
|
||||
} else {
|
||||
c.underPostdecryptBuf.Next(length)
|
||||
}
|
||||
|
||||
postDecryptedLength := len(postDecryptedData)
|
||||
blength := len(b)
|
||||
if blength >= postDecryptedLength {
|
||||
copy(b, postDecryptedData)
|
||||
return postDecryptedLength, nil
|
||||
}
|
||||
copy(b, postDecryptedData[:blength])
|
||||
c.decryptedBuf.Write(postDecryptedData[blength:])
|
||||
return blength, nil
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) preWrite(b []byte) (outData []byte, err error) {
|
||||
if b == nil {
|
||||
b = make([]byte, 0)
|
||||
}
|
||||
var iv []byte
|
||||
if iv, err = c.initEncryptor(b); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var preEncryptedData []byte
|
||||
preEncryptedData, err = c.IProtocol.PreEncrypt(b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
preEncryptedDataLen := len(preEncryptedData)
|
||||
//! \attention here the expected output buffer length MUST be accurate, it is preEncryptedDataLen now!
|
||||
|
||||
cipherData := c.writeBuf
|
||||
dataSize := preEncryptedDataLen + len(iv)
|
||||
if dataSize > len(cipherData) {
|
||||
cipherData = make([]byte, dataSize)
|
||||
} else {
|
||||
cipherData = cipherData[:dataSize]
|
||||
}
|
||||
|
||||
if iv != nil {
|
||||
// Put initialization vector in buffer before be encoded
|
||||
copy(cipherData, iv)
|
||||
}
|
||||
c.Encrypt(cipherData[len(iv):], preEncryptedData)
|
||||
return c.IObfs.Encode(cipherData)
|
||||
}
|
||||
|
||||
func (c *SSTCPConn) Write(b []byte) (n int, err error) {
|
||||
outData, err := c.preWrite(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err = c.Conn.Write(outData)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
@ -7,15 +7,14 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
shadowsocksr "github.com/mzz2017/shadowsocksR"
|
||||
"github.com/mzz2017/shadowsocksR/obfs"
|
||||
"github.com/mzz2017/shadowsocksR/protocol"
|
||||
ssrinfo "github.com/mzz2017/shadowsocksR/ssr"
|
||||
"github.com/mzz2017/shadowsocksR/streamCipher"
|
||||
|
||||
"github.com/nadoo/glider/log"
|
||||
"github.com/nadoo/glider/proxy"
|
||||
"github.com/nadoo/glider/proxy/socks"
|
||||
"github.com/nadoo/glider/proxy/ssr/internal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -87,7 +86,7 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) {
|
||||
return nil, errors.New("[ssr] unable to parse address: " + addr)
|
||||
}
|
||||
|
||||
cipher, err := streamCipher.NewStreamCipher(s.EncryptMethod, s.EncryptPassword)
|
||||
cipher, err := internal.NewStreamCipher(s.EncryptMethod, s.EncryptPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -98,7 +97,7 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ssrconn := shadowsocksr.NewSSTCPConn(c, cipher)
|
||||
ssrconn := internal.NewSSTCPConn(c, cipher)
|
||||
if ssrconn.Conn == nil || ssrconn.RemoteAddr() == nil {
|
||||
return nil, errors.New("[ssr] nil connection")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user