Introduction
Understanding how to control the IP version when making HTTP requests in Python can be crucial when dealing with servers that are accessible only via IPv4 or IPv6.
The requests
module in Python is a powerful, user-friendly tool for sending HTTP requests. By default, it automatically determines whether to use IPv4 or IPv6 based on the network stack’s configuration. This article guides you on how to explicitly force IPv4 or IPv6 when using the requests
module, with practical code examples.
Installing ‘requests’ Module
# Use pip to install the 'requests' module
pip install requests
Basic Request Example
import requests
response = requests.get('https://example.com')
print(response.text)
Understanding Network Stacks
Before forcing a specific IP version, it’s important to know that modern operating systems support a dual network stack that allows the use of both IPv4 and IPv6. However, forcing a specific version can be necessary for certain network conditions or server configurations.
Forcing IPv4
To force the use of IPv4, one can modify the default socket connection behavior. This requires a little more control over the connection process. Here’s a basic example:
import socket
import requests
from requests.packages.urllib3.util.connection import allowed_gai_family
# Override the default function in the urllib3 utility module
original_allowed_gai_family = allowed_gai_family
def forced_ipv4_gai_family():
return socket.AF_INET
allowed_gai_family = forced_ipv4_gai_family
# Now, all requests via the 'requests' module will use IPv4 only
response = requests.get('https://example.com')
print(response.text)
# Restore the original function after making IPv4 requests
allowed_gai_family = original_allowed_gai_family
Forcing IPv6
Forcing IPv6 is similar to forcing IPv4, but you direct the socket to use the IPv6 family:
import socket
import requests
from requests.packages.urllib3.util.connection import allowed_gai_family
def forced_ipv6_gai_family():
return socket.AF_INET6
allowed_gai_family = forced_ipv6_gai_family
# Attempts will be made to connect using IPv6
response = requests.get('https://example.com')
print(response.text)
# Don't forget to reset the original function
allowed_gai_family = original_allowed_gai_family
Handling Exceptions
When forcing a specific IP version, it’s possible to encounter exceptions, such as ConnectionError
if the requested domain does not support the forced IP version. Make sure to handle these:
import requests
from requests.exceptions import ConnectionError
try:
response = requests.get('https://ipv4onlysite.com')
print(response.text)
except ConnectionError as e:
print('Error connecting to the site:', e)
Advanced Use Case: Custom Adapter
In advanced scenarios, you may want to create a custom adapter to control the IP version for specific domains or request sessions:
import requests
from requests.packages.urllib3.util.connection import allowed_gai_family
# Custom adapter that forces IPv4
class IPv4Adapter(requests.adapters.HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
self.poolmanager = requests.adapters.HTTPAdapter(pool_connections=kwargs.get('connections', self.poolmanager.pool_connections),
pool_maxsize=kwargs.get('maxsize', self.poolmanager.pool_maxsize),
max_retries=kwargs.get('retries', self.poolmanager.max_retries),
pool_block=kwargs.get('block', self.poolmanager.pool_block))
self.poolmanager.pool_classes_by_scheme[IPv4Adapter.scheme] = requests.packages.urllib3.connectionpool.HTTPConnectionPool
self.poolmanager.connection_from_host = lambda host, port=None, scheme=None, pool_kwargs=None: self.poolmanager.pool_classes_by_scheme[IPv4Adapter.scheme](host, port, strict=True, timeout=IPv4Adapter.poolmanager.ConnectionTimeout, **(pool_kwargs or {}))
# Add the custom adapter to a session
session = requests.Session()
session.mount('https://example.com', IPv4Adapter())
# The following request to https://example.com will use IPv4 due to the custom adapter
response = session.get('https://example.com')
print(response.text)
Conclusion
The Python requests
module is versatile and supports both IPv4 and IPv6 usage. Forcing a specific IP protocol can be critical for compatibility or performance reasons and can be achieved through the techniques described. Always handle exceptions gracefully and reset any global state modifications to avoid side effects in other parts of your application.