Skip to content
This repository was archived by the owner on Apr 9, 2020. It is now read-only.

Commit 4a42939

Browse files
committed
Merge branch 'develop', version 1.1.4
2 parents 8920bf8 + d4a6a12 commit 4a42939

File tree

14 files changed

+273
-60
lines changed

14 files changed

+273
-60
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
*.deb
2+
script/http

.travis.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
language: go
22
go:
3-
- 1.3
3+
- 1.4.2
44
install:
55
- go get golang.org/x/crypto/blowfish
66
- go get golang.org/x/crypto/cast5
7+
- go get golang.org/x/crypto/salsa20
8+
- go get github.com/codahale/chacha20
79
- go install ./cmd/shadowsocks-local
810
- go install ./cmd/shadowsocks-server
911
script:

CHANGELOG

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
1.1.4 (2015-05-10)
2+
* Support "chacha20" encryption method, thanks to @defia
3+
* Support "salsa20" encryption method, thanks to @genzj
4+
* Fix go 1.4 canonical import paths, thanks to @ddatsh
5+
* Exit if port not bindable, thanks to @thomasf
6+
* More buffer reuse
7+
18
1.1.3 (2014-09-28)
29
* Fix can't specify encryption method in config file
310

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# shadowsocks-go
22

3-
Current version: 1.1.3 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png?branch=master)](https://travis-ci.org/shadowsocks/shadowsocks-go)
3+
Current version: 1.1.4 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png?branch=master)](https://travis-ci.org/shadowsocks/shadowsocks-go)
44

55
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).
66

@@ -36,7 +36,7 @@ server your server ip or hostname
3636
server_port server port
3737
local_port local socks5 proxy port
3838
method encryption method, null by default (table), the following methods are supported:
39-
aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb, rc4-md5, rc4, table
39+
aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb, rc4-md5, chacha20, salsa20, rc4, table
4040
password a password used to encrypt transfer
4141
timeout server option, in seconds
4242
```

cmd/shadowsocks-local/local.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func handShake(conn net.Conn) (err error) {
4949
buf := make([]byte, 258)
5050

5151
var n int
52+
ss.SetReadTimeout(conn)
5253
// make sure we get the nmethod field
5354
if n, err = io.ReadAtLeast(conn, buf, idNmethod+1); err != nil {
5455
return
@@ -92,6 +93,7 @@ func getRequest(conn net.Conn) (rawaddr []byte, host string, err error) {
9293
// refer to getRequest in server.go for why set buffer size to 263
9394
buf := make([]byte, 263)
9495
var n int
96+
ss.SetReadTimeout(conn)
9597
// read till we get possible domain length field
9698
if n, err = io.ReadAtLeast(conn, buf, idDmLen+1); err != nil {
9799
return
@@ -314,8 +316,8 @@ func handleConnection(conn net.Conn) {
314316
}
315317
}()
316318

317-
go ss.PipeThenClose(conn, remote, ss.NO_TIMEOUT)
318-
ss.PipeThenClose(remote, conn, ss.NO_TIMEOUT)
319+
go ss.PipeThenClose(conn, remote)
320+
ss.PipeThenClose(remote, conn)
319321
closed = true
320322
debug.Println("closed connection to", addr)
321323
}
@@ -354,6 +356,7 @@ func main() {
354356
flag.StringVar(&cmdLocal, "b", "", "local address, listen only to this address if specified")
355357
flag.StringVar(&cmdConfig.Password, "k", "", "password")
356358
flag.IntVar(&cmdConfig.ServerPort, "p", 0, "server port")
359+
flag.IntVar(&cmdConfig.Timeout, "t", 300, "timeout in seconds")
357360
flag.IntVar(&cmdConfig.LocalPort, "l", 0, "local socks5 proxy port")
358361
flag.StringVar(&cmdConfig.Method, "m", "", "encryption method, default: aes-256-cfb")
359362
flag.BoolVar((*bool)(&debug), "d", false, "print debug message")

cmd/shadowsocks-server/server.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import (
1919

2020
var debug ss.DebugLog
2121

22-
const dnsGoroutineNum = 64
23-
2422
func getRequest(conn *ss.Conn) (host string, extra []byte, err error) {
2523
const (
2624
idType = 0 // address type index
@@ -62,7 +60,6 @@ func getRequest(conn *ss.Conn) (host string, extra []byte, err error) {
6260
}
6361

6462
if n < reqLen { // rare case
65-
ss.SetReadTimeout(conn)
6663
if _, err = io.ReadFull(conn, buf[n:reqLen]); err != nil {
6764
return
6865
}
@@ -154,8 +151,8 @@ func handleConnection(conn *ss.Conn) {
154151
if debug {
155152
debug.Printf("piping %s<->%s", conn.RemoteAddr(), host)
156153
}
157-
go ss.PipeThenClose(conn, remote, ss.SET_TIMEOUT)
158-
ss.PipeThenClose(remote, conn, ss.NO_TIMEOUT)
154+
go ss.PipeThenClose(conn, remote)
155+
ss.PipeThenClose(remote, conn)
159156
closed = true
160157
return
161158
}
@@ -261,7 +258,7 @@ func run(port, password string) {
261258
ln, err := net.Listen("tcp", ":"+port)
262259
if err != nil {
263260
log.Printf("error listening port %v: %v\n", port, err)
264-
return
261+
os.Exit(1)
265262
}
266263
passwdManager.add(port, password, ln)
267264
var cipher *ss.Cipher
@@ -321,7 +318,7 @@ func main() {
321318
flag.StringVar(&configFile, "c", "config.json", "specify config file")
322319
flag.StringVar(&cmdConfig.Password, "k", "", "password")
323320
flag.IntVar(&cmdConfig.ServerPort, "p", 0, "server port")
324-
flag.IntVar(&cmdConfig.Timeout, "t", 60, "connection timeout (in seconds)")
321+
flag.IntVar(&cmdConfig.Timeout, "t", 300, "timeout in seconds")
325322
flag.StringVar(&cmdConfig.Method, "m", "", "encryption method, default: aes-256-cfb")
326323
flag.IntVar(&core, "core", 0, "maximum number of CPU cores to use, default is determinied by Go runtime")
327324
flag.BoolVar((*bool)(&debug), "d", false, "print debug message")

script/test.sh

+3-1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ test_server_local_pair() {
110110
test_shadowsocks $url bf-cfb
111111
test_shadowsocks $url des-cfb
112112
test_shadowsocks $url cast5-cfb
113+
test_shadowsocks $url chacha20
114+
test_shadowsocks $url salsa20
113115
}
114116

115117
start_http_server
@@ -119,7 +121,7 @@ LOCAL="shadowsocks-local"
119121
test_server_local_pair
120122

121123
if [[ -n $SS_PYTHON ]]; then
122-
SERVER="$SS_PYTHON/server.py"
124+
SERVER="$SS_PYTHON/server.py --forbidden-ip="
123125
LOCAL="shadowsocks-local"
124126
test_server_local_pair
125127

shadowsocks/config.go

+3
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,7 @@ func UpdateConfig(old, new *Config) {
127127
if old.Method == "table" {
128128
old.Method = ""
129129
}
130+
131+
old.Timeout = new.Timeout
132+
readTimeout = time.Duration(old.Timeout) * time.Second
130133
}

shadowsocks/conn.go

+36-11
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,22 @@ import (
1111
type Conn struct {
1212
net.Conn
1313
*Cipher
14+
readBuf []byte
15+
writeBuf []byte
1416
}
1517

16-
func NewConn(cn net.Conn, cipher *Cipher) *Conn {
17-
return &Conn{cn, cipher}
18+
func NewConn(c net.Conn, cipher *Cipher) *Conn {
19+
return &Conn{
20+
Conn: c,
21+
Cipher: cipher,
22+
readBuf: leakyBuf.Get(),
23+
writeBuf: leakyBuf.Get()}
24+
}
25+
26+
func (c *Conn) Close() error {
27+
leakyBuf.Put(c.readBuf)
28+
leakyBuf.Put(c.writeBuf)
29+
return c.Conn.Close()
1830
}
1931

2032
func RawAddr(addr string) (buf []byte, err error) {
@@ -72,7 +84,14 @@ func (c *Conn) Read(b []byte) (n int, err error) {
7284
return
7385
}
7486
}
75-
cipherData := make([]byte, len(b))
87+
88+
cipherData := c.readBuf
89+
if len(b) > len(cipherData) {
90+
cipherData = make([]byte, len(b))
91+
} else {
92+
cipherData = cipherData[:len(b)]
93+
}
94+
7695
n, err = c.Conn.Read(cipherData)
7796
if n > 0 {
7897
c.decrypt(b[0:n], cipherData[0:n])
@@ -81,23 +100,29 @@ func (c *Conn) Read(b []byte) (n int, err error) {
81100
}
82101

83102
func (c *Conn) Write(b []byte) (n int, err error) {
84-
var cipherData []byte
85-
dataStart := 0
103+
var iv []byte
86104
if c.enc == nil {
87-
var iv []byte
88105
iv, err = c.initEncrypt()
89106
if err != nil {
90107
return
91108
}
109+
}
110+
111+
cipherData := c.writeBuf
112+
dataSize := len(b) + len(iv)
113+
if dataSize > len(cipherData) {
114+
cipherData = make([]byte, dataSize)
115+
} else {
116+
cipherData = cipherData[:dataSize]
117+
}
118+
119+
if iv != nil {
92120
// Put initialization vector in buffer, do a single write to send both
93121
// iv and data.
94-
cipherData = make([]byte, len(b)+len(iv))
95122
copy(cipherData, iv)
96-
dataStart = len(iv)
97-
} else {
98-
cipherData = make([]byte, len(b))
99123
}
100-
c.encrypt(cipherData[dataStart:], b)
124+
125+
c.encrypt(cipherData[len(iv):], b)
101126
n, err = c.Conn.Write(cipherData)
102127
return
103128
}

shadowsocks/encrypt.go

+52-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package shadowsocks
22

33
import (
44
"bytes"
5-
"golang.org/x/crypto/blowfish"
6-
"golang.org/x/crypto/cast5"
75
"crypto/aes"
86
"crypto/cipher"
97
"crypto/des"
@@ -12,6 +10,10 @@ import (
1210
"crypto/rc4"
1311
"encoding/binary"
1412
"errors"
13+
"github.com/codahale/chacha20"
14+
"golang.org/x/crypto/blowfish"
15+
"golang.org/x/crypto/cast5"
16+
"golang.org/x/crypto/salsa20/salsa"
1517
"io"
1618
)
1719

@@ -137,22 +139,68 @@ func newRC4MD5Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
137139
return rc4.NewCipher(rc4key)
138140
}
139141

142+
func newChaCha20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
143+
return chacha20.New(key, iv)
144+
}
145+
146+
type salsaStreamCipher struct {
147+
nonce [8]byte
148+
key [32]byte
149+
counter int
150+
}
151+
152+
func (c *salsaStreamCipher) XORKeyStream(dst, src []byte) {
153+
var buf []byte
154+
padLen := c.counter % 64
155+
dataSize := len(src) + padLen
156+
if cap(dst) >= dataSize {
157+
buf = dst[:dataSize]
158+
} else if leakyBufSize >= dataSize {
159+
buf = leakyBuf.Get()
160+
defer leakyBuf.Put(buf)
161+
buf = buf[:dataSize]
162+
} else {
163+
buf = make([]byte, dataSize)
164+
}
165+
166+
var subNonce [16]byte
167+
copy(subNonce[:], c.nonce[:])
168+
binary.LittleEndian.PutUint64(subNonce[len(c.nonce):], uint64(c.counter/64))
169+
170+
// It's difficult to avoid data copy here. src or dst maybe slice from
171+
// Conn.Read/Write, which can't have padding.
172+
copy(buf[padLen:], src[:])
173+
salsa.XORKeyStream(buf, buf, &subNonce, &c.key)
174+
copy(dst, buf[padLen:])
175+
176+
c.counter += len(src)
177+
}
178+
179+
func newSalsa20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
180+
var c salsaStreamCipher
181+
copy(c.nonce[:], iv[:8])
182+
copy(c.key[:], key[:32])
183+
return &c, nil
184+
}
185+
140186
type cipherInfo struct {
141187
keyLen int
142188
ivLen int
143189
newStream func(key, iv []byte, doe DecOrEnc) (cipher.Stream, error)
144190
}
145191

146192
var cipherMethod = map[string]*cipherInfo{
193+
"rc4": {16, 0, nil},
194+
"table": {16, 0, nil},
147195
"aes-128-cfb": {16, 16, newAESStream},
148196
"aes-192-cfb": {24, 16, newAESStream},
149197
"aes-256-cfb": {32, 16, newAESStream},
150198
"des-cfb": {8, 8, newDESStream},
151199
"bf-cfb": {16, 8, newBlowFishStream},
152200
"cast5-cfb": {16, 8, newCast5Stream},
153201
"rc4-md5": {16, 16, newRC4MD5Stream},
154-
"rc4": {16, 0, nil},
155-
"table": {16, 0, nil},
202+
"chacha20": {32, 8, newChaCha20Stream},
203+
"salsa20": {32, 8, newSalsa20Stream},
156204
}
157205

158206
func CheckCipherMethod(method string) error {

0 commit comments

Comments
 (0)