Send http request through specific network interface
I found a way using pycurl
. This works like a charm.
import pycurl
from io import BytesIO
import json
def curl_post(url, data, iface=None):
c = pycurl.Curl()
buffer = BytesIO()
c.setopt(pycurl.URL, url)
c.setopt(pycurl.POST, True)
c.setopt(pycurl.HTTPHEADER, ['Content-Type: application/json'])
c.setopt(pycurl.TIMEOUT, 10)
c.setopt(pycurl.WRITEFUNCTION, buffer.write)
c.setopt(pycurl.POSTFIELDS, data)
if iface:
c.setopt(pycurl.INTERFACE, iface)
c.perform()
# Json response
resp = buffer.getvalue().decode('UTF-8')
# Check response is a JSON if not there was an error
try:
resp = json.loads(resp)
except json.decoder.JSONDecodeError:
pass
buffer.close()
c.close()
return resp
if __name__ == '__main__':
dat = {"id": 52, "configuration": [{"eno1": {"address": "192.168.1.1"}}]}
res = curl_post("http://127.0.0.1:5000/network_configuration/", json.dumps(dat), "wlp2")
print(res)
I'm leaving the question opened hopping that someone can give an answer using requests
.
Python requests, change IP address
As already mentioned in the comments and from yourself, changing the IP could help. To do this quite easily have a look at vpngate.py:
https://gist.github.com/Lazza/bbc15561b65c16db8ca8
An How to is provided at the link.
Python Requests - Use navigate site by servers IP
You will have to set a custom header host
with value of example.com
, something like:
requests.get('http://127.0.0.1/foo.php', headers={'host': 'example.com'})
should do the trick. If you want to verify that then type in the following command (requires netcat): nc -l -p 80
and then run the above command. It will produce output in the netcat window:
GET /foo.php HTTP/1.1
Host: example.com
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.6.2 CPython/3.4.3 Windows/8
How do I get the IP address from a http request using the requests library?
It turns out that it's rather involved.
Here's a monkey-patch while using requests
version 1.2.3:
Wrapping the _make_request
method on HTTPConnectionPool
to store the response from socket.getpeername()
on the HTTPResponse
instance.
For me on python 2.7.3, this instance was available on response.raw._original_response
.
from requests.packages.urllib3.connectionpool import HTTPConnectionPool
def _make_request(self,conn,method,url,**kwargs):
response = self._old_make_request(conn,method,url,**kwargs)
sock = getattr(conn,'sock',False)
if sock:
setattr(response,'peer',sock.getpeername())
else:
setattr(response,'peer',None)
return response
HTTPConnectionPool._old_make_request = HTTPConnectionPool._make_request
HTTPConnectionPool._make_request = _make_request
import requests
r = requests.get('http://www.google.com')
print r.raw._original_response.peer
Yields:
('2a00:1450:4009:809::1017', 80, 0, 0)
Ah, if there's a proxy involved or the response is chunked, the HTTPConnectionPool._make_request
isn't called.
So here's a new version patching httplib.getresponse
instead:
import httplib
def getresponse(self,*args,**kwargs):
response = self._old_getresponse(*args,**kwargs)
if self.sock:
response.peer = self.sock.getpeername()
else:
response.peer = None
return response
httplib.HTTPConnection._old_getresponse = httplib.HTTPConnection.getresponse
httplib.HTTPConnection.getresponse = getresponse
import requests
def check_peer(resp):
orig_resp = resp.raw._original_response
if hasattr(orig_resp,'peer'):
return getattr(orig_resp,'peer')
Running:
>>> r1 = requests.get('http://www.google.com')
>>> check_peer(r1)
('2a00:1450:4009:808::101f', 80, 0, 0)
>>> r2 = requests.get('https://www.google.com')
>>> check_peer(r2)
('2a00:1450:4009:808::101f', 443, 0, 0)
>>> r3 = requests.get('http://wheezyweb.readthedocs.org/en/latest/tutorial.html#what-you-ll-build')
>>> check_peer(r3)
('162.209.99.68', 80)
Also checked running with proxies set; proxy address is returned.
Update 2016/01/19
est offers an alternative that doesn't need the monkey-patch:
rsp = requests.get('http://google.com', stream=True)
# grab the IP while you can, before you consume the body!!!!!!!!
print rsp.raw._fp.fp._sock.getpeername()
# consume the body, which calls the read(), after that fileno is no longer available.
print rsp.content
Update 2016/05/19
From the comments, copying here for visibility, Richard Kenneth Niescior offers the following that is confirmed working with requests 2.10.0 and Python 3.
rsp=requests.get(..., stream=True)
rsp.raw._connection.sock.getpeername()
Update 2019/02/22
Python3 with requests version 2.19.1.
resp=requests.get(..., stream=True)
resp.raw._connection.sock.socket.getsockname()
Update 2020/01/31
Python3.8 with requests 2.22.0
resp = requests.get('https://www.google.com', stream=True)
resp.raw._connection.sock.getsockname()
Node js bind request to different interface or IP address
I had the same requirement and it turns out it's really easy to do. Just use the localAddress
option in request
(it's the same option as in the http
module):
(async () => {
let request = require('request-promise-native'); // (a promisified version of request module)
// This prints your machine's IP
console.log( await request({ uri: 'https://api.ipify.org' }) );
// This prints '***.***.***.***'
console.log( await request({ uri: 'https://api.ipify.org', localAddress: '***.***.***.***' }) );
})();
(Replace ***.***.***.***
with your new static IP)
Note that you will of course need to have already set up your static IP and have configured it in your OS. In case it helps anyone, with Ubuntu 16.04 you'd just add this to the end of your /etc/network/interfaces
file:
auto ens3:0
iface ens3:0 inet static
address ***.***.***.***
netmask 255.255.254.0
(Again, replace ***.***.***.***
with your IP) More details here.
Related Topics
Nltk-Based Text Processing with Pandas
How Does My Input Not Equal the Answer
How to Copy Inmemoryuploadedfile Object to Disk
Can't Open Lib 'Odbc Driver 13 for SQL Server'? Sym Linking Issue
How to Find the First Key in a Dictionary
Sampling Uniformly Distributed Random Points Inside a Spherical Volume
Tkinter Grid_Forget Is Clearing the Frame
Browse Files and Subfolders in Python
How to Change the String Representation of a Python Class
How to Improve My Paw Detection
Django Template Can't Loop Defaultdict
Printing a List of Objects of User Defined Class