├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── rebar.config ├── src ├── inet_cidr.app.src └── inet_cidr.erl └── test └── inet_cidr_tests.erl /.gitignore: -------------------------------------------------------------------------------- 1 | .erlang.mk 2 | inet_cidr.d 3 | ebin 4 | deps 5 | test/*.tmp 6 | test/*.beam 7 | .rebar 8 | _build 9 | _checkouts 10 | rebar.lock 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2016-2017 (c) Benoît Chesneau 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | inet_cidr 2 | 3 | 2016 (c) Benoît Chesneau 4 | 5 | natpmp is released under the MIT license. See the LICENSE 6 | file for the complete license. 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Hex.pm version](https://img.shields.io/hexpm/v/erl_cidr.svg?style=flat)](https://hex.pm/packages/erl_cidr) 2 | 3 | # inet_cidr 4 | 5 | CIDR library for Erlang. 6 | 7 | > Based on the Elixir library [InetCidr](https://github.com/Cobenian/inet_cidr) 8 | but rewritten so it can be easily used in an Erlang application without 9 | requiring Elixir. 10 | 11 | Available on [hex.pm](https://hex.pm) as [erl_cidr](https://hex.pm/packages/erl_cidr). 12 | 13 | ## Usage 14 | 15 | ### Parsing a CIDR string 16 | 17 | ```erlang 18 | 1> inet_cidr:parse("192.168.0.0/16"). 19 | {{192,168,0,0},{192,168,255,255},16} 20 | 2> inet_cidr:parse("2001:abcd::/32"). 21 | {{8193,43981,0,0,0,0,0,0}, 22 | {8193,43981,65535,65535,65535,65535,65535,65535}, 23 | 32} 24 | ``` 25 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {profiles, [{test, [{erl_opts, [export_all, debug_info]}]}]}. 2 | 3 | {cover_enabled, true}. 4 | {cover_opts, [verbose]}. 5 | 6 | {erl_opts, [warn_export_vars, 7 | warn_shadow_vars, 8 | warn_obsolete_guard]}. 9 | -------------------------------------------------------------------------------- /src/inet_cidr.app.src: -------------------------------------------------------------------------------- 1 | {application, inet_cidr, [ 2 | {description, "CIDR library for Erlang"}, 3 | {vsn, "1.2.0"}, 4 | {modules, []}, 5 | {registered, []}, 6 | {applications, [kernel,stdlib]}, 7 | 8 | {licenses, ["MIT"]}, 9 | {links, [{"Github", "https://github.com/benoitc/inet_cidr"}]}, 10 | {pkg_name, "erl_cidr"} 11 | ]}. 12 | -------------------------------------------------------------------------------- /src/inet_cidr.erl: -------------------------------------------------------------------------------- 1 | %%% -*- erlang -*- 2 | %%% This file is part of nat-pmp released under the MIT license. 3 | %%% See the NOTICE for more information. 4 | %%% 5 | %%% Copyright (c) 2016-2017 Benoît Chesneau 6 | 7 | -module(inet_cidr). 8 | 9 | -export([parse/1, parse/2]). 10 | -export([address_count/2]). 11 | -export([contains/2]). 12 | -export([usort_cidrs/1]). 13 | -export([merge_cidrs/1]). 14 | -export([to_string/1]). 15 | -export([to_binary/1]). 16 | -export([is_ipv4/1]). 17 | -export([is_ipv6/1]). 18 | 19 | -type cidr() :: {Start :: inet:ip4_address(), End :: inet:ip4_address(), MaskLen :: 0..32} 20 | | {Start :: inet:ip6_address(), End :: inet:ip6_address(), MaskLen :: 0..128}. 21 | 22 | -export_type([cidr/0]). 23 | 24 | -spec parse(string() | binary()) -> cidr(). 25 | %% @doc parses S as a CIDR notation IP address and mask 26 | parse(S) -> 27 | parse(S, false). 28 | 29 | -spec parse(string() | binary(), Adjust :: boolean()) -> cidr(). 30 | %% @doc parses S as a CIDR notation IP address and mask. 31 | %% If Adjust = `true', allow the IP to contain values beyond the mask and 32 | %% silently ignore them. Otherwise, enforce that the IP address is fully inside 33 | %% the specified mask (the default behavior of `parse/1'). 34 | parse(B, Adjust) when is_binary(B) -> 35 | parse(binary_to_list(B), Adjust); 36 | parse(S, Adjust) -> 37 | {StartAddr, PrefixLen} = parse_cidr(S, Adjust), 38 | EndAddr = calc_end_address(StartAddr, PrefixLen), 39 | {StartAddr, EndAddr, PrefixLen}. 40 | 41 | -spec address_count(inet:ip4_address(), MaskLen :: 0..32) -> pos_integer(); 42 | (inet:ip6_address(), MaskLen :: 0..128) -> pos_integer(). 43 | %% @doc return the number of IP addresses included in the CIDR block 44 | address_count(IP, Len) -> 45 | 1 bsl (bit_count(IP) - Len). 46 | 47 | -spec contains(cidr(), inet:ip_address() | cidr()) -> boolean(). 48 | %% @doc return true if the CIDR block contains the IP address or CIDR block, false otherwise. 49 | contains({StartAddr, EndAddr, _L}, Addr) when tuple_size(StartAddr) == tuple_size(EndAddr), 50 | tuple_size(StartAddr) == tuple_size(Addr) -> 51 | ip_gte(Addr, StartAddr) andalso ip_lte(Addr, EndAddr); 52 | 53 | contains({StartAddr1, EndAddr1, _L1}, 54 | {StartAddr2, EndAddr2, _L2}) when tuple_size(StartAddr1) == tuple_size(EndAddr1), 55 | tuple_size(EndAddr1) == tuple_size(StartAddr2), 56 | tuple_size(StartAddr2) == tuple_size(EndAddr2) -> 57 | ip_gte(StartAddr2, StartAddr1) andalso ip_lte(StartAddr2, EndAddr1) andalso 58 | ip_gte(EndAddr2, StartAddr1) andalso ip_lte(EndAddr2, EndAddr1); 59 | 60 | contains(_, _) -> 61 | false. 62 | 63 | -spec usort_cidrs([cidr()]) -> [cidr()]. 64 | %% @doc Unique sort a list of CIDR blocks, ordering IPv4 ranges before IPv6 ranges 65 | usort_cidrs(CIDRs) -> 66 | lists:usort(fun cidr_lte/2, CIDRs). 67 | 68 | -spec merge_cidrs([cidr()]) -> [cidr()]. 69 | %% @doc Unique sort and merge a list of CIDR blocks, ordering IPv4 ranges before IPv6 ranges. 70 | %% For merging, CIDR blocks that are contained by other CIDR blocks are removed and 71 | %% adjacent CIDR blocks are merged into larger ones. 72 | merge_cidrs(CIDRs) -> 73 | merge_sorted_cidrs(usort_cidrs(CIDRs)). 74 | 75 | -spec to_string(cidr()) -> string(). 76 | %% @doc return a CIDR block as a string. 77 | to_string({StartAddr, _EndAddr, Len}) -> 78 | inet:ntoa(StartAddr) ++ "/" ++ integer_to_list(Len). 79 | 80 | -spec to_binary(cidr()) -> binary(). 81 | %% @doc return a CIDR block as a binary string. 82 | to_binary({StartAddr, _EndAddr, Len}) -> 83 | <<(list_to_binary(inet:ntoa(StartAddr)))/binary, "/", (integer_to_binary(Len))/binary>>. 84 | 85 | -spec is_ipv4(inet:ip_address()) -> boolean(). 86 | %% @doc return true if the value is an ipv4 address 87 | is_ipv4({A, B, C, D}) -> 88 | (((A >= 0) andalso (A =< 255)) andalso 89 | ((B >= 0) andalso (B =< 255)) andalso 90 | ((C >= 0) andalso (C =< 255)) andalso 91 | ((D >= 0) andalso (D =< 255))); 92 | is_ipv4(_) -> 93 | false. 94 | 95 | -spec is_ipv6(inet:ip_address()) -> boolean(). 96 | %% @doc return true if the value is an ipv6 address 97 | is_ipv6({A, B, C, D, E, F, G, H}) -> 98 | (((A >= 0) andalso (A =< 65535)) andalso 99 | ((B >= 0) andalso (B =< 65535)) andalso 100 | ((C >= 0) andalso (C =< 65535)) andalso 101 | ((D >= 0) andalso (D =< 65535)) andalso 102 | ((E >= 0) andalso (E =< 65535)) andalso 103 | ((F >= 0) andalso (F =< 65535)) andalso 104 | ((G >= 0) andalso (G =< 65535)) andalso 105 | ((H >= 0) andalso (H =< 65535))); 106 | is_ipv6(_) -> 107 | false. 108 | 109 | %% internals 110 | 111 | bit_count({_, _, _, _}) -> 32; 112 | bit_count({_, _, _, _, _, _, _, _}) -> 128. 113 | 114 | parse_cidr(S, Adjust) -> 115 | {StartAddr, Masked, PrefixLen} = 116 | case re:split(S, "/", [{return, list}, {parts, 2}]) of 117 | [Prefix, LenStr] -> 118 | {ok, Addr} = inet:parse_address(Prefix), 119 | {PLen, _} = string:to_integer(LenStr), 120 | {Addr, band_with_mask(Addr, start_mask(Addr, PLen)), PLen}; 121 | [Prefix] -> 122 | {ok, Addr} = inet:parse_address(Prefix), 123 | PLen = case is_ipv6(Addr) of 124 | true -> 128; 125 | false -> 32 126 | end, 127 | {Addr, band_with_mask(Addr, start_mask(Addr, PLen)), PLen} 128 | end, 129 | if 130 | Adjust /= true, Masked /= StartAddr -> error(invalid_cidr); 131 | true -> ok 132 | end, 133 | {Masked, PrefixLen}. 134 | 135 | start_mask({_, _, _, _}=Addr, Len) when Len >= 0, Len =< 32 -> 136 | {A, B, C, D} = end_mask(Addr, Len), 137 | {bnot A, bnot B, bnot C, bnot D}; 138 | 139 | start_mask({_, _, _, _, _, _, _, _}=Addr, Len) when Len >= 0, Len =< 128 -> 140 | {A, B, C, D, E, F, G, H} = end_mask(Addr, Len), 141 | {bnot A, bnot B, bnot C, bnot D, bnot E, bnot F, bnot G, bnot H}. 142 | 143 | end_mask({_, _, _, _}, Len) when Len >= 0, Len =< 32 -> 144 | if 145 | Len == 32 -> {0, 0, 0, 0}; 146 | Len >= 24 -> {0, 0, 0, bmask(Len, 8)}; 147 | Len >= 16 -> {0, 0, bmask(Len, 8), 16#FF}; 148 | Len >= 8 -> {0, bmask(Len, 8), 16#FF, 16#FF}; 149 | Len >= 0 -> {bmask(Len, 8), 16#FF, 16#FF, 16#FF} 150 | end; 151 | 152 | end_mask({_, _, _, _, _, _, _, _}, Len) when Len >= 0, Len =< 128 -> 153 | if 154 | Len == 128 -> {0, 0, 0, 0, 0, 0, 0, 0}; 155 | Len >= 112 -> {0, 0, 0, 0, 0, 0, 0, bmask(Len, 16)}; 156 | Len >= 96 -> {0, 0, 0, 0, 0, 0, bmask(Len, 16), 16#FFFF}; 157 | Len >= 80 -> {0, 0, 0, 0, 0, bmask(Len, 16), 16#FFFF, 16#FFFF}; 158 | Len >= 64 -> {0, 0, 0, 0, bmask(Len, 16), 16#FFFF, 16#FFFF, 16#FFFF}; 159 | Len >= 48 -> {0, 0, 0, bmask(Len, 16), 16#FFFF, 16#FFFF, 16#FFFF, 160 | 16#FFFF}; 161 | Len >= 32 -> {0, 0, bmask(Len, 16), 16#FFFF, 16#FFFF, 16#FFFF, 16#FFFF, 162 | 16#FFFF}; 163 | Len >= 16 -> {0, bmask(Len, 16), 16#FFFF, 16#FFFF, 16#FFFF, 16#FFFF, 164 | 16#FFFF, 16#FFFF}; 165 | Len >= 0 -> {bmask(Len, 16), 16#FFFF, 16#FFFF, 16#FFFF, 16#FFFF, 166 | 16#FFFF, 16#FFFF, 16#FFFF} 167 | end. 168 | 169 | bmask(I, 8) when I >= 0, I =< 32 -> 170 | 16#FF bsr (I rem 8); 171 | bmask(I, 16) when I >= 0, I =< 128 -> 172 | 16#FFFF bsr (I rem 16). 173 | 174 | calc_end_address(Addr, Len) -> 175 | bor_with_mask(Addr, end_mask(Addr, Len)). 176 | 177 | bor_with_mask({A, B, C, D}, {E, F, G, H}) -> 178 | {A bor E, B bor F, C bor G, D bor H}; 179 | bor_with_mask({A, B, C, D, E, F, G, H}, {I, J, K, L, M, N, O, P}) -> 180 | {A bor I, B bor J, C bor K, D bor L, E bor M, F bor N, G bor O, H bor P}. 181 | 182 | band_with_mask({A, B, C, D}, {E, F, G, H}) -> 183 | {A band E, B band F, C band G, D band H}; 184 | band_with_mask({A, B, C, D, E, F, G, H}, {I, J, K, L, M, N, O, P}) -> 185 | {A band I, B band J, C band K, D band L, E band M, F band N, G band O, 186 | H band P}. 187 | 188 | ip_lte({A, B, C, D1}, {A, B, C, D2}) -> D1 =< D2; 189 | ip_lte({A, B, C1, _}, {A, B, C2, _}) -> C1 =< C2; 190 | ip_lte({A, B1, _, _}, {A, B2, _, _}) -> B1 =< B2; 191 | ip_lte({A1, _, _, _}, {A2, _, _, _}) -> A1 =< A2; 192 | ip_lte({A, B, C, D, E, F, G, H1}, {A, B, C, D, E, F, G, H2}) -> H1 =< H2; 193 | ip_lte({A, B, C, D, E, F, G1, _}, {A, B, C, D, E, F, G2, _}) -> G1 =< G2; 194 | ip_lte({A, B, C, D, E, F1, _, _}, {A, B, C, D, E, F2, _, _}) -> F1 =< F2; 195 | ip_lte({A, B, C, D, E1, _, _, _}, {A, B, C, D, E2, _, _, _}) -> E1 =< E2; 196 | ip_lte({A, B, C, D1, _, _, _, _}, {A, B, C, D2, _, _, _, _}) -> D1 =< D2; 197 | ip_lte({A, B, C1, _, _, _, _, _}, {A, B, C2, _, _, _, _, _}) -> C1 =< C2; 198 | ip_lte({A, B1, _, _, _, _, _, _}, {A, B2, _, _, _, _, _, _}) -> B1 =< B2; 199 | ip_lte({A1, _, _, _, _, _, _, _}, {A2, _, _, _, _, _, _, _}) -> A1 =< A2. 200 | 201 | ip_gte({A, B, C, D1}, {A, B, C, D2}) -> D1 >= D2; 202 | ip_gte({A, B, C1, _}, {A, B, C2, _}) -> C1 >= C2; 203 | ip_gte({A, B1, _, _}, {A, B2, _, _}) -> B1 >= B2; 204 | ip_gte({A1, _, _, _}, {A2, _, _, _}) -> A1 >= A2; 205 | ip_gte({A, B, C, D, E, F, G, H1}, {A, B, C, D, E, F, G, H2}) -> H1 >= H2; 206 | ip_gte({A, B, C, D, E, F, G1, _}, {A, B, C, D, E, F, G2, _}) -> G1 >= G2; 207 | ip_gte({A, B, C, D, E, F1, _, _}, {A, B, C, D, E, F2, _, _}) -> F1 >= F2; 208 | ip_gte({A, B, C, D, E1, _, _, _}, {A, B, C, D, E2, _, _, _}) -> E1 >= E2; 209 | ip_gte({A, B, C, D1, _, _, _, _}, {A, B, C, D2, _, _, _, _}) -> D1 >= D2; 210 | ip_gte({A, B, C1, _, _, _, _, _}, {A, B, C2, _, _, _, _, _}) -> C1 >= C2; 211 | ip_gte({A, B1, _, _, _, _, _, _}, {A, B2, _, _, _, _, _, _}) -> B1 >= B2; 212 | ip_gte({A1, _, _, _, _, _, _, _}, {A2, _, _, _, _, _, _, _}) -> A1 >= A2. 213 | 214 | % @private Compare 2 CIDR specifications based on the following criteria: 215 | % * IPv4 < IPv6 216 | % * If start range matches, sort on mask length 217 | % * Otherwise, sort on start IP 218 | cidr_lte({StartAddr, _, L1}, 219 | {StartAddr, _, L2}) -> 220 | L1 =< L2; 221 | cidr_lte({StartAddr1, _, _L1}, 222 | {StartAddr2, _, _L2}) when tuple_size(StartAddr1) =/= tuple_size(StartAddr2) -> 223 | tuple_size(StartAddr1) =< tuple_size(StartAddr2); 224 | cidr_lte({StartAddr1, _, _L1}, 225 | {StartAddr2, _, _L2}) when tuple_size(StartAddr1) == tuple_size(StartAddr2) -> 226 | ip_lte(StartAddr1, StartAddr2). 227 | 228 | %% @private merge a list of uniquely sorted CIDR blocks to their minimal 229 | %% representation. 230 | merge_sorted_cidrs(SortedCIDRs) -> 231 | merge_sorted_cidrs(SortedCIDRs, []). 232 | 233 | merge_sorted_cidrs([], Acc) -> 234 | lists:reverse(Acc); 235 | merge_sorted_cidrs([CIDR], Acc) -> 236 | lists:reverse([CIDR | Acc]); 237 | merge_sorted_cidrs([CIDR1, CIDR2 | SortedCIDRs], Acc) -> 238 | case contains(CIDR1, CIDR2) of 239 | true -> 240 | merge_sorted_cidrs([CIDR1 | SortedCIDRs], Acc); 241 | false -> 242 | merge_sorted_cidrs([CIDR2 | SortedCIDRs], [CIDR1 | Acc]) 243 | end. 244 | -------------------------------------------------------------------------------- /test/inet_cidr_tests.erl: -------------------------------------------------------------------------------- 1 | -module(inet_cidr_tests). 2 | 3 | -include_lib("eunit/include/eunit.hrl"). 4 | 5 | parse_ipv4_test_() -> 6 | [?_assertEqual({{0, 0, 0, 0}, {255, 255, 255, 255}, 0}, 7 | inet_cidr:parse("192.168.0.0/0", true)), 8 | ?_assertEqual({{192, 0, 0, 0}, {192, 255, 255, 255}, 8}, 9 | inet_cidr:parse("192.168.0.0/8", true)), 10 | ?_assertEqual({{192, 168, 0, 0}, {192, 169, 255, 255}, 15}, 11 | inet_cidr:parse("192.168.0.0/15", true)), 12 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 255, 255}, 16}, 13 | inet_cidr:parse("192.168.0.0/16")), 14 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 127, 255}, 17}, 15 | inet_cidr:parse("192.168.0.0/17")), 16 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 63, 255}, 18}, 17 | inet_cidr:parse("192.168.0.0/18")), 18 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 31, 255}, 19}, 19 | inet_cidr:parse("192.168.0.0/19")), 20 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 15, 255}, 20}, 21 | inet_cidr:parse("192.168.0.0/20")), 22 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 7, 255}, 21}, 23 | inet_cidr:parse("192.168.0.0/21")), 24 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 3, 255}, 22}, 25 | inet_cidr:parse("192.168.0.0/22")), 26 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 1, 255}, 23}, 27 | inet_cidr:parse("192.168.0.0/23")), 28 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 0, 255}, 24}, 29 | inet_cidr:parse("192.168.0.0/24")), 30 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 0, 1}, 31}, 31 | inet_cidr:parse("192.168.0.0/31")), 32 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 0, 0}, 32}, 33 | inet_cidr:parse("192.168.0.0/32")), 34 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 0, 0}, 32}, 35 | inet_cidr:parse(<<"192.168.0.0/32">>)), 36 | ?_assertEqual({{192, 168, 0, 0}, {192, 168, 0, 0}, 32}, 37 | inet_cidr:parse(<<"192.168.0.0">>))]. 38 | 39 | parse_ipv6_test_() -> 40 | [?_assertEqual({{0, 0, 0, 0, 0, 0, 0, 0}, 41 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, 42 | 0}, 43 | inet_cidr:parse("2001:abcd::/0", true)), 44 | ?_assertEqual({{8193, 43981, 0, 0, 0, 0, 0, 0}, 45 | {8193, 43981, 65535, 65535, 65535, 65535, 65535, 65535}, 46 | 32}, 47 | inet_cidr:parse("2001:abcd::/32")), 48 | ?_assertEqual({{8193, 43981, 0, 0, 0, 0, 0, 0}, 49 | {8193, 43981, 32767, 65535, 65535, 65535, 65535, 65535}, 50 | 33}, 51 | inet_cidr:parse("2001:abcd::/33")), 52 | ?_assertEqual({{8193, 43981, 0, 0, 0, 0, 0, 0}, 53 | {8193, 43981, 16383, 65535, 65535, 65535, 65535, 65535}, 54 | 34}, 55 | inet_cidr:parse("2001:abcd::/34")), 56 | ?_assertEqual({{8193, 43981, 0, 0, 0, 0, 0, 0}, 57 | {8193, 43981, 8191, 65535, 65535, 65535, 65535, 65535}, 58 | 35}, 59 | inet_cidr:parse("2001:abcd::/35")), 60 | ?_assertEqual({{8193, 43981, 0, 0, 0, 0, 0, 0}, 61 | {8193, 43981, 4095, 65535, 65535, 65535, 65535, 65535}, 62 | 36}, 63 | inet_cidr:parse("2001:abcd::/36")), 64 | ?_assertEqual({{8193, 43981, 0, 0, 0, 0, 0, 0}, 65 | {8193, 43981, 0, 0, 0, 0, 0, 0}, 66 | 128}, 67 | inet_cidr:parse("2001:abcd::/128")), 68 | ?_assertEqual({{8193, 3512, 0, 0, 0, 0, 0, 0}, 69 | {8193, 3512, 0, 65535, 65535, 65535, 65535, 65535}, 70 | 48}, 71 | inet_cidr:parse("2001:db8::/48")), 72 | ?_assertEqual({{8193, 3512, 0, 0, 0, 0, 0, 0}, 73 | {8193, 3512, 0, 65535, 65535, 65535, 65535, 65535}, 74 | 48}, 75 | inet_cidr:parse(<<"2001:db8::/48">>)), 76 | ?_assertEqual({{8193,3512,0,0,0,0,0,1},{8193,3512,0,0,0,0,0,1},128}, 77 | inet_cidr:parse(<<"2001:0db8::1/128">>)), 78 | ?_assertEqual({{8193,3512,0,0,0,0,0,1},{8193,3512,0,0,0,0,0,1},128}, 79 | inet_cidr:parse(<<"2001:0db8::1">>))] 80 | . 81 | 82 | 83 | to_string_test_() -> 84 | [?_assertEqual("192.168.0.0/16", 85 | inet_cidr:to_string({{192, 168, 0, 0}, {192, 168, 255, 255}, 16})), 86 | ?_assertEqual("2001:abcd::/32", 87 | inet_cidr:to_string({{8193, 43981, 0, 0, 0, 0, 0, 0}, 88 | {8193, 43981, 65535, 65535, 65535, 65535, 65535, 65535}, 89 | 32}))]. 90 | 91 | to_binary_test_() -> 92 | [?_assertEqual(<<"192.168.0.0/16">>, 93 | inet_cidr:to_binary({{192, 168, 0, 0}, {192, 168, 255, 255}, 16})), 94 | ?_assertEqual(<<"2001:abcd::/32">>, 95 | inet_cidr:to_binary({{8193, 43981, 0, 0, 0, 0, 0, 0}, 96 | {8193, 43981, 65535, 65535, 65535, 65535, 65535, 65535}, 97 | 32}))]. 98 | 99 | ipv4_address_count_test_() -> 100 | {ok, Addr} = inet:parse_address("192.168.0.0"), 101 | [?_assertEqual(4294967296, inet_cidr:address_count(Addr, 0)), 102 | ?_assertEqual( 65536, inet_cidr:address_count(Addr, 16)), 103 | ?_assertEqual( 32768, inet_cidr:address_count(Addr, 17)), 104 | ?_assertEqual( 256, inet_cidr:address_count(Addr, 24)), 105 | ?_assertEqual( 1, inet_cidr:address_count(Addr, 32))]. 106 | 107 | ipv6_address_count_test_() -> 108 | {ok, Addr} = inet:parse_address("2001::abcd"), 109 | [?_assertEqual(1 bsl 128, inet_cidr:address_count(Addr, 0)), 110 | ?_assertEqual(1 bsl 64, inet_cidr:address_count(Addr, 64)), 111 | ?_assertEqual(1, inet_cidr:address_count(Addr, 128))]. 112 | 113 | contains_test_() -> 114 | Block = inet_cidr:parse("192.168.1.0/24"), 115 | [?_assertNot(inet_cidr:contains(Block, {}))]. 116 | 117 | ipv4_contains_test_() -> 118 | Block = {{192, 168, 0, 0}, {192, 168, 255, 255}, 16}, 119 | [?_assert(inet_cidr:contains(Block, {192, 168, 0, 0})), 120 | ?_assert(inet_cidr:contains(Block, {192, 168, 0, 1})), 121 | ?_assert(inet_cidr:contains(Block, {192, 168, 1, 0})), 122 | ?_assert(inet_cidr:contains(Block, {192, 168, 0, 255})), 123 | ?_assert(inet_cidr:contains(Block, {192, 168, 255, 0})), 124 | ?_assert(inet_cidr:contains(Block, {192, 168, 255, 255})), 125 | ?_assertNot(inet_cidr:contains(Block, {192, 168, 255, 256})), 126 | ?_assertNot(inet_cidr:contains(Block, {192, 169, 0, 0})), 127 | ?_assertNot(inet_cidr:contains(Block, {192, 167, 255, 255}))]. 128 | 129 | ipv4_contains_cidr_test_() -> 130 | Block = {{192, 168, 0, 0}, {192, 168, 255, 255}, 16}, 131 | [?_assert(inet_cidr:contains(Block, Block)), 132 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("192.168.1.0/24"))), 133 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("192.168.254.0/24"))), 134 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("192.168.1.2/31"))), 135 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("192.168.1.1/32"))), 136 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("10.0.0.0/16"))), 137 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("10.0.0.1/32"))), 138 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("192.169.0.0/16"))), 139 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("192.168.0.0/15")))]. 140 | 141 | ipv6_contains_test_() -> 142 | Block = {{8193, 43981, 0, 0, 0, 0, 0, 0}, 143 | {8193, 43981, 8191, 65535, 65535, 65535, 65535, 65535}, 144 | 35}, 145 | [?_assert(inet_cidr:contains(Block, {8193, 43981, 0, 0, 0, 0, 0, 0})), 146 | ?_assert(inet_cidr:contains(Block, {8193, 43981, 0, 0, 0, 0, 0, 1})), 147 | ?_assert(inet_cidr:contains(Block, {8193, 43981, 8191, 65535, 65535, 65535, 65535, 65534})), 148 | ?_assert(inet_cidr:contains(Block, {8193, 43981, 8191, 65535, 65535, 65535, 65535, 65535})), 149 | ?_assertNot(inet_cidr:contains(Block, {8193, 43981, 8192, 65535, 65535, 65535, 65535, 65535})), 150 | ?_assertNot(inet_cidr:contains(Block, {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}))]. 151 | 152 | ipv6_contains_cidr_test_() -> 153 | Block = inet_cidr:parse("2001:abcd::/32"), 154 | [?_assert(inet_cidr:contains(Block, Block)), 155 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("2001:abcd:1:1:1:1:1:1/128"))), 156 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("2001:abcd:2000::/35"))), 157 | ?_assert(inet_cidr:contains(Block, inet_cidr:parse("2001:abcd:2000:1:1:1::/96"))), 158 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("2002:abcd::/35"))), 159 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("2002:abcd:1:1:1:1:1:1/128"))), 160 | ?_assertNot(inet_cidr:contains(Block, inet_cidr:parse("2001:ffff::/35")))]. 161 | 162 | usort_cidrs_test_() -> 163 | [?_assertEqual([], inet_cidr:usort_cidrs([])), 164 | ?_assertEqual([inet_cidr:parse("10.0.0.0/8")], 165 | inet_cidr:usort_cidrs([inet_cidr:parse("10.0.0.0/8")])), 166 | ?_assertEqual([inet_cidr:parse("10.0.0.0/8")], 167 | inet_cidr:usort_cidrs([inet_cidr:parse("10.0.0.0/8"), 168 | inet_cidr:parse("10.0.0.0/8")])), 169 | ?_assertEqual([inet_cidr:parse("2001:abcd::/32")], 170 | inet_cidr:usort_cidrs([inet_cidr:parse("2001:abcd::/32")])), 171 | ?_assertEqual([inet_cidr:parse("2001:abcd::/32")], 172 | inet_cidr:usort_cidrs([inet_cidr:parse("2001:abcd::/32"), 173 | inet_cidr:parse("2001:abcd::/32")])), 174 | ?_assertEqual([inet_cidr:parse("10.0.0.0/8"), 175 | inet_cidr:parse("2001:abcd::/32")], 176 | inet_cidr:usort_cidrs([inet_cidr:parse("2001:abcd::/32"), 177 | inet_cidr:parse("10.0.0.0/8"), 178 | inet_cidr:parse("2001:abcd::/32"), 179 | inet_cidr:parse("10.0.0.0/8")])), 180 | ?_assertEqual([inet_cidr:parse("10.0.0.0/8"), 181 | inet_cidr:parse("10.0.0.0/16"), 182 | inet_cidr:parse("10.1.0.0/16"), 183 | inet_cidr:parse("2001:abcd::/32")], 184 | inet_cidr:usort_cidrs([inet_cidr:parse("2001:abcd::/32"), 185 | inet_cidr:parse("10.1.0.0/16"), 186 | inet_cidr:parse("10.0.0.0/8"), 187 | inet_cidr:parse("10.0.0.0/16"), 188 | inet_cidr:parse("10.0.0.0/8")])), 189 | ?_assertEqual([inet_cidr:parse("10.0.0.0/8"), 190 | inet_cidr:parse("2001:abcd::/32"), 191 | inet_cidr:parse("2001:abcd:1::/48"), 192 | inet_cidr:parse("2001:abcd:1::/64"), 193 | inet_cidr:parse("2001:abcd:1::1/128")], 194 | inet_cidr:usort_cidrs([inet_cidr:parse("2001:abcd::/32"), 195 | inet_cidr:parse("2001:abcd:1::1/128"), 196 | inet_cidr:parse("2001:abcd:1::/64"), 197 | inet_cidr:parse("10.0.0.0/8"), 198 | inet_cidr:parse("2001:abcd:1::1/128"), 199 | inet_cidr:parse("2001:abcd:1::/48"), 200 | inet_cidr:parse("10.0.0.0/8"), 201 | inet_cidr:parse("2001:abcd:1::/64")]))]. 202 | 203 | merge_cidrs_test_() -> 204 | [?_assertEqual([], inet_cidr:merge_cidrs([])), 205 | ?_assertEqual([inet_cidr:parse("10.0.0.0/16"), 206 | inet_cidr:parse("10.10.0.0/16")], 207 | inet_cidr:merge_cidrs([inet_cidr:parse("10.10.0.0/16"), 208 | inet_cidr:parse("10.0.0.1/32"), 209 | inet_cidr:parse("10.10.99.0/24"), 210 | inet_cidr:parse("10.0.99.0/24"), 211 | inet_cidr:parse("10.0.0.0/16")])), 212 | ?_assertEqual([inet_cidr:parse("10.0.1.1/32"), 213 | inet_cidr:parse("10.0.1.2/31"), 214 | inet_cidr:parse("10.0.1.4/30")], 215 | inet_cidr:merge_cidrs([inet_cidr:parse("10.0.1.4/30"), 216 | inet_cidr:parse("10.0.1.4/32"), 217 | inet_cidr:parse("10.0.1.2/31"), 218 | inet_cidr:parse("10.0.1.1/32"), 219 | inet_cidr:parse("10.0.1.3/32"), 220 | inet_cidr:parse("10.0.1.4/30")])), 221 | ?_assertEqual([inet_cidr:parse("10.0.0.0/16")], 222 | inet_cidr:merge_cidrs([inet_cidr:parse("10.0.1.0/24"), 223 | inet_cidr:parse("10.0.254.0/24"), 224 | inet_cidr:parse("10.0.0.0/16"), 225 | inet_cidr:parse("10.0.100.99/32"), 226 | inet_cidr:parse("10.0.0.0/16")])), 227 | ?_assertEqual([inet_cidr:parse("10.0.0.0/8"), 228 | inet_cidr:parse("2001:abcd::/32")], 229 | inet_cidr:merge_cidrs([inet_cidr:parse("2001:abcd::/32"), 230 | inet_cidr:parse("2001:abcd:1::1/128"), 231 | inet_cidr:parse("2001:abcd:1::/64"), 232 | inet_cidr:parse("10.0.0.0/8"), 233 | inet_cidr:parse("2001:abcd:1::1/128"), 234 | inet_cidr:parse("2001:abcd:1::/48"), 235 | inet_cidr:parse("10.0.0.0/8"), 236 | inet_cidr:parse("2001:abcd:1::/64")])), 237 | ?_assertEqual([inet_cidr:parse("2001:abcd::/32")], 238 | inet_cidr:merge_cidrs([inet_cidr:parse("2001:abcd:abcd::/48"), 239 | inet_cidr:parse("2001:abcd:1234::/48"), 240 | inet_cidr:parse("2001:abcd:9999::/48"), 241 | inet_cidr:parse("2001:abcd::/32"), 242 | inet_cidr:parse("2001:abcd:abcd::1/128"), 243 | inet_cidr:parse("2001:abcd:abcd::4/126"), 244 | inet_cidr:parse("2001:abcd:abcd:0:0:abcd::/96")]))]. 245 | 246 | is_ipv4_test_() -> 247 | {ok, Addr} = inet:parse_address("2001::abcd"), 248 | [?_assert(inet_cidr:is_ipv4({192, 168, 0, 0})), 249 | ?_assertNot(inet_cidr:is_ipv4({192, 168, 0, 256})), 250 | ?_assertNot(inet_cidr:is_ipv4({192, 168, 0})), 251 | ?_assertNot(inet_cidr:is_ipv4({192, 168, 0, 0, 0})), 252 | ?_assertNot(inet_cidr:is_ipv4(Addr))]. 253 | 254 | is_ipv6_test_() -> 255 | [?_assert(inet_cidr:is_ipv6({8193, 43981, 0, 0, 0, 0, 0, 0})), 256 | ?_assertNot(inet_cidr:is_ipv6({192, 168, 0, 0})), 257 | ?_assertNot(inet_cidr:is_ipv6({8193, 43981, 0, 0, 0, 0, 0, 70000})), 258 | ?_assertNot(inet_cidr:is_ipv6({8193, 43981, 0, 0, 0, 0, 0})), 259 | ?_assertNot(inet_cidr:is_ipv6({8193, 43981, 0, 0, 0, 0, 0, 0, 0}))]. 260 | 261 | ipv4_ip_lte_test_() -> 262 | [?_assert(inet_cidr:ip_lte({0, 0, 0, 0}, {0, 0, 0, 0})), 263 | ?_assert(inet_cidr:ip_lte({255, 255, 255, 255}, {255, 255, 255, 255})), 264 | ?_assert(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 168, 1, 1})), 265 | ?_assert(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 168, 1, 2})), 266 | ?_assert(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 168, 2, 1})), 267 | ?_assert(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 169, 1, 1})), 268 | ?_assert(inet_cidr:ip_lte({192, 168, 1, 1}, {193, 168, 1, 1})), 269 | ?_assertNot(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 168, 1, 0})), 270 | ?_assertNot(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 168, 0, 1})), 271 | ?_assertNot(inet_cidr:ip_lte({192, 168, 1, 1}, {192, 167, 1, 1})), 272 | ?_assertNot(inet_cidr:ip_lte({192, 168, 1, 1}, {191, 168, 1, 1}))]. 273 | 274 | ipv6_ip_lte_test_() -> 275 | [?_assert(inet_cidr:ip_lte({0, 0, 0, 0, 0, 0, 0, 0}, 276 | {0, 0, 0, 0, 0, 0, 0, 0})), 277 | ?_assert(inet_cidr:ip_lte({65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, 278 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535})), 279 | ?_assert(inet_cidr:ip_lte({0, 0, 0, 0, 0, 0, 0, 0}, 280 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535})), 281 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 282 | {8193, 43981, 6, 5, 4, 3, 2, 1})), 283 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 284 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535})), 285 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 286 | {8193, 43981, 6, 5, 4, 3, 2, 2})), 287 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 288 | {8193, 43981, 6, 5, 4, 3, 3, 1})), 289 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 290 | {8193, 43981, 6, 5, 4, 4, 2, 1})), 291 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 292 | {8193, 43981, 6, 5, 5, 3, 2, 1})), 293 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 294 | {8193, 43981, 6, 6, 4, 3, 2, 1})), 295 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 296 | {8193, 43981, 7, 5, 4, 3, 2, 1})), 297 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 298 | {8193, 43982, 6, 5, 4, 3, 2, 1})), 299 | ?_assert(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 300 | {8194, 43981, 6, 5, 4, 3, 2, 1})), 301 | ?_assertNot(inet_cidr:ip_lte({65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, 302 | {8193, 43981, 6, 5, 4, 3, 2, 1})), 303 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 2}, 304 | {8193, 43981, 6, 5, 4, 3, 2, 1})), 305 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 306 | {8193, 43981, 6, 5, 4, 3, 1, 1})), 307 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 308 | {8193, 43981, 6, 5, 4, 2, 2, 1})), 309 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 310 | {8193, 43981, 6, 5, 3, 3, 2, 1})), 311 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 312 | {8193, 43981, 6, 4, 4, 3, 2, 1})), 313 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 314 | {8193, 43981, 5, 5, 4, 3, 2, 1})), 315 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 316 | {8193, 43980, 6, 5, 4, 3, 2, 1})), 317 | ?_assertNot(inet_cidr:ip_lte({8193, 43981, 6, 5, 4, 3, 2, 1}, 318 | {8192, 43981, 6, 5, 4, 3, 2, 1}))]. 319 | 320 | ipv4_ip_gte_test_() -> 321 | [?_assert(inet_cidr:ip_gte({0, 0, 0, 0}, {0, 0, 0, 0})), 322 | ?_assert(inet_cidr:ip_gte({255, 255, 255, 255}, {255, 255, 255, 255})), 323 | ?_assert(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 168, 1, 1})), 324 | ?_assert(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 168, 1, 0})), 325 | ?_assert(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 168, 0, 1})), 326 | ?_assert(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 167, 1, 1})), 327 | ?_assert(inet_cidr:ip_gte({192, 168, 1, 1}, {191, 168, 1, 1})), 328 | ?_assertNot(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 168, 1, 2})), 329 | ?_assertNot(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 168, 2, 1})), 330 | ?_assertNot(inet_cidr:ip_gte({192, 168, 1, 1}, {192, 169, 1, 1})), 331 | ?_assertNot(inet_cidr:ip_gte({192, 168, 1, 1}, {193, 168, 1, 1}))]. 332 | 333 | ipv6_ip_gte_test_() -> 334 | [?_assert(inet_cidr:ip_gte({0, 0, 0, 0, 0, 0, 0, 0}, 335 | {0, 0, 0, 0, 0, 0, 0, 0})), 336 | ?_assert(inet_cidr:ip_gte({65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, 337 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535})), 338 | ?_assert(inet_cidr:ip_gte({65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535}, 339 | {8193, 43981, 6, 5, 4, 3, 2, 1})), 340 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 341 | {8193, 43981, 6, 5, 4, 3, 2, 1})), 342 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 2}, 343 | {8193, 43981, 6, 5, 4, 3, 2, 1})), 344 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 345 | {8193, 43981, 6, 5, 4, 3, 1, 1})), 346 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 347 | {8193, 43981, 6, 5, 4, 2, 2, 1})), 348 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 349 | {8193, 43981, 6, 5, 3, 3, 2, 1})), 350 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 351 | {8193, 43981, 6, 4, 4, 3, 2, 1})), 352 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 353 | {8193, 43981, 5, 5, 4, 3, 2, 1})), 354 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 355 | {8193, 43980, 6, 5, 4, 3, 2, 1})), 356 | ?_assert(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 357 | {8192, 43981, 6, 5, 4, 3, 2, 1})), 358 | ?_assertNot(inet_cidr:ip_gte({0, 0, 0, 0, 0, 0, 0, 0}, 359 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535})), 360 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 361 | {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535})), 362 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 363 | {8193, 43981, 6, 5, 4, 3, 2, 2})), 364 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 365 | {8193, 43981, 6, 5, 4, 3, 3, 1})), 366 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 367 | {8193, 43981, 6, 5, 4, 4, 2, 1})), 368 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 369 | {8193, 43981, 6, 5, 5, 3, 2, 1})), 370 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 371 | {8193, 43981, 6, 6, 4, 3, 2, 1})), 372 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 373 | {8193, 43981, 7, 5, 4, 3, 2, 1})), 374 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 375 | {8193, 43982, 6, 5, 4, 3, 2, 1})), 376 | ?_assertNot(inet_cidr:ip_gte({8193, 43981, 6, 5, 4, 3, 2, 1}, 377 | {8194, 43981, 6, 5, 4, 3, 2, 1}))]. 378 | --------------------------------------------------------------------------------