1
0
mirror of https://github.com/peeringdb/peeringdb.git synced 2024-05-11 05:55:09 +00:00

validate netixlan ip against parent prefixes (#8)

This commit is contained in:
Stefan Pratter
2019-05-02 18:16:44 +00:00
parent ed47bddc4a
commit 01d856e424
3 changed files with 144 additions and 11 deletions

View File

@ -100,6 +100,30 @@ EMAIL = "test@20c.com"
VERBOSE = False VERBOSE = False
PREFIXES_V4 = [
u"206.223.114.0/24",
u"206.223.115.0/24",
u"206.223.116.0/24",
u"206.223.117.0/24",
u"206.223.118.0/24",
u"206.223.119.0/24",
u"206.223.120.0/24",
u"206.223.121.0/24",
u"206.223.122.0/24",
]
PREFIXES_V6 = [
u"2001:504:0:1::/64",
u"2001:504:0:2::/64",
u"2001:504:0:3::/64",
u"2001:504:0:4::/64",
u"2001:504:0:5::/64",
u"2001:504:0:6::/64",
u"2001:504:0:7::/64",
u"2001:504:0:8::/64",
u"2001:504:0:9::/64",
]
class TestJSON(unittest.TestCase): class TestJSON(unittest.TestCase):
@ -110,17 +134,32 @@ class TestJSON(unittest.TestCase):
IP6_COUNT = 1 IP6_COUNT = 1
@classmethod @classmethod
def get_ip6(cls): def get_ip6(cls, ixlan):
r = u"2001:7f8:4::1154:%d" % cls.IP6_COUNT hosts = []
for host in ixlan.ixpfx_set.filter(status=ixlan.status, protocol=6).first().prefix.hosts():
if len(hosts) < 100:
hosts.append(host)
else:
break
r = u"{}".format(hosts[cls.IP6_COUNT])
cls.IP6_COUNT += 1 cls.IP6_COUNT += 1
return r return r
@classmethod @classmethod
def get_ip4(cls): def get_ip4(cls, ixlan):
r = u"1.1.1.%d" % cls.IP4_COUNT hosts = []
for host in ixlan.ixpfx_set.filter(status=ixlan.status, protocol=4).first().prefix.hosts():
if len(hosts) < 100:
hosts.append(host)
else:
break
r = u"{}".format(hosts[cls.IP4_COUNT])
cls.IP4_COUNT += 1 cls.IP4_COUNT += 1
return r return r
@classmethod @classmethod
def get_prefix4(cls): def get_prefix4(cls):
r = u"206.41.{}.0/24".format(cls.PREFIX_COUNT) r = u"206.41.{}.0/24".format(cls.PREFIX_COUNT)
@ -318,14 +357,17 @@ class TestJSON(unittest.TestCase):
"notes": NOTE, "notes": NOTE,
"speed": 30000, "speed": 30000,
"asn": 12345, "asn": 12345,
"ipaddr4": self.get_ip4(),
"ipaddr6": self.get_ip6()
} }
data.update(**kwargs) data.update(**kwargs)
for k, v in rename.items(): for k, v in rename.items():
data[v] = data[k] data[v] = data[k]
del data[k] del data[k]
data.update(
ipaddr4=self.get_ip4(IXLan.objects.get(id=data["ixlan_id"])),
ipaddr6=self.get_ip6(IXLan.objects.get(id=data["ixlan_id"])),
)
return data return data
########################################################################## ##########################################################################
@ -615,6 +657,20 @@ class TestJSON(unittest.TestCase):
SHARED["%s_r_ok_public" % target].id, SHARED["%s_r_ok_public" % target].id,
SHARED["%s_rw_ok_public" % target].id SHARED["%s_rw_ok_public" % target].id
] ]
elif target == "ixpfx":
valid_s = [
SHARED["%s_r_ok" % target].id,
SHARED["%s_r_v6_ok" % target].id,
]
valid_m = [
SHARED["%s_r_ok" % target].id,
SHARED["%s_rw_ok" % target].id,
SHARED["%s_r_v6_ok" % target].id,
SHARED["%s_rw_v6_ok" % target].id,
]
else: else:
valid_s = [SHARED["%s_r_ok" % target].id] valid_s = [SHARED["%s_r_ok" % target].id]
@ -1329,12 +1385,13 @@ class TestJSON(unittest.TestCase):
}, },
"perms": { "perms": {
# set network to one the user doesnt have perms to # set network to one the user doesnt have perms to
"ipaddr4": self.get_ip4(), "ipaddr4": self.get_ip4(SHARED["ixlan_rw_ok"]),
"ipaddr6": self.get_ip6(), "ipaddr6": self.get_ip6(SHARED["ixlan_rw_ok"]),
"net_id": SHARED["net_r_ok"].id "net_id": SHARED["net_r_ok"].id
} }
}) })
SHARED["netixlan_id"] = r_data.get("id") SHARED["netixlan_id"] = r_data.get("id")
self.assert_update(self.db_org_admin, "netixlan", self.assert_update(self.db_org_admin, "netixlan",
@ -1352,6 +1409,26 @@ class TestJSON(unittest.TestCase):
test_success=SHARED["netixlan_id"], test_success=SHARED["netixlan_id"],
test_failure=SHARED["netixlan_r_ok"].id) test_failure=SHARED["netixlan_r_ok"].id)
##########################################################################
def test_org_admin_002_POST_PUT_netixlan_validation(self):
data = self.make_data_netixlan(net_id=SHARED["net_rw_ok"].id,
ixlan_id=SHARED["ixlan_rw_ok"].id)
test_failures = [
# test failure if ip4 not in prefix
{"invalid": { "ipaddr4": self.get_ip4(SHARED["ixlan_r_ok"]) }},
# test failure if ip6 not in prefix
{"invalid": { "ipaddr6": self.get_ip6(SHARED["ixlan_r_ok"]) }},
]
for test_failure in test_failures:
self.assert_create(self.db_org_admin, "netixlan", data,
test_failures=test_failure, test_success=False)
########################################################################## ##########################################################################
def test_org_admin_002_POST_PUT_DELETE_ixfac(self): def test_org_admin_002_POST_PUT_DELETE_ixfac(self):
@ -2719,6 +2796,12 @@ class Command(BaseCommand):
if tag in ["ix", "net", "fac", "org"]: if tag in ["ix", "net", "fac", "org"]:
data["name"] = name data["name"] = name
if tag == "ixpfx":
if kwargs.get("protocol", 4) == 4:
data["prefix"] = PREFIXES_V4[model.objects.all().count()]
elif kwargs.get("protocol") == 6:
data["prefix"] = PREFIXES_V6[model.objects.all().count()]
data.update(**kwargs) data.update(**kwargs)
try: try:
obj = model.objects.get(**data) obj = model.objects.get(**data)
@ -2886,6 +2969,14 @@ class Command(BaseCommand):
IXLanPrefix, IXLanPrefix,
status=status, status=status,
prefix=prefix, prefix=prefix,
protocol=4,
ixlan_id=SHARED["ixlan_%s_%s" % (prefix, status)].id,
)
cls.create_entity(
IXLanPrefix,
status=status,
prefix="{}_v6".format(prefix),
protocol=6,
ixlan_id=SHARED["ixlan_%s_%s" % (prefix, status)].id, ixlan_id=SHARED["ixlan_%s_%s" % (prefix, status)].id,
) )
cls.create_entity( cls.create_entity(

View File

@ -1435,7 +1435,6 @@ class IXLan(pdb_models.IXLanBase):
return False return False
@reversion.create_revision() @reversion.create_revision()
def add_netixlan(self, netixlan_info, save=True, save_others=True): def add_netixlan(self, netixlan_info, save=True, save_others=True):
""" """
@ -2286,11 +2285,40 @@ class NetworkIXLan(pdb_models.NetworkIXLanBase):
conflict_v6 = (self.ipaddr6 and ipv6.exists()) conflict_v6 = (self.ipaddr6 and ipv6.exists())
return (conflict_v4, conflict_v6) return (conflict_v4, conflict_v6)
def validate_ipaddr4(self):
if self.ipaddr4 and not self.ixlan.test_ipv4_address(self.ipaddr4):
raise ValidationError(_("IPv4 address outside of prefix"))
def validate_ipaddr6(self):
if self.ipaddr6 and not self.ixlan.test_ipv6_address(self.ipaddr6):
raise ValidationError(_("IPv6 address outside of prefix"))
def clean(self): def clean(self):
""" """
Custom model validation Custom model validation
""" """
errors = {} errors = {}
# check that the ip address can be validated agaisnt
# at least one of the prefix on the parent ixlan
try:
self.validate_ipaddr4()
except ValidationError as exc:
errors["ipaddr4"] = exc.message
try:
self.validate_ipaddr6()
except ValidationError as exc:
errors["ipaddr6"] = exc.message
if errors:
raise ValidationError(errors)
# make sure this ip address is not claimed anywhere else
conflict_v4, conflict_v6 = self.ipaddress_conflict() conflict_v4, conflict_v6 = self.ipaddress_conflict()
if conflict_v4: if conflict_v4:
errors["ipaddr4"] = _("Ip address already exists elsewhere") errors["ipaddr4"] = _("Ip address already exists elsewhere")

View File

@ -8,7 +8,7 @@ from django.db.models.query import QuerySet
from django.db.models import Prefetch, Q, Sum, IntegerField, Case, When from django.db.models import Prefetch, Q, Sum, IntegerField, Case, When
from django.db import models, transaction from django.db import models, transaction
from django.db.models.fields.related import ReverseManyToOneDescriptor, ForwardManyToOneDescriptor from django.db.models.fields.related import ReverseManyToOneDescriptor, ForwardManyToOneDescriptor
from django.core.exceptions import FieldError from django.core.exceptions import FieldError, ValidationError
from rest_framework import serializers, validators from rest_framework import serializers, validators
from rest_framework.exceptions import ValidationError as RestValidationError from rest_framework.exceptions import ValidationError as RestValidationError
# from drf_toolbox import serializers # from drf_toolbox import serializers
@ -1161,6 +1161,20 @@ class NetworkIXLanSerializer(ModelSerializer):
def get_ix_id(self, inst): def get_ix_id(self, inst):
return inst.ix_id return inst.ix_id
def validate(self, data):
netixlan = NetworkIXLan(**data)
try:
netixlan.validate_ipaddr4()
except ValidationError as exc:
raise serializers.ValidationError({"ipaddr4":exc.message})
try:
netixlan.validate_ipaddr6()
except ValidationError as exc:
raise serializers.ValidationError({"ipaddr6":exc.message})
return data
class NetworkFacilitySerializer(ModelSerializer): class NetworkFacilitySerializer(ModelSerializer):
""" """