mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
Additional IRR validators (#690)
* increase rdap lookup timeout to 2.5 * Allow as set hierarchy according to RFC 2622 5.0 during IRR validation (#151) * fix wording of validation error message (#151) * allow single as in irr validation (#151) allow as rs-set combination in irr validation (#151) Co-authored-by: Stefan Pratter <stefan@20c.com>
This commit is contained in:
@@ -163,6 +163,9 @@ set_option("DATA_QUALITY_MIN_PREFIXLEN_V6", 64)
|
|||||||
# maximum value to allow for prefix length on a v6 prefix
|
# maximum value to allow for prefix length on a v6 prefix
|
||||||
set_option("DATA_QUALITY_MAX_PREFIXLEN_V6", 116)
|
set_option("DATA_QUALITY_MAX_PREFIXLEN_V6", 116)
|
||||||
|
|
||||||
|
# maximum value to allow for irr set hierarchy depth
|
||||||
|
set_option("DATA_QUALITY_MAX_IRR_DEPTH", 3)
|
||||||
|
|
||||||
RATELIMITS = {
|
RATELIMITS = {
|
||||||
"request_login_POST": "4/m",
|
"request_login_POST": "4/m",
|
||||||
"request_translation": "2/m",
|
"request_translation": "2/m",
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class RdapLookup(rdap.RdapClient):
|
|||||||
config = dict(
|
config = dict(
|
||||||
bootstrap_url=settings.RDAP_URL.rstrip("/"),
|
bootstrap_url=settings.RDAP_URL.rstrip("/"),
|
||||||
lacnic_apikey=settings.RDAP_LACNIC_APIKEY,
|
lacnic_apikey=settings.RDAP_LACNIC_APIKEY,
|
||||||
|
timeout=2.5,
|
||||||
)
|
)
|
||||||
super(RdapLookup, self).__init__(config)
|
super(RdapLookup, self).__init__(config)
|
||||||
|
|
||||||
|
|||||||
@@ -180,23 +180,62 @@ def validate_irr_as_set(value):
|
|||||||
for item in value.split(","):
|
for item in value.split(","):
|
||||||
item = item.upper()
|
item = item.upper()
|
||||||
source = None
|
source = None
|
||||||
|
as_set = None
|
||||||
|
|
||||||
# <name>@<source>
|
# <name>@<source>
|
||||||
parts_match = re.match("^(AS|RS)-([\w\d\-]+)@(\w+)$", item)
|
parts_match = re.match("^([\w\d\-:]+)@(\w+)$", item)
|
||||||
if parts_match:
|
if parts_match:
|
||||||
source = parts_match.group(3)
|
source = parts_match.group(2)
|
||||||
|
as_set = parts_match.group(1)
|
||||||
|
|
||||||
# <source>::<name>
|
# <source>::<name>
|
||||||
else:
|
else:
|
||||||
parts_match = re.match("^(\w+)::(AS|RS)-([\w\d\-]+)$", item)
|
parts_match = re.match("^(\w+)::([\w\d\-:]+)$", item)
|
||||||
if parts_match:
|
if parts_match:
|
||||||
source = parts_match.group(1)
|
source = parts_match.group(1)
|
||||||
|
as_set = parts_match.group(2)
|
||||||
else:
|
else:
|
||||||
raise ValidationError(_("Invalid formatting: {} - should be AS-SET@SOURCE or SOURCE::AS-SET").format(item))
|
raise ValidationError(_("Invalid formatting: {} - should be AS-SET@SOURCE or SOURCE::AS-SET").format(item))
|
||||||
|
|
||||||
if source not in IRR_SOURCE:
|
if source not in IRR_SOURCE:
|
||||||
raise ValidationError(_("Unknown IRR source: {}").format(source))
|
raise ValidationError(_("Unknown IRR source: {}").format(source))
|
||||||
|
|
||||||
|
|
||||||
|
# validate set name and as hierarchy
|
||||||
|
as_parts = as_set.split(":")
|
||||||
|
|
||||||
|
if len(as_parts) > settings.DATA_QUALITY_MAX_IRR_DEPTH:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Maximum AS-SET hierarchy depth: {}").format(
|
||||||
|
settings.DATA_QUALITY_MAX_IRR_DEPTH
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
set_found = False
|
||||||
|
typ = None
|
||||||
|
types = []
|
||||||
|
|
||||||
|
for part in as_parts:
|
||||||
|
match_set = re.match("^(AS|RS)-[\w\d\-]+$", part)
|
||||||
|
match_as = re.match("^(AS)[\d]+$", part)
|
||||||
|
|
||||||
|
# set name found
|
||||||
|
|
||||||
|
if match_set:
|
||||||
|
set_found = True
|
||||||
|
types.append(match_set.group(1))
|
||||||
|
elif not match_as:
|
||||||
|
raise ValidationError(_("Invalid formatting: {} - should be RS-SET, AS-SET or AS123").format(part))
|
||||||
|
|
||||||
|
|
||||||
|
if len(list(set(types))) > 1:
|
||||||
|
raise ValidationError(
|
||||||
|
_("All parts of an hierarchical name have to be of the same type")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not set_found and len(as_parts) > 1:
|
||||||
|
raise ValidationError(_("At least one component must be an actual set name"))
|
||||||
|
|
||||||
validated.append(item)
|
validated.append(item)
|
||||||
|
|
||||||
return " ".join(validated)
|
return " ".join(validated)
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ settings.configure(
|
|||||||
DATA_QUALITY_MAX_PREFIXLEN_V4=28,
|
DATA_QUALITY_MAX_PREFIXLEN_V4=28,
|
||||||
DATA_QUALITY_MIN_PREFIXLEN_V6=64,
|
DATA_QUALITY_MIN_PREFIXLEN_V6=64,
|
||||||
DATA_QUALITY_MAX_PREFIXLEN_V6=116,
|
DATA_QUALITY_MAX_PREFIXLEN_V6=116,
|
||||||
|
DATA_QUALITY_MAX_IRR_DEPTH=3,
|
||||||
TUTORIAL_MODE=False,
|
TUTORIAL_MODE=False,
|
||||||
CAPTCHA_TEST_MODE=True,
|
CAPTCHA_TEST_MODE=True,
|
||||||
SITE_ID=1,
|
SITE_ID=1,
|
||||||
|
|||||||
@@ -156,11 +156,20 @@ def test_validate_prefix_overlap():
|
|||||||
# success validation
|
# success validation
|
||||||
("RIPE::AS-FOO", "RIPE::AS-FOO"),
|
("RIPE::AS-FOO", "RIPE::AS-FOO"),
|
||||||
("AS-FOO@RIPE", "AS-FOO@RIPE"),
|
("AS-FOO@RIPE", "AS-FOO@RIPE"),
|
||||||
|
("AS-FOO-BAR@RIPE", "AS-FOO-BAR@RIPE"),
|
||||||
("ripe::as-foo", "RIPE::AS-FOO"),
|
("ripe::as-foo", "RIPE::AS-FOO"),
|
||||||
("as-foo@ripe", "AS-FOO@RIPE"),
|
("as-foo@ripe", "AS-FOO@RIPE"),
|
||||||
("as-foo@ripe as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
("as-foo@ripe as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
||||||
("as-foo@ripe,as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
("as-foo@ripe,as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
||||||
("as-foo@ripe, as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
("as-foo@ripe, as-bar@ripe", "AS-FOO@RIPE AS-BAR@RIPE"),
|
||||||
|
(
|
||||||
|
"RIPE::AS12345:AS-FOO RIPE::AS12345:AS-FOO:AS9876",
|
||||||
|
"RIPE::AS12345:AS-FOO RIPE::AS12345:AS-FOO:AS9876"
|
||||||
|
),
|
||||||
|
("ripe::as-foo:as123:as345", "RIPE::AS-FOO:AS123:AS345"),
|
||||||
|
("RIPE::AS12345", "RIPE::AS12345"),
|
||||||
|
("AS12345@RIPE", "AS12345@RIPE"),
|
||||||
|
("RIPE::AS123456:RS-FOO", "RIPE::AS123456:RS-FOO"),
|
||||||
|
|
||||||
# fail validation
|
# fail validation
|
||||||
("AS-FOO", False),
|
("AS-FOO", False),
|
||||||
@@ -170,6 +179,11 @@ def test_validate_prefix_overlap():
|
|||||||
("UNKNOWN::ASFOO", False),
|
("UNKNOWN::ASFOO", False),
|
||||||
("AS-FOO RIPE:AS-FOO", False),
|
("AS-FOO RIPE:AS-FOO", False),
|
||||||
("AS-FOO AS-FOO@RIPE", False),
|
("AS-FOO AS-FOO@RIPE", False),
|
||||||
|
("RIPE::RS15562:RS-FOO", False),
|
||||||
|
("RIPE::AS123456:RS-FOO:AS-FOO", False),
|
||||||
|
|
||||||
|
# > DATA_QUALITY_MAX_IRR_DEPTH
|
||||||
|
("ripe::as-foo:as123:as345:as678", False),
|
||||||
])
|
])
|
||||||
def test_validate_irr_as_set(value, validated):
|
def test_validate_irr_as_set(value, validated):
|
||||||
if not validated:
|
if not validated:
|
||||||
|
|||||||
Reference in New Issue
Block a user