Detect if IPv6 is supported, OS-agnostic, no external program?
Question:
Is there a way to detect if IPv6 is supported on a system, without using external programs and in an OS-agnostic way?
I’ve searched high and low, here and throughout the Internet, it seems nearly every offered solution relies either on accessing /proc
(not available on Windows & MacOS) or running external programs.
The best I can come up with is:
import errno
import socket
def has_ip6():
try:
socket.create_connection(("::1", 0))
except OSError as e:
if e.errno == errno.EADDRNOTAVAIL:
return False
if e.errno == errno.ECONNREFUSED;
return True
raise
Is there a better way?
Answers:
EDIT: Do not use socket.has_ipv6
; check out @pepoluan’s own answer instead!
The socket module contains the constant socket.has_ipv6 specifically for indicating whether or not IPv6 is supported.
Although @averresen’s answer is not correct, it did lead me to the correct answer as specified in https://github.com/urllib3/urllib3/pull/611#issuecomment-100954017 :
def _is_ipv6_enabled():
"""Check whether IPv6 is enabled on this host."""
if socket.has_ipv6:
sock = None
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind((HOSTv6, 0))
return True
except OSError:
pass
finally:
if sock:
sock.close()
return False
So basically what I did was already on the right path, I just have to add a defensive if not socket.has_ipv6: return False
at the beginning.
Edit 1:
This is what I finally ended up with:
import socket
import errno
# On Windows, the E* constants will use the WSAE* values
# So no need to hardcode an opaque integer in the sets.
_ADDR_NOT_AVAIL = {errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT}
_ADDR_IN_USE = {errno.EADDRINUSE}
def system_has_ipv6() -> bool:
if not has_ipv6:
return False
try:
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
sock.bind(("::1", 0))
return True
except OSError as e:
if e.errno in _ADDR_NOT_AVAIL:
return False
if e.errno in _ADDR_IN_USE:
# This point shouldn't ever be reached. But just in case...
return True
# Other errors should be inspected
raise
Edit 2:
I added errno.EAFNOSUPPORT
to the _ADDR_NOT_AVAIL
set. EADDRNOTAVAIL
is the errno if IPv6 modules/drivers are loaded but disabled, EAFNOSUPPORT
is the errno if IPv6 modules/drivers are not loaded at all.
This still does not address the issue if the ISP is supporting IPV6. That will determine if you can connect with the IPV6 device or not on the internet. Is there a way to find this out
Is there a way to detect if IPv6 is supported on a system, without using external programs and in an OS-agnostic way?
I’ve searched high and low, here and throughout the Internet, it seems nearly every offered solution relies either on accessing /proc
(not available on Windows & MacOS) or running external programs.
The best I can come up with is:
import errno
import socket
def has_ip6():
try:
socket.create_connection(("::1", 0))
except OSError as e:
if e.errno == errno.EADDRNOTAVAIL:
return False
if e.errno == errno.ECONNREFUSED;
return True
raise
Is there a better way?
EDIT: Do not use socket.has_ipv6
; check out @pepoluan’s own answer instead!
The socket module contains the constant socket.has_ipv6 specifically for indicating whether or not IPv6 is supported.
Although @averresen’s answer is not correct, it did lead me to the correct answer as specified in https://github.com/urllib3/urllib3/pull/611#issuecomment-100954017 :
def _is_ipv6_enabled():
"""Check whether IPv6 is enabled on this host."""
if socket.has_ipv6:
sock = None
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind((HOSTv6, 0))
return True
except OSError:
pass
finally:
if sock:
sock.close()
return False
So basically what I did was already on the right path, I just have to add a defensive if not socket.has_ipv6: return False
at the beginning.
Edit 1:
This is what I finally ended up with:
import socket
import errno
# On Windows, the E* constants will use the WSAE* values
# So no need to hardcode an opaque integer in the sets.
_ADDR_NOT_AVAIL = {errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT}
_ADDR_IN_USE = {errno.EADDRINUSE}
def system_has_ipv6() -> bool:
if not has_ipv6:
return False
try:
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
sock.bind(("::1", 0))
return True
except OSError as e:
if e.errno in _ADDR_NOT_AVAIL:
return False
if e.errno in _ADDR_IN_USE:
# This point shouldn't ever be reached. But just in case...
return True
# Other errors should be inspected
raise
Edit 2:
I added errno.EAFNOSUPPORT
to the _ADDR_NOT_AVAIL
set. EADDRNOTAVAIL
is the errno if IPv6 modules/drivers are loaded but disabled, EAFNOSUPPORT
is the errno if IPv6 modules/drivers are not loaded at all.
This still does not address the issue if the ISP is supporting IPV6. That will determine if you can connect with the IPV6 device or not on the internet. Is there a way to find this out