packetgen 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|