[base] Fix hierarchical duplicate IP validation #116#202
Conversation
Updates AbstractIpAddress.clean() to check for duplicate IP addresses not only within the same subnet but also across any subnet that contains the IP (parent, or child). Added a corresponding test to ensure a ValidationError is raised when an IP exists in any related subnet. Fixes openwisp#116
nemesifier
left a comment
There was a problem hiding this comment.
Thanks @Stoiicc for tackling #116. The intent is right: an IP that exists in a child subnet should not be addable again in an overlapping parent subnet. But the implementation has a correctness bug and a serious performance problem, so it cannot merge as-is.
1. It ignores organization scoping (cross-tenant false conflicts)
for subnet in load_model("openwisp_ipam", "Subnet").objects.all():
...
duplicate = IpAddress.objects.filter(
ip_address=self.ip_address, subnet_id__in=related_subnet_ids
).exclude(pk=self.pk).exists()This scans every subnet in the database regardless of organization. So 10.0.1.10 in organization A's subnet would conflict with 10.0.1.10 in organization B's overlapping subnet, even though they are independent tenants. That breaks multi-tenant isolation. The check must be scoped to the relevant organization, consistently with how the rest of openwisp-ipam handles org scoping.
2. Full table scan in Python on every save
Subnet.objects.all() loads every subnet into Python and runs ip_network(...) per row on every IpAddress.clean(). On any non-trivial IPAM this is very slow. Please push the work into the database: filter candidate subnets by org and ideally test containment with a query, or at minimum restrict the loop to the small set of subnets that could plausibly contain this IP.
3. Test and style
tests/test_hierarchy_validation.py imports the concrete models directly rather than using load_model, has no trailing newline, inconsistent spacing, and calls both full_clean() and save() inside assertRaises (the save is unreachable). Please align it with the existing test style and cover the cross-org case explicitly (same IP in two different orgs must be allowed).
Correct goal, but fix the organization scoping (this is a blocker), make the lookup a bounded DB query, and clean up the test.
Checklist
Reference to Existing Issue
Closes #116 .
Description of Changes
Previously, AbstractIpAddress.clean() only checked for duplicate IP addresses within the same subnet.
As discussed in issue #116, this allows invalid configurations where:
An IP exists in a child subnet, and
The same IP is created again in a parent subnet.
This PR introduces hierarchical subnet duplicate detection by:
Identifying all related subnets
A subnet is considered related if its network contains the IP being validated.
This includes:
If the same IP exists in any related subnet, a ValidationError is raised.