Skip to content

Commit 9b4e69c

Browse files
authored
Fix ipv6 validation corner cases (#281)
This ports the ipv6 fix from bufbuild/protovalidate-go#215. For context see the description on the above PR. The summary is that this fixes the validation for some corner cases of IPv6 address validation. Namely: * Adds a check that an IPv6 address can't begin or end on a single colon. * Adds a check to fail-fast on invalid hextets.
1 parent dbdecb0 commit 9b4e69c

File tree

2 files changed

+24
-35
lines changed

2 files changed

+24
-35
lines changed

protovalidate/internal/extra_func.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -653,8 +653,11 @@ def __address_part(self) -> bool:
653653

654654
return False
655655

656-
if self.__h16():
657-
continue
656+
try:
657+
if self.__h16():
658+
continue
659+
except ValueError:
660+
return False
658661

659662
if self.__take(":"):
660663
if self.__take(":"):
@@ -666,6 +669,9 @@ def __address_part(self) -> bool:
666669

667670
if self.__take(":"):
668671
return False
672+
elif self._index == 1 or self._index == len(self._string):
673+
# invalid - string cannot start or end on single colon
674+
return False
669675

670676
continue
671677

@@ -734,7 +740,11 @@ def __h16(self) -> bool:
734740
735741
h16 = 1*4HEXDIG
736742
737-
Stores 16-bit value in _pieces.
743+
If 1-4 hex digits are found, the parsed 16-bit unsigned integer is stored
744+
in pieces and True is returned.
745+
If 0 hex digits are found, returns False.
746+
If more than 4 hex digits are found or the found hex digits cannot be
747+
converted to an int, a ValueError is raised.
738748
"""
739749

740750
start = self._index
@@ -746,23 +756,24 @@ def __h16(self) -> bool:
746756
string = self._string[start : self._index]
747757

748758
if len(string) == 0:
749-
# too short
759+
# too short, just return false
760+
# this is not an error condition, it just means we didn't find any
761+
# hex digits at the current position.
750762
return False
751763

752764
if len(string) > 4:
753765
# too long
754-
return False
755-
756-
try:
757-
value = int(string, 16)
766+
# this is an error condition, it means we found a string of more than
767+
# four valid hex digits, which is invalid in ipv6 addresses.
768+
raise ValueError
758769

759-
self._pieces.append(value)
770+
# Note that this will raise a ValueError also if string cannot be
771+
# converted to an int.
772+
value = int(string, 16)
760773

761-
return True
774+
self._pieces.append(value)
762775

763-
except ValueError:
764-
# Error converting to number
765-
return False
776+
return True
766777

767778
def __hex_dig(self) -> bool:
768779
"""Determine whether the current position is a hex digit.

tests/conformance/nonconforming.yaml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,3 @@ standard_constraints/well_known_types/duration:
77
standard_constraints/well_known_types/timestamp:
88
- gte_lte/invalid/above
99
- lte/invalid
10-
11-
library/is_ip:
12-
- version/omitted/invalid/ipv6/g
13-
# input: [type.googleapis.com/buf.validate.conformance.cases.IsIp]:{val:":0::0"}
14-
# want: validation error (1 violation)
15-
# 1. constraint_id: "library.is_ip"
16-
# got: valid
17-
- version/omitted/invalid/ipv6/h
18-
# input: [type.googleapis.com/buf.validate.conformance.cases.IsIp]:{val:"0::0:"}
19-
# want: validation error (1 violation)
20-
# 1. constraint_id: "library.is_ip"
21-
# got: valid
22-
- version/omitted/invalid/ipv6/i
23-
# input: [type.googleapis.com/buf.validate.conformance.cases.IsIp]:{val:"0::0:"}
24-
# want: validation error (1 violation)
25-
# 1. constraint_id: "library.is_ip"
26-
# got: valid
27-
- version/omitted/invalid/ipv6/j
28-
# input: [type.googleapis.com/buf.validate.conformance.cases.IsIp]:{val:"::0000ffff"}
29-
# want: validation error (1 violation)
30-
# 1. constraint_id: "library.is_ip"
31-
# got: unexpected error: string index out of range

0 commit comments

Comments
 (0)