1%%-------------------------------------------------------------------- 2%% 3%% %CopyrightBegin% 4%% 5%% Copyright Ericsson AB 2004-2016. All Rights Reserved. 6%% 7%% Licensed under the Apache License, Version 2.0 (the "License"); 8%% you may not use this file except in compliance with the License. 9%% You may obtain a copy of the License at 10%% 11%% http://www.apache.org/licenses/LICENSE-2.0 12%% 13%% Unless required by applicable law or agreed to in writing, software 14%% distributed under the License is distributed on an "AS IS" BASIS, 15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16%% See the License for the specific language governing permissions and 17%% limitations under the License. 18%% 19%% %CopyrightEnd% 20%% 21%% 22%%----------------------------------------------------------------- 23%% File: orber_acl.erl 24%% 25%% Description: 26%% Handling ACL's (Access Control Lists). 27%% 28%% Creation date: 040723 29%% 30%%----------------------------------------------------------------- 31-module(orber_acl). 32 33-include_lib("orber/include/corba.hrl"). 34-include_lib("orber/src/orber_iiop.hrl"). 35 36%%----------------------------------------------------------------- 37%% External exports 38%%----------------------------------------------------------------- 39-export([init_acl/1, init_acl/2, clear_acl/0, 40 match/2, match/3, verify/3, range/1, range/2]). 41 42%%----------------------------------------------------------------- 43%% Internal exports 44%%----------------------------------------------------------------- 45-define(ACL_DB, orber_acl_db). 46 47-define(DEBUG_LEVEL, 5). 48-define(CONTINUE, -1). 49-define(STOP, -2). 50 51-define(FORMAT(_F, _A), {error, lists:flatten(io_lib:format(_F, _A))}). 52-define(EFORMAT(_F, _A), exit(lists:flatten(io_lib:format(_F, _A)))). 53 54%%----------------------------------------------------------------- 55%% Record Definitions 56%%----------------------------------------------------------------- 57-record(acl, {key, bits = ?CONTINUE, mask, interfaces = [], 58 ports = 0, flags = 0}). 59 60%%----------------------------------------------------------------- 61%% External functions 62%%----------------------------------------------------------------- 63 64%%----------------------------------------------------------------- 65%% function : verify/1 66%% Arguments: IP - string() 67%% Filter - string() see init_acl 68%% Family - inet | inet6 69%% Returns : boolean() 70%% Exception: 71%% Effect : 72%%----------------------------------------------------------------- 73verify(IP, Filter, Family) -> 74 DB = ets:new(orber_temporary_acl_table_created_by_user, 75 [set, public, {keypos, 2}]), 76 Result = 77 case catch verify_helper(IP, Filter, Family, DB) of 78 true -> 79 true; 80 {ok, Low, High} -> 81 {false, Low, High}; 82 What -> 83 {error, ?FORMAT("Uknown Error: ~p\n", [What])} 84 end, 85 ets:delete(DB), 86 Result. 87 88verify_helper(IP, Filter, Family, DB) -> 89 init_acl([{tcp_in, Filter}], Family, DB), 90 {ok, IPTuple} = inet:getaddr(IP, Family), 91 case match_helper(tuple_to_list(IPTuple), tcp_in, DB, false, tcp_in) of 92 true -> 93 true; 94 false -> 95 range(Filter, Family) 96 end. 97 98%%----------------------------------------------------------------- 99%% function : range/1/2 100%% Arguments: Filter - string(). See init_acl 101%% Family - inet | inet6 102%% Returns : {ok, From, To} 103%% From - To - string() 104%% Exception: 105%% Effect : 106%%----------------------------------------------------------------- 107range(Filter) -> 108 range(Filter, inet). 109 110range(Filter, inet) -> 111 range_safe(Filter, inet, ".", 16#FF, "255", 8, "~p.", "~p", 3); 112range(Filter, Family) -> 113 range_safe(Filter, Family, ":", 16#FFFF, "FFFF", 16, "~.16B:", "~.16B", 7). 114 115range_safe(Filter, Family, Separator, Max, MaxStr, N, F1, F2, X) -> 116 case catch range_helper(Filter, Family, Separator, Max, MaxStr, N, F1, F2, X) of 117 {ok, Low, High} -> 118 {ok, Low, High}; 119 {'EXIT',{format,Why}} -> 120 {error, ?FORMAT("Unable to format string: ~p\n", [Why])}; 121 {'EXIT', E} -> 122 {error, ?FORMAT("Exit: ~p\n", [E])}; 123 What -> 124 {error, ?FORMAT("Unknown Error: ~p\n", [What])} 125 end. 126 127range_helper(Filter, Family, Separator, Max, MaxStr, N, F1, F2, X) -> 128 {MaskStr, Bits, _Ports} = tokenize(Filter, Family), 129 {ok, MaskTuple} = inet:getaddr(MaskStr, Family), 130 NoOfFull = Bits div N, 131 Mask = get_mask(N, (Bits rem N)), 132 case split(NoOfFull, tuple_to_list(MaskTuple)) of 133 {Full, [Partial|_DontCare]} -> 134 Beginning = pp(Full, [], F1), 135 MiddleLow = io_lib:format(F2, [(Mask band Partial) + ((Mask bxor Max) band 0)]), 136 MiddleHigh = io_lib:format(F2, [(Mask band Partial) + ((Mask bxor Max) band Max)]), 137 EndLow = lists:duplicate((X-NoOfFull), Separator ++ "0"), 138 EndHigh = lists:duplicate((X-NoOfFull), Separator ++ MaxStr), 139 Low = lists:flatten([Beginning, MiddleLow, EndLow]), 140 High = lists:flatten([Beginning, MiddleHigh, EndHigh]), 141 {ok, Low, High}; 142 {Full, []} -> 143 Address = lists:flatten(pp(Full, [], F1)), 144 {ok, Address, Address} 145 end. 146 147pp([], Acc, _) -> 148 Acc; 149pp([H|T], Acc, Format) -> 150 pp(T, Acc ++ io_lib:format(Format, [H]), Format). 151 152split(N, List) when is_integer(N) andalso N >= 0 andalso is_list(List) -> 153 case split(N, List, []) of 154 Fault when is_atom(Fault) -> 155 erlang:error(Fault, [N,List]); 156 Result -> 157 Result 158 end; 159split(N, List) -> 160 erlang:error(badarg, [N,List]). 161 162split(0, L, R) -> 163 {lists:reverse(R, []), L}; 164split(N, [H|T], R) -> 165 split(N-1, T, [H|R]); 166split(_, [], _) -> 167 badarg. 168 169 170%%----------------------------------------------------------------- 171%% function : clear_acl/0 172%% Arguments: - 173%% Returns : 174%% Exception: 175%% Effect : 176%%----------------------------------------------------------------- 177clear_acl() -> 178 clear_acl(?ACL_DB). 179clear_acl(DB) -> 180 (catch ets:delete(DB)), 181 ok. 182 183%%----------------------------------------------------------------- 184%% function : init_acl/1/2 185%% Arguments: Filters - [{Direction, Filter}] | [{Direction, Filter, [Interfaces]}] 186%% Direction - tcp_in | ssl_in | tcp_out | ssl_out 187%% Filter - string(). Examples: 188%% * "123.456.789.10" - match against all bits. 189%% * "123.456.789.10/17" - match against the 17 most significant bits. 190%% * "123.456.789.10/17#4001" - as above but only allow port 4001 191%% * "123.456.789.10/17#4001/5001" - as above but only allow port 4001-5001 192%% Family - inet | inet6 193%% Returns : ok | {'EXCEPTION', E} 194%% Exception: 'BAD_PARAM' 195%% Effect : 196%%----------------------------------------------------------------- 197init_acl(Filters) -> 198 DB = ets:new(?ACL_DB, [set, public, named_table, {keypos, 2}]), 199 case ?ORB_FLAG_TEST(orber:get_flags(), ?ORB_ENV_USE_IPV6) of 200 false -> 201 init_acl(Filters, inet, DB); 202 true -> 203 init_acl(Filters, inet6, DB) 204 end. 205 206init_acl(Filters, Family) -> 207 DB = ets:new(?ACL_DB, [set, public, named_table, {keypos, 2}]), 208 init_acl(Filters, Family, DB). 209 210init_acl([], _, DB) -> 211 {ok, DB}; 212init_acl([Data|T], Family, DB) -> 213 {Direction, Filter, Interfaces} = 214 case Data of 215 {D, F, I} -> 216 {D, F, I}; 217 {D, F} -> 218 {D, F, []} 219 end, 220 {MaskStr, Bits, Ports} = tokenize(Filter, Family), 221 case inet:getaddr(MaskStr, Family) of 222 {ok, Addr} when size(Addr) == 4 -> 223 create_mask(tuple_to_list(Addr), Bits div 8, 224 get_mask8((Bits rem 8)), DB, Direction, Interfaces, Ports), 225 init_acl(T, Family, DB); 226 {ok, Addr} -> 227 create_mask(tuple_to_list(Addr), Bits div 16, 228 get_mask16((Bits rem 16)), DB, Direction, Interfaces, Ports), 229 init_acl(T, Family, DB) 230 end. 231 232create_mask(List, Div, Mask, DB, Direction, Interfaces, Ports) -> 233 case split(Div, List) of 234 {[], [Partial|_DontCare]} -> 235 %% Less than 8/16 bits (depends on family). 236 add_parts([], Direction, (Partial band Mask), Mask, DB, 237 Interfaces, Ports); 238 {Full, [Partial|_DontCare]} -> 239 add_parts(Full, Direction, (Partial band Mask), Mask, DB, 240 Interfaces, Ports); 241 {Full, []} -> 242 %% 32 bits. 243 add_parts(Full, Direction, ?STOP, Mask, DB, Interfaces, Ports) 244 end. 245 246add_parts([], Parent, Bits, Mask, DB, Interfaces, Ports) -> 247 ets:insert(DB, #acl{key = Parent, bits = Bits, 248 mask = Mask, interfaces = Interfaces, ports = Ports}); 249add_parts([H|T], Parent, Bits, Mask, DB, Interfaces, Ports) -> 250 Key = {Parent, H}, 251 ets:insert(DB, #acl{key = Key}), 252 add_parts(T, Key, Bits, Mask, DB, Interfaces, Ports). 253 254 255%%----------------------------------------------------------------- 256%% function : match/1/2 257%% Arguments: IP - tuple() | [integer()] 258%% Direction - tcp_in | ssl_in | tcp_out | ssl_out 259%% All - boolean() 260%% Returns : 261%% Exception: 262%% Effect : 263%%----------------------------------------------------------------- 264match(IPTuple, Direction) when is_tuple(IPTuple) -> 265 match_helper(tuple_to_list(IPTuple), Direction, ?ACL_DB, false, Direction); 266match(IPList, Direction) -> 267 match_helper(IPList, Direction, ?ACL_DB, false, Direction). 268 269match(IPTuple, Direction, All) when is_tuple(IPTuple) -> 270 match_helper(tuple_to_list(IPTuple), Direction, ?ACL_DB, All, Direction); 271match(IPList, Direction, All) -> 272 match_helper(IPList, Direction, ?ACL_DB, All, Direction). 273 274match_helper([], _, _, false, _) -> false; 275match_helper([], _, _, true, _) -> {false, [], 0}; 276match_helper([H|T], Parent, DB, All, Direction) -> 277 case ets:lookup(DB, {Parent, H}) of 278 [#acl{bits = ?CONTINUE}] -> 279 match_helper(T, {Parent, H}, DB, All, Direction); 280 [#acl{bits = ?STOP}] when All == false -> 281 true; 282 [#acl{bits = ?STOP, interfaces = I, ports = Ports}] -> 283 {true, I, Ports}; 284 [#acl{bits = Bits, mask = Mask}] when All == false -> 285 Bits == (hd(T) band Mask); 286 [#acl{bits = Bits, mask = Mask, interfaces = I, ports = Ports}] -> 287 {Bits == (hd(T) band Mask), I, Ports}; 288 _ -> 289 %% Less than 8/16 significant bits (depends on family). 290 %% Should we even allow this? 291 case ets:lookup(DB, Direction) of 292 [#acl{bits = Bits, mask = Mask}] when is_integer(Bits) andalso 293 All == false -> 294 Bits == (H band Mask); 295 [#acl{bits = Bits, mask = Mask, 296 interfaces = I, ports = Ports}] when is_integer(Bits) -> 297 {Bits == (H band Mask), I, Ports}; 298 _ when All == false -> 299 false; 300 _ -> 301 {false, [], 0} 302 end 303 end. 304 305 306%%----------------------------------------------------------------- 307%% Internal functions 308%%----------------------------------------------------------------- 309%%----------------------------------------------------------------- 310%% function : tokenize/1 311%% Arguments: Filter - string(). Examples: 312%% * "123.456.789.10" - match against all. 313%% * "123.456.789.10/17" - match against the 17 most significant bits. 314%% * "123.456.789.10/17#4001" - as above but only allow port 4001 315%% * "123.456.789.10/17#4001/5001" - as above but only allow port 4001-5001 316%% Family - inet | inet6 317%% Returns : {MaskStr, Bits, Ports} 318%% MaskStr - string() 319%% Bits - integer() 320%% Ports - integer() | {integer(), integer()} 321%% Exception: 322%% Effect : 323%%----------------------------------------------------------------- 324tokenize(Filter, Family) -> 325 case string:tokens(Filter, "/#") of 326 [MaskStr] when Family == inet -> 327 {MaskStr, 32, 0}; 328 [MaskStr] when Family == inet6 -> 329 {MaskStr, 128, 0}; 330 [MaskStr, BitString] -> 331 {MaskStr, list_to_integer(BitString), 0}; 332 [MaskStr, BitString, Port] -> 333 {MaskStr, list_to_integer(BitString), list_to_integer(Port)}; 334 [MaskStr, BitString, MinPort, MaxPort] -> 335 {MaskStr, list_to_integer(BitString), 336 {list_to_integer(MinPort), list_to_integer(MaxPort)}}; 337 What -> 338 ?EFORMAT("Invalid Filter: ~p\nReason: ~p\n", [Filter, What]) 339 end. 340 341 342%%----------------------------------------------------------------- 343%% function : get_mask/2 344%% Arguments: 345%% Returns : 346%% Exception: 347%% Effect : 348%%----------------------------------------------------------------- 349get_mask(8, Bits) -> 350 get_mask8(Bits); 351get_mask(16, Bits) -> 352 get_mask16(Bits). 353 354%%----------------------------------------------------------------- 355%% function : get_mask8/1 356%% Arguments: 357%% Returns : 358%% Exception: 359%% Effect : 360%%----------------------------------------------------------------- 361get_mask8(0) -> 2#00000000; 362get_mask8(1) -> 2#10000000; 363get_mask8(2) -> 2#11000000; 364get_mask8(3) -> 2#11100000; 365get_mask8(4) -> 2#11110000; 366get_mask8(5) -> 2#11111000; 367get_mask8(6) -> 2#11111100; 368get_mask8(7) -> 2#11111110. 369 370%%----------------------------------------------------------------- 371%% function : get_mask16/1 372%% Arguments: 373%% Returns : 374%% Exception: 375%% Effect : 376%%----------------------------------------------------------------- 377get_mask16(0) -> 2#0000000000000000; 378get_mask16(1) -> 2#1000000000000000; 379get_mask16(2) -> 2#1100000000000000; 380get_mask16(3) -> 2#1110000000000000; 381get_mask16(4) -> 2#1111000000000000; 382get_mask16(5) -> 2#1111100000000000; 383get_mask16(6) -> 2#1111110000000000; 384get_mask16(7) -> 2#1111111000000000; 385get_mask16(8) -> 2#1111111100000000; 386get_mask16(9) -> 2#1111111110000000; 387get_mask16(10) -> 2#1111111111000000; 388get_mask16(11) -> 2#1111111111100000; 389get_mask16(12) -> 2#1111111111110000; 390get_mask16(13) -> 2#1111111111111000; 391get_mask16(14) -> 2#1111111111111100; 392get_mask16(15) -> 2#1111111111111110. 393 394 395%%----------------------------------------------------------------- 396%%------------- END OF MODULE ------------------------------------- 397%%----------------------------------------------------------------- 398