packetgen 2.5.2 → 2.6.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: 81bd9bfad83fea7f710f36b3b063385612bd457c5e6f91c8dd58c4dafdc71c81
4
- data.tar.gz: 9f12e1c56a87a4b01b5d0e228531d5de9f42a48f098253e72c07152d8adca14d
3
+ metadata.gz: df09d9bda17671562435fd055b6ab552aa3e19798251f953e1e260786bae168d
4
+ data.tar.gz: 79baa63b2cfa57534246b3806033dc6233ea9a2ae9da3c6aa0dc9dc803983d97
5
5
  SHA512:
6
- metadata.gz: be77a1686d765dd1fc03cc40e4be495bf4f1719da3e7a54578783280d03be4e45d4e910208bd39d160ae4af2bf9aae0e7a645b330702496cb5e7f4e84096f8b1
7
- data.tar.gz: 26da42851fdb12547c7744cbb52a325443c011c131b3e259b3c5cc111b0cf412bbd2b595ad5dca4c058299e82c99f4b9d87758fbeba873f81b7e03c4d02a88bd
6
+ metadata.gz: a6f3349f7d168b5b8391fa78e1ed90763295c7dc8db21bc0ee517195f96ca290172ad788c2c3fe4d2787809209fc502be4b05f00df6bc9f595709edf06136618
7
+ data.tar.gz: d218ba23d8c02253d75bd18f1ea552ce3aee8490895c0886504f443d87f18bbd0ed7c3e0ca13bc30f7bcf4db5fbb7abe7e4c0630bfc1f5fd36b750faa130e56c
@@ -113,3 +113,4 @@ require_relative 'header/mldv2'
113
113
  require_relative 'header/ospfv2'
114
114
  require_relative 'header/ospfv3'
115
115
  require_relative 'header/netbios'
116
+ require_relative 'header/mdns'
@@ -288,6 +288,19 @@ module PacketGen
288
288
  raise FormatError, 'no IP or IPv6 header in packet' if iph.nil?
289
289
  iph
290
290
  end
291
+
292
+ # @api private
293
+ # Get link layer header from given header
294
+ # @param [Header] header
295
+ # @return [Header]
296
+ # @raise FormatError no link layer header in packet
297
+ # @raise FormatError +header+ not in a packet
298
+ def ll_header(header)
299
+ hid = header_id(header)
300
+ llh = packet.headers[0...hid].reverse.find { |h| h.is_a? Eth or h.is_a? Dot11 }
301
+ raise FormatError, 'no link layer header in packet' if llh.nil?
302
+ llh
303
+ end
291
304
  end
292
305
  end
293
306
  end
@@ -269,12 +269,6 @@ module PacketGen
269
269
  end
270
270
  str
271
271
  end
272
-
273
- private
274
-
275
- def boolean2integer(bool)
276
- bool ? 1 : 0
277
- end
278
272
  end
279
273
 
280
274
  self.add_class DNS
@@ -70,6 +70,8 @@ module PacketGen
70
70
  break if label.length == 0 or str[start..-1].length == 0
71
71
  end
72
72
  end
73
+ # force resolution of compressed names
74
+ name_from_pointer
73
75
  self
74
76
  end
75
77
 
@@ -32,6 +32,7 @@ module PacketGen
32
32
  'MX' => 15,
33
33
  'TXT' => 16,
34
34
  'AAAA' => 28,
35
+ 'SRV' => 33,
35
36
  'NAPTR' => 35,
36
37
  'KX' => 36,
37
38
  'CERT' => 37,
@@ -109,12 +110,21 @@ module PacketGen
109
110
  # Get human readable class
110
111
  # @return [String]
111
112
  def human_rrclass
112
- self.class::CLASSES.key(self.rrclass) || "0x%04x" % self.rrclass
113
+ if self[:name].dns.is_a? MDNS
114
+ self.class::CLASSES.key(self.rrclass & 0x7fff) || "0x%04x" % (self.rrclass & 0x7fff)
115
+ else
116
+ self.class::CLASSES.key(self.rrclass) || "0x%04x" % self.rrclass
117
+ end
113
118
  end
114
119
 
115
120
  # @return [String]
116
121
  def to_human
117
- "#{human_type} #{human_rrclass} #{name}"
122
+ if self[:name].dns.is_a? MDNS
123
+ unicast_bit = (self.rrclass & 0x8000 == 0x8000) ? 'QU' : 'QM'
124
+ "#{human_type} #{human_rrclass} #{unicast_bit} #{name}"
125
+ else
126
+ "#{human_type} #{human_rrclass} #{name}"
127
+ end
118
128
  end
119
129
  end
120
130
  end
@@ -55,7 +55,8 @@ module PacketGen
55
55
  def human_rdata
56
56
  str = self[:rdata].inspect
57
57
 
58
- if self.rrclass == CLASSES['IN']
58
+ # Need to mask: mDNS uses leftmost bit as a flag (CACHE FLUSH)
59
+ if self.rrclass & 0x7fff == CLASSES['IN']
59
60
  case type
60
61
  when TYPES['A'], TYPES['AAAA']
61
62
  str = IPAddr.new_ntoh(self[:rdata]).to_s
@@ -63,7 +64,7 @@ module PacketGen
63
64
  end
64
65
 
65
66
  name = Name.new
66
- name.dns = @dns
67
+ name.dns = self[:name].dns
67
68
  case type
68
69
  when TYPES['NS'], TYPES['PTR'], TYPES['CNAME']
69
70
  str = name.read(self[:rdata]).to_human
@@ -81,11 +82,29 @@ module PacketGen
81
82
  pref = Types::Int16.new.read(self[:rdata][0, 2])
82
83
  exchange = name.read(self[:rdata][2..-1]).to_human
83
84
  str = '%u %s' % [pref.to_i, exchange]
85
+ when TYPES['SRV']
86
+ priority = Types::Int16.new.read(self[:rdata][0, 2])
87
+ weight = Types::Int16.new.read(self[:rdata][2, 2])
88
+ port = Types::Int16.new.read(self[:rdata][4, 2])
89
+ target = name.read(self[:rdata][6, self[:rdata].size]).to_human
90
+ str = "#{priority.to_i} #{weight.to_i} #{port.to_i} #{target}"
84
91
  end
85
92
 
86
93
  str
87
94
  end
88
95
 
96
+ def human_rrclass
97
+ # Get human readable class
98
+ # @return [String]
99
+ if self[:name].dns.is_a? MDNS
100
+ str = self.class::CLASSES.key(self.rrclass & 0x7fff) || "0x%04x" % (self.rrclass & 0x7fff)
101
+ str += ' CACHE-FLUSH' if self.rrclass & 0x8000 > 0
102
+ str
103
+ else
104
+ self.class::CLASSES.key(self.rrclass) || "0x%04x" % self.rrclass
105
+ end
106
+ end
107
+
89
108
  # @return [String]
90
109
  def to_human
91
110
  "#{human_type} #{human_rrclass} #{name} TTL #{ttl} #{human_rdata}"
@@ -4,5 +4,6 @@
4
4
  # This program is published under MIT license.
5
5
 
6
6
  require_relative 'http/headers'
7
+ require_relative 'http/verbs'
7
8
  require_relative 'http/response'
8
9
  require_relative 'http/request'
@@ -24,9 +24,10 @@ module PacketGen
24
24
  case s_or_h
25
25
  when String
26
26
  @data = s_or_h.split("\n").map do |h|
27
+ next unless h.include?(":")
27
28
  k, v = h.split(":", 2)
28
29
  [k, v.strip]
29
- end.to_h
30
+ end.reject(&:nil?).to_h
30
31
  when Hash
31
32
  @data = s_or_h
32
33
  end
@@ -39,9 +40,7 @@ module PacketGen
39
40
  return "\r\n" if @data.nil? || @data.empty?
40
41
  d = []
41
42
  @data.map do |k, v|
42
- str = ""
43
- str << k << ": " << v
44
- d << str
43
+ d << k + ": " + v
45
44
  end
46
45
  d.join("\r\n") << "\r\n\r\n"
47
46
  end
@@ -8,7 +8,7 @@
8
8
  module PacketGen
9
9
  module Header
10
10
  module HTTP
11
- # An HTTP/1.1 Request packet consits of:
11
+ # An HTTP/1.1 Request packet consists of:
12
12
  # * the http method ({Types::String}).
13
13
  # * the path ({Types::String}).
14
14
  # * the version ({Types::String}).
@@ -47,6 +47,9 @@ module PacketGen
47
47
  # associated http/1.1 headers
48
48
  # @return [HTTP::Headers]
49
49
  define_field :headers, HTTP::Headers
50
+ # @!attribute body
51
+ # @return [Types::String]
52
+ define_field :body, Types::String
50
53
 
51
54
  # @param [Hash] options
52
55
  # @option options [String] :method
@@ -61,14 +64,23 @@ module PacketGen
61
64
  # Read in the HTTP portion of the packet, and parse it.
62
65
  # @return [PacketGen::HTTP::Request]
63
66
  def read(str)
64
- # prepare data to parse
65
- str = str.split("\n").map(&:strip).reject(&:empty?)
67
+ str = str.bytes.map!(&:chr).join unless str.valid_encoding?
68
+ vrb = HTTP::VERBS.detect { |verb| str.include?(verb) }
69
+ str = vrb + str.split(vrb)[-1]
70
+ str = str.split("\n").map(&:chomp)
66
71
  first_line = str.shift.split
67
72
  self[:method] = first_line[0]
68
73
  self[:path] = first_line[1]
69
74
  self[:version] = first_line[2]
70
- headers = str.join("\n")
75
+ # requests can sometimes have a payload
76
+ if data_index = str.find_index("")
77
+ data = str[data_index+1..-1].join("\n")
78
+ headers = str[0..data_index-1].join("\n")
79
+ else
80
+ headers = str.join("\n")
81
+ end
71
82
  self[:headers].read(headers)
83
+ self[:body] = data
72
84
  self
73
85
  end
74
86
 
@@ -79,12 +91,12 @@ module PacketGen
79
91
  raise FormatError, "Missing #path." if self.path.empty?
80
92
  raise FormatError, "Missing #version." if self.version.empty?
81
93
  str = "".dup # build 'dat string
82
- str << self[:method] << " " << self[:path] << " " << self[:version] << "\r\n" << self[:headers].to_s
94
+ str << self[:method] << " " << self[:path] << " " << self[:version] << "\r\n" << self[:headers].to_s << self[:body]
83
95
  end
84
96
  end
85
97
  end
86
98
 
87
99
  self.add_class HTTP::Request
88
- TCP.bind_header HTTP::Request, body: ->(b) { /^(CONNECT|DELETE|GET|HEAD|OPTIONS|PATCH|POST|PUT)/ =~ b }
100
+ TCP.bind_header HTTP::Request, body: ->(b) { HTTP::REQUEST_REGEX =~ b.chars.select(&:valid_encoding?).join }
89
101
  end
90
102
  end
@@ -8,7 +8,7 @@
8
8
  module PacketGen
9
9
  module Header
10
10
  module HTTP
11
- # An HTTP/1.1 Response packet consits of:
11
+ # An HTTP/1.1 Response packet consists of:
12
12
  # * the version ({Types::String}).
13
13
  # * the status code ({Types::String}).
14
14
  # * the status message ({Types::String}).
@@ -67,7 +67,7 @@ module PacketGen
67
67
  # Read in the HTTP portion of the packet, and parse it.
68
68
  # @return [PacketGen::HTTP::Response]
69
69
  def read(str)
70
- # prepare data to parse
70
+ str = str.bytes.map!(&:chr).join unless str.valid_encoding?
71
71
  arr = str.split("\r\n")
72
72
  headers = [] # header stream
73
73
  data = [] # data stream
@@ -113,6 +113,6 @@ module PacketGen
113
113
  end
114
114
 
115
115
  self.add_class HTTP::Response
116
- TCP.bind_header HTTP::Response, body: ->(b) { /^HTTP\/1\.1\s\d{3,}\s.+/ =~ b }
116
+ TCP.bind_header HTTP::Response, body: ->(b) { /^HTTP\/1\.1\s\d{3,}\s.+/ =~ b.chars.select(&:valid_encoding?).join }
117
117
  end
118
118
  end
@@ -0,0 +1,22 @@
1
+ # This file is part of PacketGen
2
+ # See https://github.com/sdaubert/packetgen for more informations
3
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PacketGen
9
+ module Header
10
+ # @since 2.2.0
11
+ module HTTP
12
+ # @abstract Collection of useful HTTP verbs.
13
+ # @author Kent 'picat' Gruber
14
+
15
+ # Valid HTTP Verbs
16
+ VERBS = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']
17
+
18
+ # Identifiable HTTP request regular expression.
19
+ REQUEST_REGEX = Regexp.new("(" + VERBS.dup.join("|") + ")" + '\s+\S+\s+HTTP/1.1')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,75 @@
1
+ # coding: utf-8
2
+ # This file is part of PacketGen
3
+ # See https://github.com/sdaubert/packetgen for more informations
4
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module PacketGen
10
+ module Header
11
+
12
+ # Multicast DNS.
13
+ #
14
+ # See {DNS} for header format.
15
+ # @author Sylvain Daubert
16
+ class MDNS < DNS
17
+ # Port number for mDNS over UDP
18
+ UDP_PORT = 5353
19
+
20
+ # Fixup IP header according to RFC 6762:
21
+ # * set ethernet multicast address to +01:00:5E:00:00:FB+ (for IPv4)
22
+ # or +33:33:00:00:00:FB+ (for IPv6),
23
+ # * set IPv4 address to 224.0.0.251 or IPv6 address to ff02::fb.
24
+ # This method may be called as:
25
+ # # first way
26
+ # pkt.mdns.mdnsize
27
+ # # second way
28
+ # pkt.mdnsize
29
+ def mdnsize
30
+ iph = ip_header(self)
31
+ case iph
32
+ when IP
33
+ iph.dst = '224.0.0.251'
34
+ llh = ll_header(self)
35
+ mac = case llh
36
+ when Eth
37
+ llh[:dst]
38
+ when Dot11
39
+ if llh.to_ds?
40
+ llh[:mac3]
41
+ else
42
+ llh[:mac1]
43
+ end
44
+ end
45
+ mac.from_human('01:00:5E:00:00:FB')
46
+ when IPv6
47
+ iph.dst = 'ff02::fb'
48
+ llh = ll_header(self)
49
+ mac = case llh
50
+ when Eth
51
+ llh[:dst]
52
+ when Dot11
53
+ if llh.to_ds?
54
+ llh[:mac3]
55
+ else
56
+ llh[:mac1]
57
+ end
58
+ end
59
+ mac.from_human('33:33:00:00:00:FB')
60
+ end
61
+ end
62
+
63
+ # @api private
64
+ # @note This method is used internally by PacketGen and should not be
65
+ # directly called
66
+ def added_to_packet(packet)
67
+ mdns_idx = packet.headers.size
68
+ packet.instance_eval "def mdnsize() @headers[#{mdns_idx}].mdnsize; end"
69
+ end
70
+ end
71
+
72
+ self.add_class MDNS
73
+ UDP.bind_header MDNS, dport: MDNS::UDP_PORT, sport: MDNS::UDP_PORT
74
+ end
75
+ end
@@ -251,6 +251,19 @@ module PacketGen
251
251
 
252
252
  define_attributes :version, :community
253
253
 
254
+ # @param [Hash] options
255
+ # @option options [Integer,String] :version
256
+ # @option options [String] :community
257
+ # @option options [Integer] :chosen_pdu Set PDU type
258
+ # @option options [Hash] :pdu Set PDU content
259
+ def initialize(options={})
260
+ super
261
+ data.chosen = options[:chosen_pdu] if options[:chosen_pdu]
262
+ if options[:pdu]
263
+ data.root.value[data.chosen] = data.root.chosen_value.class.new(options[:pdu])
264
+ end
265
+ end
266
+
254
267
  # accessor to data payload
255
268
  # @return [GetRequest]
256
269
  def data
@@ -10,5 +10,5 @@
10
10
  # @author Sylvain Daubert
11
11
  module PacketGen
12
12
  # PacketGen version
13
- VERSION = '2.5.2'
13
+ VERSION = '2.6.0'
14
14
  end
data/packetgen.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_dependency 'pcaprub', '~>0.12.4'
27
27
  spec.add_dependency 'interfacez', '~>1.0'
28
- spec.add_dependency 'rasn1', '~>0.5', '>= 0.6.0'
28
+ spec.add_dependency 'rasn1', '~>0.5', '>= 0.6.3'
29
29
 
30
30
  spec.add_development_dependency 'bundler', '~> 1.7'
31
31
  spec.add_development_dependency 'rake', '~> 12.0'
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: 2.5.2
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Daubert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-26 00:00:00.000000000 Z
11
+ date: 2018-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pcaprub
@@ -47,7 +47,7 @@ dependencies:
47
47
  version: '0.5'
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
- version: 0.6.0
50
+ version: 0.6.3
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
@@ -57,7 +57,7 @@ dependencies:
57
57
  version: '0.5'
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 0.6.0
60
+ version: 0.6.3
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: bundler
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -188,6 +188,7 @@ files:
188
188
  - lib/packetgen/header/http/headers.rb
189
189
  - lib/packetgen/header/http/request.rb
190
190
  - lib/packetgen/header/http/response.rb
191
+ - lib/packetgen/header/http/verbs.rb
191
192
  - lib/packetgen/header/icmp.rb
192
193
  - lib/packetgen/header/icmpv6.rb
193
194
  - lib/packetgen/header/igmp.rb
@@ -217,6 +218,7 @@ files:
217
218
  - lib/packetgen/header/ipv6/extension.rb
218
219
  - lib/packetgen/header/ipv6/hop_by_hop.rb
219
220
  - lib/packetgen/header/llc.rb
221
+ - lib/packetgen/header/mdns.rb
220
222
  - lib/packetgen/header/mld.rb
221
223
  - lib/packetgen/header/mldv2.rb
222
224
  - lib/packetgen/header/mldv2/mcast_address_record.rb