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,163 @@
|
|
1
|
+
var closet = closet || {};
|
2
|
+
closet.reports = closet.reports || [];
|
3
|
+
closet.reports.push({
|
4
|
+
name: 'overview',
|
5
|
+
title: 'Overview',
|
6
|
+
items: [{
|
7
|
+
name: 'services',
|
8
|
+
title: 'Services',
|
9
|
+
options: function(pcap, opts, cb) {
|
10
|
+
opts.choice('filter', '', { values: [''].concat(['udp', 'tcp']) });
|
11
|
+
opts.choice('limit', 10, { values: [ '', 10, 20, 50, 100 ] });
|
12
|
+
opts.choice('order', 'count', { values: ['count', 'service'] });
|
13
|
+
opts.boolean('descending', true);
|
14
|
+
opts.boolean('normalize', true);
|
15
|
+
cb();
|
16
|
+
},
|
17
|
+
create: function(ctx, $root, pcap, opts) {
|
18
|
+
if (opts.order) {
|
19
|
+
opts = $.extend({}, opts, {
|
20
|
+
order: { count: 'value', service: 'key' }[opts.order]
|
21
|
+
});
|
22
|
+
}
|
23
|
+
|
24
|
+
if (opts.filter) {
|
25
|
+
var q = 'flow.proto:' + (opts.filter === 'udp' ? 17 : 6);
|
26
|
+
var r = closet.mr.count('flow.service');
|
27
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
28
|
+
closet.render.table($root, data, opts);
|
29
|
+
});
|
30
|
+
} else {
|
31
|
+
closet.api.field.terms(pcap._id, 'pkt.service', null, null, function(data) {
|
32
|
+
closet.render.table($root, data, opts);
|
33
|
+
});
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}, {
|
37
|
+
name: 'sizes',
|
38
|
+
title: 'Packet Size',
|
39
|
+
options: function(pcap, opts, cb) {
|
40
|
+
pcap.index.services.sort();
|
41
|
+
opts.choice('filter', '', { 'values': [''].concat(pcap.index.services) });
|
42
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
43
|
+
opts.choice('order', 'count', { values: ['count', 'size'] });
|
44
|
+
opts.boolean('descending', true);
|
45
|
+
opts.boolean('normalize', true);
|
46
|
+
cb();
|
47
|
+
},
|
48
|
+
create: function(ctx, $root, pcap, opts) {
|
49
|
+
if (opts.order) {
|
50
|
+
opts = $.extend({}, opts, {
|
51
|
+
order: { count: 'value', size: 'key' }[opts.order]
|
52
|
+
});
|
53
|
+
}
|
54
|
+
|
55
|
+
if (opts.filter) {
|
56
|
+
var q = 'pkt.service:' + opts.filter;
|
57
|
+
var r = closet.mr.count('pkt.length');
|
58
|
+
closet.api.packets.report(pcap._id, q, r, function(data) {
|
59
|
+
closet.render.table($root, data, opts);
|
60
|
+
});
|
61
|
+
} else {
|
62
|
+
closet.api.field.terms(pcap._id, 'pkt.length', null, null, function(data) {
|
63
|
+
closet.render.table($root, data, opts);
|
64
|
+
});
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}, {
|
68
|
+
name: 'mac',
|
69
|
+
title: 'MAC Addresses',
|
70
|
+
apply: function(pcap, fields) {
|
71
|
+
return fields.hasOwnProperty('eth.addr');
|
72
|
+
},
|
73
|
+
options: function(pcap, opts, cb) {
|
74
|
+
pcap.index.services.sort();
|
75
|
+
opts.choice('filter', '', { 'values': [''].concat(pcap.index.services) });
|
76
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
77
|
+
opts.choice('order', 'count', { values: ['count', 'mac'] });
|
78
|
+
opts.boolean('descending', true);
|
79
|
+
opts.boolean('normalize', true);
|
80
|
+
cb();
|
81
|
+
},
|
82
|
+
create: function(ctx, $root, pcap, opts) {
|
83
|
+
if (opts.order) {
|
84
|
+
opts = $.extend({}, opts, {
|
85
|
+
order: { count: 'value', mac: 'key' }[opts.order]
|
86
|
+
});
|
87
|
+
}
|
88
|
+
|
89
|
+
if (opts.filter) {
|
90
|
+
var q = 'pkt.service:' + opts.filter;
|
91
|
+
var r = closet.mr.count('eth.addr');
|
92
|
+
closet.api.packets.report(pcap._id, q, r, function(data) {
|
93
|
+
closet.render.table($root, data, opts);
|
94
|
+
});
|
95
|
+
} else {
|
96
|
+
closet.api.field.terms(pcap._id, 'eth.addr', null, null, function(data) {
|
97
|
+
closet.render.table($root, data, opts);
|
98
|
+
});
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}, {
|
102
|
+
name: 'ipv4',
|
103
|
+
title: 'IPv4 Addresses',
|
104
|
+
apply: function(pcap, fields) {
|
105
|
+
return fields.hasOwnProperty('ip.host');
|
106
|
+
},
|
107
|
+
options: function(pcap, opts, cb) {
|
108
|
+
pcap.index.services.sort();
|
109
|
+
opts.choice('filter', '', { 'values': [''].concat(pcap.index.services) });
|
110
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
111
|
+
opts.choice('order', 'count', { values: ['count', 'ip'] });
|
112
|
+
opts.boolean('descending', true);
|
113
|
+
opts.boolean('normalize', true);
|
114
|
+
cb();
|
115
|
+
},
|
116
|
+
create: function(ctx, $root, pcap, opts) {
|
117
|
+
if (opts.order) {
|
118
|
+
opts = $.extend({}, opts, {
|
119
|
+
order: { count: 'value', ip: 'key' }[opts.order]
|
120
|
+
});
|
121
|
+
}
|
122
|
+
|
123
|
+
// TODO: We'll need to have the ipv4/ipv6 type within each
|
124
|
+
// flow. This will allow us to rapidly scan for v4/v6 addresses
|
125
|
+
// instead of running through all the packets
|
126
|
+
var q = 'pkt.first:true ip.version:4';
|
127
|
+
q = q + (opts.filter ? ' pkt.service:' + opts.filter : '')
|
128
|
+
var r = closet.mr.count('ip.host');
|
129
|
+
closet.api.packets.report(pcap._id, q, r, function(data) {
|
130
|
+
closet.render.table($root, data, opts);
|
131
|
+
});
|
132
|
+
}
|
133
|
+
}, {
|
134
|
+
name: 'ipv6',
|
135
|
+
title: 'IPv6 Addresses',
|
136
|
+
apply: function(pcap, fields) {
|
137
|
+
return fields.hasOwnProperty('ipv6.host');
|
138
|
+
},
|
139
|
+
options: function(pcap, opts, cb) {
|
140
|
+
pcap.index.services.sort();
|
141
|
+
opts.choice('filter', '', { 'values': [''].concat(pcap.index.services) });
|
142
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
143
|
+
opts.choice('order', 'count', { values: ['count', 'ip'] });
|
144
|
+
opts.boolean('descending', true);
|
145
|
+
opts.boolean('normalize', true);
|
146
|
+
cb();
|
147
|
+
},
|
148
|
+
create: function(ctx, $root, pcap, opts) {
|
149
|
+
if (opts.order) {
|
150
|
+
opts = $.extend({}, opts, {
|
151
|
+
order: { count: 'value', ip: 'key' }[opts.order]
|
152
|
+
});
|
153
|
+
}
|
154
|
+
|
155
|
+
var q = 'pkt.first:true ip.version:6';
|
156
|
+
q = q + (opts.filter ? ' pkt.service:' + opts.filter : '');
|
157
|
+
var r = closet.mr.count('ipv6.host');
|
158
|
+
closet.api.packets.report(pcap._id, q, r, function(data) {
|
159
|
+
closet.render.table($root, data, opts);
|
160
|
+
});
|
161
|
+
}
|
162
|
+
}]
|
163
|
+
});
|
@@ -0,0 +1,159 @@
|
|
1
|
+
var closet = closet || {};
|
2
|
+
closet.reports = closet.reports || [];
|
3
|
+
closet.reports.push({
|
4
|
+
name: 'sip',
|
5
|
+
title: 'SIP',
|
6
|
+
apply: function(pcap, fields) {
|
7
|
+
return fields.hasOwnProperty('sip.method');
|
8
|
+
},
|
9
|
+
items: [{
|
10
|
+
name: 'calls',
|
11
|
+
title: 'Calls',
|
12
|
+
apply: function(pcap, fields) {
|
13
|
+
return fields.hasOwnProperty('sip.call.id');
|
14
|
+
},
|
15
|
+
create: function(ctx, $root, pcap, opts) {
|
16
|
+
var calls = [];
|
17
|
+
|
18
|
+
var $status = $root.find('span.throbber');
|
19
|
+
|
20
|
+
// 1. Find all the unique call-ids in the pcap
|
21
|
+
var q = 'pkt.service:sip* sip.method:invite';
|
22
|
+
var r = closet.mr.count('sip.call.id');
|
23
|
+
closet.api.packets.report(pcap._id, q, r, function(data) {
|
24
|
+
async.forEachSeries(data.rows,
|
25
|
+
function(row, next) {
|
26
|
+
var call = { id: row.key };
|
27
|
+
calls.push(call);
|
28
|
+
|
29
|
+
$status.text('processing call-id ' + call.id);
|
30
|
+
|
31
|
+
// 2. Find the first INVITE that has this callid. This tell us
|
32
|
+
// who started the call.
|
33
|
+
q = 'pkt.service:sip* sip.method:invite sip.call.id:' + closet.util.escapeQuery(call.id);
|
34
|
+
closet.api.packets.list(pcap._id, { q:q, limit:1, include_fields:true }, function(data) {
|
35
|
+
var pkt = data.rows[0];
|
36
|
+
call.src = pkt.src;
|
37
|
+
call.dst = pkt.dst;
|
38
|
+
pkt.fields = closet.util.kvsToObject(pkt.fields);
|
39
|
+
call.from = (pkt.fields['sip.from.user']||['unknown'])[0].replace(/;.*$/, '');
|
40
|
+
call.to = (pkt.fields['sip.to.user']||['unknown'])[0].replace(/;.*$/, '');
|
41
|
+
|
42
|
+
// 3. Find the unique SIP flows that make up this call
|
43
|
+
q = 'sip.call.id:' + closet.util.escapeQuery(call.id);
|
44
|
+
var r = closet.mr.count('pkt.flow');
|
45
|
+
closet.api.packets.report(pcap._id, q, r, function(data) {
|
46
|
+
var fids = $.map(data.rows, function(row) { return row.key; });
|
47
|
+
|
48
|
+
// 4. And fetch the flow information
|
49
|
+
var qf = 'flow.id:(' + fids.join('||') + ')';
|
50
|
+
closet.api.flows.list(pcap._id, { q: qf }, function(data) {
|
51
|
+
call.flows = data.rows;
|
52
|
+
|
53
|
+
// 5. Compute the span for this call-leg
|
54
|
+
call.span = {};
|
55
|
+
$.each(call.flows, function(_, flow) {
|
56
|
+
call.span.min = Math.min(call.span.min || flow.first, flow.first);
|
57
|
+
call.span.max = Math.max(call.span.max || flow.last, flow.last);
|
58
|
+
});
|
59
|
+
|
60
|
+
$status.text('extracting RTP streams for call-id ' + call.id);
|
61
|
+
|
62
|
+
// 5. For this call-id, look for sdp packets that contain RTP information
|
63
|
+
var qrtp = 'sip.call.id:' + closet.util.escapeQuery(call.id) + ' sdp.version:0';
|
64
|
+
closet.api.packets.list(pcap._id, { q: qrtp, include_fields: true }, function(data) {
|
65
|
+
var rtps = { ips: [], ports: [], media: [] };
|
66
|
+
$.each(data.rows, function(_, pkt) {
|
67
|
+
pkt.fields = closet.util.kvsToObject(pkt.fields);
|
68
|
+
var ips = pkt.fields['sdp.connection.info.address'];
|
69
|
+
var ports = pkt.fields['sdp.media.port'];
|
70
|
+
var media = pkt.fields['sdp.mime.type'];
|
71
|
+
rtps.ips = rtps.ips.concat(ips || []);
|
72
|
+
rtps.ports = rtps.ports.concat(ports || []);
|
73
|
+
rtps.media = rtps.media.concat(media || []);
|
74
|
+
});
|
75
|
+
|
76
|
+
// 6. And then stitch the RTP flows within the span together with the SIP flows
|
77
|
+
var qfrtp = 'flow.first:>=' + call.span.min + ' flow.last:<=' + call.span.max + ' flow.service:RTP flow.dst:(' + rtps.ips.join('||') + ') flow.dport:(' + rtps.ports.join('||') + ')';
|
78
|
+
closet.api.flows.list(pcap._id, { q: qfrtp }, function(data) {
|
79
|
+
call.flows = call.flows.concat(data.rows);
|
80
|
+
call.rtp = data.rows;
|
81
|
+
call.media = closet.util.unique(rtps.media);
|
82
|
+
|
83
|
+
// Compute the #total packets for this call-leg
|
84
|
+
var fids = $.map(call.flows, function(flow) { return flow.id; });
|
85
|
+
call.q = 'pkt.flow:(' + fids.join('||') + ')';
|
86
|
+
call.packets = 0;
|
87
|
+
$.each(call.flows, function(_, flow) {
|
88
|
+
call.packets += flow.packets;
|
89
|
+
});
|
90
|
+
next();
|
91
|
+
});
|
92
|
+
});
|
93
|
+
});
|
94
|
+
});
|
95
|
+
});
|
96
|
+
},
|
97
|
+
function() {
|
98
|
+
// TODO:
|
99
|
+
// - For each flow that matches the call-id, show the call-flow
|
100
|
+
// - Show statistics about the message types + error codes
|
101
|
+
ctx.render('/templates/sip.calls.template', { pcap: pcap, calls: calls }, function(content) {
|
102
|
+
$root.html(content);
|
103
|
+
});
|
104
|
+
}
|
105
|
+
);
|
106
|
+
});
|
107
|
+
}
|
108
|
+
}, {
|
109
|
+
name: 'phones',
|
110
|
+
title: 'Phones',
|
111
|
+
apply: function(pcap, fields) {
|
112
|
+
return fields.hasOwnProperty('sip.user.agent');
|
113
|
+
},
|
114
|
+
options: function(pcap, opts, cb) {
|
115
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
116
|
+
opts.choice('order', 'count', { values: [ 'count', 'phone' ] });
|
117
|
+
opts.boolean('descending', true);
|
118
|
+
opts.boolean('normalize', true);
|
119
|
+
cb();
|
120
|
+
},
|
121
|
+
create: function(ctx, $root, pcap, opts) {
|
122
|
+
opts = $.extend({}, opts, { value: 'count' });
|
123
|
+
if (opts.order) {
|
124
|
+
opts.order = { count: 'value', phone: 'key' }[opts.order];
|
125
|
+
}
|
126
|
+
|
127
|
+
var q = 'flow.service:sip*';
|
128
|
+
var r = closet.mr.count('sip.user.agent');
|
129
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
130
|
+
closet.render.table($root, data, opts);
|
131
|
+
});
|
132
|
+
}
|
133
|
+
},{
|
134
|
+
name: 'servers',
|
135
|
+
title: 'Servers',
|
136
|
+
apply: function(pcap, fields) {
|
137
|
+
return fields.hasOwnProperty('sip.server');
|
138
|
+
},
|
139
|
+
options: function(pcap, opts, cb) {
|
140
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
141
|
+
opts.choice('order', 'count', { values: [ 'count', 'server' ] });
|
142
|
+
opts.boolean('descending', true);
|
143
|
+
opts.boolean('normalize', true);
|
144
|
+
cb();
|
145
|
+
},
|
146
|
+
create: function(ctx, $root, pcap, opts) {
|
147
|
+
opts = $.extend({}, opts, { value: 'count' });
|
148
|
+
if (opts.order) {
|
149
|
+
opts.order = { count: 'value', server: 'key' }[opts.order];
|
150
|
+
}
|
151
|
+
|
152
|
+
var q = 'flow.service:sip*';
|
153
|
+
var r = closet.mr.count('sip.server');
|
154
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
155
|
+
closet.render.table($root, data, opts);
|
156
|
+
});
|
157
|
+
}
|
158
|
+
}]
|
159
|
+
});
|
@@ -0,0 +1,72 @@
|
|
1
|
+
var closet = closet || {};
|
2
|
+
closet.reports = closet.reports || [];
|
3
|
+
closet.reports.push({
|
4
|
+
name: 'tcp',
|
5
|
+
title: 'TCP',
|
6
|
+
apply: function(pcap, fields) {
|
7
|
+
return fields.hasOwnProperty('tcp.stream');
|
8
|
+
},
|
9
|
+
items: [{
|
10
|
+
name: 'dport',
|
11
|
+
title: 'Destination Ports',
|
12
|
+
options: function(pcap, opts, cb) {
|
13
|
+
var q = 'flow.proto:6';
|
14
|
+
var r = closet.mr.count('flow.service');
|
15
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
16
|
+
var services = $.map(data.rows, function(row) { return row.key; });
|
17
|
+
opts.choice('filter', '', { 'values': [''].concat(services) });
|
18
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
19
|
+
opts.choice('order', 'count', { values: ['count', 'port'] });
|
20
|
+
opts.boolean('descending', true);
|
21
|
+
opts.boolean('normalize', true);
|
22
|
+
cb();
|
23
|
+
});
|
24
|
+
},
|
25
|
+
create: function(ctx, $root, pcap, opts) {
|
26
|
+
if (opts.order) {
|
27
|
+
opts = $.extend({}, opts, {
|
28
|
+
order: { count: 'value', port: 'key' }[opts.order]
|
29
|
+
});
|
30
|
+
}
|
31
|
+
|
32
|
+
var q = 'flow.proto:6';
|
33
|
+
q = q + (opts.filter ? ' flow.service:' + opts.filter : '');
|
34
|
+
var r = closet.mr.count('flow.dport');
|
35
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
36
|
+
closet.render.table($root, data, opts);
|
37
|
+
});
|
38
|
+
}
|
39
|
+
}, {
|
40
|
+
name: 'bandwidth',
|
41
|
+
title: 'Bandwidth Utilization',
|
42
|
+
options: function(pcap, opts, cb) {
|
43
|
+
var q = 'flow.proto:6';
|
44
|
+
closet.api.flows.services(pcap._id, q, 0.0, pcap.index.about.duration, function(data) {
|
45
|
+
var services = $.map(data.rows, function(row) { return row.key; });
|
46
|
+
opts.choice('filter', '', { 'values': [''].concat(services) });
|
47
|
+
opts.choice('limit', 10, { 'values': [ '', 10, 20, 50, 100 ] });
|
48
|
+
opts.choice('order', 'bytes', { values: ['bytes', 'host'] });
|
49
|
+
opts.boolean('descending', true);
|
50
|
+
opts.boolean('normalize', false);
|
51
|
+
cb();
|
52
|
+
});
|
53
|
+
},
|
54
|
+
create: function(ctx, $root, pcap, opts) {
|
55
|
+
opts = $.extend({}, opts, { value: 'bytes' });
|
56
|
+
if (opts.order) {
|
57
|
+
opts.order = { bytes: 'value', host: 'key' }[opts.order]
|
58
|
+
}
|
59
|
+
|
60
|
+
var q = 'flow.proto:6';
|
61
|
+
q = q + (opts.filter ? ' flow.service:' + opts.filter : '');
|
62
|
+
var r = closet.mr.sum('flow.src', 'flow.bytes');
|
63
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
64
|
+
closet.render.table($root, data, opts);
|
65
|
+
});
|
66
|
+
}
|
67
|
+
}
|
68
|
+
// TODO:
|
69
|
+
// - connection rate
|
70
|
+
// - scans
|
71
|
+
]
|
72
|
+
});
|
@@ -0,0 +1,263 @@
|
|
1
|
+
var closet = closet || {};
|
2
|
+
closet.reports = closet.reports || [];
|
3
|
+
closet.reports.push({
|
4
|
+
name: 'visualize',
|
5
|
+
title: 'Visualize',
|
6
|
+
apply: function(pcap, fields) {
|
7
|
+
return pcap.index.about.flows > 0;
|
8
|
+
},
|
9
|
+
items:[{
|
10
|
+
name: 'flows',
|
11
|
+
title: 'Flows',
|
12
|
+
options: function(pcap, opts, cb) {
|
13
|
+
closet.api.flows.clients(pcap._id, '*', 0.0, pcap.index.about.duration, function(data) {
|
14
|
+
var clients = $.map(data.rows, function(row) { return row.key; });
|
15
|
+
opts.choice('client', '', { values: [''].concat(clients) });
|
16
|
+
closet.api.flows.servers(pcap._id, '*', 0.0, pcap.index.about.duration, function(data) {
|
17
|
+
var servers = $.map(data.rows, function(row) { return row.key; });
|
18
|
+
opts.choice('server', '', { values: [''].concat(servers) });
|
19
|
+
closet.api.flows.services(pcap._id, '*', 0.0, pcap.index.about.duration, function(data) {
|
20
|
+
var services = $.map(data.rows, function(row) { return row.key; });
|
21
|
+
opts.choice('service', '', { values: [''].concat(services) });
|
22
|
+
opts.choice('group', 'service', { values: [ 'service', 'src', 'dst', 'dport' ] });
|
23
|
+
opts.choice('speed', 'normal', { values: [ 'normal', 'slow' ] });
|
24
|
+
cb();
|
25
|
+
});
|
26
|
+
});
|
27
|
+
});
|
28
|
+
},
|
29
|
+
create: (function() {
|
30
|
+
var globalReportId = 0;
|
31
|
+
|
32
|
+
return function(ctx, $root, pcap, opts) {
|
33
|
+
var reportId = ++globalReportId;
|
34
|
+
var buckets = {};
|
35
|
+
var flows = {};
|
36
|
+
var packets = [];
|
37
|
+
var npackets = 1;
|
38
|
+
var timeout = { normal:50, slow:100 }[opts.speed];
|
39
|
+
var paused = false;
|
40
|
+
var fetching = false;
|
41
|
+
var timerId;
|
42
|
+
$root.html(
|
43
|
+
'<a class="create" href="javascript:void(0)">create</a>' +
|
44
|
+
'<a class="pause" href="javascript:void(0)" style="display:none">pause</a>' +
|
45
|
+
'<p/>' +
|
46
|
+
'<div class="status" style="padding-bottom:20px"></div>' +
|
47
|
+
'<table class="replay">' +
|
48
|
+
'<tbody>' +
|
49
|
+
'</tbody>' +
|
50
|
+
'</table>' +
|
51
|
+
'<div class="info" style="margin-top:20px"></div>'
|
52
|
+
);
|
53
|
+
|
54
|
+
var $buckets = $root.find('table.replay tbody');
|
55
|
+
var $status = $root.find('div.status');
|
56
|
+
var $create = $root.find('a.create');
|
57
|
+
var $pause = $root.find('a.pause');
|
58
|
+
var $info = $root.find('div.info');
|
59
|
+
|
60
|
+
$pause.click(function() {
|
61
|
+
paused = !paused;
|
62
|
+
if (paused) {
|
63
|
+
$pause.text('resume');
|
64
|
+
} else {
|
65
|
+
$pause.text('pause');
|
66
|
+
$info.empty();
|
67
|
+
timerId = timerId || setTimeout(function() { _next(); }, timeout);
|
68
|
+
}
|
69
|
+
});
|
70
|
+
|
71
|
+
// Create the key used to bucketize the flows
|
72
|
+
var _key = function(flow) {
|
73
|
+
if (opts.group === 'dport') {
|
74
|
+
return (flow.proto === 6 ? 'tcp/' : 'udp/') + flow.dport;
|
75
|
+
}
|
76
|
+
return flow[opts.group];
|
77
|
+
};
|
78
|
+
|
79
|
+
// If we are filtering on a service, map the service to the set
|
80
|
+
// of ports so that we can filter the packets that belong to
|
81
|
+
// that flow
|
82
|
+
if (opts.service) {
|
83
|
+
var q = 'flow.service:' + closet.util.escapeQuery(opts.service.replace(/-\/.*/, ''));
|
84
|
+
var r = closet.mr.count('flow.dport');
|
85
|
+
closet.api.flows.report(pcap._id, q, r, function(data) {
|
86
|
+
opts.ports = $.map(data.rows, function(row) { return row.key; });
|
87
|
+
});
|
88
|
+
}
|
89
|
+
|
90
|
+
// Generate the query depending on the opts setting
|
91
|
+
var _query = function(id) {
|
92
|
+
var q = 'pkt.flow:>=1 pkt.id:>=' + (id+1);
|
93
|
+
if (opts.client) {
|
94
|
+
var client = closet.util.escapeQuery(opts.client);
|
95
|
+
q += ' ((pkt.dir:0 pkt.src:' + client + ') || (pkt.dir:1 pkt.dst:' + client + '))';
|
96
|
+
}
|
97
|
+
if (opts.server) {
|
98
|
+
var server = closet.util.escapeQuery(opts.server);
|
99
|
+
q += ' ((pkt.dir:0 pkt.dst:' + server + ') || (pkt.dir:1 pkt.src:' + server + '))';
|
100
|
+
}
|
101
|
+
if (opts.ports) {
|
102
|
+
var ports = opts.ports.join('||');
|
103
|
+
q += ' ((pkt.dir:0 udp.dstport|tcp.dstport:(' + ports + ')) || (pkt.dir:1 udp.srcport|tcp.srcport:(' + ports + ')))';
|
104
|
+
}
|
105
|
+
if (opts.group === 'dport') {
|
106
|
+
q += ' (ip.proto:(6||17))';
|
107
|
+
}
|
108
|
+
|
109
|
+
return q;
|
110
|
+
}
|
111
|
+
|
112
|
+
// Add a flow to the list. If it's the first flow for a bucket,
|
113
|
+
// create the bucket as well.
|
114
|
+
var _add = function(flow) {
|
115
|
+
var key = _key(flow);
|
116
|
+
if (!buckets.hasOwnProperty(key)) {
|
117
|
+
var $tr = $(
|
118
|
+
'<tr>' +
|
119
|
+
'<td style="white-space:nowrap">' + closet.util.escapeHTML(key) + '</td>' +
|
120
|
+
'<td class="flows"></td>' +
|
121
|
+
'</tr>'
|
122
|
+
);
|
123
|
+
|
124
|
+
$buckets.append($tr);
|
125
|
+
buckets[key] = {};
|
126
|
+
buckets[key].$td = $tr.find('td.flows');
|
127
|
+
buckets[key].nflows = 0;
|
128
|
+
}
|
129
|
+
|
130
|
+
var $span = $(
|
131
|
+
'<div class="flow" style="cursor:pointer;float:left;position:relative;background-color:#ffdddd;border:1px solid red;margin-right:5px;margin-left:5px;margin-right:10px;height:1.2em;width:30px">' +
|
132
|
+
'<div class="fill" style="position:absolute;background-color:#e66c25;height:100%;width:1%"></div>' +
|
133
|
+
'</div>'
|
134
|
+
);
|
135
|
+
|
136
|
+
$span.click(function() {
|
137
|
+
$info.html(
|
138
|
+
'Flow <strong>' + flow.id + '</strong>. ' +
|
139
|
+
'<strong>' + flow.src + '</strong>' +
|
140
|
+
' » ' +
|
141
|
+
'<strong>' + flow.dst + '</strong>' + ' :: ' +
|
142
|
+
'<strong>' + closet.util.escapeHTML(flow.service) + '</strong> ' +
|
143
|
+
closet.util.escapeHTML(flow.title.slice(0, 80)) +
|
144
|
+
'<p/>' +
|
145
|
+
'<img class="icon" src="/static/image/16x16/Download.png"/>' +
|
146
|
+
'Download <a href="/pcaps/1/pcap/' + pcap._id + '/api/packets/slice?q=pkt.flow:' + flow.id + '">pcap</a> for this flow.'
|
147
|
+
);
|
148
|
+
});
|
149
|
+
|
150
|
+
buckets[key].$td.append($span);
|
151
|
+
buckets[key].nflows++;
|
152
|
+
flow.$span = $span;
|
153
|
+
flow.$fill = $span.find('div.fill');
|
154
|
+
flow.npackets = 1;
|
155
|
+
flows[flow.id] = flow;
|
156
|
+
};
|
157
|
+
|
158
|
+
// Remove a flow from the flow list and if it's the last
|
159
|
+
// flow in the bucket, remove the bucketized row as well
|
160
|
+
var _remove = function(flow) {
|
161
|
+
var key = _key(flow);
|
162
|
+
setTimeout(function() {
|
163
|
+
delete flows[flow.id];
|
164
|
+
flow.$fill.css('background-color', '#dd1122');
|
165
|
+
flow.$span.fadeOut(1000, function() {
|
166
|
+
$(this).remove();
|
167
|
+
if (--buckets[key].nflows === 0) {
|
168
|
+
var s_entry = buckets[key];
|
169
|
+
delete buckets[key];
|
170
|
+
s_entry.$td.parent('tr').remove();
|
171
|
+
}
|
172
|
+
});
|
173
|
+
}, 100);
|
174
|
+
};
|
175
|
+
|
176
|
+
var location = ctx.app.getLocation();
|
177
|
+
var _next = function() {
|
178
|
+
timerId = undefined;
|
179
|
+
|
180
|
+
// Abort if the user navigates to a different URL
|
181
|
+
if (ctx.app.getLocation() !== location) {
|
182
|
+
return;
|
183
|
+
}
|
184
|
+
|
185
|
+
// Abort if the user changes 'opts' to create a new viz
|
186
|
+
if (reportId !== globalReportId) {
|
187
|
+
return;
|
188
|
+
}
|
189
|
+
|
190
|
+
// Don't process this packet, if the visualization is paused
|
191
|
+
if (paused) {
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
|
195
|
+
// When we hit the low water-mark, prefetch (async) the
|
196
|
+
// next set of packets
|
197
|
+
if (packets.length === 30 && !fetching) {
|
198
|
+
var last = packets[packets.length-1];
|
199
|
+
fetching = true;
|
200
|
+
closet.api.packets.list(pcap._id, { q: _query(last.id), limit: 40, terms: false }, function(data) {
|
201
|
+
fetching = false;
|
202
|
+
packets = packets.concat(data.rows);
|
203
|
+
timerId = timerId || setTimeout(function() { _next(); }, timeout);
|
204
|
+
});
|
205
|
+
}
|
206
|
+
|
207
|
+
// Process the next packet. If there are no more packets
|
208
|
+
// and we are not in the middle of fetching more chunks,
|
209
|
+
// then we are done.
|
210
|
+
var pkt = packets.shift();
|
211
|
+
if (pkt === undefined) {
|
212
|
+
if (!fetching) {
|
213
|
+
$status.empty();
|
214
|
+
$pause.hide();
|
215
|
+
$info.empty();
|
216
|
+
$create.show();
|
217
|
+
}
|
218
|
+
return;
|
219
|
+
}
|
220
|
+
|
221
|
+
// Update the status with the current packet
|
222
|
+
$status.html(
|
223
|
+
'Packet <strong>' + pkt.src + '</strong>' +
|
224
|
+
' » ' +
|
225
|
+
'<strong>' + pkt.dst + '</strong>' + ' :: ' +
|
226
|
+
'<strong>' + closet.util.escapeHTML(pkt.service) + '</strong> ' +
|
227
|
+
closet.util.escapeHTML(pkt.title.slice(0, 80))
|
228
|
+
);
|
229
|
+
|
230
|
+
// Add/remove flows for this packet
|
231
|
+
if (!flows.hasOwnProperty(pkt.flow)) {
|
232
|
+
closet.api.flows.list(pcap._id, { q: 'flow.id:' + pkt.flow, limit: 1, terms: false }, function(data) {
|
233
|
+
var flow = data.rows[0];
|
234
|
+
_add(flow);
|
235
|
+
if (flow.first === flow.last) {
|
236
|
+
_remove(flow);
|
237
|
+
}
|
238
|
+
timerId = timerId || setTimeout(function() { _next(); }, timeout);
|
239
|
+
});
|
240
|
+
} else {
|
241
|
+
var flow = flows[pkt.flow];
|
242
|
+
var key = _key(flow);
|
243
|
+
flow.$fill.css('width', Math.floor((++flow.npackets)*100/flow.packets) + '%');
|
244
|
+
if (flow.last === pkt.id) {
|
245
|
+
_remove(flow);
|
246
|
+
}
|
247
|
+
timerId = timerId || setTimeout(function() { _next(); }, timeout);
|
248
|
+
}
|
249
|
+
};
|
250
|
+
|
251
|
+
$create.click(function() {
|
252
|
+
$(this).hide();
|
253
|
+
$pause.show();
|
254
|
+
$status.html('<span class="throbber">hang on</span>');
|
255
|
+
closet.api.packets.list(pcap._id, { q: _query(0), limit: 100, terms: false }, function(data) {
|
256
|
+
packets = data.rows;
|
257
|
+
_next();
|
258
|
+
});
|
259
|
+
});
|
260
|
+
};
|
261
|
+
}())
|
262
|
+
}]
|
263
|
+
});
|