Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8f1825776 | ||
|
|
dde25f89e1 | ||
|
|
98f73e44d0 | ||
|
|
e0189ab1de | ||
|
|
e68b3e430b | ||
|
|
bac675d7f6 | ||
|
|
291adf8b85 | ||
|
|
1423fe1921 | ||
|
|
5a5c8b9c7e | ||
|
|
70559a1030 | ||
|
|
45ee594d58 | ||
|
|
707b5c1def | ||
|
|
d91f7d85d4 | ||
|
|
5a5158b33f | ||
|
|
7f19c31640 | ||
|
|
937693519a | ||
|
|
9e6e884b12 | ||
|
|
e8501da271 | ||
|
|
99c8bbafe7 | ||
|
|
30f4f78557 | ||
|
|
dd140814a8 | ||
|
|
d228ffbe84 | ||
|
|
ab975d1753 | ||
|
|
c6bc912c11 | ||
|
|
b785d95f66 | ||
|
|
1d0c8b1800 | ||
|
|
9cfffa360e | ||
|
|
cd07001471 | ||
|
|
2cc7ee5053 | ||
|
|
9b3944c954 | ||
|
|
f1b084be06 | ||
|
|
5ea8403e56 | ||
|
|
072afd68f2 | ||
|
|
be1d1d5032 | ||
|
|
536b7d1ee6 | ||
|
|
c7b5a5a011 | ||
|
|
be2ab378ff | ||
|
|
2b4c3619d6 | ||
|
|
dae2624b30 | ||
|
|
fb789d8e9f | ||
|
|
2733e6a4ba | ||
|
|
35c3b0b41c |
@@ -17,6 +17,7 @@ develop-eggs
|
|||||||
pip-log.txt
|
pip-log.txt
|
||||||
|
|
||||||
# Unit test / coverage reports
|
# Unit test / coverage reports
|
||||||
|
htmlcov
|
||||||
.coverage
|
.coverage
|
||||||
.tox
|
.tox
|
||||||
|
|
||||||
|
|||||||
Executable
+71
@@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
result=0
|
||||||
|
|
||||||
|
function run_test {
|
||||||
|
printf '\e[0;36m'
|
||||||
|
echo "running test: $command $@"
|
||||||
|
printf '\e[0m'
|
||||||
|
|
||||||
|
$command "$@"
|
||||||
|
status=$?
|
||||||
|
if [ $status -ne 0 ]; then
|
||||||
|
printf '\e[0;31m'
|
||||||
|
echo "test failed: $command $@"
|
||||||
|
printf '\e[0m'
|
||||||
|
echo
|
||||||
|
result=1
|
||||||
|
else
|
||||||
|
printf '\e[0;32m'
|
||||||
|
echo OK
|
||||||
|
printf '\e[0m'
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
coverage erase
|
||||||
|
mkdir tmp
|
||||||
|
run_test pep8 .
|
||||||
|
run_test pyflakes .
|
||||||
|
run_test coverage run tests/nose_plugin.py -v
|
||||||
|
run_test python setup.py sdist
|
||||||
|
run_test tests/test_daemon.sh
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/aes.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/aes-ctr.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/aes-cfb1.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/aes-cfb8.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/rc4-md5.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/salsa20.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/chacha20.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/salsa20-ctr.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/table.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/server-multi-ports.json
|
||||||
|
run_test python tests/test.py --with-coverage -s tests/server-multi-passwd.json -c tests/server-multi-passwd-client-side.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/workers.json
|
||||||
|
run_test python tests/test.py --with-coverage -s tests/ipv6.json -c tests/ipv6-client-side.json
|
||||||
|
run_test python tests/test.py --with-coverage -b "-m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -q" -a "-m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -vv"
|
||||||
|
run_test python tests/test.py --with-coverage -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --workers 1" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -qq -b 127.0.0.1"
|
||||||
|
|
||||||
|
if [ -f /proc/sys/net/ipv4/tcp_fastopen ] ; then
|
||||||
|
if [ 3 -eq `cat /proc/sys/net/ipv4/tcp_fastopen` ] ; then
|
||||||
|
# we have to run it twice:
|
||||||
|
# the first time there's no syn cookie
|
||||||
|
# the second time there is syn cookie
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/fastopen.json
|
||||||
|
run_test python tests/test.py --with-coverage -c tests/fastopen.json
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_test tests/test_large_file.sh
|
||||||
|
|
||||||
|
run_test tests/test_command.sh
|
||||||
|
|
||||||
|
coverage combine && coverage report --include=shadowsocks/*
|
||||||
|
rm -rf htmlcov
|
||||||
|
rm -rf tmp
|
||||||
|
coverage html --include=shadowsocks/*
|
||||||
|
|
||||||
|
coverage report --include=shadowsocks/* | tail -n1 | rev | cut -d' ' -f 1 | rev > /tmp/shadowsocks-coverage
|
||||||
|
|
||||||
|
exit $result
|
||||||
+5
-22
@@ -9,29 +9,12 @@ cache:
|
|||||||
- dante-1.4.0
|
- dante-1.4.0
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -qq build-essential libssl-dev swig python-m2crypto python-numpy dnsutils
|
- sudo apt-get install -qq build-essential libssl-dev swig python-m2crypto python-numpy dnsutils iproute nginx bc
|
||||||
|
- sudo dd if=/dev/urandom of=/usr/share/nginx/www/file bs=1M count=10
|
||||||
|
- sudo service nginx restart
|
||||||
- pip install m2crypto salsa20 pep8 pyflakes nose coverage
|
- pip install m2crypto salsa20 pep8 pyflakes nose coverage
|
||||||
- sudo tests/socksify/install.sh
|
- sudo tests/socksify/install.sh
|
||||||
- sudo tests/libsodium/install.sh
|
- sudo tests/libsodium/install.sh
|
||||||
|
- sudo tests/setup_tc.sh
|
||||||
script:
|
script:
|
||||||
- pep8 .
|
- ./.jenkins.sh
|
||||||
- pyflakes .
|
|
||||||
- coverage run tests/nose_plugin.py -v
|
|
||||||
- python setup.py sdist
|
|
||||||
- tests/test_daemon.sh
|
|
||||||
- python tests/test.py --with-coverage -c tests/aes.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/aes-ctr.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/aes-cfb1.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/aes-cfb8.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/rc4-md5.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/salsa20.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/chacha20.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/salsa20-ctr.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/table.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/server-multi-ports.json
|
|
||||||
- python tests/test.py --with-coverage -s tests/server-multi-passwd.json -c tests/server-multi-passwd-client-side.json
|
|
||||||
- python tests/test.py --with-coverage -c tests/workers.json
|
|
||||||
- python tests/test.py --with-coverage -s tests/ipv6.json -c tests/ipv6-client-side.json
|
|
||||||
- python tests/test.py --with-coverage -b "-m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388" -a "-m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -l 1081"
|
|
||||||
- python tests/test.py --with-coverage -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081"
|
|
||||||
- coverage combine && coverage report --include=shadowsocks/*
|
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
2.6.2 2015-01-03
|
||||||
|
- Log client IP
|
||||||
|
|
||||||
|
2.6.1 2014-12-26
|
||||||
|
- Fix a problem with TCP Fast Open on local side
|
||||||
|
- Fix sometimes daemon_start returns wrong exit status
|
||||||
|
|
||||||
2.6 2014-12-21
|
2.6 2014-12-21
|
||||||
- Add daemon support
|
- Add daemon support
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Shadowsocks
|
Shadowsocks
|
||||||
|
|
||||||
Copyright (c) 2014 clowwindy
|
Copyright (c) 2012-2015 clowwindy
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
shadowsocks
|
shadowsocks
|
||||||
===========
|
===========
|
||||||
|
|
||||||
[![PyPI version]][PyPI] [![Build Status]][Travis CI]
|
[![PyPI version]][PyPI]
|
||||||
|
[![Build Status]][Travis CI]
|
||||||
|
[![Coverage Status]][Coverage]
|
||||||
|
|
||||||
A fast tunnel proxy that helps you bypass firewalls.
|
A fast tunnel proxy that helps you bypass firewalls.
|
||||||
|
|
||||||
@@ -56,8 +58,7 @@ Example:
|
|||||||
"password":"mypassword",
|
"password":"mypassword",
|
||||||
"timeout":300,
|
"timeout":300,
|
||||||
"method":"aes-256-cfb",
|
"method":"aes-256-cfb",
|
||||||
"fast_open": false,
|
"fast_open": false
|
||||||
"workers": 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Explanation of the fields:
|
Explanation of the fields:
|
||||||
@@ -74,43 +75,36 @@ Explanation of the fields:
|
|||||||
| fast_open | use [TCP_FASTOPEN], true / false |
|
| fast_open | use [TCP_FASTOPEN], true / false |
|
||||||
| workers | number of workers, available on Unix/Linux |
|
| workers | number of workers, available on Unix/Linux |
|
||||||
|
|
||||||
Run `ssserver -c /etc/shadowsocks.json` on your server. To run it in the
|
On your server:
|
||||||
background, use [Supervisor].
|
|
||||||
|
|
||||||
On your client machine, use the same configuration as your server, and
|
To run in the foreground:
|
||||||
start your client.
|
|
||||||
|
|
||||||
If you use Chrome, it's recommended to use [SwitchySharp]. Change the proxy
|
ssserver -c /etc/shadowsocks.json
|
||||||
settings to
|
|
||||||
|
|
||||||
protocol: socks5
|
To run in the background:
|
||||||
hostname: 127.0.0.1
|
|
||||||
port: your local_port
|
|
||||||
|
|
||||||
If you can't install [SwitchySharp], you can launch Chrome with the following
|
ssserver -c /etc/shadowsocks.json -d start
|
||||||
arguments to force Chrome to use the proxy:
|
ssserver -c /etc/shadowsocks.json -d stop
|
||||||
|
|
||||||
Chrome.exe --proxy-server="socks5://127.0.0.1:1080" --host-resolver-rules="MAP * 0.0.0.0 , EXCLUDE localhost"
|
On your client machine, use the same configuration as your server. Check the
|
||||||
|
README of your client for more information.
|
||||||
|
|
||||||
If you can't even download Chrome, find a friend to download a
|
Command Line Options
|
||||||
[Chrome Standalone] installer for you.
|
--------------------
|
||||||
|
|
||||||
Command line args
|
Check the options via `-h`.You can use args to override settings from
|
||||||
------------------
|
`config.json`.
|
||||||
|
|
||||||
You can use args to override settings from `config.json`.
|
|
||||||
|
|
||||||
sslocal -s server_name -p server_port -l local_port -k password -m bf-cfb
|
sslocal -s server_name -p server_port -l local_port -k password -m bf-cfb
|
||||||
ssserver -p server_port -k password -m bf-cfb --workers 2
|
ssserver -p server_port -k password -m bf-cfb --workers 2
|
||||||
ssserver -c /etc/shadowsocks/config.json
|
ssserver -c /etc/shadowsocks/config.json -d start --pid-file=/tmp/shadowsocks.pid
|
||||||
|
ssserver -c /etc/shadowsocks/config.json -d stop --pid-file=/tmp/shadowsocks.pid
|
||||||
|
|
||||||
List all available args with `-h`.
|
Documentation
|
||||||
|
-------------
|
||||||
Wiki
|
|
||||||
----
|
|
||||||
|
|
||||||
You can find all the documentation in the wiki:
|
You can find all the documentation in the wiki:
|
||||||
https://github.com/clowwindy/shadowsocks/wiki
|
https://github.com/shadowsocks/shadowsocks/wiki
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
@@ -124,24 +118,23 @@ Bugs and Issues
|
|||||||
* [Mailing list]
|
* [Mailing list]
|
||||||
|
|
||||||
|
|
||||||
[Android]: https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients#android
|
[Android]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#android
|
||||||
[Build Status]: https://img.shields.io/travis/clowwindy/shadowsocks/master.svg?style=flat
|
[Build Status]: https://img.shields.io/travis/shadowsocks/shadowsocks/master.svg?style=flat
|
||||||
[Chinese Readme]: https://github.com/clowwindy/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
|
[Chinese Readme]: https://github.com/shadowsocks/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
|
||||||
[Chrome Standalone]: https://support.google.com/installer/answer/126299
|
[Coverage Status]: http://192.81.132.184/result/shadowsocks
|
||||||
|
[Coverage]: http://192.81.132.184/job/Shadowsocks/ws/htmlcov/index.html
|
||||||
[Debian sid]: https://packages.debian.org/unstable/python/shadowsocks
|
[Debian sid]: https://packages.debian.org/unstable/python/shadowsocks
|
||||||
[the package]: https://pypi.python.org/pypi/shadowsocks
|
[the package]: https://pypi.python.org/pypi/shadowsocks
|
||||||
[Encryption]: https://github.com/clowwindy/shadowsocks/wiki/Encryption
|
[Encryption]: https://github.com/shadowsocks/shadowsocks/wiki/Encryption
|
||||||
[iOS]: https://github.com/shadowsocks/shadowsocks-iOS/wiki/Help
|
[iOS]: https://github.com/shadowsocks/shadowsocks-iOS/wiki/Help
|
||||||
[Issue Tracker]: https://github.com/clowwindy/shadowsocks/issues?state=open
|
[Issue Tracker]: https://github.com/shadowsocks/shadowsocks/issues?state=open
|
||||||
[Mailing list]: http://groups.google.com/group/shadowsocks
|
[Mailing list]: http://groups.google.com/group/shadowsocks
|
||||||
[OpenSSL for Windows]: http://slproweb.com/products/Win32OpenSSL.html
|
[OpenSSL for Windows]: http://slproweb.com/products/Win32OpenSSL.html
|
||||||
[OpenWRT]: https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients#openwrt
|
[OpenWRT]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#openwrt
|
||||||
[OS X]: https://github.com/shadowsocks/shadowsocks-iOS/wiki/Shadowsocks-for-OSX-Help
|
[OS X]: https://github.com/shadowsocks/shadowsocks-iOS/wiki/Shadowsocks-for-OSX-Help
|
||||||
[PyPI]: https://pypi.python.org/pypi/shadowsocks
|
[PyPI]: https://pypi.python.org/pypi/shadowsocks
|
||||||
[PyPI version]: https://img.shields.io/pypi/v/shadowsocks.svg?style=flat
|
[PyPI version]: https://img.shields.io/pypi/v/shadowsocks.svg?style=flat
|
||||||
[Supervisor]: https://github.com/clowwindy/shadowsocks/wiki/Configure-Shadowsocks-with-Supervisor
|
[TCP_FASTOPEN]: https://github.com/shadowsocks/shadowsocks/wiki/TCP-Fast-Open
|
||||||
[TCP_FASTOPEN]: https://github.com/clowwindy/shadowsocks/wiki/TCP-Fast-Open
|
[Travis CI]: https://travis-ci.org/shadowsocks/shadowsocks
|
||||||
[Travis CI]: https://travis-ci.org/clowwindy/shadowsocks
|
[Troubleshooting]: https://github.com/shadowsocks/shadowsocks/wiki/Troubleshooting
|
||||||
[Troubleshooting]: https://github.com/clowwindy/shadowsocks/wiki/Troubleshooting
|
[Windows]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#windows
|
||||||
[SwitchySharp]: https://chrome.google.com/webstore/detail/proxy-switchysharp/dpplabbmogkhghncfbfdeeokoefdjegm
|
|
||||||
[Windows]: https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients#windows
|
|
||||||
|
|||||||
+54
-64
@@ -1,11 +1,11 @@
|
|||||||
shadowsocks
|
shadowsocks
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|PyPI version| |Build Status|
|
|PyPI version| |Build Status| |Coverage Status|
|
||||||
|
|
||||||
A fast tunnel proxy that helps you bypass firewalls.
|
A fast tunnel proxy that helps you bypass firewalls.
|
||||||
|
|
||||||
`中文说明 <https://github.com/clowwindy/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E>`__
|
`中文说明 <https://github.com/shadowsocks/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E>`__
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
@@ -16,12 +16,12 @@ server.
|
|||||||
Client
|
Client
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
- `Windows <https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients#windows>`__
|
- `Windows <https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#windows>`__
|
||||||
/ `OS
|
/ `OS
|
||||||
X <https://github.com/shadowsocks/shadowsocks-iOS/wiki/Shadowsocks-for-OSX-Help>`__
|
X <https://github.com/shadowsocks/shadowsocks-iOS/wiki/Shadowsocks-for-OSX-Help>`__
|
||||||
- `Android <https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients#android>`__
|
- `Android <https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#android>`__
|
||||||
/ `iOS <https://github.com/shadowsocks/shadowsocks-iOS/wiki/Help>`__
|
/ `iOS <https://github.com/shadowsocks/shadowsocks-iOS/wiki/Help>`__
|
||||||
- `OpenWRT <https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients#openwrt>`__
|
- `OpenWRT <https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#openwrt>`__
|
||||||
|
|
||||||
Server
|
Server
|
||||||
~~~~~~
|
~~~~~~
|
||||||
@@ -50,9 +50,10 @@ CentOS:
|
|||||||
Windows:
|
Windows:
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
Download OpenSSL for Windows and install. Then install shadowsocks via
|
Download `OpenSSL for
|
||||||
easy\_install and pip as Linux. If you don't know how to use them, you
|
Windows <http://slproweb.com/products/Win32OpenSSL.html>`__ and install.
|
||||||
can directly download `the
|
Then install shadowsocks via easy\_install and pip as Linux. If you
|
||||||
|
don't know how to use them, you can directly download `the
|
||||||
package <https://pypi.python.org/pypi/shadowsocks>`__, and use
|
package <https://pypi.python.org/pypi/shadowsocks>`__, and use
|
||||||
``python shadowsocks/server.py`` instead of ``ssserver`` command below.
|
``python shadowsocks/server.py`` instead of ``ssserver`` command below.
|
||||||
|
|
||||||
@@ -71,82 +72,69 @@ On your server create a config file ``/etc/shadowsocks.json``. Example:
|
|||||||
"password":"mypassword",
|
"password":"mypassword",
|
||||||
"timeout":300,
|
"timeout":300,
|
||||||
"method":"aes-256-cfb",
|
"method":"aes-256-cfb",
|
||||||
"fast_open": false,
|
"fast_open": false
|
||||||
"workers": 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Explanation of the fields:
|
Explanation of the fields:
|
||||||
|
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| Name | Explanation |
|
| Name | Explanation |
|
||||||
+==================+=========================================================================================================+
|
+==================+===========================================================================================================+
|
||||||
| server | the address your server listens |
|
| server | the address your server listens |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| server\_port | server port |
|
| server\_port | server port |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| local\_address | the address your local listens |
|
| local\_address | the address your local listens |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| local\_port | local port |
|
| local\_port | local port |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| password | password used for encryption |
|
| password | password used for encryption |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| timeout | in seconds |
|
| timeout | in seconds |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| method | default: "aes-256-cfb", see `Encryption <https://github.com/clowwindy/shadowsocks/wiki/Encryption>`__ |
|
| method | default: "aes-256-cfb", see `Encryption <https://github.com/shadowsocks/shadowsocks/wiki/Encryption>`__ |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| fast\_open | use `TCP\_FASTOPEN <https://github.com/clowwindy/shadowsocks/wiki/TCP-Fast-Open>`__, true / false |
|
| fast\_open | use `TCP\_FASTOPEN <https://github.com/shadowsocks/shadowsocks/wiki/TCP-Fast-Open>`__, true / false |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
| workers | number of workers, available on Unix/Linux |
|
| workers | number of workers, available on Unix/Linux |
|
||||||
+------------------+---------------------------------------------------------------------------------------------------------+
|
+------------------+-----------------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
Run ``ssserver -c /etc/shadowsocks.json`` on your server. To run it in
|
On your server:
|
||||||
the background, use
|
|
||||||
`Supervisor <https://github.com/clowwindy/shadowsocks/wiki/Configure-Shadowsocks-with-Supervisor>`__.
|
|
||||||
|
|
||||||
On your client machine, use the same configuration as your server, and
|
To run in the foreground:
|
||||||
start your client.
|
|
||||||
|
|
||||||
If you use Chrome, it's recommended to use
|
|
||||||
`SwitchySharp <https://chrome.google.com/webstore/detail/proxy-switchysharp/dpplabbmogkhghncfbfdeeokoefdjegm>`__.
|
|
||||||
Change the proxy settings to
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
protocol: socks5
|
ssserver -c /etc/shadowsocks.json
|
||||||
hostname: 127.0.0.1
|
|
||||||
port: your local_port
|
|
||||||
|
|
||||||
If you can't install
|
To run in the background:
|
||||||
`SwitchySharp <https://chrome.google.com/webstore/detail/proxy-switchysharp/dpplabbmogkhghncfbfdeeokoefdjegm>`__,
|
|
||||||
you can launch Chrome with the following arguments to force Chrome to
|
|
||||||
use the proxy:
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
Chrome.exe --proxy-server="socks5://127.0.0.1:1080" --host-resolver-rules="MAP * 0.0.0.0 , EXCLUDE localhost"
|
ssserver -c /etc/shadowsocks.json -d start
|
||||||
|
ssserver -c /etc/shadowsocks.json -d stop
|
||||||
|
|
||||||
If you can't even download Chrome, find a friend to download a `Chrome
|
On your client machine, use the same configuration as your server. Check
|
||||||
Standalone <https://support.google.com/installer/answer/126299>`__
|
the README of your client for more information.
|
||||||
installer for you.
|
|
||||||
|
|
||||||
Command line args
|
Command Line Options
|
||||||
-----------------
|
--------------------
|
||||||
|
|
||||||
You can use args to override settings from ``config.json``.
|
Check the options via ``-h``.You can use args to override settings from
|
||||||
|
``config.json``.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
sslocal -s server_name -p server_port -l local_port -k password -m bf-cfb
|
sslocal -s server_name -p server_port -l local_port -k password -m bf-cfb
|
||||||
ssserver -p server_port -k password -m bf-cfb --workers 2
|
ssserver -p server_port -k password -m bf-cfb --workers 2
|
||||||
ssserver -c /etc/shadowsocks/config.json
|
ssserver -c /etc/shadowsocks/config.json -d start --pid-file=/tmp/shadowsocks.pid
|
||||||
|
ssserver -c /etc/shadowsocks/config.json -d stop --pid-file=/tmp/shadowsocks.pid
|
||||||
|
|
||||||
List all available args with ``-h``.
|
Documentation
|
||||||
|
-------------
|
||||||
Wiki
|
|
||||||
----
|
|
||||||
|
|
||||||
You can find all the documentation in the wiki:
|
You can find all the documentation in the wiki:
|
||||||
https://github.com/clowwindy/shadowsocks/wiki
|
https://github.com/shadowsocks/shadowsocks/wiki
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
@@ -156,12 +144,14 @@ MIT
|
|||||||
Bugs and Issues
|
Bugs and Issues
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
- `Troubleshooting <https://github.com/clowwindy/shadowsocks/wiki/Troubleshooting>`__
|
- `Troubleshooting <https://github.com/shadowsocks/shadowsocks/wiki/Troubleshooting>`__
|
||||||
- `Issue
|
- `Issue
|
||||||
Tracker <https://github.com/clowwindy/shadowsocks/issues?state=open>`__
|
Tracker <https://github.com/shadowsocks/shadowsocks/issues?state=open>`__
|
||||||
- `Mailing list <http://groups.google.com/group/shadowsocks>`__
|
- `Mailing list <http://groups.google.com/group/shadowsocks>`__
|
||||||
|
|
||||||
.. |PyPI version| image:: https://img.shields.io/pypi/v/shadowsocks.svg?style=flat
|
.. |PyPI version| image:: https://img.shields.io/pypi/v/shadowsocks.svg?style=flat
|
||||||
:target: https://pypi.python.org/pypi/shadowsocks
|
:target: https://pypi.python.org/pypi/shadowsocks
|
||||||
.. |Build Status| image:: https://img.shields.io/travis/clowwindy/shadowsocks/master.svg?style=flat
|
.. |Build Status| image:: https://img.shields.io/travis/shadowsocks/shadowsocks/master.svg?style=flat
|
||||||
:target: https://travis-ci.org/clowwindy/shadowsocks
|
:target: https://travis-ci.org/shadowsocks/shadowsocks
|
||||||
|
.. |Coverage Status| image:: http://192.81.132.184/result/shadowsocks
|
||||||
|
:target: http://192.81.132.184/job/Shadowsocks/ws/htmlcov/index.html
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ with codecs.open('README.rst', encoding='utf-8') as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="shadowsocks",
|
name="shadowsocks",
|
||||||
version="2.6",
|
version="2.6.2",
|
||||||
license='MIT',
|
license='MIT',
|
||||||
description="A fast tunnel proxy that help you get through firewalls",
|
description="A fast tunnel proxy that help you get through firewalls",
|
||||||
author='clowwindy',
|
author='clowwindy',
|
||||||
author_email='clowwindy42@gmail.com',
|
author_email='clowwindy42@gmail.com',
|
||||||
url='https://github.com/clowwindy/shadowsocks',
|
url='https://github.com/shadowsocks/shadowsocks',
|
||||||
packages=['shadowsocks', 'shadowsocks.crypto'],
|
packages=['shadowsocks', 'shadowsocks.crypto'],
|
||||||
package_data={
|
package_data={
|
||||||
'shadowsocks': ['README.rst', 'LICENSE']
|
'shadowsocks': ['README.rst', 'LICENSE']
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def load_libsodium():
|
|||||||
global loaded, libsodium, buf
|
global loaded, libsodium, buf
|
||||||
|
|
||||||
from ctypes.util import find_library
|
from ctypes.util import find_library
|
||||||
for p in ('sodium',):
|
for p in ('sodium', 'libsodium'):
|
||||||
libsodium_path = find_library(p)
|
libsodium_path = find_library(p)
|
||||||
if libsodium_path:
|
if libsodium_path:
|
||||||
break
|
break
|
||||||
|
|||||||
+11
-7
@@ -37,7 +37,7 @@ from shadowsocks import common
|
|||||||
def daemon_exec(config):
|
def daemon_exec(config):
|
||||||
if 'daemon' in config:
|
if 'daemon' in config:
|
||||||
if os.name != 'posix':
|
if os.name != 'posix':
|
||||||
raise Exception('daemon mode is only supported in unix')
|
raise Exception('daemon mode is only supported on Unix')
|
||||||
command = config['daemon']
|
command = config['daemon']
|
||||||
if not command:
|
if not command:
|
||||||
command = 'start'
|
command = 'start'
|
||||||
@@ -100,19 +100,21 @@ def freopen(f, mode, stream):
|
|||||||
|
|
||||||
|
|
||||||
def daemon_start(pid_file, log_file):
|
def daemon_start(pid_file, log_file):
|
||||||
# fork only once because we are sure parent will exit
|
|
||||||
pid = os.fork()
|
|
||||||
assert pid != -1
|
|
||||||
|
|
||||||
def handle_exit(signum, _):
|
def handle_exit(signum, _):
|
||||||
if signum == signal.SIGTERM:
|
if signum == signal.SIGTERM:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, handle_exit)
|
||||||
|
signal.signal(signal.SIGTERM, handle_exit)
|
||||||
|
|
||||||
|
# fork only once because we are sure parent will exit
|
||||||
|
pid = os.fork()
|
||||||
|
assert pid != -1
|
||||||
|
|
||||||
if pid > 0:
|
if pid > 0:
|
||||||
# parent waits for its child
|
# parent waits for its child
|
||||||
signal.signal(signal.SIGINT, handle_exit)
|
|
||||||
signal.signal(signal.SIGTERM, handle_exit)
|
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@@ -123,6 +125,9 @@ def daemon_start(pid_file, log_file):
|
|||||||
os.kill(ppid, signal.SIGINT)
|
os.kill(ppid, signal.SIGINT)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
os.setsid()
|
||||||
|
signal.signal(signal.SIG_IGN, signal.SIGHUP)
|
||||||
|
|
||||||
print('started')
|
print('started')
|
||||||
os.kill(ppid, signal.SIGTERM)
|
os.kill(ppid, signal.SIGTERM)
|
||||||
|
|
||||||
@@ -132,7 +137,6 @@ def daemon_start(pid_file, log_file):
|
|||||||
freopen(log_file, 'a', sys.stderr)
|
freopen(log_file, 'a', sys.stderr)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
os.kill(ppid, signal.SIGINT)
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ def main():
|
|||||||
tcp_server.close(next_tick=True)
|
tcp_server.close(next_tick=True)
|
||||||
udp_server.close(next_tick=True)
|
udp_server.close(next_tick=True)
|
||||||
signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler)
|
signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler)
|
||||||
|
|
||||||
|
def int_handler(signum, _):
|
||||||
|
sys.exit(1)
|
||||||
|
signal.signal(signal.SIGINT, int_handler)
|
||||||
|
|
||||||
loop.run()
|
loop.run()
|
||||||
except (KeyboardInterrupt, IOError, OSError) as e:
|
except (KeyboardInterrupt, IOError, OSError) as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ def main():
|
|||||||
tcp_servers + udp_servers))
|
tcp_servers + udp_servers))
|
||||||
signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
|
signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
|
||||||
child_handler)
|
child_handler)
|
||||||
|
|
||||||
|
def int_handler(signum, _):
|
||||||
|
sys.exit(1)
|
||||||
|
signal.signal(signal.SIGINT, int_handler)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
loop = eventloop.EventLoop()
|
loop = eventloop.EventLoop()
|
||||||
dns_resolver.add_to_loop(loop)
|
dns_resolver.add_to_loop(loop)
|
||||||
@@ -113,6 +118,7 @@ def main():
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
signal.signal(signal.SIGTERM, handler)
|
signal.signal(signal.SIGTERM, handler)
|
||||||
signal.signal(signal.SIGQUIT, handler)
|
signal.signal(signal.SIGQUIT, handler)
|
||||||
|
signal.signal(signal.SIGINT, handler)
|
||||||
|
|
||||||
# master
|
# master
|
||||||
for a_tcp_server in tcp_servers:
|
for a_tcp_server in tcp_servers:
|
||||||
|
|||||||
+16
-11
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2014 clowwindy
|
# Copyright (c) 2015 clowwindy
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -121,6 +121,7 @@ class TCPRelayHandler(object):
|
|||||||
self._data_to_write_to_remote = []
|
self._data_to_write_to_remote = []
|
||||||
self._upstream_status = WAIT_STATUS_READING
|
self._upstream_status = WAIT_STATUS_READING
|
||||||
self._downstream_status = WAIT_STATUS_INIT
|
self._downstream_status = WAIT_STATUS_INIT
|
||||||
|
self._client_address = local_sock.getpeername()[:2]
|
||||||
self._remote_address = None
|
self._remote_address = None
|
||||||
if is_local:
|
if is_local:
|
||||||
self._chosen_server = self._get_a_server()
|
self._chosen_server = self._get_a_server()
|
||||||
@@ -241,19 +242,18 @@ class TCPRelayHandler(object):
|
|||||||
self._create_remote_socket(self._chosen_server[0],
|
self._create_remote_socket(self._chosen_server[0],
|
||||||
self._chosen_server[1])
|
self._chosen_server[1])
|
||||||
self._loop.add(remote_sock, eventloop.POLL_ERR)
|
self._loop.add(remote_sock, eventloop.POLL_ERR)
|
||||||
data = b''.join(self._data_to_write_to_local)
|
data = b''.join(self._data_to_write_to_remote)
|
||||||
l = len(data)
|
l = len(data)
|
||||||
s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server)
|
s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server)
|
||||||
if s < l:
|
if s < l:
|
||||||
data = data[s:]
|
data = data[s:]
|
||||||
self._data_to_write_to_local = [data]
|
self._data_to_write_to_remote = [data]
|
||||||
self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
|
|
||||||
else:
|
else:
|
||||||
self._data_to_write_to_local = []
|
self._data_to_write_to_remote = []
|
||||||
self._update_stream(STREAM_UP, WAIT_STATUS_READING)
|
self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
|
||||||
self._stage = STAGE_STREAM
|
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
if eventloop.errno_from_exception(e) == errno.EINPROGRESS:
|
if eventloop.errno_from_exception(e) == errno.EINPROGRESS:
|
||||||
|
# in this case data is not sent at all
|
||||||
self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
|
self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
|
||||||
elif eventloop.errno_from_exception(e) == errno.ENOTCONN:
|
elif eventloop.errno_from_exception(e) == errno.ENOTCONN:
|
||||||
logging.error('fast open not supported on this OS')
|
logging.error('fast open not supported on this OS')
|
||||||
@@ -295,8 +295,9 @@ class TCPRelayHandler(object):
|
|||||||
if header_result is None:
|
if header_result is None:
|
||||||
raise Exception('can not parse header')
|
raise Exception('can not parse header')
|
||||||
addrtype, remote_addr, remote_port, header_length = header_result
|
addrtype, remote_addr, remote_port, header_length = header_result
|
||||||
logging.info('connecting %s:%d' % (common.to_str(remote_addr),
|
logging.info('connecting %s:%d from %s:%d' %
|
||||||
remote_port))
|
(common.to_str(remote_addr), remote_port,
|
||||||
|
self._client_address[0], self._client_address[1]))
|
||||||
self._remote_address = (remote_addr, remote_port)
|
self._remote_address = (remote_addr, remote_port)
|
||||||
# pause reading
|
# pause reading
|
||||||
self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
|
self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
|
||||||
@@ -318,7 +319,7 @@ class TCPRelayHandler(object):
|
|||||||
self._dns_resolver.resolve(remote_addr,
|
self._dns_resolver.resolve(remote_addr,
|
||||||
self._handle_dns_resolved)
|
self._handle_dns_resolved)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
self._log_error(e)
|
||||||
if self._config['verbose']:
|
if self._config['verbose']:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
# TODO use logging when debug completed
|
# TODO use logging when debug completed
|
||||||
@@ -339,7 +340,7 @@ class TCPRelayHandler(object):
|
|||||||
|
|
||||||
def _handle_dns_resolved(self, result, error):
|
def _handle_dns_resolved(self, result, error):
|
||||||
if error:
|
if error:
|
||||||
logging.error(error)
|
self._log_error(error)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
return
|
return
|
||||||
if result:
|
if result:
|
||||||
@@ -508,6 +509,10 @@ class TCPRelayHandler(object):
|
|||||||
else:
|
else:
|
||||||
logging.warn('unknown socket')
|
logging.warn('unknown socket')
|
||||||
|
|
||||||
|
def _log_error(self, e):
|
||||||
|
logging.error('%s when handling connection from %s:%d' %
|
||||||
|
(e, self._client_address[0], self._client_address[1]))
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
# destroy the handler and release any resources
|
# destroy the handler and release any resources
|
||||||
# promises:
|
# promises:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
import getopt
|
import getopt
|
||||||
import logging
|
import logging
|
||||||
from shadowsocks.common import to_bytes
|
from shadowsocks.common import to_bytes, to_str
|
||||||
|
|
||||||
|
|
||||||
VERBOSE_LEVEL = 5
|
VERBOSE_LEVEL = 5
|
||||||
@@ -73,7 +73,7 @@ def check_config(config):
|
|||||||
logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe')
|
logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe')
|
||||||
if config.get('server', '') in [b'127.0.0.1', b'localhost']:
|
if config.get('server', '') in [b'127.0.0.1', b'localhost']:
|
||||||
logging.warn('warning: server set to listen on %s:%s, are you sure?' %
|
logging.warn('warning: server set to listen on %s:%s, are you sure?' %
|
||||||
(config['server'], config['server_port']))
|
(to_str(config['server']), config['server_port']))
|
||||||
if (config.get('method', '') or '').lower() == b'table':
|
if (config.get('method', '') or '').lower() == b'table':
|
||||||
logging.warn('warning: table is not safe; please use a safer cipher, '
|
logging.warn('warning: table is not safe; please use a safer cipher, '
|
||||||
'like AES-256-CFB')
|
'like AES-256-CFB')
|
||||||
|
|||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# assert.sh 1.0 - bash unit testing framework
|
||||||
|
# Copyright (C) 2009, 2010, 2011, 2012 Robert Lehmann
|
||||||
|
#
|
||||||
|
# http://github.com/lehmannro/assert.sh
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export DISCOVERONLY=${DISCOVERONLY:-}
|
||||||
|
export DEBUG=${DEBUG:-}
|
||||||
|
export STOP=${STOP:-}
|
||||||
|
export INVARIANT=${INVARIANT:-}
|
||||||
|
export CONTINUE=${CONTINUE:-}
|
||||||
|
|
||||||
|
args="$(getopt -n "$0" -l \
|
||||||
|
verbose,help,stop,discover,invariant,continue vhxdic $*)" \
|
||||||
|
|| exit -1
|
||||||
|
for arg in $args; do
|
||||||
|
case "$arg" in
|
||||||
|
-h)
|
||||||
|
echo "$0 [-vxidc]" \
|
||||||
|
"[--verbose] [--stop] [--invariant] [--discover] [--continue]"
|
||||||
|
echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]"
|
||||||
|
exit 0;;
|
||||||
|
--help)
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $0 [options]
|
||||||
|
Language-agnostic unit tests for subprocesses.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-v, --verbose generate output for every individual test case
|
||||||
|
-x, --stop stop running tests after the first failure
|
||||||
|
-i, --invariant do not measure timings to remain invariant between runs
|
||||||
|
-d, --discover collect test suites only, do not run any tests
|
||||||
|
-c, --continue do not modify exit code to test suite status
|
||||||
|
-h show brief usage information and exit
|
||||||
|
--help show this help message and exit
|
||||||
|
EOF
|
||||||
|
exit 0;;
|
||||||
|
-v|--verbose)
|
||||||
|
DEBUG=1;;
|
||||||
|
-x|--stop)
|
||||||
|
STOP=1;;
|
||||||
|
-i|--invariant)
|
||||||
|
INVARIANT=1;;
|
||||||
|
-d|--discover)
|
||||||
|
DISCOVERONLY=1;;
|
||||||
|
-c|--continue)
|
||||||
|
CONTINUE=1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
printf -v _indent "\n\t" # local format helper
|
||||||
|
|
||||||
|
_assert_reset() {
|
||||||
|
tests_ran=0
|
||||||
|
tests_failed=0
|
||||||
|
tests_errors=()
|
||||||
|
tests_starttime="$(date +%s.%N)" # seconds_since_epoch.nanoseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_end() {
|
||||||
|
# assert_end [suite ..]
|
||||||
|
tests_endtime="$(date +%s.%N)"
|
||||||
|
tests="$tests_ran ${*:+$* }tests"
|
||||||
|
[[ -n "$DISCOVERONLY" ]] && echo "collected $tests." && _assert_reset && return
|
||||||
|
[[ -n "$DEBUG" ]] && echo
|
||||||
|
[[ -z "$INVARIANT" ]] && report_time=" in $(bc \
|
||||||
|
<<< "${tests_endtime%.N} - ${tests_starttime%.N}" \
|
||||||
|
| sed -e 's/\.\([0-9]\{0,3\}\)[0-9]*/.\1/' -e 's/^\./0./')s" \
|
||||||
|
|| report_time=
|
||||||
|
|
||||||
|
if [[ "$tests_failed" -eq 0 ]]; then
|
||||||
|
echo "all $tests passed$report_time."
|
||||||
|
else
|
||||||
|
for error in "${tests_errors[@]}"; do echo "$error"; done
|
||||||
|
echo "$tests_failed of $tests failed$report_time."
|
||||||
|
fi
|
||||||
|
tests_failed_previous=$tests_failed
|
||||||
|
[[ $tests_failed -gt 0 ]] && tests_suite_status=1
|
||||||
|
_assert_reset
|
||||||
|
return $tests_failed_previous
|
||||||
|
}
|
||||||
|
|
||||||
|
assert() {
|
||||||
|
# assert <command> <expected stdout> [stdin]
|
||||||
|
(( tests_ran++ )) || :
|
||||||
|
[[ -n "$DISCOVERONLY" ]] && return || true
|
||||||
|
# printf required for formatting
|
||||||
|
printf -v expected "x${2:-}" # x required to overwrite older results
|
||||||
|
result="$(eval 2>/dev/null $1 <<< ${3:-})" || true
|
||||||
|
# Note: $expected is already decorated
|
||||||
|
if [[ "x$result" == "$expected" ]]; then
|
||||||
|
[[ -n "$DEBUG" ]] && echo -n . || true
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")"
|
||||||
|
[[ -z "$result" ]] && result="nothing" || result="\"$result\""
|
||||||
|
[[ -z "$2" ]] && expected="nothing" || expected="\"$2\""
|
||||||
|
_assert_fail "expected $expected${_indent}got $result" "$1" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_raises() {
|
||||||
|
# assert_raises <command> <expected code> [stdin]
|
||||||
|
(( tests_ran++ )) || :
|
||||||
|
[[ -n "$DISCOVERONLY" ]] && return || true
|
||||||
|
status=0
|
||||||
|
(eval $1 <<< ${3:-}) > /dev/null 2>&1 || status=$?
|
||||||
|
expected=${2:-0}
|
||||||
|
if [[ "$status" -eq "$expected" ]]; then
|
||||||
|
[[ -n "$DEBUG" ]] && echo -n . || true
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
_assert_fail "program terminated with code $status instead of $expected" "$1" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
_assert_fail() {
|
||||||
|
# _assert_fail <failure> <command> <stdin>
|
||||||
|
[[ -n "$DEBUG" ]] && echo -n X
|
||||||
|
report="test #$tests_ran \"$2${3:+ <<< $3}\" failed:${_indent}$1"
|
||||||
|
if [[ -n "$STOP" ]]; then
|
||||||
|
[[ -n "$DEBUG" ]] && echo
|
||||||
|
echo "$report"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
tests_errors[$tests_failed]="$report"
|
||||||
|
(( tests_failed++ )) || :
|
||||||
|
}
|
||||||
|
|
||||||
|
_assert_reset
|
||||||
|
: ${tests_suite_status:=0} # remember if any of the tests failed so far
|
||||||
|
_assert_cleanup() {
|
||||||
|
local status=$?
|
||||||
|
# modify exit code if it's not already non-zero
|
||||||
|
[[ $status -eq 0 && -z $CONTINUE ]] && exit $tests_suite_status
|
||||||
|
}
|
||||||
|
trap _assert_cleanup EXIT
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import tornado.ioloop
|
||||||
|
import tornado.web
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
class MainHandler(tornado.web.RequestHandler):
|
||||||
|
def get(self, project):
|
||||||
|
try:
|
||||||
|
with open('/tmp/%s-coverage' % project, 'rb') as f:
|
||||||
|
coverage = f.read().strip()
|
||||||
|
n = int(coverage.strip('%'))
|
||||||
|
if n > 80:
|
||||||
|
color = 'brightgreen'
|
||||||
|
else:
|
||||||
|
color = 'yellow'
|
||||||
|
self.redirect(('https://img.shields.io/badge/'
|
||||||
|
'coverage-%s-%s.svg'
|
||||||
|
'?style=flat') %
|
||||||
|
(urllib.quote(coverage), color))
|
||||||
|
except IOError:
|
||||||
|
raise tornado.web.HTTPError(404)
|
||||||
|
|
||||||
|
application = tornado.web.Application([
|
||||||
|
(r"/([a-zA-Z0-9\-_]+)", MainHandler),
|
||||||
|
])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
application.listen(8888, address='127.0.0.1')
|
||||||
|
tornado.ioloop.IOLoop.instance().start()
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DEV=lo
|
||||||
|
PORT=8388
|
||||||
|
DELAY=100ms
|
||||||
|
|
||||||
|
type tc 2> /dev/null && (
|
||||||
|
tc qdisc add dev $DEV root handle 1: htb
|
||||||
|
tc class add dev $DEV parent 1: classid 1:1 htb rate 2mbps
|
||||||
|
tc class add dev $DEV parent 1:1 classid 1:6 htb rate 2mbps ceil 1mbps prio 0
|
||||||
|
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 6 fw flowid 1:6
|
||||||
|
|
||||||
|
tc filter add dev $DEV parent 1:0 protocol ip u32 match ip dport $PORT 0xffff flowid 1:6
|
||||||
|
tc filter add dev $DEV parent 1:0 protocol ip u32 match ip sport $PORT 0xffff flowid 1:6
|
||||||
|
|
||||||
|
tc qdisc show dev lo
|
||||||
|
)
|
||||||
|
|
||||||
+1
-1
@@ -138,7 +138,7 @@ try:
|
|||||||
finally:
|
finally:
|
||||||
for p in [p1, p2]:
|
for p in [p1, p2]:
|
||||||
try:
|
try:
|
||||||
os.kill(p.pid, signal.SIGQUIT)
|
os.kill(p.pid, signal.SIGINT)
|
||||||
os.waitpid(p.pid, 0)
|
os.waitpid(p.pid, 0)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
Executable
+40
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. tests/assert.sh
|
||||||
|
|
||||||
|
PYTHON="coverage run -a -p"
|
||||||
|
LOCAL="$PYTHON shadowsocks/local.py"
|
||||||
|
SERVER="$PYTHON shadowsocks/server.py"
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 | grep ERROR" "ERROR: config not specified"
|
||||||
|
assert "$LOCAL 2>&1 | grep usage | cut -d: -f1" "usage"
|
||||||
|
|
||||||
|
assert "$SERVER 2>&1 | grep ERROR" "ERROR: config not specified"
|
||||||
|
assert "$SERVER 2>&1 | grep usage | cut -d: -f1" "usage"
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d start | grep WARNING | awk -F\"WARNING\" '{print \$2}'" " warning: server set to listen on 127.0.0.1:8388, are you sure?"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4-md5 -k testrc4 -s 0.0.0.0 -p 8388 -t10 -d start | grep WARNING | awk -F\"WARNING\" '{print \$2}'" " warning: your timeout 10 seems too short"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4-md5 -k testrc4 -s 0.0.0.0 -p 8388 -t1000 -d start | grep WARNING | awk -F\"WARNING\" '{print \$2}'" " warning: your timeout 1000 seems too long"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4 -k testrc4 -s 0.0.0.0 -p 8388 -d start | grep WARNING | awk -F\"WARNING\" '{print \$2}'" " warning: RC4 is not safe; please use a safer cipher, like AES-256-CFB"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4-md5 -k mypassword -s 0.0.0.0 -p 8388 -d start | grep ERROR | awk -F\"ERROR\" '{print \$2}'" " DON'T USE DEFAULT PASSWORD! Please change it in your config.json!"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4-md5 -p 8388 -k testrc4 -d start | grep ERROR | awk -F\"ERROR\" '{print \$2}'" ": server addr not specified"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$LOCAL 2>&1 -m rc4-md5 -p 8388 -s 0.0.0.0 -d start | grep ERROR | awk -F\"ERROR\" '{print \$2}'" ": password not specified"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
assert "$SERVER 2>&1 -m rc4-md5 -p 8388 -s 0.0.0.0 -d start | grep ERROR | awk -F\"ERROR\" '{print \$2}'" ": password or port_password not specified"
|
||||||
|
$LOCAL 2>/dev/null 1>/dev/null -m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -d stop
|
||||||
|
|
||||||
|
|
||||||
|
assert_end command
|
||||||
+15
-14
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
function test {
|
function run_test {
|
||||||
expected=$1
|
expected=$1
|
||||||
shift
|
shift
|
||||||
echo "running test: $command $@"
|
echo "running test: $command $@"
|
||||||
@@ -20,23 +20,24 @@ do
|
|||||||
|
|
||||||
command="coverage run -p -a shadowsocks/$module.py"
|
command="coverage run -p -a shadowsocks/$module.py"
|
||||||
|
|
||||||
test 0 -c tests/aes.json -d stop --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
mkdir -p tmp
|
||||||
|
|
||||||
test 0 -c tests/aes.json -d start --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d stop --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 0 -c tests/aes.json -d stop --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
|
||||||
|
|
||||||
test 0 -c tests/aes.json -d start --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d start --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 1 -c tests/aes.json -d start --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d stop --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 0 -c tests/aes.json -d stop --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
|
||||||
|
|
||||||
test 0 -c tests/aes.json -d start --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d start --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 0 -c tests/aes.json -d restart --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 1 -c tests/aes.json -d start --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 0 -c tests/aes.json -d stop --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d stop --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
|
|
||||||
test 0 -c tests/aes.json -d restart --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d start --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 0 -c tests/aes.json -d stop --pid-file /tmp/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d restart --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
|
run_test 0 -c tests/aes.json -d stop --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
|
|
||||||
test 1 -c tests/aes.json -d start --pid-file /tmp/not_exist/shadowsocks.pid --log-file /tmp/shadowsocks.log
|
run_test 0 -c tests/aes.json -d restart --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
test 1 -c tests/aes.json -d start --pid-file /tmp/shadowsocks.pid --log-file /tmp/not_exist/shadowsocks.log
|
run_test 0 -c tests/aes.json -d stop --pid-file tmp/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
|
|
||||||
|
run_test 1 -c tests/aes.json -d start --pid-file tmp/not_exist/shadowsocks.pid --log-file tmp/shadowsocks.log
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PYTHON="coverage run -p -a"
|
||||||
|
URL=http://127.0.0.1/file
|
||||||
|
|
||||||
|
mkdir -p tmp
|
||||||
|
|
||||||
|
$PYTHON shadowsocks/local.py -c tests/aes.json &
|
||||||
|
LOCAL=$!
|
||||||
|
|
||||||
|
$PYTHON shadowsocks/server.py -c tests/aes.json &
|
||||||
|
SERVER=$!
|
||||||
|
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
time curl -o tmp/expected $URL
|
||||||
|
time curl -o tmp/result --socks5-hostname 127.0.0.1:1081 $URL
|
||||||
|
|
||||||
|
kill -s SIGINT $LOCAL
|
||||||
|
kill -s SIGINT $SERVER
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
diff tmp/expected tmp/result || exit 1
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Useful Tools
|
||||||
|
===========
|
||||||
|
|
||||||
|
autoban.py
|
||||||
|
----------
|
||||||
|
|
||||||
|
Automatically ban IPs that try to brute force crack the server.
|
||||||
|
|
||||||
|
See https://github.com/shadowsocks/shadowsocks/wiki/Ban-Brute-Force-Crackers
|
||||||
Executable
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2015 clowwindy
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function, \
|
||||||
|
with_statement
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description='See README')
|
||||||
|
parser.add_argument('-c', '--count', default=3, type=int,
|
||||||
|
help='with how many failure times it should be '
|
||||||
|
'considered as an attack')
|
||||||
|
config = parser.parse_args()
|
||||||
|
ips = {}
|
||||||
|
banned = set()
|
||||||
|
for line in sys.stdin:
|
||||||
|
if 'can not parse header when' in line:
|
||||||
|
ip = line.split()[-1].split(':')[0]
|
||||||
|
if ip not in ips:
|
||||||
|
ips[ip] = 1
|
||||||
|
print(ip)
|
||||||
|
else:
|
||||||
|
ips[ip] += 1
|
||||||
|
if ip not in banned and ips[ip] >= config.count:
|
||||||
|
banned.add(ip)
|
||||||
|
cmd = 'iptables -A INPUT -s %s -j DROP' % ip
|
||||||
|
print(cmd, file=sys.stderr)
|
||||||
|
os.system(cmd)
|
||||||
Reference in New Issue
Block a user