Add network details page

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2018-12-27 15:07:59 +01:00
parent cb552159ac
commit aa38b98ebc
2 changed files with 231 additions and 0 deletions

74
network.php Normal file
View File

@@ -0,0 +1,74 @@
<?php /*
* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
require "scripts/pi-hole/php/header.php";
// Generate CSRF token
if(empty($_SESSION['token'])) {
$_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32));
}
$token = $_SESSION['token'];
?>
<!-- Send PHP info to JS -->
<div id="token" hidden><?php echo $token ?></div>
<div class="row">
<div class="col-md-12">
<div class="box" id="network-details">
<div class="box-header with-border">
<h3 class="box-title">Network overview</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table id="network-entries" class="display table table-striped table-bordered" cellspacing="0" width="100%">
<thead>
<tr>
<th>IP address</th>
<th>MAC address</th>
<th>Interface</th>
<th>Hostname</th>
<th>First seen</th>
<th>Last Query</th>
<th>Number of queries</th>
</tr>
</thead>
<tfoot>
<tr>
<th>IP address</th>
<th>MAC address</th>
<th>Interface</th>
<th>Hostname</th>
<th>First seen</th>
<th>Last Query</th>
<th>Number of queries</th>
</tr>
</tfoot>
</table>
<label>Background color: Last query from this device seen ...</label>
<table width="100%">
<tr style="text-align: center;">
<td style="background: #E7FFDE;" width="15%">just now</td>
<td style="background-image: linear-gradient(to right, #E7FFDE 0%, #FFFFDF 100%)" width="30%"><center>... to ...</center></td>
<td style="background: #FFFFDF;" width="15%">24 hours ago</td>
<td style="background: #FFEDD9;" width="20%">&gt; 24 hours ago</td>
<td style="background: #FFBFAA;" width="20%">Device does not use Pi-hole</td>
</tr>
</table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
<!-- /.row -->
<?php
require "scripts/pi-hole/php/footer.php";
?>
<script src="scripts/vendor/moment.min.js"></script>
<script src="scripts/pi-hole/js/network.js"></script>

View File

@@ -0,0 +1,157 @@
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
var tableApi;
function escapeRegex(text) {
var map = {
"(": "\\(",
")": "\\)",
".": "\\.",
};
return text.replace(/[().]/g, function(m) { return map[m]; });
}
function refreshData() {
tableApi.ajax.url("api_db.php?network").load();
// updateSessionTimer();
}
function handleAjaxError( xhr, textStatus, error ) {
if ( textStatus === "timeout" )
{
alert( "The server took too long to send the data." );
}
else if(xhr.responseText.indexOf("Connection refused") >= 0)
{
alert( "An error occured while loading the data: Connection refused. Is FTL running?" );
}
else
{
alert( "An unknown error occured while loading the data.\n"+xhr.responseText );
}
$("#network-entries_processing").hide();
tableApi.clear();
tableApi.draw();
}
function autofilter(){
return document.getElementById("autofilter").checked;
}
function getTimestamp(){
if (!Date.now)
{
Date.now = function() { return new Date().getTime(); }
}
return Math.floor(Date.now() / 1000);
}
function valueToHex(c) {
var hex = Math.round(c).toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(values) {
return "#" + valueToHex(values[0])
+ valueToHex(values[1])
+ valueToHex(values[2]);
}
function mixColors(ratio, rgb1, rgb2)
{
return [(1.0-ratio)*rgb1[0]+ratio*rgb2[0],
(1.0-ratio)*rgb1[1]+ratio*rgb2[1],
(1.0-ratio)*rgb1[2]+ratio*rgb2[2]];
}
$(document).ready(function() {
var APIstring = "api_db.php?network";
tableApi = $("#network-entries").DataTable( {
"rowCallback": function( row, data, index )
{
var color, lastQuery = parseInt(data["lastQuery"]);
if(lastQuery > 0)
{
var diff = getTimestamp()-lastQuery;
if(diff <= 86400)
{
// Last query came in within the last 24 hours (24*60*60 = 86400)
// Color: light-green to light-yellow
var ratio = 1e0*diff/86400;
var lightgreen = [0xE7, 0xFF, 0xDE];
var lightyellow = [0xFF, 0xFF, 0xDF];
color = rgbToHex(mixColors(ratio, lightgreen, lightyellow));
}
else
{
// Last query was longer than 24 hours ago
// Color: light-orange
color = "#FFEDD9";
}
}
else
{
// This client has never sent a query to Pi-hole, color light-red
color = "#FFBFAA";
}
$(row).css("background-color", color);
if(data["lastQuery"] === 0)
{
$("td:eq(5)", row).html("Never");
}
if(data["name"].length < 1)
{
$("td:eq(3)", row).html("N/A");
}
},
dom: "<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
"ajax": {"url": APIstring, "error": handleAjaxError, "dataSrc": "network" },
"autoWidth" : false,
"processing": true,
"order" : [[5, "desc"]],
"columns": [
{data: "ip", "width" : "10%", "render": $.fn.dataTable.render.text() },
{data: "hwaddr", "width" : "10%", "render": $.fn.dataTable.render.text() },
{data: "interface", "width" : "10%", "render": $.fn.dataTable.render.text() },
{data: "name", "width" : "10%", "render": $.fn.dataTable.render.text() },
{data: "firstSeen", "width" : "10%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");}else{return data;} }},
{data: "lastQuery", "width" : "10%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");}else{return data;} }},
{data: "numQueries", "width" : "10%", "render": $.fn.dataTable.render.text() }
],
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
"stateSave": true,
stateSaveCallback: function(settings, data) {
// Store current state in client's local storage area
localStorage.setItem("network_table", JSON.stringify(data));
},
stateLoadCallback: function(settings) {
// Receive previous state from client's local storage area
var data = localStorage.getItem("network_table");
// Return if not available
if(data === null){ return null; }
data = JSON.parse(data);
// Always start on the first page
data["start"] = 0;
// Always start with empty search field
data["search"]["search"] = "";
// Apply loaded state to table
return data;
},
"columnDefs": [ {
"targets": -1,
"data": null,
"defaultContent": ""
} ]
});
} );