pcapr-local 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/LICENSE.txt +20 -0
- data/README.md +64 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/pcap2par +49 -0
- data/bin/startpcapr +40 -0
- data/bin/stoppcapr +33 -0
- data/bin/xtractr +5 -0
- data/lib/environment.rb +106 -0
- data/lib/exe/xtractr +0 -0
- data/lib/mu/pcap.rb +110 -0
- data/lib/mu/pcap/ethernet.rb +148 -0
- data/lib/mu/pcap/header.rb +75 -0
- data/lib/mu/pcap/io_pair.rb +67 -0
- data/lib/mu/pcap/io_wrapper.rb +76 -0
- data/lib/mu/pcap/ip.rb +61 -0
- data/lib/mu/pcap/ipv4.rb +257 -0
- data/lib/mu/pcap/ipv6.rb +148 -0
- data/lib/mu/pcap/packet.rb +104 -0
- data/lib/mu/pcap/pkthdr.rb +155 -0
- data/lib/mu/pcap/reader.rb +61 -0
- data/lib/mu/pcap/reader/http_family.rb +170 -0
- data/lib/mu/pcap/sctp.rb +367 -0
- data/lib/mu/pcap/sctp/chunk.rb +123 -0
- data/lib/mu/pcap/sctp/chunk/data.rb +134 -0
- data/lib/mu/pcap/sctp/chunk/init.rb +100 -0
- data/lib/mu/pcap/sctp/chunk/init_ack.rb +68 -0
- data/lib/mu/pcap/sctp/parameter.rb +110 -0
- data/lib/mu/pcap/sctp/parameter/ip_address.rb +48 -0
- data/lib/mu/pcap/stream_packetizer.rb +72 -0
- data/lib/mu/pcap/tcp.rb +505 -0
- data/lib/mu/pcap/udp.rb +69 -0
- data/lib/mu/scenario/pcap.rb +164 -0
- data/lib/mu/scenario/pcap/fields.rb +50 -0
- data/lib/mu/scenario/pcap/rtp.rb +71 -0
- data/lib/pcapr_local.rb +159 -0
- data/lib/pcapr_local/config.rb +336 -0
- data/lib/pcapr_local/db.rb +197 -0
- data/lib/pcapr_local/scanner.rb +250 -0
- data/lib/pcapr_local/server.rb +178 -0
- data/lib/pcapr_local/www/favicon.ico +0 -0
- data/lib/pcapr_local/www/favicon.png +0 -0
- data/lib/pcapr_local/www/home/index.html +138 -0
- data/lib/pcapr_local/www/static/image/16x16/Cancel.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Cancel.png.1 +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Download.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Folder3.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Full Size.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Minus.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Plus.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/Search.png +0 -0
- data/lib/pcapr_local/www/static/image/16x16/User.png +0 -0
- data/lib/pcapr_local/www/static/image/48x48/Phone.png +0 -0
- data/lib/pcapr_local/www/static/image/48x48/Video.png +0 -0
- data/lib/pcapr_local/www/static/image/bar-orange.gif +0 -0
- data/lib/pcapr_local/www/static/image/beta.png +0 -0
- data/lib/pcapr_local/www/static/image/bg.png +0 -0
- data/lib/pcapr_local/www/static/image/blockquote.png +0 -0
- data/lib/pcapr_local/www/static/image/body-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl1-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl1-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl1-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl2-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl2-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl2-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl3-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl3-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl3-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl4-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl4-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl4-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl5-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl6-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl7-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-hl8-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/body-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/bottom-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/bottom-l.png +0 -0
- data/lib/pcapr_local/www/static/image/bottom-r.png +0 -0
- data/lib/pcapr_local/www/static/image/btn-search.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-1.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-2.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-3.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-4.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-5.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-6.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-7.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl1.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl2.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl3.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-hl4.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-pathway.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-section1.png +0 -0
- data/lib/pcapr_local/www/static/image/bullet-section2.png +0 -0
- data/lib/pcapr_local/www/static/image/collapsed.gif +0 -0
- data/lib/pcapr_local/www/static/image/crosslink.png +0 -0
- data/lib/pcapr_local/www/static/image/expanded.gif +0 -0
- data/lib/pcapr_local/www/static/image/favicon.ico +0 -0
- data/lib/pcapr_local/www/static/image/favicon.png +0 -0
- data/lib/pcapr_local/www/static/image/icon-author.png +0 -0
- data/lib/pcapr_local/www/static/image/icon-created.png +0 -0
- data/lib/pcapr_local/www/static/image/p-expand.gif +0 -0
- data/lib/pcapr_local/www/static/image/pcapr-logo.png +0 -0
- data/lib/pcapr_local/www/static/image/powered-by.png +0 -0
- data/lib/pcapr_local/www/static/image/section1-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/section1-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/section1-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/section2-bg.png +0 -0
- data/lib/pcapr_local/www/static/image/section2-h3.png +0 -0
- data/lib/pcapr_local/www/static/image/section2-readmore.png +0 -0
- data/lib/pcapr_local/www/static/image/status-alert.png +0 -0
- data/lib/pcapr_local/www/static/image/status-download.png +0 -0
- data/lib/pcapr_local/www/static/image/status-info.png +0 -0
- data/lib/pcapr_local/www/static/image/status-note.png +0 -0
- data/lib/pcapr_local/www/static/image/tab-round.png +0 -0
- data/lib/pcapr_local/www/static/image/throbber.gif +0 -0
- data/lib/pcapr_local/www/static/image/user.jpg +0 -0
- data/lib/pcapr_local/www/static/script/closet/async.js +421 -0
- data/lib/pcapr_local/www/static/script/closet/closet.api.js +241 -0
- data/lib/pcapr_local/www/static/script/closet/closet.folders.js +94 -0
- data/lib/pcapr_local/www/static/script/closet/closet.js +187 -0
- data/lib/pcapr_local/www/static/script/closet/closet.mr.js +219 -0
- data/lib/pcapr_local/www/static/script/closet/closet.options.js +359 -0
- data/lib/pcapr_local/www/static/script/closet/closet.quantity.js +73 -0
- data/lib/pcapr_local/www/static/script/closet/closet.render.js +205 -0
- data/lib/pcapr_local/www/static/script/closet/closet.report.js +86 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.http.js +135 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.overview.js +163 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.sip.js +159 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.tcp.js +72 -0
- data/lib/pcapr_local/www/static/script/closet/closet.reports.visualize.js +263 -0
- data/lib/pcapr_local/www/static/script/closet/closet.util.js +40 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery-1.4.2.min.js +154 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery-ui.js +10921 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.flot.js +2123 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.flot.selection.js +184 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.flot.stack.js +184 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.form.js +643 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.jsonp.min.js +3 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.menu.js +142 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.suggest.js +308 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.core.js +203 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.slider.js +629 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.sortable.js +1055 -0
- data/lib/pcapr_local/www/static/script/jquery/jquery.ui.widget.js +236 -0
- data/lib/pcapr_local/www/static/script/json2.js +481 -0
- data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.cache.js +115 -0
- data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.template.js +117 -0
- data/lib/pcapr_local/www/static/script/sammy/sammy.js +1696 -0
- data/lib/pcapr_local/www/static/script/tipsy/jquery.tipsy.js +104 -0
- data/lib/pcapr_local/www/static/style/c3p0.css +116 -0
- data/lib/pcapr_local/www/static/style/jquery.suggest.css +27 -0
- data/lib/pcapr_local/www/static/style/page.css +1113 -0
- data/lib/pcapr_local/www/static/style/tipsy.css +7 -0
- data/lib/pcapr_local/www/templates/browse.services.template +10 -0
- data/lib/pcapr_local/www/templates/browse.template +77 -0
- data/lib/pcapr_local/www/templates/flows.template +38 -0
- data/lib/pcapr_local/www/templates/pcap.template +63 -0
- data/lib/pcapr_local/www/templates/sip.calls.template +35 -0
- data/lib/pcapr_local/www/templates/statistics.template +6 -0
- data/lib/pcapr_local/xtractr.rb +179 -0
- data/lib/pcapr_local/xtractr/instance.rb +172 -0
- data/pcapr-local.gemspec +297 -0
- data/test/mu/pcap/reader/tc_http_family.rb +251 -0
- data/test/mu/pcap/tc_ethernet.rb +71 -0
- data/test/mu/pcap/tc_header.rb +56 -0
- data/test/mu/pcap/tc_ipv4.rb +103 -0
- data/test/mu/pcap/tc_ipv6.rb +83 -0
- data/test/mu/pcap/tc_packet.rb +44 -0
- data/test/mu/pcap/tc_pair.rb +58 -0
- data/test/mu/pcap/tc_pkthdr.rb +33 -0
- data/test/mu/pcap/tc_reader.rb +76 -0
- data/test/mu/pcap/tc_tcp.rb +426 -0
- data/test/mu/pcap/tc_udp.rb +33 -0
- data/test/mu/pcap/tc_wrapper.rb +80 -0
- data/test/mu/scenario/pcap/tc_fields.rb +67 -0
- data/test/mu/scenario/pcap/tc_rtp.rb +135 -0
- data/test/mu/scenario/sip_signalled_call_1.pcap +0 -0
- data/test/mu/scenario/tc_pcap.rb +190 -0
- data/test/mu/scenario/test_data/arp.pcap +0 -0
- data/test/mu/scenario/test_data/dns.pcap +0 -0
- data/test/mu/scenario/test_data/http-v6.pcap +0 -0
- data/test/mu/scenario/test_data/http.pcap +0 -0
- data/test/mu/scenario/test_data/http_chunked.pcap +0 -0
- data/test/mu/scenario/test_data/http_deflate.pcap +0 -0
- data/test/mu/scenario/test_data/httpauth3.pcap +0 -0
- data/test/mu/scenario/test_data/icmp.pcap +0 -0
- data/test/mu/scenario/test_data/sip_signalled_call_1.pcap +0 -0
- data/test/mu/tc_pcap.rb +39 -0
- data/test/mu/testcase.rb +86 -0
- data/test/pcapr_local/arp.pcap +0 -0
- data/test/pcapr_local/data.js +3 -0
- data/test/pcapr_local/http_chunked.pcap +0 -0
- data/test/pcapr_local/tc_api.rb +181 -0
- data/test/pcapr_local/test.tgz +0 -0
- data/test/pcapr_local/test_scanner.rb +241 -0
- data/test/pcapr_local/test_xtractr.rb +219 -0
- data/test/pcapr_local/testcase.rb +107 -0
- data/test/test_export_to_scenario.sh +25 -0
- data/test/test_pcapr_local.rb +29 -0
- metadata +450 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
.tipsy { padding: 5px; font-size: 10px; opacity: 0.8; filter: alpha(opacity=80); background-repeat: no-repeat; background-image: url(tipsy.gif); }
|
2
|
+
.tipsy-inner { padding: 5px 8px 4px 8px; background-color: black; color: white; max-width: 200px; text-align: center; }
|
3
|
+
.tipsy-inner { -moz-border-radius:3px; -webkit-border-radius:3px; }
|
4
|
+
.tipsy-north { background-position: top center; }
|
5
|
+
.tipsy-south { background-position: bottom center; }
|
6
|
+
.tipsy-east { background-position: right center; }
|
7
|
+
.tipsy-west { background-position: left center; }
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="cloud" style="margin-top:10px;margin-bottom:10px">
|
2
|
+
<% closet.render.cloud(kvs, function(kv, size) { %>
|
3
|
+
<span style="font-size:<%= size %>px">
|
4
|
+
<a class="term" title="<%= kv.key %>" href="#/browse/service/<%= escape(kv.key) %>">
|
5
|
+
<%= closet.util.escapeHTML(kv.key) %>
|
6
|
+
</a>
|
7
|
+
<sup style="font-size:10px"><%= kv.value %></sup>
|
8
|
+
</span>
|
9
|
+
<% }); %>
|
10
|
+
</div>
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<% if (pcaps.filter) {%>
|
2
|
+
<span style="float:right">
|
3
|
+
<img class="icon" src="/static/image/16x16/Cancel.png"/>
|
4
|
+
<a href="#/browse">remove filter</a>
|
5
|
+
</span>
|
6
|
+
<% } %>
|
7
|
+
|
8
|
+
<ul id="p-main" class="s-result pcaps" style="margin-left: -40px">
|
9
|
+
<% $.each(pcaps.rows.slice(0, Math.min(closet.api.PAGE_SIZE, pcaps.rows.length)), function(i, row) { %>
|
10
|
+
<li class="l0">
|
11
|
+
<div class="p-body">
|
12
|
+
<% if (row.doc.index) { %>
|
13
|
+
<% var paths = row.doc.filename.split('/'); %>
|
14
|
+
<a class="term" href="#/browse/dir/">/</a>
|
15
|
+
<% $.each(paths.slice(0, paths.length-1), function(k, path) {%>
|
16
|
+
<a class="term" href="#/browse/dir/<%= escape(paths.slice(0,k+1).join('/')) %>">
|
17
|
+
<%= closet.util.escapeHTML(path) %>
|
18
|
+
</a> /
|
19
|
+
<% }); %>
|
20
|
+
<a href="#/browse/pcap/<%= escape(row.id) %>"><%= closet.util.escapeHTML(paths[paths.length-1]) %></a>
|
21
|
+
<% } else if (row.doc.status === 'indexing') { %>
|
22
|
+
<span class="throbber"/>
|
23
|
+
<span style="font-size:125%;font-weight:bold;color:#e66c25">
|
24
|
+
<%= closet.util.escapeHTML(row.doc.filename) %>
|
25
|
+
</span>
|
26
|
+
<% } else if (row.doc.status === 'failed' || row.doc.status === 'aborted') { %>
|
27
|
+
<a id="<%= row.doc._id %>" class="remove" href="javascript:void(0)">
|
28
|
+
<img class="icon" src="/static/image/16x16/Cancel.png"/>
|
29
|
+
</a>
|
30
|
+
<span style="font-size:125%;font-weight:bold;color:#dd1122">
|
31
|
+
<%= closet.util.escapeHTML(row.doc.filename) %>
|
32
|
+
</span>
|
33
|
+
<% } else {%>
|
34
|
+
<span style="font-size:125%;font-weight:bold;color:grey">
|
35
|
+
<%= closet.util.escapeHTML(row.doc.filename) %>
|
36
|
+
</span>
|
37
|
+
<% } %>
|
38
|
+
</div>
|
39
|
+
<% if (row.doc.index) { %>
|
40
|
+
<div class="p-protos">
|
41
|
+
<span>services: </span>
|
42
|
+
<% var services = row.doc.index.services.sort(); %>
|
43
|
+
<% $.each(services.slice(0,10), function(j, service) { %>
|
44
|
+
<a class="meta-proto" href="#/browse/service/<%= escape(service) %>">
|
45
|
+
<%= closet.util.escapeHTML(service) %>
|
46
|
+
</a>
|
47
|
+
<% }); %>
|
48
|
+
<% if (services.length > 10) { %>
|
49
|
+
<span>(<%= services.length-10 %> more)</span>
|
50
|
+
<% } %>
|
51
|
+
</div>
|
52
|
+
<% } %>
|
53
|
+
<div style="font-size: smaller">
|
54
|
+
<a href="#/browse/status/<%= escape(row.doc.status) %>">
|
55
|
+
<%= closet.util.escapeHTML(row.doc.status) %>
|
56
|
+
</a>,
|
57
|
+
<%= closet.quantity.timespan(new Date(row.doc.created_at)) %>,
|
58
|
+
<%= closet.quantity.bytes(row.doc.stat.size) %>
|
59
|
+
<% if (row.doc.index) { %>
|
60
|
+
<span>,
|
61
|
+
<%= closet.quantity.count(row.doc.index.about.flows,'flow') %>,
|
62
|
+
<%= closet.quantity.count(row.doc.index.about.packets,'packet') %>,
|
63
|
+
<%= row.doc.index.about.duration %> seconds
|
64
|
+
</span>
|
65
|
+
<% } %>
|
66
|
+
</div>
|
67
|
+
</li>
|
68
|
+
<% }); %>
|
69
|
+
</ul>
|
70
|
+
|
71
|
+
<% if (pcaps.rows.length === closet.api.PAGE_SIZE+1) { %>
|
72
|
+
<div style="margin-left: 20px">
|
73
|
+
<span>» </span>
|
74
|
+
<% var last = pcaps.rows[pcaps.rows.length-1]; %>
|
75
|
+
<a href="<%= path %>?nextkey=<%= escape(JSON.stringify(last.key)) %>&nextid=<%= escape(last.id) %>">more</a>
|
76
|
+
</div>
|
77
|
+
<% } %>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<div>
|
2
|
+
<% if (flows.length > 0) { %>
|
3
|
+
<span class="info">
|
4
|
+
We found <%= closet.quantity.count(flows.length, 'candidate flow') %>.
|
5
|
+
Select one to create a scenario!
|
6
|
+
</span>
|
7
|
+
<table id="flows-table">
|
8
|
+
<colgroup span="8"/>
|
9
|
+
<colgroup span="1" style="width:100%"/>
|
10
|
+
<thead>
|
11
|
+
<tr>
|
12
|
+
<td>id</td>
|
13
|
+
<td><span style="visibility:hidden">▼</span><span class="time">time</span></td>
|
14
|
+
<td>packets</td>
|
15
|
+
<td><span style="visibility:hidden">▼</span><span class="src">src</span></td>
|
16
|
+
<td>sport</td>
|
17
|
+
<td><span style="visibility:hidden">▼</span><span class="dst">dst</span></td>
|
18
|
+
<td><span class="dport">dport</span></td>
|
19
|
+
<td><span style="visibility:hidden">▼</span><span class="service">service</span></td>
|
20
|
+
<td>title</td>
|
21
|
+
</tr>
|
22
|
+
</thead>
|
23
|
+
<% $.each(flows, function(_, flow) { %>
|
24
|
+
<tr class="flow">
|
25
|
+
<td><%= flow.id %>.</td>
|
26
|
+
<td><span class="field" id="flow.time"><%= flow.time.toFixed(4) %></span></td>
|
27
|
+
<td><span class="term" href="#/packets?pkt.flow:<%= escape(flow.id) %>"><%= escape(flow.packets) %></span></td>
|
28
|
+
<td><span class="term field" id="flow.src"><%= closet.util.escapeHTML(flow.src) %></span></td>
|
29
|
+
<td><span class="term"><%= flow.sport %></span></td>
|
30
|
+
<td><span class="term field" id="flow.dst"><%= closet.util.escapeHTML(flow.dst) %></span></td>
|
31
|
+
<td><span class="term" id="flow.dport"><%= flow.dport %></span></td>
|
32
|
+
<td><span class="term field" id="flow.service"><%= closet.util.escapeHTML(flow.service) %></span></td>
|
33
|
+
<td><a href="#/browse/pcap/<%= escape(pcap._id) %>/flow/<%= escape(flow.id) %>"><%= closet.util.escapeHTML(flow.title) %></a></td>
|
34
|
+
</tr>
|
35
|
+
<% }); %>
|
36
|
+
</table>
|
37
|
+
<% } %>
|
38
|
+
</div>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<div style="margin-top:20px;margin-bottom:20px">
|
2
|
+
<div class="p-body">
|
3
|
+
<% if (pcap.index) { %>
|
4
|
+
<% var paths = pcap.filename.split('/'); %>
|
5
|
+
<a class="term" href="#/browse/dir/">/</a>
|
6
|
+
<% $.each(paths.slice(0, paths.length-1), function(k, path) {%>
|
7
|
+
<a class="term" href="#/browse/dir/<%= escape(paths.slice(0,k+1).join('/')) %>">
|
8
|
+
<%= closet.util.escapeHTML(path) %>
|
9
|
+
</a> /
|
10
|
+
<% }); %>
|
11
|
+
<a class="extern" href="/pcaps/1/pcap/<%= escape(pcap._id) %>">
|
12
|
+
<%= closet.util.escapeHTML(paths[paths.length-1]) %>
|
13
|
+
</a>
|
14
|
+
<% } else if (pcap.status === 'indexing') { %>
|
15
|
+
<span class="throbber"/>
|
16
|
+
<span style="font-size:125%;font-weight:bold;color:#e66c25">
|
17
|
+
<%= closet.util.escapeHTML(pcap.filename) %>
|
18
|
+
</span>
|
19
|
+
<% } else if (pcap.status === 'failed') { %>
|
20
|
+
<span style="font-size:125%;font-weight:bold;color:#dd1122">
|
21
|
+
<%= closet.util.escapeHTML(row.doc.filename) %>
|
22
|
+
</span>
|
23
|
+
<% } else {%>
|
24
|
+
<span style="font-size:125%;font-weight:bold;color:grey">
|
25
|
+
<%= closet.util.escapeHTML(row.doc.filename) %>
|
26
|
+
</span>
|
27
|
+
<% } %>
|
28
|
+
</div>
|
29
|
+
<div style="font-size: smaller">
|
30
|
+
<a href="#/browse/status/<%= escape(pcap.status) %>"><%= pcap.status %></a>,
|
31
|
+
<%= closet.quantity.timespan(new Date(pcap.created_at)) %>,
|
32
|
+
<%= closet.quantity.bytes(pcap.stat.size) %>
|
33
|
+
<% if (pcap.index) { %>
|
34
|
+
<span>,
|
35
|
+
<%= closet.quantity.count(pcap.index.about.flows,'flow') %>,
|
36
|
+
<%= closet.quantity.count(pcap.index.about.packets,'packet') %>,
|
37
|
+
<%= pcap.index.about.duration %> seconds
|
38
|
+
</span>
|
39
|
+
<% } %>
|
40
|
+
</div>
|
41
|
+
<p/>
|
42
|
+
<div class="reports">
|
43
|
+
<span class="showonload" style="display:none">
|
44
|
+
Reports: <select class="reports" style="padding-right:20px"></select>
|
45
|
+
</span>
|
46
|
+
<h3 class="title"></h3>
|
47
|
+
<div class="settings" style="display:none; margin-top:-10px">
|
48
|
+
<span style="color:#105892">►</span>
|
49
|
+
<a class="toggler" href="javascript:void(0)">Settings</a>
|
50
|
+
<div class="options" style="display:none;margin-left:20px;border-left:2px dotted #d0d0d0;padding-left:10px">
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
<div class="report" style="margin-top:20px">
|
54
|
+
<p/><span class="throbber">analyzing</span>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
|
58
|
+
<div style="font-size: smaller">
|
59
|
+
Download a
|
60
|
+
<a target="_none" href="/pcaps/1/export_to_par/<%= escape(pcap._id) %>">PAR file </a>
|
61
|
+
.
|
62
|
+
</div>
|
63
|
+
</div>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<div>
|
2
|
+
<% $.each(calls, function(_, call) { %>
|
3
|
+
<div>
|
4
|
+
Call <span style="font-weight:bold"><%= closet.util.escapeHTML(call.src) %></span>
|
5
|
+
»
|
6
|
+
<span style="font-weight:bold"><%= closet.util.escapeHTML(call.dst) %></span>
|
7
|
+
|
8
|
+
[<span style="font-size:smaller"><%= closet.util.escapeHTML(call.id) %></span>]
|
9
|
+
</div>
|
10
|
+
<div style="margin-left: 20px">
|
11
|
+
This call was made from <span style="font-weight:bold"><%= closet.util.escapeHTML(call.from) %></span> to
|
12
|
+
<span style="font-weight:bold"><%= closet.util.escapeHTML(call.to) %></span> and is made up
|
13
|
+
of <%= closet.quantity.count(call.flows.length,'flow') %> and
|
14
|
+
<%= closet.quantity.count(call.packets,'packet') %>.
|
15
|
+
|
16
|
+
<% if (call.rtp.length > 0) { %>
|
17
|
+
We also found <%= closet.quantity.count(call.rtp.length,'RTP stream') %> in this call
|
18
|
+
with the following media types:
|
19
|
+
<ul>
|
20
|
+
<% $.each(call.media, function(_, media) {%>
|
21
|
+
<li style="list-style: disc outside !important">
|
22
|
+
<%= closet.util.escapeHTML(media) %>
|
23
|
+
</li>
|
24
|
+
<% }); %>
|
25
|
+
</ul>
|
26
|
+
<% } %>
|
27
|
+
|
28
|
+
<div>
|
29
|
+
<img class="icon" src="/static/image/16x16/Download.png"/>
|
30
|
+
Download <a href="/pcaps/1/pcap/<%= escape(pcap._id) %>/api/packets/slice?q=<%=escape(call.q)%>">pcap</a> for this call.
|
31
|
+
</div>
|
32
|
+
<p/>
|
33
|
+
</div>
|
34
|
+
<% }); %>
|
35
|
+
</div>
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
require 'thread'
|
6
|
+
require 'net/http'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
module PcaprLocal
|
10
|
+
class Xtractr
|
11
|
+
class XtractrError < StandardError; end
|
12
|
+
|
13
|
+
EXE_PATH = File.join(ROOT, 'lib/exe/xtractr')
|
14
|
+
|
15
|
+
def initialize config
|
16
|
+
@xtractr_path = EXE_PATH
|
17
|
+
@idle_timeout = config.fetch("idle_timeout")
|
18
|
+
@index_dir = config.fetch("index_dir")
|
19
|
+
@reaper_interval = config.fetch("reaper_interval", REAPER_INTERVAL)
|
20
|
+
# Hash of index dir to xtractr instance.
|
21
|
+
@xcache = {}
|
22
|
+
# Lock to synchronize creation/destruction of xtractr instances.
|
23
|
+
@xcache_lock = Mutex.new
|
24
|
+
|
25
|
+
start_reaper
|
26
|
+
at_exit do
|
27
|
+
shutdown
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Idle xtractr process reaper runs every REAPER_INTERVAL seconds.
|
32
|
+
REAPER_INTERVAL = 10
|
33
|
+
|
34
|
+
# Start reaper thread.
|
35
|
+
def start_reaper
|
36
|
+
Thread.new do
|
37
|
+
loop do
|
38
|
+
begin
|
39
|
+
reap
|
40
|
+
rescue Exception
|
41
|
+
Logger.error "Exception while cleaning up idle processes: #{e.message}\n" + e.backtrace.join("\n")
|
42
|
+
end
|
43
|
+
sleep @reaper_interval
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Kill xtractr instances at exit (idle or not).
|
49
|
+
def shutdown
|
50
|
+
@xcache.each_value do |xtractr|
|
51
|
+
$stderr.puts "stopping xtractr process"
|
52
|
+
xtractr.stop rescue nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Kills idle xtractr processes
|
57
|
+
def reap
|
58
|
+
@xcache_lock.synchronize do
|
59
|
+
@xcache.to_a.each do |dir, xtractr|
|
60
|
+
if xtractr.lock.try_lock
|
61
|
+
# xtractr is not in use right now
|
62
|
+
begin
|
63
|
+
if xtractr.last_use + @idle_timeout < Time.new.to_f
|
64
|
+
xtractr.stop
|
65
|
+
@xcache.delete dir
|
66
|
+
end
|
67
|
+
ensure
|
68
|
+
xtractr.lock.unlock
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Does path look like an xtractr index directory?
|
76
|
+
def self.index_dir?(path)
|
77
|
+
File.exist? File.join(path, 'packets.db')
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns timestamp (float) for xtractr index.
|
81
|
+
def self.index_time(path)
|
82
|
+
db_file = File.join(path, 'packets.db')
|
83
|
+
if File.exists? db_file
|
84
|
+
File.mtime(db_file).to_f
|
85
|
+
elsif File.exists? path
|
86
|
+
File.mtime(path).to_f
|
87
|
+
else
|
88
|
+
0.0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class XtractrIndexingException < XtractrError; end
|
93
|
+
|
94
|
+
# Last line of normal xtractr indexing output.
|
95
|
+
RE_INDEXING_DONE = /optimizing terms\.db\.\.\.done/
|
96
|
+
|
97
|
+
# Indexes pcap it index_dir and returns hash containing xtractr summary data.
|
98
|
+
# Raises exception if indexing fails.
|
99
|
+
def index pcap_path, index_dir
|
100
|
+
FileUtils.mkdir_p index_dir
|
101
|
+
|
102
|
+
command = [@xtractr_path, 'index', index_dir, '--mode', 'forensics', pcap_path]
|
103
|
+
Logger.debug "running: #{command.inspect}"
|
104
|
+
xtractr_out = Tempfile.new "xtractr_out"
|
105
|
+
pid = fork do
|
106
|
+
# Xtractr forks a child process. Set process group so we
|
107
|
+
# can send signal to all processes in a group.
|
108
|
+
STDOUT.reopen xtractr_out
|
109
|
+
STDERR.reopen xtractr_out
|
110
|
+
exec *command
|
111
|
+
end
|
112
|
+
#XXX enforce timeout.
|
113
|
+
Process.wait pid
|
114
|
+
|
115
|
+
xtractr_out.rewind
|
116
|
+
output = xtractr_out.read
|
117
|
+
|
118
|
+
unless $?.exitstatus == 0 and Xtractr.index_dir?(index_dir) and output =~ RE_INDEXING_DONE
|
119
|
+
Logger.error "Indexing failed with output:\n" + output
|
120
|
+
raise XtractrIndexingException, "Indexing failed"
|
121
|
+
end
|
122
|
+
|
123
|
+
return get_summary(index_dir)
|
124
|
+
ensure
|
125
|
+
xtractr_out.close! if xtractr_out
|
126
|
+
end
|
127
|
+
|
128
|
+
def get_summary index_dir
|
129
|
+
# Start xtractr in browse mode and get summary data
|
130
|
+
browser = Instance.new index_dir, @xtractr_path
|
131
|
+
about = JSON.parse(browser.get('api/about')[2])
|
132
|
+
services = JSON.parse(browser.get('api/services')[2])
|
133
|
+
service_names = []
|
134
|
+
services["rows"].each do |row|
|
135
|
+
service_names << row['name'].downcase
|
136
|
+
end
|
137
|
+
return { :about => about, :services => service_names }
|
138
|
+
ensure
|
139
|
+
browser.stop if browser
|
140
|
+
end
|
141
|
+
|
142
|
+
# Forwards GET request to xtractr instance created for index_dir.
|
143
|
+
# A relative path will be expanded relative to the configured index_dir.
|
144
|
+
def get index_dir, url
|
145
|
+
xtractr = nil
|
146
|
+
xtractr = xtractr_for index_dir
|
147
|
+
xtractr.get url
|
148
|
+
end
|
149
|
+
|
150
|
+
# Forwards POST request to xtractr instance created for index_dir.
|
151
|
+
# A relative path will be expanded relative to the configured index_dir.
|
152
|
+
def post index_dir, url, body
|
153
|
+
xtractr = nil
|
154
|
+
xtractr = xtractr_for index_dir
|
155
|
+
xtractr.post url, body
|
156
|
+
end
|
157
|
+
|
158
|
+
def xtractr_for index_dir
|
159
|
+
# Ensure index_dir path is absolute.
|
160
|
+
if index_dir.slice(0,1) != '/'
|
161
|
+
index_dir = File.expand_path(File.join(@index_dir, index_dir))
|
162
|
+
end
|
163
|
+
|
164
|
+
# Get or create xtractr instance.
|
165
|
+
@xcache_lock.synchronize do
|
166
|
+
xtractr = @xcache[index_dir]
|
167
|
+
if not xtractr
|
168
|
+
xtractr = Instance.new(index_dir, @xtractr_path)
|
169
|
+
@xcache[index_dir] = xtractr
|
170
|
+
end
|
171
|
+
return xtractr
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
require 'pcapr_local/xtractr/instance'
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# http://www.mudynamics.com
|
2
|
+
# http://labs.mudynamics.com
|
3
|
+
# http://www.pcapr.net
|
4
|
+
|
5
|
+
require 'thread'
|
6
|
+
require 'net/http'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
module PcaprLocal
|
10
|
+
class Xtractr
|
11
|
+
class Instance
|
12
|
+
attr_reader :last_use, :lock, :pid, :port
|
13
|
+
|
14
|
+
def initialize index_dir, xtractr_path
|
15
|
+
@index_dir = index_dir
|
16
|
+
@xtractr_path = xtractr_path
|
17
|
+
@lock = Mutex.new
|
18
|
+
@last_use = Time.new.to_f # for idle timeouts
|
19
|
+
@pid = nil
|
20
|
+
@port = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Does GET request and returns response headers and body.
|
24
|
+
def get path_and_params
|
25
|
+
start if not @pid
|
26
|
+
@lock.synchronize do
|
27
|
+
@last_use = Time.new.to_f
|
28
|
+
|
29
|
+
# Make request to xtractr
|
30
|
+
uri = URI.parse("http://127.0.0.1:#{@port}/#{path_and_params}")
|
31
|
+
response = Net::HTTP.get_response(uri)
|
32
|
+
|
33
|
+
# Copy headers from response
|
34
|
+
headers = {}
|
35
|
+
response.each_header {|name,val| headers[name] = val}
|
36
|
+
|
37
|
+
return response.code.to_i, headers, response.body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Does POST request and returns response headers and body.
|
42
|
+
def post path_and_params, post_body
|
43
|
+
start if not @pid
|
44
|
+
@lock.synchronize do
|
45
|
+
@last_use = Time.new.to_f
|
46
|
+
|
47
|
+
# Make request to xtractr
|
48
|
+
Net::HTTP.start('localhost', @port) do |http|
|
49
|
+
http.request_post "/#{path_and_params}", post_body do |response|
|
50
|
+
headers = {}
|
51
|
+
response.each_header {|name,val| headers[name] = val}
|
52
|
+
return response.code.to_i, headers, response.body
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Starts underlying process.
|
59
|
+
def start
|
60
|
+
@lock.synchronize do
|
61
|
+
return if @pid
|
62
|
+
err = nil
|
63
|
+
# There is a remote possibility that the random port we pick will be
|
64
|
+
# in use at the moment we try to bind to it. Thus the retries.
|
65
|
+
3.times do |n|
|
66
|
+
begin
|
67
|
+
do_start
|
68
|
+
return
|
69
|
+
rescue => err
|
70
|
+
end
|
71
|
+
end
|
72
|
+
raise err
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class XtractrStartupException < XtractrError; end
|
77
|
+
|
78
|
+
# Start xtractr
|
79
|
+
MAX_START_TIME = 30
|
80
|
+
RE_STARTED = /starting on http:/i
|
81
|
+
def do_start
|
82
|
+
port = Instance.free_local_port
|
83
|
+
command = [@xtractr_path, 'browse', @index_dir, '--port', port.to_s]
|
84
|
+
Logger.debug "running: #{command.inspect}"
|
85
|
+
xtractr_out = Tempfile.new "xtractr_out"
|
86
|
+
pid = fork do
|
87
|
+
# Xtractr forks a child process. Set process group so we
|
88
|
+
# can send signal to all processes in a group.
|
89
|
+
Process.setpgid $$, $$
|
90
|
+
STDOUT.reopen xtractr_out
|
91
|
+
STDERR.reopen xtractr_out
|
92
|
+
Dir.chdir @index_dir
|
93
|
+
exec *command
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
Timeout.timeout MAX_START_TIME do
|
98
|
+
# Wait for "starting" line.
|
99
|
+
while xtractr_out.grep(/starting on http:\/\/127\.0\.0\.1:#{port}/i).empty?
|
100
|
+
xtractr_out.rewind
|
101
|
+
sleep 0.01
|
102
|
+
end
|
103
|
+
# Sanity check that server is up.
|
104
|
+
Net::HTTP.start('127.0.0.1', port) do |http|
|
105
|
+
http.options("/")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue Timeout::Error, SystemCallError
|
109
|
+
Logger.error "Xtractr failed to start on port #{port}"
|
110
|
+
xtractr_out.rewind
|
111
|
+
Logger.error "Xtractr output: #{xtractr_out.read.inspect}"
|
112
|
+
kind_kill -pid
|
113
|
+
raise XtractrStartupException, "Timeout waiting for xtractr to startup"
|
114
|
+
end
|
115
|
+
|
116
|
+
@last_use = Time.new.to_f
|
117
|
+
@pid = pid
|
118
|
+
@port = port
|
119
|
+
end
|
120
|
+
|
121
|
+
# Kills underlying xtractr process.
|
122
|
+
def stop
|
123
|
+
if @pid
|
124
|
+
kind_kill -@pid
|
125
|
+
@pid = nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Sends SIGTERM and waits for process to exit. If process does
|
130
|
+
# not exit within wait period, sends SIGKILL. Use a negative
|
131
|
+
# pid to kill all members of a process group.
|
132
|
+
def kind_kill pid, wait=1
|
133
|
+
begin
|
134
|
+
Process.kill 15, pid
|
135
|
+
# Wait for process (or all group members) to
|
136
|
+
# exit.
|
137
|
+
Timeout.timeout wait do
|
138
|
+
loop { Process.wait(pid) }
|
139
|
+
end
|
140
|
+
rescue Errno::ECHILD, Errno::ESRCH
|
141
|
+
# Processes is dead or group has no members.
|
142
|
+
return
|
143
|
+
rescue Timeout::Error, StandardError
|
144
|
+
# Process did not shutdown in time (or there
|
145
|
+
# was an unexpected error).
|
146
|
+
Process.kill(9, pid) rescue nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Pick a random port over 10000 and verify that it can be bound to (on localhost)
|
151
|
+
def self.free_local_port
|
152
|
+
while true
|
153
|
+
port = rand(0xffff-10000) + 10000
|
154
|
+
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
155
|
+
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
156
|
+
addr = Socket.pack_sockaddr_in(port, '127.0.0.1')
|
157
|
+
begin
|
158
|
+
socket.bind addr
|
159
|
+
return port
|
160
|
+
rescue Errno::EADDRINUSE
|
161
|
+
next # port in use
|
162
|
+
ensure
|
163
|
+
socket.close
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|