Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BulkWalk (not Walk) hangs permanently if malformed OID is anywhere in tree #408

Open
pphysch opened this issue Jun 16, 2022 · 4 comments
Open

Comments

@pphysch
Copy link

pphysch commented Jun 16, 2022

BulkWalk, but not Walk, hangs permanently if a malformed OID like the following is encountered (NET-SNMP v5.7.2 bulkwalk output shown below):

UCD-SNMP-MIB::versionIdent.0 = STRING: $Id$
UCD-SNMP-MIB::versionConfigureOptions.0 = STRING:  '--build=x86_64-redhat-linux-gnu' '--host=x86_64-redhat-linux-gnu' '--program-prefix=' '--disable-dependency-tracking' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib64' '--libexecdir=/usr/libexec' '--localstatedir=/var' '--sharedstatedir=/var/lib' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--disable-static' '--enable-shared' '--enable-as-needed' '--enable-blumenthal-aes' '--enable-embedded-perl' '--enable-ipv6' '--enable-local-smux' '--enable-mfd-rewrites' '--enable-ucd-snmp-compatibility' '--sysconfdir=/etc' '--with-cflags=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' '--with-ldflags=-Wl,-z,relro -Wl,-z,now -l
UCD-SNMP-MIB::versionClearCache.0 = INTEGER: 0

The middle OID overruns the 1 KiB buffer it has apparently been allocated, and is therefore probably not null-terminated and also has an unclosed '. I included the surrounding OIDs just in case they affect the result.

go.mod:

go 1.17

require github.com/gosnmp/gosnmp v1.35.0

Using the walkexample code with some extra debug:

package main

import (
        "flag"
        "fmt"
        "log"
        "os"
        "path/filepath"
        "time"

        "github.com/gosnmp/gosnmp"
)

func main() {
        flag.Usage = func() {
                fmt.Printf("Usage:\n")
                fmt.Printf("   %s [-community=<community>] host [oid]\n", filepath.Base(os.Args[0]))
                fmt.Printf("     host      - the host to walk/scan\n")
                fmt.Printf("     oid       - the MIB/Oid defining a subtree of values\n\n")
                flag.PrintDefaults()
        }

        var community string
        flag.StringVar(&community, "community", "public", "the community string for device")

        flag.Parse()

        if len(flag.Args()) < 1 {
                flag.Usage()
                os.Exit(1)
        }
        target := flag.Args()[0]
        var oid string
        if len(flag.Args()) > 1 {
                oid = flag.Args()[1]
        }

        gosnmp.Default.Target = target
        gosnmp.Default.Community = community
        gosnmp.Default.Timeout = time.Duration(10 * time.Second) // Timeout better suited to walking
        err := gosnmp.Default.Connect()
        if err != nil {
                fmt.Printf("Connect err: %v\n", err)
                os.Exit(1)
        }
        defer gosnmp.Default.Conn.Close()

        log.Println("Walking", oid)
        err = gosnmp.Default.BulkWalk(oid, printValue)
        if err != nil {
                fmt.Printf("Walk Error: %v\n", err)
                os.Exit(1)
        }
        log.Println("Walked", oid, "without error")
}

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("TYPE %d: %d\n", pdu.Type, gosnmp.ToBigInt(pdu.Value))
        }
        return nil
}

To reproduce

go run . myhost .1.3.6.1.4.1.2021.100

Expected behavior

All the OIDs and their values should be printed, OR an error should be returned.

Observed behavior

No OIDs nor values are printed, and the program hangs permanently.

@pphysch
Copy link
Author

pphysch commented Jun 16, 2022

This particular malformed OID value (1.3.6.1.4.1.2021.100.6.0) probably exists on any RedHat linux with NET-SNMP version 5.8 (net-snmp-5.8-22.el8.x86_64 on Rocky Linux 8 is the specific package I observed this with).

@istignedec
Copy link

Hello, I'm getting the same problem on my Cisco Nexus device using latest version of "gosnmp", but my OID doesn't seem to be malformed. BulkWalk function hangs on this OID with non-complicated value: SNMPv2-SMI::mib-2.47.1.1.1.1.2.5286 = STRING: "Linecard-1 Port-81"

Walk function runs without problems but it's much slower and it's not an option for me. Any plans about fixing this soon? Thanks

@MrSpock
Copy link

MrSpock commented Apr 3, 2024

I found solution by comparing pcap files from this library and snmpbulkwalk.
Simple fix - it looks like some SNMP devices (older, less mem ?) don't like high value of maxrepetitions.
Packet from this library with maxrepetions=50 never gets any response from devices I had so it's not like buffer issue.

I modified value of defaultMaxRepetitions in gosnmp.go 50->10 and suddenly BulkWalkAll works on all my problematic devices I had.

Fix proposal:
Please make defaultMaxRepetitions (line 39 in gosnmp.go) global (DefaultMaxRepetitions) to allow change its value and set its default value to 10. Performance difference can be seen only if you fetch hundreds it not thousands OIDS..

@SuperQ
Copy link
Contributor

SuperQ commented Apr 3, 2024

You don't need to adjust the default in the code, you can set it via MaxRepetitions in the GoSNMP struct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants