Skip to content

Commit 3866429

Browse files
authored
Merge pull request #1 from kalinon/master
Add SNMP::Client (#1)
2 parents 4a290ea + e78cbd6 commit 3866429

File tree

5 files changed

+103
-5
lines changed

5 files changed

+103
-5
lines changed

.gitignore

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
doc
2-
lib
3-
bin
4-
.crystal
5-
.shards
1+
/docs/
2+
/lib/
3+
/bin/
4+
/.shards/
5+
*.dwarf
66
app
77
*.dwarf
88
*.DS_Store
9+
shard.lock

spec/client_spec.cr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
require "./helper"
2+
3+
describe SNMP::Client do
4+
it "should perform a walk" do
5+
client = SNMP::Client.new("demo.snmplabs.com")
6+
client.should_not be_nil
7+
messages = client.walk("1.3.6.1.2.1.1.9.1.3")
8+
messages.should be_a(Array(SNMP::Message))
9+
messages.empty?.should be_false
10+
messages.size.should eq 8
11+
end
12+
end

spec/snmp_spec.cr

+5
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ describe SNMP do
272272
socket = UDPSocket.new
273273
socket.connect("demo.snmplabs.com", 161)
274274
socket.sync = false
275+
socket.read_timeout = 3
275276

276277
# Setup session
277278
session = SNMP::V3::Session.new("usr-md5-none", "authkey1")
@@ -296,6 +297,7 @@ describe SNMP do
296297
socket = UDPSocket.new
297298
socket.connect("demo.snmplabs.com", 161)
298299
socket.sync = false
300+
socket.read_timeout = 3
299301

300302
# Setup session
301303
session = SNMP::V3::Session.new("usr-md5-aes", "authkey1", "privkey1", priv_protocol: SNMP::V3::Security::PrivacyProtocol::AES)
@@ -320,6 +322,7 @@ describe SNMP do
320322
socket = UDPSocket.new
321323
socket.connect("demo.snmplabs.com", 161)
322324
socket.sync = false
325+
socket.read_timeout = 3
323326

324327
# Setup session
325328
session = SNMP::V3::Session.new("usr-md5-des", "authkey1", "privkey1")
@@ -344,6 +347,7 @@ describe SNMP do
344347
socket = UDPSocket.new
345348
socket.connect("demo.snmplabs.com", 161)
346349
socket.sync = false
350+
socket.read_timeout = 3
347351

348352
# Make request
349353
session = SNMP::Session.new
@@ -361,6 +365,7 @@ describe SNMP do
361365
# socket.connect("localhost", 32771)
362366
socket.connect("demo.snmplabs.com", 161)
363367
socket.sync = false
368+
socket.read_timeout = 3
364369

365370
# Make request
366371
session = SNMP::Session.new("public")

src/snmp.cr

+1
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,4 @@ require "./snmp/message"
117117
require "./snmp/session"
118118
require "./snmp/v3/message"
119119
require "./snmp/v3/session"
120+
require "./snmp/client"

src/snmp/client.cr

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
require "socket"
2+
require "../snmp"
3+
4+
class SNMP::Client
5+
class Error < Exception
6+
end
7+
8+
getter socket : UDPSocket
9+
getter session : SNMP::Session
10+
getter host, timeout, port
11+
12+
def initialize(@host : String, community = "public", @timeout = 3, @port = 161)
13+
@socket = UDPSocket.new
14+
socket.sync = false
15+
socket.read_timeout = timeout
16+
@session = SNMP::Session.new(community: community)
17+
end
18+
19+
private def with_socket
20+
if socket.closed?
21+
@socket = UDPSocket.new
22+
socket.sync = false
23+
socket.read_timeout = timeout
24+
end
25+
socket.connect(host, port)
26+
yield socket
27+
socket.close
28+
end
29+
30+
def get(oid : String) : SNMP::Message
31+
msg : SNMP::Message? = nil
32+
with_socket do |sock|
33+
msg = get(oid, sock)
34+
end
35+
36+
raise Error.new("Failed to read message") if msg.nil?
37+
msg
38+
end
39+
40+
private def get(oid : String, sock : UDPSocket) : SNMP::Message
41+
sock.write_bytes session.get(oid)
42+
sock.flush
43+
session.parse(sock.read_bytes(ASN1::BER))
44+
end
45+
46+
def get_next(oid : String) : SNMP::Message
47+
msg : SNMP::Message? = nil
48+
49+
with_socket do |sock|
50+
msg = get_next(oid, sock)
51+
end
52+
53+
raise Error.new("Failed to read message") if msg.nil?
54+
msg
55+
end
56+
57+
private def get_next(oid : String, sock : UDPSocket) : SNMP::Message
58+
sock.write_bytes session.get_next(oid)
59+
sock.flush
60+
session.parse(sock.read_bytes(ASN1::BER))
61+
end
62+
63+
def walk(oid : String) : Array(SNMP::Message)
64+
messages = [] of SNMP::Message
65+
with_socket do |sock|
66+
msg = get_next(oid, sock)
67+
68+
# While the message is not nil and the returned oid is a child of the request
69+
while (!msg.nil? && msg.oid.includes?(oid))
70+
# Break at END OF MIB
71+
break if msg.value.payload.empty?
72+
73+
messages << msg
74+
msg = get_next(msg.oid, sock)
75+
end
76+
end
77+
messages
78+
end
79+
end

0 commit comments

Comments
 (0)