Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sflow-rt
GitHub Repository: sflow-rt/ddos-protect
Path: blob/master/html/js/app.js
50 views
1
$(function() {
2
3
var dataURL = '../scripts/ddos.js/trend/json';
4
var controlsURL = '../scripts/ddos.js/controls/json';
5
var settingsURL = '../scripts/ddos.js/settings/json';
6
var modeURL = '../scripts/ddos.js/mode/json';
7
var groupsURL = '../scripts/ddos.js/groups/json';
8
9
var enableFlowBrowserURL = '../../../app/browse-flows/status';
10
11
var db = {};
12
var showThreshold = true;
13
var lastControlsID = 0;
14
15
function setNav(target) {
16
$('.navbar .nav-item a[href="'+target+'"]').parent().addClass('active').siblings().removeClass('active');
17
$(target).show().siblings().hide();
18
window.sessionStorage.setItem('ddos_protect_nav',target);
19
window.history.replaceState(null,'',target);
20
}
21
22
var hash = window.location.hash;
23
if(hash && $('.navbar .nav-item a[href="'+hash+'"]').length == 1) setNav(hash);
24
else setNav(window.sessionStorage.getItem('ddos_protect_nav') || $('.navbar .nav-item a').first().attr('href'));
25
26
$('.navbar .nav-link').on('click', function(e) {
27
var selected = $(this).attr('href');
28
setNav(selected);
29
if('#charts' === selected) $.event.trigger({type:'updateChart'});
30
});
31
32
$('a[href^="#"]').on('click', function(e) {
33
e.preventDefault();
34
});
35
36
$('.year').html((new Date()).getFullYear());
37
38
var browseFlowsPage = '../../browse-flows/html/index.html';
39
function openBrowseFlowsLink(id) {
40
var trend = db.trend.trends['top-5-'+id];
41
var latest = trend[trend.length - 1];
42
var ipversion = '';
43
var max = 0;
44
for(var key in latest) {
45
if(latest[key] < max) continue;
46
max = latest[key];
47
ipversion = key.indexOf(':') !== -1 ? '6' : '';
48
}
49
var parts = id.split('-');
50
var specName = 'ddos_protect_' + parts[0] + ipversion + '_' + parts[1];
51
$.get('../../../flow/'+specName+'/json', function(spec) {
52
window.location.href=browseFlowsPage+'?keys='+encodeURIComponent(spec.keys)+'&value=fps&filter='+encodeURIComponent(spec.filter);
53
});
54
}
55
56
$.get(enableFlowBrowserURL, function(status) {
57
if(!'OK' === status) return;
58
$('a.badge:hidden').show().click(function() {
59
var id = $(this).parent().parent().find('.trend').attr('id');
60
openBrowseFlowsLink(id);
61
});
62
});
63
64
var protocols = {
65
'1':'icmp',
66
'6':'tcp',
67
'17':'udp',
68
'47':'gre',
69
'50':'esp'
70
};
71
72
var ports = {
73
'19':'chargen',
74
'53':'dns',
75
'80':'http',
76
'123':'ntp',
77
'137':'netbios',
78
'161':'snmp',
79
'389':'cldap',
80
'443':'https',
81
'1900':'ssdp',
82
'4500':'ipsec'
83
};
84
85
function label(key,map) {
86
var label = map[key];
87
return label ? label+'('+key+')' : key;
88
}
89
90
var colors = $.inmon.stripchart.prototype.options.colors;
91
$('#ip-flood').chart({
92
type: 'topn',
93
stack: false,
94
includeOther:false,
95
metric: 'top-5-ip-flood',
96
legendHeadings: ['Target','Group','Protocol'],
97
keyName: (key,idx) => idx == 2 ? label(key,protocols) : key,
98
hrule:[{name:'threshold_ip_flood',color:colors[1],scale:showThreshold}],
99
units: 'Packets per Second'},
100
db);
101
$('#ip-fragmentation').chart({
102
type: 'topn',
103
stack: false,
104
includeOther:false,
105
metric: 'top-5-ip-fragmentation',
106
legendHeadings: ['Target','Group','Protocol'],
107
keyName: (key,idx) => idx == 2 ? label(key,protocols) : key,
108
hrule:[{name:'threshold_ip_fragmentation',color:colors[1],scale:showThreshold}],
109
units: 'Packets per Second'},
110
db);
111
$('#udp-flood').chart({
112
type: 'topn',
113
stack: false,
114
includeOther: false,
115
metric: 'top-5-udp-flood',
116
legendHeadings: ['Target','Group','Port'],
117
keyName: (key,idx) => idx == 2 ? label(key,ports) : key,
118
hrule: [{name:'threshold_udp_flood',color:colors[1],scale:showThreshold}],
119
units: 'Packets per Second'},
120
db);
121
$('#udp-amplification').chart({
122
type: 'topn',
123
stack: false,
124
includeOther: false,
125
metric: 'top-5-udp-amplification',
126
legendHeadings: ['Target','Group','Port'],
127
keyName: (key,idx) => idx == 2 ? label(key,ports) : key,
128
hrule: [{name:'threshold_udp_amplification',color:colors[1],scale:showThreshold}],
129
units: 'Packets per Second'},
130
db);
131
$('#tcp-flood').chart({
132
type: 'topn',
133
stack: false,
134
includeOther: false,
135
metric: 'top-5-tcp-flood',
136
legendHeadings: ['Target','Group','Port'],
137
keyName: (key,idx) => idx == 2 ? label(key,ports) : key,
138
hrule: [{name:'threshold_tcp_flood',color:colors[1],scale:showThreshold}],
139
units: 'Packets per Second'},
140
db);
141
$('#tcp-amplification').chart({
142
type: 'topn',
143
stack: false,
144
includeOther: false,
145
metric: 'top-5-tcp-amplification',
146
legendHeadings: ['Target','Group','Port'],
147
keyName: (key,idx) => idx == 2 ? label(key,ports) : key,
148
hrule: [{name:'threshold_tcp_amplification',color:colors[1],scale:showThreshold}],
149
units: 'Packets per Second'},
150
db);
151
$('#icmp-flood').chart({
152
type: 'topn',
153
stack: false,
154
includeOther: false,
155
metric: 'top-5-icmp-flood',
156
legendHeadings: ['Target','Group','Type'],
157
hrule: [{name:'threshold_icmp_flood',color:colors[1],scale:showThreshold}],
158
units: 'Packets per Second'},
159
db);
160
$('#attacks').chart({
161
type: 'trend',
162
stack: true,
163
legend: ['Active','Failed','Pending'],
164
metrics: ['controls_blocked','controls_failed','controls_pending'],
165
units: 'Number of Controls'},
166
db);
167
$('#connections').chart({
168
type: 'trend',
169
stack: false,
170
metrics: ['connections'],
171
hrule: [{name:'threshold_connections',color:colors[3],scale:showThreshold}],
172
units: 'BGP Connections'},
173
db);
174
175
function updateControlsTable(controls) {
176
var body, i, entry, html = '';
177
body = $('#controlstable tbody');
178
if(controls.length > 0) {
179
controls.sort((x,y) => y.time - x.time);
180
for(i = 0; i < controls.length; i++) {
181
entry = controls[i];
182
switch(entry.status) {
183
case 'blocked':
184
html += '<tr class="table-info" data-id="'+entry.id+'">';
185
break;
186
case 'pending':
187
html += '<tr class="table-warning" data-id="'+entry.id+'">';
188
break;;
189
case 'failed':
190
html += '<tr class="table-danger" data-id="'+entry.id+'">';
191
break;
192
default:
193
html += '<tr>';
194
}
195
html += '<td>' + entry.target + '</td>';
196
html += '<td>' + entry.group + '</td>';
197
html += '<td>' + entry.attack + '</td>';
198
html += '<td>' + entry.protocol + '</td>';
199
html += '<td>' + (new Date(entry.time)).toLocaleTimeString('en-US') + '</td>';
200
html += '<td>' + entry.action + '</td>';
201
html += '<td>' + entry.status + '</td>';
202
html += '</tr>';
203
body.html(html);
204
body.find('tr').click(function() {
205
var row = $(this);
206
var id = row.data('id');
207
var dialog = $('#control-dialog');
208
var target = $(row.children()[0]).html();
209
var action = $(row.children()[5]).html();
210
var status = $(row.children()[6]).html();
211
dialog.data('id',id);
212
dialog.data('action',action);
213
dialog.find('#control-target').html(target);
214
dialog.find('#control-group').html($(row.children()[1]).html());
215
dialog.find('#control-attack').html($(row.children()[2]).html());
216
dialog.find('#control-protocol').html($(row.children()[3]).html());
217
dialog.find('#control-action').html(action);
218
dialog.find('#control-install').prop('disabled','pending' !== status);
219
dialog.modal('show');
220
});
221
}
222
} else {
223
html = '<tr><td colspan="7" class="text-center"><em>No active controls</em></td></tr>';
224
body.html(html);
225
}
226
}
227
228
$('#control-remove').click(function() {
229
var dialog = $('#control-dialog');
230
var id = dialog.data('id');
231
$.ajax({
232
url:controlsURL,
233
type:'POST',
234
contentType:'application/json',
235
dataType:'json',
236
data:JSON.stringify({action:'allow',id:id}),
237
success: function(data) {
238
lastControlsUpdate = data.update;
239
updateControlsTable(data.controls);
240
},
241
complete: function() {
242
dialog.modal('hide');
243
}
244
});
245
});
246
247
$('#control-install').click(function() {
248
var dialog = $('#control-dialog');
249
var id = dialog.data('id');
250
$.ajax({
251
url:controlsURL,
252
type:'POST',
253
contentType:'application/json',
254
data:JSON.stringify({action:'block',id:id}),
255
success: function(data) {
256
lastControlsUpdate = data.update;
257
updateControlsTable(data.controls);
258
},
259
complete: function() {
260
dialog.modal('hide');
261
}
262
});
263
});
264
265
var lastControlsUpdate = 0;
266
function refreshControls() {
267
$.ajax({
268
url: controlsURL,
269
dataType: 'json',
270
success: function(data) {
271
lastControlsUpdate = data.update;
272
updateControlsTable(data.controls);
273
}
274
});
275
}
276
277
function updateSettings(settings) {
278
$('#settingstable tbody tr').each(function(idx) {
279
var row = $(this);
280
row.removeClass('table-info table-active table-danger table-warning table-primary table-secondary table-success table-default');
281
var cells = row.children();
282
var attack = $(cells[0]).html();
283
var vals = settings[attack];
284
if(vals) {
285
$(cells[1]).html(vals.action);
286
$(cells[2]).html(vals.threshold);
287
$(cells[3]).html(vals.timeout);
288
$(cells[4]).html(vals.include || '');
289
$(cells[5]).html(vals.exclude || '');
290
switch(vals.action) {
291
case 'drop':
292
row.addClass('table-danger');
293
break;
294
case 'filter':
295
row.addClass('table-warning');
296
break;
297
case 'mark':
298
row.addClass('table-primary');
299
break;
300
case 'limit':
301
row.addClass('table-secondary');
302
break;
303
case 'redirect':
304
row.addClass('table-info');
305
break;
306
case 'community':
307
row.addClass('table-active');
308
break;
309
case 'ignore':
310
row.addClass('table-success');
311
break;
312
default:
313
row.addClass('table-default');
314
}
315
}
316
});
317
}
318
319
function updateMode(mode) {
320
$('input:radio[name=controller_mode]').val([mode]);
321
}
322
323
$('input:radio[name=controller_mode]').click(function() {
324
var mode = $(this).val();
325
$.ajax({
326
url: modeURL,
327
type: 'POST',
328
contentType:'application/json',
329
data: JSON.stringify(mode),
330
dataType:'json'
331
});
332
});
333
334
var lastSettingsUpdate = 0;
335
function refreshSettings() {
336
$.ajax({
337
url: settingsURL,
338
dataType: 'json',
339
success: function(data) {
340
lastSettingsUpdate = data.update;
341
updateSettings(data.settings);
342
updateMode(data.mode);
343
}
344
});
345
}
346
refreshSettings();
347
348
var groupInfo;
349
function updateGroupsTable() {
350
var body, i, names, name, entry, html = '', done = {};
351
body = $('#groupstable tbody');
352
for(i = 0; i < groupInfo.external.length; i++) {
353
name = groupInfo.external[i];
354
done[name] = name;
355
entry = (groupInfo.groups[name] && groupInfo.groups[name].join(', ')) || '';
356
html += '<tr class="table-danger"><td>'+name+'</td><td class="text-wrap">'+entry+'</td></tr>';
357
}
358
for(i = 0; i < groupInfo.excluded.length; i++) {
359
name = groupInfo.excluded[i];
360
if(done[name]) continue;
361
done[name] = name;
362
entry = (groupInfo.groups[name] && groupInfo.groups[name].join(', ')) || '';
363
html += '<tr class="table-success"><td>'+name+'</td><td class="text-wrap">'+entry+'</td></tr>';
364
}
365
names = Object.keys(groupInfo.groups);
366
names.sort();
367
for(i = 0; i < names.length; i++) {
368
name = names[i];
369
if(done[name]) continue;
370
entry = (groupInfo.groups[name] && groupInfo.groups[name].join(', ')) || '';
371
html += '<tr class="table-warning"><td>'+name+'</td><td class="text-wrap">'+entry+'</td></tr>';
372
}
373
body.html(html);
374
body.find('tr').click(function() {
375
var row = $(this);
376
var dialog = $('#group-dialog');
377
var name = $(row.children()[0]).html();
378
var cidrs = $(row.children()[1]).html();
379
dialog.data('name',name);
380
dialog.find('#group-name').html(name);
381
dialog.find('#group-cidrs').val(cidrs);
382
dialog.modal('show');
383
});
384
}
385
386
$('#group-submit').click(function() {
387
var dialog = $('#group-dialog');
388
var name = dialog.data('name');
389
var cidrs = dialog.find('#group-cidrs').val().split(/[ ,]+/);
390
groupInfo.groups[name] = cidrs;
391
$.ajax({
392
url:groupsURL,
393
type:'POST',
394
contentType:'application/json',
395
data:JSON.stringify(groupInfo.groups),
396
success: function(data) {
397
lastGroupsUpdate = data.update;
398
groupInfo = data;
399
updateGroupsTable();
400
},
401
complete: function() {
402
dialog.modal('hide');
403
}
404
});
405
});
406
407
$('#group-delete').click(function() {
408
var dialog = $('#group-dialog');
409
var name = dialog.data('name');
410
delete groupInfo.groups[name];
411
$.ajax({
412
url:groupsURL,
413
type:'POST',
414
contentType:'application/json',
415
data:JSON.stringify(groupInfo.groups),
416
success: function(data) {
417
lastGroupsUpdate = data.update;
418
groupInfo = data;
419
updateGroupsTable();
420
},
421
complete: function() {
422
dialog.modal('hide');
423
}
424
});
425
});
426
427
$('#group-name').keyup(function() {
428
$('#group-create').prop('disabled',$(this).val() === "");
429
});
430
431
$('#group-create').click(function() {
432
var name = $('#group-name').val();
433
$('#group-name').val('');
434
if(groupInfo.groups[name]) return;
435
groupInfo.groups[name] = [];
436
$.ajax({
437
url:groupsURL,
438
type:'POST',
439
contentType:'application/json',
440
data:JSON.stringify(groupInfo.groups),
441
success: function(data) {
442
lastGroupsUpdate = data.update;
443
groupInfo = data;
444
updateGroupsTable();
445
}
446
});
447
});
448
449
var lastGroupsUpdate = 0;
450
function refreshGroups() {
451
$.ajax({
452
url: groupsURL,
453
dataType: 'json',
454
success: function(data) {
455
lastGroupsUpdate = data.update;
456
groupInfo = data;
457
updateGroupsTable();
458
}
459
});
460
}
461
refreshGroups();
462
463
$('#settingstable tbody tr').click(function() {
464
var row = $(this);
465
var dialog = $('#setting-dialog');
466
dialog.find('#setting-attack').html($(row.children()[0]).html());
467
dialog.find('#setting-action').val($(row.children()[1]).html());
468
dialog.find('#setting-threshold').val($(row.children()[2]).html());
469
dialog.find('#setting-timeout').val($(row.children()[3]).html());
470
dialog.find('#setting-include').val($(row.children()[4]).html());
471
dialog.find('#setting-exclude').val($(row.children()[5]).html());
472
dialog.modal('show');
473
});
474
475
$('#setting-submit').click(function() {
476
var dialog = $('#setting-dialog');
477
var attack = dialog.find('#setting-attack').html();
478
var msg = {};
479
msg[attack] = {
480
action:dialog.find('#setting-action').val(),
481
threshold:dialog.find('#setting-threshold').val(),
482
timeout:dialog.find('#setting-timeout').val(),
483
include:dialog.find('#setting-include').val(),
484
exclude:dialog.find('#setting-exclude').val()
485
};
486
$.ajax({
487
url:settingsURL,
488
type:'POST',
489
contentType:'application/json',
490
data:JSON.stringify(msg),
491
dataType:'json',
492
success: function(data) {
493
lastSettingsUpdate = data.update;
494
updateSettings(data.settings);
495
updateMode(data.mode);
496
},
497
complete: function() {
498
dialog.modal('hide');
499
}
500
});
501
});
502
503
function updateData(data) {
504
if(!data
505
|| !data.trend
506
|| !data.trend.times
507
|| data.trend.times.length == 0) return;
508
509
if(db.trend) {
510
// merge in new data
511
var maxPoints = db.trend.maxPoints;
512
db.trend.times = db.trend.times.concat(data.trend.times);
513
var remove = db.trend.times.length > maxPoints ? db.trend.times.length - maxPoints : 0;
514
if(remove) db.trend.times = db.trend.times.slice(remove);
515
for(var name in db.trend.trends) {
516
db.trend.trends[name] = db.trend.trends[name].concat(data.trend.trends[name]);
517
if(remove) db.trend.trends[name] = db.trend.trends[name].slice(remove);
518
}
519
} else db.trend = data.trend;
520
521
db.trend.start = new Date(db.trend.times[0]);
522
db.trend.end = new Date(db.trend.times[db.trend.times.length - 1]);
523
db.trend.values = data.trend.values;
524
525
$.event.trigger({type:'updateChart'});
526
}
527
528
(function pollTrends() {
529
$.ajax({
530
url: dataURL,
531
dataType: 'json',
532
data: db.trend && db.trend.end ? {after:db.trend.end.getTime()} : null,
533
success: function(data) {
534
if(data) {
535
updateData(data);
536
if(lastControlsUpdate !== data.controlsUpdate) refreshControls();
537
if(lastSettingsUpdate != data.settingsUpdate) refreshSettings();
538
if(lastGroupsUpdate != data.groupsUpdate) refreshGroups();
539
}
540
},
541
complete: function(result,status,errorThrown) {
542
setTimeout(pollTrends,1000);
543
},
544
timeout: 60000
545
});
546
})();
547
548
$(window).resize(function() {
549
$.event.trigger({type:'updateChart'});
550
});
551
});
552
553