packetgen 3.2.1 → 3.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/packetgen/header/dhcpv6/duid.rb +6 -0
- data/lib/packetgen/header/http/headers.rb +16 -1
- data/lib/packetgen/header/ip/option.rb +34 -9
- data/lib/packetgen/header/snmp.rb +19 -2
- data/lib/packetgen/types/array.rb +30 -15
- data/lib/packetgen/unknown_packet.rb +3 -2
- data/lib/packetgen/utils.rb +19 -10
- data/lib/packetgen/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad942df146df9daf8c38e049fc112b13c93fd38a45362e8dd2a43c6e8382b224
|
4
|
+
data.tar.gz: 77b48a6af0170a912e91b888456c31881bfe1fd30a693796c849a946b5e27bac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98f7f9d7dd652741cdce08cbe081310c4f4ca6745702efc5755806614f30c7930498610f9925a6d7abeef1b8b64abfa2857c77bcc638872f31577fe587ad1e63
|
7
|
+
data.tar.gz: cc4e18519b09f7eaa753f9f2e4a500c5b3d0de2aed5bbd275b636d5c21ec763dca2a34da27a16336d65e2ec86d827812c0f546c5e67dfd9b500d683f8baac7ac
|
@@ -34,13 +34,28 @@ module PacketGen
|
|
34
34
|
|
35
35
|
k, v = h.split(':', 2)
|
36
36
|
[k, v.strip]
|
37
|
-
end.
|
37
|
+
end.compact.to_h
|
38
38
|
when Hash
|
39
39
|
@data = s_or_h
|
40
40
|
end
|
41
41
|
self
|
42
42
|
end
|
43
43
|
|
44
|
+
# Get header value from its name
|
45
|
+
# @param [String] header header name
|
46
|
+
# @return [String] header value
|
47
|
+
def [](header)
|
48
|
+
data[header]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Say if +self+ include +header+ header
|
52
|
+
# @param [String] header header name
|
53
|
+
# @return [Boolean]
|
54
|
+
def header?(header)
|
55
|
+
data.key?(header)
|
56
|
+
end
|
57
|
+
alias has_header? header?
|
58
|
+
|
44
59
|
# Get binary string.
|
45
60
|
# @return [String]
|
46
61
|
def to_s
|
@@ -86,25 +86,23 @@ module PacketGen
|
|
86
86
|
# Factory to build an option from its type
|
87
87
|
# @return [Option]
|
88
88
|
def self.build(options={})
|
89
|
-
type = options
|
89
|
+
type = options[:type]
|
90
90
|
klass = case type
|
91
91
|
when String
|
92
92
|
types.key?(type) ? IP.const_get(type) : self
|
93
|
-
when Integer
|
94
|
-
types.value?(type) ? IP.const_get(types.key(type)) : self
|
95
93
|
else
|
96
|
-
self
|
94
|
+
types.value?(type) ? IP.const_get(types.key(type.to_i)) : self
|
97
95
|
end
|
96
|
+
options.delete(:type) if klass != self
|
98
97
|
klass.new(options)
|
99
98
|
end
|
100
99
|
|
101
100
|
def initialize(options={})
|
102
|
-
unless options[:type]
|
103
|
-
|
104
|
-
options[:type] = Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE"
|
105
|
-
end
|
101
|
+
options[:type] = class2type unless options[:type]
|
102
|
+
|
106
103
|
super
|
107
|
-
|
104
|
+
initialize_length_if_needed(options)
|
105
|
+
initialize_data_if_needed(options)
|
108
106
|
end
|
109
107
|
|
110
108
|
# Get binary string. Set {#length} field.
|
@@ -121,6 +119,25 @@ module PacketGen
|
|
121
119
|
str << ":#{self[:data].to_s.inspect}" if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty?
|
122
120
|
str
|
123
121
|
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def class2type
|
126
|
+
opt_name = self.class.to_s.gsub(/.*::/, '')
|
127
|
+
Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE"
|
128
|
+
end
|
129
|
+
|
130
|
+
def initialize_length_if_needed(options)
|
131
|
+
self.length = sz if respond_to?(:length) && options[:length].nil?
|
132
|
+
end
|
133
|
+
|
134
|
+
def initialize_data_if_needed(options)
|
135
|
+
return unless fields.include?(:data) && self[:data].respond_to?(:from_human) && options.key?(:data)
|
136
|
+
|
137
|
+
# Force data if data is set in options but not length
|
138
|
+
self.length += options[:data].size
|
139
|
+
self[:data].from_human(options[:data])
|
140
|
+
end
|
124
141
|
end
|
125
142
|
|
126
143
|
# End-of-option-List IP option
|
@@ -173,6 +190,10 @@ module PacketGen
|
|
173
190
|
# 16-bit stream ID
|
174
191
|
# @return [Integer]
|
175
192
|
define_field :id, Types::Int16
|
193
|
+
|
194
|
+
def to_human
|
195
|
+
super << ":#{self.id}"
|
196
|
+
end
|
176
197
|
end
|
177
198
|
|
178
199
|
# Router Alert IP option
|
@@ -183,6 +204,10 @@ module PacketGen
|
|
183
204
|
# 16-bit value. Should be 0.
|
184
205
|
# @return [Integer]
|
185
206
|
define_field :value, Types::Int16, default: 0
|
207
|
+
|
208
|
+
def to_human
|
209
|
+
super << ":#{self.value}"
|
210
|
+
end
|
186
211
|
end
|
187
212
|
end
|
188
213
|
end
|
@@ -74,6 +74,18 @@ module PacketGen
|
|
74
74
|
# @author Sylvain Daubert
|
75
75
|
class VariableBindings < RASN1::Model
|
76
76
|
sequence_of :bindings, VarBind
|
77
|
+
|
78
|
+
# Get 'idx'th element from the list
|
79
|
+
# @return [VarBind,nil]
|
80
|
+
def [](idx)
|
81
|
+
value[idx]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get element counts in list
|
85
|
+
# @return [Integer]
|
86
|
+
def size
|
87
|
+
value.size
|
88
|
+
end
|
77
89
|
end
|
78
90
|
|
79
91
|
# Class to handle GetRequest PDU
|
@@ -119,6 +131,10 @@ module PacketGen
|
|
119
131
|
integer(:error, value: 0, enum: ERRORS),
|
120
132
|
integer(:error_index, value: 0),
|
121
133
|
model(:varbindlist, VariableBindings)]
|
134
|
+
|
135
|
+
def initialize(args={})
|
136
|
+
super
|
137
|
+
end
|
122
138
|
end
|
123
139
|
|
124
140
|
# Class to handle GetNextRequest PDU
|
@@ -264,11 +280,12 @@ module PacketGen
|
|
264
280
|
data.chosen = options[:chosen_pdu] if options[:chosen_pdu]
|
265
281
|
return unless options[:pdu]
|
266
282
|
|
267
|
-
|
283
|
+
klass = data.root.chosen_value.class
|
284
|
+
data.root.value[data.chosen] = klass.new(options[:pdu])
|
268
285
|
end
|
269
286
|
|
270
287
|
# accessor to data payload
|
271
|
-
# @return [
|
288
|
+
# @return [ASN1::Types::Choice]
|
272
289
|
def data
|
273
290
|
@elements[:data]
|
274
291
|
end
|
@@ -154,26 +154,19 @@ module PacketGen
|
|
154
154
|
self
|
155
155
|
end
|
156
156
|
|
157
|
-
#
|
158
|
-
|
159
|
-
# Populate object from a string
|
160
|
-
# @param [String] str
|
157
|
+
# Populate object from a string or from an array of hashes
|
158
|
+
# @param [String, Array<Hash>] data
|
161
159
|
# @return [self]
|
162
|
-
def read(
|
160
|
+
def read(data)
|
163
161
|
clear
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
obj = create_object_from_str(str)
|
170
|
-
@array << obj
|
171
|
-
str.slice!(0, obj.sz)
|
172
|
-
break if @counter && self.size == @counter.to_i
|
162
|
+
case data
|
163
|
+
when ::Array
|
164
|
+
read_from_array(data)
|
165
|
+
else
|
166
|
+
read_from_string(data)
|
173
167
|
end
|
174
168
|
self
|
175
169
|
end
|
176
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
177
170
|
|
178
171
|
# Get size in bytes
|
179
172
|
# @return [Integer]
|
@@ -201,6 +194,28 @@ module PacketGen
|
|
201
194
|
|
202
195
|
private
|
203
196
|
|
197
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
198
|
+
|
199
|
+
def read_from_string(str)
|
200
|
+
return self if str.nil? || @counter&.to_i&.zero?
|
201
|
+
|
202
|
+
str = read_with_length_from(str)
|
203
|
+
until str.empty? || (@counter && self.size == @counter.to_i)
|
204
|
+
obj = create_object_from_str(str)
|
205
|
+
@array << obj
|
206
|
+
str.slice!(0, obj.sz)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
210
|
+
|
211
|
+
def read_from_array(ary)
|
212
|
+
return self if ary.empty?
|
213
|
+
|
214
|
+
ary.each do |hsh|
|
215
|
+
self << hsh
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
204
219
|
def record_from_hash(hsh)
|
205
220
|
obj_klass = self.class.set_of_klass
|
206
221
|
raise NotImplementedError, 'class should define #record_from_hash or declare type of elements in set with .set_of' unless obj_klass
|
@@ -61,7 +61,8 @@ module PacketGen
|
|
61
61
|
|
62
62
|
# @return [String]
|
63
63
|
def inspect
|
64
|
-
|
64
|
+
str = Inspect.dashed_line(self.class)
|
65
|
+
str << Inspect.inspect_body(body)
|
65
66
|
end
|
66
67
|
|
67
68
|
# equality if {#to_s} is equal
|
@@ -74,7 +75,7 @@ module PacketGen
|
|
74
75
|
# @return [Boolean]
|
75
76
|
def ===(other)
|
76
77
|
case other
|
77
|
-
when
|
78
|
+
when UnknownPacket
|
78
79
|
self == other
|
79
80
|
else
|
80
81
|
false
|
data/lib/packetgen/utils.rb
CHANGED
@@ -25,23 +25,32 @@ module PacketGen
|
|
25
25
|
' (ip dst %<target2>s and not ip src %<local_ip>s))' \
|
26
26
|
' and ether dst %<local_mac>s'
|
27
27
|
|
28
|
+
# @private
|
29
|
+
ARP_PATH = '/usr/sbin/arp'
|
30
|
+
# @private
|
31
|
+
IP_PATH = '/usr/bin/ip'
|
32
|
+
# @private
|
33
|
+
ARP_LINE_RE = /\((\d+\.\d+\.\d+\.\d+)\) at (([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})(?: \[ether\])? on (\w+)/.freeze
|
34
|
+
# @private
|
35
|
+
IP_LINE_RE = /^(\d+\.\d+\.\d+\.\d+) dev (\w+) lladdr (([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})/.freeze
|
36
|
+
|
28
37
|
# Get local ARP cache
|
29
38
|
# @return [Hash] key: IP address, value: array containing MAC address and
|
30
39
|
# interface name
|
31
40
|
def self.arp_cache
|
32
|
-
return self.cache_from_arp_command if File.exist?(
|
33
|
-
return self.cache_from_ip_command if File.exist?(
|
41
|
+
return self.cache_from_arp_command if File.exist?(ARP_PATH)
|
42
|
+
return self.cache_from_ip_command if File.exist?(IP_PATH)
|
34
43
|
|
35
44
|
{}
|
36
45
|
end
|
37
46
|
|
38
47
|
# @private
|
39
|
-
def self.cache_from_arp_command
|
40
|
-
raw_cache
|
48
|
+
def self.cache_from_arp_command(raw_cache=nil)
|
49
|
+
raw_cache ||= `#{ARP_PATH} -an`
|
41
50
|
|
42
51
|
cache = {}
|
43
52
|
raw_cache.split("\n").each do |line|
|
44
|
-
match = line.match(
|
53
|
+
match = line.match(ARP_LINE_RE)
|
45
54
|
cache[match[1]] = [match[2], match[4]] if match
|
46
55
|
end
|
47
56
|
|
@@ -49,12 +58,12 @@ module PacketGen
|
|
49
58
|
end
|
50
59
|
|
51
60
|
# @private
|
52
|
-
def self.cache_from_ip_command
|
53
|
-
raw_cache
|
61
|
+
def self.cache_from_ip_command(raw_cache=nil)
|
62
|
+
raw_cache ||= `#{IP_PATH} neigh`
|
54
63
|
|
55
64
|
cache = {}
|
56
65
|
raw_cache.split("\n").each do |line|
|
57
|
-
match = line.match(
|
66
|
+
match = line.match(IP_LINE_RE)
|
58
67
|
cache[match[1]] = [match[3], match[2]] if match
|
59
68
|
end
|
60
69
|
|
@@ -155,7 +164,7 @@ module PacketGen
|
|
155
164
|
# end
|
156
165
|
# @since 2.2.0
|
157
166
|
# @raise [RuntimeError] user don't have permission to capture packets on network device.
|
158
|
-
def self.mitm(target1, target2, options={})
|
167
|
+
def self.mitm(target1, target2, options={}, &block)
|
159
168
|
options = { iface: PacketGen.default_iface }.merge(options)
|
160
169
|
|
161
170
|
spoofer = Utils::ARPSpoofer.new(options)
|
@@ -168,7 +177,7 @@ module PacketGen
|
|
168
177
|
filter: MITM_FILTER % { target1: target1, target2: target2, local_ip: cfg.ipaddr(options[:iface]), local_mac: my_mac })
|
169
178
|
|
170
179
|
spoofer.start_all
|
171
|
-
mitm_core(capture, target1, target2, my_mac, &
|
180
|
+
mitm_core(capture, target1, target2, my_mac, &block)
|
172
181
|
spoofer.stop_all
|
173
182
|
end
|
174
183
|
|
data/lib/packetgen/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: packetgen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Daubert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: interfacez
|