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 + -
显示快捷键?