diff --git a/mitmproxy/net/local_ip.py b/mitmproxy/net/local_ip.py new file mode 100644 index 000000000..27468c05c --- /dev/null +++ b/mitmproxy/net/local_ip.py @@ -0,0 +1,35 @@ +from __future__ import annotations +import socket + + +def get_local_ip(reachable: str = "8.8.8.8") -> str | None: + """ + Get the default local outgoing IPv4 address without sending any packets. + This will fail if the target address is known to be unreachable. + We use Google DNS's IPv4 address as the default. + """ + # https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((reachable, 80)) + return s.getsockname()[0] + except OSError: + return None + finally: + s.close() + + +def get_local_ip6(reachable: str = "2001:4860:4860::8888") -> str | None: + """ + Get the default local outgoing IPv6 address without sending any packets. + This will fail if the target address is known to be unreachable. + We use Google DNS's IPv6 address as the default. + """ + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + try: + s.connect((reachable, 80)) + return s.getsockname()[0] + except OSError: + return None + finally: + s.close() diff --git a/mitmproxy/platform/windows.py b/mitmproxy/platform/windows.py index 969c65541..0e0515bd5 100644 --- a/mitmproxy/platform/windows.py +++ b/mitmproxy/platform/windows.py @@ -17,6 +17,8 @@ from typing import Any, ClassVar, Optional import pydivert import pydivert.consts +from mitmproxy.net.local_ip import get_local_ip, get_local_ip6 + REDIRECT_API_HOST = "127.0.0.1" REDIRECT_API_PORT = 8085 @@ -249,32 +251,6 @@ class TcpConnectionTable(collections.abc.Mapping): ) -def get_local_ip() -> Optional[str]: - # Auto-Detect local IP. This is required as re-injecting to 127.0.0.1 does not work. - # https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - try: - s.connect(("8.8.8.8", 80)) - return s.getsockname()[0] - except OSError: - return None - finally: - s.close() - - -def get_local_ip6(reachable: str) -> Optional[str]: - # The same goes for IPv6, with the added difficulty that .connect() fails if - # the target network is not reachable. - s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - try: - s.connect((reachable, 80)) - return s.getsockname()[0] - except OSError: - return None - finally: - s.close() - - class Redirect(threading.Thread): daemon = True windivert: pydivert.WinDivert @@ -442,7 +418,7 @@ class TransparentProxy: ) self.ipv4_address = get_local_ip() - self.ipv6_address = get_local_ip6("2001:4860:4860::8888") + self.ipv6_address = get_local_ip6() # print(f"IPv4: {self.ipv4_address}, IPv6: {self.ipv6_address}") self.client_server_map = ClientServerMap() diff --git a/test/mitmproxy/net/test_local_ip.py b/test/mitmproxy/net/test_local_ip.py new file mode 100644 index 000000000..f8b983a96 --- /dev/null +++ b/test/mitmproxy/net/test_local_ip.py @@ -0,0 +1,17 @@ +from mitmproxy.net import local_ip + + +def test_get_local_ip(): + # should never error, but may return None depending on the host OS configuration. + local_ip.get_local_ip() + local_ip.get_local_ip("0.0.0.0") + local_ip.get_local_ip("127.0.0.1") + local_ip.get_local_ip("invalid!") + + +def test_get_local_ip6(): + # should never error, but may return None depending on the host OS configuration. + local_ip.get_local_ip6() + local_ip.get_local_ip6("::") + local_ip.get_local_ip6("::1") + local_ip.get_local_ip("invalid!")