Skip to content

Commit

Permalink
Proxy filters, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
un33k committed Aug 19, 2021
2 parents eb4663e + 8dc6551 commit 8013363
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 14 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 4.0.0

Enhancement:

- Added test to cover more proxy scenarios (thx: Phillip Kuhrt)
- Up versioned major version number as some scenarios have changed

## 3.0.4 / 3.0.5 / 3.0.6 / 3.0.7

Enhancement:
Expand Down
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

# Notice

There is not a good _out-of-the-box_ solution against fake IP addresses, aka _IP Address Spoofing_.
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](README.md#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.
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.

# How to install

Expand Down Expand Up @@ -153,11 +153,15 @@ client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.', '
client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.', '177.139.240'])
```

`Please note:` By default, the `right-most` proxy in the chain is the `trusted` proxy and that is the one your django
server talks to. Therefore, `ipware` checks to see if the `right-most` proxy address starts with any ip pattern that was
passed in via the `proxy_trusted_ips` list.

### Proxy Count

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 when calling `get_client_ip(request, proxy_count=1)`.
In the following example, your load balancer (LB) can be seen as the _only_ proxy.
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 when calling `get_client_ip(request, proxy_count=1)`.
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
Expand Down
2 changes: 1 addition & 1 deletion ipware/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
__url__ = 'https://github.com/un33k/django-ipware'
__license__ = 'MIT'
__copyright__ = 'Copyright 2020 Val Neekman @ Neekware Inc.'
__version__ = '3.0.7'
__version__ = '4.0.0'
3 changes: 2 additions & 1 deletion ipware/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ def get_client_ip(

if proxy_trusted_ips:
for proxy in proxy_trusted_ips:
if proxy in ips[-1]:
# right most proxy is the most reliable proxy that talks to the django server
if ips[-1].startswith(proxy):
client_ip, routable = util.get_ip_info(ips[0])
if client_ip and routable:
return client_ip, routable
Expand Down
37 changes: 35 additions & 2 deletions ipware/tests/tests_ipv4.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,38 @@ def test_meta_singleton_private_fallback(self):
result = get_client_ip(request)
self.assertEqual(result, ("177.139.233.139", True))

def test_meta_proxy_trusted_ips(self):
def test_meta_proxy_trusted_ips_exact_ip_check(self):
request = HttpRequest()
request.META = {
'HTTP_X_FORWARDED_FOR': '177.139.233.139, 198.84.193.157, 198.84.193.158',
}
result = get_client_ip(request, proxy_trusted_ips=['198.84.193.158'])
self.assertEqual(result, ("177.139.233.139", True))

def test_meta_proxy_trusted_ips_exact_ips_check(self):
request = HttpRequest()
request.META = {
'HTTP_X_FORWARDED_FOR': '177.139.233.139, 198.84.193.157, 198.84.193.158',
}
result = get_client_ip(request, proxy_trusted_ips=['198.84.193.157', '198.84.193.158'])
self.assertEqual(result, ("177.139.233.139", True))

def test_meta_proxy_trusted_ips_subnet_start_with_check(self):
request = HttpRequest()
request.META = {
'HTTP_X_FORWARDED_FOR': '177.139.233.139, 198.84.193.157, 198.84.193.158',
}
result = get_client_ip(request, proxy_trusted_ips=['198.84.193'])
self.assertEqual(result, ("177.139.233.139", True))

def test_meta_proxy_trusted_ips_does_not_start_with_check(self):
request = HttpRequest()
request.META = {
'HTTP_X_FORWARDED_FOR': '177.139.233.139, 198.84.193.157, 198.84.193.158',
}
result = get_client_ip(request, proxy_trusted_ips=['84.193.158'])
self.assertEqual(result, (None, False))

def test_meta_proxy_trusted_ips_proxy_count(self):
request = HttpRequest()
request.META = {
Expand Down Expand Up @@ -197,7 +221,7 @@ def test_best_matched_ip_private(self):
ip = get_client_ip(request)
self.assertEqual(ip, ("192.168.1.1", False))

def test_best_matched_ip_private_precedence(self):
def test_best_matched_ip_private_loopback_precedence(self):
request = HttpRequest()
request.META = {
'HTTP_X_REAL_IP': '127.0.0.1',
Expand All @@ -206,6 +230,15 @@ def test_best_matched_ip_private_precedence(self):
ip = get_client_ip(request)
self.assertEqual(ip, ("192.168.1.1", False))

def test_best_matched_ip_private_precedence(self):
request = HttpRequest()
request.META = {
'HTTP_X_FORWARDED_FOR': '172.25.0.1',
'REMOTE_ADDR': '172.25.0.3',
}
ip = get_client_ip(request)
self.assertEqual(ip, ("172.25.0.3", False))

def test_100_low_range_public(self):
request = HttpRequest()
request.META = {
Expand Down
3 changes: 0 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
[bdist_wheel]
universal = 1

[metadata]
license_file = LICENSE
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python
# Learn more: https://github.com/kennethreitz/setup.py
# Learn more: https://github.com/un33k/setup.py
import os
import sys

Expand Down

0 comments on commit 8013363

Please sign in to comment.