[Python3] 소켓 기반 포트 포워딩

Alexandria·2024년 3월 3일

Python3 Advanced

목록 보기
21/27
post-thumbnail

1. Server

서버의 포트로 들어오는 데이터는 정해진 주소(TARGET_IP:TARGET_PORT)로 데이터를 전달하고 응답 데이터는 클라이언트로 전달합니다.

 +-----------------------------+         +---------------------------------------------+         +--------------------------------+
 |        OpenSSH Client       |         |            Portforwarding Server            |         |          OpenSSH Server        |
 +-----------------------------+         +----------------------+----------------------+         +--------------------------------+
 | ssh root@127.0.0.1 -p 9999  |<------->| $ python main.py                            |<------->| 192.168.0.33:22(OpenSSH Server)|
 +-----------------------------+         +---------------------------------------------+         +--------------------------------+

클라이언트가 접속할 때마다 포워딩할 서버로 접속하여 데이터를 중계해 주면 됩니다.

import socket
import threading

SERVER_IP   = ""
SERVER_PORT = 9999
TARGET_IP   = "192.168.0.38"
TARGET_PORT = 22
CLIENTS     = []

def send_data(_src_socket:socket.socket, _dst_socket:socket.socket):
    while True:
        try:
            data = _src_socket.recv(4096)
            if len(data) > 0:
                _dst_socket.sendall(data)
        except Exception as exception:
            print(f"Error : {exception}")
            break

def work(_client_socket:socket.socket, _remote_addr:tuple):
    target_socket   = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
    try:
        target_socket.connect((TARGET_IP, TARGET_PORT))

        user    = f"{_remote_addr[0]}:{_remote_addr[1]}"
        print(f"[{user} -> {TARGET_IP}] Connected")

        recv_thread = threading.Thread(target=send_data, args=(_client_socket, target_socket))
        send_thread = threading.Thread(target=send_data, args=(target_socket, _client_socket))

        recv_thread.start()
        send_thread.start()

        recv_thread.join()
        send_thread.join()
    except ConnectionRefusedError:
        print(f"{TARGET_IP}:{TARGET_PORT} is die")

    CLIENTS.remove(_client_socket)
    target_socket.close()

proxy_socket    = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
proxy_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
proxy_socket.bind((SERVER_IP, SERVER_PORT))
proxy_socket.listen()
print("Proxy run")

while True:
    try:
        client_socket, remote_addr = proxy_socket.accept()
    except KeyboardInterrupt:
        print("Proxy stop")
        break

    CLIENTS.append(client_socket)
    thread          = threading.Thread(target=work, args=(client_socket, remote_addr))
    thread.daemon   = True
    thread.start()

for client in CLIENTS:
    client.close()
proxy_socket.close()
profile
IT 도서관

0개의 댓글