sloth-snmp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5cea4c07bc9f9ce8c5e8d21f486a58186450aec95d818187ca64d998d641ede9
4
+ data.tar.gz: d1b59278de3b73f751ac6b2cfb4510522b09f8c26ed248d90babc43211f71ddf
5
+ SHA512:
6
+ metadata.gz: bb2092ad1507afc77094d4d21e7a1a215d4f96bf2bd6e93ba3e5f4dfb765159532107601b23382ebfdbf9da23525ddfc8c97cf98b4ccd34d0c33628783ac54b0
7
+ data.tar.gz: 8ac8f497c635fc6d63dff118dfce4fffd86acceacda57f18164ddd61e484edfc57039246d143d2f0cb7cac76da49c34d851310a66564bac4f2f814b70292a17e
@@ -0,0 +1,23 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor/
16
+ *.pid
17
+ *.log
18
+ *.log.*
19
+ /var/
20
+ /log/
21
+ *.swp
22
+ /.rspec_status
23
+
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.2
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in snmp_handler.gemspec
4
+ gemspec
5
+
@@ -0,0 +1,213 @@
1
+ = Sloth::Snmp
2
+
3
+ Sloth::Snmp is yet another wrapper library for snmp.
4
+
5
+ == Features
6
+
7
+ * Handles SNMP asynchronously.
8
+ * By referring to the YAML file generated from the MIB file, you can operate without describing raw OID.
9
+
10
+ == Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ [source,ruby]
15
+ ----
16
+ gem 'sloth/snmp'
17
+ ----
18
+
19
+ And then execute:
20
+
21
+ $ bundle install
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install sloth-snmp
26
+ or
27
+ $ gem install -l sloth-snmp-x.x.x.gem
28
+
29
+ == Usage
30
+
31
+ === New
32
+ [source,ruby]
33
+ ----
34
+ require "sloth/snmp"
35
+
36
+ snmp = Sloth::Snmp.new
37
+ snmp = Sloth::Snmp.new( bind: 1161 )
38
+ snmp = Sloth::Snmp.new( bind: "127.0.0.1" )
39
+ snmp = Sloth::Snmp.new( bind: "192.168.0.1:1161" )
40
+ snmp = Sloth::Snmp.new( mibs: "RS-232-MIB.yaml" )
41
+ snmp = Sloth::Snmp.new( mibs: "spec/sloth/RFC1414-MIB.yaml" )
42
+ ----
43
+
44
+ === Get
45
+
46
+ [source,ruby]
47
+ ----
48
+ require "sloth/snmp"
49
+
50
+ snmp = Sloth::Snmp.new
51
+ peer = "127.0.0.1"
52
+ topics = [ "sysDescr.0", "sysUpTime.0", "sysName.0" ],
53
+ tuples = snmp.get( peer, topics )
54
+ tuples.each do |oid, tuple|
55
+ p tuple
56
+ end
57
+ ----
58
+
59
+ === Set
60
+
61
+ [source,ruby]
62
+ ----
63
+ require "sloth/snmp"
64
+
65
+ snmp = Sloth::Snmp.new
66
+ peer = "127.0.0.1"
67
+ tuple = { topic: "sysName.0", type: SNMP::OctetString, value: Time.now.to_s },
68
+ snmp.set( peer, tuple )
69
+
70
+ tuples = snmp.get( peer, tuple[:topic] )
71
+ tuples.each do |oid, tuple|
72
+ p tuple
73
+ end
74
+ ----
75
+
76
+ === Walk
77
+
78
+ [source,ruby]
79
+ ----
80
+ require "sloth/snmp"
81
+
82
+ snmp = Sloth::Snmp.new
83
+ peer = "127.0.0.1"
84
+ topic = "internet"
85
+ tuples = snmp.walk( peer, topic )
86
+ tuples.each do |oid, tuple|
87
+ p tuple
88
+ end
89
+ ----
90
+
91
+ === Trap
92
+
93
+ [source,ruby]
94
+ ----
95
+ require "sloth/snmp"
96
+
97
+ snmp = Sloth::Snmp.new( bind: 1162 )
98
+ snmp.trap( "snmpInTraps", "snmpOutTraps" ) do |trapname, source_ip, tuples|
99
+ p [:trapname, trapname]
100
+ p [:source_ip, source_ip]
101
+ tuples.each do |oid, tuple|
102
+ p tuple
103
+ end
104
+ end
105
+
106
+ sleep
107
+ ----
108
+
109
+ == Reference
110
+
111
+ === Create a new Sloth::Snmp.
112
+
113
+ [source,ruby]
114
+ ----
115
+ Sloth::Snmp.new( mibs: nil, bind: nil, rocommunity: "public", rwcommunity: "private" )
116
+ ----
117
+
118
+ * Result:
119
+ - Sloth::Snmp object.
120
+
121
+ * Parameter:
122
+ ** mibs: Additional MIB file path, or array of the paths. (default: nil)
123
+ ** bind: Bind host and port for trap. (default: "0.0.0.0:162")
124
+ ** rocommunity: Community string for Read Only. (default: "public")
125
+ ** rwcommunity: Community string for Read/Write. (default: "private")
126
+
127
+ === SNMP Get.
128
+
129
+ [source,ruby]
130
+ ----
131
+ Sloth::Snmp#get( peer, topics, community: nil, bindto: nil, device: nil )
132
+ ----
133
+
134
+ * Result:
135
+ * Hash of key=>oid, value=>{name, value}.
136
+
137
+ * Parameter:
138
+ ** peer: Target IP address and port. (default port: 162)
139
+ ** topics: Topic(s) for SNMP Get Request.
140
+ ** community: Community string. (default: nil)
141
+ ** bindto: Interface address. (default: nil)
142
+ ** device: Interface name. (default: nil)
143
+
144
+ === SNMP Set.
145
+
146
+ [source,ruby]
147
+ ----
148
+ Sloth::Snmp#set( peer, topics, community: nil, bindto: nil, device: nil )
149
+ ----
150
+
151
+ * Result:
152
+ * Hash of key=>oid, value=>{name, value}.
153
+
154
+ * Parameter:
155
+ ** peer: Target IP address and port. (default port: 162)
156
+ ** tuple: Hash of topic, type, value for SNMP Set Request.
157
+ ** community: Community string. (default: nil)
158
+ ** bindto: Interface address. (default: nil)
159
+ ** device: Interface name. (default: nil)
160
+
161
+ === SNMP Walk.
162
+
163
+ [source,ruby]
164
+ ----
165
+ Sloth::Snmp#walk( target, topic, port: 162, community: "public", bindto: nil, device: nil )
166
+ ----
167
+
168
+ * Result:
169
+ ** Hash of key=>oid, value=>{name, value}.
170
+
171
+ * Parameter:
172
+ ** peer: Target IP address and port. (default port: 162)
173
+ ** topic: Topic for SNMP Get Next.
174
+ ** community: Community string. (default: nil)
175
+ ** bindto: Interface address. (default: nil)
176
+ ** device: Interface name. (default: nil)
177
+
178
+ === SNMP Trap.
179
+
180
+ [source,ruby]
181
+ ----
182
+ Sloth::Snmp#trap( *topics, &block )
183
+ ----
184
+
185
+ * Result:
186
+ ** nil.
187
+
188
+ * Parameter:
189
+ ** topics: The topic(s) that enables trap monitoring.
190
+ ** block: Callback action.
191
+
192
+ === SNMP Untrap.
193
+
194
+ [source,ruby]
195
+ ----
196
+ Sloth::Snmp#untrap( *topics )
197
+ ----
198
+
199
+ * Result:
200
+ ** nil.
201
+
202
+ * Parameter:
203
+ ** topics: The topic(s) that disables trap monitoring.
204
+
205
+ == Contributing
206
+
207
+ Bug reports and pull requests are welcome on GitHub at https://github.com/arimay/sloth-snmp.
208
+
209
+ == License
210
+
211
+ The gem is available as open source under the terms of the http://opensource.org/licenses/MIT[MIT License].
212
+
213
+ Copyright (c) ARIMA Yasuhiro <arima.yasuhiro@gmail.com>
@@ -0,0 +1,213 @@
1
+ = Sloth::Snmp
2
+
3
+ Sloth::Snmp はさらにもうひとつの SNMP ラッパーライブラリ.
4
+
5
+ == 特徴
6
+
7
+ * 非同期で SNMP を扱う.
8
+ * MIBファイルから生成したYAMLファイルを参照することで、生のOIDを記述することなく操作できる.
9
+
10
+ == 導入
11
+
12
+ アプリの Gemfile にこの行を追加
13
+
14
+ [source,ruby]
15
+ ----
16
+ gem 'sloth/snmp'
17
+ ----
18
+
19
+ それから実行
20
+
21
+ $ bundle install
22
+
23
+ または次のように手動で導入
24
+
25
+ $ gem install sloth-snmp
26
+ or
27
+ $ gem install -l sloth-snmp-x.x.x.gem
28
+
29
+ == 使い方
30
+
31
+ === 新規
32
+ [source,ruby]
33
+ ----
34
+ require "sloth/snmp"
35
+
36
+ snmp = Sloth::Snmp.new
37
+ snmp = Sloth::Snmp.new( bind: 1161 )
38
+ snmp = Sloth::Snmp.new( bind: "127.0.0.1" )
39
+ snmp = Sloth::Snmp.new( bind: "192.168.0.1:1161" )
40
+ snmp = Sloth::Snmp.new( mibs: "RS-232-MIB.yaml" )
41
+ snmp = Sloth::Snmp.new( mibs: "spec/sloth/RFC1414-MIB.yaml" )
42
+ ----
43
+
44
+ === 取得
45
+
46
+ [source,ruby]
47
+ ----
48
+ require "sloth/snmp"
49
+
50
+ snmp = Sloth::Snmp.new
51
+ peer = "127.0.0.1"
52
+ topics = [ "sysDescr.0", "sysUpTime.0", "sysName.0" ],
53
+ tuples = snmp.get( peer, topics )
54
+ tuples.each do |oid, tuple|
55
+ p tuple
56
+ end
57
+ ----
58
+
59
+ === 更新
60
+
61
+ [source,ruby]
62
+ ----
63
+ require "sloth/snmp"
64
+
65
+ snmp = Sloth::Snmp.new
66
+ peer = "127.0.0.1"
67
+ tuple = { topic: "sysName.0", type: SNMP::OctetString, value: Time.now.to_s },
68
+ snmp.set( peer, tuple )
69
+
70
+ tuples = snmp.get( peer, tuple[:topic] )
71
+ tuples.each do |oid, tuple|
72
+ p tuple
73
+ end
74
+ ----
75
+
76
+ === 巡回
77
+
78
+ [source,ruby]
79
+ ----
80
+ require "sloth/snmp"
81
+
82
+ snmp = Sloth::Snmp.new
83
+ peer = "127.0.0.1"
84
+ topic = "internet"
85
+ tuples = snmp.walk( peer, topic )
86
+ tuples.each do |oid, tuple|
87
+ p tuple
88
+ end
89
+ ----
90
+
91
+ === トラップ
92
+
93
+ [source,ruby]
94
+ ----
95
+ require "sloth/snmp"
96
+
97
+ snmp = Sloth::Snmp.new( bind: 1162 )
98
+ snmp.trap( "snmpInTraps", "snmpOutTraps" ) do |trapname, source_ip, tuples|
99
+ p [:trapname, trapname]
100
+ p [:source_ip, source_ip]
101
+ tuples.each do |oid, tuple|
102
+ p tuple
103
+ end
104
+ end
105
+
106
+ sleep
107
+ ----
108
+
109
+ == リファレンス
110
+
111
+ === 新たな Sloth::Snmp を作成する.
112
+
113
+ [source,ruby]
114
+ ----
115
+ Sloth::Snmp.new( mibs: nil, bind: nil, rocommunity: "public", rwcommunity: "private" )
116
+ ----
117
+
118
+ * Result:
119
+ ** Sloth::Snmp オブジェクト.
120
+
121
+ * Parameter:
122
+ ** mibs: 追加 MIB ファイルパスの文字列. またはその配列. (default: nil)
123
+ ** bind: トラップ用のバインドホストとポート. (default: "0.0.0.0:162")
124
+ ** rocommunity: 読み取り用コミュニティ文字列. (default: "public")
125
+ ** rwcommunity: 読み書き用コミュニティ文字列. (default: "private")
126
+
127
+ === SNMP Get.
128
+
129
+ [source,ruby]
130
+ ----
131
+ Sloth::Snmp#get( peer, topics, community: nil, bindto: nil, device: nil )
132
+ ----
133
+
134
+ * Result:
135
+ ** hash of key=>oid, value=>{name, value}.
136
+
137
+ * Parameter:
138
+ ** peer: 宛先IPアドレスとポート. (default port: 162)
139
+ ** topics: SNMP Get Request 用のトピック.
140
+ ** community: コミュニティ文字列. (default: nil)
141
+ ** bindto: インターフェースアドレス. (default: nil)
142
+ ** device: インターフェース名称. (default: nil)
143
+
144
+ === SNMP Set.
145
+
146
+ [source,ruby]
147
+ ----
148
+ Sloth::Snmp#set( peer, topics, community: nil, bindto: nil, device: nil )
149
+ ----
150
+
151
+ * Result:
152
+ ** hash of key=>oid, value=>{name, value}.
153
+
154
+ * Parameter:
155
+ ** peer: 宛先IPアドレスとポート. (default port: 162)
156
+ ** tuple: SNMP Set Request 用のトピック、型、値のハッシュ.
157
+ ** community: コミュニティ文字列. (default: nil)
158
+ ** bindto: インターフェースアドレス. (default: nil)
159
+ ** device: インターフェース名称. (default: nil)
160
+
161
+ === SNMP Walk.
162
+
163
+ [source,ruby]
164
+ ----
165
+ Sloth::Snmp#walk( peer, topic, port: 162, community: "public", bindto: nil, device: nil )
166
+ ----
167
+
168
+ * Result:
169
+ ** hash of key=>oid, value=>{name, value}.
170
+
171
+ * Parameter:
172
+ ** peer: 宛先IPアドレスとポート. (default port: 162)
173
+ ** topic: SNMP Get Next 用のトピック.
174
+ ** community: コミュニティ文字列. (default: nil)
175
+ ** bindto: インターフェースアドレス. (default: nil)
176
+ ** device: インターフェース名称. (default: nil)
177
+
178
+ === SNMP Trap.
179
+
180
+ [source,ruby]
181
+ ----
182
+ Sloth::Snmp#trap( *topics, &block )
183
+ ----
184
+
185
+ * Result:
186
+ ** nil.
187
+
188
+ * Parameter:
189
+ ** topics: トラップを有効化するトピック.
190
+ ** block: コールバック動作.
191
+
192
+ === SNMP Untrap.
193
+
194
+ [source,ruby]
195
+ ----
196
+ Sloth::Snmp#untrap( *topics )
197
+ ----
198
+
199
+ * Result:
200
+ ** nil.
201
+
202
+ * Parameter:
203
+ ** topics: トラップの監視を無効化するトピック.
204
+
205
+ == 貢献
206
+
207
+ 不具合報告とプルリクエストは GitHub https://github.com/arimay/sloth-snmp まで.
208
+
209
+ == ライセンス
210
+
211
+ この Gem は、 http://opensource.org/licenses/MIT[MITライセンス] の条件に基づいてオープンソースとして入手できる.
212
+
213
+ Copyright (c) ARIMA Yasuhiro <arima.yasuhiro@gmail.com>
@@ -0,0 +1,96 @@
1
+ require "bundler/gem_helper"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ class Bundler::GemHelper
10
+
11
+ def git_archive( dir = "../zip" )
12
+ FileUtils.mkdir_p dir
13
+ dest_path = File.join(dir, "#{name}-#{version}.zip")
14
+ cmnd = "git archive --format zip --prefix=#{name}/ HEAD > #{dest_path}"
15
+
16
+ _, code = sh_with_status( cmnd )
17
+ raise "Couldn't archive gem," unless code == 0
18
+
19
+ Bundler.ui.confirm "#{name} #{version} archived to #{dest_path}."
20
+ end
21
+
22
+ def git_push
23
+ ver = version.to_s
24
+
25
+ cmnd = "git push origin #{ver} "
26
+ _, code = sh_with_status( cmnd )
27
+ raise "Couldn't git push origin." unless code == 0
28
+
29
+ cmnd = "git push "
30
+ _, code = sh_with_status( cmnd )
31
+ raise "Couldn't git push." unless code == 0
32
+
33
+ Bundler.ui.confirm "Git Push #{ver}."
34
+ end
35
+
36
+ def update_version( new_version )
37
+ version_filename = %x[ find . -type f -name "version.rb" | grep -v vendor | head -1 ].chomp
38
+ version_pathname = File.expand_path( version_filename )
39
+ lines = File.open( version_pathname ).read
40
+ lines = lines.gsub( /VERSION\s*=\s*\"\d+\.\d+\.\d+\"/, "VERSION = \"#{new_version}\"" )
41
+ File.open( version_pathname, "w" ) do |file|
42
+ file.write( lines )
43
+ end
44
+
45
+ cmnd = "git add #{version_pathname} "
46
+ _, code = sh_with_status( cmnd )
47
+ raise "Couldn't git add," unless code == 0
48
+
49
+ cmnd = "git commit -m '#{new_version}' "
50
+ _, code = sh_with_status( cmnd )
51
+ raise "Couldn't git commit." unless code == 0
52
+
53
+ cmnd = "git tag #{new_version} "
54
+ _, code = sh_with_status( cmnd )
55
+ raise "Couldn't git tag." unless code == 0
56
+
57
+ Bundler.ui.confirm "Update Tags to #{new_version}."
58
+ end
59
+
60
+ end
61
+
62
+ Bundler::GemHelper.new(Dir.pwd).instance_eval do
63
+
64
+ desc "Archive #{name}-#{version}.zip from repository"
65
+ task 'zip' do
66
+ git_archive
67
+ end
68
+
69
+ desc "Git Push"
70
+ task 'push' do
71
+ git_push
72
+ end
73
+
74
+ desc "Update Version Tiny"
75
+ task 'tiny' do
76
+ major, minor, tiny = version.to_s.split('.')
77
+ new_version = [major, minor, tiny.to_i + 1].join('.')
78
+ update_version( new_version )
79
+ end
80
+
81
+ desc "Update Version Minor"
82
+ task 'minor' do
83
+ major, minor, _tiny = version.to_s.split('.')
84
+ new_version = [major, minor.to_i + 1, 0].join('.')
85
+ update_version( new_version )
86
+ end
87
+
88
+ desc "Update Version Major"
89
+ task 'major' do
90
+ major, _minor, _tiny = version.to_s.split('.')
91
+ new_version = [major.to_i + 1, 0, 0].join('.')
92
+ update_version( new_version )
93
+ end
94
+
95
+ end
96
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sloth/snmp"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ require "sloth/snmp/version"
2
+ require "sloth/snmp/impl"
3
+
@@ -0,0 +1,302 @@
1
+ require "snmp"
2
+
3
+ module Sloth
4
+ class Snmp
5
+
6
+ class Error < StandardError; end
7
+
8
+ class UDPTransportExt < ::SNMP::UDPTransport
9
+ def initialize( address_family, bindto: nil, device: nil )
10
+ super
11
+ @socket = UDPSocket.open( address_family )
12
+ if bindto
13
+ host, port = bindto.split(':') rescue nil
14
+ @socket.bind( host, port.to_i )
15
+ end
16
+ if device
17
+ @socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_BINDTODEVICE, device )
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize( mibs: nil, bind: nil, rocommunity: "public", rwcommunity: "private" )
23
+ case bind
24
+ when Integer, NilClass
25
+ @host = "0.0.0.0"
26
+ @port = bind || 162
27
+ when String
28
+ host, port = bind.split(':') rescue nil
29
+ if host.nil? || host.empty?
30
+ @host = "0.0.0.0"
31
+ else
32
+ @host = host
33
+ end
34
+ if port.nil? || port.empty?
35
+ @port = 162
36
+ else
37
+ @port = port.to_i
38
+ end
39
+ else
40
+ raise Sloth::Snmp::Error, "invalid class. : %s" % bind.class
41
+ end
42
+ @rocommunity = rocommunity
43
+ @rwcommunity = rwcommunity
44
+
45
+ @mibs = SNMP::MIB.new
46
+ @mibs.load_module( "RFC1155-SMI" )
47
+ @mibs.load_module( "RFC1158-MIB" )
48
+
49
+ case mibs
50
+ when NilClass
51
+ mibs = []
52
+ when Array
53
+ # noop
54
+ when String
55
+ mibs = [mibs]
56
+ else
57
+ raise Sloth::Snmp::Error, "invalid class. : %s" % mibs.class
58
+ end
59
+
60
+ mibpath = mibs.shift
61
+ while mibpath
62
+ mibbase = File.basename( mibpath )
63
+ mibdir = File.dirname( mibpath )
64
+ if ( mibdir == "." && mibbase == mibpath )
65
+ @mibs.load_module( mibbase.gsub( /\..*\Z/, "" ) )
66
+ else
67
+ @mibs.load_module( mibbase.gsub( /\..*\Z/, "" ), mibdir )
68
+ end
69
+ mibpath = mibs.shift
70
+ end
71
+
72
+ @topics = {}
73
+ @mutex = ::Mutex.new
74
+ end
75
+
76
+ def start_listener
77
+ @thread ||= Thread.start do
78
+ listener = SNMP::TrapListener.new( host: @host, port: @port, community: @rocommunity ) do |manager|
79
+ manager.on_trap_v2c do |mesg|
80
+ begin
81
+ next if mesg.error_status != :noError
82
+
83
+ source_ip = mesg.source_ip
84
+ trap_oid = mesg.trap_oid.join(".")
85
+ trapname = @mibs.name( trap_oid )
86
+ items = {}
87
+ mesg.each_varbind do |varbind|
88
+ oid, item = * parse_varbind( varbind )
89
+ items[oid] = item
90
+ end
91
+ Thread.start do
92
+ @mutex.synchronize do
93
+ @topics[ trap_oid ]&.call( trapname, source_ip, items )
94
+ end
95
+ end
96
+
97
+ rescue => e
98
+ raise Sloth::Snmp::Error, e.message
99
+
100
+ end
101
+ end
102
+ end
103
+ Thread.current[:listener] = listener
104
+ listener.join
105
+ end
106
+ end
107
+
108
+ def stop_listener
109
+ @mutex.synchronize do
110
+ @topics.clear
111
+ @thread[:listener].exit
112
+ @thread = nil
113
+ end
114
+ end
115
+
116
+ def trap( *topics, &block )
117
+ @mutex.synchronize do
118
+ topics.each do |topic|
119
+ trap_oid = SNMP::ObjectId.new( topic ) rescue @mibs.oid( topic )
120
+ @topics[trap_oid.to_str] = block
121
+ end
122
+ end
123
+ start_listener
124
+ end
125
+
126
+ def untrap( *topics )
127
+ @mutex.synchronize do
128
+ topics.each do |topic|
129
+ trap_oid = SNMP::ObjectId.new( topic ) rescue @mibs.oid( topic )
130
+ @topics.delete( trap_oid.to_str )
131
+ end
132
+ end
133
+ stop_listener if @topics.empty?
134
+ end
135
+
136
+ def get( peer, topics, **options )
137
+ host, port = peer.split(':') rescue nil
138
+ host = "127.0.0.1" if host.nil? || host.empty?
139
+ port = (port || 161).to_i
140
+ community = options[:rocommunity] || @rocommunity
141
+
142
+ case topics
143
+ when String
144
+ oids = [ ( SNMP::ObjectId.new( topics ) rescue @mibs.oid( topics ) ) ]
145
+ when Array
146
+ oids = topics.map do |topic|
147
+ SNMP::ObjectId.new( topic ) rescue @mibs.oid( topic )
148
+ end
149
+ else
150
+ raise Sloth::Snmp::Error, "topics missing."
151
+ end
152
+
153
+ if options[:bindto] && options[:device]
154
+ transport = UDPTransportExt.new( Socket::AF_INET, bindto: options[:bindto], device: options[:device] )
155
+ end
156
+
157
+ manager = SNMP::Manager.new( host: host, port: port, community: community, transport: transport )
158
+
159
+ items = {}
160
+ begin
161
+ response = Thread.handle_interrupt( ::Timeout::Error => :on_blocking ) do
162
+ manager.get( oids )
163
+ end
164
+
165
+ response.each_varbind do |varbind|
166
+ oid, item = * parse_varbind( varbind )
167
+ items[oid] = item
168
+ end
169
+
170
+ rescue SNMP::RequestTimeout => e
171
+ raise Sloth::Snmp::Error, e.message
172
+
173
+ rescue => e
174
+ raise Sloth::Snmp::Error, e.message
175
+
176
+ end
177
+ items
178
+ end
179
+
180
+ def walk( peer, topic, **options )
181
+ host, port = peer.split(':') rescue nil
182
+ host = "127.0.0.1" if host.nil? || host.empty?
183
+ port = (port || 161).to_i
184
+ community = options[:rocommunity] || @rocommunity
185
+
186
+ if options[:bindto] && options[:device]
187
+ transport = UDPTransportExt.new( Socket::AF_INET, bindto: options[:bindto], device: options[:device] )
188
+ end
189
+
190
+ manager = SNMP::Manager.new( host: host, port: port, community: community, transport: transport )
191
+
192
+ topic ||= "internet"
193
+ base_oid = SNMP::ObjectId.new( topic ) rescue @mibs.oid( topic )
194
+
195
+ items = {}
196
+ begin
197
+ Thread.handle_interrupt( ::Timeout::Error => :on_blocking ) do
198
+ manager.walk( base_oid ) do |varbind|
199
+ oid, item = * parse_varbind( varbind )
200
+ items[oid] = item
201
+ end
202
+ end
203
+
204
+ rescue SNMP::RequestTimeout => e
205
+ raise Sloth::Snmp::Error, e.message
206
+
207
+ rescue => e
208
+ raise Sloth::Snmp::Error, e.message
209
+
210
+ end
211
+ items
212
+ end
213
+
214
+ def set( peer, tuple, **options )
215
+ host, port = peer.split(':') rescue nil
216
+ host = "127.0.0.1" if host.nil? || host.empty?
217
+ port = (port || 161).to_i
218
+ community = options[:rwcommunity] || @rwcommunity
219
+
220
+ if options[:bindto] && options[:device]
221
+ transport = UDPTransportExt.new( Socket::AF_INET, bindto: options[:bindto], device: options[:device] )
222
+ end
223
+
224
+ varbind = build_varbind( tuple[:topic], tuple[:type], tuple[:value] )
225
+
226
+ manager = SNMP::Manager.new( host: host, port: port, community: community, transport: transport )
227
+
228
+ begin
229
+ response = Thread.handle_interrupt( ::Timeout::Error => :on_blocking ) do
230
+ manager.set( varbind )
231
+ end
232
+ response
233
+
234
+ rescue SNMP::RequestTimeout => e
235
+ raise Sloth::Snmp::Error, e.message
236
+
237
+ rescue => e
238
+ raise Sloth::Snmp::Error, e.message
239
+
240
+ ensure
241
+ manager.close
242
+ end
243
+ end
244
+
245
+ def parse_varbind( varbind, keys: nil )
246
+ keys = [:name, :value] if keys.nil? || keys.empty?
247
+ oid = varbind.name.to_str
248
+ name = @mibs.name( oid )
249
+ case varbind.value
250
+ when SNMP::OctetString
251
+ type = SNMP::OctetString
252
+ valu = varbind.value.to_s
253
+ if /[^[:print:]]/.match( valu )
254
+ valu = "0x" + valu.unpack("H*").shift
255
+ end
256
+ when SNMP::Integer
257
+ type = SNMP::Integer
258
+ valu = varbind.value.to_i
259
+ when SNMP::Counter32
260
+ type = SNMP::Counter32
261
+ valu = varbind.value.to_i
262
+ when SNMP::IpAddress
263
+ type = SNMP::IpAddress
264
+ valu = varbind.value.to_s
265
+ when SNMP::ObjectId
266
+ type = SNMP::ObjectId
267
+ valu = varbind.value
268
+ when SNMP::NoSuchInstance, SNMP::NoSuchObject
269
+ type = varbind.value
270
+ valu = nil
271
+ else
272
+ type = varbind.value
273
+ valu = nil
274
+ end
275
+
276
+ tuple = {}
277
+ tuple[:name] = name if keys.include?( :name )
278
+ tuple[:type] = type if keys.include?( :type )
279
+ tuple[:value] = valu if keys.include?( :value )
280
+ [oid, tuple]
281
+ end
282
+
283
+ def build_varbind( topic, type, value )
284
+ oid = SNMP::ObjectId.new( topic ) rescue @mibs.oid( topic )
285
+ case type
286
+ when SNMP::OctetString
287
+ SNMP::VarBind.new( oid, SNMP::OctetString.new( value ))
288
+ when SNMP::Integer
289
+ SNMP::VarBind.new( oid, SNMP::Integer.new( value ))
290
+ when SNMP::Counter32
291
+ SNMP::VarBind.new( oid, SNMP::Counter32.new( value ))
292
+ when SNMP::IpAddress
293
+ SNMP::VarBind.new( oid, SNMP::IpAddress.new( value ))
294
+ when SNMP::ObjectId
295
+ SNMP::VarBind.new( oid, SNMP::ObjectId.new( value ))
296
+ else
297
+ SNMP::VarBind.new( oid, SNMP::OctetString.new( value.to_s ))
298
+ end
299
+ end
300
+
301
+ end
302
+ end
@@ -0,0 +1,5 @@
1
+ module Sloth
2
+ class Snmp
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ #
2
+ # bundle exec ruby sample/snmp_custom.rb
3
+ # bundle exec ruby sample/snmp_custom.rb sample/SAMPLE-MIB.yml 10.0.2.1
4
+ #
5
+
6
+ require "sloth/snmp"
7
+
8
+ config = {}
9
+ mibpath = ARGV.shift
10
+ if mibpath
11
+ config.merge!( mibs: mibpath )
12
+ end
13
+
14
+ Snmp = Sloth::Snmp.new( **config )
15
+
16
+ peer = ARGV.shift || "127.0.0.1:161"
17
+
18
+ topic = "internet"
19
+ tuples = Snmp.walk( peer, topic )
20
+ tuples.each do |_oid, tuple|
21
+ p tuple
22
+ end
@@ -0,0 +1,27 @@
1
+ #
2
+ # bundle exec ruby sample/snmpget.rb
3
+ #
4
+
5
+ require "sloth/snmp"
6
+
7
+ Snmp = Sloth::Snmp.new
8
+
9
+ options = {
10
+ # bindto: "10.0.2.15",
11
+ # device: "enp0s3",
12
+ }
13
+
14
+ peer = ARGV.shift || "127.0.0.1:161"
15
+
16
+ [
17
+ [ "sysDescr.0", "sysUpTime.0", "sysName.0" ],
18
+ [ "1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0" ],
19
+ "1.3.6.1.2.1.1.5.0",
20
+ ].each do |topics|
21
+ p [:get, topics]
22
+ tuples = Snmp.get( peer, topics, **options )
23
+ tuples.each do |_oid, tuple|
24
+ p tuple
25
+ end
26
+ puts
27
+ end
@@ -0,0 +1,30 @@
1
+ #
2
+ # bundle exec ruby sample/snmpset.rb
3
+ #
4
+
5
+ require "sloth/snmp"
6
+
7
+ Snmp = Sloth::Snmp.new
8
+
9
+ options = {
10
+ # bindto: "10.0.2.15",
11
+ # device: "enp0s3",
12
+ }
13
+
14
+ peer = ARGV.shift || "127.0.0.1:161"
15
+
16
+ [
17
+ { topic: "sysName.0", type: SNMP::OctetString, value: Time.now.to_s },
18
+ ].each do |tuple|
19
+ p [:set, tuple]
20
+ pp Snmp.set( peer, tuple, **options )
21
+
22
+ # topics = [tuple[:topic]]
23
+ topics = tuple[:topic]
24
+ p [:get, topics]
25
+ tuples = Snmp.get( peer, topics, **options )
26
+ tuples.each do |_oid, tuple_|
27
+ p tuple_
28
+ end
29
+ puts
30
+ end
@@ -0,0 +1,45 @@
1
+ #
2
+ # bundle exec ruby sample/snmptrap.rb
3
+ # sudo bundle exec ruby sample/snmptrap.rb
4
+ #
5
+ # RFC1158-MIB.yaml:191:snmpInTraps: 1.3.6.1.2.1.11.19
6
+ # RFC1158-MIB.yaml:201:snmpOutTraps: 1.3.6.1.2.1.11.29
7
+ #
8
+
9
+ require "sloth/snmp"
10
+
11
+ port = ( ARGV.shift || ( Process::Sys.getuid == 0 ? 162 : 1162 ) )
12
+ p [:port, port]
13
+
14
+ Snmp = Sloth::Snmp.new( bind: port )
15
+
16
+ queue = Queue.new
17
+
18
+ p :ready
19
+ Snmp.trap( "snmpInTraps", "snmpOutTraps" ) do |trapname, source_ip, tuples|
20
+ #Snmp.trap( "1.3.6.1.2.1.11.19", "1.3.6.1.2.1.11.29" ) do |trapname, source_ip, tuples|
21
+ p ["TRAP!!", :trapname, trapname, :source_ip, source_ip]
22
+ tuples.each do |_oid, tuple|
23
+ p tuple
24
+ end
25
+ queue.push trapname
26
+ end
27
+
28
+ p :wait
29
+ sleep 1
30
+ puts
31
+
32
+ p cmnd = "snmptrap -v 2c -c public 127.0.0.1:#{port} '' .1.3.6.1.2.1.11.19 2> /dev/null "
33
+ %x[#{cmnd}]
34
+ p queue.pop
35
+
36
+ p cmnd = "snmptrap -v 2c -c public 127.0.0.1:#{port} '' .1.3.6.1.2.1.11.29 2> /dev/null "
37
+ %x[#{cmnd}]
38
+ p queue.pop
39
+
40
+ p :untrap
41
+ Snmp.untrap( "snmpInTraps", "snmpOutTraps" )
42
+ # Snmp.untrap( "1.3.6.1.2.1.11.19", "1.3.6.1.2.1.11.29" )
43
+
44
+ sleep 1
45
+ p :quit
@@ -0,0 +1,29 @@
1
+ #
2
+ # bundle exec ruby sample/snmpwalk.rb
3
+ #
4
+
5
+ require "sloth/snmp"
6
+
7
+ Snmp = Sloth::Snmp.new
8
+
9
+ options = {
10
+ # bindto: "10.0.2.15",
11
+ # device: "enp0s3",
12
+ }
13
+
14
+ peer = ARGV.shift || "127.0.0.1:161"
15
+
16
+ [
17
+ "system.8",
18
+ "system.9",
19
+ "mib-2.25.1",
20
+ "internet",
21
+ nil,
22
+ ].each do |topic|
23
+ p [:walk, topic]
24
+ tuples = Snmp.walk( peer, topic, **options )
25
+ tuples.each do |_oid, tuple|
26
+ p tuple
27
+ end
28
+ puts
29
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'lib/sloth/snmp/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "sloth-snmp"
5
+ spec.version = Sloth::Snmp::VERSION
6
+ spec.authors = ["arimay"]
7
+ spec.email = ["arima.yasuhiro@gmail.com"]
8
+
9
+ spec.summary = %q{ Sloth Snmp Library. }
10
+ spec.description = %q{ Sloth::Snmp is yet another wrapper library for snmp. }
11
+ spec.homepage = "https://github.com/arimay/sloth-snmp"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
15
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ end
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "snmp"
22
+
23
+ spec.add_development_dependency "rake", "~> 12.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sloth-snmp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - arimay
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-11-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: snmp
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: " Sloth::Snmp is yet another wrapper library for snmp. "
56
+ email:
57
+ - arima.yasuhiro@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - README.adoc
67
+ - README.ja.adoc
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - lib/sloth/snmp.rb
72
+ - lib/sloth/snmp/impl.rb
73
+ - lib/sloth/snmp/version.rb
74
+ - sample/snmpcustom.rb
75
+ - sample/snmpget.rb
76
+ - sample/snmpset.rb
77
+ - sample/snmptrap.rb
78
+ - sample/snmpwalk.rb
79
+ - sloth-snmp.gemspec
80
+ homepage: https://github.com/arimay/sloth-snmp
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubygems_version: 3.1.4
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Sloth Snmp Library.
103
+ test_files: []