Repository: getsentry/sentry

Issue:
Audit log crash on IPv6
Affected version: 8.5.0

I was just saving some preferences and faced this error:

```
DataError: ERREUR:  syntaxe en entrée invalide pour le type inet : « 2001 »
LINE 1: ...oursenaud@gpcsolutions.fr', 2, NULL, 1, NULL, 11, '2001', 'e...
                                                             ^

SQL: INSERT INTO "sentry_auditlogentry" ("organization_id", "actor_label", "actor_id", "actor_key_id", "target_object", "target_user_id", "event", "ip_address", "data", "datetime") VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING "sentry_auditlogentry"."id"
```

Looks like IPv6 addresses are not handled properly.

Also reproduced by deleting a project.
Oddly this wasn't triggered on project creation and my IPv4 was logged instead of my IPv6.



Discussion:
I think there's something else going on here. The column in the database is typed `inet` which would cover both ipv4 and ipv6. But somehow you're getting the value `2001`.

It seems that we're messing up parsing this in the `SetRemoteAddrFromForwardedFor` middleware.

/cc @JTCunning wanna take a look at this?

Seems we would have regressed here: https://github.com/getsentry/sentry/pull/3239

Yes, looks like it.
2001 is the first part of my IPv6 address `2001:470:[something]`(I use a Hurricane Electric tunnel).

@rdoursenaud: Thanks for pointing this out. The fix is pretty simple, and I'll whip up some tests to make sure that we aren't blindly separating IPs.

@JTCunning Great!
Thank YOU all @getsentry for the awesome work :)


Resolving patch:
diff --git a/src/sentry/middleware/proxy.py b/src/sentry/middleware/proxy.py
--- a/src/sentry/middleware/proxy.py
+++ b/src/sentry/middleware/proxy.py
@@ -11,7 +11,8 @@ def process_request(self, request):
             # HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs.
             # Take just the first one.
             real_ip = real_ip.split(",")[0]
-            if ':' in real_ip:
+            if ':' in real_ip and '.' in real_ip:
+                # Strip the port number off of an IPv4 FORWARDED_FOR entry.
                 real_ip = real_ip.split(':', 1)[0]
             request.META['REMOTE_ADDR'] = real_ip
 


Test patch:
diff --git a/tests/sentry/middleware/test_proxy.py b/tests/sentry/middleware/test_proxy.py
--- a/tests/sentry/middleware/test_proxy.py
+++ b/tests/sentry/middleware/test_proxy.py
@@ -1,10 +1,11 @@
 from __future__ import absolute_import
 
 from exam import fixture
-from django.http import HttpResponse, StreamingHttpResponse
+from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
 
 from sentry.testutils import TestCase
-from sentry.middleware.proxy import ContentLengthHeaderMiddleware
+from sentry.middleware.proxy import (
+    ContentLengthHeaderMiddleware, SetRemoteAddrFromForwardedFor)
 
 
 class ContentLengthHeaderMiddlewareTest(TestCase):
@@ -19,3 +20,19 @@ def test_streaming(self):
         response = self.middleware.process_response(None, StreamingHttpResponse())
         assert 'Transfer-Encoding' not in response
         assert 'Content-Length' not in response
+
+
+class SetRemoteAddrFromForwardedForTestCase(TestCase):
+    middleware = fixture(SetRemoteAddrFromForwardedFor)
+
+    def test_ipv4(self):
+        request = HttpRequest()
+        request.META['HTTP_X_FORWARDED_FOR'] = '8.8.8.8:80,8.8.4.4'
+        self.middleware.process_request(request)
+        assert request.META['REMOTE_ADDR'] == '8.8.8.8'
+
+    def test_ipv6(self):
+        request = HttpRequest()
+        request.META['HTTP_X_FORWARDED_FOR'] = '2001:4860:4860::8888,2001:4860:4860::8844'
+        self.middleware.process_request(request)
+        assert request.META['REMOTE_ADDR'] == '2001:4860:4860::8888'