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?

Asked By: pepoluan

||

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.

Answered By: Alan Verresen

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.

Answered By: pepoluan

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

Answered By: rajatksud
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.