python-requestsbinancebinance-api-clientccxtpython-requests-toolbelt

How do I force HTTP connections to use IPv4 instead of IPv6 in Python?


When attempting to connect to the Binance REST API from a Windows 11 computer, I got the following error:

ccxt.base.errors.ExchangeError: binanceus {"code":-71012,"msg":"IPv6 not supported"}

In this particular example I am using the ccxt Python library, but I assume the problem exists for any HTTP connection / library since the error comes from Binance. Here's sample code that replicates the issue on Windows 11 (works fine on a Linux machine):

import ccxt
exchange = ccxt.binanceus({'apiKey': '<your_key>', 'secret': '<your_secret>'})
print(exchange.fetch_balance())

I speculate that this is happening because by default in Windows 11 IPv6 has a higher priority than IPv4:

> netsh interface ipv6 show prefixpolicies

Querying active state...

Precedence  Label  Prefix
----------  -----  --------------------------------
        50      0  ::1/128
        40      1  ::/0
        35      4  ::ffff:0:0/96
        30      2  2002::/16
         5      5  2001::/32
         3     13  fc00::/7
         1     11  fec0::/10
         1     12  3ffe::/16
         1      3  ::/96

I suppose one solution is to change this priority so IPv4 is used by default, but I don't want to do this, and I also prefer the code to work everywhere.

Under the hood, the ccxt library uses the Python requests library, and allows the user to construct a custom Session object.

I came up with the following hack/workaround which works for me

Is there a cleaner/better/more robust way to achieve the same thing?

import ccxt
import requests
from requests_toolbelt.adapters import source
import socket


def get_ipv4_session():
    local_ipv4 = socket.gethostbyname(socket.gethostname())
    src = source.SourceAddressAdapter(local_ipv4)

    session = requests.Session()
    session.mount("https://", src)

    return session

exchange = ccxt.binanceus({
    'apiKey': '<your key>',
    'secret': '<your secret>',
    'session': get_ipv4_session()
})

print(exchange.fetch_balance())

I read the answers here as well but they seem more complicated: Force requests to use IPv4 / IPv6


Solution

  • Override requests package not to use ipV6 by adding this line.

    requests.packages.urllib3.util.connection.HAS_IPV6 = False