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/pcapng/idb.rb
CHANGED
@@ -60,7 +60,7 @@ module PacketGen
|
|
60
60
|
# @option options [Integer] :block_len2 block total length
|
61
61
|
def initialize(options={})
|
62
62
|
super
|
63
|
-
|
63
|
+
endianness(options[:endian] || :little)
|
64
64
|
@packets = []
|
65
65
|
@options_decoded = false
|
66
66
|
recalc_block_len
|
@@ -74,15 +74,12 @@ module PacketGen
|
|
74
74
|
io = to_io(str_or_io)
|
75
75
|
return self if io.eof?
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
self[:reserved].read io.read(2)
|
81
|
-
self[:snaplen].read io.read(4)
|
77
|
+
%i[type block_len link_type reserved snaplen].each do |attr|
|
78
|
+
self[attr].read io.read(self[attr].sz)
|
79
|
+
end
|
82
80
|
self[:options].read io.read(self.block_len - MIN_SIZE)
|
83
|
-
|
81
|
+
read_blocklen2_and_check(io)
|
84
82
|
|
85
|
-
check_len_coherency
|
86
83
|
self
|
87
84
|
end
|
88
85
|
|
@@ -91,6 +88,7 @@ module PacketGen
|
|
91
88
|
# @return [self]
|
92
89
|
def <<(xpb)
|
93
90
|
@packets << xpb
|
91
|
+
xpb.interface = self
|
94
92
|
self
|
95
93
|
end
|
96
94
|
|
@@ -133,7 +131,7 @@ module PacketGen
|
|
133
131
|
|
134
132
|
while idx < options.length
|
135
133
|
opt_code, opt_len = options[idx, 4].unpack("#{packstr}2")
|
136
|
-
return options[idx + 4, 1].
|
134
|
+
return options[idx + 4, 1].unpack1('C') if opt_code == OPTION_IF_TSRESOL && opt_len == 1
|
137
135
|
|
138
136
|
idx += 4 + opt_len
|
139
137
|
end
|
data/lib/packetgen/pcapng/shb.rb
CHANGED
@@ -80,7 +80,7 @@ module PacketGen
|
|
80
80
|
super
|
81
81
|
@interfaces = []
|
82
82
|
@unknown_blocks = []
|
83
|
-
|
83
|
+
endianness(options[:endian] || :little)
|
84
84
|
recalc_block_len
|
85
85
|
self.type = options[:type] || PcapNG::SHB_TYPE.to_i
|
86
86
|
end
|
@@ -92,29 +92,15 @@ module PacketGen
|
|
92
92
|
io = to_io(str_or_io)
|
93
93
|
return self if io.eof?
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
case magic_str
|
100
|
-
when MAGIC_LITTLE
|
101
|
-
force_endianness :little if @endian == :big
|
102
|
-
when MAGIC_BIG
|
103
|
-
force_endianness :big if @endian == :little
|
104
|
-
else
|
105
|
-
raise InvalidFileError, 'Incorrect magic for Section Header Block'
|
95
|
+
self[:type].read check_shb(io)
|
96
|
+
%i[block_len magic ver_major ver_minor section_len].each do |attr|
|
97
|
+
self[attr].read io.read(self[attr].sz)
|
106
98
|
end
|
99
|
+
handle_magic_and_check(self[:magic].to_s)
|
107
100
|
|
108
|
-
|
109
|
-
|
110
|
-
self[:magic].read magic_str
|
111
|
-
self[:ver_major].read io.read(2)
|
112
|
-
self[:ver_minor].read io.read(2)
|
113
|
-
self[:section_len].read io.read(8)
|
114
|
-
self[:options].read io.read(self.block_len - MIN_SIZE)
|
115
|
-
self[:block_len2].read io.read(4)
|
101
|
+
read_options(io)
|
102
|
+
read_blocklen2_and_check(io)
|
116
103
|
|
117
|
-
check_len_coherency
|
118
104
|
self
|
119
105
|
end
|
120
106
|
|
@@ -123,6 +109,7 @@ module PacketGen
|
|
123
109
|
# @return [self]
|
124
110
|
def <<(idb)
|
125
111
|
@interfaces << idb
|
112
|
+
idb.section = self
|
126
113
|
self
|
127
114
|
end
|
128
115
|
|
@@ -137,17 +124,22 @@ module PacketGen
|
|
137
124
|
super + body
|
138
125
|
end
|
139
126
|
|
127
|
+
def add_unknown_block(block)
|
128
|
+
self.unknown_blocks << block
|
129
|
+
block.section = self
|
130
|
+
end
|
131
|
+
|
140
132
|
private
|
141
133
|
|
142
134
|
def force_endianness(endian)
|
143
135
|
@endian = endian
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
self[:
|
136
|
+
%i[type block_len magic block_len2].each do |attr|
|
137
|
+
self[attr] = Types::Int32.new(0, endian).read(self[attr].to_s)
|
138
|
+
end
|
139
|
+
%i[ver_major ver_minor].each do |attr|
|
140
|
+
self[attr] = Types::Int16.new(0, endian).read(self[attr].to_s)
|
141
|
+
end
|
142
|
+
self[:section_len] = Types::Int64.new(0, endian).read(self[:section_len].to_s)
|
151
143
|
end
|
152
144
|
|
153
145
|
# Check io contains a SHB
|
@@ -160,6 +152,21 @@ module PacketGen
|
|
160
152
|
type = type_str.unpack('H*').join
|
161
153
|
raise InvalidFileError, "Incorrect type (#{type})for Section Header Block"
|
162
154
|
end
|
155
|
+
|
156
|
+
def handle_magic_and_check(magic_str)
|
157
|
+
case magic_str
|
158
|
+
when MAGIC_LITTLE
|
159
|
+
force_endianness :little if endian == :big
|
160
|
+
when MAGIC_BIG
|
161
|
+
force_endianness :big if endian == :little
|
162
|
+
else
|
163
|
+
raise InvalidFileError, 'Incorrect magic for Section Header Block'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def read_options(io)
|
168
|
+
self[:options].read io.read(self.block_len - MIN_SIZE)
|
169
|
+
end
|
163
170
|
end
|
164
171
|
end
|
165
172
|
end
|
data/lib/packetgen/pcapng/spb.rb
CHANGED
@@ -44,7 +44,7 @@ module PacketGen
|
|
44
44
|
# @option options [Integer] :block_len2 block total length
|
45
45
|
def initialize(options={})
|
46
46
|
super
|
47
|
-
|
47
|
+
endianness(options[:endian] || :little)
|
48
48
|
recalc_block_len
|
49
49
|
self.type = options[:type] || PcapNG::SPB_TYPE.to_i
|
50
50
|
end
|
@@ -66,19 +66,11 @@ module PacketGen
|
|
66
66
|
self[:type].read io.read(4)
|
67
67
|
self[:block_len].read io.read(4)
|
68
68
|
self[:orig_len].read io.read(4)
|
69
|
-
|
70
|
-
# CAUTION: snaplen == 0 -> no capture limit
|
71
|
-
data_len = if interface && interface.snaplen.to_i.positive?
|
72
|
-
[self[:orig_len].to_i, interface.snaplen.to_i].min
|
73
|
-
else
|
74
|
-
self[:orig_len].to_i
|
75
|
-
end
|
76
|
-
data_pad_len = (4 - (data_len % 4)) % 4
|
69
|
+
data_len = compute_data_len
|
77
70
|
self[:data].read io.read(data_len)
|
78
|
-
io
|
79
|
-
|
71
|
+
remove_padding(io, data_len)
|
72
|
+
read_blocklen2_and_check(io)
|
80
73
|
|
81
|
-
check_len_coherency
|
82
74
|
self.type ||= PcapNG::IDB_TYPE.to_i
|
83
75
|
self
|
84
76
|
end
|
@@ -90,6 +82,18 @@ module PacketGen
|
|
90
82
|
recalc_block_len
|
91
83
|
super
|
92
84
|
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# Take care of IDB snaplen
|
89
|
+
# CAUTION: snaplen == 0 -> no capture limit
|
90
|
+
def compute_data_len
|
91
|
+
if interface && interface.snaplen.to_i.positive?
|
92
|
+
[self[:orig_len].to_i, interface.snaplen.to_i].min
|
93
|
+
else
|
94
|
+
self[:orig_len].to_i
|
95
|
+
end
|
96
|
+
end
|
93
97
|
end
|
94
98
|
end
|
95
99
|
end
|
@@ -29,7 +29,7 @@ module PacketGen
|
|
29
29
|
# @option options [Integer] :block_len2 block total length
|
30
30
|
def initialize(options={})
|
31
31
|
super
|
32
|
-
|
32
|
+
endianness(options[:endian] || :little)
|
33
33
|
recalc_block_len
|
34
34
|
end
|
35
35
|
|
@@ -44,21 +44,13 @@ module PacketGen
|
|
44
44
|
# @param [::String,IO] str_or_io
|
45
45
|
# @return [self]
|
46
46
|
def read(str_or_io)
|
47
|
-
io =
|
48
|
-
str_or_io
|
49
|
-
else
|
50
|
-
StringIO.new(force_binary(str_or_io.to_s))
|
51
|
-
end
|
47
|
+
io = to_io(str_or_io)
|
52
48
|
return self if io.eof?
|
53
49
|
|
54
50
|
self[:type].read io.read(4)
|
55
51
|
self[:block_len].read io.read(4)
|
56
52
|
self[:body].read io.read(self[:block_len].to_i - MIN_SIZE)
|
57
|
-
|
58
|
-
|
59
|
-
unless self[:block_len].to_i == self[:block_len2].to_i
|
60
|
-
raise InvalidFileError, 'Incoherency in Header Block'
|
61
|
-
end
|
53
|
+
read_blocklen2_and_check(io)
|
62
54
|
|
63
55
|
self
|
64
56
|
end
|
@@ -38,6 +38,8 @@ module PacketGen
|
|
38
38
|
pcap.activate
|
39
39
|
end
|
40
40
|
|
41
|
+
# rubocop:disable Metrics/ParameterLists
|
42
|
+
|
41
43
|
# Capture packets from a network interface
|
42
44
|
# @param [String] iface interface name
|
43
45
|
# @param [Integer] snaplen
|
@@ -49,14 +51,14 @@ module PacketGen
|
|
49
51
|
# @author Sylvain Daubert
|
50
52
|
# @author optix2000 - add support for setting monitor mode
|
51
53
|
# @since 3.1.5 add monitor argument
|
52
|
-
def self.capture(iface:, snaplen: DEFAULT_SNAPLEN, promisc: DEFAULT_PROMISC, filter: nil, monitor: nil)
|
54
|
+
def self.capture(iface:, snaplen: DEFAULT_SNAPLEN, promisc: DEFAULT_PROMISC, filter: nil, monitor: nil, &block)
|
53
55
|
pcap = self.open_iface(iface: iface, snaplen: snaplen, promisc: promisc, monitor: monitor)
|
54
56
|
pcap.setfilter filter unless filter.nil?
|
55
|
-
pcap.each
|
56
|
-
yield packet_data
|
57
|
-
end
|
57
|
+
pcap.each(&block)
|
58
58
|
end
|
59
59
|
|
60
|
+
# rubocop:enable Metrics/ParameterLists
|
61
|
+
|
60
62
|
# Inject given data onto wire
|
61
63
|
# @param [String] iface interface name
|
62
64
|
# @param [String] data to inject
|
@@ -72,10 +74,8 @@ module PacketGen
|
|
72
74
|
# @yieldparam [String] data binary packet data
|
73
75
|
# @return [void]
|
74
76
|
# @author Kent Gruber
|
75
|
-
def self.read_pcap(filename
|
76
|
-
PCAPRUB::Pcap.open_offline(filename).each_packet
|
77
|
-
yield packet
|
78
|
-
end
|
77
|
+
def self.read_pcap(filename:, &block)
|
78
|
+
PCAPRUB::Pcap.open_offline(filename).each_packet(&block)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
data/lib/packetgen/types.rb
CHANGED
@@ -58,7 +58,7 @@ module PacketGen
|
|
58
58
|
# @since 3.1.0
|
59
59
|
# @since 3.1.1 add +:aliases+ keyword to {#initialize}
|
60
60
|
class AbstractTLV < Types::Fields
|
61
|
-
include
|
61
|
+
include Fieldable
|
62
62
|
|
63
63
|
class <<self
|
64
64
|
# @return [Hash]
|
@@ -171,9 +171,8 @@ module PacketGen
|
|
171
171
|
# @return [String]
|
172
172
|
def to_human
|
173
173
|
my_value = self[:value].is_a?(String) ? self[:value].inspect : self[:value].to_human
|
174
|
-
|
174
|
+
'type:%s,length:%u,value:%s' % [human_type, length, my_value]
|
175
175
|
end
|
176
|
-
alias format_inspect to_human
|
177
176
|
|
178
177
|
private
|
179
178
|
|
@@ -27,8 +27,8 @@ module PacketGen
|
|
27
27
|
# @author Sylvain Daubert
|
28
28
|
class Array
|
29
29
|
extend Forwardable
|
30
|
-
include Inspectable
|
31
30
|
include Enumerable
|
31
|
+
include Fieldable
|
32
32
|
include LengthFrom
|
33
33
|
|
34
34
|
# @!method [](index)
|
@@ -163,11 +163,8 @@ module PacketGen
|
|
163
163
|
return self if @counter&.to_i&.zero?
|
164
164
|
|
165
165
|
str = read_with_length_from(str)
|
166
|
-
klass = self.class.set_of_klass
|
167
166
|
until str.empty?
|
168
|
-
obj =
|
169
|
-
real_klass = real_type(obj)
|
170
|
-
obj = real_klass.new.read(str) unless real_klass == klass
|
167
|
+
obj = create_object_from_str(str)
|
171
168
|
@array << obj
|
172
169
|
str.slice!(0, obj.sz)
|
173
170
|
break if @counter && self.size == @counter.to_i
|
@@ -198,15 +195,12 @@ module PacketGen
|
|
198
195
|
def to_human
|
199
196
|
@array.map(&:to_human).join(self.class::HUMAN_SEPARATOR)
|
200
197
|
end
|
201
|
-
alias format_inspect to_human
|
202
198
|
|
203
199
|
private
|
204
200
|
|
205
201
|
def record_from_hash(hsh)
|
206
202
|
obj_klass = self.class.set_of_klass
|
207
|
-
unless obj_klass
|
208
|
-
raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of'
|
209
|
-
end
|
203
|
+
raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of' unless obj_klass
|
210
204
|
|
211
205
|
obj = obj_klass.new(hsh) if obj_klass
|
212
206
|
klass = real_type(obj)
|
@@ -216,6 +210,18 @@ module PacketGen
|
|
216
210
|
def real_type(obj)
|
217
211
|
obj.class
|
218
212
|
end
|
213
|
+
|
214
|
+
def create_object_from_str(str)
|
215
|
+
klass = self.class.set_of_klass
|
216
|
+
obj = klass.new.read(str)
|
217
|
+
real_klass = real_type(obj)
|
218
|
+
|
219
|
+
if real_klass == klass
|
220
|
+
obj
|
221
|
+
else
|
222
|
+
real_klass.new.read(str)
|
223
|
+
end
|
224
|
+
end
|
219
225
|
end
|
220
226
|
|
221
227
|
# Specialized array to handle serie of {Int8}.
|
@@ -6,17 +6,29 @@
|
|
6
6
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
7
7
|
# This program is published under MIT license.
|
8
8
|
|
9
|
+
require 'forwardable'
|
10
|
+
|
9
11
|
module PacketGen
|
10
12
|
module Types
|
11
13
|
# This class handles null-terminated strings (aka C strings).
|
12
14
|
# @author Sylvain Daubert
|
13
|
-
|
14
|
-
|
15
|
+
# @since 3.1.6 no more a subclass or regular String
|
16
|
+
class CString
|
17
|
+
extend Forwardable
|
18
|
+
include Fieldable
|
19
|
+
|
20
|
+
def_delegators :@string, :[], :length, :size, :inspect, :==, :<<,
|
21
|
+
:unpack, :force_encoding, :encoding, :index, :empty?
|
22
|
+
|
23
|
+
# @return [::String]
|
24
|
+
attr_reader :string
|
25
|
+
# @return [Integer]
|
26
|
+
attr_reader :static_length
|
15
27
|
|
16
28
|
# @param [Hash] options
|
17
29
|
# @option options [Integer] :static_length set a static length for this string
|
18
30
|
def initialize(options={})
|
19
|
-
|
31
|
+
register_internal_string ''
|
20
32
|
@static_length = options[:static_length]
|
21
33
|
end
|
22
34
|
|
@@ -24,38 +36,41 @@ module PacketGen
|
|
24
36
|
# @return [String] self
|
25
37
|
def read(str)
|
26
38
|
s = str.to_s
|
27
|
-
s = s[0,
|
39
|
+
s = s[0, static_length] if static_length?
|
28
40
|
idx = s.index(0.chr)
|
29
41
|
s = s[0, idx] unless idx.nil?
|
30
|
-
|
42
|
+
register_internal_string s
|
31
43
|
self
|
32
44
|
end
|
33
45
|
|
34
46
|
# get null-terminated string
|
35
47
|
# @return [String]
|
36
48
|
def to_s
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
s[-1] = "\x00".encode(s.encoding)
|
41
|
-
PacketGen.force_binary s
|
42
|
-
else
|
43
|
-
PacketGen.force_binary(self + "\0" * (@static_length - self.length))
|
44
|
-
end
|
49
|
+
if static_length?
|
50
|
+
s = string[0, static_length - 1]
|
51
|
+
s << "\x00" * (static_length - s.length)
|
45
52
|
else
|
46
|
-
|
53
|
+
s = "#{string}\x00"
|
47
54
|
end
|
55
|
+
PacketGen.force_binary(s)
|
48
56
|
end
|
49
57
|
|
50
58
|
# @return [Integer]
|
51
59
|
def sz
|
52
|
-
if
|
53
|
-
|
60
|
+
if static_length?
|
61
|
+
static_length
|
54
62
|
else
|
55
63
|
to_s.size
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
67
|
+
# Say if a static length is defined
|
68
|
+
# @return [Boolean]
|
69
|
+
# @since 3.1.6
|
70
|
+
def static_length?
|
71
|
+
!static_length.nil?
|
72
|
+
end
|
73
|
+
|
59
74
|
# Populate CString from a human readable string
|
60
75
|
# @param [String] str
|
61
76
|
# @return [self]
|
@@ -68,7 +83,13 @@ module PacketGen
|
|
68
83
|
idx = self.index(+"\x00".encode(self.encoding)) || self.sz
|
69
84
|
self[0, idx]
|
70
85
|
end
|
71
|
-
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def register_internal_string(str)
|
90
|
+
@string = str
|
91
|
+
PacketGen.force_binary(@string)
|
92
|
+
end
|
72
93
|
end
|
73
94
|
end
|
74
95
|
end
|