A Django application to retrieve client's IP address
Best attempt to get client's IP address while keeping it DRY.
There is not a good out-of-the-box solution against fake IP addresses, aka IP Address Spoofing.
You are encouraged to read the (Advanced users) section of this page and
use trusted_proxies_ips
and/or proxy_count
features to match your needs, especially if you are
planning to include ipware
in any authentication, security or anti-fraud related architecture.
1. easy_install django-ipware
2. pip install django-ipware
3. git clone http://github.com/un33k/django-ipware
a. cd django-ipware
b. run python setup.py install
4. wget https://github.com/un33k/django-ipware/zipball/master
a. unzip the downloaded file
b. cd into django-ipware-* directory
c. run python setup.py install
# In a view or a middleware where the `request` object is available
from ipware import get_client_ip
client_ip, is_routable = get_client_ip(request)
if client_ip is None:
# Unable to get the client's IP address
else:
# We got the client's IP address
if is_routable:
# The client's IP address is publicly routable on the Internet
else:
# The client's IP address is private
# Order of precedence is (Public, Private, Loopback, None)
The default meta precedence order is top to bottom. However, you may customize the order
by providing your own IPWARE_META_PRECEDENCE_ORDER
by adding it to your project's settings.py
# The default meta precedence order
IPWARE_META_PRECEDENCE_ORDER = (
'HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR', # <client>, <proxy1>, <proxy2>
'HTTP_CLIENT_IP',
'HTTP_X_REAL_IP',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'HTTP_VIA',
'REMOTE_ADDR',
)
Alternatively, you can provide your custom request header meta precedence order when calling get_client_ip()
.
get_client_ip(request, request_header_order=['X_FORWARDED_FOR'])
get_client_ip(request, request_header_order=['X_FORWARDED_FOR', 'HTTP_X_FORWARDED_FOR'])
You may customize the prefixes to indicate an IP address is private. This is done by adding your
own IPWARE_PRIVATE_IP_PREFIX
to your project's settings.py. IP addresses matching the following
prefixes are considered private & are not publicly routable.
# The default private IP prefixes
IPWARE_PRIVATE_IP_PREFIX = getattr(settings,
'IPWARE_PRIVATE_IP_PREFIX', (
'0.', # messages to software
'10.', # class A private block
'100.64.', '100.65.', '100.66.', '100.67.', '100.68.', '100.69.',
'100.70.', '100.71.', '100.72.', '100.73.', '100.74.', '100.75.',
'100.76.', '100.77.', '100.78.', '100.79.', '100.80.', '100.81.',
'100.82.', '100.83.', '100.84.', '100.85.', '100.86.', '100.87.',
'100.88.', '100.89.', '100.90.', '100.91.', '100.92.', '100.93.',
'100.94.', '100.95.', '100.96.', '100.97.', '100.98.', '100.99.',
'100.100.', '100.101.', '100.102.', '100.103.', '100.104.', '100.105.',
'100.106.', '100.107.', '100.108.', '100.109.', '100.110.', '100.111.',
'100.112.', '100.113.', '100.114.', '100.115.', '100.116.', '100.117.',
'100.118.', '100.119.', '100.120.', '100.121.', '100.122.', '100.123.',
'100.124.', '100.125.', '100.126.', '100.127.', # carrier-grade NAT
'169.254.', # link-local block
'172.16.', '172.17.', '172.18.', '172.19.',
'172.20.', '172.21.', '172.22.', '172.23.',
'172.24.', '172.25.', '172.26.', '172.27.',
'172.28.', '172.29.', '172.30.', '172.31.', # class B private blocks
'192.0.0.', # reserved for IANA special purpose address registry
'192.0.2.', # reserved for documentation and example code
'192.168.', # class C private block
'198.18.', '198.19.', # reserved for inter-network communications between two separate subnets
'198.51.100.', # reserved for documentation and example code
'203.0.113.', # reserved for documentation and example code
'224.', '225.', '226.', '227.', '228.', '229.', '230.', '231.', '232.',
'233.', '234.', '235.', '236.', '237.', '238.', '239.', # multicast
'240.', '241.', '242.', '243.', '244.', '245.', '246.', '247.', '248.',
'249.', '250.', '251.', '252.', '253.', '254.', '255.', # reserved
) + (
'::', # Unspecified address
'::ffff:', '2001:10:', '2001:20:' # messages to software
'2001::', # TEREDO
'2001:2::', # benchmarking
'2001:db8:', # reserved for documentation and example code
'fc00:', # IPv6 private block
'fe80:', # link-local unicast
'ff00:', # IPv6 multicast
)
)
If your Django server is behind one or more known proxy server(s), you can filter out unwanted requests by providing the list of trusted proxy IP addresses.
In the following example, your load balancer (LB) can be seen as a trusted
proxy.
`Real` Client <public> <---> <public> LB (Server) <private> <--------> <private> Django Server
^
|
`Fake` Client <private> <---> <private> LB (Server) <private> ---^
You can tell django-ipware
about the trusted proxy (or proxies) by
adding them to your project's settings.py
:
# In the above scenario, use your load balancer's IP address as a way to filter out unwanted requests.
IPWARE_PROXY_TRUSTED_IPS = [
'177.139.233.133',
'177.139.233.134',
]
Alternatively, you can provide your custom trusted proxy ip whitelist when calling get_client_ip()
:
client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.133'])
# If you have multiple proxies, simply add them to the list
client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.133', '177.139.233.134'])
# For proxy servers with fixed sub-domain and dynamic IP, use the following pattern.
client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.', '177.140'])
client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.', '177.139.240'])
If proxy_trusted_ips
is passed to get_client_ip
, that list will be
used. Otherwise, if it's not supplied or None
,
IPWARE_PROXY_TRUSTED_IPS
is used as a fallback. This can also be
None
if you wish to trust the information supplied in the headers
fully, or if you only use the proxy count (see below).
If your Django server is behind a known number of proxy server(s), you can filter out unwanted requests by providing the number of proxies. In the following example, your load balancer (LB) can be seen as the only proxy.
`Real` Client <public> <---> <public> LB (Server) <private> <--------> <private> Django Server
^
|
`Fake` Client <private> ---^
# In the above scenario, the total number of proxies can be used as a way to filter out unwanted requests.
IPWARE_PROXY_COUNT=1
Alternatively, you can provide your custom trusted proxy count when calling get_client_ip()
:
client_ip, is_routable = get_client_ip(request, proxy_count=1)
# The above may be very useful in cases where your proxy server's IP address is assigned dynamically.
# However, If you have the proxy IP address, you can use it in combination to the proxy count.
client_ip, is_routable = get_client_ip(request, proxy_count=1, proxy_trusted_ips=['177.139.233.133'])
If proxy_count
is passed to get_client_ip
, that will be used.
Otherwise, if it's not supplied or None
, IPWARE_PROXY_COUNT
is
used as a fallback. This can also be None
if you do not wish to use
a fixed count.
If your proxy server is configured such that the right-most IP address is that of the originating client, you
can indicate right-most
as the proxy order in your project's settings.py
:
# In the above scenario, the total number of proxies can be used as a way to filter out unwanted requests.
IPWARE_PROXY_ORDER='right-most'
Alternatively, you can provide your custom proxy order when calling get_client_ip()
:
client_ip, is_routable = get_client_ip(request, proxy_order='right-most')
If proxy_order
is passed to get_client_ip
, that will be used.
Otherwise, if it's not supplied or None
, IPWARE_PROXY_ORDER
is
used as a fallback. This can also be None
if you want to use the
default (which is left-most
).
Please note that the de-facto standard
for the originating client IP address is the left-most
as per <client>, <proxy1>, <proxy2>
.
To run the tests against the current environment:
python manage.py test
Released under a (MIT) license.
X.Y.Z Version
`MAJOR` version -- when you make incompatible API changes,
`MINOR` version -- when you add functionality in a backwards-compatible manner, and
`PATCH` version -- when you make backwards-compatible bug fixes.