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
Binary file
Binary file
@@ -0,0 +1,39 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'mu/testcase'
6
+ require 'mu/pcap'
7
+
8
+ module Mu
9
+ class Pcap
10
+
11
+ class Test < Mu::TestCase
12
+ def test_basics
13
+ pcap = Pcap.new
14
+ pkthdr = Pkthdr.new
15
+ pkthdr.caplen = pkthdr.len = 77
16
+ ethernet = Ethernet.new
17
+ ethernet.src = '00:01:01:00:00:01'
18
+ ethernet.dst = '00:01:01:00:00:02'
19
+ ethernet.type = Ethernet::ETHERTYPE_IP
20
+ ethernet.payload = ethernet.payload_raw = 'X' * 73
21
+ pkthdr.pkt = ethernet
22
+ pcap.pkthdrs << pkthdr
23
+
24
+ bytes = "\xa1\xb2\xc3\xd4" + "\x00\x02" + "\x00\x04" +
25
+ "\x00\x00\x00\x00" + "\x00\x00\x00\x00" +
26
+ "\x00\x00\x05\xdc" + "\x00\x00\x00\x00" +
27
+ "\x00\x00\x00\x00" + "\x00\x00\x00\x00" + # pkthdr
28
+ "\x00\x00\x00\x4d" + "\x00\x00\x00\x4d" +
29
+ "\x00\x00\x00\x02" + ("X" * 73)
30
+ pcap_in = nil
31
+ with_no_stderr do # supress warning about malformed IPv4
32
+ pcap_in = Pcap.read StringIO.new(bytes)
33
+ end
34
+ assert_equal pcap_in, pcap
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,86 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'tempfile'
6
+ require 'test/unit'
7
+ require 'pp' # Require to make pp available in tests
8
+
9
+
10
+ module Mu
11
+ class TestCase < ::Test::Unit::TestCase
12
+ def setup
13
+ self.reset
14
+ end
15
+
16
+ def self.reset
17
+ # Reset random number generator and Time.now to known values
18
+ srand 31337
19
+ end
20
+
21
+ def reset
22
+ self.class.reset
23
+ end
24
+
25
+ def assert_files_same expected_file, actual_file, message=nil
26
+ expected_file = File.expand_path expected_file
27
+ actual_file = File.expand_path actual_file
28
+
29
+ # Set TC_CREATE env variable to create missing stdout files
30
+ create_missing_file = ENV['TC_CREATE'].to_s.length > 0
31
+ # Set TC_UPDATE env variable to update stdout files instead of failing (be careful!)
32
+ bulk_update = ENV['TC_UPDATE'].to_s.length > 0
33
+
34
+ if create_missing_file and not File.exists? expected_file
35
+ File.open("/dev/tty", 'w') do |tty|
36
+ tty.puts "Warning: copying #{actual_file} to #{expected_file}"
37
+ end
38
+ File.open(expected_file, 'w') {|f| f.write File.read(actual_file)}
39
+ end
40
+
41
+ assert File.exists?(expected_file), "File #{expected_file.inspect} does not exist"
42
+ assert File.exists?(actual_file), "File #{actual_file.inspect} does not exist"
43
+
44
+ message ||= "Files differ: #{expected_file} #{actual_file}"
45
+ assert_block message do
46
+ $stderr.puts `diff -ub #{expected_file} #{actual_file} 2>&1`
47
+ if $?.exitstatus == 0
48
+ return true
49
+ end
50
+
51
+ # Hook for graphical diff/merge tools
52
+ if diff = ENV['DIFF']
53
+ puts `#{diff} #{expected_file} #{actual_file}`
54
+ else
55
+ $stderr.puts "You may want to rerun test with DIFF env variable set to a graphical diff/merge tool"
56
+ end
57
+
58
+ if bulk_update
59
+ File.open("/dev/tty", 'w') do |tty|
60
+ tty.puts "Warning: updating expected output at #{actual_file} to #{expected_file}"
61
+ end
62
+ File.open(expected_file, 'w') {|f| f.write File.read(actual_file)}
63
+ next true
64
+ end
65
+
66
+ false
67
+ end
68
+ end
69
+
70
+ # Suppress output to stderr. For testing code that may log to stderr.
71
+ def with_no_stderr # block
72
+ begin
73
+ old_stderr = $stderr
74
+ $stderr = StringIO.new
75
+ yield
76
+ ensure
77
+ $stderr = old_stderr
78
+ end
79
+ end
80
+
81
+ def default_test
82
+ # Defining this method prevents this class from running and failing
83
+ # due to lack of tests.
84
+ end
85
+ end
86
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ {"status":"indexed","updated_at":"2010/12/22 01:30:20 +0000","_id":"6808db6ca2264c01780e7fb4fb5ca623","_rev":"3-a5530512f0c1010c7d82c7f1dda0d516","type":"pcap","index":{"about":{"packets":28,"hosts":10,"version":"4.5.41604","services":7,"flows":5,"duration":9.45506},"services":["browser","nbns","arp","sip","sip/sdp","rtp","icmp"]},"filename":"A1.pcap","stat":{"inode":6395143,"size":9300,"ctime":"2010/12/18 01:41:41 +0000"},"created_at":"2010/12/22 01:30:18 +0000"}
2
+ {"status":"indexed","updated_at":"2010/12/22 01:30:23 +0000","_id":"6808db6ca2264c01780e7fb4fb5c9022","_rev":"3-1121a5eff55ba3d3c0b6e6177c5dcfcf","type":"pcap","index":{"about":{"packets":2,"hosts":3,"version":"4.5.41604","services":1,"flows":0,"duration":4.59072e-05},"services":["arp"]},"filename":"arp.pcap","stat":{"inode":6395176,"size":140,"ctime":"2010/12/20 18:56:49 +0000"},"created_at":"2010/12/22 01:30:18 +0000"}
3
+ {"status":"indexed","updated_at":"2010/12/22 01:30:26 +0000","_id":"6808db6ca2264c01780e7fb4fb5c9ada","_rev":"3-8c43c559332f027de3b27ce59c54a41b","type":"pcap","index":{"about":{"packets":22,"hosts":5,"version":"4.5.41604","services":6,"flows":4,"duration":6.29398},"services":["arp","sip/sdp","sip","rtcp","rtp","icmp"]},"filename":"sip_signalled_call_1.pcap","stat":{"inode":6395187,"size":5039,"ctime":"2010/12/21 02:04:04 +0000"},"created_at":"2010/12/22 01:30:18 +0000"}
Binary file
@@ -0,0 +1,181 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ $: << File.expand_path(File.dirname(__FILE__) + '../../../../lib')
6
+
7
+ require 'pcapr_local'
8
+ require 'test/unit'
9
+
10
+ module CouchTest
11
+ def datafile
12
+ nil
13
+ end
14
+
15
+ # Returns user config but with parameters to changed to prevent clobbering user data.
16
+ def config
17
+ config = PcaprLocal::Config.config
18
+ config['couch']['database'] = "#{config['couch']['database']}_test"
19
+ config['install_dir'] = "/tmp/pcapr_local_test"
20
+ config['pcap_dir'] = "/tmp/pcapr_local_test/pcaps"
21
+ config['index_dir'] = "/tmp/pcapr_local_test/indexes"
22
+ config['app']['port'] = config['app']['port'].to_i + 1
23
+ config
24
+ end
25
+
26
+ # Starts pcapr_local in separate process
27
+ def setup
28
+ config = self.config
29
+ host = config['app']['host']
30
+ port = config['app']['port']
31
+ @url_base = "http://#{host}:#{port}"
32
+
33
+ # Extract test pcaps and indexes
34
+ FileUtils.rm_rf '/tmp/pcapr_local_test'
35
+ test_tar = File.join(File.expand_path(File.dirname(__FILE__)), 'test.tgz')
36
+ if File.exist? test_tar
37
+ puts `tar -C /tmp/ -xzf #{test_tar}`
38
+ end
39
+
40
+ # Recreate test database.
41
+ begin
42
+ couch = config['couch']
43
+ RestClient.delete "#{couch['uri']}/#{couch['database']}"
44
+ rescue RestClient::ResourceNotFound
45
+ end
46
+ db = PcaprLocal.get_db config
47
+
48
+ # And restore it from datafile.
49
+ if self.datafile
50
+ load_docs self.datafile, db
51
+ end
52
+
53
+ # Start server.
54
+ config_file = Tempfile.new "config"
55
+ config_file.print config.to_json
56
+ config_file.flush
57
+ @pid = fork do
58
+ Process.setpgid $$, $$
59
+ exec "#{PcaprLocal::ROOT}/bin/startpcapr -f #{config_file.path} -d"
60
+ end
61
+
62
+ # And wait for it to be ready.
63
+ wait_for_server host, port
64
+ end
65
+
66
+ def wait_for_server host, port, time=10
67
+ stop = Time.new + time
68
+ while Time.new < stop
69
+ if s = TCPSocket.open(host, port) rescue nil
70
+ s.close
71
+ return
72
+ end
73
+ sleep 0.01
74
+ end
75
+
76
+ raise "Server at #{host}:#{port} took longer than #{time} seconds to start"
77
+ end
78
+
79
+ def teardown
80
+ # stop server
81
+ if @pid
82
+ Process.kill -2, @pid
83
+ Process.wait @pid
84
+ @pid = nil
85
+ end
86
+ end
87
+
88
+ def load_docs doc_file, db
89
+ open doc_file do |js|
90
+ while line = js.gets
91
+ doc = JSON.parse line
92
+ doc.delete '_rev'
93
+ db.save_doc doc, true
94
+ end
95
+
96
+ db.bulk_save
97
+ end
98
+ end
99
+
100
+ def assert_json s1, s2, msg=nil
101
+ o1 = JSON.parse s1
102
+ o2 = JSON.parse s2
103
+
104
+ if o1.is_a? Hash
105
+ o1.delete "_rev"
106
+ end
107
+
108
+ if o2.is_a? Hash
109
+ o2.delete "_rev"
110
+ end
111
+
112
+ assert_equal o1, o2, msg
113
+ end
114
+ end
115
+
116
+ class CouchTestBasic < Test::Unit::TestCase
117
+ include CouchTest
118
+
119
+ def datafile
120
+ File.join(File.dirname(__FILE__), 'data.js')
121
+ end
122
+
123
+ def test_basic
124
+ # Main page
125
+ r = RestClient.get @url_base
126
+ assert_match "pcapr.Local", r
127
+
128
+ # Status
129
+ r = RestClient.get "#{@url_base}/pcaps/1/status"
130
+ assert_equal '{"indexed,1292981418000":3}', r
131
+
132
+ # Statistics
133
+ r = RestClient.get "#{@url_base}/pcaps/1/statistics"
134
+ assert_json '{"packets":52,"bytes":14479,"services":14,"flows":9,"pcaps":3}', r
135
+
136
+ # List
137
+ list = {
138
+ 'date' => %q{{"rows":[{"id":"6808db6ca2264c01780e7fb4fb5c9022","value":null,"key":1292981418000},{"id":"6808db6ca2264c01780e7fb4fb5c9ada","value":null,"key":1292981418000},{"id":"6808db6ca2264c01780e7fb4fb5ca623","value":null,"key":1292981418000}],"offset":0,"total_rows":3}},
139
+ 'path' => %q{{"rows":[{"value":3,"key":null}]}},
140
+ 'status' => %q{{"rows":[{"value":3,"key":null}]}},
141
+ 'service' => %q{{"rows":[{"value":14,"key":null}]}},
142
+ 'keyword' => %q{{"rows":[{"value":7,"key":null}]}},
143
+ 'filename' => %q{{"rows":[{"id":"6808db6ca2264c01780e7fb4fb5ca623","value":null,"key":"A1.pcap"},{"id":"6808db6ca2264c01780e7fb4fb5c9022","value":null,"key":"arp.pcap"},{"id":"6808db6ca2264c01780e7fb4fb5c9ada","value":null,"key":"sip_signalled_call_1.pcap"}],"offset":0,"total_rows":3}},
144
+ 'directory' => %q{{"rows":[{"value":3,"key":null}]}}
145
+ }
146
+
147
+ r = RestClient.get "#{@url_base}/pcaps/1/list"
148
+ assert_json list['date'], r
149
+
150
+ list.keys.each do |key|
151
+ r = RestClient.get "#{@url_base}/pcaps/1/list?by=#{key}"
152
+ assert_json list[key], r, "unexpected result when listing by key '#{key}'"
153
+ end
154
+
155
+ # About
156
+ r = RestClient.get "#{@url_base}/pcaps/1/about/6808db6ca2264c01780e7fb4fb5c9ada"
157
+ assert_json %q{{"status":"indexed","updated_at":"2010/12/22 01:30:26 +0000","_id":"6808db6ca2264c01780e7fb4fb5c9ada","_rev":"1-2fcf4b207c34b4928bf08945a084a1e7","type":"pcap","filename":"sip_signalled_call_1.pcap","index":{"about":{"packets":22,"hosts":5,"version":"4.5.41604","services":6,"flows":4,"duration":6.29398},"services":["arp","sip/sdp","sip","rtcp","rtp","icmp"]},"stat":{"inode":6395187,"size":5039,"ctime":"2010/12/21 02:04:04 +0000"},"created_at":"2010/12/22 01:30:18 +0000"}}, r
158
+
159
+ # Remove
160
+ r = RestClient.get "#{@url_base}/pcaps/1/remove/6808db6ca2264c01780e7fb4fb5c9ada"
161
+ assert_json %q{{"error":true,"reason":"status is not failed"}}, r
162
+
163
+ # Explore on pcapr
164
+ r = RestClient.get "#{@url_base}/pcaps/1/pcap/6808db6ca2264c01780e7fb4fb5c9ada"
165
+ assert_match /pcapr/, r, "Doesn't look like we got redirected to pcapr"
166
+
167
+ # Forward to xtractr API
168
+ r = RestClient.get "#{@url_base}/pcaps/1/pcap/6808db6ca2264c01780e7fb4fb5c9ada/api/fields"
169
+ assert_equal %q{["pkt.src","pkt.dst","pkt.flow","pkt.id","pkt.pcap","pkt.first","pkt.dir","pkt.time","pkt.offset","pkt.length","pkt.service","pkt.title","arp.dst.hw.mac","arp.hw.size","arp.hw.type","arp.isgratuitous","arp.opcode","arp.proto.size","arp.proto.type","arp.src.hw.mac","eth.addr","eth.dst","eth.ig","eth.lg","eth.src","eth.type","icmp.code","icmp.type","ip.dsfield","ip.dsfield.ce","ip.dsfield.dscp","ip.dsfield.ect","ip.dst.host","ip.flags","ip.flags.df","ip.flags.mf","ip.flags.rb","ip.frag.offset","ip.hdr.len","ip.host","ip.id","ip.len","ip.proto","ip.src.host","ip.ttl","ip.version","rtcp.length","rtcp.length.check","rtcp.padding","rtcp.pt","rtcp.rc","rtcp.sc","rtcp.sdes.length","rtcp.sdes.text","rtcp.sdes.type","rtcp.sender.octetcount","rtcp.sender.packetcount","rtcp.senderssrc","rtcp.setup.frame","rtcp.setup.method","rtcp.ssrc.cum.nr","rtcp.ssrc.dlsr","rtcp.ssrc.ext.high","rtcp.ssrc.fraction","rtcp.ssrc.high.cycles","rtcp.ssrc.high.seq","rtcp.ssrc.identifier","rtcp.ssrc.jitter","rtcp.ssrc.lsr","rtcp.timestamp.ntp","rtcp.timestamp.ntp.lsw","rtcp.timestamp.ntp.msw","rtcp.timestamp.rtp","rtcp.version","rtp.cc","rtp.ext","rtp.extseq","rtp.marker","rtp.p.type","rtp.padding","rtp.seq","rtp.setup.frame","rtp.setup.method","rtp.ssrc","rtp.timestamp","rtp.version","sdp.connection.info","sdp.connection.info.address","sdp.connection.info.address.type","sdp.fmtp.parameter","sdp.media","sdp.media.attr","sdp.media.attribute.field","sdp.media.attribute.value","sdp.media.format","sdp.media.media","sdp.media.port","sdp.media.proto","sdp.mime.type","sdp.owner","sdp.owner.address","sdp.owner.address.type","sdp.owner.sessionid","sdp.owner.username","sdp.owner.version","sdp.sample.rate","sdp.session.name","sdp.time","sdp.time.start","sdp.time.stop","sdp.version","sip.allow","sip.call.id","sip.contact","sip.content.length","sip.content.type","sip.cseq","sip.cseq.method","sip.cseq.seq","sip.from.addr","sip.from.host","sip.from.user","sip.max.forwards","sip.method","sip.msg.hdr","sip.r.uri","sip.r.uri.host","sip.r.uri.user","sip.release.time","sip.request.line","sip.resend","sip.response.request","sip.response.time","sip.server","sip.status.code","sip.status.line","sip.supported","sip.tag","sip.to","sip.to.addr","sip.to.host","sip.to.user","sip.user.agent","sip.via","udp.dstport","udp.length","udp.port","udp.srcport"]}, r
170
+
171
+ # Export to zip
172
+ zip = RestClient.get "#{@url_base}/pcaps/1/export_to_par/6808db6ca2264c01780e7fb4fb5c9ada"
173
+ Tempfile.open 'zip' do |io|
174
+ io.write zip
175
+ io.flush
176
+ unzip = `unzip -l #{io.path} |awk '{print $4}'`
177
+ assert_equal "\nName\n----\nabout\npdml\npsml\nfields\npackets.dump\nnormalized.pcap\n\n\n", unzip
178
+ end
179
+
180
+ end
181
+ end
Binary file
@@ -0,0 +1,241 @@
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ require 'mu/testcase'
6
+ require 'pcapr_local'
7
+ require 'test/pcapr_local/testcase'
8
+
9
+ module PcaprLocal
10
+ class Scanner
11
+
12
+ class Test < ::PcaprLocal::Test::TestCase
13
+
14
+ class FakeXtractr
15
+ def index pcap_path, index_dir
16
+ FileUtils.mkdir_p "#{index_dir}/terms.db"
17
+ FileUtils.touch "#{index_dir}/packets.db"
18
+ FileUtils.touch "#{index_dir}/terms.db/segments"
19
+ FileUtils.touch "#{index_dir}/terms.db/segments_0"
20
+ return { "fake summary" => 'blah, blah, blah' }
21
+ end
22
+ end
23
+
24
+ PCAP = File.expand_path File.join(File.dirname(__FILE__), "arp.pcap")
25
+
26
+ def test_find_pcaps
27
+ do_setup
28
+
29
+ xtractr = FakeXtractr.new
30
+ config = {
31
+ "db" => @db,
32
+ "xtractr" => xtractr,
33
+ "index_dir" => @index_dir,
34
+ "pcap_dir" => @pcap_dir,
35
+ "queue_delay" => 0,
36
+ "interval" => 0,
37
+ }
38
+ scanner = Scanner.new config
39
+
40
+ # No pcaps
41
+ expected = Set.new
42
+ assert_equal Set.new, scanner.find_pcaps
43
+
44
+ # One pcap
45
+ FileUtils.cp PCAP, "#{@pcap_dir}/foo.pcap"
46
+ expected << 'foo.pcap'
47
+ assert_equal expected, scanner.find_pcaps
48
+
49
+ # Another
50
+ FileUtils.cp PCAP, "#{@pcap_dir}/bar.cap"
51
+ expected << 'bar.cap'
52
+ assert_equal expected, scanner.find_pcaps
53
+
54
+ # Ignore files that don't end in ".pcap" or ".cap"
55
+ FileUtils.cp PCAP, "#{@pcap_dir}/mypcap"
56
+ assert_equal expected, scanner.find_pcaps
57
+
58
+ # Should Find pcap in sub directory.
59
+ FileUtils.mkdir_p "#{@pcap_dir}/a/b/c/d"
60
+ assert_equal expected, scanner.find_pcaps
61
+ FileUtils.cp PCAP, "#{@pcap_dir}/a/b/c/d/foo.pcap"
62
+ expected << "a/b/c/d/foo.pcap"
63
+ assert_equal expected, scanner.find_pcaps
64
+
65
+ # Should not look into dir whose name begins with a "."
66
+ FileUtils.mkdir_p "#{@pcap_dir}/a/b/c/.d"
67
+ assert_equal expected, scanner.find_pcaps
68
+ FileUtils.cp PCAP, "#{@pcap_dir}/a/b/c/.d/foo.pcap"
69
+ assert_equal expected, scanner.find_pcaps
70
+
71
+ # Should handle subdir not searchable.
72
+ system "chmod a-r #{@pcap_dir}/a/b"
73
+ expected.delete "a/b/c/d/foo.pcap"
74
+ assert_equal expected, scanner.find_pcaps
75
+ system "chmod a+r #{@pcap_dir}/a/b"
76
+ expected << "a/b/c/d/foo.pcap"
77
+
78
+ # Should handle dir not searchable.
79
+ system "chmod a-rx #{@pcap_dir}"
80
+ assert_equal Set.new, scanner.find_pcaps
81
+ system "chmod a+rx #{@pcap_dir}"
82
+
83
+ # Should handle dir not searchable.
84
+ system "chmod a-x #{@pcap_dir}"
85
+ assert_equal Set.new, scanner.find_pcaps
86
+ system "chmod a+x #{@pcap_dir}"
87
+
88
+ # Should handle dir not searchable.
89
+ system "chmod a-r #{@pcap_dir}"
90
+ assert_equal Set.new, scanner.find_pcaps
91
+ system "chmod a+r #{@pcap_dir}"
92
+
93
+ # Should return empty set if directory is missing.
94
+ dir = "/tmp/test#{rand}#{$$}"
95
+ config['pcap_dir'] = dir
96
+ scanner = Scanner.new config
97
+ expected = Set.new
98
+ assert_equal expected, scanner.find_pcaps
99
+
100
+ # Should return empty set if directory is not searchable
101
+ assert_equal expected, scanner.find_pcaps
102
+ dir = "/tmp/test#{rand}#{$$}"
103
+ config['pcap_dir'] = dir
104
+ scanner = Scanner.new config
105
+ expected = Set.new
106
+ assert_equal expected, scanner.find_pcaps
107
+ ensure
108
+ system "chmod -R a+rx #{@pcap_dir}"
109
+ end
110
+
111
+ def test_remove_index_for
112
+ do_setup
113
+
114
+ config = {
115
+ "index_dir" => @index_dir,
116
+ "reaper_interval" => 60,
117
+ "idle_timeout" => 60,
118
+ }
119
+ xtractr = Xtractr.new config
120
+
121
+ config = {
122
+ "db" => @db,
123
+ "xtractr" => xtractr,
124
+ "index_dir" => @index_dir,
125
+ "pcap_dir" => @pcap_dir,
126
+ "queue_delay" => 0,
127
+ "interval" => 0,
128
+ }
129
+ scanner = Scanner.new config
130
+
131
+ FileUtils.cp PCAP, "#{@pcap_dir}/foo.pcap"
132
+
133
+ # Create index
134
+ index_data = xtractr.index "#{@pcap_dir}/foo.pcap", "#{@index_dir}/foo.pcap"
135
+ assert File.directory? "#{@index_dir}/foo.pcap"
136
+ # Remove it
137
+ scanner.remove_index_for "foo.pcap"
138
+ assert_equal false, File.exist?("#{@index_dir}/foo.pcap")
139
+
140
+ # Create index with extra file, index should not be removed.
141
+ index_data = xtractr.index "#{@pcap_dir}/foo.pcap", "#{@index_dir}/foo.pcap"
142
+ FileUtils.touch "#{@index_dir}/foo.pcap/extra_file"
143
+ assert File.directory? "#{@index_dir}/foo.pcap"
144
+ scanner.remove_index_for "foo.pcap"
145
+ assert File.directory? "#{@index_dir}/foo.pcap"
146
+ FileUtils.rm_rf "#{@index_dir}/foo.pcap"
147
+ end
148
+
149
+ def test_basics
150
+ do_setup
151
+
152
+ xtractr = FakeXtractr.new
153
+ config = {
154
+ "db" => @db,
155
+ "xtractr" => xtractr,
156
+ "index_dir" => @index_dir,
157
+ "pcap_dir" => @pcap_dir,
158
+ "queue_delay" => 0,
159
+ "interval" => 0,
160
+ }
161
+ scanner = Scanner.new config
162
+ expected = ['.', '..']
163
+
164
+ # No pcaps, No indexes
165
+ scanner.scan
166
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
167
+
168
+ # One pcap added. Create one index.
169
+ FileUtils.cp PCAP, "#{@pcap_dir}/foo.pcap"
170
+ scanner.scan
171
+ expected << "foo.pcap"
172
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
173
+
174
+ # Two additional pcaps. Should have 3 indexes.
175
+ FileUtils.cp PCAP, "#{@pcap_dir}/bar.pcap"
176
+ FileUtils.cp PCAP, "#{@pcap_dir}/baz.pcap"
177
+ expected << "bar.pcap"
178
+ expected << "baz.pcap"
179
+ scanner.scan
180
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
181
+
182
+ # Delete an index, It should be recreated.
183
+ FileUtils.rm_r "#{@index_dir}/bar.pcap"
184
+ expected.delete "bar.pcap"
185
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
186
+ scanner.scan
187
+ expected << "bar.pcap"
188
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
189
+
190
+ # Remove pcap, index should be removed.
191
+ File.unlink "#{@pcap_dir}/baz.pcap"
192
+ expected.delete "baz.pcap"
193
+ scanner.scan
194
+ scanner.scan
195
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
196
+
197
+ # Scanner should find pcaps in subdirectory
198
+ FileUtils.mkdir_p "#{@pcap_dir}/a/b/c/d/"
199
+ FileUtils.cp PCAP, "#{@pcap_dir}/a/b/c/d/nested.pcap"
200
+ scanner.scan
201
+ expected << "a"
202
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
203
+ assert File.exist? "#{@index_dir}/a/b/c/d/nested.pcap/terms.db"
204
+
205
+ # Pcap should not be indexed until its modification time is older
206
+ # than queue_delay seconds.
207
+ delay_sec = 2
208
+ config['queue_delay'] = delay_sec
209
+ scanner = Scanner.new config
210
+ FileUtils.cp PCAP, "#{@pcap_dir}/new.pcap"
211
+ scanner.scan
212
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
213
+ sleep delay_sec + 1
214
+ scanner.scan
215
+ expected << "new.pcap"
216
+ assert_equal expected.sort, Dir.entries(@index_dir).sort
217
+
218
+ # Check that database has expected pcaps.
219
+ expected = [
220
+ {"id"=>"0dddee3f87f14f1621e5744d667a95b7", "value"=>nil, "key"=>"a/b/c/d/nested.pcap"},
221
+ {"id"=>"6fc1ee4334c5564563c717bf7ccd734b", "value"=>nil, "key"=>"bar.pcap"},
222
+ {"id"=>"291eddbc4e2a539e6df74b141ea434f0", "value"=>nil, "key"=>"foo.pcap"},
223
+ {"id"=>"2517876b6c06c5fdcd4745a14ca96491", "value"=>nil, "key"=>"new.pcap"}
224
+ ]
225
+ by_filename = []
226
+ @db.each_in_view 'pcaps/by_filename' do |row|
227
+ by_filename << row
228
+ end
229
+ by_filename.sort_by {|h| h['key']}
230
+ assert_equal expected, by_filename
231
+
232
+ # Check that all pcaps are indexed.
233
+ @db.each_in_view 'pcaps/by_filename' do |row|
234
+ doc = @db.get row["id"]
235
+ assert_equal "indexed", doc.fetch("status")
236
+ end
237
+ end
238
+ end
239
+
240
+ end
241
+ end