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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 539fce01eed5ce8711896ea7c9f22d29e3878b5165676ff673dd527c748d1fdb
4
- data.tar.gz: bd724c164c6adf60b772b1ead15f9861853f4723711fe44cfdf49520a16a78c7
3
+ metadata.gz: 8f3faa715cd36e918df79355267c50690bdde15f1566e23947d26890e7b89a82
4
+ data.tar.gz: d374447f230500b0c5be84b225d3a5576f019afc4870dc6512c659bc2e069d67
5
5
  SHA512:
6
- metadata.gz: f63e7926b399ee2550fdb29fa688bf4c580ad7b8be2f0518089e94c758d1fb84d70f9e1f148c004d5008697b6dbf83bc32637f994119126ceace6e1ef259c1a0
7
- data.tar.gz: 8be8c39afec1aee25250b7c8e7f1bbcc81f680356079cca3d179fc671f407d53a4365b6df72c58c9b2947df6e6fe1f80f28b3cb9d31f2dfa445b61aaa3de1693
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
- Interfacez.default
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'
@@ -122,7 +122,11 @@ module PacketGen
122
122
  def add_packet(data, &block)
123
123
  raw_packets << data
124
124
  if @parse
125
- packet = Packet.parse(data)
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
- # Define some methods from given ASN.1 fields to mimic {Base} attributes
23
- # @param [Array<Symbol>] attributes
24
- # @return [void]
25
- def self.define_attributes(*attributes)
26
- @attributes = attributes
27
- attributes.each do |attr|
28
- class_eval "def #{attr}; @elements[:#{attr}].value; end\n" \
29
- "def #{attr}=(v); @elements[:#{attr}].value = v; end"
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
- parse(str, ber: true)
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
- ds = frame_ctrl & 3
71
- case ds
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
- ds = frame_ctrl & 3
84
- case ds
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
- ds = frame_ctrl & 3
96
- case ds
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, 1
113
- self.mac2 = mac
102
+ when 0
103
+ %i[mac2 mac1]
104
+ when 1
105
+ %i[mac2 mac3]
114
106
  when 2
115
- self.mac3 = mac
107
+ %i[mac3 mac1]
116
108
  when 3
117
- self.mac4 = mac
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.chars.select(&:valid_encoding?).join }
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
- self[:version].read first_line[0]
91
- self[:status_code].read first_line[1]
92
- self[:status_mesg].read first_line[2..-1].join(' ')
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.chars.select(&:valid_encoding?).join }
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
- if OSPFv2.const_defined? klassname
233
- OSPFv2.const_get klassname
234
- else
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
- if OSPFv3.const_defined? klassname
222
- OSPFv3.const_get klassname
223
- else
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
@@ -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 block_given?
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.array_to_file(file: filename, array: [self])
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, 'cannot identify first header in string' if first_header.nil?
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 [void]
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 [void]
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
@@ -23,7 +23,7 @@ module PacketGen
23
23
  raw_cache = `/usr/sbin/arp -an`
24
24
 
25
25
  cache = {}
26
- raw_cache.split(/\n/).each do |line|
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? ipaddr
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
- spa: Config.instance.ipaddr(iface), tpa: ipaddr)
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 do
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
@@ -10,5 +10,5 @@
10
10
  # @author Sylvain Daubert
11
11
  module PacketGen
12
12
  # PacketGen version
13
- VERSION = '3.1.8'
13
+ VERSION = '3.2.0'
14
14
  end
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.1.8
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-03-13 00:00:00.000000000 Z
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.3
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: []