-
-
-
+
-
-
-
-
-
+
+
+
+
+
diff --git a/scripts/pi-hole/js/footer.js b/scripts/pi-hole/js/footer.js
index 2a38b3d1..31a2414d 100644
--- a/scripts/pi-hole/js/footer.js
+++ b/scripts/pi-hole/js/footer.js
@@ -163,6 +163,37 @@ function updateInfo() {
updateSystemInfo();
updateSensorsInfo();
updateVersionInfo();
+ updateFtlInfo();
+}
+
+var ftlinfoTimer = null;
+function updateFtlInfo() {
+ $.ajax({
+ url: "/api/info/ftl",
+ })
+ .done(function (data) {
+ var ftl = data.ftl;
+ var database = ftl.database;
+ var intl = new Intl.NumberFormat();
+ $("#num_groups").text(intl.format(database.groups));
+ $("#num_clients").text(intl.format(database.clients));
+ $("#num_lists").text(intl.format(database.lists));
+ $("#num_gravity").text(intl.format(database.gravity));
+ $("#num_allowed").text(intl.format(database.domains.allowed));
+ $("#num_denied").text(intl.format(database.domains.denied));
+
+ $("#sysinfo-cpu-ftl").text("(" + ftl["%cpu"].toFixed(1) + "% used by FTL)");
+ $("#sysinfo-ram-ftl").text("(" + ftl["%mem"].toFixed(1) + "% used by FTL)");
+ $("#sysinfo-pid-ftl").text(ftl.pid);
+ $("#sysinfo-privacy_level").text(ftl.privacy_level);
+ $("#sysinfo-ftl-overlay").hide();
+ // Update every 120 seconds
+ clearTimeout(ftlinfoTimer);
+ ftlinfoTimer = setTimeout(updateFtlInfo, 120000);
+ })
+ .fail(function (data) {
+ apiFailure(data);
+ });
}
function updateSystemInfo() {
@@ -171,25 +202,37 @@ function updateSystemInfo() {
})
.done(function (data) {
var system = data.system;
- var memory = (100 * system.memory.ram.used) / system.memory.ram.total;
- var totalGB = 1e-6 * system.memory.ram.total;
+ var percentRAM = system.memory.ram["%used"];
+ var percentSwap = system.memory.swap["%used"];
+ var totalRAMGB = system.memory.ram.total / 1024 / 1024;
+ var totalSwapGB = system.memory.swap.total / 1024 / 1024;
var swap =
system.memory.swap.total > 0
- ? ((1e-6 * system.memory.swap.used) / system.memory.swap.total).toFixed(1) + " %"
+ ? ((1e2 * system.memory.swap.used) / system.memory.swap.total).toFixed(1) + " %"
: "N/A";
var color;
- color = memory > 75 ? "text-red" : "text-green-light";
+ color = percentRAM > 75 ? "text-red" : "text-green-light";
$("#memory").html(
'
Memory usage: ' +
- memory.toFixed(1) +
+ percentRAM.toFixed(1) +
" %"
);
$("#memory").prop(
"title",
- "Total memory: " + totalGB.toFixed(1) + " GB, Swap usage: " + swap
+ "Total memory: " + totalRAMGB.toFixed(1) + " GB, Swap usage: " + swap
);
+ $("#sysinfo-memory-ram").text(
+ percentRAM.toFixed(1) + "% of " + totalRAMGB.toFixed(1) + " GB is used"
+ );
+ if (system.memory.swap.total > 0) {
+ $("#sysinfo-memory-swap").text(
+ percentSwap.toFixed(1) + "% of " + totalSwapGB.toFixed(1) + " GB is used"
+ );
+ } else {
+ $("#sysinfo-memory-swap").text("No swap space available");
+ }
color = system.cpu.load.percent[0] > 100 ? "text-red" : "text-green-light";
$("#cpu").html(
@@ -213,6 +256,20 @@ function updateSystemInfo() {
system.procs +
" processes"
);
+ $("#sysinfo-cpu").text(
+ system.cpu.load.percent[0].toFixed(1) +
+ "% (load: " +
+ system.cpu.load.raw[0].toFixed(2) +
+ " " +
+ system.cpu.load.raw[1].toFixed(2) +
+ " " +
+ system.cpu.load.raw[2].toFixed(2) +
+ ") on " +
+ system.cpu.nprocs +
+ " cores running " +
+ system.procs +
+ " processes"
+ );
var startdate = moment()
.subtract(system.uptime, "seconds")
@@ -225,6 +282,10 @@ function updateSystemInfo() {
startdate +
")"
);
+ $("#sysinfo-uptime").text(
+ moment.duration(1000 * system.uptime).humanize() + " (running since " + startdate + ")"
+ );
+ $("#sysinfo-system-overlay").hide();
// Update every 20 seconds
clearTimeout(systemTimer);
systemTimer = setTimeout(updateSystemInfo, 20000);
diff --git a/scripts/pi-hole/js/settings.js b/scripts/pi-hole/js/settings.js
index 1acf786d..ea76ea52 100644
--- a/scripts/pi-hole/js/settings.js
+++ b/scripts/pi-hole/js/settings.js
@@ -5,10 +5,76 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
-/* global utils:false, checkMessages:false */
+/* global utils:false, checkMessages:false, apiFailure:false */
var token = $("#token").text();
+var hostinfoTimer = null;
+function updateHostInfo() {
+ $.ajax({
+ url: "/api/info/host",
+ })
+ .done(function (data) {
+ var host = data.host;
+ var uname = host.uname;
+ if (uname.domainname !== "(none)") {
+ $("#sysinfo-hostname").text(uname.nodename + "." + uname.domainname);
+ } else {
+ $("#sysinfo-hostname").text(uname.nodename);
+ }
+
+ $("#sysinfo-kernel").text(
+ uname.sysname +
+ " " +
+ uname.nodename +
+ " " +
+ uname.release +
+ " " +
+ uname.version +
+ " " +
+ uname.machine
+ );
+ // Update every 120 seconds
+ clearTimeout(hostinfoTimer);
+ hostinfoTimer = setTimeout(updateHostInfo, 120000);
+ })
+ .fail(function (data) {
+ apiFailure(data);
+ });
+}
+
+var cacheinfoTimer = null;
+function updateCacheInfo() {
+ $.ajax({
+ url: "/api/info/cache",
+ })
+ .done(function (data) {
+ var cache = data.cache;
+ $("#sysinfo-cache-size").text(cache.size);
+ $("#sysinfo-cache-inserted").text(cache.inserted);
+ $("#sysinfo-cache-evicted").text(cache.evicted);
+ $("#sysinfo-cache-expired").text(cache.expired);
+ $("#sysinfo-cache-immortal").text(cache.immortal);
+ $("#sysinfo-cache-valid-a").text(cache.valid.a);
+ $("#sysinfo-cache-valid-aaaa").text(cache.valid.aaaa);
+ $("#sysinfo-cache-valid-cname").text(cache.valid.cname);
+ $("#sysinfo-cache-valid-srv").text(cache.valid.srv);
+ $("#sysinfo-cache-valid-ds").text(cache.valid.ds);
+ $("#sysinfo-cache-valid-dnskey").text(cache.valid.dnskey);
+ $("#sysinfo-cache-valid-other").text(cache.valid.other);
+ $("#sysinfo-cache-overlay").hide();
+ // Update every 10 seconds
+ clearTimeout(cacheinfoTimer);
+ cacheinfoTimer = setTimeout(updateCacheInfo, 10000);
+ })
+ .fail(function (data) {
+ apiFailure(data);
+ });
+}
+
$(function () {
+ updateHostInfo();
+ updateCacheInfo();
+
$("[data-static]").on("click", function () {
var row = $(this).closest("tr");
var mac = row.find("#MAC").text();
diff --git a/scripts/pi-hole/php/func.php b/scripts/pi-hole/php/func.php
index df128552..48297557 100644
--- a/scripts/pi-hole/php/func.php
+++ b/scripts/pi-hole/php/func.php
@@ -133,388 +133,6 @@ if (!function_exists('hash_equals')) {
}
}
-/**
- * More safely execute a command with pihole shell script.
- *
- * For example,
- *
- * pihole_execute("-h");
- *
- * would execute command
- *
- * sudo pihole -h
- *
- * and returns output of that command as a string.
- *
- * @param $argument_string String of arguments to run pihole with
- */
-function pihole_execute($argument_string)
-{
- $escaped = escapeshellcmd($argument_string);
- $output = null;
- $return_status = -1;
- $command = 'sudo pihole '.$escaped;
- exec($command, $output, $return_status);
- if ($return_status !== 0) {
- trigger_error("Executing {$command} failed.", E_USER_WARNING);
- }
-
- return $output;
-}
-
-// Custom DNS
-$customDNSFile = '/etc/pihole/custom.list';
-
-function echoCustomDNSEntries()
-{
- $entries = getCustomDNSEntries();
-
- $data = array();
- foreach ($entries as $entry) {
- $data[] = array($entry->domain, $entry->ip);
- }
-
- return array('data' => $data);
-}
-
-function getCustomDNSEntries()
-{
- global $customDNSFile;
-
- $entries = array();
-
- $handle = fopen($customDNSFile, 'r');
- if ($handle) {
- while (($line = fgets($handle)) !== false) {
- $line = str_replace("\r", '', $line);
- $line = str_replace("\n", '', $line);
- $explodedLine = explode(' ', $line);
-
- if (count($explodedLine) != 2) {
- continue;
- }
-
- $data = array();
- $data["ip"] = $explodedLine[0];
- $data["domain"] = $explodedLine[1];
- $data["domains"] = array_slice($explodedLine, 0, -1);
- $entries[] = $data;
- }
-
- fclose($handle);
- }
-
- return $entries;
-}
-
-function addCustomDNSEntry($ip = '', $domain = '', $reload = '', $json = true)
-{
- try {
- if (isset($_REQUEST['ip'])) {
- $ip = trim($_REQUEST['ip']);
- }
-
- if (isset($_REQUEST['domain'])) {
- $domain = trim($_REQUEST['domain']);
- }
-
- if (isset($_REQUEST['reload'])) {
- $reload = $_REQUEST['reload'];
- }
-
- if (empty($ip)) {
- return returnError('IP must be set', $json);
- }
-
- $ipType = get_ip_type($ip);
-
- if (!$ipType) {
- return returnError('IP must be valid', $json);
- }
-
- if (empty($domain)) {
- return returnError('Domain must be set', $json);
- }
-
- $num = 0;
- // Check if each submitted domain is valid
- $domains = array_map('trim', explode(',', $domain));
- foreach ($domains as $d) {
- if (!validDomain($d)) {
- return returnError("Domain '{$d}' is not valid", $json);
- }
- ++$num;
- }
-
- // Only check for duplicates if adding new records from the web UI (not through Teleporter)
- if (isset($_REQUEST['ip']) || isset($_REQUEST['domain'])) {
- $existingEntries = getCustomDNSEntries();
- foreach ($existingEntries as $entry) {
- foreach ($domains as $d) {
- if ($entry->domain == $d && get_ip_type($entry->ip) == $ipType) {
- return returnError("The domain {$d} already has a custom DNS entry for an IPv".$ipType, $json);
- }
- }
- }
- }
-
- // if $reload is not set and more then one domain is supplied, restart FTL only once after all entries were added
- if (($num > 0) && (empty($reload))) {
- $reload = 'false';
- }
- // Add records
- foreach ($domains as $domain) {
- pihole_execute('-a addcustomdns '.$ip.' '.$domain.' '.$reload);
- }
- if ($num > 0) {
- pihole_execute('restartdns');
- }
-
- return returnSuccess('', $json);
- } catch (Exception $ex) {
- return returnError($ex->getMessage(), $json);
- }
-}
-
-function deleteCustomDNSEntry()
-{
- try {
- $ip = !empty($_REQUEST['ip']) ? $_REQUEST['ip'] : '';
- $domain = !empty($_REQUEST['domain']) ? $_REQUEST['domain'] : '';
-
- if (empty($ip)) {
- return returnError('IP must be set');
- }
-
- if (empty($domain)) {
- return returnError('Domain must be set');
- }
-
- $existingEntries = getCustomDNSEntries();
-
- $found = false;
- foreach ($existingEntries as $entry) {
- if ($entry->domain == $domain) {
- if ($entry->ip == $ip) {
- $found = true;
-
- break;
- }
- }
- }
-
- if (!$found) {
- return returnError('This domain/ip association does not exist');
- }
-
- pihole_execute('-a removecustomdns '.$ip.' '.$domain);
-
- return returnSuccess();
- } catch (Exception $ex) {
- return returnError($ex->getMessage());
- }
-}
-
-function deleteAllCustomDNSEntries($reload = '')
-{
- try {
- if (isset($_REQUEST['reload'])) {
- $reload = $_REQUEST['reload'];
- }
-
- $existingEntries = getCustomDNSEntries();
- // passing false to pihole_execute stops pihole from reloading after each entry has been deleted
- foreach ($existingEntries as $entry) {
- pihole_execute('-a removecustomdns '.$entry->ip.' '.$entry->domain.' '.$reload);
- }
- } catch (Exception $ex) {
- return returnError($ex->getMessage());
- }
-
- return returnSuccess();
-}
-
-// CNAME
-$customCNAMEFile = '/etc/dnsmasq.d/05-pihole-custom-cname.conf';
-
-function echoCustomCNAMEEntries()
-{
- $entries = getCustomCNAMEEntries();
-
- $data = array();
- foreach ($entries as $entry) {
- $data[] = array($entry->domain, $entry->target);
- }
-
- return array('data' => $data);
-}
-
-function getCustomCNAMEEntries()
-{
- global $customCNAMEFile;
-
- $entries = array();
-
- if (!file_exists($customCNAMEFile)) {
- return $entries;
- }
-
- $handle = fopen($customCNAMEFile, 'r');
- if ($handle) {
- while (($line = fgets($handle)) !== false) {
- $line = str_replace('cname=', '', $line);
- $line = str_replace("\r", '', $line);
- $line = str_replace("\n", '', $line);
- $explodedLine = explode(',', $line);
-
- if (count($explodedLine) <= 1) {
- continue;
- }
-
- $data = array();
- $data["domains"] = array_slice($explodedLine, 0, -1);
- $data["domain"] = implode(',', $data["domains"]);
- $data["target"] = $explodedLine[count($explodedLine) - 1];
- $entries[] = $data;
- }
-
- fclose($handle);
- }
-
- return $entries;
-}
-
-function addCustomCNAMEEntry($domain = '', $target = '', $reload = '', $json = true)
-{
- try {
- if (isset($_REQUEST['domain'])) {
- $domain = $_REQUEST['domain'];
- }
-
- if (isset($_REQUEST['target'])) {
- $target = trim($_REQUEST['target']);
- }
-
- if (isset($_REQUEST['reload'])) {
- $reload = $_REQUEST['reload'];
- }
-
- if (empty($domain)) {
- return returnError('Domain must be set', $json);
- }
-
- if (empty($target)) {
- return returnError('Target must be set', $json);
- }
-
- if (!validDomain($target)) {
- return returnError('Target must be valid', $json);
- }
-
- $num = 0;
- $domains = array_map('trim', explode(',', $domain));
- foreach ($domains as $d) {
- // Check if each submitted domain is valid
- if (!validDomain($d)) {
- return returnError("Domain '{$d}' is not valid", $json);
- }
-
- // Check if each submitted domain is different than the target to avoid loops
- if (strtolower($d) === strtolower($target)) {
- return returnError('Domain and target cannot be the same', $json);
- }
-
- ++$num;
- }
-
- $existingEntries = getCustomCNAMEEntries();
-
- // Check if a record for one of the domains already exists
- foreach ($existingEntries as $entry) {
- foreach ($domains as $d) {
- if (in_array($d, $entry->domains)) {
- return returnError("There is already a CNAME record for '{$d}'", $json);
- }
- }
- }
-
- // if $reload is not set and more then one domain is supplied, restart FTL only once after all entries were added
- if (($num > 0) && (empty($reload))) {
- $reload = 'false';
- }
- // add records
- foreach ($domains as $d) {
- pihole_execute('-a addcustomcname '.$d.' '.$target.' '.$reload);
- }
-
- if ($num > 0) {
- pihole_execute('restartdns');
- }
-
- return returnSuccess('', $json);
- } catch (Exception $ex) {
- return returnError($ex->getMessage(), $json);
- }
-}
-
-function deleteCustomCNAMEEntry()
-{
- try {
- $target = !empty($_REQUEST['target']) ? $_REQUEST['target'] : '';
- $domain = !empty($_REQUEST['domain']) ? $_REQUEST['domain'] : '';
-
- if (empty($target)) {
- return returnError('Target must be set');
- }
-
- if (empty($domain)) {
- return returnError('Domain must be set');
- }
-
- $existingEntries = getCustomCNAMEEntries();
-
- $found = false;
- foreach ($existingEntries as $entry) {
- if ($entry->domain == $domain) {
- if ($entry->target == $target) {
- $found = true;
-
- break;
- }
- }
- }
-
- if (!$found) {
- return returnError('This domain/ip association does not exist');
- }
-
- pihole_execute('-a removecustomcname '.$domain.' '.$target);
-
- return returnSuccess();
- } catch (Exception $ex) {
- return returnError($ex->getMessage());
- }
-}
-
-function deleteAllCustomCNAMEEntries($reload = '')
-{
- try {
- if (isset($_REQUEST['reload'])) {
- $reload = $_REQUEST['reload'];
- }
-
- $existingEntries = getCustomCNAMEEntries();
- // passing false to pihole_execute stops pihole from reloading after each entry has been deleted
- foreach ($existingEntries as $entry) {
- pihole_execute('-a removecustomcname '.$entry->domain.' '.$entry->target.' '.$reload);
- }
- } catch (Exception $ex) {
- return returnError($ex->getMessage());
- }
-
- return returnSuccess();
-}
-
function returnSuccess($message = '', $json = true)
{
if ($json) {
diff --git a/scripts/pi-hole/php/sidebar.php b/scripts/pi-hole/php/sidebar.php
index 22508b99..6d43f9b2 100644
--- a/scripts/pi-hole/php/sidebar.php
+++ b/scripts/pi-hole/php/sidebar.php
@@ -59,22 +59,36 @@
- Domains
+ Domains
+
+
+
+
diff --git a/settings.php b/settings.php
index 8ecf22b2..1560fc90 100644
--- a/settings.php
+++ b/settings.php
@@ -10,187 +10,6 @@
require 'scripts/pi-hole/php/header_authenticated.php';
-$piholeFTLConf = array();
-
-// Handling of PHP internal errors
-$last_error = error_get_last();
-if (isset($last_error) && ($last_error['type'] === E_WARNING || $last_error['type'] === E_ERROR)) {
- $error .= 'There was a problem applying your settings.
Debugging information:
PHP error ('.htmlspecialchars($last_error['type']).'): '.htmlspecialchars($last_error['message']).' in '.htmlspecialchars($last_error['file']).':'.htmlspecialchars($last_error['line']);
-}
-/*
-// Timezone is set in docker via ENV otherwise get it from commandline
-$timezone = htmlspecialchars(getenv('TZ'));
-if (empty($timezone)) {
- $timezone = shell_exec("date +'%Z'");
-}
-*/
-?>
-
-
- refresh to the gravity page and start updating immediately
- ?>
-
-
-
- 0) { ?>
-
-
-
Info
-
-
-
-
- 0) { ?>
-
-
-
Error
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ | Hostname: |
+ |
+
+
+ | CPU: |
+ |
+
+
+ | Used memory: |
+
+ |
+
+ | Used swap: |
+ |
+
+
+ | Kernel: |
+ |
+
+
+ | Uptime: |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
DNS cache size:
|
- |
+ |
|
DNS cache insertions:
|
- |
+ |
|
DNS cache evictions:
|
- |
+ |
+
+
+ |
+ Valid A records in cache:
+ |
+ |
+
+
+ |
+ Valid AAAA records in cache:
+ |
+ |
+
+
+ |
+ Valid CNAME records in cache:
+ |
+ |
+
+
+ |
+ Valid SRV records in cache:
+ |
+ |
+
+
+ |
+ Valid DS records in cache:
+ |
+ |
+
+
+ |
+ Valid DNSKEY records in cache:
+ |
+ |
+
+
+ |
+ Other valid records in cache:
+ |
+ |
+
+
+ |
+ DNS cache expiries:
+ |
+ |
+
+
+ |
+ Immortal DNS cache entries:
+ |
+ |
See also our
DNS cache documentation.
-
-
The FTL service is offline!
-
+
+
+
@@ -598,7 +505,7 @@ if ($DHCP) {
}
}
-//readStaticLeasesFile();
+// readStaticLeasesFile();
?>
@@ -1434,7 +1341,7 @@ if (isset($piholeFTLConf['RATE_LIMIT'])) {
-
+
-