Giter VIP home page Giter VIP logo

gosnmp's Introduction

gosnmp

Mentioned in Awesome Go

Build Status PkgGoDev

GoSNMP is an SNMP client library fully written in Go. It provides Get, GetNext, GetBulk, Walk, BulkWalk, Set and Traps. It supports IPv4 and IPv6, using SNMPv1, SNMPv2c or SNMPv3. Builds are tested against linux/amd64 and linux/386.

About

gosnmp was started by Andreas Louca, then completely rewritten by Sonia Hamilton (2012-2020), and now ownership has been transferred to the community at gosnmp/gosnmp.

For support and help, join us in the #snmp channel of Gophers Slack.

Overview

GoSNMP has the following SNMP functions:

  • Get (single or multiple OIDs)
  • GetNext
  • GetBulk (SNMPv2c and SNMPv3 only)
  • Walk - retrieves a subtree of values using GETNEXT.
  • BulkWalk - retrieves a subtree of values using GETBULK (SNMPv2c and SNMPv3 only).
  • BulkWalkAll - similar to BulkWalk but returns a filled array of all values rather than using a callback function to stream results.
  • Set - supports Integers and OctetStrings.
  • SendTrap - send SNMP TRAPs.
  • Listen - act as an NMS for receiving TRAPs.

GoSNMP has the following helper functions:

  • ToBigInt - treat returned values as *big.Int
  • Partition - facilitates dividing up large slices of OIDs

gosnmp/gosnmp has completely diverged from alouca/gosnmp, your code will require modification in these (and other) locations:

  • the Get function has a different method signature
  • the NewGoSNMP function has been removed, use Connect instead (see Usage below). Connect uses the GoSNMP struct; gosnmp.Default is provided for you to build on.
  • GoSNMP no longer relies on alouca/gologger - you can use your logger if it conforms to the gosnmp.LoggerInterface interface; otherwise debugging will disabled.
type LoggerInterface interface {
    Print(v ...interface{})
    Printf(format string, v ...interface{})
}

To enable logging, you must call gosnmp.NewLogger() function, and pass a pointer to your logging interface, for example with standard *log.Logger:

gosnmp.Default.Logger = gosnmp.NewLogger(log.New(os.Stdout, "", 0))

or

g := &gosnmp.GoSNMP{
    ...
    Logger:    gosnmp.NewLogger(log.New(os.Stdout, "", 0)),
}

You can completely remove the logging code from your application using the golang build tag "gosnmp_nodebug", for example:

go build -tags gosnmp_nodebug

This will completely disable the logging of the gosnmp library, even if the logger interface is specified in the code. This provides a small performance improvement.

Installation

go get github.com/gosnmp/gosnmp

Documentation

https://pkg.go.dev/github.com/gosnmp/gosnmp

Usage

Here is examples/example/main.go, demonstrating how to use GoSNMP:

// Default is a pointer to a GoSNMP struct that contains sensible defaults
// eg port 161, community public, etc
g.Default.Target = "192.168.1.10"
err := g.Default.Connect()
if err != nil {
    log.Fatalf("Connect() err: %v", err)
}
defer g.Default.Conn.Close()

oids := []string{"1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.7.0"}
result, err2 := g.Default.Get(oids) // Get() accepts up to g.MAX_OIDS
if err2 != nil {
    log.Fatalf("Get() err: %v", err2)
}

for i, variable := range result.Variables {
    fmt.Printf("%d: oid: %s ", i, variable.Name)

    // the Value of each variable returned by Get() implements
    // interface{}. You could do a type switch...
    switch variable.Type {
    case g.OctetString:
        bytes := variable.Value.([]byte)
        fmt.Printf("string: %s\n", string(bytes))
    default:
        // ... or often you're just interested in numeric values.
        // ToBigInt() will return the Value as a BigInt, for plugging
        // into your calculations.
        fmt.Printf("number: %d\n", g.ToBigInt(variable.Value))
    }
}

Running this example gives the following output (from my printer):

% go run example.go
0: oid: 1.3.6.1.2.1.1.4.0 string: Administrator
1: oid: 1.3.6.1.2.1.1.7.0 number: 104
  • examples/example2.go is similar to example.go, however it uses a custom &GoSNMP rather than g.Default
  • examples/walkexample.go demonstrates using BulkWalk
  • examples/example3.go demonstrates SNMPv3
  • examples/trapserver.go demonstrates writing an SNMP v2c trap server

MIB Parser

I don't have any plans to write a mib parser. Others have suggested https://github.com/sleepinggenius2/gosmi

Contributions

Contributions are welcome, especially ones that have packet captures (see below).

If you've never contributed to a Go project before, here is an example workflow.

  1. fork this repo on the GitHub webpage
  2. go get github.com/gosnmp/gosnmp
  3. cd $GOPATH/src/github.com/gosnmp/gosnmp
  4. git remote rename origin upstream
  5. git remote add origin [email protected]:<your-github-username>/gosnmp.git
  6. git checkout -b development
  7. git push -u origin development (setup where you push to, check it works)

Packet Captures

Create your packet captures in the following way:

Expected output, obtained via an snmp command. For example:

% snmpget -On -v2c -c public 203.50.251.17 1.3.6.1.2.1.1.7.0 \
  1.3.6.1.2.1.2.2.1.2.6 1.3.6.1.2.1.2.2.1.5.3
.1.3.6.1.2.1.1.7.0 = INTEGER: 78
.1.3.6.1.2.1.2.2.1.2.6 = STRING: GigabitEthernet0
.1.3.6.1.2.1.2.2.1.5.3 = Gauge32: 4294967295

A packet capture, obtained while running the snmpget. For example:

sudo tcpdump -s 0 -i eth0 -w foo.pcap host 203.50.251.17 and port 161

Bugs

Rane's document SNMP: Simple? Network Management Protocol was useful when learning the SNMP protocol.

Please create an issue on Github with packet captures (upload capture to Google Drive, Dropbox, or similar) containing samples of missing BER types, or of any other bugs you find. If possible, please include 2 or 3 examples of the missing/faulty BER type.

The following BER types have been implemented:

  • 0x00 UnknownType
  • 0x01 Boolean
  • 0x02 Integer
  • 0x03 BitString
  • 0x04 OctetString
  • 0x05 Null
  • 0x06 ObjectIdentifier
  • 0x07 ObjectDescription
  • 0x40 IPAddress (IPv4 & IPv6)
  • 0x41 Counter32
  • 0x42 Gauge32
  • 0x43 TimeTicks
  • 0x44 Opaque (Float & Double)
  • 0x45 NsapAddress
  • 0x46 Counter64
  • 0x47 Uinteger32
  • 0x78 OpaqueFloat
  • 0x79 OpaqueDouble
  • 0x80 NoSuchObject
  • 0x81 NoSuchInstance
  • 0x82 EndOfMibView

Running the Tests

Local testing in Docker

docker build -t gosnmp/gosnmp:latest .
docker run -it gosnmp/gosnmp:latest

or

export GOSNMP_TARGET=1.2.3.4
export GOSNMP_PORT=161
export GOSNMP_TARGET_IPV4=1.2.3.4
export GOSNMP_PORT_IPV4=161
export GOSNMP_TARGET_IPV6='0:0:0:0:0:ffff:102:304'
export GOSNMP_PORT_IPV6=161
go test -v -tags all        # for example
go test -v -tags helper     # for example

Tests are grouped as follows:

  • Unit tests (validating data packing and marshalling):
    • marshal_test.go
    • misc_test.go
  • Public API consistency tests:
    • gosnmp_api_test.go
  • End-to-end integration tests:
    • generic_e2e_test.go

The generic end-to-end integration test generic_e2e_test.go should work against any SNMP MIB-2 compliant host (e.g. a router, NAS box, printer).

Mocks were generated using:

mockgen -source=interface.go -destination=mocks/gosnmp_mock.go -package=mocks

However they're currently removed, as they were breaking linting.

To profile cpu usage:

go test -cpuprofile cpu.out
go test -c
go tool pprof gosnmp.test cpu.out

To profile memory usage:

go test -memprofile mem.out
go test -c
go tool pprof gosnmp.test mem.out

To check test coverage:

go get github.com/axw/gocov/gocov
go get github.com/matm/gocov-html
gocov test github.com/gosnmp/gosnmp | gocov-html > gosnmp.html && firefox gosnmp.html &

To measure the performance of password hash caching:

Password hash caching can be disabled during benchmark tests by using the golang build tag "gosnmp_nopwdcache", so:

go build -tags gosnmp_nopwdcache -bench=Benchmark.*Hash

will benchmark the code without password hash caching. Removing the tag will run the benchmark with caching enabled (default behavior of package).

License

Parts of the code are taken from the Golang project (specifically some functions for unmarshaling BER responses), which are under the same terms and conditions as the Go language. The rest of the code is under a BSD license.

See the LICENSE file for more details.

The remaining code is Copyright 2012 the GoSNMP Authors - see AUTHORS.md for a list of authors.

gosnmp's People

Contributors

benjamin-thomas avatar blind-oracle avatar brian-brazil avatar codedance avatar ctrlrsf avatar dependabot[bot] avatar dswarbrick avatar eferro avatar frozenbubbleboy avatar hdm avatar it1804 avatar jclc avatar kauppine avatar krkini16 avatar laurel-rao avatar leucos avatar mei-rune avatar n3integration avatar nikandfor avatar nwaizer avatar slayercat avatar soniah avatar stefanhauth avatar superq avatar timrots avatar toni-moreno avatar upsampled avatar virtuallynathan avatar wdreeveii avatar zamedic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gosnmp's Issues

race issues with global logging vars

Hi,

Global vars LoggingDisabled bool and slog Logger are detected as not being safe owing to unsynchronized reads/writes (when calling gosnmp from concurrent go routines). Visible using go run -race.

I guess there are two directions:

  1. created synchronized access methods to global logging state
  2. remove global vars and pass state around from gosnmp.GoSNMP

Thoughts ?

Timeout Problems

Hi.

Every time I try to pull data from a snmp agent it returns timeout if the host (server) is in another network.

if the agent is in the same network it works fine.

tcpdump shows the petition and the response but the snmpget still jumps with timeout error.
if the test run in a host from the same network the data comes ok.

tested snmpget (part of snmp-utils) and works w/o problems there is sime limites over this library?

refactoring of the constant?

do you consider to refactor this part of the code

const (
    // maxOids is the maximum number of oids allowed in a Get()
    maxOids = 60

    // Base OID for MIB-2 defined SNMP variables
    baseOid = ".1.3.6.1.2.1"

    // Java SNMP uses 50, snmp-net uses 10
    defaultMaxRepetitions = 50

    // TODO comment
    defaultNonRepeaters = 0
)

by moving it to the Default for example.
the reason is:
a lot of networking hardware uses oids from the private space (.1.3.6.1.4...)
(.1.3.6.1.2 is IETF only)
as well as i have found a problem with defaultMaxRepetitions equals to 50 size on some of the networking hardware (so IMO it's better to be configurable instead of hardcoding)

Error when decoding empty SNMP response

Empty SNMP GET requests/responses are perfectly valid (the reply has error-status = noError), but gosnmp fails to decode the response (and promptly retries, failing again, of course):

Unable to decode packet: Error in unmarshalResponse: Expected a sequence when unmarshalling a VB, got 0

PCAP:

curl -q https://gist.githubusercontent.com/fxkr/0b377dad1480ab62ff9c/raw/06a07e77627c8d0456f7c49198fbb0d2388cb25b/gistfile1.txt | base64 -d > test.pcapng

Optimize Performance

Lets eek out as much performance as possible...
cpu_profile
mem_profile

Here are profiles with tons of samples (ignore the CSV stuff...)

Incorrect decoding of OctetString

Problem

OctetStrings (as in the ASN.1 type) store arbitrary binary data in bytes (multiples of eight). In real-world devices, OctetStrings are used for many proposes. One is of course text (strings), but another typical use is to encode values in a bit-string (e.g. bit flag encoded enumerations). The current implementation in GoSNMP assumes text only and casts the value to a string() leading to loss of data (e.g. 0x00 are lost).

Offending Code

helper.go

  case OctetString:
        // 0x04
        if LoggingDisabled != true {
            slog.Print("decodeValue: type is OctetString")
        }
        length, cursor := parseLength(data)
        retVal.Type = OctetString
        if data[cursor] == 0 && length == 2 {
            retVal.Value = ""
        } else if data[cursor] == 0 {
            retVal.Value = fmt.Sprintf("% x", data[cursor:length])
        } else {
            retVal.Value = string(data[cursor:length])
        }

Recommendation

I feel it's important to not break the public API (we'll leave that to GoSNMPv2). We can fix this in a compatible way by extending the SnmpPDU "variable" data struct to store a raw value alongside the cast value (and do this for all (most) types).

type variable struct {
    Name  []int
    Type  Asn1BER
    Value interface{}
    RawValue []byte   # New value to store raw binary
}

This would allow usage code like:

for _, v := range result.Variables {
   switch v.Type {
   case gosnmp.OctetString:
       myRawBitString := v.RawValue
       // Do what you need to do with the bytes
       myStandardString := v.Value  // Existing - only OK for text
   }
}

Alternative

Break the external API and change variable.Value to a []byte array rather than a string - leave it up to the consumer/user to do the conversation.

Questions/Discussion

  • To break API or not to break API - that is the [first] question?
  • Should the SnmpPDU struct member name be RawValue, ValueRaw, or ByteData, or other?
  • Should we perform endianness conversation so it's consistent?
  • Should we store RawValue for all types where it makes sense or may be useful? I think it cant hurt and performance overhead would be minimal as we already have slices in memory.

Action

@codedance is happy to take this one on. Just looking for conformation form others before moving forward. Areas to change are:

  • helper.go
  • example code
  • documentation

Problem with request timeouts

The biggest problem here is that the timeout is defined as a final deadline. If the snmp query hasn't completed in xxx seconds, return an error. This is a huge problem for walking large tables. It forces you to tailor timeouts on a per request basis.

The next problem is that the timeout is divided among retry attempts. If you have a large amount of retries, and a relatively small timeout, your effective request timeout is extremely small.

A timeout is a safety feature designed to detect when a server is not responding. Example: You do not use a final deadline when downloading arbitrary files because each file is different and no single timeout will adequately fit all file sizes.

What you want to do instead is use a timeout to identify when a server has failed to send data. That is - to error out only when the server is not responding. The last thing you want to do is kill a large data transfer in progress because of some arbitrary deadline. You will simply have to retry and that will only swamp your network with needless/pointless data transfer.

I want to take the following steps to mitigate these problems:

  1. Eliminate 'final deadline' and instead move to a 'server has failed to respond' timeout.
  2. Eliminate request deadlines and allow any 1 'retry' to use the full allotted timeout.

Taking these steps will significantly improve the usability of this library by allowing timeouts to reflect hardware/network problems and eliminate the possibility that large transfers may cause a timeout.

Is the gosnmp client usable concurrently?

Hi,

I tried to execute two BulkWalk() routines on the same client, and I get out of order results. I'm sure if I'm doing something wrong or the client should not be used concurrently. Here's an example of what I'm doing:

package main

import (
    "fmt"
    "log"
    "os"
    "sync"
    "time"

    "github.com/soniah/gosnmp"
)

var wg sync.WaitGroup

const (
    devClientCount string = ".1.3.6.1.4.1.29671.1.1.4.1.5"
    devName               = ".1.3.6.1.4.1.29671.1.1.4.1.2"
)

func main() {
    client := &gosnmp.GoSNMP{
        Target:    "n46.meraki.com",
        Port:      16100,
        Community: "public",
        Version:   gosnmp.Version2c,
        Timeout:   time.Duration(2) * time.Second,
    }
    err := client.Connect()
    if err != nil {
        log.Fatalf("Connect() err: %v", err)
    }
    defer client.Conn.Close()
    wg.Add(1)
    go walk(devClientCount, client)

    wg.Add(1)
    go walk(devClientCount, client)

    wg.Wait()
}

func walk(oid string, client *gosnmp.GoSNMP) {
    defer wg.Done()
    err := client.BulkWalk(oid, printValue)
    if err != nil {
        fmt.Printf("Walk Error: %v\n", err)
        os.Exit(1)
    }
}

func printValue(pdu gosnmp.SnmpPDU) error {
    fmt.Printf("%s = ", pdu.Name)

    switch pdu.Type {
    case gosnmp.OctetString:
        b := pdu.Value.([]byte)
        fmt.Printf("STRING: %s\n", string(b))
    default:
        fmt.Printf("INTEGER %d: %d\n", pdu.Type, gosnmp.ToBigInt(pdu.Value))
    }
    return nil
}

Error on snmpv3 bulkwalk error (integer divide by zero)

Hi @soniah

When doing the same query over snmpbulkwalk command I got the expected result.

[root@lab01 influxsnmp]# snmpbulkwalk -v 3 -u v3userauth -l authNoPriv -a MD5 -A v3passauth  192.168.1.99 ifName
IF-MIB::ifName.1 = STRING: lo
IF-MIB::ifName.2 = STRING: eth0
IF-MIB::ifName.3 = STRING: sit0

but fails when done with gosnmp with the following code

...
...

          UsmParams = &gosnmp.UsmSecurityParameters{
                                UserName:                 s.V3AuthUser,
                                AuthenticationProtocol:   authpmap[s.V3AuthProt],
                                AuthenticationPassphrase: s.V3AuthPass,
                                PrivacyProtocol:          gosnmp.NoPriv,
                                PrivacyPassphrase:        "",
                        }

...
...
                fmt.Printf("DEBUG: USMPARAMS %+v\n", *UsmParams)
                client = &gosnmp.GoSNMP{
                        Target:             hostIPs[0],
                        Port:               uint16(s.Port),
                        Version:            gosnmp.Version3,
                        Timeout:            time.Duration(s.Timeout) * time.Second,
                        Retries:            s.Retries,
                        SecurityModel:      gosnmp.UserSecurityModel,
                        MsgFlags:           gosnmp.AuthPriv,
                        SecurityParameters: UsmParams,
                }
                fmt.Printf("DEBUG: CLIENT %+v\n", *client)
...
 fmt.Println("Looking up column names for:", c.Host)
   pdus, err := client.BulkWalkAll(ifName)
        if err != nil {
                fatal("SNMP bulkwalk error", err)
        }

And with these paràmeters.

[snmp.hostsnmpv3c]

host = "hostsnmpv3c"
port = 161
timeout = 20
retries = 5
repeat = 0
#snmp version /auth params
snmpversion = "3"
v3seclevel = "AuthPriv"
#only needed if Auth v3 enabled
v3authuser = "v3userpriv"
v3authpass = "v3passpriv"
v3authprot = "MD5"
#only needed if Privacy v3 enabled
3privpass = "v3passenc"
v3privprot = "DES"
# runtime parameters
freq = 30
extratags = [ "tagA=4","tagB=5" ,"tagC=6" ]
debug  = true

we have the following error:

DEBUG: USMPARAMS {AuthoritativeEngineID: AuthoritativeEngineBoots:0 AuthoritativeEngineTime:0 UserName:v3userauth AuthenticationParameters: PrivacyParameters:[] AuthenticationProtocol:2 PrivacyProtocol:1 AuthenticationPassphrase:v3passauth PrivacyPassphrase: localDESSalt:0 localAESSalt:0}
DEBUG: CLIENT {Target:192.168.1.99 Port:161 Version:3 Community: Timeout:20s Retries:5 Logger:<nil> loggingEnabled:false MsgFlags:3 SecurityModel:3 SecurityParameters:0xc820199c20 ContextEngineID: ContextName: Conn:<nil> MaxRepetitions:0 NonRepeaters:0 requestID:0 random:<nil> msgID:0}
Looking up column names for: hostsnmpv3b
Packet sanity verified, we got all the bytes (117)
parseRawField: version
0       02 01 03 30 11 02 04 0f
8       51 4d a3 02 03 00 ff e3
Parsed version 3
parseRawField: msgID
0       02 04 0f 51 4d a3 02 03
8       00 ff e3 04 01 00 02 01
Parsed message ID 256986531
parseRawField: maxMsgSize
0       02 03 00 ff e3 04 01 00
8       02 01 03 04 23 30 21 04
parseRawField: msgFlags
0       04 01 00 02 01 03 04 23
8       30 21 04 11 80 00 1f 88
parsed msg flags
parseRawField: msgSecurityModel
0       02 01 03 04 23 30 21 04
8       11 80 00 1f 88 80 30 3c
Parsed security model 3
parseRawField: msgAuthoritativeEngineID
0       04 11 80 00 1f 88 80 30
8       3c a3 16 68 42 ff 56 00
Parsed authoritativeEngineID ▒▒▒0<▒hB▒V
parseRawField: msgAuthoritativeEngineBoots
0       02 01 0c 02 03 03 17 0a
8       04 00 04 00 04 00 30 36
Parsed authoritativeEngineBoots 12
parseRawField: msgAuthoritativeEngineTime
0       02 03 03 17 0a 04 00 04
8       00 04 00 30 36 04 11 80
Parsed authoritativeEngineTime 202506
parseRawField: msgUserName
0       04 00 04 00 04 00 30 36
8       04 11 80 00 1f 88 80 30
Parsed userName
parseRawField: msgAuthenticationParameters
0       04 00 04 00 30 36 04 11
8       80 00 1f 88 80 30 3c a3
Parsed authenticationParameters
parseRawField: msgPrivacyParameters
0       04 00 30 36 04 11 80 00
8       1f 88 80 30 3c a3 16 68
Parsed privacyParameters
parseRawField: contextEngineID
0       04 11 80 00 1f 88 80 30
8       3c a3 16 68 42 ff 56 00
Parsed contextEngineID ▒▒▒0<▒hB▒V
parseRawField: contextName
0       04 00 a8 1f 02 04 d7 f0
8       ab bd 02 01 00 02 01 00
Parsed contextName
SNMP Packet is GET RESPONSE
0       a8 1f 02 04 d7 f0 ab bd
8       02 01 00 02 01 00 30 11
getResponseLength: 33
parseRawField: request id
0       02 04 d7 f0 ab bd 02 01
8       00 02 01 00 30 11 30 0f
requestID: 3622874045
parseRawField: error-status
0       02 01 00 02 01 00 30 11
8       30 0f 06 0a 2b 06 01 06
errorStatus: 0
parseRawField: error index
0       02 01 00 30 11 30 0f 06
8       0a 2b 06 01 06 03 0f 01
error-index: 0

=== unmarshalVBL()
0       30 11 30 0f 06 0a 2b 06
8       01 06 03 0f 01 01 04 00
16      30 11 30
vblLength: 19

STARTING a varbind. Cursor 2
0       30 0f 06 0a 2b 06 01 06
8       03 0f 01 01 04 00 41 01
16      30
parseRawField: OID
0       06 0a 2b 06 01 06 03 0f
8       06 0a 2b 06 01 06 03
OID: .1.3.6.1.6.3.15.1.1.4.0
decodeValue: value
0       41 01 42
decodeValue: type is Counter32
decodeValue: value is 0x42
2016/04/04 14:48:24 SNMP bulkwalk error recover: runtime error: integer divide by zero

Can you help me to understand which is the problem?

Thank you very much

Use struct members instead of arguments to struct methods

The code has several places where a struct has a method which takes arguments that are also struct members.

For example: https://github.com/soniah/gosnmp/blob/f6904fd235070fe56e2c2d799ac5f5862fc32543/marshal.go#L253

packetOut.marshalMsg(pdus, packetOut.PDUType, msgID, reqID)

The obvious one is packetOut.PDUType. The marshalMsg method already has access to packetOut.PDUType because they are both members of the same struct (SnmpPacket).
However all the others can be removed as well.

  • pdus - SnmpPacket has a Variables member which should be used instead.
  • msgID - SnmpPacket has a MsgID member
  • reqID - SnmpPacket has a RequestID member

Numerous other methods are used the same way:

  • marshalSnmpV3ScopedPDU
  • prepareSnmpV3ScopedPDU
  • marshalPDU
  • marshalVBL

Another example, (*GoSNMP).GetBulk(oids []string, nonRepeaters uint8, maxRepetitions uint8).
The GoSNMP struct has NonRepeaters and MaxRepetitions members. Why, if we're not going to use them?

Aside from not being proper go, these make the code very confusing to follow. And in that last case, confusing to use.

Excess results in bulkwalk

When I'm trying to BulkWalk oid ".1.3.6.1.2.1.4.22.1.2.1" I'm getting excess results

...
.1.3.6.1.2.1.4.22.1.2.1.10.11.44.254 - correct
.1.3.6.1.2.1.4.22.1.2.1.10.90.90.99 - correct
.1.3.6.1.2.1.4.22.1.2.115.10.198.224.1 - excess
.1.3.6.1.2.1.4.22.1.2.115.10.198.224.3 - excess
...

That's how I've fixed it in alouca's gosnmp https://github.com/hh-h/gosnmp/commit/a84b137b46fc707baef573108cbcc86a459e6db8
So I think it'll be enough only add same logic in https://github.com/soniah/gosnmp/blob/master/walk.go#L61 ?
if !strings.HasPrefix(v.Name, rootOid + string(".")) {
Because in original netsnmp code oid is array of ints

gosnmp/helper.go - Request ID failing on what I believe are valid Request IDs

I'm not sure if this is a correct fix, but it allows my tool to decode these OctetStrings correctly.

I made the slight adjustment to line 484 replacing with 485. I realize the int64 can wrap to an incorrect value via the return int(), but I haven't noticed any unexpected side effects yet.

Failed requests:

parseRawField: request id
0 02 05 00 b4 8b 01 5c 02
8 01 00 02 01 00 30 76 30
parseRawField: request idDebug Type Integer: 2 - 2 - length: 7
[.1.3.6.1.2.1.1.1.0] %!q(*gosnmp.SnmpPacket=) err: Unable to decode packet: Error in unmarshalResponse: Error parsing SNMP packet request ID: Unable to parse raw INTEGER: 020500b48b015c0201000201003076307406082b06010201010100046848575f5245563a203030324a2c2056454e444f523a20436f6d6d53636f70652c20424f4f54523a20323030392e30312d35382c2053575f5245563a2076322e362e31322e332c204d4f44454c3a204c78532d31363031362c204150505f5245563a20322e362e3138 err: integer too large

09:35:24.419003 IP (tos 0x0, ttl 50, id 0, offset 0, flags [DF], proto: UDP (17), length: 178) x.x.135.154.snmp > x.x.13.141.60483: [udp sum ok] { SNMPv2c { GetResponse(133) R=-1675185393 .1.3.6.1.2.1.1.1.0="HW_REV: 002J, VENDOR: CommScope, BOOTR: 2009.01-58, SW_REV: v2.6.12.3, MODEL: LxS-16016, APP_REV: 2.6.18" } }
....C..D.0.......public.......&........0v0t..+........hHW_REV: 002J, VENDOR: CommScope, BOOTR: 2009.01-58, SW_REV: v2.6.12.3, MODEL: LxS-16016, APP_REV: 2.6.18

Working:

parseRawField: request id
0 02 04 7a 2f 72 0e 02 01
8 00 02 01 00 30 76 30 74
parseRawField: request idDebug Type Integer NIL: 2 - 2 - length: 6
[.1.3.6.1.2.1.1.1.0] HW_REV: 002J, VENDOR: CommScope, BOOTR: 2009.01-58, SW_REV: v2.6.12.3, MODEL: LxS-16016, APP_REV: 2.6.18

09:35:29.843499 IP (tos 0x0, ttl 50, id 0, offset 0, flags [DF], proto: UDP (17), length: 177) x.x.135.154.snmp > x.x.13.141.38767: [udp sum ok] { SNMPv2c { GetResponse(132) R=977264967 .1.3.6.1.2.1.1.1.0="HW_REV: 002J, VENDOR: CommScope, BOOTR: 2009.01-58, SW_REV: v2.6.12.3, MODEL: LxS-16016, APP_REV: 2.6.18" } }
....o....0.......public.....:?.G......0v0t..+........hHW_REV: 002J, VENDOR: CommScope, BOOTR: 2009.01-58, SW_REV: v2.6.12.3, MODEL: LxS-16016, APP_REV: 2.6.18

gosnmp/helper.go

477 // parseInt treats the given bytes as a big-endian, signed integer and returns
478 // the result.
479 func parseInt(bytes []byte) (int, error) {
480 ret64, err := parseInt64(bytes)
481 if err != nil {
482 return 0, err
483 }
484 // if ret64 != int64(int(ret64)) {
485 if ret64 != int64(ret64) {
486 return 0, errors.New("integer too large")
487 }
488 return int(ret64), nil
489 }

why MaxRepetitions is uint8

when I use bulkget, the MaxRepetitions value is bigger than 255,because the cpu num is bigger than 255.

so,why MaxRepetitions is uint8,when use int32,what will happen

SET OctetString support

There is no single SNMP package in go with reasonable support for SNMP set v2c.
Currently only Integer set is supported.
Any chances to add OctetString or Hex writes ?

e2e tests fail on OS X?

TestGenericBasicGet
--- FAIL: TestGenericBasicGet (0.02 seconds)
generic_e2e_test.go:51: Expected sysDescr to be OctetString
FAIL
exit status 1
FAIL _/Users/nowens002c/Code/gosnmp 0.026s
TestGenericMultiGet
--- FAIL: TestGenericMultiGet (0.00 seconds)
generic_e2e_test.go:76: Expected OctetString
FAIL
exit status 1
FAIL _/Users/nowens002c/Code/gosnmp 0.011s
TestGenericGetNext
PASS
ok _/Users/nowens002c/Code/gosnmp 0.011s
TestGenericWalk
--- FAIL: TestGenericWalk (0.00 seconds)
generic_e2e_test.go:104: WalkAll() Failed with error => OID not increasing: 1.3.6.1.2.1.1.4.0
FAIL
exit status 1

That's on the current master branch, using SNMPd that comes default with OS X.

10:gosnmp nowens002c$ snmpget -v2c -c public localhost .1.3.6.1.2.1.1.1.0
SNMPv2-MIB::sysDescr.0 = No Such Object available on this agent at this OID

SNMP v3 auth broken

It looks like either 4bdba85 or eb2302e broke snmp v3 auth support (4bdba85 doesn't even compile). When I try to use it, I just get lots of:

&GoSNMP.SecurityModel indicates the User Security Model, but &GoSNMP.SecurityParameters is not of type &UsmSecurityParameters

Previous commits worked fine.

The request gets sent off successfully, but the error is thrown handling the response.

Packet looks like this:

image

GoSNMP object at time of error looks like:

&gosnmp.GoSNMP{
    Conn:(*net.UDPConn)(0xc82013a338),
    Target:"127.0.0.1",
    Port:0x489,
    Community:"",
    Version:0x3,
    Timeout:5000000000,
    Retries:5,
    Logger:(*log.Logger)(0xc8203245f0),
    loggingEnabled:false,
    MaxOids:60,
    MaxRepetitions:0x32,
    NonRepeaters:2,
    requestID:0x3522560a,
    random:(*rand.Rand)(0xc820137cc0),
    rxBuf:(*[65535]uint8)(0xc820342000),
    MsgFlags:0x5,
    SecurityModel:0x3,
    SecurityParameters: &gosnmp.UsmSecurityParameters{
        AuthoritativeEngineID:"",
        AuthoritativeEngineBoots:0x0,
        AuthoritativeEngineTime:0x0,
        UserName:"user",
        AuthenticationParameters:"",
        PrivacyParameters:[]uint8(nil),
        AuthenticationProtocol:0x2,
        PrivacyProtocol:0x1,
        AuthenticationPassphrase:"asdfasdf",
        PrivacyPassphrase:"",
        localDESSalt:0x0,
        localAESSalt:0x0
    }
    ContextEngineID:"",
    ContextName:"",
    msgID:0x5437ec10
}

Set Logger for testing

Adding short circuit code reduced test coverage, so setting the logger should fix this.

uint64toBigInt, is this still needed?

helper.go line 474:

//TODO: Figure out if this is still an issue?
// Issue 4389: math/big: add SetUint64 and Uint64 functions to *Int
// uint64ToBigInt copied from: http://github.com/cznic/mathutil/blob/master/mathutil.go#L341
// replace with Uint64ToBigInt or equivalent when using Go 1.1
var uint64ToBigIntDelta big.Int

func init() {
    uint64ToBigIntDelta.SetBit(&uint64ToBigIntDelta, 63, 1)
}

func uint64ToBigInt(n uint64) *big.Int {
    if n <= math.MaxInt64 {
        return big.NewInt(int64(n))
    }

    y := big.NewInt(int64(n - uint64(math.MaxInt64) - 1))
    return y.Add(y, &uint64ToBigIntDelta)
}

use parseLength in parseRawField with ObjectIdentifier

in helper.go
func parseRawField

case ObjectIdentifier:
length := int(data[1])
oid, err := parseObjectIdentifier(data[2 : 2+length])
return oid, length + 2, err

change to
case ObjectIdentifier:
length, cursor := parseLength(data)
oid, err := parseObjectIdentifier(data[cursor:length])
return oid, length, err

here is packet from my device

0000   30 82 00 43 02 01 00 04 82 00 06 70 75 62 6c 69  0..C.......publi
0010   63 a2 82 00 32 02 04 31 b7 3a 5c 02 01 00 02 02  c...2..1.:\.....
0020   00 00 30 82 00 21 30 82 00 1d 06 81 08 2b 06 01  ..0..!0......+..
0030   02 01 01 05 00 04 82 00 0e 48 46 43 20 53 4e 4d  .........HFC SNM
0040   50 20 41 67 65 6e 74                             P Agent

it use 2 byte length in ObjectIdentifier 81 08

Udp listen

Good day.

Help to understand the best way to solve this problem:

00:00:20.414081 IP 10.12.2.2.23568 > 10.15.44.1.161:  C=totgfh0xre GetNextRequest(30)  .1.3.6.1.2.1.31.1.1.1.1
00:00:20.442642 IP 8.9.1.1.161 > 10.12.2.2.23568:  C=totgfh0xre GetResponse(35)  .1.3.6.1.2.1.31.1.1.1.1.1="fxp0"

Some equipment is responsible at a different address (it can not be configure).
Such as Juniper.
Accordingly, I get "Last error was: Error reading from UDP: read udp 10.15.44.1:161: i/o timeout"

Walk tests broken in perf_wip branch

I suspect its due to me adding leading dots to all of the OIDs, but i could be wrong.

Any idea Chris?

TestGenericWalk
--- FAIL: TestGenericWalk (0.00 seconds)
generic_e2e_test.go:104: WalkAll() Failed with error => OID not increasing: .1.3.6.1.2.1.1.4.0
FAIL
exit status 1

Duplicate packets put connection in bad state

If any duplicate packets are sent or received, the connection is put into a bad state where any attempts to use it can fail.

For example:

  1. Caller performs a request (req#1).
  2. Due to a faulty network, we receive 2 response packets for req#1.
  3. We read the first response packet and return a normal response to the caller, while the duplicate packet sits on the socket receive buffer.
  4. Caller performs another request (req#2)
  5. We read off the socket and receive the duplicate packet for req#1.
  6. This results in an Out of order response error and we retry the request.
  7. We send req#3 as a retry of req#2
  8. We read off the socket and receive the response to req#2.
  9. Because req#2 is in allReqIDs, we don't throw a Out of order response, but instead return successfully. The response to req#3 is still sitting on the socket receive buffer.
  10. Skip to step 4 and repeat any number of times.
  11. Eventually due to faulty network, another duplicate response is received, leaving 2 response packets sitting on the buffer.
  12. Now we send 2 retry requests because we read 2 unexpected packets.
  13. Eventually we receive enough duplicate packets to where we have more responses sitting on the buffer than we have retries. Now every single request the caller performs results in a Out of order response error. The only solution is to close the connection.

I think the solution here is that when an Out of order response is generated, DO NOT send another request. Continue waiting for a response. Let the timeout kick in if the real response is not read.

Connect() fails to dial IPv6 agent

When performing (*GoSNMP).Connect() the error returned is

Error establishing connection to host: dial udp: too many colons in address 2001:db8::7357:161
  • I've replaced the actual IPv6 address with one from the IPv6 doc range

This issue stems from the fmt.Sprintf method of deriving the address from the Target and Port fields of the GoSNMP structure. It would be more appropriate to use the net.JoinHostPort(host, port string) string function instead as this copes with different address families correctly.

Removing the Connect() call and setting (*GoSNMP).Conn as below works

// var c *gosnmp.GoSNMP
addr := net.JoinHostPort(c.Target, strconv.Itoa(int(c.Port)))
c.Conn, err = net.DialTimeout("udp", addr, c.Timeout)
if err != nil {
    log.Fatal(err)
}

SystemDate is displayed with special characters

When I try to get and display the system date using oid: 1.3.6.1.2.1.25.1.2.0, it is displayed with special characters (please see the attachment).

I am using the tip version of go.

$ go version
go version devel +e05b48e Thu Dec 10 08:04:07 2015 +0000 linux/amd64

When I get it through snmpget, I get the normal date:

HOST-RESOURCES-MIB::hrSystemDate.0 = STRING: 2015-12-10,21:39:49.0,+0:0

screen shot 2015-12-10 at 4 56 28 pm

Multithreading issue?

I am using the library with 15 simultaneous threads. Sometimes I get false values which mixup my rrd graphics. Any Idea how to solve this?

device someswitch fetched: 70 .1.3.6.1.2.1.31.1.1.1.10.10111 25027549639180
device someswitch fetched: 70 .1.3.6.1.2.1.31.1.1.1.10.10111 25027572865391
device someswitch fetched: 70 .1.3.6.1.2.1.31.1.1.1.10.10111 90438050323
device someswitch fetched: 70 .1.3.6.1.2.1.31.1.1.1.10.10111 25027622435917
device someswitch fetched: 70 .1.3.6.1.2.1.31.1.1.1.10.10111 25027639781760

Tcpdump -v looks like

someswitch.161 > monitorserver.55751:  { SNMPv2c C=bla { GetResponse(38) R=-1251415802  .1.3.6.1.2.1.31.1.1.1.10.10111=25027549639180.000000 } }
someswitch.161 > monitorserver.51930:  { SNMPv2c C=bla { GetResponse(38) R=1668428858  .1.3.6.1.2.1.31.1.1.1.10.10111=25027570860335.000000 } }
someswitch.161 > monitorserver.51578:  { SNMPv2c C=bla { GetResponse(38) R=-1144811484  .1.3.6.1.2.1.31.1.1.1.10.10111=25027572865391.000000 } }
someswitch.161 > monitorserver.60215:  { SNMPv2c C=bla { GetResponse(38) R=-1081929899  .1.3.6.1.2.1.31.1.1.1.10.10111=25027593968410.000000 } }
someswitch.161 > monitorserver.51400:  { SNMPv2c C=bla { GetResponse(38) R=-524292265  .1.3.6.1.2.1.31.1.1.1.10.10111=25027615759785.000000 } }
someswitch.161 > monitorserver.56794:  { SNMPv2c C=bla { GetResponse(38) R=-1679001924  .1.3.6.1.2.1.31.1.1.1.10.10111=25027622435917.000000 } }
someswitch.161 > monitorserver.51984:  { SNMPv2c C=bla { GetResponse(38) R=-1214439598  .1.3.6.1.2.1.31.1.1.1.10.10111=25027639781760.000000 } }

trap support

It would be really nice if gosnmp provides and trap support.

Any plans for SNMPv3 support?

Hey

I've been following gosnmp for a while and i'm considering implementing some things with it however i will need SNMPv3 in the long run. Do you have any plans for SNMPv3 and would you be willing to accept merge requests that implements it?

I'm well aware of the fact that it's still a product under development and that things might change over time. Just curious about what direction you'd like to take the project in?

Best regards,
Andreas Falk

Handling of counter 64 values fail with large numbers

Hi,

I'm running into a problem where gosnmp (and WapSNMP if that matters) fails to decode large counter 64 values.

Here's an example with logging enabled. I added a log line to parseInt64 to dump the input bytes:

Packet sanity verified, we got all the bytes ([62])
parseInt64: 01
Parsed version [1]
Parsed community [redacted]
getResponseLength: [43]
parseInt64: d4 6a 68 fa
requestID: [3563743482]
parseInt64: 00
errorStatus: [0]
parseInt64: 00
error-index: [0]
vblLength: [29]
OID: [.1.3.6.1.2.1.31.1.1.1.11.502]
[decodeValue: type is Counter64]
parseInt64: 00 ff ff ff ff ff 1e e5 3a
decodeValue: err is [integer too large]

9 bytes are passed into parseInt64: 00 ff ff ff ff ff 1e e5 3a, which causes it to immediately fail. snmp4j (and net-snmp) both successfully parse this value simply dropping the leading 0-octet.

Please see http://grepcode.com/file/repo1.maven.org/maven2/org.snmp4j/snmp4j/1.8.1/org/snmp4j/asn1/BER.java#BER.decodeUnsignedInt64%28org.snmp4j.asn1.BERInputStream%2Corg.snmp4j.asn1.BER.MutableByte%29 for how this is handled in snmp4j.

SNMPV3 usm traps do not initialize/update AuthoritativeEngineId/Boots/Time

Please correct me if I am wrong, but the AuthoritativeEngine Id, AuthoritativeEngineBoots, and AuthoritativeEngineTime parameters in the SNMPV3 USM are not initialized and maintained when sending traps. I believe this is an expectation of an SNMPV3 USM agent.

Also, byte for byte, how well do GoSNMP trap packets match those emitted from other libraries?

SNMP Set Integer is limited to 255 values.

Hi Sonia,

Your implementation for SnmpSET Integer is limited only to Integers below 255.
Code responsible for that error is in marshal.go line 314:
intBytes := []byte{byte(pdu.Value.(int))}

There is no checking how big Value is and does it fits in one byte.
Here is example of wrong behavior and why: http://play.golang.org/p/ReKLueuwHo
I will propose pull request with solution I already have

ip address with length 0

I've run into devices returning a 0 length ip addresses, mainly Lexmark printers (for example Lexmark CX310dn)

This line returns the following error in my program:

Error decoding value: got ipaddress len 0, expected 4 or 16

For the moment, I've been ignoring/skipping this error in my own program, but was wondering if there would be any drawbacks or objections to initialize an "empty" ip address (for example 0.0.0.0 or nil) and not return an error instead?

Any thoughts?

Atomic incrementers unnecessary

marshal.go (sendOneRequest) uses several atomic incrementers for tracking request ID and message ID. These are not necessary. Atomic incrementers are meant to protect simultaneous modification of a variable. However the design of the function is such that it can't be called multiple times in parallel anyway. Attempting to use it in parallel would result in multiple simultaneous requests, which would result in simultaneous reads on the socket. Thus each parallel instance of sendOneRequest could receive responses meant for another instance of sendOneRequest.

To simplify the code, and avoid the illusion that the function is parallel safe, they should be removed. Or the function should be redesigned so that it truly is parallel safe.

We should also put something in the documentation that indicates that it's not parallel safe.

Suggested License Text Change

I suggest we make a contributors.md file or something, and update the text at the top of the files to say "Copyright 2014 GoSNMP Authors" or something.

snmp connection Return Value Problems

In the connect function is performed by a connection:

x.Conn, err = net.DialTimeout("udp", addr, x.Timeout)
if err != nil {
return fmt.Errorf("Error establishing connection to host: %s\n", err.Error())
}

When using net.DialTimeout ( "udp", addr, x.Timeout) connection, if the ip address is unable to connect, does not return an error message. But returns nil

Counter64 decodeValue: err is integer too large

Hi,

Particularly large counter64 values are not being decoded:

OID: .1.3.6.1.4.1.2636.3.2.5.1.28.[cut]
decodeValue: value
0 46 09 00 90 60 1f c3 c2
8 80 dc b8 30 4b 06 3f 2b
decodeValue: type is Counter64
decodeValue: err is integer too large
decodeValue: value is

For the same oid (value pulled slightly later) snmpwalk displays:
Counter64: 10403350101715041544

bc -l
l(10403350101715041544)/l(2)
63.17368198476992770177
ie 2^63 + a bit extra

I tried using parseUint64 here https://github.com/soniah/gosnmp/blob/master/helper.go#L161 but later realised it still fails because BER encoded length is 9 bytes.

Could fix by using parseUint64 + amend parseUint64 so that either length <=8 or (length = 9 and bytes[0] == 0) ? Or is there a more appropriate way ?

Regards,
-Sam.

gosnmp.Connect() return not nil even with remote snmpd daemon stoped

Hi @soniah . I'm building some improvements in mi snmpcollector, I would like detect when snmp device is offline to try do periodic re-connections.

When doing the first connection it returns non nil value , but my snmpd daemon is stopped

https://github.com/toni-moreno/snmpcollector/blob/master/pkg/snmp.go#L172

After when trying to do a bulkwalk the client detects errors.

INFO[0000] First SNMP connection to host  hostsnmpv3b stablished  <--here first gosnmp.Connect()
INFO[0000] Filter not found for measurement:i linux_cpu 
INFO[0000] Loading Indexed values in : linux_ports      
FATA[0000] SNMP bulkwalk error Error reading from UDP: read udp 127.0.0.1:55412->127.0.0.1:161: read: connection refused 

Can you review if I'm doing something wrong ?

Thank you very much

Consideration of initial Read() buffer size

Following on from comment here:

3e6fc99

Auto scaling the initial buffer size based on the oid count is clever (marshal.go => dispatch() ). It's a compromise between memory usage vs possible network re-requests. For typical numeric values the current defaults will be fine but it may cause issues with OctetStrings?

For reference, both snmp4j and net-snmp defaults to ~64k buffers (e.g. max datagram size). Max OctetString in the RFC is 65535

I have a dozen or so different snmp devices in here. I'll do some scanning and see what pops up.

'tooBig' error caused by fixed OID limit is going unhandled

Bug report

Recently I have setup an InfluxDB server and I am using Telegraf to poll Cisco switches for SNMP traffic. On recent builds of Telegraf, I have seen quite a lot of the following error:

2016/05/17 16:36:32 SNMP Error for host 'XXXXXXX:161': Unable to decode packet: nil

I had also noticed that the series of some switches were simply not receiving metrics, where some switches had received some, sporadically. Most were fine.

I was sure the two were related and after searching in vain, I took a packet capture. I could then see that the switch was returning a 'tooBig' error. My SNMP terminology isn't great, but essentially Telegraf asked for 60 OIDs and the switch returned the error.

The shortest explanation of this error I could find was:

The size of the Response-PDU would be too large to transport.

The value which dictates the maximum number of OIDs in a request appears to be here:

const (
    // maxOids is the maximum number of oids allowed in a Get()
    maxOids = 60

    // Base OID for MIB-2 defined SNMP variables
    baseOid = ".1.3.6.1.2.1"

    // Java SNMP uses 50, snmp-net uses 10
    defaultMaxRepetitions = 50
)

https://github.com/soniah/gosnmp/blob/master/gosnmp.go

Proposal:

I would like to see this constant replaced with a variable in the GoSNMP struct which starts a few lines down from the snippet above.

Use case: [Why is this important (helps with prioritizing requests)]

This is useful because it means legacy or low power/capacity devices which support SNMP can be catered for. It's the client's responsibility to react to and deal with the 'tooBig' error and this way we can.

snmp.Get(m.snmpOids[i:end]) randomly crashes

Hi @soniah .

I'm having something strange in my gosnmp client with influxsnmp tool (https://github.com/toni-moreno/influxsnmp/blob/first_big_refactor)

when running a Cisco Switch scan with the influxsnmp tool ( cisco has aprox 500 ports) , this is the expected output:

#./influxsnmp -showConfig  

...
(a lot of debug loging)
...
...
SNMP host: CISCO_SWITCH_XXXX
=========================================
Host: A.B.C.D Port: 161 Version: 2c
----------------------------------------------
 Measuremet : cisco_cpu
 ----------------------------------------------
        *Metric[Cisco_CPU]      Name[usage]     OID:.1.3.6.1.4.1.9.9.109.1.1.1.1.8.1    (GAUGE)
 Measuremet : cisco_mem
 ----------------------------------------------
        *Metric[Cisco_memFree]  Name[free]      OID:.1.3.6.1.4.1.9.9.48.1.1.1.6.1       (GAUGE)
        *Metric[Cisco_memUsed]  Name[used]      OID:.1.3.6.1.4.1.9.9.48.1.1.1.5.1       (GAUGE)
 Measuremet : cisco_ports
 ----------------------------------------------
        *Metric[ifHCInOctets]   Name[In.bytes]  OID:.1.3.6.1.2.1.31.1.1.1.6     (COUNTER64)
        *Metric[ifHCOutOctets]  Name[Out.bytes] OID:.1.3.6.1.2.1.31.1.1.1.10    (COUNTER64)
        *Metric[ifHCInUcastPkts]        Name[In.packets]        OID:.1.3.6.1.2.1.31.1.1.1.7     (COUNTER64)
        *Metric[ifHCOutUcastPkts]       Name[Out.packets]       OID:.1.3.6.1.2.1.31.1.1.1.7     (COUNTER64)
 ---------------------------------------------------------
                Index[104 / Fa9/6]
                Index[194 / VLAN-434]
                Index[505 / VLAN-251]
                Index[85 / Gi2/37]
                Index[88 / Gi2/40]
  ...
...
...
(+500 ports)
...
...
                Index[220 / VLAN-529]
                Index[46 / Gi1/46]
                Index[55 / Gi2/7]

It always crashes when gosnmp.Logger is not set. and randomly ( sometimes yes and sometimes no) when gosnmp.Logger is set.

this is the output.

2016/04/11 17:44:04 OK measurement  cisco_ports SNMP RESULT OID .1.3.6.1.2.1.31.1.1.1.7.484 MetricFound 50889
2016/04/11 17:44:04 Rawdata: +0x41b4b0
2016/04/11 17:44:04 DEBUG GET SNMP DATA FROM 1860 to 1920
2016/04/11 17:44:04 selected OIDS [.1.3.6.1.2.1.31.1.1.1.10.376 .1.3.6.1.2.1.31.1.1.1.7.376 .1.3.6.1.2.1.31.1.1.1.7.376 .1.3.6.1.2.1.31.1.1.1.6.376 .1.3.6.1.2.1.31.1.1.1.7.113 .1.3.6.1.2.1.31.1.1.1.7.113 .1.3.6.1.2.1.31.1.1.1.6.113 .1.3.6.1.2.1.31.1.1.1.10.113 .1.3.6.1.2.1.31.1.1.1.7.59 .1.3.6.1.2.1.31.1.1.1.6.59 .1.3.6.1.2.1.31.1.1.1.10.59 .1.3.6.1.2.1.31.1.1.1.7.59 .1.3.6.1.2.1.31.1.1.1.6.146 .1.3.6.1.2.1.31.1.1.1.10.146 .1.3.6.1.2.1.31.1.1.1.7.146 .1.3.6.1.2.1.31.1.1.1.7.146 .1.3.6.1.2.1.31.1.1.1.6.507 .1.3.6.1.2.1.31.1.1.1.10.507 .1.3.6.1.2.1.31.1.1.1.7.507 .1.3.6.1.2.1.31.1.1.1.7.507 .1.3.6.1.2.1.31.1.1.1.6.187 .1.3.6.1.2.1.31.1.1.1.10.187 .1.3.6.1.2.1.31.1.1.1.7.187 .1.3.6.1.2.1.31.1.1.1.7.187 .1.3.6.1.2.1.31.1.1.1.10.399 .1.3.6.1.2.1.31.1.1.1.7.399 .1.3.6.1.2.1.31.1.1.1.7.399 .1.3.6.1.2.1.31.1.1.1.6.399 .1.3.6.1.2.1.31.1.1.1.6.142 .1.3.6.1.2.1.31.1.1.1.10.142 .1.3.6.1.2.1.31.1.1.1.7.142 .1.3.6.1.2.1.31.1.1.1.7.142 .1.3.6.1.2.1.31.1.1.1.7.215 .1.3.6.1.2.1.31.1.1.1.7.215 .1.3.6.1.2.1.31.1.1.1.6.215 .1.3.6.1.2.1.31.1.1.1.10.215 .1.3.6.1.2.1.31.1.1.1.7.112 .1.3.6.1.2.1.31.1.1.1.6.112 .1.3.6.1.2.1.31.1.1.1.10.112 .1.3.6.1.2.1.31.1.1.1.7.112 .1.3.6.1.2.1.31.1.1.1.10.139 .1.3.6.1.2.1.31.1.1.1.7.139 .1.3.6.1.2.1.31.1.1.1.7.139 .1.3.6.1.2.1.31.1.1.1.6.139 .1.3.6.1.2.1.31.1.1.1.7.111 .1.3.6.1.2.1.31.1.1.1.7.111 .1.3.6.1.2.1.31.1.1.1.6.111 .1.3.6.1.2.1.31.1.1.1.10.111 .1.3.6.1.2.1.31.1.1.1.7.486 .1.3.6.1.2.1.31.1.1.1.6.486 .1.3.6.1.2.1.31.1.1.1.10.486 .1.3.6.1.2.1.31.1.1.1.7.486 .1.3.6.1.2.1.31.1.1.1.10.394 .1.3.6.1.2.1.31.1.1.1.7.394 .1.3.6.1.2.1.31.1.1.1.7.394 .1.3.6.1.2.1.31.1.1.1.6.394 .1.3.6.1.2.1.31.1.1.1.6.338 .1.3.6.1.2.1.31.1.1.1.10.338 .1.3.6.1.2.1.31.1.1.1.7.338 .1.3.6.1.2.1.31.1.1.1.7.338]
SNMP (10.241.254.11) get error: Unable to decode packet: nil
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x415962]

goroutine 1 [running]:
main.(*InfluxMeasurement).GetSnmpData(0xc820014cd0, 0xc820162300, 0x1, 0x0, 0x0, 0x0)
        /root/grafana-lab/src/github.com/paulstuart/influxsnmp/snmpmetric.go:350 +0x1272
main.(*SnmpDeviceCfg).Init(0xc8201ac000, 0xc820156f55, 0x12)
        /root/grafana-lab/src/github.com/paulstuart/influxsnmp/snmpdevice.go:246 +0x2ce6
main.init.1()
        /root/grafana-lab/src/github.com/paulstuart/influxsnmp/main.go:158 +0x5fe
main.init()
        /root/grafana-lab/src/github.com/paulstuart/influxsnmp/web.go:282 +0x4f0

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        /usr/lib/golang/src/runtime/asm_amd64.s:1696 +0x1

You can see the crashing code here: ( https://github.com/toni-moreno/influxsnmp/blob/first_big_refactor/snmpmetric.go#L342 )

Can you help me to debug this panic please?

Possible performance improvement idea?

My use case involves SNMP polling many unique hosts, so a lot of time is spent by the code doing context switches to create sockets and such. My idea is as follows:

  • Create a pool of net.UDPConn's with bogus addresses (127.0.0.1?)
  • Change the Send method to use net.WriteToUDP which takes in an Addr
  • ????
  • Profit!

No idea if this is sensible, I'll craft up a but of example code or just give it a shot soon.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.