Skip to content

Commit f584509

Browse files
committed
port x_tunnel to python3
1 parent e80bfcc commit f584509

17 files changed

Lines changed: 1053 additions & 89 deletions

lib/common/simple_http_client.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ def __init__(self, address, http_proxy=None, use_https=False, conn_life=30, cert
3030
self.conn_life = conn_life
3131
self.cert = cert
3232

33-
3433
if not self.http_proxy:
3534
self.path_base = ""
3635
else:
@@ -134,7 +133,7 @@ def request(self, method="GET", path="", header={}, data="", timeout=60):
134133
if start > end:
135134
self.sock_pool.put(response.conn)
136135
#logging.info("POST t:%d s:%d %d %s", (time.time()-time_request)*1000, length, response.status, req_path)
137-
response_data = b"".join(data_buffer).decode("iso-8859-1")
136+
response_data = b"".join(data_buffer)
138137
return response_data, 200, response
139138

140139
data = response.read(65535)
@@ -159,32 +158,33 @@ def request(self, method="GET", path="", header={}, data="", timeout=60):
159158
self.sock = None
160159
return "", 400, response
161160

162-
163161
def fetch(self, method, host, path, headers, payload, bufsize=8192, timeout=20):
164162
request_data = '%s %s HTTP/1.1\r\n' % (method, path)
165163
request_data += ''.join('%s: %s\r\n' % (k, v) for k, v in list(headers.items()))
166164
request_data += '\r\n'
165+
request_data = request_data.encode()
166+
167+
if not isinstance(payload, bytes):
168+
payload = payload.encode()
167169

168170
#print("request:%s" % request_data)
169171
#print("payload:%s" % payload)
170172

171173
conn = self.get_conn()
172174
if not conn:
173-
logging.warn("get sock fail")
175+
logging.warning("get sock fail")
174176
return
175177

176178
if len(request_data) + len(payload) < 1300:
177-
if isinstance(payload,bytes):
178-
payload = payload.decode('iso-8859-1')
179179
payload = request_data + payload
180180
else:
181-
conn.sock.send(request_data.encode())
181+
conn.sock.send(request_data)
182182

183183
payload_len = len(payload)
184184
start = 0
185185
while start < payload_len:
186186
send_size = min(payload_len - start, 65535)
187-
sended = conn.sock.send(payload[start:start+send_size].encode())
187+
sended = conn.sock.send(payload[start:start+send_size])
188188
start += sended
189189

190190
conn.sock.settimeout(timeout)
@@ -197,8 +197,8 @@ def fetch(self, method, host, path, headers, payload, bufsize=8192, timeout=20):
197197
response.begin()
198198
#conn.sock.settimeout(orig_timeout)
199199
except http.client.BadStatusLine as e:
200-
logging.warn("fetch bad status line:%r", e)
200+
logging.warning("fetch bad status line:%r", e)
201201
response = None
202202
except Exception as e:
203-
logging.warn("fetch:%r", e)
203+
logging.warning("fetch:%r", e)
204204
return response

lib/common/utils.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
g_ip_check = re.compile(r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$')
66

7+
78
def check_ip_valid(ip):
89
ret = g_ip_check.match(ip)
910
if ret is not None:
@@ -17,7 +18,17 @@ def check_ip_valid(ip):
1718

1819

1920
def str2hex(data):
20-
return ":".join("{:02x}".format(ord(c)) for c in data)
21+
out_list = []
22+
if isinstance(data, bytes):
23+
data1 = data.decode('iso-8859-1')
24+
25+
for c in data1:
26+
#print(c)
27+
cc = ord(c)
28+
ccc = "{:02x}".format(cc)
29+
out_list.append(ccc)
30+
out_str = ":".join(out_list)
31+
return out_str
2132

2233

2334
def generate_random_lowercase(n):

lib/common/xconfig.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ def __init__(self, config_path):
1414

1515
def load(self):
1616
if os.path.isfile(self.config_path):
17-
with file(self.config_path, 'r') as f:
18-
self.file_config = json.loads(f.read())
17+
with open(self.config_path, 'r') as f:
18+
content = f.read()
19+
self.file_config = json.loads(content)
1920

2021
for var_name in self.default_config:
2122
if self.file_config and var_name in self.file_config:
@@ -32,7 +33,7 @@ def save(self):
3233
else:
3334
self.file_config[var_name] = getattr(self, var_name)
3435

35-
with file(self.config_path, "w") as f:
36+
with open(self.config_path, "w") as f:
3637
f.write(json.dumps(self.file_config, indent=2))
3738

3839
def set_var(self, var_name, default_value):

lib/noarch/encrypt.py

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright (c) 2014 clowwindy
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
24+
25+
import os
26+
import sys
27+
import hashlib
28+
import logging as xlog
29+
30+
31+
from scrypto import m2, rc4_md5, salsa20_ctr, ctypes_openssl, table
32+
33+
34+
method_supported = {}
35+
method_supported.update(rc4_md5.ciphers)
36+
method_supported.update(salsa20_ctr.ciphers)
37+
method_supported.update(ctypes_openssl.ciphers)
38+
# let M2Crypto override ctypes_openssl
39+
method_supported.update(m2.ciphers)
40+
method_supported.update(table.ciphers)
41+
42+
43+
def random_string(length):
44+
try:
45+
import M2Crypto.Rand
46+
return M2Crypto.Rand.rand_bytes(length)
47+
except ImportError:
48+
return os.urandom(length)
49+
50+
51+
cached_keys = {}
52+
53+
54+
def try_cipher(key, method=None):
55+
Encryptor(key, method)
56+
57+
58+
def EVP_BytesToKey(password, key_len, iv_len):
59+
# equivalent to OpenSSL's EVP_BytesToKey() with count 1
60+
# so that we make the same key and iv as nodejs version
61+
if hasattr(password, 'encode'):
62+
password = password.encode('utf-8')
63+
r = cached_keys.get(password, None)
64+
if r:
65+
return r
66+
m = []
67+
i = 0
68+
while len(b''.join(m)) < (key_len + iv_len):
69+
md5 = hashlib.md5()
70+
data = password
71+
if i > 0:
72+
data = m[i - 1] + password
73+
md5.update(data)
74+
m.append(md5.digest())
75+
i += 1
76+
ms = b''.join(m)
77+
key = ms[:key_len]
78+
iv = ms[key_len:key_len + iv_len]
79+
cached_keys[password] = (key, iv)
80+
return key, iv
81+
82+
83+
class Encryptor(object):
84+
def __init__(self, key, method):
85+
self.key = key
86+
self.method = method
87+
self.iv = None
88+
self.iv_sent = False
89+
self.cipher_iv = b''
90+
self.decipher = None
91+
method = method.lower()
92+
self._method_info = self.get_method_info(method)
93+
if self._method_info:
94+
self.cipher = self.get_cipher(key, method, 1,
95+
random_string(self._method_info[1]))
96+
else:
97+
xlog.error('method %s not supported' % method)
98+
sys.exit(1)
99+
100+
def get_method_info(self, method):
101+
method = method.lower()
102+
m = method_supported.get(method)
103+
return m
104+
105+
def iv_len(self):
106+
return len(self.cipher_iv)
107+
108+
def get_cipher(self, password, method, op, iv):
109+
if hasattr(password, 'encode'):
110+
password = password.encode('utf-8')
111+
m = self._method_info
112+
if m[0] > 0:
113+
key, iv_ = EVP_BytesToKey(password, m[0], m[1])
114+
else:
115+
# key_length == 0 indicates we should use the key directly
116+
key, iv = password, b''
117+
118+
iv = iv[:m[1]]
119+
if op == 1:
120+
# this iv is for cipher not decipher
121+
self.cipher_iv = iv[:m[1]]
122+
return m[2](method, key, iv, op)
123+
124+
def encrypt(self, buf):
125+
if len(buf) == 0:
126+
return buf
127+
128+
if not self.iv_sent:
129+
head = self.cipher_iv
130+
self.iv_sent = True
131+
else:
132+
head = ""
133+
return head + self.cipher.update(buf)
134+
135+
def decrypt(self, buf):
136+
if len(buf) == 0:
137+
return buf
138+
if self.decipher is None:
139+
decipher_iv_len = self._method_info[1]
140+
decipher_iv = buf[:decipher_iv_len]
141+
self.decipher = self.get_cipher(self.key, self.method, 0,
142+
iv=decipher_iv)
143+
buf = buf[decipher_iv_len:]
144+
if len(buf) == 0:
145+
return buf
146+
return self.decipher.update(buf)
147+
148+
def encrypt_all(password, method, op, data):
149+
result = []
150+
method = method.lower()
151+
(key_len, iv_len, m) = method_supported[method]
152+
if key_len > 0:
153+
key, _ = EVP_BytesToKey(password, key_len, iv_len)
154+
else:
155+
key = password
156+
if op:
157+
iv = random_string(iv_len)
158+
result.append(iv)
159+
else:
160+
iv = data[:iv_len]
161+
data = data[iv_len:]
162+
cipher = m(method, key, iv, op)
163+
result.append(cipher.update(data))
164+
return b''.join(result)
165+
166+
167+
try:
168+
from Crypto.Cipher.ARC4 import new as RC4Cipher
169+
except ImportError:
170+
xlog.warn('Load Crypto.Cipher.ARC4 Failed, Use Pure Python Instead.')
171+
class RC4Cipher(object):
172+
def __init__(self, key):
173+
x = 0
174+
box = list(range(256))
175+
for i, y in enumerate(box):
176+
x = (x + y + ord(key[i % len(key)])) & 0xff
177+
box[i], box[x] = box[x], y
178+
self.__box = box
179+
self.__x = 0
180+
self.__y = 0
181+
def encrypt(self, data):
182+
out = []
183+
out_append = out.append
184+
x = self.__x
185+
y = self.__y
186+
box = self.__box
187+
for char in data:
188+
x = (x + 1) & 0xff
189+
y = (y + box[x]) & 0xff
190+
box[x], box[y] = box[y], box[x]
191+
out_append(chr(ord(char) ^ box[(box[x] + box[y]) & 0xff]))
192+
self.__x = x
193+
self.__y = y
194+
return ''.join(out)

lib/noarch/scrypto/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright (c) 2014 clowwindy
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+

0 commit comments

Comments
 (0)