2015-10-09 18 views
5

Làm cách nào để buộc thư viện requests sử dụng phiên bản giao thức internet cụ thể để nhận yêu cầu? Hoặc điều này có thể đạt được tốt hơn với một phương pháp khác trong Python? Tôi có thể nhưng tôi không muốn sử dụng curl ...Yêu cầu lực lượng sử dụng IPv4/IPv6

Ví dụ để làm rõ mục đích:

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

Trả lời

1

này là hoàn toàn chưa được kiểm tra và có lẽ sẽ yêu cầu một số tinh chỉnh, nhưng kết hợp câu trả lời từ Using Python “requests” with existing socket connectionhow to force python httplib library to use only A requests, có vẻ như bạn sẽ có thể tạo ra một chỉ ổ cắm IPv6 và sau đó có yêu cầu sử dụng cho hồ bơi kết nối của nó với một cái gì đó như:

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

Rất tiếc, tôi vẫn nhận được câu trả lời IPv4. Tôi đã thử 'print (requests.get ('https://icanhazip.com') .text)'. – ominug

+0

Thật không may, tôi không có quyền truy cập vào bất kỳ điều gì với ipv6 tại thời điểm này; Tôi đã thêm một tuyên bố in và một tuyên bố kết nối chỉ để đảm bảo rằng tôi đã không bỏ lỡ một cái gì đó với cách một đi về monkeypatching đối tượng HTTPConnection – Foon

+0

Ok, tôi đã thử nó một lần nữa. Phương thức kết nối không được gọi. – ominug

1

Sau khi đọc câu trả lời trước, tôi đã phải thay đổi mã để buộc IPv4 thay vì IPv6. Lưu ý rằng tôi đã sử dụng socket.AF_INET thay vì socket.AF_INET6 và self.sock.connect() có đối số tuple 2-item.

tôi cũng cần phải ghi đè lên các HTTP S kết nối đó là chênh lệch nhiều so với HttpConnection từ requests kết thúc tốt đẹp httplib.HTTPSConnection để xác minh giấy chứng nhận nếu module ssl có sẵn.

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

Câu trả lời này làm việc cho tôi, với báo trước rằng nó kết quả trong 'InsecureRequestWarning: Yêu cầu HTTPS chưa được xác minh đang được thực hiện. Thêm xác minh chứng chỉ được khuyến khích mạnh mẽ. Xem: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestCảnh báo 'khi chạy trên https – kyrenia

0

tôi sử dụng phương pháp tương tự như https://stackoverflow.com/a/33046939/5059062, nhưng thay vì vá ra một phần trong socket mà làm cho các yêu cầu DNS để nó chỉ không IPv6 hoặc IPv4, cho mỗi yêu cầu, có nghĩa là điều này có thể được sử dụng trong urllib cũng hiệu quả như trong requests.

Điều này có thể không tốt nếu chương trình của bạn cũng sử dụng các đường ống unix và những thứ khác, vì vậy tôi đôn đốc thận trọng với 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)) 

và không 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)) 

Tested trong 3.5.2

0

Tôi đã tìm thấy một giải pháp tối giản để buộc urrlib3 sử dụng hoặc IPv4 hoặc IPv6. Phương pháp này được sử dụng bởi urrlib3 để tạo kết nối mới cho cả Http và Https. Bạn có thể chỉ định trong đó bất kỳ AF_FAMILY nào bạn muốn sử dụng.

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 
Các vấn đề liên quan