【发布时间】:2017-11-15 20:23:34
【问题描述】:
问题
我需要在请求之前检查来自 URL 的域是否未指向私有 IP,并返回用于 HTTP 连接的 IP。
这是我的测试脚本:
import ipaddress
import requests
import socket
import sys
from urllib.parse import urlparse
def get_ip(url):
hostname = socket.gethostbyname(urlparse(url).hostname)
print('IP: {}'.format(hostname))
if hostname:
return ipaddress.IPv4Address(hostname).is_private
def get_req(url):
private_ip = get_ip(url)
if not private_ip:
try:
with requests.Session() as s:
s.max_redirects = 5
r = s.get(url, timeout=5, stream=True)
return {'url': url, 'staus_code': r.status_code}
except requests.exceptions.RequestException:
return 'ERROR'
return 'Private IP'
if __name__ == '__main__':
print(get_req(sys.argv[1]))
如果域正在解析多个 IP,这将不起作用,例如,如果网站托管在 CloudFlare 后面:
# python test.py http://example.com
IP: 104.31.65.106
{'staus_code': 200, 'url': 'http://exmaple.com'}
来自 tcpdump 的 sn-p:
22:21:51.833221 IP 1.2.3.4.54786 > 104.31.64.106.80: Flags [S], seq 902413592, win 29200, options [mss 1460,sackOK,TS val 252001723 ecr 0,nop,wscale 7], length 0
22:21:51.835313 IP 104.31.64.106.80 > 1.2.3.4.54786: Flags [S.], seq 2314392251, ack 902413593, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 10], length 0
22:21:51.835373 IP 1.2.3.4.54786 > 104.31.64.106.80: Flags [.], ack 1, win 229, length 0
脚本在104.31.65.106 上对其进行了测试,但在104.31.64.106 上建立了 HTTP 连接
我看到了this 线程,但我不会使用响应正文,所以the connection won't be released 实际上我的请求模块版本没有这些属性。
有没有办法通过requests 模块实现这一点,还是我必须使用另一个库,如urllib 或urliib3?
澄清一下:我只需要在尝试连接到专用网络地址时阻止该请求。如果有多个选项并且选择了一个公共地址,那很好。
【问题讨论】:
-
为什么
rsp=requests.get(..., stream=True);rsp.raw._connection.sock.getpeername()不适合你? -
好的,所以我刚刚测试了它,我想我可以在 try/except 块中关闭连接,但看起来流只有在服务器启用了 keep-alive 时才有效,否则连接会立即关闭,我得到
AttributeError: 'NoneType' object has no attribute 'getpeername'。我还想在发出请求之前检查 IP。 -
为什么所有的恶作剧都是
with requests.Session() as s然后s = requests.Session()?这只是替换了您配置的会话,删除s = ...行。 -
@MartijnPieters 我相信这是测试留下的,我刚刚删除了它。
-
如果主机名可以解析为公共地址或私有地址,您想阻止该请求吗?或者仅当当前选择的 IP 地址不是公共地址时?