From 139498937a97c258581bf5efe1c2925d348f828d Mon Sep 17 00:00:00 2001 From: Wiard van Rij <5786097+wiardvanrij@users.noreply.github.com> Date: Mon, 7 Dec 2020 22:45:06 +0100 Subject: [PATCH] Add support to convert snmp hex strings to integers (#8426) --- plugins/inputs/snmp/README.md | 24 ++++++++++------ plugins/inputs/snmp/snmp.go | 47 ++++++++++++++++++++++++++++---- plugins/inputs/snmp/snmp_test.go | 6 ++++ 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/plugins/inputs/snmp/README.md b/plugins/inputs/snmp/README.md index ea6e7a95b..0eb0ac31a 100644 --- a/plugins/inputs/snmp/README.md +++ b/plugins/inputs/snmp/README.md @@ -113,15 +113,21 @@ option operate similar to the `snmpget` utility. # is_tag = false ## Apply one of the following conversions to the variable value: - ## float(X) Convert the input value into a float and divides by the - ## Xth power of 10. Effectively just moves the decimal left - ## X places. For example a value of `123` with `float(2)` - ## will result in `1.23`. - ## float: Convert the value into a float with no adjustment. Same - ## as `float(0)`. - ## int: Convert the value into an integer. - ## hwaddr: Convert the value to a MAC address. - ## ipaddr: Convert the value to an IP address. + ## float(X): Convert the input value into a float and divides by the + ## Xth power of 10. Effectively just moves the decimal left + ## X places. For example a value of `123` with `float(2)` + ## will result in `1.23`. + ## float: Convert the value into a float with no adjustment. Same + ## as `float(0)`. + ## int: Convert the value into an integer. + ## hwaddr: Convert the value to a MAC address. + ## ipaddr: Convert the value to an IP address. + ## hextoint:X:Y Convert a hex string value to integer. Where X is the Endian + ## and Y the bit size. For example: hextoint:LittleEndian:uint64 + ## or hextoint:BigEndian:uint32. Valid options for the Endian are: + ## BigEndian and LittleEndian. For the bit size: uint16, uint32 + ## and uint64. + ## # conversion = "" ``` diff --git a/plugins/inputs/snmp/snmp.go b/plugins/inputs/snmp/snmp.go index 623c9ba61..f8fa50004 100644 --- a/plugins/inputs/snmp/snmp.go +++ b/plugins/inputs/snmp/snmp.go @@ -3,6 +3,7 @@ package snmp import ( "bufio" "bytes" + "encoding/binary" "fmt" "log" "math" @@ -574,12 +575,6 @@ func (s *Snmp) getConnection(idx int) (snmpConnection, error) { } // fieldConvert converts from any type according to the conv specification -// "float"/"float(0)" will convert the value into a float. -// "float(X)" will convert the value into a float, and then move the decimal before Xth right-most digit. -// "int" will convert the value into an integer. -// "hwaddr" will convert the value into a MAC address. -// "ipaddr" will convert the value into into an IP address. -// "" will convert a byte slice into a string. func fieldConvert(conv string, v interface{}) (interface{}, error) { if conv == "" { if bs, ok := v.([]byte); ok { @@ -671,6 +666,46 @@ func fieldConvert(conv string, v interface{}) (interface{}, error) { return v, nil } + split := strings.Split(conv, ":") + if split[0] == "hextoint" && len(split) == 3 { + + endian := split[1] + bit := split[2] + + bv, ok := v.([]byte) + if !ok { + return v, nil + } + + if endian == "LittleEndian" { + switch bit { + case "uint64": + v = binary.LittleEndian.Uint64(bv) + case "uint32": + v = binary.LittleEndian.Uint32(bv) + case "uint16": + v = binary.LittleEndian.Uint16(bv) + default: + return nil, fmt.Errorf("invalid bit value (%s) for hex to int conversion", bit) + } + } else if endian == "BigEndian" { + switch bit { + case "uint64": + v = binary.BigEndian.Uint64(bv) + case "uint32": + v = binary.BigEndian.Uint32(bv) + case "uint16": + v = binary.BigEndian.Uint16(bv) + default: + return nil, fmt.Errorf("invalid bit value (%s) for hex to int conversion", bit) + } + } else { + return nil, fmt.Errorf("invalid Endian value (%s) for hex to int conversion", endian) + } + + return v, nil + } + if conv == "ipaddr" { var ipbs []byte diff --git a/plugins/inputs/snmp/snmp_test.go b/plugins/inputs/snmp/snmp_test.go index 8368ed738..199fbe83c 100644 --- a/plugins/inputs/snmp/snmp_test.go +++ b/plugins/inputs/snmp/snmp_test.go @@ -739,6 +739,12 @@ func TestFieldConvert(t *testing.T) { {[]byte("abcd"), "ipaddr", "97.98.99.100"}, {"abcd", "ipaddr", "97.98.99.100"}, {[]byte("abcdefghijklmnop"), "ipaddr", "6162:6364:6566:6768:696a:6b6c:6d6e:6f70"}, + {[]byte{0x00, 0x09, 0x3E, 0xE3, 0xF6, 0xD5, 0x3B, 0x60}, "hextoint:BigEndian:uint64", uint64(2602423610063712)}, + {[]byte{0x00, 0x09, 0x3E, 0xE3}, "hextoint:BigEndian:uint32", uint32(605923)}, + {[]byte{0x00, 0x09}, "hextoint:BigEndian:uint16", uint16(9)}, + {[]byte{0x00, 0x09, 0x3E, 0xE3, 0xF6, 0xD5, 0x3B, 0x60}, "hextoint:LittleEndian:uint64", uint64(6934371307618175232)}, + {[]byte{0x00, 0x09, 0x3E, 0xE3}, "hextoint:LittleEndian:uint32", uint32(3812493568)}, + {[]byte{0x00, 0x09}, "hextoint:LittleEndian:uint16", uint16(2304)}, } for _, tc := range testTable {