From bf937b093f9a95db552a94881394e55f796a0abf Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 2 Aug 2013 14:53:35 +0800 Subject: [PATCH 01/16] Fix go test. --- sample-config/server-multi-port.json | 2 +- shadowsocks/config_test.go | 2 +- shadowsocks/encrypt_test.go | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sample-config/server-multi-port.json b/sample-config/server-multi-port.json index 1ef4f645..4f0a5fa9 100644 --- a/sample-config/server-multi-port.json +++ b/sample-config/server-multi-port.json @@ -3,5 +3,5 @@ "8387": "foobar", "8388": "barfoo" }, - "timeout": 600, + "timeout": 600 } diff --git a/shadowsocks/config_test.go b/shadowsocks/config_test.go index ba495a3c..3ac9d2cc 100644 --- a/shadowsocks/config_test.go +++ b/shadowsocks/config_test.go @@ -25,7 +25,7 @@ func TestConfigJson(t *testing.T) { func TestServerMultiPort(t *testing.T) { config, err := ParseConfig("../sample-config/server-multi-port.json") if err != nil { - t.Fatal("error parsing multi server-multi-port.json:", err) + t.Fatal("error parsing ../sample-config/server-multi-port.json:", err) } if config.PortPassword["8387"] != "foobar" { diff --git a/shadowsocks/encrypt_test.go b/shadowsocks/encrypt_test.go index c000cd11..b2583d3a 100644 --- a/shadowsocks/encrypt_test.go +++ b/shadowsocks/encrypt_test.go @@ -163,30 +163,30 @@ func benchmarkCipherInit(b *testing.B, ci *cipherInfo) { func BenchmarkAES128Init(b *testing.B) { ci := cipherMethod["aes-128-cfb"] - benchmarkCipherInit(b, &ci) + benchmarkCipherInit(b, ci) } func BenchmarkAES192Init(b *testing.B) { ci := cipherMethod["aes-192-cfb"] - benchmarkCipherInit(b, &ci) + benchmarkCipherInit(b, ci) } func BenchmarkAES256Init(b *testing.B) { ci := cipherMethod["aes-256-cfb"] - benchmarkCipherInit(b, &ci) + benchmarkCipherInit(b, ci) } func BenchmarkBlowFishInit(b *testing.B) { ci := cipherMethod["bf-cfb"] - benchmarkCipherInit(b, &ci) + benchmarkCipherInit(b, ci) } func BenchmarkCast5Init(b *testing.B) { ci := cipherMethod["bf-cfb"] - benchmarkCipherInit(b, &ci) + benchmarkCipherInit(b, ci) } func BenchmarkDESInit(b *testing.B) { ci := cipherMethod["des-cfb"] - benchmarkCipherInit(b, &ci) + benchmarkCipherInit(b, ci) } From 1f6548024c1e9e709055e9eb52f3fadca639b309 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 2 Aug 2013 15:00:56 +0800 Subject: [PATCH 02/16] Update test script to use shadowsocks-nodejs from npm. --- script/test.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/script/test.sh b/script/test.sh index 0286a0a0..8481927d 100755 --- a/script/test.sh +++ b/script/test.sh @@ -91,16 +91,12 @@ LOCAL="shadowsocks-local" test_server_local_pair if [[ -n $SS_NODEJS ]]; then - pushd $SS_NODEJS - - SERVER="node server.js" + SERVER="ssserver" LOCAL="shadowsocks-local" test_server_local_pair SERVER="shadowsocks-server" - LOCAL="node local.js" + LOCAL="sslocal" test_server_local_pair - - popd $SS_NODEJS fi From bb0ce1854590d2b2e1d7de404ceed0b62e20f26c Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 2 Aug 2013 15:05:57 +0800 Subject: [PATCH 03/16] Do a single write to send both iv and data. --- shadowsocks/conn.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/shadowsocks/conn.go b/shadowsocks/conn.go index fbd124a9..59e97ba0 100644 --- a/shadowsocks/conn.go +++ b/shadowsocks/conn.go @@ -84,18 +84,23 @@ func (c Conn) Read(b []byte) (n int, err error) { } func (c Conn) Write(b []byte) (n int, err error) { + var cipherData []byte + dataStart := 0 if c.enc == nil { var iv []byte iv, err = c.initEncrypt() if err != nil { return } - if _, err = c.Conn.Write(iv); err != nil { - return - } + // Put initialization vector in buffer, do a single write to send both + // iv and data. + cipherData = make([]byte, len(b)+len(iv)) + copy(cipherData, iv) + dataStart = len(iv) + } else { + cipherData = make([]byte, len(b)) } - cipherData := make([]byte, len(b)) - c.encrypt(cipherData, b) + c.encrypt(cipherData[dataStart:], b) n, err = c.Conn.Write(cipherData) return } From ac3abd30d6566b1c3a567e22e6fb79d1207889aa Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 2 Aug 2013 15:32:18 +0800 Subject: [PATCH 04/16] Use method "aes-256-cfb" in sample config. --- config.json | 1 + sample-config/client-multi-server.json | 2 +- sample-config/server-multi-port.json | 1 + shadowsocks/config_test.go | 11 +++++++---- shadowsocks/testdata/config.json | 6 ------ 5 files changed, 10 insertions(+), 11 deletions(-) delete mode 100644 shadowsocks/testdata/config.json diff --git a/config.json b/config.json index 0a9f3193..95e79bcf 100644 --- a/config.json +++ b/config.json @@ -3,5 +3,6 @@ "server_port":8388, "local_port":1080, "password":"barfoo!", + "method": "aes-256-cfb", "timeout":600 } diff --git a/sample-config/client-multi-server.json b/sample-config/client-multi-server.json index 3b534e1b..3651fad8 100644 --- a/sample-config/client-multi-server.json +++ b/sample-config/client-multi-server.json @@ -2,6 +2,6 @@ "local_port":1081, "server_password": [ ["127.0.0.1:8387", "foobar"], - ["127.0.0.1:8388", "barfoo", "rc4"] + ["127.0.0.1:8388", "barfoo", "aes-256-cfb"] ] } diff --git a/sample-config/server-multi-port.json b/sample-config/server-multi-port.json index 4f0a5fa9..9a68cc3d 100644 --- a/sample-config/server-multi-port.json +++ b/sample-config/server-multi-port.json @@ -3,5 +3,6 @@ "8387": "foobar", "8388": "barfoo" }, + "method": "aes-256-cfb", "timeout": 600 } diff --git a/shadowsocks/config_test.go b/shadowsocks/config_test.go index 3ac9d2cc..90aaf8f5 100644 --- a/shadowsocks/config_test.go +++ b/shadowsocks/config_test.go @@ -5,7 +5,7 @@ import ( ) func TestConfigJson(t *testing.T) { - config, err := ParseConfig("testdata/config.json") + config, err := ParseConfig("../config.json") if err != nil { t.Fatal("error parsing config.json:", err) } @@ -13,8 +13,11 @@ func TestConfigJson(t *testing.T) { if config.Password != "barfoo!" { t.Error("wrong password from config") } - if config.Timeout != 0 { - t.Error("tiemout should default to 0") + if config.Timeout != 600 { + t.Error("timeout should be 600") + } + if config.Method != "aes-256-cfb" { + t.Error("method should be aes-256-cfb") } srvArr := config.GetServerArray() if len(srvArr) != 1 || srvArr[0] != "127.0.0.1" { @@ -85,7 +88,7 @@ func TestClientMultiServerArray(t *testing.T) { if sv[1] != "barfoo" { t.Error("server_password 2nd server passwd wrong") } - if sv[2] != "rc4" { + if sv[2] != "aes-256-cfb" { t.Error("server_password 2nd server enc method wrong") } } diff --git a/shadowsocks/testdata/config.json b/shadowsocks/testdata/config.json deleted file mode 100644 index c6c0acf1..00000000 --- a/shadowsocks/testdata/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "server":"127.0.0.1", - "server_port":8388, - "local_port":1081, - "password":"barfoo!" -} From 808754ab9d11e069a7540d6d746a3bb2dbf8098a Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Thu, 12 Sep 2013 10:23:35 +0800 Subject: [PATCH 05/16] Fix issue 19: 32-bit deb arch name should be i386. --- script/build.sh | 22 +++++++++++----------- script/createdeb.sh | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/script/build.sh b/script/build.sh index 75d00ec8..b0d41fed 100755 --- a/script/build.sh +++ b/script/build.sh @@ -43,19 +43,19 @@ build() { popd } -build darwin amd64 mac64 local -build linux amd64 linux64 local -build linux 386 linux32 local -build windows amd64 win64 local -build windows 386 win32 local - -build linux amd64 linux64 server -build linux 386 linux32 server +#build darwin amd64 mac64 local +#build linux amd64 linux64 local +#build linux 386 linux32 local +#build windows amd64 win64 local +#build windows 386 win32 local + +#build linux amd64 linux64 server +#build linux 386 linux32 server #build darwin amd64 mac64 server -build windows amd64 win64 server -build windows 386 win32 server +#build windows amd64 win64 server +#build windows 386 win32 server script/createdeb.sh amd64 -script/createdeb.sh 386 +script/createdeb.sh i386 mv shadowsocks-go_$version-1-*.deb bin/ rm -rf shadowsocks-go_$version-1* diff --git a/script/createdeb.sh b/script/createdeb.sh index fb022789..92a061c8 100755 --- a/script/createdeb.sh +++ b/script/createdeb.sh @@ -13,7 +13,7 @@ export GOOS=linux arch=$1 case $arch in - 386) + i386) export GOARCH=386 ;; amd64) From 6d5b35bcba7b99bcd549717602b5960cdb3ece74 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Mon, 7 Oct 2013 15:45:45 +0800 Subject: [PATCH 06/16] Define Conn Read/Write as method on pointer. --- shadowsocks/conn.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks/conn.go b/shadowsocks/conn.go index 59e97ba0..e29e3444 100644 --- a/shadowsocks/conn.go +++ b/shadowsocks/conn.go @@ -65,7 +65,7 @@ func Dial(addr, server string, cipher *Cipher) (c *Conn, err error) { return DialWithRawAddr(ra, server, cipher) } -func (c Conn) Read(b []byte) (n int, err error) { +func (c *Conn) Read(b []byte) (n int, err error) { if c.dec == nil { iv := make([]byte, c.info.ivLen) if _, err = io.ReadFull(c.Conn, iv); err != nil { @@ -83,7 +83,7 @@ func (c Conn) Read(b []byte) (n int, err error) { return } -func (c Conn) Write(b []byte) (n int, err error) { +func (c *Conn) Write(b []byte) (n int, err error) { var cipherData []byte dataStart := 0 if c.enc == nil { From f4a608015947ac592868289abee30c50f2fcb510 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Tue, 8 Oct 2013 21:46:43 +0800 Subject: [PATCH 07/16] Accept both "table" and "" as encryption method. --- shadowsocks/encrypt.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shadowsocks/encrypt.go b/shadowsocks/encrypt.go index c189d77f..b3eecc8d 100644 --- a/shadowsocks/encrypt.go +++ b/shadowsocks/encrypt.go @@ -117,10 +117,13 @@ var cipherMethod = map[string]*cipherInfo{ "cast5-cfb": {16, 8, newCast5Cipher}, "des-cfb": {8, 8, des.NewCipher}, "rc4": {16, 0, nil}, - "": {16, 0, nil}, // table encryption + "table": {16, 0, nil}, } func CheckCipherMethod(method string) error { + if method == "" { + method = "table" + } _, ok := cipherMethod[method] if !ok { return errors.New("Unsupported encryption method: " + method) @@ -142,6 +145,9 @@ func NewCipher(method, password string) (c *Cipher, err error) { if password == "" { return nil, errEmptyPassword } + if method == "" { + method = "table" + } mi, ok := cipherMethod[method] if !ok { return nil, errors.New("Unsupported encryption method: " + method) @@ -152,7 +158,7 @@ func NewCipher(method, password string) (c *Cipher, err error) { c = &Cipher{key: key, info: mi} if mi.newBlock == nil { - if method == "" { + if method == "table" { c.enc, c.dec = newTableCipher(key) } else if method == "rc4" { c.enc, c.dec, err = newRC4Cipher(key) From 5998d5bf5b2402e348fda2a6bbd6d328bf9c2c4f Mon Sep 17 00:00:00 2001 From: lidashuang Date: Tue, 11 Mar 2014 15:52:29 +0800 Subject: [PATCH 08/16] fmt.Errorf() replace errors.New() and fmt.Errorf() --- cmd/shadowsocks-server/server.go | 2 +- shadowsocks/conn.go | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd/shadowsocks-server/server.go b/cmd/shadowsocks-server/server.go index a7889c1e..cb308cdf 100644 --- a/cmd/shadowsocks-server/server.go +++ b/cmd/shadowsocks-server/server.go @@ -57,7 +57,7 @@ func getRequest(conn *ss.Conn) (host string, extra []byte, err error) { case typeDm: reqLen = int(buf[idDmLen]) + lenDmBase default: - err = errors.New(fmt.Sprintf("addr type %d not supported", buf[idType])) + err = fmt.Errorf("addr type %d not supported", buf[idType]) return } diff --git a/shadowsocks/conn.go b/shadowsocks/conn.go index e29e3444..b0b58e75 100644 --- a/shadowsocks/conn.go +++ b/shadowsocks/conn.go @@ -2,7 +2,6 @@ package shadowsocks import ( "encoding/binary" - "errors" "fmt" "io" "net" @@ -21,13 +20,11 @@ func NewConn(cn net.Conn, cipher *Cipher) *Conn { func RawAddr(addr string) (buf []byte, err error) { host, portStr, err := net.SplitHostPort(addr) if err != nil { - return nil, errors.New( - fmt.Sprintf("shadowsocks: address error %s %v", addr, err)) + return nil, fmt.Errorf("shadowsocks: address error %s %v", addr, err) } port, err := strconv.Atoi(portStr) if err != nil { - return nil, errors.New( - fmt.Sprintf("shadowsocks: invalid port %s", addr)) + return nil, fmt.Errorf("shadowsocks: invalid port %s", addr) } hostLen := len(host) From 211bdfc36a81ab80a19f54e8adb48777ec0fa325 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Sat, 5 Apr 2014 23:21:53 +0800 Subject: [PATCH 09/16] Recommend to use aes-128-cfb. --- README.md | 4 ++-- config.json | 2 +- sample-config/client-multi-server.json | 4 ++-- sample-config/server-multi-port.json | 2 +- shadowsocks/config_test.go | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 20a0f81f..abcacf09 100644 --- a/README.md +++ b/README.md @@ -51,9 +51,9 @@ SOCKS5 127.0.0.1:local_port ## About encryption methods -AES is recommended for shadowsocks-go. ([Intel AES Instruction Set](http://en.wikipedia.org/wiki/AES_instruction_set) will be used if available and can make encryption/decryption fast.) +AES is recommended for shadowsocks-go. [Intel AES Instruction Set](http://en.wikipedia.org/wiki/AES_instruction_set) will be used if available and can make encryption/decryption very fast. To be more specific, **`aes-128-cfb` is recommended as it is faster and [secure enough](https://www.schneier.com/blog/archives/2009/07/another_new_aes.html)**. -**rc4 and table encryption methods are deprecated because they are not secure**. +**rc4 and table encryption methods are deprecated because they are not secure.** ## Command line options diff --git a/config.json b/config.json index 95e79bcf..8475f08d 100644 --- a/config.json +++ b/config.json @@ -3,6 +3,6 @@ "server_port":8388, "local_port":1080, "password":"barfoo!", - "method": "aes-256-cfb", + "method": "aes-128-cfb", "timeout":600 } diff --git a/sample-config/client-multi-server.json b/sample-config/client-multi-server.json index 3651fad8..21e20580 100644 --- a/sample-config/client-multi-server.json +++ b/sample-config/client-multi-server.json @@ -1,7 +1,7 @@ { - "local_port":1081, + "local_port": 1081, "server_password": [ ["127.0.0.1:8387", "foobar"], - ["127.0.0.1:8388", "barfoo", "aes-256-cfb"] + ["127.0.0.1:8388", "barfoo", "aes-128-cfb"] ] } diff --git a/sample-config/server-multi-port.json b/sample-config/server-multi-port.json index 9a68cc3d..39ac351f 100644 --- a/sample-config/server-multi-port.json +++ b/sample-config/server-multi-port.json @@ -3,6 +3,6 @@ "8387": "foobar", "8388": "barfoo" }, - "method": "aes-256-cfb", + "method": "aes-128-cfb", "timeout": 600 } diff --git a/shadowsocks/config_test.go b/shadowsocks/config_test.go index 90aaf8f5..1dcef0cf 100644 --- a/shadowsocks/config_test.go +++ b/shadowsocks/config_test.go @@ -16,8 +16,8 @@ func TestConfigJson(t *testing.T) { if config.Timeout != 600 { t.Error("timeout should be 600") } - if config.Method != "aes-256-cfb" { - t.Error("method should be aes-256-cfb") + if config.Method != "aes-128-cfb" { + t.Error("method should be aes-128-cfb") } srvArr := config.GetServerArray() if len(srvArr) != 1 || srvArr[0] != "127.0.0.1" { @@ -88,7 +88,7 @@ func TestClientMultiServerArray(t *testing.T) { if sv[1] != "barfoo" { t.Error("server_password 2nd server passwd wrong") } - if sv[2] != "aes-256-cfb" { + if sv[2] != "aes-128-cfb" { t.Error("server_password 2nd server enc method wrong") } } From 9064175f2a008a755da8e2f8201cf51e99fcd727 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Wed, 10 Sep 2014 23:42:36 +0800 Subject: [PATCH 10/16] Remove dependency on leakybuf by importing code. --- shadowsocks/leakybuf.go | 40 ++++++++++++++++++++++++++++++++++++++++ shadowsocks/pipe.go | 3 +-- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 shadowsocks/leakybuf.go diff --git a/shadowsocks/leakybuf.go b/shadowsocks/leakybuf.go new file mode 100644 index 00000000..3c7dd8c5 --- /dev/null +++ b/shadowsocks/leakybuf.go @@ -0,0 +1,40 @@ +// Provides leaky buffer, based on the example in Effective Go. +package shadowsocks + +type LeakyBuf struct { + bufSize int // size of each buffer + freeList chan []byte +} + +// NewLeakyBuf creates a leaky buffer which can hold at most n buffer, each +// with bufSize bytes. +func NewLeakyBuf(n, bufSize int) *LeakyBuf { + return &LeakyBuf{ + bufSize: bufSize, + freeList: make(chan []byte, n), + } +} + +// Get returns a buffer from the leaky buffer or create a new buffer. +func (lb *LeakyBuf) Get() (b []byte) { + select { + case b = <-lb.freeList: + default: + b = make([]byte, lb.bufSize) + } + return +} + +// Put add the buffer into the free buffer pool for reuse. Panic if the buffer +// size is not the same with the leaky buffer's. This is intended to expose +// error usage of leaky buffer. +func (lb *LeakyBuf) Put(b []byte) { + if len(b) != lb.bufSize { + panic("invalid buffer size that's put into leaky buffer") + } + select { + case lb.freeList <- b: + default: + } + return +} diff --git a/shadowsocks/pipe.go b/shadowsocks/pipe.go index f41ce8f7..35f356f6 100644 --- a/shadowsocks/pipe.go +++ b/shadowsocks/pipe.go @@ -2,7 +2,6 @@ package shadowsocks import ( // "io" - "github.com/cyfdecyf/leakybuf" "net" "time" ) @@ -21,7 +20,7 @@ func SetReadTimeout(c net.Conn) { const bufSize = 4096 const nBuf = 2048 -var pipeBuf = leakybuf.NewLeakyBuf(nBuf, bufSize) +var pipeBuf = NewLeakyBuf(nBuf, bufSize) // PipeThenClose copies data from src to dst, closes dst when done. func PipeThenClose(src, dst net.Conn, timeoutOpt int) { From 8c8895e1e450801134d052fb4117e464018e8a93 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Wed, 17 Sep 2014 22:43:09 +0800 Subject: [PATCH 11/16] Create cipher stream for different encrypt method. --- shadowsocks/encrypt.go | 81 ++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/shadowsocks/encrypt.go b/shadowsocks/encrypt.go index b3eecc8d..8be06a90 100644 --- a/shadowsocks/encrypt.go +++ b/shadowsocks/encrypt.go @@ -89,33 +89,57 @@ func newRC4Cipher(key []byte) (enc, dec cipher.Stream, err error) { return rc4Enc, &rc4Dec, nil } -// Ciphers from go.crypto has NewCipher returning specific type of cipher -// instead of cipher.Block, so we need to have the following adapter -// functions. -// The specific cipher types makes it possible to use Copy to optimize cipher -// initialization. +type DecOrEnc int -func newBlowFishCipher(key []byte) (cipher.Block, error) { - return blowfish.NewCipher(key) +const ( + Decrypt DecOrEnc = iota + Encrypt +) + +func newStream(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 newAESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { + block, err := aes.NewCipher(key) + return newStream(block, err, key, iv, doe) } -func newCast5Cipher(key []byte) (cipher.Block, error) { - return cast5.NewCipher(key) +func newDESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { + block, err := des.NewCipher(key) + return newStream(block, err, key, iv, doe) +} + +func newBlowFishStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { + block, err := blowfish.NewCipher(key) + return newStream(block, err, key, iv, doe) +} + +func newCast5Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { + block, err := cast5.NewCipher(key) + return newStream(block, err, key, iv, doe) } type cipherInfo struct { - keyLen int - ivLen int - newBlock func([]byte) (cipher.Block, error) + keyLen int + ivLen int + newStream func(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) } var cipherMethod = map[string]*cipherInfo{ - "aes-128-cfb": {16, 16, aes.NewCipher}, - "aes-192-cfb": {24, 16, aes.NewCipher}, - "aes-256-cfb": {32, 16, aes.NewCipher}, - "bf-cfb": {16, 8, newBlowFishCipher}, - "cast5-cfb": {16, 8, newCast5Cipher}, - "des-cfb": {8, 8, des.NewCipher}, + "aes-128-cfb": {16, 16, newAESStream}, + "aes-192-cfb": {24, 16, newAESStream}, + "aes-256-cfb": {32, 16, newAESStream}, + "bf-cfb": {16, 8, newBlowFishStream}, + "cast5-cfb": {16, 8, newCast5Stream}, + "des-cfb": {8, 8, newDESStream}, "rc4": {16, 0, nil}, "table": {16, 0, nil}, } @@ -157,7 +181,7 @@ func NewCipher(method, password string) (c *Cipher, err error) { c = &Cipher{key: key, info: mi} - if mi.newBlock == nil { + if mi.newStream == nil { if method == "table" { c.enc, c.dec = newTableCipher(key) } else if method == "rc4" { @@ -171,26 +195,21 @@ func NewCipher(method, password string) (c *Cipher, err error) { } // Initializes the block cipher with CFB mode, returns IV. -func (c *Cipher) initEncrypt() ([]byte, error) { - iv := make([]byte, c.info.ivLen) +func (c *Cipher) initEncrypt() (iv []byte, err error) { + iv = make([]byte, c.info.ivLen) if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } - block, err := c.info.newBlock(c.key) + c.enc, err = c.info.newStream(c.key, iv, Encrypt) if err != nil { return nil, err } - c.enc = cipher.NewCFBEncrypter(block, iv) - return iv, nil + return } -func (c *Cipher) initDecrypt(iv []byte) error { - block, err := c.info.newBlock(c.key) - if err != nil { - return err - } - c.dec = cipher.NewCFBDecrypter(block, iv) - return nil +func (c *Cipher) initDecrypt(iv []byte) (err error) { + c.dec, err = c.info.newStream(c.key, iv, Decrypt) + return } func (c *Cipher) encrypt(dst, src []byte) { From dd6f7da1ac8237ab7f5f012b593e4221eafdba8c Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Sun, 21 Sep 2014 10:12:04 +0800 Subject: [PATCH 12/16] New encryption method rc4-md5. --- shadowsocks/encrypt.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/shadowsocks/encrypt.go b/shadowsocks/encrypt.go index 8be06a90..a5bf34b6 100644 --- a/shadowsocks/encrypt.go +++ b/shadowsocks/encrypt.go @@ -96,7 +96,8 @@ const ( Encrypt ) -func newStream(block cipher.Block, err error, key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { +func newStream(block cipher.Block, err error, key, iv []byte, + doe DecOrEnc) (cipher.Stream, error) { if err != nil { return nil, err } @@ -127,6 +128,15 @@ func newCast5Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) { return newStream(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) +} + type cipherInfo struct { keyLen int ivLen int @@ -137,9 +147,10 @@ var cipherMethod = map[string]*cipherInfo{ "aes-128-cfb": {16, 16, newAESStream}, "aes-192-cfb": {24, 16, newAESStream}, "aes-256-cfb": {32, 16, newAESStream}, + "des-cfb": {8, 8, newDESStream}, "bf-cfb": {16, 8, newBlowFishStream}, "cast5-cfb": {16, 8, newCast5Stream}, - "des-cfb": {8, 8, newDESStream}, + "rc4-md5": {16, 16, newRC4MD5Stream}, "rc4": {16, 0, nil}, "table": {16, 0, nil}, } From 3ffa3a111376098bfbddd8817e8135b224e4eb33 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Sun, 21 Sep 2014 10:13:15 +0800 Subject: [PATCH 13/16] Use shadowsocks-py to test compatibility. --- script/http.go | 21 ++++++++++++++++ script/test.sh | 66 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 script/http.go diff --git a/script/http.go b/script/http.go new file mode 100644 index 00000000..6ae6f4d7 --- /dev/null +++ b/script/http.go @@ -0,0 +1,21 @@ +/* Simple http server for testing. */ +package main + +import ( + "fmt" + "net/http" + "os" +) + +func handler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello, shadowsocks-go!") +} + +func main() { + if len(os.Args) != 2 { + fmt.Println("Usage: http ") + os.Exit(1) + } + http.HandleFunc("/", handler) + http.ListenAndServe("127.0.0.1:"+os.Args[1], nil) +} diff --git a/script/test.sh b/script/test.sh index 8481927d..307c4b4f 100755 --- a/script/test.sh +++ b/script/test.sh @@ -1,8 +1,22 @@ #!/bin/bash +# Run in the scripts directory. +cd "$( dirname "${BASH_SOURCE[0]}" )" + OPTION="-p 8389 -k foobar" LOCAL_PORT="1090" SOCKS="127.0.0.1:$LOCAL_PORT" +HTTP_PORT="8123" + +start_http_server() { + go build http.go + ./http $HTTP_PORT & + http_pid=$! +} + +stop_http_server() { + kill -SIGTERM $http_pid +} test_get() { local url @@ -45,23 +59,32 @@ test_shadowsocks() { $LOCAL $OPTION -s 127.0.0.1 -l $LOCAL_PORT -m "$method" & local_pid=$! - # wait server and client finish startup - sleep 1 + # Wait server and client finish startup. + sleeptime=0.1 + if echo $SERVER $LOCAL | grep 'py'; then + # The python version is slow to start. + if [[ $method == "table" ]]; then + sleeptime=2 + else + sleeptime=0.5 + fi + fi + sleep $sleeptime for i in {1..3}; do - if ! test_get $url " Date: Sun, 21 Sep 2014 11:48:49 +0800 Subject: [PATCH 14/16] Use aes-256-cfb as default encryption method. --- cmd/shadowsocks-local/local.go | 2 +- cmd/shadowsocks-server/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/shadowsocks-local/local.go b/cmd/shadowsocks-local/local.go index 68ec07dc..e0336a4f 100644 --- a/cmd/shadowsocks-local/local.go +++ b/cmd/shadowsocks-local/local.go @@ -355,7 +355,7 @@ func main() { flag.StringVar(&cmdConfig.Password, "k", "", "password") flag.IntVar(&cmdConfig.ServerPort, "p", 0, "server port") flag.IntVar(&cmdConfig.LocalPort, "l", 0, "local socks5 proxy port") - flag.StringVar(&cmdConfig.Method, "m", "", "encryption method, use empty string or rc4") + flag.StringVar(&cmdConfig.Method, "m", "aes-256-cfb", "encryption method") flag.BoolVar((*bool)(&debug), "d", false, "print debug message") flag.Parse() diff --git a/cmd/shadowsocks-server/server.go b/cmd/shadowsocks-server/server.go index cb308cdf..391d2b21 100644 --- a/cmd/shadowsocks-server/server.go +++ b/cmd/shadowsocks-server/server.go @@ -322,7 +322,7 @@ func main() { flag.StringVar(&cmdConfig.Password, "k", "", "password") flag.IntVar(&cmdConfig.ServerPort, "p", 0, "server port") flag.IntVar(&cmdConfig.Timeout, "t", 60, "connection timeout (in seconds)") - flag.StringVar(&cmdConfig.Method, "m", "", "encryption method, use empty string or rc4") + flag.StringVar(&cmdConfig.Method, "m", "aes-256-cfb", "encryption method") flag.IntVar(&core, "core", 0, "maximum number of CPU cores to use, default is determinied by Go runtime") flag.BoolVar((*bool)(&debug), "d", false, "print debug message") From 5052b3ef25218c8113d0a7518a42404cc3b02f6c Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Sun, 21 Sep 2014 10:22:34 +0800 Subject: [PATCH 15/16] Fix Travis-CI test. --- .travis.yml | 7 +------ script/test.sh | 6 +++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 503d829f..a9648dbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,10 @@ language: go go: - - 1.1 + - 1.3 install: - - go get github.com/cyfdecyf/leakybuf - go get code.google.com/p/go.crypto/blowfish - go get code.google.com/p/go.crypto/cast5 - - pushd $TRAVIS_BUILD_DIR - go install ./cmd/shadowsocks-local - go install ./cmd/shadowsocks-server - - popd script: - - pushd $TRAVIS_BUILD_DIR - PATH=$PATH:$HOME/gopath/bin bash -x ./script/test.sh - - popd diff --git a/script/test.sh b/script/test.sh index 307c4b4f..4a288327 100755 --- a/script/test.sh +++ b/script/test.sh @@ -61,7 +61,10 @@ test_shadowsocks() { # Wait server and client finish startup. sleeptime=0.1 - if echo $SERVER $LOCAL | grep 'py'; then + if [ -n "$TRAVIS" ]; then + # On Travis we need to wait a little longer. + sleeptime=1 + elif echo $SERVER $LOCAL | grep 'py'; then # The python version is slow to start. if [[ $method == "table" ]]; then sleeptime=2 @@ -69,6 +72,7 @@ test_shadowsocks() { sleeptime=0.5 fi fi + echo $sleeptime sleep $sleeptime for i in {1..3}; do From fb3fcfac2d9652a32de77370b1e3f8a3d57a666c Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Sun, 21 Sep 2014 11:34:30 +0800 Subject: [PATCH 16/16] Bump version to 1.1.2 --- CHANGELOG | 4 ++++ README.md | 12 ++++++------ script/build.sh | 32 ++++++++++++++++---------------- shadowsocks/util.go | 2 +- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e9f800cb..72826e95 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +1.1.2 (2014-09-21) + * Support new encryption method "rc4-md5" + * Use aes-256-cfb as default encryption method for command line app + 1.1.1 (2013-07-12) * Add -b option to limit listen address for client * Fix can't override server address on command line diff --git a/README.md b/README.md index abcacf09..7106909a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # shadowsocks-go -Current version: 1.1.1 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png?branch=develop)](https://travis-ci.org/shadowsocks/shadowsocks-go) +Current version: 1.1.2 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png?branch=develop)](https://travis-ci.org/shadowsocks/shadowsocks-go) shadowsocks-go is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks). @@ -23,7 +23,7 @@ go get github.com/shadowsocks/shadowsocks-go/cmd/shadowsocks-server go get github.com/shadowsocks/shadowsocks-go/cmd/shadowsocks-local ``` -It's recommend to disable cgo when compiling shadowsocks-go. This will prevent the go runtime from creating too many threads for dns lookup. +It's recommended to disable cgo when compiling shadowsocks-go. This will prevent the go runtime from creating too many threads for dns lookup. # Usage @@ -35,8 +35,8 @@ Configuration file is in json format and has the same syntax with [shadowsocks-n server your server ip or hostname server_port server port local_port local socks5 proxy port -method encryption method, null by default, the following methods are supported: - aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb, rc4 +method encryption method, null by default (table), the following methods are supported: + aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb, rc4-md5, rc4, table password a password used to encrypt transfer timeout server option, in seconds ``` @@ -61,10 +61,10 @@ Command line options can override settings from configuration files. Use `-h` op ``` shadowsocks-local -s server_address -p server_port -k password - -m rc4 -c config.json + -m aes-128-cfb -c config.json -b local_address -l local_port shadowsocks-server -p server_port -k password - -m rc4 -c config.json + -m aes-128-cfb -c config.json -t timeout ``` diff --git a/script/build.sh b/script/build.sh index b0d41fed..207b4cfa 100755 --- a/script/build.sh +++ b/script/build.sh @@ -43,19 +43,19 @@ build() { popd } -#build darwin amd64 mac64 local -#build linux amd64 linux64 local -#build linux 386 linux32 local -#build windows amd64 win64 local -#build windows 386 win32 local - -#build linux amd64 linux64 server -#build linux 386 linux32 server -#build darwin amd64 mac64 server -#build windows amd64 win64 server -#build windows 386 win32 server - -script/createdeb.sh amd64 -script/createdeb.sh i386 -mv shadowsocks-go_$version-1-*.deb bin/ -rm -rf shadowsocks-go_$version-1* +build darwin amd64 mac64 local +build linux amd64 linux64 local +build linux 386 linux32 local +build windows amd64 win64 local +build windows 386 win32 local + +build linux amd64 linux64 server +build linux 386 linux32 server +build darwin amd64 mac64 server +build windows amd64 win64 server +build windows 386 win32 server + +#script/createdeb.sh amd64 +#script/createdeb.sh i386 +#mv shadowsocks-go_$version-1-*.deb bin/ +#rm -rf shadowsocks-go_$version-1* diff --git a/shadowsocks/util.go b/shadowsocks/util.go index 801b966a..a026e9f2 100644 --- a/shadowsocks/util.go +++ b/shadowsocks/util.go @@ -7,7 +7,7 @@ import ( ) func PrintVersion() { - const version = "1.1.1" + const version = "1.1.2" fmt.Println("shadowsocks-go version", version) }