packetgen 3.1.8 → 3.2.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/lib/packetgen.rb +10 -1
- data/lib/packetgen/capture.rb +5 -1
- data/lib/packetgen/header/asn1_base.rb +19 -9
- data/lib/packetgen/header/dot11/data.rb +19 -29
- data/lib/packetgen/header/http/request.rb +5 -1
- data/lib/packetgen/header/http/response.rb +10 -4
- data/lib/packetgen/header/http/verbs.rb +1 -1
- data/lib/packetgen/header/ospfv2/lsa.rb +7 -3
- data/lib/packetgen/header/ospfv3/lsa.rb +7 -3
- data/lib/packetgen/packet.rb +3 -3
- data/lib/packetgen/pcapng/file.rb +4 -2
- data/lib/packetgen/unknown_packet.rb +84 -0
- data/lib/packetgen/utils.rb +5 -6
- data/lib/packetgen/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f3faa715cd36e918df79355267c50690bdde15f1566e23947d26890e7b89a82
|
4
|
+
data.tar.gz: d374447f230500b0c5be84b225d3a5576f019afc4870dc6512c659bc2e069d67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de7911facea630eaa2d3d4afd2ae15e1cbd927241ebf0c63ec096c64eac31c58e519d379476763c50fc1b4290029cec4b14dbf9e96ae9aa05dc06701cf45af32
|
7
|
+
data.tar.gz: 69881fc66b4af80177bdad4b5b2daa4bd28259596bbf8a36112998aa9a8c117c7c9898180372635fcc1b47376e2fab4fb5cece88be5c000277cdce825fb03168
|
data/lib/packetgen.rb
CHANGED
@@ -95,7 +95,15 @@ module PacketGen
|
|
95
95
|
# Get default network interface (ie. first non-loopback declared interface)
|
96
96
|
# @return [String]
|
97
97
|
def self.default_iface
|
98
|
-
|
98
|
+
return @default_iface if defined? @default_iface
|
99
|
+
|
100
|
+
@default_iface = Interfacez.raw_interface_addresses.each do |iface|
|
101
|
+
next unless iface.broadaddr
|
102
|
+
next unless Interfacez.ipv4_address_of(iface.name)
|
103
|
+
next unless Interfacez.ipv6_address_of(iface.name)
|
104
|
+
|
105
|
+
break iface.name
|
106
|
+
end
|
99
107
|
end
|
100
108
|
|
101
109
|
# Get loopback network interface
|
@@ -126,6 +134,7 @@ require 'packetgen/types'
|
|
126
134
|
require 'packetgen/pcapng'
|
127
135
|
require 'packetgen/pcap'
|
128
136
|
require 'packetgen/packet'
|
137
|
+
require 'packetgen/unknown_packet'
|
129
138
|
require 'packetgen/capture'
|
130
139
|
require 'packetgen/inject'
|
131
140
|
require 'packetgen/proto'
|
data/lib/packetgen/capture.rb
CHANGED
@@ -122,7 +122,11 @@ module PacketGen
|
|
122
122
|
def add_packet(data, &block)
|
123
123
|
raw_packets << data
|
124
124
|
if @parse
|
125
|
-
|
125
|
+
begin
|
126
|
+
packet = Packet.parse(data)
|
127
|
+
rescue ParseError
|
128
|
+
packet = UnknownPacket.new.parse(data)
|
129
|
+
end
|
126
130
|
packets << packet
|
127
131
|
block&.call(packet)
|
128
132
|
elsif block
|
@@ -19,14 +19,20 @@ module PacketGen
|
|
19
19
|
class ASN1Base < RASN1::Model
|
20
20
|
include Headerable
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
class <<self
|
23
|
+
# Define some methods from given ASN.1 fields to mimic {Base} attributes
|
24
|
+
# @param [Array<Symbol>] attributes
|
25
|
+
# @return [void]
|
26
|
+
def define_attributes(*attributes)
|
27
|
+
@attributes = attributes
|
28
|
+
attributes.each do |attr|
|
29
|
+
class_eval "def #{attr}; @elements[:#{attr}].value; end\n" \
|
30
|
+
"def #{attr}=(v); @elements[:#{attr}].value = v; end"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def known_headers
|
35
|
+
@known_headers ||= {}.freeze
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
@@ -37,7 +43,11 @@ module PacketGen
|
|
37
43
|
# @param [String] str
|
38
44
|
# @return [ASN1Base] self
|
39
45
|
def read(str)
|
40
|
-
|
46
|
+
begin
|
47
|
+
parse(str, ber: true)
|
48
|
+
rescue RASN1::ASN1Error
|
49
|
+
# suppress exception to allow guessing
|
50
|
+
end
|
41
51
|
self
|
42
52
|
end
|
43
53
|
|
@@ -67,59 +67,49 @@ module PacketGen
|
|
67
67
|
# Get destination MAC address
|
68
68
|
# @return [String]
|
69
69
|
def dst
|
70
|
-
|
71
|
-
|
72
|
-
when 0, 2
|
73
|
-
self.mac1
|
74
|
-
when 1, 3
|
75
|
-
self.mac3
|
76
|
-
end
|
70
|
+
_src_mac, dst_mac = src_dst_from_mac
|
71
|
+
self.send(dst_mac)
|
77
72
|
end
|
78
73
|
|
79
74
|
# Set destination MAC address
|
80
75
|
# @param [String] mac MAC address to set
|
81
76
|
# @return [String]
|
82
77
|
def dst=(mac)
|
83
|
-
|
84
|
-
|
85
|
-
when 0, 2
|
86
|
-
self.mac1 = mac
|
87
|
-
when 1, 3
|
88
|
-
self.mac3 = mac
|
89
|
-
end
|
78
|
+
_src_mac, dst_mac = src_dst_from_mac
|
79
|
+
self.send("#{dst_mac}=", mac)
|
90
80
|
end
|
91
81
|
|
92
82
|
# Get source MAC address
|
93
83
|
# @return [String]
|
94
84
|
def src
|
95
|
-
|
96
|
-
|
97
|
-
when 0, 1
|
98
|
-
self.mac2
|
99
|
-
when 2
|
100
|
-
self.mac3
|
101
|
-
when 3
|
102
|
-
self.mac4
|
103
|
-
end
|
85
|
+
src_mac, = src_dst_from_mac
|
86
|
+
self.send(src_mac)
|
104
87
|
end
|
105
88
|
|
106
89
|
# Set source MAC address
|
107
90
|
# @param [String] mac MAC address to set
|
108
91
|
# @return [String]
|
109
92
|
def src=(mac)
|
93
|
+
src_mac, = src_dst_from_mac
|
94
|
+
self.send("#{src_mac}=", mac)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def src_dst_from_mac
|
110
100
|
ds = frame_ctrl & 3
|
111
101
|
case ds
|
112
|
-
when 0
|
113
|
-
|
102
|
+
when 0
|
103
|
+
%i[mac2 mac1]
|
104
|
+
when 1
|
105
|
+
%i[mac2 mac3]
|
114
106
|
when 2
|
115
|
-
|
107
|
+
%i[mac3 mac1]
|
116
108
|
when 3
|
117
|
-
|
109
|
+
%i[mac4 mac3]
|
118
110
|
end
|
119
111
|
end
|
120
112
|
|
121
|
-
private
|
122
|
-
|
123
113
|
def define_applicable_fields
|
124
114
|
super
|
125
115
|
if (subtype >= 8) && !@applicable_fields.include?(:qos_ctrl)
|
@@ -81,6 +81,10 @@ module PacketGen
|
|
81
81
|
self
|
82
82
|
end
|
83
83
|
|
84
|
+
def parse?
|
85
|
+
VERBS.include?(self.verb) && self.version.start_with?('HTTP/1.')
|
86
|
+
end
|
87
|
+
|
84
88
|
# String representation of data.
|
85
89
|
# @return [String]
|
86
90
|
def to_s
|
@@ -116,6 +120,6 @@ module PacketGen
|
|
116
120
|
end
|
117
121
|
|
118
122
|
self.add_class HTTP::Request
|
119
|
-
TCP.bind HTTP::Request, body: ->(b) { HTTP::REQUEST_REGEX =~ b
|
123
|
+
TCP.bind HTTP::Request, body: ->(b) { b.nil? ? '' : HTTP::REQUEST_REGEX =~ b }
|
120
124
|
end
|
121
125
|
end
|
@@ -87,15 +87,21 @@ module PacketGen
|
|
87
87
|
end
|
88
88
|
unless headers.empty?
|
89
89
|
first_line = headers.shift.split
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
if first_line.size >= 3
|
91
|
+
self[:version].read first_line[0]
|
92
|
+
self[:status_code].read first_line[1]
|
93
|
+
self[:status_mesg].read first_line[2..-1].join(' ')
|
94
|
+
end
|
93
95
|
self[:headers].read(headers.join("\n"))
|
94
96
|
end
|
95
97
|
self[:body].read data.join("\n")
|
96
98
|
self
|
97
99
|
end
|
98
100
|
|
101
|
+
def parse?
|
102
|
+
version.start_with?('HTTP/1.')
|
103
|
+
end
|
104
|
+
|
99
105
|
# String representation of data.
|
100
106
|
# @return [String]
|
101
107
|
def to_s
|
@@ -112,6 +118,6 @@ module PacketGen
|
|
112
118
|
end
|
113
119
|
|
114
120
|
self.add_class HTTP::Response
|
115
|
-
TCP.bind HTTP::Response, body: ->(b) { %r[^HTTP/1\.1\s\d{3,}\s.+] =~ b
|
121
|
+
TCP.bind HTTP::Response, body: ->(b) { b.nil? ? '' : %r[^HTTP/1\.1\s\d{3,}\s.+] =~ b }
|
116
122
|
end
|
117
123
|
end
|
@@ -16,7 +16,7 @@ module PacketGen
|
|
16
16
|
VERBS = %w[GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATCH].freeze
|
17
17
|
|
18
18
|
# Identifiable HTTP request regular expression.
|
19
|
-
REQUEST_REGEX = Regexp.new("(#{VERBS.dup.join('|')})\\s+\\S+\\s+HTTP/1.1")
|
19
|
+
REQUEST_REGEX = Regexp.new("^(#{VERBS.dup.join('|')})\\s+\\S+\\s+HTTP/1.1")
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -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
|
@@ -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
|
data/lib/packetgen/packet.rb
CHANGED
@@ -81,7 +81,7 @@ module PacketGen
|
|
81
81
|
# @return [Array<Packet>] captured packet
|
82
82
|
def self.capture(**kwargs, &block)
|
83
83
|
capture = Capture.new(**kwargs)
|
84
|
-
if
|
84
|
+
if block
|
85
85
|
capture.start(&block)
|
86
86
|
else
|
87
87
|
capture.start
|
@@ -216,7 +216,7 @@ module PacketGen
|
|
216
216
|
# @return [Array] see return from {PcapNG::File#to_file}
|
217
217
|
# @see File
|
218
218
|
def to_f(filename)
|
219
|
-
PcapNG::File.new.
|
219
|
+
PcapNG::File.new.read_array([self]).to_f(filename)
|
220
220
|
end
|
221
221
|
alias write to_f
|
222
222
|
|
@@ -287,7 +287,7 @@ module PacketGen
|
|
287
287
|
if first_header.nil?
|
288
288
|
# No decoding forced for first header. Have to guess it!
|
289
289
|
first_header = guess_first_header(binary_str)
|
290
|
-
raise ParseError,
|
290
|
+
raise ParseError, "cannot identify first header in string: #{binary_str.inspect}" if first_header.nil?
|
291
291
|
end
|
292
292
|
|
293
293
|
add first_header
|
@@ -264,7 +264,7 @@ module PacketGen
|
|
264
264
|
# @param [Time, nil] timestamp initial timestamp, used for first packet
|
265
265
|
# @param [Numeric, nil] ts_inc timestamp increment, in seconds, to increment
|
266
266
|
# initial timestamp for each packet
|
267
|
-
# @return [
|
267
|
+
# @return [self]
|
268
268
|
# @note if +timestamp+ and/or +ts_inc+ are nil, {SPB} sections are created
|
269
269
|
# for each packet, else {EPB} ones are used
|
270
270
|
# @since 3.1.6
|
@@ -276,11 +276,12 @@ module PacketGen
|
|
276
276
|
classify_block(section, block)
|
277
277
|
ts = update_ts(ts, ts_inc)
|
278
278
|
end
|
279
|
+
self
|
279
280
|
end
|
280
281
|
|
281
282
|
# Update current object from a hash of packets and timestamps
|
282
283
|
# @param [Hash{Time => Packet}] hsh
|
283
|
-
# @return [
|
284
|
+
# @return [self]
|
284
285
|
# @since 3.1.6
|
285
286
|
def read_hash(hsh)
|
286
287
|
section = create_new_shb_section
|
@@ -288,6 +289,7 @@ module PacketGen
|
|
288
289
|
block = create_block_from_pkt(pkt, section, ts, 0)
|
289
290
|
classify_block(section, block)
|
290
291
|
end
|
292
|
+
self
|
291
293
|
end
|
292
294
|
|
293
295
|
# @return [String]
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# This file is part of PacketGen
|
5
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
6
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
7
|
+
# This program is published under MIT license.
|
8
|
+
|
9
|
+
module PacketGen
|
10
|
+
# Unknown packet, minimaly mimicking a {Packet}.
|
11
|
+
#
|
12
|
+
# An unknown packet is generated when capturing packets, and a packet cannot
|
13
|
+
# be parsed.
|
14
|
+
# @since 3.2.0
|
15
|
+
class UnknownPacket
|
16
|
+
# List of headers. Always empty
|
17
|
+
# @return [Array]
|
18
|
+
attr_reader :headers
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@headers = [].freeze
|
22
|
+
@binary_str = PacketGen.force_binary('')
|
23
|
+
end
|
24
|
+
|
25
|
+
# Unknown packet, so unknown protocol.
|
26
|
+
# @return [false]
|
27
|
+
def is?(_protocol)
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get packet body
|
32
|
+
# @return [Types]
|
33
|
+
def body
|
34
|
+
@binary_str
|
35
|
+
end
|
36
|
+
alias to_s body
|
37
|
+
|
38
|
+
# Set packet body
|
39
|
+
# @param [String] str
|
40
|
+
# @return [void]
|
41
|
+
def body=(str)
|
42
|
+
@binary_str = PacketGen.force_binary(str)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Write packet to a PCapNG file on disk.
|
46
|
+
# @param [String] filename
|
47
|
+
# @return [Array] see return from {PcapNG::File#to_file}
|
48
|
+
# @see File
|
49
|
+
def to_f(filename)
|
50
|
+
PcapNG::File.new.read_array([self]).to_f(filename)
|
51
|
+
end
|
52
|
+
alias write to_f
|
53
|
+
|
54
|
+
# Read binary string
|
55
|
+
# @param [String] binary_string
|
56
|
+
# @return [self]
|
57
|
+
def parse(binary_str, _first_header: nil)
|
58
|
+
@binary_str = PacketGen.force_binary(binary_str)
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [String]
|
63
|
+
def inspect
|
64
|
+
# TODO
|
65
|
+
end
|
66
|
+
|
67
|
+
# equality if {#to_s} is equal
|
68
|
+
# @return [Boolean]
|
69
|
+
def ==(other)
|
70
|
+
to_s == other.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
# True only if +other+ is an {UnknownPacket} and +other == self+
|
74
|
+
# @return [Boolean]
|
75
|
+
def ===(other)
|
76
|
+
case other
|
77
|
+
when UnknwonPacket
|
78
|
+
self == other
|
79
|
+
else
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/packetgen/utils.rb
CHANGED
@@ -23,7 +23,7 @@ module PacketGen
|
|
23
23
|
raw_cache = `/usr/sbin/arp -an`
|
24
24
|
|
25
25
|
cache = {}
|
26
|
-
raw_cache.split(
|
26
|
+
raw_cache.split("\n").each do |line|
|
27
27
|
match = line.match(/\((\d+\.\d+\.\d+\.\d+)\) at (([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})(?: \[ether\])? on (\w+)/)
|
28
28
|
cache[match[1]] = [match[2], match[4]] if match
|
29
29
|
end
|
@@ -46,7 +46,7 @@ module PacketGen
|
|
46
46
|
def self.arp(ipaddr, options={})
|
47
47
|
unless options[:no_cache]
|
48
48
|
local_cache = self.arp_cache
|
49
|
-
return local_cache[ipaddr].first if local_cache.key?
|
49
|
+
return local_cache[ipaddr].first if local_cache.key?(ipaddr)
|
50
50
|
end
|
51
51
|
|
52
52
|
iface = options[:iface] || PacketGen.default_iface
|
@@ -54,13 +54,12 @@ module PacketGen
|
|
54
54
|
my_hwaddr = Config.instance.hwaddr(iface)
|
55
55
|
arp_pkt = Packet.gen('Eth', dst: 'ff:ff:ff:ff:ff:ff', src: my_hwaddr)
|
56
56
|
.add('ARP', sha: Config.instance.hwaddr(iface),
|
57
|
-
|
57
|
+
spa: Config.instance.ipaddr(iface),
|
58
|
+
tpa: ipaddr)
|
58
59
|
|
59
60
|
capture = Capture.new(iface: iface, timeout: timeout, max: 1,
|
60
61
|
filter: "arp src #{ipaddr} and ether dst #{my_hwaddr}")
|
61
|
-
cap_thread = Thread.new
|
62
|
-
capture.start
|
63
|
-
end
|
62
|
+
cap_thread = Thread.new { capture.start }
|
64
63
|
|
65
64
|
arp_pkt.to_w(iface)
|
66
65
|
cap_thread.join
|
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.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Daubert
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: interfacez
|
@@ -233,10 +233,11 @@ files:
|
|
233
233
|
- lib/packetgen/types/oui.rb
|
234
234
|
- lib/packetgen/types/string.rb
|
235
235
|
- lib/packetgen/types/tlv.rb
|
236
|
+
- lib/packetgen/unknown_packet.rb
|
236
237
|
- lib/packetgen/utils.rb
|
237
238
|
- lib/packetgen/utils/arp_spoofer.rb
|
238
239
|
- lib/packetgen/version.rb
|
239
|
-
homepage:
|
240
|
+
homepage:
|
240
241
|
licenses:
|
241
242
|
- MIT
|
242
243
|
metadata:
|
@@ -245,7 +246,7 @@ metadata:
|
|
245
246
|
bug_tracker_uri: https://github.com/sdaubert/packetgen/issues
|
246
247
|
documentation_uri: https://www.rubydoc.info/gems/packetgen
|
247
248
|
wiki_uri: https://github.com/sdaubert/packetgen/wiki
|
248
|
-
post_install_message:
|
249
|
+
post_install_message:
|
249
250
|
rdoc_options:
|
250
251
|
- "--title"
|
251
252
|
- PacketGen - network packet dissector
|
@@ -266,8 +267,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
266
267
|
- !ruby/object:Gem::Version
|
267
268
|
version: '0'
|
268
269
|
requirements: []
|
269
|
-
rubygems_version: 3.2.
|
270
|
-
signing_key:
|
270
|
+
rubygems_version: 3.2.5
|
271
|
+
signing_key:
|
271
272
|
specification_version: 4
|
272
273
|
summary: Network packet generator and dissector
|
273
274
|
test_files: []
|