Git Product home page Git Product logo

ruby-netsnmp's Introduction

netsnmp

Gem Version 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.

ruby-netsnmp's People

Contributors

honeyryderchuck avatar jinxka avatar mschaf avatar netforces avatar stakach avatar

Stargazers

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

Watchers

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

ruby-netsnmp's Issues

SNMPV3. Failing to load some legacy MIBs.

Thank you for handling issue #69
We are now able to load the majority of MIBs. yet we still have an error related to the parslet lib:
Weird error.
Failed to load MIB TROPIC-ACCESSPORT-MIB Failed to match sequence (SPACE{0, } MODULES?) at line 1 char 1.
Failed to load MIB TROPIC-SLOT-MIB Failed to match sequence (SPACE{0, } MODULES?) at line 1 char 1.

ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]

["/opt/mono/embedded/lib/ruby/gems/2.4.0/gems/parslet-2.0.0/lib/parslet/cause.rb:70:in `raise'", 
"/opt/mono/embedded/lib/ruby/gems/2.4.0/gems/parslet-2.0.0/lib/parslet/atoms/base.rb:49:in `parse'", 
"/opt/mono/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:111:in `block in do_load'", 
"/opt/mono/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:111:in `synchronize'", 
"/opt/mono/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:111:in `do_load'", 
"/opt/mono/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:88:in `load'", 
"v3.rb:30:in `block in <main>'", 
"v3.rb:27:in `each'", "v3.rb:27:in `<main>'"]

I am Attaching the MIBs below.
Thank you for your reactiveness.

PS: No problem using standard ruby snmp library for v2c or snmpwalk in V2 or v3 or even Python SNIMP V2/V3.

JRuby Support

Currently there are some issues with jruby's openssl:

  • ASN1 modules are broken

testing on the digest and cipher modules are (for now) depending on asn1 modules to be fixed.

MIB parser

It's time to add support for MIB (both SMIv1 and SMIv2)

Failure in aes.rb on Ubuntu 16/18 when using auth_proto=SHA and priv_proto=AES

Forgive me as I am a total Ruby newbie!

Using code like the following ...
snmp = NETSNMP::Client.new(host: '127.0.0.1', port: 161, version: 3,
username: user, auth_protocol: auth_proto, auth_password: auth_pass,
priv_protocol: priv_proto, priv_password: priv_pass)

I get the following error ...
Traceback (most recent call last):
9: from ./test.rb:13:in <main>' 8: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/client.rb:56:in get'
7: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/client.rb:144:in handle_retries' 6: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/client.rb:56:in block in get'
5: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/v3_session.rb:23:in send' 4: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/session.rb:41:in send'
3: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/v3_session.rb:76:in decode' 2: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/message.rb:34:in decode'
1: from /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/security_parameters.rb:89:in decode' /var/lib/gems/2.5.0/gems/netsnmp-0.1.4/lib/netsnmp/encryption/aes.rb:38:in decrypt': invalid encrypted PDU received (NETSNMP::Error)

If I make the following edits to aes.rb ...
def decrypt(encrypted_data, salt:, engine_boots:, engine_time:)
raise Error, "invalid priv salt received" unless (salt.length % 8).zero?
p "Encrypted data = #{encrypted_data}"
p "Encrypted data length = #{encrypted_data.length}"
p "Encrypted data length mod8 = #{encrypted_data.length % 8}"
p "Encrypted data length mod8 is zero = #{(encrypted_data.length % 8).zero?}"
p "Does Integer have a 'zero?=' method? = #{(encrypted_data.length % 8).methods.include? 'zero?='.to_sym }"
p "Does Integer have a 'zero?' method? = #{(encrypted_data.length % 8).methods.include? 'zero?'.to_sym }"
#raise Error, "invalid encrypted PDU received" unless (encrypted_data.length % 8).zero?

Then everything appears to work just fine and it produces the following output ...
"Encrypted data = \x96\x16$\xBB}\x9C ---SNIP TO OBSCURE--- \xE7\xEF\xC8I\x17\xC4"
"Encrypted data length = 77"
"Encrypted data length mod8 = 5"
"Encrypted data length mod8 is zero = false"
"Does Integer have a 'zero?=' method? = false"
"Does Integer have a 'zero?' method? = true"

So the root cause of the failure is the absence of method zero?= on my host, but also my encrypted data does not divide through by zero.

ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-gnu]

gem list | grep netsnmp
netsnmp (0.1.4)

Occasional "Decryption error" with SNMPv3

Hello,

Note: This was most likely introduced in 0.4.2, after downgrading to 0.4.1 the issues disappeared.

Occasionally*, I get the following error:

/usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/v3_session.rb:100:in `decode': Decryption error (NETSNMP::Error)

I traced it down, it's not a network issue, according to wireshark the sent packet is already malformed. I also compared the hex output from debug with the sent packet in Wireshark, there's no difference.

So I assume there's something wrong with the ruby code generating the get-packet.

Initalization:

      class Secrets
        def self.snmp_user
                "Influx"
        end
        def self.snmp_auth_password
                'xx'
        end
        def self.snmp_priv_password
                'xx'
        end
      end
      manager = NETSNMP::Client.new(host: ip_address, port: 161, username: Secrets.snmp_user,
        auth_password: Secrets.snmp_auth_password, auth_protocol: "sha",
        priv_password: Secrets.snmp_priv_password, priv_protocol: "aes",
        retry: 10, debug: $stderr, debug_level: 2)

Query:

      oids = %w(IF-MIB::ifHCOutOctets IF-MIB::ifHCInOctets IF-MIB::ifInErrors IF-MIB::ifOutErrors IF-MIB::ifInDiscards IF-MIB::ifOutDiscards)
      puts "*****************walk2" if debug
      oids.each{|oid|
        manager.walk(oid: oid).each {|oid_code, value|
        [...]

Output including debug:

[....]

sending request...

pdu: 3039
        engine_id: 0411 8000 1f88 0430 3133 3130 3130 3132 3132 ("\x80\x00\x1F\x88\x04013101012120")
        context: 0400 ("")
        request: a122
                request_id: 0204 053b 35d5 ("87766485")
                error: 0201 ("0")
                error_index: 0201 ("0")
                varbinds: 3014
                        Sequence: 3012
                                ObjectId: 060e 2b06 0102 0102 0201 0e81 eeb6 9e38 ("1.3.6.1.2.1.2.2.1.14.500010808")
                                Null: 0500

encoding PDU in V3 message...

security_params: 303b
        engine_id: 0411 8000 1f88 0430 3133 3130 3130 3132 3132 ("\x80\x00\x1F\x88\x04013101012120")
        engine_boots: 0201 ("12")
        engine_time: 0203 1efa ("2030242")
        username: 0406 496e 666c 7578 ("Influx")
        auth_mask: 040c 0000 0000 0000 0000 0000 0000 ("\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000")
        salt: 0408 0000 0000 0000 008e ("\x00\x00\x00\x00\x00\x00\x00\x8E")

v3_message: 3081
        message_version: 0201 ("3")
        headers: 3011
                message_id: 0204 784e 3854 ("2018392148")
                max_message_size: 0203 00ff ("65507")
                message_flags: 0401 ("\a")
                security_model: 0201 ("3")
        security_params: 043d 303b 0411 8000 1f88 0430 3133 3130 3130 3132 3132 3002 010c 0203 1efa a204 0649 6e66 6c75 7804 0c00 0000 0000 0000 0000 0000 0004 0800 0000 0000 0000 ("0;\x04\x11\x80\x00\x1F\x88\x04013101012120\x02\x01\f\x02\x03\x1E\xFA\xA2\x04\x06Influx\x04\f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\b\x00\x00\x00\x00\x00\x00\x00\x8E")
        encrypted_pdu: 0440 cacb d443 362a e0a8 2fa8 2867 f5d6 cb19 b6b3 a33c f396 c85c e87f 3593 dda4 9130 c5fe 4479 8bc9 8bce 3b58 9c19 f8d4 998a b3b3 68e8 0abb 972c e96d 0984 df82 1ff2 ("\xCA\xCB\xD4C6*\xE0\xA8/\xA8(g\xF5\xD6\xCB\x19\xB6\xB3\xA3<\xF3\x96\xC8\\\xE8\x7F5\x93\xDD\xA4\x910\xC5\xFEDy\x8B\xC9\x8B\xCE;X\x9C\x19\xF8\xD4\x99\x8A\xB3\xB3h\xE8\n\xBB\x97,\xE9m\t\x84\xDF\x82\x1F\xF2")

3081 9702 0103 3011 0204 784e 3854 0203
00ff e304 0107 0201 0304 3d30 3b04 1180
001f 8804 3031 3331 3031 3031 3231 3230
0201 0c02 031e faa2 0406 496e 666c 7578
040c 0000 0000 0000 0000 0000 0000 0408
0000 0000 0000 008e 0440 cacb d443 362a
e0a8 2fa8 2867 f5d6 cb19 b6b3 a33c f396
c85c e87f 3593 dda4 9130 c5fe 4479 8bc9
8bce 3b58 9c19 f8d4 998a b3b3 68e8 0abb
972c e96d 0984 df82 1ff2

signing V3 message...

auth: 040c 885e 4e3e 6a8c c189 9e5c 3052 ("\x88^N>j\x8C\xC1\x89\x9E\\0R")

3081 9702 0103 3011 0204 784e 3854 0203
00ff e304 0107 0201 0304 3d30 3b04 1180
001f 8804 3031 3331 3031 3031 3231 3230
0201 0c02 031e faa2 0406 496e 666c 7578
040c 885e 4e3e 6a8c c189 9e04 0c00 0000
0000 0000 0000 0000 0052 0408 0000 0000
0000 008e 0440 cacb d443 362a e0a8 2fa8
2867 f5d6 cb19 b6b3 a33c f396 c85c e87f
3593 dda4 9130 c5fe 4479 8bc9 8bce 3b58
9c19 f8d4 998a b3b3 68e8 0abb 972c e96d
0984 df82 1ff2

received encoded V3 message

3077 0201 0330 1102 0478 4e38 5402 0300
ffe3 0401 0002 0103 0429 3027 0411 8000
1f88 0430 3133 3130 3130 3132 3132 3002
010c 0203 1efa a504 0649 6e66 6c75 7804
0004 0030 3404 1180 001f 8804 3031 3331
3031 3031 3231 3230 0400 a81d 0201 0002
0100 0201 0030 1230 1006 0a2b 0601 0603
0f01 0106 0041 0209

v3_message: 3077
        message_version: 0201 ("3")
        headers: 3011
                Integer: 0204 784e 3854 ("2018392148")
                Integer: 0203 00ff ("65507")
                message_flags: 0401 ("\x00")
                Integer: 0201 ("3")
        security_params: 0429 3027 0411 8000 1f88 0430 3133 3130 3130 3132 3132 3002 010c 0203 1efa a504 0649 6e66 6c75 7804 0004 ("0'\x04\x11\x80\x00\x1F\x88\x04013101012120\x02\x01\f\x02\x03\x1E\xFA\xA5\x04\x06Influx\x04\x00\x04\x00")
        pdu: 3034
                OctetString: 0411 8000 1f88 0430 3133 3130 3130 3132 3132 ("\x80\x00\x1F\x88\x04013101012120")
                OctetString: 0400 ("")
                ASN1Data: a81d
                        Integer: 0201 ("0")
                        Integer: 0201 ("0")
                        Integer: 0201 ("0")
                        Sequence: 3012
                                Sequence: 3010
                                        ObjectId: 060a 2b06 0106 030f 0101 0600 ("1.3.6.1.6.3.15.1.1.6.0")
                                        ASN1Data: 4102 0954

security_params: 3027
        engine_id: 0411 8000 1f88 0430 3133 3130 3130 3132 3132 ("\x80\x00\x1F\x88\x04013101012120")
        engine_boots: 0201 ("12")
        engine_time: 0203 1efa ("2030245")
        username: 0406 496e 666c 7578 ("Influx")
        auth_param: 0400 ("")
        priv_param: 0400 ("")

received response PDU

pdu: 3034
        engine_id: 0411 8000 1f88 0430 3133 3130 3130 3132 3132 ("\x80\x00\x1F\x88\x04013101012120")
        context: 0400 ("")
        request: a81d
                request_id: 0201 ("0")
                error: 0201 ("0")
                error_index: 0201 ("0")
                varbinds: 3012
                        Sequence: 3010
                                ObjectId: 060a 2b06 0106 030f 0101 0600 ("1.3.6.1.6.3.15.1.1.6.0")
                                Integer: 0202 0954 ("2388")
Error while querying:
Traceback (most recent call last):
        10: from snmp.rb:101:in `each'
         9: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:84:in `block in walk'
         8: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:84:in `catch'
         7: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:85:in `block (2 levels) in walk'
         6: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:85:in `loop'
         5: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:86:in `block (3 levels) in walk'
         4: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:67:in `get_next'
         3: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:155:in `handle_retries'
         2: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/client.rb:67:in `block in get_next'
         1: from /usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/v3_session.rb:27:in `send'
/usr/local/rvm/gems/ruby-2.7.3/gems/netsnmp-0.4.2/lib/netsnmp/v3_session.rb:100:in `decode': Decryption error (NETSNMP::Error)

Full trace from beginning to end is available as well as a pcap file.

What information do you need to find the reason of this issue?

Environment: netsnmp-0.4.2, ruby-2.7.3, SNMP server: Palo Alto Firewall with PAN-OS 9.1.4

*Occasionally: I currently query 10 firewalls for various traffic statistics, the script finishes without any error around 50% of the time.

Thanks
Sebastian

Counter64 OID Values Are Returned as nil

This is a follow up to #23. Apologies for not being clear previously.

For reference, here is my setup.

Ruby:

$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]

Ubuntu:

$ cat /etc/issue
Ubuntu 16.04.4 LTS \n \l

ruby-netsnmp Gem:

$ gem query netsnmp

*** LOCAL GEMS ***

netsnmp (0.1.5)

The values of Counter64 OIDs are reported as nil. Compare the following.

Here is an example of ifHCInOctets table returned by snmpwalk:

$ snmpwalk -v3 -l authNoPriv -u myuser -a sha -A "mypassword" myhost.example.com ifHCInOctets
IF-MIB::ifHCInOctets.1 = Counter64: 92491218
IF-MIB::ifHCInOctets.2 = Counter64: 16155773819
IF-MIB::ifHCInOctets.3 = Counter64: 0
IF-MIB::ifHCInOctets.15 = Counter64: 14546980809
IF-MIB::ifHCInOctets.17 = Counter64: 15662965
IF-MIB::ifHCInOctets.18 = Counter64: 11646536
IF-MIB::ifHCInOctets.19 = Counter64: 12299679
IF-MIB::ifHCInOctets.20 = Counter64: 122748726
IF-MIB::ifHCInOctets.21 = Counter64: 12830296

And here is the same table values returned by Sensu plugin using ruby-netsnmp gem:

$ ruby metrics-snmp-if.rb -h myhost.example.com -u myuser -p mypassword -l auth_no_priv | grep ifHCInOctets
snmp.interfaces.lo.ifHCInOctets
snmp.interfaces.eth0.ifHCInOctets
snmp.interfaces.vti90.ifHCInOctets
snmp.interfaces.vti91.ifHCInOctets
snmp.interfaces.vti0.ifHCInOctets
snmp.interfaces.vti1.ifHCInOctets
snmp.interfaces.vti2.ifHCInOctets
snmp.interfaces.vti3.ifHCInOctets

I believe the simple fix is to modify convert_application_asn method in lib/netsnmp/varbind.rb from:

    def convert_application_asn(asn)
      case asn.tag
      when 0 # IP Address
        IPAddr.new_ntoh(asn.value)
      when 1, # ASN counter 32
           2 # gauge
        val = asn.value
        val.prepend("\x00") while val.bytesize < 4
        asn.value.unpack("N*")[0] || 0

to:

    def convert_application_asn(asn)
      case asn.tag
      when 0 # IP Address
        IPAddr.new_ntoh(asn.value)
      when 1, # ASN counter 32
           2, # gauge
           6  # ASN Counter 64
        val = asn.value
        val.prepend("\x00") while val.bytesize < 4
        asn.value.unpack("N*")[0] || 0

Example of my output after the fix is applied:

$ ruby metrics-snmp-if.rb -h myhost.example.com -u myuser -p mypassword -l auth_no_priv | grep ifHCInOctets
snmp.interfaces.lo.ifHCInOctets 92491218 1530802973
snmp.interfaces.eth0.ifHCInOctets 63110204 1530802973
snmp.interfaces.vti90.ifHCInOctets 56824152 1530802973
snmp.interfaces.vti91.ifHCInOctets 15665023 1530802973
snmp.interfaces.vti0.ifHCInOctets 11648594 1530802973
snmp.interfaces.vti1.ifHCInOctets 12301529 1530802973
snmp.interfaces.vti2.ifHCInOctets 122750576 1530802973
snmp.interfaces.vti3.ifHCInOctets 12832458 1530802973

V3 cannot parse TROPIC-GLOBAL-MIB

If I use the Python SNIMPY package, I can poll without problems using V3 but Impossible with ruby-netsnmp v3. The library cannot figure out how to parse this MIB: TROPIC-GLOBAL-MIB

/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:141:in `block in store_oid_in_identifiers': didn't find a module to import "tropicModules" from (NETSNMP::Error)
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:126:in `each'
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:126:in `flat_map'
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:126:in `store_oid_in_identifiers'
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:121:in `block in do_load'
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:120:in `each'
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:120:in `do_load'
	from /opt/sensu/embedded/lib/ruby/gems/2.4.0/gems/netsnmp-0.6.4/lib/netsnmp/mib.rb:88:in `load'
Below is the MIB.

https://drive.google.com/file/d/1OGz3oSFOrZU0XXptTff0ihaxDgCPICUH/view?usp=sharing

Thanks for your help.
PS: Using SNMP v2 with other ruby modules (like ruby-snmp), It is fine.

SNMPSet two different OIDs in one request command?

Use case, I am trying to save the config file on a network switch device snAgWriteNVRAM 1.3.6.1.4.1.1991.1.1.2.1.3.0 after enabling/disabling an interface port. The OID to save the config file requires an additional OID for snAgGblPassword 1.3.6.1.4.1.1991.1.1.2.1.15.0 (System Security Access Password).

My successful SNMPSet command on CLI with two OIDs look like this:

snmpset -v 3 -u <username> -l authPriv -a <auth_protocol:> -A <auth_password> -x <priv_protocol> -X priv_password -t 3 <host> 1.3.6.1.4.1.1991.1.1.2.1.15.0 s <snAgGblPassword> 1.3.6.1.4.1.1991.1.1.2.1.3.0 i 3

# For readability, the above looks like this
snmpset 
  -v 3
  -u <username>
  -l authPriv
  -a <auth_protocol:> -A <auth_password>
  -x <priv_protocol> -X <priv_password>
  -t 3 <host>
  1.3.6.1.4.1.1991.1.1.2.1.15.0 s <snAgGblPassword>
  1.3.6.1.4.1.1991.1.1.2.1.3.0 i 3

The SNMPSet command will fail without the accompanying snAgGblPassword OID being set BEFORE the snAgWriteNVRAM OID. So order matters as well.

SNMPv3 not working with APC UPS

Hello,
I am trying to pull data of a APC Smart UPS X with the AP9631 network card.

I can use snmpget to query oids just fine, e.g.

$ snmpget -v3 -u apc -a MD5 -A 123456789 -x AES -X 123456789 -l authPriv 10.2.0.60 -On 1.3.6.1.2.1.33.1.4.4.1.2.1
> .1.3.6.1.2.1.33.1.4.4.1.2.1 = INTEGER: 231 RMS Volts

But when I try it via ruby

NETSNMP::Client.new(host: "10.2.0.60", username: "apc", auth_password: "123456789", auth_protocol: :md5, priv_password: "12
3456789", priv_protocol: :aes, security_level: :auth_priv).get("1.3.6.1.2.1.33.1.4.4.1.2.1")

I get Timeout after 2 seconds (Timeout::Error.
My assumtion is, that these two should do exactly the same, am I wrong with that?

I looked at the requests with wireshark and they are slightly different.
snmpget:
Screenshot from 2022-05-05 01-08-09
ruby-netsnmp:
Screenshot from 2022-05-05 01-08-39

I am using:

  • Ruby: 2.7.5
  • ruby-netsnmp: 0.6.3
  • snmpget: NET-SNMP version: 5.8
  • Ubuntu 20.04.3 LTS

Different encoding of results

Using gem 'netsnmp', '~> 0.3.0'

Is this an issue with xor? I installed xorcist, but same results.

This is the request/results from the snmpwalk command on CLI:

$ snmpwalk -v 3 <auth> <ip address> 1.3.6.1.4.1.1991.1.1.3.33.1.1.1.4

iso.3.6.1.4.1.1991.1.1.3.33.1.1.1.4.8.76.65.71.45.77.65.84.72 = Hex-STRING: 00 00 00 06 00 00 00 07 00 00 0C 8C
iso.3.6.1.4.1.1991.1.1.3.33.1.1.1.4.14.76.65.71.45.84.72.69.45.84.72.73.78.71.83 = Hex-STRING: 00 00 00 0A 00 00 00 0B 00 00 0C 0A
iso.3.6.1.4.1.1991.1.1.3.33.1.1.1.4.14.76.65.71.45.84.72.69.83.69.45.65.76.83.79 = Hex-STRING: 00 00 00 10 00 00 00 11 00 00 0C 88

This is the results from this gem, converted to hash from the Enumarato (for readability):

=> {
  "1.3.6.1.4.1.1991.1.1.3.33.1.1.1.4.8.76.65.71.45.77.65.84.72"=>
  "00 00 00 06 00 00 00 07 00 00 0C 8C",
 "1.3.6.1.4.1.1991.1.1.3.33.1.1.1.4.14.76.65.71.45.84.72.69.45.84.72.73.78.71.83"=>
  "\u0000\u0000\u0000\n\u0000\u0000\u0000\v\u0000\u0000\f\n",
 "1.3.6.1.4.1.1991.1.1.3.33.1.1.1.4.14.76.65.71.45.84.72.69.83.69.45.65.76.83.79"=>
  "00 00 00 10 00 00 00 11 00 00 0C 88"
  }

The first and last values are <Encoding:US-ASCII>, but the second value is <Encoding:UTF-8>. Is it possible to force the encoding to the ASCII encoding? As we can see from the returned values, ASCII matches the results from the CLI.

Having two different encodings requires a conditional to handle the results separately.

Counter32 and Counter64 Values Issue

Here is my setup.

Ruby:

$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]

Ubuntu:

$ cat /etc/issue
Ubuntu 16.04.4 LTS \n \l

ruby-netsnmp Gem:

$ gem query netsnmp

*** LOCAL GEMS ***

netsnmp (0.1.4)

From what I can tell, the values of Counter32 OIDs are reported incorrectly. Compare the following.

Here is an example of ifInOctets table returned by snmpwalk:

$ snmpwalk -v3 -l authNoPriv -u myuser -a sha -A "mypassword" myhost.example.com ifInOctets
IF-MIB::ifInOctets.1 = Counter32: 92484354
IF-MIB::ifInOctets.2 = Counter32: 3332448588
IF-MIB::ifInOctets.3 = Counter32: 0
IF-MIB::ifInOctets.15 = Counter32: 2569477446
IF-MIB::ifInOctets.17 = Counter32: 13813612
IF-MIB::ifInOctets.18 = Counter32: 10101063
IF-MIB::ifInOctets.19 = Counter32: 10705215
IF-MIB::ifInOctets.20 = Counter32: 61569568
IF-MIB::ifInOctets.21 = Counter32: 11202500

And here is the same table values returned by Sensu plugin using ruby-netsnmp gem:

$ ruby metrics-snmp-if.rb -h myhost.example.com -u myuser -p mypassword -l auth_no_priv | grep ifInOctets
snmp.interfaces.lo.ifInOctets 1411 1530644867
snmp.interfaces.eth0.ifInOctets 198 1530644867
snmp.interfaces.vti90.ifInOctets 153 1530644867
snmp.interfaces.vti91.ifInOctets 210 1530644867
snmp.interfaces.vti0.ifInOctets 154 1530644867
snmp.interfaces.vti1.ifInOctets 163 1530644867
snmp.interfaces.vti2.ifInOctets 939 1530644867
snmp.interfaces.vti3.ifInOctets 170 1530644867

I believe the simple fix is to change line 106 in lib/netsnmp/varbind.rb from:

        asn.value.unpack("n*")[0] || 0

to:

        asn.value.unpack("N*")[0] || 0

(in other words, replacing n* with N*)

Additionally, the gem currently returns nil when retrieving Counter64 OIDs. I believe the fix for that is to add the following lines 113-114 to lib/netsnmp/varbind.rb:

      when 6 # ASN counter 64
        asn.value.unpack("N*")[0] || 0

Example of my output after the fix is applied:

$ ruby metrics-snmp-if.rb -h myhost.example.com -u myuser -p mypassword -l auth_no_priv | grep ifInOctets
snmp.interfaces.lo.ifInOctets 92484354 1530645343
snmp.interfaces.eth0.ifInOctets 13021274 1530645343
snmp.interfaces.vti90.ifInOctets 10037049 1530645343
snmp.interfaces.vti91.ifInOctets 13820746 1530645343
snmp.interfaces.vti0.ifInOctets 10105389 1530645343
snmp.interfaces.vti1.ifInOctets 10709437 1530645343
snmp.interfaces.vti2.ifInOctets 61576026 1530645343
snmp.interfaces.vti3.ifInOctets 11206618 1530645343

$ ruby metrics-snmp-if.rb -h myhost.example.com -u myuser -p mypassword -l auth_no_priv | grep ifHCInOctets
snmp.interfaces.lo.ifHCInOctets 92484354 1530645383
snmp.interfaces.eth0.ifHCInOctets 29798688 1530645383
snmp.interfaces.vti90.ifHCInOctets 26814267 1530645383
snmp.interfaces.vti91.ifHCInOctets 13821238 1530645383
snmp.interfaces.vti0.ifHCInOctets 10105673 1530645383
snmp.interfaces.vti1.ifHCInOctets 10709721 1530645383
snmp.interfaces.vti2.ifHCInOctets 61576518 1530645383
snmp.interfaces.vti3.ifHCInOctets 11207006 1530645383

walk method does not work

Trying to get the list of SSIDs on a Ruckus ZoneDirector. Using shell snmpwalk commands works as expected:

#   $ snmpwalk -On -v3  -l authPriv -u "my_user" -a MD5 -A "my_pass"  -x DES -X "my_pass" 192.168.161.202 .1.3.6.1.4.1.25053.1.2.2.2.1.1.1.1.2
#   .1.3.6.1.4.1.25053.1.2.2.2.1.1.1.1.2.1 = STRING: "MYSSID1"
#   .1.3.6.1.4.1.25053.1.2.2.2.1.1.1.1.2.2 = STRING: "MYSSID2"

Trying the following code returns nothing:

require 'netsnmp'

# example you can test against the docker simulator provided. port attribute might be different. 
manager = NETSNMP::Client.new(host: "192.168.161.202", port: 161, username: "my_user",
                              auth_password: "my_pass", auth_protocol: :md5, 
                              priv_password: "my_pass", priv_protocol: :des,
                              timeout: 30, version: "v3")

manager.walk(oid: ".1.3.6.1.4.1.25053.1.2.2.2.1.1.1.1.2") do |oid_code, value| 
  puts "for #{oid_code}: #{value}"
end

Using a more "manual" method to get the data works:

require 'netsnmp'

# example you can test against the docker simulator provided. port attribute might be different. 
manager = NETSNMP::Client.new(host: "192.168.161.202", port: 161, username: "my_user",
                              auth_password: "my_pass", auth_protocol: :md5, 
                              priv_password: "my_pass", priv_protocol: :des,
                              timeout: 30, version: "v3")

count=1
loop do 
  value = manager.get(oid: ".1.3.6.1.4.1.25053.1.2.2.2.1.1.1.1.2.#{count}")
  break if value == 0
  puts "SSID #{count}: #{value}"
  count = count + 1
end 

Running ruby v2.3.1p112 with the netsnmp gem v0.1.3

Bug AES decrypt when salt is empty

Hello,

I had a case when one of my device returned an empty salt (""), and I got the error 'iv must be 16 bytes'

After investigating, I found that we verify if the salt is '% 8' but not if it's present.

(''.length % 8).zero? is true, it should not.

raise Error, "invalid priv salt received" unless (salt.length % 8).zero?

Cisco Mibs Brake when using mib names

If I use the Cisco mibs by name (i.e. ciscoMemoryPoolFree), I would get the following error:

"errorMessage": "invalid OBJECT ID 48.1.1.1.7.7: first num too large",
"errorType": "Function<OpenSSL::ASN1::ASN1Error>"

If I use the OID it works and provides the correct feedback

Errors in 0.1.4

Trying to use 0.1.4:

/usr/lib64/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:68:in `require': /usr/lib64/ruby/gems/2.0.0/gems/netsnmp-0.1.4/lib/netsnmp/pdu.rb:64: syntax error, unexpected ',' (SyntaxError)
    def initialize(type:, headers:,
                         ^

and

/usr/lib64/ruby/gems/2.0.0/gems/netsnmp-0.1.4/lib/netsnmp/pdu.rb:91: syntax error, unexpected ','
    def add_varbind(oid:, **options)
                         ^

SNMPv3 with DES and MD5 fails: invalid message authentication salt

These parameters are used:
client = NETSNMP::Client.new({host: 'a.b.c.d', port: 161, version: '3', username: 'user', security_level: 3, auth_protocol: 'md5', auth_password: 'Password1', priv_protocol: 'des', priv_password: 'Password1'})
client.get(oid: "1.3.6.1.2.1.1.5.0")

Error: invalid message authentication salt

Testing in Windows and Ubuntu.
The same parameters were validated and work on Ubuntu with a command-line tool.

uninitialized constant Socket::MSG_NOSIGNAL

Looks like the newer versions of netsnmp are complaining about Socket::MSG_NOSIGNAL

By downgrading to 0.4.0, this error goes away. Confirmed this on both ruby 2.7.3 and 3.0.1

manager.get(oid: "sysName.0")


# uninitialized constant Socket::MSG_NOSIGNAL
# Did you mean?  Socket::MSG_HOLD

The gem does not recognize authentication failures

Hello,

As you can read in the title, it looks like the gem does not recognize the authentication failures.

When using bad passwords, I was expecting the client to raise an error 'Authentication failure', like it does on the snmpget command:

image

But instead of raising an error, it returns an integer which correspond to the number of requests received by the device.

Is it voluntary?

Setting Gauge32 type OID fails

Sample code:

require 'netsnmp'
manager2 = NETSNMP::Client.new(host: "10.81.35.132", community: "public", version: "1")

manager2.set(oid: "1.3.6.1.2.1.17.7.1.4.5.1.1.1", value: 1000)

manager2.close

Result:

/Users/courchea/.rbenv/versions/2.3.5/lib/ruby/gems/2.3.0/gems/netsnmp-0.1.3/lib/netsnmp/client.rb:143:in `rescue in handle_retries': uninitiali
zed constant NETSNMP::Client::Timeout (NameError)
Did you mean?  Time
        from /Users/courchea/.rbenv/versions/2.3.5/lib/ruby/gems/2.3.0/gems/netsnmp-0.1.3/lib/netsnmp/client.rb:141:in `handle_retries'
        from /Users/courchea/.rbenv/versions/2.3.5/lib/ruby/gems/2.3.0/gems/netsnmp-0.1.3/lib/netsnmp/client.rb:130:in `set'

        from test.rb:5:in `<main>'

Trying via the CLI snmpset works:

snmpset -c public -v1 10.81.35.132 1.3.6.1.2.1.17.7.1.4.5.1
.1.1 u 1000
SNMPv2-SMI::mib-2.17.7.1.4.5.1.1.1 = Gauge32: 1000

cc @mdeloupy

The gem does not recognize a missing OID

Hello,

I've crossed an issue with one of my device where the gem does not understand that the OID is missing while the snmpget command does.

image

Instead of raising the usual IPAddr::AddressFamilyError, the gem detects an Integer:0. This is problematic for me because I use the presence/absence of specific OIDs to detect the type of product I'm dealing with.

The debug from snmpget

Sending 70 bytes to UDP: [141.94.173.41]:30007->[0.0.0.0]:42102
0000: 30 44 02 01  03 30 11 02  04 74 03 FB  CE 02 03 00    0D...0...t......
0016: FF E3 04 01  04 02 01 03  04 10 30 0E  04 00 02 01    ..........0.....
0032: 00 02 01 00  04 00 04 00  04 00 30 1A  04 00 04 06    ..........0.....
0048: 70 75 62 6C  69 63 A0 0E  02 04 24 6C  5E 79 02 01    public....$l^y..
0064: 00 02 01 00  30 00                                    ....0.


Received 131 byte packet from UDP: [141.94.173.41]:30007->[0.0.0.0]:42102
0000: 30 81 80 02  01 03 30 11  02 04 74 03  FB CE 02 03    0.....0...t.....
0016: 00 FF E3 04  01 00 02 01  03 04 26 30  24 04 15 80    ..........&0$...
0032: 00 4F B8 05  38 63 38 31  61 39 61 66  32 37 65 36    .O..8c81a9af27e6
0048: 00 07 C3 40  02 01 02 02  02 0B E4 04  00 04 00 04    ...@............
0064: 00 30 40 04  15 80 00 4F  B8 05 38 63  38 31 61 39    [email protected]
0080: 61 66 32 37  65 36 00 07  C3 40 04 06  70 75 62 6C    [email protected]
0096: 69 63 A8 1F  02 04 24 6C  5E 79 02 01  00 02 01 00    ic....$l^y......
0112: 30 11 30 0F  06 0A 2B 06  01 06 03 0F  01 01 04 00    0.0...+.........
0128: 41 01 10                                              A..


Sending 159 bytes to UDP: [141.94.173.41]:30007->[0.0.0.0]:42102
0000: 30 81 9C 02  01 03 30 11  02 04 74 03  FB CD 02 03    0.....0...t.....
0016: 00 FF E3 04  01 07 02 01  03 04 43 30  41 04 15 80    ..........C0A...
0032: 00 4F B8 05  38 63 38 31  61 39 61 66  32 37 65 36    .O..8c81a9af27e6
0048: 00 07 C3 40  02 01 02 02  02 0B E4 04  09 73 69 6D    [email protected]
0064: 75 6C 61 74  6F 72 04 0C  18 BC D5 F2  97 6C 77 D1    ulator.......lw.
0080: 5D 0B 6C EA  04 08 75 E6  7D 63 AA 0D  7D ED 04 3F    ].l...u.}c..}..?
0096: B2 99 78 DD  40 A8 2D 18  B8 73 7E 91  A3 1D 07 E9    [email protected]~.....
0112: 74 1C AC 55  43 68 14 C3  B5 83 89 BE  B9 2E DA D2    t..UCh..........
0128: 02 90 C1 D3  9C 4E C2 9E  87 9B 1D AF  F7 76 4E 93    .....N.......vN.
0144: F9 D3 77 AB  2C 96 94 FC  3E 5E 02 9E  99 80 B8       ..w.,...>^.....


Received 160 byte packet from UDP: [141.94.173.41]:30007->[0.0.0.0]:42102
0000: 30 81 9D 02  01 03 30 11  02 04 74 03  FB CD 02 03    0.....0...t.....
0016: 00 FF E3 04  01 03 02 01  03 04 43 30  41 04 15 80    ..........C0A...
0032: 00 4F B8 05  38 63 38 31  61 39 61 66  32 37 65 36    .O..8c81a9af27e6
0048: 00 07 C3 40  02 01 02 02  02 0B E4 04  09 73 69 6D    [email protected]
0064: 75 6C 61 74  6F 72 04 0C  0B F5 02 08  D9 E6 EA 17    ulator..........
0080: 69 E7 11 3A  04 08 D7 C5  4E CA C7 6F  25 81 04 40    i..:....N..o%..@
0096: 44 C9 4D 85  E5 05 E4 3D  36 6E 6E 13  63 10 BD 66    D.M....=6nn.c..f
0112: 21 5E A7 B2  10 1B 73 11  E5 01 AB 93  3D 60 0B A9    !^....s.....=`..
0128: A8 53 43 B6  6F 3A 21 09  DE CD DA CD  3C CF 51 36    .SC.o:!.....<.Q6
0144: 58 74 2F 9D  76 6E 85 BB  6E B8 39 10  C5 24 4F 22    Xt/.vn..n.9..$O"

iso.3.6.1.4.5.4.2.3 = No Such Instance currently exists at this OID

We are also able to give you an access to one of our test environment, if you can help us with this issue.

Not working with v1 (maybe)

I'm trying to get some values from proprietary service, supporting only V1. It works fine with console program:

snmpget -v1 -c public 10.0.251.1 SNMPv2-SMI::enterprises.10159.1.2.2.1.1.24.17.51.101.101.54.48.48.48.57.49.48.48.48.53.49.48.48.49
SNMPv2-SMI::enterprises.10159.1.2.2.1.1.24.17.51.101.101.54.48.48.48.57.49.48.48.48.53.49.48.48.49 = STRING: "Shelf-3,2"

While simple ruby program fails with timeout:

cat snmp-test.rb
require 'netsnmp'
require "netsnmp/mib/parser"
require 'pp'

oid = NETSNMP::MIB.oid('SNMPv2-SMI::enterprises.10159.1.2.2.1.1.24.17.51.101.101.54.48.48.48.57.49.48.48.48.53.49.48.48.49')
ADDR = '10.0.251.1'
COMM = 'public'
TMOUT = 2

print "get!\n"

manager = NETSNMP::Client.new(
  :host => ADDR, :community => COMM,
  :version => 1, :timeout => TMOUT
)
response = manager.get(oid: oid)
pp response

ruby ./snmp-test.rb

get!
Traceback (most recent call last):
        12: from p2v.rb:19:in `<main>'
        11: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/client.rb:55:in `get'
        10: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/client.rb:155:in `handle_retries'
         9: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/client.rb:55:in `block in get'
         8: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:45:in `send'
         7: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:88:in `send'
         6: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:98:in `recv'
         5: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:107:in `perform_io'
         4: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:107:in `loop'
         3: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:109:in `block in perform_io'
         2: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:99:in `block in recv'
         1: from /opt/rh/rh-ruby27/root/usr/share/ruby/socket.rb:1272:in `recvfrom_nonblock'
/opt/rh/rh-ruby27/root/usr/share/ruby/socket.rb:1272:in `__recvfrom_nonblock': Resource temporarily unavailable - recvfrom(2) would block (IO::EAGAINWaitReadable)
        11: from p2v.rb:19:in `<main>'
        10: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/client.rb:55:in `get'
         9: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/client.rb:155:in `handle_retries'
         8: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/client.rb:55:in `block in get'
         7: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:45:in `send'
         6: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:88:in `send'
         5: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:98:in `recv'
         4: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:107:in `perform_io'
         3: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:107:in `loop'
         2: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:108:in `block in perform_io'
         1: from /home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:111:in `rescue in block in perform_io'
/home/serg/.gem/ruby/gems/netsnmp-0.4.1/lib/netsnmp/session.rb:120:in `wait': Timeout after 2 seconds (Timeout::Error)

How can I debug this?

Certain gauge / counter32 values are being encoded incorrectly

We ran across this when we needed to set a gauge type. Some values would work (0 to 127, and 256 and up), but some values won't work (128 to 255).

The command we used was (excute the obviously bogus OID)

manager.set(oid: '1.2.3', value: 255, type: :gauge)

Bitwise, the difference between the values are

  • 0 to 127 got padded to a byte, which always started with a zero (0000 0000 to 0111 1111)
  • 128 to 255 were also a byte, but doesn't start with a zero (1000 0000 to 1111 1111)
  • 256 and above were padded to two bytes, and didn't start with a zero (0000 0001 0000 0000 to 0111 1111 1111 1111)

It looks like ASN encoding requires a leading zero:

OpenSSL::ASN1::Integer.new(127).to_der
=> "\x02\x01\x7F"
OpenSSL::ASN1::Integer.new(128).to_der
=> "\x02\x02\x00\x80

Notice the extra byte added to 128 - 1000 0000 is encoded as 0000 0000 1000 0000

On this line the code removes empty bytes for gauges (and close to that also counters), and then wraps the value in OpenSSL::ASN1::ASN1Data.

I believe the fix is to either add a check in line 81 to ensure that the bytes always have leading zero, or to use OpenSSL::ASN1::Integer instead of OpenSSL::ASN1::ASN1Data

Crystal language port

Would you ever consider porting this gem to Crystal as a shard? Is this even possible?
Thanks for this excellent gem.

Counter32 values are way off

Hello

ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-gnu]

gem list | grep netsnmp
netsnmp (0.1.4)

This is on Ubuntu 16 and 18.

If I walk the following OID, 1.3.6.1.4.1.2021.11, using snmpwalk ...
iso.3.6.1.4.1.2021.11.1.0 = INTEGER: 1
iso.3.6.1.4.1.2021.11.2.0 = STRING: "systemStats"
--snip--
iso.3.6.1.4.1.2021.11.11.0 = INTEGER: 99
iso.3.6.1.4.1.2021.11.50.0 = Counter32: 389775
iso.3.6.1.4.1.2021.11.51.0 = Counter32: 144655
iso.3.6.1.4.1.2021.11.52.0 = Counter32: 167738
iso.3.6.1.4.1.2021.11.53.0 = Counter32: 50723103
iso.3.6.1.4.1.2021.11.54.0 = Counter32: 60808
--snip--

You can see that, e.g., .53.0, "CPU idle" is ~50 million. But using netsnmp I get the following ...
1.3.6.1.4.1.2021.11.1.0 = 1
1.3.6.1.4.1.2021.11.2.0 = systemStats
--snip--
1.3.6.1.4.1.2021.11.11.0 = 98
1.3.6.1.4.1.2021.11.50.0 = 1522
1.3.6.1.4.1.2021.11.51.0 = 565
1.3.6.1.4.1.2021.11.52.0 = 655
1.3.6.1.4.1.2021.11.53.0 = 773
1.3.6.1.4.1.2021.11.54.0 = 237
--snip--

So the values are out by a factor of ~65k. I could just multiply through by 65535 (or << 16) for each value I find, but that seems a bit dubious to me? Why are the values I'm getting via netsnmp so far out? Is the correct approach to multiply by 65k? If so, why is this not documented in the wiki? Am I doing something wrong?

Thanks, Simon.

Reading Gauge32 type OID returns nil

Trying to read a Gauge32 type of OID:

snmpwalk -c public -v1 10.81.35.130 .1.3.6.1.2.1.17.7.1.4.5.1.1.1
SNMPv2-SMI::mib-2.17.7.1.4.5.1.1.1 = Gauge32: 805

When using the following code:

require 'netsnmp'

manager = NETSNMP::Client.new(host: "10.81.35.130", port: 161, community: "public",
                              timeout: 30, version: "1")

value = manager.get(oid: ".1.3.6.1.2.1.17.7.1.4.5.1.1.1")
puts "Value: [#{value}]"
puts value.inspect

manager.close

I get:

$ ruby test2.rb
Value: []
nil

Cannot load MIB file

Hello! I try to use netsnmp gem with Panasas hardware. Here is a MIB-file, which cannot be parsed (but snmpget/snmpwalk work fine with it), I get this error:

...
        5: from /home/serg/.gem/ruby/gems/netsnmp-0.4.0/lib/netsnmp/mib.rb:82:in `load'
        4: from /home/serg/.gem/ruby/gems/netsnmp-0.4.0/lib/netsnmp/mib.rb:97:in `do_load'
        3: from /home/serg/.gem/ruby/gems/netsnmp-0.4.0/lib/netsnmp/mib.rb:97:in `synchronize'
        2: from /home/serg/.gem/ruby/gems/netsnmp-0.4.0/lib/netsnmp/mib.rb:97:in `block in do_load'
        1: from /home/serg/.gem/ruby/gems/parslet-2.0.0/lib/parslet/atoms/base.rb:49:in `parse'
/home/serg/.gem/ruby/gems/parslet-2.0.0/lib/parslet/cause.rb:70:in `raise': Failed to match sequence (SPACE{0, } MODULES?) at line 2 char 1. (Parslet::ParseFailed)

It comes with several other MIB-files and I load them in recommended order (there is special README file), I can send them also if needed. But I think there is something unusual in the file, but parser output cannot tell me where...

PANASAS-HW-MIB-V1.mib.txt

Recommend Projects

  • React photo React

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

  • Vue.js photo Vue.js

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

  • Typescript photo Typescript

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

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

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

  • web

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

  • server

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

  • Machine learning

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

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

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

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.