SNMP++ 03-SNMP中字符串类型的BER编码与解码
2016-05-26 21:08
351 查看
阅读完本文你可以学到:
(1)SNMP 中字符串型类型(包括基本类型 OCTER STRING 及其引申类型,如 IpAddress 等)的 BER 编码与解码。
一、理论知识
1、Tag
OCTER STRING 对应的 Tag 为 0x04,IpAddress 对应的 Tag 为 0x40。字符串类型的 Tag 占用一个八位组。
2、Length
Length有三种形式:定长短格式、定长长格式和变长格式。(SNMP 的所有内置类型的 Length 段都采用定长格式)
定长短格式:采用定长方式,当长度不大于127个八位组时,Length 只在一个八位组中编码。此时,bit0~bit6 表示实际长度,最高位 bit7 为0(用于区分其他两种格式)。
定长长格式:采用定长方式,当长度大于127个八位组时,Length 在多个八位组中编码,此时第一个八位组低七位(bit0~bit6)表示的是 Length 所占的长度,第一个八位组的最高位 bit7 为1,第一个八位组的低七位不能全为 0(用于区分其他两种格式)。
变长格式:采用变长方式,Length 所在八位组固定编码为 0x80,但在 Value 编码结束后以两个 0x00 结尾。这种方式使得可以在编码没有完全结束的情况下,可以先发送部分消息给对方。
3、Value(字符串类型的值编码)
SNMP 中字符串类型的值编码是直接将计算机存储的二进制形式数据作为编码值,占用 0 或多个八位组。
二、代码实现
(1)SNMP 中字符串型类型(包括基本类型 OCTER STRING 及其引申类型,如 IpAddress 等)的 BER 编码与解码。
一、理论知识
1、Tag
OCTER STRING 对应的 Tag 为 0x04,IpAddress 对应的 Tag 为 0x40。字符串类型的 Tag 占用一个八位组。
2、Length
Length有三种形式:定长短格式、定长长格式和变长格式。(SNMP 的所有内置类型的 Length 段都采用定长格式)
定长短格式:采用定长方式,当长度不大于127个八位组时,Length 只在一个八位组中编码。此时,bit0~bit6 表示实际长度,最高位 bit7 为0(用于区分其他两种格式)。
定长长格式:采用定长方式,当长度大于127个八位组时,Length 在多个八位组中编码,此时第一个八位组低七位(bit0~bit6)表示的是 Length 所占的长度,第一个八位组的最高位 bit7 为1,第一个八位组的低七位不能全为 0(用于区分其他两种格式)。
变长格式:采用变长方式,Length 所在八位组固定编码为 0x80,但在 Value 编码结束后以两个 0x00 结尾。这种方式使得可以在编码没有完全结束的情况下,可以先发送部分消息给对方。
3、Value(字符串类型的值编码)
SNMP 中字符串类型的值编码是直接将计算机存储的二进制形式数据作为编码值,占用 0 或多个八位组。
二、代码实现
/************************************************************************/ /* asn1.h */ /************************************************************************/ #pragma once typedef unsigned char u_char; 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_string(u_char *data, size_t *datalength, u_char type, const u_char *string, size_t stringlength); const u_char* _asn_parse_string(const u_char *data, size_t *datalength, u_char *type, u_char *string, size_t *stringlength);
/************************************************************************/ /* 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 (NULL == data || NULL == datalength) return NULL; if (*datalength < 1) return NULL; *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 (NULL == data || NULL == datalength || NULL == type || NULL == length) return NULL; if (*datalength < 1) return NULL; *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 (NULL == data || NULL == datalength) return NULL; const u_char *initdatap = data; if (length < 0x80) { /* 定长短格式 */ if (*datalength < 1) return NULL; *data++ = (u_char)length; } else if (length <= 0xFF) { /* 定长长格式,长度占用一个八位组 */ if (*datalength < 2) return NULL; *data++ = (u_char)0x81; /* Length 段的第一个八位组为 10000001,对应的十六进制即为 0x81 */ *data++ = (u_char)length; /* 将 length 的低 bit0~bit7 赋值给 *data,并使 data 指向 data 的下一个八位组 */ } else if (length <= 0xFFFF) { /* 定长长格式,长度占用两个八位组 */ if (*datalength < 3) return NULL; *data++ = (u_char)0x82; /* Length 段的第一个八位组为 10000010,对应的十六进制即为 0x82 */ *data++ = (u_char)(length >> 8); /* 将 length 的低 bit8~bit15 赋值给 *data,并使 data 指向 data 的下一个八位组 */ *data++ = (u_char)length; /* 将 length 的低 bit0~bit7 赋值给 *data,并使 data 指向 data 的下一个八位组 */ } else { /* 长度太长,不支持 */ return NULL; } *datalength -= (data - initdatap); return data; } const u_char* _asn_parse_length(const u_char *data, size_t *datalength, size_t *length) { if (NULL == data || NULL == datalength || NULL == length) return NULL; const u_char *initdatap = data; u_char lengthbyte = *data++; if (lengthbyte < 0x80) { /* 定长短格式 */ *length = lengthbyte; } else if (lengthbyte == 0x80) { /* 0x80 为变长格式,不支持 */ return NULL; } else { /* 定长长格式 */ size_t bytes = (size_t)(lengthbyte - 0x80); /* 计算 Length 段占用的八位组个数 */ if (bytes > sizeof(*length)) return NULL; /* Length 段太长 */ *length = 0; /* 消除 *length 的初值可能对 *length 最终结果带来的影响 */ while (bytes--) { *length <<= 8; *length |= (*data++); } } *datalength -= (data - initdatap); return data; } /* 参数 stringlength 为 strlen(string) 得到的结果*/ u_char* _asn_build_string(u_char *data, size_t *datalength, u_char type, const u_char *string, size_t stringlength) { if (NULL == data || NULL == datalength || NULL == string) return NULL; if ((data = _asn_build_header(data, datalength, type, stringlength)) == NULL) return NULL; if (*datalength < stringlength) return NULL; memmove_s(data, *datalength, string, stringlength); *datalength -= stringlength; data += stringlength; return data; } /* 参数 stringlength 【in】string的缓冲区大小 【out】string的有效长度 */ const u_char* _asn_parse_string(const u_char *data, size_t *datalength, u_char *type, u_char *string, size_t *stringlength) { if (NULL == data || NULL == datalength || NULL == type || NULL == string || NULL == stringlength) return NULL; size_t asn_length = 0; if ((data = _asn_parse_header(data, datalength, type, &asn_length)) == NULL) return NULL; if (*stringlength < asn_length) return NULL; /* 字符串 string 缓冲区太小 */ memmove_s(string, *stringlength, data, asn_length); if (*stringlength > asn_length) string[asn_length] = '\0'; *stringlength = asn_length; data += asn_length; *datalength -= asn_length; 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 (NULL == 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_char msg[] = "12345678910"; _asn_build_string(buf, &validlen, 0x06, msg, strlen((char *)msg)); print(buf, sizeof(buf)-validlen); u_char msg2[100]; size_t msg2_len = sizeof(msg2); u_char type; validlen = sizeof(buf)-validlen; _asn_parse_string(buf, &validlen, &type, msg2, &msg2_len); print(msg2, msg2_len); return 0; }
相关文章推荐
- Python中则正则表达式
- OSX 的文件系统 MAC
- Linux--进程组、会话、守护进程
- JSP系列:(2)JSP基础-Page指令详解
- 利用Travis CI 让你的github项目持续构建
- C轮魔咒:智能硬件为什么融资难
- Dialog中IME获取不到keyevent的原因
- JSP输出HTML时产生的大量空格和换行的去除方法
- Linux系统信息
- PHP - json_encode中文乱码
- AVR单片机EEPROM学习
- PHP - json_encode中文乱码
- android 关于定位我的几点分享?
- exec()函数
- 找水王续
- WebStorm中配置ExtJS
- 在物理机上部署 boot2docker 完全攻略
- android应用 DPI不同的适配问题分析
- WebStorm中配置ExtJS
- php......留言板