Bläddra i källkod

Fixes #21196: `q` filter should match on primary IP only for IP address values (#21401)

Jeremy Stretch 3 veckor sedan
förälder
incheckning
76fd3e3c61
2 ändrade filer med 28 tillägg och 8 borttagningar
  1. 15 5
      netbox/dcim/filtersets.py
  2. 13 3
      netbox/virtualization/filtersets.py

+ 15 - 5
netbox/dcim/filtersets.py

@@ -1,8 +1,10 @@
 import django_filters
+import netaddr
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import gettext as _
 from drf_spectacular.types import OpenApiTypes
 from drf_spectacular.utils import extend_schema_field
+from netaddr.core import AddrFormatError
 
 from circuits.models import CircuitTermination, VirtualCircuit, VirtualCircuitTermination
 from extras.filtersets import LocalConfigContextFilterSet
@@ -1329,16 +1331,24 @@ class DeviceFilterSet(
     def search(self, queryset, name, value):
         if not value.strip():
             return queryset
-        return queryset.filter(
+        qs_filter = (
             Q(name__icontains=value) |
             Q(virtual_chassis__name__icontains=value) |
             Q(serial__icontains=value.strip()) |
             Q(asset_tag__icontains=value.strip()) |
             Q(description__icontains=value.strip()) |
-            Q(comments__icontains=value) |
-            Q(primary_ip4__address__startswith=value) |
-            Q(primary_ip6__address__startswith=value)
-        ).distinct()
+            Q(comments__icontains=value)
+        )
+        # If the given value looks like an IP address, look for primary IPv4/IPv6 assignments
+        try:
+            ipaddress = netaddr.IPNetwork(value)
+            if ipaddress.version == 4:
+                qs_filter |= Q(primary_ip4__address__host__inet=ipaddress.ip)
+            elif ipaddress.version == 6:
+                qs_filter |= Q(primary_ip6__address__host__inet=ipaddress.ip)
+        except (AddrFormatError, ValueError):
+            pass
+        return queryset.filter(qs_filter)
 
     def _has_primary_ip(self, queryset, name, value):
         params = Q(primary_ip4__isnull=False) | Q(primary_ip6__isnull=False)

+ 13 - 3
netbox/virtualization/filtersets.py

@@ -1,6 +1,8 @@
 import django_filters
+import netaddr
 from django.db.models import Q
 from django.utils.translation import gettext as _
+from netaddr.core import AddrFormatError
 
 from dcim.base_filtersets import ScopedFilterSet
 from dcim.filtersets import CommonInterfaceFilterSet
@@ -229,14 +231,22 @@ class VirtualMachineFilterSet(
     def search(self, queryset, name, value):
         if not value.strip():
             return queryset
-        return queryset.filter(
+        qs_filter = Q(
             Q(name__icontains=value) |
             Q(description__icontains=value) |
             Q(comments__icontains=value) |
-            Q(primary_ip4__address__startswith=value) |
-            Q(primary_ip6__address__startswith=value) |
             Q(serial__icontains=value)
         )
+        # If the given value looks like an IP address, look for primary IPv4/IPv6 assignments
+        try:
+            ipaddress = netaddr.IPNetwork(value)
+            if ipaddress.version == 4:
+                qs_filter |= Q(primary_ip4__address__host__inet=ipaddress.ip)
+            elif ipaddress.version == 6:
+                qs_filter |= Q(primary_ip6__address__host__inet=ipaddress.ip)
+        except (AddrFormatError, ValueError):
+            pass
+        return queryset.filter(qs_filter)
 
     def _has_primary_ip(self, queryset, name, value):
         params = Q(primary_ip4__isnull=False) | Q(primary_ip6__isnull=False)