esockd_access.erl 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(esockd_access).
  17. -type cidr() :: string().
  18. -type rule() :: {allow, all} |
  19. {allow, cidr()} |
  20. {deny, all} |
  21. {deny, cidr()}.
  22. -type range() :: {cidr(), pos_integer(), pos_integer()}.
  23. -export_type([cidr/0, range/0, rule/0]).
  24. -type range_rule() :: {allow, all} |
  25. {allow, range()} |
  26. {deny, all} |
  27. {deny, range()}.
  28. -export([rule/1, match/2, range/1, mask/1, atoi/1, itoa/1]).
  29. %%------------------------------------------------------------------------------
  30. %% @doc
  31. %% Build CIDR, Make rule.
  32. %%
  33. %% @end
  34. %%------------------------------------------------------------------------------
  35. -spec rule(rule()) -> range_rule().
  36. rule({allow, all}) ->
  37. {allow, all};
  38. rule({allow, CIDR}) when is_list(CIDR) ->
  39. rule(allow, CIDR);
  40. rule({deny, CIDR}) when is_list(CIDR) ->
  41. rule(deny, CIDR);
  42. rule({deny, all}) ->
  43. {deny, all}.
  44. rule(Type, CIDR) when is_list(CIDR) ->
  45. {Start, End} = range(CIDR), {Type, {CIDR, Start, End}}.
  46. %%------------------------------------------------------------------------------
  47. %% @doc
  48. %% Match Addr with Access Rules.
  49. %%
  50. %% @end
  51. %%------------------------------------------------------------------------------
  52. -spec match(inet:ip_address(), [range_rule()]) -> {matched, allow} | {matched, deny} | nomatch.
  53. match(Addr, Rules) when is_tuple(Addr) ->
  54. match2(atoi(Addr), Rules).
  55. match2(_I, []) ->
  56. nomatch;
  57. match2(_I, [{allow, all}|_]) ->
  58. {matched, allow};
  59. match2(I, [{allow, {_, Start, End}}|_]) when I >= Start, I =< End ->
  60. {matched, allow};
  61. match2(I, [{allow, {_, _Start, _End}}|Rules]) ->
  62. match2(I, Rules);
  63. match2(I, [{deny, {_, Start, End}}|_]) when I >= Start, I =< End ->
  64. {matched, deny};
  65. match2(I, [{deny, {_, _Start, _End}}|Rules]) ->
  66. match2(I, Rules);
  67. match2(_I, [{deny, all}|_]) ->
  68. {matched, deny}.
  69. %%------------------------------------------------------------------------------
  70. %% @doc
  71. %% CIDR range.
  72. %%
  73. %% @end
  74. %%------------------------------------------------------------------------------
  75. -spec range(cidr()) -> {pos_integer(), pos_integer()}.
  76. range(CIDR) ->
  77. case string:tokens(CIDR, "/") of
  78. [Addr] ->
  79. {ok, IP} = inet:getaddr(Addr, inet),
  80. {atoi(IP), atoi(IP)};
  81. [Addr, Mask] ->
  82. {ok, IP} = inet:getaddr(Addr, inet),
  83. {Start, End} = subnet(IP, mask(list_to_integer(Mask))),
  84. {Start, End}
  85. end.
  86. subnet(IP, Mask) ->
  87. Start = atoi(IP) band Mask,
  88. End = Start bor (Mask bxor 16#FFFFFFFF),
  89. {Start, End}.
  90. %%------------------------------------------------------------------------------
  91. %% @doc
  92. %% Mask Int
  93. %%
  94. %% @end
  95. %%------------------------------------------------------------------------------
  96. -spec mask(0..32) -> 0..16#FFFFFFFF.
  97. mask(0) ->
  98. 16#00000000;
  99. mask(32) ->
  100. 16#FFFFFFFF;
  101. mask(N) when N >= 1, N =< 31 ->
  102. lists:foldl(fun(I, Mask) -> (1 bsl I) bor Mask end, 0, lists:seq(32 - N, 31)).
  103. %%------------------------------------------------------------------------------
  104. %% @doc
  105. %% Addr to Integer.
  106. %%
  107. %% @end
  108. %%------------------------------------------------------------------------------
  109. atoi({A, B, C, D}) ->
  110. (A bsl 24) + (B bsl 16) + (C bsl 8) + D.
  111. %%------------------------------------------------------------------------------
  112. %% @doc
  113. %% Integer to Addr.
  114. %%
  115. %% @end
  116. %%------------------------------------------------------------------------------
  117. itoa(I) ->
  118. A = (I bsr 24) band 16#FF,
  119. B = (I bsr 16) band 16#FF,
  120. C = (I bsr 8) band 16#FF,
  121. D = I band 16#FF,
  122. {A, B, C, D}.