diff --git a/rest_framework_tracking/base_mixins.py b/rest_framework_tracking/base_mixins.py index a4725a5..0ab2a4e 100644 --- a/rest_framework_tracking/base_mixins.py +++ b/rest_framework_tracking/base_mixins.py @@ -111,11 +111,8 @@ def _get_path(self, request): def _get_ip_address(self, request): """Get the remote ip address the request was generated from.""" - ipaddr = request.META.get("HTTP_X_FORWARDED_FOR", None) - if ipaddr: - ipaddr = ipaddr.split(",")[0] - else: - ipaddr = request.META.get("REMOTE_ADDR", "").split(",")[0] + raw_possibles = request.META.get("HTTP_X_FORWARDED_FOR", "").split(",") + raw_possibles += request.META.get("REMOTE_ADDR", "").split(",") # Account for IPv4 and IPv6 addresses, each possibly with port appended. Possibilities are: # @@ -123,15 +120,25 @@ def _get_ip_address(self, request): # :port # []:port # Note that ipv6 addresses are colon separated hex numbers - possibles = (ipaddr.lstrip("[").split("]")[0], ipaddr.split(":")[0]) - + raw_possibles = [addr.strip() for addr in raw_possibles] + possibles = [] + for possible_addr in raw_possibles: + if '[' in possible_addr: + # IPv6 with port + possibles.append(possible_addr.rsplit(":", 1)[0].strip("[]")) + elif possible_addr.count(":") == 1: + # IPv4 with port + possibles.append(possible_addr.split(":")[0]) + else: + # IPv4/IPv6 without port and others + possibles.append(possible_addr) for addr in possibles: try: return str(ipaddress.ip_address(addr)) except ValueError: pass - return ipaddr + return raw_possibles[0] def _get_view_name(self, request): """Get view name.""" diff --git a/tests/test_mixins.py b/tests/test_mixins.py index a9eb79f..7dbb9e1 100644 --- a/tests/test_mixins.py +++ b/tests/test_mixins.py @@ -105,6 +105,14 @@ def test_log_ip_xforwarded_list(self): log = APIRequestLog.objects.first() self.assertEqual(log.remote_addr, "127.0.0.8") + def test_log_ip_xforwarded_list_with_unknown_ip(self): + request = APIRequestFactory().get("/logging") + request.META["HTTP_X_FORWARDED_FOR"] = "unknown, 128.1.1.9" + + MockLoggingView.as_view()(request).render() + log = APIRequestLog.objects.first() + self.assertEqual(log.remote_addr, "128.1.1.9") + def test_log_host(self): self.client.get("/logging") log = APIRequestLog.objects.first() diff --git a/tox.ini b/tox.ini index c171b37..9a2a23c 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ tox_pyenv_fallback = True commands = python -V pip install --upgrade pip pipenv pipenv install --skip-lock - ./runtests.py --fast + python runtests.py --fast passenv = DATABASE_URL PYTHON_VERSION