packetgen 3.1.5 → 3.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/pgconsole +1 -0
- data/lib/packetgen.rb +2 -2
- data/lib/packetgen/capture.rb +9 -0
- data/lib/packetgen/header/base.rb +68 -70
- data/lib/packetgen/header/dhcpv6/duid.rb +3 -1
- data/lib/packetgen/header/dhcpv6/option.rb +3 -1
- data/lib/packetgen/header/dns/name.rb +18 -7
- data/lib/packetgen/header/dns/question.rb +2 -0
- data/lib/packetgen/header/dot11.rb +23 -6
- data/lib/packetgen/header/dot11/data.rb +9 -5
- data/lib/packetgen/header/eap.rb +3 -2
- data/lib/packetgen/header/eth.rb +4 -8
- data/lib/packetgen/header/http/headers.rb +3 -4
- data/lib/packetgen/header/http/request.rb +32 -17
- data/lib/packetgen/header/http/response.rb +1 -1
- 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 +2 -3
- data/lib/packetgen/header/ip/option.rb +4 -4
- data/lib/packetgen/header/ipv6/addr.rb +1 -2
- 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 +6 -0
- 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 +2 -0
- data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -1
- data/lib/packetgen/header/snmp.rb +3 -2
- data/lib/packetgen/header/tcp/option.rb +8 -6
- data/lib/packetgen/packet.rb +7 -3
- 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 +164 -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 +8 -8
- data/lib/packetgen/types.rb +1 -0
- data/lib/packetgen/types/abstract_tlv.rb +2 -3
- data/lib/packetgen/types/array.rb +15 -9
- data/lib/packetgen/types/cstring.rb +38 -17
- data/lib/packetgen/types/fieldable.rb +65 -0
- data/lib/packetgen/types/fields.rb +91 -56
- data/lib/packetgen/types/int.rb +2 -2
- data/lib/packetgen/types/int_string.rb +7 -2
- data/lib/packetgen/types/length_from.rb +18 -10
- data/lib/packetgen/types/oui.rb +1 -2
- data/lib/packetgen/types/string.rb +45 -8
- data/lib/packetgen/types/tlv.rb +1 -2
- data/lib/packetgen/utils.rb +2 -2
- data/lib/packetgen/version.rb +1 -1
- metadata +13 -12
- data/lib/packetgen/inspectable.rb +0 -20
data/lib/packetgen/header/eth.rb
CHANGED
@@ -33,7 +33,7 @@ module PacketGen
|
|
33
33
|
# Ethernet MAC address, as a group of 6 bytes
|
34
34
|
# @author Sylvain Daubert
|
35
35
|
class MacAddr < Types::Fields
|
36
|
-
include
|
36
|
+
include Types::Fieldable
|
37
37
|
|
38
38
|
# @!attribute a0
|
39
39
|
# @return [Integer] first byte from MacAddr
|
@@ -63,12 +63,9 @@ module PacketGen
|
|
63
63
|
bytes = str.split(/:/)
|
64
64
|
raise ArgumentError, 'not a MAC address' unless bytes.size == 6
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
self[:a3].read(bytes[3].to_i(16))
|
70
|
-
self[:a4].read(bytes[4].to_i(16))
|
71
|
-
self[:a5].read(bytes[5].to_i(16))
|
66
|
+
6.times do |i|
|
67
|
+
self["a#{i}".to_sym].read(bytes[i].to_i(16))
|
68
|
+
end
|
72
69
|
self
|
73
70
|
end
|
74
71
|
|
@@ -77,7 +74,6 @@ module PacketGen
|
|
77
74
|
def to_human
|
78
75
|
fields.map { |m| '%02x' % self[m] }.join(':')
|
79
76
|
end
|
80
|
-
alias format_inspect to_human
|
81
77
|
|
82
78
|
def ==(other)
|
83
79
|
other.is_a?(self.class) &&
|
@@ -12,7 +12,7 @@ module PacketGen
|
|
12
12
|
# @abstract Base class for HTTP headers.
|
13
13
|
# @author Kent 'picat' Gruber
|
14
14
|
class Headers
|
15
|
-
include
|
15
|
+
include Types::Fieldable
|
16
16
|
|
17
17
|
# Underlying Headers data (or nil).
|
18
18
|
# @return [Hash, nil]
|
@@ -20,7 +20,7 @@ module PacketGen
|
|
20
20
|
alias to_h data
|
21
21
|
|
22
22
|
def initialize
|
23
|
-
@data =
|
23
|
+
@data = {}
|
24
24
|
end
|
25
25
|
|
26
26
|
# Populate object from a string or directly from a hash.
|
@@ -48,7 +48,7 @@ module PacketGen
|
|
48
48
|
|
49
49
|
d = []
|
50
50
|
@data.map do |k, v|
|
51
|
-
d << k
|
51
|
+
d << "#{k}: #{v}"
|
52
52
|
end
|
53
53
|
d.join("\r\n") << "\r\n\r\n"
|
54
54
|
end
|
@@ -58,7 +58,6 @@ module PacketGen
|
|
58
58
|
def to_human
|
59
59
|
@data
|
60
60
|
end
|
61
|
-
alias format_inspect to_human
|
62
61
|
|
63
62
|
# Read human-readable data to populate header data.
|
64
63
|
# @param [String, Hash] data
|
@@ -67,23 +67,17 @@ module PacketGen
|
|
67
67
|
# Read in the HTTP portion of the packet, and parse it.
|
68
68
|
# @return [PacketGen::HTTP::Request]
|
69
69
|
def read(str)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
self[:path].read first_line[1]
|
77
|
-
self[:version].read first_line[2]
|
70
|
+
lines = lines(str)
|
71
|
+
first_line_words = lines.shift.split
|
72
|
+
self[:verb].read first_line_words[0]
|
73
|
+
self[:path].read first_line_words[1]
|
74
|
+
self[:version].read first_line_words[2]
|
75
|
+
|
78
76
|
# requests can sometimes have a payload
|
79
|
-
|
80
|
-
data = str[data_index + 1..-1].join("\n")
|
81
|
-
headers = str[0..data_index - 1].join("\n")
|
82
|
-
else
|
83
|
-
headers = str.join("\n")
|
84
|
-
end
|
77
|
+
headers, data = headers_and_payload_from_lines(lines)
|
85
78
|
self[:headers].read(headers)
|
86
|
-
self[:body].read
|
79
|
+
self[:body].read(data)
|
80
|
+
|
87
81
|
self
|
88
82
|
end
|
89
83
|
|
@@ -94,8 +88,29 @@ module PacketGen
|
|
94
88
|
raise FormatError, 'Missing #path.' if self.path.empty?
|
95
89
|
raise FormatError, 'Missing #version.' if self.version.empty?
|
96
90
|
|
97
|
-
|
98
|
-
|
91
|
+
"#{self.verb.dup} #{self.path} #{self.version}\r\n#{self[:headers]}#{self.body}"
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# @todo check verb is correct or raise a ParseError
|
97
|
+
def lines(str)
|
98
|
+
str = str.bytes.map!(&:chr).join unless str.valid_encoding?
|
99
|
+
# vrb = HTTP::VERBS.detect { |verb| str.include?(verb) }
|
100
|
+
|
101
|
+
str.split("\r\n").map(&:chomp)
|
102
|
+
end
|
103
|
+
|
104
|
+
def headers_and_payload_from_lines(lines)
|
105
|
+
if (data_index = lines.find_index(''))
|
106
|
+
data = lines[data_index + 1..-1].join("\n")
|
107
|
+
headers = lines[0..data_index - 1].join("\n")
|
108
|
+
else
|
109
|
+
headers = lines.join("\n")
|
110
|
+
data = nil
|
111
|
+
end
|
112
|
+
|
113
|
+
[headers, data]
|
99
114
|
end
|
100
115
|
end
|
101
116
|
end
|
@@ -104,7 +104,7 @@ module PacketGen
|
|
104
104
|
raise FormatError, 'Missing #version.' if self.version.empty?
|
105
105
|
|
106
106
|
str = +''
|
107
|
-
str << self
|
107
|
+
str << self.version << ' ' << self.status_code << ' ' << self.status_mesg << "\r\n"
|
108
108
|
str << self[:headers].to_s if self[:headers].given?
|
109
109
|
str << self.body
|
110
110
|
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,7 +11,7 @@ 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
|
14
|
+
include Types::Fieldable
|
15
15
|
|
16
16
|
# @!attribute a1
|
17
17
|
# @return [Integer] IP address first byte
|
@@ -26,7 +26,7 @@ module PacketGen
|
|
26
26
|
# @return [Integer] IP address fourth byte
|
27
27
|
define_field :a4, Types::Int8
|
28
28
|
|
29
|
-
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
|
30
30
|
|
31
31
|
# Read a dotted address
|
32
32
|
# @param [String] str
|
@@ -49,7 +49,6 @@ module PacketGen
|
|
49
49
|
def to_human
|
50
50
|
fields.map { |f| self[f].to_i.to_s }.join('.')
|
51
51
|
end
|
52
|
-
alias format_inspect to_human
|
53
52
|
|
54
53
|
# Addr as an integer
|
55
54
|
# @return [Integer]
|
@@ -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
|
@@ -14,7 +14,7 @@ module PacketGen
|
|
14
14
|
# IPv6 address, as a group of 8 2-byte words
|
15
15
|
# @author Sylvain Daubert
|
16
16
|
class Addr < Types::Fields
|
17
|
-
include
|
17
|
+
include Types::Fieldable
|
18
18
|
|
19
19
|
# @!attribute a1
|
20
20
|
# 1st 2-byte word of IPv6 address
|
@@ -75,7 +75,6 @@ module PacketGen
|
|
75
75
|
def to_human
|
76
76
|
IPAddr.new(to_a.map { |a| a.to_i.to_s(16) }.join(':')).to_s
|
77
77
|
end
|
78
|
-
alias format_inspect to_human
|
79
78
|
|
80
79
|
# Return an array of address 16-bit words
|
81
80
|
# @return [Array<Integer>]
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|