Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
cyfdecyf committed Feb 12, 2013
2 parents 6b8a5ad + 0881fdf commit 4a25aea
Show file tree
Hide file tree
Showing 18 changed files with 155 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .gitignore
@@ -1 +1 @@
table.cache
*.deb
13 changes: 13 additions & 0 deletions .travis.yml
@@ -0,0 +1,13 @@
language: go
install:
- mkdir -p $GOPATH/src/github.com/shadowsocks/shadowsocks-go/shadowsocks
- mv * $GOPATH/src/github.com/shadowsocks/shadowsocks-go
- pushd $GOPATH/src/github.com/shadowsocks/shadowsocks-go
- go install ./cmd/shadowsocks-local
- go install ./cmd/shadowsocks-server
- popd
script:
- pushd $GOPATH/src/github.com/shadowsocks/shadowsocks-go
- PATH=$PATH:$GOPATH/bin/ bash -x ./testscript/test.sh
- popd

21 changes: 11 additions & 10 deletions Makefile
@@ -1,26 +1,27 @@
# Use shadowsocks as command prefix to avoid name conflict
# Maybe ss-local/server is better because easier to type
PREFIX := shadowsocks
LOCAL := $(GOBIN)/$(PREFIX)-local
SERVER := $(GOBIN)/$(PREFIX)-server

# TODO define the install package path for use in clean and detect whether
# package need re-build
LOCAL := $(GOPATH)/bin/$(PREFIX)-local
SERVER := $(GOPATH)/bin/$(PREFIX)-server
CGO := CGO_ENABLED=0

all: $(LOCAL) $(SERVER) $(TEST)

.PHONY: clean

clean:
rm -rf $(LOCAL) $(SERVER) $(TEST)
rm -f $(LOCAL) $(SERVER) $(TEST)

# -a option is needed to ensure we disabled CGO
$(LOCAL): shadowsocks/*.go cmd/$(PREFIX)-local/*.go
cd shadowsocks; go install
cd cmd/$(PREFIX)-local; go install
cd cmd/$(PREFIX)-local; $(CGO) go install -a

$(SERVER): shadowsocks/*.go cmd/$(PREFIX)-server/*.go
cd shadowsocks; go install
cd cmd/$(PREFIX)-server; go install
cd cmd/$(PREFIX)-server; $(CGO) go install -a

local: $(LOCAL)

server: $(SERVER)

test:
cd shadowsocks; go test
2 changes: 1 addition & 1 deletion README.md
@@ -1,6 +1,6 @@
# shadowsocks-go

Current version: 0.6
Current version: 0.6 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png)](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).

Expand Down
1 change: 0 additions & 1 deletion TODO
@@ -1 +0,0 @@
Add test script to test both server and client.
2 changes: 1 addition & 1 deletion cmd/shadowsocks-httpget/httpget.go
Expand Up @@ -51,7 +51,7 @@ func doOneRequest(client *http.Client, uri string, buf []byte) (err error) {

func get(connid int, uri, serverAddr string, rawAddr []byte, cipher ss.Cipher, done chan []time.Duration) {
reqDone := 0
reqTime := make([]time.Duration, config.nreq, config.nreq)
reqTime := make([]time.Duration, config.nreq)
defer func() {
done <- reqTime[:reqDone]
}()
Expand Down
30 changes: 19 additions & 11 deletions cmd/shadowsocks-local/local.go
Expand Up @@ -40,7 +40,7 @@ func handShake(conn net.Conn) (err error) {
// the current rfc defines only 3 authentication methods (plus 2 reserved),
// so it won't be such long in practice

buf := make([]byte, 258, 258)
buf := make([]byte, 258)

var n int
// make sure we get the nmethod field
Expand Down Expand Up @@ -83,7 +83,7 @@ func getRequest(conn net.Conn) (rawaddr []byte, host string, err error) {
lenDmBase = 3 + 1 + 1 + 2 // 3 + 1addrType + 1addrLen + 2port, plus addrLen
)
// refer to getRequest in server.go for why set buffer size to 263
buf := make([]byte, 263, 263)
buf := make([]byte, 263)
var n int
// read till we get possible domain length field
if n, err = io.ReadAtLeast(conn, buf, idDmLen+1); err != nil {
Expand Down Expand Up @@ -159,7 +159,7 @@ func initServers(config *ss.Config) {
srvPort := strconv.Itoa(config.ServerPort)
srvArr := config.GetServerArray()
n := len(srvArr)
servers.srvCipher = make([]*ServerCipher, n, n)
servers.srvCipher = make([]*ServerCipher, n)

for i, s := range srvArr {
if ss.HasPort(s) {
Expand All @@ -171,7 +171,7 @@ func initServers(config *ss.Config) {
}
} else {
n := len(config.ServerPassword)
servers.srvCipher = make([]*ServerCipher, n, n)
servers.srvCipher = make([]*ServerCipher, n)

cipherCache := make(map[string]ss.Cipher)
i := 0
Expand Down Expand Up @@ -226,7 +226,12 @@ func handleConnection(conn net.Conn) {
if debug {
debug.Printf("socks connect from %s\n", conn.RemoteAddr().String())
}
defer conn.Close()
closed := false
defer func() {
if !closed {
conn.Close()
}
}()

var err error = nil
if err = handShake(conn); err != nil {
Expand Down Expand Up @@ -254,13 +259,16 @@ func handleConnection(conn net.Conn) {
}
return
}
defer remote.Close()
defer func() {
if !closed {
remote.Close()
}
}()

c := make(chan byte, 2)
go ss.Pipe(conn, remote, c)
go ss.Pipe(remote, conn, c)
<-c // close the other connection whenever one connection is closed
debug.Println("closing connection to", addr)
go ss.PipeThenClose(conn, remote, ss.NO_TIMEOUT)
ss.PipeThenClose(remote, conn, ss.NO_TIMEOUT)
closed = true
debug.Println("closed connection to", addr)
}

func run(port string) {
Expand Down
22 changes: 14 additions & 8 deletions cmd/shadowsocks-server/server.go
Expand Up @@ -42,7 +42,7 @@ func getRequest(conn *ss.Conn) (host string, extra []byte, err error) {
// buf size should at least have the same size with the largest possible
// request size (when addrType is 3, domain name has at most 256 bytes)
// 1(addrType) + 1(lenByte) + 256(max length address) + 2(port)
buf := make([]byte, 260, 260)
buf := make([]byte, 260)
var n int
// read till we get possible domain length field
ss.SetReadTimeout(conn)
Expand Down Expand Up @@ -103,12 +103,15 @@ func handleConnection(conn *ss.Conn) {
if debug {
debug.Printf("new client %s->%s\n", conn.RemoteAddr().String(), conn.LocalAddr())
}
closed := false
defer func() {
if debug {
debug.Printf("closing pipe %s<->%s\n", conn.RemoteAddr(), host)
debug.Printf("closed pipe %s<->%s\n", conn.RemoteAddr(), host)
}
atomic.AddInt32(&connCnt, -1)
conn.Close()
if !closed {
conn.Close()
}
}()

host, extra, err := getRequest(conn)
Expand All @@ -128,7 +131,11 @@ func handleConnection(conn *ss.Conn) {
}
return
}
defer remote.Close()
defer func() {
if !closed {
remote.Close()
}
}()
// write extra bytes read from
if extra != nil {
// debug.Println("getRequest read extra data, writing to remote, len", len(extra))
Expand All @@ -140,10 +147,9 @@ func handleConnection(conn *ss.Conn) {
if debug {
debug.Printf("piping %s<->%s", conn.RemoteAddr(), host)
}
c := make(chan byte, 2)
go ss.Pipe(conn, remote, c)
go ss.Pipe(remote, conn, c)
<-c // close the other connection whenever one connection is closed
go ss.PipeThenClose(conn, remote, ss.SET_TIMEOUT)
ss.PipeThenClose(remote, conn, ss.NO_TIMEOUT)
closed = true
return
}

Expand Down
2 changes: 1 addition & 1 deletion config.json
Expand Up @@ -3,5 +3,5 @@
"server_port":8388,
"local_port":1080,
"password":"barfoo!",
"timeout":60
"timeout":0
}
41 changes: 41 additions & 0 deletions createdeb.sh
@@ -0,0 +1,41 @@
#!/bin/bash

if [[ $# != 1 ]]; then
echo "$0 <arch, i386 or amd64>"
exit 1
fi

export CGO_ENABLED=0
export GOOS=linux

arch=$1
case $arch in
i386)
export GOARCH=386
;;
amd64)
export GOARCH=amd64
;;
*)
echo "arch $i not supported"
exit 1
;;
esac

# build shadowsocks server
pushd cmd/shadowsocks-server
go build -a -v || exit 1
popd

# create debian package
DEBDIR=shadowsocks-go_0.6-1-$arch
rm -rf $DEBDIR
cp -r deb $DEBDIR

sed -i -e "s/^Architecture.*$/Architecture: $arch/" $DEBDIR/DEBIAN/control || exit 1

mkdir -p $DEBDIR/usr/bin
cp cmd/shadowsocks-server/shadowsocks-server $DEBDIR/usr/bin/shadowsocks

fakeroot dpkg-deb --build $DEBDIR

9 changes: 9 additions & 0 deletions deb/DEBIAN/control
@@ -0,0 +1,9 @@
Package: shadowsocks-go
Version: 0.6-1
Section: net
Priority: optional
Architecture: any
Depends:
Maintainer: CYF <cyfdecyf@gmail.com>
Description: shadowsocks-go is the go port of shadowsocks, a light weight tunneling proxy
This package contains only the server.
2 changes: 1 addition & 1 deletion sample-config/shadowsocks → deb/etc/init.d/shadowsocks
Expand Up @@ -16,7 +16,7 @@
# Note: this script requires sudo in order to run shadowsocks as the specified
# user.

BIN=/usr/local/bin/shadowsocks
BIN=/usr/bin/shadowsocks
CONFIG_FILE=/etc/shadowsocks/config.json
LOG_FILE=/var/log/shadowsocks
USER=nobody
Expand Down
7 changes: 7 additions & 0 deletions deb/etc/shadowsocks/config.json
@@ -0,0 +1,7 @@
{
"server":"127.0.0.1",
"server_port":8388,
"local_port":1080,
"password":"barfoo!",
"timeout":0
}
2 changes: 1 addition & 1 deletion shadowsocks/conn.go
Expand Up @@ -33,7 +33,7 @@ func RawAddr(addr string) (buf []byte, err error) {

hostLen := len(host)
l := 1 + 1 + hostLen + 2 // addrType + lenByte + address + port
buf = make([]byte, l, l)
buf = make([]byte, l)
buf[0] = 3 // 3 means the address is domain name
buf[1] = byte(hostLen) // host address length followed by host address
copy(buf[2:], host)
Expand Down
6 changes: 3 additions & 3 deletions shadowsocks/encrypt.go
Expand Up @@ -29,10 +29,10 @@ type TableCipher struct {
func NewTableCipher(key string) (c Cipher, err error) {
const tbl_size = 256
tbl := TableCipher{
make([]byte, tbl_size, tbl_size),
make([]byte, tbl_size, tbl_size),
make([]byte, tbl_size),
make([]byte, tbl_size),
}
table := make([]uint64, tbl_size, tbl_size)
table := make([]uint64, tbl_size)

h := md5.New()
h.Write([]byte(key))
Expand Down
4 changes: 2 additions & 2 deletions shadowsocks/encrypt_test.go
Expand Up @@ -37,8 +37,8 @@ const text = "Don't tell me the moon is shining; show me the glint of light on b

func testCiphter(t *testing.T, c Cipher, msg string) {
n := len(text)
cipherBuf := make([]byte, n, n)
originTxt := make([]byte, n, n)
cipherBuf := make([]byte, n)
originTxt := make([]byte, n)

c.Encrypt(cipherBuf, []byte(text))
c.Decrypt(originTxt, cipherBuf)
Expand Down
19 changes: 11 additions & 8 deletions shadowsocks/pipe.go
Expand Up @@ -6,21 +6,25 @@ import (
"time"
)

const (
NO_TIMEOUT = iota
SET_TIMEOUT
)

func SetReadTimeout(c net.Conn) {
if readTimeout != 0 {
c.SetReadDeadline(time.Now().Add(readTimeout))
}
}

func Pipe(src, dst net.Conn, end chan byte) {
// Should not use io.Copy here.
// io.Copy will try to use the ReadFrom interface of TCPConn, but the src
// here is not a regular file, so sendfile is not applicable.
// io.Copy will fallback to the normal copy after discovering this,
// introducing unnecessary overhead.
// PipeThenClose copies data from src to dst, closes dst when done.
func PipeThenClose(src, dst net.Conn, timeoutOpt int) {
defer dst.Close()
buf := make([]byte, 4096)
for {
SetReadTimeout(src)
if timeoutOpt == SET_TIMEOUT {
SetReadTimeout(src)
}
n, err := src.Read(buf)
// read may return EOF with n > 0
// should always process n > 0 bytes before handling error
Expand All @@ -42,5 +46,4 @@ func Pipe(src, dst net.Conn, end chan byte) {
break
}
}
end <- 1
}
29 changes: 19 additions & 10 deletions testscript/test.sh
@@ -1,6 +1,6 @@
#!/bin/bash

OPTION="-p 8389 -k foobar"
OPTION="-p 8389 -k foobar -d"
LOCAL_PORT="1090"
SOCKS="127.0.0.1:$LOCAL_PORT"

Expand All @@ -12,22 +12,31 @@ test_get() {
url=$1
method=$2

shadowsocks-server $OPTION -m "$method" >/dev/null 2>&1 &
shadowsocks-server $OPTION -m "$method" &
server_pid=$!
shadowsocks-local $OPTION -s 127.0.0.1 -l $LOCAL_PORT -m "$method" >/dev/null 2>&1 &
shadowsocks-local $OPTION -s 127.0.0.1 -l $LOCAL_PORT -m "$method" &
local_pid=$!

# wait server and client finish startup
sleep 1
sleep 0.5

if curl -s --socks5 $SOCKS $url >/dev/null 2>&1; then
echo "get $url $method passed"
else
echo "get $url $method FAILED!!!"
exit 1
fi
# get 5 times
for i in {1..5}; do
if ! curl -s --socks5 $SOCKS $url >/dev/null 2>&1; then
echo "=============================="
echo "GET $url $method FAILED!!!"
echo "=============================="
kill -SIGINT $server_pid
kill -SIGINT $local_pid
exit 1
fi
done
echo "=============================="
echo "GET $url $method passed"
echo "=============================="
kill -SIGINT $server_pid
kill -SIGINT $local_pid
sleep 0.5
}

test_get baidu.com
Expand Down

0 comments on commit 4a25aea

Please sign in to comment.