move to pypi
This commit is contained in:
parent
da3981ac23
commit
794ff240a6
10 changed files with 169 additions and 62 deletions
10
.travis.yml
10
.travis.yml
|
@ -1,15 +1,11 @@
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "2.6"
|
- 2.6
|
||||||
- "2.7"
|
- 2.7
|
||||||
|
- pypy
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -qq libevent-dev python-gevent
|
- sudo apt-get install -qq libevent-dev python-gevent
|
||||||
- pip install gevent
|
- pip install gevent
|
||||||
- pip install simplejson
|
|
||||||
script:
|
script:
|
||||||
- python test.py
|
- python test.py
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- dev
|
|
||||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Shadowsocks
|
||||||
|
|
||||||
|
Copyright (c) 2013 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.
|
45
README.md
45
README.md
|
@ -2,7 +2,7 @@ shadowsocks
|
||||||
===========
|
===========
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/clowwindy/shadowsocks.png)](https://travis-ci.org/clowwindy/shadowsocks)
|
[![Build Status](https://travis-ci.org/clowwindy/shadowsocks.png)](https://travis-ci.org/clowwindy/shadowsocks)
|
||||||
Current version: 1.2.3
|
Current version: 1.3.0
|
||||||
|
|
||||||
shadowsocks is a lightweight tunnel proxy which can help you get through firewalls
|
shadowsocks is a lightweight tunnel proxy which can help you get through firewalls
|
||||||
|
|
||||||
|
@ -16,19 +16,34 @@ First, make sure you have Python 2.6 or 2.7.
|
||||||
$ python --version
|
$ python --version
|
||||||
Python 2.6.8
|
Python 2.6.8
|
||||||
|
|
||||||
|
Install Shadowsocks.
|
||||||
|
|
||||||
Then edit `config.json`, change the following values:
|
pip install shadowsocks
|
||||||
|
|
||||||
server your server ip or hostname
|
Create a file named `config.json`, with the following content.
|
||||||
|
|
||||||
|
{
|
||||||
|
"server":"my_server_ip",
|
||||||
|
"server_port":8388,
|
||||||
|
"local_port":1080,
|
||||||
|
"password":"barfoo!",
|
||||||
|
"timeout":600,
|
||||||
|
"method":null
|
||||||
|
}
|
||||||
|
|
||||||
|
Explaination of the fields:
|
||||||
|
|
||||||
|
server your server IP (IPv4/IPv6), notice that your server will listen to this IP
|
||||||
server_port server port
|
server_port server port
|
||||||
local_port local port
|
local_port local port
|
||||||
password a password used to encrypt transfer
|
password a password used to encrypt transfer
|
||||||
|
timeout in seconds
|
||||||
method encryption method, "bf-cfb", "aes-256-cfb", "des-cfb", "rc4", etc. Default is table
|
method encryption method, "bf-cfb", "aes-256-cfb", "des-cfb", "rc4", etc. Default is table
|
||||||
|
|
||||||
|
`cd` into the directory of `config.json`. Run `ssserver` on your server. To run it in the background, run
|
||||||
|
`nohup ssserver > log &`.
|
||||||
|
|
||||||
Put all the files on your server. Run `python server.py` on your server. To run it in the background, run `nohup python server.py > log &`.
|
On your client machine, run `sslocal`.
|
||||||
|
|
||||||
Put all the files on your client machine. Run `python local.py` on your client machine.
|
|
||||||
|
|
||||||
Change the proxy setting in your browser into
|
Change the proxy setting in your browser into
|
||||||
|
|
||||||
|
@ -36,6 +51,15 @@ Change the proxy setting in your browser into
|
||||||
hostname: 127.0.0.1
|
hostname: 127.0.0.1
|
||||||
port: your local_port
|
port: your local_port
|
||||||
|
|
||||||
|
Command line args
|
||||||
|
------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
ssserver -p server_port -k password -m bf-cfb
|
||||||
|
ssserver -c /etc/shadowsocks/config.json
|
||||||
|
|
||||||
Encryption
|
Encryption
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -49,15 +73,6 @@ Others:
|
||||||
|
|
||||||
pip install M2Crypto
|
pip install M2Crypto
|
||||||
|
|
||||||
|
|
||||||
Command line args
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
You can use args to override settings from `config.json`.
|
|
||||||
|
|
||||||
python local.py -s server_name -p server_port -l local_port -k password -m bf-cfb -b bind_address -6
|
|
||||||
python server.py -p server_port -k password -m bf-cfb -6
|
|
||||||
|
|
||||||
Performance
|
Performance
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
21
setup.py
Normal file
21
setup.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name = "shadowsocks",
|
||||||
|
version = "1.3.0",
|
||||||
|
license = 'MIT',
|
||||||
|
description = "a lightweight tunnel proxy",
|
||||||
|
author = 'clowwindy42@gmail.com',
|
||||||
|
url = 'https://github.com/clowwindy/shadowsocks',
|
||||||
|
packages = ['shadowsocks'],
|
||||||
|
package_data={
|
||||||
|
'shadowsocks': ['README.md', 'LICENSE', 'config.json']
|
||||||
|
},
|
||||||
|
install_requires = ['setuptools',
|
||||||
|
],
|
||||||
|
entry_points="""
|
||||||
|
[console_scripts]
|
||||||
|
sslocal = shadowsocks.local:main
|
||||||
|
ssserver = shadowsocks.server:main
|
||||||
|
""",
|
||||||
|
)
|
1
shadowsocks/__init__.py
Normal file
1
shadowsocks/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#!/usr/bin/python
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
# Copyright (c) 2012 clowwindy
|
# Copyright (c) 2013 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
|
||||||
|
@ -43,6 +43,7 @@ import os
|
||||||
import logging
|
import logging
|
||||||
import getopt
|
import getopt
|
||||||
import encrypt
|
import encrypt
|
||||||
|
import utils
|
||||||
|
|
||||||
|
|
||||||
def send_all(sock, data):
|
def send_all(sock, data):
|
||||||
|
@ -142,28 +143,48 @@ class Socks5Server(SocketServer.StreamRequestHandler):
|
||||||
logging.warn(e)
|
logging.warn(e)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
try:
|
global SERVER, REMOTE_PORT, PORT, KEY, METHOD, LOCAL, IPv6
|
||||||
os.chdir(os.path.dirname(__file__) or '.')
|
|
||||||
except NameError:
|
|
||||||
# fix py2exe
|
|
||||||
if hasattr(sys, "frozen") and sys.frozen in \
|
|
||||||
("windows_exe", "console_exe"):
|
|
||||||
p = os.path.dirname(os.path.abspath(sys.executable))
|
|
||||||
os.chdir(p)
|
|
||||||
print 'shadowsocks v1.2.3'
|
|
||||||
|
|
||||||
with open('config.json', 'rb') as f:
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
config = json.load(f)
|
format='%(asctime)s %(levelname)-8s %(message)s',
|
||||||
SERVER = config['server']
|
datefmt='%Y-%m-%d %H:%M:%S', filemode='a+')
|
||||||
REMOTE_PORT = config['server_port']
|
|
||||||
PORT = config['local_port']
|
# fix py2exe
|
||||||
KEY = config['password']
|
if hasattr(sys, "frozen") and sys.frozen in \
|
||||||
METHOD = config.get('method', None)
|
("windows_exe", "console_exe"):
|
||||||
LOCAL = config.get('local', '')
|
p = os.path.dirname(os.path.abspath(sys.executable))
|
||||||
|
os.chdir(p)
|
||||||
|
version = ''
|
||||||
|
try:
|
||||||
|
import pkg_resources
|
||||||
|
version = pkg_resources.get_distribution('shadowsocks').version
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
print 'shadowsocks %s' % version
|
||||||
|
|
||||||
|
METHOD = None
|
||||||
|
LOCAL = ''
|
||||||
IPv6 = False
|
IPv6 = False
|
||||||
|
|
||||||
optlist, args = getopt.getopt(sys.argv[1:], 's:b:p:k:l:m:6')
|
config_path = utils.find_config()
|
||||||
|
optlist, args = getopt.getopt(sys.argv[1:], 's:b:p:k:l:m:c:6')
|
||||||
|
for key, value in optlist:
|
||||||
|
if key == '-c':
|
||||||
|
config_path = value
|
||||||
|
|
||||||
|
if config_path:
|
||||||
|
logging.info('loading config from %s' % config_path)
|
||||||
|
with open(config_path, 'rb') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
SERVER = config['server']
|
||||||
|
REMOTE_PORT = config['server_port']
|
||||||
|
PORT = config['local_port']
|
||||||
|
KEY = config['password']
|
||||||
|
METHOD = config.get('method', None)
|
||||||
|
LOCAL = config.get('local', '')
|
||||||
|
|
||||||
|
optlist, args = getopt.getopt(sys.argv[1:], 's:b:p:k:l:m:c:6')
|
||||||
for key, value in optlist:
|
for key, value in optlist:
|
||||||
if key == '-p':
|
if key == '-p':
|
||||||
REMOTE_PORT = int(value)
|
REMOTE_PORT = int(value)
|
||||||
|
@ -180,10 +201,6 @@ if __name__ == '__main__':
|
||||||
elif key == '-6':
|
elif key == '-6':
|
||||||
IPv6 = True
|
IPv6 = True
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG,
|
|
||||||
format='%(asctime)s %(levelname)-8s %(message)s',
|
|
||||||
datefmt='%Y-%m-%d %H:%M:%S', filemode='a+')
|
|
||||||
|
|
||||||
encrypt.init_table(KEY, METHOD)
|
encrypt.init_table(KEY, METHOD)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -197,3 +214,6 @@ if __name__ == '__main__':
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
server.shutdown()
|
server.shutdown()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
# Copyright (c) 2012 clowwindy
|
# Copyright (c) 2013 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
|
||||||
|
@ -43,6 +43,7 @@ import os
|
||||||
import logging
|
import logging
|
||||||
import getopt
|
import getopt
|
||||||
import encrypt
|
import encrypt
|
||||||
|
import utils
|
||||||
|
|
||||||
|
|
||||||
def send_all(sock, data):
|
def send_all(sock, data):
|
||||||
|
@ -123,21 +124,40 @@ class Socks5Server(SocketServer.StreamRequestHandler):
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
logging.warn(e)
|
logging.warn(e)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
os.chdir(os.path.dirname(__file__) or '.')
|
global SERVER, PORT, KEY, METHOD, IPv6
|
||||||
|
|
||||||
print 'shadowsocks v1.2.3'
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
|
format='%(asctime)s %(levelname)-8s %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S', filemode='a+')
|
||||||
|
|
||||||
|
version = ''
|
||||||
|
try:
|
||||||
|
import pkg_resources
|
||||||
|
version = pkg_resources.get_distribution('shadowsocks').version
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
print 'shadowsocks %s' % version
|
||||||
|
|
||||||
|
METHOD = None
|
||||||
|
IPv6 = False
|
||||||
|
|
||||||
|
config_path = utils.find_config()
|
||||||
|
optlist, args = getopt.getopt(sys.argv[1:], 'p:k:m:c:6')
|
||||||
|
for key, value in optlist:
|
||||||
|
if key == '-c':
|
||||||
|
config_path = value
|
||||||
with open('config.json', 'rb') as f:
|
with open('config.json', 'rb') as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
|
||||||
SERVER = config['server']
|
if config_path:
|
||||||
PORT = config['server_port']
|
logging.info('loading config from %s' % config_path)
|
||||||
KEY = config['password']
|
SERVER = config['server']
|
||||||
METHOD = config.get('method', None)
|
PORT = config['server_port']
|
||||||
IPv6 = False
|
KEY = config['password']
|
||||||
|
METHOD = config.get('method', None)
|
||||||
|
|
||||||
optlist, args = getopt.getopt(sys.argv[1:], 'p:k:m:6')
|
optlist, args = getopt.getopt(sys.argv[1:], 'p:k:m:c:6')
|
||||||
for key, value in optlist:
|
for key, value in optlist:
|
||||||
if key == '-p':
|
if key == '-p':
|
||||||
PORT = int(value)
|
PORT = int(value)
|
||||||
|
@ -148,10 +168,6 @@ if __name__ == '__main__':
|
||||||
elif key == '-6':
|
elif key == '-6':
|
||||||
IPv6 = True
|
IPv6 = True
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG,
|
|
||||||
format='%(asctime)s %(levelname)-8s %(message)s',
|
|
||||||
datefmt='%Y-%m-%d %H:%M:%S', filemode='a+')
|
|
||||||
|
|
||||||
encrypt.init_table(KEY, METHOD)
|
encrypt.init_table(KEY, METHOD)
|
||||||
if IPv6:
|
if IPv6:
|
||||||
ThreadingTCPServer.address_family = socket.AF_INET6
|
ThreadingTCPServer.address_family = socket.AF_INET6
|
||||||
|
@ -161,3 +177,6 @@ if __name__ == '__main__':
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
14
shadowsocks/utils.py
Normal file
14
shadowsocks/utils.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def find_config():
|
||||||
|
config_path = 'config.json'
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
return config_path
|
||||||
|
config_path = os.path.join(os.path.dirname(__file__), '../', 'config.json')
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
return config_path
|
||||||
|
return None
|
4
test.py
4
test.py
|
@ -82,9 +82,9 @@ decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
|
||||||
for i in range(0, 256):
|
for i in range(0, 256):
|
||||||
assert(target2[0][i] == ord(encrypt_table[i]))
|
assert(target2[0][i] == ord(encrypt_table[i]))
|
||||||
assert(target2[1][i] == ord(decrypt_table[i]))
|
assert(target2[1][i] == ord(decrypt_table[i]))
|
||||||
p1 = Popen(['python', 'server.py'], shell=False, bufsize=0, stdin=PIPE,
|
p1 = Popen(['python', 'shadowsocks/server.py'], shell=False, bufsize=0, stdin=PIPE,
|
||||||
stdout=PIPE, stderr=PIPE, close_fds=True)
|
stdout=PIPE, stderr=PIPE, close_fds=True)
|
||||||
p2 = Popen(['python', 'local.py'], shell=False, bufsize=0, stdin=PIPE,
|
p2 = Popen(['python', 'shadowsocks/local.py'], shell=False, bufsize=0, stdin=PIPE,
|
||||||
stdout=PIPE, stderr=PIPE, close_fds=True)
|
stdout=PIPE, stderr=PIPE, close_fds=True)
|
||||||
p3 = None
|
p3 = None
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue