Skip to content

Commit

Permalink
[fix] Prevented IP version mismatch between master subnets #154
Browse files Browse the repository at this point in the history
Fixes #154
  • Loading branch information
dee077 authored Jan 24, 2025
1 parent 683bc7d commit 77e21b0
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 77e21b0

Please sign in to comment.