├── LICENSE ├── README.md ├── client.py ├── proxy_client.ini ├── proxy_server.ini └── server.py /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2023, kay的小屋 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mini_Reverse_Proxy 2 | 3 | 1.用不到100行代码实现一个Python迷你内网穿透、反向正向代理的小工具 4 | 5 | 2.基于tcp长连接的Python迷你内网穿透小工具; 6 | 7 | 3.适当改装可以实现流量正向、反向代理; 8 | 9 | 4.方便快速插入程序中 10 | 11 | ## 用法Usage 12 | 13 | 程序分为服务器端与客户端两个程序,每个程序对应一个.ini配置文件. 14 | 15 | 16 | *请先启动server.py后打开client.py* 17 | 18 | 19 | proxy_server.ini 20 | ``` 21 | [comment] 22 | bind_port=7000 23 | visit_port=5003 24 | local_ip=127.0.0.1 25 | ``` 26 | 27 | proxy_client.ini 28 | ``` 29 | [comment] 30 | remote_ip=127.0.0.1 31 | remote_port=7000 32 | local_ip=127.0.0.1 33 | local_port=8199 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import time,json 3 | import threading 4 | import configparser 5 | 6 | # 这里定义了一个计时器类,用于在指定时间内执行任务 7 | class Timer(object): 8 | def __init__(self, interval, function, args=[], kwargs={}): 9 | self.interval = interval 10 | self.function = function 11 | self.args = args 12 | self.kwargs = kwargs 13 | self.timer = None 14 | 15 | def start(self): 16 | self.timer = threading.Timer(self.interval, self.function, self.args, self.kwargs) 17 | self.timer.start() 18 | 19 | def cancel(self): 20 | self.timer.cancel() 21 | 22 | class HeartbeatClient(object): 23 | def __init__(self, host, port): 24 | self.host = host 25 | self.port = port 26 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 27 | self.connected = False 28 | 29 | # 这里定义了一个方法,用于发送心跳包 30 | def send_heartbeat(self): 31 | while self.connected: 32 | self.socket.send(b'heartbeat') 33 | time.sleep(10) 34 | 35 | def connect(self): 36 | try: 37 | self.socket.connect((self.host, self.port)) 38 | self.connected = True 39 | 40 | # 开启两个线程分别用于发送心跳包和等待用户输入消息 41 | t1 = threading.Thread(target=self.send_heartbeat) 42 | t1.start() 43 | 44 | # 设置一个定时器,在100秒钟内如果没有收到服务端消息,则停止发送心跳包 45 | self.timer = Timer(100, self.close) 46 | self.timer.start() 47 | 48 | while self.connected: 49 | data = self.socket.recv(8192) 50 | if data !=b'heartbeat': 51 | 52 | #这块可以用作代理,内网穿透,看需求进行更改 53 | remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 54 | remote_socket.connect((local_ip, local_port)) 55 | remote_socket.send(data) 56 | 57 | while True: 58 | response = remote_socket.recv(8192) 59 | if len(response) == 0: 60 | break 61 | 62 | self.socket.send(response) 63 | 64 | # 关闭连接 65 | remote_socket.close() 66 | 67 | 68 | if not data: 69 | self.close() 70 | else: 71 | # 更新定时器,表示仍然在收到服务端消息 72 | self.timer.cancel() 73 | self.timer.start() 74 | if data.decode('utf-8')=='heartbeat': 75 | print('{} server connecting!'.format(data.decode('utf-8'))) 76 | except: 77 | self.close() 78 | def close(self): 79 | self.connected = False 80 | self.socket.close() 81 | self.timer.cancel() 82 | 83 | if __name__ == '__main__': 84 | global remote_ip,remote_port,local_ip,local_port 85 | config=configparser.ConfigParser() 86 | config.read('proxy_client.ini') 87 | remote_ip=config.get('comment','remote_ip') 88 | remote_port=config.getint('comment','remote_port') 89 | 90 | local_ip=config.get('comment','local_ip') 91 | local_port=config.getint('comment','local_port') 92 | 93 | client = HeartbeatClient(remote_ip, remote_port) 94 | client.connect() 95 | -------------------------------------------------------------------------------- /proxy_client.ini: -------------------------------------------------------------------------------- 1 | [comment] 2 | remote_ip=127.0.0.1 3 | remote_port=7000 4 | 5 | local_ip=127.0.0.1 6 | local_port=8199 -------------------------------------------------------------------------------- /proxy_server.ini: -------------------------------------------------------------------------------- 1 | [comment] 2 | bind_port=7000 3 | visit_port=5003 4 | local_ip=127.0.0.1 5 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import socket,time,configparser 3 | 4 | 5 | # 这里定义了一个方法,用于发送心跳包 6 | def send_heartbeat(conn): 7 | while 1: 8 | conn.send(b'heartbeat') 9 | time.sleep(10) 10 | 11 | 12 | def handle_client(client_socket, conn): 13 | BUFFER_SIZE = 8192 14 | while True: 15 | data = client_socket.recv(BUFFER_SIZE) 16 | if not data: 17 | # 如果没有数据了则退出循环 18 | break 19 | if data != b'heartbeat': 20 | conn.send(data) 21 | response = conn.recv(BUFFER_SIZE) 22 | if not response: 23 | # 如果没有收到回复数据则退出循环 24 | break 25 | if response != b'heartbeat': 26 | client_socket.send(response) 27 | 28 | else: 29 | conn.send(b'heartbeat') 30 | client_socket.close() 31 | 32 | 33 | 34 | if __name__ == '__main__': 35 | global HOST,PORT,visit_port,bind_port 36 | config=configparser.ConfigParser() 37 | config.read('proxy_server.ini') 38 | HOST=config.get('comment','local_ip') 39 | PORT=config.getint('comment','bind_port') 40 | visit_port=config.getint('comment','visit_port') 41 | 42 | 43 | 44 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 45 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 设置端口复用 46 | s.bind((HOST, PORT)) 47 | s.listen() 48 | print(f'Server listening on {HOST}:{PORT}...') 49 | conn, addr = s.accept() 50 | 51 | t1 = threading.Thread(target=send_heartbeat,args=(conn,)) 52 | t1.start() 53 | 54 | print(f'Server connected on {addr[0]}:{addr[1]} successfully...') 55 | 56 | proxy_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 57 | proxy_socket.bind((HOST, visit_port)) 58 | proxy_socket.listen(5) 59 | print(f'代理服务器正在监听 {HOST}:{visit_port} ...') 60 | 61 | while True: 62 | client_socket, client_address = proxy_socket.accept() 63 | print(f'接收到来自 {client_address[0]}:{client_address[1]} 的连接。') 64 | client_thread = threading.Thread(target=handle_client, args=(client_socket,conn,)) 65 | client_thread.start() 66 | 67 | 68 | 69 | --------------------------------------------------------------------------------