1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2020. 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%% 22%% ts:run(snmp, snmp_agent_test, [batch]). 23%% 24-module(snmp_test_mgr_misc). 25 26%% API 27-export([start_link_packet/8, start_link_packet/9, start_link_packet/10, 28 stop/1, 29 send_discovery_pdu/2, 30 send_pdu/2, send_msg/4, send_bytes/2, 31 get_pdu/1, set_pdu/2, format_hdr/1]). 32 33%% internal exports 34-export([init_packet/11]). 35 36-compile({no_auto_import, [error/2]}). 37 38-define(SNMP_USE_V3, true). 39-include_lib("snmp/include/snmp_types.hrl"). 40-include_lib("snmp/src/misc/snmp_verbosity.hrl"). 41-include("snmp_test_lib.hrl"). 42 43 44%%---------------------------------------------------------------------- 45%% The InHandler process will receive messages on the form {snmp_pdu, Pdu}. 46%%---------------------------------------------------------------------- 47 48start_link_packet( 49 InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz) -> 50 start_link_packet( 51 InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, 52 false). 53 54start_link_packet( 55 InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, 56 Dbg) -> 57 start_link_packet( 58 InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, 59 Dbg, inet). 60 61start_link_packet( 62 InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz, 63 Dbg, IpFamily) when is_integer(UdpPort) -> 64 do_start_link_packet(InHandler, 65 AgentIp, UdpPort, TrapUdp, 66 VsnHdr, Version, Dir, BufSz, 67 Dbg, IpFamily); 68start_link_packet(InHandler, 69 AgentIp, {AReqPort, ATrapPort} = UdpPorts, TrapUdp, 70 VsnHdr, Version, Dir, BufSz, 71 Dbg, IpFamily) when is_integer(AReqPort) andalso 72 is_integer(ATrapPort) -> 73 do_start_link_packet(InHandler, 74 AgentIp, UdpPorts, TrapUdp, 75 VsnHdr, Version, Dir, BufSz, 76 Dbg, IpFamily). 77 78do_start_link_packet(InHandler, 79 AgentIp, UdpPorts, TrapUdp, 80 VsnHdr, Version, Dir, BufSz, 81 Dbg, IpFamily) -> 82 Args = 83 [self(), 84 InHandler, 85 AgentIp, UdpPorts, TrapUdp, 86 VsnHdr, Version, Dir, BufSz, 87 Dbg, IpFamily], 88 proc_lib:start_link(?MODULE, init_packet, Args). 89 90stop(Pid) -> 91 Pid ! {stop, self()}, 92 receive 93 {Pid, stopped} -> ok 94 end. 95 96 97send_discovery_pdu(Pdu, PacketPid) when is_record(Pdu, pdu) -> 98 PacketPid ! {send_discovery_pdu, self(), Pdu}, 99 await_discovery_response_pdu(). 100 101await_discovery_response_pdu() -> 102 receive 103 {discovery_response, Reply} -> 104 Reply 105 end. 106 107 108send_pdu(Pdu, PacketPid) when is_record(Pdu, pdu) -> 109 PacketPid ! {send_pdu, Pdu}. 110 111send_msg(Msg, PacketPid, Ip, Udp) when is_record(Msg, message) -> 112 PacketPid ! {send_msg, Msg, Ip, Udp}. 113 114send_bytes(Bytes, PacketPid) -> 115 PacketPid ! {send_bytes, Bytes}. 116 117%%-------------------------------------------------- 118%% The SNMP encode/decode process 119%%-------------------------------------------------- 120init_packet( 121 Parent, 122 SnmpMgr, AgentIp, UdpPorts, TrapUdp, VsnHdr, Version, Dir, BufSz, 123 DbgOptions, IpFamily) -> 124 %% This causes "verbosity printouts" to print (from the 125 %% specified level) in the modules we "borrow" from the 126 %% agent code (burr,,,). 127 %% With "our" name (mgr_misc). 128 put(sname, mgr_misc), 129 init_debug(DbgOptions), 130 %% Make use of the "test name" print "feature" 131 put(tname, "MGR-MISC"), 132 ?IPRINT("starting"), 133 UdpOpts = [{recbuf,BufSz}, {reuseaddr, true}, IpFamily], 134 {ok, UdpId} = gen_udp:open(TrapUdp, UdpOpts), 135 put(msg_id, 1), 136 init_usm(Version, Dir), 137 proc_lib:init_ack(Parent, self()), 138 ?IPRINT("started"), 139 packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, []). 140 141init_debug(Dbg) when is_atom(Dbg) -> 142 put(debug,Dbg), 143 %% put(verbosity, silence); 144 put(verbosity, trace); 145init_debug(DbgOptions) when is_list(DbgOptions) -> 146 case lists:keysearch(debug, 1, DbgOptions) of 147 {value, {_, Dbg}} when is_atom(Dbg) -> 148 put(debug, Dbg); 149 _ -> 150 put(debug, false) 151 end, 152 case lists:keysearch(verbosity, 1, DbgOptions) of 153 {value, {_, Ver}} when is_atom(Ver) -> 154 put(verbosity, Ver); 155 _ -> 156 put(verbosity, silence) 157 end, 158 ok. 159 160 161packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, MsgData) -> 162 receive 163 {send_discovery_pdu, From, Pdu} -> 164 d("packet_loop -> received send_discovery_pdu with" 165 "~n From: ~p" 166 "~n Pdu: ~p", [From, Pdu]), 167 case mk_discovery_msg(Version, Pdu, VsnHdr, "") of 168 error -> 169 ok; 170 {M, B} when is_list(B) -> 171 put(discovery, {M, From}), 172 display_outgoing_message(M), 173 Port = select_request_port(UdpPorts), 174 udp_send(UdpId, AgentIp, Port, B) 175 end, 176 packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, []); 177 178 {send_pdu, Pdu} -> 179 d("packet_loop -> received send_pdu with" 180 "~n Pdu: ~p", [Pdu]), 181 case mk_msg(Version, Pdu, VsnHdr, MsgData) of 182 error -> 183 ok; 184 B when is_list(B) -> 185 Port = select_request_port(UdpPorts), 186 udp_send(UdpId, AgentIp, Port, B) 187 end, 188 packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, []); 189 190 {send_msg, Msg, Ip, Udp} -> 191 d("packet_loop -> received send_msg with" 192 "~n Msg: ~p" 193 "~n Ip: ~p" 194 "~n Udp: ~p", [Msg,Ip,Udp]), 195 case catch snmp_pdus:enc_message(Msg) of 196 {'EXIT', Reason} -> 197 ?EPRINT("Encoding error:" 198 "~n Msg: ~w" 199 "~n Reason: ~w",[Msg, Reason]); 200 B when is_list(B) -> 201 udp_send(UdpId, Ip, Udp, B) 202 end, 203 packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, []); 204 205 {udp, UdpId, Ip, Port, Bytes} -> 206 d("packet_loop -> received udp with" 207 "~n UdpId: ~p" 208 "~n Ip: ~p" 209 "~n Port: ~p (~p)" 210 "~n sz(Bytes): ~p", [UdpId, Ip, Port, UdpPorts, sz(Bytes)]), 211 case UdpPorts of 212 Port -> 213 ok; 214 {Port, _} -> % Should be a (request) response 215 ok; 216 {_, Port} -> % Should be a trap 217 ok; 218 _ -> 219 d("packet_loop -> received packet from unknown port" 220 "~n ~p", [Port]), 221 exit({snmp_packet_from_unknown_port, Port, UdpPorts}) 222 end, 223 MsgData3 = handle_udp_packet(Version, erase(discovery), 224 UdpId, Ip, Port, Bytes, 225 SnmpMgr, AgentIp), 226 packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, 227 MsgData3); 228 229 {udp_error, UdpId, Reason} -> 230 gen_udp:close(UdpId), 231 exit({udp_error, Reason}); 232 233 {send_bytes, B} -> 234 d("packet_loop -> received send_bytes with" 235 "~n sz(B): ~p", [sz(B)]), 236 Port = select_request_port(UdpPorts), 237 udp_send(UdpId, AgentIp, Port, B), 238 packet_loop(SnmpMgr, UdpId, AgentIp, UdpPorts, VsnHdr, Version, []); 239 240 {stop, Pid} -> 241 d("packet_loop -> received stop from ~p", [Pid]), 242 gen_udp:close(UdpId), 243 Pid ! {self(), stopped}, 244 exit(normal); 245 246 Other -> 247 d("packet_loop -> received unknown" 248 "~n ~p", [Other]), 249 exit({snmp_packet_got_other, Other}) 250 end. 251 252select_request_port({Port, _}) when is_integer(Port) -> 253 Port; 254select_request_port(Port) when is_integer(Port) -> 255 Port. 256 257%% select_trap_port({_, Port}) when is_integer(Port) -> 258%% Port; 259%% select_trap_port(Port) when is_integer(Port) -> 260%% Port. 261 262handle_udp_packet(_V, undefined, 263 UdpId, Ip, UdpPort, 264 Bytes, SnmpMgr, AgentIp) -> 265 try snmp_pdus:dec_message_only(Bytes) of 266 Message when Message#message.version =:= 'version-3' -> 267 d("handle_udp_packet -> version 3"), 268 handle_v3_message(SnmpMgr, UdpId, Ip, UdpPort, AgentIp, 269 Bytes, Message); 270 271 Message when is_record(Message, message) -> 272 d("handle_udp_packet -> version 1 or 2"), 273 handle_v1_or_v2_message(SnmpMgr, UdpId, Ip, UdpPort, AgentIp, 274 Bytes, Message) 275 276 catch 277 Class:Error:_ -> 278 ?EPRINT("Decoding error: " 279 "~n Class: ~w" 280 "~n Error: ~p" 281 "~n Bytes: ~p" 282 "~n Port: ~w" 283 "~n Ip: ~p)", 284 [Class, Error, Bytes, UdpPort, Ip]), 285 [] 286 end; 287handle_udp_packet(V, {DiscoReqMsg, From}, _UdpId, _Ip, _UdpPort, 288 Bytes, _, _AgentIp) -> 289 DiscoRspMsg = (catch snmp_pdus:dec_message(Bytes)), 290 display_incomming_message(DiscoRspMsg), 291 _Reply = (catch check_discovery_result(V, DiscoReqMsg, DiscoRspMsg)), 292 case (catch check_discovery_result(V, DiscoReqMsg, DiscoRspMsg)) of 293 {ok, AgentEngineID} when is_list(AgentEngineID) -> 294 %% Ok, step 1 complete, now for step 2 295 %% Which we skip for now 296 OK = {ok, AgentEngineID}, 297 From ! {discovery_response, OK}, 298 []; 299 Error -> 300 From ! {discovery_response, Error}, 301 [] 302 end. 303 304handle_v3_message(Mgr, UdpId, Ip, UdpPort, AgentIp, 305 Bytes, Message) -> 306 try handle_v3_msg(Bytes, Message) of 307 {ok, NewData, MsgData} -> 308 Msg = Message#message{data = NewData}, 309 case Mgr of 310 {pdu, Pid} -> 311 Pdu = get_pdu(Msg), 312 d("handle_v3_message -> send pdu to manager (~p): " 313 "~n ~p", [Pid, Pdu]), 314 Pid ! {snmp_pdu, Pdu}; 315 {msg, Pid} -> 316 d("handle_v3_message -> send msg to manager (~p): " 317 "~n ~p", [Pid, Msg]), 318 Pid ! {snmp_msg, Msg, Ip, UdpPort} 319 end, 320 MsgData 321 322 catch 323 throw:{error, Reason, B}:_ -> 324 udp_send(UdpId, AgentIp, UdpPort, B), 325 ?EPRINT("Decoding (v3) error - Auto-sending Report:" 326 "~n Reason: ~p" 327 "~n Port: ~p" 328 "~n Ip: ~p", 329 [Reason, UdpPort, Ip]), 330 []; 331 332 throw:{error, Reason}:_ -> 333 ?EPRINT("Decoding (v3) error:" 334 "~n Reason: ~p" 335 "~n Bytes: ~p" 336 "~n Port: ~p" 337 "~n Ip: ~p", 338 [Reason, Bytes, UdpPort, Ip]), 339 []; 340 341 Class:Error:_ -> 342 ?EPRINT("Decoding (v3) error:" 343 "~n Class: ~p" 344 "~n Error: ~p" 345 "~n Bytes: ~p" 346 "~n Port: ~p" 347 "~n Ip: ~p", 348 [Class, Error, Bytes, UdpPort, Ip]), 349 [] 350 351 end. 352 353handle_v1_or_v2_message(Mgr, _UdpId, Ip, UdpPort, _AgentIp, 354 Bytes, Message) -> 355 try snmp_pdus:dec_pdu(Message#message.data) of 356 Pdu when is_record(Pdu, pdu) -> 357 case Mgr of 358 {pdu, Pid} -> 359 d("handle_v1_or_v2_message -> send pdu to manager (~p): " 360 "~n ~p", [Pid, Pdu]), 361 Pid ! {snmp_pdu, Pdu}; 362 {msg, Pid} -> 363 d("handle_v1_or_v2_message -> send msg to manager (~p): " 364 "~n ~p", [Pid, Pdu]), 365 Msg = Message#message{data = Pdu}, 366 Pid ! {snmp_msg, Msg, Ip, UdpPort} 367 end; 368 Pdu when is_record(Pdu, trappdu) -> 369 case Mgr of 370 {pdu, Pid} -> 371 d("handle_v1_or_v2_message -> send trap-pdu to manager (~p): " 372 "~n ~p", [Pid, Pdu]), 373 Pid ! {snmp_pdu, Pdu}; 374 {msg, Pid} -> 375 d("handle_v1_or_v2_message -> send trap-msg to manager (~p): " 376 "~n ~p", [Pid, Pdu]), 377 Msg = Message#message{data = Pdu}, 378 Pid ! {snmp_msg, Msg, Ip, UdpPort} 379 end 380 381 catch 382 Class:Error:_ -> 383 ?EPRINT("Decoding (v1 or v2) error: " 384 "~n Class: ~p" 385 "~n Error: ~p " 386 "~n Bytes: ~p" 387 "~n Port: ~p" 388 "~n Ip: ~p", 389 [Class, Error, Bytes, UdpPort, Ip]) 390 end. 391 392 393%% This function assumes that the agent and the manager (thats us) 394%% has the same version. 395check_discovery_result('version-3', DiscoReqMsg, DiscoRspMsg) -> 396 ReqMsgID = getMsgID(DiscoReqMsg), 397 RspMsgID = getMsgID(DiscoRspMsg), 398 check_msgID(ReqMsgID, RspMsgID), 399 ReqRequestId = getRequestId('version-3', DiscoReqMsg), 400 RspRequestId = getRequestId('version-3', DiscoRspMsg), 401 check_requestId(ReqRequestId, RspRequestId), 402 {ok, getMsgAuthEngineID(DiscoRspMsg)}; 403check_discovery_result(Version, DiscoReqMsg, DiscoRspMsg) -> 404 ReqRequestId = getRequestId(Version, DiscoReqMsg), 405 RspRequestId = getRequestId(Version, DiscoRspMsg), 406 check_requestId(ReqRequestId, RspRequestId), 407 {ok, getSysDescr(DiscoRspMsg)}. 408 409check_msgID(ID, ID) -> 410 ok; 411check_msgID(ReqMsgID, RspMsgID) -> 412 throw({error, {invalid_msgID, ReqMsgID, RspMsgID}}). 413 414check_requestId(Id,Id) -> 415 ok; 416check_requestId(ReqRequestId, RspRequestId) -> 417 throw({error, {invalid_requestId, ReqRequestId, RspRequestId}}). 418 419getMsgID(M) when is_record(M, message) -> 420 (M#message.vsn_hdr)#v3_hdr.msgID. 421 422getRequestId('version-3',M) when is_record(M, message) -> 423 ((M#message.data)#scopedPdu.data)#pdu.request_id; 424getRequestId(_Version,M) when is_record(M, message) -> 425 (M#message.data)#pdu.request_id; 426getRequestId(Version,M) -> 427 io:format("************* ERROR ****************" 428 "~n Version: ~w" 429 "~n M: ~w~n", [Version,M]), 430 throw({error, {unknown_request_id, Version, M}}). 431 432getMsgAuthEngineID(M) when is_record(M, message) -> 433 SecParams1 = (M#message.vsn_hdr)#v3_hdr.msgSecurityParameters, 434 SecParams2 = snmp_pdus:dec_usm_security_parameters(SecParams1), 435 SecParams2#usmSecurityParameters.msgAuthoritativeEngineID. 436 437getSysDescr(M) when is_record(M, message) -> 438 getSysDescr((M#message.data)#pdu.varbinds); 439getSysDescr([]) -> 440 not_found; 441getSysDescr([#varbind{oid = [1,3,6,1,2,1,1,1], value = Value}|_]) -> 442 Value; 443getSysDescr([#varbind{oid = [1,3,6,1,2,1,1,1,0], value = Value}|_]) -> 444 Value; 445getSysDescr([_|T]) -> 446 getSysDescr(T). 447 448handle_v3_msg(Packet, #message{vsn_hdr = V3Hdr, data = Data}) -> 449 d("handle_v3_msg -> entry"), 450 %% Code copied from snmp_mpd.erl 451 #v3_hdr{msgID = MsgId, msgFlags = MsgFlags, 452 msgSecurityModel = MsgSecurityModel, 453 msgSecurityParameters = SecParams} = V3Hdr, 454 SecModule = get_security_module(MsgSecurityModel), 455 d("handle_v3_msg -> SecModule: ~p", [SecModule]), 456 SecLevel = hd(MsgFlags) band 3, 457 d("handle_v3_msg -> SecLevel: ~p", [SecLevel]), 458 IsReportable = snmp_misc:is_reportable(MsgFlags), 459 SecRes = (catch SecModule:process_incoming_msg(list_to_binary(Packet), 460 Data,SecParams,SecLevel)), 461 {_SecEngineID, SecName, ScopedPDUBytes, SecData, _} = 462 check_sec_module_result(SecRes, V3Hdr, Data, IsReportable), 463 case (catch snmp_pdus:dec_scoped_pdu(ScopedPDUBytes)) of 464 ScopedPDU when is_record(ScopedPDU, scopedPdu) -> 465 {ok, ScopedPDU, {MsgId, SecName, SecData}}; 466 {'EXIT', Reason} -> 467 throw({error, Reason}); 468 Error -> 469 throw({error, {scoped_pdu_decode_failed, Error}}) 470 end; 471handle_v3_msg(_Packet, BadMessage) -> 472 throw({error, bad_message, BadMessage}). 473 474get_security_module(?SEC_USM) -> 475 snmpa_usm; 476get_security_module(SecModel) -> 477 throw({error, {unknown_sec_model, SecModel}}). 478 479check_sec_module_result(Res, V3Hdr, Data, IsReportable) -> 480 d("check_sec_module_result -> entry with" 481 "~n Res: ~p", [Res]), 482 case Res of 483 {ok, X} -> 484 X; 485 {error, Reason, []} -> 486 throw({error, {securityError, Reason}}); 487 {error, Reason, ErrorInfo} when IsReportable == true -> 488 #v3_hdr{msgID = MsgID, msgSecurityModel = MsgSecModel} = V3Hdr, 489 case generate_v3_report_msg(MsgID, MsgSecModel, Data, ErrorInfo) of 490 error -> 491 throw({error, {securityError, Reason}}); 492 Packet -> 493 throw({error, {securityError, Reason}, Packet}) 494 end; 495 {error, Reason, _} -> 496 throw({error, {securityError, Reason}}); 497 Else -> 498 throw({error, {securityError, Else}}) 499 end. 500 501generate_v3_report_msg(_MsgID, _MsgSecurityModel, Data, ErrorInfo) -> 502 d("generate_v3_report_msg -> entry with" 503 "~n ErrorInfo: ~p", [ErrorInfo]), 504 {Varbind, SecName, Opts} = ErrorInfo, 505 ReqId = 506 if is_record(Data, scopedPdu) -> (Data#scopedPdu.data)#pdu.request_id; 507 true -> 0 508 end, 509 Pdu = #pdu{type = report, request_id = ReqId, 510 error_status = noError, error_index = 0, 511 varbinds = [Varbind]}, 512 SecLevel = snmp_misc:get_option(securityLevel, Opts, 0), 513 SnmpEngineID = snmp_framework_mib:get_engine_id(), 514 ContextEngineID = 515 snmp_misc:get_option(contextEngineID, Opts, SnmpEngineID), 516 ContextName = snmp_misc:get_option(contextName, Opts, ""), 517 mk_msg('version-3', Pdu, {ContextName, SecName, SnmpEngineID, 518 ContextEngineID, SecLevel}, 519 undefined). 520 521 522mk_discovery_msg('version-3', Pdu, _VsnHdr, UserName) -> 523 ScopedPDU = #scopedPdu{contextEngineID = "", 524 contextName = "", 525 data = Pdu}, 526 Bytes = snmp_pdus:enc_scoped_pdu(ScopedPDU), 527 MsgID = get(msg_id), 528 put(msg_id, MsgID+1), 529 UsmSecParams = 530 #usmSecurityParameters{msgAuthoritativeEngineID = "", 531 msgAuthoritativeEngineBoots = 0, 532 msgAuthoritativeEngineTime = 0, 533 msgUserName = UserName, 534 msgPrivacyParameters = "", 535 msgAuthenticationParameters = ""}, 536 SecBytes = snmp_pdus:enc_usm_security_parameters(UsmSecParams), 537 PduType = Pdu#pdu.type, 538 Hdr = #v3_hdr{msgID = MsgID, 539 msgMaxSize = 1000, 540 msgFlags = snmp_misc:mk_msg_flags(PduType, 0), 541 msgSecurityModel = ?SEC_USM, 542 msgSecurityParameters = SecBytes}, 543 Msg = #message{version = 'version-3', vsn_hdr = Hdr, data = Bytes}, 544 case (catch snmp_pdus:enc_message_only(Msg)) of 545 {'EXIT', Reason} -> 546 ?EPRINT("Discovery encoding error: " 547 "~n Pdu: ~p" 548 "~n Reason: ~p", [Pdu, Reason]), 549 error; 550 L when is_list(L) -> 551 {Msg#message{data = ScopedPDU}, L} 552 end; 553mk_discovery_msg(Version, Pdu, {Com, _, _, _, _}, _UserName) -> 554 Msg = #message{version = Version, vsn_hdr = Com, data = Pdu}, 555 case catch snmp_pdus:enc_message(Msg) of 556 {'EXIT', Reason} -> 557 ?EPRINT("Discovery encoding error:" 558 "~n Pdu: ~p" 559 "~n Reason: ~p", [Pdu, Reason]), 560 error; 561 L when is_list(L) -> 562 {Msg, L} 563 end. 564 565 566mk_msg('version-3', Pdu, {Context, User, EngineID, CtxEngineId, SecLevel}, 567 MsgData) -> 568 d("mk_msg(version-3) -> entry with" 569 "~n Pdu: ~p" 570 "~n Context: ~p" 571 "~n User: ~p" 572 "~n EngineID: ~p" 573 "~n CtxEngineID: ~p" 574 "~n SecLevel: ~p", 575 [Pdu, Context, User, EngineID, CtxEngineId, SecLevel]), 576 %% Code copied from snmp_mpd.erl 577 {MsgId, SecName, SecData} = 578 if 579 is_tuple(MsgData) andalso (Pdu#pdu.type =:= 'get-response') -> 580 MsgData; 581 true -> 582 Md = get(msg_id), 583 put(msg_id, Md + 1), 584 {Md, User, []} 585 end, 586 ScopedPDU = #scopedPdu{contextEngineID = CtxEngineId, 587 contextName = Context, 588 data = Pdu}, 589 ScopedPDUBytes = snmp_pdus:enc_scoped_pdu(ScopedPDU), 590 591 PduType = Pdu#pdu.type, 592 V3Hdr = #v3_hdr{msgID = MsgId, 593 msgMaxSize = 1000, 594 msgFlags = snmp_misc:mk_msg_flags(PduType, SecLevel), 595 msgSecurityModel = ?SEC_USM}, 596 Message = #message{version = 'version-3', vsn_hdr = V3Hdr, 597 data = ScopedPDUBytes}, 598 SecEngineID = case PduType of 599 'get-response' -> snmp_framework_mib:get_engine_id(); 600 _ -> EngineID 601 end, 602 case catch snmpa_usm:generate_outgoing_msg(Message, SecEngineID, 603 SecName, SecData, SecLevel) of 604 {'EXIT', Reason} -> 605 ?EPRINT("version-3 message encoding exit" 606 "~n Pdu: ~p" 607 "~n Reason: ~p", [Pdu, Reason]), 608 error; 609 {error, Reason} -> 610 ?EPRINT("version-3 message encoding error" 611 "~n Pdu: ~p" 612 "~n Reason: ~p", [Pdu, Reason]), 613 error; 614 Packet -> 615 Packet 616 end; 617mk_msg(Version, Pdu, {Com, _User, _EngineID, _Ctx, _SecLevel}, _SecData) -> 618 Msg = #message{version = Version, vsn_hdr = Com, data = Pdu}, 619 case catch snmp_pdus:enc_message(Msg) of 620 {'EXIT', Reason} -> 621 ?EPRINT("~w encoding error" 622 "~n Pdu: ~p" 623 "~n Reason: ~p", [Version, Pdu, Reason]), 624 error; 625 B when is_list(B) -> 626 B 627 end. 628 629format_hdr(#message{version = 'version-3', 630 vsn_hdr = #v3_hdr{msgID = MsgId}, 631 data = #scopedPdu{contextName = CName}}) -> 632 io_lib:format("v3, ContextName = \"~s\" Message ID = ~w\n", 633 [CName, MsgId]); 634format_hdr(#message{version = Vsn, vsn_hdr = Com}) -> 635 io_lib:format("~w, CommunityName = \"~s\"\n", [vsn(Vsn), Com]). 636 637vsn('version-1') -> v1; 638vsn('version-2') -> v2c. 639 640 641udp_send(UdpId, AgentIp, UdpPort, B) -> 642 ?vlog("attempt send message (~w bytes) to ~p", [sz(B), {AgentIp, UdpPort}]), 643 case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of 644 {error, ErrorReason} -> 645 ?EPRINT("failed (error) sending message to ~p:~p: " 646 "~n ~p",[AgentIp, UdpPort, ErrorReason]), 647 error; 648 {'EXIT', ExitReason} -> 649 ?EPRINT("failed (exit) sending message to ~p:~p:" 650 "~n ~p",[AgentIp, UdpPort, ExitReason]), 651 error; 652 _ -> 653 ok 654 end. 655 656 657get_pdu(#message{version = 'version-3', data = #scopedPdu{data = Pdu}}) -> 658 Pdu; 659get_pdu(#message{data = Pdu}) -> 660 Pdu. 661 662set_pdu(Msg, RePdu) when Msg#message.version == 'version-3' -> 663 SP = (Msg#message.data)#scopedPdu{data = RePdu}, 664 Msg#message{data = SP}; 665set_pdu(Msg, RePdu) -> 666 Msg#message{data = RePdu}. 667 668 669%% Disgustingly, we borrow stuff from the agent, including the 670%% local-db. Also, disgustingly, the local-db may actually not 671%% have died yet. But since we actually *need* a clean local-db, 672%% we must make sure its dead before we try to start the new 673%% instance... 674init_usm('version-3', Dir) -> 675 ?IPRINT("init_usm -> create (and init) fake \"agent\" table", []), 676 ets:new(snmp_agent_table, [set, public, named_table]), 677 ets:insert(snmp_agent_table, {agent_mib_storage, persistent}), 678 %% The local-db process may *still* be running (from a previous 679 %% test case), on the way down, but not yet dead. 680 %% Either way, before we try to start it, make sure its old instance 681 %% dead and *gone*! 682 %% How do we do that without getting hung up? Calling the stop 683 %% function, will not do since it uses Timeout=infinity. 684 ?IPRINT("init_usm -> ensure (old) fake local-db is dead", []), 685 ensure_local_db_dead(), 686 ?IPRINT("init_usm -> try start fake local-db", []), 687 case snmpa_local_db:start_link(normal, Dir, 688 [{sname, "MGR-LOCAL-DB"}, 689 {verbosity, trace}]) of 690 {ok, Pid} -> 691 ?IPRINT("init_usm -> local-db started: ~p" 692 "~n ~p", [Pid, process_info(Pid)]); 693 {error, {already_started, Pid}} -> 694 LDBInfo = process_info(Pid), 695 ?EPRINT("init_usm -> local-db already started: ~p" 696 "~n ~p", [Pid, LDBInfo]), 697 ?FAIL({still_running, snmpa_local_db, LDBInfo}); 698 {error, Reason} -> 699 ?EPRINT("init_usm -> failed start local-db: " 700 "~n ~p", [Reason]), 701 ?FAIL({failed_starting, snmpa_local_db, Reason}) 702 end, 703 NameDb = snmpa_agent:db(snmpEngineID), 704 ?IPRINT("init_usm -> try set manager engine-id"), 705 R = snmp_generic:variable_set(NameDb, "mgrEngine"), 706 snmp_verbosity:print(info, info, "init_usm -> engine-id set result: ~p", [R]), 707 ?IPRINT("init_usm -> try set engine boots (framework-mib)"), 708 snmp_framework_mib:set_engine_boots(1), 709 ?IPRINT("init_usm -> try set engine time (framework-mib)"), 710 snmp_framework_mib:set_engine_time(1), 711 ?IPRINT("init_usm -> try usm (mib) reconfigure"), 712 snmp_user_based_sm_mib:reconfigure(Dir), 713 ?IPRINT("init_usm -> done"), 714 ok; 715init_usm(_Vsn, _Dir) -> 716 ok. 717 718ensure_local_db_dead() -> 719 ensure_dead(whereis(snmpa_local_db), 2000). 720 721ensure_dead(Pid, Timeout) when is_pid(Pid) -> 722 MRef = erlang:monitor(process, Pid), 723 try 724 begin 725 ensure_dead_wait(Pid, MRef, Timeout), 726 ensure_dead_stop(Pid, MRef, Timeout), 727 ensure_dead_kill(Pid, MRef, Timeout), 728 exit(failed_stop_local_db) 729 end 730 catch 731 throw:ok -> 732 ok 733 end; 734ensure_dead(_, _) -> 735 ?IPRINT("ensure_dead -> already dead", []), 736 ok. 737 738ensure_dead_wait(Pid, MRef, Timeout) -> 739 receive 740 {'DOWN', MRef, process, Pid, _Info} -> 741 ?IPRINT("ensure_dead_wait -> died peacefully"), 742 throw(ok) 743 after Timeout -> 744 ?WPRINT("ensure_dead_wait -> giving up"), 745 ok 746 end. 747 748ensure_dead_stop(Pid, MRef, Timeout) -> 749 %% Spawn a stop'er process 750 StopPid = spawn(fun() -> snmpa_local_db:stop() end), 751 receive 752 {'DOWN', MRef, process, Pid, _Info} -> 753 ?NPRINT("ensure_dead -> dead (stopped)"), 754 throw(ok) 755 after Timeout -> 756 ?WPRINT("ensure_dead_stop -> giving up"), 757 exit(StopPid, kill), 758 ok 759 end. 760 761ensure_dead_kill(Pid, MRef, Timeout) -> 762 exit(Pid, kill), 763 receive 764 {'DOWN', MRef, process, Pid, _Info} -> 765 ?NPRINT("ensure_dead -> dead (killed)"), 766 throw(ok) 767 after Timeout -> 768 ?WPRINT("ensure_dead_kill -> giving up"), 769 ok 770 end. 771 772 773 774display_incomming_message(M) -> 775 display_message("Incomming",M). 776 777display_outgoing_message(M) -> 778 display_message("Outgoing", M). 779 780display_message(Direction, M) when is_record(M, message) -> 781 io:format("~s SNMP message:~n", [Direction]), 782 V = M#message.version, 783 display_version(V), 784 display_hdr(V, M#message.vsn_hdr), 785 display_msg_data(V, Direction, M#message.data); 786display_message(Direction, M) -> 787 io:format("~s message unknown: ~n~p", [Direction, M]). 788 789display_version('version-3') -> 790 display_prop("Version",'SNMPv3'); 791display_version(V) -> 792 display_prop("Version",V). 793 794display_hdr('version-3',H) -> 795 display_msgID(H#v3_hdr.msgID), 796 display_msgMaxSize(H#v3_hdr.msgMaxSize), 797 display_msgFlags(H#v3_hdr.msgFlags), 798 SecModel = H#v3_hdr.msgSecurityModel, 799 display_msgSecurityModel(SecModel), 800 display_msgSecurityParameters(SecModel,H#v3_hdr.msgSecurityParameters); 801display_hdr(_V,Community) -> 802 display_community(Community). 803 804display_community(Community) -> 805 display_prop("Community",Community). 806 807display_msgID(Id) -> 808 display_prop("msgID",Id). 809 810display_msgMaxSize(Size) -> 811 display_prop("msgMaxSize",Size). 812 813display_msgFlags([Flags]) -> 814 display_prop("msgFlags",Flags); 815display_msgFlags([]) -> 816 display_prop("msgFlags",no_value_to_display); 817display_msgFlags(Flags) -> 818 display_prop("msgFlags",Flags). 819 820display_msgSecurityModel(?SEC_USM) -> 821 display_prop("msgSecurityModel",'USM'); 822display_msgSecurityModel(Model) -> 823 display_prop("msgSecurityModel",Model). 824 825display_msgSecurityParameters(?SEC_USM,Params) -> 826 display_usmSecurityParameters(Params); 827display_msgSecurityParameters(_Model,Params) -> 828 display_prop("msgSecurityParameters",Params). 829 830display_usmSecurityParameters(P) when is_list(P) -> 831 P1 = lists:flatten(P), 832 display_usmSecurityParameters(snmp_pdus:dec_usm_security_parameters(P1)); 833display_usmSecurityParameters(P) when is_record(P,usmSecurityParameters) -> 834 ID = P#usmSecurityParameters.msgAuthoritativeEngineID, 835 display_msgAuthoritativeEngineID(ID), 836 Boots = P#usmSecurityParameters.msgAuthoritativeEngineBoots, 837 display_msgAuthoritativeEngineBoots(Boots), 838 Time = P#usmSecurityParameters.msgAuthoritativeEngineTime, 839 display_msgAuthoritativeEngineTime(Time), 840 Name = P#usmSecurityParameters.msgUserName, 841 display_msgUserName(Name), 842 SecParams = P#usmSecurityParameters.msgAuthenticationParameters, 843 display_msgAuthenticationParameters(SecParams), 844 PrivParams = P#usmSecurityParameters.msgPrivacyParameters, 845 display_msgPrivacyParameters(PrivParams); 846display_usmSecurityParameters(P) -> 847 display_prop("unknown USM sec paraams",P). 848 849display_msgAuthoritativeEngineID(ID) -> 850 display_prop("msgAuthoritativeEngineID",ID). 851 852display_msgAuthoritativeEngineBoots(V) -> 853 display_prop("msgAuthoritativeEngineBoots",V). 854 855display_msgAuthoritativeEngineTime(V) -> 856 display_prop("msgAuthoritativeEngineTime",V). 857 858display_msgUserName(V) -> 859 display_prop("msgUserName",V). 860 861display_msgAuthenticationParameters(V) -> 862 display_prop("msgAuthenticationParameters",V). 863 864display_msgPrivacyParameters(V) -> 865 display_prop("msgPrivacyParameters",V). 866 867display_msg_data('version-3',Direction,D) when is_record(D,scopedPdu) -> 868 display_scoped_pdu(Direction,D); 869display_msg_data(_Version,Direction,D) when is_record(D,pdu) -> 870 display_pdu(Direction,D); 871display_msg_data(_Version,_Direction,D) -> 872 display_prop("Unknown message data",D). 873 874display_scoped_pdu(Direction,P) -> 875 display_contextEngineID(P#scopedPdu.contextEngineID), 876 display_contextName(P#scopedPdu.contextName), 877 display_scoped_pdu_data(Direction,P#scopedPdu.data). 878 879display_contextEngineID(Id) -> 880 display_prop("contextEngineID",Id). 881 882display_contextName(Name) -> 883 display_prop("contextName",Name). 884 885display_scoped_pdu_data(Direction,D) when is_record(D,pdu) -> 886 display_pdu(Direction,D); 887display_scoped_pdu_data(Direction,D) when is_record(D,trappdu) -> 888 display_trappdu(Direction,D); 889display_scoped_pdu_data(_Direction,D) -> 890 display_prop("Unknown scoped pdu data",D). 891 892display_pdu(Direction, P) -> 893 io:format("~s PDU:~n", [Direction]), 894 display_type(P#pdu.type), 895 display_request_id(P#pdu.request_id), 896 display_error_status(P#pdu.error_status), 897 display_error_index(P#pdu.error_index), 898 display_varbinds(P#pdu.varbinds). 899 900display_type(T) -> 901 display_prop("Type",T). 902 903display_request_id(Id) -> 904 display_prop("Request id",Id). 905 906display_error_status(S) -> 907 display_prop("Error status",S). 908 909display_error_index(I) -> 910 display_prop("Error index",I). 911 912display_varbinds([H|T]) -> 913 display_prop_hdr("Varbinds"), 914 display_varbind(H), 915 display_varbinds(T); 916display_varbinds([]) -> 917 ok. 918 919display_varbind(V) when is_record(V,varbind) -> 920 display_oid(V#varbind.oid), 921 display_vtype(V#varbind.variabletype), 922 display_value(V#varbind.value), 923 display_org_index(V#varbind.org_index); 924display_varbind(V) -> 925 display_prop("\tVarbind",V). 926 927display_oid(V) -> 928 display_prop("\tOid",V). 929 930display_vtype(V) -> 931 display_prop("\t\tVariable type",V). 932 933display_value(V) -> 934 display_prop("\t\tValue",V). 935 936display_org_index(V) -> 937 display_prop("\t\tOrg index",V). 938 939display_trappdu(Direction,P) -> 940 io:format("~s TRAP-PDU:~n",[Direction]), 941 display_prop("TRAP-PDU",P). 942 943display_prop(S,no_value_to_display) -> 944 io:format("\t~s: ~n",[S]); 945display_prop(S,V) -> 946 io:format("\t~s: ~p~n",[S,V]). 947 948 949display_prop_hdr(S) -> 950 io:format("\t~s:~n",[S]). 951 952 953%%---------------------------------------------------------------------- 954%% Debug 955%%---------------------------------------------------------------------- 956 957sz(L) when is_list(L) -> 958 iolist_size(L); 959sz(B) when is_binary(B) -> 960 size(B); 961sz(O) -> 962 {unknown_size, O}. 963 964d(F) -> d(F, []). 965d(F,A) -> d(get(debug), F, A). 966 967d(true, F, A) -> 968 ?IPRINT(F, A); 969d(_,_F,_A) -> 970 ok. 971 972