多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > SNMP++ 04-SNMP中OBJECT IDENTIFIER的BER編碼與解碼及一些思考

SNMP++ 04-SNMP中OBJECT IDENTIFIER的BER編碼與解碼及一些思考

來源:程序員人生   發布時間:2016-06-13 11:14:25 閱讀次數:2813次

瀏覽完本文你可以學到:

(1)SNMP 中 OBJECT IDENTIFIER 的 BER 編碼與解碼代碼實現。

(2)在學習 OBJECT IDENTIFIER 編解碼進程中的1些思考(思考過后,曉得當觸及對無符號數組進行傳輸編碼時,可以給出1個較佳的方案)。

(3)snmp++⑶.3.7 版本中函數 asn_parse_objid 存在的 bug。


1、理論知識

1、Tag

OBJECT IDENTIFIER 對應的 Tag 為 0x06,占用1個8位組。

2、Length

Length有3種情勢:定長短格式、定長長格式和變長格式。(SNMP 的所有內置類型的 Length 段都采取定長格式)

定長短格式:采取定長方式,當長度不大于127個8位組時,Length 只在1個8位組中編碼。此時,bit0~bit6 表示實際長度,最高位 bit7 為0(用于辨別其他兩種格式)。

定長長格式:采取定長方式,當長度大于127個8位組時,Length 在多個8位組中編碼,此時第1個8位組低7位(bit0~bit6)表示的是 Length 所占的長度,第1個8位組的最高位 bit7 為1,第1個8位組的低7位不能全為 0(用于辨別其他兩種格式)。

變長格式:采取變長方式,Length 所在8位組固定編碼為 0x80,但在 Value 編碼結束后以兩個 0x00 結尾。這類方式使得可以在編碼沒有完全結束的情況下,可以先發送部份消息給對方。

3、Value

所有的子標識符(OID 點分10進制中的1位數值)連續編碼。(筆者注:內存大小對應的 OID 為 .1.3.6.1.2.1.25.2.2.0,其子標識符自頂到下順次為 1,3,6,1,2,1,25,2,2,0。)

每一個子標識符由1個或多個字節組成。子標識符是由1個字節還是多個字節表示的辨別規則是:每一個字節最高有效位 bit7 表征了該子標識符是不是為編碼后的最后1個字節。bit7 為 0 表示這個字節是 OID 中最后1個編碼字節;bit7 為 1 時表示該字節不是該子標識符最后1個編碼(OID沒有負值)。正因如此,對數值大于 127 的子標識符必定要使用多于1個字節的編碼。如對數值為 128(0x80 = 1000 0000B)的子標識符,就應當使用兩個字節編碼:1000 0001 0000 0000,值為 81 00。

子標識符編碼應盡量地使用字節(也就少1個字節),規定 OID 的第1個子標識符和第2個子標識符經過運算組合后編碼為1個字節。該運算法則為:(X * 40)+ Y = Z。

其中 X 表示第1個子標識符,Y 為第2個子標識符。X 的取值為(0,1,2)。另外之所以使用1個“magic number” 為 40,是由于首個子標識符為 0 或 1 的 OID 的第2個子標識符最大的是 39(這類不見得有多優雅的解決方案也確切減少了1個字節的編碼等)。這就使得具有 N 個子標識符的 OID,第 i 個(2 <= i <= N  - 1)編碼值對應 OID 中的第(i + 1)個子標識符。正是由于上述方程的束縛條件,使得方程的結果也是唯1的,即當 Z 為表5⑶總第1列所列出的值時,就能夠推導出前兩個子 OID 的值。

表5⑶ OID TLV示例(16 進制)

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

2、思考——設計1個包格式,滿足“發送端將1個無符號 int 數組中的內容發送到接收端,接收端接收并打印”?

最簡單地方案多是: 其他信息 + 整數1 + 整數2 + . . . + 整數 i + . . . + 整數 n。(其中,“其他信息”在這里的討論中其實不觸及。在這類方案中每一個整數 i 占 4 個字節)。

現在增加需求:盡量地使用字節

思路之1:對每一個無符號整數進行緊縮,即對每一個無符號整數盡量地只傳輸其有效位。比如,無符號整數 1 (0x00000001)在原來的傳輸中要占 4 個字節,現在通過1種規則使得只傳輸1個字節 0x01。

這類思路是可以減少傳輸字節的,但同時會帶來“不同無符號整數的有效位可能占用不同的字節數”的問題。此時,我們不能不提供額外的信息對無符號整型數組進行劃分。

額外的信息是指甚么?

方案1(提供額外信息的1種嘗試方式,暫不斟酌是不是可行)為:在每一個無符號整數(只含有效位)的后面插入1個特殊標識(最少占1個字節 ),以辨別不同的整數。同時,我們需要對與該特殊標知趣同的的無符號整數進行“字符填充”類似的工作,以保證透明傳輸(我們先不斟酌該工作的繁瑣度)。

假設方案1可行,那末額外信息最少要使用1個字節,這個字節指的就是特殊標識。那末,是不是存在更佳方案呢?

是的,看看 SNMP 中是如何對 OID 進行編解碼的(見1、理論知識)。不要驚訝,你完全可以把 OID 看做是1個1維無符號整型數組:每一個子標識符都不會是負數,相鄰子標識符就像數組中的相鄰元素。

SNMP 中對 OID 的編碼規則可以使得:額外信息最多使用1個字節。為何呢?見表 2⑴ 。

表 2⑴

無符號整數 x 采取 OID 編碼規則后占用的8位組個數 額外信息占用的8位組個數
0 <= x < 27 1 0
x = 27 2 1
2< x < 214 2 0
x = 214 3 1
. . . . . . . . .


3、snmp++⑶.3.7 版本中函數 asn_parse_objid 存在的 bug
unsigned char *asn_parse_objid(unsigned char *data,
                               int *datalength,
                               unsigned char *type,
                               oid *objid,
                               int *objidlength);
bug 描寫:函數 asn_parse_objid 實現中未對 *objidlength 表征的 objid 緩沖大小是不是足夠進行判斷。當 *objidlength 為0 時,直接取用 objid[0],會產生數組訪問越界;當 *objidlength 為1 時,直接取用 objid[1],也會產生數組訪問越界。

4、代碼實現
/************************************************************************/ /* asn1.h */ /************************************************************************/ #pragma once typedef unsigned char u_char; typedef unsigned long u_long; typedef u_long oid; #define MAX_OID_LEN 128 #define MAX_SUBID 0xFFFFFFFF static u_char* _asn_build_header(u_char *data, size_t *datalength, u_char type, size_t length); static const u_char* _asn_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 *datalength, size_t *length); u_char* _asn_build_objid(u_char *data, size_t *datalength, u_char type, oid *objid, const size_t objidlength); const u_char* _asn_parse_objid(const u_char *data, size_t *datalength, u_char *type, oid *objid, size_t *objidlength);

/************************************************************************/ /* asn1.cpp */ /************************************************************************/ #include "stdafx.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); } /* 支持的最大長度為65535字節 */ u_char* _asn_build_length(u_char *data, size_t *datalength, size_t length) { if (nullptr == data || nullptr == datalength) return nullptr; const u_char *initdatap = data; if (length < 0x80) { /* 定長短格式 */ if (*datalength < 1) return nullptr; *data++ = (u_char)length; } else if (length <= 0xFF) { /* 定長長格式,長度占用1個8位組 */ if (*datalength < 2) return nullptr; *data++ = (u_char)0x81; /* Length 段的第1個8位組為 10000001,對應的106進制即為 0x81 */ *data++ = (u_char)length; /* 將 length 的低 bit0~bit7 賦值給 *data,并使 data 指向 data 的下1個8位組 */ } else if (length <= 0xFFFF) { /* 定長長格式,長度占用兩個8位組 */ if (*datalength < 3) return nullptr; *data++ = (u_char)0x82; /* Length 段的第1個8位組為 10000010,對應的106進制即為 0x82 */ *data++ = (u_char)(length >> 8); /* 將 length 的低 bit8~bit15 賦值給 *data,并使 data 指向 data 的下1個8位組 */ *data++ = (u_char)length; /* 將 length 的低 bit0~bit7 賦值給 *data,并使 data 指向 data 的下1個8位組 */ } else { /* 長度太長,不支持 */ return nullptr; } *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) { /* 定長短格式 */ *length = lengthbyte; } else if (lengthbyte == 0x80) { /* 0x80 為變長格式,不支持 */ return nullptr; } else { /* 定長長格式 */ size_t bytes = (size_t)(lengthbyte - 0x80); /* 計算 Length 段占用的8位組個數 */ if (bytes > sizeof(*length)) return nullptr; /* Length 段太長 */ *length = 0; /* 消除 *length 的初值可能對 *length 終究結果帶來的影響 */ 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) return nullptr; /* bad first sub_identifier */ else if (objidlength == 1) first_objid_val = objid[0] * 40; else { /* second sub_identifier <= 39 when first sub_identifier is 0 or 1 */ if (objid[1] >= 40 && objid[0] < 2) return nullptr; /* bad second sub_identifier */ first_objid_val = objid[0] * 40 + objid[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; else return 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_length) 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 >> 14 | 0x80); *data++ = (u_char)((subid >> 7 & 0x07f) | 0x80); *data++ = (u_char)(subid & 0x07f); break; case 4: *data++ = (u_char)(subid >> 21 | 0x80); *data++ = (u_char)((subid >> 14 & 0x07f) | 0x80); *data++ = (u_char)((subid >> 7 & 0x07f) | 0x80); *data++ = (u_char)(subid & 0x07f); break; case 5: *data++ = (u_char)(subid >> 28 | 0x80); *data++ = (u_char)((subid >> 21 & 0x07f) | 0x80); *data++ = (u_char)((subid >> 14 & 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 encodings of the form 06 00 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 & 0x07f); --asn_length; } while ((*data++ & 0x80) && asn_length > 0); if (subid > MAX_SUBID) return nullptr; /* sub_identifier too long */ if (i >= *objidlength) return nullptr; /* objid overflow */ *oidp++ = (oid)subid; } if (*objidlength < 2) return nullptr; /* objid overflow */ if (objid[1] < 40) objid[0] = 0; else if (objid[1] < 80) objid[0] = 1, objid[1] -= 40; else objid[0] = 2, objid[1] -= 80; *objidlength = (size_t)(oidp - objid); *datalength -= (data - initdatap); return data; }

// snmp_get.cpp : 定義控制臺利用程序的入口點。 // #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 (size_t i = 0; i < datalength; ++i) { printf("0x%.2X ", data[i]); } printf("\n\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,110,9,10012340}/*{1, 3, 6, 1, 2, 1, 25, 2, 2, 0}*/; if (_asn_build_objid(buf, &validlen, 0x06, oid, sizeof(oid) / sizeof(*oid)) == nullptr) return ⑴; 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 ⑴; } for (size_t i = 0; i < oidlength; ++i) { cout << oid2[i] << " "; } cout << endl; cout << "oidlength:" << oidlength << endl; return 0; }

注:“1、理論知識 3. Value”中的內容引自《深入理解Net-Snmp》(張春強著)。


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲男人的天堂久久无 | 国产精品久久久久久五月尺 | 亚洲精品第一第二区 | 免费在线一区二区三区 | 亚洲国产欧美日韩 | 国产一成人精品福利网站 | 国产亚洲视频在线观看 | 亚洲另类视频 | 日本不卡视频在线 | 中文字幕第9页 | 欧美性妇| 国产精品视_精品国产免费 国产精品视频1区 | 国产一区二区三区免费看 | 最近的中文字幕视频完整 | 国产a毛片| freexx性| 亚洲人成网站在线观看播放 | jizzjizzjizz18中国 | 欧美69xx性欧美 | 亚洲欧美一级视频 | 亚洲 欧美 手机 在线观看 | 欧美亚洲偷图色综合91 | 亚洲最大在线视频 | 欧美巨大xxxx做受孕妇视频 | 欧美日韩欧美 | 和同事激情中文版在线观看 | 亚洲无线乱码高清在线观看一区 | 久久久久无码国产精品一区 | 一级做a爰片性色毛片新版的 | 精品国产亚洲人成在线 | 亚洲福利网址 | 国产精品久久久久久 | 全黄大全大色全免费大片 | 亚洲精品在线观看视频 | 久久这里都是精品 | 国产精品久久久久久搜索 | 亚洲国产人久久久成人精品网站 | 在线精品自拍亚洲第一区 | 欧美精品在线免费观看 | 亚洲精品久久久久久久无 | 久久精品国产网红主播图片 |