From 82acf6066a56598baa4813601405f471d49e12a6 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 26 Jun 2025 23:33:16 +0800 Subject: [PATCH] Revert rusty Wireguard stuff --- mitmproxy/net/udp.py | 3 +- mitmproxy/proxy/mode_servers.py | 133 +--------------------- mitmproxy/proxy/mode_specs.py | 10 -- mitmproxy/proxy/server.py | 9 +- setup.cfg | 1 - setup.py | 5 +- test/mitmproxy/proxy/test_mode_servers.py | 90 +-------------- test/mitmproxy/proxy/test_mode_specs.py | 3 - 8 files changed, 10 insertions(+), 244 deletions(-) diff --git mitmproxy/net/udp.py mitmproxy/net/udp.py index abec86a58..8cdb85ebd 100644 --- mitmproxy/net/udp.py +++ mitmproxy/net/udp.py @@ -6,7 +6,6 @@ import socket from typing import Any, Callable, Optional, Union, cast from mitmproxy.connection import Address -from mitmproxy.net import udp_wireguard from mitmproxy.utils import human logger = logging.getLogger(__name__) @@ -183,7 +182,7 @@ class DatagramWriter: self._closed = None @property - def _protocol(self) -> DrainableDatagramProtocol | udp_wireguard.WireGuardDatagramTransport: + def _protocol(self) -> DrainableDatagramProtocol: return self._transport.get_protocol() # type: ignore def write(self, data: bytes) -> None: diff --git mitmproxy/proxy/mode_servers.py mitmproxy/proxy/mode_servers.py index ca00d4389..e025b73ea 100644 --- mitmproxy/proxy/mode_servers.py +++ mitmproxy/proxy/mode_servers.py @@ -12,24 +12,19 @@ Example: from __future__ import annotations import asyncio -import json import logging import socket -import textwrap import typing from abc import ABCMeta, abstractmethod from contextlib import contextmanager -from pathlib import Path from typing import ClassVar, Generic, TypeVar, cast, get_args import errno -import mitmproxy_wireguard as wg from mitmproxy import ctx, flow, platform from mitmproxy.connection import Address from mitmproxy.master import Master from mitmproxy.net import local_ip, udp -from mitmproxy.net.udp_wireguard import WireGuardDatagramTransport from mitmproxy.proxy import commands, layers, mode_specs, server from mitmproxy.proxy.context import Context from mitmproxy.proxy.layer import Layer @@ -136,8 +131,8 @@ class ServerInstance(Generic[M], metaclass=ABCMeta): async def handle_tcp_connection( self, - reader: asyncio.StreamReader | wg.TcpStream, - writer: asyncio.StreamWriter | wg.TcpStream, + reader: asyncio.StreamReader, + writer: asyncio.StreamWriter, ) -> None: handler = ProxyConnectionHandler( ctx.master, reader, writer, ctx.options, self.mode @@ -154,10 +149,6 @@ class ServerInstance(Generic[M], metaclass=ABCMeta): else: handler.layer.context.client.sockname = original_dst handler.layer.context.server.address = original_dst - elif isinstance(self.mode, mode_specs.WireGuardMode): - original_dst = writer.get_extra_info("original_dst") - handler.layer.context.client.sockname = original_dst - handler.layer.context.server.address = original_dst connection_id = ( handler.layer.context.client.transport_protocol, @@ -185,8 +176,6 @@ class ServerInstance(Generic[M], metaclass=ABCMeta): handler.layer = self.make_top_layer(handler.layer.context) handler.layer.context.client.transport_protocol = "udp" handler.layer.context.server.transport_protocol = "udp" - if isinstance(self.mode, mode_specs.WireGuardMode): - handler.layer.context.server.address = local_addr # pre-register here - we may get datagrams before the task is executed. self.manager.connections[connection_id] = handler @@ -282,124 +271,6 @@ class AsyncioServerInstance(ServerInstance[M], metaclass=ABCMeta): return self._listen_addrs -class WireGuardServerInstance(ServerInstance[mode_specs.WireGuardMode]): - _server: wg.Server | None = None - _listen_addrs: tuple[Address, ...] = tuple() - - server_key: str - client_key: str - - def make_top_layer(self, context: Context) -> Layer: - return layers.modes.TransparentProxy(context) - - @property - def is_running(self) -> bool: - return self._server is not None - - async def start(self) -> None: - assert self._server is None - host = self.mode.listen_host(ctx.options.listen_host) - port = self.mode.listen_port(ctx.options.listen_port) - - if self.mode.data: - conf_path = Path(self.mode.data).expanduser() - else: - conf_path = Path(ctx.options.confdir).expanduser() / "wireguard.conf" - - try: - if not conf_path.exists(): - conf_path.write_text(json.dumps({ - "server_key": wg.genkey(), - "client_key": wg.genkey(), - }, indent=4)) - - try: - c = json.loads(conf_path.read_text()) - self.server_key = c["server_key"] - self.client_key = c["client_key"] - except Exception as e: - raise ValueError(f"Invalid configuration file ({conf_path}): {e}") from e - # error early on invalid keys - p = wg.pubkey(self.client_key) - _ = wg.pubkey(self.server_key) - - self._server = await wg.start_server( - host, - port, - self.server_key, - [p], - self.wg_handle_tcp_connection, - self.wg_handle_udp_datagram, - ) - self._listen_addrs = (self._server.getsockname(),) - except Exception as e: - self.last_exception = e - message = f"{self.mode.description} failed to listen on {host or '*'}:{port} with {e}" - raise OSError(message) from e - else: - self.last_exception = None - - addrs = " and ".join({human.format_address(a) for a in self.listen_addrs}) - conf = self.client_conf() - assert conf - logger.info( - f"{self.mode.description} listening at {addrs}.\n" - + "------------------------------------------------------------\n" - + conf - + "\n------------------------------------------------------------" - ) - - def client_conf(self) -> str | None: - if not self._server: - return None - host = local_ip.get_local_ip() or local_ip.get_local_ip6() - port = self.mode.listen_port(ctx.options.listen_port) - return textwrap.dedent(f""" - [Interface] - PrivateKey = {self.client_key} - Address = 10.0.0.1/32 - DNS = 10.0.0.53 - - [Peer] - PublicKey = {wg.pubkey(self.server_key)} - AllowedIPs = 0.0.0.0/0 - Endpoint = {host}:{port} - """).strip() - - def to_json(self) -> dict: - return { - "wireguard_conf": self.client_conf(), - **super().to_json() - } - - async def stop(self) -> None: - assert self._server is not None - self._server.close() - await self._server.wait_closed() - self._server = None - self.last_exception = None - - addrs = " and ".join({human.format_address(a) for a in self.listen_addrs}) - logger.info(f"Stopped {self.mode.description} at {addrs}.") - - @property - def listen_addrs(self) -> tuple[Address, ...]: - return self._listen_addrs - - async def wg_handle_tcp_connection(self, stream: wg.TcpStream) -> None: - await self.handle_tcp_connection(stream, stream) - - def wg_handle_udp_datagram(self, data: bytes, remote_addr: Address, local_addr: Address) -> None: - assert self._server is not None - transport = WireGuardDatagramTransport(self._server, local_addr, remote_addr) - self.handle_udp_datagram( - transport, - data, - remote_addr, - local_addr - ) - - class RegularInstance(AsyncioServerInstance[mode_specs.RegularMode]): def make_top_layer(self, context: Context) -> Layer: return layers.modes.HttpProxy(context) diff --git mitmproxy/proxy/mode_specs.py mitmproxy/proxy/mode_specs.py index 1e34a4406..f1aa100b7 100644 --- mitmproxy/proxy/mode_specs.py +++ mitmproxy/proxy/mode_specs.py @@ -245,13 +245,3 @@ class DnsMode(ProxyMode): def __post_init__(self) -> None: _check_empty(self.data) - - -class WireGuardMode(ProxyMode): - """Proxy Server based on WireGuard""" - description = "WireGuard server" - default_port = 51820 - transport_protocol = UDP - - def __post_init__(self) -> None: - pass diff --git mitmproxy/proxy/server.py mitmproxy/proxy/server.py index 1341564ad..5ed711144 100644 --- mitmproxy/proxy/server.py +++ mitmproxy/proxy/server.py @@ -18,7 +18,6 @@ from contextlib import contextmanager from dataclasses import dataclass from typing import Optional, Union -import mitmproxy_wireguard as wg from OpenSSL import SSL from mitmproxy import http, options as moptions, tls @@ -80,8 +79,8 @@ class TimeoutWatchdog: @dataclass class ConnectionIO: handler: Optional[asyncio.Task] = None - reader: Optional[Union[asyncio.StreamReader, udp.DatagramReader, wg.TcpStream]] = None - writer: Optional[Union[asyncio.StreamWriter, udp.DatagramWriter, wg.TcpStream]] = None + reader: Optional[Union[asyncio.StreamReader, udp.DatagramReader]] = None + writer: Optional[Union[asyncio.StreamWriter, udp.DatagramWriter]] = None class ConnectionHandler(metaclass=abc.ABCMeta): @@ -413,8 +412,8 @@ class ConnectionHandler(metaclass=abc.ABCMeta): class LiveConnectionHandler(ConnectionHandler, metaclass=abc.ABCMeta): def __init__( self, - reader: Union[asyncio.StreamReader, wg.TcpStream], - writer: Union[asyncio.StreamWriter, wg.TcpStream], + reader: asyncio.StreamReader, + writer: asyncio.StreamWriter, options: moptions.Options, mode: mode_specs.ProxyMode, ) -> None: diff --git setup.cfg setup.cfg index a43c808d5..0a3cb9560 100644 --- setup.cfg +++ setup.cfg @@ -69,7 +69,6 @@ exclude = mitmproxy/net/http/message.py mitmproxy/net/http/multipart.py mitmproxy/net/tls.py - mitmproxy/net/udp_wireguard.py mitmproxy/options.py mitmproxy/proxy/config.py mitmproxy/proxy/server.py diff --git setup.py setup.py index 94ef426ed..d88549b83 100644 --- setup.py +++ setup.py @@ -76,18 +76,17 @@ setup( "asgiref>=3.2.10,<3.6", "Brotli>=1.0,<1.1", "certifi>=2019.9.11", # no semver here - this should always be on the last release! - "cryptography>=38.0,<38.1", + "cryptography>=3.4.8", "flask>=1.1.1,<2.3", "h11>=0.11,<0.15", "h2>=4.1,<5", "hyperframe>=6.0,<7", "kaitaistruct>=0.10,<0.11", "ldap3>=2.8,<2.10", - "mitmproxy_wireguard>=0.1.6,<0.2", "msgpack>=1.0.0, <1.1.0", "passlib>=1.6.5, <1.8", "protobuf>=3.14,<5", - "pyOpenSSL>=22.1,<22.2", + "pyOpenSSL>=21.0", "pyparsing>=2.4.2,<3.1", "pyperclip>=1.6.0,<1.9", "ruamel.yaml>=0.16,<0.18", diff --git test/mitmproxy/proxy/test_mode_servers.py test/mitmproxy/proxy/test_mode_servers.py index c1228b3ca..75a524d94 100644 --- test/mitmproxy/proxy/test_mode_servers.py +++ test/mitmproxy/proxy/test_mode_servers.py @@ -8,7 +8,7 @@ import pytest import mitmproxy.platform from mitmproxy.addons.proxyserver import Proxyserver from mitmproxy.net import udp -from mitmproxy.proxy.mode_servers import DnsInstance, ServerInstance, WireGuardServerInstance +from mitmproxy.proxy.mode_servers import DnsInstance, ServerInstance from mitmproxy.proxy.server import ConnectionHandler from mitmproxy.test import taddons @@ -25,9 +25,6 @@ def test_make(): assert inst.mode.description assert inst.to_json() - with pytest.raises(ValueError, match="is not a spec for a WireGuardServerInstance server."): - WireGuardServerInstance.make("regular", manager) - async def test_last_exception_and_running(monkeypatch): manager = MagicMock() @@ -111,91 +108,6 @@ async def test_transparent(failure, monkeypatch, caplog_async): assert await caplog_async.await_log("Stopped transparent proxy") -async def test_wireguard(tdata, monkeypatch, caplog): - caplog.set_level("DEBUG") - - async def handle_client(self: ConnectionHandler): - t = self.transports[self.client] - data = await t.reader.read(65535) - t.writer.write(data.upper()) - await t.writer.drain() - t.writer.close() - - monkeypatch.setattr(ConnectionHandler, "handle_client", handle_client) - - system = platform.system() - if system == "Linux": - test_client_name = "linux-x86_64" - elif system == "Darwin": - test_client_name = "macos-x86_64" - elif system == "Windows": - test_client_name = "windows-x86_64.exe" - else: - return pytest.skip("Unsupported platform for wg-test-client.") - - test_client_path = tdata.path(f"wg-test-client/{test_client_name}") - test_conf = tdata.path(f"wg-test-client/test.conf") - - with taddons.context(Proxyserver()): - inst = WireGuardServerInstance.make(f"wireguard:{test_conf}@0", MagicMock()) - - await inst.start() - assert "WireGuard server listening" in caplog.text - - _, port = inst.listen_addrs[0] - - assert inst.is_running - proc = await asyncio.create_subprocess_exec( - test_client_path, - str(port), - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - stdout, stderr = await proc.communicate() - - try: - assert proc.returncode == 0 - except AssertionError: - print(stdout) - print(stderr) - raise - - await inst.stop() - assert "Stopped WireGuard server" in caplog.text - - -async def test_wireguard_generate_conf(tmp_path): - with taddons.context(Proxyserver()) as tctx: - tctx.options.confdir = str(tmp_path) - inst = WireGuardServerInstance.make(f"wireguard@0", MagicMock()) - assert not inst.client_conf() # should not error. - - await inst.start() - - assert (tmp_path / "wireguard.conf").exists() - assert inst.client_conf() - assert inst.to_json()["wireguard_conf"] - k = inst.server_key - - inst2 = WireGuardServerInstance.make(f"wireguard@0", MagicMock()) - await inst2.start() - assert k == inst2.server_key - - await inst.stop() - await inst2.stop() - - -async def test_wireguard_invalid_conf(tmp_path): - with taddons.context(Proxyserver()): - # directory instead of filename - inst = WireGuardServerInstance.make(f"wireguard:{tmp_path}", MagicMock()) - - with pytest.raises(OSError): - await inst.start() - - assert "Invalid configuration file" in repr(inst.last_exception) - - async def test_tcp_start_error(): manager = MagicMock() diff --git test/mitmproxy/proxy/test_mode_specs.py test/mitmproxy/proxy/test_mode_specs.py index e2e7eecf9..3891a188e 100644 --- test/mitmproxy/proxy/test_mode_specs.py +++ test/mitmproxy/proxy/test_mode_specs.py @@ -58,9 +58,6 @@ def test_parse_specific_modes(): assert ProxyMode.parse("dns") assert ProxyMode.parse("reverse:dns://8.8.8.8") assert ProxyMode.parse("reverse:dtls://127.0.0.1:8004") - assert ProxyMode.parse("wireguard") - assert ProxyMode.parse("wireguard:foo.conf").data == "foo.conf" - assert ProxyMode.parse("wireguard@51821").listen_port() == 51821 with pytest.raises(ValueError, match="invalid port"): ProxyMode.parse("regular@invalid-port")