使用Python连接SOCKS5认证代理服务器,并在本地端口转发为HTTP代理的脚本。

使用Python连接SOCKS5认证代理服务器,并在本地端口转发为HTTP代理的脚本。

为解决 Proxy SwitchyOmega 无法连接带密码认证的 SOCKS5 服务器的问题,我们可以使用 Python 编写一个脚本来连接 SOCKS5 服务器,并在本地转发为 HTTP 服务器。

  1. 配置 SOCKS5 代理服务器的连接信息。
  2. 实现一个 HTTP 代理服务器,将请求通过 SOCKS5 代理进行转发。
  3. 启动 HTTP 代理服务器,并在终端显示上传和下载数据量。

以下是具体步骤和代码实现。

1. 安装所需库

首先,请确保你已经安装了以下库:

pip install requests pysocks

如果报错,请尝试备用安装环境库

pip install altgraph==0.17.4 anyio==4.3.0 appdirs==1.4.4 argon2-cffi==23.1.0 argon2-cffi-bindings==21.2.0 arrow==1.3.0 astroid==3.1.0 asttokens==2.4.1 async-lru==2.0.4 async-timeout==4.0.3 attrs==23.2.0 Babel==2.14.0 beautifulsoup4==4.12.3 bleach==6.1.0 bleak==0.22.1 bleak-winrt==1.2.0 certifi==2024.2.2 cffi==1.16.0 charset-normalizer==3.3.2 click==8.1.7 colorama==0.4.6 comm==0.2.2 contourpy==1.2.0 cryptography==41.0.4 cycler==0.12.1 debugpy==1.8.1 decorator==5.1.1 defusedxml==0.7.1 dill==0.3.8 enum-compat==0.0.3 exceptiongroup==1.2.0 executing==2.0.1 fastjsonschema==2.19.1 fonttools==4.50.0 fqdn==1.5.1 fuzzywuzzy==0.18.0 h11==0.14.0 httpcore==1.0.4 httpx==0.27.0 idna==3.6 importlib_metadata==7.1.0 importlib_resources==6.3.1 ipykernel==6.29.3 ipython==8.18.1 ipywidgets==8.1.2 isoduration==20.11.0 isort==5.13.2 jedi==0.19.1 Jinja2==3.1.3 json5==0.9.24 jsonpointer==2.4 jsonschema==4.21.1 jsonschema-specifications==2023.12.1 jupyter==1.0.0 jupyter-console==6.6.3 jupyter-events==0.10.0 jupyter-lsp==2.2.4 jupyter_client==8.6.1 jupyter_core==5.7.2 jupyter_server==2.13.0 jupyter_server_terminals==0.5.3 jupyterlab==4.1.5 jupyterlab_pygments==0.3.0 jupyterlab_server==2.25.4 jupyterlab_widgets==3.0.10 keyboard==0.13.5 keyring==23.0.0 kiwisolver==1.4.5 Levenshtein==0.25.1 MarkupSafe==2.1.5 matplotlib==3.8.3 matplotlib-inline==0.1.6 mccabe==0.7.0 mistune==3.0.2 MouseInfo==0.1.3 nbclient==0.10.0 nbconvert==7.16.3 nbformat==5.10.3 nest-asyncio==1.6.0 notebook==7.1.2 notebook_shim==0.2.4 npyscreen==4.10.5 ntplib==0.4.0 numpy==1.26.4 opencv-python==4.9.0.80 overrides==7.7.0 packaging==24.0 pandas==1.1.5 pandocfilters==1.5.1 parso==0.8.3 pefile==2023.2.7 pillow==10.2.0 platformdirs==4.2.0 prometheus_client==0.20.0 prompt-toolkit==3.0.43 psutil==5.9.8 pure-eval==0.2.2 PyAutoGUI==0.9.54 PyBluez==0.30 pychrome==0.2.4 pycookiecheat==0.6.0 pycparser==2.21 pyee==11.1.0 pygatt==4.0.5 PyGetWindow==0.0.9 Pygments==2.17.2 pyinstaller==6.6.0 pyinstaller-hooks-contrib==2024.5 pylint==3.1.0 PyMsgBox==1.0.9 pynput==1.7.6 pyparsing==3.1.2 pyperclip==1.8.2 pypiwin32==223 pyppeteer==2.0.0 PyRect==0.2.0 PyScreeze==0.1.30 pyserial==3.5 PySocks==1.7.1 pytesseract==0.3.10 python-dateutil==2.9.0.post0 python-json-logger==2.0.7 python-Levenshtein==0.25.1 pytweening==1.2.0 pytz==2024.1 pywin32==306 pywin32-ctypes==0.2.2 pywinpty==2.0.13 PyYAML==6.0.1 pyzmq==25.1.2 qtconsole==5.5.1 QtPy==2.4.1 rapidfuzz==3.9.0 referencing==0.34.0 requests==2.31.0 rfc3339-validator==0.1.4 rfc3986-validator==0.1.1 rpds-py==0.18.0 Send2Trash==1.8.2 six==1.16.0 sniffio==1.3.1 soupsieve==2.5 stack-data==0.6.3 terminado==0.18.1 tinycss2==1.2.1 tomli==2.0.1 tomlkit==0.12.5 tornado==6.4 tqdm==4.66.4 traitlets==5.14.2 types-python-dateutil==2.9.0.20240316 typing_extensions==4.10.0 uri-template==1.3.0 urllib3==1.26.18 wcwidth==0.2.13 webcolors==1.13 webencodings==0.5.1 websocket-client==1.7.0 websockets==10.4 widgetsnbextension==4.0.10 zipp==3.18.1

2. 创建配置文件

我们需要创建一个配置文件来保存SOCKS5代理的配置信息。创建一个名为 socks5.ini 的文件,内容如下:

[SOCKS5]
HOST=your_socks5_proxy_host
PORT=your_socks5_proxy_port
USERNAME=your_username
PASSWORD=your_password

请根据实际情况填写你的SOCKS5代理的主机、端口、用户名和密码。

3. 编写代码

以下是实现的完整代码,将其保存为 socks5_http_proxy.py

import socketserver
import http.server
import socket
import socks
import select
import threading
import time
import configparser
from urllib.parse import urlparse

# 读取SOCKS5配置文件
config = configparser.ConfigParser()
config.read('socks5.ini')

SOCKS5_PROXY_HOST = config['SOCKS5']['HOST']
SOCKS5_PROXY_PORT = int(config['SOCKS5']['PORT'])
SOCKS5_USERNAME = config['SOCKS5']['USERNAME']
SOCKS5_PASSWORD = config['SOCKS5']['PASSWORD']

# 全局变量来跟踪数据传输量
total_upload = 0
total_download = 0
current_upload = 0
current_download = 0
lock = threading.Lock()

# 设置SOCKS5代理
socks.set_default_proxy(
    socks.SOCKS5,
    SOCKS5_PROXY_HOST,
    SOCKS5_PROXY_PORT,
    username=SOCKS5_USERNAME,
    password=SOCKS5_PASSWORD
)
socket.socket = socks.socksocket

class ProxyHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
    def log_message(self, format, *args):
        return  # 禁用默认的日志记录

    def do_GET(self):
        self.handle_http_request()

    def do_POST(self):
        self.handle_http_request()

    def handle_http_request(self):
        global total_upload, total_download, current_upload, current_download

        url = self.path
        parsed_url = urlparse(url)
        hostname = parsed_url.hostname
        port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80)

        try:
            conn = socks.socksocket()
            conn.connect((hostname, port))

            self.send_response(200)
            self.end_headers()

            if self.command == 'GET':
                request_line = f"{self.command} {parsed_url.path}?{parsed_url.query} HTTP/1.1\r\n"
                headers = "\r\n".join([f"{k}: {v}" for k, v in self.headers.items()])
                conn.sendall((request_line + headers + "\r\n\r\n").encode('utf-8'))

            elif self.command == 'POST':
                content_length = int(self.headers['Content-Length'])
                post_data = self.rfile.read(content_length)
                request_line = f"{self.command} {parsed_url.path} HTTP/1.1\r\n"
                headers = "\r\n".join([f"{k}: {v}" for k, v in self.headers.items()])
                conn.sendall((request_line + headers + "\r\n\r\n").encode('utf-8') + post_data)

                with lock:
                    total_upload += content_length
                    current_upload += content_length

            response_data = b""
            while True:
                data = conn.recv(8192)
                if not data:
                    break
                response_data += data
                self.wfile.write(data)

                with lock:
                    total_download += len(data)
                    current_download += len(data)

        except Exception as e:
            self.send_error(500, str(e).encode('ascii', 'replace').decode())
        finally:
            conn.close()

def print_status():
    global current_upload, current_download, total_upload, total_download
    while True:
        time.sleep(1)
        with lock:
            # 转换当前上传和下载速率为 KB/s
            current_upload_kb = current_upload / 1024
            current_download_kb = current_download / 1024

            # 转换总上传和下载数据量为 MB 或 GB
            total_upload_mb = total_upload / (1024 * 1024)
            total_download_mb = total_download / (1024 * 1024)

            if total_upload_mb >= 1024:
                total_upload_str = f"{total_upload_mb / 1024:.2f} GB"
            else:
                total_upload_str = f"{total_upload_mb:.2f} MB"

            if total_download_mb >= 1024:
                total_download_str = f"{total_download_mb / 1024:.2f} GB"
            else:
                total_download_str = f"{total_download_mb:.2f} MB"

            print(f"\r当前上传: {current_upload_kb:.2f} KB/s | 当前下载: {current_download_kb:.2f} KB/s | 总上传: {total_upload_str} | 总下载: {total_download_str}", end='')
            current_upload = 0
            current_download = 0

def start_proxy_server():
    PORT = 18888
    httpd = socketserver.ThreadingTCPServer(('', PORT), ProxyHTTPRequestHandler)
    threading.Thread(target=httpd.serve_forever, daemon=True).start()
    print(f'本地HTTP代理服务器运行在端口 {PORT}')

if __name__ == '__main__':
    # 启动状态显示线程
    status_thread = threading.Thread(target=print_status)
    status_thread.daemon = True
    status_thread.start()

    # 启动代理服务器
    start_proxy_server()

    # 保持主线程运行
    while True:
        time.sleep(1)

4. 运行代理服务器

在终端运行代理服务器:

python socks5_http_proxy.py

你会看到类似以下的输出:

本地HTTP代理服务器运行在端口 18888
当前上传: 0.00 KB/s | 当前下载: 0.00 KB/s | 总上传: 0.00 MB | 总下载: 0.00 MB

5. 使用代理服务器

在浏览器或其他支持代理配置的应用中,将代理设置为 http://localhost:18888

结语

通过这篇教程,我们成功地创建了一个通过SOCKS5代理转发的HTTP代理服务器,并在本地端口监听。你可以根据需要进行扩展和修改,以满足特定的需求。如果你有任何问题或建议,欢迎在评论区留言。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,基于 Python 的 PySocks 库,可以实现一个简单的 SOCKS5 代理服务器,并支持用户认证和域名白名单。 以下是代码实现: ```python import socket import select import struct import sys import argparse import socks # 需要安装 PySocks 库,可以通过 pip 安装 # 定义常量 SOCKS_VERSION = 5 USER_AUTHENTICATION = 2 NO_ACCEPTABLE_METHODS = 0xFF SUCCESS = 0 # 定义命令行参数 parser = argparse.ArgumentParser() parser.add_argument("--ip", type=str, default="127.0.0.1", help="代理服务器 IP 地址,默认为 127.0.0.1") parser.add_argument("--port", type=int, default=1080, help="代理服务器端口号,默认为 1080") parser.add_argument("--username", type=str, default=None, help="代理服务器用户名,默认为 None") parser.add_argument("--password", type=str, default=None, help="代理服务器密码,默认为 None") parser.add_argument("--whitelist", type=str, default=None, help="代理服务器域名白名单,多个域名用逗号分隔,默认为 None") args = parser.parse_args() # 解析域名白名单 whitelist = [] if args.whitelist is not None: whitelist = args.whitelist.split(",") # 创建代理服务器 Socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((args.ip, args.port)) server_socket.listen(5) print(f"代理服务器已启动,监听地址为 {args.ip}:{args.port},用户名为 {args.username},密码为 {args.password},域名白名单为 {whitelist}") inputs = [server_socket] # 处理 SOCKS5 协议的请求 def handle_socks5_request(client_socket): # 接收客户端发来的协议版本和支持的身份验证方式 version, nmethods = struct.unpack("!BB", client_socket.recv(2)) # 校验协议版本是否为 SOCKS5 if version != SOCKS_VERSION: print("无效的协议版本") client_socket.close() return # 接收客户端发来的身份验证方式 methods = client_socket.recv(nmethods) # 判断客户端是否支持用户名密码验证方式 if USER_AUTHENTICATION not in methods: print("不支持用户名密码身份验证方式") client_socket.sendall(struct.pack("!BB", SOCKS_VERSION, NO_ACCEPTABLE_METHODS)) client_socket.close() return # 向客户端发送支持的身份验证方式 client_socket.sendall(struct.pack("!BB", SOCKS_VERSION, USER_AUTHENTICATION)) # 接收客户端发来的用户名和密码 version, username_length = struct.unpack("!BB", client_socket.recv(2)) username = client_socket.recv(username_length).decode("utf-8") password_length = struct.unpack("!B", client_socket.recv(1))[0] password = client_socket.recv(password_length).decode("utf-8") # 校验用户名和密码是否正确 if args.username is not None and args.password is not None: if username != args.username or password != args.password: print("用户名或密码错误") client_socket.sendall(struct.pack("!BB", SOCKS_VERSION, NO_ACCEPTABLE_METHODS)) client_socket.close() return # 向客户端发送身份验证通过的消息 client_socket.sendall(struct.pack("!BB", SOCKS_VERSION, SUCCESS)) # 接收客户端发来的请求 version, cmd, _, address_type = struct.unpack("!BBBB", client_socket.recv(4)) if address_type == 1: # IPv4 address = socket.inet_ntoa(client_socket.recv(4)) elif address_type == 3: # 域名 address_length = struct.unpack("!B", client_socket.recv(1))[0] address = client_socket.recv(address_length).decode("utf-8") elif address_type == 4: # IPv6 address = socket.inet_ntop(socket.AF_INET6, client_socket.recv(16)) else: print("不支持的地址类型") client_socket.close() return port = struct.unpack("!H", client_socket.recv(2))[0] print(f"收到请求:{address}:{port}") # 校验域名是否在白名单中 if address in whitelist: print(f"请求的域名 {address} 在白名单中,允许访问") else: print(f"请求的域名 {address} 不在白名单中,禁止访问") client_socket.close() return # 连接远程服务器,并将请求转发过去 remote_socket = socks.socksocket() remote_socket.set_proxy(socks.SOCKS5, args.ip, args.port) remote_socket.connect((address, port)) client_socket.sendall(struct.pack("!BBBB", SOCKS_VERSION, SUCCESS, 0, address_type)) if address_type == 1: client_socket.sendall(socket.inet_aton(address)) elif address_type == 3: client_socket.sendall(struct.pack("!B", len(address)) + address.encode("utf-8")) elif address_type == 4: client_socket.sendall(socket.inet_pton(socket.AF_INET6, address)) client_socket.sendall(struct.pack("!H", port)) inputs.append(client_socket) inputs.append(remote_socket) print(f"请求 {address}:{port} 转发成功") while True: readable, _, _ = select.select(inputs, [], []) for sock in readable: if sock is server_socket: # 有新的客户端连接进来 client_socket, client_address = sock.accept() inputs.append(client_socket) print(f"客户端 {client_address} 已连接") else: # 处理客户端发来的请求 try: handle_socks5_request(sock) except Exception as e: print(f"请求处理失败:{e}") sock.close() inputs.remove(sock) ``` 通过命令行参数,可以设置代理服务器的 IP 地址、端口号、用户名、密码和域名白名单。启动代理服务器后,可以使用浏览器或其他支持 SOCKS5 协议的应用程序进行访问,代理服务器会根据域名白名单进行筛选,只允许访问指定的域名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值