snmp_pdus.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 744 行 · 第 1/2 页
ERL
744 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(snmp_pdus).-define(SNMP_USE_V3, true).-include("snmp_types.hrl").-define(VMODULE,"PDUS").-include("snmp_verbosity.hrl").%% See RFC1155, RFC1157, RFC1901, RFC1902, RFC1905, RFC2272%% API-export([enc_message/1, enc_message_only/1, enc_pdu/1, enc_varbind/1, enc_oct_str_tag/1, enc_scoped_pdu/1, enc_usm_security_parameters/1, dec_message/1, dec_message_only/1, dec_pdu/1, dec_scoped_pdu_data/1, dec_scoped_pdu/1, dec_usm_security_parameters/1, strip_encrypted_scoped_pdu_data/1, octet_str_to_bits/1, bits_to_str/1, get_encoded_length/1]).%% Returns the number of octets required to encode Length.get_encoded_length(Length) -> length(elength(Length)).dec_message([48 | Bytes]) -> Bytes2 = get_data_bytes(Bytes), {SNMPversion, Rest1} = dec_int_tag(Bytes2), case dec_snmp_ver(SNMPversion) of 'version-3' -> dec_rest_v3_msg(Rest1); Vsn -> % 1 or 2 dec_rest_v1_v2_msg(Vsn, Rest1) end.dec_message_only([48 | Bytes]) -> Bytes2 = get_data_bytes(Bytes), {SNMPversion, Rest1} = dec_int_tag(Bytes2), case dec_snmp_ver(SNMPversion) of 'version-3' -> dec_rest_v3_msg_only(Rest1); Vsn -> % 1 or 2 dec_rest_v1_v2_msg_only(Vsn, Rest1) end.dec_snmp_ver(0) -> 'version-1';dec_snmp_ver(1) -> 'version-2';dec_snmp_ver(3) -> 'version-3';dec_snmp_ver(Vsn) -> exit({bad_version, Vsn}).dec_rest_v1_v2_msg(Vsn, Rest1) -> {Community, Rest2} = dec_oct_str_tag(Rest1), PDU = dec_pdu(Rest2), #message{version = Vsn, vsn_hdr = Community, data = PDU}.dec_rest_v1_v2_msg_only(Vsn, Rest1) -> {Community, Rest2} = dec_oct_str_tag(Rest1), #message{version = Vsn, vsn_hdr = Community, data = Rest2}.dec_rest_v3_msg_only([48 | Bytes]) -> % starts with header data sequence {Size, Tail} = dec_len(Bytes), {HBytes, Bytes1} = split_at(Tail, Size, []), %% Decode HeaderData {MsgID, HBytes1} = dec_int_tag(HBytes), chk_msg_id(MsgID), {MsgMaxSize, HBytes2} = dec_int_tag(HBytes1), chk_msg_max_size(MsgMaxSize), {MsgFlags, HBytes3} = dec_oct_str_tag(HBytes2), {MsgSecurityModel, []} = dec_int_tag(HBytes3), chk_msg_sec_model(MsgSecurityModel), %% Continue with Message% {MsgSecurityParameters, Bytes2} = dec_oct_str_tag(Bytes1), [4 | Bytes1a] = Bytes1, {Size1a, Tail1a} = dec_len(Bytes1a), {MsgSecurityParameters, Bytes2} = split_at(Tail1a, Size1a, []), %% [48 , HdrDataLen, HdrData, 4, MsgSecLen, MsgSec, ...] %% NOTE: HdrDataLen is always so small that one octet is enough to %% encode its length. %% MsgSecLen is worse... but for USM, it is small enough for %% one octet. USM is currently the only secmodel. %% 1 + 1 + Size + 1 + 1 + Size1a HdrSize = Size + Size1a + 4, V3Hdr = #v3_hdr{msgID = MsgID, msgMaxSize = MsgMaxSize, msgFlags = MsgFlags, %dec_msg_flags(MsgFlags), msgSecurityModel = MsgSecurityModel, msgSecurityParameters = MsgSecurityParameters, hdr_size = HdrSize}, #message{version = 'version-3', vsn_hdr = V3Hdr, data = Bytes2}.dec_rest_v3_msg(Bytes) -> Message = dec_rest_v3_msg_only(Bytes), Data = Message#message.data, Message#message{data = dec_scoped_pdu_data(Data)}.dec_scoped_pdu_data([48 | Bytes]) -> % plaintext {ScopedPdu, []} = dec_scoped_pdu_notag(Bytes), ScopedPdu;dec_scoped_pdu_data([4 | Bytes]) -> % encryptedPDU {EncryptedPDU, []} = dec_oct_str_notag(Bytes), EncryptedPDU. dec_scoped_pdu([48 | Bytes]) -> element(1, dec_scoped_pdu_notag(Bytes)).dec_scoped_pdu_notag(Bytes) -> Bytes1 = get_data_bytes(Bytes), {ContextEngineID, Bytes2} = dec_oct_str_tag(Bytes1), {ContextName, Bytes3} = dec_oct_str_tag(Bytes2), Pdu = dec_pdu(Bytes3), {#scopedPdu{contextEngineID = ContextEngineID, contextName = ContextName, data = Pdu}, []}.dec_pdu_tag(160) -> 'get-request';dec_pdu_tag(161) -> 'get-next-request';dec_pdu_tag(162) -> 'get-response';dec_pdu_tag(163) -> 'set-request';%% 164 SNMPv1 Trap%% 165 Bulkdec_pdu_tag(166) -> 'inform-request';dec_pdu_tag(167) -> 'snmpv2-trap';dec_pdu_tag(168) -> report.dec_pdu([164 | Bytes]) -> % It's a trap Bytes2 = get_data_bytes(Bytes), {Enterprise, Rest1} = dec_oid_tag(Bytes2), {{'IpAddress', AgentAddr}, Rest2} = dec_value(Rest1), {GenericTrap, Rest3} = dec_int_tag(Rest2), {SpecificTrap, Rest4} = dec_int_tag(Rest3), {{'TimeTicks', TimeStamp}, VBBytes} = dec_value(Rest4), VBs = dec_VBs(VBBytes), #trappdu{enterprise = Enterprise, agent_addr = AgentAddr, generic_trap = GenericTrap, specific_trap = SpecificTrap, time_stamp = TimeStamp, varbinds = VBs};dec_pdu([165 | Bytes]) -> % Bulk Bytes2 = get_data_bytes(Bytes), {RequestID, Rest1} = dec_int_tag(Bytes2), {NonRepeaters, Rest2} = dec_int_tag(Rest1), {MaxRepetitions,VBbytes} = dec_int_tag(Rest2), VBs = dec_VBs(VBbytes), #pdu{type = 'get-bulk-request', request_id = RequestID, error_status = NonRepeaters, error_index = MaxRepetitions, varbinds = VBs};dec_pdu([PduTag | Bytes]) -> Type = dec_pdu_tag(PduTag), Bytes2 = get_data_bytes(Bytes), {RequestID, Rest1} = dec_int_tag(Bytes2), {ErrStat, Rest2} = dec_int_tag(Rest1), ErrStatus = case lists:keysearch(ErrStat, 2, errMsgs()) of {value, {ErrStatName, _ErrStat}} -> ErrStatName; false -> ErrStat end, {ErrIndex, VarbindsBytes} = dec_int_tag(Rest2), VBs = dec_VBs(VarbindsBytes), #pdu{type = Type, request_id = RequestID, error_status = ErrStatus, error_index = ErrIndex, varbinds = VBs}.dec_VBs([48 | Bytes]) -> Bytes1 = get_data_bytes(Bytes), dec_individual_VBs(Bytes1, 1, []).dec_individual_VBs([], _No, VBs) -> lists:reverse(VBs);dec_individual_VBs([48 | Bytes], OrgIndex, AccVBs) -> {_SizeOfThisVB, Bytes2} = dec_len(Bytes), {Oid, Rest} = dec_oid_tag(Bytes2), {{Type, Value}, Rest2} = dec_value(Rest), % perhaps we should check that we have eaten SizeOfThisVB bytes, but we % don't consider ourselves to have time for such list traversing stuff. dec_individual_VBs(Rest2, OrgIndex + 1, [#varbind{oid = Oid, variabletype = Type, value = Value, org_index = OrgIndex} | AccVBs]).dec_usm_security_parameters([48 | Bytes1]) -> {_Len, Bytes2} = dec_len(Bytes1), {MsgAuthEngineID, Bytes3} = dec_oct_str_tag(Bytes2), {MsgAuthEngineBoots, Bytes4} = dec_int_tag(Bytes3), {MsgAuthEngineTime, Bytes5} = dec_int_tag(Bytes4), {MsgUserName, Bytes6} = dec_oct_str_tag(Bytes5), {MsgAuthParams, Bytes7} = dec_oct_str_tag(Bytes6), {MsgPrivParams, []} = dec_oct_str_tag(Bytes7), #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID, msgAuthoritativeEngineBoots = MsgAuthEngineBoots, msgAuthoritativeEngineTime = MsgAuthEngineTime, msgUserName = MsgUserName, msgAuthenticationParameters = MsgAuthParams, msgPrivacyParameters = MsgPrivParams}.strip_encrypted_scoped_pdu_data([48 | Bytes]) -> {Size, Tail} = dec_len(Bytes), [48 | elength(Size)] ++ strip(Size, Tail).strip(N, [H|T]) when N > 0 -> [H | strip(N-1, T)];strip(0, _Tail) -> [].%%----------------------------------------------------------------------%% Returns:{Type, Value}%%----------------------------------------------------------------------dec_value([6 | Bytes]) -> {Value, Rest} = dec_oid_notag(Bytes), {{'OBJECT IDENTIFIER', Value}, Rest};dec_value([5,0 | T]) -> {{'NULL', 'NULL'}, T};dec_value([2 | Bytes]) -> {Value, Rest} = dec_integer_notag(Bytes), {{'INTEGER', Value}, Rest};dec_value([4 | Bytes]) -> {Value, Rest} = dec_oct_str_notag(Bytes), {{'OCTET STRING', Value}, Rest};dec_value([64 | Bytes]) -> {Value, Rest} = dec_oct_str_notag(Bytes), {{'IpAddress', Value}, Rest};dec_value([65 | Bytes]) -> {Value, Rest} = dec_integer_notag(Bytes), if Value >= 0, Value =< 4294967295 -> {{'Counter32', Value}, Rest}; true -> exit({error, {bad_counter32, Value}}) end;dec_value([66 | Bytes]) -> {Value, Rest} = dec_integer_notag(Bytes), if Value >= 0, Value =< 4294967295 -> {{'Unsigned32', Value}, Rest}; true -> exit({error, {bad_unsigned32, Value}}) end;dec_value([67 | Bytes]) -> {Value, Rest} = dec_integer_notag(Bytes), if Value >= 0, Value =< 4294967295 -> {{'TimeTicks', Value}, Rest}; true -> exit({error, {bad_timeticks, Value}}) end;dec_value([68 | Bytes]) -> {Value, Rest} = dec_oct_str_notag(Bytes), {{'Opaque', Value}, Rest};dec_value([70 | Bytes]) -> {Value, Rest} = dec_integer_notag(Bytes), if Value >= 0, Value =< 18446744073709551615 -> {{'Counter64', Value}, Rest}; true -> exit({error, {bad_counter64, Value}}) end;dec_value([128,0|T]) -> {{'NULL', noSuchObject}, T};dec_value([129,0|T]) -> {{'NULL', noSuchInstance}, T};dec_value([130,0|T]) -> {{'NULL', endOfMibView}, T}.%%----------------------------------------------------------------------%% Purpose: Uses the beginning length bytes to return the actual data.%% If data has the wrong length, the program is exited.%% Pre: Tag is removed.%%----------------------------------------------------------------------get_data_bytes(Bytes) -> {Size, Tail} = dec_len(Bytes), if length(Tail) == Size -> Tail; true -> exit({error, {wrong_length, Bytes}}) end.split_at(L, 0, Acc) -> {lists:reverse(Acc), L};split_at([H|T], N, Acc) -> split_at(T, N-1, [H|Acc]).%%----------------------------------------------------------------------%% All decoding routines return: {Data, RestBytes}%%----------------------------------------------------------------------dec_int_tag([2 | Bytes]) -> dec_integer_notag(Bytes).dec_integer_notag(Ints) -> {Size, Ints2} = dec_len(Ints), if hd(Ints2) band 128 == 0 -> %% Positive number dec_pos_int(Ints2, Size, 8 * (Size - 1)); true -> %% Negative dec_neg_int(Ints2, Size, 8 * (Size - 1)) end.dec_pos_int(T, 0, _) -> {0, T};dec_pos_int([Byte|Tail], Size, Shift) -> {Int, Rest} = dec_pos_int(Tail, Size - 1, Shift - 8), {(Byte bsl Shift) bor Int, Rest}.dec_neg_int(T, 0, _) -> {0, T};dec_neg_int([Byte|Tail], Size, Shift) -> {Int, Rest} = dec_pos_int(Tail, Size - 1, Shift-8), {(-128 + (Byte band 127) bsl Shift) bor Int, Rest}.dec_oct_str_tag([4 | Bytes]) -> dec_oct_str_notag(Bytes).dec_oct_str_notag(Bytes) -> {Size, Tail} = dec_len(Bytes), split_at(Tail, Size, []).dec_oid_tag([6 | Bytes]) -> dec_oid_notag(Bytes).dec_oid_notag(Bytes) -> {Size, [H | Tail]} = dec_len(Bytes), {Oid, Rest} = dec_oid_elements(Tail, Size - 1, []), {[H div 40, H rem 40 | Oid], Rest}.dec_oid_elements(L, 0, Acc) -> {lists:reverse(Acc), L};dec_oid_elements([Dig|Tail], Size, Acc) when Dig < 128 -> dec_oid_elements(Tail, Size - 1, [Dig | Acc]);dec_oid_elements([Dig|Tail], Size, Acc) -> {Num, Neaten, Tl} = dec_oid_element(Tail,1,Dig band 127), dec_oid_elements(Tl, Size - Neaten, [Num|Acc]).dec_oid_element([Dig|Tail], Neaten, Num) when Dig < 128 -> {Num*128+Dig,Neaten+1,Tail};dec_oid_element([Dig|Tail],Neaten, Num) -> dec_oid_element(Tail, Neaten+1, Num*128 + (Dig band 127)).chk_msg_id(MsgId) when MsgId >= 0, MsgId =< 2147483647 -> ok;chk_msg_id(MsgId) -> exit({bad_msg_id, MsgId}). chk_msg_max_size(MMS) when MMS >= 484, MMS =< 2147483647 -> ok;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?