Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve IPv6 validation #201

Merged
merged 7 commits into from May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion tests/test_ipv6.py
Expand Up @@ -5,11 +5,15 @@


@pytest.mark.parametrize(('address',), [
('::',),
('::1',),
('dead:beef:0:0:0:0:42:1',),
('1::',),
('dead:beef:0:0:0:0000:42:1',),
('abcd:ef::42:1',),
('0:0:0:0:0:ffff:1.2.3.4',),
('::192.168.30.2',),
('0000:0000:0000:0000:0000::',),
('0:a:b:c:d:e:f::',),
])
def test_returns_true_on_valid_ipv6_address(address):
assert ipv6(address)
Expand All @@ -20,7 +24,19 @@ def test_returns_true_on_valid_ipv6_address(address):
('abc.0.0.1',),
('abcd:1234::123::1',),
('1:2:3:4:5:6:7:8:9',),
('1:2:3:4:5:6:7:8::',),
('1:2:3:4:5:6:7::8:9',),
('abcd::1ffff',),
('1111:',),
(':8888',),
(':1.2.3.4',),
('18:05',),
(':',),
(':1:2:',),
(':1:2::',),
('::1:2::',),
('8::1:2::9',),
('02001:0000:1234:0000:0000:C1C0:ABCD:0876',),
])
def test_returns_failed_validation_on_invalid_ipv6_address(address):
assert isinstance(ipv6(address), ValidationFailure)
30 changes: 19 additions & 11 deletions validators/ip_address.py
Expand Up @@ -4,7 +4,7 @@
@validator
def ipv4(value):
"""
Return whether or not given value is a valid IP version 4 address.
Return whether a given value is a valid IP version 4 address.

This validator is based on `WTForms IPAddress validator`_

Expand Down Expand Up @@ -32,7 +32,7 @@ def ipv4(value):
@validator
def ipv4_cidr(value):
"""
Return whether or not given value is a valid CIDR-notated IP version 4
Return whether a given value is a valid CIDR-notated IP version 4
address range.

This validator is based on RFC4632 3.1.
Expand All @@ -57,7 +57,7 @@ def ipv4_cidr(value):
@validator
def ipv6(value):
"""
Return whether or not given value is a valid IP version 6 address
Return whether a given value is a valid IP version 6 address
(including IPv4-mapped IPv6 addresses).

This validator is based on `WTForms IPAddress validator`_.
Expand Down Expand Up @@ -95,10 +95,6 @@ def ipv6(value):
else:
ipv4_groups = []

max_groups = 6 if ipv4_groups else 8
if len(ipv6_groups) > max_groups:
return False

count_blank = 0
for part in ipv6_groups:
if not part:
Expand All @@ -109,20 +105,32 @@ def ipv6(value):
except ValueError:
return False
else:
if not 0 <= num <= 65536:
if not 0 <= num <= 65536 or len(part) > 4:
return False

if count_blank < 2:
max_groups = 6 if ipv4_groups else 8
part_count = len(ipv6_groups) - count_blank
if count_blank == 0 and part_count == max_groups:
# no :: -> must have size of max_groups
return True
elif count_blank == 1 and ipv6_groups[-1] and ipv6_groups[0] and part_count < max_groups:
# one :: inside the address or prefix or suffix : -> filter least two cases
return True
elif count_blank == 2 and part_count < max_groups and (
((ipv6_groups[0] and not ipv6_groups[-1]) or (not ipv6_groups[0] and ipv6_groups[-1])) or ipv4_groups):
# leading or trailing :: or : at end and begin -> filter last case
# Check if it has ipv4 groups because they get removed from the ipv6_groups
return True
elif count_blank == 2 and not ipv6_groups[0] and not ipv6_groups[1]:
elif count_blank == 3 and part_count == 0:
# :: is the address -> filter everything else
return True
return False


@validator
def ipv6_cidr(value):
"""
Returns whether or not given value is a valid CIDR-notated IP version 6
Returns whether a given value is a valid CIDR-notated IP version 6
address range.

This validator is based on RFC4632 3.1.
Expand Down