Skip to content

Commit

Permalink
add net-tree visualization
Browse files Browse the repository at this point in the history
  • Loading branch information
superstes committed Oct 19, 2024
1 parent a75a5ef commit e96ab2d
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 20 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
visualization/*.json
visualization/*.json
visualization/*.png
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The databases created from the gathered data will be and stay open-source!
<a href="https://github.com/O-X-L/risk-db/blob/latest/visualization">
<img src="https://raw.githubusercontent.com/O-X-L/risk-db/refs/heads/latest/visualization/world_map_example.webp" alt="World Map Example" width="800"/>
<img src="https://raw.githubusercontent.com/O-X-L/risk-db/refs/heads/latest/visualization/asn_chart_example.webp" alt="ASN Chart Example" width="800"/>
<img src="https://raw.githubusercontent.com/O-X-L/risk-db/refs/heads/latest/visualization/net_tree_example.webp" alt="Net Tree Example" width="800"/>
</a>

----
Expand Down
32 changes: 29 additions & 3 deletions visualization/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

It uses this javascript library: [StephanWagner/svgMap](https://github.com/StephanWagner/svgMap)

Use:
Usage:

1. Download the free [IPInfo country database](https://ipinfo.io/products/free-ip-database)

Expand All @@ -26,11 +26,11 @@ Use:

----

## ASN Chart
## ASN Bubble-Chart

It uses this javascript library: [d3js](https://d3js.org/)

Use:
Usage:

1. Copy the `risk_asn_med.json` into this directory

Expand All @@ -43,3 +43,29 @@ Use:
3. Open the file in your browser: [http://localhost:8000/asn_chart.html](http://localhost:8000/world_map.html)

<img src="https://raw.githubusercontent.com/O-X-L/risk-db/refs/heads/latest/visualization/asn_chart_example.webp" alt="ASN Chart Example" width="800"/>

----

## Network Tree-Chart

It uses this javascript library: [d3js](https://d3js.org/)

Usage:

1. Download the free [IPInfo ASN database](https://ipinfo.io/products/free-ip-database)

2. Generate the JSON file

```bash
python3 net_tree.py -a ~/Downloads/country_asn.mmdb -n ~/Downloads/risk_net4_med.json
```

3. For testing - run the minimal python3 webserver to enable JS to access the JSON file:

```bash
python3 test_server.py
```

4. Open the file in your browser: [http://localhost:8000/net_tree.html](http://localhost:8000/world_map.html)

<img src="https://raw.githubusercontent.com/O-X-L/risk-db/refs/heads/latest/visualization/net_tree_example.webp" alt="Net Tree Example" width="800"/>
32 changes: 16 additions & 16 deletions visualization/asn_chart.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

.bubble-asn {
font-weight: bold;
text-anchor: middle;
}

.bubble-info {
Expand Down Expand Up @@ -44,7 +45,10 @@
</style>
</head>
<body>
<!-- see: https://observablehq.com/@d3/bubble-chart/2 -->
<!--
see: https://observablehq.com/@d3/bubble-chart/2
see2: https://medium.com/@jhren/d3-data-visualization-in-javascript-use-d3-js-to-create-a-bubble-chart-3fba181faacd
-->
<div id="infos"></div>
<svg id="chart"></svg>
<script>
Expand Down Expand Up @@ -73,35 +77,35 @@
function showASNInfos(e) {
let infos = JSON.parse(e.currentTarget.querySelectorAll(".bubble-info")[0].textContent);
let infoContainer = document.getElementById('infos');
infoContainer.innerHTML = '<b>ASN</b>: ' + infos.asn + '<br>';
infoContainer.innerHTML += '<b>Org</b>: ' + infos.info.org.name + '<br>';
infoContainer.innerHTML = `<b>ASN</b>: ${infos.asn}<br>`;
infoContainer.innerHTML += `<b>Org</b>: ${infos.info.org.name}<br>`;
if (infos.info.org.country != '' && infos.info.org.country !== null) {
infoContainer.innerHTML += '<b>Country</b>: ' + infos.info.org.country + '<br>';
infoContainer.innerHTML += `<b>Country</b>: ${infos.info.org.country}<br>`;
}
infoContainer.innerHTML += '<b>IPv4 Addresses</b>: ' + numberWithDot(infos.info.ipv4) + '<br>';
infoContainer.innerHTML += '<b>IPv6 Addresses</b>: ' + numberWithDot(infos.info.ipv6) + '<br>';
infoContainer.innerHTML += `<b>IPv4 Addresses</b>: ${numberWithDot(infos.info.ipv4)}<br>`;
infoContainer.innerHTML += `<b>IPv6 Addresses</b>: ${numberWithDot(infos.info.ipv6)}<br>`;
let kinds = [];
for (let [k, v] of Object.entries(infos.kind)) {
if (v === true) {
kinds.push(k);
}
}
if (kinds.length > 0) {
infoContainer.innerHTML += '<b>Kind</b>: ' + kinds.join(', ') + '<br>';
infoContainer.innerHTML += `<b>Kind</b>: ${kinds.join(', ')}<br>`;
}
let urls = ['<a href="https://risk.oxl.app/api/asn/' + infos.asn + '">oxl_riskdb</a>'];
let urls = [`<a href="https://risk.oxl.app/api/asn/${infos.asn}">oxl_riskdb</a>`];
for (let [k, v] of Object.entries(infos.info.url)) {
urls.push('<a href="' + v + '">' + k + '</a>');
urls.push(`<a href="${v}">${k}</a>`);
}
infoContainer.innerHTML += '<b>URLs</b>: ' + urls.join(', ') + '<br><hr>';
infoContainer.innerHTML += `<b>URLs</b>: ${urls.join(', ')}<br><hr>`;
for (let [k, v] of Object.entries(infos.reports)) {
let r = '<small><b>Reports ' + k + '</b>: ';
let r = `<small><b>Reports ${k}</b>: `;
if (k == 'rel_by_ip4') {
r += v;
} else {
r += numberWithDot(v);
}
infoContainer.innerHTML += r + '</small><br>';
infoContainer.innerHTML += `${r}</small><br>`;
}
}

Expand Down Expand Up @@ -148,20 +152,16 @@
.attr("fill", d => colorScale(d.data.asn));

bubbles.append("text")
.style("text-anchor", "middle")
.append("tspan")
.attr("class", "bubble-asn")
.text(d => d.data.asn);

// hover infos
bubbles.append("text")
.style("text-anchor", "bottom")
.append("tspan")
.attr("class", "bubble-info")
.text(d => JSON.stringify(d.data));

d3.selectAll("text").style("fill", "black");

for (let b of document.querySelectorAll(".bubble")) {
b.addEventListener("mouseover", showASNInfos);
}
Expand Down
175 changes: 175 additions & 0 deletions visualization/net_tree.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/svg" href="https://files.oxl.at/img/oxl3_sm.png">

<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
#chart {
width: 100vw;
height: 100vh;
}

.net {
overflow: hidden;
font-weight: bold;
transform
}

.net-cidr {
display: inline-block;
margin-top: 100px;
}

.net-info {
visibility: hidden;
display: none;
}

#infos {
width: 20vw;
height: 25vh;
background-color: whitesmoke;
opacity: 0.85;
z-index: 2;
border-radius: 10px;
border-width: 2px;
border-color: black;
border-style: solid;
position: absolute;
padding: 20px;
overflow: hidden;
}

</style>
</head>
<body>
<!--
see: https://observablehq.com/@d3/treemap/2
see2: https://d3-graph-gallery.com/graph/treemap_basic.html
-->
<div id="infos"></div>
<svg id="chart"></svg>
<script>
// start test webserver: 'python3 test_server.py'

const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight - 50;
const NET_PAD = 5;
const CATEGORIES = ['all', 'bot', 'probe', 'rate', 'attack', 'crawler'];
const COLORSCHEME = [
// red-ish
"#B93022", "#FF383D", "#D32669", "#C43F03", "#E70291", "#E211C0", "#6A3D52", "#C75839", "#E7A8B0",
"#DB7277", "#A23E48",
// purple-ish
"#9F8AD2", "#4B2ED1", "#9C1091", "#EA77DF", "#8D0BE8", "#BB65BC", "#993CF3", "#9F09EF", "#CD0099",
"#EA2794", "#DC8581", "#9C1686",
// orange-ish
"#E37F6F", "#C5824E", "#FDCA29", "#D99620", "#E7C014", "#F9C630", "#F6BC55", "#B9AB58", "#DB8E94",
"#D27E7E",
];

function numberWithDot(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}

function showNetInfos(e) {
let infos = JSON.parse(e.currentTarget.querySelectorAll(".net-info")[0].textContent);

var x = event.clientX;
var y = event.clientY;
console.log(infos, x, y);

var infoContainer = document.getElementById('infos');
infoContainer.style.left = `${x}px`;
infoContainer.style.top = `${y}px`;

infoContainer.innerHTML = `<b>Network</b>: ${infos.name}<br>`;
infoContainer.innerHTML += `<b>Reported IPs</b>: ${infos.reported_ips}<br>`;
infoContainer.innerHTML += `<b>Reputation</b>: ${infos.reputation.toUpperCase()}<br>`;
infoContainer.innerHTML += `<b>ASN</b>: ${infos.asn}<br>`;
infoContainer.innerHTML += `<b>Org</b>: ${infos.as_name}<br>`;

if (infos.country !== undefined) {
infoContainer.innerHTML += `<b>Country</b>: ${infos.country}<br>`;
}

let urls = [];
for (let [k, v] of Object.entries(infos.url)) {
urls.push(`<a href="${v}">${k}</a>`);
}
infoContainer.innerHTML += `<b>URLs</b>: ${urls.join(', ')}<br><hr>`;

for (let c of CATEGORIES) {
if (c in infos) {
infoContainer.innerHTML += `<small><b>Reports ${c}</b>: ${numberWithDot(infos[c])}</small><br>`;
}
}
}

function createChart() {
d3.json('net_tree.json', function(data) {
var svg = d3.select("#chart");

var root = d3.stratify()
.id(function(d) { return d.name; })
.parentId(function(d) { if (d.name == 'root') { return null } else { return 'root' }; })
(data.children);

root.sum(function(d) { return +d.all })

d3.treemap()
.size([WIDTH, HEIGHT])
.padding(4)
(root)

const colorScale = d3.scaleOrdinal()
.range(COLORSCHEME);

const nets = svg.selectAll(".net")
.data(root.descendants().slice(1))
.enter()
.append("g")
.attr("class", "net");

nets.append("rect")
.attr('x', function (d) { return d.x0; })
.attr('y', function (d) { return d.y0; })
.attr('width', function (d) { return d.x1 - d.x0; })
.attr('height', function (d) { return d.y1 - d.y0; })
.style("fill", d => colorScale(d.data.reported_ips))
.attr("class", "net");

nets.append("text")
.append("tspan")
.attr("class", "net-cidr")
.text(d => d.data.name)
.style('fill', 'whitesmoke');

// hover infos
nets.append("text")
.style("text-anchor", "bottom")
.append("tspan")
.attr("class", "net-info")
.text(d => JSON.stringify(d.data));

for (let n of document.querySelectorAll(".net")) {
let r = n.querySelectorAll("rect")[0];
if (r === undefined) {
continue;
}
let c = n.querySelectorAll("text")[0];
c.setAttribute("transform", `translate(${r.x.baseVal.value + NET_PAD}, ${r.y.baseVal.value + NET_PAD + 30})`);

n.addEventListener("mouseover", showNetInfos);
}

});
}

createChart();
</script>
</body>
</html>
Loading

0 comments on commit e96ab2d

Please sign in to comment.