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.

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

报告相同问题?

悬赏问题

  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮