DIY-pcap 0.4.1 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -4
- data/DIY-pcap.gemspec +17 -17
- data/Gemfile +3 -3
- data/Rakefile +1 -1
- data/lib/DIY-pcap.rb +2 -2
- data/lib/diy/command.rb +7 -1
- data/lib/diy/controller.rb +10 -15
- data/lib/diy/live.rb +9 -2
- data/lib/diy/parser/mu/pcap/ethernet.rb +148 -148
- data/lib/diy/parser/mu/pcap/header.rb +75 -75
- data/lib/diy/parser/mu/pcap/io_pair.rb +67 -67
- data/lib/diy/parser/mu/pcap/io_wrapper.rb +76 -76
- data/lib/diy/parser/mu/pcap/ip.rb +61 -61
- data/lib/diy/parser/mu/pcap/ipv4.rb +257 -257
- data/lib/diy/parser/mu/pcap/ipv6.rb +148 -148
- data/lib/diy/parser/mu/pcap/packet.rb +104 -104
- data/lib/diy/parser/mu/pcap/pkthdr.rb +155 -155
- data/lib/diy/parser/mu/pcap/reader.rb +61 -61
- data/lib/diy/parser/mu/pcap/reader/http_family.rb +170 -170
- data/lib/diy/parser/mu/pcap/sctp.rb +367 -367
- data/lib/diy/parser/mu/pcap/sctp/chunk.rb +123 -123
- data/lib/diy/parser/mu/pcap/sctp/chunk/data.rb +134 -134
- data/lib/diy/parser/mu/pcap/sctp/chunk/init.rb +100 -100
- data/lib/diy/parser/mu/pcap/sctp/chunk/init_ack.rb +68 -68
- data/lib/diy/parser/mu/pcap/sctp/parameter.rb +110 -110
- data/lib/diy/parser/mu/pcap/sctp/parameter/ip_address.rb +48 -48
- data/lib/diy/parser/mu/pcap/stream_packetizer.rb +72 -72
- data/lib/diy/parser/mu/pcap/tcp.rb +505 -505
- data/lib/diy/parser/mu/pcap/udp.rb +69 -69
- data/lib/diy/parser/mu/scenario/pcap.rb +172 -172
- data/lib/diy/parser/mu/scenario/pcap/fields.rb +50 -50
- data/lib/diy/parser/mu/scenario/pcap/rtp.rb +71 -71
- data/lib/diy/parser/pcap.rb +109 -109
- data/lib/diy/version.rb +1 -1
- metadata +7 -9
@@ -1,69 +1,69 @@
|
|
1
|
-
# http://www.mudynamics.com
|
2
|
-
# http://labs.mudynamics.com
|
3
|
-
# http://www.pcapr.net
|
4
|
-
|
5
|
-
module Mu
|
6
|
-
class Pcap
|
7
|
-
|
8
|
-
class UDP < Packet
|
9
|
-
attr_accessor :src_port, :dst_port
|
10
|
-
|
11
|
-
def initialize src_port=0, dst_port=0
|
12
|
-
super()
|
13
|
-
@src_port = src_port
|
14
|
-
@dst_port = dst_port
|
15
|
-
end
|
16
|
-
|
17
|
-
def flow_id
|
18
|
-
return [:udp, @src_port, @dst_port]
|
19
|
-
end
|
20
|
-
|
21
|
-
FMT_nnnn = 'nnnn'
|
22
|
-
def self.from_bytes bytes
|
23
|
-
bytes_length = bytes.length
|
24
|
-
bytes_length >= 8 or
|
25
|
-
raise ParseError, "Truncated UDP header: expected 8 bytes, got #{bytes_length} bytes"
|
26
|
-
sport, dport, length, checksum = bytes.unpack(FMT_nnnn)
|
27
|
-
bytes_length >= length or
|
28
|
-
raise ParseError, "Truncated UDP packet: expected #{length} bytes, got #{bytes_length} bytes"
|
29
|
-
udp = UDP.new sport, dport
|
30
|
-
udp.payload_raw = bytes[8..-1]
|
31
|
-
udp.payload = bytes[8..length]
|
32
|
-
return udp
|
33
|
-
end
|
34
|
-
|
35
|
-
def write io, ip
|
36
|
-
length = @payload.length
|
37
|
-
length_8 = length + 8
|
38
|
-
if length_8 > 65535
|
39
|
-
Pcap.warning "UDP payload is too large"
|
40
|
-
end
|
41
|
-
pseudo_header = ip.pseudo_header length_8
|
42
|
-
header = [@src_port, @dst_port, length_8, 0] \
|
43
|
-
.pack FMT_nnnn
|
44
|
-
checksum = IP.checksum(pseudo_header + header + @payload)
|
45
|
-
header = [@src_port, @dst_port, length_8, checksum] \
|
46
|
-
.pack FMT_nnnn
|
47
|
-
io.write header
|
48
|
-
io.write @payload
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.udp? packet
|
52
|
-
return packet.is_a?(Ethernet) &&
|
53
|
-
packet.payload.is_a?(IP) &&
|
54
|
-
packet.payload.payload.is_a?(UDP)
|
55
|
-
end
|
56
|
-
|
57
|
-
def to_s
|
58
|
-
return "udp(%d, %d, %s)" % [@src_port, @dst_port, @payload.inspect]
|
59
|
-
end
|
60
|
-
|
61
|
-
def == other
|
62
|
-
return super &&
|
63
|
-
self.src_port == other.src_port &&
|
64
|
-
self.dst_port == other.dst_port
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
module Mu
|
6
|
+
class Pcap
|
7
|
+
|
8
|
+
class UDP < Packet
|
9
|
+
attr_accessor :src_port, :dst_port
|
10
|
+
|
11
|
+
def initialize src_port=0, dst_port=0
|
12
|
+
super()
|
13
|
+
@src_port = src_port
|
14
|
+
@dst_port = dst_port
|
15
|
+
end
|
16
|
+
|
17
|
+
def flow_id
|
18
|
+
return [:udp, @src_port, @dst_port]
|
19
|
+
end
|
20
|
+
|
21
|
+
FMT_nnnn = 'nnnn'
|
22
|
+
def self.from_bytes bytes
|
23
|
+
bytes_length = bytes.length
|
24
|
+
bytes_length >= 8 or
|
25
|
+
raise ParseError, "Truncated UDP header: expected 8 bytes, got #{bytes_length} bytes"
|
26
|
+
sport, dport, length, checksum = bytes.unpack(FMT_nnnn)
|
27
|
+
bytes_length >= length or
|
28
|
+
raise ParseError, "Truncated UDP packet: expected #{length} bytes, got #{bytes_length} bytes"
|
29
|
+
udp = UDP.new sport, dport
|
30
|
+
udp.payload_raw = bytes[8..-1]
|
31
|
+
udp.payload = bytes[8..length]
|
32
|
+
return udp
|
33
|
+
end
|
34
|
+
|
35
|
+
def write io, ip
|
36
|
+
length = @payload.length
|
37
|
+
length_8 = length + 8
|
38
|
+
if length_8 > 65535
|
39
|
+
Pcap.warning "UDP payload is too large"
|
40
|
+
end
|
41
|
+
pseudo_header = ip.pseudo_header length_8
|
42
|
+
header = [@src_port, @dst_port, length_8, 0] \
|
43
|
+
.pack FMT_nnnn
|
44
|
+
checksum = IP.checksum(pseudo_header + header + @payload)
|
45
|
+
header = [@src_port, @dst_port, length_8, checksum] \
|
46
|
+
.pack FMT_nnnn
|
47
|
+
io.write header
|
48
|
+
io.write @payload
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.udp? packet
|
52
|
+
return packet.is_a?(Ethernet) &&
|
53
|
+
packet.payload.is_a?(IP) &&
|
54
|
+
packet.payload.payload.is_a?(UDP)
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
return "udp(%d, %d, %s)" % [@src_port, @dst_port, @payload.inspect]
|
59
|
+
end
|
60
|
+
|
61
|
+
def == other
|
62
|
+
return super &&
|
63
|
+
self.src_port == other.src_port &&
|
64
|
+
self.dst_port == other.dst_port
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -1,172 +1,172 @@
|
|
1
|
-
# http://www.mudynamics.com
|
2
|
-
# http://labs.mudynamics.com
|
3
|
-
# http://www.pcapr.net
|
4
|
-
|
5
|
-
require 'tempfile'
|
6
|
-
require 'fileutils'
|
7
|
-
require 'mu/scenario/pcap/fields'
|
8
|
-
require 'mu/pcap'
|
9
|
-
require 'json'
|
10
|
-
|
11
|
-
module Mu
|
12
|
-
class Scenario
|
13
|
-
|
14
|
-
module Pcap
|
15
|
-
TSHARK_READ_TIMEOUT = 10.0 # seconds
|
16
|
-
TSHARK_LINES_PER_PACKET = 16384
|
17
|
-
TSHARK_OPTS = "-n -o tcp.desegment_tcp_streams:false"
|
18
|
-
TSHARK_OPTS_SUFFIX = TSHARK_OPTS
|
19
|
-
TSHARK_SIZE_OPTS = "-n -o 'column.format: cum_size, \"%B\"'"
|
20
|
-
TSHARK_PSML_OPTS = %Q{#{TSHARK_OPTS} -o 'column.format: "Protocol", "%p", "Info", "%i"'}
|
21
|
-
|
22
|
-
MAX_PCAP_SIZE = 102400 # 100KB
|
23
|
-
MAX_RAW_PCAP_SIZE_MB = 25
|
24
|
-
MAX_RAW_PCAP_SIZE = MAX_RAW_PCAP_SIZE_MB * 1024 * 1000
|
25
|
-
EXCLUDE_FROM_SIZE_CHECK = ['rtp'].freeze
|
26
|
-
|
27
|
-
class PcapTooLarge < StandardError; end
|
28
|
-
|
29
|
-
def self.reset_options options
|
30
|
-
return unless options
|
31
|
-
tshark_opts = options << ' ' << TSHARK_OPTS_SUFFIX
|
32
|
-
remove_const(:TSHARK_OPTS) if const_defined?(:TSHARK_OPTS)
|
33
|
-
const_set(:TSHARK_OPTS, tshark_opts)
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.validate_pcap_size(path)
|
37
|
-
tshark_filter = EXCLUDE_FROM_SIZE_CHECK.map{ |proto| "not #{proto}" }.join " and "
|
38
|
-
io = ::IO.popen "tshark #{TSHARK_SIZE_OPTS} -r #{path} -R '#{tshark_filter}' | tail -1"
|
39
|
-
if ::IO.select [ io ], nil, nil, TSHARK_READ_TIMEOUT
|
40
|
-
if io.eof?
|
41
|
-
size = 0
|
42
|
-
else
|
43
|
-
last_line = io.readline
|
44
|
-
size = last_line.to_i
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
if size.nil? or size == 0
|
49
|
-
size = File.size(path)
|
50
|
-
end
|
51
|
-
|
52
|
-
if size > MAX_PCAP_SIZE
|
53
|
-
raise PcapTooLarge, "Selected packets have a size of #{size} bytes which " +
|
54
|
-
"exceeds the #{MAX_PCAP_SIZE} byte maximum."
|
55
|
-
end
|
56
|
-
|
57
|
-
if size > MAX_RAW_PCAP_SIZE
|
58
|
-
raise PcapTooLarge, "Selected packets have a raw size of #{size} bytes which " +
|
59
|
-
"exceeds the #{MAX_RAW_PCAP_SIZE_MB}MB maximum."
|
60
|
-
end
|
61
|
-
|
62
|
-
return size
|
63
|
-
end
|
64
|
-
|
65
|
-
PAR_VERSION = 1
|
66
|
-
def self.export_to_par pcap_path, opts=nil
|
67
|
-
opts ||= {}
|
68
|
-
|
69
|
-
# Open pcap file
|
70
|
-
File.exist?(pcap_path) or raise "Cannot open file '#{pcap_path}'."
|
71
|
-
validate_pcap_size pcap_path
|
72
|
-
pcap = open pcap_path, 'rb'
|
73
|
-
|
74
|
-
# Get Mu::Pcap::Packets
|
75
|
-
packets = to_pcap_packets pcap, opts[:isolate_l7]
|
76
|
-
|
77
|
-
# Write normalized packets to tempfile
|
78
|
-
tmpdir = Dir.mktmpdir
|
79
|
-
norm_pcap = File.open "#{tmpdir}/normalized.pcap", 'wb'
|
80
|
-
pcap = Mu::Pcap.from_packets packets
|
81
|
-
pcap.write norm_pcap
|
82
|
-
norm_pcap.close
|
83
|
-
|
84
|
-
# Get wireshark dissected field values for all packets.
|
85
|
-
`tshark -T fields #{TSHARK_OPTS} #{Fields::TSHARK_OPTS} -Eseparator='\xff' -r #{norm_pcap.path} > #{tmpdir}/fields`
|
86
|
-
fields = open "#{tmpdir}/fields", 'rb'
|
87
|
-
|
88
|
-
# Get wireshark dissected field values for all packets.
|
89
|
-
fields_array = []
|
90
|
-
if fields
|
91
|
-
packets.each do |packet|
|
92
|
-
fields_array << Fields.next_from_io(fields)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Protocol specific preprocessing, packets may be deleted.
|
97
|
-
Rtp.preprocess packets, fields_array
|
98
|
-
|
99
|
-
File.open "#{tmpdir}/packets.dump", 'wb' do |f|
|
100
|
-
Marshal.dump packets, f
|
101
|
-
end
|
102
|
-
|
103
|
-
# Create a second pcap with packets removed.
|
104
|
-
norm_pcap = File.open "#{tmpdir}/normalized.pcap", 'wb'
|
105
|
-
pcap = Mu::Pcap.from_packets packets
|
106
|
-
pcap.write norm_pcap
|
107
|
-
norm_pcap.close
|
108
|
-
|
109
|
-
# Dump PSML to file.
|
110
|
-
# (The no-op filter sometimes produces slighty more verbose descriptions.)
|
111
|
-
`tshark -T psml #{TSHARK_PSML_OPTS} -r #{norm_pcap.path} -R 'rtp or not rtp' > #{tmpdir}/psml`
|
112
|
-
|
113
|
-
# Dump PDML io file.
|
114
|
-
`tshark -T pdml #{TSHARK_OPTS} -r #{norm_pcap.path} > #{tmpdir}/pdml`
|
115
|
-
pdml = open "#{tmpdir}/pdml", 'rb'
|
116
|
-
|
117
|
-
# Create about
|
118
|
-
open "#{tmpdir}/about", 'w' do |about|
|
119
|
-
about.puts({:par_version => PAR_VERSION}.to_json)
|
120
|
-
end
|
121
|
-
|
122
|
-
# Create zip
|
123
|
-
Dir.chdir tmpdir do
|
124
|
-
system "zip -q dissected.zip about pdml psml fields packets.dump normalized.pcap"
|
125
|
-
return open("dissected.zip")
|
126
|
-
end
|
127
|
-
ensure
|
128
|
-
if tmpdir
|
129
|
-
FileUtils.rm_rf tmpdir
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.to_pcap_packets io, isolate_l7=true
|
134
|
-
packets = []
|
135
|
-
|
136
|
-
# Read Pcap packets from Pcap
|
137
|
-
Mu::Pcap.each_pkthdr io do |pkthdr|
|
138
|
-
if pkthdr.len != pkthdr.caplen
|
139
|
-
raise Mu::Pcap::ParseError, "Error: Capture contains truncated packets. " +
|
140
|
-
"Try recapturing with an increased snapshot length."
|
141
|
-
end
|
142
|
-
if not pkthdr.pkt.is_a? Mu::Pcap::Ethernet
|
143
|
-
warning 'Unable to parse packet, skipping.'
|
144
|
-
end
|
145
|
-
packets << pkthdr.pkt
|
146
|
-
end
|
147
|
-
|
148
|
-
if (packets.length == 0)
|
149
|
-
raise Mu::Pcap::ParseError, "No valid packets found!"
|
150
|
-
end
|
151
|
-
|
152
|
-
packets = Mu::Pcap::IPv4.reassemble packets
|
153
|
-
|
154
|
-
if isolate_l7
|
155
|
-
packets = Mu::Pcap::Packet.isolate_l7 packets
|
156
|
-
end
|
157
|
-
|
158
|
-
packets = Mu::Pcap::Packet.normalize packets
|
159
|
-
packets = Mu::Pcap::TCP.split packets
|
160
|
-
|
161
|
-
packets
|
162
|
-
end
|
163
|
-
|
164
|
-
def self.warning msg
|
165
|
-
$stderr.puts "WARNING: #{msg}"#, caller, $!
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
require 'mu/scenario/pcap/rtp'
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
require 'tempfile'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'mu/scenario/pcap/fields'
|
8
|
+
require 'mu/pcap'
|
9
|
+
require 'json'
|
10
|
+
|
11
|
+
module Mu
|
12
|
+
class Scenario
|
13
|
+
|
14
|
+
module Pcap
|
15
|
+
TSHARK_READ_TIMEOUT = 10.0 # seconds
|
16
|
+
TSHARK_LINES_PER_PACKET = 16384
|
17
|
+
TSHARK_OPTS = "-n -o tcp.desegment_tcp_streams:false"
|
18
|
+
TSHARK_OPTS_SUFFIX = TSHARK_OPTS
|
19
|
+
TSHARK_SIZE_OPTS = "-n -o 'column.format: cum_size, \"%B\"'"
|
20
|
+
TSHARK_PSML_OPTS = %Q{#{TSHARK_OPTS} -o 'column.format: "Protocol", "%p", "Info", "%i"'}
|
21
|
+
|
22
|
+
MAX_PCAP_SIZE = 102400 # 100KB
|
23
|
+
MAX_RAW_PCAP_SIZE_MB = 25
|
24
|
+
MAX_RAW_PCAP_SIZE = MAX_RAW_PCAP_SIZE_MB * 1024 * 1000
|
25
|
+
EXCLUDE_FROM_SIZE_CHECK = ['rtp'].freeze
|
26
|
+
|
27
|
+
class PcapTooLarge < StandardError; end
|
28
|
+
|
29
|
+
def self.reset_options options
|
30
|
+
return unless options
|
31
|
+
tshark_opts = options << ' ' << TSHARK_OPTS_SUFFIX
|
32
|
+
remove_const(:TSHARK_OPTS) if const_defined?(:TSHARK_OPTS)
|
33
|
+
const_set(:TSHARK_OPTS, tshark_opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.validate_pcap_size(path)
|
37
|
+
tshark_filter = EXCLUDE_FROM_SIZE_CHECK.map{ |proto| "not #{proto}" }.join " and "
|
38
|
+
io = ::IO.popen "tshark #{TSHARK_SIZE_OPTS} -r #{path} -R '#{tshark_filter}' | tail -1"
|
39
|
+
if ::IO.select [ io ], nil, nil, TSHARK_READ_TIMEOUT
|
40
|
+
if io.eof?
|
41
|
+
size = 0
|
42
|
+
else
|
43
|
+
last_line = io.readline
|
44
|
+
size = last_line.to_i
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if size.nil? or size == 0
|
49
|
+
size = File.size(path)
|
50
|
+
end
|
51
|
+
|
52
|
+
if size > MAX_PCAP_SIZE
|
53
|
+
raise PcapTooLarge, "Selected packets have a size of #{size} bytes which " +
|
54
|
+
"exceeds the #{MAX_PCAP_SIZE} byte maximum."
|
55
|
+
end
|
56
|
+
|
57
|
+
if size > MAX_RAW_PCAP_SIZE
|
58
|
+
raise PcapTooLarge, "Selected packets have a raw size of #{size} bytes which " +
|
59
|
+
"exceeds the #{MAX_RAW_PCAP_SIZE_MB}MB maximum."
|
60
|
+
end
|
61
|
+
|
62
|
+
return size
|
63
|
+
end
|
64
|
+
|
65
|
+
PAR_VERSION = 1
|
66
|
+
def self.export_to_par pcap_path, opts=nil
|
67
|
+
opts ||= {}
|
68
|
+
|
69
|
+
# Open pcap file
|
70
|
+
File.exist?(pcap_path) or raise "Cannot open file '#{pcap_path}'."
|
71
|
+
validate_pcap_size pcap_path
|
72
|
+
pcap = open pcap_path, 'rb'
|
73
|
+
|
74
|
+
# Get Mu::Pcap::Packets
|
75
|
+
packets = to_pcap_packets pcap, opts[:isolate_l7]
|
76
|
+
|
77
|
+
# Write normalized packets to tempfile
|
78
|
+
tmpdir = Dir.mktmpdir
|
79
|
+
norm_pcap = File.open "#{tmpdir}/normalized.pcap", 'wb'
|
80
|
+
pcap = Mu::Pcap.from_packets packets
|
81
|
+
pcap.write norm_pcap
|
82
|
+
norm_pcap.close
|
83
|
+
|
84
|
+
# Get wireshark dissected field values for all packets.
|
85
|
+
`tshark -T fields #{TSHARK_OPTS} #{Fields::TSHARK_OPTS} -Eseparator='\xff' -r #{norm_pcap.path} > #{tmpdir}/fields`
|
86
|
+
fields = open "#{tmpdir}/fields", 'rb'
|
87
|
+
|
88
|
+
# Get wireshark dissected field values for all packets.
|
89
|
+
fields_array = []
|
90
|
+
if fields
|
91
|
+
packets.each do |packet|
|
92
|
+
fields_array << Fields.next_from_io(fields)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Protocol specific preprocessing, packets may be deleted.
|
97
|
+
Rtp.preprocess packets, fields_array
|
98
|
+
|
99
|
+
File.open "#{tmpdir}/packets.dump", 'wb' do |f|
|
100
|
+
Marshal.dump packets, f
|
101
|
+
end
|
102
|
+
|
103
|
+
# Create a second pcap with packets removed.
|
104
|
+
norm_pcap = File.open "#{tmpdir}/normalized.pcap", 'wb'
|
105
|
+
pcap = Mu::Pcap.from_packets packets
|
106
|
+
pcap.write norm_pcap
|
107
|
+
norm_pcap.close
|
108
|
+
|
109
|
+
# Dump PSML to file.
|
110
|
+
# (The no-op filter sometimes produces slighty more verbose descriptions.)
|
111
|
+
`tshark -T psml #{TSHARK_PSML_OPTS} -r #{norm_pcap.path} -R 'rtp or not rtp' > #{tmpdir}/psml`
|
112
|
+
|
113
|
+
# Dump PDML io file.
|
114
|
+
`tshark -T pdml #{TSHARK_OPTS} -r #{norm_pcap.path} > #{tmpdir}/pdml`
|
115
|
+
pdml = open "#{tmpdir}/pdml", 'rb'
|
116
|
+
|
117
|
+
# Create about
|
118
|
+
open "#{tmpdir}/about", 'w' do |about|
|
119
|
+
about.puts({:par_version => PAR_VERSION}.to_json)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Create zip
|
123
|
+
Dir.chdir tmpdir do
|
124
|
+
system "zip -q dissected.zip about pdml psml fields packets.dump normalized.pcap"
|
125
|
+
return open("dissected.zip")
|
126
|
+
end
|
127
|
+
ensure
|
128
|
+
if tmpdir
|
129
|
+
FileUtils.rm_rf tmpdir
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.to_pcap_packets io, isolate_l7=true
|
134
|
+
packets = []
|
135
|
+
|
136
|
+
# Read Pcap packets from Pcap
|
137
|
+
Mu::Pcap.each_pkthdr io do |pkthdr|
|
138
|
+
if pkthdr.len != pkthdr.caplen
|
139
|
+
raise Mu::Pcap::ParseError, "Error: Capture contains truncated packets. " +
|
140
|
+
"Try recapturing with an increased snapshot length."
|
141
|
+
end
|
142
|
+
if not pkthdr.pkt.is_a? Mu::Pcap::Ethernet
|
143
|
+
warning 'Unable to parse packet, skipping.'
|
144
|
+
end
|
145
|
+
packets << pkthdr.pkt
|
146
|
+
end
|
147
|
+
|
148
|
+
if (packets.length == 0)
|
149
|
+
raise Mu::Pcap::ParseError, "No valid packets found!"
|
150
|
+
end
|
151
|
+
|
152
|
+
packets = Mu::Pcap::IPv4.reassemble packets
|
153
|
+
|
154
|
+
if isolate_l7
|
155
|
+
packets = Mu::Pcap::Packet.isolate_l7 packets
|
156
|
+
end
|
157
|
+
|
158
|
+
packets = Mu::Pcap::Packet.normalize packets
|
159
|
+
packets = Mu::Pcap::TCP.split packets
|
160
|
+
|
161
|
+
packets
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.warning msg
|
165
|
+
$stderr.puts "WARNING: #{msg}"#, caller, $!
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
require 'mu/scenario/pcap/rtp'
|