Skip to content

Commit 94e9ca3

Browse files
authored
Merge pull request #31 from n-rodriguez/fix/v1trap-hierarchy
refactor: V1Trap derives from PDU, not the v2 Trap
2 parents 52082ca + b5c8e69 commit 94e9ca3

5 files changed

Lines changed: 39 additions & 11 deletions

File tree

spec/notifications_spec.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe SNMP::Session do
4545
parsed.version.should eq(SNMP::Version::V1)
4646
parsed.request.should eq(SNMP::Request::V1_Trap)
4747
trap = parsed.pdu.as(SNMP::V1Trap)
48-
trap.oid.should eq("1.3.6.1.4.1.9")
48+
trap.enterprise.should eq("1.3.6.1.4.1.9")
4949
trap.agent_address.should eq("10.0.0.1")
5050
trap.generic_trap.should eq(SNMP::GenericTrap::LinkDown)
5151
trap.specific_trap.should eq(0)

spec/snmp_spec.cr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ describe SNMP do
1616

1717
snmp_pdu = snmp.pdu
1818
if snmp_pdu.is_a?(SNMP::V1Trap)
19-
snmp_pdu.oid.should eq("1.3.6.1.6.3.1.1.5")
19+
snmp_pdu.enterprise.should eq("1.3.6.1.6.3.1.1.5")
20+
# PDU#oid keeps its standard meaning: the first varbind's OID
21+
snmp_pdu.oid.should eq("1.3.6.1.2.1.2.2.1.1.26")
2022
snmp_pdu.agent_address.should eq("10.230.254.28")
2123
snmp_pdu.generic_trap.should eq(SNMP::GenericTrap::LinkUp)
2224
snmp_pdu.specific_trap.should eq(0)

spec/v1_trap_spec.cr

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
require "./helper"
2+
3+
describe SNMP::V1Trap do
4+
it "is a PDU but not a v2 Trap (RFC 1157 traps are their own PDU variant)" do
5+
trap = SNMP::V1Trap.new("10.0.0.1", SNMP::GenericTrap::LinkDown, 0, enterprise: "1.3.6.1.4.1.9")
6+
trap.is_a?(SNMP::PDU).should be_true
7+
trap.is_a?(SNMP::Trap).should be_false
8+
end
9+
10+
it "exposes the enterprise OID as #enterprise, keeping PDU#oid for the first varbind" do
11+
vb = SNMP::VarBind.new("1.3.6.1.2.1.2.2.1.1.26")
12+
vb.value.set_integer(26)
13+
trap = SNMP::V1Trap.new("10.0.0.1", SNMP::GenericTrap::LinkUp, 0,
14+
enterprise: "1.3.6.1.4.1.9", time_ticks: 42_u32, varbinds: [vb])
15+
16+
trap.enterprise.should eq("1.3.6.1.4.1.9")
17+
trap.oid.should eq("1.3.6.1.2.1.2.2.1.1.26")
18+
trap.time_ticks.should eq(42)
19+
end
20+
end

src/snmp/session.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class SNMP::Session
100100
# enterprise OID, *agent_address* a dotted-quad IPv4 string.
101101
def trap_v1(enterprise, agent_address, generic_trap : GenericTrap, specific_trap = 0, uptime = 0, varbinds : Array(VarBind) = [] of VarBind, request_id = rand(REQUEST_ID_RANGE))
102102
pdu = V1Trap.new(agent_address, generic_trap, specific_trap.to_i32,
103-
oid: enterprise, time_ticks: uptime.to_u32, varbinds: varbinds, request_id: request_id)
103+
enterprise: enterprise, time_ticks: uptime.to_u32, varbinds: varbinds, request_id: request_id)
104104
SNMP::Message.new(@community, Request::V1_Trap, pdu, version: Version::V1)
105105
end
106106

src/snmp/v1_trap.cr

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
class SNMP::V1Trap < SNMP::Trap
1+
# An RFC 1157 Trap-PDU. It is its own variant of the protocol's PDU CHOICE —
2+
# not an SNMPv2 trap — so it derives from PDU directly and carries the v1
3+
# fields (enterprise, agent address, generic/specific trap, timestamp) itself.
4+
# The v2-style request-id / error fields inherited from PDU have no meaning in
5+
# a v1 trap and stay at their defaults.
6+
class SNMP::V1Trap < SNMP::PDU
27
def initialize(ber : ASN1::BER)
38
pdu = SNMP.ber_fields(ber, 6, "v1 trap")
4-
@oid = pdu[0].get_object_id
9+
@enterprise = pdu[0].get_object_id
510
@agent_address = pdu[1].payload.join(".")
611
@generic_trap = SNMP.decode_enum(GenericTrap, pdu[2].get_integer, "generic-trap")
712
@specific_trap = pdu[3].get_integer.to_i32
@@ -10,25 +15,26 @@ class SNMP::V1Trap < SNMP::Trap
1015
VarBind.new(varbind)
1116
end
1217

13-
# Compatibility with regular PDUs
14-
# V1 traps are very different: https://tools.ietf.org/html/rfc1157#page-27
18+
# The v2-style PDU fields do not exist on the v1 wire
1519
@request_id = 0
1620
@error_status = ErrorStatus::NoError
1721
@error_index = 0
1822
end
1923

24+
property enterprise : String
2025
property agent_address : String
2126
property generic_trap : GenericTrap
2227
property specific_trap : Int32
28+
property time_ticks : UInt32
2329

24-
def initialize(@agent_address, @generic_trap, @specific_trap, **args)
25-
super(**args)
30+
def initialize(@agent_address, @generic_trap, @specific_trap = 0, @enterprise = "", @time_ticks = 0_u32, varbinds : Array(VarBind) = [] of VarBind, request_id = 0)
31+
super(request_id, varbinds)
2632
end
2733

2834
# RFC 1157 Trap-PDU wire structure — distinct from the standard PDU layout, so
29-
# this overrides `PDU#to_ber`. `@oid` holds the enterprise OID.
35+
# this overrides `PDU#to_ber`.
3036
def to_ber(tag_number)
31-
enterprise = ASN1::BER.new.set_object_id(@oid)
37+
enterprise = ASN1::BER.new.set_object_id(@enterprise)
3238
agent = IpAddress.new(@agent_address).to_ber
3339
generic = ASN1::BER.new.set_integer(@generic_trap.to_i)
3440
specific = ASN1::BER.new.set_integer(@specific_trap)

0 commit comments

Comments
 (0)