fix(erlang): validate tuple segment ranges in ip2region_util

This commit is contained in:
Alice39s 2026-06-28 05:17:55 +09:00
parent b1eb00e25e
commit e50ead2cba
No known key found for this signature in database
GPG Key ID: 0E0AA11C3939DDDD
2 changed files with 20 additions and 6 deletions

View File

@ -11,11 +11,15 @@
-export([ipv4_to_n/1, ip_version/1, ip_to_bytes/1]).
-define(IS_UINT8(V), is_integer(V), V >= 0, V =< 255).
-define(IS_UINT16(V), is_integer(V), V >= 0, V =< 65535).
-spec ip_version(Ip :: tuple() | list() | binary() | integer()) ->
ipv4 | ipv6 | {error, atom()}.
ip_version(Ip) when is_integer(Ip), Ip >= 0, Ip =< 16#FFFFFFFF -> ipv4;
ip_version({_, _, _, _}) -> ipv4;
ip_version({_, _, _, _, _, _, _, _}) -> ipv6;
ip_version({A, B, C, D}) when ?IS_UINT8(A), ?IS_UINT8(B), ?IS_UINT8(C), ?IS_UINT8(D) -> ipv4;
ip_version({A, B, C, D, E, F, G, H}) when ?IS_UINT16(A), ?IS_UINT16(B), ?IS_UINT16(C), ?IS_UINT16(D),
?IS_UINT16(E), ?IS_UINT16(F), ?IS_UINT16(G), ?IS_UINT16(H) -> ipv6;
ip_version(Ip) when is_binary(Ip) ->
ip_version(binary_to_list(Ip));
ip_version(Ip) when is_list(Ip) ->
@ -31,9 +35,10 @@ ip_version(_) ->
{ok, ipv4 | ipv6, binary()} | {error, atom()}.
ip_to_bytes(Ip) when is_integer(Ip), Ip >= 0, Ip =< 16#FFFFFFFF ->
{ok, ipv4, <<Ip:32>>};
ip_to_bytes({A, B, C, D}) ->
ip_to_bytes({A, B, C, D}) when ?IS_UINT8(A), ?IS_UINT8(B), ?IS_UINT8(C), ?IS_UINT8(D) ->
{ok, ipv4, <<A, B, C, D>>};
ip_to_bytes({A, B, C, D, E, F, G, H}) ->
ip_to_bytes({A, B, C, D, E, F, G, H}) when ?IS_UINT16(A), ?IS_UINT16(B), ?IS_UINT16(C), ?IS_UINT16(D),
?IS_UINT16(E), ?IS_UINT16(F), ?IS_UINT16(G), ?IS_UINT16(H) ->
{ok, ipv6, <<A:16, B:16, C:16, D:16, E:16, F:16, G:16, H:16>>};
ip_to_bytes(Ip) when is_binary(Ip) ->
ip_to_bytes(binary_to_list(Ip));
@ -52,7 +57,7 @@ ip_to_bytes(_) ->
-spec ipv4_to_n(Ip :: tuple() | list() | binary() | integer()) ->
non_neg_integer() | {error, atom()}.
ipv4_to_n(IntIp) when is_integer(IntIp), IntIp >= 0, IntIp =< 16#FFFFFFFF -> IntIp;
ipv4_to_n({A, B, C, D}) ->
ipv4_to_n({A, B, C, D}) when ?IS_UINT8(A), ?IS_UINT8(B), ?IS_UINT8(C), ?IS_UINT8(D) ->
<<N:32>> = <<A, B, C, D>>,
N;
ipv4_to_n(Ip) when is_binary(Ip) ->

View File

@ -34,8 +34,15 @@ invalid_inputs_test_() ->
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(atom)),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(-1)),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(16#100000000)),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes({256, 0, 0, 1})),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes({-1, 0, 0, 0})),
?_assertEqual({error, bad_ip_format},
ip2region_util:ip_to_bytes({0, 0, 0, 0, 0, 0, 0, 65536})),
?_assertEqual({error, bad_ip_format},
ip2region_util:ip_to_bytes({0, 0, 0, 0, 0, 0, 0, -1})),
?_assertEqual({error, bad_ip_format}, ip2region_util:ipv4_to_n(-1)),
?_assertEqual({error, bad_ip_format}, ip2region_util:ipv4_to_n(16#100000000))
?_assertEqual({error, bad_ip_format}, ip2region_util:ipv4_to_n(16#100000000)),
?_assertEqual({error, bad_ip_format}, ip2region_util:ipv4_to_n({256, 0, 0, 1}))
].
ip_version_test_() ->
@ -45,6 +52,8 @@ ip_version_test_() ->
?_assertEqual(ipv4, ip2region_util:ip_version(16779264 + 1)),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_version("::ggg")),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_version({1,2,3})),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_version({256,0,0,1})),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_version({0,0,0,0,0,0,0,65536})),
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_version(16#100000000))
].