├── .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 | --------------------------------------------------------------------------------