packetgen 3.1.8 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|