diff options
| author | 姜萍 <[email protected]> | 2022-05-29 17:59:26 +0800 |
|---|---|---|
| committer | 姜萍 <[email protected]> | 2022-05-29 17:59:26 +0800 |
| commit | 9f0f12ed28357ae167cb9aab3a614da0f8cd4bab (patch) | |
| tree | 0eac2d3fbfc11e7639b9a0254a8c24d8a43bd8f2 /sflow-rt/app/flow-trend/scripts | |
initmaster
Diffstat (limited to 'sflow-rt/app/flow-trend/scripts')
| -rw-r--r-- | sflow-rt/app/flow-trend/scripts/inc/trend.js | 49 | ||||
| -rw-r--r-- | sflow-rt/app/flow-trend/scripts/top.js | 159 |
2 files changed, 208 insertions, 0 deletions
diff --git a/sflow-rt/app/flow-trend/scripts/inc/trend.js b/sflow-rt/app/flow-trend/scripts/inc/trend.js new file mode 100644 index 0000000..e550352 --- /dev/null +++ b/sflow-rt/app/flow-trend/scripts/inc/trend.js @@ -0,0 +1,49 @@ +function Trend(maxPoints, stepSize) { + this.maxPoints = maxPoints; + this.trends = {}; + this.times = new Array(maxPoints); + var i, t = (new Date()).getTime(), stepMs = stepSize * 1000; + for(i = maxPoints - 1; i >= 0; i--) { t -= stepMs; this.times[i] = t; } +} + +Trend.prototype.addPoints = function(now,values) { + this.times.push(now); + + var name, i; + for (name in values) { + var points = this.trends[name]; + if(!points) { + points = new Array(this.maxPoints); + for(i = 0; i < this.maxPoints; i++) points[i] = 0; + this.trends[name] = points; + } + points.push(values[name]); + points.shift(); + } + this.times.shift(); +} + +Trend.prototype.after = function(tval) { + var res = new Trend(0,0); + res.maxPoints = this.maxPoints; + for(var i = 0; i < this.times.length; i++) { + var t = this.times[i]; + if(tval < t) { + res.times.push(t); + for (var name in this.trends) { + var val = this.trends[name][i]; + var trend = res.trends[name]; + if(!trend) { + trend = []; + res.trends[name] = trend; + } + trend.push(val); + } + } + } + return res; +} + +Trend.prototype.remove = function(name) { + delete this.trends[name]; +} diff --git a/sflow-rt/app/flow-trend/scripts/top.js b/sflow-rt/app/flow-trend/scripts/top.js new file mode 100644 index 0000000..a9c2983 --- /dev/null +++ b/sflow-rt/app/flow-trend/scripts/top.js @@ -0,0 +1,159 @@ +// author: InMon Corp. +// version: 1.0 +// date: 3/2/2017 +// description: Flow Trend +// copyright: Copyright (c) 2017 InMon Corp. ALL RIGHTS RESERVED + +include(scriptdir()+'/inc/trend.js'); + +var SEP = '_SEP_'; + +var defaultShortcuts = [ +{category:'Traffic', protocol:'IP', description:'Sources',keys:'ipsource',value:'bps',filter:''}, +{category:'Traffic', protocol:'IP', description:'Destinations',keys:'ipdestination',value:'bps',filter:''}, +{category:'Traffic', protocol:'IP', description:'Source-Destination pairs',keys:'ipsource,ipdestination',value:'bps',filter:''}, +{category:'Traffic', protocol:'IPv6', description:'Sources',keys:'ip6source',value:'bps',filter:''}, +{category:'Traffic', protocol:'IPv6', description:'Destinations',keys:'ip6destination',value:'bps',filter:''}, +{category:'Traffic', protocol:'IPv6', description:'Source-Destination pairs',keys:'ip6source,ip6destination',value:'bps',filter:''}, +{category:'Traffic', protocol:'Ethernet', description:'Sources',keys:'macsource,oui:macsource:name',value:'frames',filter:''}, +{category:'Traffic', protocol:'Ethernet', description:'Sources of broadcasts',keys:'macsource,oui:macsource:name',value:'frames',filter:'macdestination=FFFFFFFFFFFF'}, +{category:'Security', protocol:'TCP', description:'Connection attempts',keys:'ipsource,ipdestination,tcpdestinationport',value:'frames',filter:'tcpflags~.......1.'}, +{category:'Security', protocol:'ARP', description:'Source of requests',keys:'arpipsender',value:'requests',filter:'arpoperation=1'}, +{category:'Security', protocol:'DNS', description:'Requested domains',keys:'dnsqname',value:'requests',filter:''}, +{category:'Security', protocol:'DNS', description:'Clients',keys:'or:ipsource:ip6source',value:'requests',filter:'dnsqr=false'}, +{category:'Security', protocol:'DNS', description:'Servers',keys:'or:ipsource:ip6source',value:'requests',filter:'dnsqr=true'}, +{category:'Security', protocol:'ICMP', description:'Unreachable ports', keys:'ipdestination,icmpunreachableport', value:'fps', filter:''}, +{category:'Security', protocol:'ICMP', description:'Unreachable protocols', keys:'ipdestination,icmpunreachableprotocol', value:'fps', filter:''}, +{category:'Security', protocol:'ICMP', description:'Unreachable hosts', keys:'ipdestination,icmpunreachablehost', value:'fps', filter:''}, +{category:'Security', protocol:'ICMP', description:'Unreachable networks', keys:'ipdestination,icmpunreachablenet', value:'fps', filter:''}, +{category:'Virtualization', protocol:'VxLAN', description:'Tenant VNI', keys:'vxlanvni',value:'bps',filter:''}, +{category:'Virtualization', protocol:'NVGRE', description:'Tenant VSID', keys:'grevsid', value:'bps',filter:''}, +{category:'Virtualization', protocol:'Geneve', description:'Tenant VNI', keys:'genevevni',value:'bps',filter:''} +]; + +var aggMode = getSystemProperty('flow-trend.aggMode') || 'max'; +var maxFlows = getSystemProperty('flow-trend.maxFlows') || 10; +var minValue = getSystemProperty('flow-trend.minValue') || 0.01; +var agents = getSystemProperty('flow-trend.agents') || 'ALL'; +var t = getSystemProperty('flow-trend.t') || 2; + +var shortcuts = storeGet('shortcuts') || defaultShortcuts; + +var userFlows = {}; + +function escapeRegExp(str) { + // seems like a bug - Rhino doesn't convert Java strings into native JavaScript strings + str = new String(str); + return str ? str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") : null; +} + +var specID = 0; +function flowSpec(keys,value,filter) { + var keysStr = keys ? keys.join(',') : ''; + var valueStr = value ? value.join(',') : ''; + var filterStr = filter ? filter.join('&') : ''; + + if(keysStr.length === 0 || valueStr.length === 0) return null; + + var key = keysStr || ''; + if(valueStr) key += '#' + valueStr; + if(filterStr) key += '#' + filterStr; + var entry = userFlows[key]; + if(!entry) { + // try to create flow + var name = 'flow_trend_' + specID; + try { + setFlow(name,{keys:keysStr, value:valueStr, filter: filterStr.length > 0 ? filterStr : null, t:t, n:maxFlows, fs:SEP}); + entry = {name:name, trend: new Trend(300,1)}; + entry.trend.addPoints(Date.now(), {topn:{}}); + userFlows[key] = entry; + specID++; + } catch(e) { + entry = null; + } + } + if(!entry) return null; + entry.lastQuery = (new Date()).getTime(); + + return entry; +} + +setIntervalHandler(function(now) { + var key, entry, top, topN, i; + for(key in userFlows) { + entry = userFlows[key]; + if(now - entry.lastQuery > 10000) { + clearFlow(entry.name); + delete userFlows[key]; + } else { + topN = {}; + top = activeFlows(agents,entry.name,maxFlows,minValue,aggMode); + if(top) { + for(i = 0; i < top.length; i++) { + topN[top[i].key] = top[i].value; + } + } + entry.trend.addPoints(now,{topn:topN}); + } + } +},1); + +function validShortcuts(obj) { + if(!Array.isArray(obj)) return false; + var attrs = ['category','protocol','description','keys','value','filter']; + for(var i = 0; i < obj.length; i++) { + let shortcut = obj[i]; + for(var j = 0; j < attrs.length; j++) { + let attr = attrs[j]; + if(!shortcut.hasOwnProperty(attr)) return false; + if(typeof shortcut[attr] !== 'string') return false; + } + } + return true; +} + +setHttpHandler(function(req) { + var result, trend, key, entry, path = req.path; + if(!path || path.length === 0) throw "not_found"; + + switch(path[0]) { + case 'shortcuts': + if(path.length > 1) throw "not_found"; + switch(req.method) { + case 'POST': + case 'PUT': + if(req.error) throw "bad_request"; + if(!validShortcuts(req.body)) throw "bad_request"; + shortcuts = req.body; + storeSet('shortcuts', shortcuts); + break; + default: return shortcuts; + } + break; + case 'flowkeys': + if(path.length > 1) throw "not_found"; + result = []; + var search = req.query['search']; + if(search) { + var matcher = new RegExp('^' + escapeRegExp(search), 'i'); + for(key in flowKeys()) { + if(matcher.test(key)) result.push(key); + } + } else { + for(key in flowKeys()) result.push(key); + } + result.sort(); + break; + case 'flows': + if(path.length > 1) throw "not_found"; + entry = flowSpec(req.query['keys'],req.query['value'],req.query['filter']); + if(!entry) throw 'bad_request'; + trend = entry.trend; + result = {}; + result.trend = req.query.after ? trend.after(parseInt(req.query.after)) : trend; + break; + default: throw 'not_found'; + } + return result; +}); + |
