From 4f06028a7bcb820362432423ade8c36ba325dcdb Mon Sep 17 00:00:00 2001 From: DerEnderKeks Date: Sat, 24 Feb 2024 18:53:15 +0100 Subject: [PATCH 1/2] fix: use dual-stack socket instead of IPv4-only By using an INET6 socket with IPV6_V6ONLY disabled, legacy IPv4 can still be reached. To connect to v4 IPs, the addresses are mapped to IPv6. IPv6 addresses are only used when a hostname resolves to one and the system has a non-local IPv6 available. For hosts with IPv6 completely disabled for some reason, the socket falls back to v4-only. --- pychromecast/socket_client.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pychromecast/socket_client.py b/pychromecast/socket_client.py index e7ea12585..1d5316ab9 100644 --- a/pychromecast/socket_client.py +++ b/pychromecast/socket_client.py @@ -360,7 +360,16 @@ def mdns_backoff( self.host, self.port, ) - self.socket.connect((self.host, self.port)) + + mapped_host = socket.getaddrinfo( + self.host, + self.port, + self.socket.family, + socket.SOCK_STREAM, + flags=(socket.AI_ADDRCONFIG | socket.AI_V4MAPPED), + )[0][4] + + self.socket.connect(mapped_host) context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = ssl.CERT_NONE @@ -1133,7 +1142,13 @@ def new_socket() -> socket.socket: Try to set SO_REUSEPORT for BSD-flavored systems if it's an option. Catches errors if not. """ - new_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + new_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + new_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) # ensuring dual-stack + except OSError: + # falling back to IPv4 on systems without IPv6 + new_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + new_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: From a77ccafe314b2e5accfeeb9728c2fe6d4aed6446 Mon Sep 17 00:00:00 2001 From: DerEnderKeks Date: Thu, 21 Mar 2024 15:46:51 +0100 Subject: [PATCH 2/2] style: move comment to make black happy --- pychromecast/socket_client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pychromecast/socket_client.py b/pychromecast/socket_client.py index 1d5316ab9..0e513242d 100644 --- a/pychromecast/socket_client.py +++ b/pychromecast/socket_client.py @@ -1144,7 +1144,8 @@ def new_socket() -> socket.socket: """ try: new_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - new_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) # ensuring dual-stack + # ensuring dual-stack + new_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) except OSError: # falling back to IPv4 on systems without IPv6 new_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)