1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-26 12:07:47 -05:00

refine shadowsocks server

This commit is contained in:
Darien Raymond 2016-10-31 15:24:28 +01:00
parent fbb44e7e02
commit be4f3d0772
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
10 changed files with 513 additions and 360 deletions

View File

@ -0,0 +1,48 @@
package shadowsocks
import (
"v2ray.com/core/common/alloc"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray"
)
type Client struct {
serverPicker protocol.ServerPicker
meta *proxy.OutboundHandlerMeta
}
func (this *Client) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error {
defer payload.Release()
defer ray.OutboundInput().Release()
defer ray.OutboundOutput().Close()
network := destination.Network
var server *protocol.ServerSpec
var conn internet.Connection
err := retry.Timed(5, 100).On(func() error {
server = this.serverPicker.PickServer()
dest := server.Destination()
dest.Network = network
rawConn, err := internet.Dial(this.meta.Address, dest, this.meta.StreamSettings)
if err != nil {
return err
}
conn = rawConn
return nil
})
if err != nil {
log.Error("Shadowsocks|Client: Failed to find an available destination:", err)
return err
}
log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination())
return nil
}

View File

@ -1,6 +1,7 @@
package shadowsocks
import (
"bytes"
"crypto/cipher"
"crypto/md5"
"errors"
@ -9,6 +10,18 @@ import (
"v2ray.com/core/common/protocol"
)
type ShadowsocksAccount struct {
Cipher Cipher
Key []byte
}
func (this *ShadowsocksAccount) Equals(another protocol.Account) bool {
if account, ok := another.(*ShadowsocksAccount); ok {
return bytes.Equal(this.Key, account.Key)
}
return false
}
func (this *Account) GetCipher() (Cipher, error) {
switch this.CipherType {
case CipherType_AES_128_CFB:
@ -24,15 +37,15 @@ func (this *Account) GetCipher() (Cipher, error) {
}
}
func (this *Account) Equals(another protocol.Account) bool {
if account, ok := another.(*Account); ok {
return account.Password == this.Password
}
return false
}
func (this *Account) AsAccount() (protocol.Account, error) {
return this, nil
cipher, err := this.GetCipher()
if err != nil {
return nil, err
}
return &ShadowsocksAccount{
Cipher: cipher,
Key: this.GetCipherKey(),
}, nil
}
func (this *Account) GetCipherKey() []byte {

View File

@ -62,9 +62,34 @@ func (x CipherType) String() string {
}
func (CipherType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type Account_OneTimeAuth int32
const (
Account_Auto Account_OneTimeAuth = 0
Account_Disabled Account_OneTimeAuth = 1
Account_Enabled Account_OneTimeAuth = 2
)
var Account_OneTimeAuth_name = map[int32]string{
0: "Auto",
1: "Disabled",
2: "Enabled",
}
var Account_OneTimeAuth_value = map[string]int32{
"Auto": 0,
"Disabled": 1,
"Enabled": 2,
}
func (x Account_OneTimeAuth) String() string {
return proto.EnumName(Account_OneTimeAuth_name, int32(x))
}
func (Account_OneTimeAuth) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }
type Account struct {
Password string `protobuf:"bytes,1,opt,name=password" json:"password,omitempty"`
CipherType CipherType `protobuf:"varint,2,opt,name=cipher_type,json=cipherType,enum=v2ray.core.proxy.shadowsocks.CipherType" json:"cipher_type,omitempty"`
Password string `protobuf:"bytes,1,opt,name=password" json:"password,omitempty"`
CipherType CipherType `protobuf:"varint,2,opt,name=cipher_type,json=cipherType,enum=v2ray.core.proxy.shadowsocks.CipherType" json:"cipher_type,omitempty"`
Ota Account_OneTimeAuth `protobuf:"varint,3,opt,name=ota,enum=v2ray.core.proxy.shadowsocks.Account_OneTimeAuth" json:"ota,omitempty"`
}
func (m *Account) Reset() { *m = Account{} }
@ -110,34 +135,38 @@ func init() {
proto.RegisterType((*ServerConfig)(nil), "v2ray.core.proxy.shadowsocks.ServerConfig")
proto.RegisterType((*ClientConfig)(nil), "v2ray.core.proxy.shadowsocks.ClientConfig")
proto.RegisterEnum("v2ray.core.proxy.shadowsocks.CipherType", CipherType_name, CipherType_value)
proto.RegisterEnum("v2ray.core.proxy.shadowsocks.Account_OneTimeAuth", Account_OneTimeAuth_name, Account_OneTimeAuth_value)
}
func init() { proto.RegisterFile("v2ray.com/core/proxy/shadowsocks/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 371 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x50, 0xdd, 0xab, 0xd3, 0x30,
0x14, 0xb7, 0xf7, 0x5e, 0xee, 0x9d, 0x27, 0x53, 0x6b, 0x9e, 0xc6, 0x10, 0x2c, 0x7b, 0xaa, 0x17,
0x4c, 0x67, 0xfd, 0xc0, 0x07, 0x5f, 0xda, 0xd2, 0xb1, 0x21, 0x4c, 0xe9, 0x36, 0x04, 0x11, 0x4a,
0x97, 0x46, 0x57, 0x5c, 0x9b, 0x90, 0xb4, 0x9b, 0xfd, 0xef, 0x65, 0xc9, 0x3a, 0x87, 0x0f, 0xbb,
0x6f, 0x39, 0x27, 0xbf, 0xcf, 0x03, 0xaf, 0x77, 0xbe, 0xcc, 0x5a, 0x42, 0x79, 0xe9, 0x51, 0x2e,
0x99, 0x27, 0x24, 0xff, 0xd3, 0x7a, 0x6a, 0x93, 0xe5, 0x7c, 0xaf, 0x38, 0xfd, 0xad, 0x3c, 0xca,
0xab, 0x9f, 0xc5, 0x2f, 0x22, 0x24, 0xaf, 0x39, 0x7e, 0xd1, 0xc1, 0x25, 0x23, 0x1a, 0x4a, 0xce,
0xa0, 0xc3, 0x57, 0xff, 0x89, 0x51, 0x5e, 0x96, 0xbc, 0xf2, 0x34, 0x95, 0xf2, 0xad, 0xd7, 0x28,
0x26, 0x8d, 0xd0, 0x70, 0xfc, 0x00, 0x54, 0x31, 0xb9, 0x63, 0x32, 0x55, 0x82, 0x51, 0xc3, 0x18,
0x09, 0xb8, 0x0b, 0x28, 0xe5, 0x4d, 0x55, 0xe3, 0x21, 0xf4, 0x44, 0xa6, 0xd4, 0x9e, 0xcb, 0x7c,
0x60, 0x39, 0x96, 0xfb, 0x38, 0x39, 0xcd, 0x78, 0x06, 0x88, 0x16, 0x62, 0xc3, 0x64, 0x5a, 0xb7,
0x82, 0x0d, 0xae, 0x1c, 0xcb, 0x7d, 0xea, 0xbb, 0xe4, 0x52, 0x6e, 0x12, 0x69, 0xc2, 0xb2, 0x15,
0x2c, 0x01, 0x7a, 0x7a, 0x8f, 0x18, 0xf4, 0x17, 0x3a, 0x46, 0xa4, 0x4f, 0x80, 0x5f, 0x02, 0x6a,
0x72, 0x91, 0xb2, 0x2a, 0x5b, 0x6f, 0x99, 0x71, 0xee, 0x25, 0xd0, 0xe4, 0x22, 0x36, 0x1b, 0xfc,
0x0e, 0x6e, 0x0e, 0x15, 0xb5, 0x29, 0xf2, 0x9d, 0x73, 0x53, 0xd3, 0x8f, 0x74, 0xfd, 0xc8, 0x4a,
0x31, 0x99, 0x68, 0xf4, 0x28, 0x81, 0x7e, 0xb4, 0x2d, 0x58, 0x55, 0x1f, 0x6d, 0x42, 0xb8, 0x35,
0xed, 0x07, 0x96, 0x73, 0xed, 0x22, 0xff, 0xfe, 0x92, 0x8e, 0x09, 0x18, 0x57, 0xb9, 0xe0, 0x45,
0x55, 0x27, 0x47, 0xe6, 0xfd, 0x0f, 0x80, 0x7f, 0xa5, 0x30, 0x82, 0xbb, 0xd5, 0xfc, 0xf3, 0xfc,
0xcb, 0xb7, 0xb9, 0xfd, 0x08, 0x3f, 0x03, 0x14, 0xc4, 0x8b, 0xf4, 0x8d, 0xff, 0x31, 0x8d, 0x26,
0xa1, 0x6d, 0x75, 0x0b, 0xff, 0xfd, 0x07, 0xbd, 0xb8, 0xc2, 0x7d, 0xe8, 0x45, 0xd3, 0x20, 0x9a,
0x06, 0xfe, 0xd8, 0xbe, 0xc6, 0xcf, 0xe1, 0x49, 0x37, 0xa5, 0xb3, 0x78, 0xb2, 0xb4, 0x6f, 0xc2,
0x4f, 0xe0, 0x50, 0x5e, 0x5e, 0xbc, 0x69, 0x88, 0x4c, 0x9b, 0xaf, 0x87, 0xa0, 0xdf, 0xd1, 0xd9,
0xcf, 0xfa, 0x56, 0x87, 0x7f, 0xfb, 0x37, 0x00, 0x00, 0xff, 0xff, 0xff, 0xed, 0x11, 0xa8, 0x7b,
0x02, 0x00, 0x00,
// 431 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x91, 0x4f, 0x6f, 0xd3, 0x40,
0x10, 0xc5, 0xeb, 0x24, 0x6a, 0xc3, 0x6c, 0x00, 0xb3, 0xa7, 0x28, 0x42, 0xc2, 0xca, 0x29, 0x54,
0x62, 0xdd, 0x9a, 0x3f, 0xe2, 0xc0, 0xc5, 0x31, 0xa9, 0x5a, 0x21, 0xa5, 0xc8, 0x4d, 0x85, 0x84,
0x90, 0x2c, 0x77, 0x3d, 0x10, 0x8b, 0xd8, 0xb3, 0xda, 0xb5, 0x5b, 0xf2, 0x91, 0xf9, 0x16, 0xc8,
0xeb, 0x24, 0x44, 0x1c, 0xc2, 0xcd, 0x33, 0x7e, 0xef, 0xf9, 0xcd, 0xcf, 0xf0, 0xea, 0x3e, 0xd0,
0xe9, 0x5a, 0x48, 0x2a, 0x7c, 0x49, 0x1a, 0x7d, 0xa5, 0xe9, 0xd7, 0xda, 0x37, 0xcb, 0x34, 0xa3,
0x07, 0x43, 0xf2, 0xa7, 0xf1, 0x25, 0x95, 0xdf, 0xf3, 0x1f, 0x42, 0x69, 0xaa, 0x88, 0x3f, 0xdf,
0xca, 0x35, 0x0a, 0x2b, 0x15, 0x7b, 0xd2, 0xd1, 0xcb, 0x7f, 0xc2, 0x24, 0x15, 0x05, 0x95, 0xbe,
0xb5, 0x4a, 0x5a, 0xf9, 0xb5, 0x41, 0xdd, 0x06, 0x8d, 0xce, 0xfe, 0x23, 0x35, 0xa8, 0xef, 0x51,
0x27, 0x46, 0xa1, 0x6c, 0x1d, 0xe3, 0xdf, 0x0e, 0x9c, 0x84, 0x52, 0x52, 0x5d, 0x56, 0x7c, 0x04,
0x7d, 0x95, 0x1a, 0xf3, 0x40, 0x3a, 0x1b, 0x3a, 0x9e, 0x33, 0x79, 0x14, 0xef, 0x66, 0x7e, 0x05,
0x4c, 0xe6, 0x6a, 0x89, 0x3a, 0xa9, 0xd6, 0x0a, 0x87, 0x1d, 0xcf, 0x99, 0x3c, 0x09, 0x26, 0xe2,
0x50, 0x71, 0x11, 0x59, 0xc3, 0x62, 0xad, 0x30, 0x06, 0xb9, 0x7b, 0xe6, 0x11, 0x74, 0xa9, 0x4a,
0x87, 0x5d, 0x1b, 0x71, 0x7e, 0x38, 0x62, 0x53, 0x4d, 0x5c, 0x97, 0xb8, 0xc8, 0x0b, 0x0c, 0xeb,
0x6a, 0x19, 0x37, 0xee, 0x71, 0x00, 0x6c, 0x6f, 0xc7, 0xfb, 0xd0, 0x0b, 0xeb, 0x8a, 0xdc, 0x23,
0x3e, 0x80, 0xfe, 0xc7, 0xdc, 0xa4, 0x77, 0x2b, 0xcc, 0x5c, 0x87, 0x33, 0x38, 0x99, 0x95, 0xed,
0xd0, 0x19, 0x23, 0x0c, 0x6e, 0x2c, 0x80, 0xc8, 0xc2, 0xe7, 0x2f, 0x80, 0xd5, 0x99, 0x4a, 0xb0,
0x15, 0xd8, 0x93, 0xfb, 0x31, 0xd4, 0x99, 0xda, 0x58, 0xf8, 0x1b, 0xe8, 0x35, 0x70, 0xed, 0xb5,
0x2c, 0xf0, 0xf6, 0xab, 0xb6, 0x64, 0xc5, 0x96, 0xac, 0xb8, 0x35, 0xa8, 0x63, 0xab, 0x1e, 0xc7,
0x30, 0x88, 0x56, 0x39, 0x96, 0xd5, 0xe6, 0x33, 0x53, 0x38, 0x6e, 0xb9, 0x0f, 0x1d, 0xaf, 0x3b,
0x61, 0xc1, 0xe9, 0xa1, 0x9c, 0xb6, 0xe0, 0xac, 0xcc, 0x14, 0xe5, 0x65, 0x15, 0x6f, 0x9c, 0xa7,
0xdf, 0x00, 0xfe, 0xd2, 0x6c, 0xae, 0xba, 0x9d, 0x7f, 0x9a, 0x5f, 0x7f, 0x99, 0xbb, 0x47, 0xfc,
0x29, 0xb0, 0x70, 0x76, 0x93, 0x9c, 0x07, 0xef, 0x93, 0xe8, 0x62, 0xea, 0x3a, 0xdb, 0x45, 0xf0,
0xf6, 0x9d, 0x5d, 0x74, 0x1a, 0x24, 0xd1, 0x65, 0x18, 0x5d, 0x86, 0xc1, 0x99, 0xdb, 0xe5, 0xcf,
0xe0, 0xf1, 0x76, 0x4a, 0xae, 0x66, 0x17, 0x0b, 0xb7, 0x37, 0xfd, 0x00, 0x9e, 0xa4, 0xe2, 0xe0,
0x9f, 0x98, 0xb2, 0xf6, 0x9a, 0xcf, 0x4d, 0xd1, 0xaf, 0x6c, 0xef, 0xcd, 0xdd, 0xb1, 0x2d, 0xff,
0xfa, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x59, 0xf6, 0xcd, 0xed, 0xf5, 0x02, 0x00, 0x00,
}

View File

@ -9,8 +9,14 @@ import "v2ray.com/core/common/protocol/user.proto";
import "v2ray.com/core/common/protocol/server_spec.proto";
message Account {
enum OneTimeAuth {
Auto = 0;
Disabled = 1;
Enabled = 2;
}
string password = 1;
CipherType cipher_type = 2;
OneTimeAuth ota = 3;
}
enum CipherType {

12
proxy/shadowsocks/init.go Normal file
View File

@ -0,0 +1,12 @@
package shadowsocks
import (
"v2ray.com/core/common/loader"
"v2ray.com/core/proxy/registry"
)
func init() {
// Must happen after config is initialized
registry.MustRegisterInboundHandlerCreator(loader.GetType(new(ServerConfig)), new(ServerFactory))
}

View File

@ -118,10 +118,11 @@ func (this *ChunkWriter) Release() {
this.auth = nil
}
func (this *ChunkWriter) Write(payload *alloc.Buffer) (int, error) {
func (this *ChunkWriter) Write(payload *alloc.Buffer) error {
totalLength := payload.Len()
authBytes := this.auth.Authenticate(nil, payload.Bytes())
payload.Prepend(authBytes)
payload.SliceBack(AuthSize)
this.auth.Authenticate(payload.Value[:0], payload.Value[AuthSize:])
payload.PrependUint16(uint16(totalLength))
return this.writer.Write(payload.Bytes())
_, err := this.writer.Write(payload.Bytes())
return err
}

View File

@ -26,12 +26,11 @@ func TestNormalChunkReading(t *testing.T) {
func TestNormalChunkWriting(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewBuffer().Clear()
buffer := alloc.NewLocalBuffer(512).Clear()
writer := NewChunkWriter(buffer, NewAuthenticator(ChunkKeyGenerator(
[]byte{21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36})))
nBytes, err := writer.Write(alloc.NewBuffer().Clear().Append([]byte{11, 12, 13, 14, 15, 16, 17, 18}))
err := writer.Write(alloc.NewLocalBuffer(256).Clear().Append([]byte{11, 12, 13, 14, 15, 16, 17, 18}))
assert.Error(err).IsNil()
assert.Int(nBytes).Equals(buffer.Len())
assert.Bytes(buffer.Value).Equals([]byte{0, 8, 39, 228, 69, 96, 133, 39, 254, 26, 201, 70, 11, 12, 13, 14, 15, 16, 17, 18})
}

View File

@ -2,141 +2,343 @@ package shadowsocks
import (
"bytes"
"crypto/rand"
"errors"
"io"
"v2ray.com/core/common/alloc"
"v2ray.com/core/common/log"
"v2ray.com/core/common/crypto"
v2io "v2ray.com/core/common/io"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport"
"v2ray.com/core/common/protocol"
)
const (
Version = 1
RequestOptionOneTimeAuth = protocol.RequestOption(101)
AddrTypeIPv4 = 1
AddrTypeIPv6 = 4
AddrTypeDomain = 3
)
type Request struct {
Address v2net.Address
Port v2net.Port
OTA bool
UDPPayload *alloc.Buffer
}
func (this *Request) Release() {
this.Address = nil
if this.UDPPayload != nil {
this.UDPPayload.Release()
func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHeader, v2io.Reader, error) {
rawAccount, err := user.GetTypedAccount()
if err != nil {
return nil, nil, errors.New("Shadowsocks|TCP: Failed to parse account: " + err.Error())
}
}
account := rawAccount.(*ShadowsocksAccount)
func (this *Request) DetachUDPPayload() *alloc.Buffer {
payload := this.UDPPayload
this.UDPPayload = nil
return payload
}
func ReadRequest(reader io.Reader, auth *Authenticator, udp bool) (*Request, error) {
buffer := alloc.NewSmallBuffer()
buffer := alloc.NewLocalBuffer(256)
defer buffer.Release()
_, err := io.ReadFull(reader, buffer.Value[:1])
ivLen := account.Cipher.IVSize()
_, err = io.ReadFull(reader, buffer.Value[:ivLen])
if err != nil {
if err != io.EOF {
log.Warning("Shadowsocks: Failed to read address type: ", err)
return nil, transport.ErrCorruptedPacket
}
return nil, err
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read IV: " + err.Error())
}
lenBuffer := 1
request := new(Request)
iv := append([]byte(nil), buffer.Value[:ivLen]...)
stream, err := account.Cipher.NewDecodingStream(account.Key, iv)
if err != nil {
return nil, nil, errors.New("Shadowsocks|TCP: Failed to initialize decoding stream: " + err.Error())
}
reader = crypto.NewCryptionReader(stream, reader)
authenticator := NewAuthenticator(HeaderKeyGenerator(account.Key, iv))
request := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandTCP,
}
lenBuffer := 1
_, err = io.ReadFull(reader, buffer.Value[:1])
if err != nil {
return nil, nil, errors.New("Sahdowsocks|TCP: Failed to read address type: " + err.Error())
}
addrType := (buffer.Value[0] & 0x0F)
if (buffer.Value[0] & 0x10) == 0x10 {
request.OTA = true
request.Option |= RequestOptionOneTimeAuth
}
switch addrType {
case AddrTypeIPv4:
_, err := io.ReadFull(reader, buffer.Value[lenBuffer:lenBuffer+4])
if err != nil {
log.Warning("Shadowsocks: Failed to read IPv4 address: ", err)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read IPv4 address: " + err.Error())
}
request.Address = v2net.IPAddress(buffer.Value[lenBuffer : lenBuffer+4])
lenBuffer += 4
case AddrTypeIPv6:
_, err := io.ReadFull(reader, buffer.Value[lenBuffer:lenBuffer+16])
if err != nil {
log.Warning("Shadowsocks: Failed to read IPv6 address: ", err)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read IPv6 address: " + err.Error())
}
request.Address = v2net.IPAddress(buffer.Value[lenBuffer : lenBuffer+16])
lenBuffer += 16
case AddrTypeDomain:
_, err := io.ReadFull(reader, buffer.Value[lenBuffer:lenBuffer+1])
if err != nil {
log.Warning("Shadowsocks: Failed to read domain lenth: ", err)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read domain lenth: " + err.Error())
}
domainLength := int(buffer.Value[lenBuffer])
lenBuffer++
_, err = io.ReadFull(reader, buffer.Value[lenBuffer:lenBuffer+domainLength])
if err != nil {
log.Warning("Shadowsocks: Failed to read domain: ", err)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read domain: " + err.Error())
}
request.Address = v2net.DomainAddress(string(buffer.Value[lenBuffer : lenBuffer+domainLength]))
lenBuffer += domainLength
default:
log.Warning("Shadowsocks: Unknown address type: ", addrType)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Unknown address type.")
}
_, err = io.ReadFull(reader, buffer.Value[lenBuffer:lenBuffer+2])
if err != nil {
log.Warning("Shadowsocks: Failed to read port: ", err)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read port: " + err.Error())
}
request.Port = v2net.PortFromBytes(buffer.Value[lenBuffer : lenBuffer+2])
lenBuffer += 2
var authBytes []byte
if udp {
nBytes, err := reader.Read(buffer.Value[lenBuffer:])
if request.Option.Has(RequestOptionOneTimeAuth) {
authBytes := buffer.Value[lenBuffer : lenBuffer+AuthSize]
_, err = io.ReadFull(reader, authBytes)
if err != nil {
log.Warning("Shadowsocks: Failed to read UDP payload: ", err)
return nil, transport.ErrCorruptedPacket
return nil, nil, errors.New("Shadowsocks|TCP: Failed to read OTA: " + err.Error())
}
buffer.Slice(0, lenBuffer+nBytes)
if request.OTA {
authBytes = buffer.Value[lenBuffer+nBytes-AuthSize:]
request.UDPPayload = alloc.NewSmallBuffer().Clear().Append(buffer.Value[lenBuffer : lenBuffer+nBytes-AuthSize])
lenBuffer = lenBuffer + nBytes - AuthSize
} else {
request.UDPPayload = alloc.NewSmallBuffer().Clear().Append(buffer.Value[lenBuffer:])
}
} else {
if request.OTA {
authBytes = buffer.Value[lenBuffer : lenBuffer+AuthSize]
_, err = io.ReadFull(reader, authBytes)
if err != nil {
log.Warning("Shadowsocks: Failed to read OTA: ", err)
return nil, transport.ErrCorruptedPacket
}
}
}
if request.OTA {
actualAuth := auth.Authenticate(nil, buffer.Value[0:lenBuffer])
actualAuth := authenticator.Authenticate(nil, buffer.Value[0:lenBuffer])
if !bytes.Equal(actualAuth, authBytes) {
log.Warning("Shadowsocks: Invalid OTA.")
return nil, proxy.ErrInvalidAuthentication
return nil, nil, errors.New("Shadowsocks|TCP: Invalid OTA")
}
}
return request, nil
var chunkReader v2io.Reader
if request.Option.Has(RequestOptionOneTimeAuth) {
chunkReader = NewChunkReader(reader, NewAuthenticator(ChunkKeyGenerator(iv)))
} else {
chunkReader = v2io.NewAdaptiveReader(reader)
}
return request, chunkReader, nil
}
func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (v2io.Writer, error) {
user := request.User
rawAccount, err := user.GetTypedAccount()
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to parse account: " + err.Error())
}
account := rawAccount.(*ShadowsocksAccount)
iv := make([]byte, account.Cipher.IVSize())
rand.Read(iv)
_, err = writer.Write(iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to write IV: " + err.Error())
}
stream, err := account.Cipher.NewEncodingStream(account.Key, iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to create encoding stream: " + err.Error())
}
writer = crypto.NewCryptionWriter(stream, writer)
header := alloc.NewLocalBuffer(512).Clear()
switch request.Address.Family() {
case v2net.AddressFamilyIPv4:
header.AppendBytes(AddrTypeIPv4)
header.Append([]byte(request.Address.IP()))
case AddrTypeIPv6:
header.AppendBytes(AddrTypeIPv6)
header.Append([]byte(request.Address.IP()))
case AddrTypeDomain:
header.AppendBytes(AddrTypeDomain, byte(len(request.Address.Domain())))
header.Append([]byte(request.Address.Domain()))
default:
return nil, errors.New("Shadowsocks|TCP: Unsupported address type. ")
}
header.AppendUint16(uint16(request.Port))
if request.Option.Has(RequestOptionOneTimeAuth) {
header.Value[0] |= 0x10
authenticator := NewAuthenticator(HeaderKeyGenerator(account.Key, iv))
header.Value = authenticator.Authenticate(header.Value, header.Value)
}
_, err = writer.Write(header.Value)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to write header: " + err.Error())
}
var chunkWriter v2io.Writer
if request.Option.Has(RequestOptionOneTimeAuth) {
chunkWriter = NewChunkWriter(writer, NewAuthenticator(ChunkKeyGenerator(iv)))
} else {
chunkWriter = v2io.NewAdaptiveWriter(writer)
}
return chunkWriter, nil
}
func ReadTCPResponse(user *protocol.User, reader io.Reader) (v2io.Reader, error) {
rawAccount, err := user.GetTypedAccount()
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to parse account: " + err.Error())
}
account := rawAccount.(*ShadowsocksAccount)
iv := make([]byte, account.Cipher.IVSize())
_, err = io.ReadFull(reader, iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to read IV: " + err.Error())
}
stream, err := account.Cipher.NewDecodingStream(account.Key, iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to initialize decoding stream: " + err.Error())
}
return v2io.NewAdaptiveReader(crypto.NewCryptionReader(stream, reader)), nil
}
func WriteTCPResponse(request *protocol.RequestHeader, writer io.Writer) (v2io.Writer, error) {
user := request.User
rawAccount, err := user.GetTypedAccount()
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to parse account: " + err.Error())
}
account := rawAccount.(*ShadowsocksAccount)
iv := make([]byte, account.Cipher.IVSize())
rand.Read(iv)
_, err = writer.Write(iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to write IV: " + err.Error())
}
stream, err := account.Cipher.NewEncodingStream(account.Key, iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to create encoding stream: " + err.Error())
}
return v2io.NewAdaptiveWriter(crypto.NewCryptionWriter(stream, writer)), nil
}
func EncodeUDPPacket(request *protocol.RequestHeader, payload *alloc.Buffer) (*alloc.Buffer, error) {
user := request.User
rawAccount, err := user.GetTypedAccount()
if err != nil {
return nil, errors.New("Shadowsocks|UDP: Failed to parse account: " + err.Error())
}
account := rawAccount.(*ShadowsocksAccount)
buffer := alloc.NewLocalBuffer(2048)
ivLen := account.Cipher.IVSize()
buffer.Slice(0, ivLen)
rand.Read(buffer.Value)
iv := buffer.Value
switch request.Address.Family() {
case v2net.AddressFamilyIPv4:
buffer.AppendBytes(AddrTypeIPv4)
buffer.Append([]byte(request.Address.IP()))
case AddrTypeIPv6:
buffer.AppendBytes(AddrTypeIPv6)
buffer.Append([]byte(request.Address.IP()))
case AddrTypeDomain:
buffer.AppendBytes(AddrTypeDomain, byte(len(request.Address.Domain())))
buffer.Append([]byte(request.Address.Domain()))
default:
return nil, errors.New("Shadowsocks|UDP: Unsupported address type. ")
}
buffer.AppendUint16(uint16(request.Port))
buffer.Append(payload.Value)
if request.Option.Has(RequestOptionOneTimeAuth) {
authenticator := NewAuthenticator(HeaderKeyGenerator(account.Key, iv))
buffer.Value[ivLen] |= 0x0F
buffer.Value = authenticator.Authenticate(buffer.Value, buffer.Value[ivLen:])
}
stream, err := account.Cipher.NewEncodingStream(account.Key, iv)
if err != nil {
return nil, errors.New("Shadowsocks|TCP: Failed to create encoding stream: " + err.Error())
}
stream.XORKeyStream(buffer.Value[ivLen:], buffer.Value[ivLen:])
return buffer, nil
}
func DecodeUDPPacket(user *protocol.User, payload *alloc.Buffer) (*protocol.RequestHeader, *alloc.Buffer, error) {
rawAccount, err := user.GetTypedAccount()
if err != nil {
return nil, nil, errors.New("Shadowsocks|UDP: Failed to parse account: " + err.Error())
}
account := rawAccount.(*ShadowsocksAccount)
ivLen := account.Cipher.IVSize()
iv := payload.Value[:ivLen]
payload.SliceFrom(ivLen)
stream, err := account.Cipher.NewDecodingStream(account.Key, iv)
if err != nil {
return nil, nil, errors.New("Shadowsocks|UDP: Failed to initialize decoding stream: " + err.Error())
}
stream.XORKeyStream(payload.Value, payload.Value)
authenticator := NewAuthenticator(HeaderKeyGenerator(account.Key, iv))
request := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandUDP,
}
addrType := (payload.Value[0] & 0x0F)
if (payload.Value[0] & 0x10) == 0x10 {
request.Option |= RequestOptionOneTimeAuth
}
if request.Option.Has(RequestOptionOneTimeAuth) {
payloadLen := payload.Len() - AuthSize
authBytes := payload.Value[payloadLen:]
actualAuth := authenticator.Authenticate(nil, payload.Value[0:payloadLen])
if !bytes.Equal(actualAuth, authBytes) {
return nil, nil, errors.New("Shadowsocks|UDP: Invalid OTA.")
}
payload.Slice(0, payloadLen)
}
payload.SliceFrom(1)
switch addrType {
case AddrTypeIPv4:
request.Address = v2net.IPAddress(payload.Value[:4])
payload.SliceFrom(4)
case AddrTypeIPv6:
request.Address = v2net.IPAddress(payload.Value[:16])
payload.SliceFrom(16)
case AddrTypeDomain:
domainLength := int(payload.Value[0])
request.Address = v2net.DomainAddress(string(payload.Value[1 : 1+domainLength]))
payload.SliceFrom(1 + domainLength)
default:
return nil, nil, errors.New("Shadowsocks|UDP: Unknown address type: " + err.Error())
}
request.Port = v2net.PortFromBytes(payload.Value[:2])
payload.SliceFrom(2)
return request, payload, nil
}

View File

@ -1,136 +1,77 @@
package shadowsocks_test
import (
"io"
"testing"
"v2ray.com/core/common/alloc"
"v2ray.com/core/common/loader"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/proxy/shadowsocks"
"v2ray.com/core/testing/assert"
"v2ray.com/core/transport"
)
func TestNormalRequestParsing(t *testing.T) {
func TestUDPEncoding(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear()
buffer.AppendBytes(1, 127, 0, 0, 1, 0, 80)
request := &protocol.RequestHeader{
Version: Version,
Command: protocol.RequestCommandUDP,
Address: v2net.LocalHostIP,
Port: 1234,
User: &protocol.User{
Email: "love@v2ray.com",
Account: loader.NewTypedSettings(&Account{
Password: "shadowsocks-password",
CipherType: CipherType_AES_128_CFB,
Ota: Account_Disabled,
}),
},
}
request, err := ReadRequest(buffer, nil, false)
data := alloc.NewLocalBuffer(256).Clear().AppendString("test string")
encodedData, err := EncodeUDPPacket(request, data)
assert.Error(err).IsNil()
assert.Address(request.Address).Equals(v2net.LocalHostIP)
assert.Port(request.Port).Equals(v2net.Port(80))
assert.Bool(request.OTA).IsFalse()
}
func TestEmptyPayload(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear()
_, err := ReadRequest(buffer, nil, false)
assert.Error(err).Equals(io.EOF)
}
func TestSingleBytePayload(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear().AppendBytes(1)
_, err := ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrCorruptedPacket)
}
func TestWrongAddressType(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear().AppendBytes(5)
_, err := ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrCorruptedPacket)
}
func TestInsufficientAddressRequest(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear().AppendBytes(1, 1)
_, err := ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrCorruptedPacket)
buffer = alloc.NewLocalBuffer(2048).Clear().AppendBytes(4, 1)
_, err = ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrCorruptedPacket)
buffer = alloc.NewLocalBuffer(2048).Clear().AppendBytes(3, 255, 1)
_, err = ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrCorruptedPacket)
}
func TestInsufficientPortRequest(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear().AppendBytes(1, 1, 2, 3, 4, 5)
_, err := ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrCorruptedPacket)
}
func TestOTARequest(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear()
buffer.AppendBytes(0x13, 13, 119, 119, 119, 46, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 0, 239, 115, 52, 212, 178, 172, 26, 6, 168, 0)
auth := NewAuthenticator(HeaderKeyGenerator(
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5},
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5}))
request, err := ReadRequest(buffer, auth, false)
decodedRequest, decodedData, err := DecodeUDPPacket(request.User, encodedData)
assert.Error(err).IsNil()
assert.Address(request.Address).Equals(v2net.DomainAddress("www.v2ray.com"))
assert.Bool(request.OTA).IsTrue()
assert.Bytes(decodedData.Value).Equals(data.Value)
assert.Address(decodedRequest.Address).Equals(request.Address)
assert.Port(decodedRequest.Port).Equals(request.Port)
}
func TestInvalidOTARequest(t *testing.T) {
func TestTCPRequest(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear()
buffer.AppendBytes(0x13, 13, 119, 119, 119, 46, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 0, 239, 115, 52, 212, 178, 172, 26, 6, 168, 1)
request := &protocol.RequestHeader{
Version: Version,
Command: protocol.RequestCommandTCP,
Address: v2net.LocalHostIP,
Option: RequestOptionOneTimeAuth,
Port: 1234,
User: &protocol.User{
Email: "love@v2ray.com",
Account: loader.NewTypedSettings(&Account{
Password: "tcp-password",
CipherType: CipherType_CHACHA20,
}),
},
}
auth := NewAuthenticator(HeaderKeyGenerator(
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5},
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5}))
_, err := ReadRequest(buffer, auth, false)
assert.Error(err).Equals(proxy.ErrInvalidAuthentication)
}
data := alloc.NewLocalBuffer(256).Clear().AppendString("test string")
cache := alloc.NewLargeBuffer().Clear()
func TestUDPRequestParsing(t *testing.T) {
assert := assert.On(t)
buffer := alloc.NewLocalBuffer(2048).Clear()
buffer.AppendBytes(1, 127, 0, 0, 1, 0, 80, 1, 2, 3, 4, 5, 6)
request, err := ReadRequest(buffer, nil, true)
writer, err := WriteTCPRequest(request, cache)
assert.Error(err).IsNil()
assert.Address(request.Address).Equals(v2net.LocalHostIP)
assert.Port(request.Port).Equals(v2net.Port(80))
assert.Bool(request.OTA).IsFalse()
assert.Bytes(request.UDPPayload.Value).Equals([]byte{1, 2, 3, 4, 5, 6})
}
func TestUDPRequestWithOTA(t *testing.T) {
assert := assert.On(t)
writer.Write(data)
buffer := alloc.NewLocalBuffer(2048).Clear()
buffer.AppendBytes(
0x13, 13, 119, 119, 119, 46, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
58, 32, 223, 30, 57, 199, 50, 139, 143, 101)
auth := NewAuthenticator(HeaderKeyGenerator(
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5},
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5}))
request, err := ReadRequest(buffer, auth, true)
decodedRequest, reader, err := ReadTCPSession(request.User, cache)
assert.Error(err).IsNil()
assert.Address(request.Address).Equals(v2net.DomainAddress("www.v2ray.com"))
assert.Bool(request.OTA).IsTrue()
assert.Bytes(request.UDPPayload.Value).Equals([]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0})
assert.Address(decodedRequest.Address).Equals(request.Address)
assert.Port(decodedRequest.Port).Equals(request.Port)
decodedData, err := reader.Read()
assert.Error(err).IsNil()
assert.Bytes(decodedData.Value).Equals([]byte("test string"))
}

View File

@ -2,22 +2,17 @@
package shadowsocks
import (
"crypto/rand"
"io"
"sync"
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/common"
"v2ray.com/core/common/alloc"
"v2ray.com/core/common/crypto"
v2io "v2ray.com/core/common/io"
"v2ray.com/core/common/loader"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy"
"v2ray.com/core/proxy/registry"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/udp"
)
@ -25,8 +20,7 @@ import (
type Server struct {
packetDispatcher dispatcher.PacketDispatcher
config *ServerConfig
cipher Cipher
cipherKey []byte
user *protocol.User
meta *proxy.InboundHandlerMeta
accepting bool
tcpHub *internet.TCPHub
@ -38,23 +32,11 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler
if config.GetUser() == nil {
return nil, protocol.ErrUserMissing
}
rawAccount, err := config.GetUser().GetTypedAccount()
if err != nil {
return nil, err
}
account, ok := rawAccount.(*Account)
if !ok {
return nil, protocol.ErrUnknownAccountType
}
cipher, err := account.GetCipher()
if err != nil {
return nil, err
}
s := &Server{
config: config,
meta: meta,
cipher: cipher,
cipherKey: account.GetCipherKey(),
config: config,
meta: meta,
user: config.GetUser(),
}
space.InitializeApplication(func() error {
@ -84,7 +66,6 @@ func (this *Server) Close() {
this.udpHub.Close()
this.udpHub = nil
}
}
func (this *Server) Start() error {
@ -115,73 +96,30 @@ func (this *Server) Start() error {
}
func (this *Server) handlerUDPPayload(payload *alloc.Buffer, session *proxy.SessionInfo) {
defer payload.Release()
source := session.Source
ivLen := this.cipher.IVSize()
iv := payload.Value[:ivLen]
payload.SliceFrom(ivLen)
stream, err := this.cipher.NewDecodingStream(this.cipherKey, iv)
request, data, err := DecodeUDPPacket(this.user, payload)
if err != nil {
log.Error("Shadowsocks: Failed to create decoding stream: ", err)
log.Info("Shadowsocks|Server: Skipping invalid UDP packet from: ", source, ": ", err)
log.Access(source, "", log.AccessRejected, err)
payload.Release()
return
}
reader := crypto.NewCryptionReader(stream, payload)
request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(this.cipherKey, iv)), true)
if err != nil {
if err != io.EOF {
log.Access(source, "", log.AccessRejected, err)
log.Warning("Shadowsocks: Invalid request from ", source, ": ", err)
}
return
}
//defer request.Release()
dest := v2net.UDPDestination(request.Address, request.Port)
dest := request.Destination()
log.Access(source, dest, log.AccessAccepted, "")
log.Info("Shadowsocks: Tunnelling request to ", dest)
log.Info("Shadowsocks|Server: Tunnelling request to ", dest)
this.udpServer.Dispatch(&proxy.SessionInfo{Source: source, Destination: dest}, request.DetachUDPPayload(), func(destination v2net.Destination, payload *alloc.Buffer) {
this.udpServer.Dispatch(&proxy.SessionInfo{Source: source, Destination: dest}, data, func(destination v2net.Destination, payload *alloc.Buffer) {
defer payload.Release()
response := alloc.NewBuffer().Slice(0, ivLen)
defer response.Release()
rand.Read(response.Value)
respIv := response.Value
stream, err := this.cipher.NewEncodingStream(this.cipherKey, respIv)
data, err := EncodeUDPPacket(request, payload)
if err != nil {
log.Error("Shadowsocks: Failed to create encoding stream: ", err)
log.Warning("Shadowsocks|Server: Failed to encode UDP packet: ", err)
return
}
defer data.Release()
writer := crypto.NewCryptionWriter(stream, response)
switch request.Address.Family() {
case v2net.AddressFamilyIPv4:
writer.Write([]byte{AddrTypeIPv4})
writer.Write(request.Address.IP())
case v2net.AddressFamilyIPv6:
writer.Write([]byte{AddrTypeIPv6})
writer.Write(request.Address.IP())
case v2net.AddressFamilyDomain:
writer.Write([]byte{AddrTypeDomain, byte(len(request.Address.Domain()))})
writer.Write([]byte(request.Address.Domain()))
}
writer.Write(request.Port.Bytes(nil))
writer.Write(payload.Value)
if request.OTA {
respAuth := NewAuthenticator(HeaderKeyGenerator(this.cipherKey, respIv))
respAuth.Authenticate(response.Value, response.Value[ivLen:])
}
this.udpHub.WriteTo(response.Value, source)
this.udpHub.WriteTo(data.Value, source)
})
}
@ -197,41 +135,22 @@ func (this *Server) handleConnection(conn internet.Connection) {
bufferedReader := v2io.NewBufferedReader(timedReader)
defer bufferedReader.Release()
ivLen := this.cipher.IVSize()
_, err := io.ReadFull(bufferedReader, buffer.Value[:ivLen])
if err != nil {
if err != io.EOF {
log.Access(conn.RemoteAddr(), "", log.AccessRejected, err)
log.Warning("Shadowsocks: Failed to read IV: ", err)
}
return
}
iv := buffer.Value[:ivLen]
stream, err := this.cipher.NewDecodingStream(this.cipherKey, iv)
if err != nil {
log.Error("Shadowsocks: Failed to create decoding stream: ", err)
return
}
reader := crypto.NewCryptionReader(stream, bufferedReader)
request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(this.cipherKey, iv)), false)
request, bodyReader, err := ReadTCPSession(this.user, bufferedReader)
if err != nil {
log.Access(conn.RemoteAddr(), "", log.AccessRejected, err)
log.Warning("Shadowsocks: Invalid request from ", conn.RemoteAddr(), ": ", err)
log.Info("Shadowsocks|Server: Failed to create request from: ", conn.RemoteAddr(), ": ", err)
return
}
defer request.Release()
defer bodyReader.Release()
bufferedReader.SetCached(false)
userSettings := this.config.GetUser().GetSettings()
userSettings := this.user.GetSettings()
timedReader.SetTimeOut(userSettings.PayloadReadTimeout)
dest := v2net.TCPDestination(request.Address, request.Port)
dest := request.Destination()
log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, "")
log.Info("Shadowsocks: Tunnelling request to ", dest)
log.Info("Shadowsocks|Server: Tunnelling request to ", dest)
ray := this.packetDispatcher.DispatchToOutbound(this.meta, &proxy.SessionInfo{
Source: v2net.DestinationFromAddr(conn.RemoteAddr()),
@ -242,41 +161,28 @@ func (this *Server) handleConnection(conn internet.Connection) {
var writeFinish sync.Mutex
writeFinish.Lock()
go func() {
if payload, err := ray.InboundOutput().Read(); err == nil {
payload.SliceBack(ivLen)
rand.Read(payload.Value[:ivLen])
defer writeFinish.Unlock()
stream, err := this.cipher.NewEncodingStream(this.cipherKey, payload.Value[:ivLen])
if err != nil {
log.Error("Shadowsocks: Failed to create encoding stream: ", err)
return
}
stream.XORKeyStream(payload.Value[ivLen:], payload.Value[ivLen:])
bufferedWriter := v2io.NewBufferedWriter(conn)
defer bufferedWriter.Release()
conn.Write(payload.Value)
payload.Release()
writer := crypto.NewCryptionWriter(stream, conn)
v2writer := v2io.NewAdaptiveWriter(writer)
v2io.Pipe(ray.InboundOutput(), v2writer)
writer.Release()
v2writer.Release()
responseWriter, err := WriteTCPResponse(request, bufferedWriter)
if err != nil {
log.Warning("Shadowsocks|Server: Failed to write response: ", err)
return
}
defer responseWriter.Release()
if payload, err := ray.InboundOutput().Read(); err == nil {
responseWriter.Write(payload)
bufferedWriter.SetCached(false)
v2io.Pipe(ray.InboundOutput(), responseWriter)
}
writeFinish.Unlock()
}()
var payloadReader v2io.Reader
if request.OTA {
payloadAuth := NewAuthenticator(ChunkKeyGenerator(iv))
payloadReader = NewChunkReader(reader, payloadAuth)
} else {
payloadReader = v2io.NewAdaptiveReader(reader)
}
v2io.Pipe(payloadReader, ray.InboundInput())
v2io.Pipe(bodyReader, ray.InboundInput())
ray.InboundInput().Close()
payloadReader.Release()
writeFinish.Lock()
}
@ -295,7 +201,3 @@ func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *
}
return NewServer(rawConfig.(*ServerConfig), space, meta)
}
func init() {
registry.MustRegisterInboundHandlerCreator(loader.GetType(new(ServerConfig)), new(ServerFactory))
}