| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- %%--------------------------------------------------------------------
- %% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
- %%
- %% Licensed under the Apache License, Version 2.0 (the "License");
- %% you may not use this file except in compliance with the License.
- %% You may obtain a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing, software
- %% distributed under the License is distributed on an "AS IS" BASIS,
- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- %% See the License for the specific language governing permissions and
- %% limitations under the License.
- %%--------------------------------------------------------------------
- -module(esockd_access).
- -type cidr() :: string().
- -type rule() :: {allow, all} |
- {allow, cidr()} |
- {deny, all} |
- {deny, cidr()}.
- -type range() :: {cidr(), pos_integer(), pos_integer()}.
- -export_type([cidr/0, range/0, rule/0]).
- -type range_rule() :: {allow, all} |
- {allow, range()} |
- {deny, all} |
- {deny, range()}.
- -export([rule/1, match/2, range/1, mask/1, atoi/1, itoa/1]).
- %%------------------------------------------------------------------------------
- %% @doc
- %% Build CIDR, Make rule.
- %%
- %% @end
- %%------------------------------------------------------------------------------
- -spec rule(rule()) -> range_rule().
- rule({allow, all}) ->
- {allow, all};
- rule({allow, CIDR}) when is_list(CIDR) ->
- rule(allow, CIDR);
- rule({deny, CIDR}) when is_list(CIDR) ->
- rule(deny, CIDR);
- rule({deny, all}) ->
- {deny, all}.
- rule(Type, CIDR) when is_list(CIDR) ->
- {Start, End} = range(CIDR), {Type, {CIDR, Start, End}}.
- %%------------------------------------------------------------------------------
- %% @doc
- %% Match Addr with Access Rules.
- %%
- %% @end
- %%------------------------------------------------------------------------------
- -spec match(inet:ip_address(), [range_rule()]) -> {matched, allow} | {matched, deny} | nomatch.
- match(Addr, Rules) when is_tuple(Addr) ->
- match2(atoi(Addr), Rules).
- match2(_I, []) ->
- nomatch;
- match2(_I, [{allow, all}|_]) ->
- {matched, allow};
- match2(I, [{allow, {_, Start, End}}|_]) when I >= Start, I =< End ->
- {matched, allow};
- match2(I, [{allow, {_, _Start, _End}}|Rules]) ->
- match2(I, Rules);
- match2(I, [{deny, {_, Start, End}}|_]) when I >= Start, I =< End ->
- {matched, deny};
- match2(I, [{deny, {_, _Start, _End}}|Rules]) ->
- match2(I, Rules);
- match2(_I, [{deny, all}|_]) ->
- {matched, deny}.
- %%------------------------------------------------------------------------------
- %% @doc
- %% CIDR range.
- %%
- %% @end
- %%------------------------------------------------------------------------------
- -spec range(cidr()) -> {pos_integer(), pos_integer()}.
- range(CIDR) ->
- case string:tokens(CIDR, "/") of
- [Addr] ->
- {ok, IP} = inet:getaddr(Addr, inet),
- {atoi(IP), atoi(IP)};
- [Addr, Mask] ->
- {ok, IP} = inet:getaddr(Addr, inet),
- {Start, End} = subnet(IP, mask(list_to_integer(Mask))),
- {Start, End}
- end.
- subnet(IP, Mask) ->
- Start = atoi(IP) band Mask,
- End = Start bor (Mask bxor 16#FFFFFFFF),
- {Start, End}.
- %%------------------------------------------------------------------------------
- %% @doc
- %% Mask Int
- %%
- %% @end
- %%------------------------------------------------------------------------------
- -spec mask(0..32) -> 0..16#FFFFFFFF.
- mask(0) ->
- 16#00000000;
- mask(32) ->
- 16#FFFFFFFF;
- mask(N) when N >= 1, N =< 31 ->
- lists:foldl(fun(I, Mask) -> (1 bsl I) bor Mask end, 0, lists:seq(32 - N, 31)).
- %%------------------------------------------------------------------------------
- %% @doc
- %% Addr to Integer.
- %%
- %% @end
- %%------------------------------------------------------------------------------
- atoi({A, B, C, D}) ->
- (A bsl 24) + (B bsl 16) + (C bsl 8) + D.
- %%------------------------------------------------------------------------------
- %% @doc
- %% Integer to Addr.
- %%
- %% @end
- %%------------------------------------------------------------------------------
- itoa(I) ->
- A = (I bsr 24) band 16#FF,
- B = (I bsr 16) band 16#FF,
- C = (I bsr 8) band 16#FF,
- D = I band 16#FF,
- {A, B, C, D}.
|