2015-10-09 1 views
5

Come forzare la libreria requests per utilizzare una versione di protocollo Internet specifica per una richiesta di ricezione? O questo può essere ottenuto meglio con un altro metodo in Python? Potrei ma non voglio usare curl ...Forza richieste di utilizzo di IPv4/IPv6

esempio per chiarire scopo:

import requests 
r = requests.get('https://my-dyn-dns-service.domain/?hostname=my.domain', 
       auth = ('myUserName', 'my-password')) 

risposta

1

Ciò è completamente testato e probabilmente richiederà alcune modifiche, ma combinando le risposte da Using Python “requests” with existing socket connection e how to force python httplib library to use only A requests, sembra che si dovrebbe essere in grado di creare un unico presa IPv6 e quindi avere le richieste di uso che per la sua pool di connessioni con qualcosa di simile:

try: 
    from http.client import HTTPConnection 
except ImportError: 
    from httplib import HTTPConnection 

class MyHTTPConnection(HTTPConnection): 
    def connect(self): 
     print("This actually called called") 
     self.sock = socket.socket(socket.AF_INET6) 
     self.sock.connect((self.host, self.port,0,0)) 
     if self._tunnel_host: 
      self._tunnel() 

requests.packages.urllib3.connectionpool.HTTPConnection = MyHTTPConnection 
+0

Siamo spiacenti, ho ancora una risposta IPv4. Ho provato 'print (requests.get ('https://icanhazip.com') .text)'. – ominug

+0

Purtroppo, non ho accesso a nulla con ipv6 al momento; Ho aggiunto una dichiarazione di stampa e una dichiarazione di connessione solo per assicurarmi che non mi sia sfuggito qualcosa di come si parla di monkeypatching dell'oggetto HTTPConnection – Foon

+0

Ok, l'ho provato di nuovo. Il metodo di connessione non viene chiamato. – ominug

1

Dopo aver letto la risposta precedente, ho dovuto modificare il codice per forzare IPv4 invece di IPv6. Si noti che ho usato socket.AF_INET invece di socket.AF_INET6 e self.sock.connect() ha un argomento di tupla a 2 voci.

ho anche bisogno di ignorare il HTTP S Connection, che è molto diverso da quello HTTPConnection dal requests avvolge il httplib.HTTPSConnection per verificare il certificato se il modulo ssl è disponibile.

import socket 
import ssl 
try: 
    from http.client import HTTPConnection 
except ImportError: 
    from httplib import HTTPConnection 
from requests.packages.urllib3.connection import VerifiedHTTPSConnection 

# HTTP 
class MyHTTPConnection(HTTPConnection): 
    def connect(self): 
     self.sock = socket.socket(socket.AF_INET) 
     self.sock.connect((self.host, self.port)) 
     if self._tunnel_host: 
      self._tunnel() 

requests.packages.urllib3.connectionpool.HTTPConnection = MyHTTPConnection 
requests.packages.urllib3.connectionpool.HTTPConnectionPool.ConnectionCls = MyHTTPConnection 

# HTTPS 
class MyHTTPSConnection(VerifiedHTTPSConnection): 
    def connect(self): 
     self.sock = socket.socket(socket.AF_INET) 
     self.sock.connect((self.host, self.port)) 
     if self._tunnel_host: 
      self._tunnel() 
     self.sock = ssl.wrap_socket(self.sock, self.key_file, self.cert_file) 

requests.packages.urllib3.connectionpool.HTTPSConnection = MyHTTPSConnection 
requests.packages.urllib3.connectionpool.VerifiedHTTPSConnection = MyHTTPSConnection 
requests.packages.urllib3.connectionpool.HTTPSConnectionPool.ConnectionCls = MyHTTPSConnection 
+0

Questa risposta ha funzionato per me, con l'avvertenza che risulta in 'InsecureRequestWarning: viene effettuata una richiesta HTTPS non verificata. L'aggiunta della verifica del certificato è fortemente consigliata. Vedi: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning' quando si esegue su https – kyrenia

0

ho preso un approccio simile a https://stackoverflow.com/a/33046939/5059062, ma invece patchato la parte in socket che rende le richieste DNS in modo che solo fa IPv6 o IPv4, per ogni richiesta, il che significa che questo può essere utilizzato in urllib altrettanto efficacemente come in requests.

Potrebbe non essere corretto se il programma utilizza anche pipe unix e altre cose simili, quindi raccomando cautela con monkeypatching.

import requests 
import socket 
from unittest.mock import patch 
import re 

orig_getaddrinfo = socket.getaddrinfo 
def getaddrinfoIPv6(host, port, family=0, type=0, proto=0, flags=0): 
    return orig_getaddrinfo(host=host, port=port, family=socket.AF_INET6, type=type, proto=proto, flags=flags) 

def getaddrinfoIPv4(host, port, family=0, type=0, proto=0, flags=0): 
    return orig_getaddrinfo(host=host, port=port, family=socket.AF_INET, type=type, proto=proto, flags=flags) 

with patch('socket.getaddrinfo', side_effect=getaddrinfoIPv6): 
    r = requests.get('http://ip6.me') 
    print('ipv6: '+re.search(r'\+3>(.*?)</',r.content.decode('utf-8')).group(1)) 

with patch('socket.getaddrinfo', side_effect=getaddrinfoIPv4): 
    r = requests.get('http://ip6.me') 
    print('ipv4: '+re.search(r'\+3>(.*?)</',r.content.decode('utf-8')).group(1)) 

e senza requests:

import urllib.request 
import socket 
from unittest.mock import patch 
import re 

orig_getaddrinfo = socket.getaddrinfo 
def getaddrinfoIPv6(host, port, family=0, type=0, proto=0, flags=0): 
    return orig_getaddrinfo(host=host, port=port, family=socket.AF_INET6, type=type, proto=proto, flags=flags) 

def getaddrinfoIPv4(host, port, family=0, type=0, proto=0, flags=0): 
    return orig_getaddrinfo(host=host, port=port, family=socket.AF_INET, type=type, proto=proto, flags=flags) 

with patch('socket.getaddrinfo', side_effect=getaddrinfoIPv6): 
    r = urllib.request.urlopen('http://ip6.me') 
    print('ipv6: '+re.search(r'\+3>(.*?)</',r.read().decode('utf-8')).group(1)) 

with patch('socket.getaddrinfo', side_effect=getaddrinfoIPv4): 
    r = urllib.request.urlopen('http://ip6.me') 
    print('ipv4: '+re.search(r'\+3>(.*?)</',r.read().decode('utf-8')).group(1)) 

Testato 3.5.2

0

ho trovato una soluzione minimalista per forzare urrlib3 di utilizzare IPv4 o IPv6. Questo metodo è utilizzato da urrlib3 per creare una nuova connessione sia per Http che per Https. Puoi specificare qualsiasi AF_FAMILY che desideri utilizzare.

import socket 
import requests.packages.urllib3.util.connection as urllib3_cn 


    def allowed_gai_family(): 
    """ 
    https://github.com/shazow/urllib3/blob/master/urllib3/util/connection.py 
    """ 
    family = socket.AF_INET 
    if urllib3_cn.HAS_IPV6: 
     family = socket.AF_INET6 # force ipv6 only if it is available 
    return family 

urllib3_cn.allowed_gai_family = allowed_gai_family