packetgen 3.1.5 → 3.1.6
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/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
|