Skip to content

Commit

Permalink
[bug] Prevent IPv4 subnet creation from IPv6 master subnet #154
Browse files Browse the repository at this point in the history
Added validation to restrict creating an IPv4 subnet under an IPv6 master subnet. Now, the UI displays an appropriate error message instead of a server error.

Fixes #154
  • Loading branch information
dee077 committed Jan 16, 2025
1 parent 49e1671 commit 3680f74
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 9 deletions.
12 changes: 12 additions & 0 deletions openwisp_ipam/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ def _validate_overlapping_subnets(self):
def _validate_master_subnet_consistency(self):
if not self.master_subnet:
return
subnet_version = ip_network(self.subnet).version
master_subnet_version = ip_network(self.master_subnet.subnet).version
if subnet_version != master_subnet_version:
raise ValidationError(
{
'master_subnet': _(
f'IP version mismatch: Subnet {self.subnet} is IPv'
f'{subnet_version}, but Master Subnet '
f'{self.master_subnet.subnet} is IPv{master_subnet_version}.'
)
}
)
if not ip_network(self.subnet).subnet_of(ip_network(self.master_subnet.subnet)):
raise ValidationError({'master_subnet': _('Invalid master subnet.')})

Expand Down
30 changes: 21 additions & 9 deletions openwisp_ipam/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import csv
from io import StringIO
from ipaddress import IPv4Network, IPv6Network
from ipaddress import IPv4Network, IPv6Network, ip_network

from django.core.exceptions import ValidationError
from django.test import TestCase
Expand Down Expand Up @@ -336,15 +336,27 @@ def test_retrieves_ipv6_ipnetwork_type(self):
self.assertIsInstance(instance.subnet, IPv6Network)

def test_incompatible_ipadresses(self):
instance = self._create_subnet(subnet='10.1.2.0/24')
try:
self._create_subnet(subnet='2001:db8::0/32', master_subnet=instance)
except TypeError as err:
self.assertEqual(
str(err), '2001:db8::/32 and 10.1.2.0/24 are not of the same version'
org = self._create_org(name='org', slug='org')
master = self._create_subnet(
name='IPv6', organization=org, subnet='2001:db8:85a3::64/128'
)
subnet_ip = '192.166.45.0/24'
with self.assertRaises(ValidationError) as context_manager:
self._create_subnet(
name='IPv4',
organization=org,
subnet=subnet_ip,
master_subnet=master,
)
else:
self.fail('TypeError not raised')
message_dict = context_manager.exception.message_dict
master_version = ip_network(master.subnet).version
subnet_version = ip_network(subnet_ip).version
error_message = (
f'IP version mismatch: Subnet {subnet_ip} is IPv{subnet_version}, '
f'but Master Subnet {master.subnet} is IPv{master_version}.'
)
self.assertIn('master_subnet', message_dict)
self.assertIn(error_message, message_dict['master_subnet'])

def test_ipadresses_missing_attribute(self):
instance = self._create_subnet(subnet='10.1.2.0/24')
Expand Down

0 comments on commit 3680f74

Please sign in to comment.