The problem
I need to check if domain from URL is not pointing to a private IP before request and also return IP that was used for HTTP connection.
This is my test script:
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]))
This won't work if domain is resolving to multiply IPs, for instance if website is hosted behind CloudFlare:
# python test.py http://example.com
IP: 104.31.65.106
{'staus_code': 200, 'url': 'http://exmaple.com'}
A snippet from tcpdump:
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
The script tested it on 104.31.65.106
but HTTP connection was made on 104.31.64.106
I saw this thread but I won't be consuming the response body so the connection won't be released and actually my version of requests module doesn't have these attributes.
Is there a way to achive this with requests
module or do I have to use another library like urllib
or urliib3
?
To clarify: I only need to prevent the request if an attempt would be made to connect to a private network address. If there are multiple options and a public address is picked, it's fine.