packetgen 1.4.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Vendor ID payloads, as defined in RFC 7296 §3.12.
7
+ #
8
+ # A Vendor ID payload contains a generic payload header (see {Payload})
9
+ # and data field (type {Types::String}):
10
+ # 1 2 3
11
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | |
16
+ # ~ VendorID Data ~
17
+ # | |
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ #
20
+ # == Create a Vendor ID payload
21
+ # # Create a IKE packet with a Vendor ID payload
22
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
23
+ # pkt.add('IKE::VendorID', data: "abcdefgh")
24
+ # @author Sylvain Daubert
25
+ class VendorID < Payload
26
+
27
+ # Payload type number
28
+ PAYLOAD_TYPE = 43
29
+ end
30
+ end
31
+
32
+ self.add_class IKE::VendorID
33
+ end
34
+ end
@@ -211,16 +211,16 @@ module PacketGen
211
211
  next if attr == :body
212
212
  str << Inspect.inspect_attribute(attr, value, 2)
213
213
  if attr == :u8
214
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'version', version]
215
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'ihl', ihl]
214
+ str << shift + Inspect::FMT_ATTR % ['', 'version', version]
215
+ str << shift + Inspect::FMT_ATTR % ['', 'ihl', ihl]
216
216
  elsif attr == :frag
217
217
  flags = flag_rsv? ? %w(RSV) : []
218
218
  flags << 'DF' if flag_df?
219
219
  flags << 'MF' if flag_mf?
220
220
  flags_str = flags.empty? ? 'none' : flags.join(',')
221
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'flags', flags_str]
221
+ str << shift + Inspect::FMT_ATTR % ['', 'flags', flags_str]
222
222
  foff = Inspect.int_dec_hex(fragment_offset, 4)
223
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'frag_offset', foff]
223
+ str << shift + Inspect::FMT_ATTR % ['', 'frag_offset', foff]
224
224
  end
225
225
  end
226
226
  str
@@ -206,11 +206,11 @@ module PacketGen
206
206
  str << Inspect.inspect_attribute(attr, value, 2)
207
207
  if attr == :u32
208
208
  shift = Inspect.shift_level(2)
209
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'version', version]
209
+ str << shift + Inspect::FMT_ATTR % ['', 'version', version]
210
210
  tclass = Inspect.int_dec_hex(traffic_class, 2)
211
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'tclass', tclass]
211
+ str << shift + Inspect::FMT_ATTR % ['', 'tclass', tclass]
212
212
  fl_value = Inspect.int_dec_hex(flow_label, 5)
213
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'flow_label', fl_value]
213
+ str << shift + Inspect::FMT_ATTR % ['', 'flow_label', fl_value]
214
214
  end
215
215
  end
216
216
  str
@@ -0,0 +1,283 @@
1
+ # coding: utf-8
2
+ # This file is part of PacketGen
3
+ # See https://github.com/sdaubert/packetgen for more informations
4
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ module PacketGen
8
+ module Header
9
+
10
+ # Dissect error
11
+ class DissectError < ParseError; end
12
+
13
+ # Simple Network Management Protocol (SNMP)
14
+ # @author Sylvain Daubert
15
+ # @since 2.0.0
16
+ class SNMP < ASN1Base
17
+
18
+ # Agents listen to this port
19
+ UDP_PORT1 = 161
20
+ # Configuration sinks listen to this port
21
+ UDP_PORT2 = 162
22
+
23
+ PDU_GET = 0
24
+ PDU_NEXT = 1
25
+ PDU_RESPONSE = 2
26
+ PDU_SET = 3
27
+ PDU_TRAPv1 = 4
28
+ PDU_BULK = 5
29
+ PDU_INFORM = 6
30
+ PDU_TRAPv2 = 7
31
+ PDU_REPORT = 8
32
+
33
+ ERRORS = { 'no_error' => 0,
34
+ 'too_big' => 1,
35
+ 'no_such_name' => 2,
36
+ 'bad_value' => 3,
37
+ 'read_only' => 4,
38
+ 'generic_error' => 5,
39
+ 'no_access' => 6,
40
+ 'wrong_type' => 7,
41
+ 'wrong_length' => 8,
42
+ 'wrong_encoding' => 9,
43
+ 'wrong_value' => 10,
44
+ 'no_creation' => 11,
45
+ 'inconsistent_value' => 12,
46
+ 'ressource_unavailable' => 13,
47
+ 'commit_failed' => 14,
48
+ 'undo_failed' => 15,
49
+ 'authorization_error' => 16,
50
+ 'not_writable' => 17,
51
+ 'inconsistent_name' => 18
52
+ }
53
+
54
+ # Class to handle SNMP VarBind
55
+ # VarBind ::= SEQUENCE {
56
+ # name OBJECT IDENTIFIER,
57
+ # value ANY -- depends on name
58
+ # }
59
+ # @author Sylvain Daubert
60
+ class VarBind < RASN1::Model
61
+ sequence :varbind,
62
+ content: [objectid(:name),
63
+ any(:value)]
64
+ end
65
+
66
+ # Class to handle SNMP VariableBindingsList
67
+ # VarBindList ::= SEQUENCE (SIZE (0..max-bindings)) OF VarBind
68
+ # @author Sylvain Daubert
69
+ class VariableBindings < RASN1::Model
70
+ sequence_of :bindings, VarBind
71
+ end
72
+
73
+ # Class to handle GetRequest PDU
74
+ # GetRequest-PDU ::= [0] IMPLICIT PDU
75
+ #
76
+ # PDU ::= SEQUENCE {
77
+ # request-id INTEGER (-214783648..214783647),
78
+ #
79
+ # error-status -- sometimes ignored
80
+ # INTEGER {
81
+ # noError(0),
82
+ # tooBig(1),
83
+ # noSuchName(2), -- for proxy compatibility
84
+ # badValue(3), -- for proxy compatibility
85
+ # readOnly(4), -- for proxy compatibility
86
+ # genErr(5),
87
+ # noAccess(6),
88
+ # wrongType(7),
89
+ # wrongLength(8),
90
+ # wrongEncoding(9),
91
+ # wrongValue(10),
92
+ # noCreation(11),
93
+ # inconsistentValue(12),
94
+ # resourceUnavailable(13),
95
+ # commitFailed(14),
96
+ # undoFailed(15),
97
+ # authorizationError(16),
98
+ # notWritable(17),
99
+ # inconsistentName(18)
100
+ # },
101
+ #
102
+ # error-index -- sometimes ignored
103
+ # INTEGER (0..max-bindings),
104
+ #
105
+ # variable-bindings -- values are sometimes ignored
106
+ # VarBindList
107
+ # }
108
+ # @author Sylvain Daubert
109
+ class GetRequest < RASN1::Model
110
+ sequence :pdu,
111
+ implicit: SNMP::PDU_GET, constructed: true,
112
+ content: [integer(:id, value: 0),
113
+ enumerated(:error, enum: ERRORS),
114
+ integer(:error_index),
115
+ model(:varbindlist, VariableBindings)]
116
+
117
+ # @return [String]
118
+ def inspect
119
+ Inspect.inspect_body(to_der, self.class)
120
+ end
121
+ end
122
+
123
+ # Class to handle GetNextRequest PDU
124
+ # GetNextRequest-PDU ::= [1] IMPLICIT PDU -- PDU definition: see GetRequest
125
+ # @author Sylvain Daubert
126
+ class GetNextRequest < GetRequest
127
+ root_options implicit: SNMP::PDU_NEXT
128
+ end
129
+
130
+ # Class to handle GetResponse PDU
131
+ # GetResponse-PDU ::= [2] IMPLICIT PDU -- PDU definition: see GetRequest
132
+ # @author Sylvain Daubert
133
+ class GetResponse < GetRequest
134
+ root_options implicit: SNMP::PDU_RESPONSE
135
+ end
136
+
137
+ # Class to handle SetRequest PDU
138
+ # SetRequest-PDU ::= [3] IMPLICIT PDU -- PDU definition: see GetRequest
139
+ # @author Sylvain Daubert
140
+ class SetRequest < GetRequest
141
+ root_options implicit: SNMP::PDU_GET
142
+ end
143
+
144
+ # Class to handle Trap from SNMPv1
145
+ # Trap-PDU ::= [4] IMPLICIT SEQUENCE {
146
+ # enterprise OBJECT IDENTIFIER,
147
+ # agent-addr NetworkAddress,
148
+ # generic-trap -- generic trap type
149
+ # INTEGER {
150
+ # coldStart(0),
151
+ # warmStart(1),
152
+ # linkDown(2),
153
+ # linkUp(3),
154
+ # authenticationFailure(4),
155
+ # egpNeighborLoss(5),
156
+ # enterpriseSpecific(6)
157
+ # },
158
+ # specific-trap INTEGER,
159
+ # time-stamp TimeTicks,
160
+ # variable-bindings VarBindList
161
+ # }
162
+ class Trapv1 < RASN1::Model
163
+ sequence :trap,
164
+ implicit: SNMP::PDU_TRAPv1, constructed: true,
165
+ content: [objectid(:enterprise),
166
+ octet_string(:agent_addr),
167
+ enumerated(:generic_trap, enum: { 'cold_start' => 0,
168
+ 'warm_start' => 1,
169
+ 'link_down' => 2,
170
+ 'link_up' => 3,
171
+ 'auth_failure' => 4,
172
+ 'egp_neighbor_loss' => 5,
173
+ 'specific' => 6 }),
174
+ integer(:specific_trap),
175
+ integer(:timestamp),
176
+ model(:varbindlist, VariableBindings)]
177
+ end
178
+
179
+ # Class to handle Bulk PDU
180
+ # GetBulkRequest-PDU ::= [5] IMPLICIT BulkPDU
181
+ #
182
+ # BulkPDU ::= -- must be identical in
183
+ # SEQUENCE { -- structure to PDU
184
+ # request-id INTEGER (-214783648..214783647),
185
+ # non-repeaters INTEGER (0..max-bindings),
186
+ # max-repetitions INTEGER (0..max-bindings),
187
+ # variable-bindings -- values are ignored
188
+ # VarBindList
189
+ # }
190
+ # @author Sylvain Daubert
191
+ class Bulk < RASN1::Model
192
+ sequence :bulkpdu,
193
+ implicit: SNMP::PDU_BULK, constructed: true,
194
+ content: [integer(:id, value: 0),
195
+ integer(:non_repeaters),
196
+ integer(:max_repetitions),
197
+ model(:varbindlist, VariableBindings)]
198
+
199
+ # @return [String]
200
+ def inspect
201
+ Inspect.inspect_body(to_der, self.class)
202
+ end
203
+ end
204
+
205
+ # Class to handle InformRequest PDU
206
+ # InformRequest-PDU ::= [6] IMPLICIT PDU -- PDU definition: see GetRequest
207
+ # @author Sylvain Daubert
208
+ class InformRequest < GetRequest
209
+ root_options implicit: SNMP::PDU_INFORM
210
+ end
211
+
212
+ # Class to handle Trapv2 PDU
213
+ # SNMPv2-Trap-PDU ::= [7] IMPLICIT PDU -- PDU definition: see GetRequest
214
+ # @author Sylvain Daubert
215
+ class Trapv2 < GetRequest
216
+ root_options implicit: SNMP::PDU_TRAPv2
217
+ end
218
+
219
+ # Class to handle Report PDU
220
+ # Report-PDU ::= [8] IMPLICIT PDU -- PDU definition: see GetRequest
221
+ # @author Sylvain Daubert
222
+ class Report < GetRequest
223
+ root_options implicit: SNMP::PDU_REPORT
224
+ end
225
+
226
+ # Class to handle PDUs from SNMP packet
227
+ # PDUs ::= CHOICE {
228
+ # get-request [0] IMPLICIT PDU,
229
+ # get-next-request [1] IMPLICIT PDU,
230
+ # get-response [2] IMPLICIT PDU,
231
+ # set-request [3] IMPLICIT PDU,
232
+ # snmpV1-trap [4] IMPLICIT PDU,
233
+ # get-bulk-request [5] IMPLICIT PDU,
234
+ # inform-request [6] IMPLICIT PDU,
235
+ # snmpV2-trap [7] IMPLICIT PDU,
236
+ # report [8] IMPLICIT PDU
237
+ # }
238
+ # @author Sylvain Daubert
239
+ class PDUs < RASN1::Model
240
+ choice :pdus,
241
+ content: [model(:get_request, GetRequest),
242
+ model(:get_next_request, GetNextRequest),
243
+ model(:get_response, GetResponse),
244
+ model(:set_request, SetRequest),
245
+ #model(:trapv1, Trapv1),
246
+ model(:bulk, Bulk),
247
+ model(:inform, InformRequest),
248
+ model(:trapv2, Trapv2),
249
+ model(:report, Report)]
250
+ end
251
+
252
+ sequence :message,
253
+ content: [enumerated(:version, value: 'v2c',
254
+ enum: { 'v1' => 0, 'v2c' => 1, 'v2' => 2, 'v3' => 3 }),
255
+ octet_string(:community, value: 'public'),
256
+ model(:data, PDUs)]
257
+
258
+ define_attributes :version, :community
259
+
260
+ # accessor to data payload
261
+ # @return [GetRequest]
262
+ def data
263
+ @elements[:data]
264
+ end
265
+
266
+ def inspect
267
+ str = super
268
+ str << Inspect.shift_level(2)
269
+ if self[:data].chosen.nil?
270
+ str << Inspect::FMT_ATTR % [self[:data].type, :data, '']
271
+ else
272
+ data = self[:data]
273
+ str << Inspect::FMT_ATTR % [data.type, :data, data.chosen_value.type]
274
+ str << data.chosen_value.inspect
275
+ end
276
+ end
277
+ end
278
+
279
+ self.add_class SNMP
280
+ UDP.bind_header SNMP, dport: SNMP::UDP_PORT1, sport: SNMP::UDP_PORT1
281
+ UDP.bind_header SNMP, dport: SNMP::UDP_PORT2, sport: SNMP::UDP_PORT2
282
+ end
283
+ end
@@ -217,13 +217,13 @@ module PacketGen
217
217
  str << Inspect.inspect_attribute(attr, value, 2)
218
218
  if attr == :u16
219
219
  doff = Inspect.int_dec_hex(data_offset, 1)
220
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'data_offset', doff]
221
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'reserved', reserved]
220
+ str << shift + Inspect::FMT_ATTR % ['', 'data_offset', doff]
221
+ str << shift + Inspect::FMT_ATTR % ['', 'reserved', reserved]
222
222
  flags = ''
223
223
  %w(ns cwr ece urg ack psh rst syn fin).each do |fl|
224
224
  flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
225
225
  end
226
- str << shift + Inspect::INSPECT_FMT_ATTR % ['', 'flags', flags]
226
+ str << shift + Inspect::FMT_ATTR % ['', 'flags', flags]
227
227
  end
228
228
  end
229
229
  str
@@ -6,10 +6,10 @@ module PacketGen
6
6
  module Inspect
7
7
 
8
8
  # Maximum number of characters on a line for INSPECT
9
- INSPECT_MAX_WIDTH = 70
9
+ MAX_WIDTH = 70
10
10
 
11
11
  # Format to inspect attribute
12
- INSPECT_FMT_ATTR = "%10s %12s: %s\n"
12
+ FMT_ATTR = "%12s %12s: %s\n"
13
13
 
14
14
  # Create a dashed line with +obj+ class writing in it
15
15
  # @param [String] name
@@ -17,7 +17,7 @@ module PacketGen
17
17
  # @return [String]
18
18
  def self.dashed_line(name, level=1)
19
19
  str = '--' * level << " #{name} "
20
- str << '-' * (INSPECT_MAX_WIDTH - str.length) << "\n"
20
+ str << '-' * (MAX_WIDTH - str.length) << "\n"
21
21
  end
22
22
 
23
23
  # @return [String]
@@ -44,23 +44,49 @@ module PacketGen
44
44
  # @return [String]
45
45
  def self.inspect_attribute(attr, value, level=1)
46
46
  str = shift_level(level)
47
- val = if value.is_a? Types::Int
47
+ val = if value.is_a?(Types::Int) or value.is_a?(Integer)
48
48
  int_dec_hex(value, value.to_s.size * 2)
49
49
  elsif value.respond_to? :to_human
50
50
  value.to_human
51
51
  else
52
52
  value.to_s.inspect
53
53
  end
54
- str << INSPECT_FMT_ATTR % [value.class.to_s.sub(/.*::/, ''), attr, val]
54
+ str << FMT_ATTR % [value.class.to_s.sub(/.*::/, ''), attr, val]
55
+ end
56
+
57
+ # Format a ASN.1 attribute for +#inspect+.
58
+ # 3 cases are handled:
59
+ # * attribute value is a {Types::Int}: show value as integer and in
60
+ # hexdecimal format,
61
+ # * attribute value responds to +#to_human+: call it,
62
+ # * else, +#to_s+ is used to format attribute value.
63
+ # @param [Symbol] name attribute name
64
+ # @param [RASN1::Types::Base,RASN1::Model] attr attribute
65
+ # @param [Integer] level
66
+ # @return [String]
67
+ def self.inspect_asn1_attribute(name, attr, level=1)
68
+ str = shift_level(level)
69
+ val = case attr
70
+ when RASN1::Types::Enumerated
71
+ hexsize = attr.value_size * 2
72
+ "%-10s (0x%0#{hexsize}x)" % [attr.value, attr.to_i]
73
+ when RASN1::Types::Integer
74
+ int_dec_hex(attr.value, attr.value_size * 2)
75
+ when RASN1::Model
76
+ attr.root.type
77
+ else
78
+ attr.value.to_s.inspect
79
+ end
80
+ str << FMT_ATTR % [attr.type, name, val]
55
81
  end
56
82
 
57
83
  # @param [#to_s] body
58
84
  # @return [String]
59
- def self.inspect_body(body)
85
+ def self.inspect_body(body, name='Body')
60
86
  return '' if body.nil? or body.empty?
61
- str = dashed_line('Body', 2)
87
+ str = dashed_line(name, 2)
62
88
  str << (0..15).to_a.map { |v| " %02d" % v}.join << "\n"
63
- str << '-' * INSPECT_MAX_WIDTH << "\n"
89
+ str << '-' * MAX_WIDTH << "\n"
64
90
  if body.size > 0
65
91
  (body.size / 16 + 1).times do |i|
66
92
  octets = body.to_s[i*16, 16].unpack('C*')
@@ -71,7 +97,7 @@ module PacketGen
71
97
  str << "\n"
72
98
  end
73
99
  end
74
- str << '-' * INSPECT_MAX_WIDTH << "\n"
100
+ str << '-' * MAX_WIDTH << "\n"
75
101
  end
76
102
  end
77
103
  end