mirror of https://github.com/v2ray/v2ray-core
refactor shadowsocks
parent
c9554546db
commit
e9c784d4bd
|
@ -1,6 +0,0 @@
|
|||
package crypto
|
||||
|
||||
type Authenticator interface {
|
||||
AuthSize() int
|
||||
Authenticate(auth []byte, data []byte) []byte
|
||||
}
|
|
@ -4,9 +4,6 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/alloc"
|
||||
"github.com/v2ray/v2ray-core/common/crypto"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
"github.com/v2ray/v2ray-core/transport"
|
||||
)
|
||||
|
||||
// ReadFrom reads from a reader and put all content to a buffer.
|
||||
|
@ -55,68 +52,3 @@ func (this *AdaptiveReader) Read() (*alloc.Buffer, error) {
|
|||
}
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
type ChunkReader struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
func NewChunkReader(reader io.Reader) *ChunkReader {
|
||||
return &ChunkReader{
|
||||
reader: reader,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ChunkReader) Read() (*alloc.Buffer, error) {
|
||||
buffer := alloc.NewLargeBuffer()
|
||||
if _, err := io.ReadFull(this.reader, buffer.Value[:2]); err != nil {
|
||||
alloc.Release(buffer)
|
||||
return nil, err
|
||||
}
|
||||
length := serial.BytesLiteral(buffer.Value[:2]).Uint16Value()
|
||||
if _, err := io.ReadFull(this.reader, buffer.Value[:length]); err != nil {
|
||||
alloc.Release(buffer)
|
||||
return nil, err
|
||||
}
|
||||
buffer.Slice(0, int(length))
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
type AuthenticationReader struct {
|
||||
reader Reader
|
||||
authenticator crypto.Authenticator
|
||||
authBeforePayload bool
|
||||
}
|
||||
|
||||
func NewAuthenticationReader(reader Reader, auth crypto.Authenticator, authBeforePayload bool) *AuthenticationReader {
|
||||
return &AuthenticationReader{
|
||||
reader: reader,
|
||||
authenticator: auth,
|
||||
authBeforePayload: authBeforePayload,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *AuthenticationReader) Read() (*alloc.Buffer, error) {
|
||||
buffer, err := this.reader.Read()
|
||||
if err != nil {
|
||||
alloc.Release(buffer)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authSize := this.authenticator.AuthSize()
|
||||
var authBytes, payloadBytes []byte
|
||||
if this.authBeforePayload {
|
||||
authBytes = buffer.Value[:authSize]
|
||||
payloadBytes = buffer.Value[authSize:]
|
||||
} else {
|
||||
payloadBytes = buffer.Value[:authSize]
|
||||
authBytes = buffer.Value[authSize:]
|
||||
}
|
||||
|
||||
actualAuthBytes := this.authenticator.Authenticate(nil, payloadBytes)
|
||||
if !serial.BytesLiteral(authBytes).Equals(serial.BytesLiteral(actualAuthBytes)) {
|
||||
alloc.Release(buffer)
|
||||
return nil, transport.CorruptedPacket
|
||||
}
|
||||
buffer.Value = payloadBytes
|
||||
return buffer, nil
|
||||
}
|
||||
|
|
|
@ -3,8 +3,12 @@ package shadowsocks
|
|||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"io"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/alloc"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
"github.com/v2ray/v2ray-core/transport"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -23,10 +27,6 @@ func NewAuthenticator(keygen KeyGenerator) *Authenticator {
|
|||
}
|
||||
}
|
||||
|
||||
func (this *Authenticator) AuthSize() int {
|
||||
return AuthSize
|
||||
}
|
||||
|
||||
func (this *Authenticator) Authenticate(auth []byte, data []byte) []byte {
|
||||
hasher := hmac.New(sha1.New, this.key())
|
||||
hasher.Write(data)
|
||||
|
@ -53,3 +53,44 @@ func ChunkKeyGenerator(iv []byte) func() []byte {
|
|||
return newKey
|
||||
}
|
||||
}
|
||||
|
||||
type ChunkReader struct {
|
||||
reader io.Reader
|
||||
auth *Authenticator
|
||||
}
|
||||
|
||||
func NewChunkReader(reader io.Reader, auth *Authenticator) *ChunkReader {
|
||||
return &ChunkReader{
|
||||
reader: reader,
|
||||
auth: auth,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ChunkReader) Read() (*alloc.Buffer, error) {
|
||||
buffer := alloc.NewLargeBuffer()
|
||||
if _, err := io.ReadFull(this.reader, buffer.Value[:2]); err != nil {
|
||||
alloc.Release(buffer)
|
||||
return nil, err
|
||||
}
|
||||
// There is a potential buffer overflow here. Large buffer is 64K bytes,
|
||||
// while uin16 + 10 will be more than that
|
||||
length := serial.BytesLiteral(buffer.Value[:2]).Uint16Value() + AuthSize
|
||||
if _, err := io.ReadFull(this.reader, buffer.Value[:length]); err != nil {
|
||||
alloc.Release(buffer)
|
||||
return nil, err
|
||||
}
|
||||
buffer.Slice(0, int(length))
|
||||
|
||||
authBytes := buffer.Value[:AuthSize]
|
||||
payload := buffer.Value[AuthSize:]
|
||||
|
||||
actualAuthBytes := this.auth.Authenticate(nil, payload)
|
||||
if !serial.BytesLiteral(authBytes).Equals(serial.BytesLiteral(actualAuthBytes)) {
|
||||
alloc.Release(buffer)
|
||||
log.Debug("AuthenticationReader: Unexpected auth: ", authBytes)
|
||||
return nil, transport.CorruptedPacket
|
||||
}
|
||||
buffer.Value = payload
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ func ReadRequest(reader io.Reader, auth *Authenticator) (*Request, error) {
|
|||
lenBuffer += 2
|
||||
|
||||
if request.OTA {
|
||||
authBytes := buffer.Value[lenBuffer : lenBuffer+auth.AuthSize()]
|
||||
authBytes := buffer.Value[lenBuffer : lenBuffer+AuthSize]
|
||||
_, err = io.ReadFull(reader, authBytes)
|
||||
if err != nil {
|
||||
log.Error("Shadowsocks: Failed to read OTA: ", err)
|
||||
|
|
|
@ -155,7 +155,7 @@ func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) {
|
|||
return
|
||||
}
|
||||
|
||||
request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)))
|
||||
request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(iv, key)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ func (this *Shadowsocks) handleConnection(conn *hub.TCPConn) {
|
|||
var payloadReader v2io.Reader
|
||||
if request.OTA {
|
||||
payloadAuth := NewAuthenticator(ChunkKeyGenerator(iv))
|
||||
payloadReader = v2io.NewAuthenticationReader(v2io.NewChunkReader(reader), payloadAuth, true)
|
||||
payloadReader = NewChunkReader(reader, payloadAuth)
|
||||
} else {
|
||||
payloadReader = v2io.NewAdaptiveReader(reader)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue