BER encoding and decoding of object identifier in snmp++ 04-snmp and some considerations

Source: Internet
Author: User
Tags snmp

After reading this article you can learn:

(1) The BER encoding and decoding code of the OBJECT IDENTIFIER in SNMP is implemented.

(2) Some thinking in learning the process of OBJECT IDENTIFIER codec (after thinking about it, it is possible to give a better solution when it involves the transfer encoding of an unsigned array).

(3) A bug exists in the snmp++-3.3.7 version of the function Asn_parse_objid.


First, theoretical knowledge

1. Tag

The OBJECT IDENTIFIER corresponds to a Tag of 0x06, occupying a eight-bit group.

2. Length

Length has three forms: fixed-length format, fixed-length format, and variable-length format. (The length segment for all built-in types of SNMP is in fixed-length format)

Fixed length format: In a fixed length mode, when the length is not greater than 127 eight-bit groups, length only in a eight-bit group encoded. At this point, bit0~bit6 represents the actual length, and the highest bit bit7 is 0 (used to differentiate between the other two formats).

Fixed length long format: In a fixed-length way, when the length is greater than 127 eight-bit groups, length is encoded in multiple eight-bit groups, at this time the first eight-bit group low seven bits (BIT0~BIT6) represents the length, the first eight-bit group of the highest bit bit7 is 1, The low seven bits of the first eight-bit group cannot be all 0 (used to differentiate between the other two formats).

Variable-length format: The variable-length method, length where the eight-bit group is fixed encoded as 0x80, but ends with two 0x00 after the Value encoding ends. This way, you can send a partial message to each other before the code is completely closed.

3. Value

All sub-identifiers (OID points in decimal, one numeric value) are continuously encoded. (I note: the memory size corresponding to the OID is. 1.3.6.1.2.1.25.2.2.0, and its sub-identifiers are 1,3,6,1,2,1,25,2,2,0 from top to bottom.) )

Each child identifier consists of one or more bytes. The rule that a child identifier is represented by a byte or multiple bytes is that the most significant bit of each byte bit7 indicates whether the child identifier is the last byte after the encoding. A bit7 of 0 means that the byte is the last encoded byte in the OID, and a bit7 of 1 indicates that the byte is not the last encoding of the child identifier (theOID has no negative value ). Because of this, it is necessary to use more than one byte of encoding for a child identifier with a value greater than 127. For sub-identifiers with a value of (0x80 = 0000B), you should use two-byte encoding: 1000 0001 0000 0000 with a value of 81 00.

The child identifier encoding should use as much of the byte (and one less byte) as possible, stipulating that the first child identifier of the OID and the second child identifier are encoded into one byte after the operation is combined. The algorithm is: (X * +) + Y = Z.

Where X represents the first child identifier and Y is the second child identifier. The value of X is (0,1,2). Another reason to use a "magic number" is 40, because the first sub-identifier is 0 or 1 of the second child identifier of the largest is 39 (this is not a more elegant solution does reduce the encoding of one byte, etc.). This causes the OID with N child identifiers, and the first I (2 <= i <= N-1) encoded value to correspond to the (i + 1) sub-identifier in the OID. It is precisely because of the constraints of the above equation that the result of the equation is unique, that is, when Z is the value listed in the Total first column of table 5-3, it is possible to push the value of the first two sub-OIDs.

Table 5-3 OID TLV Example (16 binary)

Z X Y
0 <= Z <= 39 0 Z
<= Z <= 79 1 Z-40
Z >= 80 2 Z-80

Second, think--design a package format that satisfies the sending end to send the contents of an unsigned int array to the receiving end, receiving and printing "?

The simplest scenario might be: additional information + integer 1 + integer 2 + ... + integer i + ... + integer n. (where "other information" is not covered in the discussion here.) In this scenario, each integer I occupies 4 bytes).

Now Add demand: Use bytes as much as you can .

One way of thinking: to compress each unsigned integer, that is, to transmit as much of its significant bits as possible to each unsigned integer. For example, unsigned integer 1 (0x00000001) takes 4 bytes in the original transmission, and now passes a rule that transmits only one byte of 0x01.

This idea is to reduce the transmission of bytes, but at the same time will bring the "valid bits of different unsigned integers may occupy a different number of bytes" problem. At this point, we have to provide additional information to partition an array of unsigned integers.

What does the additional information mean?

Scenario 1 (an attempt to provide additional information that is not considered feasible) is to insert a special identifier (at least one byte) after each unsigned integer (with a valid bit) to differentiate between different integers. At the same time, we need to do a "character fill" operation similar to an unsigned integer that is the same as that particular identity, to ensure transparent transmission (we don't consider the complexity of the work first).

If scenario 1 is feasible, then the additional information must use at least one byte, which refers to the special identifier. So, is there a better solution?

Yes, look at how the OID is encoded in SNMP (see First, theoretical knowledge). Don't be surprised, you can think of OID as a one-dimensional unsigned integer array: Each child identifier is not a negative number, and an adjacent sub-identifier is like an adjacent element in an array.

The encoding rules for OIDs in SNMP make it possible to use up to one byte for additional information. Why is it? See table 2-1.

Table 2-1

unsigned integer x Number of eight-bit groups occupied after using OID encoding rules Number of eight-bit groups occupied by additional information
0 <= x < 27 1 0
x = 27 2 1
< x < 214 2 0
x = 214 3 1
. . . . . . . . .


Third, the snmp++-3.3.7 version of the function Asn_parse_objid existing bug
unsigned char *asn_parse_objid (unsigned char *data,
int *datalength,
unsigned char *type,
OID *objid,
int *objidlength);
Bug Description: The function Asn_parse_objid implementation does not determine whether the ObjID buffer size is sufficient for *objidlength characterization. When *objidlength is 0 o'clock, a direct fetch of objid[0] will result in array access, and when *objidlength is 1 o'clock, direct fetch objid[1] will also result in an array access out of bounds.
Iv. Implementation of the Code
/************************************************************************//* Asn1.h *//************************************************************************/#pragma oncetype def unsigned char u_char;typedef unsigned long u_long;typedef u_long oid; #define Max_oid_len 128#define max_subid 0xFFFF Ffffstatic u_char* _asn_build_header (U_char *data, size_t *datalength, U_char type, size_t length); Static const u_char* _a Sn_parse_header (const U_char *data, size_t *datalength, U_char *type, size_t *length); static u_char* _asn_build_length (U _char *data, size_t *datalength, size_t length), Static const u_char* _asn_parse_length (const U_char *data, size_t *datalen Gth, size_t *length); u_char* _asn_build_objid (U_char *data, size_t *datalength, U_char type, oid *objid, const size_t Obji dlength); const u_char* _asn_parse_objid (const U_char *data, size_t *datalength, U_char *type, oid *objid, size_t *objidlen GTH);

/************************************************************************//* Asn1.cpp *//************************************************************************/#include "Stdaf X.h "#include" Asn1.h "u_char* _asn_build_header (U_char *data, size_t *datalength, U_char type, size_t length) {if (nullptr = = Data | | nullptr = = datalength) return nullptr;if (*datalength < 1) return nullptr;*data++ = type;--(*datalength); return _asn_ Build_length (data, datalength, length);} Const u_char* _asn_parse_header (const U_char *data, size_t *datalength, U_char *type, size_t *length) {if (nullptr = = Data || nullptr = = Datalength | | nullptr = = Type | | nullptr = = length) return nullptr;if (*datalength < 1) return Nullptr;*type = *data++;--(*datalength); return _asn_parse _length (data, datalength, length);} /* Maximum length supported is 65535 bytes */u_char* _asn_build_length (U_char *data, size_t *datalength, size_t length) {if (nullptr = = Data | | nul Lptr = = datalength) rEturn nullptr;const U_char *initdatap = data;if (Length < 0x80) {/* Fixed length format */if (*datalength < 1) return Nullptr;*da ta++ = (U_char) length;}       else if (length <= 0xFF) {/* Fixed long long format, length occupies a eight-bit group */if (*datalength < 2) return nullptr;*data++ = (U_char) 0x81;     /* The first eight-bit group of the length segment is 10000001, and the corresponding hexadecimal is 0x81 */*data++ = (u_char) length; /* Assign a low bit0~bit7 of length to *data, and make data point to the next eight-bit group of data */}else if (length <= 0xFFFF) {/* Fixed long format, two eight-bit group */if (*d          Atalength < 3) return nullptr;*data++ = (U_char) 0x82; /* The first eight-bit group of the Length segment is 10000010, and the corresponding hexadecimal is 0x82 */*data++ = (U_char) (length >> 8);        /* Assigns the low bit8~bit15 of length to *data and causes data to point to the next eight-bit group of data */*data++ = (u_char) length; /* Assign the low bit0~bit7 of length to *data and make data point to the next eight-bit group of data */}else{/* length is too long, */return nullptr is not supported;} *datalength-= (DATA-INITDATAP); return data;} Const u_char* _asn_parse_length (const U_char *data, size_t *datalength, size_t *length) {if (nullptr = = Data | | nullptr = datalength | | nullptr == length) return nullptr;const U_char *initdatap = Data;u_char lengthbyte = *data++;if (Lengthbyte < 0x80) {/* Fixed length format * /*length = Lengthbyte;} else if (Lengthbyte = = 0x80) {/* 0x80 is a variable-length format, */return nullptr is not supported;}   else{/* Fixed length long format */size_t bytes = (size_t) (lengthbyte-0x80);   /* Calculates the number of eight-bit groups occupied by the length segment */if (bytes > sizeof (*length)) return nullptr;   /* length segment too long */*length = 0; /* Eliminate the *length initial value may affect the *length end result */while (bytes--) {*length <<= 8;*length |= (*data++);}} *datalength-= (DATA-INITDATAP); return data;} u_char* _asn_build_objid (U_char *data, size_t *datalength, U_char type, oid *objid, const size_t objidlength) {if (nullptr = = Data | | nullptr = = Datalength | | nullptr = = ObjID) return Nullptr;u_long first_objid_val;if (objidlength = 0) First_objid_val = 0;else if (objid[0] > 2) r Eturn nullptr;/* Bad First sub_identifier */else if (objidlength = = 1) first_objid_val = objid[0] * 40;else{/* second sub_i Dentifier <= If first sub_identifier is 0 or 1 */if (objid[1] >= && objid[0] < 2) return nullptr;/* bad second sub_identifier */first_objid_val = objid[0] * + Obji D[1];} U_char Objid_size[max_oid_len];u_long subid = first_objid_val;size_t asn_length = 0;if (objidlength > sizeof (objid_ Size)/sizeof (*objid_size)) return nullptr;for (size_t i = 1;;) {if (SubID < (u_long) 0x80) objid_size[i] = 1, asn_length + = 1;else if (SubID < (u_long) 0x4000) objid_size[i] = 2, Asn_ Length + = 2;else if (SubID < (u_long) 0x200000) objid_size[i] = 3, asn_length + = 3;else if (SubID < (u_long) 0x10000000 ) Objid_size[i] = 4, asn_length + = 4;else if (subid <= (u_long) 0xffffffff) Objid_size[i] = 5, asn_length + = 5;elsereturn nullptr;/* Sub_identifier too long */if (++i >= objidlength) break;subid = Objid[i];} if (data = _asn_build_header (data, datalength, type, asn_length)) = = nullptr) return nullptr;if (*datalength < Asn_leng TH) return nullptr;oid *op = ObjID + 2;for (size_t i = 1, subid = First_objid_val; i < objidlength; ++i) {if (I! = 1) subid = *op++;switch (Objid_size[i]) {Case 1:*data++ = (u_char) subid;break;case 2:*data++ = (U_char) (SubID >> 7 | 0x80) *data++ = (U_char) (SubID & 0x07f); Break;case 3:*data++ = (U_char) (SubID >> 0x80); *data++ = (U_char) (( SubID >> 7 & 0x07f) | 0x80) *data++ = (U_char) (SubID & 0x07f); Break;case 4:*data++ = (U_char) (SubID >> 0x80); *data++ = (U_char) (( SubID >> & 0x07f) |  0x80) *data++ = (U_char) ((subid >> 7 & 0x07f) | 0x80); *data++ = (U_char) (SubID & 0x07f); Break;case 5:*data++  = (U_char) (SubID >> | 0x80); *data++ = (U_char) ((subid >> 0x07f) | 0x80); *data++ = (U_char) ((subid >> & 0x07f) |  0x80) *data++ = (U_char) ((subid >> 7 & 0x07f) | 0x80); *data++ = (U_char) (SubID & 0x07f); Break;default:return nullptr;}} *datalength-= Asn_length;return data;} Const u_char* _asn_parse_objid (const U_char *data, size_t *datalength, U_char *type, oid *objid, size_t *objidlength) {if ( NulLPTR = = Data | | nullptr = = Datalength | | nullptr = = Type | | nullptr = = ObjID | | nullptr = = objidlength) return nullptr;const U_char *initdatap = data;oid *OIDP = ObjID + 1;size_t asn_length;  if (data = _asn_parse_header (data, datalength, type, &asn_length)) = = nullptr) return nullptr;if (*type! = 0x06) return nullptr;/* wrong Type. Not an OID */if (Asn_length > *datalength) return nullptr;/* data overflow *//* Handle Invalid object identifier Encodin GS of the form xx robustly */if (asn_length = = 0) {if (*objidlength < 2) return nullptr;objid[0] = objid[1] = 0;} U_long subid;for (size_t i = 1; asn_length > 0; ++i) {subid = 0;do {subid <<= 7;subid |= (u_long) (*data & 0x07 f);--asn_length;} while ((*data++ & 0x80) && asn_length > 0), if (SubID > Max_subid) return nullptr;/* Sub_identifier too lo Ng */if (i >= *objidlength) return nullptr;/* objid overflow */*oidp++ = (OID) subid;} if (*objidlength < 2) return nullptr;/* ObjID overflow */if (objid[1] < Objid[0] = 0;else if (objid[1] <) objid[0] = 1, objid[1]-= 40;elseobjid[0] = 2, objid[1]-= 80;*objidlength = (s ize_t) (Oidp-objid); *datalength-= (DATA-INITDATAP); return data;}

Snmp_get.cpp: Defines the entry point of the console application. #include "stdafx.h" #include <stdio.h> #include <iostream>using namespace std; #include <string.h># Include "Asn1.h" void print (const U_char *data, size_t datalength) {if (nullptr = = Data | | datalength < 1) return;for (siz e_t i = 0; i < datalength; ++i) {printf ("0x%.2x", Data[i]);} printf ("\ n");} int _tmain (int argc, _tchar* argv[]) {U_char buf[100];size_t Validlen = sizeof (BUF); U_long oid[] = {1,3,6,1,4,1,1048576,11 0,9,10012340}/*{1, 3, 6, 1, 2, 1, A, 2, 2, 0}*/;if (_asn_build_objid (buf, &validlen, 0x06, OID, sizeof (OID)/sizeof ( *oid) = = nullptr) return-1;print (buf, sizeof (BUF)-validlen); U_long oid2[20];size_t oidlength = sizeof (OID2)/sizeof (* OID2); U_char type;validlen = sizeof (BUF)-validlen;if (_asn_parse_objid (buf, &validlen, &type, Oid2, & oidlength) = = nullptr) {cout << "_asn_parse_objid error" << endl;return-1;} for (size_t i = 0; i < oidlength; ++i) {cout << oid2[i] << "";} cout &LT;&LT Endl;cout << "oidlength:" << oidlength << endl;return 0;}

Note: "First, theoretical knowledge 3." The contents of "Value" are quoted in the "deep understanding of Net-snmp" (Zhangchunqiang).


BER encoding and decoding of object identifier in snmp++ 04-snmp and some considerations

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.