diff --git a/api_db.php b/api_db.php
index 7090ed49..2cd99bf8 100644
--- a/api_db.php
+++ b/api_db.php
@@ -12,18 +12,35 @@ require("scripts/pi-hole/php/password.php");
require("scripts/pi-hole/php/auth.php");
check_cors();
+// Set maximum execution time to 10 minutes
+ini_set("max_execution_time","600");
+
$data = array();
+// Get posible non-standard location of FTL's database
+$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf");
+if(isset($FTLsettings["DBFILE"]))
+{
+ $DBFILE = $FTLsettings["DBFILE"];
+}
+else
+{
+ $DBFILE = "/etc/pihole/pihole-FTL.db";
+}
+
// Needs package php5-sqlite, e.g.
// sudo apt-get install php5-sqlite
function SQLite3_connect($trytoreconnect)
{
- try {
+ global $DBFILE;
+ try
+ {
// connect to database
- return new SQLite3('/etc/pihole/pihole-FTL.db', SQLITE3_OPEN_READONLY);
+ return new SQLite3($DBFILE, SQLITE3_OPEN_READONLY);
}
- catch (Exception $exception) {
+ catch (Exception $exception)
+ {
// sqlite3 throws an exception when it is unable to connect, try to reconnect after 3 seconds
if($trytoreconnect)
{
@@ -33,8 +50,14 @@ function SQLite3_connect($trytoreconnect)
}
}
-$db = SQLite3_connect(true);
-
+if(strlen($DBFILE) > 0)
+{
+ $db = SQLite3_connect(true);
+}
+else
+{
+ die("No database available");
+}
if(!$db)
{
die("Error connecting to database");
@@ -42,20 +65,17 @@ if(!$db)
if (isset($_GET['getAllQueries']) && $auth)
{
- if($_GET['getAllQueries'] === "empty")
- {
- $allQueries = array();
- }
- else
+ $allQueries = array();
+ if($_GET['getAllQueries'] !== "empty")
{
$from = intval($_GET["from"]);
$until = intval($_GET["until"]);
$results = $db->query('SELECT timestamp,type,domain,client,status FROM queries WHERE timestamp >= '.$from.' AND timestamp <= '.$until.' ORDER BY timestamp ASC');
- $allQueries = array();
- while ($row = $results->fetchArray())
- {
- $allQueries[] = [$row[0],$row[1] == 1 ? "IPv4" : "IPv6",$row[2],$row[3],$row[4]];
- }
+ if(!is_bool($results))
+ while ($row = $results->fetchArray())
+ {
+ $allQueries[] = [$row[0],$row[1] == 1 ? "IPv4" : "IPv6",$row[2],$row[3],$row[4]];
+ }
}
$result = array('data' => $allQueries);
$data = array_merge($data, $result);
@@ -77,13 +97,33 @@ if (isset($_GET['topClients']) && $auth)
{
$limit = "WHERE timestamp <= ".$_GET["until"];
}
- $results = $db->query('SELECT client,count(client) FROM queries '.$limit.' GROUP by client order by count(client) desc limit 10');
+ $results = $db->query('SELECT client,count(client) FROM queries '.$limit.' GROUP by client order by count(client) desc limit 20');
+
$clients = array();
- while ($row = $results->fetchArray())
- {
- $clients[$row[0]] = intval($row[1]);
- // var_dump($row);
- }
+
+ if(!is_bool($results))
+ while ($row = $results->fetchArray())
+ {
+ // Convert client to lower case
+ $c = strtolower($row[0]);
+ if(array_key_exists($c, $clients))
+ {
+ // Entry already exists, add to it (might appear multiple times due to mixed capitalization in the database)
+ $clients[$c] += intval($row[1]);
+ }
+ else
+ {
+ // Entry does not yet exist
+ $clients[$c] = intval($row[1]);
+ }
+ }
+
+ // Sort by number of hits
+ arsort($clients);
+
+ // Extract only the first ten entries
+ $clients = array_slice($clients, 0, 10);
+
$result = array('top_sources' => $clients);
$data = array_merge($data, $result);
}
@@ -104,12 +144,33 @@ if (isset($_GET['topDomains']) && $auth)
{
$limit = " AND timestamp <= ".$_GET["until"];
}
- $results = $db->query('SELECT domain,count(domain) FROM queries WHERE (STATUS == 2 OR STATUS == 3)'.$limit.' GROUP by domain order by count(domain) desc limit 10');
+ $results = $db->query('SELECT domain,count(domain) FROM queries WHERE (STATUS == 2 OR STATUS == 3)'.$limit.' GROUP by domain order by count(domain) desc limit 20');
+
$domains = array();
- while ($row = $results->fetchArray())
- {
- $domains[$row[0]] = intval($row[1]);
- }
+
+ if(!is_bool($results))
+ while ($row = $results->fetchArray())
+ {
+ // Convert client to lower case
+ $c = strtolower($row[0]);
+ if(array_key_exists($c, $domains))
+ {
+ // Entry already exists, add to it (might appear multiple times due to mixed capitalization in the database)
+ $domains[$c] += intval($row[1]);
+ }
+ else
+ {
+ // Entry does not yet exist
+ $domains[$c] = intval($row[1]);
+ }
+ }
+
+ // Sort by number of hits
+ arsort($domains);
+
+ // Extract only the first ten entries
+ $domains = array_slice($domains, 0, 10);
+
$result = array('top_domains' => $domains);
$data = array_merge($data, $result);
}
@@ -131,11 +192,14 @@ if (isset($_GET['topAds']) && $auth)
$limit = " AND timestamp <= ".$_GET["until"];
}
$results = $db->query('SELECT domain,count(domain) FROM queries WHERE (STATUS == 1 OR STATUS == 4)'.$limit.' GROUP by domain order by count(domain) desc limit 10');
+
$addomains = array();
- while ($row = $results->fetchArray())
- {
- $addomains[$row[0]] = intval($row[1]);
- }
+
+ if(!is_bool($results))
+ while ($row = $results->fetchArray())
+ {
+ $addomains[$row[0]] = intval($row[1]);
+ }
$result = array('top_ads' => $addomains);
$data = array_merge($data, $result);
}
@@ -143,21 +207,36 @@ if (isset($_GET['topAds']) && $auth)
if (isset($_GET['getMinTimestamp']) && $auth)
{
$results = $db->query('SELECT MIN(timestamp) FROM queries');
- $result = array('mintimestamp' => $results->fetchArray()[0]);
+
+ if(!is_bool($results))
+ $result = array('mintimestamp' => $results->fetchArray()[0]);
+ else
+ $result = array();
+
$data = array_merge($data, $result);
}
if (isset($_GET['getMaxTimestamp']) && $auth)
{
$results = $db->query('SELECT MAX(timestamp) FROM queries');
- $result = array('maxtimestamp' => $results->fetchArray()[0]);
+
+ if(!is_bool($results))
+ $result = array('maxtimestamp' => $results->fetchArray()[0]);
+ else
+ $result = array();
+
$data = array_merge($data, $result);
}
if (isset($_GET['getQueriesCount']) && $auth)
{
$results = $db->query('SELECT COUNT(timestamp) FROM queries');
- $result = array('count' => $results->fetchArray()[0]);
+
+ if(!is_bool($results))
+ $result = array('count' => $results->fetchArray()[0]);
+ else
+ $result = array();
+
$data = array_merge($data, $result);
}
@@ -195,22 +274,28 @@ if (isset($_GET['getGraphData']) && $auth)
}
// Count permitted queries in intervals
- $results = $db->query('SELECT (timestamp/'.$interval.')*'.$interval.' interval, COUNT(*) FROM queries WHERE (status == 2 OR status == 3)'.$limit.' GROUP by interval ORDER by interval');
+ $results = $db->query('SELECT (timestamp/'.$interval.')*'.$interval.' interval, COUNT(*) FROM queries WHERE (status != 0 )'.$limit.' GROUP by interval ORDER by interval');
+
$domains = array();
- while ($row = $results->fetchArray())
- {
- $domains[$row[0]] = intval($row[1]);
- }
+
+ if(!is_bool($results))
+ while ($row = $results->fetchArray())
+ {
+ $domains[$row[0]] = intval($row[1]);
+ }
$result = array('domains_over_time' => $domains);
$data = array_merge($data, $result);
// Count blocked queries in intervals
$results = $db->query('SELECT (timestamp/'.$interval.')*'.$interval.' interval, COUNT(*) FROM queries WHERE (status == 1 OR status == 4 OR status == 5)'.$limit.' GROUP by interval ORDER by interval');
+
$addomains = array();
- while ($row = $results->fetchArray())
- {
- $addomains[$row[0]] = intval($row[1]);
- }
+
+ if(!is_bool($results))
+ while ($row = $results->fetchArray())
+ {
+ $addomains[$row[0]] = intval($row[1]);
+ }
$result = array('ads_over_time' => $addomains);
$data = array_merge($data, $result);
}
diff --git a/db_graph.php b/db_graph.php
index 9dbdba73..2642bf14 100644
--- a/db_graph.php
+++ b/db_graph.php
@@ -22,7 +22,6 @@ $token = $_SESSION['token'];
Compute graphical statistics from the Pi-hole query database
-
@@ -39,6 +38,11 @@ $token = $_SESSION['token'];
+
+
+ Depending on how large of a range you specified, the request may time out while Pi-hole tries to retrieve all the data.
+
+
diff --git a/db_lists.php b/db_lists.php
index 0ddc9dda..c0e39408 100644
--- a/db_lists.php
+++ b/db_lists.php
@@ -39,6 +39,11 @@ $token = $_SESSION['token'];
+
+
+ Depending on how large of a range you specified, the request may time out while Pi-hole tries to retrieve all the data.
+
+
+
+
+ Depending on how large of a range you specified, the request may time out while Pi-hole tries to retrieve all the data.
+
+
diff --git a/queries.php b/queries.php
index c51bc434..8d5a8eb4 100644
--- a/queries.php
+++ b/queries.php
@@ -118,6 +118,7 @@ if(strlen($showing) > 0)
Domain |
Client |
Status |
+ DNSSEC |
Action |
@@ -128,6 +129,7 @@ if(strlen($showing) > 0)
Domain |
Client |
Status |
+ DNSSEC |
Action |
diff --git a/scripts/pi-hole/js/db_graph.js b/scripts/pi-hole/js/db_graph.js
index d543f16b..8da24ad6 100644
--- a/scripts/pi-hole/js/db_graph.js
+++ b/scripts/pi-hole/js/db_graph.js
@@ -14,6 +14,8 @@ var from = moment(start__).utc().valueOf()/1000;
var end__ = moment();
var until = moment(end__).utc().valueOf()/1000;
+var timeoutWarning = $("#timeoutWarning");
+
$(function () {
$("#querytime").daterangepicker(
{
@@ -80,6 +82,7 @@ function compareNumbers(a, b) {
function updateQueriesOverTime() {
$("#queries-over-time .overlay").show();
+ timeoutWarning.show();
$.getJSON("api_db.php?getGraphData&from="+from+"&until="+until, function(data) {
// convert received objects to arrays
@@ -135,6 +138,7 @@ function updateQueriesOverTime() {
timeLineChart.options.scales.xAxes[0].display=true;
$("#queries-over-time .overlay").hide();
+ timeoutWarning.hide();
timeLineChart.update();
});
}
diff --git a/scripts/pi-hole/js/db_lists.js b/scripts/pi-hole/js/db_lists.js
index 75a21746..43e569f7 100644
--- a/scripts/pi-hole/js/db_lists.js
+++ b/scripts/pi-hole/js/db_lists.js
@@ -14,6 +14,9 @@ var from = moment(start__).utc().valueOf()/1000;
var end__ = moment();
var until = moment(end__).utc().valueOf()/1000;
+var timeoutWarning = $("#timeoutWarning");
+var listsStillLoading = 0;
+
$(function () {
$("#querytime").daterangepicker(
{
@@ -97,6 +100,10 @@ function updateTopClientsChart() {
}
$("#client-frequency .overlay").hide();
+
+ listsStillLoading--;
+ if(listsStillLoading === 0)
+ timeoutWarning.hide();
});
}
@@ -135,6 +142,10 @@ function updateTopDomainsChart() {
}
$("#domain-frequency .overlay").hide();
+
+ listsStillLoading--;
+ if(listsStillLoading === 0)
+ timeoutWarning.hide();
});
}
@@ -171,10 +182,16 @@ function updateTopAdsChart() {
}
$("#ad-frequency .overlay").hide();
+
+ listsStillLoading--;
+ if(listsStillLoading === 0)
+ timeoutWarning.hide();
});
}
$("#querytime").on("apply.daterangepicker", function(ev, picker) {
+ timeoutWarning.show();
+ listsStillLoading = 3;
updateTopClientsChart();
updateTopDomainsChart();
updateTopAdsChart();
diff --git a/scripts/pi-hole/js/db_queries.js b/scripts/pi-hole/js/db_queries.js
index 8a47df5c..751081d4 100644
--- a/scripts/pi-hole/js/db_queries.js
+++ b/scripts/pi-hole/js/db_queries.js
@@ -16,6 +16,8 @@ var until = moment(end__).utc().valueOf()/1000;
var instantquery = false;
var daterange;
+var timeoutWarning = $("#timeoutWarning");
+
// Do we want to filter queries?
var GETDict = {};
location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];});
@@ -141,6 +143,7 @@ function handleAjaxError( xhr, textStatus, error ) {
var reloadCallback = function()
{
+ timeoutWarning.hide();
statistics = [0,0,0,0];
var data = tableApi.rows().data();
for (var i = 0; i < data.length; i++) {
@@ -171,6 +174,7 @@ var reloadCallback = function()
};
function refreshTableData() {
+ timeoutWarning.show();
var APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
statistics = [0,0,0];
tableApi.ajax.url(APIstring).load(reloadCallback);
diff --git a/scripts/pi-hole/js/queries.js b/scripts/pi-hole/js/queries.js
index 4c97905e..ef403a6f 100644
--- a/scripts/pi-hole/js/queries.js
+++ b/scripts/pi-hole/js/queries.js
@@ -135,37 +135,66 @@ $(document).ready(function() {
{
$(row).css("color","red");
$("td:eq(4)", row).html( "Pi-holed" );
- $("td:eq(5)", row).html( "" );
+ $("td:eq(6)", row).html( "" );
}
else if (data[4] === "2")
{
$(row).css("color","green");
$("td:eq(4)", row).html( "OK
(forwarded)" );
- $("td:eq(5)", row).html( "" );
+ $("td:eq(6)", row).html( "" );
}
else if (data[4] === "3")
{
$(row).css("color","green");
$("td:eq(4)", row).html( "OK
(cached)" );
- $("td:eq(5)", row).html( "" );
-
+ $("td:eq(6)", row).html( "" );
}
else if (data[4] === "4")
{
$(row).css("color","red");
$("td:eq(4)", row).html( "Pi-holed
(wildcard)" );
- $("td:eq(5)", row).html( "" );
+ $("td:eq(6)", row).html( "" );
}
else if (data[4] === "5")
{
$(row).css("color","red");
$("td:eq(4)", row).html( "Pi-holed
(blacklist)" );
- $("td:eq(5)", row).html( "" );
+ $("td:eq(6)", row).html( "" );
}
else
{
$("td:eq(4)", row).html( "Unknown" );
- $("td:eq(5)", row).html( "" );
+ $("td:eq(6)", row).html( "" );
+ }
+ if (data[5] === "1")
+ {
+ $("td:eq(5)", row).css("color","green");
+ $("td:eq(5)", row).html( "SECURE" );
+ }
+ else if (data[5] === "2")
+ {
+ $("td:eq(5)", row).css("color","orange");
+ $("td:eq(5)", row).html( "INSECURE" );
+ }
+ else if (data[5] === "3")
+ {
+ $("td:eq(5)", row).css("color","red");
+ $("td:eq(5)", row).html( "BOGUS" );
+ }
+ else if (data[5] === "4")
+ {
+ $("td:eq(5)", row).css("color","red");
+ $("td:eq(5)", row).html( "ABANDONED" );
+ }
+ else if (data[5] === "5")
+ {
+ $("td:eq(5)", row).css("color","red");
+ $("td:eq(5)", row).html( "?" );
+ }
+ else
+ {
+ $("td:eq(5)", row).css("color","black");
+ $("td:eq(5)", row).html( "-" );
}
},
dom: "<'row'<'col-sm-12'f>>" +
@@ -179,10 +208,11 @@ $(document).ready(function() {
"columns": [
{ "width" : "15%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(data).format("Y-MM-DD [
]HH:mm:ss z");}else{return data;} }},
{ "width" : "10%" },
- { "width" : "40%", "render": $.fn.dataTable.render.text() },
- { "width" : "20%", "render": $.fn.dataTable.render.text() },
+ { "width" : "37%", "render": $.fn.dataTable.render.text() },
+ { "width" : "8%", "render": $.fn.dataTable.render.text() },
{ "width" : "10%" },
{ "width" : "5%" },
+ { "width" : "10%" }
],
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
"columnDefs": [ {
@@ -195,22 +225,22 @@ $(document).ready(function() {
// Query type IPv4 / IPv6
api.$("td:eq(1)").click( function () { if(autofilter()){ api.search( this.innerHTML ).draw(); $("#resetButton").show(); }});
api.$("td:eq(1)").hover(
- function () { this.title="Click to show only "+this.innerHTML+" queries"; this.style.color="#72afd2" },
- function () { this.style.color="" }
+ function () { this.title="Click to show only "+this.innerHTML+" queries"; this.style.color="#72afd2"; },
+ function () { this.style.color=""; }
);
api.$("td:eq(1)").css("cursor","pointer");
// Domain
api.$("td:eq(2)").click( function () { if(autofilter()){ api.search( this.innerHTML ).draw(); $("#resetButton").show(); }});
api.$("td:eq(2)").hover(
- function () { this.title="Click to show only queries with domain "+this.innerHTML; this.style.color="#72afd2" },
- function () { this.style.color="" }
+ function () { this.title="Click to show only queries with domain "+this.innerHTML; this.style.color="#72afd2"; },
+ function () { this.style.color=""; }
);
api.$("td:eq(2)").css("cursor","pointer");
// Client
api.$("td:eq(3)").click( function () { if(autofilter()){ api.search( this.innerHTML ).draw(); $("#resetButton").show(); }});
api.$("td:eq(3)").hover(
- function () { this.title="Click to show only queries made by "+this.innerHTML; this.style.color="#72afd2" },
- function () { this.style.color="" }
+ function () { this.title="Click to show only queries made by "+this.innerHTML; this.style.color="#72afd2"; },
+ function () { this.style.color=""; }
);
api.$("td:eq(3)").css("cursor","pointer");
}
diff --git a/scripts/pi-hole/php/auth.php b/scripts/pi-hole/php/auth.php
index 85d38f8f..f5032488 100644
--- a/scripts/pi-hole/php/auth.php
+++ b/scripts/pi-hole/php/auth.php
@@ -119,7 +119,7 @@ function check_csrf($token) {
function check_domain() {
if(isset($_POST['domain'])){
- $domains = preg_split('\s+', $_POST['domain']);
+ $domains = preg_split('/\s+/', $_POST['domain']);
foreach($domains as $domain)
{
$validDomain = is_valid_domain_name($domain);
diff --git a/scripts/pi-hole/php/savesettings.php b/scripts/pi-hole/php/savesettings.php
index ad1b0eae..7b67ffed 100644
--- a/scripts/pi-hole/php/savesettings.php
+++ b/scripts/pi-hole/php/savesettings.php
@@ -123,7 +123,7 @@ function isinserverlist($addr) {
"Norton" => ["v4_1" => "199.85.126.10", "v4_2" => "199.85.127.10"],
"Comodo" => ["v4_1" => "8.26.56.26", "v4_2" => "8.20.247.20"],
"DNS.WATCH" => ["v4_1" => "84.200.69.80", "v4_2" => "84.200.70.40", "v6_1" => "2001:1608:10:25:0:0:1c04:b12f", "v6_2" => "2001:1608:10:25:0:0:9249:d69b"],
- "Quad9" => ["v4_1" => "9.9.9.9", "v6_1" => "2620:fe::fe"]
+ "Quad9" => ["v4_1" => "9.9.9.9", "v4_2" => "149.112.112.112", "v6_1" => "2620:fe::fe"]
];
$adlist = [];
@@ -320,9 +320,9 @@ function readAdlists()
$first = true;
foreach($clients as $client)
{
- if(!validDomainWildcard($client))
+ if(!validDomainWildcard($client) && !validIP($client))
{
- $error .= "Top Clients entry ".htmlspecialchars($client)." is invalid (use only IP addresses)!
";
+ $error .= "Top Clients entry ".htmlspecialchars($client)." is invalid (use only host names and IP addresses)!
";
}
if(!$first)
{
diff --git a/scripts/pi-hole/php/teleporter.php b/scripts/pi-hole/php/teleporter.php
index 0427b7c0..9efe7fd1 100644
--- a/scripts/pi-hole/php/teleporter.php
+++ b/scripts/pi-hole/php/teleporter.php
@@ -176,6 +176,7 @@ else
archive_add_file("/etc/pihole/","blacklist.txt");
archive_add_file("/etc/pihole/","adlists.list");
archive_add_file("/etc/pihole/","setupVars.conf");
+ archive_add_file("/etc/pihole/","auditlog.list");
archive_add_directory("/etc/dnsmasq.d/");
$archive["wildcardblocking.txt"] = getWildcardListContent();
diff --git a/scripts/pi-hole/php/update_checker.php b/scripts/pi-hole/php/update_checker.php
index 9bd4ab06..d479318a 100644
--- a/scripts/pi-hole/php/update_checker.php
+++ b/scripts/pi-hole/php/update_checker.php
@@ -44,12 +44,12 @@ else
/********** Get Pi-hole FTL (not a git repository) **********/
$FTL_branch = $branches[2];
- if($FTL_branch !== "master") {
+ if(substr($versions[2], 0, 4) === "vDev") {
$FTL_current = "vDev";
$FTL_commit = $versions[2];
}
else {
- $FTL_current = explode("-",$versions[2])[0];
+ $FTL_current = $versions[2];
}
// Get data from GitHub
diff --git a/settings.php b/settings.php
index a032c9ee..0af4711e 100644
--- a/settings.php
+++ b/settings.php
@@ -288,6 +288,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"