packetgen 3.3.3 → 4.1.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 +38 -22
- data/lib/packetgen/capture.rb +2 -2
- data/lib/packetgen/config.rb +0 -1
- data/lib/packetgen/deprecation.rb +14 -8
- data/lib/packetgen/header/arp.rb +17 -18
- data/lib/packetgen/header/asn1_base.rb +2 -1
- data/lib/packetgen/header/base.rb +42 -40
- data/lib/packetgen/header/bootp.rb +35 -37
- data/lib/packetgen/header/dhcp/option.rb +21 -21
- data/lib/packetgen/header/dhcp/options.rb +3 -3
- data/lib/packetgen/header/dhcp.rb +8 -9
- data/lib/packetgen/header/dhcpv6/duid.rb +16 -16
- data/lib/packetgen/header/dhcpv6/option.rb +83 -61
- data/lib/packetgen/header/dhcpv6/options.rb +4 -4
- data/lib/packetgen/header/dhcpv6/relay.rb +6 -5
- data/lib/packetgen/header/dhcpv6.rb +17 -18
- data/lib/packetgen/header/dns/name.rb +21 -16
- data/lib/packetgen/header/dns/opt.rb +5 -2
- data/lib/packetgen/header/dns/option.rb +14 -14
- data/lib/packetgen/header/dns/qdsection.rb +3 -3
- data/lib/packetgen/header/dns/question.rb +7 -8
- data/lib/packetgen/header/dns/rr.rb +56 -43
- data/lib/packetgen/header/dns/rrsection.rb +6 -6
- data/lib/packetgen/header/dns.rb +103 -90
- data/lib/packetgen/header/dot11/control.rb +12 -12
- data/lib/packetgen/header/dot11/data.rb +25 -24
- data/lib/packetgen/header/dot11/element.rb +4 -4
- data/lib/packetgen/header/dot11/management.rb +21 -18
- data/lib/packetgen/header/dot11/sub_mngt.rb +40 -53
- data/lib/packetgen/header/dot11.rb +117 -122
- data/lib/packetgen/header/dot1q.rb +12 -13
- data/lib/packetgen/header/dot1x.rb +13 -13
- data/lib/packetgen/header/eap/fast.rb +4 -4
- data/lib/packetgen/header/eap/md5.rb +16 -8
- data/lib/packetgen/header/eap/tls.rb +18 -19
- data/lib/packetgen/header/eap/ttls.rb +22 -21
- data/lib/packetgen/header/eap.rb +73 -48
- data/lib/packetgen/header/eth.rb +41 -27
- data/lib/packetgen/header/gre.rb +33 -11
- data/lib/packetgen/header/http/headers.rb +7 -6
- data/lib/packetgen/header/http/request.rb +38 -29
- data/lib/packetgen/header/http/response.rb +35 -27
- data/lib/packetgen/header/http/verbs.rb +1 -3
- data/lib/packetgen/header/icmp.rb +14 -14
- data/lib/packetgen/header/icmpv6.rb +10 -9
- data/lib/packetgen/header/igmp.rb +26 -15
- data/lib/packetgen/header/igmpv3/group_record.rb +18 -13
- data/lib/packetgen/header/igmpv3/mq.rb +16 -18
- data/lib/packetgen/header/igmpv3/mr.rb +5 -5
- data/lib/packetgen/header/igmpv3.rb +12 -11
- data/lib/packetgen/header/ip/addr.rb +19 -15
- data/lib/packetgen/header/ip/option.rb +47 -36
- data/lib/packetgen/header/ip/options.rb +1 -1
- data/lib/packetgen/header/ip.rb +77 -95
- data/lib/packetgen/header/ipv6/addr.rb +28 -27
- data/lib/packetgen/header/ipv6/extension.rb +13 -11
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +32 -13
- data/lib/packetgen/header/ipv6.rb +42 -35
- data/lib/packetgen/header/llc.rb +28 -21
- data/lib/packetgen/header/mdns.rb +10 -3
- data/lib/packetgen/header/mld.rb +15 -13
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +17 -12
- data/lib/packetgen/header/mldv2/mlq.rb +22 -24
- data/lib/packetgen/header/mldv2/mlr.rb +8 -8
- data/lib/packetgen/header/mldv2.rb +1 -1
- data/lib/packetgen/header/ospfv2/db_description.rb +17 -18
- data/lib/packetgen/header/ospfv2/hello.rb +18 -17
- data/lib/packetgen/header/ospfv2/ls_ack.rb +6 -7
- data/lib/packetgen/header/ospfv2/ls_request.rb +14 -13
- data/lib/packetgen/header/ospfv2/ls_update.rb +9 -9
- data/lib/packetgen/header/ospfv2/lsa.rb +79 -60
- data/lib/packetgen/header/ospfv2/lsa_header.rb +12 -11
- data/lib/packetgen/header/ospfv2.rb +49 -46
- data/lib/packetgen/header/ospfv3/db_description.rb +20 -22
- data/lib/packetgen/header/ospfv3/hello.rb +17 -16
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +22 -20
- data/lib/packetgen/header/ospfv3/ls_ack.rb +7 -8
- data/lib/packetgen/header/ospfv3/ls_request.rb +18 -18
- data/lib/packetgen/header/ospfv3/ls_update.rb +10 -10
- data/lib/packetgen/header/ospfv3/lsa.rb +62 -51
- data/lib/packetgen/header/ospfv3/lsa_header.rb +12 -11
- data/lib/packetgen/header/ospfv3.rb +54 -52
- data/lib/packetgen/header/sctp/chunk.rb +80 -56
- data/lib/packetgen/header/sctp/error.rb +174 -202
- data/lib/packetgen/header/sctp/padded32.rb +3 -3
- data/lib/packetgen/header/sctp/parameter.rb +89 -136
- data/lib/packetgen/header/sctp.rb +19 -8
- data/lib/packetgen/header/snmp.rb +108 -7
- data/lib/packetgen/header/tcp/option.rb +52 -39
- data/lib/packetgen/header/tcp/options.rb +13 -5
- data/lib/packetgen/header/tcp.rb +83 -65
- data/lib/packetgen/header/tftp.rb +31 -25
- data/lib/packetgen/header/udp.rb +21 -19
- data/lib/packetgen/header.rb +23 -18
- data/lib/packetgen/headerable.rb +21 -5
- data/lib/packetgen/inspect.rb +3 -8
- data/lib/packetgen/packet.rb +146 -71
- data/lib/packetgen/pcap.rb +15 -4
- data/lib/packetgen/pcapng/block.rb +20 -18
- data/lib/packetgen/pcapng/epb.rb +13 -15
- data/lib/packetgen/pcapng/file.rb +44 -111
- data/lib/packetgen/pcapng/idb.rb +11 -12
- data/lib/packetgen/pcapng/shb.rb +15 -16
- data/lib/packetgen/pcapng/spb.rb +9 -11
- data/lib/packetgen/pcapng/unknown_block.rb +6 -17
- data/lib/packetgen/pcapng.rb +6 -4
- data/lib/packetgen/pcaprub_wrapper.rb +17 -1
- data/lib/packetgen/proto.rb +5 -1
- data/lib/packetgen/unknown_packet.rb +5 -5
- data/lib/packetgen/utils/arp_spoofer.rb +18 -19
- data/lib/packetgen/utils.rb +4 -3
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +12 -5
- metadata +29 -38
- data/lib/packetgen/types/abstract_tlv.rb +0 -278
- data/lib/packetgen/types/array.rb +0 -287
- data/lib/packetgen/types/cstring.rb +0 -109
- data/lib/packetgen/types/enum.rb +0 -171
- data/lib/packetgen/types/fieldable.rb +0 -66
- data/lib/packetgen/types/fields.rb +0 -622
- data/lib/packetgen/types/int.rb +0 -473
- data/lib/packetgen/types/int_string.rb +0 -102
- data/lib/packetgen/types/length_from.rb +0 -54
- data/lib/packetgen/types/oui.rb +0 -52
- data/lib/packetgen/types/string.rb +0 -97
- data/lib/packetgen/types/tlv.rb +0 -161
- data/lib/packetgen/types.rb +0 -26
@@ -1,278 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# This file is part of PacketGen
|
5
|
-
# See https://github.com/lemontree55/packetgen for more informations
|
6
|
-
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
7
|
-
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
8
|
-
# This program is published under MIT license.
|
9
|
-
|
10
|
-
module PacketGen
|
11
|
-
module Types
|
12
|
-
# This class is an abstract class to define type-length-value data.
|
13
|
-
#
|
14
|
-
# This class supersedes {TLV} class, which is not well defined on some corner
|
15
|
-
# cases.
|
16
|
-
#
|
17
|
-
# ===Usage
|
18
|
-
# To simply define a new TLV class, do:
|
19
|
-
# MyTLV = PacketGen::Types::AbstractTLV.create
|
20
|
-
# MyTLV.define_type_enum 'one' => 1, 'two' => 2
|
21
|
-
# This will define a new +MyTLV+ class, subclass of {Fields}. This class will
|
22
|
-
# define 3 fields:
|
23
|
-
# * +#type+, as a {Int8Enum} by default,
|
24
|
-
# * +#length+, as a {Int8} by default,
|
25
|
-
# * and +#value+, as a {String} by default.
|
26
|
-
# +.define_type_enum+ is, here, necessary to define enum hash to be used
|
27
|
-
# for +#type+ accessor, as this one is defined as an {Enum}.
|
28
|
-
#
|
29
|
-
# This class may then be used as older {TLV} class:
|
30
|
-
# tlv = MyTLV.new(type: 1, value: 'abcd') # automagically set #length from value
|
31
|
-
# tlv.type #=> 1
|
32
|
-
# tlv.human_type #=> 'one'
|
33
|
-
# tlv.length #=> 4
|
34
|
-
# tlv.value #=> "abcd"
|
35
|
-
#
|
36
|
-
# ===Advanced usage
|
37
|
-
# Each field's type may be changed at generating TLV class:
|
38
|
-
# MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
|
39
|
-
# length_class: PacketGen::Types::Int16,
|
40
|
-
# value_class: PacketGen::Header::IP::Addr)
|
41
|
-
# tlv = MyTLV.new(type: 1, value: '1.2.3.4')
|
42
|
-
# tlv.type #=> 1
|
43
|
-
# tlv.length #=> 4
|
44
|
-
# tlv.value #=> '1.2.3.4'
|
45
|
-
# tlv.to_s #=> "\x00\x01\x00\x04\x01\x02\x03\x04"
|
46
|
-
#
|
47
|
-
# Some aliases may also be defined. For example, to create a TLV type
|
48
|
-
# whose +type+ field should be named +code+:
|
49
|
-
# MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
|
50
|
-
# length_class: PacketGen::Types::Int16,
|
51
|
-
# aliases: { code: :type })
|
52
|
-
# tlv = MyTLV.new(code: 1, value: 'abcd')
|
53
|
-
# tlv.code #=> 1
|
54
|
-
# tlv.type #=> 1
|
55
|
-
# tlv.length #=> 4
|
56
|
-
# tlv.value #=> 'abcd'
|
57
|
-
#
|
58
|
-
# @author Sylvain Daubert
|
59
|
-
# @since 3.1.0
|
60
|
-
# @since 3.1.1 add +:aliases+ keyword to {#initialize}
|
61
|
-
class AbstractTLV < Types::Fields
|
62
|
-
include Fieldable
|
63
|
-
|
64
|
-
# @private
|
65
|
-
FIELD_TYPES = { 'T' => :type, 'L' => :length, 'V' => :value }.freeze
|
66
|
-
|
67
|
-
class << self
|
68
|
-
# @return [Hash]
|
69
|
-
attr_accessor :aliases
|
70
|
-
# @deprecated
|
71
|
-
attr_accessor :header_in_length
|
72
|
-
# @private
|
73
|
-
attr_accessor :field_in_length
|
74
|
-
|
75
|
-
# rubocop:disable Metrics/ParameterLists
|
76
|
-
|
77
|
-
# Generate a TLV class
|
78
|
-
# @param [Class] type_class Class to use for +type+
|
79
|
-
# @param [Class] length_class Class to use for +length+
|
80
|
-
# @param [Class] value_class Class to use for +value+
|
81
|
-
# @param [Boolean] header_in_length if +true +, +type+ and +length+ fields are
|
82
|
-
# included in length. Deprecated, use +field_in_length+ instead.
|
83
|
-
# @param [String] field_order give field order. Each character in [T,L,V] MUST be present once, in the desired order.
|
84
|
-
# @param [String] field_in_length give fields to compute length on.
|
85
|
-
# @return [Class]
|
86
|
-
# @since 3.1.4 Add +header_in_length+ parameter
|
87
|
-
# @since 3.3.1 Add +field_order+ and +field_in_length' parameters. Deprecate +header_in_length+ parameter.
|
88
|
-
def create(type_class: Int8Enum, length_class: Int8, value_class: String,
|
89
|
-
aliases: {}, header_in_length: false, field_order: 'TLV', field_in_length: 'V')
|
90
|
-
Deprecation.deprecated_option(self, 'create', 'header_in_length', klass_method: true) if header_in_length
|
91
|
-
raise Error, '.create cannot be called on a subclass of PacketGen::Types::AbstractTLV' unless self.equal?(AbstractTLV)
|
92
|
-
|
93
|
-
klass = Class.new(self)
|
94
|
-
klass.aliases = aliases
|
95
|
-
klass.header_in_length = header_in_length
|
96
|
-
klass.field_in_length = field_in_length
|
97
|
-
|
98
|
-
check_field_in_length(field_in_length)
|
99
|
-
check_field_order(field_order)
|
100
|
-
generate_fields(klass, field_order, type_class, length_class, value_class)
|
101
|
-
|
102
|
-
aliases.each do |al, orig|
|
103
|
-
klass.instance_eval do
|
104
|
-
alias_method al, orig if klass.method_defined?(orig)
|
105
|
-
alias_method :"#{al}=", :"#{orig}=" if klass.method_defined?(:"#{orig}=")
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
klass
|
110
|
-
end
|
111
|
-
# rubocop:enable Metrics/ParameterLists
|
112
|
-
|
113
|
-
# @!attribute type
|
114
|
-
# @abstract Type attribute for real TLV class
|
115
|
-
# @return [Integer]
|
116
|
-
# @!attribute length
|
117
|
-
# @abstract Length attribute for real TLV class
|
118
|
-
# @return [Integer]
|
119
|
-
# @!attribute value
|
120
|
-
# @abstract Value attribute for real TLV class
|
121
|
-
# @return [Object]
|
122
|
-
|
123
|
-
# @abstract Should only be called on real TLV classes, created by {.create}.
|
124
|
-
# Set enum hash for {#type} field.
|
125
|
-
# @param [Hash{String, Symbol => Integer}] hsh enum hash
|
126
|
-
# @return [void]
|
127
|
-
def define_type_enum(hsh)
|
128
|
-
field_defs[:type][:enum].clear
|
129
|
-
field_defs[:type][:enum].merge!(hsh)
|
130
|
-
end
|
131
|
-
|
132
|
-
# @abstract Should only be called on real TLV classes, created by {.create}.
|
133
|
-
# Set default value for {#type} field.
|
134
|
-
# @param [Integer,String,Symbol,nil] default default value from +hsh+ for type
|
135
|
-
# @return [void]
|
136
|
-
# @since 3.4.0
|
137
|
-
def define_type_default(default)
|
138
|
-
field_defs[:type][:default] = default
|
139
|
-
end
|
140
|
-
|
141
|
-
private
|
142
|
-
|
143
|
-
def check_field_in_length(field_in_length)
|
144
|
-
return if /^[TLV]{1,3}$/.match?(field_in_length)
|
145
|
-
|
146
|
-
raise 'field_in_length must only contain T, L and/or V characters'
|
147
|
-
end
|
148
|
-
|
149
|
-
def check_field_order(field_order)
|
150
|
-
return if field_order.match(/^[TLV]{3,3}$/) && (field_order[0] != field_order[1]) && (field_order[0] != field_order[2]) && (field_order[1] != field_order[2])
|
151
|
-
|
152
|
-
raise 'field_order must contain all three letters TLV, each once'
|
153
|
-
end
|
154
|
-
|
155
|
-
def generate_fields(klass, field_order, type_class, length_class, value_class)
|
156
|
-
field_order.each_char do |field_type|
|
157
|
-
case field_type
|
158
|
-
when 'T'
|
159
|
-
if type_class < Enum
|
160
|
-
klass.define_field(:type, type_class, enum: {})
|
161
|
-
else
|
162
|
-
klass.define_field(:type, type_class)
|
163
|
-
end
|
164
|
-
when 'L'
|
165
|
-
klass.define_field(:length, length_class)
|
166
|
-
when 'V'
|
167
|
-
klass.define_field(:value, value_class)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# @!attribute type
|
174
|
-
# @abstract Type attribute
|
175
|
-
# @return [Integer]
|
176
|
-
# @!attribute length
|
177
|
-
# @abstract Length
|
178
|
-
# @return [Integer]
|
179
|
-
# @!attribute value
|
180
|
-
# @abstract Value attribute
|
181
|
-
# @return [Object]
|
182
|
-
|
183
|
-
# @abstract Should only be called on real TLV classes, created by {.create}.
|
184
|
-
# @param [Hash] options
|
185
|
-
# @option options [Integer] :type
|
186
|
-
# @option options [Integer] :length
|
187
|
-
# @option options [Object] :value
|
188
|
-
def initialize(options={})
|
189
|
-
@header_in_length = self.class.header_in_length
|
190
|
-
@field_in_length = self.class.field_in_length
|
191
|
-
self.class.aliases.each do |al, orig|
|
192
|
-
options[orig] = options[al] if options.key?(al)
|
193
|
-
end
|
194
|
-
|
195
|
-
super
|
196
|
-
# used #value= defined below, which set length if needed
|
197
|
-
self.value = options[:value] if options[:value]
|
198
|
-
calc_length unless options.key?(:length)
|
199
|
-
end
|
200
|
-
|
201
|
-
# @abstract Should only be called on real TLV class instances.
|
202
|
-
# Populate object from a binary string
|
203
|
-
# @param [String,nil] str
|
204
|
-
# @return [Fields] self
|
205
|
-
def read(str)
|
206
|
-
return self if str.nil?
|
207
|
-
|
208
|
-
idx = 0
|
209
|
-
fields.each do |field_name|
|
210
|
-
field = self[field_name]
|
211
|
-
length = field_name == :value ? real_length : field.sz
|
212
|
-
field.read(str[idx, length])
|
213
|
-
idx += field.sz
|
214
|
-
end
|
215
|
-
|
216
|
-
self
|
217
|
-
end
|
218
|
-
|
219
|
-
# @abstract Should only be called on real TLV class instances.
|
220
|
-
# Set +value+. May set +length+ if value is a {Types::String}.
|
221
|
-
# @param [Object] val
|
222
|
-
# @return [Object]
|
223
|
-
# @since 3.4.0 Base on field's +#from_human+ method
|
224
|
-
def value=(val)
|
225
|
-
if val.is_a?(self[:value].class)
|
226
|
-
self[:value] = val
|
227
|
-
elsif self[:value].respond_to?(:from_human)
|
228
|
-
self[:value].from_human(val)
|
229
|
-
else
|
230
|
-
self[:value].read(val)
|
231
|
-
end
|
232
|
-
calc_length
|
233
|
-
val
|
234
|
-
end
|
235
|
-
|
236
|
-
# @abstract Should only be called on real TLV class instances.
|
237
|
-
# Get human-readable type
|
238
|
-
# @return [String]
|
239
|
-
def human_type
|
240
|
-
self[:type].to_human.to_s
|
241
|
-
end
|
242
|
-
|
243
|
-
# @abstract Should only be called on real TLV class instances.
|
244
|
-
# @return [String]
|
245
|
-
def to_human
|
246
|
-
my_value = self[:value].is_a?(String) ? self[:value].inspect : self[:value].to_human
|
247
|
-
'type:%s,length:%u,value:%s' % [human_type, length, my_value]
|
248
|
-
end
|
249
|
-
|
250
|
-
# Calculate length
|
251
|
-
# @return [void]
|
252
|
-
# @since 3.4.0
|
253
|
-
def calc_length
|
254
|
-
fil = @field_in_length
|
255
|
-
fil = 'TLV' if @header_in_length
|
256
|
-
|
257
|
-
length = 0
|
258
|
-
fil.each_char do |field_type|
|
259
|
-
length += self[FIELD_TYPES[field_type]].sz
|
260
|
-
end
|
261
|
-
self.length = length
|
262
|
-
end
|
263
|
-
|
264
|
-
private
|
265
|
-
|
266
|
-
def real_length
|
267
|
-
if @header_in_length
|
268
|
-
self.length - self[:type].sz - self[:length].sz
|
269
|
-
else
|
270
|
-
length = self.length
|
271
|
-
length -= self[:type].sz if @field_in_length.include?('T')
|
272
|
-
length -= self[:length].sz if @field_in_length.include?('L')
|
273
|
-
length
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
@@ -1,287 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# This file is part of PacketGen
|
4
|
-
# See https://github.com/lemontree55/packetgen for more informations
|
5
|
-
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
6
|
-
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
7
|
-
# This program is published under MIT license.
|
8
|
-
|
9
|
-
require 'forwardable'
|
10
|
-
|
11
|
-
module PacketGen
|
12
|
-
module Types
|
13
|
-
# @abstract Base class to define set of {Fields} subclasses.
|
14
|
-
# == #record_from_hash
|
15
|
-
# Subclasses should define private method +#record_from_hash+. This method
|
16
|
-
# is called by {#push} to add an object to the set.
|
17
|
-
#
|
18
|
-
# A default method is defined by {Array}: it calls constructor of class defined
|
19
|
-
# by {.set_of}.
|
20
|
-
#
|
21
|
-
# == #real_type
|
22
|
-
# Subclasses should define private method +#real_type+ if {.set_of} type
|
23
|
-
# may be subclassed. This method should return real class to use. It
|
24
|
-
# takes an only argument, which is of type given by {.set_of}.
|
25
|
-
#
|
26
|
-
# Default behaviour of this method is to return argument's class.
|
27
|
-
#
|
28
|
-
# @author Sylvain Daubert
|
29
|
-
class Array
|
30
|
-
extend Forwardable
|
31
|
-
include Enumerable
|
32
|
-
include Fieldable
|
33
|
-
include LengthFrom
|
34
|
-
|
35
|
-
# @!method [](index)
|
36
|
-
# Return the element at +index+.
|
37
|
-
# @param [integer] index
|
38
|
-
# @return [Object]
|
39
|
-
# @!method clear
|
40
|
-
# Clear array.
|
41
|
-
# @return [void]
|
42
|
-
# @!method each
|
43
|
-
# Calls the given block once for each element in self, passing that
|
44
|
-
# element as a parameter. Returns the array itself.
|
45
|
-
# @return [Array]
|
46
|
-
# @method empty?
|
47
|
-
# Return +true+ if contains no element.
|
48
|
-
# @return [Booelan]
|
49
|
-
# @!method first
|
50
|
-
# Return first element
|
51
|
-
# @return [Object]
|
52
|
-
# @!method last
|
53
|
-
# Return last element.
|
54
|
-
# @return [Object]
|
55
|
-
# @!method size
|
56
|
-
# Get number of element in array
|
57
|
-
# @return [Integer]
|
58
|
-
def_delegators :@array, :[], :clear, :each, :empty?, :first, :last, :size
|
59
|
-
alias length size
|
60
|
-
|
61
|
-
# Separator used in {#to_human}.
|
62
|
-
# May be ovverriden by subclasses
|
63
|
-
HUMAN_SEPARATOR = ','
|
64
|
-
|
65
|
-
# rubocop:disable Naming/AccessorMethodName
|
66
|
-
class << self
|
67
|
-
# Get class set with {.set_of}.
|
68
|
-
# @return [Class]
|
69
|
-
# @since 3.0.0
|
70
|
-
def set_of_klass
|
71
|
-
@klass
|
72
|
-
end
|
73
|
-
|
74
|
-
# Define type of objects in set. Used by {#read} and {#push}.
|
75
|
-
# @param [Class] klass
|
76
|
-
# @return [void]
|
77
|
-
def set_of(klass)
|
78
|
-
@klass = klass
|
79
|
-
end
|
80
|
-
end
|
81
|
-
# rubocop:enable Naming/AccessorMethodName
|
82
|
-
|
83
|
-
# @param [Hash] options
|
84
|
-
# @option options [Int] counter Int object used as a counter for this set
|
85
|
-
def initialize(options={})
|
86
|
-
@counter = options[:counter]
|
87
|
-
@array = []
|
88
|
-
initialize_length_from(options)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Initialize array for copy:
|
92
|
-
# * duplicate internal array.
|
93
|
-
def initialize_copy(_other)
|
94
|
-
@array = @array.dup
|
95
|
-
end
|
96
|
-
|
97
|
-
def ==(other)
|
98
|
-
@array == case other
|
99
|
-
when Array
|
100
|
-
other.to_a
|
101
|
-
else
|
102
|
-
other
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# Clear array. Reset associated counter, if any.
|
107
|
-
# @return [void]
|
108
|
-
def clear!
|
109
|
-
@array.clear
|
110
|
-
@counter&.read(0)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Delete an object from this array. Update associated counter if any
|
114
|
-
# @param [Object] obj
|
115
|
-
# @return [Object] deleted object
|
116
|
-
def delete(obj)
|
117
|
-
deleted = @array.delete(obj)
|
118
|
-
@counter.read(@counter.to_i - 1) if @counter && deleted
|
119
|
-
deleted
|
120
|
-
end
|
121
|
-
|
122
|
-
# Delete element at +index+.
|
123
|
-
# @param [Integer] index
|
124
|
-
# @return [Object,nil] deleted object
|
125
|
-
def delete_at(index)
|
126
|
-
deleted = @array.delete_at(index)
|
127
|
-
@counter.read(@counter.to_i - 1) if @counter && deleted
|
128
|
-
deleted
|
129
|
-
end
|
130
|
-
|
131
|
-
# @abstract depend on private method +#record_from_hash+ which should be
|
132
|
-
# declared by subclasses.
|
133
|
-
# Add an object to this array
|
134
|
-
# @param [Object] obj type depends on subclass
|
135
|
-
# @return [Array] self
|
136
|
-
def push(obj)
|
137
|
-
obj = case obj
|
138
|
-
when Hash
|
139
|
-
record_from_hash obj
|
140
|
-
else
|
141
|
-
obj
|
142
|
-
end
|
143
|
-
@array << obj
|
144
|
-
self
|
145
|
-
end
|
146
|
-
|
147
|
-
# @abstract depend on private method +#record_from_hash+ which should be
|
148
|
-
# declared by subclasses.
|
149
|
-
# Add an object to this array, and increment associated counter, if any
|
150
|
-
# @param [Object] obj type depends on subclass
|
151
|
-
# @return [Array] self
|
152
|
-
def <<(obj)
|
153
|
-
push obj
|
154
|
-
@counter&.read(@counter.to_i + 1)
|
155
|
-
self
|
156
|
-
end
|
157
|
-
|
158
|
-
# Populate object from a string or from an array of hashes
|
159
|
-
# @param [String, Array<Hash>] data
|
160
|
-
# @return [self]
|
161
|
-
def read(data)
|
162
|
-
clear
|
163
|
-
case data
|
164
|
-
when ::Array
|
165
|
-
read_from_array(data)
|
166
|
-
else
|
167
|
-
read_from_string(data)
|
168
|
-
end
|
169
|
-
self
|
170
|
-
end
|
171
|
-
|
172
|
-
# Get size in bytes
|
173
|
-
# @return [Integer]
|
174
|
-
def sz
|
175
|
-
to_s.size
|
176
|
-
end
|
177
|
-
|
178
|
-
# Return an Array
|
179
|
-
# @return [::Array]
|
180
|
-
def to_a
|
181
|
-
@array
|
182
|
-
end
|
183
|
-
|
184
|
-
# Get binary string
|
185
|
-
# @return [String]
|
186
|
-
def to_s
|
187
|
-
@array.map(&:to_s).join
|
188
|
-
end
|
189
|
-
|
190
|
-
# Get a human readable string
|
191
|
-
# @return [String]
|
192
|
-
def to_human
|
193
|
-
@array.map(&:to_human).join(self.class::HUMAN_SEPARATOR)
|
194
|
-
end
|
195
|
-
|
196
|
-
private
|
197
|
-
|
198
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
199
|
-
|
200
|
-
def read_from_string(str)
|
201
|
-
return self if str.nil? || @counter&.to_i&.zero?
|
202
|
-
|
203
|
-
str = read_with_length_from(str)
|
204
|
-
until str.empty? || (@counter && self.size == @counter.to_i)
|
205
|
-
obj = create_object_from_str(str)
|
206
|
-
@array << obj
|
207
|
-
str.slice!(0, obj.sz)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
211
|
-
|
212
|
-
def read_from_array(ary)
|
213
|
-
return self if ary.empty?
|
214
|
-
|
215
|
-
ary.each do |hsh|
|
216
|
-
self << hsh
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
def record_from_hash(hsh)
|
221
|
-
obj_klass = self.class.set_of_klass
|
222
|
-
raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of' unless obj_klass
|
223
|
-
|
224
|
-
obj = obj_klass.new(hsh) if obj_klass
|
225
|
-
klass = real_type(obj)
|
226
|
-
klass == obj_klass ? obj : klass.new(hsh)
|
227
|
-
end
|
228
|
-
|
229
|
-
def real_type(_obj)
|
230
|
-
self.class.set_of_klass
|
231
|
-
end
|
232
|
-
|
233
|
-
def create_object_from_str(str)
|
234
|
-
klass = self.class.set_of_klass
|
235
|
-
obj = klass.new.read(str)
|
236
|
-
real_klass = real_type(obj)
|
237
|
-
|
238
|
-
if real_klass == klass
|
239
|
-
obj
|
240
|
-
else
|
241
|
-
real_klass.new.read(str)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
# @private
|
247
|
-
module ArrayOfIntMixin
|
248
|
-
def read_from_array(ary)
|
249
|
-
return self if ary.empty?
|
250
|
-
|
251
|
-
ary.each do |i|
|
252
|
-
self << self.class.set_of_klass.new(i)
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
# Specialized array to handle serie of {Int8}.
|
258
|
-
class ArrayOfInt8 < Array
|
259
|
-
include ArrayOfIntMixin
|
260
|
-
set_of Int8
|
261
|
-
end
|
262
|
-
|
263
|
-
# Specialized array to handle serie of {Int16}.
|
264
|
-
class ArrayOfInt16 < Array
|
265
|
-
include ArrayOfIntMixin
|
266
|
-
set_of Int16
|
267
|
-
end
|
268
|
-
|
269
|
-
# Specialized array to handle serie of {Int16le}.
|
270
|
-
class ArrayOfInt16le < Array
|
271
|
-
include ArrayOfIntMixin
|
272
|
-
set_of Int16le
|
273
|
-
end
|
274
|
-
|
275
|
-
# Specialized array to handle serie of {Int32}.
|
276
|
-
class ArrayOfInt32 < Types::Array
|
277
|
-
include ArrayOfIntMixin
|
278
|
-
set_of Types::Int32
|
279
|
-
end
|
280
|
-
|
281
|
-
# Specialized array to handle serie of {Int32le}.
|
282
|
-
class ArrayOfInt32le < Types::Array
|
283
|
-
include ArrayOfIntMixin
|
284
|
-
set_of Types::Int32le
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# This file is part of PacketGen
|
5
|
-
# See https://github.com/lemontree55/packetgen for more informations
|
6
|
-
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
7
|
-
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
8
|
-
# This program is published under MIT license.
|
9
|
-
|
10
|
-
require 'forwardable'
|
11
|
-
|
12
|
-
module PacketGen
|
13
|
-
module Types
|
14
|
-
# This class handles null-terminated strings (aka C strings).
|
15
|
-
# @author Sylvain Daubert
|
16
|
-
# @since 3.1.6 no more a subclass or regular String
|
17
|
-
class CString
|
18
|
-
extend Forwardable
|
19
|
-
include Fieldable
|
20
|
-
|
21
|
-
def_delegators :@string, :[], :length, :size, :inspect, :==,
|
22
|
-
:unpack, :force_encoding, :encoding, :index, :empty?,
|
23
|
-
:encode, :slice, :slice!
|
24
|
-
|
25
|
-
# @return [::String]
|
26
|
-
attr_reader :string
|
27
|
-
# @return [Integer]
|
28
|
-
attr_reader :static_length
|
29
|
-
|
30
|
-
# @param [Hash] options
|
31
|
-
# @option options [Integer] :static_length set a static length for this string
|
32
|
-
def initialize(options={})
|
33
|
-
register_internal_string(+'')
|
34
|
-
@static_length = options[:static_length]
|
35
|
-
end
|
36
|
-
|
37
|
-
# @param [::String] str
|
38
|
-
# @return [String] self
|
39
|
-
def read(str)
|
40
|
-
s = str.to_s
|
41
|
-
s = s[0, static_length] if static_length?
|
42
|
-
register_internal_string s
|
43
|
-
remove_null_character
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
# get null-terminated string
|
48
|
-
# @return [String]
|
49
|
-
def to_s
|
50
|
-
if static_length?
|
51
|
-
s = string[0, static_length - 1]
|
52
|
-
s << "\x00" * (static_length - s.length)
|
53
|
-
else
|
54
|
-
s = "#{string}\x00"
|
55
|
-
end
|
56
|
-
PacketGen.force_binary(s)
|
57
|
-
end
|
58
|
-
|
59
|
-
# Append the given string to CString
|
60
|
-
# @param [#to_s] str
|
61
|
-
# @return [self]
|
62
|
-
def <<(str)
|
63
|
-
@string << str.to_s
|
64
|
-
remove_null_character
|
65
|
-
self
|
66
|
-
end
|
67
|
-
|
68
|
-
# @return [Integer]
|
69
|
-
def sz
|
70
|
-
if static_length?
|
71
|
-
static_length
|
72
|
-
else
|
73
|
-
to_s.size
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Say if a static length is defined
|
78
|
-
# @return [Boolean]
|
79
|
-
# @since 3.1.6
|
80
|
-
def static_length?
|
81
|
-
!static_length.nil?
|
82
|
-
end
|
83
|
-
|
84
|
-
# Populate CString from a human readable string
|
85
|
-
# @param [String] str
|
86
|
-
# @return [self]
|
87
|
-
def from_human(str)
|
88
|
-
read str
|
89
|
-
end
|
90
|
-
|
91
|
-
# @return [String]
|
92
|
-
def to_human
|
93
|
-
string
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
def register_internal_string(str)
|
99
|
-
@string = str
|
100
|
-
PacketGen.force_binary(@string)
|
101
|
-
end
|
102
|
-
|
103
|
-
def remove_null_character
|
104
|
-
idx = string.index(0.chr)
|
105
|
-
register_internal_string(string[0, idx]) unless idx.nil?
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|