Skip to content

Commit

Permalink
Improve IPv6 validation (#201)
Browse files Browse the repository at this point in the history
* Improve IPv6 validation
fixes #107

* Add some comments

* Fix ipv4 with double colon

* Fix falsy to long ipv6 result and detect to long parts

* Check for length

* Take empty parts in account

* Reduce length calculation
  • Loading branch information
SimonIT committed May 4, 2022
1 parent 29df081 commit f816ce1
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 12 deletions.
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

0 comments on commit f816ce1

Please sign in to comment.