Sling Academy
Home/Python/Python ‘requests’ module: How to force use of IPv4 or IPv6

Python ‘requests’ module: How to force use of IPv4 or IPv6

Last updated: January 02, 2024

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.

Next Article: Python: How to Upload Files with ‘httpx’ (form-data)

Previous Article: How to Block Requests Sent by Python ‘requests’ Module?

Series: Python: Network & JSON tutorials

Python

You May Also Like

  • Introduction to yfinance: Fetching Historical Stock Data in Python
  • Monitoring Volatility and Daily Averages Using cryptocompare
  • Advanced DOM Interactions: XPath and CSS Selectors in Playwright (Python)
  • Automating Strategy Updates and Version Control in freqtrade
  • Setting Up a freqtrade Dashboard for Real-Time Monitoring
  • Deploying freqtrade on a Cloud Server or Docker Environment
  • Optimizing Strategy Parameters with freqtrade’s Hyperopt
  • Risk Management: Setting Stop Loss, Trailing Stops, and ROI in freqtrade
  • Integrating freqtrade with TA-Lib and pandas-ta Indicators
  • Handling Multiple Pairs and Portfolios with freqtrade
  • Using freqtrade’s Backtesting and Hyperopt Modules
  • Developing Custom Trading Strategies for freqtrade
  • Debugging Common freqtrade Errors: Exchange Connectivity and More
  • Configuring freqtrade Bot Settings and Strategy Parameters
  • Installing freqtrade for Automated Crypto Trading in Python
  • Scaling cryptofeed for High-Frequency Trading Environments
  • Building a Real-Time Market Dashboard Using cryptofeed in Python
  • Customizing cryptofeed Callbacks for Advanced Market Insights
  • Integrating cryptofeed into Automated Trading Bots