mirror of
https://github.com/pi-hole/web.git
synced 2026-04-24 02:39:25 +01:00
Merge branch 'devel' into devel
This commit is contained in:
@@ -8,51 +8,62 @@
|
||||
|
||||
require_once('auth.php');
|
||||
|
||||
$type = $_POST['list'];
|
||||
$list = $_POST['list'];
|
||||
|
||||
// Perform all of the authentication for list editing
|
||||
// when NOT invoked and authenticated from API
|
||||
if (empty($api)) {
|
||||
list_verify($type);
|
||||
list_verify($list);
|
||||
}
|
||||
|
||||
// Don't check if the added item is a valid domain for regex expressions. Regex
|
||||
// filters are validated by FTL on import and skipped if invalid
|
||||
if($type !== "regex") {
|
||||
// Only check domains we add to the exact lists.
|
||||
// Regex are validated by FTL during import
|
||||
$check_lists = ["white","black","audit"];
|
||||
if(in_array($list, $check_lists)) {
|
||||
check_domain();
|
||||
}
|
||||
|
||||
// Escape shell metacharacters
|
||||
$domains = escapeshellcmd($_POST['domain']);
|
||||
// Split individual domains into array
|
||||
$domains = preg_split('/\s+/', trim($_POST['domain']));
|
||||
|
||||
switch($type) {
|
||||
case "white":
|
||||
if(!isset($_POST["auditlog"]))
|
||||
echo shell_exec("sudo pihole -w --web ".$domains);
|
||||
else
|
||||
{
|
||||
echo shell_exec("sudo pihole -w --web ".$domains);
|
||||
echo shell_exec("sudo pihole -a audit ".$domains);
|
||||
}
|
||||
break;
|
||||
case "black":
|
||||
if(!isset($_POST["auditlog"]))
|
||||
echo shell_exec("sudo pihole -b --web ".$domains);
|
||||
else
|
||||
{
|
||||
echo shell_exec("sudo pihole -b --web ".$domains);
|
||||
echo shell_exec("sudo pihole -a audit ".$domains);
|
||||
}
|
||||
break;
|
||||
case "regex":
|
||||
echo shell_exec("sudo pihole --regex --web ".$domains);
|
||||
break;
|
||||
case "wild":
|
||||
echo shell_exec("sudo pihole --wild --web ".$domains);
|
||||
break;
|
||||
case "audit":
|
||||
echo shell_exec("sudo pihole -a audit ".$domains);
|
||||
break;
|
||||
require_once("func.php");
|
||||
require_once("database.php");
|
||||
$GRAVITYDB = getGravityDBFilename();
|
||||
$db = SQLite3_connect($GRAVITYDB, SQLITE3_OPEN_READWRITE);
|
||||
|
||||
switch($list) {
|
||||
case "white":
|
||||
echo add_to_table($db, "whitelist", $domains);
|
||||
break;
|
||||
|
||||
case "black":
|
||||
echo add_to_table($db, "blacklist", $domains);
|
||||
break;
|
||||
|
||||
case "black_regex":
|
||||
echo add_to_table($db, "regex_blacklist", $domains);
|
||||
break;
|
||||
|
||||
case "white_regex":
|
||||
echo add_to_table($db, "regex_whitelist", $domains);
|
||||
break;
|
||||
|
||||
case "black_wild":
|
||||
echo add_to_table($db, "regex_blacklist", $domains, true);
|
||||
break;
|
||||
|
||||
case "white_wild":
|
||||
echo add_to_table($db, "regex_whitelist", $domains, true);
|
||||
break;
|
||||
|
||||
case "audit":
|
||||
echo add_to_table($db, "domain_audit", $domains);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Invalid list!");
|
||||
}
|
||||
|
||||
// Reload lists in pihole-FTL after having added something
|
||||
echo shell_exec("sudo pihole restartdns reload");
|
||||
?>
|
||||
|
||||
@@ -11,7 +11,6 @@ $ERRORLOG = getenv('PHP_ERROR_LOG');
|
||||
if (empty($ERRORLOG)) {
|
||||
$ERRORLOG = '/var/log/lighttpd/error.log';
|
||||
}
|
||||
$regexfile = "/etc/pihole/regex.list";
|
||||
|
||||
function pi_log($message) {
|
||||
error_log(date('Y-m-d H:i:s') . ': ' . $message . "\n", 3, $GLOBALS['ERRORLOG']);
|
||||
|
||||
@@ -33,7 +33,13 @@ function SQLite3_connect_try($filename, $mode, $trytoreconnect)
|
||||
if($trytoreconnect)
|
||||
{
|
||||
sleep(3);
|
||||
$db = SQLite3_connect_try($filename, $mode, false);
|
||||
return SQLite3_connect_try($filename, $mode, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we should not try again (or are already trying again!), we return the exception string
|
||||
// so the user gets it on the dashboard
|
||||
return $filename.": ".$exception->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,10 +54,184 @@ function SQLite3_connect($filename, $mode=SQLITE3_OPEN_READONLY)
|
||||
{
|
||||
die("No database available");
|
||||
}
|
||||
if(!$db)
|
||||
if(is_string($db))
|
||||
{
|
||||
die("Error connecting to database");
|
||||
die("Error connecting to database\n".$db);
|
||||
}
|
||||
|
||||
// Add busy timeout so methods don't fail immediately when, e.g., FTL is currently reading from the DB
|
||||
$db->busyTimeout(5000);
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add domains to a given table
|
||||
*
|
||||
* @param $db object The SQLite3 database connection object
|
||||
* @param $table string The target table
|
||||
* @param $domains array Array of domains (strings) to be added to the table
|
||||
* @param $wildcardstyle boolean Whether to format the input domains in legacy wildcard notation
|
||||
* @param $returnnum boolean Whether to return an integer or a string
|
||||
* @return string Success/error and number of processed domains
|
||||
*/
|
||||
function add_to_table($db, $table, $domains, $wildcardstyle=false, $returnnum=false)
|
||||
{
|
||||
// Begin transaction
|
||||
if(!$db->exec("BEGIN TRANSACTION;"))
|
||||
{
|
||||
if($returnnum)
|
||||
return 0;
|
||||
else
|
||||
return "Error: Unable to begin transaction for ".$table." table.";
|
||||
}
|
||||
$initialcount = intval($db->querySingle("SELECT COUNT(*) FROM ".$table.";"));
|
||||
|
||||
// Prepare SQLite statememt
|
||||
$stmt = $db->prepare("INSERT OR IGNORE INTO ".$table." (domain) VALUES (:domain);");
|
||||
|
||||
// Return early if we failed to prepare the SQLite statement
|
||||
if(!$stmt)
|
||||
{
|
||||
if($returnnum)
|
||||
return 0;
|
||||
else
|
||||
return "Error: Failed to prepare statement for ".$table." table.";
|
||||
}
|
||||
|
||||
// Loop over domains and inject the lines into the database
|
||||
$num = 0;
|
||||
foreach($domains as $domain)
|
||||
{
|
||||
// Limit max length for a domain entry to 253 chars
|
||||
if(strlen($domain) > 253)
|
||||
continue;
|
||||
|
||||
if($wildcardstyle)
|
||||
$domain = "(\\.|^)".str_replace(".","\\.",$domain)."$";
|
||||
|
||||
$stmt->bindValue(":domain", $domain, SQLITE3_TEXT);
|
||||
|
||||
if($stmt->execute() && $stmt->reset())
|
||||
$num++;
|
||||
else
|
||||
{
|
||||
$stmt->close();
|
||||
if($returnnum)
|
||||
return $num;
|
||||
else
|
||||
{
|
||||
if($num === 1)
|
||||
$plural = "";
|
||||
else
|
||||
$plural = "s";
|
||||
return "Error: ".$db->lastErrorMsg().", added ".$num." domain".$plural;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close prepared statement and return number of processed rows
|
||||
$stmt->close();
|
||||
$db->exec("COMMIT;");
|
||||
|
||||
if($returnnum)
|
||||
return $num;
|
||||
else
|
||||
{
|
||||
$finalcount = intval($db->querySingle("SELECT COUNT(*) FROM ".$table.";"));
|
||||
$modified = $finalcount - $initialcount;
|
||||
|
||||
// If we add less domains than the user specified, then they wanted to add duplicates
|
||||
if($modified !== $num)
|
||||
{
|
||||
$delta = $num - $modified;
|
||||
$extra = " (skipped ".$delta." duplicates)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$extra = "";
|
||||
}
|
||||
|
||||
if($num === 1)
|
||||
$plural = "";
|
||||
else
|
||||
$plural = "s";
|
||||
return "Success, added ".$modified." of ".$num." domain".$plural.$extra;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove domains from a given table
|
||||
*
|
||||
* @param $db object The SQLite3 database connection object
|
||||
* @param $table string The target table
|
||||
* @param $domains array Array of domains (strings) to be removed from the table
|
||||
* @param $returnnum boolean Whether to return an integer or a string
|
||||
* @return string Success/error and number of processed domains
|
||||
*/
|
||||
function remove_from_table($db, $table, $domains, $returnnum=false)
|
||||
{
|
||||
// Begin transaction
|
||||
if(!$db->exec("BEGIN TRANSACTION;"))
|
||||
{
|
||||
if($returnnum)
|
||||
return 0;
|
||||
else
|
||||
return "Error: Unable to begin transaction for ".$table." table.";
|
||||
}
|
||||
$initialcount = intval($db->querySingle("SELECT COUNT(*) FROM ".$table.";"));
|
||||
|
||||
// Prepare SQLite statememt
|
||||
$stmt = $db->prepare("DELETE FROM ".$table." WHERE domain = :domain;");
|
||||
|
||||
// Return early if we failed to prepare the SQLite statement
|
||||
if(!$stmt)
|
||||
{
|
||||
if($returnnum)
|
||||
return 0;
|
||||
else
|
||||
return "Error: Failed to prepare statement for ".$table." table.";
|
||||
}
|
||||
|
||||
// Loop over domains and remove the lines from the database
|
||||
$num = 0;
|
||||
foreach($domains as $domain)
|
||||
{
|
||||
$stmt->bindValue(":domain", $domain, SQLITE3_TEXT);
|
||||
|
||||
if($stmt->execute() && $stmt->reset())
|
||||
$num++;
|
||||
else
|
||||
{
|
||||
$stmt->close();
|
||||
if($returnnum)
|
||||
return $num;
|
||||
else
|
||||
{
|
||||
if($num === 1)
|
||||
$plural = "";
|
||||
else
|
||||
$plural = "s";
|
||||
return "Error: ".$db->lastErrorMsg().", removed ".$num." domain".$plural;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close prepared statement and return number or processed rows
|
||||
$stmt->close();
|
||||
$db->exec("COMMIT;");
|
||||
|
||||
if($returnnum)
|
||||
return $num;
|
||||
else
|
||||
{
|
||||
if($num === 1)
|
||||
$plural = "";
|
||||
else
|
||||
$plural = "s";
|
||||
return "Success, removed ".$num." domain".$plural;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -45,21 +45,4 @@ if(!function_exists('hash_equals')) {
|
||||
}
|
||||
}
|
||||
|
||||
function add_regex($regex, $mode=FILE_APPEND, $append="\n")
|
||||
{
|
||||
global $regexfile;
|
||||
if(file_put_contents($regexfile, $regex.$append, $mode) === FALSE)
|
||||
{
|
||||
$err = error_get_last()["message"];
|
||||
echo "Unable to add regex \"".htmlspecialchars($regex)."\" to ${regexfile}<br>Error message: $err";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send SIGHUP to pihole-FTL using a frontend command
|
||||
// to force reloading of the regex domains
|
||||
// This will also wipe the resolver's cache
|
||||
echo exec("sudo pihole restartdns reload");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -21,7 +21,7 @@ function getTableContent($listname) {
|
||||
global $db;
|
||||
$entries = array();
|
||||
$querystr = implode(" ",array("SELECT ${listname}.*,\"group\".enabled as group_enabled",
|
||||
"FROM $listname",
|
||||
"FROM ${listname}",
|
||||
"LEFT JOIN ${listname}_by_group ON ${listname}_by_group.${listname}_id = ${listname}.id",
|
||||
"LEFT JOIN \"group\" ON \"group\".id = ${listname}_by_group.group_id",
|
||||
"GROUP BY domain;"));
|
||||
@@ -54,13 +54,15 @@ function filterArray(&$inArray) {
|
||||
switch ($listtype)
|
||||
{
|
||||
case "white":
|
||||
$list = getTableContent("whitelist");
|
||||
$exact = getTableContent("whitelist");
|
||||
$regex = getTableContent("regex_whitelist");
|
||||
$list = array_merge($exact, $regex);
|
||||
break;
|
||||
|
||||
case "black":
|
||||
$exact = getTableContent("blacklist");
|
||||
$regex = getTableContent("regex");
|
||||
$list = array_merge($exact, $regex);
|
||||
$regex = getTableContent("regex_blacklist");
|
||||
$list = array_merge($exact, $regex);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,51 +1,59 @@
|
||||
<?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. */
|
||||
|
||||
function gravity_last_update($raw = false){
|
||||
/*
|
||||
@walter-exit <walter@exclusive-it.nl> | April 23rd, 2018:
|
||||
Checks when the gravity list was last updated, if it exists at all.
|
||||
Returns the info in human-readable format for use on the dashboard,
|
||||
or raw for use by the API.
|
||||
*/
|
||||
$gravitylist = "/etc/pihole/gravity.list";
|
||||
if (file_exists($gravitylist)){
|
||||
$date_file_created_unix = filemtime($gravitylist);
|
||||
$date_file_created = date_create("@".$date_file_created_unix);
|
||||
$date_now = date_create("now");
|
||||
$gravitydiff = date_diff($date_file_created,$date_now);
|
||||
if($raw){
|
||||
$output = array(
|
||||
"file_exists"=> true,
|
||||
"absolute" => $date_file_created_unix,
|
||||
"relative" => array(
|
||||
"days" => $gravitydiff->format("%a"),
|
||||
"hours" => $gravitydiff->format("%H"),
|
||||
"minutes" => $gravitydiff->format("%I"),
|
||||
)
|
||||
);
|
||||
}else{
|
||||
if($gravitydiff->d > 1){
|
||||
$output = $gravitydiff->format("Blocking list updated %a days, %H:%I ago");
|
||||
}elseif($gravitydiff->d == 1){
|
||||
$output = $gravitydiff->format("Blocking list updated one day, %H:%I ago");
|
||||
}else{
|
||||
$output = $gravitydiff->format("Blocking list updated %H:%I ago");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if($raw){
|
||||
$output = array("file_exists"=>false);
|
||||
}else{
|
||||
$output = "Blocking list not found";
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
?>
|
||||
<?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/database.php";
|
||||
|
||||
function gravity_last_update($raw = false)
|
||||
{
|
||||
$db = SQLite3_connect(getGravityDBFilename());
|
||||
$date_file_created_unix = $db->querySingle("SELECT value FROM info WHERE property = 'updated';");
|
||||
if($date_file_created_unix === false)
|
||||
{
|
||||
if($raw)
|
||||
{
|
||||
// Array output
|
||||
return array("file_exists" => false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// String output
|
||||
return "Gravity database not available";
|
||||
}
|
||||
}
|
||||
$date_file_created = date_create("@".intval($date_file_created_unix));
|
||||
$date_now = date_create("now");
|
||||
$gravitydiff = date_diff($date_file_created,$date_now);
|
||||
if($raw)
|
||||
{
|
||||
// Array output
|
||||
return array(
|
||||
"file_exists"=> true,
|
||||
"absolute" => $date_file_created_unix,
|
||||
"relative" => array(
|
||||
"days" => $gravitydiff->format("%a"),
|
||||
"hours" => $gravitydiff->format("%H"),
|
||||
"minutes" => $gravitydiff->format("%I"),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if($gravitydiff->d > 1)
|
||||
{
|
||||
// String output (more than one day ago)
|
||||
return $gravitydiff->format("Blocking list updated %a days, %H:%I (hh:mm) ago");
|
||||
}
|
||||
elseif($gravitydiff->d == 1)
|
||||
{
|
||||
// String output (one day ago)
|
||||
return $gravitydiff->format("Blocking list updated one day, %H:%I (hh:mm) ago");
|
||||
}
|
||||
|
||||
// String output (less than one day ago)
|
||||
return $gravitydiff->format("Blocking list updated %H:%I (hh:mm) ago");
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -60,6 +60,15 @@
|
||||
{
|
||||
$temperatureunit = $_POST["tempunit"];
|
||||
}
|
||||
// Get user-defined temperature limit if set
|
||||
if(isset($setupVars['TEMPERATURE_LIMIT']))
|
||||
{
|
||||
$temperaturelimit = intval($setupVars['TEMPERATURE_LIMIT']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$temperaturelimit = 60;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -339,7 +348,7 @@ if($auth) {
|
||||
{
|
||||
if ($celsius >= -273.15) {
|
||||
echo "<a id=\"temperature\"><i class=\"fa fa-fire\" style=\"color:";
|
||||
if ($celsius > 60) {
|
||||
if ($celsius > $temperaturelimit) {
|
||||
echo "#FF0000";
|
||||
}
|
||||
else
|
||||
|
||||
@@ -16,25 +16,36 @@ if (empty($api)) {
|
||||
list_verify($type);
|
||||
}
|
||||
|
||||
// Don't check if the added item is a valid domain for regex expressions.
|
||||
// Regex filters are validated by FTL on import and skipped if invalid
|
||||
if($type !== "regex") {
|
||||
check_domain();
|
||||
}
|
||||
// Split individual domains into array
|
||||
$domains = preg_split('/\s+/', trim($_POST['domain']));
|
||||
|
||||
// Escape shell metacharacters
|
||||
$domain = escapeshellcmd($_POST['domain']);
|
||||
require_once("func.php");
|
||||
|
||||
require("database.php");
|
||||
$GRAVITYDB = getGravityDBFilename();
|
||||
$db = SQLite3_connect($GRAVITYDB, SQLITE3_OPEN_READWRITE);
|
||||
|
||||
switch($type) {
|
||||
case "white":
|
||||
exec("sudo pihole -w -q -d ".$domain);
|
||||
break;
|
||||
case "black":
|
||||
exec("sudo pihole -b -q -d ".$domain);
|
||||
break;
|
||||
case "regex":
|
||||
exec("sudo pihole --regex -q -d ".$domain);
|
||||
break;
|
||||
case "white":
|
||||
echo remove_from_table($db, "whitelist", $domains);
|
||||
break;
|
||||
|
||||
case "black":
|
||||
echo remove_from_table($db, "blacklist", $domains);
|
||||
break;
|
||||
|
||||
case "black_regex":
|
||||
echo remove_from_table($db, "regex_blacklist", $domains);
|
||||
break;
|
||||
|
||||
case "white_regex":
|
||||
echo remove_from_table($db, "regex_whitelist", $domains);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Invalid list!");
|
||||
}
|
||||
|
||||
// Reload lists in pihole-FTL after having removed something
|
||||
echo shell_exec("sudo pihole restartdns reload");
|
||||
?>
|
||||
|
||||
@@ -16,7 +16,9 @@ if (php_sapi_name() !== "cli") {
|
||||
check_csrf(isset($_POST["token"]) ? $_POST["token"] : "");
|
||||
}
|
||||
|
||||
$db = SQLite3_connect(getGravityDBFilename());
|
||||
$db = SQLite3_connect(getGravityDBFilename(), SQLITE3_OPEN_READWRITE);
|
||||
|
||||
$flushed_tables = array();
|
||||
|
||||
function archive_add_file($path,$name,$subdir="")
|
||||
{
|
||||
@@ -30,23 +32,158 @@ function archive_add_file($path,$name,$subdir="")
|
||||
*
|
||||
* @param $name string The name of the file in the archive to save the table to
|
||||
* @param $table string The table to export
|
||||
* @param $column string The column on the table to export
|
||||
*/
|
||||
function archive_add_table($name, $table, $column)
|
||||
function archive_add_table($name, $table)
|
||||
{
|
||||
global $archive, $db;
|
||||
|
||||
$results = $db->query("SELECT $column FROM $table");
|
||||
$content = "";
|
||||
$results = $db->query("SELECT * FROM $table");
|
||||
|
||||
while($row = $results->fetchArray()) {
|
||||
$content .= $row[0]."\n";
|
||||
// Return early without creating a file if the
|
||||
// requested table cannot be accessed
|
||||
if(is_null($results))
|
||||
return;
|
||||
|
||||
$content = array();
|
||||
while ($row = $results->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
array_push($content, $row);
|
||||
}
|
||||
|
||||
$archive[$name] = $content;
|
||||
$archive[$name] = json_encode($content);
|
||||
}
|
||||
|
||||
function archive_add_directory($path, $subdir="")
|
||||
|
||||
/**
|
||||
* Restore the contents of a table from an uploaded archive
|
||||
*
|
||||
* @param $file object The file in the archive to restore the table from
|
||||
* @param $table string The table to import
|
||||
* @param $flush boolean Whether to flush the table before importing the archived data
|
||||
* @return integer Number of restored rows
|
||||
*/
|
||||
function archive_restore_table($file, $table, $flush=false)
|
||||
{
|
||||
global $db, $flushed_tables;
|
||||
|
||||
$json_string = file_get_contents($file);
|
||||
// Return early if we cannot extract the JSON string
|
||||
if(is_null($json_string))
|
||||
return 0;
|
||||
|
||||
$contents = json_decode($json_string, true);
|
||||
// Return early if we cannot decode the JSON string
|
||||
if(is_null($contents))
|
||||
return 0;
|
||||
|
||||
// Flush table if requested, only flush each table once
|
||||
if($flush && !in_array($table, $flushed_tables))
|
||||
{
|
||||
$db->exec("DELETE FROM ".$table);
|
||||
array_push($flushed_tables, $table);
|
||||
}
|
||||
|
||||
// Prepare field name for domain/address depending on the table we restore to
|
||||
if($table === "adlist")
|
||||
{
|
||||
$sql = "INSERT OR IGNORE INTO adlist";
|
||||
$sql .= " (id,address,enabled,date_added,comment)";
|
||||
$sql .= " VALUES (:id,:address,:enabled,:date_added,:comment);";
|
||||
$field = "address";
|
||||
}
|
||||
elseif($table === "domain_audit")
|
||||
{
|
||||
$sql = "INSERT OR IGNORE INTO domain_audit";
|
||||
$sql .= " (id,domain,date_added)";
|
||||
$sql .= " VALUES (:id,:domain,:date_added);";
|
||||
$field = "domain";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = "INSERT OR IGNORE INTO ".$table;
|
||||
$sql .= " (id,domain,enabled,date_added,comment)";
|
||||
$sql .= " VALUES (:id,:domain,:enabled,:date_added,:comment);";
|
||||
$field = "domain";
|
||||
}
|
||||
|
||||
// Prepare SQLite statememt
|
||||
$stmt = $db->prepare($sql);
|
||||
|
||||
// Return early if we fail to prepare the SQLite statement
|
||||
if(!$stmt)
|
||||
{
|
||||
echo "Failed to prepare statement for ".$table." table.";
|
||||
echo $sql;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Loop over rows and inject the entries into the database
|
||||
$num = 0;
|
||||
foreach($contents as $row)
|
||||
{
|
||||
// Limit max length for a domain entry to 253 chars
|
||||
if(strlen($row[$field]) > 253)
|
||||
continue;
|
||||
|
||||
$stmt->bindValue(":id", $row["id"], SQLITE3_INTEGER);
|
||||
$stmt->bindValue(":date_added", $row["date_added"], SQLITE3_INTEGER);
|
||||
$stmt->bindValue(":".$field, $row[$field], SQLITE3_TEXT);
|
||||
|
||||
if($table !== "domain_audit")
|
||||
{
|
||||
$stmt->bindValue(":enabled", $row["enabled"], SQLITE3_INTEGER);
|
||||
if(is_null($row["comment"]))
|
||||
$type = SQLITE3_NULL;
|
||||
else
|
||||
$type = SQLITE3_TEXT;
|
||||
$stmt->bindValue(":comment", $row["comment"], $type);
|
||||
}
|
||||
|
||||
if($stmt->execute() && $stmt->reset() && $stmt->clear())
|
||||
$num++;
|
||||
else
|
||||
{
|
||||
$stmt->close();
|
||||
return $num;
|
||||
}
|
||||
}
|
||||
|
||||
// Close database connection and return number or processed rows
|
||||
$stmt->close();
|
||||
return $num;
|
||||
}
|
||||
|
||||
=======
|
||||
/**
|
||||
* Create table rows from an uploaded archive file
|
||||
*
|
||||
* @param $file object The file of the file in the archive to import
|
||||
* @param $table string The target table
|
||||
* @param $flush boolean Whether to flush the table before importing the archived data
|
||||
* @param $wildcardstyle boolean Whether to format the input domains in legacy wildcard notation
|
||||
* @return integer Number of processed rows from the imported file
|
||||
*/
|
||||
function archive_insert_into_table($file, $table, $flush=false, $wildcardstyle=false)
|
||||
{
|
||||
global $db, $flushed_tables;
|
||||
|
||||
$domains = array_filter(explode("\n",file_get_contents($file)));
|
||||
// Return early if we cannot extract the lines in the file
|
||||
if(is_null($domains))
|
||||
return 0;
|
||||
|
||||
// Flush table if requested, only flush each table once
|
||||
if($flush && !in_array($table, $flushed_tables))
|
||||
{
|
||||
$db->exec("DELETE FROM ".$table);
|
||||
array_push($flushed_tables, $table);
|
||||
}
|
||||
|
||||
// Add domains to requested table
|
||||
return add_to_table($db, $table, $domains, $wildcardstyle, true);
|
||||
}
|
||||
|
||||
function archive_add_directory($path,$subdir="")
|
||||
{
|
||||
if($dir = opendir($path))
|
||||
{
|
||||
@@ -54,47 +191,13 @@ function archive_add_directory($path, $subdir="")
|
||||
{
|
||||
if($entry !== "." && $entry !== "..")
|
||||
{
|
||||
archive_add_file($path, $entry, $subdir);
|
||||
archive_add_file($path,$entry,$subdir);
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
}
|
||||
}
|
||||
|
||||
function limit_length(&$item, $key)
|
||||
{
|
||||
// limit max length for a domain entry to 253 chars
|
||||
// return only a part of the string if it is longer
|
||||
$item = substr($item, 0, 253);
|
||||
}
|
||||
|
||||
function process_file($contents, $check=True)
|
||||
{
|
||||
$domains = array_filter(explode("\n", $contents));
|
||||
|
||||
// Walk array and apply a max string length
|
||||
// function to every member of the array of domains
|
||||
array_walk($domains, "limit_length");
|
||||
|
||||
// Check validity of domains (don't do it for regex filters)
|
||||
if($check)
|
||||
{
|
||||
check_domains($domains);
|
||||
}
|
||||
|
||||
return $domains;
|
||||
}
|
||||
|
||||
function check_domains($domains)
|
||||
{
|
||||
foreach($domains as $domain)
|
||||
{
|
||||
if(!is_valid_domain_name($domain)){
|
||||
die(htmlspecialchars($domain).' is not a valid domain');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_POST["action"]))
|
||||
{
|
||||
if($_FILES["zip_file"]["name"] && $_POST["action"] == "in")
|
||||
@@ -128,74 +231,92 @@ if(isset($_POST["action"]))
|
||||
|
||||
$importedsomething = false;
|
||||
|
||||
foreach(new RecursiveIteratorIterator($archive) as $file)
|
||||
$flushtables = isset($_POST["flushtables"]);
|
||||
|
||||
foreach($archive as $file)
|
||||
{
|
||||
if(isset($_POST["blacklist"]) && $file->getFilename() === "blacklist.txt")
|
||||
{
|
||||
$blacklist = process_file(file_get_contents($file));
|
||||
echo "Processing blacklist.txt (".count($blacklist)." entries)<br>\n";
|
||||
exec("sudo pihole -b -nr --nuke");
|
||||
exec("sudo pihole -b -q -nr ".implode(" ", $blacklist));
|
||||
$num = archive_insert_into_table($file, "blacklist", $flushtables);
|
||||
echo "Processed blacklist (exact) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["whitelist"]) && $file->getFilename() === "whitelist.txt")
|
||||
{
|
||||
$whitelist = process_file(file_get_contents($file));
|
||||
echo "Processing whitelist.txt (".count($whitelist)." entries)<br>\n";
|
||||
exec("sudo pihole -w -nr --nuke");
|
||||
exec("sudo pihole -w -q -nr ".implode(" ", $whitelist));
|
||||
$num = archive_insert_into_table($file, "whitelist", $flushtables);
|
||||
echo "Processed whitelist (exact) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["regexlist"]) && $file->getFilename() === "regex.list")
|
||||
{
|
||||
$regexlist = process_file(file_get_contents($file), false);
|
||||
echo "Processing regex.list (".count($regexlist)." entries)<br>\n";
|
||||
|
||||
$escapedRegexlist = array_map("escapeshellcmd", $regexlist);
|
||||
exec("sudo pihole --regex -nr --nuke");
|
||||
exec("sudo pihole --regex -q -nr ".implode(" ", $escapedRegexlist));
|
||||
$num = archive_insert_into_table($file, "regex_blacklist", $flushtables);
|
||||
echo "Processed blacklist (regex) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
// Also try to import legacy wildcard list if found
|
||||
if(isset($_POST["regexlist"]) && $file->getFilename() === "wildcardblocking.txt")
|
||||
{
|
||||
$wildlist = process_file(file_get_contents($file));
|
||||
echo "Processing wildcardblocking.txt (".count($wildlist)." entries)<br>\n";
|
||||
exec("sudo pihole --wild -nr --nuke");
|
||||
exec("sudo pihole --wild -q -nr ".implode(" ", $wildlist));
|
||||
$num = archive_insert_into_table($file, "regex_blacklist", $flushtables, true);
|
||||
echo "Processed blacklist (regex, wildcard style) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["auditlog"]) && $file->getFilename() === "auditlog.list")
|
||||
{
|
||||
$auditlog = process_file(file_get_contents($file));
|
||||
echo "Processing auditlog.list (".count($auditlog)." entries)<br>\n";
|
||||
exec("sudo pihole -a clearaudit");
|
||||
exec("sudo pihole -a audit ".implode(" ",$auditlog));
|
||||
}
|
||||
|
||||
if(isset($_POST["dhcpleases"]) && $file->getFilename() === "04-pihole-static-dhcp.conf")
|
||||
{
|
||||
$dhcpleases = processStaticLeasesFile($file->getPathname());
|
||||
echo "Processing DHCP leases 04-pihole-static-dhcp.conf (".count($dhcpleases)." entries)";
|
||||
$counter_leases_added = 0;
|
||||
foreach($dhcpleases as $lease) {
|
||||
$result = addDHCPLease($lease["hwaddr"], $lease["IP"], $lease["host"]);
|
||||
if($result['value']) {
|
||||
$counter_leases_added++;
|
||||
}
|
||||
}
|
||||
echo " - Added ".$counter_leases_added."/".count($dhcpleases)."<br>\n";
|
||||
$num = archive_insert_into_table($file, "domain_audit", $flushtables);
|
||||
echo "Processed blacklist (regex) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if($importedsomething)
|
||||
if(isset($_POST["blacklist"]) && $file->getFilename() === "blacklist.exact.json")
|
||||
{
|
||||
exec("sudo pihole restartdns");
|
||||
$num = archive_restore_table($file, "blacklist", $flushtables);
|
||||
echo "Processed blacklist (exact) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["regexlist"]) && $file->getFilename() === "blacklist.regex.json")
|
||||
{
|
||||
$num = archive_restore_table($file, "regex_blacklist", $flushtables);
|
||||
echo "Processed blacklist (regex) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["whitelist"]) && $file->getFilename() === "whitelist.exact.json")
|
||||
{
|
||||
$num = archive_restore_table($file, "whitelist", $flushtables);
|
||||
echo "Processed whitelist (exact) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["regex_whitelist"]) && $file->getFilename() === "whitelist.regex.json")
|
||||
{
|
||||
$num = archive_restore_table($file, "regex_whitelist", $flushtables);
|
||||
echo "Processed whitelist (regex) (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["adlist"]) && $file->getFilename() === "adlist.json")
|
||||
{
|
||||
$num = archive_restore_table($file, "adlist", $flushtables);
|
||||
echo "Processed adlist (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
|
||||
if(isset($_POST["auditlog"]) && $file->getFilename() === "domain_audit.json")
|
||||
{
|
||||
$num = archive_restore_table($file, "domain_audit", $flushtables);
|
||||
echo "Processed domain_audit (".$num." entries)<br>\n";
|
||||
$importedsomething = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($importedsomething)
|
||||
{
|
||||
exec("sudo pihole restartdns reload");
|
||||
}
|
||||
|
||||
unlink($fullfilename);
|
||||
@@ -217,12 +338,13 @@ else
|
||||
exit("cannot open/create ".htmlentities($archive_file_name)."<br>\nPHP user: ".exec('whoami')."\n");
|
||||
}
|
||||
|
||||
archive_add_table("whitelist.txt", "whitelist", "domain");
|
||||
archive_add_table("blacklist.txt", "blacklist", "domain");
|
||||
archive_add_table("regex.list", "regex", "domain");
|
||||
archive_add_table("adlists.list", "adlist", "address");
|
||||
archive_add_table("whitelist.exact.json", "whitelist");
|
||||
archive_add_table("whitelist.regex.json", "regex_whitelist");
|
||||
archive_add_table("blacklist.exact.json", "blacklist");
|
||||
archive_add_table("blacklist.regex.json", "regex_blacklist");
|
||||
archive_add_table("adlist.json", "adlist");
|
||||
archive_add_table("domain_audit.json", "domain_audit");
|
||||
archive_add_file("/etc/pihole/","setupVars.conf");
|
||||
archive_add_file("/etc/pihole/","auditlog.list");
|
||||
archive_add_directory("/etc/dnsmasq.d/","dnsmasq.d/");
|
||||
|
||||
$archive->compress(Phar::GZ); // Creates a gziped copy
|
||||
|
||||
Reference in New Issue
Block a user