All Projects → swisscom → ruby-netsnmp

swisscom / ruby-netsnmp

Licence: Apache-2.0 License
SNMP library in ruby (v1, v2c, v3)

Programming Languages

ruby
36898 projects - #4 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to ruby-netsnmp

Cocoa-Printer-Server
Make your USB Printers to IP Printers.
Stars: ✭ 22 (-29.03%)
Mutual labels:  snmp, snmp-protocol
tnm4j
A simplified SNMP API for Java, based on Jürgen Schönwälder's Tnm extension for Tcl.
Stars: ✭ 34 (+9.68%)
Mutual labels:  snmp
fapro
Fake Protocol Server
Stars: ✭ 1,338 (+4216.13%)
Mutual labels:  snmp
snmp-formula
docs.saltstack.com/en/latest/topics/development/conventions/formulas.html
Stars: ✭ 16 (-48.39%)
Mutual labels:  snmp
snmp notifier
A webhook to relay Prometheus alerts as SNMP traps, because sometimes, you have to deal with legacy
Stars: ✭ 33 (+6.45%)
Mutual labels:  snmp
dnms
Another network monitoring app built with nodejs.
Stars: ✭ 18 (-41.94%)
Mutual labels:  snmp
virgin-media-hub3
Python API and command line interface to the Virgin Media Hub 3 broadband router
Stars: ✭ 63 (+103.23%)
Mutual labels:  snmp
hnmp
High-level Python SNMP library
Stars: ✭ 44 (+41.94%)
Mutual labels:  snmp
scotty
A Tcl extension for building network management (SNMP, ICMP, UDP, DNS) applications
Stars: ✭ 29 (-6.45%)
Mutual labels:  snmp
snmpclitools
Pure-Python SNMP management tools
Stars: ✭ 36 (+16.13%)
Mutual labels:  snmp
triple-buffer
Implementation of triple buffering in Rust
Stars: ✭ 66 (+112.9%)
Mutual labels:  nonblocking
snmp-elixir
An SNMP client library for Elixir
Stars: ✭ 27 (-12.9%)
Mutual labels:  snmp
noc
Official read only mirror for
Stars: ✭ 84 (+170.97%)
Mutual labels:  snmp
GPONMonitor
GPON Monitoring tool for Dasan Networks GPON OLTs
Stars: ✭ 26 (-16.13%)
Mutual labels:  snmp
delta
DDD-centric event-sourcing library for the JVM
Stars: ✭ 15 (-51.61%)
Mutual labels:  nonblocking
Mikrotik-Router-Monitoring-System
SNMP based Router Monitoring System for Mikrotik Routers
Stars: ✭ 29 (-6.45%)
Mutual labels:  snmp
gondul
Network management/monitoring system specialized for temporary events
Stars: ✭ 40 (+29.03%)
Mutual labels:  snmp
influx snmp
SNMP Data Collection and Analytics with the TICK Stack (Telegraf, InfluxDB, Chronograf and Kapacitor)
Stars: ✭ 28 (-9.68%)
Mutual labels:  snmp
rabe-zabbix
Collection of various Zabbix templates and helper scripts created or used by Radio Bern RaBe
Stars: ✭ 93 (+200%)
Mutual labels:  snmp
tdm
Telemetry Data Mapper to ease data discovery, correlation, and usage with YANG, MIBs, etc.
Stars: ✭ 33 (+6.45%)
Mutual labels:  snmp

netsnmp

Tests Code Climate Docs

The netsnmp gem provides a ruby native implementation of the SNMP protocol (v1/2c abd v3).

Installation

Add this line to your application's Gemfile:

gem 'netsnmp'

And then execute:

$ bundle

Or install it yourself as:

$ gem install netsnmp

Features

This gem provides:

  • Implementation in ruby of the SNMP Protocol for v3, v2c and v1 (most notable the rfc3414 and 3826).
  • SNMPv3 USM supporting MD5/SHA/SHA256 auth and DES/AES128 privacy crypto algorithms.
  • Client/Manager API with simple interface for get, genext, set and walk.
  • Pure Ruby.
  • Support for concurrency and evented I/O.

Why?

If you look for snmp gems in ruby toolbox, you'll find a bunch. You may ask, why not just use one of them?

Most of them only implement v1 and v2, so if your requirement is to use v3, you're left with only 2 choices: net-snmp (unmantained since 2013) and its follow-up net-snmp2, which started as a fork to fix some bugs left unattended. Both libraries wrap the C netsnmp library using FFI, which leaves them vulnerable to the following bugs (experienced in both libraries):

  • Dependency of specific versions of netsnmp C package.
  • Memory Leaks.
  • Doesn't work reliable in ruby > 2.0.0-p576, crashing the VM.
  • Network I/O done by the library, thereby blocking the GVL, thereby making all snmp calls block the whole ruby VM.
    • This means, multi-threading is impossible.
    • This means, evented I/O is impossible.

All of these issues are resolved here.

Features

  • Client Interface, which supports SNMP v3, v2c, and v1
  • Supports get, getnext, set and walk calls
  • MIB support
  • Proxy IO object support (for eventmachine/celluloid-io)
  • Ruby >= 2.1 support (modern)
  • Pure Ruby (no FFI)
  • Easy PDU debugging

Examples

You can use the docker container provided under spec/support to test against these examples (the port used in the examples should be the docker external port mapped to port 161).

require 'netsnmp'

# example you can test against the docker simulator provided. port attribute might be different.
manager = NETSNMP::Client.new(host: "localhost", port: 33445, username: "simulator",
                              auth_password: "auctoritas", auth_protocol: :md5,
                              priv_password: "privatus", priv_protocol: :des,
                              context: "a172334d7d97871b72241397f713fa12")

# SNMP get
manager.get(oid: "sysName.0") #=> 'tt'

# SNMP walk
# sysORDescr
manager.walk(oid: "sysORDescr").each do |oid_code, value|
  # do something with them
  puts "for #{oid_code}: #{value}"
end

manager.close

# SNMP set
manager2 = NETSNMP::Client.new(host: "localhost", port: 33445, username: "simulator",
                               auth_password: "auctoritas", auth_protocol: :md5,
                               priv_password: "privatus", priv_protocol: :des,
                               context: "0886e1397d572377c17c15036a1e6c66")

# setting to 43, becos yes
# sysUpTimeInstance
manager2.set("1.3.6.1.2.1.1.3.0", value: 43)

manager2.close

SNMP v2/v1 examples will be similar (beware of the differences in the initialization attributes).

SNMP Application Types

All previous examples were done specifying primitive types, i.e. unless specified otherwise, it's gonna try to convert a ruby "primitive" type to an ASN.1 primitive type, and vice-versa:

  • Integer -> ASN.1 Integer
  • String -> ASN.1 Octet String
  • nil -> ASN.1 Null
  • true, false -> ASN.1 Boolean

That means that, if you pass value: 43 to the #set call, it's going to build a varbind with an ASN.1 Integer. If You issue a #get and the response contains an ASN.1 Integer, it's going to return an Integer.

However, SNMP defines application-specific ASN.1 types, for which there is support, albeit limited. Currently, there is support for ip addresses and timeticks.

  • IPAddr -> ASN.1 context-specific

If you create an IPAddr object (ruby standard library ipaddr) and pass it to the #set call, it will map to the SNMP content-specific code. If the response of a #get call contains an ip address, it will map to an IPAddr object.

  • NETSNMP::Timeticks -> ASN.1 content-specific

The NETSNMP::Timeticks type is internal to this library, but it is a ruby Numeric type. You are safe to use it "as a numeric", that is, perform calculations.

Counter32 and Counter64 types will map to plain integers.

You can find usage examples here. If you need support to a missing type, you have the following options:

  • Use the :type parameter in #set calls:
# as a symbol
manager.set("somecounteroid", value: 999999, type: :counter64)
# as the SNMP specific type id, if you're familiar with the protocol
manager.set("somecounteroid", value: 999999, type: 6)
  • Fork this library, extend support, write a test and submit a PR (the desired solution ;) )

MIB

netsnmp will load the default MIBs from known or advertised (via MIBDIRS) directories (provided that they're installed in the system). These will be used for the OID conversion.

Sometimes you'll need to load more, your own MIBs, in which case, you can use the following API:

require "netsnmp"

NETSNMP::MIB.load("MY-MIB")
# or, if it's not in any of the known locations
NETSNMP::MIB.load("/path/to/MY-MIB.txt")

You can install common SNMP mibs by using your package manager:

# using apt-get
> apt-get install snmp-mibs-downloader
# using apk
> apk --update add net-snmp-libs

Concurrency

In ruby, you are usually adviced not to share IO objects across threads. The same principle applies here to NETSNMP::Client: provided you use it within a thread of execution, it should behave safely. So, something like this would be possible:

general_options = { auth_protocol: ....
routers.map do |r|
  Thread.start do
    NETSNMP::Client.new(general_options.merge(host: r)) do |cl|
      cli.get(oid: "1.6.3.......

    end
  end
end.each(&:join)

Evented IO is also supported, in that you can pass a :proxy object as an already opened channel of communication to the client. Very important: you have to take care of the lifecycle, as the client will not connect and will not close the object, it will assume no control over it.

When passing a proxy object, you can omit the :host parameter.

The proxy object will have to be a duck-type implementing #send, which is a method receiving the sending PDU payload, and return the payload of the receiving PDU.

Here is a small pseudo-code example:

# beware, we are inside a warp-speed loop!!!
general_options = { auth_protocol: ....
proxy = SpecialUDPImplementation.new(host: router)
NETSNMP::Client.new(general_options.merge(proxy: proxy)) do |cl|
  # this get call will eventually #send to the proxy...
  cli.get(oid: "1.6.3.......

end
# client isn't usable anymore, but now we must close to proxy
proxy.close

For more information about this subject, the specs test this feature against celluloid-io. An eventmachine could be added, if someone would be kind enough to provide an implementation.

Performance

XOR

This library has some workarounds to some missing features in the ruby language, namely the inexistence of a byte array structure. The closest we have is a byte stream presented as a String with ASCII encoding. A method was added to the String class called #xor for some operations needed internally. To prevent needless monkey-patches, Refinements have been employed.

If #xor becomes at some point the bottleneck of your usage, this gem has also support for xorcist. You just have to add it to your Gemfile (or install it in the system):

# Gemfile

gem 'netsnmp'

# or, in the command line

$ gem install netsnmp

and netsnmp will automatically pick it up.

Auth/Priv Key

If you'll use this gem often with SNMP v3 and auth/priv security level enabled, you'll have that funny feeling that everything could be a bit faster. Well, this is basically because the true performance bottleneck of this gem is the generation of the auth and pass keys used for authorization and encryption. Although this is a one-time thing for each client, its lag will be noticeable if you're running on > 100 hosts.

There is a recommended work-around, but this is only usable if you are using the same user/authpass/privpass on all the hosts!!!. Use this with care, then:

$shared_security_parameters = NETSNMP::SecurityParameters.new(security_level: :authpriv, username: "mustermann",
                                                              auth_protocol: :md5, priv_protocol: :aes, ....
# this will eager-load the auth/priv_key
...

# over 9000 routers are running on this event loop!!! this is just one!
NETSNMP::Client.new(share_options.merge(proxy: router_proxy, security_parameters: $shared_security_parameters.dup).new do |cl|
  cli.get(oid:  .....
end

Compatibility

This library supports and is tested against ruby versions 2.1 or more recent, including ruby 3. It also supports and tests against Truffleruby.

OpenSSL

All encoding/decoding/encryption/decryption/digests are done using openssl, which is (still) a part of the standard library. If at some point openssl is removed and not specifically distributed, you'll have to install it yourself. Hopefully this will never happen.

It also uses the openssl ASN.1 API to encode/decode BERs, which is known to be strict, and may not be able to decode PDUs if not compliant with the supported RFC.

Debugging

You can either set the NETSNMP_DEBUG to the desided debug level (currently, 1 and 2). The logs will be written to stderr.

You can also set it for a specific client:

manager2 = NETSNMP::Client.new(debug: $stderr, debug_level: 2, ....)

Tests

This library uses RSpec. The client specs are "integration" tests, in that we communicate with an snmpsim-built snmp agent simulator.

RSpec

You can run all tests by typing:

> bundle exec rake spec
# or
> bundle exec rspec
...

Docker

The most straightforward way of running the tests is by using the docker-compose setup (which is also what's used in the CI). Run it against the ruby version you're targeting:

> docker-compose -f docker-compose.yml -f docker-compose-ruby-${RUBY_MAJOR_VERSION}.${RUBY_MAJOR_VERSION}.yml run netsnmp

The CI runs the tests against all supported ruby versions. If changes break a specific version of ruby, make sure you commit appropriate changes addressing the edge case, or let me know in the issues board, so I can help.

SNMP Simulator

The SNMP simulator runs in its own container in the docker setup.

You can install the package yourself (ex: pip install snmpsim) and run the server locally, and then set the SNMP_PORT environment variable, where the snmp simulator is running.

CI

The job of the CI is:

  • Run all the tests;
  • Make sure the tests cover an appropriate surface of the code;
  • Lint the code;
  • (for ruby 3.0) type check the code;

Contributing

  • Fork this repository
  • Make your changes and send me a pull request
  • If I like them I'll merge them
  • If I've accepted a patch, feel free to ask for a commit bit!

TODO

There are some features which this gem doesn't support. It was built to provide a client (or manager, in SNMP language) implementation only, and the requirements were fulfilled. However, these notable misses will stand-out:

  • No server (Agent, in SNMP-ish) implementation.
  • No getbulk support.

So if you like the gem, but would rather have these features implemented, please help by sending us a PR and we'll gladly review it.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].