packetgen 1.3.0 → 1.4.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 +18 -41
- data/lib/packetgen.rb +1 -1
- data/lib/packetgen/header.rb +14 -9
- data/lib/packetgen/header/arp.rb +1 -0
- data/lib/packetgen/header/base.rb +50 -1
- data/lib/packetgen/header/dot11.rb +349 -0
- data/lib/packetgen/header/dot11/control.rb +59 -0
- data/lib/packetgen/header/dot11/data.rb +43 -0
- data/lib/packetgen/header/dot11/element.rb +35 -0
- data/lib/packetgen/header/dot11/management.rb +25 -0
- data/lib/packetgen/header/dot11/sub_mngt.rb +178 -0
- data/lib/packetgen/header/dot1q.rb +42 -0
- data/lib/packetgen/header/dot1x.rb +78 -0
- data/lib/packetgen/header/esp.rb +2 -2
- data/lib/packetgen/header/eth.rb +1 -8
- data/lib/packetgen/header/ip.rb +13 -2
- data/lib/packetgen/header/ipv6.rb +12 -1
- data/lib/packetgen/header/llc.rb +56 -0
- data/lib/packetgen/inspect.rb +1 -1
- data/lib/packetgen/packet.rb +12 -8
- data/lib/packetgen/pcapng.rb +11 -0
- data/lib/packetgen/pcapng/file.rb +5 -2
- data/lib/packetgen/types.rb +1 -0
- data/lib/packetgen/types/fields.rb +80 -10
- data/lib/packetgen/types/int_string.rb +1 -1
- data/lib/packetgen/types/oui.rb +48 -0
- data/lib/packetgen/types/string.rb +9 -4
- data/lib/packetgen/types/tlv.rb +83 -6
- data/lib/packetgen/version.rb +1 -1
- metadata +12 -2
data/lib/packetgen/header/esp.rb
CHANGED
@@ -48,14 +48,14 @@ module PacketGen
|
|
48
48
|
#
|
49
49
|
# # encrypt ESP payload
|
50
50
|
# cipher = OpenSSL::Cipher.new('aes-128-gcm')
|
51
|
-
# cipher.encrypt
|
51
|
+
# cipher.encrypt!
|
52
52
|
# cipher.key = 16bytes_key
|
53
53
|
# iv = 8bytes_iv
|
54
54
|
# esp.esp.encrypt! cipher, iv, salt: 4bytes_gcm_salt
|
55
55
|
#
|
56
56
|
# === Decrypt a ESP packet using CBC mode and HMAC-SHA-256
|
57
57
|
# cipher = OpenSSL::Cipher.new('aes-128-cbc')
|
58
|
-
# cipher.decrypt
|
58
|
+
# cipher.decrypt!
|
59
59
|
# cipher.key = 16bytes_key
|
60
60
|
#
|
61
61
|
# hmac = OpenSSL::HMAC.new(hmac_key, OpenSSL::Digest::SHA256.new)
|
data/lib/packetgen/header/eth.rb
CHANGED
@@ -21,7 +21,7 @@ module PacketGen
|
|
21
21
|
# pkt.eth # => PacketGen::Header::Eth
|
22
22
|
#
|
23
23
|
# == Ethernet attributes
|
24
|
-
# eth.dst = "00:01:02:03:04:05
|
24
|
+
# eth.dst = "00:01:02:03:04:05"
|
25
25
|
# eth.src # => "00:01:01:01:01:01"
|
26
26
|
# eth[:src] # => PacketGen::Header::Eth::MacAddr
|
27
27
|
# eth.ethertype # => 16-bit Integer
|
@@ -77,13 +77,6 @@ module PacketGen
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
# @private snap length for PCAPRUB
|
81
|
-
PCAP_SNAPLEN = 0xffff
|
82
|
-
# @private promiscuous (or not) for PCAPRUB
|
83
|
-
PCAP_PROMISC = false
|
84
|
-
# @private timeout for PCAPRUB
|
85
|
-
PCAP_TIMEOUT = 1
|
86
|
-
|
87
80
|
# @!attribute dst
|
88
81
|
# @return [MacAddr] Destination MAC address
|
89
82
|
define_field :dst, MacAddr, default: '00:00:00:00:00:00'
|
data/lib/packetgen/header/ip.rb
CHANGED
@@ -107,6 +107,9 @@ module PacketGen
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
# IP Ether type
|
111
|
+
ETHERTYPE = 0x0800
|
112
|
+
|
110
113
|
# @!attribute u8
|
111
114
|
# First byte of IP header. May be accessed through {#version} and {#ihl}.
|
112
115
|
# @return [Integer] first byte of IP header.
|
@@ -153,7 +156,7 @@ module PacketGen
|
|
153
156
|
# @!attribute flag_df
|
154
157
|
# @return [Boolean] Don't Fragment flag
|
155
158
|
# @!attribute flag_mf
|
156
|
-
# @return [
|
159
|
+
# @return [Boolean] More Fragment flags
|
157
160
|
# @!attribute fragment_offset
|
158
161
|
# @return [Integer] 13-bit fragment offset
|
159
162
|
define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13
|
@@ -222,11 +225,19 @@ module PacketGen
|
|
222
225
|
end
|
223
226
|
str
|
224
227
|
end
|
228
|
+
|
229
|
+
# Check version field
|
230
|
+
# @see [Base#parse?]
|
231
|
+
def parse?
|
232
|
+
version == 4
|
233
|
+
end
|
225
234
|
end
|
226
235
|
|
227
236
|
self.add_class IP
|
228
237
|
|
229
|
-
Eth.bind_header IP, ethertype:
|
238
|
+
Eth.bind_header IP, ethertype: IP::ETHERTYPE
|
239
|
+
SNAP.bind_header IP, proto_id: IP::ETHERTYPE
|
240
|
+
Dot1q.bind_header IP, ethertype: IP::ETHERTYPE
|
230
241
|
IP.bind_header IP, protocol: 4
|
231
242
|
end
|
232
243
|
end
|
@@ -114,6 +114,9 @@ module PacketGen
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
+
# IPv6 Ether type
|
118
|
+
ETHERTYPE = 0x86dd
|
119
|
+
|
117
120
|
# @!attribute u32
|
118
121
|
# First 32-bit word of IPv6 header
|
119
122
|
# @return [Integer]
|
@@ -212,11 +215,19 @@ module PacketGen
|
|
212
215
|
end
|
213
216
|
str
|
214
217
|
end
|
218
|
+
|
219
|
+
# Check version field
|
220
|
+
# @see [Base#parse?]
|
221
|
+
def parse?
|
222
|
+
version == 6
|
223
|
+
end
|
215
224
|
end
|
216
225
|
|
217
226
|
self.add_class IPv6
|
218
227
|
|
219
|
-
Eth.bind_header IPv6, ethertype:
|
228
|
+
Eth.bind_header IPv6, ethertype: IPv6::ETHERTYPE
|
229
|
+
SNAP.bind_header IPv6, proto_id: IPv6::ETHERTYPE
|
230
|
+
Dot1q.bind_header IPv6, ethertype: IPv6::ETHERTYPE
|
220
231
|
IP.bind_header IPv6, protocol: 41 # 6to4
|
221
232
|
end
|
222
233
|
end
|
@@ -0,0 +1,56 @@
|
|
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
|
+
# Logical-Link Control header
|
11
|
+
#
|
12
|
+
# A LLC header consists of:
|
13
|
+
# * a {#dsap} ({Types::Int8}),
|
14
|
+
# * a {#ssap} ({Types::Int8}),
|
15
|
+
# * a {#control} ({Types::Int8}),
|
16
|
+
# * and a {#body} (a {Types::String} or another {Base} class).
|
17
|
+
# @author Sylvain Daubert
|
18
|
+
class LLC < Base
|
19
|
+
# @!attribute dsap
|
20
|
+
# @return [Integer] 8-bit dsap value
|
21
|
+
define_field :dsap, Types::Int8
|
22
|
+
# @!attribute ssap
|
23
|
+
# @return [Integer] 8-bit ssap value
|
24
|
+
define_field :ssap, Types::Int8
|
25
|
+
# @!attribute control
|
26
|
+
# @return [Integer] 8-bit control value
|
27
|
+
define_field :control, Types::Int8
|
28
|
+
# @!attribute body
|
29
|
+
# @return [Types::String,Header::Base]
|
30
|
+
define_field :body, Types::String
|
31
|
+
end
|
32
|
+
self.add_class LLC
|
33
|
+
Dot11::Data.bind_header LLC, op: :and, type: 2, :wep? => false
|
34
|
+
|
35
|
+
# Sub-Network Access Protocol
|
36
|
+
#
|
37
|
+
# A SNAP header consists of:
|
38
|
+
# * a {#oui} ({Types::OUI}),
|
39
|
+
# * a {#proto_id} ({Types::Int16}),
|
40
|
+
# * and a {#body} (a {Types::String} or another {Base} class).
|
41
|
+
# @author Sylvain Daubert
|
42
|
+
class SNAP < Base
|
43
|
+
# @!attribute oui
|
44
|
+
# @return [Types::OUI]
|
45
|
+
define_field :oui, Types::OUI
|
46
|
+
# @!attribute proto_id
|
47
|
+
# @return [Integer] 16-bit protocol id
|
48
|
+
define_field :proto_id, Types::Int16
|
49
|
+
# @!attribute body
|
50
|
+
# @return [Types::String,Header::Base]
|
51
|
+
define_field :body, Types::String
|
52
|
+
end
|
53
|
+
self.add_class SNAP
|
54
|
+
LLC.bind_header SNAP, op: :and, dsap: 170, ssap: 170, control: 3
|
55
|
+
end
|
56
|
+
end
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -57,7 +57,7 @@ module PacketGen
|
|
57
57
|
# @param [#to_s] body
|
58
58
|
# @return [String]
|
59
59
|
def self.inspect_body(body)
|
60
|
-
return '' if body.nil?
|
60
|
+
return '' if body.nil? or body.empty?
|
61
61
|
str = dashed_line('Body', 2)
|
62
62
|
str << (0..15).to_a.map { |v| " %02d" % v}.join << "\n"
|
63
63
|
str << '-' * INSPECT_MAX_WIDTH << "\n"
|
data/lib/packetgen/packet.rb
CHANGED
@@ -319,11 +319,14 @@ module PacketGen
|
|
319
319
|
if prev_header
|
320
320
|
bindings = prev_header.class.known_headers[header.class]
|
321
321
|
if bindings.nil?
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
322
|
+
bindings = prev_header.class.known_headers[header.class.superclass]
|
323
|
+
if bindings.nil?
|
324
|
+
msg = "#{prev_header.class} knowns no layer association with #{protocol}. "
|
325
|
+
msg << "Try #{prev_header.class}.bind_layer(PacketGen::Header::#{protocol}, "
|
326
|
+
msg << "#{prev_header.protocol_name.downcase}_proto_field: "
|
327
|
+
msg << "value_for_#{protocol.downcase})"
|
328
|
+
raise ArgumentError, msg
|
329
|
+
end
|
327
330
|
end
|
328
331
|
bindings.set(prev_header) if !bindings.empty? and !parsing
|
329
332
|
prev_header[:body] = header
|
@@ -359,8 +362,9 @@ module PacketGen
|
|
359
362
|
last_known_hdr = @headers.last
|
360
363
|
search_header(last_known_hdr) do |nh|
|
361
364
|
str = last_known_hdr.body
|
362
|
-
|
363
|
-
|
365
|
+
nheader = nh.new
|
366
|
+
nheader = nheader.read(str)
|
367
|
+
add_header nheader, parsing: true
|
364
368
|
end
|
365
369
|
decode_packet_bottom_up = (@headers.last != last_known_hdr)
|
366
370
|
end
|
@@ -368,7 +372,7 @@ module PacketGen
|
|
368
372
|
|
369
373
|
def search_header(hdr)
|
370
374
|
hdr.class.known_headers.each do |nh, bindings|
|
371
|
-
if bindings.check?(hdr)
|
375
|
+
if bindings.check?(hdr) and hdr.parse?
|
372
376
|
yield nh
|
373
377
|
break
|
374
378
|
end
|
data/lib/packetgen/pcapng.rb
CHANGED
@@ -21,6 +21,17 @@ module PacketGen
|
|
21
21
|
|
22
22
|
# IEEE 802.3 Ethernet (10Mb, 100Mb, 1000Mb, and up)
|
23
23
|
LINKTYPE_ETHERNET = 1
|
24
|
+
# Raw IP; the packet begins with an IPv4 or IPv6 header, with the "version"
|
25
|
+
# field of the header indicating whether it's an IPv4 or IPv6 header.
|
26
|
+
LINKTYPE_RAW = 101
|
27
|
+
# IEEE 802.11 wireless LAN
|
28
|
+
LINKTYPE_IEEE802_11 = 105
|
29
|
+
# RadioTap link layer informations + IEEE 802.11 wireless LAN
|
30
|
+
LINKTYPE_IEEE802_11_RADIOTAP = 127
|
31
|
+
# Per-Packet Information information, as specified by the Per-Packet Information
|
32
|
+
# Header Specification, followed by a packet with the LINKTYPE_ value specified
|
33
|
+
# by the +pph_dlt+ field of that header.
|
34
|
+
LINKTYPE_PPI = 192
|
24
35
|
# Raw IPv4; the packet begins with an IPv4 header.
|
25
36
|
LINKTYPE_IPV4 = 228
|
26
37
|
# Raw IPv6; the packet begins with an IPv6 header.
|
@@ -12,9 +12,12 @@ module PacketGen
|
|
12
12
|
# Known link types
|
13
13
|
KNOWN_LINK_TYPES = {
|
14
14
|
LINKTYPE_ETHERNET => 'Eth',
|
15
|
+
LINKTYPE_IEEE802_11 => 'Dot11',
|
16
|
+
LINKTYPE_IEEE802_11_RADIOTAP => 'RadioTap',
|
17
|
+
LINKTYPE_PPI => 'PPI',
|
15
18
|
LINKTYPE_IPV4 => 'IP',
|
16
19
|
LINKTYPE_IPV6 => 'IPv6'
|
17
|
-
}
|
20
|
+
}.freeze
|
18
21
|
|
19
22
|
# Get file sections
|
20
23
|
# @return [Array]
|
@@ -74,7 +77,7 @@ module PacketGen
|
|
74
77
|
end
|
75
78
|
end
|
76
79
|
|
77
|
-
# Give an array of
|
80
|
+
# Give an array of raw packets (raw data from packets).
|
78
81
|
# If a block is given, yield raw packet data from the given file.
|
79
82
|
# @overload read_packet_bytes(fname)
|
80
83
|
# @param [String] fname pcapng file name
|
data/lib/packetgen/types.rb
CHANGED
@@ -6,8 +6,84 @@
|
|
6
6
|
module PacketGen
|
7
7
|
module Types
|
8
8
|
|
9
|
-
# @abstract
|
10
|
-
#
|
9
|
+
# @abstract Set of fields
|
10
|
+
# This class is a base class to define headers or anything else with a binary
|
11
|
+
# format containing multiple fields.
|
12
|
+
#
|
13
|
+
# == Basics
|
14
|
+
# A {Fields} subclass is generaly composed of multiple binary fields. These fields
|
15
|
+
# have each a given type. All types from {Types} module are supported, and all
|
16
|
+
# {Fields} subclasses may also be used as field type.
|
17
|
+
#
|
18
|
+
# To define a new subclass, it has to inherit from {Fields}. And some class
|
19
|
+
# methods have to be used to declare attributes/fields:
|
20
|
+
# class MyBinaryStructure < PacketGen::Types::Fields
|
21
|
+
# # define a first Int8 attribute, with default value: 1
|
22
|
+
# define_field :attr1, PacketGen::Types::Int8, default: 1
|
23
|
+
# #define a second attribute, of kind Int32
|
24
|
+
# define_field :attr2, PacketGen::Types::Int32
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# These defintions create 4 methods: +#attr1+, +#attr1=+, +#attr2+ and +#attr2=+.
|
28
|
+
# All these methods take and/or return Integers.
|
29
|
+
#
|
30
|
+
# Fields may also be accessed through {#[]} ans {#[]=}. These methods give access
|
31
|
+
# to type object:
|
32
|
+
# mybs = MyBinaryStructure.new
|
33
|
+
# mybs.attr1 # => Integer
|
34
|
+
# mybs[:attr1] # => PacketGen::Types::Int8
|
35
|
+
#
|
36
|
+
# {#initialize} accepts an option hash to populate attributes. Keys are attribute
|
37
|
+
# name symbols, and values are those expected by writer accessor.
|
38
|
+
#
|
39
|
+
# {#read} is able to populate object from a binary string.
|
40
|
+
#
|
41
|
+
# {#to_s} returns binary string from object.
|
42
|
+
#
|
43
|
+
# == Add Fields
|
44
|
+
# {.define_field} adds a field to Fields subclass. A lot of field types may be
|
45
|
+
# defined: integer types, string types (to handle a stream of bytes). More
|
46
|
+
# complex field types may be defined using others Fields subclasses:
|
47
|
+
# # define a 16-bit little-endian integer field, named type
|
48
|
+
# define_field :type, PacketGen::Types::Int16le
|
49
|
+
# # define a string field
|
50
|
+
# define_field :body, PacketGen::Types::String
|
51
|
+
# # define afield using a complex type (Fields subclass)
|
52
|
+
# define_field :mac_addr, PacketGen::Eth::MacAddr
|
53
|
+
#
|
54
|
+
# This example creates six methods on our Fields subclass: +#type+, +#type=+,
|
55
|
+
# +#body+, +#body=+, +#mac_addr+ and +#mac_addr=+.
|
56
|
+
#
|
57
|
+
# {.define_field} has many options (third optional Hash argument):
|
58
|
+
# * +:default+ gives default field value. It may be a simple value (an Integer
|
59
|
+
# for an Int field, for example) or a lambda,
|
60
|
+
# * +:builder+ to give a builder/constructor lambda to create field. The lambda
|
61
|
+
# takes one argument: {Fields} subclass object owning field.
|
62
|
+
# For example:
|
63
|
+
# # 32-bit integer field defaulting to 1
|
64
|
+
# define_field :type, PacketGen::Types::Int32, default: 1
|
65
|
+
# # 16-bit integer field, created with a random value. Each instance of this
|
66
|
+
# # object will have a different value.
|
67
|
+
# define_field :id, PacketGen::Types::Int16, default: ->{ rand(65535) }
|
68
|
+
# # a size field
|
69
|
+
# define_field :body_size, PacketGen::Type::Int16
|
70
|
+
# # String field which length is taken from body_size field
|
71
|
+
# define_field :body, PacketGen::Type::String, builder: ->(obj) { PacketGen::Type::String.new('', length_from: obj[:body_size]) }
|
72
|
+
#
|
73
|
+
# {.define_field_before} and {.define_field_after} are also defined to relatively
|
74
|
+
# create a field from anoher one (for example, when adding a field in a subclass).
|
75
|
+
# == Generating bit fields
|
76
|
+
# {.define_bit_fields_on} creates a bit field on a previuously declared integer
|
77
|
+
# field. For example, +frag+ field in IP header:
|
78
|
+
# define_field :frag, Types::Int16, default: 0
|
79
|
+
# define_bit_fields_on :frag, :flag_rsv, :flag_df, :flag_mf, :fragment_offset, 13
|
80
|
+
#
|
81
|
+
# This example generates methods:
|
82
|
+
# * +#frag+ and +#frag=+ to access +frag+ field as a 16-bit integer,
|
83
|
+
# * +#flag_rsv?+, +#flag_rsv=+, +#flag_df?+, +#flag_df=+, +#flag_mf?+ and +#flag_mf=+
|
84
|
+
# to access Boolean RSV, MF and DF flags from +frag+ field,
|
85
|
+
# * +#fragment_offset+ and +#fragment_offset=+ to access 13-bit integer fragment
|
86
|
+
# offset subfield from +frag+ field.
|
11
87
|
# @author Sylvain Daubert
|
12
88
|
class Fields
|
13
89
|
|
@@ -187,7 +263,7 @@ module PacketGen
|
|
187
263
|
|
188
264
|
# Create a new header object
|
189
265
|
# @param [Hash] options Keys are symbols. They should have name of object
|
190
|
-
# attributes, as defined by {.define_field} and by {.
|
266
|
+
# attributes, as defined by {.define_field} and by {.define_bit_fields_on}.
|
191
267
|
def initialize(options={})
|
192
268
|
@fields = {}
|
193
269
|
self.class.class_eval { @field_defs }.each do |field, ary|
|
@@ -235,12 +311,6 @@ module PacketGen
|
|
235
311
|
@ordered_fields ||= self.class.class_eval { @ordered_fields }
|
236
312
|
end
|
237
313
|
|
238
|
-
# Return header protocol name
|
239
|
-
# @return [String]
|
240
|
-
def protocol_name
|
241
|
-
self.class.to_s.sub(/.*::/, '')
|
242
|
-
end
|
243
|
-
|
244
314
|
# Populate object from a binary string
|
245
315
|
# @param [String] str
|
246
316
|
# @return [Fields] self
|
@@ -283,7 +353,7 @@ module PacketGen
|
|
283
353
|
fields.map { |f| force_binary @fields[f].to_s }.join
|
284
354
|
end
|
285
355
|
|
286
|
-
# Size of object as binary
|
356
|
+
# Size of object as binary string
|
287
357
|
# @return [nteger]
|
288
358
|
def sz
|
289
359
|
to_s.size
|
@@ -0,0 +1,48 @@
|
|
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 Types
|
9
|
+
|
10
|
+
# OUI type, defined as a set of 3 bytes
|
11
|
+
# oui = OUI.new
|
12
|
+
# oui.from_human('00:01:02')
|
13
|
+
# oui.to_human # => "00:01:02"
|
14
|
+
#@author Sylvain Daubert
|
15
|
+
class OUI < Types::Fields
|
16
|
+
# @attribute b2
|
17
|
+
# @return [Integer] left-most byte
|
18
|
+
define_field :b2, Types::Int8
|
19
|
+
# @attribute b1
|
20
|
+
# @return [Integer] center byte
|
21
|
+
define_field :b1, Types::Int8
|
22
|
+
# @attribute b0
|
23
|
+
# @return [Integer] right-most byte
|
24
|
+
define_field :b0, Types::Int8
|
25
|
+
|
26
|
+
# Read a human-readable string to populate object
|
27
|
+
# @param [String] str
|
28
|
+
# @return [OUI] self
|
29
|
+
def from_human(str)
|
30
|
+
return self if str.nil?
|
31
|
+
bytes = str.split(/:/)
|
32
|
+
unless bytes.size == 3
|
33
|
+
raise ArgumentError, 'not a OUI'
|
34
|
+
end
|
35
|
+
self[:b2].read(bytes[0].to_i(16))
|
36
|
+
self[:b1].read(bytes[1].to_i(16))
|
37
|
+
self[:b0].read(bytes[2].to_i(16))
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get OUI in human readable form (colon-separated bytes)
|
42
|
+
# @return [String]
|
43
|
+
def to_human
|
44
|
+
fields.map { |m| "#{'%02x' % self[m]}" }.join(':')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -7,15 +7,15 @@
|
|
7
7
|
module PacketGen
|
8
8
|
module Types
|
9
9
|
|
10
|
-
# This class is just like regular String. It only adds #read and #sz methods
|
10
|
+
# This class is just like regular String. It only adds {#read} and {#sz} methods
|
11
11
|
# to be compatible with others {Types}.
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class String < ::String
|
14
14
|
|
15
15
|
# @param [String] str
|
16
16
|
# @param [Hash] options
|
17
|
-
# @option options [Types::Int] :length_from object from which
|
18
|
-
# reading
|
17
|
+
# @option options [Types::Int,Proc] :length_from object or proc from which
|
18
|
+
# takes length when reading
|
19
19
|
def initialize(str='', options={})
|
20
20
|
super(str)
|
21
21
|
@length_from = options[:length_from]
|
@@ -25,7 +25,12 @@ module PacketGen
|
|
25
25
|
# @return [String] self
|
26
26
|
def read(str)
|
27
27
|
s = str.to_s
|
28
|
-
s =
|
28
|
+
s = case @length_from
|
29
|
+
when Int
|
30
|
+
s[0, @length_from.to_i]
|
31
|
+
else
|
32
|
+
s
|
33
|
+
end
|
29
34
|
self.replace s
|
30
35
|
self
|
31
36
|
end
|