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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -4
- data/README.md +6 -6
- data/lib/packetgen.rb +0 -1
- data/lib/packetgen/capture.rb +15 -37
- data/lib/packetgen/header.rb +6 -2
- data/lib/packetgen/header/asn1_base.rb +86 -0
- data/lib/packetgen/header/base.rb +68 -44
- data/lib/packetgen/header/crypto.rb +62 -0
- data/lib/packetgen/header/dns.rb +3 -3
- data/lib/packetgen/header/dot11.rb +5 -0
- data/lib/packetgen/header/esp.rb +7 -43
- data/lib/packetgen/header/ike.rb +235 -0
- data/lib/packetgen/header/ike/auth.rb +197 -0
- data/lib/packetgen/header/ike/cert.rb +105 -0
- data/lib/packetgen/header/ike/certreq.rb +69 -0
- data/lib/packetgen/header/ike/id.rb +131 -0
- data/lib/packetgen/header/ike/ke.rb +74 -0
- data/lib/packetgen/header/ike/nonce.rb +35 -0
- data/lib/packetgen/header/ike/notify.rb +220 -0
- data/lib/packetgen/header/ike/payload.rb +307 -0
- data/lib/packetgen/header/ike/sa.rb +577 -0
- data/lib/packetgen/header/ike/sk.rb +255 -0
- data/lib/packetgen/header/ike/ts.rb +287 -0
- data/lib/packetgen/header/ike/vendor_id.rb +34 -0
- data/lib/packetgen/header/ip.rb +4 -4
- data/lib/packetgen/header/ipv6.rb +3 -3
- data/lib/packetgen/header/snmp.rb +283 -0
- data/lib/packetgen/header/tcp.rb +3 -3
- data/lib/packetgen/inspect.rb +35 -9
- data/lib/packetgen/packet.rb +23 -9
- data/lib/packetgen/types/fields.rb +11 -3
- data/lib/packetgen/version.rb +1 -1
- data/packetgen.gemspec +2 -0
- metadata +52 -2
@@ -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
|
data/lib/packetgen/header/ip.rb
CHANGED
@@ -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::
|
215
|
-
str << shift + Inspect::
|
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::
|
221
|
+
str << shift + Inspect::FMT_ATTR % ['', 'flags', flags_str]
|
222
222
|
foff = Inspect.int_dec_hex(fragment_offset, 4)
|
223
|
-
str << shift + Inspect::
|
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::
|
209
|
+
str << shift + Inspect::FMT_ATTR % ['', 'version', version]
|
210
210
|
tclass = Inspect.int_dec_hex(traffic_class, 2)
|
211
|
-
str << shift + Inspect::
|
211
|
+
str << shift + Inspect::FMT_ATTR % ['', 'tclass', tclass]
|
212
212
|
fl_value = Inspect.int_dec_hex(flow_label, 5)
|
213
|
-
str << shift + Inspect::
|
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
|
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -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::
|
221
|
-
str << shift + Inspect::
|
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::
|
226
|
+
str << shift + Inspect::FMT_ATTR % ['', 'flags', flags]
|
227
227
|
end
|
228
228
|
end
|
229
229
|
str
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -6,10 +6,10 @@ module PacketGen
|
|
6
6
|
module Inspect
|
7
7
|
|
8
8
|
# Maximum number of characters on a line for INSPECT
|
9
|
-
|
9
|
+
MAX_WIDTH = 70
|
10
10
|
|
11
11
|
# Format to inspect attribute
|
12
|
-
|
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 << '-' * (
|
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?
|
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 <<
|
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(
|
87
|
+
str = dashed_line(name, 2)
|
62
88
|
str << (0..15).to_a.map { |v| " %02d" % v}.join << "\n"
|
63
|
-
str << '-' *
|
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 << '-' *
|
100
|
+
str << '-' * MAX_WIDTH << "\n"
|
75
101
|
end
|
76
102
|
end
|
77
103
|
end
|