From 22df9213ea927ac3df38bba6b07b018b414fd72b Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 16:28:52 +0100 Subject: [PATCH 01/10] removed old snmp implementation, refactoring --- Gopkg.lock | 7 +- Gopkg.toml | 4 - alarm/alarm_collector.go | 36 + alarm/alarm_counter.go | 6 + alarm/datasource.go | 5 + bgp/bgp_collector.go | 27 + bgp/bgp_session.go | 5 + bgp/datasource.go | 5 + convert.go | 9 - interfaces/datasource.go | 5 + interfaces/interface_collector.go | 54 + interfaces/interface_stats.go | 10 + junos_collector.go | 260 +-- main.go | 18 +- vendor/github.com/soniah/gosnmp/.gitignore | 41 - vendor/github.com/soniah/gosnmp/.travis.yml | 26 - vendor/github.com/soniah/gosnmp/AUTHORS.md | 19 - vendor/github.com/soniah/gosnmp/LICENSE | 57 - vendor/github.com/soniah/gosnmp/README.md | 260 --- .../soniah/gosnmp/examples/example.go | 46 - .../soniah/gosnmp/examples/example2.go | 67 - .../soniah/gosnmp/examples/example3.go | 59 - .../soniah/gosnmp/examples/trapserver.go | 56 - .../soniah/gosnmp/examples/walkexample.go | 70 - .../soniah/gosnmp/generic_e2e_test.go | 396 ----- vendor/github.com/soniah/gosnmp/gosnmp.go | 450 ------ .../soniah/gosnmp/gosnmp_api_test.go | 99 -- vendor/github.com/soniah/gosnmp/helper.go | 729 --------- .../github.com/soniah/gosnmp/helper_test.go | 78 - vendor/github.com/soniah/gosnmp/marshal.go | 872 ---------- .../github.com/soniah/gosnmp/marshal_test.go | 1402 ----------------- vendor/github.com/soniah/gosnmp/misc_test.go | 152 -- .../github.com/soniah/gosnmp/snmp-notes.txt | 71 - vendor/github.com/soniah/gosnmp/snmp_users.sh | 19 - vendor/github.com/soniah/gosnmp/trap.go | 185 --- vendor/github.com/soniah/gosnmp/trap.md | 100 -- vendor/github.com/soniah/gosnmp/trap_test.go | 181 --- vendor/github.com/soniah/gosnmp/v3.go | 399 ----- vendor/github.com/soniah/gosnmp/v3_usm.go | 655 -------- vendor/github.com/soniah/gosnmp/walk.go | 112 -- 40 files changed, 182 insertions(+), 6870 deletions(-) create mode 100644 alarm/alarm_collector.go create mode 100644 alarm/alarm_counter.go create mode 100644 alarm/datasource.go create mode 100644 bgp/bgp_collector.go create mode 100644 bgp/bgp_session.go create mode 100644 bgp/datasource.go delete mode 100644 convert.go create mode 100644 interfaces/datasource.go create mode 100644 interfaces/interface_collector.go create mode 100644 interfaces/interface_stats.go delete mode 100644 vendor/github.com/soniah/gosnmp/.gitignore delete mode 100644 vendor/github.com/soniah/gosnmp/.travis.yml delete mode 100644 vendor/github.com/soniah/gosnmp/AUTHORS.md delete mode 100644 vendor/github.com/soniah/gosnmp/LICENSE delete mode 100644 vendor/github.com/soniah/gosnmp/README.md delete mode 100644 vendor/github.com/soniah/gosnmp/examples/example.go delete mode 100644 vendor/github.com/soniah/gosnmp/examples/example2.go delete mode 100644 vendor/github.com/soniah/gosnmp/examples/example3.go delete mode 100644 vendor/github.com/soniah/gosnmp/examples/trapserver.go delete mode 100644 vendor/github.com/soniah/gosnmp/examples/walkexample.go delete mode 100644 vendor/github.com/soniah/gosnmp/generic_e2e_test.go delete mode 100644 vendor/github.com/soniah/gosnmp/gosnmp.go delete mode 100644 vendor/github.com/soniah/gosnmp/gosnmp_api_test.go delete mode 100644 vendor/github.com/soniah/gosnmp/helper.go delete mode 100644 vendor/github.com/soniah/gosnmp/helper_test.go delete mode 100644 vendor/github.com/soniah/gosnmp/marshal.go delete mode 100644 vendor/github.com/soniah/gosnmp/marshal_test.go delete mode 100644 vendor/github.com/soniah/gosnmp/misc_test.go delete mode 100644 vendor/github.com/soniah/gosnmp/snmp-notes.txt delete mode 100755 vendor/github.com/soniah/gosnmp/snmp_users.sh delete mode 100644 vendor/github.com/soniah/gosnmp/trap.go delete mode 100644 vendor/github.com/soniah/gosnmp/trap.md delete mode 100644 vendor/github.com/soniah/gosnmp/trap_test.go delete mode 100644 vendor/github.com/soniah/gosnmp/v3.go delete mode 100644 vendor/github.com/soniah/gosnmp/v3_usm.go delete mode 100644 vendor/github.com/soniah/gosnmp/walk.go diff --git a/Gopkg.lock b/Gopkg.lock index 8d45fc55..bca72969 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -61,11 +61,6 @@ revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e" version = "v1.0.3" -[[projects]] - name = "github.com/soniah/gosnmp" - packages = ["."] - revision = "55acec044875c95a3fb3fbc37160cb766501939f" - [[projects]] branch = "master" name = "golang.org/x/crypto" @@ -87,6 +82,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "2f8d380dafeae7bb65e081264c19816ad9596b49ba384a19c0364d258af05d43" + inputs-digest = "a6cebbe049ed9f30fbcbc092e916b2f4c9deda42c90b933dbe9c4872524d3880" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index cd4d2854..f0843273 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,3 @@ [[constraint]] branch = "master" name = "github.com/prometheus/common" - -[[constraint]] - name = "github.com/soniah/gosnmp" - revision = "55acec044875c95a3fb3fbc37160cb766501939f" diff --git a/alarm/alarm_collector.go b/alarm/alarm_collector.go new file mode 100644 index 00000000..9c2c3102 --- /dev/null +++ b/alarm/alarm_collector.go @@ -0,0 +1,36 @@ +package alarm + +import "github.com/prometheus/client_golang/prometheus" + +const prefix = "junos_alarms_" + +var ( + alarmsYellowCount *prometheus.Desc + alarmsRedCount *prometheus.Desc +) + +func init() { + l := []string{"target"} + alarmsYellowCount = prometheus.NewDesc(prefix+"yellow_count", "Number of yollow alarms (not silenced)", l, nil) + alarmsRedCount = prometheus.NewDesc(prefix+"red_count", "Number of red alarms (not silenced)", l, nil) +} + +type AlarmCollector struct { +} + +func (*AlarmCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- alarmsYellowCount + ch <- alarmsRedCount +} + +func (c *AlarmCollector) Collect(datasource AlarmDatasource, ch chan<- prometheus.Metric, labelValues []string) error { + counter, err := datasource.AlarmCounter() + if err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric(alarmsYellowCount, prometheus.GaugeValue, counter.YellowCount, labelValues...) + ch <- prometheus.MustNewConstMetric(alarmsRedCount, prometheus.GaugeValue, counter.RedCount, labelValues...) + + return nil +} diff --git a/alarm/alarm_counter.go b/alarm/alarm_counter.go new file mode 100644 index 00000000..2e8d8c28 --- /dev/null +++ b/alarm/alarm_counter.go @@ -0,0 +1,6 @@ +package alarm + +type AlarmCounter struct { + YellowCount float64 + RedCount float64 +} diff --git a/alarm/datasource.go b/alarm/datasource.go new file mode 100644 index 00000000..5d83d087 --- /dev/null +++ b/alarm/datasource.go @@ -0,0 +1,5 @@ +package alarm + +type AlarmDatasource interface { + AlarmCounter() (*AlarmCounter, error) +} diff --git a/bgp/bgp_collector.go b/bgp/bgp_collector.go new file mode 100644 index 00000000..8e75aded --- /dev/null +++ b/bgp/bgp_collector.go @@ -0,0 +1,27 @@ +package bgp + +import "github.com/prometheus/client_golang/prometheus" + +type BgpCollector struct { +} + +func (*BgpCollector) Describe(ch chan<- *prometheus.Desc) { + +} + +func (c *BgpCollector) Collect(datasource BgpDatasource, ch chan<- prometheus.Metric) error { + sessions, err := datasource.BgpSessions() + if err != nil { + return err + } + + for _, s := range sessions { + c.collectForSession(s, ch) + } + + return nil +} + +func (*BgpCollector) collectForSession(s *BgpSession, ch chan<- prometheus.Metric) { + +} diff --git a/bgp/bgp_session.go b/bgp/bgp_session.go new file mode 100644 index 00000000..f19c61f2 --- /dev/null +++ b/bgp/bgp_session.go @@ -0,0 +1,5 @@ +package bgp + +type BgpSession struct { + +} diff --git a/bgp/datasource.go b/bgp/datasource.go new file mode 100644 index 00000000..598203e8 --- /dev/null +++ b/bgp/datasource.go @@ -0,0 +1,5 @@ +package bgp + +type BgpDatasource interface { + BgpSessions() ([]*BgpSession, error) +} diff --git a/convert.go b/convert.go deleted file mode 100644 index 90e5aa3a..00000000 --- a/convert.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func noConvert(v float64) float64 { - return float64(v) -} - -func bitsToBytes(v float64) float64 { - return float64(v * 8) -} diff --git a/interfaces/datasource.go b/interfaces/datasource.go new file mode 100644 index 00000000..812e63e7 --- /dev/null +++ b/interfaces/datasource.go @@ -0,0 +1,5 @@ +package interfaces + +type InterfaceStatsDatasource interface { + InterfaceStats() ([]*InterfaceStats, error) +} diff --git a/interfaces/interface_collector.go b/interfaces/interface_collector.go new file mode 100644 index 00000000..0867ac89 --- /dev/null +++ b/interfaces/interface_collector.go @@ -0,0 +1,54 @@ +package interfaces + +import "github.com/prometheus/client_golang/prometheus" + +const prefix = "junos_interface_" + +var ( + receiveBytesDesc *prometheus.Desc + receiveErrorsDesc *prometheus.Desc + receiveDropsDesc *prometheus.Desc + transmitBytesDesc *prometheus.Desc + transmitErrorsDesc *prometheus.Desc + transmitDropsDesc *prometheus.Desc +) + +func init() { + l := []string{"name", "description", "mac", "target"} + receiveBytesDesc = prometheus.NewDesc(prefix+"interface_receive_bytes", "Received data in bytes", l, nil) + receiveErrorsDesc = prometheus.NewDesc(prefix+"interface_receive_errors", "Number of errors caused by incoming packets", l, nil) + receiveDropsDesc = prometheus.NewDesc(prefix+"interface_receive_drops", "Number of dropped incoming packets", l, nil) + transmitBytesDesc = prometheus.NewDesc(prefix+"interface_transmit_bytes", "Transmitted data in bytes", l, nil) + transmitErrorsDesc = prometheus.NewDesc(prefix+"interface_transmit_errors", "Number of errors caused by outgoing packets", l, nil) + transmitDropsDesc = prometheus.NewDesc(prefix+"interface_transmit_drops", "Number of dropped outgoing packets", l, nil) +} + +type InterfaceCollector struct { + +} + +func (*InterfaceCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- receiveBytesDesc + ch <- receiveErrorsDesc + ch <- receiveDropsDesc + ch <- transmitBytesDesc + ch <- transmitDropsDesc + ch <- transmitErrorsDesc +} + +func (c *InterfaceCollector) Collect(datasource InterfaceStatsDatasource, ch chan<- prometheus.Metric) error { + stats, err := datasource.InterfaceStats() + if err != nil { + return err + } + + for _, s := range stats { + c.collectForInterface(s, ch) + } + + return nil +} + +func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prometheus.Metric) { + +} \ No newline at end of file diff --git a/interfaces/interface_stats.go b/interfaces/interface_stats.go new file mode 100644 index 00000000..5352e142 --- /dev/null +++ b/interfaces/interface_stats.go @@ -0,0 +1,10 @@ +package interfaces + +type InterfaceStats struct { + ReceiveBytes float64 + ReceiveErrors float64 + ReceiveDrops float64 + TransmitBytes float64 + TransmitErrors float64 + TransmitDrops float64 +} diff --git a/junos_collector.go b/junos_collector.go index 323e9dd2..b652c7f1 100644 --- a/junos_collector.go +++ b/junos_collector.go @@ -2,272 +2,58 @@ package main import ( "strings" - - "sync" - "time" + "github.com/czerwonk/junos_exporter/alarm" + "github.com/czerwonk/junos_exporter/bgp" + "github.com/czerwonk/junos_exporter/interfaces" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/log" - "github.com/soniah/gosnmp" ) -type ValueConverter func(float64) float64 - -const ( - numberOfInterfaceLabels = 3 - prefix = "junos_" -) +const prefix = "junos_" var ( scrapeDurationDesc *prometheus.Desc upDesc *prometheus.Desc - receiveBytesDesc *prometheus.Desc - receiveErrorsDesc *prometheus.Desc - receiveDropsDesc *prometheus.Desc - transmitBytesDesc *prometheus.Desc - transmitErrorsDesc *prometheus.Desc - transmitDropsDesc *prometheus.Desc - alarmsYellowCount *prometheus.Desc - alarmsRedCount *prometheus.Desc ) func init() { upDesc = prometheus.NewDesc(prefix+"up", "Scrape of target was successful", []string{"target"}, nil) scrapeDurationDesc = prometheus.NewDesc(prefix+"collector_duration_seconds", "Duration of a collector scrape for one target", []string{"target"}, nil) - alarmsYellowCount = prometheus.NewDesc(prefix+"alarms_yellow_count", "Number of yollow alarms (not silenced)", []string{"target"}, nil) - alarmsRedCount = prometheus.NewDesc(prefix+"alarms_red_count", "Number of red alarms (not silenced)", []string{"target"}, nil) - - l := []string{"name", "description", "mac", "target"} - receiveBytesDesc = prometheus.NewDesc(prefix+"interface_receive_bytes", "Received data in bytes", l, nil) - receiveErrorsDesc = prometheus.NewDesc(prefix+"interface_receive_errors", "Number of errors caused by incoming packets", l, nil) - receiveDropsDesc = prometheus.NewDesc(prefix+"interface_receive_drops", "Number of dropped incoming packets", l, nil) - transmitBytesDesc = prometheus.NewDesc(prefix+"interface_transmit_bytes", "Transmitted data in bytes", l, nil) - transmitErrorsDesc = prometheus.NewDesc(prefix+"interface_transmit_errors", "Number of errors caused by outgoing packets", l, nil) - transmitDropsDesc = prometheus.NewDesc(prefix+"interface_transmit_drops", "Number of dropped outgoing packets", l, nil) } type JunosCollector struct { - targets []string - community string -} - -type scope struct { - interfaces []string - interfaceLabels map[string][]string - snmp *gosnmp.GoSNMP - ch chan<- prometheus.Metric - err error -} - -func NewJunosCollector(targets []string, community string) *JunosCollector { - return &JunosCollector{targets: targets, community: community} + interfaceCollector *interfaces.InterfaceCollector + alarmCollector *alarm.AlarmCollector + bgpCollector *bgp.BgpCollector } func (c *JunosCollector) Describe(ch chan<- *prometheus.Desc) { ch <- upDesc ch <- scrapeDurationDesc - ch <- alarmsYellowCount - ch <- alarmsRedCount - ch <- receiveBytesDesc - ch <- receiveErrorsDesc - ch <- receiveDropsDesc - ch <- transmitBytesDesc - ch <- transmitDropsDesc - ch <- transmitErrorsDesc -} - -func (c *JunosCollector) Collect(ch chan<- prometheus.Metric) { - wg := &sync.WaitGroup{} - wg.Add(len(c.targets)) - - for _, t := range c.targets { - go c.collectForTarget(t, ch, wg) - } - - wg.Wait() -} - -func (c *JunosCollector) collectForTarget(target string, ch chan<- prometheus.Metric, wg *sync.WaitGroup) { - defer wg.Done() - - s := &scope{interfaceLabels: make(map[string][]string), snmp: &gosnmp.GoSNMP{}, ch: ch} - s.snmp.Port = 161 - s.snmp.Timeout = time.Duration(2) * time.Second - s.snmp.Target = target - s.snmp.Community = c.community - s.snmp.Version = 1 - s.snmp.MaxOids = 255 - - start := time.Now() - defer func() { ch <- c.durationMetric(time.Since(start), s) }() - c.collectMetrics(s) - if s.err != nil { - log.Error(s.err) - - ch <- c.upMetric(0, s) - return - } - - ch <- c.upMetric(1, s) -} - -func (c *JunosCollector) upMetric(value float64, s *scope) prometheus.Metric { - m, _ := prometheus.NewConstMetric(upDesc, prometheus.GaugeValue, value, s.snmp.Target) - return m + c.interfaceCollector.Describe(ch) + c.alarmCollector.Describe(ch) + c.bgpCollector.Describe(ch) } -func (c *JunosCollector) durationMetric(t time.Duration, s *scope) prometheus.Metric { - m, _ := prometheus.NewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, float64(t*time.Second), s.snmp.Target) - return m -} - -func (c *JunosCollector) collectMetrics(s *scope) { - err := s.snmp.Connect() - if err != nil { - s.err = err - return - } - - c.fetchMetricForOid(".1.3.6.1.4.1.2636.3.4.2.2.2.0", alarmsYellowCount, noConvert, s) - c.fetchMetricForOid(".1.3.6.1.4.1.2636.3.4.2.3.2.0", alarmsRedCount, noConvert, s) - - err = c.fetchInterfaces(s) - if err != nil { - s.err = err - return - } - - c.fetchInterfaceLabelFromOid(".1.3.6.1.2.1.31.1.1.1.1", 0, s) - c.fetchInterfaceLabelFromOid(".1.3.6.1.2.1.31.1.1.1.18", 1, s) - c.fetchInterfaceMetricFromOid(".1.3.6.1.2.1.31.1.1.1.6", receiveBytesDesc, bitsToBytes, s) - c.fetchInterfaceMetricFromOid(".1.3.6.1.2.1.31.1.1.1.10", transmitBytesDesc, bitsToBytes, s) - c.fetchInterfaceMetricFromOid(".1.3.6.1.2.1.2.2.1.13", receiveDropsDesc, noConvert, s) - c.fetchInterfaceMetricFromOid(".1.3.6.1.2.1.2.2.1.14", receiveErrorsDesc, noConvert, s) - c.fetchInterfaceMetricFromOid(".1.3.6.1.2.1.2.2.1.19", transmitDropsDesc, noConvert, s) - c.fetchInterfaceMetricFromOid(".1.3.6.1.2.1.2.2.1.20", transmitErrorsDesc, noConvert, s) -} - -func (c *JunosCollector) fetchInterfaces(s *scope) error { - s.interfaces = make([]string, 0) - res, err := s.snmp.BulkWalkAll(".1.3.6.1.2.1.2.2.1.1") - if err != nil { - return err - } - - for _, v := range res { - idx := c.getId(v.Name) - s.interfaces = append(s.interfaces, idx) - s.interfaceLabels[idx] = make([]string, numberOfInterfaceLabels) - } - - return nil -} - -func (c *JunosCollector) fetchMetricForOid(oid string, desc *prometheus.Desc, converter ValueConverter, s *scope) { - h := func(p gosnmp.SnmpPDU) error { - return c.handlePduAsMetric(desc, p, converter, s, s.snmp.Target) - } - - oids := []string{oid} - c.fetchForOids(oids, h, s) -} - -func (c *JunosCollector) fetchForOids(oids []string, handler func(gosnmp.SnmpPDU) error, s *scope) { - res, err := s.snmp.Get(oids) - if err != nil { - s.err = err - return - } - - if res.Variables == nil { - log.Errorf("No result for OIDs: %s", oids) - return - } - - for _, v := range res.Variables { - if v.Value != nil { - err := handler(v) - if err != nil { - return - } - } - } -} - -func (c *JunosCollector) fetchInterfaceLabelFromOid(oid string, index int, s *scope) { - h := func(p gosnmp.SnmpPDU) error { - c.handlePduAsLabel(index, p, s) - return nil - } - - c.fetchForInterfaces(oid, h, s) -} - -func (c *JunosCollector) fetchInterfaceMetricFromOid(oid string, desc *prometheus.Desc, converter ValueConverter, s *scope) { - h := func(p gosnmp.SnmpPDU) error { - return c.handlePduAsInterfaceMetric(desc, p, converter, s) - } - - c.fetchForInterfaces(oid, h, s) -} - -func (c *JunosCollector) fetchForInterfaces(oid string, handler func(gosnmp.SnmpPDU) error, s *scope) { - if s.err != nil { - return - } - - oids := c.getOidsForInterfaces(oid, s) - c.fetchForOids(oids, handler, s) -} - -func (c *JunosCollector) getOidsForInterfaces(oid string, s *scope) []string { - oids := make([]string, len(s.interfaceLabels)) - i := 0 - for _, x := range s.interfaces { - oids[i] = oid + "." + x - i++ +func (c *JunosCollector) Collect(ch chan<- prometheus.Metric) { + for _, h := range strings.Split(*sshHosts, ",") { + go c.collectForHost(strings.Trim(h, " "), ch) } - - return oids -} - -func (c *JunosCollector) handlePduAsLabel(index int, p gosnmp.SnmpPDU, s *scope) { - id := c.getId(p.Name) - - b := p.Value.([]byte) - s.interfaceLabels[id][index] = string(b) } -func (c *JunosCollector) handlePduAsInterfaceMetric(desc *prometheus.Desc, pdu gosnmp.SnmpPDU, converter ValueConverter, s *scope) error { - id := c.getId(pdu.Name) - l := append(s.interfaceLabels[id], s.snmp.Target) - - return c.handlePduAsMetric(desc, pdu, converter, s, l...) -} - -func (c *JunosCollector) handlePduAsMetric(desc *prometheus.Desc, pdu gosnmp.SnmpPDU, converter ValueConverter, s *scope, l ...string) error { - var v float64 = 0 - switch pdu.Value.(type) { - case uint: - v = float64(pdu.Value.(uint)) - case uint64: - v = float64(pdu.Value.(uint64)) - } +func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric) { + l := []string{host} - m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, converter(v), l...) + t := time.Now() + defer func() { + ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, time.Since(t).Seconds(), l...) + }() - if err != nil { - return err - } - - s.ch <- m - - return nil -} + ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1, l...) -func (c *JunosCollector) getId(oid string) string { - t := strings.Split(oid, ".") - return t[len(t)-1] + //c.interfaceCollector.Collect() + //c.alarmCollector.Collect() + //c.bgpCollector.Collect() } diff --git a/main.go b/main.go index 8bf33101..4b67600c 100644 --- a/main.go +++ b/main.go @@ -6,24 +6,20 @@ import ( "net/http" "os" - "strings" - - "sync" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/log" ) -const version string = "0.3.0" +const version string = "0.4.0" var ( showVersion = flag.Bool("version", false, "Print version information.") listenAddress = flag.String("web.listen-address", ":9326", "Address on which to expose metrics and web interface.") metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") - snmpTargets = flag.String("snmp.targets", "127.0.0.1", "Addresses or hostnames of switches or routers (comma separated)") - snmpCommunity = flag.String("snmp.community", "default", "Community allowed to access SNMP") - mutex = &sync.Mutex{} + sshHosts = flag.String("ssh.targets", "", "Hosts to scrape") + sshUsername = flag.String("ssh.user", "junos_exporter", "Username to use when connecting to junos devices using ssh") + sshKeyFile = flag.String("ssh.key_file", "junos_exporter", "Public key file to use when connecting to junos devices using ssh") ) func init() { @@ -72,12 +68,8 @@ func startServer() { } func handleMetricsRequest(w http.ResponseWriter, r *http.Request) { - mutex.Lock() - defer mutex.Unlock() - reg := prometheus.NewRegistry() - targets := strings.Split(*snmpTargets, ",") - reg.MustRegister(NewJunosCollector(targets, *snmpCommunity)) + reg.MustRegister(&JunosCollector{}) promhttp.HandlerFor(reg, promhttp.HandlerOpts{ ErrorLog: log.NewErrorLogger(), diff --git a/vendor/github.com/soniah/gosnmp/.gitignore b/vendor/github.com/soniah/gosnmp/.gitignore deleted file mode 100644 index 1195fd62..00000000 --- a/vendor/github.com/soniah/gosnmp/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe - -# Editor Files -.*.sw* -*.orig - -# Mac OS X crap -.DS_Store# On branch master - -# Verax testing symlinks -device - -# test coverage outputs -coverage.json -gosnmp.html - -# profiling outputs -cpu.out -mem.out -gosnmp.test diff --git a/vendor/github.com/soniah/gosnmp/.travis.yml b/vendor/github.com/soniah/gosnmp/.travis.yml deleted file mode 100644 index 0e50b6cf..00000000 --- a/vendor/github.com/soniah/gosnmp/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: go - -go: -- 1.2 -- 1.3 -- 1.4 -- 1.5 -- 1.6 -- 1.7 - -env: - global: - - GOSNMP_TARGET=127.0.0.1 - - GOSNMP_PORT=161 - -before_install: - - sudo apt-get update -qq - - sudo apt-get install snmpd - -install: - - go get github.com/soniah/gosnmp - - sudo ./snmp_users.sh - - sudo /etc/init.d/snmpd restart - -script: - - go test diff --git a/vendor/github.com/soniah/gosnmp/AUTHORS.md b/vendor/github.com/soniah/gosnmp/AUTHORS.md deleted file mode 100644 index 08909c1a..00000000 --- a/vendor/github.com/soniah/gosnmp/AUTHORS.md +++ /dev/null @@ -1,19 +0,0 @@ -# GoSNMP authors - -* Jon Auer (@jda) -* Chris Dance (@codedance) -* Jacob Dubinsky (@jdubinsky) -* Eduardo Ferro (@eferro) -* Mattias Folke (@msfe) -* Geoff Garside (@geoffgarside) -* Miroslav Genov (@mgenov) -* Jaime Gil de Sagredo Luna (@jaimegildesagredo) -* Sonia Hamilton (@soniah) -* Marcin Jurczuk (@mrspock) -* Andreas Louca (@alouca) -* Nathan Owens (@virtuallynathan) -* Whitham Reeve (@wdreeveii) -* Benjamin Thomas (@benjamin-thomas) -* Ross Wilson (@schotlandzegtja) - -In alphabetical order of surname. In vim: highlight, then `!sort -k3`. diff --git a/vendor/github.com/soniah/gosnmp/LICENSE b/vendor/github.com/soniah/gosnmp/LICENSE deleted file mode 100644 index bc31e68e..00000000 --- a/vendor/github.com/soniah/gosnmp/LICENSE +++ /dev/null @@ -1,57 +0,0 @@ -Copyright 2012 Andreas Louca and Jon Auer, 2013 Sonia Hamilton. All -rights reserved. Use of this source code is governed by a BSD-style -license that can be found in the LICENSE file. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Parts of the gosnmp code are from GoLang ASN.1 Library -(as marked in the source code). -For those part of code the following license applies: - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/soniah/gosnmp/README.md b/vendor/github.com/soniah/gosnmp/README.md deleted file mode 100644 index 1432e99e..00000000 --- a/vendor/github.com/soniah/gosnmp/README.md +++ /dev/null @@ -1,260 +0,0 @@ -gosnmp -====== -[![Build Status](https://travis-ci.org/soniah/gosnmp.svg?branch=master)](https://travis-ci.org/soniah/gosnmp) -[![GoDoc](https://godoc.org/github.com/soniah/gosnmp?status.png)](http://godoc.org/github.com/soniah/gosnmp) -https://github.com/soniah/gosnmp - -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 __SNMPv2c__ or __SNMPv3__. - -About ------ - -**soniah/gosnmp** is based on **alouca/gosnmp** - many thanks to Andreas -Louca for starting the project, other contributors (AUTHORS.md) and -these project collaborators: - -* Chris Dance ([@codedance](https://github.com/codedance/)) -* Nathan Owens ([@virtuallynathan](https://github.com/virtuallynathan/)) -* Whitham Reeve ([@wdreeveii](https://github.com/wdreeveii/)) - -Sonia Hamilton, sonia@snowfrog.net, http://www.snowfrog.net. - -Overview --------- - -GoSNMP has the following SNMP functions: - -* **Get** (single or multiple OIDs) -* **GetNext** -* **GetBulk** -* **Walk** - retrieves a subtree of values using GETNEXT. -* **BulkWalk** - retrieves a subtree of values using GETBULK. -* **Set** - supports Integers and OctetStrings -* **SendTrap** - send 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 - -**soniah/gosnmp** has diverged _significantly_ 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.Logger` interface; otherwise - debugging will be discarded (/dev/null). - -```go -type Logger interface { - Print(v ...interface{}) - Printf(format string, v ...interface{}) -} -``` - -GoSNMP is still under development, therefore API's may change and bugs -will be squashed. Test Driven Development is used - you can help by -sending packet captures (see Packet Captures below). There may be more -than one branch on github. **master** is safe to pull from, other -branches unsafe as history may be rewritten. - -Installation ------------- - -Install via **go get**: - -```shell -go get github.com/soniah/gosnmp -``` - -Documentation -------------- - -See http://godoc.org/github.com/soniah/gosnmp or your local go doc -server for full documentation, as well as the examples. - -```shell -cd $GOPATH -godoc -http=:6060 & -$preferred_browser http://localhost:6060/pkg & -``` - -Usage ------ - -Here is code from **examples/example.go**, demonstrating how to use GoSNMP: - -```go -// 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): - -```shell -% 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 is 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 - -Bugs ----- - -Rane's document [SNMP: Simple? Network Management -Protocol](http://www.rane.com/note161.html) was useful for me when -learning the SNMP protocol. - -Please create an [issue](https://github.com/soniah/gosnmp/issues) 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: - -* 0x02 Integer -* 0x04 OctetString -* 0x06 ObjectIdentifier -* 0x40 IPAddress (IPv4 & IPv6) -* 0x41 Counter32 -* 0x42 Gauge32 -* 0x43 TimeTicks -* 0x46 Counter64 -* 0x47 Uinteger32 -* 0x80 NoSuchObject -* 0x81 NoSuchInstance -* 0x82 EndOfMibView - -The following (less common) BER types haven't been implemented, as I ran out of -time or haven't been able to find example devices to query: - -* 0x00 EndOfContents -* 0x01 Boolean -* 0x03 BitString -* 0x07 ObjectDescription -* 0x44 Opaque -* 0x45 NsapAddress - -Packet Captures ---------------- - -Create your packet captures in the following way: - -Expected output, obtained via an **snmp** command. For example: - -```shell -% 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: - -```shell -sudo tcpdump -s 0 -i eth0 -w foo.pcap host 203.50.251.17 and port 161 -``` - -Running the Tests ------------------ - -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). -To use, set the environment variables `GOSNMP_TARGET` & `GOSNMP_PORT`, for -example: - -```shell -export GOSNMP_TARGET=1.2.3.4 -export GOSNMP_PORT=161 -``` - -To profile cpu usage: - -```shell -go test -cpuprofile cpu.out -go test -c -go tool pprof gosnmp.test cpu.out -``` - -To profile memory usage: - -```shell -go test -memprofile mem.out -go test -c -go tool pprof gosnmp.test mem.out -``` - -To check test coverage: - -```shell -go get github.com/axw/gocov/gocov -go get github.com/matm/gocov-html -gocov test github.com/soniah/gosnmp | gocov-html > gosnmp.html && firefox gosnmp.html & -``` - -License -------- - -Some parts of the code are borrowed by 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-2016 the GoSNMP Authors - see -AUTHORS.md for a list of authors. diff --git a/vendor/github.com/soniah/gosnmp/examples/example.go b/vendor/github.com/soniah/gosnmp/examples/example.go deleted file mode 100644 index 24131ef5..00000000 --- a/vendor/github.com/soniah/gosnmp/examples/example.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2012-2014 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package main - -import ( - "fmt" - "log" - - g "github.com/soniah/gosnmp" -) - -func main() { - - // 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: - fmt.Printf("string: %s\n", string(variable.Value.([]byte))) - 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)) - } - } -} diff --git a/vendor/github.com/soniah/gosnmp/examples/example2.go b/vendor/github.com/soniah/gosnmp/examples/example2.go deleted file mode 100644 index e61cdd02..00000000 --- a/vendor/github.com/soniah/gosnmp/examples/example2.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2012-2014 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package main - -import ( - "fmt" - "log" - "os" - "strconv" - "time" - - g "github.com/soniah/gosnmp" -) - -func main() { - - // get Target and Port from environment - envTarget := os.Getenv("GOSNMP_TARGET") - envPort := os.Getenv("GOSNMP_PORT") - if len(envTarget) <= 0 { - log.Fatalf("environment variable not set: GOSNMP_TARGET") - } - if len(envPort) <= 0 { - log.Fatalf("environment variable not set: GOSNMP_PORT") - } - port, _ := strconv.ParseUint(envPort, 10, 16) - - // Build our own GoSNMP struct, rather than using g.Default. - // Do verbose logging of packets. - params := &g.GoSNMP{ - Target: envTarget, - Port: uint16(port), - Community: "public", - Version: g.Version2c, - Timeout: time.Duration(2) * time.Second, - Logger: log.New(os.Stdout, "", 0), - } - err := params.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - defer params.Conn.Close() - - oids := []string{"1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.7.0"} - result, err2 := params.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: - fmt.Printf("string: %s\n", string(variable.Value.([]byte))) - 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)) - } - } -} diff --git a/vendor/github.com/soniah/gosnmp/examples/example3.go b/vendor/github.com/soniah/gosnmp/examples/example3.go deleted file mode 100644 index 6ff682c2..00000000 --- a/vendor/github.com/soniah/gosnmp/examples/example3.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2012-2014 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package main - -import ( - "fmt" - "log" - "time" - - g "github.com/soniah/gosnmp" -) - -func main() { - - // build our own GoSNMP struct, rather than using g.Default - params := &g.GoSNMP{ - Target: "192.168.91.20", - Port: 161, - Version: g.Version3, - Timeout: time.Duration(30) * time.Second, - SecurityModel: g.UserSecurityModel, - MsgFlags: g.AuthPriv, - SecurityParameters: &g.UsmSecurityParameters{UserName: "user", - AuthenticationProtocol: g.SHA, - AuthenticationPassphrase: "password", - PrivacyProtocol: g.DES, - PrivacyPassphrase: "password", - }, - } - err := params.Connect() - if err != nil { - log.Fatalf("Connect() err: %v", err) - } - defer params.Conn.Close() - - oids := []string{"1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.7.0"} - result, err2 := params.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: - fmt.Printf("string: %s\n", string(variable.Value.([]byte))) - 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)) - } - } -} diff --git a/vendor/github.com/soniah/gosnmp/examples/trapserver.go b/vendor/github.com/soniah/gosnmp/examples/trapserver.go deleted file mode 100644 index 793e169a..00000000 --- a/vendor/github.com/soniah/gosnmp/examples/trapserver.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -/* -The developer of the trapserver code (https://github.com/jda) says "I'm working -on the best level of abstraction but I'm able to receive traps from a Cisco -switch and Net-SNMP". - -Pull requests welcome. -*/ - -package main - -import ( - "flag" - "fmt" - "log" - "net" - "os" - "path/filepath" - - g "github.com/soniah/gosnmp" -) - -func main() { - flag.Usage = func() { - fmt.Printf("Usage:\n") - fmt.Printf(" %s\n", filepath.Base(os.Args[0])) - flag.PrintDefaults() - } - - tl := g.NewTrapListener() - tl.OnNewTrap = myTrapHandler - tl.Params = g.Default - tl.Params.Logger = log.New(os.Stdout, "", 0) - - err := tl.Listen("0.0.0.0:9162") - if err != nil { - log.Panicf("error in listen: %s", err) - } -} - -func myTrapHandler(packet *g.SnmpPacket, addr *net.UDPAddr) { - log.Printf("got trapdata from %s\n", addr.IP) - for _, v := range packet.Variables { - switch v.Type { - case g.OctetString: - b := v.Value.([]byte) - fmt.Printf("OID: %s, string: %x\n", v.Name, b) - - default: - log.Printf("trap: %+v\n", v) - } - } -} diff --git a/vendor/github.com/soniah/gosnmp/examples/walkexample.go b/vendor/github.com/soniah/gosnmp/examples/walkexample.go deleted file mode 100644 index 0b7736ba..00000000 --- a/vendor/github.com/soniah/gosnmp/examples/walkexample.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012-2014 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// This program demonstrates BulkWalk. -package main - -import ( - "flag" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/soniah/gosnmp" -) - -func main() { - flag.Usage = func() { - fmt.Printf("Usage:\n") - fmt.Printf(" %s [-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() - - err = gosnmp.Default.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("TYPE %d: %d\n", pdu.Type, gosnmp.ToBigInt(pdu.Value)) - } - return nil -} diff --git a/vendor/github.com/soniah/gosnmp/generic_e2e_test.go b/vendor/github.com/soniah/gosnmp/generic_e2e_test.go deleted file mode 100644 index 36635565..00000000 --- a/vendor/github.com/soniah/gosnmp/generic_e2e_test.go +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// This set of end-to-end integration tests execute gosnmp against a real -// SNMP MIB-2 host. Potential test systems could include a router, NAS box, printer, -// or a linux box running snmpd, snmpsimd.py, etc. -// -// Ensure "gosnmp-test-host" is defined in your hosts file, and points to your -// generic test system. - -package gosnmp - -import ( - "fmt" - "os" - "strconv" - "strings" - "testing" - "time" -) - -func setupConnection(t *testing.T) { - envTarget := os.Getenv("GOSNMP_TARGET") - envPort := os.Getenv("GOSNMP_PORT") - - if len(envTarget) <= 0 { - t.Skip("skipping: environment variable not set: GOSNMP_TARGET") - } - Default.Target = envTarget - - if len(envPort) <= 0 { - t.Skip("skipping: environment variable not set: GOSNMP_PORT") - } - port, _ := strconv.ParseUint(envPort, 10, 16) - Default.Port = uint16(port) - - err := Default.Connect() - if err != nil { - if len(envTarget) > 0 { - t.Fatalf("Connection failed. Is snmpd reachable on %s:%s?\n(err: %v)", - envTarget, envPort, err) - } - } -} - -func TestGenericBasicGet(t *testing.T) { - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestGenericMultiGet(t *testing.T) { - setupConnection(t) - defer Default.Conn.Close() - - oids := []string{ - ".1.3.6.1.2.1.1.1.0", // SNMP MIB-2 sysDescr - ".1.3.6.1.2.1.1.5.0", // SNMP MIB-2 sysName - } - result, err := Default.Get(oids) - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 2 { - t.Fatalf("Expected result of size 2") - } - for _, v := range result.Variables { - if v.Type != OctetString { - t.Fatalf("Expected OctetString") - } - } -} - -func TestGenericGetNext(t *testing.T) { - setupConnection(t) - defer Default.Conn.Close() - - sysDescrOid := ".1.3.6.1.2.1.1.1.0" // SNMP MIB-2 sysDescr - result, err := Default.GetNext([]string{sysDescrOid}) - if err != nil { - t.Fatalf("GetNext() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Name == sysDescrOid { - t.Fatalf("Expected next OID") - } -} - -func TestGenericWalk(t *testing.T) { - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.WalkAll("") - if err != nil { - t.Fatalf("WalkAll() Failed with error => %v", err) - } - if len(result) <= 1 { - t.Fatalf("Expected multiple values, got %d", len(result)) - } -} - -func TestGenericBulkWalk(t *testing.T) { - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.BulkWalkAll("") - if err != nil { - t.Fatalf("BulkWalkAll() Failed with error => %v", err) - } - if len(result) <= 1 { - t.Fatalf("Expected multiple values, got %d", len(result)) - } -} - -// Standard exception/error tests - -func TestMaxOids(t *testing.T) { - setupConnection(t) - defer Default.Conn.Close() - - Default.MaxOids = 1 - - var err error - oids := []string{".1.3.6.1.2.1.1.7.0", - ".1.3.6.1.2.1.2.2.1.10.1"} // 2 arbitrary Oids - errString := "oid count (2) is greater than MaxOids (1)" - - _, err = Default.Get(oids) - if err == nil { - t.Fatalf("Expected too many oids failure. Got nil") - } else if err.Error() != errString { - t.Fatalf("Expected too many oids failure. Got => %v", err) - } - - _, err = Default.GetNext(oids) - if err == nil { - t.Fatalf("Expected too many oids failure. Got nil") - } else if err.Error() != errString { - t.Fatalf("Expected too many oids failure. Got => %v", err) - } - - _, err = Default.GetBulk(oids, 0, 0) - if err == nil { - t.Fatalf("Expected too many oids failure. Got nil") - } else if err.Error() != errString { - t.Fatalf("Expected too many oids failure. Got => %v", err) - } -} - -func TestGenericFailureUnknownHost(t *testing.T) { - unknownHost := fmt.Sprintf("gosnmp-test-unknown-host-%d", time.Now().UTC().UnixNano()) - Default.Target = unknownHost - err := Default.Connect() - if err == nil { - t.Fatalf("Expected connection failure due to unknown host") - } - if !strings.Contains(strings.ToLower(err.Error()), "no such host") { - t.Fatalf("Expected connection error of type 'no such host'! Got => %v", err) - } - _, err = Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err == nil { - t.Fatalf("Expected get to fail due to missing connection") - } -} - -func TestGenericFailureConnectionTimeout(t *testing.T) { - Default.Target = "198.51.100.1" // Black hole - err := Default.Connect() - if err != nil { - t.Fatalf("Did not expect connection error with IP address") - } - _, err = Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err == nil { - t.Fatalf("Expected Get() to fail due to invalid IP") - } - if !strings.Contains(err.Error(), "timeout") { - t.Fatalf("Expected timeout error. Got => %v", err) - } -} - -func TestGenericFailureConnectionRefused(t *testing.T) { - Default.Target = "127.0.0.1" - Default.Port = 1 // Don't expect SNMP to be running here! - err := Default.Connect() - if err != nil { - t.Fatalf("Did not expect connection error with IP address") - } - _, err = Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err == nil { - t.Fatalf("Expected Get() to fail due to invalid port") - } - if !(strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "forcibly closed")) { - t.Fatalf("Expected connection refused error. Got => %v", err) - } -} - -func TestSnmpV3NoAuthNoPrivBasicGet(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = NoAuthNoPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "noAuthNoPrivUser"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestSnmpV3AuthNoPrivMD5Get(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = AuthNoPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "authMD5OnlyUser", AuthenticationProtocol: MD5, AuthenticationPassphrase: "testingpass0123456789"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestSnmpV3AuthNoPrivSHAGet(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = AuthNoPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "authSHAOnlyUser", AuthenticationProtocol: SHA, AuthenticationPassphrase: "testingpass9876543210"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestSnmpV3AuthMD5PrivDESGet(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = AuthPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "authMD5PrivDESUser", - AuthenticationProtocol: MD5, - AuthenticationPassphrase: "testingpass9876543210", - PrivacyProtocol: DES, - PrivacyPassphrase: "testingpass9876543210"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestSnmpV3AuthSHAPrivDESGet(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = AuthPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "authSHAPrivDESUser", - AuthenticationProtocol: SHA, - AuthenticationPassphrase: "testingpassabc6543210", - PrivacyProtocol: DES, - PrivacyPassphrase: "testingpassabc6543210"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestSnmpV3AuthMD5PrivAESGet(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = AuthPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "authMD5PrivAESUser", - AuthenticationProtocol: MD5, - AuthenticationPassphrase: "AEStestingpass9876543210", - PrivacyProtocol: AES, - PrivacyPassphrase: "AEStestingpass9876543210"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} - -func TestSnmpV3AuthSHAPrivAESGet(t *testing.T) { - Default.Version = Version3 - Default.MsgFlags = AuthPriv - Default.SecurityModel = UserSecurityModel - Default.SecurityParameters = &UsmSecurityParameters{UserName: "authSHAPrivAESUser", - AuthenticationProtocol: SHA, - AuthenticationPassphrase: "AEStestingpassabc6543210", - PrivacyProtocol: AES, - PrivacyPassphrase: "AEStestingpassabc6543210"} - setupConnection(t) - defer Default.Conn.Close() - - result, err := Default.Get([]string{".1.3.6.1.2.1.1.1.0"}) // SNMP MIB-2 sysDescr - if err != nil { - t.Fatalf("Get() failed with error => %v", err) - } - if len(result.Variables) != 1 { - t.Fatalf("Expected result of size 1") - } - if result.Variables[0].Type != OctetString { - t.Fatalf("Expected sysDescr to be OctetString") - } - sysDescr := result.Variables[0].Value.([]byte) - if len(sysDescr) == 0 { - t.Fatalf("Got a zero length sysDescr") - } -} diff --git a/vendor/github.com/soniah/gosnmp/gosnmp.go b/vendor/github.com/soniah/gosnmp/gosnmp.go deleted file mode 100644 index 974f304c..00000000 --- a/vendor/github.com/soniah/gosnmp/gosnmp.go +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gosnmp - -import ( - "fmt" - "io/ioutil" - "log" - "math/big" - "math/rand" - "net" - "strconv" - "time" -) - -const ( - // MaxOids is the maximum number of OIDs permitted in a single call, - // otherwise error. MaxOids too high can cause remote devices to fail - // strangely. 60 seems to be a common value that works, but you will want - // to change this in the GoSNMP struct - 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 -) - -// GoSNMP represents GoSNMP library state -type GoSNMP struct { - // Conn is net connection to use, typically established using GoSNMP.Connect() - Conn net.Conn - - // Target is an ipv4 address - Target string - - // Port is a udp port - Port uint16 - - // Community is an SNMP Community string - Community string - - // Version is an SNMP Version - Version SnmpVersion - - // Timeout is the timeout for the SNMP Query - Timeout time.Duration - - // Set the number of retries to attempt within timeout. - Retries int - - // Logger is the GoSNMP.Logger to use for debugging. If nil, debugging - // output will be discarded (/dev/null). For verbose logging to stdout: - // x.Logger = log.New(os.Stdout, "", 0) - Logger Logger - - // loggingEnabled is set if the Logger is nil, short circuits any 'Logger' calls - loggingEnabled bool - - // MaxOids is the maximum number of oids allowed in a Get() - // (default: MaxOids) - MaxOids int - - // MaxRepetitions sets the GETBULK max-repetitions used by BulkWalk* - MaxRepetitions uint8 - - // NonRepeaters sets the GETBULK max-repeaters used by BulkWalk* - // (default: 0 as per RFC 1905) - NonRepeaters int - - // Internal - used to sync requests to responses - requestID uint32 - random *rand.Rand - - rxBuf *[rxBufSize]byte // has to be pointer due to https://github.com/golang/go/issues/11728 - - // MsgFlags is an SNMPV3 MsgFlags - MsgFlags SnmpV3MsgFlags - - // SecurityModel is an SNMPV3 Security Model - SecurityModel SnmpV3SecurityModel - - // SecurityParameters is an SNMPV3 Security Model paramaters struct - SecurityParameters SnmpV3SecurityParameters - - // ContextEngineID is SNMPV3 ContextEngineID in ScopedPDU - ContextEngineID string - - // ContextName is SNMPV3 ContextName in ScopedPDU - ContextName string - - // Internal - used to sync requests to responses - snmpv3 - msgID uint32 -} - -// Default connection settings -var Default = &GoSNMP{ - Port: 161, - Community: "public", - Version: Version2c, - Timeout: time.Duration(2) * time.Second, - Retries: 3, - MaxOids: MaxOids, -} - -// SnmpPDU will be used when doing SNMP Set's -type SnmpPDU struct { - - // Name is an oid in string format eg ".1.3.6.1.4.9.27" - Name string - - // The type of the value eg Integer - Type Asn1BER - - // The value to be set by the SNMP set, or the value when - // sending a trap - Value interface{} - - // Logger implements the Logger interface - Logger Logger -} - -// Asn1BER is the type of the SNMP PDU -type Asn1BER byte - -// Asn1BER's - http://www.ietf.org/rfc/rfc1442.txt -const ( - EndOfContents Asn1BER = 0x00 - UnknownType = 0x00 // TODO these should all be type Asn1BER, however - Boolean = 0x01 // tests fail if implemented. See for example - Integer = 0x02 /// http://stackoverflow.com/questions/5037610/typed-constant-declaration-list. - BitString = 0x03 - OctetString = 0x04 - Null = 0x05 - ObjectIdentifier = 0x06 - ObjectDescription = 0x07 - IPAddress = 0x40 - Counter32 = 0x41 - Gauge32 = 0x42 - TimeTicks = 0x43 - Opaque = 0x44 - NsapAddress = 0x45 - Counter64 = 0x46 - Uinteger32 = 0x47 - NoSuchObject = 0x80 - NoSuchInstance = 0x81 - EndOfMibView = 0x82 -) - -// SNMPError is the type for standard SNMP errors. -type SNMPError uint8 - -// SNMP Errors -const ( - NoError SNMPError = iota // No error occurred. This code is also used in all request PDUs, since they have no error status to report. - TooBig // The size of the Response-PDU would be too large to transport. - NoSuchName // The name of a requested object was not found. - BadValue // A value in the request didn't match the structure that the recipient of the request had for the object. For example, an object in the request was specified with an incorrect length or type. - ReadOnly // An attempt was made to set a variable that has an Access value indicating that it is read-only. - GenErr // An error occurred other than one indicated by a more specific error code in this table. - NoAccess // Access was denied to the object for security reasons. - WrongType // The object type in a variable binding is incorrect for the object. - WrongLength // A variable binding specifies a length incorrect for the object. - WrongEncoding // A variable binding specifies an encoding incorrect for the object. - WrongValue // The value given in a variable binding is not possible for the object. - NoCreation // A specified variable does not exist and cannot be created. - InconsistentValue // A variable binding specifies a value that could be held by the variable but cannot be assigned to it at this time. - ResourceUnavailable // An attempt to set a variable required a resource that is not available. - CommitFailed // An attempt to set a particular variable failed. - UndoFailed // An attempt to set a particular variable as part of a group of variables failed, and the attempt to then undo the setting of other variables was not successful. - AuthorizationError // A problem occurred in authorization. - NotWritable // The variable cannot be written or created. - InconsistentName // The name in a variable binding specifies a variable that does not exist. -) - -// -// Public Functions (main interface) -// - -// Connect creates and opens a socket. Because UDP is a connectionless -// protocol, you won't know if the remote host is responding until you send -// packets. And if the host is regularly disappearing and reappearing, you won't -// know if you've only done a Connect(). -// -// For historical reasons (ie this is part of the public API), the method won't -// be renamed. -func (x *GoSNMP) Connect() error { - var err error - err = x.validateParameters() - if err != nil { - return err - } - - addr := net.JoinHostPort(x.Target, strconv.Itoa(int(x.Port))) - x.Conn, err = net.DialTimeout("udp", addr, x.Timeout) - if err != nil { - return fmt.Errorf("Error establishing connection to host: %s\n", err.Error()) - } - if x.random == nil { - x.random = rand.New(rand.NewSource(time.Now().UTC().UnixNano())) - } - // http://tools.ietf.org/html/rfc3412#section-6 - msgID only - // uses the first 31 bits - // msgID INTEGER (0..2147483647) - x.msgID = uint32(x.random.Int31()) - // RequestID is Integer32 from SNMPV2-SMI and uses all 32 bits - x.requestID = x.random.Uint32() - - x.rxBuf = new([rxBufSize]byte) - - return nil -} - -func (x *GoSNMP) validateParameters() error { - if x.Logger == nil { - x.Logger = log.New(ioutil.Discard, "", 0) - } else { - x.loggingEnabled = true - } - - if x.MaxOids == 0 { - x.MaxOids = MaxOids - } else if x.MaxOids < 0 { - return fmt.Errorf("MaxOids cannot be less than 0") - } - - if x.Version == Version3 { - x.MsgFlags |= Reportable // tell the snmp server that a report PDU MUST be sent - - err := x.validateParametersV3() - if err != nil { - return err - } - err = x.SecurityParameters.init(x.Logger) - if err != nil { - return err - } - } - - return nil -} - -func (x *GoSNMP) mkSnmpPacket(pdutype PDUType, pdus []SnmpPDU, nonRepeaters uint8, maxRepetitions uint8) *SnmpPacket { - var newSecParams SnmpV3SecurityParameters - if x.SecurityParameters != nil { - newSecParams = x.SecurityParameters.Copy() - } - return &SnmpPacket{ - Version: x.Version, - Community: x.Community, - MsgFlags: x.MsgFlags, - SecurityModel: x.SecurityModel, - SecurityParameters: newSecParams, - ContextEngineID: x.ContextEngineID, - ContextName: x.ContextName, - Error: 0, - ErrorIndex: 0, - PDUType: pdutype, - NonRepeaters: nonRepeaters, - MaxRepetitions: maxRepetitions, - Variables: pdus, - } -} - -// Get sends an SNMP GET request -func (x *GoSNMP) Get(oids []string) (result *SnmpPacket, err error) { - oidCount := len(oids) - if oidCount > x.MaxOids { - return nil, fmt.Errorf("oid count (%d) is greater than MaxOids (%d)", - oidCount, x.MaxOids) - } - // convert oids slice to pdu slice - var pdus []SnmpPDU - for _, oid := range oids { - pdus = append(pdus, SnmpPDU{oid, Null, nil, x.Logger}) - } - // build up SnmpPacket - packetOut := x.mkSnmpPacket(GetRequest, pdus, 0, 0) - return x.send(packetOut, true) -} - -// Set sends an SNMP SET request -func (x *GoSNMP) Set(pdus []SnmpPDU) (result *SnmpPacket, err error) { - var packetOut *SnmpPacket - switch pdus[0].Type { - case Integer, OctetString: - packetOut = x.mkSnmpPacket(SetRequest, pdus, 0, 0) - default: - return nil, fmt.Errorf("ERR:gosnmp currently only supports SNMP SETs for Integers and OctetStrings") - } - return x.send(packetOut, true) -} - -// GetNext sends an SNMP GETNEXT request -func (x *GoSNMP) GetNext(oids []string) (result *SnmpPacket, err error) { - oidCount := len(oids) - if oidCount > x.MaxOids { - return nil, fmt.Errorf("oid count (%d) is greater than MaxOids (%d)", - oidCount, x.MaxOids) - } - - // convert oids slice to pdu slice - var pdus []SnmpPDU - for _, oid := range oids { - pdus = append(pdus, SnmpPDU{oid, Null, nil, x.Logger}) - } - - // Marshal and send the packet - packetOut := x.mkSnmpPacket(GetNextRequest, pdus, 0, 0) - - return x.send(packetOut, true) -} - -// GetBulk sends an SNMP GETBULK request -// -// For maxRepetitions greater than 255, use BulkWalk() or BulkWalkAll() -func (x *GoSNMP) GetBulk(oids []string, nonRepeaters uint8, maxRepetitions uint8) (result *SnmpPacket, err error) { - oidCount := len(oids) - if oidCount > x.MaxOids { - return nil, fmt.Errorf("oid count (%d) is greater than MaxOids (%d)", - oidCount, x.MaxOids) - } - - // convert oids slice to pdu slice - var pdus []SnmpPDU - for _, oid := range oids { - pdus = append(pdus, SnmpPDU{oid, Null, nil, x.Logger}) - } - - // Marshal and send the packet - packetOut := x.mkSnmpPacket(GetBulkRequest, pdus, nonRepeaters, maxRepetitions) - return x.send(packetOut, true) -} - -// -// SNMP Walk functions - Analogous to net-snmp's snmpwalk commands -// - -// WalkFunc is the type of the function called for each data unit visited -// by the Walk function. If an error is returned processing stops. -type WalkFunc func(dataUnit SnmpPDU) error - -// BulkWalk retrieves a subtree of values using GETBULK. As the tree is -// walked walkFn is called for each new value. The function immediately returns -// an error if either there is an underlaying SNMP error (e.g. GetBulk fails), -// or if walkFn returns an error. -func (x *GoSNMP) BulkWalk(rootOid string, walkFn WalkFunc) error { - return x.walk(GetBulkRequest, rootOid, walkFn) -} - -// BulkWalkAll is similar to BulkWalk but returns a filled array of all values -// rather than using a callback function to stream results. -func (x *GoSNMP) BulkWalkAll(rootOid string) (results []SnmpPDU, err error) { - return x.walkAll(GetBulkRequest, rootOid) -} - -// Walk retrieves a subtree of values using GETNEXT - a request is made for each -// value, unlike BulkWalk which does this operation in batches. As the tree is -// walked walkFn is called for each new value. The function immediately returns -// an error if either there is an underlaying SNMP error (e.g. GetNext fails), -// or if walkFn returns an error. -func (x *GoSNMP) Walk(rootOid string, walkFn WalkFunc) error { - return x.walk(GetNextRequest, rootOid, walkFn) -} - -// WalkAll is similar to Walk but returns a filled array of all values rather -// than using a callback function to stream results. -func (x *GoSNMP) WalkAll(rootOid string) (results []SnmpPDU, err error) { - return x.walkAll(GetNextRequest, rootOid) -} - -// -// Public Functions (helpers) - in alphabetical order -// - -// Partition - returns true when dividing a slice into -// partitionSize lengths, including last partition which may be smaller -// than partitionSize. This is useful when you have a large array of OIDs -// to run Get() on. See the tests for example usage. -// -// For example for a slice of 8 items to be broken into partitions of -// length 3, Partition returns true for the currentPosition having -// the following values: -// -// 0 1 2 3 4 5 6 7 -// T T T -// -func Partition(currentPosition, partitionSize, sliceLength int) bool { - if currentPosition < 0 || currentPosition >= sliceLength { - return false - } - if partitionSize == 1 { // redundant, but an obvious optimisation - return true - } - if currentPosition%partitionSize == partitionSize-1 { - return true - } - if currentPosition == sliceLength-1 { - return true - } - return false -} - -// ToBigInt converts SnmpPDU.Value to big.Int, or returns a zero big.Int for -// non int-like types (eg strings). -// -// This is a convenience function to make working with SnmpPDU's easier - it -// reduces the need for type assertions. A big.Int is convenient, as SNMP can -// return int32, uint32, and uint64. -func ToBigInt(value interface{}) *big.Int { - var val int64 - switch value := value.(type) { // shadow - case int: - val = int64(value) - case int8: - val = int64(value) - case int16: - val = int64(value) - case int32: - val = int64(value) - case int64: - val = int64(value) - case uint: - val = int64(value) - case uint8: - val = int64(value) - case uint16: - val = int64(value) - case uint32: - val = int64(value) - case uint64: - return (uint64ToBigInt(value)) - case string: - // for testing and other apps - numbers may appear as strings - var err error - if val, err = strconv.ParseInt(value, 10, 64); err != nil { - return new(big.Int) - } - default: - return new(big.Int) - } - return big.NewInt(val) -} diff --git a/vendor/github.com/soniah/gosnmp/gosnmp_api_test.go b/vendor/github.com/soniah/gosnmp/gosnmp_api_test.go deleted file mode 100644 index 65017b18..00000000 --- a/vendor/github.com/soniah/gosnmp/gosnmp_api_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// The purpose of these tests is to validate gosnmp's public APIs. -// -// IMPORTANT: If you're modifying _any_ existing code in this file, you -// should be asking yourself about API compatibility! - -package gosnmp_test // force external view - -import ( - "io/ioutil" - "log" - "net" - "testing" - "time" - - "github.com/soniah/gosnmp" -) - -func TestAPIConfigTypes(t *testing.T) { - g := &gosnmp.GoSNMP{} - g.Target = "" - g.Port = 0 - g.Community = "" - g.Version = gosnmp.Version1 - g.Version = gosnmp.Version2c - g.Timeout = time.Duration(0) - g.Retries = 0 - g.Logger = log.New(ioutil.Discard, "", 0) - g.MaxOids = 0 - g.MaxRepetitions = 0 - g.NonRepeaters = 0 - - var c net.Conn - c = g.Conn - _ = c -} - -func TestAPIDefault(t *testing.T) { - var g *gosnmp.GoSNMP - g = gosnmp.Default - _ = g -} - -func TestAPIConnectMethodSignature(t *testing.T) { - var f func() error - f = gosnmp.Default.Connect - _ = f -} - -func TestAPIGetMethodSignature(t *testing.T) { - var f func([]string) (*gosnmp.SnmpPacket, error) - f = gosnmp.Default.Get - _ = f -} - -func TestAPISetMethodSignature(t *testing.T) { - var f func([]gosnmp.SnmpPDU) (*gosnmp.SnmpPacket, error) - f = gosnmp.Default.Set - _ = f -} - -func TestAPIGetNextMethodSignature(t *testing.T) { - var f func([]string) (*gosnmp.SnmpPacket, error) - f = gosnmp.Default.GetNext - _ = f -} - -func TestAPIBulkWalkMethodSignature(t *testing.T) { - var f func(string, gosnmp.WalkFunc) error - f = gosnmp.Default.BulkWalk - _ = f -} - -func TestAPIBulkWalkAllMethodSignature(t *testing.T) { - var f func(string) ([]gosnmp.SnmpPDU, error) - f = gosnmp.Default.BulkWalkAll - _ = f -} - -func TestAPIWalkMethodSignature(t *testing.T) { - var f func(string, gosnmp.WalkFunc) error - f = gosnmp.Default.Walk - _ = f -} - -func TestAPIWalkAllMethodSignature(t *testing.T) { - var f func(string) ([]gosnmp.SnmpPDU, error) - f = gosnmp.Default.WalkAll - _ = f -} - -func TestAPIWalkFuncSignature(t *testing.T) { - var f gosnmp.WalkFunc - f = func(du gosnmp.SnmpPDU) (err error) { return } - _ = f -} diff --git a/vendor/github.com/soniah/gosnmp/helper.go b/vendor/github.com/soniah/gosnmp/helper.go deleted file mode 100644 index 7b4cdb73..00000000 --- a/vendor/github.com/soniah/gosnmp/helper.go +++ /dev/null @@ -1,729 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gosnmp - -import ( - // "bytes" - "bytes" - "encoding/binary" - "encoding/hex" - "errors" - "fmt" - "log" - "math" - "math/big" - "net" - "os" - "strconv" - "strings" -) - -// variable struct is used by decodeValue(), which is used for debugging -type variable struct { - Name []int - Type Asn1BER - Value interface{} -} - -// -- helper functions (mostly) in alphabetical order -------------------------- - -// Check makes checking errors easy, so they actually get a minimal check -func (x *GoSNMP) Check(err error) { - if err != nil { - x.Logger.Printf("Check: %v\n", err) - os.Exit(1) - } -} - -// Check makes checking errors easy, so they actually get a minimal check -func (p *SnmpPacket) Check(err error) { - if err != nil { - p.Logger.Printf("Check: %v\n", err) - os.Exit(1) - } -} - -// Check makes checking errors easy, so they actually get a minimal check -func (p *SnmpPDU) Check(err error) { - if err != nil { - p.Logger.Printf("Check: %v\n", err) - os.Exit(1) - } -} - -// Check makes checking errors easy, so they actually get a minimal check -func Check(err error) { - if err != nil { - log.Fatalf("Check: %v\n", err) - } -} - -func (x *GoSNMP) decodeValue(data []byte, msg string) (retVal *variable, err error) { - retVal = new(variable) - - switch Asn1BER(data[0]) { - - case Integer: - // 0x02. signed - x.logPrint("decodeValue: type is Integer") - length, cursor := parseLength(data) - var ret int - var err error - if ret, err = parseInt(data[cursor:length]); err != nil { - x.logPrintf("%v:", err) - return retVal, fmt.Errorf("bytes: % x err: %v", data, err) - } - retVal.Type = Integer - retVal.Value = ret - case OctetString: - // 0x04 - x.logPrint("decodeValue: type is OctetString") - length, cursor := parseLength(data) - retVal.Type = OctetString - retVal.Value = []byte(data[cursor:length]) - case Null: - // 0x05 - x.logPrint("decodeValue: type is Null") - retVal.Type = Null - retVal.Value = nil - case ObjectIdentifier: - // 0x06 - x.logPrint("decodeValue: type is ObjectIdentifier") - rawOid, _, err := parseRawField(data, "OID") - if err != nil { - return nil, fmt.Errorf("Error parsing OID Value: %s", err.Error()) - } - var oid []int - var ok bool - if oid, ok = rawOid.([]int); !ok { - return nil, fmt.Errorf("unable to type assert rawOid |%v| to []int", rawOid) - } - retVal.Type = ObjectIdentifier - retVal.Value = oidToString(oid) - case IPAddress: - // 0x40 - x.logPrint("decodeValue: type is IPAddress") - retVal.Type = IPAddress - switch data[1] { - case 0: // real life, buggy devices returning bad data - retVal.Value = nil - return retVal, nil - case 4: // IPv4 - if len(data) < 6 { - return nil, fmt.Errorf("not enough data for ipv4 address: %x", data) - } - retVal.Value = net.IPv4(data[2], data[3], data[4], data[5]).String() - case 16: // IPv6 - if len(data) < 18 { - return nil, fmt.Errorf("not enough data for ipv6 address: %x", data) - } - d := make(net.IP, 16) - copy(d, data[2:17]) - retVal.Value = d.String() - default: - return nil, fmt.Errorf("got ipaddress len %d, expected 4 or 16", data[1]) - } - case Counter32: - // 0x41. unsigned - x.logPrint("decodeValue: type is Counter32") - length, cursor := parseLength(data) - ret, err := parseUint(data[cursor:length]) - if err != nil { - x.logPrintf("decodeValue: err is %v", err) - break - } - retVal.Type = Counter32 - retVal.Value = ret - case Gauge32: - // 0x42. unsigned - x.logPrint("decodeValue: type is Gauge32") - length, cursor := parseLength(data) - ret, err := parseUint(data[cursor:length]) - if err != nil { - x.logPrintf("decodeValue: err is %v", err) - break - } - retVal.Type = Gauge32 - retVal.Value = ret - case TimeTicks: - // 0x43 - x.logPrint("decodeValue: type is TimeTicks") - length, cursor := parseLength(data) - ret, err := parseInt(data[cursor:length]) - if err != nil { - x.logPrintf("decodeValue: err is %v", err) - break - } - retVal.Type = TimeTicks - retVal.Value = ret - case Counter64: - // 0x46 - x.logPrint("decodeValue: type is Counter64") - length, cursor := parseLength(data) - ret, err := parseUint64(data[cursor:length]) - if err != nil { - x.logPrintf("decodeValue: err is %v", err) - break - } - retVal.Type = Counter64 - retVal.Value = ret - case NoSuchObject: - // 0x80 - x.logPrint("decodeValue: type is NoSuchObject") - retVal.Type = NoSuchObject - retVal.Value = nil - case NoSuchInstance: - // 0x81 - x.logPrint("decodeValue: type is NoSuchInstance") - retVal.Type = NoSuchInstance - retVal.Value = nil - case EndOfMibView: - // 0x82 - x.logPrint("decodeValue: type is EndOfMibView") - retVal.Type = EndOfMibView - retVal.Value = nil - default: - x.logPrintf("decodeValue: type %x isn't implemented", data[0]) - retVal.Type = UnknownType - retVal.Value = nil - } - x.logPrintf("decodeValue: value is %#v", retVal.Value) - return -} - -// dump bytes in a format similar to Wireshark -func dumpBytes1(data []byte, msg string, maxlength int) { - var buffer bytes.Buffer - buffer.WriteString(msg) - length := maxlength - if len(data) < maxlength { - length = len(data) - } - length *= 2 //One Byte Symobls Two Hex - hexStr := hex.EncodeToString(data) - for i := 0; length >= i+16; i += 16 { - buffer.WriteString("\n") - buffer.WriteString(strconv.Itoa(i / 2)) - buffer.WriteString("\t") - buffer.WriteString(hexStr[i : i+2]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+2 : i+4]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+4 : i+6]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+6 : i+8]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+8 : i+10]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+10 : i+12]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+12 : i+14]) - buffer.WriteString(" ") - buffer.WriteString(hexStr[i+14 : i+16]) - } - leftOver := length % 16 - if leftOver != 0 { - buffer.WriteString("\n") - buffer.WriteString(strconv.Itoa((length - leftOver) / 2)) - buffer.WriteString("\t") - for i := 0; leftOver >= i+2; i += 2 { - buffer.WriteString(hexStr[i : i+2]) - buffer.WriteString(" ") - } - } - buffer.WriteString("\n") -} - -// dump bytes in one row, up to about screen width. Returns a string -// rather than (dumpBytes1) writing to debugging log. -func dumpBytes2(desc string, bb []byte, cursor int) string { - cursor = cursor - 4 // give some context to dump - if cursor < 0 { - cursor = 0 - } - result := desc - for i, b := range bb[cursor:] { - if i > 30 { // about screen width... - break - } - result += fmt.Sprintf(" %02x", b) - } - return result -} - -func checkByteEquality2(a, b []byte) bool { - - if a == nil && b == nil { - return true - } - - if a == nil || b == nil { - return false - } - - if len(a) != len(b) { - return false - } - - for i := range a { - if a[i] != b[i] { - return false - } - } - - return true -} - -func marshalUvarInt(x uint32) []byte { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, x) - i := 0 - for ; i < 3; i++ { - if buf[i] != 0 { - break - } - } - buf = buf[i:] - // if the highest bit in buf is set and x is not negative - prepend a byte to make it positive - if len(buf) > 0 && buf[0]&0x80 > 0 { - buf = append([]byte{0}, buf...) - } - return buf -} - -func marshalBase128Int(out *bytes.Buffer, n int64) (err error) { - if n == 0 { - err = out.WriteByte(0) - return - } - - l := 0 - for i := n; i > 0; i >>= 7 { - l++ - } - - for i := l - 1; i >= 0; i-- { - o := byte(n >> uint(i*7)) - o &= 0x7f - if i != 0 { - o |= 0x80 - } - err = out.WriteByte(o) - if err != nil { - return - } - } - - return nil -} - -// marshalInt16 builds a byte representation of -// a 16 bit int in BigEndian form. -func marshalInt16(value int) (rs []byte, err error) { - if value <= 0xff { - rs = []byte{byte(value)} - return rs, nil - } - if value > 0xff && value <= 0xffff { - rs = []byte{byte(((value >> 8) & 0xff)), byte((value & 0xff))} - return rs, nil - } - return nil, fmt.Errorf("Unable to marshal %v", rs) -} - -// Counter32, Gauge32, TimeTicks, Unsigned32 -func marshalUint32(v interface{}) ([]byte, error) { - bs := make([]byte, 4) - source := v.(uint32) - binary.BigEndian.PutUint32(bs, source) // will panic on failure - // truncate leading zeros. Cleaner technique? - if source <= 0xff { - return bs[3:], nil - } - if source <= 0xffff { - return bs[2:], nil - } - if source <= 0xffffff { - return bs[1:], nil - } - return bs, nil -} - -// marshalLength builds a byte representation of length -// -// http://luca.ntop.org/Teaching/Appunti/asn1.html -// -// Length octets. There are two forms: short (for lengths between 0 and 127), -// and long definite (for lengths between 0 and 2^1008 -1). -// -// * Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length. -// * Long form. Two to 127 octets. Bit 8 of first octet has value "1" and bits -// 7-1 give the number of additional length octets. Second and following -// octets give the length, base 256, most significant digit first. -func marshalLength(length int) ([]byte, error) { - // more convenient to pass length as int than uint64. Therefore check < 0 - if length < 0 { - return nil, fmt.Errorf("length must be greater than zero") - } else if length < 127 { - return []byte{byte(length)}, nil - } - - buf := new(bytes.Buffer) - err := binary.Write(buf, binary.BigEndian, uint64(length)) - if err != nil { - return nil, err - } - bufBytes := buf.Bytes() - - // strip leading zeros - for idx, octect := range bufBytes { - if octect != 00 { - bufBytes = bufBytes[idx:len(bufBytes)] - break - } - } - - header := []byte{byte(128 | len(bufBytes))} - return append(header, bufBytes...), nil -} - -func marshalObjectIdentifier(oid []int) (ret []byte, err error) { - out := new(bytes.Buffer) - if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 { - return nil, errors.New("invalid object identifier") - } - - err = out.WriteByte(byte(oid[0]*40 + oid[1])) - if err != nil { - return - } - for i := 2; i < len(oid); i++ { - err = marshalBase128Int(out, int64(oid[i])) - if err != nil { - return - } - } - - ret = out.Bytes() - return -} - -func marshalOID(oid string) ([]byte, error) { - var err error - - // Encode the oid - oid = strings.Trim(oid, ".") - oidParts := strings.Split(oid, ".") - oidBytes := make([]int, len(oidParts)) - - // Convert the string OID to an array of integers - for i := 0; i < len(oidParts); i++ { - oidBytes[i], err = strconv.Atoi(oidParts[i]) - if err != nil { - return nil, fmt.Errorf("Unable to parse OID: %s\n", err.Error()) - } - } - - mOid, err := marshalObjectIdentifier(oidBytes) - - if err != nil { - return nil, fmt.Errorf("Unable to marshal OID: %s\n", err.Error()) - } - - return mOid, err -} - -func oidToString(oid []int) (ret string) { - oidAsString := make([]string, len(oid)+1) - - // used for appending of the first dot - oidAsString[0] = "" - for i := range oid { - oidAsString[i+1] = strconv.Itoa(oid[i]) - } - - return strings.Join(oidAsString, ".") -} - -// MrSpock changes. TODO NO tests for this yet - waiting for .pcap -func ipv4toBytes(ip net.IP) []byte { - return []byte(ip)[12:] -} - -// parseBase128Int parses a base-128 encoded int from the given offset in the -// given byte slice. It returns the value and the new offset. -func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) { - offset = initOffset - for shifted := 0; offset < len(bytes); shifted++ { - if shifted > 4 { - err = fmt.Errorf("Structural Error: base 128 integer too large") - return - } - ret <<= 7 - b := bytes[offset] - ret |= int(b & 0x7f) - offset++ - if b&0x80 == 0 { - return - } - } - err = fmt.Errorf("Syntax Error: truncated base 128 integer") - return -} - -// parseBitString parses an ASN.1 bit string from the given byte slice and returns it. -func parseBitString(bytes []byte) (ret BitStringValue, err error) { - if len(bytes) == 0 { - err = errors.New("zero length BIT STRING") - return - } - paddingBits := int(bytes[0]) - if paddingBits > 7 || - len(bytes) == 1 && paddingBits > 0 || - bytes[len(bytes)-1]&((1< 8 { - // We'll overflow an int64 in this case. - err = errors.New("integer too large") - return - } - for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { - ret <<= 8 - ret |= int64(bytes[bytesRead]) - } - - // Shift up and down in order to sign extend the result. - ret <<= 64 - uint8(len(bytes))*8 - ret >>= 64 - uint8(len(bytes))*8 - return -} - -// parseInt treats the given bytes as a big-endian, signed integer and returns -// the result. -func parseInt(bytes []byte) (int, error) { - ret64, err := parseInt64(bytes) - if err != nil { - return 0, err - } - if ret64 != int64(int(ret64)) { - return 0, errors.New("integer too large") - } - return int(ret64), nil -} - -// parseLength parses and calculates an snmp packet length -// -// http://luca.ntop.org/Teaching/Appunti/asn1.html -// -// Length octets. There are two forms: short (for lengths between 0 and 127), -// and long definite (for lengths between 0 and 2^1008 -1). -// -// * Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length. -// * Long form. Two to 127 octets. Bit 8 of first octet has value "1" and bits -// 7-1 give the number of additional length octets. Second and following -// octets give the length, base 256, most significant digit first. -func parseLength(bytes []byte) (length int, cursor int) { - if len(bytes) <= 2 { - // handle null octet strings ie "0x04 0x00" - cursor = len(bytes) - length = len(bytes) - } else if int(bytes[1]) <= 127 { - length = int(bytes[1]) - length += 2 - cursor += 2 - } else { - numOctets := int(bytes[1]) & 127 - for i := 0; i < numOctets; i++ { - length <<= 8 - length += int(bytes[2+i]) - } - length += 2 + numOctets - cursor += 2 + numOctets - } - return length, cursor -} - -// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and -// returns it. An object identifier is a sequence of variable length integers -// that are assigned in a hierarchy. -func parseObjectIdentifier(bytes []byte) (s []int, err error) { - if len(bytes) == 0 { - err = fmt.Errorf("zero length OBJECT IDENTIFIER") - return - } - - // In the worst case, we get two elements from the first byte (which is - // encoded differently) and then every varint is a single byte long. - s = make([]int, len(bytes)+1) - - // The first byte is 40*value1 + value2: - s[0] = int(bytes[0]) / 40 - s[1] = int(bytes[0]) % 40 - i := 2 - for offset := 1; offset < len(bytes); i++ { - var v int - v, offset, err = parseBase128Int(bytes, offset) - if err != nil { - return - } - s[i] = v - } - s = s[0:i] - return -} - -func parseRawField(data []byte, msg string) (interface{}, int, error) { - switch Asn1BER(data[0]) { - case Integer: - length, cursor := parseLength(data) - i, err := parseInt(data[cursor:length]) - if err != nil { - return nil, 0, fmt.Errorf("Unable to parse raw INTEGER: %x err: %v", data, err) - } - return i, length, nil - case OctetString: - length, cursor := parseLength(data) - return string(data[cursor:length]), length, nil - case ObjectIdentifier: - length, cursor := parseLength(data) - oid, err := parseObjectIdentifier(data[cursor:length]) - return oid, length, err - case IPAddress: - length, _ := parseLength(data) - switch data[1] { - case 0: // real life, buggy devices returning bad data - return nil, length, nil - case 4: // IPv4 - if len(data) < 6 { - return nil, 0, fmt.Errorf("not enough data for ipv4 address: %x", data) - } - return net.IPv4(data[2], data[3], data[4], data[5]).String(), length, nil - default: - return nil, 0, fmt.Errorf("got ipaddress len %d, expected 4", data[1]) - } - case TimeTicks: - length, cursor := parseLength(data) - ret, err := parseInt(data[cursor:length]) - if err != nil { - return nil, 0, fmt.Errorf("Error in parseInt: %s", err) - } - return ret, length, nil - } - - return nil, 0, fmt.Errorf("Unknown field type: %x\n", data[0]) -} - -// parseUint64 treats the given bytes as a big-endian, unsigned integer and returns -// the result. -func parseUint64(bytes []byte) (ret uint64, err error) { - if len(bytes) > 9 || (len(bytes) > 8 && bytes[0] != 0x0) { - // We'll overflow a uint64 in this case. - err = errors.New("integer too large") - return - } - for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { - ret <<= 8 - ret |= uint64(bytes[bytesRead]) - } - return -} - -// parseUint treats the given bytes as a big-endian, signed integer and returns -// the result. -func parseUint(bytes []byte) (uint, error) { - ret64, err := parseUint64(bytes) - if err != nil { - return 0, err - } - if ret64 != uint64(uint(ret64)) { - return 0, errors.New("integer too large") - } - return uint(ret64), nil -} - -// 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) -} - -// -- Bit String --------------------------------------------------------------- - -// BitStringValue is the structure to use when you want an ASN.1 BIT STRING type. A -// bit string is padded up to the nearest byte in memory and the number of -// valid bits is recorded. Padding bits will be zero. -type BitStringValue struct { - Bytes []byte // bits packed into bytes. - BitLength int // length in bits. -} - -// At returns the bit at the given index. If the index is out of range it -// returns false. -func (b BitStringValue) At(i int) int { - if i < 0 || i >= b.BitLength { - return 0 - } - x := i / 8 - y := 7 - uint(i%8) - return int(b.Bytes[x]>>y) & 1 -} - -// RightAlign returns a slice where the padding bits are at the beginning. The -// slice may share memory with the BitString. -func (b BitStringValue) RightAlign() []byte { - shift := uint(8 - (b.BitLength % 8)) - if shift == 8 || len(b.Bytes) == 0 { - return b.Bytes - } - - a := make([]byte, len(b.Bytes)) - a[0] = b.Bytes[0] >> shift - for i := 1; i < len(b.Bytes); i++ { - a[i] = b.Bytes[i-1] << (8 - shift) - a[i] |= b.Bytes[i] >> shift - } - - return a -} - -// -- SnmpVersion -------------------------------------------------------------- - -func (s SnmpVersion) String() string { - if s == Version1 { - return "1" - } else if s == Version2c { - return "2c" - } - return "3" -} diff --git a/vendor/github.com/soniah/gosnmp/helper_test.go b/vendor/github.com/soniah/gosnmp/helper_test.go deleted file mode 100644 index 4128f1ba..00000000 --- a/vendor/github.com/soniah/gosnmp/helper_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import "testing" - -func TestOidToString(t *testing.T) { - oid := []int{1, 2, 3, 4, 5} - expected := ".1.2.3.4.5" - result := oidToString(oid) - - if result != expected { - t.Errorf("oidToString(%v) = %s, want %s", oid, result, expected) - } -} - -func TestWithAnotherOid(t *testing.T) { - oid := []int{4, 3, 2, 1, 3} - expected := ".4.3.2.1.3" - result := oidToString(oid) - - if result != expected { - t.Errorf("oidToString(%v) = %s, want %s", oid, result, expected) - } -} - -func BenchmarkOidToString(b *testing.B) { - oid := []int{1, 2, 3, 4, 5} - for i := 0; i < b.N; i++ { - oidToString(oid) - } -} - -type testsMarshalUint32T struct { - value uint32 - goodBytes []byte -} - -var testsMarshalUint32 = []testsMarshalUint32T{ - {0, []byte{0x00}}, - {2, []byte{0x02}}, // 2 - {257, []byte{0x01, 0x01}}, // FF + 2 - {65537, []byte{0x01, 0x00, 0x01}}, // FFFF + 2 - {16777217, []byte{0x01, 0x00, 0x00, 0x01}}, // FFFFFF + 2 - {18542501, []byte{0x01, 0x1a, 0xef, 0xa5}}, -} - -func TestMarshalUint32(t *testing.T) { - for i, test := range testsMarshalUint32 { - result, err := marshalUint32(test.value) - if err != nil { - t.Errorf("%d: expected %0x got err %v", i, test.goodBytes, err) - } - if !checkByteEquality2(test.goodBytes, result) { - t.Errorf("%d: expected %0x got %0x", i, test.goodBytes, result) - } - } -} - -func TestParseUint64(t *testing.T) { - tests := []struct { - data []byte - n uint64 - }{ - {[]byte{}, 0}, - {[]byte{0x00}, 0}, - {[]byte{0x01}, 1}, - {[]byte{0x01, 0x01}, 257}, - {[]byte{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xb3, 0xbf}, 18446744073694786495}, - } - for _, test := range tests { - if ret, err := parseUint64(test.data); err != nil || ret != test.n { - t.Errorf("parseUint64(%v) = %d, %v want %d, ", test.data, ret, err, test.n) - } - } -} diff --git a/vendor/github.com/soniah/gosnmp/marshal.go b/vendor/github.com/soniah/gosnmp/marshal.go deleted file mode 100644 index 6d622480..00000000 --- a/vendor/github.com/soniah/gosnmp/marshal.go +++ /dev/null @@ -1,872 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import ( - "bytes" - "encoding/asn1" - "encoding/binary" - "fmt" - "net" - "sync/atomic" - "time" -) - -// -// Remaining globals and definitions located here. -// See http://www.rane.com/note161.html for a succint description of the SNMP -// protocol. -// - -// SnmpVersion 1, 2c and 3 implemented -type SnmpVersion uint8 - -// SnmpVersion 1, 2c and 3 implemented -const ( - Version1 SnmpVersion = 0x0 - Version2c SnmpVersion = 0x1 - Version3 SnmpVersion = 0x3 -) - -// SnmpPacket struct represents the entire SNMP Message or Sequence at the -// application layer. -type SnmpPacket struct { - Version SnmpVersion - MsgFlags SnmpV3MsgFlags - SecurityModel SnmpV3SecurityModel - SecurityParameters SnmpV3SecurityParameters - ContextEngineID string - ContextName string - Community string - PDUType PDUType - MsgID uint32 - RequestID uint32 - Error SNMPError - ErrorIndex uint8 - NonRepeaters uint8 - MaxRepetitions uint8 - Variables []SnmpPDU - Logger Logger - - // Trap V1 header - Enterprise []int - AgentAddr string - GenericTrap int - SpecificTrap int - Timestamp int -} - -// VarBind struct represents an SNMP Varbind. -type VarBind struct { - Name asn1.ObjectIdentifier - Value asn1.RawValue -} - -// PDUType describes which SNMP Protocol Data Unit is being sent. -type PDUType byte - -// The currently supported PDUType's -const ( - Sequence PDUType = 0x30 - GetRequest PDUType = 0xa0 - GetNextRequest PDUType = 0xa1 - GetResponse PDUType = 0xa2 - SetRequest PDUType = 0xa3 - Trap PDUType = 0xa4 // v1 - GetBulkRequest PDUType = 0xa5 - InformRequest PDUType = 0xa6 - SNMPv2Trap PDUType = 0xa7 // v2c, v3 - Report PDUType = 0xa8 -) - -const rxBufSize = 65535 // max size of IPv4 & IPv6 packet - -// Logger is an interface used for debugging. Both Print and -// Printf have the same interfaces as Package Log in the std library. The -// Logger interface is small to give you flexibility in how you do -// your debugging. -// -// For verbose logging to stdout: -// -// gosnmp_logger = log.New(os.Stdout, "", 0) -type Logger interface { - Print(v ...interface{}) - Printf(format string, v ...interface{}) -} - -func (x *GoSNMP) logPrint(v ...interface{}) { - if x.loggingEnabled { - x.Logger.Print(v) - } -} - -func (x *GoSNMP) logPrintf(format string, v ...interface{}) { - if x.loggingEnabled { - x.Logger.Printf(format, v) - } -} - -// send/receive one snmp request -func (x *GoSNMP) sendOneRequest(packetOut *SnmpPacket, - wait bool) (result *SnmpPacket, err error) { - finalDeadline := time.Now().Add(x.Timeout) - - allReqIDs := make([]uint32, 0, x.Retries+1) - allMsgIDs := make([]uint32, 0, x.Retries+1) - for retries := 0; ; retries++ { - if retries > 0 { - x.logPrintf("Retry number %d. Last error was: %v", retries, err) - if time.Now().After(finalDeadline) { - err = fmt.Errorf("Request timeout (after %d retries)", retries-1) - break - } - if retries > x.Retries { - // Report last error - break - } - } - err = nil - - reqDeadline := time.Now().Add(x.Timeout / time.Duration(x.Retries+1)) - x.Conn.SetDeadline(reqDeadline) - - // Request ID is an atomic counter (started at a random value) - reqID := atomic.AddUint32(&(x.requestID), 1) // TODO: fix overflows - allReqIDs = append(allReqIDs, reqID) - - packetOut.RequestID = reqID - - if x.Version == Version3 { - msgID := atomic.AddUint32(&(x.msgID), 1) // TODO: fix overflows - allMsgIDs = append(allMsgIDs, msgID) - - packetOut.MsgID = msgID - - err = x.initPacket(packetOut) - if err != nil { - break - } - } - - var outBuf []byte - outBuf, err = packetOut.marshalMsg() - if err != nil { - // Don't retry - not going to get any better! - err = fmt.Errorf("marshal: %v", err) - break - } - - _, err = x.Conn.Write(outBuf) - if err != nil { - continue - } - - // all sends wait for the return packet, except for SNMPv2Trap - if wait == false { - return &SnmpPacket{}, nil - } - - for { - // Receive response and try receiving again on any decoding error. - // Let the deadline abort us if we don't receive a valid response. - - var resp []byte - resp, err = x.receive() - if err != nil { - // receive error. retrying won't help. abort - break - } - result = new(SnmpPacket) - result.Logger = x.Logger - - result.MsgFlags = packetOut.MsgFlags - if packetOut.SecurityParameters != nil { - result.SecurityParameters = packetOut.SecurityParameters.Copy() - } - - var cursor int - cursor, err = x.unmarshalHeader(resp, result) - if err != nil { - err = fmt.Errorf("Unable to decode packet: %s", err.Error()) - continue - } - - if x.Version == Version3 { - err = x.testAuthentication(resp, result) - if err != nil { - break - } - resp, cursor, err = x.decryptPacket(resp, cursor, result) - } - - err = x.unmarshalPayload(resp, cursor, result) - if err != nil { - err = fmt.Errorf("Unable to decode packet: %s", err.Error()) - continue - } - if result == nil || len(result.Variables) < 1 { - err = fmt.Errorf("Unable to decode packet: nil") - continue - } - - validID := false - for _, id := range allReqIDs { - if id == result.RequestID { - validID = true - } - } - if result.RequestID == 0 { - validID = true - } - if !validID { - if result.Version == Version3 { - // detect out-of-time-window error and go out of this function with all data - // (outside it will be handled and retransmitted ) - if len(result.Variables) == 1 && result.Variables[0].Name == ".1.3.6.1.6.3.15.1.1.2.0" { - break - } - } - err = fmt.Errorf("Out of order response") - continue - } - - break - } - if err != nil { - continue - } - - // Success! - return result, nil - } - - // Return last error - return nil, err -} - -// generic "sender" that negotiate any version of snmp request -// -// all sends wait for the return packet, except for SNMPv2Trap -func (x *GoSNMP) send(packetOut *SnmpPacket, wait bool) (result *SnmpPacket, err error) { - defer func() { - if e := recover(); e != nil { - err = fmt.Errorf("recover: %v", e) - } - }() - - if x.Conn == nil { - return nil, fmt.Errorf("&GoSNMP.Conn is missing. Provide a connection or use Connect()") - } - - if x.Retries < 0 { - x.Retries = 0 - } - - if packetOut.Version == Version3 { - if err = x.negotiateInitialSecurityParameters(packetOut, wait); err != nil { - return &SnmpPacket{}, err - } - } - - // perform request - result, err = x.sendOneRequest(packetOut, wait) - if err != nil { - return result, err - } - - if result.Version == Version3 { - err = x.storeSecurityParameters(result) - - // detect out-of-time-window error and retransmit with updated auth engine parameters - if len(result.Variables) == 1 && result.Variables[0].Name == ".1.3.6.1.6.3.15.1.1.2.0" { - err = x.updatePktSecurityParameters(packetOut) - if err != nil { - return nil, err - } - result, err = x.sendOneRequest(packetOut, wait) - } - } - return result, err -} - -// -- Marshalling Logic -------------------------------------------------------- - -// marshal an SNMP message -func (packet *SnmpPacket) marshalMsg() ([]byte, error) { - var err error - buf := new(bytes.Buffer) - - // version - buf.Write([]byte{2, 1, byte(packet.Version)}) - - if packet.Version == Version3 { - buf, err = packet.marshalV3(buf) - if err != nil { - return nil, err - } - } else { - // community - buf.Write([]byte{4, uint8(len(packet.Community))}) - buf.WriteString(packet.Community) - // pdu - pdu, err := packet.marshalPDU() - if err != nil { - return nil, err - } - buf.Write(pdu) - } - - // build up resulting msg - sequence, length then the tail (buf) - msg := new(bytes.Buffer) - msg.WriteByte(byte(Sequence)) - - bufLengthBytes, err2 := marshalLength(buf.Len()) - if err2 != nil { - return nil, err2 - } - msg.Write(bufLengthBytes) - buf.WriteTo(msg) // reverse logic - want to do msg.Write(buf) - - authenticatedMessage, err := packet.authenticate(msg.Bytes()) - if err != nil { - return nil, err - } - - return authenticatedMessage, nil -} - -// marshal a PDU -func (packet *SnmpPacket) marshalPDU() ([]byte, error) { - buf := new(bytes.Buffer) - - // requestid - buf.Write([]byte{2, 4}) - err := binary.Write(buf, binary.BigEndian, packet.RequestID) - if err != nil { - return nil, err - } - - if packet.PDUType == GetBulkRequest { - // non repeaters - buf.Write([]byte{2, 1, packet.NonRepeaters}) - - // max repetitions - buf.Write([]byte{2, 1, packet.MaxRepetitions}) - } else { // get and getnext have same packet format - - // error - buf.Write([]byte{2, 1, 0}) - - // error index - buf.Write([]byte{2, 1, 0}) - } - - // varbind list - vbl, err := packet.marshalVBL() - if err != nil { - return nil, err - } - buf.Write(vbl) - - // build up resulting pdu - request type, length, then the tail (buf) - pdu := new(bytes.Buffer) - pdu.WriteByte(byte(packet.PDUType)) - - bufLengthBytes, err2 := marshalLength(buf.Len()) - if err2 != nil { - return nil, err2 - } - pdu.Write(bufLengthBytes) - - buf.WriteTo(pdu) // reverse logic - want to do pdu.Write(buf) - return pdu.Bytes(), nil -} - -// marshal a varbind list -func (packet *SnmpPacket) marshalVBL() ([]byte, error) { - - vblBuf := new(bytes.Buffer) - for _, pdu := range packet.Variables { - vb, err := marshalVarbind(&pdu) - if err != nil { - return nil, err - } - vblBuf.Write(vb) - } - - vblBytes := vblBuf.Bytes() - vblLengthBytes, err := marshalLength(len(vblBytes)) - if err != nil { - return nil, err - } - - // FIX does bytes.Buffer give better performance than byte slices? - result := []byte{byte(Sequence)} - result = append(result, vblLengthBytes...) - result = append(result, vblBytes...) - return result, nil -} - -// marshal a varbind -func marshalVarbind(pdu *SnmpPDU) ([]byte, error) { - oid, err := marshalOID(pdu.Name) - if err != nil { - return nil, err - } - pduBuf := new(bytes.Buffer) - tmpBuf := new(bytes.Buffer) - - // Marshal the PDU type into the appropriate BER - switch pdu.Type { - - case Null: - pduBuf.Write([]byte{byte(Sequence), byte(len(oid) + 4)}) - pduBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))}) - pduBuf.Write(oid) - pduBuf.Write([]byte{Null, 0x00}) - - /* - NUMBERS: - - Integer32 and INTEGER: - -2^31 and 2^31-1 inclusive (-2147483648 to 2147483647 decimal) - - Counter32, Gauge32, TimeTicks, Unsigned32: - non-negative integer, maximum value of 2^32-1 (4294967295 decimal) - */ - - case Integer: - // TODO tests currently only cover positive integers - - // Oid - tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))}) - tmpBuf.Write(oid) - - // Number - var intBytes []byte - switch value := pdu.Value.(type) { - case byte: - intBytes = []byte{byte(pdu.Value.(int))} - case int: - intBytes, err = marshalInt16(value) - pdu.Check(err) - default: - return nil, fmt.Errorf("Unable to marshal PDU Integer; not byte or int.") - } - tmpBuf.Write([]byte{byte(Integer), byte(len(intBytes))}) - tmpBuf.Write(intBytes) - - // Sequence, length of oid + integer, then oid/integer data - pduBuf.WriteByte(byte(Sequence)) - pduBuf.WriteByte(byte(len(oid) + len(intBytes) + 4)) - pduBuf.Write(tmpBuf.Bytes()) - - case Counter32, Gauge32, TimeTicks, Uinteger32: - // Oid - tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))}) - tmpBuf.Write(oid) - - // Number - var intBytes []byte - switch value := pdu.Value.(type) { - case uint32: - intBytes, err = marshalUint32(value) - pdu.Check(err) - default: - return nil, fmt.Errorf("Unable to marshal pdu.Type %v; unknown pdu.Value %v", pdu.Type, pdu.Value) - } - tmpBuf.Write([]byte{byte(pdu.Type), byte(len(intBytes))}) - tmpBuf.Write(intBytes) - - // Sequence, length of oid + integer, then oid/integer data - pduBuf.WriteByte(byte(Sequence)) - pduBuf.WriteByte(byte(len(oid) + len(intBytes) + 4)) - pduBuf.Write(tmpBuf.Bytes()) - - case OctetString: - - //Oid - tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))}) - tmpBuf.Write(oid) - - //OctetString - var octetStringBytes []byte - switch value := pdu.Value.(type) { - case []byte: - octetStringBytes = value - case string: - octetStringBytes = []byte(value) - default: - return nil, fmt.Errorf("Unable to marshal PDU OctetString; not []byte or String.") - } - - var length []byte - length, err = marshalLength(len(octetStringBytes)) - if err != nil { - return nil, err - } - tmpBuf.WriteByte(byte(OctetString)) - tmpBuf.Write(length) - tmpBuf.Write(octetStringBytes) - - tmpBytes := tmpBuf.Bytes() - - length, err = marshalLength(len(tmpBytes)) - if err != nil { - return nil, err - } - // Sequence, length of oid + octetstring, then oid/octetstring data - pduBuf.WriteByte(byte(Sequence)) - - pduBuf.Write(length) - pduBuf.Write(tmpBytes) - - case ObjectIdentifier: - - //Oid - tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))}) - tmpBuf.Write(oid) - value := pdu.Value.(string) - oidBytes, err := marshalOID(value) - pdu.Check(err) - - //Oid data - var length []byte - length, err = marshalLength(len(oidBytes)) - if err != nil { - return nil, err - } - tmpBuf.WriteByte(byte(pdu.Type)) - tmpBuf.Write(length) - tmpBuf.Write(oidBytes) - - tmpBytes := tmpBuf.Bytes() - length, err = marshalLength(len(tmpBytes)) - if err != nil { - return nil, err - } - // Sequence, length of oid + oid, then oid/oid data - pduBuf.WriteByte(byte(Sequence)) - pduBuf.Write(length) - pduBuf.Write(tmpBytes) - - // MrSpock changes. TODO NO tests for this yet - waiting for .pcap - case IPAddress: - //Oid - tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))}) - tmpBuf.Write(oid) - //OctetString - var ipAddressBytes []byte - switch value := pdu.Value.(type) { - case []byte: - ipAddressBytes = value - case string: - ip := net.ParseIP(value) - ipAddressBytes = ipv4toBytes(ip) - default: - return nil, fmt.Errorf("Unable to marshal PDU IPAddress; not []byte or String.") - } - tmpBuf.Write([]byte{byte(IPAddress), byte(len(ipAddressBytes))}) - tmpBuf.Write(ipAddressBytes) - // Sequence, length of oid + octetstring, then oid/octetstring data - pduBuf.WriteByte(byte(Sequence)) - pduBuf.WriteByte(byte(len(oid) + len(ipAddressBytes) + 4)) - pduBuf.Write(tmpBuf.Bytes()) - - default: - return nil, fmt.Errorf("Unable to marshal PDU: unknown BER type %q", pdu.Type) - } - - return pduBuf.Bytes(), nil -} - -// -- Unmarshalling Logic ------------------------------------------------------ - -func (x *GoSNMP) unmarshalHeader(packet []byte, response *SnmpPacket) (int, error) { - if len(packet) < 2 { - return 0, fmt.Errorf("Cannot unmarshal empty packet") - } - if response == nil { - return 0, fmt.Errorf("Cannot unmarshal response into nil packet reference") - } - - response.Variables = make([]SnmpPDU, 0, 5) - - // Start parsing the packet - cursor := 0 - - // First bytes should be 0x30 - if PDUType(packet[0]) != Sequence { - return 0, fmt.Errorf("Invalid packet header\n") - } - - length, cursor := parseLength(packet) - if len(packet) != length { - return 0, fmt.Errorf("Error verifying packet sanity: Got %d Expected: %d\n", len(packet), length) - } - x.logPrintf("Packet sanity verified, we got all the bytes (%d)", length) - - // Parse SNMP Version - rawVersion, count, err := parseRawField(packet[cursor:], "version") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMP packet version: %s", err.Error()) - } - - cursor += count - if version, ok := rawVersion.(int); ok { - response.Version = SnmpVersion(version) - x.logPrintf("Parsed version %d", version) - } - - if response.Version == Version3 { - cursor, err = x.unmarshalV3Header(packet, cursor, response) - if err != nil { - return 0, err - } - } else { - // Parse community - rawCommunity, count, err := parseRawField(packet[cursor:], "community") - if err != nil { - return 0, fmt.Errorf("Error parsing community string: %s", err.Error()) - } - cursor += count - if community, ok := rawCommunity.(string); ok { - response.Community = community - x.logPrintf("Parsed community %s", community) - } - } - return cursor, nil -} - -func (x *GoSNMP) unmarshalPayload(packet []byte, cursor int, response *SnmpPacket) error { - var err error - // Parse SNMP packet type - requestType := PDUType(packet[cursor]) - switch requestType { - // known, supported types - case GetResponse, GetNextRequest, GetBulkRequest, Report, SNMPv2Trap: - response.PDUType = requestType - err = x.unmarshalResponse(packet[cursor:], response) - if err != nil { - return fmt.Errorf("Error in unmarshalResponse: %s", err.Error()) - } - case Trap: - response.PDUType = requestType - err = x.unmarshalTrapV1(packet[cursor:], response) - if err != nil { - return fmt.Errorf("Error in unmarshalTrapV1: %s", err.Error()) - } - default: - return fmt.Errorf("Unknown PDUType %#x", requestType) - } - return nil -} - -func (x *GoSNMP) unmarshalResponse(packet []byte, response *SnmpPacket) error { - cursor := 0 - - getResponseLength, cursor := parseLength(packet) - if len(packet) != getResponseLength { - return fmt.Errorf("Error verifying Response sanity: Got %d Expected: %d\n", len(packet), getResponseLength) - } - x.logPrintf("getResponseLength: %d", getResponseLength) - - // Parse Request-ID - rawRequestID, count, err := parseRawField(packet[cursor:], "request id") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet request ID: %s", err.Error()) - } - cursor += count - if requestid, ok := rawRequestID.(int); ok { - response.RequestID = uint32(requestid) - x.logPrintf("requestID: %d", response.RequestID) - } - - if response.PDUType == GetBulkRequest { - // Parse Non Repeaters - rawNonRepeaters, count, err := parseRawField(packet[cursor:], "non repeaters") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet non repeaters: %s", err.Error()) - } - cursor += count - if nonRepeaters, ok := rawNonRepeaters.(int); ok { - response.NonRepeaters = uint8(nonRepeaters) - } - - // Parse Max Repetitions - rawMaxRepetitions, count, err := parseRawField(packet[cursor:], "max repetitions") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet max repetitions: %s", err.Error()) - } - cursor += count - if maxRepetitions, ok := rawMaxRepetitions.(int); ok { - response.MaxRepetitions = uint8(maxRepetitions) - } - } else { - // Parse Error-Status - rawError, count, err := parseRawField(packet[cursor:], "error-status") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error: %s", err.Error()) - } - cursor += count - if errorStatus, ok := rawError.(int); ok { - response.Error = SNMPError(errorStatus) - x.logPrintf("errorStatus: %d", uint8(errorStatus)) - } - - // Parse Error-Index - rawErrorIndex, count, err := parseRawField(packet[cursor:], "error index") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error index: %s", err.Error()) - } - cursor += count - if errorindex, ok := rawErrorIndex.(int); ok { - response.ErrorIndex = uint8(errorindex) - x.logPrintf("error-index: %d", uint8(errorindex)) - } - } - - return x.unmarshalVBL(packet[cursor:], response) -} - -func (x *GoSNMP) unmarshalTrapV1(packet []byte, response *SnmpPacket) error { - cursor := 0 - - getResponseLength, cursor := parseLength(packet) - if len(packet) != getResponseLength { - return fmt.Errorf("Error verifying Response sanity: Got %d Expected: %d\n", len(packet), getResponseLength) - } - x.logPrintf("getResponseLength: %d", getResponseLength) - - // Parse Enterprise - rawEnterprise, count, err := parseRawField(packet[cursor:], "enterprise") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error: %s", err.Error()) - } - cursor += count - if Enterpise, ok := rawEnterprise.([]int); ok { - response.Enterprise = Enterpise - x.logPrintf("Enterprise: %+v", Enterpise) - } - - // Parse AgentAddr - rawAgentAddr, count, err := parseRawField(packet[cursor:], "agent-addr") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error: %s", err.Error()) - } - cursor += count - if AgentAddr, ok := rawAgentAddr.(string); ok { - response.AgentAddr = AgentAddr - x.logPrintf("AgentAddr: %s", AgentAddr) - } - - // Parse GenericTrap - rawGenericTrap, count, err := parseRawField(packet[cursor:], "generic-trap") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error: %s", err.Error()) - } - cursor += count - if GenericTrap, ok := rawGenericTrap.(int); ok { - response.GenericTrap = GenericTrap - x.logPrintf("GenericTrap: %d", GenericTrap) - } - - // Parse SpecificTrap - rawSpecificTrap, count, err := parseRawField(packet[cursor:], "specific-trap") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error: %s", err.Error()) - } - cursor += count - if SpecificTrap, ok := rawSpecificTrap.(int); ok { - response.SpecificTrap = SpecificTrap - x.logPrintf("SpecificTrap: %d", SpecificTrap) - } - - // Parse TimeStamp - rawTimestamp, count, err := parseRawField(packet[cursor:], "time-stamp") - if err != nil { - return fmt.Errorf("Error parsing SNMP packet error: %s", err.Error()) - } - cursor += count - if Timestamp, ok := rawTimestamp.(int); ok { - response.Timestamp = Timestamp - x.logPrintf("Timestamp: %d", Timestamp) - } - - return x.unmarshalVBL(packet[cursor:], response) -} - -// unmarshal a Varbind list -func (x *GoSNMP) unmarshalVBL(packet []byte, response *SnmpPacket) error { - - var cursor, cursorInc int - var vblLength int - if packet[cursor] != 0x30 { - return fmt.Errorf("Expected a sequence when unmarshalling a VBL, got %x", packet[cursor]) - } - - vblLength, cursor = parseLength(packet) - if len(packet) != vblLength { - return fmt.Errorf("Error verifying: packet length %d vbl length %d\n", len(packet), vblLength) - } - x.logPrintf("vblLength: %d", vblLength) - - // check for an empty response - if vblLength == 2 && packet[1] == 0x00 { - return nil - } - - // Loop & parse Varbinds - for cursor < vblLength { - if packet[cursor] != 0x30 { - return fmt.Errorf("Expected a sequence when unmarshalling a VB, got %x", packet[cursor]) - } - - _, cursorInc = parseLength(packet[cursor:]) - cursor += cursorInc - - // Parse OID - rawOid, oidLength, err := parseRawField(packet[cursor:], "OID") - if err != nil { - return fmt.Errorf("Error parsing OID Value: %s", err.Error()) - } - cursor += oidLength - - var oid []int - var ok bool - if oid, ok = rawOid.([]int); !ok { - return fmt.Errorf("unable to type assert rawOid |%v| to []int", rawOid) - } - oidStr := oidToString(oid) - x.logPrintf("OID: %s", oidStr) - - // Parse Value - v, err := x.decodeValue(packet[cursor:], "value") - if err != nil { - return fmt.Errorf("Error decoding value: %v", err) - } - valueLength, _ := parseLength(packet[cursor:]) - cursor += valueLength - response.Variables = append(response.Variables, SnmpPDU{oidStr, v.Type, v.Value, x.Logger}) - } - return nil -} - -// receive response from network and read into a byte array -func (x *GoSNMP) receive() ([]byte, error) { - n, err := x.Conn.Read(x.rxBuf[:]) - if err != nil { - return nil, fmt.Errorf("Error reading from UDP: %s", err.Error()) - } - - if n == rxBufSize { - // This should never happen unless we're using something like a unix domain socket. - return nil, fmt.Errorf("response buffer too small") - } - - resp := make([]byte, n) - copy(resp, x.rxBuf[:n]) - return resp, nil -} diff --git a/vendor/github.com/soniah/gosnmp/marshal_test.go b/vendor/github.com/soniah/gosnmp/marshal_test.go deleted file mode 100644 index 554ea11d..00000000 --- a/vendor/github.com/soniah/gosnmp/marshal_test.go +++ /dev/null @@ -1,1402 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import ( - "bytes" - "io/ioutil" - "log" - "net" - "testing" - "time" -) - -// Tests in alphabetical order of function being tested - -// -- Enmarshal ---------------------------------------------------------------- - -// "Enmarshal" not "Marshal" - easier to select tests via a regex - -type testsEnmarshalVarbindPosition struct { - oid string - - /* - start and finish position of bytes are calculated with application layer - starting at byte 0. There are two ways to understand Wireshark dumps, - switch between them: - - 1) the standard decode of the full packet - easier to understand - what's actually happening - - 2) for counting byte positions: select "Simple Network Management - Protocal" line in Wiresharks middle pane, then right click and choose - "Export Packet Bytes..." (as .raw). Open the capture in wireshark, it - will decode as "BER Encoded File". Click on each varbind and the - "packet bytes" window will highlight the corresponding bytes, then the - start and end positions can be found. - */ - - /* - go-bindata has changed output format. Old style is needed: - - go get -u github.com/jteeuwen/go-bindata/... - git co 79847ab - rm ~/go/bin/go-bindata # belts and braces - go install - ~/go/bin/go-bindata -uncompressed *.pcap - */ - - start int - finish int - pduType Asn1BER - pduValue interface{} -} - -type testsEnmarshalT struct { - version SnmpVersion - community string - requestType PDUType - requestid uint32 - msgid uint32 - // function and function name returning bytes from tcpdump - goodBytes func() []byte - funcName string // could do this via reflection - // start position of the pdu - pduStart int - // start position of the vbl - vblStart int - // finish position of pdu, vbl and message - all the same - finish int - // a slice of positions containing start and finish of each varbind - vbPositions []testsEnmarshalVarbindPosition -} - -var testsEnmarshal = []testsEnmarshalT{ - { - Version2c, - "public", - GetRequest, - 1871507044, - 0, - kyoceraRequestBytes, - "kyocera_request", - 0x0e, // pdu start - 0x1d, // vbl start - 0xa0, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.2.1.1.7.0", 0x20, 0x2d, Null, nil}, - {".1.3.6.1.2.1.2.2.1.10.1", 0x2e, 0x3d, Null, nil}, - {".1.3.6.1.2.1.2.2.1.5.1", 0x3e, 0x4d, Null, nil}, - {".1.3.6.1.2.1.1.4.0", 0x4e, 0x5b, Null, nil}, - {".1.3.6.1.2.1.43.5.1.1.15.1", 0x5c, 0x6c, Null, nil}, - {".1.3.6.1.2.1.4.21.1.1.127.0.0.1", 0x6d, 0x7f, Null, nil}, - {".1.3.6.1.4.1.23.2.5.1.1.1.4.2", 0x80, 0x92, Null, nil}, - {".1.3.6.1.2.1.1.3.0", 0x93, 0xa0, Null, nil}, - }, - }, - { - Version1, - "privatelab", - SetRequest, - 526895288, - 0, - portOnOutgoing1, - "portOnOutgoing1", - 0x11, // pdu start - 0x1f, // vbl start - 0x36, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.4.1.318.1.1.4.4.2.1.3.5", 0x21, 0x36, Integer, 1}, - }, - }, - { - Version1, - "privatelab", - SetRequest, - 1826072803, - 0, - portOffOutgoing1, - "portOffOutgoing1", - 0x11, // pdu start - 0x1f, // vbl start - 0x36, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.4.1.318.1.1.4.4.2.1.3.5", 0x21, 0x36, Integer, 2}, - }, - }, - // MrSpock Set stuff - { - Version2c, - "private", - SetRequest, - 756726019, - 0, - setOctet1, - "setOctet1", - 0x0e, // pdu start - 0x1c, // vbl start - 0x32, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.4.1.2863.205.1.1.75.1.0", - 0x1e, 0x32, OctetString, []byte{0x80}}, - }, - }, - { - Version2c, - "private", - SetRequest, - 1000552357, - 0, - setOctet2, - "setOctet2", - 0x0e, // pdu start - 0x1c, // vbl start - 0x37, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.4.1.2863.205.1.1.75.2.0", - 0x1e, 0x36, OctetString, "telnet"}, - }, - }, - // MrSpock Set stuff - { - Version2c, - "private", - SetRequest, - 1664317637, - 0, - setInteger1, - "setInteger1", - 0x0e, // pdu start - 0x1c, // vbl start - 0x7f, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.4.1.2863.205.10.1.33.2.5.1.2.2", 0x1e, 0x36, Integer, 5001}, - {".1.3.6.1.4.1.2863.205.10.1.33.2.5.1.3.2", 0x37, 0x4f, Integer, 5001}, - {".1.3.6.1.4.1.2863.205.10.1.33.2.5.1.4.2", 0x50, 0x67, Integer, 2}, - {".1.3.6.1.4.1.2863.205.10.1.33.2.5.1.5.2", 0x68, 0x7f, Integer, 1}, - }, - }, - // Issue 35, empty responses. - { - Version2c, - "public", - GetRequest, - 1883298028, - 0, - emptyErrRequest, - "emptyErrRequest", - 0x0d, // pdu start - 0x1b, // vbl start - 0x1c, // finish - []testsEnmarshalVarbindPosition{}, - }, - // trap - TimeTicks - // snmptrap different with timetick 2, integer 5 - - // trap1 - capture is from frame - less work, decode easier - // varbinds - because Wireshark is decoding as BER's, need to subtract 2 - // from start of varbinds - { - Version2c, - "public", - SNMPv2Trap, - 1918693186, - 0, - trap1, - "trap1", - 0x0e, // pdu start - 0x1c, // vbl start - 0x82, // finish - []testsEnmarshalVarbindPosition{ - {".1.3.6.1.2.1.1.3.0", 0x1e, 0x2f, TimeTicks, uint32(18542501)}, - {".1.3.6.1.6.3.1.1.4.1.0", 0x30, 0x45, ObjectIdentifier, ".1.3.6.1.2.1.1"}, - {".1.3.6.1.2.1.1.1.0", 0x46, 0x59, OctetString, "red laptop"}, - {".1.3.6.1.2.1.1.7.0", 0x5e, 0x6c, Integer, 5}, - {".1.3.6.1.2.1.1.2", 0x6d, 0x82, ObjectIdentifier, ".1.3.6.1.4.1.2.3.4.5"}, - }, - }, -} - -// helpers for Enmarshal tests - -// vbPosPdus returns a slice of oids in the given test -func vbPosPdus(test testsEnmarshalT) (pdus []SnmpPDU) { - for _, vbp := range test.vbPositions { - pdu := SnmpPDU{vbp.oid, vbp.pduType, vbp.pduValue, nil} - pdus = append(pdus, pdu) - } - return -} - -// checkByteEquality walks the bytes in testBytes, and compares them to goodBytes -func checkByteEquality(t *testing.T, test testsEnmarshalT, testBytes []byte, - start int, finish int) { - - testBytesLen := len(testBytes) - - goodBytes := test.goodBytes() - goodBytes = goodBytes[start : finish+1] - for cursor := range goodBytes { - if testBytesLen < cursor { - t.Errorf("%s: testBytesLen (%d) < cursor (%d)", test.funcName, - testBytesLen, cursor) - break - } - if testBytes[cursor] != goodBytes[cursor] { - t.Errorf("%s: cursor %d: testBytes != goodBytes:\n%s\n%s", - test.funcName, - cursor, - dumpBytes2("good", goodBytes, cursor), - dumpBytes2("test", testBytes, cursor)) - break - } - } -} - -// Enmarshal tests in order that should be used for troubleshooting -// ie check each varbind is working, then the varbind list, etc - -func TestEnmarshalVarbind(t *testing.T) { - Default.Logger = log.New(ioutil.Discard, "", 0) - - for _, test := range testsEnmarshal { - for j, test2 := range test.vbPositions { - snmppdu := &SnmpPDU{test2.oid, test2.pduType, test2.pduValue, nil} - testBytes, err := marshalVarbind(snmppdu) - if err != nil { - t.Errorf("#%s:%d:%s err returned: %v", - test.funcName, j, test2.oid, err) - } - - checkByteEquality(t, test, testBytes, test2.start, test2.finish) - } - } -} - -func TestEnmarshalVBL(t *testing.T) { - Default.Logger = log.New(ioutil.Discard, "", 0) - - for _, test := range testsEnmarshal { - x := &SnmpPacket{ - Community: test.community, - Version: test.version, - RequestID: test.requestid, - Variables: vbPosPdus(test), - } - - testBytes, err := x.marshalVBL() - if err != nil { - t.Errorf("#%s: marshalVBL() err returned: %v", test.funcName, err) - } - - checkByteEquality(t, test, testBytes, test.vblStart, test.finish) - } -} - -func TestEnmarshalPDU(t *testing.T) { - Default.Logger = log.New(ioutil.Discard, "", 0) - - for _, test := range testsEnmarshal { - x := &SnmpPacket{ - Community: test.community, - Version: test.version, - PDUType: test.requestType, - RequestID: test.requestid, - Variables: vbPosPdus(test), - } - - testBytes, err := x.marshalPDU() - if err != nil { - t.Errorf("#%s: marshalPDU() err returned: %v", test.funcName, err) - } - - checkByteEquality(t, test, testBytes, test.pduStart, test.finish) - } -} - -func TestEnmarshalMsg(t *testing.T) { - Default.Logger = log.New(ioutil.Discard, "", 0) - - for _, test := range testsEnmarshal { - x := &SnmpPacket{ - Community: test.community, - Version: test.version, - PDUType: test.requestType, - RequestID: test.requestid, - MsgID: test.msgid, - Variables: vbPosPdus(test), - } - - testBytes, err := x.marshalMsg() - if err != nil { - t.Errorf("#%s: marshal() err returned: %v", test.funcName, err) - } - checkByteEquality(t, test, testBytes, 0, test.finish) - } -} - -// -- Unmarshal ----------------------------------------------------------------- - -var testsUnmarshal = []struct { - in func() []byte - out *SnmpPacket -}{ - {kyoceraResponseBytes, - &SnmpPacket{ - Version: Version2c, - Community: "public", - PDUType: GetResponse, - RequestID: 1066889284, - Error: 0, - ErrorIndex: 0, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.2.1.1.7.0", - Type: Integer, - Value: 104, - }, - { - Name: ".1.3.6.1.2.1.2.2.1.10.1", - Type: Counter32, - Value: 271070065, - }, - { - Name: ".1.3.6.1.2.1.2.2.1.5.1", - Type: Gauge32, - Value: 100000000, - }, - { - Name: ".1.3.6.1.2.1.1.4.0", - Type: OctetString, - Value: []byte("Administrator"), - }, - { - Name: ".1.3.6.1.2.1.43.5.1.1.15.1", - Type: Null, - Value: nil, - }, - { - Name: ".1.3.6.1.2.1.4.21.1.1.127.0.0.1", - Type: IPAddress, - Value: "127.0.0.1", - }, - { - Name: ".1.3.6.1.4.1.23.2.5.1.1.1.4.2", - Type: OctetString, - Value: []byte{0x00, 0x15, 0x99, 0x37, 0x76, 0x2b}, - }, - { - Name: ".1.3.6.1.2.1.1.3.0", - Type: TimeTicks, - Value: 318870100, - }, - }, - }, - }, - {ciscoResponseBytes, - &SnmpPacket{ - Version: Version2c, - Community: "public", - PDUType: GetResponse, - RequestID: 4876669, - Error: 0, - ErrorIndex: 0, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.2.1.1.7.0", - Type: Integer, - Value: 78, - }, - { - Name: ".1.3.6.1.2.1.2.2.1.2.6", - Type: OctetString, - Value: []byte("GigabitEthernet0"), - }, - { - Name: ".1.3.6.1.2.1.2.2.1.5.3", - Type: Gauge32, - Value: uint(4294967295), - }, - { - Name: ".1.3.6.1.2.1.2.2.1.7.2", - Type: NoSuchInstance, - Value: nil, - }, - { - Name: ".1.3.6.1.2.1.2.2.1.9.3", - Type: TimeTicks, - Value: 2970, - }, - { - Name: ".1.3.6.1.2.1.3.1.1.2.10.1.10.11.0.17", - Type: OctetString, - Value: []byte{0x00, 0x07, 0x7d, 0x4d, 0x09, 0x00}, - }, - { - Name: ".1.3.6.1.2.1.3.1.1.3.10.1.10.11.0.2", - Type: IPAddress, - Value: "10.11.0.2", - }, - { - Name: ".1.3.6.1.2.1.4.20.1.1.110.143.197.1", - Type: IPAddress, - Value: "110.143.197.1", - }, - { - Name: ".1.3.6.1.66.1", - Type: NoSuchObject, - Value: nil, - }, - { - Name: ".1.3.6.1.2.1.1.2.0", - Type: ObjectIdentifier, - Value: ".1.3.6.1.4.1.9.1.1166", - }, - }, - }, - }, - {portOnIncoming1, - &SnmpPacket{ - Version: Version1, - Community: "privatelab", - PDUType: GetResponse, - RequestID: 526895288, - Error: 0, - ErrorIndex: 0, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.4.1.318.1.1.4.4.2.1.3.5", - Type: Integer, - Value: 1, - }, - }, - }, - }, - {portOffIncoming1, - &SnmpPacket{ - Version: Version1, - Community: "privatelab", - PDUType: GetResponse, - RequestID: 1826072803, - Error: 0, - ErrorIndex: 0, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.4.1.318.1.1.4.4.2.1.3.5", - Type: Integer, - Value: 2, - }, - }, - }, - }, - {ciscoGetnextResponseBytes, - &SnmpPacket{ - Version: Version2c, - Community: "public", - PDUType: GetResponse, - RequestID: 1528674030, - Error: 0, - ErrorIndex: 0, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.2.1.3.1.1.3.2.1.192.168.104.2", - Type: IPAddress, - Value: "192.168.104.2", - }, - { - Name: ".1.3.6.1.2.1.92.1.2.1.0", - Type: Counter32, - Value: 0, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.3.3", - Type: OctetString, - Value: []byte("The MIB module for managing IP and ICMP implementations"), - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.2", - Type: TimeTicks, - Value: 21, - }, - { - Name: ".1.3.6.1.2.1.2.1.0", - Type: Integer, - Value: 3, - }, - { - Name: ".1.3.6.1.2.1.1.2.0", - Type: ObjectIdentifier, - Value: ".1.3.6.1.4.1.8072.3.2.10", - }, - }, - }, - }, - {ciscoGetbulkResponseBytes, - &SnmpPacket{ - Version: Version2c, - Community: "public", - PDUType: GetResponse, - RequestID: 250000266, - NonRepeaters: 0, - MaxRepetitions: 10, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.2.1.1.9.1.4.1", - Type: TimeTicks, - Value: 21, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.2", - Type: TimeTicks, - Value: 21, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.3", - Type: TimeTicks, - Value: 21, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.4", - Type: TimeTicks, - Value: 21, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.5", - Type: TimeTicks, - Value: 21, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.6", - Type: TimeTicks, - Value: 23, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.7", - Type: TimeTicks, - Value: 23, - }, - { - Name: ".1.3.6.1.2.1.1.9.1.4.8", - Type: TimeTicks, - Value: 23, - }, - { - Name: ".1.3.6.1.2.1.2.1.0", - Type: Integer, - Value: 3, - }, - { - Name: ".1.3.6.1.2.1.2.2.1.1.1", - Type: Integer, - Value: 1, - }, - }, - }, - }, - {emptyErrResponse, - &SnmpPacket{ - Version: Version2c, - Community: "public", - PDUType: GetResponse, - RequestID: 1883298028, - Error: 0, - Variables: []SnmpPDU{}, - }, - }, - {counter64Response, - &SnmpPacket{ - Version: Version2c, - Community: "public", - PDUType: GetResponse, - RequestID: 190378322, - Error: 0, - ErrorIndex: 0, - Variables: []SnmpPDU{ - { - Name: ".1.3.6.1.2.1.31.1.1.1.10.1", - Type: Counter64, - Value: 1527943, - }, - }, - }, - }, -} - -func TestUnmarshal(t *testing.T) { - Default.Logger = log.New(ioutil.Discard, "", 0) - -SANITY: - for i, test := range testsUnmarshal { - var err error - var res = new(SnmpPacket) - var cursor int - - var buf = test.in() - cursor, err = Default.unmarshalHeader(buf, res) - if err != nil { - t.Errorf("#%d, UnmarshalHeader returned err: %v", i, err) - continue SANITY - } - if res.Version == Version3 { - buf, cursor, err = Default.decryptPacket(buf, cursor, res) - if err != nil { - t.Errorf("#%d, decryptPacket returned err: %v", i, err) - } - } - err = Default.unmarshalPayload(test.in(), cursor, res) - if err != nil { - t.Errorf("#%d, UnmarshalPayload returned err: %v", i, err) - } - if res == nil { - t.Errorf("#%d, Unmarshal returned nil", i) - continue SANITY - } - - // test "header" fields - if res.Version != test.out.Version { - t.Errorf("#%d Version result: %v, test: %v", i, res.Version, test.out.Version) - } - if res.Community != test.out.Community { - t.Errorf("#%d Community result: %v, test: %v", i, res.Community, test.out.Community) - } - if res.PDUType != test.out.PDUType { - t.Errorf("#%d PDUType result: %v, test: %v", i, res.PDUType, test.out.PDUType) - } - if res.RequestID != test.out.RequestID { - t.Errorf("#%d RequestID result: %v, test: %v", i, res.RequestID, test.out.RequestID) - } - if res.Error != test.out.Error { - t.Errorf("#%d Error result: %v, test: %v", i, res.Error, test.out.Error) - } - if res.ErrorIndex != test.out.ErrorIndex { - t.Errorf("#%d ErrorIndex result: %v, test: %v", i, res.ErrorIndex, test.out.ErrorIndex) - } - - // test varbind values - for n, vb := range test.out.Variables { - if len(res.Variables) < n { - t.Errorf("#%d:%d ran out of varbind results", i, n) - continue SANITY - } - vbr := res.Variables[n] - - if vbr.Name != vb.Name { - t.Errorf("#%d:%d Name result: %v, test: %v", i, n, vbr.Name, vb.Name) - } - if vbr.Type != vb.Type { - t.Errorf("#%d:%d Type result: %v, test: %v", i, n, vbr.Type, vb.Type) - } - - switch vb.Type { - case Integer, Gauge32, Counter32, TimeTicks, Counter64: - vbval := ToBigInt(vb.Value) - vbrval := ToBigInt(vbr.Value) - if vbval.Cmp(vbrval) != 0 { - t.Errorf("#%d:%d Value result: %v, test: %v", i, n, vbr.Value, vb.Value) - } - case OctetString: - if !bytes.Equal(vb.Value.([]byte), vbr.Value.([]byte)) { - t.Errorf("#%d:%d Value result: %v, test: %v", i, n, vbr.Value, vb.Value) - } - case IPAddress, ObjectIdentifier: - if vb.Value != vbr.Value { - t.Errorf("#%d:%d Value result: %v, test: %v", i, n, vbr.Value, vb.Value) - } - case Null, NoSuchObject, NoSuchInstance: - if (vb.Value != nil) || (vbr.Value != nil) { - t.Errorf("#%d:%d Value result: %v, test: %v", i, n, vbr.Value, vb.Value) - } - default: - t.Errorf("#%d:%d Unhandled case result: %v, test: %v", i, n, vbr.Value, vb.Value) - } - - } - } -} - -// ----------------------------------------------------------------------------- - -/* - -* byte dumps generated using tcpdump and github.com/jteeuwen/go-bindata eg - `sudo tcpdump -s 0 -i eth0 -w cisco.pcap host 203.50.251.17 and port 161` - -* Frame, Ethernet II, IP and UDP layers removed from generated bytes -*/ - -/* -kyoceraResponseBytes corresponds to the response section of this snmpget - -Simple Network Management Protocol - version: v2c (1) - community: public - data: get-response (2) - get-response - request-id: 1066889284 - error-status: noError (0) - error-index: 0 - variable-bindings: 8 items - 1.3.6.1.2.1.1.7.0: 104 - 1.3.6.1.2.1.2.2.1.10.1: 271070065 - 1.3.6.1.2.1.2.2.1.5.1: 100000000 - 1.3.6.1.2.1.1.4.0: 41646d696e6973747261746f72 - 1.3.6.1.2.1.43.5.1.1.15.1: Value (Null) - 1.3.6.1.2.1.4.21.1.1.127.0.0.1: 127.0.0.1 (127.0.0.1) - 1.3.6.1.4.1.23.2.5.1.1.1.4.2: 00159937762b - 1.3.6.1.2.1.1.3.0: 318870100 -*/ - -func kyoceraResponseBytes() []byte { - return []byte{ - 0x30, 0x81, 0xc2, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0xa2, 0x81, 0xb4, 0x02, 0x04, 0x3f, 0x97, 0x70, 0x44, 0x02, - 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x81, 0xa5, 0x30, 0x0d, 0x06, 0x08, - 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x07, 0x00, 0x02, 0x01, 0x68, 0x30, - 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x0a, - 0x01, 0x41, 0x04, 0x10, 0x28, 0x33, 0x71, 0x30, 0x12, 0x06, 0x0a, 0x2b, - 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x05, 0x01, 0x42, 0x04, 0x05, - 0xf5, 0xe1, 0x00, 0x30, 0x19, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, - 0x01, 0x04, 0x00, 0x04, 0x0d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, - 0x01, 0x02, 0x01, 0x2b, 0x05, 0x01, 0x01, 0x0f, 0x01, 0x05, 0x00, 0x30, - 0x15, 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x04, 0x15, 0x01, 0x01, - 0x7f, 0x00, 0x00, 0x01, 0x40, 0x04, 0x7f, 0x00, 0x00, 0x01, 0x30, 0x17, - 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x17, 0x02, 0x05, 0x01, 0x01, - 0x01, 0x04, 0x02, 0x04, 0x06, 0x00, 0x15, 0x99, 0x37, 0x76, 0x2b, 0x30, - 0x10, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00, 0x43, - 0x04, 0x13, 0x01, 0x92, 0x54, - } -} - -/* -ciscoResponseBytes corresponds to the response section of this snmpget: - -% 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.2.2.1.7.2 1.3.6.1.2.1.2.2.1.9.3 1.3.6.1.2.1.3.1.1.2.10.1.10.11.0.17 1.3.6.1.2.1.3.1.1.3.10.1.10.11.0.2 1.3.6.1.2.1.4.20.1.1.110.143.197.1 1.3.6.1.66.1 1.3.6.1.2.1.1.2.0 -.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 -.1.3.6.1.2.1.2.2.1.7.2 = No Such Instance currently exists at this OID -.1.3.6.1.2.1.2.2.1.9.3 = Timeticks: (2970) 0:00:29.70 -.1.3.6.1.2.1.3.1.1.2.10.1.10.11.0.17 = Hex-STRING: 00 07 7D 4D 09 00 -.1.3.6.1.2.1.3.1.1.3.10.1.10.11.0.2 = Network Address: 0A:0B:00:02 -.1.3.6.1.2.1.4.20.1.1.110.143.197.1 = IPAddress: 110.143.197.1 -.1.3.6.1.66.1 = No Such Object available on this agent at this OID -.1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.9.1.1166 -*/ - -func ciscoResponseBytes() []byte { - return []byte{ - 0x30, 0x81, - 0xf1, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0xa2, 0x81, 0xe3, 0x02, 0x03, 0x4a, 0x69, 0x7d, 0x02, 0x01, 0x00, 0x02, - 0x01, 0x00, 0x30, 0x81, 0xd5, 0x30, 0x0d, 0x06, 0x08, 0x2b, 0x06, 0x01, - 0x02, 0x01, 0x01, 0x07, 0x00, 0x02, 0x01, 0x4e, 0x30, 0x1e, 0x06, 0x0a, - 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x06, 0x04, 0x10, - 0x47, 0x69, 0x67, 0x61, 0x62, 0x69, 0x74, 0x45, 0x74, 0x68, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x30, 0x30, 0x13, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, - 0x01, 0x02, 0x02, 0x01, 0x05, 0x03, 0x42, 0x05, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, - 0x01, 0x07, 0x02, 0x81, 0x00, 0x30, 0x10, 0x06, 0x0a, 0x2b, 0x06, 0x01, - 0x02, 0x01, 0x02, 0x02, 0x01, 0x09, 0x03, 0x43, 0x02, 0x0b, 0x9a, 0x30, - 0x19, 0x06, 0x0f, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x03, 0x01, 0x01, 0x02, - 0x0a, 0x01, 0x0a, 0x0b, 0x00, 0x11, 0x04, 0x06, 0x00, 0x07, 0x7d, 0x4d, - 0x09, 0x00, 0x30, 0x17, 0x06, 0x0f, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x03, - 0x01, 0x01, 0x03, 0x0a, 0x01, 0x0a, 0x0b, 0x00, 0x02, 0x40, 0x04, 0x0a, - 0x0b, 0x00, 0x02, 0x30, 0x17, 0x06, 0x0f, 0x2b, 0x06, 0x01, 0x02, 0x01, - 0x04, 0x14, 0x01, 0x01, 0x6e, 0x81, 0x0f, 0x81, 0x45, 0x01, 0x40, 0x04, - 0x6e, 0x8f, 0xc5, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x06, 0x01, 0x42, - 0x01, 0x80, 0x00, 0x30, 0x15, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, - 0x01, 0x02, 0x00, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x09, 0x01, - 0x89, 0x0e, - } -} - -/* -kyoceraRequestBytes corresponds to the request section of this snmpget: - -snmpget -On -v2c -c public 192.168.1.10 1.3.6.1.2.1.1.7.0 1.3.6.1.2.1.2.2.1.10.1 1.3.6.1.2.1.2.2.1.5.1 1.3.6.1.2.1.1.4.0 1.3.6.1.2.1.43.5.1.1.15.1 1.3.6.1.2.1.4.21.1.1.127.0.0.1 1.3.6.1.4.1.23.2.5.1.1.1.4.2 1.3.6.1.2.1.1.3.0 -.1.3.6.1.2.1.1.7.0 = INTEGER: 104 -.1.3.6.1.2.1.2.2.1.10.1 = Counter32: 144058856 -.1.3.6.1.2.1.2.2.1.5.1 = Gauge32: 100000000 -.1.3.6.1.2.1.1.4.0 = STRING: "Administrator" -.1.3.6.1.2.1.43.5.1.1.15.1 = NULL -.1.3.6.1.2.1.4.21.1.1.127.0.0.1 = IPAddress: 127.0.0.1 -.1.3.6.1.4.1.23.2.5.1.1.1.4.2 = Hex-STRING: 00 15 99 37 76 2B -.1.3.6.1.2.1.1.3.0 = Timeticks: (120394900) 13 days, 22:25:49.00 -*/ - -func kyoceraRequestBytes() []byte { - return []byte{ - 0x30, 0x81, - 0x9e, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0xa0, 0x81, 0x90, 0x02, 0x04, 0x6f, 0x8c, 0xee, 0x64, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x00, 0x30, 0x81, 0x81, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, - 0x01, 0x02, 0x01, 0x01, 0x07, 0x00, 0x05, 0x00, 0x30, 0x0e, 0x06, 0x0a, - 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x0a, 0x01, 0x05, 0x00, - 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, - 0x05, 0x01, 0x05, 0x00, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, - 0x01, 0x01, 0x04, 0x00, 0x05, 0x00, 0x30, 0x0f, 0x06, 0x0b, 0x2b, 0x06, - 0x01, 0x02, 0x01, 0x2b, 0x05, 0x01, 0x01, 0x0f, 0x01, 0x05, 0x00, 0x30, - 0x11, 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x04, 0x15, 0x01, 0x01, - 0x7f, 0x00, 0x00, 0x01, 0x05, 0x00, 0x30, 0x11, 0x06, 0x0d, 0x2b, 0x06, - 0x01, 0x04, 0x01, 0x17, 0x02, 0x05, 0x01, 0x01, 0x01, 0x04, 0x02, 0x05, - 0x00, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, - 0x00, 0x05, 0x00, - } -} - -// === snmpset dumps === - -/* -port_on_*1() correspond to this snmpset and response: - -snmpset -v 1 -c privatelab 192.168.100.124 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 i 1 - -Simple Network Management Protocol - version: version-1 (0) - community: privatelab - data: set-request (3) - set-request - request-id: 526895288 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5: - Object Name: 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 (iso.3.6.1.4.1.318.1.1.4.4.2.1.3.5) - Value (Integer32): 1 - -Simple Network Management Protocol - version: version-1 (0) - community: privatelab - data: get-response (2) - get-response - request-id: 526895288 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5: - Object Name: 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 (iso.3.6.1.4.1.318.1.1.4.4.2.1.3.5) - Value (Integer32): 1 -*/ - -func portOnOutgoing1() []byte { - return []byte{ - 0x30, 0x35, 0x02, 0x01, 0x00, 0x04, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x6c, 0x61, 0x62, 0xa3, 0x24, 0x02, 0x04, 0x1f, 0x67, 0xc8, - 0xb8, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x16, 0x30, 0x14, 0x06, - 0x0f, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x3e, 0x01, 0x01, 0x04, 0x04, - 0x02, 0x01, 0x03, 0x05, 0x02, 0x01, 0x01, - } -} - -func portOnIncoming1() []byte { - return []byte{ - 0x30, 0x82, 0x00, 0x35, 0x02, 0x01, 0x00, 0x04, 0x0a, 0x70, 0x72, 0x69, - 0x76, 0x61, 0x74, 0x65, 0x6c, 0x61, 0x62, 0xa2, 0x24, 0x02, 0x04, 0x1f, - 0x67, 0xc8, 0xb8, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x16, 0x30, - 0x14, 0x06, 0x0f, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x3e, 0x01, 0x01, - 0x04, 0x04, 0x02, 0x01, 0x03, 0x05, 0x02, 0x01, 0x01, - } -} - -/* -port_off_*1() correspond to this snmpset and response: - -snmpset -v 1 -c privatelab 192.168.100.124 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 i 2 - -Simple Network Management Protocol - version: version-1 (0) - community: privatelab - data: set-request (3) - set-request - request-id: 1826072803 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5: - Object Name: 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 (iso.3.6.1.4.1.318.1.1.4.4.2.1.3.5) - Value (Integer32): 2 - -Simple Network Management Protocol - version: version-1 (0) - community: privatelab - data: get-response (2) - get-response - request-id: 1826072803 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5: - Object Name: 1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 (iso.3.6.1.4.1.318.1.1.4.4.2.1.3.5) - Value (Integer32): 2 -*/ - -func portOffOutgoing1() []byte { - return []byte{ - 0x30, 0x35, 0x02, 0x01, 0x00, 0x04, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x6c, 0x61, 0x62, 0xa3, 0x24, 0x02, 0x04, 0x6c, 0xd7, 0xa8, - 0xe3, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x16, 0x30, 0x14, 0x06, - 0x0f, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x3e, 0x01, 0x01, 0x04, 0x04, - 0x02, 0x01, 0x03, 0x05, 0x02, 0x01, 0x02, - } -} - -func portOffIncoming1() []byte { - return []byte{ - 0x30, 0x82, 0x00, 0x35, 0x02, 0x01, 0x00, 0x04, 0x0a, 0x70, 0x72, 0x69, - 0x76, 0x61, 0x74, 0x65, 0x6c, 0x61, 0x62, 0xa2, 0x24, 0x02, 0x04, 0x6c, - 0xd7, 0xa8, 0xe3, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x16, 0x30, - 0x14, 0x06, 0x0f, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x3e, 0x01, 0x01, - 0x04, 0x04, 0x02, 0x01, 0x03, 0x05, 0x02, 0x01, 0x02, - } -} - -// MrSpock START - -/* -setOctet1: -Simple Network Management Protocol - version: v2c (1) - community: private - data: set-request (3) - set-request - request-id: 756726019 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.4.1.2863.205.1.1.75.1.0: 80 - Object Name: 1.3.6.1.4.1.2863.205.1.1.75.1.0 (iso.3.6.1.4.1.2863.205.1.1.75.1.0) - Value (OctetString): 80 - -setOctet2: -Simple Network Management Protocol - version: v2c (1) - community: private - data: set-request (3) - set-request - request-id: 1000552357 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.4.1.2863.205.1.1.75.2.0: 74656c6e6574 - Object Name: 1.3.6.1.4.1.2863.205.1.1.75.2.0 (iso.3.6.1.4.1.2863.205.1.1.75.2.0) - Value (OctetString): 74656c6e6574 ("telnet") -*/ - -func setOctet1() []byte { - return []byte{ - 0x30, 0x31, 0x02, 0x01, 0x01, 0x04, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0xa3, 0x23, 0x02, 0x04, 0x2d, 0x1a, 0xb9, 0x03, 0x02, 0x01, - 0x00, 0x02, 0x01, 0x00, 0x30, 0x15, 0x30, 0x13, 0x06, 0x0e, 0x2b, 0x06, - 0x01, 0x04, 0x01, 0x96, 0x2f, 0x81, 0x4d, 0x01, 0x01, 0x4b, 0x01, 0x00, - 0x04, 0x01, 0x80, - } -} - -func setOctet2() []byte { - return []byte{ - 0x30, 0x36, 0x02, 0x01, 0x01, 0x04, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0xa3, 0x28, 0x02, 0x04, 0x3b, 0xa3, 0x37, 0xa5, 0x02, 0x01, - 0x00, 0x02, 0x01, 0x00, 0x30, 0x1a, 0x30, 0x18, 0x06, 0x0e, 0x2b, 0x06, - 0x01, 0x04, 0x01, 0x96, 0x2f, 0x81, 0x4d, 0x01, 0x01, 0x4b, 0x02, 0x00, - 0x04, 0x06, 0x74, 0x65, 0x6c, 0x6e, 0x65, 0x74, - } -} - -/* setInteger1: -snmpset -c private -v2c 10.80.0.14 \ - .1.3.6.1.4.1.2863.205.10.1.33.2.5.1.2.2 i 5001 \ - .1.3.6.1.4.1.2863.205.10.1.33.2.5.1.3.2 i 5001 \ - .1.3.6.1.4.1.2863.205.10.1.33.2.5.1.4.2 i 2 \ - .1.3.6.1.4.1.2863.205.10.1.33.2.5.1.5.2 i 1 - -Simple Network Management Protocol - version: v2c (1) - community: private - data: set-request (3) - set-request - request-id: 1664317637 - error-status: noError (0) - error-index: 0 - variable-bindings: 4 items - 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.2.2: - Object Name: 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.2.2 (iso.3.6.1.4.1.2863.205.10.1.33.2.5.1.2.2) - Value (Integer32): 5001 - 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.3.2: - Object Name: 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.3.2 (iso.3.6.1.4.1.2863.205.10.1.33.2.5.1.3.2) - Value (Integer32): 5001 - 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.4.2: - Object Name: 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.4.2 (iso.3.6.1.4.1.2863.205.10.1.33.2.5.1.4.2) - Value (Integer32): 2 - 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.5.2: - Object Name: 1.3.6.1.4.1.2863.205.10.1.33.2.5.1.5.2 (iso.3.6.1.4.1.2863.205.10.1.33.2.5.1.5.2) - Value (Integer32): 1 -*/ - -func setInteger1() []byte { - return []byte{ - 0x30, 0x7e, 0x02, 0x01, 0x01, 0x04, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0xa3, 0x70, 0x02, 0x04, 0x63, 0x33, 0x78, 0xc5, 0x02, 0x01, - 0x00, 0x02, 0x01, 0x00, 0x30, 0x62, 0x30, 0x17, 0x06, 0x11, 0x2b, 0x06, - 0x01, 0x04, 0x01, 0x96, 0x2f, 0x81, 0x4d, 0x0a, 0x01, 0x21, 0x02, 0x05, - 0x01, 0x02, 0x02, 0x02, 0x02, 0x13, 0x89, 0x30, 0x17, 0x06, 0x11, 0x2b, - 0x06, 0x01, 0x04, 0x01, 0x96, 0x2f, 0x81, 0x4d, 0x0a, 0x01, 0x21, 0x02, - 0x05, 0x01, 0x03, 0x02, 0x02, 0x02, 0x13, 0x89, 0x30, 0x16, 0x06, 0x11, - 0x2b, 0x06, 0x01, 0x04, 0x01, 0x96, 0x2f, 0x81, 0x4d, 0x0a, 0x01, 0x21, - 0x02, 0x05, 0x01, 0x04, 0x02, 0x02, 0x01, 0x02, 0x30, 0x16, 0x06, 0x11, - 0x2b, 0x06, 0x01, 0x04, 0x01, 0x96, 0x2f, 0x81, 0x4d, 0x0a, 0x01, 0x21, - 0x02, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x01, - } -} - -// MrSpock FINISH - -func ciscoGetnextResponseBytes() []byte { - return []byte{ - 0x30, 0x81, - 0xc8, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0xa2, 0x81, 0xba, 0x02, 0x04, 0x5b, 0x1d, 0xb6, 0xee, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x00, 0x30, 0x81, 0xab, 0x30, 0x19, 0x06, 0x11, 0x2b, 0x06, - 0x01, 0x02, 0x01, 0x03, 0x01, 0x01, 0x03, 0x02, 0x01, 0x81, 0x40, 0x81, - 0x28, 0x68, 0x02, 0x40, 0x04, 0xc0, 0xa8, 0x68, 0x02, 0x30, 0x0f, 0x06, - 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x5c, 0x01, 0x02, 0x01, 0x00, 0x41, - 0x01, 0x00, 0x30, 0x45, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, - 0x09, 0x01, 0x03, 0x03, 0x04, 0x37, 0x54, 0x68, 0x65, 0x20, 0x4d, 0x49, - 0x42, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, - 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x20, 0x49, 0x50, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x49, 0x43, 0x4d, 0x50, 0x20, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, - 0x01, 0x04, 0x02, 0x43, 0x01, 0x15, 0x30, 0x0d, 0x06, 0x08, 0x2b, 0x06, - 0x01, 0x02, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, 0x03, 0x30, 0x16, 0x06, - 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00, 0x06, 0x0a, 0x2b, - 0x06, 0x01, 0x04, 0x01, 0xbf, 0x08, 0x03, 0x02, 0x0a, - } -} - -func ciscoGetnextRequestBytes() []byte { - return []byte{ - 0x30, 0x7e, - 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa1, - 0x71, 0x02, 0x04, 0x5b, 0x1d, 0xb6, 0xee, 0x02, 0x01, 0x00, 0x02, 0x01, - 0x00, 0x30, 0x63, 0x30, 0x15, 0x06, 0x11, 0x2b, 0x06, 0x01, 0x02, 0x01, - 0x03, 0x01, 0x01, 0x03, 0x02, 0x01, 0x81, 0x40, 0x81, 0x28, 0x68, 0x01, - 0x05, 0x00, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x5c, - 0x01, 0x02, 0x05, 0x00, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, - 0x01, 0x01, 0x09, 0x01, 0x03, 0x02, 0x05, 0x00, 0x30, 0x0e, 0x06, 0x0a, - 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, 0x04, 0x01, 0x05, 0x00, - 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, - 0x04, 0x08, 0x05, 0x00, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, - 0x01, 0x01, 0x01, 0x00, 0x05, 0x00, - } -} - -/* cisco getbulk bytes corresponds to this snmpbulkget command: - -$ snmpbulkget -v2c -cpublic 127.0.0.1:161 1.3.6.1.2.1.1.9.1.3.52 -iso.3.6.1.2.1.1.9.1.4.1 = Timeticks: (21) 0:00:00.21 -iso.3.6.1.2.1.1.9.1.4.2 = Timeticks: (21) 0:00:00.21 -iso.3.6.1.2.1.1.9.1.4.3 = Timeticks: (21) 0:00:00.21 -iso.3.6.1.2.1.1.9.1.4.4 = Timeticks: (21) 0:00:00.21 -iso.3.6.1.2.1.1.9.1.4.5 = Timeticks: (21) 0:00:00.21 -iso.3.6.1.2.1.1.9.1.4.6 = Timeticks: (23) 0:00:00.23 -iso.3.6.1.2.1.1.9.1.4.7 = Timeticks: (23) 0:00:00.23 -iso.3.6.1.2.1.1.9.1.4.8 = Timeticks: (23) 0:00:00.23 -iso.3.6.1.2.1.2.1.0 = INTEGER: 3 -iso.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1 - -*/ -func ciscoGetbulkRequestBytes() []byte { - return []byte{ - 0x30, 0x2b, - 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa5, - 0x1e, 0x02, 0x04, 0x7d, 0x89, 0x68, 0xda, 0x02, 0x01, 0x00, 0x02, 0x01, - 0x0a, 0x30, 0x10, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, - 0x01, 0x09, 0x01, 0x03, 0x34, 0x05, 0x00, 0x00, - } -} - -func ciscoGetbulkResponseBytes() []byte { - return []byte{ - 0x30, 0x81, - 0xc5, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0xa2, 0x81, 0xb7, 0x02, 0x04, 0x0e, 0xe6, 0xb3, 0x8a, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x00, 0x30, 0x81, 0xa8, 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, - 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, 0x04, 0x01, 0x43, 0x01, 0x15, 0x30, - 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, 0x04, - 0x02, 0x43, 0x01, 0x15, 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, - 0x01, 0x01, 0x09, 0x01, 0x04, 0x03, 0x43, 0x01, 0x15, 0x30, 0x0f, 0x06, - 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, 0x04, 0x04, 0x43, - 0x01, 0x15, 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, - 0x09, 0x01, 0x04, 0x05, 0x43, 0x01, 0x15, 0x30, 0x0f, 0x06, 0x0a, 0x2b, - 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, 0x04, 0x06, 0x43, 0x01, 0x17, - 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x09, 0x01, - 0x04, 0x07, 0x43, 0x01, 0x17, 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, - 0x02, 0x01, 0x01, 0x09, 0x01, 0x04, 0x08, 0x43, 0x01, 0x17, 0x30, 0x0d, - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x01, 0x00, 0x02, 0x01, - 0x03, 0x30, 0x0f, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, - 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, - } -} - -/* -Issue 35, empty responses. -Simple Network Management Protocol - version: v2c (1) - community: public - data: get-request (0) - get-request - request-id: 1883298028 - error-status: noError (0) - error-index: 0 - variable-bindings: 0 items -*/ -func emptyErrRequest() []byte { - return []byte{ - 0x30, 0x1b, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0xa0, 0x0e, 0x02, 0x04, 0x70, 0x40, 0xd8, 0xec, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x00, 0x30, 0x00, - } -} - -/* -Issue 35, empty responses. - -Simple Network Management Protocol - version: v2c (1) - community: public - data: get-response (2) - get-response - request-id: 1883298028 - error-status: noError (0) - error-index: 0 - variable-bindings: 0 items -*/ -func emptyErrResponse() []byte { - return []byte{ - 0x30, 0x1b, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0xa2, 0x0e, 0x02, 0x04, 0x70, 0x40, 0xd8, 0xec, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x00, 0x30, 0x00, - } -} - -/* -Issue 15, test Counter64. - -Simple Network Management Protocol - version: v2c (1) - community: public - data: get-response (2) - get-response - request-id: 190378322 - error-status: noError (0) - error-index: 0 - variable-bindings: 1 item - 1.3.6.1.2.1.31.1.1.1.10.1: 1527943 - Object Name: 1.3.6.1.2.1.31.1.1.1.10.1 (iso.3.6.1.2.1.31.1.1.1.10.1) - Value (Counter64): 1527943 -*/ -func counter64Response() []byte { - return []byte{ - 0x30, 0x2f, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0xa2, 0x22, 0x02, 0x04, 0x0b, 0x58, 0xf1, 0x52, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x00, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0b, 0x2b, 0x06, 0x01, - 0x02, 0x01, 0x1f, 0x01, 0x01, 0x01, 0x0a, 0x01, 0x46, 0x03, 0x17, 0x50, - 0x87, - } -} - -func TestUnmarshalEmptyPanic(t *testing.T) { - var in = []byte{} - var res = new(SnmpPacket) - - _, err := Default.unmarshalHeader(in, res) - if err == nil { - t.Errorf("unmarshalHeader did not gracefully detect empty packet") - } -} - -func TestSendOneRequest_dups(t *testing.T) { - srvr, err := net.ListenUDP("udp4", &net.UDPAddr{}) - defer srvr.Close() - - x := &GoSNMP{ - Version: Version2c, - Target: srvr.LocalAddr().(*net.UDPAddr).IP.String(), - Port: uint16(srvr.LocalAddr().(*net.UDPAddr).Port), - Timeout: time.Millisecond * 100, - Retries: 2, - } - if err := x.Connect(); err != nil { - t.Fatalf("Error connecting: %s", err) - } - - go func() { - buf := make([]byte, 256) - for { - n, addr, err := srvr.ReadFrom(buf) - if err != nil { - return - } - buf := buf[:n] - - var reqPkt SnmpPacket - var cursor int - cursor, err = x.unmarshalHeader(buf, &reqPkt) - if err != nil { - t.Errorf("Error: %s", err) - } - // if x.Version == Version3 { - // buf, cursor, err = x.decryptPacket(buf, cursor, &reqPkt) - // if err != nil { - // t.Errorf("Error: %s", err) - // } - //} - err = x.unmarshalPayload(buf, cursor, &reqPkt) - if err != nil { - t.Errorf("Error: %s", err) - } - - rspPkt := x.mkSnmpPacket(GetResponse, []SnmpPDU{ - { - Name: ".1.2", - Type: Integer, - Value: 123, - }, - }, 0, 0) - rspPkt.RequestID = reqPkt.RequestID - outBuf, err := rspPkt.marshalMsg() - if err != nil { - t.Errorf("ERR: %s", err) - } - srvr.WriteTo(outBuf, addr) - for i := 0; i <= x.Retries; i++ { - srvr.WriteTo(outBuf, addr) - } - } - }() - - pdus := []SnmpPDU{SnmpPDU{Name: ".1.2", Type: Null}} - reqPkt := x.mkSnmpPacket(GetResponse, pdus, 0, 0) //not actually a GetResponse, but we need something our test server can unmarshal - - _, err = x.sendOneRequest(reqPkt, true) - if err != nil { - t.Errorf("Error: %s", err) - return - } - - _, err = x.sendOneRequest(reqPkt, true) - if err != nil { - t.Errorf("Error: %s", err) - return - } -} - -func BenchmarkSendOneRequest(b *testing.B) { - b.StopTimer() - - srvr, err := net.ListenUDP("udp4", &net.UDPAddr{}) - defer srvr.Close() - - x := &GoSNMP{ - Version: Version2c, - Target: srvr.LocalAddr().(*net.UDPAddr).IP.String(), - Port: uint16(srvr.LocalAddr().(*net.UDPAddr).Port), - Timeout: time.Millisecond * 100, - Retries: 2, - } - if err := x.Connect(); err != nil { - b.Fatalf("Error connecting: %s", err) - } - - go func() { - buf := make([]byte, 256) - outBuf := counter64Response() - for { - _, addr, err := srvr.ReadFrom(buf) - if err != nil { - return - } - - copy(outBuf[17:21], buf[11:15]) // evil: copy request ID - srvr.WriteTo(outBuf, addr) - } - }() - - pdus := []SnmpPDU{SnmpPDU{Name: ".1.3.6.1.2.1.31.1.1.1.10.1", Type: Null}} - reqPkt := x.mkSnmpPacket(GetRequest, pdus, 0, 0) - - // make sure everything works before starting the test - _, err = x.sendOneRequest(reqPkt, true) - if err != nil { - b.Fatalf("Precheck failed: %s", err) - } - - b.StartTimer() - - for n := 0; n < b.N; n++ { - _, err = x.sendOneRequest(reqPkt, true) - if err != nil { - b.Fatalf("Error: %s", err) - return - } - } -} - -/* -$ snmptrap -v 2c -c public 192.168.1.10 '' SNMPv2-MIB::system SNMPv2-MIB::sysDescr.0 s "red laptop" SNMPv2-MIB::sysServices.0 i "5" - -Simple Network Management Protocol - version: v2c (1) - community: public - data: snmpV2-trap (7) - snmpV2-trap - request-id: 1271509950 - error-status: noError (0) - error-index: 0 - variable-bindings: 5 items - 1.3.6.1.2.1.1.3.0: 1034156 - Object Name: 1.3.6.1.2.1.1.3.0 (iso.3.6.1.2.1.1.3.0) - Value (Timeticks): 1034156 - 1.3.6.1.6.3.1.1.4.1.0: 1.3.6.1.2.1.1 (iso.3.6.1.2.1.1) - Object Name: 1.3.6.1.6.3.1.1.4.1.0 (iso.3.6.1.6.3.1.1.4.1.0) - Value (OID): 1.3.6.1.2.1.1 (iso.3.6.1.2.1.1) - 1.3.6.1.2.1.1.1.0: 726564206c6170746f70 - Object Name: 1.3.6.1.2.1.1.1.0 (iso.3.6.1.2.1.1.1.0) - Value (OctetString): 726564206c6170746f70 - Variable-binding-string: red laptop - 1.3.6.1.2.1.1.7.0: - Object Name: 1.3.6.1.2.1.1.7.0 (iso.3.6.1.2.1.1.7.0) - Value (Integer32): 5 - 1.3.6.1.2.1.1.2: 1.3.6.1.4.1.2.3.4.5 (iso.3.6.1.4.1.2.3.4.5) - Object Name: 1.3.6.1.2.1.1.2 (iso.3.6.1.2.1.1.2) - Value (OID): 1.3.6.1.4.1.2.3.4.5 (iso.3.6.1.4.1.2.3.4.5) -*/ - -func trap1() []byte { - return []byte{ - 0x30, 0x81, 0x80, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa7, 0x73, - 0x02, 0x04, 0x72, 0x5c, 0xef, 0x42, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x65, 0x30, 0x10, - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00, 0x43, 0x04, 0x01, 0x1a, 0xef, 0xa5, - 0x30, 0x14, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x06, 0x03, 0x01, 0x01, 0x04, 0x01, 0x00, 0x06, 0x06, - 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x30, 0x16, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, - 0x01, 0x00, 0x04, 0x0a, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x61, 0x70, 0x74, 0x6f, 0x70, 0x30, 0x0d, - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x07, 0x00, 0x02, 0x01, 0x05, 0x30, 0x14, 0x06, - 0x07, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x02, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x3a, 0x05, 0x00, 0xa1, 0x27, 0x42, 0x0c, 0x46, 0x00, - 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x10, 0x4a, 0x7d, 0x34, 0x3a, 0xa5, 0x74, 0xda, 0x38, 0x4d, - 0x6c, 0x6c, 0x08, 0x00, 0x45, 0x00, 0x00, 0x38, 0xcc, 0xdb, 0x40, 0x00, 0xff, 0x01, 0x2b, 0x74, - 0xc0, 0xa8, 0x01, 0x0a, 0xc0, 0xa8, 0x01, 0x1a, 0x03, 0x03, 0x11, 0x67, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x9f, 0xe6, 0x8f, 0x40, 0x00, 0x40, 0x11, 0x00, 0x00, 0xc0, 0xa8, 0x01, 0x1a, - 0xc0, 0xa8, 0x01, 0x0a, 0xaf, 0x78, 0x00, 0xa2, 0x00, 0x8b, 0x0b, 0x3a, 0x00, 0x00, 0x68, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x3a, - 0x05, 0x00, 0xca, 0x94, 0x67, 0x0c, 0x01, 0x00, 0x1c, 0x00, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x64, - 0x75, 0x6d, 0x70, 0x63, 0x61, 0x70, 0x02, 0x00, 0x08, 0x00, 0x74, 0x3a, 0x05, 0x00, 0xdf, 0xba, - 0x27, 0x0c, 0x03, 0x00, 0x08, 0x00, 0x74, 0x3a, 0x05, 0x00, 0x18, 0x94, 0x67, 0x0c, 0x04, 0x00, - 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00} -} diff --git a/vendor/github.com/soniah/gosnmp/misc_test.go b/vendor/github.com/soniah/gosnmp/misc_test.go deleted file mode 100644 index 61b5812b..00000000 --- a/vendor/github.com/soniah/gosnmp/misc_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import ( - "bytes" - "reflect" - "testing" -) - -// Tests in alphabetical order of function being tested - -// ----------------------------------------------------------------------------- - -var testsMarshalLength = []struct { - length int - expected []byte -}{ - {1, []byte{0x01}}, - {129, []byte{0x81, 0x81}}, - {256, []byte{0x82, 0x01, 0x00}}, - {272, []byte{0x82, 0x01, 0x10}}, - {435, []byte{0x82, 0x01, 0xb3}}, -} - -func TestMarshalLength(t *testing.T) { - for i, test := range testsMarshalLength { - testBytes, err := marshalLength(test.length) - if err != nil { - t.Errorf("%d: length %d got err %v", i, test.length, err) - } - if !reflect.DeepEqual(testBytes, test.expected) { - t.Errorf("%d: length %d got |%x| expected |%x|", - i, test.length, testBytes, test.expected) - } - } -} - -// ----------------------------------------------------------------------------- - -var testsPartition = []struct { - currentPosition int - partitionSize int - sliceLength int - ok bool -}{ - {-1, 3, 8, false}, // test out of range - {8, 3, 8, false}, // test out of range - {0, 3, 8, false}, // test 0-7/3 per doco - {1, 3, 8, false}, - {2, 3, 8, true}, - {3, 3, 8, false}, - {4, 3, 8, false}, - {5, 3, 8, true}, - {6, 3, 8, false}, - {7, 3, 8, true}, - {-1, 1, 3, false}, // partition size of one - {0, 1, 3, true}, - {1, 1, 3, true}, - {2, 1, 3, true}, - {3, 1, 3, false}, -} - -func TestPartition(t *testing.T) { - for i, test := range testsPartition { - ok := Partition(test.currentPosition, test.partitionSize, test.sliceLength) - if ok != test.ok { - t.Errorf("#%d: Bad result: %v (expected %v)", i, ok, test.ok) - } - } -} - -// --------------------------------------------------------------------- - -var testsSnmpVersionString = []struct { - in SnmpVersion - out string -}{ - {Version1, "1"}, - {Version2c, "2c"}, - {Version3, "3"}, -} - -func TestSnmpVersionString(t *testing.T) { - for i, test := range testsSnmpVersionString { - result := test.in.String() - if result != test.out { - t.Errorf("#%d, got %v expected %v", i, result, test.out) - } - } -} - -// --------------------------------------------------------------------- - -var testSnmpV3MD5HMAC = []struct { - password string - engineid string - outKey []byte -}{ - {"maplesyrup", string([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}), []byte{0x52, 0x6f, 0x5e, 0xed, 0x9f, 0xcc, 0xe2, 0x6f, 0x89, 0x64, 0xc2, 0x93, 0x07, 0x87, 0xd8, 0x2b}}, -} - -func TestMD5HMAC(t *testing.T) { - for i, test := range testSnmpV3MD5HMAC { - result := md5HMAC(test.password, test.engineid) - if !bytes.Equal(result, test.outKey) { - t.Errorf("#%d, got %v expected %v", i, result, test.outKey) - } - } -} - -var testSnmpV3SHAHMAC = []struct { - password string - engineid string - outKey []byte -}{ - {"maplesyrup", string([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}), []byte{0x66, 0x95, 0xfe, 0xbc, 0x92, 0x88, 0xe3, 0x62, 0x82, 0x23, 0x5f, 0xc7, 0x15, 0x1f, 0x12, 0x84, 0x97, 0xb3, 0x8f, 0x3f}}, -} - -func TestSHAHMAC(t *testing.T) { - for i, test := range testSnmpV3SHAHMAC { - result := shaHMAC(test.password, test.engineid) - if !bytes.Equal(result, test.outKey) { - t.Errorf("#%d, got %v expected %v", i, result, test.outKey) - } - } -} - -// --------------------------------------------------------------------- - -/* -var testMarshalTimeticks = []struct { - timeticks uint32 - out []byte -}{ - {1034156, []byte{0x0f, 0xc7, 0xac}}, -} - -func TestMarshalTimeticks(t *testing.T) { - for i, test := range testMarshalTimeticks { - result, err := marshalTimeticks(test.timeticks) - if err != nil { - t.Errorf("%d: expected %v got err %v", i, result, err) - } - if !bytes.Equal(result, test.out) { - t.Errorf("#%d, got %v expected %v", i, result, test.out) - } - } -} -*/ diff --git a/vendor/github.com/soniah/gosnmp/snmp-notes.txt b/vendor/github.com/soniah/gosnmp/snmp-notes.txt deleted file mode 100644 index b0d04e74..00000000 --- a/vendor/github.com/soniah/gosnmp/snmp-notes.txt +++ /dev/null @@ -1,71 +0,0 @@ -install: - -$ sudo apt-get install snmp-mibs-downloader snmp snmpd -$ sudo download-mibs -# -# USAGE: snmptranslate [OPTIONS] OID [OID]... for example -# from /usr/share/mibs/ietf/SNMPv2-MIB -# http://net-snmp.sourceforge.net/wiki/index.php/TUT:snmptranslate -# -$ snmptranslate -Tp -IR system # for SNMPv2-MIB - -# https://l3net.wordpress.com/2013/05/12/installing-net-snmp-mibs-on-ubuntu-and-debian/ -# for gui MIB browser -# -# http://stackoverflow.com/questions/19947680/what-is-the-correct-snmptrap-command-format - -$ sudo diff ~/snmpd.conf /etc/snmp/snmpd.conf -15c15 -< agentAddress udp:127.0.0.1:161 ---- -> # agentAddress udp:127.0.0.1:161 -17c17 -< #agentAddress udp:161,udp6:[::1]:161 ---- -> agentAddress udp:161,udp6:[::1]:161 -51c51 -< rocommunity public default -V systemonly ---- -> rocommunity public 10.0.0.0/16 -126c126 -< trapsink localhost public ---- -> #trapsink localhost public -128c128 -< #trap2sink localhost public ---- -> trap2sink localhost public - -/etc/snmp/snmp.conf: -mibs +ALL - -$ sudo /etc/init.d/snmpd restart - -snmptrap: - -The TYPE is a single character, one of: - i INTEGER INTEGER - u UNSIGNED - c COUNTER32 - s STRING DisplayString - x HEX STRING - d DECIMAL STRING - n NULLOBJ - o OBJID OBJECT IDENTIFIER - t TIMETICKS - a IPADDRESS - b BITS - -/usr/share/mibs/ietf/SNMPv2-MIB - -line:77 sysDescr -line: 146 sysServices -line: 88 sysObjectID - -snmptrap -v 2c -c public 192.168.1.10 '' SNMPv2-MIB::system SNMPv2-MIB::sysDescr.0 s "red laptop" SNMPv2-MIB::sysServices.0 i "5" SNMPv2-MIB::sysObjectID o "1.3.6.1.4.1.2.3.4.5" - -# also https://l3net.wordpress.com/2013/05/12/installing-net-snmp-mibs-on-ubuntu-and-debian/ -# for gui MIB browser - -# also https://l3net.wordpress.com/2013/05/12/installing-net-snmp-mibs-on-ubuntu-and-debian/ -# for gui MIB browser diff --git a/vendor/github.com/soniah/gosnmp/snmp_users.sh b/vendor/github.com/soniah/gosnmp/snmp_users.sh deleted file mode 100755 index 097d9971..00000000 --- a/vendor/github.com/soniah/gosnmp/snmp_users.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -cat << EOF >> /etc/snmp/snmpd.conf -createUser noAuthNoPrivUser -createUser authMD5OnlyUser MD5 testingpass0123456789 -createUser authSHAOnlyUser SHA testingpass9876543210 -createUser authMD5PrivDESUser MD5 testingpass9876543210 DES -createUser authSHAPrivDESUser SHA testingpassabc6543210 DES -createUser authMD5PrivAESUser MD5 AEStestingpass9876543210 AES -createUser authSHAPrivAESUser SHA AEStestingpassabc6543210 AES - -rouser noAuthNoPrivUser noauth -rouser authMD5OnlyUser auth -rouser authSHAOnlyUser auth -rouser authMD5PrivDESUser authPriv -rouser authSHAPrivDESUser authPriv -rouser authMD5PrivAESUser authPriv -rouser authSHAPrivAESUser authPriv -EOF diff --git a/vendor/github.com/soniah/gosnmp/trap.go b/vendor/github.com/soniah/gosnmp/trap.go deleted file mode 100644 index 6999a7fb..00000000 --- a/vendor/github.com/soniah/gosnmp/trap.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import ( - "fmt" - "log" - "net" - "sync" - "time" -) - -// -// Sending Traps ie GoSNMP acting as an Agent -// - -// SendTrap sends a SNMP Trap (v2c/v3 only) -// -// pdus[0] can a pdu of Type TimeTicks (with the desired uint32 epoch -// time). Otherwise a TimeTicks pdu will be prepended, with time set to -// now. This mirrors the behaviour of the Net-SNMP command-line tools. -// -// SendTrap doesn't wait for a return packet from the NMS (Network -// Management Station). -// -// See also Listen() and examples for creating an NMS. -func (x *GoSNMP) SendTrap(pdus []SnmpPDU) (result *SnmpPacket, err error) { - switch x.Version { - case Version2c, Version3: - // do nothing - default: - err = fmt.Errorf("SendTrap doesn't support %s", x.Version) - return nil, err - } - - if len(pdus) == 0 { - return nil, fmt.Errorf("Sendtrap requires at least 1 pdu") - } - - if pdus[0].Type == TimeTicks { - // check is uint32 - if _, ok := pdus[0].Value.(uint32); !ok { - return nil, fmt.Errorf("Sendtrap TimeTick must be uint32") - } - } - - // add a timetick to start, set to now - now := uint32(time.Now().Unix()) - timetickPDU := SnmpPDU{"1.3.6.1.2.1.1.3.0", TimeTicks, now, x.Logger} - // prepend timetickPDU - pdus = append([]SnmpPDU{timetickPDU}, pdus...) - - packetOut := x.mkSnmpPacket(SNMPv2Trap, pdus, 0, 0) - - // all sends wait for the return packet, except for SNMPv2Trap - // -> wait is false - return x.send(packetOut, false) -} - -// -// Receiving Traps ie GoSNMP acting as an NMS (Network Management -// Station). -// -// GoSNMP.unmarshal() currently only handles SNMPv2Trap (ie v2c, v3) -// - -// A TrapListener defineds parameters for running a SNMP Trap receiver. -// nil values will be replaced by default values. -type TrapListener struct { - OnNewTrap func(s *SnmpPacket, u *net.UDPAddr) - Params *GoSNMP - - // these unexported fields are for letting test cases - // know we are ready - listening bool - c *sync.Cond - m sync.Mutex -} - -// optional constructor for TrapListener -func NewTrapListener() *TrapListener { - tl := &TrapListener{} - tl.c = sync.NewCond(&sync.Mutex{}) - return tl -} - -// safely check if TrapListener is ready and listening -func (t *TrapListener) ready() bool { - t.m.Lock() - defer t.m.Unlock() - return t.listening -} - -// Listen listens on the UDP address addr and calls the OnNewTrap -// function specified in *TrapListener for every trap recieved. -func (t *TrapListener) Listen(addr string) (err error) { - if t.Params == nil { - t.Params = Default - } - t.Params.validateParameters() - - if t.OnNewTrap == nil { - t.OnNewTrap = debugTrapHandler - } - - udpAddr, err := net.ResolveUDPAddr("udp", addr) - if err != nil { - return err - } - - conn, err := net.ListenUDP("udp", udpAddr) - if err != nil { - return err - } - defer conn.Close() - - // mark that we are listening now - func() { - t.m.Lock() - defer t.m.Unlock() - t.listening = true - t.c.Broadcast() - }() - - // don't forget to mark that we are no longer listening later on - defer func() { - t.m.Lock() - defer t.m.Unlock() - t.listening = false - t.c.Broadcast() - }() - - for { - var buf [4096]byte - rlen, remote, err := conn.ReadFromUDP(buf[:]) - if err != nil { - t.Params.logPrintf("TrapListener: error in read %s\n", err) - } - - msg := buf[:rlen] - traps := t.Params.unmarshalTrap(msg) - if traps != nil { - t.OnNewTrap(traps, remote) - } - } -} - -// Default trap handler -func debugTrapHandler(s *SnmpPacket, u *net.UDPAddr) { - log.Printf("got trapdata from %+v: %+v\n", u, s) -} - -// Unmarshal SNMP Trap -func (x *GoSNMP) unmarshalTrap(trap []byte) (result *SnmpPacket) { - result = new(SnmpPacket) - - if x.SecurityParameters != nil { - result.SecurityParameters = x.SecurityParameters.Copy() - } - - cursor, err := x.unmarshalHeader(trap, result) - if err != nil { - x.logPrintf("unmarshalTrap: %s\n", err) - return nil - } - - if result.Version == Version3 { - if result.SecurityModel == UserSecurityModel { - err = x.testAuthentication(trap, result) - if err != nil { - x.logPrintf("unmarshalTrap v3 auth: %s\n", err) - return nil - } - } - trap, cursor, err = x.decryptPacket(trap, cursor, result) - } - err = x.unmarshalPayload(trap, cursor, result) - if err != nil { - x.logPrintf("unmarshalTrap: %s\n", err) - return nil - } - return result -} diff --git a/vendor/github.com/soniah/gosnmp/trap.md b/vendor/github.com/soniah/gosnmp/trap.md deleted file mode 100644 index e4c33f88..00000000 --- a/vendor/github.com/soniah/gosnmp/trap.md +++ /dev/null @@ -1,100 +0,0 @@ -# setup for working on traps - -``` -$ sudo aptitude -y install snmp-mibs-downloader snmp snmpd snmp-mibs-downloader -``` - -In the file `/etc/snmp/snmp.conf` -``` -mibs +ALL -``` - -In the file `/etc/snmp/snmpd.conf` - -``` -comment out: - agentAddress udp:127.0.0.1:161 - -uncomment: - agentAddress udp:161,udp6:[::1]:161 - -comment out: - rocommunity public default -V systemonly - -uncomment: - rocommunity public 10.0.0.0/16 - -comment out: - trapsink localhost public - -uncomment: - trap2sink localhost public -``` - -Create the file `~/.snmp/snmp.conf` with the contents: - -``` -# ~ expansion fails -persistentDir /home/sonia/.snmp_persist -``` - -``` -$ sudo /etc/init.d/snmpd restart -``` - -# test - -``` -snmptrap -v 2c -c public 192.168.1.10 '' SNMPv2-MIB::system SNMPv2-MIB::sysDescr.0 s "red laptop" SNMPv2-MIB::sysServices.0 i "5" SNMPv2-MIB::sysObjectID o "1.3.6.1.4.1.2.3.4.5" -``` - -# tshark, wireshark - -``` -sudo aptitude -y install wireshark tshark -sudo dpkg-reconfigure wireshark-common # allow captures -sudo usermod -a -G wireshark sonia -sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/dumpcap -sudo getcap /usr/bin/dumpcap -# still 'Couldn't run /usr/bin/dumpcap in child process', so nuke it -sudo chmod 777 /usr/bin/dumpcap -``` -Logout, login to apply wireshark and tshark permissions - -In a second terminal, run: - -``` -tshark -i eth0 -f "port 161" -w trap.pcap -``` - -# snmptrap and MIBs - -``` -The TYPE is a single character, one of: - i INTEGER INTEGER - u UNSIGNED - c COUNTER32 - s STRING DisplayString - x HEX STRING - d DECIMAL STRING - n NULLOBJ - o OBJID OBJECT IDENTIFIER - t TIMETICKS - a IPADDRESS - b BITS -``` - -# finding MIBs - -Look in the file `/usr/share/mibs/ietf/SNMPv2-MIB`. Here are some -example lines: - -``` -line:77 sysDescr -line:88 sysObjectID -line:146 sysServices -``` - -For a gui MIB browser: - -https://l3net.wordpress.com/2013/05/12/installing-net-snmp-mibs-on-ubuntu-and-debian/ diff --git a/vendor/github.com/soniah/gosnmp/trap_test.go b/vendor/github.com/soniah/gosnmp/trap_test.go deleted file mode 100644 index e3ed91d6..00000000 --- a/vendor/github.com/soniah/gosnmp/trap_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import ( - "log" - "net" - "os" //"io/ioutil" - "testing" - "time" -) - -const ( - trapTestAddress = "127.0.0.1" - - // this is bad. Listen and Connect expect different address formats - // so we need an int verson and a string version - they should be the same. - trapTestPort = 9162 - trapTestPortString = "9162" - - trapTestOid = ".1.2.3.4.5" - trapTestPayload = "TRAPTEST1234" -) - -var testsUnmarshalTrap = []struct { - in func() []byte - out *SnmpPacket -}{ - {genericV3Trap, - &SnmpPacket{ - Version: Version3, - PDUType: SNMPv2Trap, - RequestID: 190378322, - MsgFlags: AuthNoPriv, - SecurityParameters: &UsmSecurityParameters{ - UserName: "myuser", - AuthenticationProtocol: MD5, - AuthenticationPassphrase: "mypassword", - Logger: log.New(os.Stdout, "", 0), - }, - }, - }, -} - -/*func TestUnmarshalTrap(t *testing.T) { - Default.Logger = log.New(os.Stdout, "", 0) - -SANITY: - for i, test := range testsUnmarshalTrap { - - Default.SecurityParameters = test.out.SecurityParameters.Copy() - - var buf = test.in() - var res = Default.unmarshalTrap(buf) - if res == nil { - t.Errorf("#%d, UnmarshalTrap returned nil", i) - continue SANITY - } - - // test enough fields fields to ensure unmarshalling was sucessful. - // full unmarshal testing is performed in TestUnmarshal - if res.Version != test.out.Version { - t.Errorf("#%d Version result: %v, test: %v", i, res.Version, test.out.Version) - } - if res.RequestID != test.out.RequestID { - t.Errorf("#%d RequestID result: %v, test: %v", i, res.RequestID, test.out.RequestID) - } - } -} -*/ -func genericV3Trap() []byte { - return []byte{ - 0x30, 0x81, 0xd7, 0x02, 0x01, 0x03, 0x30, 0x11, 0x02, 0x04, 0x62, 0xaf, - 0x5a, 0x8e, 0x02, 0x03, 0x00, 0xff, 0xe3, 0x04, 0x01, 0x01, 0x02, 0x01, - 0x03, 0x04, 0x33, 0x30, 0x31, 0x04, 0x11, 0x80, 0x00, 0x1f, 0x88, 0x80, - 0x77, 0xdf, 0xe4, 0x4f, 0xaa, 0x70, 0x02, 0x58, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x01, 0x0f, 0x02, 0x01, 0x00, 0x04, 0x06, 0x6d, 0x79, 0x75, 0x73, - 0x65, 0x72, 0x04, 0x0c, 0xd8, 0xb6, 0x9c, 0xb8, 0x22, 0x91, 0xfc, 0x65, - 0xb6, 0x84, 0xcb, 0xfe, 0x04, 0x00, 0x30, 0x81, 0x89, 0x04, 0x11, 0x80, - 0x00, 0x1f, 0x88, 0x80, 0x77, 0xdf, 0xe4, 0x4f, 0xaa, 0x70, 0x02, 0x58, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa7, 0x72, 0x02, 0x04, 0x39, 0x19, - 0x9c, 0x61, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x64, 0x30, 0x0f, - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00, 0x43, 0x03, - 0x15, 0x2f, 0xec, 0x30, 0x14, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x06, 0x03, - 0x01, 0x01, 0x04, 0x01, 0x00, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x02, 0x01, - 0x01, 0x30, 0x16, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, - 0x00, 0x04, 0x0a, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x61, 0x70, 0x74, 0x6f, - 0x70, 0x30, 0x0d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x07, - 0x00, 0x02, 0x01, 0x05, 0x30, 0x14, 0x06, 0x07, 0x2b, 0x06, 0x01, 0x02, - 0x01, 0x01, 0x02, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x03, - 0x04, 0x05} -} - -func makeTestTrapHandler(t *testing.T, done chan int) func(*SnmpPacket, *net.UDPAddr) { - return func(packet *SnmpPacket, addr *net.UDPAddr) { - // log.Printf("got trapdata from %s\n", addr.IP) - - for _, v := range packet.Variables { - switch v.Type { - case OctetString: - b := v.Value.([]byte) - // log.Printf("OID: %s, string: %x\n", v.Name, b) - - // Only one OctetString in the payload, so it must be the expected one - if v.Name != trapTestOid { - t.Fatalf("incorrect trap OID received, expected %s got %s", trapTestOid, v.Name) - done <- 0 - } - if string(b) != trapTestPayload { - t.Fatalf("incorrect trap payload received, expected %s got %x", trapTestPayload, b) - done <- 0 - } - default: - // log.Printf("trap: %+v\n", v) - } - } - done <- 0 - } -} - -// test sending a basic SNMP trap, using our own listener to receive -func TestSendTrap(t *testing.T) { - done := make(chan int) - - tl := NewTrapListener() - tl.OnNewTrap = makeTestTrapHandler(t, done) - tl.Params = Default - - // listener goroutine - go func() { - err := tl.Listen(net.JoinHostPort(trapTestAddress, trapTestPortString)) - if err != nil { - t.Fatalf("error in listen: %s", err) - } - }() - - // wait until listener is ready - tl.c.L.Lock() - for !tl.ready() { - tl.c.Wait() - } - tl.c.L.Unlock() - - ts := &GoSNMP{ - Target: trapTestAddress, - Port: trapTestPort, - Community: "public", - Version: Version2c, - Timeout: time.Duration(2) * time.Second, - Retries: 3, - MaxOids: MaxOids, - } - - err := ts.Connect() - if err != nil { - t.Fatalf("Connect() err: %v", err) - } - defer ts.Conn.Close() - - pdu := SnmpPDU{ - Name: trapTestOid, - Type: OctetString, - Value: trapTestPayload, - } - pdus := []SnmpPDU{pdu} - - _, err = ts.SendTrap(pdus) - if err != nil { - t.Fatalf("SendTrap() err: %v", err) - } - - // wait for response from handler - select { - case <-done: - case <-time.After(5 * time.Second): - t.Fatal("timed out waiting for trap to be received") - } - -} diff --git a/vendor/github.com/soniah/gosnmp/v3.go b/vendor/github.com/soniah/gosnmp/v3.go deleted file mode 100644 index ef693025..00000000 --- a/vendor/github.com/soniah/gosnmp/v3.go +++ /dev/null @@ -1,399 +0,0 @@ -package gosnmp - -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -import ( - "bytes" - "encoding/binary" - "fmt" -) - -// SnmpV3MsgFlags contains various message flags to describe Authentication, Privacy, and whether a report PDU must be sent. -type SnmpV3MsgFlags uint8 - -// Possible values of SnmpV3MsgFlags -const ( - NoAuthNoPriv SnmpV3MsgFlags = 0x0 // No authentication, and no privacy - AuthNoPriv SnmpV3MsgFlags = 0x1 // Authentication and no privacy - AuthPriv SnmpV3MsgFlags = 0x3 // Authentication and privacy - Reportable SnmpV3MsgFlags = 0x4 // Report PDU must be sent. -) - -// SnmpV3SecurityModel describes the security model used by a SnmpV3 connection -type SnmpV3SecurityModel uint8 - -// UserSecurityModel is the only SnmpV3SecurityModel currently implemented. -const ( - UserSecurityModel SnmpV3SecurityModel = 3 -) - -// SnmpV3SecurityParameters is a generic interface type to contain various implementations of SnmpV3SecurityParameters -type SnmpV3SecurityParameters interface { - Copy() SnmpV3SecurityParameters - validate(flags SnmpV3MsgFlags) error - init(log Logger) error - initPacket(packet *SnmpPacket) error - discoveryRequired() *SnmpPacket - getDefaultContextEngineID() string - setSecurityParameters(in SnmpV3SecurityParameters) error - marshal(flags SnmpV3MsgFlags) ([]byte, error) - unmarshal(flags SnmpV3MsgFlags, packet []byte, cursor int) (int, error) - authenticate(packet []byte) error - isAuthentic(packetBytes []byte, packet *SnmpPacket) (bool, error) - encryptPacket(scopedPdu []byte) ([]byte, error) - decryptPacket(packet []byte, cursor int) ([]byte, error) -} - -func (x *GoSNMP) validateParametersV3() error { - // update following code if you implement a new security model - if x.SecurityModel != UserSecurityModel { - return fmt.Errorf("The SNMPV3 User Security Model is the only SNMPV3 security model currently implemented") - } - - return x.SecurityParameters.validate(x.MsgFlags) -} - -// authenticate the marshalled result of a snmp version 3 packet -func (packet *SnmpPacket) authenticate(msg []byte) ([]byte, error) { - defer func() { - if e := recover(); e != nil { - fmt.Printf("recover: %v\n", e) - } - }() - if packet.Version != Version3 { - return msg, nil - } - if packet.MsgFlags&AuthNoPriv > 0 { - err := packet.SecurityParameters.authenticate(msg) - if err != nil { - return nil, err - } - } - - return msg, nil -} - -func (x *GoSNMP) testAuthentication(packet []byte, result *SnmpPacket) error { - if x.Version != Version3 { - return fmt.Errorf("testAuthentication called with non Version3 connection") - } - - if x.MsgFlags&AuthNoPriv > 0 { - authentic, err := x.SecurityParameters.isAuthentic(packet, result) - if err != nil { - return err - } - if !authentic { - return fmt.Errorf("Incoming packet is not authentic, discarding") - } - } - - return nil -} - -func (x *GoSNMP) initPacket(packetOut *SnmpPacket) error { - - if x.MsgFlags&AuthPriv > AuthNoPriv { - return x.SecurityParameters.initPacket(packetOut) - } - - return nil -} - -// http://tools.ietf.org/html/rfc2574#section-2.2.3 This code does not -// check if the last message received was more than 150 seconds ago The -// snmpds that this code was tested on emit an 'out of time window' -// error with the new time and this code will retransmit when that is -// received. -func (x *GoSNMP) negotiateInitialSecurityParameters(packetOut *SnmpPacket, wait bool) error { - if x.Version != Version3 || packetOut.Version != Version3 { - return fmt.Errorf("negotiateInitialSecurityParameters called with non Version3 connection or packet") - } - - if x.SecurityModel != packetOut.SecurityModel { - return fmt.Errorf("connection security model does not match security model defined in packet") - } - - if discoveryPacket := packetOut.SecurityParameters.discoveryRequired(); discoveryPacket != nil { - result, err := x.sendOneRequest(discoveryPacket, wait) - - if err != nil { - return err - } - - err = x.storeSecurityParameters(result) - if err != nil { - return err - } - - err = x.updatePktSecurityParameters(packetOut) - if err != nil { - return err - } - } - - return nil -} - -// save the connection security parameters after a request/response -func (x *GoSNMP) storeSecurityParameters(result *SnmpPacket) error { - - if x.Version != Version3 || result.Version != Version3 { - return fmt.Errorf("storeParameters called with non Version3 connection or packet") - } - - if x.SecurityModel != result.SecurityModel { - return fmt.Errorf("connection security model does not match security model extracted from packet") - } - - if x.ContextEngineID == "" { - x.ContextEngineID = result.SecurityParameters.getDefaultContextEngineID() - } - - return x.SecurityParameters.setSecurityParameters(result.SecurityParameters) -} - -// update packet security parameters to match connection security parameters -func (x *GoSNMP) updatePktSecurityParameters(packetOut *SnmpPacket) error { - if x.Version != Version3 || packetOut.Version != Version3 { - return fmt.Errorf("updatePktSecurityParameters called with non Version3 connection or packet") - } - - if x.SecurityModel != packetOut.SecurityModel { - return fmt.Errorf("connection security model does not match security model extracted from packet") - } - - err := packetOut.SecurityParameters.setSecurityParameters(x.SecurityParameters) - if err != nil { - return err - } - - if packetOut.ContextEngineID == "" { - packetOut.ContextEngineID = x.ContextEngineID - } - - return nil -} - -func (packet *SnmpPacket) marshalV3(buf *bytes.Buffer) (*bytes.Buffer, error) { - - emptyBuffer := new(bytes.Buffer) // used when returning errors - - header, err := packet.marshalV3Header() - if err != nil { - return emptyBuffer, err - } - buf.Write([]byte{byte(Sequence), byte(len(header))}) - buf.Write(header) - - var securityParameters []byte - securityParameters, err = packet.SecurityParameters.marshal(packet.MsgFlags) - if err != nil { - return emptyBuffer, err - } - - buf.Write([]byte{byte(OctetString)}) - secParamLen, err := marshalLength(len(securityParameters)) - if err != nil { - return emptyBuffer, err - } - buf.Write(secParamLen) - buf.Write(securityParameters) - - scopedPdu, err := packet.marshalV3ScopedPDU() - if err != nil { - return emptyBuffer, err - } - buf.Write(scopedPdu) - return buf, nil -} - -// marshal a snmp version 3 packet header -func (packet *SnmpPacket) marshalV3Header() ([]byte, error) { - buf := new(bytes.Buffer) - - // msg id - buf.Write([]byte{byte(Integer), 4}) - err := binary.Write(buf, binary.BigEndian, packet.MsgID) - if err != nil { - return nil, err - } - - // maximum response msg size - maxmsgsize := marshalUvarInt(rxBufSize) - buf.Write([]byte{byte(Integer), byte(len(maxmsgsize))}) - buf.Write(maxmsgsize) - - // msg flags - buf.Write([]byte{byte(OctetString), 1, byte(packet.MsgFlags)}) - - // msg security model - buf.Write([]byte{byte(Integer), 1, byte(packet.SecurityModel)}) - - return buf.Bytes(), nil -} - -// marshal and encrypt (if necessary) a snmp version 3 Scoped PDU -func (packet *SnmpPacket) marshalV3ScopedPDU() ([]byte, error) { - var b []byte - - scopedPdu, err := packet.prepareV3ScopedPDU() - if err != nil { - return nil, err - } - pduLen, err := marshalLength(len(scopedPdu)) - if err != nil { - return nil, err - } - b = append([]byte{byte(Sequence)}, pduLen...) - scopedPdu = append(b, scopedPdu...) - if packet.MsgFlags&AuthPriv > AuthNoPriv { - scopedPdu, err = packet.SecurityParameters.encryptPacket(scopedPdu) - if err != nil { - return nil, err - } - } - - return scopedPdu, nil -} - -// prepare the plain text of a snmp version 3 Scoped PDU -func (packet *SnmpPacket) prepareV3ScopedPDU() ([]byte, error) { - var buf bytes.Buffer - - //ContextEngineID - idlen, err := marshalLength(len(packet.ContextEngineID)) - if err != nil { - return nil, err - } - buf.Write(append([]byte{byte(OctetString)}, idlen...)) - buf.WriteString(packet.ContextEngineID) - - //ContextName - namelen, err := marshalLength(len(packet.ContextName)) - if err != nil { - return nil, err - } - buf.Write(append([]byte{byte(OctetString)}, namelen...)) - buf.WriteString(packet.ContextName) - - data, err := packet.marshalPDU() - if err != nil { - return nil, err - } - buf.Write(data) - return buf.Bytes(), nil -} - -func (x *GoSNMP) unmarshalV3Header(packet []byte, - cursor int, - response *SnmpPacket) (int, error) { - - if PDUType(packet[cursor]) != Sequence { - return 0, fmt.Errorf("Invalid SNMPV3 Header\n") - } - - _, cursorTmp := parseLength(packet[cursor:]) - cursor += cursorTmp - - rawMsgID, count, err := parseRawField(packet[cursor:], "msgID") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 message ID: %s", err.Error()) - } - cursor += count - if MsgID, ok := rawMsgID.(int); ok { - response.MsgID = uint32(MsgID) - x.logPrintf("Parsed message ID %d", MsgID) - } - // discard msg max size - _, count, err = parseRawField(packet[cursor:], "maxMsgSize") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 maxMsgSize: %s", err.Error()) - } - cursor += count - // discard msg max size - - rawMsgFlags, count, err := parseRawField(packet[cursor:], "msgFlags") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 msgFlags: %s", err.Error()) - } - cursor += count - if MsgFlags, ok := rawMsgFlags.(string); ok { - response.MsgFlags = SnmpV3MsgFlags(MsgFlags[0]) - x.logPrintf("parsed msg flags %s", MsgFlags) - } - - rawSecModel, count, err := parseRawField(packet[cursor:], "msgSecurityModel") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 msgSecModel: %s", err.Error()) - } - cursor += count - if SecModel, ok := rawSecModel.(int); ok { - response.SecurityModel = SnmpV3SecurityModel(SecModel) - x.logPrintf("Parsed security model %d", SecModel) - } - - if PDUType(packet[cursor]) != OctetString { - return 0, fmt.Errorf("Invalid SNMPV3 Security Parameters\n") - } - _, cursorTmp = parseLength(packet[cursor:]) - cursor += cursorTmp - - if response.SecurityParameters == nil { - return 0, fmt.Errorf("Unable to parse V3 packet - unknown security model") - } - - cursor, err = response.SecurityParameters.unmarshal(response.MsgFlags, packet, cursor) - if err != nil { - return 0, err - } - return cursor, nil -} - -func (x *GoSNMP) decryptPacket(packet []byte, cursor int, response *SnmpPacket) ([]byte, int, error) { - var err error - switch PDUType(packet[cursor]) { - case OctetString: - // pdu is encrypted - packet, err = response.SecurityParameters.decryptPacket(packet, cursor) - if err != nil { - return nil, 0, err - } - fallthrough - case Sequence: - // pdu is plaintext - tlength, cursorTmp := parseLength(packet[cursor:]) - // truncate padding that may have been included with - // the encrypted PDU - packet = packet[:cursor+tlength] - cursor += cursorTmp - rawContextEngineID, count, err := parseRawField(packet[cursor:], "contextEngineID") - if err != nil { - return nil, 0, fmt.Errorf("Error parsing SNMPV3 contextEngineID: %s", err.Error()) - } - cursor += count - if contextEngineID, ok := rawContextEngineID.(string); ok { - response.ContextEngineID = contextEngineID - x.logPrintf("Parsed contextEngineID %s", contextEngineID) - } - rawContextName, count, err := parseRawField(packet[cursor:], "contextName") - if err != nil { - return nil, 0, fmt.Errorf("Error parsing SNMPV3 contextName: %s", err.Error()) - } - cursor += count - if contextName, ok := rawContextName.(string); ok { - response.ContextName = contextName - x.logPrintf("Parsed contextName %s", contextName) - } - - default: - return nil, 0, fmt.Errorf("Error parsing SNMPV3 scoped PDU\n") - } - return packet, cursor, nil -} diff --git a/vendor/github.com/soniah/gosnmp/v3_usm.go b/vendor/github.com/soniah/gosnmp/v3_usm.go deleted file mode 100644 index 69437ce9..00000000 --- a/vendor/github.com/soniah/gosnmp/v3_usm.go +++ /dev/null @@ -1,655 +0,0 @@ -package gosnmp - -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/md5" - crand "crypto/rand" - "crypto/sha1" - "encoding/binary" - "fmt" - "hash" - "sync/atomic" -) - -// SnmpV3AuthProtocol describes the authentication protocol in use by an authenticated SnmpV3 connection. -type SnmpV3AuthProtocol uint8 - -// NoAuth, MD5, and SHA are implemented -const ( - NoAuth SnmpV3AuthProtocol = 1 - MD5 SnmpV3AuthProtocol = 2 - SHA SnmpV3AuthProtocol = 3 -) - -// SnmpV3PrivProtocol is the privacy protocol in use by an private SnmpV3 connection. -type SnmpV3PrivProtocol uint8 - -// NoPriv, DES implemented, AES planned -const ( - NoPriv SnmpV3PrivProtocol = 1 - DES SnmpV3PrivProtocol = 2 - AES SnmpV3PrivProtocol = 3 -) - -// UsmSecurityParameters is an implementation of SnmpV3SecurityParameters for the UserSecurityModel -type UsmSecurityParameters struct { - AuthoritativeEngineID string - AuthoritativeEngineBoots uint32 - AuthoritativeEngineTime uint32 - UserName string - AuthenticationParameters string - PrivacyParameters []byte - - AuthenticationProtocol SnmpV3AuthProtocol - PrivacyProtocol SnmpV3PrivProtocol - - AuthenticationPassphrase string - PrivacyPassphrase string - - secretKey []byte - privacyKey []byte - - localDESSalt uint32 - localAESSalt uint64 - - Logger Logger -} - -// Copy method for UsmSecurityParameters used to copy a SnmpV3SecurityParameters without knowing it's implementation -func (sp *UsmSecurityParameters) Copy() SnmpV3SecurityParameters { - return &UsmSecurityParameters{AuthoritativeEngineID: sp.AuthoritativeEngineID, - AuthoritativeEngineBoots: sp.AuthoritativeEngineBoots, - AuthoritativeEngineTime: sp.AuthoritativeEngineTime, - UserName: sp.UserName, - AuthenticationParameters: sp.AuthenticationParameters, - PrivacyParameters: sp.PrivacyParameters, - AuthenticationProtocol: sp.AuthenticationProtocol, - PrivacyProtocol: sp.PrivacyProtocol, - AuthenticationPassphrase: sp.AuthenticationPassphrase, - PrivacyPassphrase: sp.PrivacyPassphrase, - secretKey: sp.secretKey, - privacyKey: sp.privacyKey, - localDESSalt: sp.localDESSalt, - localAESSalt: sp.localAESSalt, - Logger: sp.Logger, - } -} - -func (sp *UsmSecurityParameters) getDefaultContextEngineID() string { - return sp.AuthoritativeEngineID -} - -func (sp *UsmSecurityParameters) setSecurityParameters(in SnmpV3SecurityParameters) error { - var insp *UsmSecurityParameters - var err error - - if insp, err = castUsmSecParams(in); err != nil { - return err - } - - if sp.AuthoritativeEngineID != insp.AuthoritativeEngineID { - sp.AuthoritativeEngineID = insp.AuthoritativeEngineID - if sp.AuthenticationProtocol > NoAuth { - sp.secretKey = genlocalkey(sp.AuthenticationProtocol, - sp.AuthenticationPassphrase, - sp.AuthoritativeEngineID) - } - if sp.PrivacyProtocol > NoPriv { - sp.privacyKey = genlocalkey(sp.AuthenticationProtocol, - sp.PrivacyPassphrase, - sp.AuthoritativeEngineID) - } - } - sp.AuthoritativeEngineBoots = insp.AuthoritativeEngineBoots - sp.AuthoritativeEngineTime = insp.AuthoritativeEngineTime - - return nil -} - -func (sp *UsmSecurityParameters) validate(flags SnmpV3MsgFlags) error { - - securityLevel := flags & AuthPriv // isolate flags that determine security level - - switch securityLevel { - case AuthPriv: - if sp.PrivacyProtocol <= NoPriv { - return fmt.Errorf("SecurityParameters.PrivacyProtocol is required") - } - if sp.PrivacyPassphrase == "" { - return fmt.Errorf("SecurityParameters.PrivacyPassphrase is required") - } - fallthrough - case AuthNoPriv: - if sp.AuthenticationProtocol <= NoAuth { - return fmt.Errorf("SecurityParameters.AuthenticationProtocol is required") - } - if sp.AuthenticationPassphrase == "" { - return fmt.Errorf("SecurityParameters.AuthenticationPassphrase is required") - } - fallthrough - case NoAuthNoPriv: - if sp.UserName == "" { - return fmt.Errorf("SecurityParameters.UserName is required") - } - default: - return fmt.Errorf("MsgFlags must be populated with an appropriate security level") - } - - return nil -} - -func (sp *UsmSecurityParameters) init(log Logger) error { - var err error - - sp.Logger = log - - switch sp.PrivacyProtocol { - case AES: - salt := make([]byte, 8) - _, err = crand.Read(salt) - if err != nil { - return fmt.Errorf("Error creating a cryptographically secure salt: %s\n", err.Error()) - } - sp.localAESSalt = binary.BigEndian.Uint64(salt) - case DES: - salt := make([]byte, 4) - _, err = crand.Read(salt) - if err != nil { - return fmt.Errorf("Error creating a cryptographically secure salt: %s\n", err.Error()) - } - sp.localDESSalt = binary.BigEndian.Uint32(salt) - } - - return nil -} - -func castUsmSecParams(secParams SnmpV3SecurityParameters) (*UsmSecurityParameters, error) { - s, ok := secParams.(*UsmSecurityParameters) - if !ok || s == nil { - return nil, fmt.Errorf("SecurityParameters is not of type *UsmSecurityParameters") - } - return s, nil -} - -// MD5 HMAC key calculation algorithm -func md5HMAC(password string, engineID string) []byte { - comp := md5.New() - var pi int // password index - for i := 0; i < 1048576; i += 64 { - var chunk []byte - for e := 0; e < 64; e++ { - chunk = append(chunk, password[pi%len(password)]) - pi++ - } - comp.Write(chunk) - } - compressed := comp.Sum(nil) - local := md5.New() - local.Write(compressed) - local.Write([]byte(engineID)) - local.Write(compressed) - final := local.Sum(nil) - return final -} - -// SHA HMAC key calculation algorithm -func shaHMAC(password string, engineID string) []byte { - hash := sha1.New() - var pi int // password index - for i := 0; i < 1048576; i += 64 { - var chunk []byte - for e := 0; e < 64; e++ { - chunk = append(chunk, password[pi%len(password)]) - pi++ - } - hash.Write(chunk) - } - hashed := hash.Sum(nil) - local := sha1.New() - local.Write(hashed) - local.Write([]byte(engineID)) - local.Write(hashed) - final := local.Sum(nil) - return final -} - -func genlocalkey(authProtocol SnmpV3AuthProtocol, passphrase string, engineID string) []byte { - var secretKey []byte - switch authProtocol { - default: - secretKey = md5HMAC(passphrase, engineID) - case SHA: - secretKey = shaHMAC(passphrase, engineID) - } - return secretKey -} - -// http://tools.ietf.org/html/rfc2574#section-8.1.1.1 -// localDESSalt needs to be incremented on every packet. -func (sp *UsmSecurityParameters) usmAllocateNewSalt() (interface{}, error) { - var newSalt interface{} - - switch sp.PrivacyProtocol { - case AES: - newSalt = atomic.AddUint64(&(sp.localAESSalt), 1) - default: - newSalt = atomic.AddUint32(&(sp.localDESSalt), 1) - } - return newSalt, nil -} - -func (sp *UsmSecurityParameters) usmSetSalt(newSalt interface{}) error { - - switch sp.PrivacyProtocol { - case AES: - aesSalt, ok := newSalt.(uint64) - if !ok { - return fmt.Errorf("salt provided to usmSetSalt is not the correct type for the AES privacy protocol") - } - var salt = make([]byte, 8) - binary.BigEndian.PutUint64(salt, aesSalt) - sp.PrivacyParameters = salt - default: - desSalt, ok := newSalt.(uint32) - if !ok { - return fmt.Errorf("salt provided to usmSetSalt is not the correct type for the DES privacy protocol") - } - var salt = make([]byte, 8) - binary.BigEndian.PutUint32(salt, sp.AuthoritativeEngineBoots) - binary.BigEndian.PutUint32(salt[4:], desSalt) - sp.PrivacyParameters = salt - } - return nil -} - -func (sp *UsmSecurityParameters) initPacket(packet *SnmpPacket) error { - // http://tools.ietf.org/html/rfc2574#section-8.1.1.1 - // localDESSalt needs to be incremented on every packet. - newSalt, err := sp.usmAllocateNewSalt() - if err != nil { - return err - } - if packet.MsgFlags&AuthPriv > AuthNoPriv { - var s *UsmSecurityParameters - if s, err = castUsmSecParams(packet.SecurityParameters); err != nil { - return err - } - return s.usmSetSalt(newSalt) - } - - return nil -} - -func (sp *UsmSecurityParameters) discoveryRequired() *SnmpPacket { - - if sp.AuthoritativeEngineID == "" { - var emptyPdus []SnmpPDU - - // send blank packet to discover authoriative engine ID/boots/time - blankPacket := &SnmpPacket{ - Version: Version3, - MsgFlags: Reportable | NoAuthNoPriv, - SecurityModel: UserSecurityModel, - SecurityParameters: &UsmSecurityParameters{Logger: sp.Logger}, - PDUType: GetRequest, - Logger: sp.Logger, - Variables: emptyPdus, - } - - return blankPacket - } - return nil -} - -func usmFindAuthParamStart(packet []byte) (uint32, error) { - idx := bytes.Index(packet, []byte{byte(OctetString), 12, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}) - - if idx < 0 { - return 0, fmt.Errorf("Unable to locate the position in packet to write authentication key") - } - - return uint32(idx + 2), nil -} - -func (sp *UsmSecurityParameters) authenticate(packet []byte) error { - - var extkey [64]byte - - copy(extkey[:], sp.secretKey) - - var k1, k2 [64]byte - - for i := 0; i < 64; i++ { - k1[i] = extkey[i] ^ 0x36 - k2[i] = extkey[i] ^ 0x5c - } - - var h, h2 hash.Hash - - switch sp.AuthenticationProtocol { - default: - h = md5.New() - h2 = md5.New() - case SHA: - h = sha1.New() - h2 = sha1.New() - } - - h.Write(k1[:]) - h.Write(packet) - d1 := h.Sum(nil) - h2.Write(k2[:]) - h2.Write(d1) - authParamStart, err := usmFindAuthParamStart(packet) - if err != nil { - return err - } - - copy(packet[authParamStart:authParamStart+12], h2.Sum(nil)[:12]) - - return nil -} - -// determine whether a message is authentic -func (sp *UsmSecurityParameters) isAuthentic(packetBytes []byte, packet *SnmpPacket) (bool, error) { - - var packetSecParams *UsmSecurityParameters - var err error - - if packetSecParams, err = castUsmSecParams(packet.SecurityParameters); err != nil { - return false, err - } - // TODO: investigate call chain to determine if this is really the best spot for this - - var extkey [64]byte - - copy(extkey[:], sp.secretKey) - - var k1, k2 [64]byte - - for i := 0; i < 64; i++ { - k1[i] = extkey[i] ^ 0x36 - k2[i] = extkey[i] ^ 0x5c - } - - var h, h2 hash.Hash - - switch sp.AuthenticationProtocol { - default: - h = md5.New() - h2 = md5.New() - case SHA: - h = sha1.New() - h2 = sha1.New() - } - - h.Write(k1[:]) - h.Write(packetBytes) - d1 := h.Sum(nil) - h2.Write(k2[:]) - h2.Write(d1) - - result := h2.Sum(nil)[:12] - for k, v := range []byte(packetSecParams.AuthenticationParameters) { - if result[k] != v { - return false, nil - } - } - return true, nil -} - -func (sp *UsmSecurityParameters) encryptPacket(scopedPdu []byte) ([]byte, error) { - var b []byte - - switch sp.PrivacyProtocol { - case AES: - var iv [16]byte - binary.BigEndian.PutUint32(iv[:], sp.AuthoritativeEngineBoots) - binary.BigEndian.PutUint32(iv[4:], sp.AuthoritativeEngineTime) - copy(iv[8:], sp.PrivacyParameters) - - block, err := aes.NewCipher(sp.privacyKey[:16]) - if err != nil { - return nil, err - } - stream := cipher.NewCFBEncrypter(block, iv[:]) - ciphertext := make([]byte, len(scopedPdu)) - stream.XORKeyStream(ciphertext, scopedPdu) - pduLen, err := marshalLength(len(ciphertext)) - if err != nil { - return nil, err - } - b = append([]byte{byte(OctetString)}, pduLen...) - scopedPdu = append(b, ciphertext...) - default: - preiv := sp.privacyKey[8:] - var iv [8]byte - for i := 0; i < len(iv); i++ { - iv[i] = preiv[i] ^ sp.PrivacyParameters[i] - } - block, err := des.NewCipher(sp.privacyKey[:8]) - if err != nil { - return nil, err - } - mode := cipher.NewCBCEncrypter(block, iv[:]) - - pad := make([]byte, des.BlockSize-len(scopedPdu)%des.BlockSize) - scopedPdu = append(scopedPdu, pad...) - - ciphertext := make([]byte, len(scopedPdu)) - mode.CryptBlocks(ciphertext, scopedPdu) - pduLen, err := marshalLength(len(ciphertext)) - if err != nil { - return nil, err - } - b = append([]byte{byte(OctetString)}, pduLen...) - scopedPdu = append(b, ciphertext...) - } - - return scopedPdu, nil -} - -func (sp *UsmSecurityParameters) decryptPacket(packet []byte, cursor int) ([]byte, error) { - _, cursorTmp := parseLength(packet[cursor:]) - cursorTmp += cursor - - switch sp.PrivacyProtocol { - case AES: - var iv [16]byte - binary.BigEndian.PutUint32(iv[:], sp.AuthoritativeEngineBoots) - binary.BigEndian.PutUint32(iv[4:], sp.AuthoritativeEngineTime) - copy(iv[8:], sp.PrivacyParameters) - - block, err := aes.NewCipher(sp.privacyKey[:16]) - if err != nil { - return nil, err - } - stream := cipher.NewCFBDecrypter(block, iv[:]) - plaintext := make([]byte, len(packet[cursorTmp:])) - stream.XORKeyStream(plaintext, packet[cursorTmp:]) - copy(packet[cursor:], plaintext) - packet = packet[:cursor+len(plaintext)] - default: - if len(packet[cursorTmp:])%des.BlockSize != 0 { - return nil, fmt.Errorf("Error decrypting ScopedPDU: not multiple of des block size.") - } - preiv := sp.privacyKey[8:] - var iv [8]byte - for i := 0; i < len(iv); i++ { - iv[i] = preiv[i] ^ sp.PrivacyParameters[i] - } - block, err := des.NewCipher(sp.privacyKey[:8]) - if err != nil { - return nil, err - } - mode := cipher.NewCBCDecrypter(block, iv[:]) - - plaintext := make([]byte, len(packet[cursorTmp:])) - mode.CryptBlocks(plaintext, packet[cursorTmp:]) - copy(packet[cursor:], plaintext) - // truncate packet to remove extra space caused by the - // octetstring/length header that was just replaced - packet = packet[:cursor+len(plaintext)] - } - return packet, nil -} - -// marshal a snmp version 3 security parameters field for the User Security Model -func (sp *UsmSecurityParameters) marshal(flags SnmpV3MsgFlags) ([]byte, error) { - var buf bytes.Buffer - var err error - - // msgAuthoritativeEngineID - buf.Write([]byte{byte(OctetString), byte(len(sp.AuthoritativeEngineID))}) - buf.WriteString(sp.AuthoritativeEngineID) - - // msgAuthoritativeEngineBoots - msgAuthoritativeEngineBoots := marshalUvarInt(sp.AuthoritativeEngineBoots) - buf.Write([]byte{byte(Integer), byte(len(msgAuthoritativeEngineBoots))}) - buf.Write(msgAuthoritativeEngineBoots) - - // msgAuthoritativeEngineTime - msgAuthoritativeEngineTime := marshalUvarInt(sp.AuthoritativeEngineTime) - buf.Write([]byte{byte(Integer), byte(len(msgAuthoritativeEngineTime))}) - buf.Write(msgAuthoritativeEngineTime) - - // msgUserName - buf.Write([]byte{byte(OctetString), byte(len(sp.UserName))}) - buf.WriteString(sp.UserName) - - // msgAuthenticationParameters - if flags&AuthNoPriv > 0 { - buf.Write([]byte{byte(OctetString), 12, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0}) - } else { - buf.Write([]byte{byte(OctetString), 0}) - } - // msgPrivacyParameters - if flags&AuthPriv > AuthNoPriv { - privlen, err := marshalLength(len(sp.PrivacyParameters)) - if err != nil { - return nil, err - } - buf.Write([]byte{byte(OctetString)}) - buf.Write(privlen) - buf.Write(sp.PrivacyParameters) - } else { - buf.Write([]byte{byte(OctetString), 0}) - } - - // wrap security parameters in a sequence - paramLen, err := marshalLength(buf.Len()) - if err != nil { - return nil, err - } - tmpseq := append([]byte{byte(Sequence)}, paramLen...) - tmpseq = append(tmpseq, buf.Bytes()...) - - return tmpseq, nil -} - -func (sp *UsmSecurityParameters) unmarshal(flags SnmpV3MsgFlags, packet []byte, cursor int) (int, error) { - - var err error - - if PDUType(packet[cursor]) != Sequence { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model parameters\n") - } - _, cursorTmp := parseLength(packet[cursor:]) - cursor += cursorTmp - - rawMsgAuthoritativeEngineID, count, err := parseRawField(packet[cursor:], "msgAuthoritativeEngineID") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model msgAuthoritativeEngineID: %s", err.Error()) - } - cursor += count - if AuthoritativeEngineID, ok := rawMsgAuthoritativeEngineID.(string); ok { - if sp.AuthoritativeEngineID != AuthoritativeEngineID { - sp.AuthoritativeEngineID = AuthoritativeEngineID - sp.Logger.Printf("Parsed authoritativeEngineID %s", AuthoritativeEngineID) - if sp.AuthenticationProtocol > NoAuth { - sp.secretKey = genlocalkey(sp.AuthenticationProtocol, - sp.AuthenticationPassphrase, - sp.AuthoritativeEngineID) - } - if sp.PrivacyProtocol > NoPriv { - sp.privacyKey = genlocalkey(sp.AuthenticationProtocol, - sp.PrivacyPassphrase, - sp.AuthoritativeEngineID) - } - } - } - - rawMsgAuthoritativeEngineBoots, count, err := parseRawField(packet[cursor:], "msgAuthoritativeEngineBoots") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model msgAuthoritativeEngineBoots: %s", err.Error()) - } - cursor += count - if AuthoritativeEngineBoots, ok := rawMsgAuthoritativeEngineBoots.(int); ok { - sp.AuthoritativeEngineBoots = uint32(AuthoritativeEngineBoots) - sp.Logger.Printf("Parsed authoritativeEngineBoots %d", AuthoritativeEngineBoots) - } - - rawMsgAuthoritativeEngineTime, count, err := parseRawField(packet[cursor:], "msgAuthoritativeEngineTime") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model msgAuthoritativeEngineTime: %s", err.Error()) - } - cursor += count - if AuthoritativeEngineTime, ok := rawMsgAuthoritativeEngineTime.(int); ok { - sp.AuthoritativeEngineTime = uint32(AuthoritativeEngineTime) - sp.Logger.Printf("Parsed authoritativeEngineTime %d", AuthoritativeEngineTime) - } - - rawMsgUserName, count, err := parseRawField(packet[cursor:], "msgUserName") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model msgUserName: %s", err.Error()) - } - cursor += count - if msgUserName, ok := rawMsgUserName.(string); ok { - sp.UserName = msgUserName - sp.Logger.Printf("Parsed userName %s", msgUserName) - } - - rawMsgAuthParameters, count, err := parseRawField(packet[cursor:], "msgAuthenticationParameters") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model msgAuthenticationParameters: %s", err.Error()) - } - if msgAuthenticationParameters, ok := rawMsgAuthParameters.(string); ok { - sp.AuthenticationParameters = msgAuthenticationParameters - sp.Logger.Printf("Parsed authenticationParameters %s", msgAuthenticationParameters) - } - // blank msgAuthenticationParameters to prepare for authentication check later - if flags&AuthNoPriv > 0 { - blank := make([]byte, 12) - copy(packet[cursor+2:cursor+14], blank) - } - cursor += count - - rawMsgPrivacyParameters, count, err := parseRawField(packet[cursor:], "msgPrivacyParameters") - if err != nil { - return 0, fmt.Errorf("Error parsing SNMPV3 User Security Model msgPrivacyParameters: %s", err.Error()) - } - cursor += count - if msgPrivacyParameters, ok := rawMsgPrivacyParameters.(string); ok { - sp.PrivacyParameters = []byte(msgPrivacyParameters) - sp.Logger.Printf("Parsed privacyParameters %s", msgPrivacyParameters) - } - - return cursor, nil -} diff --git a/vendor/github.com/soniah/gosnmp/walk.go b/vendor/github.com/soniah/gosnmp/walk.go deleted file mode 100644 index 2a363eb2..00000000 --- a/vendor/github.com/soniah/gosnmp/walk.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2012-2016 The GoSNMP Authors. All rights reserved. Use of this -// source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -package gosnmp - -import ( - "fmt" - "strings" -) - -func (x *GoSNMP) walk(getRequestType PDUType, rootOid string, walkFn WalkFunc) error { - if rootOid == "" || rootOid == "." { - rootOid = baseOid - } - - if !strings.HasPrefix(rootOid, ".") { - rootOid = string(".") + rootOid - } - - oid := rootOid - requests := 0 - maxReps := x.MaxRepetitions - if maxReps == 0 { - maxReps = defaultMaxRepetitions - } - - getFn := func(oid string) (result *SnmpPacket, err error) { - switch getRequestType { - case GetBulkRequest: - return x.GetBulk([]string{oid}, uint8(x.NonRepeaters), uint8(maxReps)) - case GetNextRequest: - return x.GetNext([]string{oid}) - default: - return nil, fmt.Errorf("Unsupported request type: %d", getRequestType) - } - } - -RequestLoop: - for { - - requests++ - response, err := getFn(oid) - if err != nil { - return err - } - if len(response.Variables) == 0 { - break RequestLoop - } - - if response.Error == NoSuchName { - x.Logger.Print("Walk terminated with NoSuchName") - break RequestLoop - } - - for k, v := range response.Variables { - if v.Type == EndOfMibView || v.Type == NoSuchObject || v.Type == NoSuchInstance { - x.Logger.Printf("BulkWalk terminated with type 0x%x", v.Type) - break RequestLoop - } - if !strings.HasPrefix(v.Name, rootOid) { - // Not in the requested root range. - // if this is the first request, and the first variable in that request - // and this condition is triggered - the first result is out of range - // need to perform a regular get request - // this request has been too narrowly defined to be found with a getNext - // Issue #78 - if requests == 1 && k == 0 { - err = x.getToWalk(rootOid, walkFn) - if err != nil { - return err - } - } - break RequestLoop - } - if v.Name == oid { - return fmt.Errorf("OID not increasing: %s", v.Name) - } - // Report our pdu - if err := walkFn(v); err != nil { - return err - } - } - // Save last oid for next request - oid = response.Variables[len(response.Variables)-1].Name - } - x.Logger.Printf("BulkWalk completed in %d requests", requests) - return nil -} - -func (x *GoSNMP) walkAll(getRequestType PDUType, rootOid string) (results []SnmpPDU, err error) { - err = x.walk(getRequestType, rootOid, func(dataUnit SnmpPDU) error { - results = append(results, dataUnit) - return nil - }) - return results, err -} - -func (x *GoSNMP) getToWalk(rootOid string, walkFn WalkFunc) error { - response, err := x.Get([]string{rootOid}) - if err != nil { - return err - } - - for _, v := range response.Variables { - err = walkFn(v) - if err != nil { - return err - } - } - return nil -} From b54379ad0b377dfcf908a1dcdc8580b7a8671bdd Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 17:03:34 +0100 Subject: [PATCH 02/10] simple ssh implementation --- connector/connection.go | 88 +++++++++++++++++++++++++++++++++++++++++ junos_collector.go | 25 ++++++++++-- 2 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 connector/connection.go diff --git a/connector/connection.go b/connector/connection.go new file mode 100644 index 00000000..18e77b66 --- /dev/null +++ b/connector/connection.go @@ -0,0 +1,88 @@ +package connector + +import ( + "strings" + "golang.org/x/crypto/ssh" + "io/ioutil" +) + +func NewSshConnection(host, user, keyFile string) (*SshConnection, error) { + if !strings.Contains(host, ":") { + host = host+":22" + } + + c := &SshConnection{} + err := c.Connect(host, user, keyFile) + if err != nil { + return nil, err + } + + return c, nil +} + +type SshConnection struct { + session *ssh.Session +} + +func (c *SshConnection) Connect(host, user, keyFile string) error { + pk, err := loadPublicKeyFile(keyFile) + if err != nil { + return err + } + + config := &ssh.ClientConfig{ + User: user, + Auth: []ssh.AuthMethod{pk}, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + + conn, err := ssh.Dial("tcp", host, config) + if err != nil { + return err + } + + c.session, err = openSession(conn) + return err +} + +func (c *SshConnection) Close() { + if c.session == nil { + return + } + + c.session.Close() +} + +func openSession(conn *ssh.Client) (*ssh.Session, error) { + session, err := conn.NewSession() + if err != nil { + return nil, err + } + + modes := ssh.TerminalModes{ + ssh.ECHO: 0, // disable echoing + ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud + ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud + } + + if err := session.RequestPty("xterm", 80, 40, modes); err != nil { + session.Close() + return nil, err + } + + return session, nil +} + +func loadPublicKeyFile(file string) (ssh.AuthMethod, error) { + b, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + key, err := ssh.ParsePrivateKey(b) + if err != nil { + return nil, err + } + + return ssh.PublicKeys(key), nil +} diff --git a/junos_collector.go b/junos_collector.go index b652c7f1..0adf1813 100644 --- a/junos_collector.go +++ b/junos_collector.go @@ -8,6 +8,9 @@ import ( "github.com/czerwonk/junos_exporter/bgp" "github.com/czerwonk/junos_exporter/interfaces" "github.com/prometheus/client_golang/prometheus" + "github.com/czerwonk/junos_exporter/connector" + "github.com/prometheus/common/log" + "sync" ) const prefix = "junos_" @@ -38,12 +41,20 @@ func (c *JunosCollector) Describe(ch chan<- *prometheus.Desc) { } func (c *JunosCollector) Collect(ch chan<- prometheus.Metric) { - for _, h := range strings.Split(*sshHosts, ",") { - go c.collectForHost(strings.Trim(h, " "), ch) + hosts := strings.Split(*sshHosts, ",") + wg := &sync.WaitGroup{} + + wg.Add(len(hosts)) + for _, h := range hosts { + go c.collectForHost(strings.Trim(h, " "), ch, wg) } + + wg.Wait() } -func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric) { +func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric, wg *sync.WaitGroup) { + defer wg.Done() + l := []string{host} t := time.Now() @@ -51,6 +62,14 @@ func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, time.Since(t).Seconds(), l...) }() + conn, err := connector.NewSshConnection(host, *sshUsername, *sshKeyFile) + if err != nil { + log.Errorln(err) + ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 0, l...) + return + } + defer conn.Close() + ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1, l...) //c.interfaceCollector.Collect() From 5e5502823749b16bba94fe3e571c99ab89d84945 Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 17:13:55 +0100 Subject: [PATCH 03/10] first command executed with ssh --- connector/connection.go | 30 +++++++++++++++++++----------- junos_collector.go | 5 +++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/connector/connection.go b/connector/connection.go index 18e77b66..66b459ba 100644 --- a/connector/connection.go +++ b/connector/connection.go @@ -4,6 +4,8 @@ import ( "strings" "golang.org/x/crypto/ssh" "io/ioutil" + "errors" + "bytes" ) func NewSshConnection(host, user, keyFile string) (*SshConnection, error) { @@ -45,12 +47,29 @@ func (c *SshConnection) Connect(host, user, keyFile string) error { return err } +func (c *SshConnection) RunCommand(cmd string) ([]byte, error) { + if c.session == nil { + return nil, errors.New("Session must be opened first") + } + + var b = &bytes.Buffer{} + c.session.Stdout = b + + err := c.session.Run(cmd) + if err != nil { + return nil, err + } + + return b.Bytes(), nil +} + func (c *SshConnection) Close() { if c.session == nil { return } c.session.Close() + c.session = nil } func openSession(conn *ssh.Client) (*ssh.Session, error) { @@ -59,17 +78,6 @@ func openSession(conn *ssh.Client) (*ssh.Session, error) { return nil, err } - modes := ssh.TerminalModes{ - ssh.ECHO: 0, // disable echoing - ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud - ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud - } - - if err := session.RequestPty("xterm", 80, 40, modes); err != nil { - session.Close() - return nil, err - } - return session, nil } diff --git a/junos_collector.go b/junos_collector.go index 0adf1813..27ab5f9b 100644 --- a/junos_collector.go +++ b/junos_collector.go @@ -72,6 +72,11 @@ func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1, l...) + x, err := conn.RunCommand("show interfaces | display xml") + if err == nil { + log.Info(string(x)) + } + //c.interfaceCollector.Collect() //c.alarmCollector.Collect() //c.bgpCollector.Collect() From d6d5da134c5cf794051841f1e5511ca5f55366db Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 17:32:00 +0100 Subject: [PATCH 04/10] rpc client implements all datasource interfaces now --- bgp/bgp_collector.go | 6 +++--- interfaces/interface_collector.go | 6 +++--- junos_collector.go | 18 ++++++++---------- rpc/rpc_client.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 rpc/rpc_client.go diff --git a/bgp/bgp_collector.go b/bgp/bgp_collector.go index 8e75aded..e7866704 100644 --- a/bgp/bgp_collector.go +++ b/bgp/bgp_collector.go @@ -9,19 +9,19 @@ func (*BgpCollector) Describe(ch chan<- *prometheus.Desc) { } -func (c *BgpCollector) Collect(datasource BgpDatasource, ch chan<- prometheus.Metric) error { +func (c *BgpCollector) Collect(datasource BgpDatasource, ch chan<- prometheus.Metric, labelValues []string) error { sessions, err := datasource.BgpSessions() if err != nil { return err } for _, s := range sessions { - c.collectForSession(s, ch) + c.collectForSession(s, ch, labelValues) } return nil } -func (*BgpCollector) collectForSession(s *BgpSession, ch chan<- prometheus.Metric) { +func (*BgpCollector) collectForSession(s *BgpSession, ch chan<- prometheus.Metric, labelValues []string) { } diff --git a/interfaces/interface_collector.go b/interfaces/interface_collector.go index 0867ac89..bc189fff 100644 --- a/interfaces/interface_collector.go +++ b/interfaces/interface_collector.go @@ -36,19 +36,19 @@ func (*InterfaceCollector) Describe(ch chan<- *prometheus.Desc) { ch <- transmitErrorsDesc } -func (c *InterfaceCollector) Collect(datasource InterfaceStatsDatasource, ch chan<- prometheus.Metric) error { +func (c *InterfaceCollector) Collect(datasource InterfaceStatsDatasource, ch chan<- prometheus.Metric, labelValues []string) error { stats, err := datasource.InterfaceStats() if err != nil { return err } for _, s := range stats { - c.collectForInterface(s, ch) + c.collectForInterface(s, ch, labelValues) } return nil } -func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prometheus.Metric) { +func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prometheus.Metric, labelValues []string) { } \ No newline at end of file diff --git a/junos_collector.go b/junos_collector.go index 27ab5f9b..22b821de 100644 --- a/junos_collector.go +++ b/junos_collector.go @@ -4,13 +4,15 @@ import ( "strings" "time" + "sync" + "github.com/czerwonk/junos_exporter/alarm" "github.com/czerwonk/junos_exporter/bgp" + "github.com/czerwonk/junos_exporter/connector" "github.com/czerwonk/junos_exporter/interfaces" + "github.com/czerwonk/junos_exporter/rpc" "github.com/prometheus/client_golang/prometheus" - "github.com/czerwonk/junos_exporter/connector" "github.com/prometheus/common/log" - "sync" ) const prefix = "junos_" @@ -72,12 +74,8 @@ func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1, l...) - x, err := conn.RunCommand("show interfaces | display xml") - if err == nil { - log.Info(string(x)) - } - - //c.interfaceCollector.Collect() - //c.alarmCollector.Collect() - //c.bgpCollector.Collect() + rpc := rpc.NewClient(conn) + c.interfaceCollector.Collect(rpc, ch, l) + c.alarmCollector.Collect(rpc, ch, l) + c.bgpCollector.Collect(rpc, ch, l) } diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go new file mode 100644 index 00000000..da628739 --- /dev/null +++ b/rpc/rpc_client.go @@ -0,0 +1,28 @@ +package rpc + +import ( + "github.com/czerwonk/junos_exporter/alarm" + "github.com/czerwonk/junos_exporter/interfaces" + "github.com/czerwonk/junos_exporter/bgp" + "github.com/czerwonk/junos_exporter/connector" +) + +type RpcClient struct { + conn *connector.SshConnection +} + +func NewClient(ssh *connector.SshConnection) *RpcClient { + return &RpcClient{conn: ssh} +} + +func (*RpcClient) AlarmCounter() (*alarm.AlarmCounter, error) { + return &alarm.AlarmCounter{}, nil +} + +func (*RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { + return make([]*interfaces.InterfaceStats, 0), nil +} + +func (*RpcClient) BgpSessions() ([]*bgp.BgpSession, error) { + return make([]*bgp.BgpSession, 0), nil +} \ No newline at end of file From 18390d8d3882e91cc460cde1ec3f0255fe55245e Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 17:42:18 +0100 Subject: [PATCH 05/10] updated README --- README.md | 22 +++++++++++++++++----- main.go | 4 ++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b6d3c132..1f6c0886 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,9 @@ [![Docker Build Statu](https://img.shields.io/docker/build/czerwonk/junos_exporter.svg)](https://hub.docker.com/r/czerwonk/junos_exporter/builds) [![Go Report Card](https://goreportcard.com/badge/github.com/czerwonk/junos_exporter)](https://goreportcard.com/report/github.com/czerwonk/junos_exporter) -Exporter for metrics from devices running JunOS (via SNMP) https://prometheus.io/ +Exporter for metrics from devices running JunOS (via SSH) https://prometheus.io/ ## Remarks -this is an early version - This project is an alternative approach for collecting metrics from Juniper devices. The set of metrics is minimal to increase performance. We (a few friends from the Freifunk communiy and myself) used the generic snmp_exporter before. @@ -16,18 +14,32 @@ We wanted to have an KIS and vendor specific exporter instead. This approach should allow us to scrape our metrics in a very time efficient way. For this reason this project was started. +## Important notice for users of version < 0.5 +In version 0.5 SNMP was replaced by SSH. This is was a breaking change. +All SNMP related parameters were removed at this point. +Please have a look on the new SSH related parameters and update your service units accordingly. + ## Install ``` go get -u github.com/czerwonk/junos_exporter ``` +## Usage +In this example we want to scrape 3 hosts: +* Host 1 (DNS: host1.example.com, Port: 22) +* Host 2 (DNS: host2.example.com, Port: 2233) +* Host 3 (IP: 172.16.0.1, Port: 22) + +``` +./junos_exporter -ssh.targets="host1.example.com,host2.example.com:2233,172.16.0.1" -ssh.keyfile=junos_exporter +``` + ## Third Party Components This software uses components of the following projects * Prometheus Go client library (https://github.com/prometheus/client_golang) -* gosnmp (https://github.com/soniah/gosnmp) ## License (c) Daniel Czerwonk, 2017. Licensed under [MIT](LICENSE) license. ## Prometheus -see https://prometheus.io/ +see https://prometheus.io/ \ No newline at end of file diff --git a/main.go b/main.go index 4b67600c..a652dd74 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( "github.com/prometheus/common/log" ) -const version string = "0.4.0" +const version string = "0.5.0" var ( showVersion = flag.Bool("version", false, "Print version information.") @@ -19,7 +19,7 @@ var ( metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.") sshHosts = flag.String("ssh.targets", "", "Hosts to scrape") sshUsername = flag.String("ssh.user", "junos_exporter", "Username to use when connecting to junos devices using ssh") - sshKeyFile = flag.String("ssh.key_file", "junos_exporter", "Public key file to use when connecting to junos devices using ssh") + sshKeyFile = flag.String("ssh.keyfile", "junos_exporter", "Public key file to use when connecting to junos devices using ssh") ) func init() { From d102c2990f7ea87964dbfc54c4b299276856e6a8 Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 18:22:17 +0100 Subject: [PATCH 06/10] imeplemted alarms parsing --- connector/connection.go | 46 +++++++++++++++-------------------------- junos_collector.go | 17 ++++++++++++--- rpc/alarm_rpc.go | 11 ++++++++++ rpc/rpc_client.go | 42 +++++++++++++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 rpc/alarm_rpc.go diff --git a/connector/connection.go b/connector/connection.go index 66b459ba..386af775 100644 --- a/connector/connection.go +++ b/connector/connection.go @@ -1,16 +1,16 @@ package connector import ( + "bytes" + "io/ioutil" "strings" + "golang.org/x/crypto/ssh" - "io/ioutil" - "errors" - "bytes" ) func NewSshConnection(host, user, keyFile string) (*SshConnection, error) { if !strings.Contains(host, ":") { - host = host+":22" + host = host + ":22" } c := &SshConnection{} @@ -23,7 +23,7 @@ func NewSshConnection(host, user, keyFile string) (*SshConnection, error) { } type SshConnection struct { - session *ssh.Session + conn *ssh.Client } func (c *SshConnection) Connect(host, user, keyFile string) error { @@ -33,29 +33,26 @@ func (c *SshConnection) Connect(host, user, keyFile string) error { } config := &ssh.ClientConfig{ - User: user, - Auth: []ssh.AuthMethod{pk}, + User: user, + Auth: []ssh.AuthMethod{pk}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - conn, err := ssh.Dial("tcp", host, config) - if err != nil { - return err - } - - c.session, err = openSession(conn) + c.conn, err = ssh.Dial("tcp", host, config) return err } func (c *SshConnection) RunCommand(cmd string) ([]byte, error) { - if c.session == nil { - return nil, errors.New("Session must be opened first") + session, err := c.conn.NewSession() + if err != nil { + return nil, err } + defer session.Close() var b = &bytes.Buffer{} - c.session.Stdout = b + session.Stdout = b - err := c.session.Run(cmd) + err = session.Run(cmd) if err != nil { return nil, err } @@ -64,21 +61,12 @@ func (c *SshConnection) RunCommand(cmd string) ([]byte, error) { } func (c *SshConnection) Close() { - if c.session == nil { + if c.conn == nil { return } - c.session.Close() - c.session = nil -} - -func openSession(conn *ssh.Client) (*ssh.Session, error) { - session, err := conn.NewSession() - if err != nil { - return nil, err - } - - return session, nil + c.conn.Close() + c.conn = nil } func loadPublicKeyFile(file string) (ssh.AuthMethod, error) { diff --git a/junos_collector.go b/junos_collector.go index 22b821de..6729b11e 100644 --- a/junos_collector.go +++ b/junos_collector.go @@ -75,7 +75,18 @@ func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1, l...) rpc := rpc.NewClient(conn) - c.interfaceCollector.Collect(rpc, ch, l) - c.alarmCollector.Collect(rpc, ch, l) - c.bgpCollector.Collect(rpc, ch, l) + err = c.interfaceCollector.Collect(rpc, ch, l) + if err != nil { + log.Errorln(err) + } + + err = c.alarmCollector.Collect(rpc, ch, l) + if err != nil { + log.Errorln(err) + } + + err = c.bgpCollector.Collect(rpc, ch, l) + if err != nil { + log.Errorln(err) + } } diff --git a/rpc/alarm_rpc.go b/rpc/alarm_rpc.go new file mode 100644 index 00000000..f28d3444 --- /dev/null +++ b/rpc/alarm_rpc.go @@ -0,0 +1,11 @@ +package rpc + +type AlarmRpc struct { + Information struct { + Details []AlarmDetails `xml:"alarm-detail"` + } `xml:"alarm-information"` +} + +type AlarmDetails struct { + Class string `xml:"alarm-class"` +} diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index da628739..674f2cef 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -1,10 +1,13 @@ package rpc import ( + "encoding/xml" + "fmt" + "github.com/czerwonk/junos_exporter/alarm" - "github.com/czerwonk/junos_exporter/interfaces" "github.com/czerwonk/junos_exporter/bgp" "github.com/czerwonk/junos_exporter/connector" + "github.com/czerwonk/junos_exporter/interfaces" ) type RpcClient struct { @@ -15,8 +18,29 @@ func NewClient(ssh *connector.SshConnection) *RpcClient { return &RpcClient{conn: ssh} } -func (*RpcClient) AlarmCounter() (*alarm.AlarmCounter, error) { - return &alarm.AlarmCounter{}, nil +func (c *RpcClient) AlarmCounter() (*alarm.AlarmCounter, error) { + red := 0 + yellow := 0 + + cmds := []string{"show system alarms", "show chassis alarms"} + + for _, cmd := range cmds { + var a = AlarmRpc{} + err := c.runCommandAndParse(cmd, &a) + if err != nil { + return nil, err + } + + for _, d := range a.Information.Details { + if d.Class == "Major" { + red++ + } else if d.Class == "Minor" { + yellow++ + } + } + } + + return &alarm.AlarmCounter{RedCount: float64(red), YellowCount: float64(yellow)}, nil } func (*RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { @@ -25,4 +49,14 @@ func (*RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { func (*RpcClient) BgpSessions() ([]*bgp.BgpSession, error) { return make([]*bgp.BgpSession, 0), nil -} \ No newline at end of file +} + +func (c *RpcClient) runCommandAndParse(cmd string, obj interface{}) error { + b, err := c.conn.RunCommand(fmt.Sprintf("%s | display xml", cmd)) + if err != nil { + return err + } + + err = xml.Unmarshal(b, obj) + return err +} From a0efd7578c12fbf08a97d438fa509a511386a1e2 Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 19:17:07 +0100 Subject: [PATCH 07/10] implemented first 2 interface metrics --- interfaces/interface_collector.go | 6 ++++-- interfaces/interface_stats.go | 3 +++ rpc/interface_rpc.go | 26 ++++++++++++++++++++++ rpc/rpc_client.go | 36 +++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 rpc/interface_rpc.go diff --git a/interfaces/interface_collector.go b/interfaces/interface_collector.go index bc189fff..acd545fe 100644 --- a/interfaces/interface_collector.go +++ b/interfaces/interface_collector.go @@ -14,7 +14,7 @@ var ( ) func init() { - l := []string{"name", "description", "mac", "target"} + l := []string{"target", "name", "description", "mac"} receiveBytesDesc = prometheus.NewDesc(prefix+"interface_receive_bytes", "Received data in bytes", l, nil) receiveErrorsDesc = prometheus.NewDesc(prefix+"interface_receive_errors", "Number of errors caused by incoming packets", l, nil) receiveDropsDesc = prometheus.NewDesc(prefix+"interface_receive_drops", "Number of dropped incoming packets", l, nil) @@ -50,5 +50,7 @@ func (c *InterfaceCollector) Collect(datasource InterfaceStatsDatasource, ch cha } func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prometheus.Metric, labelValues []string) { - + l := append(labelValues, []string{ s.Name, s.Description, s.Mac }...) + ch <- prometheus.MustNewConstMetric(receiveBytesDesc, prometheus.GaugeValue, s.ReceiveBytes, l...) + ch <- prometheus.MustNewConstMetric(transmitBytesDesc, prometheus.GaugeValue, s.TransmitBytes, l...) } \ No newline at end of file diff --git a/interfaces/interface_stats.go b/interfaces/interface_stats.go index 5352e142..c2c8b68d 100644 --- a/interfaces/interface_stats.go +++ b/interfaces/interface_stats.go @@ -1,6 +1,9 @@ package interfaces type InterfaceStats struct { + Name string + Description string + Mac string ReceiveBytes float64 ReceiveErrors float64 ReceiveDrops float64 diff --git a/rpc/interface_rpc.go b/rpc/interface_rpc.go new file mode 100644 index 00000000..f1606699 --- /dev/null +++ b/rpc/interface_rpc.go @@ -0,0 +1,26 @@ +package rpc + +type InterfaceRpc struct { + Information struct { + Interfaces []PhyInterface `xml:"physical-interface"` + } `xml:"interface-information"` +} + +type PhyInterface struct { + Name string `xml:"name"` + Description string `xml:"description"` + MacAddress string `xml:"current-physical-address"` + Stats TrafficStat `xml:"traffic-statistics"` + LogicalInterfaces []LogInterface `xml:"logical-interface"` +} + +type LogInterface struct { + Name string `xml:"name"` + Description string `xml:"description"` + Stats TrafficStat `xml:"traffic-statistics"` +} + +type TrafficStat struct { + InputBytes int64 `xml:"input-bytes"` + OutputBytes int64 `xml:"output-bytes"` +} \ No newline at end of file diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 674f2cef..f286ae37 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -43,8 +43,35 @@ func (c *RpcClient) AlarmCounter() (*alarm.AlarmCounter, error) { return &alarm.AlarmCounter{RedCount: float64(red), YellowCount: float64(yellow)}, nil } -func (*RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { - return make([]*interfaces.InterfaceStats, 0), nil +func (c *RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { + var x = InterfaceRpc{} + err := c.runCommandAndParse("show interfaces detail", &x) + if err != nil { + return nil, err + } + + stats := make([]*interfaces.InterfaceStats, 0) + for _, i := range x.Information.Interfaces { + s := &interfaces.InterfaceStats{} + s.Name = i.Name + s.Description = i.Description + s.Mac = i.MacAddress + fillWithTrafficStat(s, &i.Stats) + + stats = append(stats, s) + + for _, l := range i.LogicalInterfaces { + sl := &interfaces.InterfaceStats{} + sl.Name = l.Name + sl.Description = l.Description + sl.Mac = i.MacAddress + fillWithTrafficStat(sl, &l.Stats) + + stats = append(stats, sl) + } + } + + return stats, nil } func (*RpcClient) BgpSessions() ([]*bgp.BgpSession, error) { @@ -60,3 +87,8 @@ func (c *RpcClient) runCommandAndParse(cmd string, obj interface{}) error { err = xml.Unmarshal(b, obj) return err } + +func fillWithTrafficStat(s *interfaces.InterfaceStats, t *TrafficStat) { + s.ReceiveBytes = float64(t.InputBytes) + s.TransmitBytes = float64(t.OutputBytes) +} From 9f07fb6c32b7edc4e0b06db438c3b61e554ff74c Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 19:51:52 +0100 Subject: [PATCH 08/10] reimplementation of version 0.3 feature set --- README.md | 4 +-- interfaces/interface_collector.go | 7 ++++++ interfaces/interface_stats.go | 7 +++--- rpc/interface_rpc.go | 8 ++++++ rpc/rpc_client.go | 41 +++++++++++++++++-------------- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1f6c0886..c0e410e5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This approach should allow us to scrape our metrics in a very time efficient way For this reason this project was started. ## Important notice for users of version < 0.5 -In version 0.5 SNMP was replaced by SSH. This is was a breaking change. +In version 0.5 SNMP was replaced by SSH. This is was a breaking change (metric names were kept). All SNMP related parameters were removed at this point. Please have a look on the new SSH related parameters and update your service units accordingly. @@ -42,4 +42,4 @@ This software uses components of the following projects (c) Daniel Czerwonk, 2017. Licensed under [MIT](LICENSE) license. ## Prometheus -see https://prometheus.io/ \ No newline at end of file +see https://prometheus.io/ diff --git a/interfaces/interface_collector.go b/interfaces/interface_collector.go index acd545fe..461ad23c 100644 --- a/interfaces/interface_collector.go +++ b/interfaces/interface_collector.go @@ -53,4 +53,11 @@ func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prom l := append(labelValues, []string{ s.Name, s.Description, s.Mac }...) ch <- prometheus.MustNewConstMetric(receiveBytesDesc, prometheus.GaugeValue, s.ReceiveBytes, l...) ch <- prometheus.MustNewConstMetric(transmitBytesDesc, prometheus.GaugeValue, s.TransmitBytes, l...) + + if s.IsPhysical { + ch <- prometheus.MustNewConstMetric(transmitErrorsDesc, prometheus.GaugeValue, s.TransmitErrors, l...) + ch <- prometheus.MustNewConstMetric(transmitDropsDesc, prometheus.GaugeValue, s.TransmitDrops, l...) + ch <- prometheus.MustNewConstMetric(receiveErrorsDesc, prometheus.GaugeValue, s.ReceiveErrors, l...) + ch <- prometheus.MustNewConstMetric(receiveDropsDesc, prometheus.GaugeValue, s.ReceiveDrops, l...) + } } \ No newline at end of file diff --git a/interfaces/interface_stats.go b/interfaces/interface_stats.go index c2c8b68d..d5da043d 100644 --- a/interfaces/interface_stats.go +++ b/interfaces/interface_stats.go @@ -1,9 +1,10 @@ package interfaces type InterfaceStats struct { - Name string - Description string - Mac string + Name string + Description string + Mac string + IsPhysical bool ReceiveBytes float64 ReceiveErrors float64 ReceiveDrops float64 diff --git a/rpc/interface_rpc.go b/rpc/interface_rpc.go index f1606699..2f4e85ca 100644 --- a/rpc/interface_rpc.go +++ b/rpc/interface_rpc.go @@ -12,6 +12,14 @@ type PhyInterface struct { MacAddress string `xml:"current-physical-address"` Stats TrafficStat `xml:"traffic-statistics"` LogicalInterfaces []LogInterface `xml:"logical-interface"` + InputErrors struct { + Drops int64 `xml:"input-drops"` + Errors int64 `xml:"input-errors"` + } `xml:"input-error-list"` + OutputErrors struct { + Drops int64 `xml:"output-drops"` + Errors int64 `xml:"output-errors"` + } `xml:"output-error-list"` } type LogInterface struct { diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index f286ae37..9576aae7 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -45,27 +45,37 @@ func (c *RpcClient) AlarmCounter() (*alarm.AlarmCounter, error) { func (c *RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { var x = InterfaceRpc{} - err := c.runCommandAndParse("show interfaces detail", &x) + err := c.runCommandAndParse("show interfaces statistics detail", &x) if err != nil { return nil, err } stats := make([]*interfaces.InterfaceStats, 0) - for _, i := range x.Information.Interfaces { - s := &interfaces.InterfaceStats{} - s.Name = i.Name - s.Description = i.Description - s.Mac = i.MacAddress - fillWithTrafficStat(s, &i.Stats) + for _, phy := range x.Information.Interfaces { + s := &interfaces.InterfaceStats{ + IsPhysical: true, + Name: phy.Name, + Description: phy.Description, + Mac: phy.MacAddress, + ReceiveDrops: float64(phy.InputErrors.Drops), + ReceiveErrors: float64(phy.InputErrors.Errors), + ReceiveBytes: float64(phy.Stats.InputBytes), + TransmitDrops: float64(phy.OutputErrors.Drops), + TransmitErrors: float64(phy.OutputErrors.Errors), + TransmitBytes: float64(phy.Stats.OutputBytes), + } stats = append(stats, s) - for _, l := range i.LogicalInterfaces { - sl := &interfaces.InterfaceStats{} - sl.Name = l.Name - sl.Description = l.Description - sl.Mac = i.MacAddress - fillWithTrafficStat(sl, &l.Stats) + for _, log := range phy.LogicalInterfaces { + sl := &interfaces.InterfaceStats{ + IsPhysical: false, + Name: log.Name, + Description: log.Description, + Mac: phy.MacAddress, + ReceiveBytes: float64(log.Stats.InputBytes), + TransmitBytes: float64(log.Stats.OutputBytes), + } stats = append(stats, sl) } @@ -87,8 +97,3 @@ func (c *RpcClient) runCommandAndParse(cmd string, obj interface{}) error { err = xml.Unmarshal(b, obj) return err } - -func fillWithTrafficStat(s *interfaces.InterfaceStats, t *TrafficStat) { - s.ReceiveBytes = float64(t.InputBytes) - s.TransmitBytes = float64(t.OutputBytes) -} From f5c77aaa3100a58abd4a3016a5a7b2b2af81d9e4 Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 20:34:54 +0100 Subject: [PATCH 09/10] implemented bgp session metrics --- bgp/bgp_collector.go | 48 +++++++++++++++++++++++++- bgp/bgp_session.go | 11 +++++- interfaces/interface_collector.go | 17 +++++----- rpc/alarm_rpc.go | 2 +- rpc/bgp_rpc.go | 22 ++++++++++++ rpc/interface_rpc.go | 26 +++++++------- rpc/rpc_client.go | 56 ++++++++++++++++++++++--------- 7 files changed, 141 insertions(+), 41 deletions(-) create mode 100644 rpc/bgp_rpc.go diff --git a/bgp/bgp_collector.go b/bgp/bgp_collector.go index e7866704..ca5d28aa 100644 --- a/bgp/bgp_collector.go +++ b/bgp/bgp_collector.go @@ -2,11 +2,43 @@ package bgp import "github.com/prometheus/client_golang/prometheus" +const prefix string = "junos_bgp_seesion_" + +var ( + upDesc *prometheus.Desc + receivedPrefixesDesc *prometheus.Desc + acceptedPrefixesDesc *prometheus.Desc + rejectedPrefixesDesc *prometheus.Desc + activePrefixesDesc *prometheus.Desc + inputMessagesDesc *prometheus.Desc + outputMessagesDesc *prometheus.Desc + flapsDesc *prometheus.Desc +) + +func init() { + l := []string{"target", "asn", "ip"} + upDesc = prometheus.NewDesc(prefix+"up", "Session is up (1 = Established)", l, nil) + receivedPrefixesDesc = prometheus.NewDesc(prefix+"prefixes_received_count", "Number of received prefixes", l, nil) + acceptedPrefixesDesc = prometheus.NewDesc(prefix+"prefixes_accepted_count", "Number of accepted prefixes", l, nil) + rejectedPrefixesDesc = prometheus.NewDesc(prefix+"prefixes_rejected_count", "Number of rejected prefixes", l, nil) + activePrefixesDesc = prometheus.NewDesc(prefix+"prefixes_active_count", "Number of active prefixes (best route in RIB)", l, nil) + inputMessagesDesc = prometheus.NewDesc(prefix+"messages_input_count", "Number of received messages", l, nil) + outputMessagesDesc = prometheus.NewDesc(prefix+"messages_output_count", "Number of transmitted messages", l, nil) + flapsDesc = prometheus.NewDesc(prefix+"flap_count", "Number of session flaps", l, nil) +} + type BgpCollector struct { } func (*BgpCollector) Describe(ch chan<- *prometheus.Desc) { - + ch <- upDesc + ch <- receivedPrefixesDesc + ch <- acceptedPrefixesDesc + ch <- rejectedPrefixesDesc + ch <- activePrefixesDesc + ch <- inputMessagesDesc + ch <- outputMessagesDesc + ch <- flapsDesc } func (c *BgpCollector) Collect(datasource BgpDatasource, ch chan<- prometheus.Metric, labelValues []string) error { @@ -23,5 +55,19 @@ func (c *BgpCollector) Collect(datasource BgpDatasource, ch chan<- prometheus.Me } func (*BgpCollector) collectForSession(s *BgpSession, ch chan<- prometheus.Metric, labelValues []string) { + l := append(labelValues, []string{s.Asn, s.Ip}...) + + up := 0 + if s.Up { + up = 1 + } + ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, float64(up), l...) + ch <- prometheus.MustNewConstMetric(receivedPrefixesDesc, prometheus.GaugeValue, float64(s.ReceivedPrefixes), l...) + ch <- prometheus.MustNewConstMetric(acceptedPrefixesDesc, prometheus.GaugeValue, float64(s.AcceptedPrefixes), l...) + ch <- prometheus.MustNewConstMetric(rejectedPrefixesDesc, prometheus.GaugeValue, float64(s.RejectedPrefixes), l...) + ch <- prometheus.MustNewConstMetric(activePrefixesDesc, prometheus.GaugeValue, float64(s.ActivePrefixes), l...) + ch <- prometheus.MustNewConstMetric(inputMessagesDesc, prometheus.GaugeValue, float64(s.InputMessages), l...) + ch <- prometheus.MustNewConstMetric(outputMessagesDesc, prometheus.GaugeValue, float64(s.OutputMessages), l...) + ch <- prometheus.MustNewConstMetric(flapsDesc, prometheus.GaugeValue, float64(s.Flaps), l...) } diff --git a/bgp/bgp_session.go b/bgp/bgp_session.go index f19c61f2..4bd1388d 100644 --- a/bgp/bgp_session.go +++ b/bgp/bgp_session.go @@ -1,5 +1,14 @@ package bgp type BgpSession struct { - + Ip string + Asn string + Up bool + ReceivedPrefixes float64 + AcceptedPrefixes float64 + RejectedPrefixes float64 + ActivePrefixes float64 + InputMessages float64 + OutputMessages float64 + Flaps float64 } diff --git a/interfaces/interface_collector.go b/interfaces/interface_collector.go index 461ad23c..9539884d 100644 --- a/interfaces/interface_collector.go +++ b/interfaces/interface_collector.go @@ -15,16 +15,15 @@ var ( func init() { l := []string{"target", "name", "description", "mac"} - receiveBytesDesc = prometheus.NewDesc(prefix+"interface_receive_bytes", "Received data in bytes", l, nil) - receiveErrorsDesc = prometheus.NewDesc(prefix+"interface_receive_errors", "Number of errors caused by incoming packets", l, nil) - receiveDropsDesc = prometheus.NewDesc(prefix+"interface_receive_drops", "Number of dropped incoming packets", l, nil) - transmitBytesDesc = prometheus.NewDesc(prefix+"interface_transmit_bytes", "Transmitted data in bytes", l, nil) - transmitErrorsDesc = prometheus.NewDesc(prefix+"interface_transmit_errors", "Number of errors caused by outgoing packets", l, nil) - transmitDropsDesc = prometheus.NewDesc(prefix+"interface_transmit_drops", "Number of dropped outgoing packets", l, nil) + receiveBytesDesc = prometheus.NewDesc(prefix+"receive_bytes", "Received data in bytes", l, nil) + receiveErrorsDesc = prometheus.NewDesc(prefix+"receive_errors", "Number of errors caused by incoming packets", l, nil) + receiveDropsDesc = prometheus.NewDesc(prefix+"receive_drops", "Number of dropped incoming packets", l, nil) + transmitBytesDesc = prometheus.NewDesc(prefix+"transmit_bytes", "Transmitted data in bytes", l, nil) + transmitErrorsDesc = prometheus.NewDesc(prefix+"transmit_errors", "Number of errors caused by outgoing packets", l, nil) + transmitDropsDesc = prometheus.NewDesc(prefix+"transmit_drops", "Number of dropped outgoing packets", l, nil) } type InterfaceCollector struct { - } func (*InterfaceCollector) Describe(ch chan<- *prometheus.Desc) { @@ -50,7 +49,7 @@ func (c *InterfaceCollector) Collect(datasource InterfaceStatsDatasource, ch cha } func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prometheus.Metric, labelValues []string) { - l := append(labelValues, []string{ s.Name, s.Description, s.Mac }...) + l := append(labelValues, []string{s.Name, s.Description, s.Mac}...) ch <- prometheus.MustNewConstMetric(receiveBytesDesc, prometheus.GaugeValue, s.ReceiveBytes, l...) ch <- prometheus.MustNewConstMetric(transmitBytesDesc, prometheus.GaugeValue, s.TransmitBytes, l...) @@ -60,4 +59,4 @@ func (*InterfaceCollector) collectForInterface(s *InterfaceStats, ch chan<- prom ch <- prometheus.MustNewConstMetric(receiveErrorsDesc, prometheus.GaugeValue, s.ReceiveErrors, l...) ch <- prometheus.MustNewConstMetric(receiveDropsDesc, prometheus.GaugeValue, s.ReceiveDrops, l...) } -} \ No newline at end of file +} diff --git a/rpc/alarm_rpc.go b/rpc/alarm_rpc.go index f28d3444..0088708f 100644 --- a/rpc/alarm_rpc.go +++ b/rpc/alarm_rpc.go @@ -3,7 +3,7 @@ package rpc type AlarmRpc struct { Information struct { Details []AlarmDetails `xml:"alarm-detail"` - } `xml:"alarm-information"` + } `xml:"alarm-information"` } type AlarmDetails struct { diff --git a/rpc/bgp_rpc.go b/rpc/bgp_rpc.go new file mode 100644 index 00000000..577cee2c --- /dev/null +++ b/rpc/bgp_rpc.go @@ -0,0 +1,22 @@ +package rpc + +type BgpRpc struct { + Information struct { + Peers []BgpPeer `xml:"bgp-peer"` + } `xml:"bgp-information"` +} + +type BgpPeer struct { + Ip string `xml:"peer-address"` + Asn string `xml:"peer-as"` + State string `xml:"peer-state"` + Flaps int64 `xml:"flap-count"` + InputMessages int64 `xml:"input-messages"` + OutputMessages int64 `xml:"output-messages"` + Rib struct { + ActivePrefixes int64 `xml:"active-prefix-count"` + ReceivedPrefixes int64 `xml:"received-prefix-count"` + AcceptedPrefixes int64 `xml:"accepted-prefix-count"` + RejectedPrefixes int64 `xml:"suppressed-prefix-count"` + } `xml:"bgp-rib"` +} diff --git a/rpc/interface_rpc.go b/rpc/interface_rpc.go index 2f4e85ca..08511510 100644 --- a/rpc/interface_rpc.go +++ b/rpc/interface_rpc.go @@ -3,32 +3,32 @@ package rpc type InterfaceRpc struct { Information struct { Interfaces []PhyInterface `xml:"physical-interface"` - } `xml:"interface-information"` + } `xml:"interface-information"` } type PhyInterface struct { - Name string `xml:"name"` - Description string `xml:"description"` - MacAddress string `xml:"current-physical-address"` - Stats TrafficStat `xml:"traffic-statistics"` + Name string `xml:"name"` + Description string `xml:"description"` + MacAddress string `xml:"current-physical-address"` + Stats TrafficStat `xml:"traffic-statistics"` LogicalInterfaces []LogInterface `xml:"logical-interface"` - InputErrors struct { - Drops int64 `xml:"input-drops"` + InputErrors struct { + Drops int64 `xml:"input-drops"` Errors int64 `xml:"input-errors"` } `xml:"input-error-list"` OutputErrors struct { - Drops int64 `xml:"output-drops"` + Drops int64 `xml:"output-drops"` Errors int64 `xml:"output-errors"` } `xml:"output-error-list"` } type LogInterface struct { - Name string `xml:"name"` - Description string `xml:"description"` - Stats TrafficStat `xml:"traffic-statistics"` + Name string `xml:"name"` + Description string `xml:"description"` + Stats TrafficStat `xml:"traffic-statistics"` } type TrafficStat struct { - InputBytes int64 `xml:"input-bytes"` + InputBytes int64 `xml:"input-bytes"` OutputBytes int64 `xml:"output-bytes"` -} \ No newline at end of file +} diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 9576aae7..bbe03d3c 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -53,27 +53,27 @@ func (c *RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { stats := make([]*interfaces.InterfaceStats, 0) for _, phy := range x.Information.Interfaces { s := &interfaces.InterfaceStats{ - IsPhysical: true, - Name: phy.Name, - Description: phy.Description, - Mac: phy.MacAddress, - ReceiveDrops: float64(phy.InputErrors.Drops), - ReceiveErrors: float64(phy.InputErrors.Errors), - ReceiveBytes: float64(phy.Stats.InputBytes), - TransmitDrops: float64(phy.OutputErrors.Drops), + IsPhysical: true, + Name: phy.Name, + Description: phy.Description, + Mac: phy.MacAddress, + ReceiveDrops: float64(phy.InputErrors.Drops), + ReceiveErrors: float64(phy.InputErrors.Errors), + ReceiveBytes: float64(phy.Stats.InputBytes), + TransmitDrops: float64(phy.OutputErrors.Drops), TransmitErrors: float64(phy.OutputErrors.Errors), - TransmitBytes: float64(phy.Stats.OutputBytes), + TransmitBytes: float64(phy.Stats.OutputBytes), } stats = append(stats, s) for _, log := range phy.LogicalInterfaces { sl := &interfaces.InterfaceStats{ - IsPhysical: false, - Name: log.Name, - Description: log.Description, - Mac: phy.MacAddress, - ReceiveBytes: float64(log.Stats.InputBytes), + IsPhysical: false, + Name: log.Name, + Description: log.Description, + Mac: phy.MacAddress, + ReceiveBytes: float64(log.Stats.InputBytes), TransmitBytes: float64(log.Stats.OutputBytes), } @@ -84,8 +84,32 @@ func (c *RpcClient) InterfaceStats() ([]*interfaces.InterfaceStats, error) { return stats, nil } -func (*RpcClient) BgpSessions() ([]*bgp.BgpSession, error) { - return make([]*bgp.BgpSession, 0), nil +func (c *RpcClient) BgpSessions() ([]*bgp.BgpSession, error) { + var x = BgpRpc{} + err := c.runCommandAndParse("show bgp summary", &x) + if err != nil { + return nil, err + } + + sessions := make([]*bgp.BgpSession, 0) + for _, peer := range x.Information.Peers { + s := &bgp.BgpSession{ + Ip: peer.Ip, + Up: peer.State == "Established", + Asn: peer.Asn, + Flaps: float64(peer.Flaps), + InputMessages: float64(peer.InputMessages), + OutputMessages: float64(peer.OutputMessages), + AcceptedPrefixes: float64(peer.Rib.AcceptedPrefixes), + ActivePrefixes: float64(peer.Rib.ActivePrefixes), + ReceivedPrefixes: float64(peer.Rib.ReceivedPrefixes), + RejectedPrefixes: float64(peer.Rib.RejectedPrefixes), + } + + sessions = append(sessions, s) + } + + return sessions, nil } func (c *RpcClient) runCommandAndParse(cmd string, obj interface{}) error { From fdc773dc57f34ae4726ff1d47b9d99100c4c8fd1 Mon Sep 17 00:00:00 2001 From: Daniel Czerwonk Date: Sat, 6 Jan 2018 20:46:55 +0100 Subject: [PATCH 10/10] debug mode --- connector/connection.go | 9 +++++---- junos_collector.go | 2 +- main.go | 1 + rpc/rpc_client.go | 17 ++++++++++++++--- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/connector/connection.go b/connector/connection.go index 386af775..107de897 100644 --- a/connector/connection.go +++ b/connector/connection.go @@ -13,8 +13,8 @@ func NewSshConnection(host, user, keyFile string) (*SshConnection, error) { host = host + ":22" } - c := &SshConnection{} - err := c.Connect(host, user, keyFile) + c := &SshConnection{Host: host} + err := c.Connect(user, keyFile) if err != nil { return nil, err } @@ -24,9 +24,10 @@ func NewSshConnection(host, user, keyFile string) (*SshConnection, error) { type SshConnection struct { conn *ssh.Client + Host string } -func (c *SshConnection) Connect(host, user, keyFile string) error { +func (c *SshConnection) Connect(user, keyFile string) error { pk, err := loadPublicKeyFile(keyFile) if err != nil { return err @@ -38,7 +39,7 @@ func (c *SshConnection) Connect(host, user, keyFile string) error { HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - c.conn, err = ssh.Dial("tcp", host, config) + c.conn, err = ssh.Dial("tcp", c.Host, config) return err } diff --git a/junos_collector.go b/junos_collector.go index 6729b11e..65f21421 100644 --- a/junos_collector.go +++ b/junos_collector.go @@ -74,7 +74,7 @@ func (c *JunosCollector) collectForHost(host string, ch chan<- prometheus.Metric ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, 1, l...) - rpc := rpc.NewClient(conn) + rpc := rpc.NewClient(conn, *debug) err = c.interfaceCollector.Collect(rpc, ch, l) if err != nil { log.Errorln(err) diff --git a/main.go b/main.go index a652dd74..b0519749 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ var ( sshHosts = flag.String("ssh.targets", "", "Hosts to scrape") sshUsername = flag.String("ssh.user", "junos_exporter", "Username to use when connecting to junos devices using ssh") sshKeyFile = flag.String("ssh.keyfile", "junos_exporter", "Public key file to use when connecting to junos devices using ssh") + debug = flag.Bool("debug", false, "Show verbose debug output in log") ) func init() { diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index bbe03d3c..cf4005cd 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -4,6 +4,8 @@ import ( "encoding/xml" "fmt" + "log" + "github.com/czerwonk/junos_exporter/alarm" "github.com/czerwonk/junos_exporter/bgp" "github.com/czerwonk/junos_exporter/connector" @@ -11,11 +13,12 @@ import ( ) type RpcClient struct { - conn *connector.SshConnection + conn *connector.SshConnection + debug bool } -func NewClient(ssh *connector.SshConnection) *RpcClient { - return &RpcClient{conn: ssh} +func NewClient(ssh *connector.SshConnection, debug bool) *RpcClient { + return &RpcClient{conn: ssh, debug: debug} } func (c *RpcClient) AlarmCounter() (*alarm.AlarmCounter, error) { @@ -113,11 +116,19 @@ func (c *RpcClient) BgpSessions() ([]*bgp.BgpSession, error) { } func (c *RpcClient) runCommandAndParse(cmd string, obj interface{}) error { + if c.debug { + log.Printf("Running command on %s: %s\n", c.conn.Host, cmd) + } + b, err := c.conn.RunCommand(fmt.Sprintf("%s | display xml", cmd)) if err != nil { return err } + if c.debug { + log.Printf("Output for %s: %s\n", c.conn.Host, string(b)) + } + err = xml.Unmarshal(b, obj) return err }