diff options
author | Rory Byrne <[email protected]> | 2015-05-14 10:54:31 +0100 |
---|---|---|
committer | Rory Byrne <[email protected]> | 2015-05-22 09:05:00 +0100 |
commit | c0be40c2dad6661d28e7aafb35057f06095bb2bb (patch) | |
tree | 0f888b34fa50d974eeadeaeac29f700ae4cb2d92 | |
parent | efbfe9602983ff451b864e557bdf3733222b78ba (diff) | |
download | otp-c0be40c2dad6661d28e7aafb35057f06095bb2bb.tar.gz otp-c0be40c2dad6661d28e7aafb35057f06095bb2bb.tar.bz2 otp-c0be40c2dad6661d28e7aafb35057f06095bb2bb.zip |
Fix parsing of IPv6 addresses to limit leading zeros
The current implementations of inet:parse_ipv6_address/1 and
inet:parse_ipv6strict_address/1 permit address strings which have an
unlimited number of leading zeros. Addresses such as:
"0000000000000000000000000000000ffff::"
"::00000000000000000000000000000000000000000000000000000000"
"::0000000f435:1"
If we are using this facility to validate string representations of
IPv6 addresses, then we would end up validating addresses which are
non-conformant (with respect to RFC 4291 section 2.2) and potentially
dangerous.
This patch ensures that each segment of an IPv6 address has a maximum
of 4 hex digits.
-rw-r--r-- | lib/kernel/src/inet_parse.erl | 30 | ||||
-rw-r--r-- | lib/kernel/test/inet_SUITE.erl | 3 |
2 files changed, 15 insertions, 18 deletions
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl index a88c94a453..a694642b19 100644 --- a/lib/kernel/src/inet_parse.erl +++ b/lib/kernel/src/inet_parse.erl @@ -675,28 +675,22 @@ ipv6_addr_done(Ar, Br, N) -> ipv6_addr_done(Ar) -> list_to_tuple(lists:reverse(Ar)). -%% Collect Hex digits -hex(Cs) -> hex(Cs, []). -%% -hex([C|Cs], R) when C >= $0, C =< $9 -> - hex(Cs, [C|R]); -hex([C|Cs], R) when C >= $a, C =< $f -> - hex(Cs, [C|R]); -hex([C|Cs], R) when C >= $A, C =< $F -> - hex(Cs, [C|R]); -hex(Cs, [_|_]=R) when is_list(Cs) -> +%% Collect 1-4 Hex digits +hex(Cs) -> hex(Cs, [], 4). +%% +hex([C|Cs], R, N) when C >= $0, C =< $9, N > 0 -> + hex(Cs, [C|R], N-1); +hex([C|Cs], R, N) when C >= $a, C =< $f, N > 0 -> + hex(Cs, [C|R], N-1); +hex([C|Cs], R, N) when C >= $A, C =< $F, N > 0 -> + hex(Cs, [C|R], N-1); +hex(Cs, [_|_]=R, _) when is_list(Cs) -> {lists:reverse(R),Cs}; -hex(_, _) -> +hex(_, _, _) -> erlang:error(badarg). %% Hex string to integer -hex_to_int(Cs0) -> - case strip0(Cs0) of - Cs when length(Cs) =< 4 -> - erlang:list_to_integer("0"++Cs, 16); - _ -> - erlang:error(badarg) - end. +hex_to_int(Cs) -> erlang:list_to_integer(Cs, 16). %% Dup onto head of existing list dup(0, _, L) -> diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 44a32fc1ec..c77de9316f 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -569,8 +569,11 @@ parse_address(Config) when is_list(Config) -> "::-1", "::g", "f:f11::10100:2", + "f:f11::01100:2", "::17000", + "::01700", "10000::", + "01000::", "::8:7:6:5:4:3:2:1", "8:7:6:5:4:3:2:1::", "8:7:6:5:4::3:2:1", |