1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2019. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%%---------------------------------------------------------------------- 21%% Purpose: Basic module for reading and verifying config files 22%%---------------------------------------------------------------------- 23-module(snmp_conf). 24 25 26%% External exports 27%% Avoid warning for local function error/1 clashing with autoimported BIF. 28-compile({no_auto_import,[error/1]}). 29-export([read_files/2, no_gen/2, no_order/2, no_filter/1, keyorder/4]). 30-export([read/2, read/3]). 31 32%% Basic (type) check functions 33-export([check_mandatory/2, 34 check_integer/1, check_integer/2, 35 36 check_string/1, check_string/2, 37 38 check_atom/2, 39 40 check_timer/1, 41 42 all_domains/0, 43 check_domain/1, 44 domain_to_name/1, 45 all_tdomains/0, 46 check_tdomain/1, 47 mk_tdomain/0, mk_tdomain/1, 48 tdomain_to_family/1, tdomain_to_domain/1, 49 which_domain/1, 50 mk_addr_string/1, 51 check_ip/1, check_ip/2, 52 check_port/1, 53%% ip_port_to_domaddr/2, 54 check_address/2, check_address/3, 55 check_taddress/2, 56 mk_taddress/1, mk_taddress/2, 57 58 check_packet_size/1, 59 60 check_oid/1, 61 check_imask/1, check_emask/1, 62 63 check_mp_model/1, 64 check_sec_model/1, check_sec_model/2, check_sec_model/3, 65 check_sec_level/1, 66 67 all_integer/1 68 ]). 69 70 71-define(SNMP_USE_V3, true). 72-include_lib("snmp/include/snmp_types.hrl"). 73-include_lib("snmp/include/SNMP-FRAMEWORK-MIB.hrl"). 74-include_lib("snmp/include/TRANSPORT-ADDRESS-MIB.hrl"). 75-include_lib("snmp/include/SNMPv2-TM.hrl"). 76 77-define(VMODULE,"CONF"). 78-include("snmp_verbosity.hrl"). 79 80 81-define(is_word(P), (((P) band (bnot 65535)) =:= 0)). 82-define(is_word(P0, P1), ((((P0) bor (P1)) band (bnot 255)) =:= 0)). 83 84mk_word(B0, B1) -> ((B0) bsl 8) bor (B1). 85mk_bytes(W) -> [(W) bsr 8,(W) band 255]. 86 87-define( 88 is_ipv4_addr(A0, A1, A2, A3), 89 ((((A0) bor (A1) bor (A2) bor (A3)) band (bnot 255)) =:= 0)). 90 91-define( 92 is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), 93 ((((A0) bor (A1) bor (A2) bor (A3) bor (A4) bor (A5) bor (A6) bor (A7)) 94 band (bnot 65535)) =:= 0)). 95-define( 96 is_ipv6_addr( 97 A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15), 98 ((((A0) bor (A1) bor (A2) bor (A3) bor 99 (A4) bor (A5) bor (A6) bor (A7) bor 100 (A8) bor (A9) bor (A10) bor (A11) bor 101 (A12) bor (A13) bor (A14) bor (A15)) 102 band (bnot 65535)) =:= 0)). 103 104 105%%----------------------------------------------------------------- 106 107%% read_files(Dir, Files) -> Configs 108%% Dir - string() - Full path to the config dir. 109%% Files - [{FileName, Gen, Order, Check, Filter}] 110%% FileName - string() - Name of the config file. 111%% Gen - function/2 - In case of failure when reading the config file, 112%% this function is called to either generate a 113%% default file or issue the error. 114%% Returns a generated config list corresponding 115%% to the written file. 116%% (Dir, Error) -> Configs. 117%% Order - function/2 - An ordering function that is used to process 118%% the read config entries using lists:sort/2. 119%% Returns true if arg 1 compares less than or 120%% equal to arg 2, false otherwise. 121%% Check - function/2 - Check each entry as they are read from the file. 122%% (Entry, State) -> 123%% {ok,NewState} | {{ok,NewEntry},NewState} | 124%% throw(Error) 125%% State =:= 'undefined' the first time. 126%% Filter - function/1 - Process all the config entries read from the file 127%% (Configs) -> [config_entry()]. 128%% Configs - [config_entry()] 129%% config_entry() - term() 130 131read_files(Dir, Files) when is_list(Dir) andalso is_list(Files) -> 132 read_files(Dir, Files, []). 133 134read_files(_Dir, [], Res) -> 135 lists:reverse(Res); 136read_files(Dir, [{FileName, Gen, Order, Check, Filter}|Files], Res) 137 when is_list(FileName), 138 is_function(Gen), 139 is_function(Order), 140 is_function(Check), 141 is_function(Filter) -> 142 ?vdebug("read_files -> entry with~n" 143 " FileName: ~p", [FileName]), 144 File = filename:join(Dir, FileName), 145 Confs = 146 case file:read_file_info(File) of 147 {ok,_} -> 148 read(File, Order, Check); 149 {error, R} -> 150 ?vlog("failed reading file info for ~s: ~n" 151 " ~p", [FileName, R]), 152 Gen(Dir, R) 153 end, 154 read_files(Dir, Files, [Filter(Confs)|Res]). 155 156 157 158no_gen(_Dir, _R) -> []. 159no_order(_, _) -> true. 160no_filter(X) -> X. 161 162%% Order tuples on element N with Keys first in appearence order. 163%% 164%% An ordering function (A, B) shall return true iff 165%% A is less than or equal to B i.e shall return 166%% false iff A is to be ordered after B. 167 168-spec keyorder(N, A, B, Keys) -> 169 boolean() when 170 N :: integer(), 171 A :: tuple(), 172 B :: tuple(), 173 Keys :: maybe_improper_list(). 174 175keyorder(N, A, B, _) when element(N, A) == element(N, B) -> 176 true; 177keyorder(N, A, B, [Key | _]) 178 when tuple_size(A) >= 1, element(N, B) == Key -> 179 false; 180keyorder(N, A, B, [Key | _]) 181 when element(N, A) == Key, tuple_size(B) >= 1 -> 182 true; 183keyorder(N, A, B, [_ | Keys]) -> 184 keyorder(N, A, B, Keys); 185keyorder(_, A, B, []) when tuple_size(A) >= 1, tuple_size(B) >= 1 -> 186 %% Do not order other keys 187 true; 188keyorder(N, A, B, sort) -> 189 %% Order other keys according to standard sort order 190 element(N, A) =< element(N, B). 191 192 193read(File, Verify) -> 194 Check = fun (Row, State) -> {Verify(Row), State} end, 195 read(File, fun no_order/2, Check). 196 197%% Ret. Res | exit(Reason) 198read(File, Order, Check) when is_function(Order), is_function(Check) -> 199 ?vdebug("read -> entry with~n" 200 " File: ~p", [File]), 201 Fd = open_file(File), 202 Lines = read_fd(File, Order, Check, Fd, 1, []), 203 file:close(Fd), 204 Lines. 205 206read_fd(File, Order, Check, Fd, StartLine, Res) -> 207 case do_read(Fd, "", StartLine) of 208 {ok, Row, EndLine} -> 209 ?vtrace("read_fd ->~n" 210 " Row: ~p~n" 211 " EndLine: ~p", [Row,EndLine]), 212 read_fd( 213 File, Order, Check, Fd, EndLine, 214 [{StartLine, Row, EndLine}|Res]); 215 {error, Error, EndLine} -> 216 ?vtrace("read_fd -> read failure:~n" 217 " Error: ~p~n" 218 " EndLine: ~p", [Error,EndLine]), 219 file:close(Fd), 220 error({failed_reading, File, StartLine, EndLine, Error}); 221 {eof, _EndLine} -> 222 Lines = 223 lists:sort( 224 fun ({_, RowA, _}, {_, RowB, _}) -> 225 Order(RowA, RowB) 226 end, 227 lists:reverse(Res)), 228 ?vtrace("read_fd to read_check ->~n" 229 " Lines: ~p", [Lines]), 230 read_check(File, Check, Lines, undefined, []) 231 end. 232 233read_check(_, _, [], _, Res) -> 234 lists:reverse(Res); 235read_check(File, Check, [{StartLine, Row, EndLine}|Lines], State, Res) -> 236 try Check(Row, State) of 237 {Rows, NewState} when is_list(Rows) -> 238 ?vtrace("read_check -> ok:~n" 239 " Rows: ~p~n", [Rows]), 240 read_check(File, Check, Lines, NewState, Rows ++ Res); 241 {ok, NewState} -> 242 ?vtrace("read_check -> ok", []), 243 read_check(File, Check, Lines, NewState, [Row | Res]); 244 {{ok, NewRow}, NewState} -> 245 ?vtrace("read_check -> ok:~n" 246 " NewRow: ~p~n", [NewRow]), 247 read_check(File, Check, Lines, NewState, [NewRow | Res]) 248 catch 249 throw:{error, Reason} -> 250 ?vtrace("read_check -> error:" 251 "~n Reason: ~p", [Reason]), 252 error({failed_check, File, StartLine, EndLine, Reason}); 253 C:E:S -> 254 ?vtrace("read_check -> failure:" 255 "~n Class: ~p" 256 "~n Error: ~p" 257 "~n Stack: ~p", [C, E, S]), 258 error({failed_check, File, StartLine, EndLine, {C, E, S}}) 259 end. 260 261open_file(File) -> 262 case file:open(File, [read]) of 263 {ok, Fd} -> 264 Fd; 265 {error, Reason} -> 266 error({failed_open, File, Reason}) 267 end. 268 269do_read(Io, Prompt, StartLine) -> 270 case io:request(Io, {get_until,Prompt,erl_scan,tokens,[StartLine]}) of 271 {ok, Toks, EndLine} -> 272 case erl_parse:parse_term(Toks) of 273 {ok, Term} -> 274 {ok, Term, EndLine}; 275 {error, {Line, erl_parse, Error}} -> 276 {error, {parse_error, Error}, Line} 277 end; 278 Other -> 279 Other 280 end. 281 282 283 284%%----------------------------------------------------------------- 285 286 287check_mandatory(L, [{Key, Value}|T]) -> 288 case lists:keymember(Key, 1, L) of 289 true -> 290 check_mandatory(L, T); 291 false when Value == mandatory -> 292 error({missing_mandatory, Key}); 293 false -> 294 {value, V} = Value, 295 check_mandatory([{Key, V} | L], T) 296 end; 297check_mandatory(L, []) -> 298 {ok, L}. 299 300 301%% --------- 302 303check_integer(I) -> check_integer(I, any). 304 305check_integer(I, any) when is_integer(I) -> ok; 306check_integer(I, pos) when is_integer(I), I > 0 -> ok; 307check_integer(I, neg) when is_integer(I), I < 0 -> ok; 308check_integer(I1, {gt, I2}) 309 when is_integer(I1) andalso is_integer(I2) andalso (I1 > I2) -> ok; 310check_integer(I1, {gte, I2}) 311 when is_integer(I1) andalso is_integer(I2) andalso (I1 >= I2) -> ok; 312check_integer(I1, {lt, I2}) 313 when is_integer(I1) andalso is_integer(I2) andalso (I1 < I2) -> ok; 314check_integer(I1, {lte, I2}) 315 when is_integer(I1) andalso is_integer(I2) andalso (I1 =< I2) -> ok; 316check_integer(I1, {eq, I1}) 317 when is_integer(I1) -> ok; 318check_integer(I, {range, L, U}) 319 when (is_integer(I) andalso 320 is_integer(L) andalso 321 is_integer(U) andalso 322 (I >= L) andalso (I =< U)) -> ok; 323check_integer(I, _) -> error({invalid_integer, I}). 324 325check_packet_size(S) -> 326 case (catch check_integer(S, {range, 484, 2147483647})) of 327 ok -> 328 ok; 329 {error, _} -> 330 error({invalid_packet_size, S}) 331 end. 332 333%% --------- 334 335check_string(X) when is_list(X) -> ok; 336check_string(X) -> error({invalid_string, X}). 337 338check_string(X, any) 339 when is_list(X) -> ok; 340check_string(X, {gt, Len}) 341 when is_list(X) andalso (length(X) > Len) -> ok; 342check_string(X, {gt, _Len}) 343 when is_list(X) -> error({invalid_length, X}); 344check_string(X, {gte, Len}) 345 when is_list(X) andalso (length(X) >= Len) -> ok; 346check_string(X, {gte, _Len}) 347 when is_list(X) -> error({invalid_length, X}); 348check_string(X, {lt, Len}) 349 when is_list(X) andalso (length(X) < Len) -> ok; 350check_string(X, {lt, _Len}) 351 when is_list(X) -> error({invalid_length, X}); 352check_string(X, {lte, Len}) 353 when is_list(X) andalso (length(X) =< Len) -> ok; 354check_string(X, {lte, _Len}) 355 when is_list(X) -> error({invalid_length, X}); 356check_string(X, Len) 357 when is_list(X) andalso is_integer(Len) andalso (length(X) =:= Len) -> ok; 358check_string(X, _Len) when is_list(X) -> error({invalid_length, X}); 359check_string(X, _Len) -> error({invalid_string, X}). 360 361 362check_atom(X, Atoms) -> 363 case lists:keysearch(X, 1, Atoms) of 364 {value, {X, Val}} -> 365 {ok, Val}; 366 _ -> 367 error({invalid_atom, X, Atoms}) 368 end. 369 370 371%% --------- 372 373check_mp_model(MPModel) when is_atom(MPModel) -> 374 All = [{v1, ?MP_V1}, {v2c, ?MP_V2C}, {v3, ?MP_V3}], 375 check_atom(MPModel, All); 376check_mp_model(?MP_V1) -> 377 {ok, ?MP_V1}; 378check_mp_model(?MP_V2C) -> 379 {ok, ?MP_V2C}; 380check_mp_model(?MP_V3) -> 381 {ok, ?MP_V3}; 382check_mp_model(BadMpModel) -> 383 error({invalid_mp_model, BadMpModel}). 384 385 386%% --------- 387 388check_sec_model(SecModel) when is_atom(SecModel) -> 389 check_sec_model(SecModel, []); 390check_sec_model(?SEC_ANY) -> 391 {ok, ?SEC_ANY}; 392check_sec_model(?SEC_V1) -> 393 {ok, ?SEC_V1}; 394check_sec_model(?SEC_V2C) -> 395 {ok, ?SEC_V2C}; 396check_sec_model(?SEC_USM) -> 397 {ok, ?SEC_USM}; 398check_sec_model(BadSecModel) -> 399 error({invalid_sec_model, BadSecModel}). 400 401check_sec_model(SecModel, Exclude) when is_atom(SecModel) -> 402 All = [{any, ?SEC_ANY}, 403 {v1, ?SEC_V1}, 404 {v2c, ?SEC_V2C}, 405 {usm, ?SEC_USM}], 406 Alt = [{X, Y} || {X, Y} <- All, not lists:member(X, Exclude)], 407 case (catch check_atom(SecModel, Alt) ) of 408 {error, _} -> 409 error({invalid_sec_model, SecModel}); 410 OK -> 411 OK 412 end; 413check_sec_model(BadSecModel, _Exclude) -> 414 error({invalid_sec_model, BadSecModel}). 415 416check_sec_model(v1, v1, Exclude) -> 417 check_sec_model2(v1, ?SEC_V1, Exclude); 418check_sec_model(v1, SecModel, _Exclude) -> 419 error({invalid_sec_model, v1, SecModel}); 420check_sec_model(v2c, v2c, Exclude) -> 421 check_sec_model2(v2c, ?SEC_V2C, Exclude); 422check_sec_model(v2c, SecModel, _Exclude) -> 423 error({invalid_sec_model, v2c, SecModel}); 424check_sec_model(v3, usm, Exclude) -> 425 check_sec_model2(v3, ?SEC_USM, Exclude); 426check_sec_model(v3, SecModel, _Exclude) -> 427 error({invalid_sec_model, v3, SecModel}); 428check_sec_model(M1, M2, _Exclude) -> 429 error({invalid_sec_model, M1, M2}). 430 431check_sec_model2(SecModel, SM, Exclude) -> 432 case lists:member(SecModel, Exclude) of 433 false -> 434 {ok, SM}; 435 true -> 436 error({invalid_sec_model, SecModel}) 437 end. 438 439 440%% --------- 441 442check_sec_level(SecLevel) when is_atom(SecLevel) -> 443 All = [{noAuthNoPriv, ?'SnmpSecurityLevel_noAuthNoPriv'}, 444 {authNoPriv, ?'SnmpSecurityLevel_authNoPriv'}, 445 {authPriv, ?'SnmpSecurityLevel_authPriv'}], 446 case (catch check_atom(SecLevel, All)) of 447 {error, _} -> 448 error({invalid_sec_level, SecLevel}); 449 OK -> 450 OK 451 end; 452check_sec_level(?'SnmpSecurityLevel_noAuthNoPriv' = SL) -> 453 {ok, SL}; 454check_sec_level(?'SnmpSecurityLevel_authNoPriv' = SL) -> 455 {ok, SL}; 456check_sec_level(?'SnmpSecurityLevel_authPriv' = SL) -> 457 {ok, SL}; 458check_sec_level(BadSecLevel) -> 459 error({invalid_sec_level, BadSecLevel}). 460 461 462%% --------- 463all_tdomains() -> 464 [ 465 ?transportDomainUdpIpv4, 466 ?transportDomainUdpIpv6, 467 ?transportDomainUdpIpv4z, 468 ?transportDomainUdpIpv6z, 469 ?transportDomainTcpIpv4, 470 ?transportDomainTcpIpv6, 471 ?transportDomainTcpIpv4z, 472 ?transportDomainTcpIpv6z, 473 ?transportDomainSctpIpv4, 474 ?transportDomainSctpIpv6, 475 ?transportDomainSctpIpv4z, 476 ?transportDomainSctpIpv6z, 477 ?transportDomainLocal, 478 ?transportDomainUdpDns, 479 ?transportDomainTcpDns, 480 ?transportDomainSctpDns 481 ]. 482 483check_tdomain(TDomain) -> 484 SupportedTDomains = 485 [ 486 ?snmpUDPDomain, % Legacy 487 ?transportDomainUdpIpv4, 488 ?transportDomainUdpIpv6 489 ], 490 AllTDomains = all_tdomains(), 491 case lists:member(TDomain, SupportedTDomains) of 492 true -> 493 ok; 494 false -> 495 case lists:member(TDomain, AllTDomains) of 496 true -> 497 error({unsupported_tdomain, TDomain}); 498 false -> 499 error({unknown_tdomain, TDomain}) 500 end 501 end. 502 503 504%% --------- 505 506mk_tdomain() -> 507 mk_tdomain(snmpUDPDomain). 508 509mk_tdomain(snmpUDPDomain) -> 510 mk_tdomain(transportDomainUdpIpv4); 511mk_tdomain(transportDomainUdpIpv4) -> 512 ?transportDomainUdpIpv4; 513mk_tdomain(transportDomainUdpIpv6) -> 514 ?transportDomainUdpIpv6; 515mk_tdomain(BadDomain) -> 516 error({bad_domain, BadDomain}). 517 518 519%% --------- 520 521tdomain_to_family(snmpUDPDomain) -> 522 inet; 523tdomain_to_family(transportDomainUdpIpv4) -> 524 inet; 525tdomain_to_family(transportDomainUdpIpv6) -> 526 inet6; 527tdomain_to_family(?snmpUDPDomain) -> 528 inet; 529tdomain_to_family(?transportDomainUdpIpv4) -> 530 inet; 531tdomain_to_family(?transportDomainUdpIpv6) -> 532 inet6; 533tdomain_to_family(BadDomain) -> 534 error({bad_domain, BadDomain}). 535 536 537%% --------- 538 539tdomain_to_domain(?snmpUDPDomain) -> 540 snmpUDPDomain; 541tdomain_to_domain(?transportDomainUdpIpv4) -> 542 transportDomainUdpIpv4; 543tdomain_to_domain(?transportDomainUdpIpv6) -> 544 transportDomainUdpIpv6; 545tdomain_to_domain(BadTDomain) -> 546 error({bad_tdomain, BadTDomain}). 547 548 549%% --------- 550 551check_taddress(?snmpUDPDomain, X) -> 552 check_taddress(transportDomainUdpIpv4, X); 553check_taddress(snmpUDPDomain, X) -> 554 check_taddress(transportDomainUdpIpv4, X); 555%% 556check_taddress(?transportDomainUdpIpv4, X) -> 557 check_taddress(transportDomainUdpIpv4, X); 558check_taddress(transportDomainUdpIpv4, X) -> 559 case X of 560 [A0,A1,A2,A3,P0,P1] 561 when ?is_ipv4_addr(A0, A1, A2, A3), ?is_word(P0, P1) -> 562 ok; 563 _ -> 564 error({invalid_taddress, X}) 565 end; 566%% 567check_taddress(?transportDomainUdpIpv6, X) -> 568 check_taddress(transportDomainUdpIpv6, X); 569check_taddress(transportDomainUdpIpv6, X) -> 570 case X of 571 [A0,A1,A2,A3,A4,A5,A6,A7,P0,P1] 572 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), 573 ?is_word(P0, P1) -> 574 ok; 575 _ -> 576 error({invalid_taddress, X}) 577 end; 578%% 579check_taddress(BadDomain, _X) -> 580 error({invalid_tdomain, BadDomain}). 581 582 583 584%% --------- 585 586check_timer(infinity) -> 587 {ok, infinity}; 588check_timer(T) when is_record(T, snmp_incr_timer) -> 589 {ok, T}; 590check_timer({WaitFor, Factor, Incr, Retry} = T) -> 591 case (catch do_check_timer(WaitFor, Factor, Incr, Retry)) of 592 ok -> 593 {ok, #snmp_incr_timer{wait_for = WaitFor, 594 factor = Factor, 595 incr = Incr, 596 max_retries = Retry}}; 597 _Err -> 598 error({invalid_timer, T}) 599 end; 600check_timer(Timeout) -> 601 case (catch check_integer(Timeout, {gt, 0})) of 602 ok -> 603 {ok, #snmp_incr_timer{wait_for = Timeout, 604 factor = 1, 605 incr = 0, 606 max_retries = 0}}; 607 _Err -> 608 error({invalid_timer, Timeout}) 609 end. 610 611do_check_timer(WaitFor, Factor, Incr, Retry) -> 612 check_integer(WaitFor, {gt, 0}), 613 check_integer(Factor, {gt, 0}), 614 check_integer(Incr, {gte, 0}), 615 check_integer(Retry, {gte, 0}), 616 ok. 617 618 619%% --------- 620 621all_domains() -> 622 [ 623 transportDomainUdpIpv4, 624 transportDomainUdpIpv6, 625 transportDomainUdpIpv4z, 626 transportDomainUdpIpv6z, 627 transportDomainTcpIpv4, 628 transportDomainTcpIpv6, 629 transportDomainTcpIpv4z, 630 transportDomainTcpIpv6z, 631 transportDomainSctpIpv4, 632 transportDomainSctpIpv6, 633 transportDomainSctpIpv4z, 634 transportDomainSctpIpv6z, 635 transportDomainLocal, 636 transportDomainUdpDns, 637 transportDomainTcpDns, 638 transportDomainSctpDns 639 ]. 640 641check_domain(snmpUDPDomain) -> ok; 642check_domain(transportDomainUdpIpv4) -> ok; 643check_domain(transportDomainUdpIpv6) -> ok; 644check_domain(Domain) -> 645 case lists:member(Domain, all_domains()) of 646 true -> 647 error({unsupported_domain, Domain}); 648 false -> 649 error({unknown_domain, Domain}) 650 end. 651 652domain_to_name(snmpUDPDomain) -> 653 undefined; 654domain_to_name(transportDomainUdpIpv4) -> 655 udpIpv4; 656domain_to_name(transportDomainUdpIpv6) -> 657 udpIpv6; 658domain_to_name(transportDomainUdpIpv4z) -> 659 udpIpv4z; 660domain_to_name(transportDomainUdpIpv6z) -> 661 udpIpv6z; 662domain_to_name(transportDomainTcpIpv4) -> 663 tcpIpv4; 664domain_to_name(transportDomainTcpIpv6) -> 665 tcpIpv6; 666domain_to_name(transportDomainTcpIpv4z) -> 667 tcpIpv4z; 668domain_to_name(transportDomainTcpIpv6z) -> 669 tcpIpv6z; 670domain_to_name(transportDomainSctpIpv4) -> 671 sctpIpv4; 672domain_to_name(transportDomainSctpIpv6) -> 673 sctpIpv6; 674domain_to_name(transportDomainSctpIpv4z) -> 675 sctpIpv4z; 676domain_to_name(transportDomainSctpIpv6z) -> 677 sctpIpv6z; 678domain_to_name(transportDomainLocal) -> 679 local; 680domain_to_name(transportDomainUdpDns) -> 681 udpDns; 682domain_to_name(transportDomainTcpDns) -> 683 tcpDns; 684domain_to_name(transportDomainSctpDns) -> 685 sctpDns; 686domain_to_name(BadDomain) -> 687 error({bad_domain, BadDomain}). 688 689%% --------- 690 691mk_taddress(Address) -> 692 mk_taddress(snmpUDPDomain, Address). 693 694%% The values of Domain, Ip and Port has both been checked at this 695%% point, so we dont need to do that again, but this function is 696%% also used on incoming packets from net_if so a little 697%% check that net_if does not supply bad arguments is in order. 698%% 699%% These are just for convenience 700mk_taddress(?snmpUDPDomain, Address) -> 701 mk_taddress(snmpUDPDomain, Address); 702mk_taddress(?transportDomainUdpIpv4, Address) -> 703 mk_taddress(transportDomainUdpIpv4, Address); 704mk_taddress(?transportDomainUdpIpv6, Address) -> 705 mk_taddress(transportDomainUdpIpv6, Address); 706%% 707mk_taddress(snmpUDPDomain, Address) -> % Legacy 708 mk_taddress(transportDomainUdpIpv4, Address); 709mk_taddress(transportDomainUdpIpv4 = Domain, Address) -> 710 case Address of 711 [] -> % Empty mask 712 []; 713 {Ip, Port} when tuple_size(Ip) =:= 4, is_integer(Port) -> 714 tuple_to_list(Ip) ++ mk_bytes(Port); 715 _ -> 716 erlang:error(badarg, [Domain,Address]) 717 end; 718mk_taddress(transportDomainUdpIpv6 = Domain, Address) -> 719 case Address of 720 [] -> % Empty mask 721 []; 722 {{A, B, C, D, E, F, G, H}, Port} -> 723 [A bsr 8, A band 255, 724 B bsr 8, B band 255, 725 C bsr 8, C band 255, 726 D bsr 8, D band 255, 727 E bsr 8, E band 255, 728 F bsr 8, F band 255, 729 G bsr 8, G band 255, 730 H bsr 8, H band 255, 731 Port bsr 8, Port band 255]; 732 _ -> 733 erlang:error(badarg, [Domain,Address]) 734 end; 735%% Bad domain 736mk_taddress(BadDomain, _) -> 737 error({bad_domain, BadDomain}). 738 739 740%% --------- 741 742%% XXX remove, when net_if handles one socket per transport domain 743 744which_domain([A0,A1,A2,A3]) 745 when ?is_ipv4_addr(A0, A1, A2, A3) -> 746 transportDomainUdpIpv4; 747which_domain({A0, A1, A2, A3}) 748 when ?is_ipv4_addr(A0, A1, A2, A3) -> 749 transportDomainUdpIpv4; 750which_domain([A0,A1,A2,A3,A4,A5,A6,A7]) 751 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> 752 transportDomainUdpIpv6; 753which_domain([A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15]) 754 when ?is_ipv6_addr( 755 A0, A1, A2, A3, A4, A5, A6, A7, 756 A8, A9, A10, A11, A12, A13, A14, A15) -> 757 transportDomainUdpIpv6; 758which_domain({A0, A1, A2, A3, A4, A5, A6, A7}) 759 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> 760 transportDomainUdpIpv6. 761 762%% --------- 763 764mk_addr_string({Domain, Addr}) when is_atom(Domain) -> 765 %% XXX There is only code for IP domains here 766 case check_address_ip(Domain, Addr) of 767 false -> 768 case check_address_ip_port(Domain, Addr) of 769 false -> 770 error({bad_address, {Domain, Addr}}); 771 true -> 772 {IP, Port} = Addr, 773 mk_addr_string_ntoa(Domain, IP, Port); 774 {IP, Port} -> 775 mk_addr_string_ntoa(Domain, IP, Port) 776 end; 777 true -> 778 mk_addr_string_ntoa(Domain, Addr); 779 IP -> 780 mk_addr_string_ntoa(Domain, IP) 781 end; 782mk_addr_string({_IP, Port} = Addr) when is_integer(Port) -> 783 mk_addr_string({snmpUDPDomain, Addr}); 784mk_addr_string(Strange) -> 785 lists:flatten(io_lib:format("~w", [Strange])). 786 787 788mk_addr_string_ntoa({_, _, _, _} = IP) -> 789 inet:ntoa(IP); 790mk_addr_string_ntoa(IP) -> 791 lists:flatten(io_lib:format("[~s]", [inet:ntoa(IP)])). 792 793mk_addr_string_ntoa(Domain, IP) -> 794 case domain_to_name(Domain) of 795 undefined -> 796 mk_addr_string_ntoa(IP); 797 Name -> 798 lists:flatten( 799 io_lib:format("~w://~s", [Name, mk_addr_string_ntoa(IP)])) 800 end. 801 802mk_addr_string_ntoa(Domain, IP, Port) -> 803 lists:flatten( 804 io_lib:format( 805 "~s:~w", [mk_addr_string_ntoa(Domain, IP), Port])). 806 807%% --------- 808 809check_ip(X) -> 810 check_ip(snmpUDPDomain, X). 811 812check_ip(Domain, IP) -> 813 %% XXX There is only code for IP domains here 814 case check_address_ip(Domain, IP) of 815 false -> 816 error({bad_address, {Domain, IP}}); 817 true -> 818 ok; 819 FixedIP -> 820 {ok, FixedIP} 821 end. 822 823 824%% --------- 825 826check_port(Port) when ?is_word(Port) -> 827 ok; 828check_port(Port) -> 829 error({bad_port, Port}). 830 831%% ip_port_to_domaddr(IP, Port) when ?is_word(Port) -> 832%% %% XXX There is only code for IP domains here 833%% case check_address_ip(transportDomainUdpIpv4, IP) of 834%% false -> 835%% case check_address_ip(transportDomainUdpIpv6, IP) of 836%% false -> 837%% error({bad_address, {transportDomainUdpIpv4, {IP, Port}}}); 838%% true -> 839%% {transportDomainUdpIpv6, {IP, Port}}; 840%% FixedIP -> 841%% {transportDomainUdpIpv6, {FixedIP, Port}} 842%% end; 843%% true -> 844%% {transportDomainUdpIpv4, {IP, Port}}; 845%% FixedIP -> 846%% {transportDomainUdpIpv4, {FixedIP, Port}} 847%% end; 848%% ip_port_to_domaddr(IP, Port) -> 849%% error({bad_address, {transportDomainUdpIpv4, {IP, Port}}}). 850 851%% Check a configuration term field from a file to see if it 852%% can be fixed to be fed to mk_taddress/2. 853 854check_address(Domain, Address, DefaultPort) -> 855 %% If Address does not contain Port or contains Port =:= 0 856 %% create an address containing DefaultPort 857 %% 858 %% XXX There is only code for IP domains here 859 case check_address_ip(Domain, Address) of 860 false -> 861 case check_address_ip_port(Domain, Address) of 862 false -> 863 error({bad_address, {Domain, Address}}); 864 true -> 865 case Address of 866 {IP, 0} -> 867 {ok, {IP, DefaultPort}}; 868 _ -> 869 ok 870 end; 871 {FixedIP, 0} -> 872 {ok, {FixedIP, DefaultPort}}; 873 FixedAddress -> 874 {ok, FixedAddress} 875 end; 876 true -> 877 {ok, {Address, DefaultPort}}; 878 FixedIP -> 879 {ok, {FixedIP, DefaultPort}} 880 end. 881 882check_address(Domain, Address) -> 883 %% Address has to contain Port 884 %% 885 %% XXX There is only code for IP domains here 886 case check_address_ip_port(Domain, Address) of 887 false -> 888 error({bad_address, {Domain, Address}}); 889 true -> 890 ok; 891 FixedAddress -> 892 {ok, FixedAddress} 893 end. 894 895%% -> IP 896check_address_ip(Domain, Address) 897 when Domain =:= snmpUDPDomain; 898 Domain =:= transportDomainUdpIpv4 -> 899 case Address of 900 %% Erlang native format 901 {A0, A1, A2, A3} 902 when ?is_ipv4_addr(A0, A1, A2, A3) -> 903 true; 904 %% Erlangish format 905 [A0,A1,A2,A3] 906 when ?is_ipv4_addr(A0, A1, A2, A3) -> 907 {A0, A1, A2, A3}; 908 _ -> 909 false 910 end; 911check_address_ip(transportDomainUdpIpv6, Address) -> 912 case Address of 913 %% Erlang native format 914 {A0, A1, A2, A3, A4, A5, A6, A7} 915 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> 916 true; 917 %% Erlangish format 918 [A0,A1,A2,A3,A4,A5,A6,A7] 919 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> 920 {A0, A1, A2, A3, A4, A5, A6, A7}; 921 %% SNMP standards format 922 [A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15] 923 when ?is_ipv6_addr( 924 A0, A1, A2, A3, A4, A5, A6, A7, 925 A8, A9, A10, A11, A12, A13, A14, A15) -> 926 {mk_word(A0, A1), mk_word(A2, A3), 927 mk_word(A4, A5), mk_word(A6, A7), 928 mk_word(A8, A9), mk_word(A10, A11), 929 mk_word(A12, A13), mk_word(A14, A15)}; 930 _ -> 931 false 932 end; 933check_address_ip(BadDomain, _) -> 934 error({bad_domain, BadDomain}). 935 936%% -> {IP, Port} 937check_address_ip_port(Domain, Address) 938 when Domain =:= snmpUDPDomain; 939 Domain =:= transportDomainUdpIpv4 -> 940 case Address of 941 {IP, Port} when ?is_word(Port) -> 942 case check_address_ip(Domain, IP) of 943 false -> 944 false; 945 true -> 946 true; 947 FixedIP -> 948 {FixedIP, Port} 949 end; 950 %% SNMP standards format 951 [A0,A1,A2,A3,P0,P1] 952 when ?is_ipv4_addr(A0, A1, A2, A3), ?is_word(P0, P1) -> 953 {{A0, A1, A2, A3}, mk_word(P0, P1)}; 954 _ -> 955 false 956 end; 957check_address_ip_port(transportDomainUdpIpv6 = Domain, Address) -> 958 case Address of 959 {IP, Port} when ?is_word(Port) -> 960 case check_address_ip(Domain, IP) of 961 false -> 962 false; 963 true -> 964 true; 965 FixedIP -> 966 {FixedIP, Port} 967 end; 968 %% Erlang friendly list format 969 [A0,A1,A2,A3,A4,A5,A6,A7,P] 970 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), 971 ?is_word(P) -> 972 {{A0, A1, A2, A3, A4, A5, A6, A7}, P}; 973 %% Strange hybrid format with port as bytes 974 [A0,A1,A2,A3,A4,A5,A6,A7,P0,P1] 975 when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7), 976 ?is_word(P0, P1) -> 977 {{A0, A1, A2, A3, A4, A5, A6, A7}, mk_word(P0, P1)}; 978 %% SNMP standards format 979 [A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,P0,P1] 980 when ?is_ipv6_addr( 981 A0, A1, A2, A3, A4, A5, A6, A7, 982 A8, A9, A10, A11, A12, A13, A14, A15), 983 ?is_word(P0, P1) -> 984 {{mk_word(A0, A1), mk_word(A2, A3), 985 mk_word(A4, A5), mk_word(A6, A7), 986 mk_word(A8, A9), mk_word(A10, A11), 987 mk_word(A12, A13), mk_word(A14, A15)}, 988 mk_word(P0, P1)}; 989 _ -> 990 false 991 end; 992check_address_ip_port(BadDomain, _) -> 993 error({bad_domain, BadDomain}). 994 995 996 997%% --------- 998 999check_oid([E1,E2|_] = X) when E1 * 40 + E2 =< 255 -> 1000 case all_integer(X) of 1001 true -> 1002 ok; 1003 _ -> 1004 error({invalid_object_identifier, X}) 1005 end; 1006check_oid(X) -> 1007 error({invalid_object_identifier, X}). 1008 1009 1010%% --------- 1011 1012%% Check a (view) mask in the internal form (all 0 and 1): 1013check_imask(null) -> 1014 {ok, []}; 1015check_imask(IMask) when is_list(IMask) -> 1016 do_check_imask(IMask), 1017 {ok, IMask}. 1018 1019do_check_imask([]) -> 1020 ok; 1021do_check_imask([0|IMask]) -> 1022 do_check_imask(IMask); 1023do_check_imask([1|IMask]) -> 1024 do_check_imask(IMask); 1025do_check_imask([X|_]) -> 1026 error({invalid_internal_mask_element, X}). 1027 1028 1029%% Check a (view) mask in the external form (according to MIB, 1030%% an OCTET STRING of at most length 16). 1031check_emask(EMask) when is_list(EMask) andalso (length(EMask) =< 16) -> 1032 do_check_emask(EMask). 1033 1034do_check_emask([]) -> 1035 ok; 1036do_check_emask([X|EMask]) 1037 when is_integer(X) andalso (X >= 16#00) andalso (X =< 16#FF) -> 1038 do_check_emask(EMask); 1039do_check_emask([X|_]) -> 1040 error({invalid_external_mask_element, X}). 1041 1042 1043%% --------- 1044 1045all_integer([H|T]) when is_integer(H) -> all_integer(T); 1046all_integer([_H|_T]) -> false; 1047all_integer([]) -> true. 1048 1049 1050%% --------- 1051 1052error(Reason) -> 1053 throw({error, Reason}). 1054 1055