packetgen 3.1.4 → 3.2.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/README.md +0 -1
- data/bin/pgconsole +1 -0
- data/lib/packetgen.rb +19 -3
- data/lib/packetgen/capture.rb +30 -9
- data/lib/packetgen/config.rb +15 -9
- data/lib/packetgen/deprecation.rb +1 -1
- data/lib/packetgen/header/asn1_base.rb +19 -9
- data/lib/packetgen/header/base.rb +68 -70
- data/lib/packetgen/header/dhcpv6/duid.rb +3 -1
- data/lib/packetgen/header/dhcpv6/option.rb +4 -12
- data/lib/packetgen/header/dns/name.rb +18 -7
- data/lib/packetgen/header/dns/qdsection.rb +1 -1
- data/lib/packetgen/header/dns/question.rb +2 -0
- data/lib/packetgen/header/dot11.rb +25 -38
- data/lib/packetgen/header/dot11/data.rb +28 -34
- data/lib/packetgen/header/dot1x.rb +1 -14
- data/lib/packetgen/header/eap.rb +14 -17
- data/lib/packetgen/header/eth.rb +5 -6
- data/lib/packetgen/header/http/headers.rb +4 -2
- data/lib/packetgen/header/http/request.rb +37 -18
- data/lib/packetgen/header/http/response.rb +11 -5
- data/lib/packetgen/header/http/verbs.rb +1 -1
- data/lib/packetgen/header/igmpv3/group_record.rb +2 -0
- data/lib/packetgen/header/ip.rb +27 -26
- data/lib/packetgen/header/ip/addr.rb +3 -1
- data/lib/packetgen/header/ip/option.rb +4 -4
- data/lib/packetgen/header/ipv6/addr.rb +2 -0
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +2 -0
- data/lib/packetgen/header/ospfv2/ls_request.rb +2 -0
- data/lib/packetgen/header/ospfv2/lsa.rb +13 -3
- data/lib/packetgen/header/ospfv2/lsa_header.rb +2 -1
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +2 -0
- data/lib/packetgen/header/ospfv3/ls_request.rb +2 -0
- data/lib/packetgen/header/ospfv3/lsa.rb +9 -3
- data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -1
- data/lib/packetgen/header/snmp.rb +3 -2
- data/lib/packetgen/header/tcp.rb +1 -20
- data/lib/packetgen/header/tcp/option.rb +8 -6
- data/lib/packetgen/inspect.rb +1 -17
- data/lib/packetgen/packet.rb +10 -6
- data/lib/packetgen/pcapng.rb +11 -11
- data/lib/packetgen/pcapng/block.rb +15 -2
- data/lib/packetgen/pcapng/epb.rb +22 -15
- data/lib/packetgen/pcapng/file.rb +166 -81
- data/lib/packetgen/pcapng/idb.rb +7 -9
- data/lib/packetgen/pcapng/shb.rb +35 -28
- data/lib/packetgen/pcapng/spb.rb +16 -12
- data/lib/packetgen/pcapng/unknown_block.rb +3 -11
- data/lib/packetgen/pcaprub_wrapper.rb +25 -11
- data/lib/packetgen/types.rb +1 -0
- data/lib/packetgen/types/abstract_tlv.rb +3 -1
- data/lib/packetgen/types/array.rb +17 -10
- data/lib/packetgen/types/cstring.rb +56 -19
- data/lib/packetgen/types/enum.rb +4 -0
- data/lib/packetgen/types/fieldable.rb +65 -0
- data/lib/packetgen/types/fields.rb +180 -113
- data/lib/packetgen/types/int.rb +15 -1
- data/lib/packetgen/types/int_string.rb +8 -0
- data/lib/packetgen/types/length_from.rb +18 -10
- data/lib/packetgen/types/oui.rb +2 -0
- data/lib/packetgen/types/string.rb +58 -7
- data/lib/packetgen/types/tlv.rb +2 -0
- data/lib/packetgen/unknown_packet.rb +84 -0
- data/lib/packetgen/utils.rb +6 -7
- data/lib/packetgen/version.rb +1 -1
- metadata +18 -15
@@ -87,15 +87,21 @@ module PacketGen
|
|
87
87
|
end
|
88
88
|
unless headers.empty?
|
89
89
|
first_line = headers.shift.split
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
if first_line.size >= 3
|
91
|
+
self[:version].read first_line[0]
|
92
|
+
self[:status_code].read first_line[1]
|
93
|
+
self[:status_mesg].read first_line[2..-1].join(' ')
|
94
|
+
end
|
93
95
|
self[:headers].read(headers.join("\n"))
|
94
96
|
end
|
95
97
|
self[:body].read data.join("\n")
|
96
98
|
self
|
97
99
|
end
|
98
100
|
|
101
|
+
def parse?
|
102
|
+
version.start_with?('HTTP/1.')
|
103
|
+
end
|
104
|
+
|
99
105
|
# String representation of data.
|
100
106
|
# @return [String]
|
101
107
|
def to_s
|
@@ -104,7 +110,7 @@ module PacketGen
|
|
104
110
|
raise FormatError, 'Missing #version.' if self.version.empty?
|
105
111
|
|
106
112
|
str = +''
|
107
|
-
str << self
|
113
|
+
str << self.version << ' ' << self.status_code << ' ' << self.status_mesg << "\r\n"
|
108
114
|
str << self[:headers].to_s if self[:headers].given?
|
109
115
|
str << self.body
|
110
116
|
end
|
@@ -112,6 +118,6 @@ module PacketGen
|
|
112
118
|
end
|
113
119
|
|
114
120
|
self.add_class HTTP::Response
|
115
|
-
TCP.bind HTTP::Response, body: ->(b) { %r[^HTTP/1\.1\s\d{3,}\s.+] =~ b
|
121
|
+
TCP.bind HTTP::Response, body: ->(b) { b.nil? ? '' : %r[^HTTP/1\.1\s\d{3,}\s.+] =~ b }
|
116
122
|
end
|
117
123
|
end
|
@@ -16,7 +16,7 @@ module PacketGen
|
|
16
16
|
VERBS = %w[GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATCH].freeze
|
17
17
|
|
18
18
|
# Identifiable HTTP request regular expression.
|
19
|
-
REQUEST_REGEX = Regexp.new(
|
19
|
+
REQUEST_REGEX = Regexp.new("^(#{VERBS.dup.join('|')})\\s+\\S+\\s+HTTP/1.1")
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
data/lib/packetgen/header/ip.rb
CHANGED
@@ -131,7 +131,7 @@ module PacketGen
|
|
131
131
|
# @since 2.2.0
|
132
132
|
# @return [Types::String]
|
133
133
|
define_field :options, Options, optional: ->(h) { h.ihl > 5 },
|
134
|
-
|
134
|
+
builder: ->(h, t) { t.new(length_from: -> { (h.ihl - 5) * 4 }) }
|
135
135
|
# @!attribute body
|
136
136
|
# @return [Types::String,Header::Base]
|
137
137
|
define_field :body, Types::String
|
@@ -166,7 +166,7 @@ module PacketGen
|
|
166
166
|
|
167
167
|
data = hdr.to_s
|
168
168
|
data << "\x00" if data.size.odd?
|
169
|
-
sum = data.unpack('n*').
|
169
|
+
sum = data.unpack('n*').sum
|
170
170
|
|
171
171
|
hdr.checksum = old_checksum if old_checksum
|
172
172
|
|
@@ -191,17 +191,10 @@ module PacketGen
|
|
191
191
|
# @return [Integer]
|
192
192
|
def calc_checksum
|
193
193
|
# Checksum is only on header, so cannot use IP.sum16,
|
194
|
-
# which also
|
195
|
-
|
196
|
-
checksum
|
197
|
-
checksum
|
198
|
-
checksum += self.frag
|
199
|
-
checksum += (self.ttl << 8) | self.protocol
|
200
|
-
checksum += (self[:src].to_i >> 16)
|
201
|
-
checksum += (self[:src].to_i & 0xffff)
|
202
|
-
checksum += self[:dst].to_i >> 16
|
203
|
-
checksum += self[:dst].to_i & 0xffff
|
204
|
-
options.to_s.unpack('n*').each { |x| checksum += x }
|
194
|
+
# which also calculates checksum on #body.
|
195
|
+
nb_words = ihl * 2
|
196
|
+
self.checksum = 0
|
197
|
+
checksum = to_s.unpack("n#{nb_words}").sum
|
205
198
|
self[:checksum].value = IP.reduce_checksum(checksum)
|
206
199
|
end
|
207
200
|
|
@@ -238,20 +231,9 @@ module PacketGen
|
|
238
231
|
super do |attr|
|
239
232
|
case attr
|
240
233
|
when :u8
|
241
|
-
|
242
|
-
str = Inspect.inspect_attribute(attr, self[attr])
|
243
|
-
str << shift << Inspect::FMT_ATTR % ['', 'version', version]
|
244
|
-
str << shift << Inspect::FMT_ATTR % ['', 'ihl', ihl]
|
234
|
+
inspect_u8
|
245
235
|
when :frag
|
246
|
-
|
247
|
-
str = Inspect.inspect_attribute(attr, self[attr])
|
248
|
-
flags = flag_rsv? ? %w[RSV] : []
|
249
|
-
flags << 'DF' if flag_df?
|
250
|
-
flags << 'MF' if flag_mf?
|
251
|
-
flags_str = flags.empty? ? 'none' : flags.join(',')
|
252
|
-
str << shift << Inspect::FMT_ATTR % ['', 'flags', flags_str]
|
253
|
-
foff = Inspect.int_dec_hex(fragment_offset, 4)
|
254
|
-
str << shift << Inspect::FMT_ATTR % ['', 'frag_offset', foff]
|
236
|
+
inspect_frag
|
255
237
|
end
|
256
238
|
end
|
257
239
|
end
|
@@ -276,6 +258,25 @@ module PacketGen
|
|
276
258
|
self[:src], self[:dst] = self[:dst], self[:src]
|
277
259
|
self
|
278
260
|
end
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def inspect_u8
|
265
|
+
shift = Inspect.shift_level
|
266
|
+
str = Inspect.inspect_attribute(:u8, self[:u8])
|
267
|
+
str << shift << Inspect::FMT_ATTR % ['', 'version', version]
|
268
|
+
str << shift << Inspect::FMT_ATTR % ['', 'ihl', ihl]
|
269
|
+
end
|
270
|
+
|
271
|
+
def inspect_frag
|
272
|
+
shift = Inspect.shift_level
|
273
|
+
str = Inspect.inspect_attribute(:frag, self[:frag])
|
274
|
+
flags = %i[rsv df mf].select { |flag| send("flag_#{flag}?") }.map(&:upcase)
|
275
|
+
flags_str = flags.empty? ? 'none' : flags.join(',')
|
276
|
+
str << shift << Inspect::FMT_ATTR % ['', 'flags', flags_str]
|
277
|
+
foff = Inspect.int_dec_hex(fragment_offset, 4)
|
278
|
+
str << shift << Inspect::FMT_ATTR % ['', 'frag_offset', foff]
|
279
|
+
end
|
279
280
|
end
|
280
281
|
|
281
282
|
self.add_class IP
|
@@ -11,6 +11,8 @@ module PacketGen
|
|
11
11
|
# IP address, as a group of 4 bytes
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class Addr < Types::Fields
|
14
|
+
include Types::Fieldable
|
15
|
+
|
14
16
|
# @!attribute a1
|
15
17
|
# @return [Integer] IP address first byte
|
16
18
|
define_field :a1, Types::Int8
|
@@ -24,7 +26,7 @@ module PacketGen
|
|
24
26
|
# @return [Integer] IP address fourth byte
|
25
27
|
define_field :a4, Types::Int8
|
26
28
|
|
27
|
-
IPV4_ADDR_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})
|
29
|
+
IPV4_ADDR_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.freeze
|
28
30
|
|
29
31
|
# Read a dotted address
|
30
32
|
# @param [String] str
|
@@ -26,6 +26,8 @@ module PacketGen
|
|
26
26
|
# Base class for IP options
|
27
27
|
# @author Sylvain Daubert
|
28
28
|
class Option < Types::Fields
|
29
|
+
include Types::Fieldable
|
30
|
+
|
29
31
|
# EOL option type
|
30
32
|
EOL_TYPE = 0x00
|
31
33
|
# NOP option type
|
@@ -115,10 +117,8 @@ module PacketGen
|
|
115
117
|
# Get a human readable string
|
116
118
|
# @return [String]
|
117
119
|
def to_human
|
118
|
-
str = self.
|
119
|
-
if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty?
|
120
|
-
str << ":#{self[:data].to_s.inspect}"
|
121
|
-
end
|
120
|
+
str = self.instance_of?(Option) ? +"unk-#{type}" : self.class.to_s.sub(/.*::/, '')
|
121
|
+
str << ":#{self[:data].to_s.inspect}" if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty?
|
122
122
|
str
|
123
123
|
end
|
124
124
|
end
|
@@ -52,6 +52,8 @@ module PacketGen
|
|
52
52
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
53
53
|
# @author Sylvain Daubert
|
54
54
|
class McastAddressRecord < Types::Fields
|
55
|
+
include Types::Fieldable
|
56
|
+
|
55
57
|
# Known record types
|
56
58
|
RECORD_TYPES = IGMPv3::GroupRecord::RECORD_TYPES
|
57
59
|
|
@@ -23,6 +23,8 @@ module PacketGen
|
|
23
23
|
# LSA router payload}.
|
24
24
|
# @author Sylvain Daubert
|
25
25
|
class TosMetric < Types::Fields
|
26
|
+
include Types::Fieldable
|
27
|
+
|
26
28
|
# @!attribute tos
|
27
29
|
# 8-bit IP Type of Service that this metric refers to.
|
28
30
|
# @return [Integer]
|
@@ -52,6 +54,8 @@ module PacketGen
|
|
52
54
|
# This class handles links in a {LSARouter LSA router payload}.
|
53
55
|
# @author Sylvain Daubert
|
54
56
|
class Link < Types::Fields
|
57
|
+
include Types::Fieldable
|
58
|
+
|
55
59
|
# @!attribute id
|
56
60
|
# @return [IP::Addr]
|
57
61
|
define_field :id, IP::Addr
|
@@ -136,6 +140,8 @@ module PacketGen
|
|
136
140
|
# This class handles external links in {LSAASExternal LSA AS-External payloads}.
|
137
141
|
# @author Sylvain Daubert
|
138
142
|
class External < Types::Fields
|
143
|
+
include Types::Fieldable
|
144
|
+
|
139
145
|
# @!attribute u8
|
140
146
|
# @return [Integer]
|
141
147
|
define_field :u8, Types::Int8
|
@@ -223,9 +229,13 @@ module PacketGen
|
|
223
229
|
|
224
230
|
def get_lsa_class_by_human_type(htype)
|
225
231
|
klassname = "LSA#{htype.to_s.delete('-')}"
|
226
|
-
|
227
|
-
OSPFv2.
|
228
|
-
|
232
|
+
begin
|
233
|
+
if OSPFv2.const_defined? klassname
|
234
|
+
OSPFv2.const_get klassname
|
235
|
+
else
|
236
|
+
LSA
|
237
|
+
end
|
238
|
+
rescue NameError
|
229
239
|
LSA
|
230
240
|
end
|
231
241
|
end
|
@@ -29,6 +29,8 @@ module PacketGen
|
|
29
29
|
# is also a base class for different LSA class, as {LSARouter}.
|
30
30
|
# @author Sylvain Daubert
|
31
31
|
class LSAHeader < Types::Fields
|
32
|
+
include Types::Fieldable
|
33
|
+
|
32
34
|
# LSA Types
|
33
35
|
TYPES = {
|
34
36
|
'Router' => 1,
|
@@ -75,7 +77,6 @@ module PacketGen
|
|
75
77
|
# Compute and set Fletcher-16 checksum on LSA
|
76
78
|
# @return [Integer]
|
77
79
|
def calc_checksum
|
78
|
-
self.checksum = 0
|
79
80
|
bytes = to_s[2..-1].unpack('C*')
|
80
81
|
|
81
82
|
c0 = c1 = 0
|
@@ -11,6 +11,8 @@ module PacketGen
|
|
11
11
|
# This class handles links in a {LSARouter OSPFv3 LSA router payload}.
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class Link < Types::Fields
|
14
|
+
include Types::Fieldable
|
15
|
+
|
14
16
|
# @!attribute type
|
15
17
|
# @return [Integer]
|
16
18
|
define_field :type, Types::Int8
|
@@ -216,9 +218,13 @@ module PacketGen
|
|
216
218
|
|
217
219
|
def get_lsa_class_by_human_type(htype)
|
218
220
|
klassname = "LSA#{htype.to_s.delete('-')}"
|
219
|
-
|
220
|
-
OSPFv3.
|
221
|
-
|
221
|
+
begin
|
222
|
+
if OSPFv3.const_defined? klassname
|
223
|
+
OSPFv3.const_get klassname
|
224
|
+
else
|
225
|
+
LSA
|
226
|
+
end
|
227
|
+
rescue NameError
|
222
228
|
LSA
|
223
229
|
end
|
224
230
|
end
|
@@ -29,6 +29,8 @@ module PacketGen
|
|
29
29
|
# But this class is also a base class for different LSA class, as {LSARouter}.
|
30
30
|
# @author Sylvain Daubert
|
31
31
|
class LSAHeader < Types::Fields
|
32
|
+
include Types::Fieldable
|
33
|
+
|
32
34
|
# LSA known types
|
33
35
|
TYPES = {
|
34
36
|
'Router' => 0x2001,
|
@@ -76,7 +78,6 @@ module PacketGen
|
|
76
78
|
# Compute and set Fletcher-16 checksum on LSA
|
77
79
|
# @return [Integer]
|
78
80
|
def calc_checksum
|
79
|
-
self.checksum = 0
|
80
81
|
bytes = to_s[2..-1].unpack('C*')
|
81
82
|
|
82
83
|
c0 = c1 = 0
|
@@ -246,7 +246,8 @@ module PacketGen
|
|
246
246
|
end
|
247
247
|
|
248
248
|
sequence :message,
|
249
|
-
content: [integer(:version,
|
249
|
+
content: [integer(:version,
|
250
|
+
value: 'v2c',
|
250
251
|
enum: { 'v1' => 0, 'v2c' => 1, 'v2' => 2, 'v3' => 3 }),
|
251
252
|
octet_string(:community, value: 'public'),
|
252
253
|
model(:data, PDUs)]
|
@@ -295,7 +296,7 @@ module PacketGen
|
|
295
296
|
begin
|
296
297
|
str << Inspect.inspect_body(self[:message].to_der, 'ASN.1 DER')
|
297
298
|
rescue StandardError => e
|
298
|
-
raise unless e.message
|
299
|
+
raise unless e.message.match?(/TAG.*not handled/)
|
299
300
|
end
|
300
301
|
str
|
301
302
|
end
|
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -121,7 +121,7 @@ module PacketGen
|
|
121
121
|
# @!attribute options
|
122
122
|
# TCP options
|
123
123
|
# @return [Options]
|
124
|
-
define_field :options, TCP::Options
|
124
|
+
define_field :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
|
125
125
|
# @!attribute body
|
126
126
|
# @return [Types::String,Header::Base]
|
127
127
|
define_field :body, Types::String
|
@@ -189,25 +189,6 @@ module PacketGen
|
|
189
189
|
# @return [Boolean] 1-bit FIN flag
|
190
190
|
define_bit_fields_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg,
|
191
191
|
:flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin
|
192
|
-
# Read a TCP header from a string
|
193
|
-
# @param [String] str binary string
|
194
|
-
# @return [self]
|
195
|
-
def read(str)
|
196
|
-
return self if str.nil?
|
197
|
-
|
198
|
-
force_binary str
|
199
|
-
self[:sport].read str[0, 2]
|
200
|
-
self[:dport].read str[2, 2]
|
201
|
-
self[:seqnum].read str[4, 4]
|
202
|
-
self[:acknum].read str[8, 4]
|
203
|
-
self[:u16].read str[12, 2]
|
204
|
-
self[:window].read str[14, 2]
|
205
|
-
self[:checksum].read str[16, 2]
|
206
|
-
self[:urg_pointer].read str[18, 2]
|
207
|
-
self[:options].read str[20, (self.data_offset - 5) * 4] if self.data_offset > 5
|
208
|
-
self[:body].read str[self.data_offset * 4..-1]
|
209
|
-
self
|
210
|
-
end
|
211
192
|
|
212
193
|
# Compute checksum and set +checksum+ field
|
213
194
|
# @return [Integer]
|
@@ -11,6 +11,8 @@ module PacketGen
|
|
11
11
|
# Base class to describe a TCP option
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class Option < Types::Fields
|
14
|
+
include Types::Fieldable
|
15
|
+
|
14
16
|
# EOL option value
|
15
17
|
EOL_KIND = 0
|
16
18
|
# NOP option value
|
@@ -91,15 +93,15 @@ module PacketGen
|
|
91
93
|
# Setter for value attribute
|
92
94
|
# @param[String,Integer]
|
93
95
|
# @return [String, Integer]
|
94
|
-
def value=(
|
96
|
+
def value=(val)
|
95
97
|
case self[:value]
|
96
98
|
when Types::Int
|
97
99
|
self.length = 2 + self[:value].sz
|
98
|
-
when String
|
99
|
-
self.length = 2 + Types::String.new.read(
|
100
|
+
when Types::String
|
101
|
+
self.length = 2 + Types::String.new.read(val).sz
|
100
102
|
end
|
101
|
-
self[:value].read
|
102
|
-
|
103
|
+
self[:value].read val
|
104
|
+
val
|
103
105
|
end
|
104
106
|
|
105
107
|
# Get binary string
|
@@ -112,7 +114,7 @@ module PacketGen
|
|
112
114
|
# Get option as a human readable string
|
113
115
|
# @return [String]
|
114
116
|
def to_human
|
115
|
-
str = self.
|
117
|
+
str = self.instance_of?(Option) ? +"unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
|
116
118
|
str << ":#{self[:value].to_s.inspect}" if (length > 2) && !self[:value].to_s.empty?
|
117
119
|
str
|
118
120
|
end
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -68,23 +68,7 @@ module PacketGen
|
|
68
68
|
# @return [String]
|
69
69
|
def self.inspect_attribute(attr, value, level=1)
|
70
70
|
type = value.class.to_s.sub(/.*::/, '')
|
71
|
-
|
72
|
-
when Types::Enum
|
73
|
-
enum_human_hex(value.to_human, value.to_i, value.sz * 2)
|
74
|
-
when Types::Int
|
75
|
-
int_dec_hex(value, value.sz * 2)
|
76
|
-
when Integer
|
77
|
-
int_dec_hex(value, value.sz * 2)
|
78
|
-
when String
|
79
|
-
value.to_s.inspect
|
80
|
-
else
|
81
|
-
if value.respond_to? :to_human
|
82
|
-
value.to_human
|
83
|
-
else
|
84
|
-
value.to_s.inspect
|
85
|
-
end
|
86
|
-
end
|
87
|
-
self.format(type, attr, val, level)
|
71
|
+
self.format(type, attr, value.format_inspect, level)
|
88
72
|
end
|
89
73
|
|
90
74
|
# Format a ASN.1 attribute for +#inspect+.
|