blob: d2ab8bdae2228142528221948fa7e48cd4e955f3 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
const React = require('react');
const ContentLoaderMixin = require('../../../js/components/ContentLoaderMixin.react');
const ChartMixin = require('../../../js/components/ChartMixin.react');
const PolloNetworkViewMixin = require('../../../js/components/PolloNetworkViewMixin.react');
const SpotActions = require('../../../js/actions/SpotActions');
const EdInActions = require('../../../js/actions/EdInActions');
const SpotConstants = require('../../../js/constants/SpotConstants');
const SuspiciousStore = require('../stores/SuspiciousStore');
const SUSPICIOUS_QUERY_LENGTH = 64;
const ID_SEPARATOR = '-';
const TYPE_SEPARATOR = '::';
function createNodeId(type, id) {
return `node${ID_SEPARATOR}${type}${TYPE_SEPARATOR}${id}`;
}
function getDataFromNodeId(id) {
const rawData = id.split(ID_SEPARATOR)[1];
const data = rawData.split(TYPE_SEPARATOR);
return {
type: data[0],
[data[0]]: data[1]
};
}
function createLinkId(tld, ip_dst) {
return `link${ID_SEPARATOR}tld${TYPE_SEPARATOR}${tld}${ID_SEPARATOR}ip_dst${TYPE_SEPARATOR}${ip_dst}`;
}
function getNodesFromData(data) {
const nodes = {};
data.forEach((item) => {
['tld', 'ip_dst'].forEach((field) => {
const id = createNodeId(field, item[field]);
if (!(id in nodes)) {
nodes[id] = {
id: id,
label: item[field],
internalIp: field==='tld' ? 1 : 0,
hits: 1
};
}
else {
nodes[id].hits++;
}
});
});
return nodes;
}
function getLinksFromData(data, nodes) {
const links = {};
data.forEach((item, idx) => {
const id = createLinkId(item.tld, item.ip_dst);
// Items where dns_qry_name is too long, are suspicious according to bussiness rules
const score = item.dns_qry_name.length>SUSPICIOUS_QUERY_LENGTH ? Number.MAX_VALUE : -Math.log(item.score);
if (!(id in links)) {
links[id] = {
id: id,
source: nodes[createNodeId('tld', item.tld)],
target: nodes[createNodeId('ip_dst', item.ip_dst)],
score
};
}
else {
links[id].score = Math.max(links[id].score, score)
}
});
return links;
}
function getStateFromData({data}) {
const nodes = getNodesFromData(data);
const links = getLinksFromData(data, nodes);
return {
nodes: Object.keys(nodes).map(nodeId => nodes[nodeId]),
links: Object.keys(links).map(linkId => links[linkId])
};
}
const NetworkViewPanel = React.createClass({
mixins: [ContentLoaderMixin, ChartMixin, PolloNetworkViewMixin],
componentDidMount() {
SuspiciousStore.addChangeDataListener(this._onChange);
SuspiciousStore.addThreatHighlightListener(this._onHighlight);
SuspiciousStore.addThreatUnhighlightListener(this._onUnhighlight);
SuspiciousStore.addThreatSelectListener(this._onSelect);
},
componentWillUmount() {
SuspiciousStore.removeChangeDataListener(this._onChange);
SuspiciousStore.removeThreatHighlightListener(this._onHighlight);
SuspiciousStore.removeThreatUnhighlightListener(this._onUnhighlight);
SuspiciousStore.removeThreatSelectListener(this._onSelect);
},
// render is inherited from Mixins
_onChange() {
const data = SuspiciousStore.getData();
const state = {loading: data.loading};
if (state.loading===false && data.data instanceof Array) {
state.data = getStateFromData(data);
state.data.maxNodes = SpotConstants.MAX_SUSPICIOUS_ROWS;
}
this.replaceState(state);
},
_onHighlight() {
const threat = SuspiciousStore.getHighlightedThreat();
this.highlightNodes([createNodeId('tld', threat.tld), createNodeId('ip_dst', threat.ip_dst)]);
this.highlightEdge(createLinkId(threat.tld, threat.ip_dst));
},
_onUnhighlight() {
this.unhighlight();
},
_onSelect() {
const threat = SuspiciousStore.getSelectedThreat();
this.selectNodes([createNodeId('tld', threat.tld), createNodeId('ip_dst', threat.ip_dst)]);
this.selectEdge(createLinkId(threat.tld, threat.ip_dst));
},
_onClick(id) {
const data = getDataFromNodeId(id);
if (data.type=='tld') return;
EdInActions.selectIp(data.ip_dst);
SpotActions.toggleMode(SpotConstants.DETAILS_PANEL, SpotConstants.VISUAL_DETAILS_MODE);
EdInActions.reloadVisualDetails();
},
_onContextualClick(id) {
d3.event.preventDefault();
const data = getDataFromNodeId(id);
EdInActions.setFilter(data.tld || data.ip_dst);
EdInActions.reloadSuspicious();
}
});
module.exports = NetworkViewPanel;