packetgen 2.5.2 → 2.6.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/header.rb +1 -0
- data/lib/packetgen/header/base.rb +13 -0
- data/lib/packetgen/header/dns.rb +0 -6
- data/lib/packetgen/header/dns/name.rb +2 -0
- data/lib/packetgen/header/dns/question.rb +12 -2
- data/lib/packetgen/header/dns/rr.rb +21 -2
- data/lib/packetgen/header/http.rb +1 -0
- data/lib/packetgen/header/http/headers.rb +3 -4
- data/lib/packetgen/header/http/request.rb +18 -6
- data/lib/packetgen/header/http/response.rb +3 -3
- data/lib/packetgen/header/http/verbs.rb +22 -0
- data/lib/packetgen/header/mdns.rb +75 -0
- data/lib/packetgen/header/snmp.rb +13 -0
- data/lib/packetgen/version.rb +1 -1
- data/packetgen.gemspec +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df09d9bda17671562435fd055b6ab552aa3e19798251f953e1e260786bae168d
|
4
|
+
data.tar.gz: 79baa63b2cfa57534246b3806033dc6233ea9a2ae9da3c6aa0dc9dc803983d97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6f3349f7d168b5b8391fa78e1ed90763295c7dc8db21bc0ee517195f96ca290172ad788c2c3fe4d2787809209fc502be4b05f00df6bc9f595709edf06136618
|
7
|
+
data.tar.gz: d218ba23d8c02253d75bd18f1ea552ce3aee8490895c0886504f443d87f18bbd0ed7c3e0ca13bc30f7bcf4db5fbb7abe7e4c0630bfc1f5fd36b750faa130e56c
|
data/lib/packetgen/header.rb
CHANGED
@@ -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
|
data/lib/packetgen/header/dns.rb
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
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 =
|
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}"
|
@@ -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
|
-
|
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
|
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
|
-
|
65
|
-
|
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
|
-
|
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) {
|
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
|
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
|
-
|
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
|
data/lib/packetgen/version.rb
CHANGED
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.
|
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.
|
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-
|
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.
|
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.
|
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
|