Requests, Bind to an Ip

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



Leave a reply



Submit