metodo - Biblioteca de ''solicitudes'' de Python: ¿definir un DNS específico?
requests python https (2)
Debería ver TransportAdapters , incluido el código fuente. La documentación sobre ellos no es buena, pero dan acceso de bajo nivel a mucha de la funcionalidad descrita en RFC 2818 y RFC 6125 . En particular, esos documentos fomentan (¿requieren?) El código del lado del cliente para soportar DNS específicos de la aplicación con el fin de verificar los certificados ''CommonName y SubjectAltName. El argumento de palabra clave que necesita en esas llamadas es "assert_hostname". A continuación se explica cómo configurarlo con la biblioteca de solicitudes:
from requests import Session, HTTPError
from requests.adapters import HTTPAdapter, DEFAULT_POOLSIZE, DEFAULT_RETRIES, DEFAULT_POOLBLOCK
class DNSResolverHTTPSAdapter(HTTPAdapter):
def __init__(self, common_name, host, pool_connections=DEFAULT_POOLSIZE, pool_maxsize=DEFAULT_POOLSIZE,
max_retries=DEFAULT_RETRIES, pool_block=DEFAULT_POOLBLOCK):
self.__common_name = common_name
self.__host = host
super(DNSResolverHTTPSAdapter, self).__init__(pool_connections=pool_connections, pool_maxsize=pool_maxsize,
max_retries=max_retries, pool_block=pool_block)
def get_connection(self, url, proxies=None):
redirected_url = url.replace(self.__common_name, self.__host)
return super(DNSResolverHTTPSAdapter, self).get_connection(redirected_url, proxies=proxies)
def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs):
pool_kwargs[''assert_hostname''] = self.__common_name
super(DNSResolverHTTPSAdapter, self).init_poolmanager(connections, maxsize, block=block, **pool_kwargs)
common_name = ''SuperSecretSarahServer''
host = ''192.168.33.51''
port = 666
base_url = ''https://{}:{}/api/''.format(common_name, port)
my_session = Session()
my_session.mount(self.base_url.lower(), DNSResolverHTTPSAdapter(common_name, host))
user_name = ''sarah''
url = ''{}users/{}''.format(self.base_url, user_name)
default_response_kwargs = {
''auth'': (NAME, PASSWORD),
''headers'': {''Content-Type'': ''application/json''},
''verify'': SSL_OPTIONS[''ca_certs''],
''cert'': (SSL_OPTIONS[''certfile''], SSL_OPTIONS[''keyfile''])
}
response = my_session.get(url, **default_response_kwargs)
Utilizo common_name
para el nombre que se espera que esté en el certificado y cómo su código hará referencia a la máquina deseada. Utilizo el host
para un nombre reconocido por el mundo externo: FQDN, IP, entrada de DNS, ... Por supuesto, el diccionario SSL_OPTIONS (en mi ejemplo) debe listar los nombres de archivo / clave apropiados en su máquina. (Además, NAME y PASSWORD deberían resolver corregir las cadenas).
En mi proyecto estoy manejando todas las solicitudes HTTP con la biblioteca de requests
python.
Ahora, necesito consultar el servidor http utilizando un DNS específico: hay dos entornos, cada uno con su propio DNS, y los cambios se realizan de forma independiente.
Por lo tanto, cuando se ejecuta el código, debe usar DNS específico para el entorno y no el DNS especificado en mi conexión a Internet.
¿Alguien ha intentado esto usando python-requests? Solo he encontrado una solución para urllib2:
https://stackoverflow.com/questions/4623090/python-set-custom-dns-server-for-urllib-requests
requests
utiliza urllib3
, que en última instancia utiliza httplib.HTTPConnection
también, por lo que las técnicas de https://.com/questions/4623090/python-set-custom-dns-server-for-urllib-requests (ahora eliminadas, meramente vinculado a Tell urllib2 para usar DNS personalizado ) aún se aplican, hasta cierto punto.
El módulo urllib3.connection
subclasifica httplib.HTTPConnection
bajo el mismo nombre, después de haber reemplazado el método .connect()
con uno que llama a self._new_conn
. A su vez, esto delega en urllib3.util.connection.create_connection()
. Quizás sea más fácil parchar esa función:
from urllib3.util import connection
_orig_create_connection = connection.create_connection
def patched_create_connection(address, *args, **kwargs):
"""Wrap urllib3''s create_connection to resolve the name elsewhere"""
# resolve hostname to an ip address; use your own
# resolver here, as otherwise the system resolver will be used.
host, port = address
hostname = your_dns_resolver(host)
return _orig_create_connection((hostname, port), *args, **kwargs)
connection.create_connection = patched_create_connection
y proporcionaría su propio código para resolver la parte de host
de la dirección en una dirección IP en lugar de confiar en la llamada connection.create_connection()
(que ajusta socket.create_connection()
) para resolver el nombre de host por usted.
Al igual que todos los parches, tenga cuidado de que el código no haya cambiado significativamente en lanzamientos posteriores; el parche aquí fue creado contra urllib3
versión 1.21.1. pero debería funcionar para versiones tan atrás como 1.9.
Tenga en cuenta que esta respuesta se volvió a escribir para que funcione con las versiones más recientes de urllib3
, que han agregado una ubicación de parche mucho más conveniente. Consulte el historial de edición para el método anterior, aplicable a la versión <1.9, como un parche para la versión vendida de urllib3
lugar de una instalación independiente.