pcapr-local 0.1.10

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.
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