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 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,5 @@
1
+ class PStream::Error::PcapNotFound < PStream::Error
2
+ def initialize(pcap)
3
+ super("File not found: #{pcap}")
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class PStream::Error::PcapNotReadable < PStream::Error
2
+ def initialize(pcap)
3
+ super("File not readable: #{pcap}")
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class PStream::Error::TsharkNotFound < PStream::Error
2
+ def initialize
3
+ super("Please install tshark!")
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class PStream::Error < RuntimeError
2
+ end
3
+
4
+ require "pstream/error/pcap_not_found"
5
+ require "pstream/error/pcap_not_readable"
6
+ require "pstream/error/tshark_not_found"
@@ -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: []