SNMP 協議 分析 抓包 Protocol Specification 拆包實踐


 

gosnmp/main.go at v1.35.0 · gosnmp/gosnmp · GitHub https://github.com/gosnmp/gosnmp/blob/v1.35.0/examples/example3/main.go

params := &g.GoSNMP{
Target: "192.168.91.20",
Port: 161,
Version: g.Version3,
SecurityModel: g.UserSecurityModel,
MsgFlags: g.AuthPriv,
Timeout: time.Duration(30) * time.Second,
SecurityParameters: &g.UsmSecurityParameters{UserName: "user",
AuthenticationProtocol: g.SHA,
AuthenticationPassphrase: "password",
PrivacyProtocol: g.DES,
PrivacyPassphrase: "password",
},
}

 

$ snmpwalk --help
USAGE: snmpwalk [OPTIONS] AGENT [OID]

Version: 5.7.2
Web: http://www.net-snmp.org/
Email: net-snmp-coders@lists.sourceforge.net

OPTIONS:
-h, --help display this help message
-H display configuration file directives understood
-v 1|2c|3 specifies SNMP version to use
-V, --version display package version number
SNMP Version 1 or 2c specific
-c COMMUNITY set the community string
SNMP Version 3 specific
-a PROTOCOL set authentication protocol (MD5|SHA)
-A PASSPHRASE set authentication protocol pass phrase
-e ENGINE-ID set security engine ID (e.g. 800000020109840301)
-E ENGINE-ID set context engine ID (e.g. 800000020109840301)
-l LEVEL set security level (noAuthNoPriv|authNoPriv|authPriv)
-n CONTEXT set context name (e.g. bridge1)
-u USER-NAME set security name (e.g. bert)
-x PROTOCOL set privacy protocol (DES|AES)
-X PASSPHRASE set privacy protocol pass phrase
-Z BOOTS,TIME set destination engine boots/time
General communication options
-r RETRIES set the number of retries
-t TIMEOUT set the request timeout (in seconds)
Debugging
-d dump input/output packets in hexadecimal
-D[TOKEN[,...]] turn on debugging output for the specified TOKENs
(ALL gives extremely verbose debugging output)
General options
-m MIB[:...] load given list of MIBs (ALL loads everything)
-M DIR[:...] look in given list of directories for MIBs
(default: $HOME/.snmp/mibs:/usr/local/share/snmp/mibs)
-P MIBOPTS Toggle various defaults controlling MIB parsing:
u: allow the use of underlines in MIB symbols
c: disallow the use of "--" to terminate comments
d: save the DESCRIPTIONs of the MIB objects
e: disable errors when MIB symbols conflict
w: enable warnings when MIB symbols conflict
W: enable detailed warnings when MIB symbols conflict
R: replace MIB symbols from latest module
-O OUTOPTS Toggle various defaults controlling output display:
0: print leading 0 for single-digit hex characters
a: print all strings in ascii format
b: do not break OID indexes down
e: print enums numerically
E: escape quotes in string indices
f: print full OIDs on output
n: print OIDs numerically
q: quick print for easier parsing
Q: quick print with equal-signs
s: print only last symbolic element of OID
S: print MIB module-id plus last element
t: print timeticks unparsed as numeric integers
T: print human-readable text along with hex strings
u: print OIDs using UCD-style prefix suppression
U: don't print units
v: print values only (not OID = value)
x: print all strings in hex format
X: extended index format
-I INOPTS Toggle various defaults controlling input parsing:
b: do best/regex matching to find a MIB node
h: don't apply DISPLAY-HINTs
r: do not check values for range/type legality
R: do random access to OID labels
u: top-level OIDs must have '.' prefix (UCD-style)
s SUFFIX: Append all textual OIDs with SUFFIX before parsing
S PREFIX: Prepend all textual OIDs with PREFIX before parsing
-L LOGOPTS Toggle various defaults controlling logging:
e: log to standard error
o: log to standard output
n: don't log at all
f file: log to the specified file
s facility: log to syslog (via the specified facility)

(variants)
[EON] pri: log to standard error, output or /dev/null for level 'pri' and above
[EON] p1-p2: log to standard error, output or /dev/null for levels 'p1' to 'p2'
[FS] pri token: log to file/syslog for level 'pri' and above
[FS] p1-p2 token: log to file/syslog for levels 'p1' to 'p2'
-C APPOPTS Set various application specific behaviours:
p: print the number of variables found
i: include given OID in the search range
I: don't include the given OID, even if no results are returned
c: do not check returned OIDs are increasing
t: Display wall-clock time to complete the walk
T: Display wall-clock time to complete each request
E {OID}: End the walk at the specified OID

 

 

 

 

rfc1157 https://datatracker.ietf.org/doc/html/rfc1157#section-3.2.2

 

4.  Protocol Specification

   The network management protocol is an application protocol by which
   the variables of an agent's MIB may be inspected or altered.

   Communication among protocol entities is accomplished by the exchange
   of messages, each of which is entirely and independently represented
   within a single UDP datagram using the basic encoding rules of ASN.1
   (as discussed in Section 3.2.2).  A message consists of a version
   identifier, an SNMP community name, and a protocol data unit (PDU).
   A protocol entity receives messages at UDP port 161 on the host with
   which it is associated for all messages except for those which report
   traps (i.e., all messages except those which contain the Trap-PDU).
   Messages which report traps should be received on UDP port 162 for
   further processing.  An implementation of this protocol need not
   accept messages whose length exceeds 484 octets.  However, it is
   recommended that implementations support larger datagrams whenever
   feasible.

   It is mandatory that all implementations of the SNMP support the five
   PDUs:  GetRequest-PDU, GetNextRequest-PDU, GetResponse-PDU,
   SetRequest-PDU, and Trap-PDU.

    RFC1157-SNMP DEFINITIONS ::= BEGIN

     IMPORTS
          ObjectName, ObjectSyntax, NetworkAddress, IpAddress, TimeTicks
                  FROM RFC1155-SMI;


     -- top-level message

             Message ::=
                     SEQUENCE {
                          version        -- version-1 for this RFC
                             INTEGER {
                                 version-1(0)
                             },

                         community      -- community name
                             OCTET STRING,

                         data           -- e.g., PDUs if trivial
                             ANY        -- authentication is being used
                     }






Case, Fedor, Schoffstall, & Davin [Page 16]


RFC 1157 SNMP May 1990 -- protocol data units PDUs ::= CHOICE { get-request GetRequest-PDU, get-next-request GetNextRequest-PDU, get-response GetResponse-PDU, set-request SetRequest-PDU, trap Trap-PDU } -- the individual PDUs and commonly used -- data types will be defined later END 

 

packet:PACKET: 234 bytes, wire length 234 cap length 234 @ 2021-11-01 19:37:02.933491 +0800 CST

- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..220..] SrcMAC=00:0 c:17:43:9b:44 DstMAC=1c:98:ec:2a:75:18 EthernetType=IPv4 Length=0}

- Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..200..] Version=4 IHL=5 TOS=0 Length=220 Id=45535 Flags=DF FragOffset=0 TTL=64 Protocol=UDP Checksu

m=14166 SrcIP=10.20.30.171 DstIP=10.20.30.9 Options=[] Padding=[]}

- Layer 3 (08 bytes) = UDP {Contents=[..8..] Payload=[..192..] SrcPort=31453 DstPort=162(snmptrap) Length=200 Checksum=52923}

- Layer 4 (192 bytes) = Payload 192 byte(s)

UDP:&{{[122 221 0 162 0 200 206 187] [

(48 129  189)  (2 1 1 )(4 6  112 117 98 108 105 99) (167 129 175)(2 4 31 169 179 27)(2 1 0 2 1 0) (48 129  160 )  

(48 16  6 8  43 6 1 2 1 1 3 0            67 4   2 175 245 221 )  

(48 25  6 10  43 6 1 6 3 1 1 4 1 0        6 11   43 6 1 4 1 129 224 41 1 8 11)  

(48 16  6 11  43 6 1 4 1 129 224 41 3 1 1  2 1  0)  

(48 64  6 11  43 6 1 4 1 129 224 41 3 1 2  4 49  77 111 117 110 116 32 108 111 99 97 116 105 111 110 32 47 100 97

116 97 32 104 97 115 32 101 120 99 101 101 100 101 100 32 117 115 97 103 101 32

116 104 114 101 115 104 111 108 100 )

(48 29  6 11  43 6 1 4 1 129 224 41 3 1 3  6 14  43 6 1 4 1 129 224 41 1 5 1 1 5 1)

 

]} 31453 162(snmptrap) 200 52923 [122 221] [0 162] {<nil>}}

packet:PACKET: 269 bytes, wire length 269 cap length 269 @ 2021-11-01 19:37:24.239214 +0800 CST

- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..255..] SrcMAC=00:0c:17:49:23:c4 DstMAC=1c:98:ec:2a:75:18 EthernetType=IPv4 Length=0}

- Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..235..] Version=4 IHL=5 TOS=0 Length=255 Id=14536 Flags=DF FragOffset=0 TTL=64 Protocol=UDP Checksu

m=45270 SrcIP=10.20.30.31 DstIP=10.20.30.9 Options=[] Padding=[]}

- Layer 3 (08 bytes) = UDP {Contents=[..8..] Payload=[..227..] SrcPort=3255 9 DstPort=162(snmptrap) Length=235 Checksum=59772}

- Layer 4 (227 bytes) = Payload 227 byte(s)

UDP:&{{[127 47 0 162 0 235 233 124] [

(48 129 224) (2 1 1) (4 6 112 117 98 108 105 99) (167 129 210)( 2 4 13 129 120 77)  (2 1 0 2 1 0)  (48 129 195) 

(48 16  6 8   43 6 1 2 1 1 3 0            67 4  2 220 87 227)

(48 25  6 10  43 6 1 6 3 1 1 4 1 0         6 11  43 6 1 4 1 129 224 41 1 8 23)  

(48 16  6 11  43 6 1 4 1 129 224 41 3 1 1   2 1  0)

(48 99  6 11  43 6 1 4 1 129 224 4 1 3 1 2   4 84  72 68 68 32 83 77 65 82 84 32 97 116 116 114 105 98 117 116 101 32

39 85 68 77 65 95 67 82 67 95 69 114 114 111 114 95 67 111 117 110 116 39 32 102

111 114 32 100 105 115 107 32 39 80 83 68 45 115 108 111 116 45 51 39 32 99 104

97 110 103 101 100 32 102 114 111 109 32 48 32 116 111 32 49)

(48 29  6 11  43 6 1 4 1 129 224 41 3 1 3  6 14  43 6 1 4 1 129 224 41 1 3 1 1 14 2)

 

]} 32559 162(snmptra p) 235 59772 [127 47] [0 162] {<nil>}}

 

主體結構:

(類型-1個字節,字節數-1個字節,內容)

 

packet:PACKET: 234 bytes, wire length 234 cap length 234 @ 2021-11-01 19:37:02.9

33491 +0800 CST

- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..220..] SrcMAC=00:0

c:17:43:9b:44 DstMAC=1c:98:ec:2a:75:18 EthernetType=IPv4 Length=0}

- Layer 2 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..200..] Version=4 I

HL=5 TOS=0 Length=220 Id=45535 Flags=DF FragOffset=0 TTL=64 Protocol=UDP Checksu

m=14166 SrcIP=10.20.30.171 DstIP=10.20.30.9 Options=[] Padding=[]}

- Layer 3 (08 bytes) = UDP      {Contents=[..8..] Payload=[..192..] SrcPort=3145

3 DstPort=162(snmptrap) Length=200 Checksum=52923}

- Layer 4 (192 bytes) = Payload 192 byte(s)

 

UDP:&{{[122 221 0 162 0 200 206 187] [(UDP payload)]} 31453 162(snmptrap) 200 52923 [122 221] [0 1

62] {<nil>}}

 

UDP payload:[48 129 189 2 1 1 4 6 112 117 98 108 105 99 167 129 175 2 4 31 169 1

79 27 2 1 0 2 1 0 48 129 160 48 16 6 8 43 6 1 2 1 1 3 0 67 4 2 175 245 221 48 25

 6 10 43 6 1 6 3 1 1 4 1 0 6 11 43 6 1 4 1 129 224 41 1 8 11 48 16 6 11 43 6 1 4

 1 129 224 41 3 1 1 2 1 0 48 64 6 11 43 6 1 4 1 129 224 41 3 1 2 4 49 77 111 117

 110 116 32 108 111 99 97 116 105 111 110 32 47 100 97 116 97 32 104 97 115 32 1

01 120 99 101 101 100 101 100 32 117 115 97 103 101 32 116 104 114 101 115 104 1

11 108 100 48 29 6 11 43 6 1 4 1 129 224 41 3 1 3 6 14 43 6 1 4 1 129 224 41 1 5

 1 1 5 1]

 

 

packet:PACKET: 269 bytes, wire length 269 cap length 269 @ 2021-11-01 19:37:24.2

39214 +0800 CST

- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..255..] SrcMAC=00:0

c:17:49:23:c4 DstMAC=1c:98:ec:2a:75:18 EthernetType=IPv4 Length=0}

- Layer 2 (20 bytes) = IPv4     {Contents=[..20..] Payload=[..235..] Version=4 I

HL=5 TOS=0 Length=255 Id=14536 Flags=DF FragOffset=0 TTL=64 Protocol=UDP Checksu

m=45270 SrcIP=10.20.30.31 DstIP=10.20.30.9 Options=[] Padding=[]}

- Layer 3 (08 bytes) = UDP      {Contents=[..8..] Payload=[..227..] SrcPort=3255

9 DstPort=162(snmptrap) Length=235 Checksum=59772}

- Layer 4 (227 bytes) = Payload 227 byte(s)

 

 

UDP:&{{[127 47 0 162 0 235 233 124] [(UDP payload)]} 32559 162(snmptra

p) 235 59772 [127 47] [0 162] {<nil>}}

 

UDP payload:[48 129 224 2 1 1 4 6 112 117 98 108 105 99 167 129 210 2 4 13 129 1

20 77 2 1 0 2 1 0 48 129 195 48 16 6 8 43 6 1 2 1 1 3 0 67 4 2 220 87 227 48 25

6 10 43 6 1 6 3 1 1 4 1 0 6 11 43 6 1 4 1 129 224 41 1 8 23 48 16 6 11 43 6 1 4

1 129 224 41 3 1 1 2 1 0 48 99 6 11 43 6 1 4 1 129 224 41 3 1 2 4 84 72 68 68 32

 83 77 65 82 84 32 97 116 116 114 105 98 117 116 101 32 39 85 68 77 65 95 67 82

67 95 69 114 114 111 114 95 67 111 117 110 116 39 32 102 111 114 32 100 105 115

107 32 39 80 83 68 45 115 108 111 116 45 51 39 32 99 104 97 110 103 101 100 32 1

02 114 111 109 32 48 32 116 111 32 49 48 29 6 11 43 6 1 4 1 129 224 41 3 1 3 6 1

4 43 6 1 4 1 129 224 41 1 3 1 1 14 2]  

 

 

EndOfContents     Asn1BER = 0x00

UnknownType       Asn1BER = 0x00

Boolean           Asn1BER = 0x01

Integer           Asn1BER = 0x02

BitString         Asn1BER = 0x03

OctetString       Asn1BER = 0x04

Null              Asn1BER = 0x05

ObjectIdentifier  Asn1BER = 0x06

ObjectDescription Asn1BER = 0x07

IPAddress         Asn1BER = 0x40

Counter32         Asn1BER = 0x41

Gauge32           Asn1BER = 0x42

TimeTicks         Asn1BER = 0x43

Opaque            Asn1BER = 0x44

NsapAddress       Asn1BER = 0x45

Counter64         Asn1BER = 0x46

Uinteger32        Asn1BER = 0x47

OpaqueFloat       Asn1BER = 0x78

OpaqueDouble      Asn1BER = 0x79

NoSuchObject      Asn1BER = 0x80

NoSuchInstance    Asn1BER = 0x81

EndOfMibView      Asn1BER = 0x82

 

 

 

[轉] Snmpv1 v2報文格式詳細介紹 - CurrentJ - ITeye博客 https://www.iteye.com/blog/currentj-2280760

SNMP的報文格式

SNMP代理和管理站通過SNMP協議中的標准消息進行通信,每個消息都是一個單獨的數據報。SNMP使用UDP(用戶數據報協議)作為第四層協議(傳輸協議),進行無連接操作。SNMP消息報文包含兩個部分:SNMP報頭和協議數據單元PDU。

 

 

 

在實際網絡傳輸環境下,SNMP報文的長度取決於其所采用的編碼方式。SNMP統一采用BER(Basic Encoding Rule)的編碼規則,同時在正式SNMP規范中使用的是ASN.1語法,AbastractSyntax Notation v1,即抽象語法描述語言。這兩個概念在后面實踐環節再做進一步介紹,這里只要稍微了解一下即可,不妨礙我們對協議本身的分析。這里我們簡單解釋一下BER編碼規則:

    BER作為ANS.1的基本編碼規則,描述具體的ANS.1對象如何編碼為比特流在網絡上進行傳輸。BER編碼規則由三部分組成:

 

 

 

 

SNMP中定義了幾種基本的數據類型,其中v1和v2版有些改動,具體參見相應的RFC文檔。這里我們只介紹幾種最常見的類型:

l  INTEGER:一個整數

l  OCTER STRING: 0或多個8bit字節,每個字節在0~255之間取值

l  DisplayString:0或多個8bit字節,每個字節必須是ASCII碼。在MIB-II中,所有該類型變量不能超過255個字符(0個字符可以)

l  NULL:代表相關的變量沒有值

l  IpAddress:4字節長的OCTER STRING,以網絡字節序表示IP地址

l  PhyAddress:6字節長的OCTER STRING,代表物理地址

l  Counter:非負整數,可以從0遞增到232-1()。達到最大值后歸0

l  TimeTicks:時間計數器,以0.01秒為單位遞增,不同的變量可以有不同的遞增幅度。所以在定義這種類型的變量時需要制定遞增幅度

l  SEQUENCE:與C語言中的結構體類似

l  SEQUENCE OF:一個向量,參見后面ANS.1語法詳細介紹章節

SNMP報文在傳輸層是封裝在UDP報文中的,而UDP又是基於IP網絡的,因此,我們可以得到完整的報文描述結構,如下圖所示:

 

 

 

 

 PDU類型其實包含兩個字節,第一個字節表示真實的PDU的類型;第二個字節表示后面報文所占的字節總數。針對SNMPv1,這個字段取值如下:

表1 PDU類型

PDU類型

   名 稱

0

get-request

1

get-next-request

2

get-response

3

set-request

4

trap

 也就是說,trap的類型是4。但是在數據報文中,該字段一般表示為ax,其中x取[0,4],即a0~a3表示相應的get、set等操作,a4表示trap報文。這里除了類型字段意外,其他字段均采用BER編碼方式:

 

 

實戰演練之報文格式分析

    Trap報文格式和上述圖5所展示的結構有些差別,這里我們只分析SNMPv1和SNMPv2的Trap報文格式。trap報文前面的部分都一樣,區別在PDU協議數據單元部分。

SNMPv1報文

SNMPv1的Trap報文格式如下所示:

 

 

 

注意:除了PDU類型和PDU長度字段外,后面的每個字段都是BER編碼方式。

    trap類型”可以取以下值,其中0~6是已定義的特定trap,7及其以后的類型由供應商自定義。

表2 trap類型、名稱及描述信息

trap類型

名稱

描述信息

0

coldStart

代理進程對自己初始化

1

warmStart

代理進程對自己重新初始化

2

linkDown

一個接口已從工作狀態變為故障狀態(報文中的第一個變量標識此接口)

3

linkUp

一個接口已從故障狀態變為工作狀態(報文中的第一個變量標識此接口)

4

authenticationFailure

從SNMP管理進程收到無效共同體的報文

5

egpNeighborLoss

一個EGP鄰站已變為故障狀態(報文中的第一個變量包含鄰站IP地址)

6

enterpriseSpecific

在這個特定的代碼段中查找trap信息

 

通過wireshark抓包工具,捕獲一條如下的SNMP報文,接下來對其進行仔細分析。

SNMPv1原始報文內容:

00 23 5a 9e 58b9 00 4c 41 49 50 55 08 00 45 00 00 48 00 00 40 00 40 11 a5 4e c0 a80a 01 c0 a8  0a05 0c 00 00 a200 34 ff e0 30 2a 02 01 00 04 06 70 75 62 6c 69 63a4 1d 06 0a 2b 06 01 04 01 bf 08 03 02 0a 40 04 c0 a8 0a01 02 01 00 02 01 00 43 01 0e 30 00

 

目的MAC:00 23 5a 9e 58 b9

源MAC:00 4c 41 49 50 55

協議類型:08 00 ,為IP數據報

IP頭:45 00 00 48 00 00 40 00 40 11 a5 4e c0 a80a 01 c0 a80a 05 0c

UDP頭:0c 00 00 a2 00 34 ff e0

其余部分都為SNMP報文,接下來我們對照前面的報文結構體來逐個分析一下。

n  30 表示SNMP消息是ASN.1的SEQUENCE類型;

n  2a 表示該SNMP報文的總長度是42(0x2a)個字節,該字段所表示的報文長度起始於它后面的第一個字節直到報文結束;

n  02 01 00 表示版本號,可見其確實為BER編碼方式。02表示該字段是INTEGER類型;01表示該字段占1個字節;00表示版本號,該值為“版本號-1”;

n  04 06 70 75 62 6c 69 63 表示團體名,04表示該字段為OCTETSTRING類型;06表示該字段占6個字節;70 75 62 6c 69 63表示團體名的ANSII碼的十六進制形式,這里是“public”;

n  a4 1d 其中a4中的“4”表示這是一個trap報文,a4又叫報文的標簽標記;1d表示后面還有29(0x1d)個字節的數據;

n  06 0a 2b 06 01 04 01 bf 08 03 02 0a 企業OID標識。06表示該字段是個對象標識符,OBJECTIDENTIFIER;0a表示該字段占10(0x0a)個字節;關於SNMP的OID的編碼方式有些奇特:例如1.3.6.1.2…. 取前兩個數字分別記為x和y。編碼時40*x+y,這里x=1,y=3,因此結果為40*1+3=43,即表示十六進制的2b。因此,這里的企業OID編碼即為1.3.6.1.4.1.8072.3.2.10;

n  40 04 c0 a80a 01 同樣40表示該字段為OCTET STRING 類型;04表示IP地址占4個字節;IP地址為192.168.10.1;

n  02 01 00 其中00表示trap類型為coldStart;

n  02 01 00 其中00表示我們指定的trap即specific-trap也為coldStart類型;

n  43 01 0e 43表示為TimeTicks類型;01表示該字段占1個字節;0e即十進制的14表示時間標簽為0.14秒,這里時間計數器以0.01秒遞增;

n  30 00 30表示“鍵-值”值對的編碼類型為SEQUENCE;00表示該字段占0個字節,即沒有該字段。

 

SNMPv2報文 SNMPv2的Trap報文格式如圖8所示:

 

 

同樣的,這里除了trap類型和報文長度是標准網絡字節序之外,其余協議字段也均為BER編碼方式。可以看到v2版的trap報文正在向統一的報文格式發展,已經非常類似普通的SNMP請求、響應報文了。

SNMPv2原始報文內容:

00 23 5a 9e 58b9 00 4c 41 49 50 55 08 00 45 00 00 7b 00 00 40 00 40 11 a5 1b c0 a8 0a01 c0 a8 0a05 0c 01 00 a2 0067 04 bb 305d 02 01 01 04 06 70 75 62 6c 69 63a7 50 0204 1773 2c fb 02 01 00 02 01 00 30 42 30 0d 06 08 2b 06 01 02 01 01 03 00 43 01 0e 30 17 060a 2b 06 01 06 03 01 01 04 01 00 06 09 2b 06 01 0603 01 01 05 01 3018 060a2b 06 01 06 03 01 01 04 0300 06 0a2b 06 01 04 01 bf 08 03 02 0a

 

目的MAC:00 23 5a 9e 58 b9

源MAC:00 4c 41 49 50 55

協議類型:08 00,IP報文

IP頭:45 00 00 7b 00 00 40 00 40 11 a5 1b c0 a80a 01 c0 a80a 05

UDP頭:0c 01 00 a2 00 67 04 bb

余下部分全為SNMP報文內容,這里我們做一下簡單的約定:

xx 標注類型;xx 標注長度;xx 標注真正的數據。

這樣一來上面這串原始數據就好分析多了J

n  30 5d 整個SNMP報文的編碼方式為30,即SEQUENCE類型,報文長度93(0x5d)字節;

n  02 01 01 版本號01即v2版本;

n  04 06 70 75 62 6c 69 63 團體名70 75 62 6c69 63  即英文的“public”;

n  a7 50 a7表示trap類型為7,即廠商自定義trap;50表示PDU區段占80(0x50)字節;

n  02 04 17 73 2c fb 請求ID為17 73 2c fb 十進制的393424123;

n  02 01 00 錯誤狀態0;

n  02 01 00 錯誤索引0;

n  30 42 “變量名-值”對編碼類型30 即SEQUENCE類型;“變量名-值”所占總字節0x42,即66字節;

n  30 0d 06 08 2b 06 01 02 01 01 03 00 43 01 0e 第一個“名-值”對區段編碼方式30 即SEQUENCE類型;第一個“名-值”對總長度0x0d,13字節;第一個變量名的編碼類型0x06,時間標簽;第一個變量名占0x08個字節;第一個變量名2b 06 01 02 01 01 03 00,為1.3.6.1.2.1.1.3.0;第一個變量值為0x0e,即14;

n  30 17 06 0a2b 06 01 06 03 01 01 04 0100 06 09 2b 06 01 06 03 01 01 05 01 第二個“名-值”對;變量名1.3.6.1.6.3.1.1.4.1.0;變量值1.3.6.1.6.3.1.1.5.1;

n  30 18 06 0a2b 06 01 06 03 01 01 04 0300 06 0a2b 06 01 04 01 bf 08 03 02 0a 第三個“名-值”對;變量名1.3.6.1.6.3.1.1.4.3.0;變量值1.3.6.1.4.1.8072.3.2.10;

 

 

 

通過

"github.com/google/gopacket"獲取UDP包,
將包交由
"github.com/gosnmp/gosnmp"
處理拆包。

 

snmpdata := v.Params.UnmarshalTrap(UDP.Payload, false)

github.com/gosnmp/gosnmp@v1.33.0/trap.go:363

// UnmarshalTrap unpacks the SNMP Trap.
//
// NOTE: the trap code is currently unreliable when working with snmpv3 - pull requests welcome
func (x *GoSNMP) UnmarshalTrap(trap []byte, useResponseSecurityParameters bool) (result *SnmpPacket) {
result = new(SnmpPacket)

if x.SecurityParameters != nil {
err := x.SecurityParameters.initSecurityKeys()
if err != nil {
return nil
}
result.SecurityParameters = x.SecurityParameters.Copy()
}

cursor, err := x.unmarshalHeader(trap, result)
if err != nil {
x.Logger.Printf("UnmarshalTrap: %s\n", err)
return nil
}

if result.Version == Version3 {
if result.SecurityModel == UserSecurityModel {
err = x.testAuthentication(trap, result, useResponseSecurityParameters)
if err != nil {
x.Logger.Printf("UnmarshalTrap v3 auth: %s\n", err)
return nil
}
}

trap, cursor, err = x.decryptPacket(trap, cursor, result)
if err != nil {
x.Logger.Printf("UnmarshalTrap v3 decrypt: %s\n", err)
return nil
}
}
err = x.unmarshalPayload(trap, cursor, result)
if err != nil {
x.Logger.Printf("UnmarshalTrap: %s\n", err)
return nil
}
return result
}

github.com/gosnmp/gosnmp@v1.33.0/marshal.go:923

// -- Unmarshalling Logic ------------------------------------------------------

func (x *GoSNMP) unmarshalHeader(packet []byte, response *SnmpPacket) (int, error) {
if len(packet) < 2 {
return 0, fmt.Errorf("cannot unmarshal empty packet")
}
if response == nil {
return 0, fmt.Errorf("cannot unmarshal response into nil packet reference")
}

response.Variables = make([]SnmpPDU, 0, 5)

// Start parsing the packet
cursor := 0

// First bytes should be 0x30
if PDUType(packet[0]) != Sequence {
return 0, fmt.Errorf("invalid packet header")
}

length, cursor, err := parseLength(packet)
if err != nil {
return 0, err
}
if len(packet) != length {
return 0, fmt.Errorf("error verifying packet sanity: Got %d Expected: %d", len(packet), length)
}
x.Logger.Printf("Packet sanity verified, we got all the bytes (%d)", length)

// Parse SNMP Version
rawVersion, count, err := parseRawField(x.Logger, packet[cursor:], "version")
if err != nil {
return 0, fmt.Errorf("error parsing SNMP packet version: %w", err)
}

cursor += count
if cursor > len(packet) {
return 0, fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
}

if version, ok := rawVersion.(int); ok {
response.Version = SnmpVersion(version)
x.Logger.Printf("Parsed version %d", version)
}

if response.Version == Version3 {
oldcursor := cursor
cursor, err = x.unmarshalV3Header(packet, cursor, response)
if err != nil {
return 0, err
}
x.Logger.Printf("UnmarshalV3Header done. [with SecurityParameters]. Header Size %d. Last 4 Bytes=[%v]", cursor-oldcursor, packet[cursor-4:cursor])
} else {
// Parse community
rawCommunity, count, err := parseRawField(x.Logger, packet[cursor:], "community")
if err != nil {
return 0, fmt.Errorf("error parsing community string: %w", err)
}
cursor += count
if cursor > len(packet) {
return 0, fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
}

if community, ok := rawCommunity.(string); ok {
response.Community = community
x.Logger.Printf("Parsed community %s", community)
}
}
return cursor, nil
}
func (x *GoSNMP) unmarshalPayload(packet []byte, cursor int, response *SnmpPacket) error {
if len(packet) == 0 {
return errors.New("cannot unmarshal nil or empty payload packet")
}
if cursor > len(packet) {
return fmt.Errorf("cannot unmarshal payload, packet length %d cursor %d", len(packet), cursor)
}
if response == nil {
return errors.New("cannot unmarshal payload response into nil packet reference")
}

// Parse SNMP packet type
requestType := PDUType(packet[cursor])
x.Logger.Printf("UnmarshalPayload Meet PDUType %#x. Offset %v", requestType, cursor)
switch requestType {
// known, supported types
case GetResponse, GetNextRequest, GetBulkRequest, Report, SNMPv2Trap, GetRequest, SetRequest, InformRequest:
response.PDUType = requestType
if err := x.unmarshalResponse(packet[cursor:], response); err != nil {
return fmt.Errorf("error in unmarshalResponse: %w", err)
}
// If it's an InformRequest, mark the trap.
response.IsInform = (requestType == InformRequest)
case Trap:
response.PDUType = requestType
if err := x.unmarshalTrapV1(packet[cursor:], response); err != nil {
return fmt.Errorf("error in unmarshalTrapV1: %w", err)
}
default:
x.Logger.Printf("UnmarshalPayload Meet Unknown PDUType %#x. Offset %v", requestType, cursor)
return fmt.Errorf("unknown PDUType %#x", requestType)
}
return nil
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM