packetgen 3.1.6 → 3.2.1
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 +1 -2
- data/bin/pgconsole +3 -3
- data/lib/packetgen/capture.rb +5 -1
- data/lib/packetgen/header/arp.rb +24 -13
- data/lib/packetgen/header/asn1_base.rb +19 -9
- data/lib/packetgen/header/base.rb +1 -1
- data/lib/packetgen/header/dhcpv6/option.rb +11 -13
- data/lib/packetgen/header/dns/opt.rb +2 -2
- data/lib/packetgen/header/dns/rr.rb +61 -28
- data/lib/packetgen/header/dns.rb +13 -6
- data/lib/packetgen/header/dot11/data.rb +19 -29
- data/lib/packetgen/header/dot11/management.rb +2 -5
- data/lib/packetgen/header/dot11.rb +1 -1
- data/lib/packetgen/header/eap.rb +1 -1
- data/lib/packetgen/header/eth.rb +1 -1
- data/lib/packetgen/header/http/request.rb +5 -1
- data/lib/packetgen/header/http/response.rb +46 -20
- data/lib/packetgen/header/http/verbs.rb +1 -1
- data/lib/packetgen/header/igmp.rb +1 -1
- data/lib/packetgen/header/ip/option.rb +2 -1
- data/lib/packetgen/header/ipv6/addr.rb +3 -0
- data/lib/packetgen/header/mdns.rb +19 -25
- data/lib/packetgen/header/mld.rb +1 -1
- data/lib/packetgen/header/ospfv2/lsa.rb +7 -3
- data/lib/packetgen/header/ospfv2/lsa_header.rb +2 -4
- data/lib/packetgen/header/ospfv2.rb +1 -1
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +14 -5
- data/lib/packetgen/header/ospfv3/lsa.rb +8 -4
- data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -4
- data/lib/packetgen/header/ospfv3.rb +1 -1
- data/lib/packetgen/header/snmp.rb +20 -14
- data/lib/packetgen/header/tcp/option.rb +1 -1
- data/lib/packetgen/header/tcp.rb +12 -5
- data/lib/packetgen/header/tftp.rb +15 -9
- data/lib/packetgen/inspect.rb +15 -9
- data/lib/packetgen/packet.rb +51 -5
- data/lib/packetgen/pcapng/file.rb +17 -15
- data/lib/packetgen/pcapng.rb +1 -0
- data/lib/packetgen/pcaprub_wrapper.rb +0 -4
- data/lib/packetgen/types/abstract_tlv.rb +1 -1
- data/lib/packetgen/types/array.rb +8 -1
- data/lib/packetgen/types/cstring.rb +20 -7
- data/lib/packetgen/types/fields.rb +19 -19
- data/lib/packetgen/types/int.rb +7 -0
- data/lib/packetgen/types/oui.rb +1 -1
- data/lib/packetgen/types/string.rb +16 -3
- data/lib/packetgen/types/tlv.rb +17 -9
- data/lib/packetgen/unknown_packet.rb +84 -0
- data/lib/packetgen/utils.rb +60 -27
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +13 -4
- metadata +7 -7
@@ -31,32 +31,10 @@ module PacketGen
|
|
31
31
|
case iph
|
32
32
|
when IP
|
33
33
|
iph.dst = '224.0.0.251'
|
34
|
-
|
35
|
-
mac = case llh
|
36
|
-
when Eth
|
37
|
-
llh[:dst]
|
38
|
-
when Dot11
|
39
|
-
if llh.to_ds?
|
40
|
-
llh[:mac3]
|
41
|
-
else
|
42
|
-
llh[:mac1]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
mac.from_human('01:00:5E:00:00:FB')
|
34
|
+
dst_mac.from_human('01:00:5E:00:00:FB')
|
46
35
|
when IPv6
|
47
36
|
iph.dst = 'ff02::fb'
|
48
|
-
|
49
|
-
mac = case llh
|
50
|
-
when Eth
|
51
|
-
llh[:dst]
|
52
|
-
when Dot11
|
53
|
-
if llh.to_ds?
|
54
|
-
llh[:mac3]
|
55
|
-
else
|
56
|
-
llh[:mac1]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
mac.from_human('33:33:00:00:00:FB')
|
37
|
+
dst_mac.from_human('33:33:00:00:00:FB')
|
60
38
|
end
|
61
39
|
end
|
62
40
|
|
@@ -67,12 +45,28 @@ module PacketGen
|
|
67
45
|
# Needed by new bind API.
|
68
46
|
def added_to_packet(packet)
|
69
47
|
mdns_idx = packet.headers.size
|
70
|
-
packet.instance_eval "def mdnsize() @headers[#{mdns_idx}].mdnsize; end"
|
48
|
+
packet.instance_eval "def mdnsize() @headers[#{mdns_idx}].mdnsize; end" # def mdnsize() @headers[4].mdnsize; end
|
71
49
|
return unless packet.is? 'UDP'
|
72
50
|
return unless packet.udp.sport.zero?
|
73
51
|
|
74
52
|
packet.udp.sport = UDP_PORT
|
75
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def dst_mac
|
58
|
+
llh = ll_header(self)
|
59
|
+
case llh
|
60
|
+
when Eth
|
61
|
+
llh[:dst]
|
62
|
+
when Dot11
|
63
|
+
if llh.to_ds?
|
64
|
+
llh[:mac3]
|
65
|
+
else
|
66
|
+
llh[:mac1]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
76
70
|
end
|
77
71
|
|
78
72
|
self.add_class MDNS
|
data/lib/packetgen/header/mld.rb
CHANGED
@@ -68,7 +68,7 @@ module PacketGen
|
|
68
68
|
# directly called
|
69
69
|
def added_to_packet(packet)
|
70
70
|
mld_idx = packet.headers.size
|
71
|
-
packet.instance_eval "def mldize() @headers[#{mld_idx}].mldize; end"
|
71
|
+
packet.instance_eval "def mldize() @headers[#{mld_idx}].mldize; end" # def mldize() @headers[3].mldize; end
|
72
72
|
end
|
73
73
|
|
74
74
|
# Fixup IP header according to RFC 2710:
|
@@ -229,9 +229,13 @@ module PacketGen
|
|
229
229
|
|
230
230
|
def get_lsa_class_by_human_type(htype)
|
231
231
|
klassname = "LSA#{htype.to_s.delete('-')}"
|
232
|
-
|
233
|
-
OSPFv2.
|
234
|
-
|
232
|
+
begin
|
233
|
+
if OSPFv2.const_defined? klassname
|
234
|
+
OSPFv2.const_get klassname
|
235
|
+
else
|
236
|
+
LSA
|
237
|
+
end
|
238
|
+
rescue NameError
|
235
239
|
LSA
|
236
240
|
end
|
237
241
|
end
|
@@ -77,17 +77,15 @@ module PacketGen
|
|
77
77
|
# Compute and set Fletcher-16 checksum on LSA
|
78
78
|
# @return [Integer]
|
79
79
|
def calc_checksum
|
80
|
-
bytes = to_s[2..-1].unpack('C*')
|
81
|
-
|
82
80
|
c0 = c1 = 0
|
83
|
-
|
81
|
+
to_s[2..-1].unpack('C*').each do |byte|
|
84
82
|
c0 += byte
|
85
83
|
c1 += c0
|
86
84
|
end
|
87
85
|
c0 %= 255
|
88
86
|
c1 %= 255
|
89
87
|
|
90
|
-
x = ((sz -
|
88
|
+
x = ((sz - 17) * c0 - c1) % 255
|
91
89
|
x += 255 if x <= 0
|
92
90
|
y = 255 * 2 - c0 - x
|
93
91
|
y -= 255 if y > 255
|
@@ -167,7 +167,7 @@ module PacketGen
|
|
167
167
|
# directly called
|
168
168
|
def added_to_packet(packet)
|
169
169
|
ospf_idx = packet.headers.size
|
170
|
-
packet.instance_eval "def ospfize(**kwargs) @headers[#{ospf_idx}].ospfize(**kwargs); end"
|
170
|
+
packet.instance_eval "def ospfize(**kwargs) @headers[#{ospf_idx}].ospfize(**kwargs); end" # def ospfize(**kwargs) @headers[2].ospfize(**kwargs); end
|
171
171
|
end
|
172
172
|
|
173
173
|
# Compute checksum and set +checksum+ field
|
@@ -71,11 +71,8 @@ module PacketGen
|
|
71
71
|
# @param [String] str
|
72
72
|
# @return [void]
|
73
73
|
def from_human(str)
|
74
|
-
|
75
|
-
|
76
|
-
addr = IPv6::Addr.new.from_human(pfx)
|
77
|
-
ary_size = (len + 31) / 32
|
78
|
-
ary = addr.to_a[0...ary_size * 2]
|
74
|
+
ary, len = ary_and_prefix_len_from_str(str)
|
75
|
+
|
79
76
|
self.prefix.clear
|
80
77
|
ary.each_with_index do |v, i|
|
81
78
|
if i.even?
|
@@ -86,6 +83,18 @@ module PacketGen
|
|
86
83
|
end
|
87
84
|
self.length = len
|
88
85
|
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def ary_and_prefix_len_from_str(str)
|
90
|
+
pfx, len = str.split('/')
|
91
|
+
len = (len || 128).to_i
|
92
|
+
addr = IPv6::Addr.new.from_human(pfx)
|
93
|
+
ary_size = (len + 31) / 32
|
94
|
+
ary = addr.to_a[0...ary_size * 2]
|
95
|
+
|
96
|
+
[ary, len]
|
97
|
+
end
|
89
98
|
end
|
90
99
|
|
91
100
|
# Array of {IPv6Prefix}
|
@@ -35,7 +35,7 @@ module PacketGen
|
|
35
35
|
# @return [String]
|
36
36
|
def to_human
|
37
37
|
"Link<type:#{type},metric:#{metric},id:#{interface_id}," \
|
38
|
-
|
38
|
+
"neighbor_id:#{neighbor_interface_id},neighbor_router:#{neighbor_router_id}>"
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -218,9 +218,13 @@ module PacketGen
|
|
218
218
|
|
219
219
|
def get_lsa_class_by_human_type(htype)
|
220
220
|
klassname = "LSA#{htype.to_s.delete('-')}"
|
221
|
-
|
222
|
-
OSPFv3.
|
223
|
-
|
221
|
+
begin
|
222
|
+
if OSPFv3.const_defined? klassname
|
223
|
+
OSPFv3.const_get klassname
|
224
|
+
else
|
225
|
+
LSA
|
226
|
+
end
|
227
|
+
rescue NameError
|
224
228
|
LSA
|
225
229
|
end
|
226
230
|
end
|
@@ -78,17 +78,15 @@ module PacketGen
|
|
78
78
|
# Compute and set Fletcher-16 checksum on LSA
|
79
79
|
# @return [Integer]
|
80
80
|
def calc_checksum
|
81
|
-
bytes = to_s[2..-1].unpack('C*')
|
82
|
-
|
83
81
|
c0 = c1 = 0
|
84
|
-
|
82
|
+
to_s[2..-1].unpack('C*').each do |byte|
|
85
83
|
c0 += byte
|
86
84
|
c1 += c0
|
87
85
|
end
|
88
86
|
c0 %= 255
|
89
87
|
c1 %= 255
|
90
88
|
|
91
|
-
x = ((sz -
|
89
|
+
x = ((sz - 17) * c0 - c1) % 255
|
92
90
|
x += 255 if x <= 0
|
93
91
|
y = 255 * 2 - c0 - x
|
94
92
|
y -= 255 if y > 255
|
@@ -145,7 +145,7 @@ module PacketGen
|
|
145
145
|
# directly called
|
146
146
|
def added_to_packet(packet)
|
147
147
|
ospf_idx = packet.headers.size
|
148
|
-
packet.instance_eval "def ospfize(**kwargs) @headers[#{ospf_idx}].ospfize(**kwargs); end"
|
148
|
+
packet.instance_eval "def ospfize(**kwargs) @headers[#{ospf_idx}].ospfize(**kwargs); end" # def ospfize(**kwargs) @headers[2].ospfize(**kwargs); end
|
149
149
|
end
|
150
150
|
|
151
151
|
# Compute checksum and set +checksum+ field
|
@@ -286,20 +286,11 @@ module PacketGen
|
|
286
286
|
def inspect
|
287
287
|
str = super
|
288
288
|
str << Inspect.shift_level
|
289
|
-
if self[:data].chosen.nil?
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
str << Inspect.dashed_line('ASN.1 content')
|
295
|
-
str << data.chosen_value.inspect(1)
|
296
|
-
begin
|
297
|
-
str << Inspect.inspect_body(self[:message].to_der, 'ASN.1 DER')
|
298
|
-
rescue StandardError => e
|
299
|
-
raise unless e.message.match?(/TAG.*not handled/)
|
300
|
-
end
|
301
|
-
str
|
302
|
-
end
|
289
|
+
str << if self[:data].chosen.nil?
|
290
|
+
Inspect::FMT_ATTR % [self[:data].type, :data, '']
|
291
|
+
else
|
292
|
+
inspect_data
|
293
|
+
end
|
303
294
|
end
|
304
295
|
|
305
296
|
# @api private
|
@@ -315,6 +306,21 @@ module PacketGen
|
|
315
306
|
|
316
307
|
packet.udp.sport = packet.udp.dport
|
317
308
|
end
|
309
|
+
|
310
|
+
private
|
311
|
+
|
312
|
+
def inspect_data
|
313
|
+
data = self[:data]
|
314
|
+
str = Inspect::FMT_ATTR % [data.type, :data, data.chosen_value.type]
|
315
|
+
str << Inspect.dashed_line('ASN.1 content')
|
316
|
+
str << data.chosen_value.inspect(1)
|
317
|
+
begin
|
318
|
+
str << Inspect.inspect_body(self[:message].to_der, 'ASN.1 DER')
|
319
|
+
rescue StandardError => e
|
320
|
+
raise unless e.message.match?(/TAG.*not handled/)
|
321
|
+
end
|
322
|
+
str
|
323
|
+
end
|
318
324
|
end
|
319
325
|
|
320
326
|
self.add_class SNMP
|
@@ -43,7 +43,7 @@ module PacketGen
|
|
43
43
|
# @!attribute value
|
44
44
|
# @return [Integer,String] option value
|
45
45
|
define_field :value, Types::String, optional: ->(h) { h.length? && h.length > 2 },
|
46
|
-
|
46
|
+
builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) }
|
47
47
|
|
48
48
|
# @param [hash] options
|
49
49
|
# @option options [Integer] :kind
|
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -216,11 +216,7 @@ module PacketGen
|
|
216
216
|
doff = Inspect.int_dec_hex(data_offset, 1)
|
217
217
|
str << shift << Inspect::FMT_ATTR % ['', 'data_offset', doff]
|
218
218
|
str << shift << Inspect::FMT_ATTR % ['', 'reserved', reserved]
|
219
|
-
|
220
|
-
%w[ns cwr ece urg ack psh rst syn fin].each do |fl|
|
221
|
-
flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
|
222
|
-
end
|
223
|
-
str << shift << Inspect::FMT_ATTR % ['', 'flags', flags]
|
219
|
+
str << shift << Inspect::FMT_ATTR % ['', 'flags', flags2string]
|
224
220
|
end
|
225
221
|
end
|
226
222
|
|
@@ -231,6 +227,17 @@ module PacketGen
|
|
231
227
|
self[:sport], self[:dport] = self[:dport], self[:sport]
|
232
228
|
self
|
233
229
|
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
def flags2string
|
234
|
+
flags = +''
|
235
|
+
%w[ns cwr ece urg ack psh rst syn fin].each do |fl|
|
236
|
+
flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
|
237
|
+
end
|
238
|
+
|
239
|
+
flags
|
240
|
+
end
|
234
241
|
end
|
235
242
|
|
236
243
|
self.add_class TCP
|
@@ -102,22 +102,18 @@ module PacketGen
|
|
102
102
|
client_tid = packet.udp.sport
|
103
103
|
server_tid = nil
|
104
104
|
ary.each do |pkt|
|
105
|
+
next unless pkt.is?('UDP')
|
106
|
+
|
105
107
|
if server_tid.nil?
|
106
|
-
next unless pkt.
|
108
|
+
next unless pkt.udp.dport == client_tid
|
107
109
|
|
108
110
|
server_tid = pkt.udp.sport
|
109
111
|
else
|
110
|
-
next unless pkt.is?('UDP')
|
111
|
-
|
112
112
|
tids = [server_tid, client_tid]
|
113
113
|
ports = [pkt.udp.sport, pkt.udp.dport]
|
114
114
|
next unless (tids - ports).empty?
|
115
115
|
end
|
116
|
-
|
117
|
-
udp_dport = pkt.udp.dport
|
118
|
-
pkt.encapsulate tftp
|
119
|
-
# need to fix it as #encapsulate force it to 69
|
120
|
-
pkt.udp.dport = udp_dport
|
116
|
+
decode_tftp_packet(pkt)
|
121
117
|
end
|
122
118
|
end
|
123
119
|
|
@@ -135,7 +131,17 @@ module PacketGen
|
|
135
131
|
def added_to_packet(packet)
|
136
132
|
return if packet.respond_to? :tftp
|
137
133
|
|
138
|
-
packet.instance_eval("def tftp(arg=nil); header(#{self.class}, arg); end")
|
134
|
+
packet.instance_eval("def tftp(arg=nil); header(#{self.class}, arg); end") # def tftp(arg=nil); header(TFTP, arg); end
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def decode_tftp_packet(pkt)
|
140
|
+
tftp = Packet.parse(pkt.body, first_header: 'TFTP')
|
141
|
+
udp_dport = pkt.udp.dport
|
142
|
+
pkt.encapsulate tftp
|
143
|
+
# need to fix it as #encapsulate force it to 69
|
144
|
+
pkt.udp.dport = udp_dport
|
139
145
|
end
|
140
146
|
|
141
147
|
# TFTP Read Request header
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -12,6 +12,8 @@ module PacketGen
|
|
12
12
|
module Inspect
|
13
13
|
# Maximum number of characters on a line for INSPECT
|
14
14
|
MAX_WIDTH = 70
|
15
|
+
# @private
|
16
|
+
SEPARATOR = ('-' * MAX_WIDTH << "\n").freeze
|
15
17
|
|
16
18
|
# Format to inspect attribute
|
17
19
|
FMT_ATTR = "%14s %16s: %s\n"
|
@@ -105,19 +107,23 @@ module PacketGen
|
|
105
107
|
return '' if body.nil? || body.empty?
|
106
108
|
|
107
109
|
str = dashed_line(name, 2)
|
108
|
-
|
109
|
-
str <<
|
110
|
+
0.upto(15) { |v| str << ' %02d' % v }
|
111
|
+
str << "\n" << SEPARATOR
|
110
112
|
unless body.empty?
|
111
113
|
(body.size / 16 + 1).times do |i|
|
112
|
-
|
113
|
-
o_str = octets.map { |v| ' %02x' % v }.join
|
114
|
-
str << o_str
|
115
|
-
str << ' ' * (3 * 16 - o_str.size) unless o_str.size >= 3 * 16
|
116
|
-
str << ' ' << octets.map { |v| v < 128 && v > 31 ? v.chr : '.' }.join
|
117
|
-
str << "\n"
|
114
|
+
str << self.convert_body_slice(body.to_s[i * 16, 16])
|
118
115
|
end
|
119
116
|
end
|
120
|
-
str <<
|
117
|
+
str << SEPARATOR
|
118
|
+
end
|
119
|
+
|
120
|
+
# @private
|
121
|
+
def self.convert_body_slice(bslice)
|
122
|
+
octets = bslice.unpack('C*')
|
123
|
+
str = octets.map { |v| ' %02x' % v }.join
|
124
|
+
str << ' ' * (48 - str.size) unless str.size >= 48
|
125
|
+
str << ' ' << octets.map { |v| (32..127).cover?(v) ? v.chr : '.' }.join
|
126
|
+
str << "\n"
|
121
127
|
end
|
122
128
|
end
|
123
129
|
end
|
data/lib/packetgen/packet.rb
CHANGED
@@ -51,6 +51,9 @@ module PacketGen
|
|
51
51
|
# Get packet headers, ordered as they appear in the packet.
|
52
52
|
# @return [Array<Header::Base>]
|
53
53
|
attr_reader :headers
|
54
|
+
# Activaye or deactivate header cache (activated by default)
|
55
|
+
# @return [Boolean]
|
56
|
+
attr_accessor :cache_headers
|
54
57
|
|
55
58
|
# Create a new Packet
|
56
59
|
# @param [String] protocol base protocol for packet
|
@@ -81,7 +84,7 @@ module PacketGen
|
|
81
84
|
# @return [Array<Packet>] captured packet
|
82
85
|
def self.capture(**kwargs, &block)
|
83
86
|
capture = Capture.new(**kwargs)
|
84
|
-
if
|
87
|
+
if block
|
85
88
|
capture.start(&block)
|
86
89
|
else
|
87
90
|
capture.start
|
@@ -121,6 +124,8 @@ module PacketGen
|
|
121
124
|
# @private
|
122
125
|
def initialize
|
123
126
|
@headers = []
|
127
|
+
@header_cache = {}
|
128
|
+
@cache_headers = true
|
124
129
|
end
|
125
130
|
|
126
131
|
# Add a protocol header in packet.
|
@@ -166,7 +171,7 @@ module PacketGen
|
|
166
171
|
# @raise [ArgumentError] unknown protocol
|
167
172
|
def is?(protocol)
|
168
173
|
klass = check_protocol protocol
|
169
|
-
headers.any?
|
174
|
+
headers.any?(klass)
|
170
175
|
end
|
171
176
|
|
172
177
|
# Recalculate all packet checksums
|
@@ -216,7 +221,7 @@ module PacketGen
|
|
216
221
|
# @return [Array] see return from {PcapNG::File#to_file}
|
217
222
|
# @see File
|
218
223
|
def to_f(filename)
|
219
|
-
PcapNG::File.new.
|
224
|
+
PcapNG::File.new.read_array([self]).to_f(filename)
|
220
225
|
end
|
221
226
|
alias write to_f
|
222
227
|
|
@@ -271,6 +276,7 @@ module PacketGen
|
|
271
276
|
headers.delete(hdr)
|
272
277
|
add_header(next_hdr, previous_header: prev_hdr) if prev_hdr && next_hdr
|
273
278
|
end
|
279
|
+
invalidate_header_cache
|
274
280
|
rescue ArgumentError => e
|
275
281
|
raise FormatError, e.message
|
276
282
|
end
|
@@ -287,7 +293,7 @@ module PacketGen
|
|
287
293
|
if first_header.nil?
|
288
294
|
# No decoding forced for first header. Have to guess it!
|
289
295
|
first_header = guess_first_header(binary_str)
|
290
|
-
raise ParseError,
|
296
|
+
raise ParseError, "cannot identify first header in string: #{binary_str.inspect}" if first_header.nil?
|
291
297
|
end
|
292
298
|
|
293
299
|
add first_header
|
@@ -356,6 +362,7 @@ module PacketGen
|
|
356
362
|
headers.each do |header|
|
357
363
|
add_magic_header_method header
|
358
364
|
end
|
365
|
+
invalidate_header_cache
|
359
366
|
end
|
360
367
|
|
361
368
|
# Give first header of packet
|
@@ -409,7 +416,7 @@ module PacketGen
|
|
409
416
|
# @return [Header::Base]
|
410
417
|
def header(klass, arg)
|
411
418
|
layer = arg.is_a?(Integer) ? arg : 1
|
412
|
-
header =
|
419
|
+
header = find_header(klass, layer)
|
413
420
|
return header unless arg.is_a? Hash
|
414
421
|
|
415
422
|
arg.each do |key, value|
|
@@ -421,6 +428,19 @@ module PacketGen
|
|
421
428
|
header
|
422
429
|
end
|
423
430
|
|
431
|
+
# Get header from cache, or find it in packet
|
432
|
+
# @param [Class] klass
|
433
|
+
# @param [Integer] layer
|
434
|
+
# @return [Header::Base]
|
435
|
+
def find_header(klass, layer)
|
436
|
+
header = fetch_header_from_cache(klass, layer)
|
437
|
+
return header if header
|
438
|
+
|
439
|
+
header = headers.select { |h| h.is_a? klass }[layer - 1]
|
440
|
+
add_header_to_cache(header, klass, layer)
|
441
|
+
header
|
442
|
+
end
|
443
|
+
|
424
444
|
# check if protocol is known
|
425
445
|
# @param [String] protocol
|
426
446
|
# @raise [ArgumentError] unknown protocol
|
@@ -438,6 +458,7 @@ module PacketGen
|
|
438
458
|
# @return [void]
|
439
459
|
# @raise [BindingError]
|
440
460
|
def add_header(header, previous_header: nil, parsing: false)
|
461
|
+
invalidate_header_cache
|
441
462
|
prev_header = previous_header || last_header
|
442
463
|
add_to_previous_header(prev_header, header, parsing) if prev_header
|
443
464
|
|
@@ -521,6 +542,31 @@ module PacketGen
|
|
521
542
|
|
522
543
|
nil
|
523
544
|
end
|
545
|
+
|
546
|
+
def invalidate_header_cache
|
547
|
+
return unless cache_headers
|
548
|
+
|
549
|
+
@header_cache = {}
|
550
|
+
end
|
551
|
+
|
552
|
+
# Fetch header from cache if authorized
|
553
|
+
# @param [Class] klass
|
554
|
+
# @param [Integer] layer
|
555
|
+
# @return [Header::Base,nil]
|
556
|
+
def fetch_header_from_cache(klass, layer)
|
557
|
+
@header_cache.fetch(klass, []).fetch(layer - 1, nil) if cache_headers
|
558
|
+
end
|
559
|
+
|
560
|
+
# Add header to cache if authorized
|
561
|
+
# @param [Class] klass
|
562
|
+
# @param [Integer] layer
|
563
|
+
# @return [Header::Base,nil]
|
564
|
+
def add_header_to_cache(header, klass, layer)
|
565
|
+
return unless cache_headers
|
566
|
+
|
567
|
+
@header_cache[klass] ||= []
|
568
|
+
@header_cache[klass][layer - 1] = header
|
569
|
+
end
|
524
570
|
end
|
525
571
|
end
|
526
572
|
|
@@ -9,7 +9,7 @@ module PacketGen
|
|
9
9
|
module PcapNG
|
10
10
|
# PcapNG::File is a complete Pcap-NG file handler.
|
11
11
|
# @author Sylvain Daubert
|
12
|
-
class File
|
12
|
+
class File # rubocop:disable Metrics/ClassLength
|
13
13
|
# Known link types
|
14
14
|
KNOWN_LINK_TYPES = {
|
15
15
|
LINKTYPE_ETHERNET => 'Eth',
|
@@ -21,13 +21,11 @@ module PacketGen
|
|
21
21
|
}.freeze
|
22
22
|
|
23
23
|
# @private
|
24
|
-
BLOCK_TYPES =
|
25
|
-
PcapNG.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
].freeze
|
24
|
+
BLOCK_TYPES = PcapNG.constants(false).select { |c| c.to_s.include?('_TYPE') }.map do |c|
|
25
|
+
type_value = PcapNG.const_get(c).to_i
|
26
|
+
klass = PcapNG.const_get(c.to_s.delete_suffix('_TYPE'))
|
27
|
+
[type_value, klass]
|
28
|
+
end.to_h.freeze
|
31
29
|
|
32
30
|
# Get file sections
|
33
31
|
# @return [Array]
|
@@ -204,7 +202,7 @@ module PacketGen
|
|
204
202
|
# @return [Array] array of 2 elements: filename and size written
|
205
203
|
# @todo for 4.0, replace +options+ by +append+ kwarg
|
206
204
|
def to_file(filename, options={})
|
207
|
-
mode =
|
205
|
+
mode = options[:append] && ::File.exist?(filename) ? 'ab' : 'wb'
|
208
206
|
::File.open(filename, mode) { |f| f.write(self.to_s) }
|
209
207
|
[filename, self.to_s.size]
|
210
208
|
end
|
@@ -264,7 +262,7 @@ module PacketGen
|
|
264
262
|
# @param [Time, nil] timestamp initial timestamp, used for first packet
|
265
263
|
# @param [Numeric, nil] ts_inc timestamp increment, in seconds, to increment
|
266
264
|
# initial timestamp for each packet
|
267
|
-
# @return [
|
265
|
+
# @return [self]
|
268
266
|
# @note if +timestamp+ and/or +ts_inc+ are nil, {SPB} sections are created
|
269
267
|
# for each packet, else {EPB} ones are used
|
270
268
|
# @since 3.1.6
|
@@ -276,11 +274,12 @@ module PacketGen
|
|
276
274
|
classify_block(section, block)
|
277
275
|
ts = update_ts(ts, ts_inc)
|
278
276
|
end
|
277
|
+
self
|
279
278
|
end
|
280
279
|
|
281
280
|
# Update current object from a hash of packets and timestamps
|
282
281
|
# @param [Hash{Time => Packet}] hsh
|
283
|
-
# @return [
|
282
|
+
# @return [self]
|
284
283
|
# @since 3.1.6
|
285
284
|
def read_hash(hsh)
|
286
285
|
section = create_new_shb_section
|
@@ -288,6 +287,7 @@ module PacketGen
|
|
288
287
|
block = create_block_from_pkt(pkt, section, ts, 0)
|
289
288
|
classify_block(section, block)
|
290
289
|
end
|
290
|
+
self
|
291
291
|
end
|
292
292
|
|
293
293
|
# @return [String]
|
@@ -315,12 +315,12 @@ module PacketGen
|
|
315
315
|
shb = parse_shb(SHB.new, io)
|
316
316
|
raise InvalidFileError, 'no Section header found' unless shb.is_a?(SHB)
|
317
317
|
|
318
|
-
to_parse = if shb.section_len.to_i
|
319
|
-
# Section length is defined
|
320
|
-
StringIO.new(io.read(shb.section_len.to_i))
|
321
|
-
else
|
318
|
+
to_parse = if shb.section_len.to_i == 0xffffffffffffffff
|
322
319
|
# section length is undefined
|
323
320
|
io
|
321
|
+
else
|
322
|
+
# Section length is defined
|
323
|
+
StringIO.new(io.read(shb.section_len.to_i))
|
324
324
|
end
|
325
325
|
|
326
326
|
until to_parse.eof?
|
@@ -386,6 +386,7 @@ module PacketGen
|
|
386
386
|
end
|
387
387
|
end
|
388
388
|
|
389
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
389
390
|
# Extract and check options for #array_to_file
|
390
391
|
def array_to_file_options_from_hash(options)
|
391
392
|
%i[filename arr ts].each do |deprecated_opt|
|
@@ -402,6 +403,7 @@ module PacketGen
|
|
402
403
|
|
403
404
|
[filename, ary, ts, ts_inc, append]
|
404
405
|
end
|
406
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
405
407
|
|
406
408
|
def create_new_shb_section
|
407
409
|
section = SHB.new
|
data/lib/packetgen/pcapng.rb
CHANGED
@@ -38,8 +38,6 @@ module PacketGen
|
|
38
38
|
pcap.activate
|
39
39
|
end
|
40
40
|
|
41
|
-
# rubocop:disable Metrics/ParameterLists
|
42
|
-
|
43
41
|
# Capture packets from a network interface
|
44
42
|
# @param [String] iface interface name
|
45
43
|
# @param [Integer] snaplen
|
@@ -57,8 +55,6 @@ module PacketGen
|
|
57
55
|
pcap.each(&block)
|
58
56
|
end
|
59
57
|
|
60
|
-
# rubocop:enable Metrics/ParameterLists
|
61
|
-
|
62
58
|
# Inject given data onto wire
|
63
59
|
# @param [String] iface interface name
|
64
60
|
# @param [String] data to inject
|