pstream 0.1.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 +7 -0
- data/bin/pstream +98 -0
- data/lib/pstream/error/pcap_not_found.rb +5 -0
- data/lib/pstream/error/pcap_not_readable.rb +5 -0
- data/lib/pstream/error/tshark_not_found.rb +5 -0
- data/lib/pstream/error.rb +6 -0
- data/lib/pstream/stream.rb +25 -0
- data/lib/pstream.rb +97 -0
- data/lib/string.rb +32 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 49d303c1bea9a3531778ce20c6fb023bf20109b4
|
4
|
+
data.tar.gz: ec4f4c2aa67ccd3266cadda652cbef2b938634b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 952f3f520e597628ae22b6890c002357d2dd84d3e17ff1ed44c193d19db7f37e3dcedeabc8f95042cc28562c293a1b29b7cca6ed33f9b3a6666a4eb6b99ef84f
|
7
|
+
data.tar.gz: a30dee7152071b7da0b1428c384b17ad6ba917fc22ce7e25cc62863101303880fa9c69d5048c0105844553125392f0cc2f885c29aa4682660d4d825cb2662107
|
data/bin/pstream
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "pstream"
|
5
|
+
require "string"
|
6
|
+
|
7
|
+
class PStreamExit
|
8
|
+
GOOD = 0
|
9
|
+
INVALID_OPTION = 1
|
10
|
+
INVALID_ARGUMENT = 2
|
11
|
+
MISSING_ARGUMENT = 3
|
12
|
+
EXTRA_ARGUMENTS = 4
|
13
|
+
EXCEPTION = 5
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(args)
|
17
|
+
options = Hash.new
|
18
|
+
options["ciphers"] = false
|
19
|
+
options["prot"] = "tcp"
|
20
|
+
options["stream"] = nil
|
21
|
+
|
22
|
+
info = "Analyze pcap files. Can view tcp/udp streams or " \
|
23
|
+
"ciphersuites in use."
|
24
|
+
|
25
|
+
parser = OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] <pcap>"
|
27
|
+
|
28
|
+
opts.on(
|
29
|
+
"-c",
|
30
|
+
"--ciphersuites",
|
31
|
+
"Show ciphersuite negotiation from ssl handshakes"
|
32
|
+
) do
|
33
|
+
options["ciphers"] = true
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-h", "--help", "Display this help message") do
|
37
|
+
puts opts
|
38
|
+
exit PStreamExit::GOOD
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("-s", "--stream=NUM", "Show specified stream") do |s|
|
42
|
+
options["stream"] = s.to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on("-u", "--udp", "Use UDP") do
|
46
|
+
options["prot"] = "udp"
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("", info.word_wrap(80))
|
50
|
+
end
|
51
|
+
|
52
|
+
begin
|
53
|
+
parser.parse!
|
54
|
+
rescue OptionParser::InvalidOption => e
|
55
|
+
puts e.message
|
56
|
+
puts parser
|
57
|
+
exit PStreamExit::INVALID_OPTION
|
58
|
+
rescue OptionParser::InvalidArgument => e
|
59
|
+
puts e.message
|
60
|
+
puts parser
|
61
|
+
exit PStreamExit::INVALID_ARGUMENT
|
62
|
+
rescue OptionParser::MissingArgument => e
|
63
|
+
puts e.message
|
64
|
+
puts parser
|
65
|
+
exit PStreamExit::MISSING_ARGUMENT
|
66
|
+
end
|
67
|
+
|
68
|
+
if (args.length != 1)
|
69
|
+
puts parser
|
70
|
+
exit PStreamExit::EXTRA_ARGUMENTS
|
71
|
+
end
|
72
|
+
|
73
|
+
options["pcap"] = args[0]
|
74
|
+
return options
|
75
|
+
end
|
76
|
+
|
77
|
+
options = parse(ARGV)
|
78
|
+
|
79
|
+
begin
|
80
|
+
pstream = PStream.new(options["pcap"])
|
81
|
+
|
82
|
+
if (options["stream"])
|
83
|
+
case options["prot"]
|
84
|
+
when "tcp"
|
85
|
+
puts pstream.tcp_streams[options["stream"]].contents
|
86
|
+
when "udp"
|
87
|
+
puts pstream.udp_streams[options["stream"]].contents
|
88
|
+
end
|
89
|
+
elsif (options["ciphers"])
|
90
|
+
puts pstream.ciphers
|
91
|
+
else
|
92
|
+
puts pstream.summary
|
93
|
+
end
|
94
|
+
rescue PStream::Error => e
|
95
|
+
puts e.message
|
96
|
+
exit PStreamExit::EXCEPTION
|
97
|
+
end
|
98
|
+
exit PStreamExit::GOOD
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class PStream::Stream
|
2
|
+
attr_accessor :desc
|
3
|
+
attr_accessor :frames
|
4
|
+
attr_accessor :id
|
5
|
+
|
6
|
+
def contents
|
7
|
+
out = %x(
|
8
|
+
tshark -r #{@pcap} -z follow,#{@prot},hex,#{@id} | \
|
9
|
+
sed "s|^ ||" | \grep -E "^[0-9A-Fa-f]{8}"
|
10
|
+
)
|
11
|
+
return out
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(pcap, prot, id, desc, frames)
|
15
|
+
@desc = desc
|
16
|
+
@frames = frames
|
17
|
+
@id = id
|
18
|
+
@pcap = pcap
|
19
|
+
@prot = prot
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s()
|
23
|
+
return contents
|
24
|
+
end
|
25
|
+
end
|
data/lib/pstream.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "scoobydoo"
|
3
|
+
|
4
|
+
class PStream
|
5
|
+
attr_accessor :tcp_streams
|
6
|
+
attr_accessor :udp_streams
|
7
|
+
|
8
|
+
def ciphers
|
9
|
+
# List ciphers during ssl handshake
|
10
|
+
out = %x(
|
11
|
+
tshark -r #{@pcap} -Y ssl.handshake.ciphersuite -V | \
|
12
|
+
\grep -E "Internet Protocol|Hostname:|Cipher Suite"
|
13
|
+
)
|
14
|
+
return out
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_streams(prot)
|
18
|
+
streams = Array.new
|
19
|
+
|
20
|
+
out = %x(
|
21
|
+
tshark -r #{@pcap} -z conv,#{prot} | \grep -E "<->" | \
|
22
|
+
awk '{print $1, $2, $3, "|", $8, "Frames"}'
|
23
|
+
)
|
24
|
+
|
25
|
+
count = 0
|
26
|
+
out.split("\n").each do |line|
|
27
|
+
desc, frames = line.split(" | ")
|
28
|
+
|
29
|
+
id = count
|
30
|
+
id = desc.gsub(" <-> ", ",") if (prot == "udp")
|
31
|
+
|
32
|
+
streams.push(Stream.new(@pcap, prot, id, desc, frames))
|
33
|
+
count += 1
|
34
|
+
end
|
35
|
+
|
36
|
+
return streams
|
37
|
+
end
|
38
|
+
private :get_streams
|
39
|
+
|
40
|
+
def initialize(pcap)
|
41
|
+
if (ScoobyDoo.where_are_you("tshark").nil?)
|
42
|
+
raise PStream::Error::TsharkNotFound.new
|
43
|
+
end
|
44
|
+
|
45
|
+
@pcap = Pathname.new(pcap).expand_path
|
46
|
+
|
47
|
+
if (!@pcap.exist?)
|
48
|
+
raise PStream::Error::PcapNotFound.new(@pcap)
|
49
|
+
elsif (!@pcap.readable?)
|
50
|
+
raise PStream::Error::PcapNotReadable.new(@pcap)
|
51
|
+
end
|
52
|
+
|
53
|
+
@tcp_streams = get_streams("tcp")
|
54
|
+
@udp_streams = get_streams("udp")
|
55
|
+
end
|
56
|
+
|
57
|
+
def summary
|
58
|
+
ret = Array.new
|
59
|
+
|
60
|
+
# List TCP streams
|
61
|
+
ret.push("TCP Streams:")
|
62
|
+
count = 0
|
63
|
+
@tcp_streams.each do |stream|
|
64
|
+
ret.push("#{count} | #{stream.desc} | #{stream.frames}")
|
65
|
+
count += 1
|
66
|
+
end
|
67
|
+
ret.push("")
|
68
|
+
|
69
|
+
# List UDP streams
|
70
|
+
ret.push("UDP Streams:")
|
71
|
+
count = 0
|
72
|
+
@udp_streams.each do |stream|
|
73
|
+
ret.push("#{count} | #{stream.desc} | #{stream.frames}")
|
74
|
+
count += 1
|
75
|
+
end
|
76
|
+
ret.push("")
|
77
|
+
|
78
|
+
# List ciphers that were actually selected
|
79
|
+
ret.push("Ciphers in use:")
|
80
|
+
f = "ssl.handshake.ciphersuite && ssl.handshake.type == 2"
|
81
|
+
out = %x(
|
82
|
+
tshark -r #{@pcap} -Y "#{f}" -V | \
|
83
|
+
\grep -E "Cipher Suite:" | \
|
84
|
+
sed -r "s|^ +Cipher Suite: ||g" | sort -u
|
85
|
+
)
|
86
|
+
ret.concat(out.split("\n"))
|
87
|
+
|
88
|
+
return ret.join("\n")
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
return summary
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
require "pstream/error"
|
97
|
+
require "pstream/stream"
|
data/lib/string.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Redefine String class to allow for colorizing, rsplit, and word wrap
|
2
|
+
class String
|
3
|
+
def blue
|
4
|
+
return colorize(36)
|
5
|
+
end
|
6
|
+
|
7
|
+
def colorize(color)
|
8
|
+
return "\e[#{color}m#{self}\e[0m"
|
9
|
+
end
|
10
|
+
|
11
|
+
def green
|
12
|
+
return colorize(32)
|
13
|
+
end
|
14
|
+
|
15
|
+
def red
|
16
|
+
return colorize(31)
|
17
|
+
end
|
18
|
+
|
19
|
+
def rsplit(pattern)
|
20
|
+
ret = rpartition(pattern)
|
21
|
+
ret.delete_at(1)
|
22
|
+
return ret
|
23
|
+
end
|
24
|
+
|
25
|
+
def white
|
26
|
+
return colorize(37)
|
27
|
+
end
|
28
|
+
|
29
|
+
def word_wrap(width = 70)
|
30
|
+
return scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).join("\n")
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pstream
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Miles Whittaker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: scoobydoo
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.1'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.1.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.1'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.1.1
|
33
|
+
description: ''
|
34
|
+
email: mjwhitta@gmail.com
|
35
|
+
executables:
|
36
|
+
- pstream
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- bin/pstream
|
41
|
+
- lib/pstream.rb
|
42
|
+
- lib/pstream/error.rb
|
43
|
+
- lib/pstream/error/pcap_not_found.rb
|
44
|
+
- lib/pstream/error/pcap_not_readable.rb
|
45
|
+
- lib/pstream/error/tshark_not_found.rb
|
46
|
+
- lib/pstream/stream.rb
|
47
|
+
- lib/string.rb
|
48
|
+
homepage: http://mjwhitta.github.io/pstream
|
49
|
+
licenses:
|
50
|
+
- GPL-3.0
|
51
|
+
metadata: {}
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 2.4.5.1
|
69
|
+
signing_key:
|
70
|
+
specification_version: 4
|
71
|
+
summary: ''
|
72
|
+
test_files: []
|