In my project I'm handling all HTTP requests with python requests
library.
Now, I need to query the http server using specific DNS - there are two environments, each using its own DNS, and changes are made independently.
So, when the code is running, it should use DNS specific to the environment, and not the DNS specified in my internet connection.
Has anyone tried this using python-requests? I've only found solution for urllib2:
https://stackoverflow.com/questions/4623090/python-set-custom-dns-server-for-urllib-requests
requests
usesurllib3
, which ultimately useshttplib.HTTPConnection
as well, so the techniques fromhttps://stackoverflow.com/questions/4623090/python-set-custom-dns-server-for-urllib-requests(now deleted, it merely linked to Tell urllib2 to use custom DNS) still apply, to a certain extent.The
urllib3.connection
module subclasseshttplib.HTTPConnection
under the same name, having replaced the.connect()
method with one that callsself._new_conn
. In turn, this delegates tourllib3.util.connection.create_connection()
. It is perhaps easiest to patch that function:and you'd provide your own code to resolve the
host
portion of the address into an ip address instead of relying on theconnection.create_connection()
call (which wrapssocket.create_connection()
) to resolve the hostname for you.Like all monkeypatching, be careful that the code hasn't significantly changed in later releases; the patch here was created against
urllib3
version 1.21.1. but should work for versions as far back as 1.9.Note that this answer was re-written to work with newer
urllib3
releases, which have added a much more convenient patching location. See the edit history for the old method, applicable to version < 1.9, as a patch to the vendoredurllib3
version rather than a stand-alone installation.A customized HTTPAdapter will do the trick.
Don't forget to set
server_hostname
to enable SNI.I know this is an old thread but here is my python3 compatible solution using tldextract and dnspython. I've left some commented out code to illustrate how to debug and set additional session parameters.
And here it the console output :
Hope this helps.
You should look into the TransportAdapters, including the source code. The documentation on them isn't great, but they give low-level access to a lot of the functionality described in RFC 2818 and RFC 6125. In particular, those documents encourage (require?) client-side code to support application-specific DNS for the purpose of checking certificates' CommonName and SubjectAltName. The keyword argument you need in those calls is "assert_hostname". Here's how to set it with the requests library:
I use
common_name
for the name expected to be on the certificate and how your code will reference the desired machine. I usehost
for a name recognized by the external world - FQDN, IP, DNS entry, ... Of course, the SSL_OPTIONS dictionary (in my example) must list appropriate certificate / key filenames on your machine. (Plus, NAME and PASSWORD should resolve to correct strings.)Or just use subprocess with curl and add
--dns-servers