pcapr-local 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/.document +5 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +64 -0
  4. data/Rakefile +57 -0
  5. data/VERSION +1 -0
  6. data/bin/pcap2par +49 -0
  7. data/bin/startpcapr +40 -0
  8. data/bin/stoppcapr +33 -0
  9. data/bin/xtractr +5 -0
  10. data/lib/environment.rb +106 -0
  11. data/lib/exe/xtractr +0 -0
  12. data/lib/mu/pcap.rb +110 -0
  13. data/lib/mu/pcap/ethernet.rb +148 -0
  14. data/lib/mu/pcap/header.rb +75 -0
  15. data/lib/mu/pcap/io_pair.rb +67 -0
  16. data/lib/mu/pcap/io_wrapper.rb +76 -0
  17. data/lib/mu/pcap/ip.rb +61 -0
  18. data/lib/mu/pcap/ipv4.rb +257 -0
  19. data/lib/mu/pcap/ipv6.rb +148 -0
  20. data/lib/mu/pcap/packet.rb +104 -0
  21. data/lib/mu/pcap/pkthdr.rb +155 -0
  22. data/lib/mu/pcap/reader.rb +61 -0
  23. data/lib/mu/pcap/reader/http_family.rb +170 -0
  24. data/lib/mu/pcap/sctp.rb +367 -0
  25. data/lib/mu/pcap/sctp/chunk.rb +123 -0
  26. data/lib/mu/pcap/sctp/chunk/data.rb +134 -0
  27. data/lib/mu/pcap/sctp/chunk/init.rb +100 -0
  28. data/lib/mu/pcap/sctp/chunk/init_ack.rb +68 -0
  29. data/lib/mu/pcap/sctp/parameter.rb +110 -0
  30. data/lib/mu/pcap/sctp/parameter/ip_address.rb +48 -0
  31. data/lib/mu/pcap/stream_packetizer.rb +72 -0
  32. data/lib/mu/pcap/tcp.rb +505 -0
  33. data/lib/mu/pcap/udp.rb +69 -0
  34. data/lib/mu/scenario/pcap.rb +164 -0
  35. data/lib/mu/scenario/pcap/fields.rb +50 -0
  36. data/lib/mu/scenario/pcap/rtp.rb +71 -0
  37. data/lib/pcapr_local.rb +159 -0
  38. data/lib/pcapr_local/config.rb +336 -0
  39. data/lib/pcapr_local/db.rb +197 -0
  40. data/lib/pcapr_local/scanner.rb +250 -0
  41. data/lib/pcapr_local/server.rb +178 -0
  42. data/lib/pcapr_local/www/favicon.ico +0 -0
  43. data/lib/pcapr_local/www/favicon.png +0 -0
  44. data/lib/pcapr_local/www/home/index.html +138 -0
  45. data/lib/pcapr_local/www/static/image/16x16/Cancel.png +0 -0
  46. data/lib/pcapr_local/www/static/image/16x16/Cancel.png.1 +0 -0
  47. data/lib/pcapr_local/www/static/image/16x16/Download.png +0 -0
  48. data/lib/pcapr_local/www/static/image/16x16/Folder3.png +0 -0
  49. data/lib/pcapr_local/www/static/image/16x16/Full Size.png +0 -0
  50. data/lib/pcapr_local/www/static/image/16x16/Minus.png +0 -0
  51. data/lib/pcapr_local/www/static/image/16x16/Plus.png +0 -0
  52. data/lib/pcapr_local/www/static/image/16x16/Search.png +0 -0
  53. data/lib/pcapr_local/www/static/image/16x16/User.png +0 -0
  54. data/lib/pcapr_local/www/static/image/48x48/Phone.png +0 -0
  55. data/lib/pcapr_local/www/static/image/48x48/Video.png +0 -0
  56. data/lib/pcapr_local/www/static/image/bar-orange.gif +0 -0
  57. data/lib/pcapr_local/www/static/image/beta.png +0 -0
  58. data/lib/pcapr_local/www/static/image/bg.png +0 -0
  59. data/lib/pcapr_local/www/static/image/blockquote.png +0 -0
  60. data/lib/pcapr_local/www/static/image/body-bg.png +0 -0
  61. data/lib/pcapr_local/www/static/image/body-h3.png +0 -0
  62. data/lib/pcapr_local/www/static/image/body-hl1-bg.png +0 -0
  63. data/lib/pcapr_local/www/static/image/body-hl1-h3.png +0 -0
  64. data/lib/pcapr_local/www/static/image/body-hl1-readmore.png +0 -0
  65. data/lib/pcapr_local/www/static/image/body-hl2-bg.png +0 -0
  66. data/lib/pcapr_local/www/static/image/body-hl2-h3.png +0 -0
  67. data/lib/pcapr_local/www/static/image/body-hl2-readmore.png +0 -0
  68. data/lib/pcapr_local/www/static/image/body-hl3-bg.png +0 -0
  69. data/lib/pcapr_local/www/static/image/body-hl3-h3.png +0 -0
  70. data/lib/pcapr_local/www/static/image/body-hl3-readmore.png +0 -0
  71. data/lib/pcapr_local/www/static/image/body-hl4-bg.png +0 -0
  72. data/lib/pcapr_local/www/static/image/body-hl4-h3.png +0 -0
  73. data/lib/pcapr_local/www/static/image/body-hl4-readmore.png +0 -0
  74. data/lib/pcapr_local/www/static/image/body-hl5-h3.png +0 -0
  75. data/lib/pcapr_local/www/static/image/body-hl6-h3.png +0 -0
  76. data/lib/pcapr_local/www/static/image/body-hl7-h3.png +0 -0
  77. data/lib/pcapr_local/www/static/image/body-hl8-h3.png +0 -0
  78. data/lib/pcapr_local/www/static/image/body-readmore.png +0 -0
  79. data/lib/pcapr_local/www/static/image/bottom-bg.png +0 -0
  80. data/lib/pcapr_local/www/static/image/bottom-l.png +0 -0
  81. data/lib/pcapr_local/www/static/image/bottom-r.png +0 -0
  82. data/lib/pcapr_local/www/static/image/btn-search.png +0 -0
  83. data/lib/pcapr_local/www/static/image/bullet-1.png +0 -0
  84. data/lib/pcapr_local/www/static/image/bullet-2.png +0 -0
  85. data/lib/pcapr_local/www/static/image/bullet-3.png +0 -0
  86. data/lib/pcapr_local/www/static/image/bullet-4.png +0 -0
  87. data/lib/pcapr_local/www/static/image/bullet-5.png +0 -0
  88. data/lib/pcapr_local/www/static/image/bullet-6.png +0 -0
  89. data/lib/pcapr_local/www/static/image/bullet-7.png +0 -0
  90. data/lib/pcapr_local/www/static/image/bullet-hl1.png +0 -0
  91. data/lib/pcapr_local/www/static/image/bullet-hl2.png +0 -0
  92. data/lib/pcapr_local/www/static/image/bullet-hl3.png +0 -0
  93. data/lib/pcapr_local/www/static/image/bullet-hl4.png +0 -0
  94. data/lib/pcapr_local/www/static/image/bullet-pathway.png +0 -0
  95. data/lib/pcapr_local/www/static/image/bullet-section1.png +0 -0
  96. data/lib/pcapr_local/www/static/image/bullet-section2.png +0 -0
  97. data/lib/pcapr_local/www/static/image/collapsed.gif +0 -0
  98. data/lib/pcapr_local/www/static/image/crosslink.png +0 -0
  99. data/lib/pcapr_local/www/static/image/expanded.gif +0 -0
  100. data/lib/pcapr_local/www/static/image/favicon.ico +0 -0
  101. data/lib/pcapr_local/www/static/image/favicon.png +0 -0
  102. data/lib/pcapr_local/www/static/image/icon-author.png +0 -0
  103. data/lib/pcapr_local/www/static/image/icon-created.png +0 -0
  104. data/lib/pcapr_local/www/static/image/p-expand.gif +0 -0
  105. data/lib/pcapr_local/www/static/image/pcapr-logo.png +0 -0
  106. data/lib/pcapr_local/www/static/image/powered-by.png +0 -0
  107. data/lib/pcapr_local/www/static/image/section1-bg.png +0 -0
  108. data/lib/pcapr_local/www/static/image/section1-h3.png +0 -0
  109. data/lib/pcapr_local/www/static/image/section1-readmore.png +0 -0
  110. data/lib/pcapr_local/www/static/image/section2-bg.png +0 -0
  111. data/lib/pcapr_local/www/static/image/section2-h3.png +0 -0
  112. data/lib/pcapr_local/www/static/image/section2-readmore.png +0 -0
  113. data/lib/pcapr_local/www/static/image/status-alert.png +0 -0
  114. data/lib/pcapr_local/www/static/image/status-download.png +0 -0
  115. data/lib/pcapr_local/www/static/image/status-info.png +0 -0
  116. data/lib/pcapr_local/www/static/image/status-note.png +0 -0
  117. data/lib/pcapr_local/www/static/image/tab-round.png +0 -0
  118. data/lib/pcapr_local/www/static/image/throbber.gif +0 -0
  119. data/lib/pcapr_local/www/static/image/user.jpg +0 -0
  120. data/lib/pcapr_local/www/static/script/closet/async.js +421 -0
  121. data/lib/pcapr_local/www/static/script/closet/closet.api.js +241 -0
  122. data/lib/pcapr_local/www/static/script/closet/closet.folders.js +94 -0
  123. data/lib/pcapr_local/www/static/script/closet/closet.js +187 -0
  124. data/lib/pcapr_local/www/static/script/closet/closet.mr.js +219 -0
  125. data/lib/pcapr_local/www/static/script/closet/closet.options.js +359 -0
  126. data/lib/pcapr_local/www/static/script/closet/closet.quantity.js +73 -0
  127. data/lib/pcapr_local/www/static/script/closet/closet.render.js +205 -0
  128. data/lib/pcapr_local/www/static/script/closet/closet.report.js +86 -0
  129. data/lib/pcapr_local/www/static/script/closet/closet.reports.http.js +135 -0
  130. data/lib/pcapr_local/www/static/script/closet/closet.reports.overview.js +163 -0
  131. data/lib/pcapr_local/www/static/script/closet/closet.reports.sip.js +159 -0
  132. data/lib/pcapr_local/www/static/script/closet/closet.reports.tcp.js +72 -0
  133. data/lib/pcapr_local/www/static/script/closet/closet.reports.visualize.js +263 -0
  134. data/lib/pcapr_local/www/static/script/closet/closet.util.js +40 -0
  135. data/lib/pcapr_local/www/static/script/jquery/jquery-1.4.2.min.js +154 -0
  136. data/lib/pcapr_local/www/static/script/jquery/jquery-ui.js +10921 -0
  137. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.js +2123 -0
  138. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.selection.js +184 -0
  139. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.stack.js +184 -0
  140. data/lib/pcapr_local/www/static/script/jquery/jquery.form.js +643 -0
  141. data/lib/pcapr_local/www/static/script/jquery/jquery.jsonp.min.js +3 -0
  142. data/lib/pcapr_local/www/static/script/jquery/jquery.menu.js +142 -0
  143. data/lib/pcapr_local/www/static/script/jquery/jquery.suggest.js +308 -0
  144. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.core.js +203 -0
  145. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.slider.js +629 -0
  146. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.sortable.js +1055 -0
  147. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.widget.js +236 -0
  148. data/lib/pcapr_local/www/static/script/json2.js +481 -0
  149. data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.cache.js +115 -0
  150. data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.template.js +117 -0
  151. data/lib/pcapr_local/www/static/script/sammy/sammy.js +1696 -0
  152. data/lib/pcapr_local/www/static/script/tipsy/jquery.tipsy.js +104 -0
  153. data/lib/pcapr_local/www/static/style/c3p0.css +116 -0
  154. data/lib/pcapr_local/www/static/style/jquery.suggest.css +27 -0
  155. data/lib/pcapr_local/www/static/style/page.css +1113 -0
  156. data/lib/pcapr_local/www/static/style/tipsy.css +7 -0
  157. data/lib/pcapr_local/www/templates/browse.services.template +10 -0
  158. data/lib/pcapr_local/www/templates/browse.template +77 -0
  159. data/lib/pcapr_local/www/templates/flows.template +38 -0
  160. data/lib/pcapr_local/www/templates/pcap.template +63 -0
  161. data/lib/pcapr_local/www/templates/sip.calls.template +35 -0
  162. data/lib/pcapr_local/www/templates/statistics.template +6 -0
  163. data/lib/pcapr_local/xtractr.rb +179 -0
  164. data/lib/pcapr_local/xtractr/instance.rb +172 -0
  165. data/pcapr-local.gemspec +297 -0
  166. data/test/mu/pcap/reader/tc_http_family.rb +251 -0
  167. data/test/mu/pcap/tc_ethernet.rb +71 -0
  168. data/test/mu/pcap/tc_header.rb +56 -0
  169. data/test/mu/pcap/tc_ipv4.rb +103 -0
  170. data/test/mu/pcap/tc_ipv6.rb +83 -0
  171. data/test/mu/pcap/tc_packet.rb +44 -0
  172. data/test/mu/pcap/tc_pair.rb +58 -0
  173. data/test/mu/pcap/tc_pkthdr.rb +33 -0
  174. data/test/mu/pcap/tc_reader.rb +76 -0
  175. data/test/mu/pcap/tc_tcp.rb +426 -0
  176. data/test/mu/pcap/tc_udp.rb +33 -0
  177. data/test/mu/pcap/tc_wrapper.rb +80 -0
  178. data/test/mu/scenario/pcap/tc_fields.rb +67 -0
  179. data/test/mu/scenario/pcap/tc_rtp.rb +135 -0
  180. data/test/mu/scenario/sip_signalled_call_1.pcap +0 -0
  181. data/test/mu/scenario/tc_pcap.rb +190 -0
  182. data/test/mu/scenario/test_data/arp.pcap +0 -0
  183. data/test/mu/scenario/test_data/dns.pcap +0 -0
  184. data/test/mu/scenario/test_data/http-v6.pcap +0 -0
  185. data/test/mu/scenario/test_data/http.pcap +0 -0
  186. data/test/mu/scenario/test_data/http_chunked.pcap +0 -0
  187. data/test/mu/scenario/test_data/http_deflate.pcap +0 -0
  188. data/test/mu/scenario/test_data/httpauth3.pcap +0 -0
  189. data/test/mu/scenario/test_data/icmp.pcap +0 -0
  190. data/test/mu/scenario/test_data/sip_signalled_call_1.pcap +0 -0
  191. data/test/mu/tc_pcap.rb +39 -0
  192. data/test/mu/testcase.rb +86 -0
  193. data/test/pcapr_local/arp.pcap +0 -0
  194. data/test/pcapr_local/data.js +3 -0
  195. data/test/pcapr_local/http_chunked.pcap +0 -0
  196. data/test/pcapr_local/tc_api.rb +181 -0
  197. data/test/pcapr_local/test.tgz +0 -0
  198. data/test/pcapr_local/test_scanner.rb +241 -0
  199. data/test/pcapr_local/test_xtractr.rb +219 -0
  200. data/test/pcapr_local/testcase.rb +107 -0
  201. data/test/test_export_to_scenario.sh +25 -0
  202. data/test/test_pcapr_local.rb +29 -0
  203. metadata +450 -0
@@ -0,0 +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
@@ -0,0 +1,164 @@
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_SIZE_OPTS = "-n -o 'column.format: cum_size, \"%B\"'"
19
+ TSHARK_PSML_OPTS = %Q{#{TSHARK_OPTS} -o 'column.format: "Protocol", "%p", "Info", "%i"'}
20
+
21
+ MAX_PCAP_SIZE = 102400 # 100KB
22
+ MAX_RAW_PCAP_SIZE_MB = 25
23
+ MAX_RAW_PCAP_SIZE = MAX_RAW_PCAP_SIZE_MB * 1024 * 1000
24
+ EXCLUDE_FROM_SIZE_CHECK = ['rtp'].freeze
25
+
26
+ class PcapTooLarge < StandardError; end
27
+
28
+ def self.validate_pcap_size(path)
29
+ tshark_filter = EXCLUDE_FROM_SIZE_CHECK.map{ |proto| "not #{proto}" }.join " and "
30
+ io = ::IO.popen "tshark #{TSHARK_SIZE_OPTS} -r #{path} -R '#{tshark_filter}' | tail -1"
31
+ if ::IO.select [ io ], nil, nil, TSHARK_READ_TIMEOUT
32
+ if io.eof?
33
+ size = 0
34
+ else
35
+ last_line = io.readline
36
+ size = last_line.to_i
37
+ end
38
+ end
39
+
40
+ if size.nil? or size == 0
41
+ size = File.size(path)
42
+ end
43
+
44
+ if size > MAX_PCAP_SIZE
45
+ raise PcapTooLarge, "Selected packets have a size of #{size} bytes which " +
46
+ "exceeds the #{MAX_PCAP_SIZE} byte maximum."
47
+ end
48
+
49
+ if size > MAX_RAW_PCAP_SIZE
50
+ raise PcapTooLarge, "Selected packets have a raw size of #{size} bytes which " +
51
+ "exceeds the #{MAX_RAW_PCAP_SIZE_MB}MB maximum."
52
+ end
53
+
54
+ return size
55
+ end
56
+
57
+ PAR_VERSION = 1
58
+ def self.export_to_par pcap_path, opts=nil
59
+ opts ||= {}
60
+
61
+ # Open pcap file
62
+ File.exist?(pcap_path) or raise "Cannot open file '#{pcap_path}'."
63
+ validate_pcap_size pcap_path
64
+ pcap = open pcap_path, 'rb'
65
+
66
+ # Get Mu::Pcap::Packets
67
+ packets = to_pcap_packets pcap, opts[:isolate_l7]
68
+
69
+ # Write normalized packets to tempfile
70
+ tmpdir = Dir.mktmpdir
71
+ norm_pcap = File.open "#{tmpdir}/normalized.pcap", 'wb'
72
+ pcap = Mu::Pcap.from_packets packets
73
+ pcap.write norm_pcap
74
+ norm_pcap.close
75
+
76
+ # Get wireshark dissected field values for all packets.
77
+ `tshark -T fields #{TSHARK_OPTS} #{Fields::TSHARK_OPTS} -Eseparator='\xff' -r #{norm_pcap.path} > #{tmpdir}/fields`
78
+ fields = open "#{tmpdir}/fields", 'rb'
79
+
80
+ # Get wireshark dissected field values for all packets.
81
+ fields_array = []
82
+ if fields
83
+ packets.each do |packet|
84
+ fields_array << Fields.next_from_io(fields)
85
+ end
86
+ end
87
+
88
+ # Protocol specific preprocessing, packets may be deleted.
89
+ Rtp.preprocess packets, fields_array
90
+
91
+ File.open "#{tmpdir}/packets.dump", 'wb' do |f|
92
+ Marshal.dump packets, f
93
+ end
94
+
95
+ # Create a second pcap with packets removed.
96
+ norm_pcap = File.open "#{tmpdir}/normalized.pcap", 'wb'
97
+ pcap = Mu::Pcap.from_packets packets
98
+ pcap.write norm_pcap
99
+ norm_pcap.close
100
+
101
+ # Dump PSML to file.
102
+ # (The no-op filter sometimes produces slighty more verbose descriptions.)
103
+ `tshark -T psml #{TSHARK_PSML_OPTS} -r #{norm_pcap.path} -R 'rtp or not rtp' > #{tmpdir}/psml`
104
+
105
+ # Dump PDML io file.
106
+ `tshark -T pdml #{TSHARK_OPTS} -r #{norm_pcap.path} > #{tmpdir}/pdml`
107
+ pdml = open "#{tmpdir}/pdml", 'rb'
108
+
109
+ # Create about
110
+ open "#{tmpdir}/about", 'w' do |about|
111
+ about.puts({:par_version => PAR_VERSION}.to_json)
112
+ end
113
+
114
+ # Create zip
115
+ Dir.chdir tmpdir do
116
+ system "zip -q dissected.zip about pdml psml fields packets.dump normalized.pcap"
117
+ return open("dissected.zip")
118
+ end
119
+ ensure
120
+ if tmpdir
121
+ FileUtils.rm_rf tmpdir
122
+ end
123
+ end
124
+
125
+ def self.to_pcap_packets io, isolate_l7=true
126
+ packets = []
127
+
128
+ # Read Pcap packets from Pcap
129
+ Mu::Pcap.each_pkthdr io do |pkthdr|
130
+ if pkthdr.len != pkthdr.caplen
131
+ raise Mu::Pcap::ParseError, "Error: Capture contains truncated packets. " +
132
+ "Try recapturing with an increased snapshot length."
133
+ end
134
+ if not pkthdr.pkt.is_a? Mu::Pcap::Ethernet
135
+ warning 'Unable to parse packet, skipping.'
136
+ end
137
+ packets << pkthdr.pkt
138
+ end
139
+
140
+ if (packets.length == 0)
141
+ raise Mu::Pcap::ParseError, "No valid packets found!"
142
+ end
143
+
144
+ packets = Mu::Pcap::IPv4.reassemble packets
145
+
146
+ if isolate_l7
147
+ packets = Mu::Pcap::Packet.isolate_l7 packets
148
+ end
149
+
150
+ packets = Mu::Pcap::Packet.normalize packets
151
+ packets = Mu::Pcap::TCP.split packets
152
+
153
+ packets
154
+ end
155
+
156
+ def self.warning msg
157
+ $stderr.puts "WARNING: #{msg}"#, caller, $!
158
+ end
159
+ end
160
+
161
+ end
162
+ end
163
+
164
+ require 'mu/scenario/pcap/rtp'
@@ -0,0 +1,50 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'mu/scenario/pcap'
6
+
7
+ module Mu
8
+ class Scenario
9
+ module Pcap
10
+
11
+ class Fields
12
+ FIELDS = [
13
+ :rtp,
14
+ :"rtp.setup-frame"
15
+ ].freeze
16
+ FIELD_COUNT = FIELDS.length
17
+ SEPARATOR = "\xff".freeze
18
+ TSHARK_OPTS = "-Eseparator='#{SEPARATOR}'"
19
+ FIELDS.each do |field|
20
+ TSHARK_OPTS << " -e #{field}"
21
+ end
22
+ TSHARK_OPTS.freeze
23
+
24
+ def self.readline io
25
+ if ::IO.select [ io ], nil, nil, Pcap::TSHARK_READ_TIMEOUT
26
+ return io.readline.chomp
27
+ end
28
+
29
+ raise Errno::ETIMEDOUT, "read timed out"
30
+ end
31
+
32
+ def self.next_from_io io
33
+ if line = readline(io)
34
+ fields = line.split SEPARATOR, FIELD_COUNT
35
+ hash = {}
36
+ FIELDS.each do |key|
37
+ val = fields.shift
38
+ hash[key] = val.empty? ? nil : val
39
+ end
40
+ return hash
41
+ end
42
+ rescue Exception => e
43
+ Pcap.warning e.message
44
+ return nil
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,71 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ module Mu
6
+ class Scenario
7
+ module Pcap
8
+ module Rtp
9
+
10
+ TRUNC_COUNT = 5
11
+
12
+ def self.preprocess packets, fields_per_packet
13
+ signaled_by = []
14
+ prev_signal_frame = {}
15
+ packets.each_with_index do |packet, idx|
16
+ fields = fields_per_packet[idx]
17
+ if fields and fields[:rtp]
18
+ flow_id = packet.flow_id
19
+ if frame = fields[:"rtp.setup-frame"]
20
+ prev_signal_frame[flow_id] = frame
21
+ else
22
+ if frame = prev_signal_frame[flow_id]
23
+ fields[:"rtp.setup-frame"] = frame
24
+ else
25
+ packets[idx] = nil
26
+ fields_per_packet[idx] = nil
27
+ next
28
+ end
29
+ end
30
+ sig_idx = frame.to_i
31
+ signaled_by[idx] = sig_idx
32
+ end
33
+ end
34
+
35
+ flow_to_count = Hash.new 0
36
+ prev_setup_frame = {}
37
+ keep_frames = []
38
+ packets.each_with_index do |packet, idx|
39
+ if setup_frame = signaled_by[idx]
40
+ flow = packet.flow_id
41
+ count = flow_to_count[flow]
42
+ if setup_frame != prev_setup_frame[flow]
43
+ prev_setup_frame[flow] = setup_frame
44
+ count = 1
45
+ else
46
+ count += 1
47
+ end
48
+ if count <= TRUNC_COUNT
49
+ keep_frames << idx + 1
50
+ else
51
+ packets[idx] = nil
52
+ fields_per_packet[idx] = nil
53
+ end
54
+ flow_to_count[flow] = count
55
+ end
56
+ end
57
+
58
+ packets.reject! {|p| not p }
59
+ fields_per_packet.reject! {|p| not p }
60
+
61
+ filter = "not rtp"
62
+ keep_frames.each do |frame|
63
+ filter << " or frame.number == #{frame}"
64
+ end
65
+
66
+ return filter
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,159 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'rubygems'
6
+ require 'environment'
7
+ require 'pcapr_local/config'
8
+ require 'pcapr_local/scanner'
9
+ require 'pcapr_local/server'
10
+ require 'pcapr_local/xtractr'
11
+ require 'logger'
12
+
13
+ module PcaprLocal
14
+ START_SCRIPT = File.join(ROOT, 'bin/pcapr_start.rb')
15
+
16
+ # We share a single Logger across all of pcapr.Local.
17
+ Logger = Logger.new(STDOUT)
18
+
19
+ # Recreate logger using configured log location.
20
+ LOGFILE = "server.log"
21
+ def self.start_logging log_dir
22
+ if log_dir and not log_dir.empty?
23
+ if const_defined? :Logger
24
+ remove_const :Logger
25
+ end
26
+
27
+ logfile = File.join(log_dir, LOGFILE)
28
+ FileUtils.mkdir_p log_dir
29
+ const_set :Logger, Logger.new(logfile, 5)
30
+ end
31
+ end
32
+
33
+ # Start xtractr instance manager.
34
+ def self.start_xtractr config
35
+ xtractr_config = config['xtractr'].merge(
36
+ "index_dir" => config.fetch("index_dir"),
37
+ "pcap_dir" => config.fetch("pcap_dir")
38
+ )
39
+ Xtractr.new xtractr_config
40
+ end
41
+
42
+ # Start file system scanner.
43
+ def self.start_scanner config, db, xtractr
44
+ scanner_config = config.fetch('scanner').merge(
45
+ "index_dir" => config.fetch("index_dir"),
46
+ "pcap_dir" => config.fetch("pcap_dir"),
47
+ "db" => db,
48
+ "xtractr" => xtractr
49
+ )
50
+ PcaprLocal::Scanner.start scanner_config
51
+ end
52
+
53
+ # Start webserver UI/API
54
+ def self.start_app config, db, scanner, xtractr
55
+ app_config = config.fetch "app"
56
+ root = File.expand_path(File.dirname(__FILE__))
57
+ app_file = File.join(root, "pcapr_local/server.rb")
58
+ PcaprLocal::Server.run! \
59
+ :app_file => app_file,
60
+ :dump_errors => true,
61
+ :logging => true,
62
+ :port => app_config.fetch("port"),
63
+ :bind => app_config.fetch("host"),
64
+ :db => db,
65
+ :scanner => scanner,
66
+ :xtractr => xtractr
67
+ end
68
+
69
+ def self.get_db config
70
+ PcaprLocal::DB.get_db config.fetch("couch")
71
+ end
72
+
73
+ def self.start config=nil
74
+ config ||= PcaprLocal::Config.config
75
+
76
+ # Check that server is not already running.
77
+ check_pid_file config['pidfile']
78
+
79
+ # Start logging.
80
+ if config["log_dir"]
81
+ start_logging config['log_dir']
82
+ end
83
+ start_msg = "Starting server at #{config['app']['host']}:#{config['app']['port']}"
84
+ Logger.info start_msg
85
+ puts start_msg
86
+ puts "Log is at #{config['log_dir']}/#{LOGFILE}"
87
+
88
+ # Deamonize
89
+ unless config['debug_mode']
90
+ puts "Moving server process to the background. Run 'stoppcapr' to stop the server."
91
+ Process.daemon
92
+ end
93
+
94
+ # Create pid file that will be deleted when we shutdown.
95
+ create_pid_file config['pidfile']
96
+
97
+ # Get database instance
98
+ db = get_db config
99
+
100
+ # Xtractr manager
101
+ xtractr = start_xtractr config
102
+
103
+ # Start scanner thread
104
+ scanner = start_scanner config, db, xtractr
105
+
106
+ # Start application server
107
+ start_app config, db, scanner, xtractr
108
+ end
109
+
110
+ def self.check_pid_file file
111
+ if File.exist? file
112
+ # If we get Errno::ESRCH then process does not exist and
113
+ # we can safely cleanup the pid file.
114
+ pid = File.read(file).to_i
115
+ begin
116
+ Process.kill(0, pid)
117
+ rescue Errno::ESRCH
118
+ stale_pid = true
119
+ rescue
120
+ end
121
+
122
+ unless stale_pid
123
+ puts "Server is already running (pid=#{pid})"
124
+ exit
125
+ end
126
+ end
127
+ end
128
+
129
+ def self.create_pid_file file
130
+ File.open(file, "w") { |f| f.puts Process.pid }
131
+
132
+ # Remove pid file during shutdown
133
+ at_exit do
134
+ Logger.info "Shutting down." rescue nil
135
+ if File.exist? file
136
+ File.unlink file
137
+ end
138
+ end
139
+ end
140
+
141
+ # Sends SIGTERM to process in pidfile. Server should trap this
142
+ # and shutdown cleanly.
143
+ def self.stop config=nil
144
+ user_config = Config.user_config_path
145
+ if File.exist?(user_config)
146
+ config = PcaprLocal::Config.config user_config
147
+ pid_file = config["pidfile"]
148
+ if pid_file and File.exist? pid_file
149
+ pid = Integer(File.read(pid_file))
150
+ Process.kill -15, -pid
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ if __FILE__ == $0
157
+ PcaprLocal.start
158
+ end
159
+