dqc18251 2018-08-05 23:04
浏览 39
已采纳

递归定义SNMP消息

I am messing around with an SNMP library in Go and came up with a type Field that defines an SNMP BER encoded field according to this document. Each field consists of a type, length, and value, where the type is an ASN.1 type, length is the length of the field's value, and the value can be another field, a sequence of fields, or a sequence of bytes. This made me think about the possibility of recursively defining an SNMP message. Here is some code I came up with, but I'm stuck trying to translate it into a recursive structure:

package main

import "fmt"

// ASN.1 BER encoded types.
type ASN1BER byte

const (
    Integer          ASN1BER = 0x02
    BitString                = 0x03
    OctetString              = 0x04
    Null                     = 0x05
    ObjectIdentifier         = 0x06
    Sequence                 = 0x30
    GetRequest               = 0xa0
)

// SNMP versions.
type Version byte

const (
    Version1  Version = 0x00
    Version2c         = 0x01
)

// SNMP message field.
type Field struct {
    Type  ASN1BER
    Len   int
    Value interface{}
}

func main() {
    // SNMP Message
    msg := &Field{Type: Sequence, Len: 44, Value: []*Field{
        // SNMP Version
        {Type: Integer, Len: 1, Value: Version2c},
        // Community String
        {Type: OctetString, Len: 7, Value: []byte("private")},
        // Get-Request PDU
        {Type: GetRequest, Len: 30, Value: []*Field{
            // Request ID
            {Type: Integer, Len: 1, Value: []byte{0x01}},
            // Error Status
            {Type: Integer, Len: 1, Value: []byte{0x00}},
            // Error Index
            {Type: Integer, Len: 1, Value: []byte{0x00}},
            // Varbind List
            {Type: Sequence, Len: 19, Value: []*Field{
                // Varbind
                {Type: Sequence, Len: 17, Value: []*Field{
                    // OID 1.3.6.1.4.1.2680.1.2.7.3.2.0
                    {Type: ObjectIdentifier, Len: 13, Value: []byte{0x2b, 0x06, 0x01, 0x04, 0x01, 0x94, 0x78, 0x01, 0x02, 0x07, 0x03, 0x02, 0x00}},
                    // Value
                    {Type: Null, Len: 0},
                }}},
            }},
        }},
    }
    fmt.Println(msg)
}

Is it possible to represent the SNMP message recursively? If so, what would be the base case(s) and the recursive case(s)? The goal is to be able to recursively print, encode, and decode SNMP messages.

  • 写回答

1条回答 默认 最新

  • duanposhi3641 2018-08-06 14:02
    关注

    The solution is to have a type switch which would branch into different code paths depending on the actual type of Value—possibly resursively.

    package main
    
    import (
        "fmt"
        "log"
        "reflect"
    )
    
    // ASN.1 BER encoded types.
    type ASN1BER byte
    
    const (
        Integer          ASN1BER = 0x02
        BitString                = 0x03
        OctetString              = 0x04
        Null                     = 0x05
        ObjectIdentifier         = 0x06
        Sequence                 = 0x30
        GetRequest               = 0xa0
    )
    
    // SNMP versions.
    type Version byte
    
    const (
        Version1  Version = 0x00
        Version2c         = 0x01
    )
    
    // SNMP message field.
    type Field struct {
        Type  ASN1BER
        Len   int
        Value interface{}
    }
    
    func walk(f *Field, indent string) error {
        switch f.Type {
        case GetRequest, Sequence:
            indent += "\t"
            switch v := f.Value.(type) {
            case *Field:
                return walk(v, indent)
            case []*Field:
                for _, f := range v {
                    err := walk(f, indent)
                    if err != nil {
                        return err
                    }
                }
            default:
                return &ValueTypeError{
                    ASNType:   f.Type,
                    ValueType: reflect.TypeOf(v),
                }
            }
        default:
            fmt.Printf("%sType: %d; value: %v
    ", indent, f.Type, f.Value)
        }
        return nil
    }
    
    type ValueTypeError struct {
        ASNType   ASN1BER
        ValueType reflect.Type
    }
    
    func (e *ValueTypeError) Error() string {
        return fmt.Sprintf("invalid Go type (%s) for ASN1BER type %d",
            e.ValueType.Name(), e.ASNType)
    }
    
    func main() {
        // SNMP Message
        msg := Field{Type: Sequence, Len: 44, Value: []*Field{
            // SNMP Version
            {Type: Integer, Len: 1, Value: Version2c},
            // Community String
            {Type: OctetString, Len: 7, Value: []byte("private")},
            // Get-Request PDU
            {Type: GetRequest, Len: 30, Value: []*Field{
                // Request ID
                {Type: Integer, Len: 1, Value: []byte{0x01}},
                // Error Status
                {Type: Integer, Len: 1, Value: []byte{0x00}},
                // Error Index
                {Type: Integer, Len: 1, Value: []byte{0x00}},
                // Varbind List
                {Type: Sequence, Len: 19, Value: []*Field{
                    // Varbind
                    {Type: Sequence, Len: 17, Value: []*Field{
                        // OID 1.3.6.1.4.1.2680.1.2.7.3.2.0
                        {Type: ObjectIdentifier, Len: 13, Value: []byte{0x2b, 0x06, 0x01, 0x04, 0x01, 0x94, 0x78, 0x01, 0x02, 0x07, 0x03, 0x02, 0x00}},
                        // Value
                        {Type: Null, Len: 0},
                    }}},
                }},
            }},
        }
    
        bad := Field{
            Type:  Sequence,
            Value: 42,
        }
    
        for i, f := range [...]*Field{&msg, &bad} {
            log.Println("walking:", i)
            err := walk(f, "")
            if err != nil {
                log.Println("error:", err)
            }
        }
    }
    

    Playground link.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 如何通过代码传输视频到亚马逊平台
  • ¥15 php查询mysql数据库并显示至下拉列表中
  • ¥15 freertos下使用外部中断失效
  • ¥15 输入的char字符转为int类型,不是对应的ascall码,如何才能使之转换为对应ascall码?或者使输入的char字符可以正常与其他字符比较?
  • ¥15 devserver配置完 启动服务 无法访问static上的资源
  • ¥15 解决websocket跟c#客户端通信
  • ¥30 Python调用dll文件输出Nan重置dll状态
  • ¥15 浮动div的高度控制问题。
  • ¥66 换电脑后应用程序报错
  • ¥50 array数据同步问题