1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 09:50:43 +00:00

shadowsocks client

This commit is contained in:
Darien Raymond 2016-10-31 16:35:18 +01:00
parent be4f3d0772
commit c221802963
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
5 changed files with 149 additions and 11 deletions

View File

@ -1,7 +1,11 @@
package shadowsocks
import (
"errors"
"sync"
"v2ray.com/core/common/alloc"
v2io "v2ray.com/core/common/io"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
@ -39,10 +43,96 @@ func (this *Client) Dispatch(destination v2net.Destination, payload *alloc.Buffe
return nil
})
if err != nil {
log.Error("Shadowsocks|Client: Failed to find an available destination:", err)
return err
return errors.New("Shadowsocks|Client: Failed to find an available destination:" + err.Error())
}
log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination())
request := &protocol.RequestHeader{
Version: Version,
Address: destination.Address,
Port: destination.Port,
}
if destination.Network == v2net.Network_TCP {
request.Command = protocol.RequestCommandTCP
} else {
request.Command = protocol.RequestCommandUDP
}
user := server.PickUser()
rawAccount, err := user.GetTypedAccount()
if err != nil {
return errors.New("Shadowsocks|Client: Failed to get a valid user account: " + err.Error())
}
account := rawAccount.(*ShadowsocksAccount)
request.User = user
if account.OneTimeAuth {
request.Option |= RequestOptionOneTimeAuth
}
if request.Command == protocol.RequestCommandTCP {
bufferedWriter := v2io.NewBufferedWriter(conn)
defer bufferedWriter.Release()
bodyWriter, err := WriteTCPRequest(request, bufferedWriter)
defer bodyWriter.Release()
if err != nil {
return errors.New("Shadowsock|Client: Failed to write request: " + err.Error())
}
if err := bodyWriter.Write(payload); err != nil {
return errors.New("Shadowsocks|Client: Failed to write payload: " + err.Error())
}
bufferedWriter.SetCached(false)
v2io.Pipe(ray.OutboundInput(), bodyWriter)
var responseMutex sync.Mutex
responseMutex.Lock()
go func() {
defer responseMutex.Unlock()
responseReader, err := ReadTCPResponse(user, conn)
if err != nil {
log.Warning("Shadowsocks|Client: Failed to read response: " + err.Error())
return
}
v2io.Pipe(responseReader, ray.OutboundOutput())
}()
responseMutex.Lock()
}
if request.Command == protocol.RequestCommandUDP {
writer := &UDPWriter{
Writer: conn,
Request: request,
}
if err := writer.Write(payload); err != nil {
return errors.New("Shadowsocks|Client: Failed to write payload: " + err.Error())
}
v2io.Pipe(ray.OutboundInput(), writer)
timedReader := v2net.NewTimeOutReader(16, conn)
var responseMutex sync.Mutex
responseMutex.Lock()
go func() {
defer responseMutex.Unlock()
reader := &UDPReader{
Reader: timedReader,
User: user,
}
v2io.Pipe(reader, ray.OutboundOutput())
}()
responseMutex.Lock()
}
return nil
}

View File

@ -11,8 +11,9 @@ import (
)
type ShadowsocksAccount struct {
Cipher Cipher
Key []byte
Cipher Cipher
Key []byte
OneTimeAuth bool
}
func (this *ShadowsocksAccount) Equals(another protocol.Account) bool {
@ -43,8 +44,9 @@ func (this *Account) AsAccount() (protocol.Account, error) {
return nil, err
}
return &ShadowsocksAccount{
Cipher: cipher,
Key: this.GetCipherKey(),
Cipher: cipher,
Key: this.GetCipherKey(),
OneTimeAuth: this.Ota == Account_Auto || this.Ota == Account_Enabled,
}, nil
}

View File

@ -342,3 +342,46 @@ func DecodeUDPPacket(user *protocol.User, payload *alloc.Buffer) (*protocol.Requ
return request, payload, nil
}
type UDPReader struct {
Reader io.Reader
User *protocol.User
}
func (this *UDPReader) Read() (*alloc.Buffer, error) {
buffer := alloc.NewLocalBuffer(2048)
nBytes, err := this.Reader.Read(buffer.Value)
if err != nil {
buffer.Release()
return nil, err
}
buffer.Slice(0, nBytes)
_, payload, err := DecodeUDPPacket(this.User, buffer)
if err != nil {
buffer.Release()
return nil, err
}
return payload, nil
}
func (this *UDPReader) Release() {
}
type UDPWriter struct {
Writer io.Writer
Request *protocol.RequestHeader
}
func (this *UDPWriter) Write(buffer *alloc.Buffer) error {
payload, err := EncodeUDPPacket(this.Request, buffer)
if err != nil {
return err
}
_, err = this.Writer.Write(payload.Value)
payload.Release()
return err
}
func (this *UDPWriter) Release() {
}

View File

@ -0,0 +1,5 @@
package shadowsocks_test
import (
// . "v2ray.com/core/proxy/shadowsocks"
)

View File

@ -30,11 +30,9 @@ func TestShadowsocksServerConfigParsing(t *testing.T) {
rawAccount, err := config.User.GetTypedAccount()
assert.Error(err).IsNil()
account, ok := rawAccount.(*shadowsocks.Account)
account, ok := rawAccount.(*shadowsocks.ShadowsocksAccount)
assert.Bool(ok).IsTrue()
cipher, err := account.GetCipher()
assert.Error(err).IsNil()
assert.Int(cipher.KeySize()).Equals(16)
assert.Bytes(account.GetCipherKey()).Equals([]byte{160, 224, 26, 2, 22, 110, 9, 80, 65, 52, 80, 20, 38, 243, 224, 241})
assert.Int(account.Cipher.KeySize()).Equals(16)
assert.Bytes(account.Key).Equals([]byte{160, 224, 26, 2, 22, 110, 9, 80, 65, 52, 80, 20, 38, 243, 224, 241})
}