bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/snmp/mib/mib.go (about)

     1  // Package mib parses modules of the virtual management information store.
     2  package mib
     3  
     4  import (
     5  	"bytes"
     6  	"fmt"
     7  	"os/exec"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  
    12  	"bosun.org/snmp/asn1"
    13  )
    14  
    15  var mibDir = ""
    16  
    17  // Load registers an additional directory with MIB files. The standard
    18  // system MIBs are always pre-loaded.
    19  func Load(dir string) {
    20  	if mibDir == "" {
    21  		mibDir = dir
    22  	} else {
    23  		mibDir += ":" + dir
    24  	}
    25  }
    26  
    27  // Lookup looks up the given object prefix using the snmptranslate utility.
    28  func Lookup(prefix string) (asn1.ObjectIdentifier, error) {
    29  	cache.Lock()
    30  	if oid, ok := cache.lookup[prefix]; ok {
    31  		cache.Unlock()
    32  		return oid, nil
    33  	}
    34  	cache.Unlock()
    35  	if oid, err := parseOID(prefix); err == nil {
    36  		cache.Lock()
    37  		cache.lookup[prefix] = oid
    38  		cache.Unlock()
    39  		return oid, nil
    40  	}
    41  	cmd := exec.Command(
    42  		"snmptranslate",
    43  		"-Le",
    44  		"-M", "+"+mibDir,
    45  		"-m", "all",
    46  		"-On",
    47  		prefix,
    48  	)
    49  	stdout := new(bytes.Buffer)
    50  	stderr := new(bytes.Buffer)
    51  	cmd.Stdout = stdout
    52  	cmd.Stderr = stderr
    53  	if err := cmd.Run(); err != nil {
    54  		return nil, fmt.Errorf("snmp: Lookup(%q): %q: %s", prefix, cmd.Args, err)
    55  	}
    56  	if stderr.Len() != 0 {
    57  		return nil, fmt.Errorf("snmp: Lookup(%q): %q: %s", prefix, cmd.Args, stderr)
    58  	}
    59  	oid, err := parseOID(strings.TrimSpace(stdout.String()))
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	cache.Lock()
    64  	cache.lookup[prefix] = oid
    65  	cache.Unlock()
    66  	return oid, nil
    67  }
    68  
    69  func init() {
    70  	cache.lookup = make(map[string]asn1.ObjectIdentifier)
    71  }
    72  
    73  // cache avoids excessive use of snmptranslate.
    74  var cache struct {
    75  	lookup map[string]asn1.ObjectIdentifier
    76  	sync.Mutex
    77  }
    78  
    79  // parseOID parses the string-encoded OID, for example the
    80  // string "1.3.6.1.2.1.1.5.0" becomes sysName.0
    81  func parseOID(s string) (oid asn1.ObjectIdentifier, err error) {
    82  	if s[0] == '.' {
    83  		s = s[1:]
    84  	}
    85  	var n int
    86  	for _, elem := range strings.Split(s, ".") {
    87  		n, err = strconv.Atoi(elem)
    88  		if err != nil {
    89  			return
    90  		}
    91  		oid = append(oid, n)
    92  	}
    93  	return
    94  }