Yes, urllib3
fully supports IPv6 connectivity. As a modern Python HTTP client library, urllib3
leverages Python's built-in http.client
module, which provides native IPv6 support for both HTTP and HTTPS connections.
Basic IPv6 Usage
Using Literal IPv6 Addresses
When connecting to a specific IPv6 address, wrap it in square brackets to distinguish it from port numbers:
import urllib3
# Create a PoolManager instance
http = urllib3.PoolManager()
# IPv6 address wrapped in square brackets
url = 'http://[2001:db8::1]/'
try:
response = http.request('GET', url)
print(f"Status: {response.status}")
print(f"Content: {response.data.decode('utf-8')[:100]}...")
except urllib3.exceptions.ConnectTimeoutError:
print("Connection timed out - IPv6 may not be available")
except Exception as e:
print(f"Error: {e}")
IPv6 with Custom Ports
Specify ports after the closing bracket:
import urllib3
http = urllib3.PoolManager()
# IPv6 address with custom port
url = 'http://[2001:db8::1]:8080/api/data'
response = http.request('GET', url)
print(f"Response: {response.status}")
HTTPS over IPv6
IPv6 works seamlessly with HTTPS connections:
import urllib3
# Disable SSL warnings for demo (not recommended in production)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
http = urllib3.PoolManager()
# HTTPS with IPv6
url = 'https://[2606:2800:220:1:248:1893:25c8:1946]/'
try:
response = http.request('GET', url, timeout=10)
print(f"HTTPS IPv6 Status: {response.status}")
except Exception as e:
print(f"HTTPS IPv6 Error: {e}")
Hostname Resolution
When using hostnames, DNS resolution automatically handles IPv4/IPv6 selection:
import urllib3
import socket
http = urllib3.PoolManager()
# Test IPv6-enabled hostname
hostname = 'ipv6.google.com'
# Check what IP addresses the hostname resolves to
try:
addr_info = socket.getaddrinfo(hostname, 80, socket.AF_UNSPEC)
print("Available addresses:")
for info in addr_info:
print(f" {info[4][0]} ({info[0].name})")
except socket.gaierror as e:
print(f"DNS resolution failed: {e}")
# Make request (urllib3 will choose appropriate IP version)
try:
response = http.request('GET', f'https://{hostname}/')
print(f"Response status: {response.status}")
except Exception as e:
print(f"Request failed: {e}")
Forcing IPv6 Connections
To ensure only IPv6 connections are used, you can customize the socket creation:
import urllib3
import socket
from urllib3.util.connection import create_connection
def create_ipv6_connection(address, timeout=None, source_address=None, socket_options=None):
"""Force IPv6 connection"""
host, port = address
# Resolve to IPv6 addresses only
addr_info = socket.getaddrinfo(host, port, socket.AF_INET6, socket.SOCK_STREAM)
if not addr_info:
raise socket.error("No IPv6 addresses found")
# Use the first IPv6 address
family, type_, proto, canonname, sockaddr = addr_info[0]
sock = socket.socket(family, type_, proto)
if timeout is not None:
sock.settimeout(timeout)
sock.connect(sockaddr)
return sock
# Monkey patch urllib3 to use IPv6-only connections
urllib3.util.connection.create_connection = create_ipv6_connection
http = urllib3.PoolManager()
response = http.request('GET', 'https://ipv6.google.com/')
print(f"IPv6-only connection status: {response.status}")
Testing IPv6 Connectivity
Check if your system supports IPv6:
import urllib3
import socket
def test_ipv6_support():
"""Test if IPv6 is available on the system"""
try:
# Try to create an IPv6 socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.close()
print("✓ IPv6 socket creation successful")
# Test IPv6 connectivity
http = urllib3.PoolManager()
response = http.request('GET', 'https://ipv6.google.com/', timeout=5)
print(f"✓ IPv6 connectivity test: {response.status}")
return True
except Exception as e:
print(f"✗ IPv6 not available: {e}")
return False
# Run the test
if test_ipv6_support():
print("Your system supports IPv6 with urllib3")
else:
print("IPv6 support is limited or unavailable")
Common Issues and Troubleshooting
Network Configuration Issues
import urllib3
from urllib3.exceptions import ConnectTimeoutError, NewConnectionError
http = urllib3.PoolManager()
def test_ipv6_connection(url):
"""Test IPv6 connection with proper error handling"""
try:
response = http.request('GET', url, timeout=10)
return f"Success: {response.status}"
except ConnectTimeoutError:
return "Error: Connection timeout - check IPv6 connectivity"
except NewConnectionError as e:
if "Name or service not known" in str(e):
return "Error: DNS resolution failed"
elif "Network is unreachable" in str(e):
return "Error: IPv6 network unreachable - check network config"
return f"Error: Connection failed - {e}"
except Exception as e:
return f"Error: {e}"
# Test various IPv6 endpoints
test_urls = [
'https://[2606:2800:220:1:248:1893:25c8:1946]/', # Example.com IPv6
'https://ipv6.google.com/',
'https://test-ipv6.com/'
]
for url in test_urls:
result = test_ipv6_connection(url)
print(f"{url}: {result}")
Best Practices
- Always handle exceptions when working with IPv6, as not all networks support it
- Use brackets around literal IPv6 addresses in URLs
- Test connectivity before deploying IPv6-dependent applications
- Provide fallback to IPv4 when IPv6 is unavailable
- Consider dual-stack implementations for maximum compatibility
Requirements
- Python 3.x with
urllib3
installed - IPv6-enabled network stack
- Proper network configuration with IPv6 connectivity
- DNS servers that support AAAA records for hostname resolution
urllib3 handles IPv6 transparently, making it easy to build applications that work with both IPv4 and IPv6 addresses without additional complexity.