├── .gitignore
├── LICENSE
├── README.md
├── client.py
└── server.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 |
26 | # PyInstaller
27 | # Usually these files are written by a python script from a template
28 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
29 | *.manifest
30 | *.spec
31 |
32 | # Installer logs
33 | pip-log.txt
34 | pip-delete-this-directory.txt
35 |
36 | # Unit test / coverage reports
37 | htmlcov/
38 | .tox/
39 | .coverage
40 | .coverage.*
41 | .cache
42 | nosetests.xml
43 | coverage.xml
44 | *,cover
45 |
46 | # Translations
47 | *.mo
48 | *.pot
49 |
50 | # Django stuff:
51 | *.log
52 |
53 | # Sphinx documentation
54 | docs/_build/
55 |
56 | # PyBuilder
57 | target/
58 |
59 | # IntelliJ IDEA
60 | .idea/
61 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 impakho
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 all
13 | 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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PyProxy
2 | A simple http/https proxy that helps you bypass firewalls
3 |
4 | ## Dependency
5 | - socket
6 | - threading
7 |
8 | ## How to use it?
9 | ### For Server:
10 | ```
11 | def main():
12 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
13 | sock.bind(('0.0.0.0', 5200))
14 | sock.listen(4096)
15 | ```
16 | You can modify the server listen port, the maximum number of TCP keep-alive connections here.
17 |
18 | And then, run `python server.py` to start the proxy server.
19 |
20 | ### For Client:
21 | ```
22 | def main():
23 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
24 | sock.bind(('127.0.0.1', 1080))
25 | sock.listen(256)
26 | ```
27 | You can modify the client listen port, the maximum number of TCP keep-alive connections here.
28 |
29 | ```
30 | def clientIn(client, address):
31 | sockr = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
32 | try:
33 | sockr.connect(('127.0.0.1', 5200))
34 | ```
35 | You should put your server ip and port here.
36 |
37 | And then, run `python client.py` to start the proxy client.
38 |
39 | ### Demo Server
40 | Server Address: pp.pakho.xyz
41 |
42 | Server Port: 5200
43 |
44 | ### Finally
45 | Configure http/https(not socks4/socks5) proxy with your client ip and port in any software supported it.
46 |
47 | Have fun!
48 |
49 | ## License
50 | PyProxy is published under MIT License. See the LICENSE file for more.
51 |
52 |
53 |
54 | # PyProxy
55 | 一个简单的http/https代理,可以帮助你穿越防火墙
56 |
57 | ## 依赖
58 | - socket
59 | - threading
60 |
61 | ## 怎样使用?
62 | ### 服务端:
63 | ```
64 | def main():
65 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
66 | sock.bind(('0.0.0.0', 5200))
67 | sock.listen(4096)
68 | ```
69 | 你可以在这里设置服务器IP和监听端口,还可以修改最大TCP连接数。
70 |
71 | 然后,运行 `python server.py` 启动服务端。
72 |
73 | ### 客户端:
74 | ```
75 | def main():
76 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
77 | sock.bind(('127.0.0.1', 1080))
78 | sock.listen(256)
79 | ```
80 | 你可以在这里设置本地客户端的监听端口,还可以修改最大TCP连接数。
81 |
82 | ```
83 | def clientIn(client, address):
84 | sockr = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
85 | try:
86 | sockr.connect(('127.0.0.1', 5200))
87 | ```
88 | 你应该把服务器IP和端口填在这里。
89 |
90 | 然后,运行 `python client.py` 启动客户端。
91 |
92 | ### 测试服务器
93 | 服务器地址: pp.pakho.xyz
94 |
95 | 服务器端口: 5200
96 |
97 | ### 最后
98 | 在你的软件中,使用客户端IP和端口来配置http/https代理,不是socks4/socks5代理。
99 |
100 | 祝你愉快!
101 |
102 | ## 许可协议
103 | PyProxy采用MIT许可协议。查看LICENSE文件了解更多。
--------------------------------------------------------------------------------
/client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import print_function
5 | import socket
6 | import threading
7 |
8 |
9 | def getHost_IP(host):
10 | ip = host
11 | kw = ':'
12 | if not len(ip): return ''
13 | if kw in ip: ip = ip.split(kw)[0]
14 | try:
15 | ip = socket.gethostbyname(ip)
16 | if '127.0.0.' in ip: ip = ''
17 | return ip
18 | except:
19 | return ''
20 |
21 |
22 | def getHost_Port(host):
23 | port = host
24 | kw = ':'
25 | if not len(port): return 0
26 | if kw in port:
27 | return int(port.split(kw)[1])
28 | else:
29 | return 80
30 |
31 |
32 | def clientIn(client, address):
33 | sockr = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
34 | try:
35 | sockr.connect(('127.0.0.1', 5200))
36 | except:
37 | print('ConnectERR: Server')
38 | client.close()
39 | else:
40 | sockrSend(client, sockr)
41 |
42 |
43 | def sockrRecv(client, sockr):
44 | SSL = 0
45 | header = ''
46 | headerOver = 0
47 | status = 1
48 | length = -1
49 | lengthRecv = -1
50 | gzip = 0
51 | while True:
52 | try:
53 | sockr.settimeout(15)
54 | recv = sockr.recv(256)
55 | except:
56 | print('Socket Timeout')
57 | break
58 | if len(recv):
59 | if headerOver == 0:
60 | header += recv
61 | if '\r\n\r\n' in header: headerOver = 1
62 | if '\r\n' in header and status == 1:
63 | statusSplit = header.split('\r\n')[0]
64 | if ' 1' in statusSplit: status = 0
65 | if '204' in statusSplit: status = 0
66 | if '304' in statusSplit: status = 0
67 | if '\r\nContent-Length: ' in header and length == -1:
68 | lengthSplit = header.split('\r\nContent-Length: ')[1]
69 | if '\r\n' in lengthSplit: length = int(lengthSplit.split('\r\n')[0])
70 | if '\r\nTransfer-Encoding: chunked\r\n' in header and gzip == 0: gzip = 1
71 | if headerOver == 1:
72 | if lengthRecv == -1:
73 | lengthRecv = len(header.split('\r\n\r\n')[1])
74 | else:
75 | lengthRecv = len(recv)
76 | if status == 0:
77 | recv = recv.split('\r\n\r\n')[0] + '\r\n\r\n'
78 | elif length != -1:
79 | if length > lengthRecv:
80 | length -= lengthRecv
81 | else:
82 | recv = recv[:length]
83 | length = 0
84 | elif gzip == 1:
85 | if '\r\n0\r\n\r\n' in recv:
86 | recv = recv.split('\r\n0\r\n\r\n')[0] + '\r\n0\r\n\r\n'
87 | gzip = -1
88 | if header == 'HTTP/1.1 200 Connection Established\r\n\r\n':
89 | threadRecvSSL = threading.Thread(target=sockrRecvSSL, args=(client, sockr))
90 | threadRecvSSL.start()
91 | threadSendSSL = threading.Thread(target=sockrSendSSL, args=(client, sockr))
92 | threadSendSSL.start()
93 | SSL = 1
94 | length = 0
95 | try:
96 | client.send(recv)
97 | except:
98 | print('Client Closed')
99 | break
100 | if headerOver == 1:
101 | if status == 0 or length == 0 or gzip == -1:
102 | break
103 | else:
104 | break
105 | if SSL == 0:
106 | sockr.close()
107 | client.close()
108 |
109 |
110 | def sockrSend(client, sockr):
111 | succ = 1
112 | header = ''
113 | headerOver = 0
114 | length = -1
115 | lengthRecv = -1
116 | while True:
117 | try:
118 | client.settimeout(15)
119 | recv = client.recv(10)
120 | except:
121 | print('Client Timeout')
122 | succ = 0
123 | break
124 | if len(recv):
125 | if headerOver == 0:
126 | header += recv
127 | if '\r\n\r\n' in header: headerOver = 1
128 | if '\r\nContent-Length: ' in header and length == -1:
129 | lengthSplit = header.split('\r\nContent-Length: ')[1]
130 | if '\r\n' in lengthSplit: length = int(lengthSplit.split('\r\n')[0])
131 | if headerOver == 1:
132 | if lengthRecv == -1:
133 | lengthRecv = len(header.split('\r\n\r\n')[1])
134 | else:
135 | lengthRecv = len(recv)
136 | if length != -1 and length != 0:
137 | if length > lengthRecv:
138 | length -= lengthRecv
139 | else:
140 | recv = recv[:length]
141 | length = 0
142 | try:
143 | sockr.send(recv[::-1])
144 | except:
145 | print('Socket Closed')
146 | succ = 0
147 | break
148 | if headerOver == 1:
149 | if length == -1 or length == 0:
150 | break
151 | else:
152 | break
153 | if succ == 1:
154 | sockrRecv(client, sockr)
155 | else:
156 | sockr.close()
157 | client.close()
158 |
159 |
160 | def sockrRecvSSL(client, sockr):
161 | while True:
162 | try:
163 | sockr.settimeout(30)
164 | recv = sockr.recv(256)
165 | except:
166 | break
167 | if len(recv):
168 | try:
169 | client.send(recv)
170 | except:
171 | break
172 | else:
173 | break
174 | sockr.close()
175 | client.close()
176 |
177 |
178 | def sockrSendSSL(client, sockr):
179 | while True:
180 | try:
181 | client.settimeout(30)
182 | recv = client.recv(10)
183 | except:
184 | break
185 | if len(recv):
186 | try:
187 | sockr.send(recv)
188 | except:
189 | break
190 | else:
191 | break
192 | sockr.close()
193 | client.close()
194 |
195 |
196 | def main():
197 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
198 | sock.bind(('127.0.0.1', 1080))
199 | sock.listen(256)
200 | while True:
201 | client, address = sock.accept()
202 | thread = threading.Thread(target=clientIn, args=(client, address))
203 | thread.start()
204 |
205 |
206 | if __name__ == '__main__':
207 | main()
208 |
--------------------------------------------------------------------------------
/server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import print_function
5 | import socket
6 | import threading
7 |
8 |
9 | def isset(obj):
10 | if obj == 0: return 0
11 | return 1
12 |
13 |
14 | def getMethod(header):
15 | if 'CONNECT' in header[0:10]: return 1
16 | return 0
17 |
18 |
19 | def getHost(header):
20 | rn = '\r\n'
21 | kw = 'Host: '
22 | if not kw in header: return ''
23 | hostSplit = header.split(kw)[1]
24 | if not rn in hostSplit: return ''
25 | return hostSplit.split(rn)[0]
26 |
27 |
28 | def getHost_IP(header):
29 | ip = getHost(header)
30 | kw = ':'
31 | if not len(ip): return ''
32 | if kw in ip: ip = ip.split(kw)[0]
33 | try:
34 | ip = socket.gethostbyname(ip)
35 | if '127.0.0.' in ip: ip = ''
36 | return ip
37 | except:
38 | return ''
39 |
40 |
41 | def getHost_Port(header):
42 | port = getHost(header)
43 | kw = ':'
44 | if not len(port): return 0
45 | if kw in port:
46 | return int(port.split(kw)[1])
47 | else:
48 | return 80
49 |
50 |
51 | def clientIn(client, address):
52 | succ = 1
53 | header = ''
54 | headerOver = 0
55 | method = -1
56 | ip = ''
57 | port = 0
58 | length = -1
59 | lengthRecv = -1
60 | while True:
61 | try:
62 | client.settimeout(30)
63 | recv = client.recv(10)[::-1]
64 | except:
65 | print('Client Timeout')
66 | succ = 0
67 | break
68 | if len(recv):
69 | if headerOver == 0:
70 | header += recv
71 | if '\r\n\r\n' in header: headerOver = 1
72 | if '\r\n' in header and method == -1:
73 | method = getMethod(header)
74 | if ' http://' in header:
75 | headerReStr = 'http://' + header.split('http://')[1].split('/')[0]
76 | header = header.replace(headerReStr, '')
77 | if ip == '': ip = getHost_IP(header)
78 | if port == 0 and method == 0: port = getHost_Port(header)
79 | if port == 0 and method == 1: port = 443
80 | if '\r\nProxy-Connection: ' in header:
81 | headerReStr = '\r\nProxy-Connection: '
82 | header = header.replace(headerReStr, '\r\nConnection: ')
83 | if '\r\nContent-Length: ' in header and length == -1:
84 | lengthSplit = header.split('\r\nContent-Length: ')[1]
85 | if '\r\n' in lengthSplit: length = int(lengthSplit.split('\r\n')[0])
86 | if headerOver == 1:
87 | if lengthRecv == -1:
88 | lengthRecv = len(header.split('\r\n\r\n')[1])
89 | sockr = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
90 | try:
91 | sockr.connect((ip, port))
92 | except:
93 | print('ConnectERR: ' + ip + ':' + str(port))
94 | succ = 0
95 | break
96 | else:
97 | header = recv
98 | lengthRecv = len(header)
99 | if length != -1 and length != 0:
100 | if length > lengthRecv:
101 | length -= lengthRecv
102 | else:
103 | recv = recv[:length]
104 | length = 0
105 | if method == 1: break
106 | try:
107 | sockr.send(header)
108 | except:
109 | print('Socket Closed')
110 | succ = 0
111 | break
112 | if length == -1 or length == 0:
113 | break
114 | else:
115 | break
116 | if succ == 1:
117 | if method == 0:
118 | sockrRecv(client, sockr)
119 | if method == 1:
120 | client.send('HTTP/1.1 200 Connection Established\r\n\r\n')
121 | threadRecvSSL = threading.Thread(target=sockrRecvSSL, args=(client, sockr))
122 | threadRecvSSL.start()
123 | threadSendSSL = threading.Thread(target=sockrSendSSL, args=(client, sockr))
124 | threadSendSSL.start()
125 | else:
126 | client.close()
127 |
128 |
129 | def sockrRecv(client, sockr):
130 | SSL = 0
131 | header = ''
132 | headerOver = 0
133 | status = 1
134 | length = -1
135 | lengthRecv = -1
136 | gzip = 0
137 | while True:
138 | try:
139 | sockr.settimeout(30)
140 | recv = sockr.recv(256)
141 | except:
142 | print('Socket Timeout')
143 | break
144 | if len(recv):
145 | if headerOver == 0:
146 | header += recv
147 | if '\r\n\r\n' in header: headerOver = 1
148 | if '\r\n' in header and status == 1:
149 | statusSplit = header.split('\r\n')[0]
150 | if ' 1' in statusSplit: status = 0
151 | if '204' in statusSplit: status = 0
152 | if '304' in statusSplit: status = 0
153 | if '\r\nContent-Length: ' in header and length == -1:
154 | lengthSplit = header.split('\r\nContent-Length: ')[1]
155 | if '\r\n' in lengthSplit: length = int(lengthSplit.split('\r\n')[0])
156 | if '\r\nTransfer-Encoding: chunked\r\n' in header and gzip == 0: gzip = 1
157 | if headerOver == 1:
158 | if lengthRecv == -1:
159 | lengthRecv = len(header.split('\r\n\r\n')[1])
160 | else:
161 | lengthRecv = len(recv)
162 | if status == 0:
163 | recv = recv.split('\r\n\r\n')[0] + '\r\n\r\n'
164 | elif length != -1:
165 | if length > lengthRecv:
166 | length -= lengthRecv
167 | else:
168 | recv = recv[:length]
169 | length = 0
170 | elif gzip == 1:
171 | if '\r\n0\r\n\r\n' in recv:
172 | recv = recv.split('\r\n0\r\n\r\n')[0] + '\r\n0\r\n\r\n'
173 | gzip = -1
174 | if header == 'HTTP/1.1 200 Connection Established\r\n\r\n':
175 | threadRecvSSL = threading.Thread(target=sockrRecvSSL, args=(client, sockr))
176 | threadRecvSSL.start()
177 | threadSendSSL = threading.Thread(target=sockrSendSSL, args=(client, sockr))
178 | threadSendSSL.start()
179 | SSL = 1
180 | length = 0
181 | try:
182 | client.send(recv)
183 | except:
184 | print('Client Closed')
185 | break
186 | if headerOver == 1:
187 | if status == 0 or length == 0 or gzip == -1:
188 | break
189 | else:
190 | break
191 | if SSL == 0:
192 | sockr.close()
193 | client.close()
194 |
195 |
196 | def sockrRecvSSL(client, sockr):
197 | while True:
198 | try:
199 | sockr.settimeout(60)
200 | recv = sockr.recv(256)
201 | except:
202 | break
203 | if len(recv):
204 | try:
205 | client.send(recv)
206 | except:
207 | break
208 | else:
209 | break
210 | sockr.close()
211 | client.close()
212 |
213 |
214 | def sockrSendSSL(client, sockr):
215 | while True:
216 | try:
217 | client.settimeout(60)
218 | recv = client.recv(10)
219 | except:
220 | break
221 | if len(recv):
222 | try:
223 | sockr.send(recv)
224 | except:
225 | break
226 | else:
227 | break
228 | sockr.close()
229 | client.close()
230 |
231 |
232 | def main():
233 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
234 | sock.bind(('0.0.0.0', 5200))
235 | sock.listen(4096)
236 | while True:
237 | client, address = sock.accept()
238 | thread = threading.Thread(target=clientIn, args=(client, address))
239 | thread.start()
240 |
241 |
242 | if __name__ == '__main__':
243 | main()
244 |
--------------------------------------------------------------------------------