Search code examples
pythoncurlnetwork-programminglibcurlpycurl

PycURL send DNS traffic through particular interface


I have multiple interfaces on the box and want to force the traffic through a particular interface using python.

This thread answers how to do that for HTTP traffic. But when I look at tcpdump, the DNS queries do not honor the interface setting. libcurl provides options to force DNS traffic through a particular interface using option CURLOPT_DNS_INTERFACE and CURLOPT_DNS_LOCAL_IP4

I tried using the same through C and it seems to honor the interface when libcurl is built with c-ares support.

But when the same options are used from the pycurl version result in the following errors:

AttributeError: DNS_INTERFACE
AttributeError: DNS_LOCAL_IP4

I am trying monkey patching suggested on this thread. But based on the comments, other people already reported that it's not working. Thanks.

[edit] Tested the above-mentioned monkey-patching with bind, tcpdump still shows traffic through a different interface. Fixed formatting.


Solution

  • The AttributeError happens since PycURL only supports curl options that it lists in src/module.c. One can add support for CURLOPT_DNS_INTERFACE by mirroring how it supports CURLOPT_INTERFACE -- by adding

        insint_c(d, "DNS_INTERFACE", CURLOPT_DNS_INTERFACE);
    

    and

        case CURLOPT_DNS_INTERFACE:
    

    in src/module.c and src/easyopt.c after the lines about CURLOPT_INTERFACE, I could build a version that supports DNS_INTERFACE. I used python setup.py install for the build (see docs), running into two errors that were solved with this answer and make src/docstrings.c (see GitHub).

    Here the example from the docs with DNS_INTERFACE added:

    import pycurl
    from StringIO import StringIO
    
    buffer = StringIO()
    c = pycurl.Curl()
    c.setopt(c.URL, 'http://pycurl.io/')
    c.setopt(c.WRITEDATA, buffer)
    c.setopt(c.DNS_INTERFACE, "enp9s0")
    c.perform()
    c.close()
    
    body = buffer.getvalue()
    print(body)
    

    It currently gives me pycurl.error: (4, '') on the c.setopt(c.DNS_INTERFACE, "enp9s0"), but this error would likely not happen for you since you built libcurl with c-ares support.