Merge branch 'devel' into customizeadlists

This commit is contained in:
DL6ER
2016-12-30 20:43:07 +00:00
86 changed files with 336 additions and 214 deletions

View File

@@ -0,0 +1,18 @@
<?php
require('auth.php');
$type = $_POST['list'];
// All of the verification for list editing
list_verify($type);
switch($type) {
case "white":
echo exec("sudo pihole -w -q ${_POST['domain']}");
break;
case "black":
echo exec("sudo pihole -b -q ${_POST['domain']}");
break;
}
?>

View File

@@ -0,0 +1,137 @@
<?php
require('func.php');
$ERRORLOG = getenv('PHP_ERROR_LOG');
if (empty($ERRORLOG)) {
$ERRORLOG = '/var/log/lighttpd/error.log';
}
function pi_log($message) {
error_log(date('Y-m-d H:i:s') . ': ' . $message . "\n", 3, $GLOBALS['ERRORLOG']);
}
function log_and_die($message) {
pi_log($message);
die($message);
}
function check_cors() {
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
$ipv4 = isset($setupVars["IPV4_ADDRESS"]) ? explode("/", $setupVars["IPV4_ADDRESS"])[0] : $_SERVER['SERVER_ADDR'];
// Check CORS
$AUTHORIZED_HOSTNAMES = array(
$ipv4,
$_SERVER["SERVER_NAME"],
"pi.hole",
"localhost"
);
# Allow user set virtual hostnames
$virtual_host = getenv('VIRTUAL_HOST');
if (! empty($virtual_host))
array_push($AUTHORIZED_HOSTNAMES, $virtual_host);
// Since the Host header is easily manipulated, we can only check if it's wrong and can't use it
// to validate that the client is authorized, only unauthorized.
$server_host = $_SERVER['HTTP_HOST'];
// If HTTP_HOST contains a non-standard port (!= 80) we have to strip the port
if(strpos($server_host, ":"))
{
$server_host = parse_url($_SERVER['HTTP_HOST'], PHP_URL_HOST);
}
if(isset($_SERVER['HTTP_HOST']) && !in_array($server_host, $AUTHORIZED_HOSTNAMES)) {
log_and_die("Failed Host Check: " . $server_host .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
}
if(isset($_SERVER['HTTP_ORIGIN'])) {
$server_origin = $_SERVER['HTTP_ORIGIN'];
// If HTTP_ORIGIN contains a non-standard port (!= 80) we have to strip the port
if(strpos($server_origin, ":"))
{
$server_origin = parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
}
if(!in_array($server_origin, $AUTHORIZED_HOSTNAMES)) {
log_and_die("Failed CORS: " . $server_origin .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
}
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}");
}
// If there's no HTTP_ORIGIN, CORS should not be used
}
function check_csrf($token) {
// Check CSRF token
$session_started = function_exists("session_status") ?
session_status() == PHP_SESSION_ACTIVE :
session_id() == "";
if(!$session_started) {
session_start();
}
// Credit: http://php.net/manual/en/function.hash-equals.php#119576
if(!function_exists('hash_equals')) {
function hash_equals($known_string, $user_string) {
$ret = 0;
if (strlen($known_string) !== strlen($user_string)) {
$user_string = $known_string;
$ret = 1;
}
$res = $known_string ^ $user_string;
for ($i = strlen($res) - 1; $i >= 0; --$i) {
$ret |= ord($res[$i]);
}
return !$ret;
}
}
if(!isset($_SESSION['token']) || empty($token) || !hash_equals($_SESSION['token'], $token)) {
log_and_die("Wrong token");
}
}
function check_domain() {
if(isset($_POST['domain'])){
$validDomain = is_valid_domain_name($_POST['domain']);
if(!$validDomain){
log_and_die($_POST['domain']. ' is not a valid domain');
}
}
}
function list_verify($type) {
if(!isset($_POST['domain']) || !isset($_POST['list']) || !(isset($_POST['pw']) || isset($_POST['token']))) {
log_and_die("Missing POST variables");
}
if(isset($_POST['token']))
{
check_cors();
check_csrf($_POST['token']);
}
elseif(isset($_POST['pw']))
{
require("password.php");
if(strlen($pwhash) == 0)
{
log_and_die("No password set - ${type}listing with password not supported");
}
elseif($wrongpassword)
{
log_and_die("Wrong password - ${type}listing of ${_POST['domain']} not permitted");
}
}
else
{
log_and_die("Not allowed!");
}
check_domain();
}
?>

View File

@@ -0,0 +1,624 @@
<?php
$log = array();
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
$hosts = file_exists("/etc/hosts") ? file("/etc/hosts") : array();
// Check if pihole.log exists and is readable
$logListName = checkfile("/var/log/pihole.log");
$log = new \SplFileObject($logListName);
// Check if preEventHorizon exists and is readable
$gravityListName = checkfile("/etc/pihole/list.preEventHorizon");
$gravity = new \SplFileObject($gravityListName);
// whitelist.txt is optional and might not be there
$whiteListFile = checkfile("/etc/pihole/whitelist.txt");
$whitelist = new \SplFileObject($whiteListFile);
// blacklist.txt is optional and might not be there
$blackListFile = checkfile("/etc/pihole/blacklist.txt");
$blacklist = new \SplFileObject($blackListFile);
if(isset($setupVars["API_PRIVACY_MODE"]))
{
$privacyMode = $setupVars["API_PRIVACY_MODE"];
}
else
{
$privacyMode = false;
}
/******* Public Members ********/
function getSummaryData() {
$domains_being_blocked = gravityCount();
$dns_queries_today = countDnsQueries();
$ads_blocked_today = countBlockedQueries();
$ads_percentage_today = $dns_queries_today > 0 ? ($ads_blocked_today / $dns_queries_today * 100) : 0;
return array(
'domains_being_blocked' => $domains_being_blocked,
'dns_queries_today' => $dns_queries_today,
'ads_blocked_today' => $ads_blocked_today,
'ads_percentage_today' => $ads_percentage_today,
);
}
function getOverTimeData() {
global $log;
$dns_queries = getDnsQueries($log);
$ads_blocked = getBlockedQueries($log);
$domains_over_time = overTime($dns_queries);
$ads_over_time = overTime($ads_blocked);
// Provide a minimal valid array if there have are no blocked
// queries at all. Otherwise the output of the API is inconsistent.
if(count($ads_blocked) == 0)
{
$ads_over_time = [1 => 0];
}
alignTimeArrays($ads_over_time, $domains_over_time);
return Array(
'domains_over_time' => $domains_over_time,
'ads_over_time' => $ads_over_time,
);
}
function getOverTimeData10mins() {
global $log;
$dns_queries = getDnsQueries($log);
$ads_blocked = getBlockedQueries($log);
$domains_over_time = overTime10mins($dns_queries);
$ads_over_time = overTime10mins($ads_blocked);
// Provide a minimal valid array if there have are no blocked
// queries at all. Otherwise the output of the API is inconsistent.
if(count($ads_blocked) == 0)
{
$ads_over_time = [1 => 0];
}
alignTimeArrays($ads_over_time, $domains_over_time);
return Array(
'domains_over_time' => $domains_over_time,
'ads_over_time' => $ads_over_time,
);
}
function getTopItems() {
global $log,$privacyMode;
$dns_queries = getDnsQueries($log);
$ads_blocked = getBlockedQueries($log);
$topAds = topItems($ads_blocked);
if(!$privacyMode)
{
$topQueries = topItems($dns_queries, $topAds);
}
else
{
$topQueries = [];
}
return Array(
'top_queries' => $topQueries,
'top_ads' => $topAds,
);
}
function getRecentItems($qty) {
global $log;
$dns_queries = getDnsQueries($log);
return Array(
'recent_queries' => getRecent($dns_queries, $qty)
);
}
function getIpvType() {
global $log;
$dns_queries = getDnsQueries($log);
$queryTypes = array();
foreach($dns_queries as $query) {
$info = trim(explode(": ", $query)[1]);
$queryType = explode(" ", $info)[0];
if (isset($queryTypes[$queryType])) {
$queryTypes[$queryType]++;
}
else {
$queryTypes[$queryType] = 1;
}
}
return $queryTypes;
}
function resolveIPs(&$array) {
$hostarray = [];
foreach ($array as $key => $value)
{
$hostname = gethostbyaddr($key);
// If we found a hostname for the IP, replace it
if($hostname)
{
// Generate HOST entry
$hostarray["$hostname|$key"] = $value;
}
else
{
// Generate IP entry
$hostarray[$key] = $value;
}
}
$array = $hostarray;
// Sort new array
arsort($array);
}
function getForwardDestinations() {
global $log, $setupVars;
$forwards = getForwards($log);
$destinations = array();
foreach ($forwards as $forward) {
$exploded = explode(" ", trim($forward));
$dest = $exploded[count($exploded) - 1];
if (isset($destinations[$dest])) {
$destinations[$dest]++;
}
else {
$destinations[$dest] = 1;
}
}
if(istrue($setupVars["API_GET_UPSTREAM_DNS_HOSTNAME"]))
{
resolveIPs($destinations);
}
return $destinations;
}
// Check for existance of variable
// and test it only if it exists
function istrue(&$argument) {
$ret = false;
if(isset($argument))
{
if($argument)
{
$ret = true;
}
}
return $ret;
}
function getQuerySources() {
global $log, $setupVars;
$dns_queries = getDnsQueries($log);
$sources = array();
foreach($dns_queries as $query) {
$exploded = explode(" ", $query);
$ip = trim($exploded[count($exploded)-1]);
if (isset($sources[$ip])) {
$sources[$ip]++;
}
else {
$sources[$ip] = 1;
}
}
global $setupVars;
if(isset($setupVars["API_EXCLUDE_CLIENTS"]))
{
$sources = excludeFromList($sources, "API_EXCLUDE_CLIENTS");
}
arsort($sources);
$sources = array_slice($sources, 0, 10);
if(istrue($setupVars["API_GET_CLIENT_HOSTNAME"]))
{
resolveIPs($sources);
}
return Array(
'top_sources' => $sources
);
}
$showBlocked = false;
$showPermitted = false;
function setShowBlockedPermitted()
{
global $showBlocked, $showPermitted, $setupVars;
if(isset($setupVars["API_QUERY_LOG_SHOW"]))
{
if($setupVars["API_QUERY_LOG_SHOW"] === "all")
{
$showBlocked = true;
$showPermitted = true;
}
elseif($setupVars["API_QUERY_LOG_SHOW"] === "permittedonly")
{
$showBlocked = false;
$showPermitted = true;
}
elseif($setupVars["API_QUERY_LOG_SHOW"] === "blockedonly")
{
$showBlocked = true;
$showPermitted = false;
}
elseif($setupVars["API_QUERY_LOG_SHOW"] === "nothing")
{
$showBlocked = false;
$showPermitted = false;
}
else
{
// Invalid settings, show everything
$showBlocked = true;
$showPermitted = true;
}
}
else
{
$showBlocked = true;
$showPermitted = true;
}
}
function getAllQueries($orderBy) {
global $log,$showBlocked,$showPermitted,$privacyMode;
$allQueries = array("data" => array());
$dns_queries = getDnsQueries($log);
// Create empty array for gravity
$gravity_domains = getGravity();
setShowBlockedPermitted();
// Privacy mode?
if($privacyMode)
{
$showPermitted = false;
}
if(!$showBlocked && !$showPermitted)
{
// Nothing to do for us here
return [];
}
foreach ($dns_queries as $query) {
$time = date_create(substr($query, 0, 16));
$exploded = explode(" ", trim($query));
$domain = $exploded[count($exploded)-3];
$tmp = $exploded[count($exploded)-4];
$status = isset($gravity_domains[$domain]) ? "Pi-holed" : "OK";
if(($status === "Pi-holed" && $showBlocked) || ($status === "OK" && $showPermitted))
{
$type = substr($exploded[count($exploded)-4], 6, -1);
$client = $exploded[count($exploded)-1];
if($orderBy == "orderByClientDomainTime"){
$allQueries['data'][hasHostName($client)][$domain][$time->format('Y-m-d\TH:i:s')] = $status;
}elseif ($orderBy == "orderByClientTimeDomain"){
$allQueries['data'][hasHostName($client)][$time->format('Y-m-d\TH:i:s')][$domain] = $status;
}elseif ($orderBy == "orderByTimeClientDomain"){
$allQueries['data'][$time->format('Y-m-d\TH:i:s')][hasHostName($client)][$domain] = $status;
}elseif ($orderBy == "orderByTimeDomainClient"){
$allQueries['data'][$time->format('Y-m-d\TH:i:s')][$domain][hasHostName($client)] = $status;
}elseif ($orderBy == "orderByDomainClientTime"){
$allQueries['data'][$domain][hasHostName($client)][$time->format('Y-m-d\TH:i:s')] = $status;
}elseif ($orderBy == "orderByDomainTimeClient"){
$allQueries['data'][$domain][$time->format('Y-m-d\TH:i:s')][hasHostName($client)] = $status;
}else{
array_push($allQueries['data'], array(
$time->format('Y-m-d\TH:i:s'),
$type,
$domain,
hasHostName($client),
$status,
""
));
}
}
}
return $allQueries;
}
function tailPiholeLog($param) {
// Not using SplFileObject here, since direct
// usage of f-streams will be much faster for
// files as large as the pihole.log
global $logListName;
$file = fopen($logListName,"r");
$offset = intval($param);
if($offset > 0)
{
// Seeks on the file pointer where we want to continue reading is known
fseek($file, $offset);
$lines = [];
while (!feof($file)) {
array_push($lines,fgets($file));
}
return ["offset" => ftell($file), "lines" => $lines];
}
else
{
// Locate the current position of the file read/write pointer
fseek($file, -1, SEEK_END);
// Add one to skip the very last "\n" in the log file
return ["offset" => ftell($file)+1];
}
fclose($file);
}
/******** Private Members ********/
function gravityCount() {
global $gravityListName,$blackListFile;
$preEventHorizon = exec("grep -c ^ $gravityListName");
$blacklist = exec("grep -c ^ $blackListFile");
return ($preEventHorizon + $blacklist);
}
function getDnsQueries(\SplFileObject $log) {
$log->rewind();
$lines = [];
foreach ($log as $line) {
if(strpos($line, ": query[A") !== false) {
$lines[] = $line;
}
}
return $lines;
}
function countDnsQueries() {
global $logListName;
return exec("grep -c \": query\\[A\" $logListName");
}
function getDnsQueriesAll(\SplFileObject $log) {
$log->rewind();
$lines = [];
foreach ($log as $line) {
if(strpos($line, ": query[A") || strpos($line, "gravity.list") || strpos($line, ": forwarded") !== false) {
$lines[] = $line;
}
}
return $lines;
}
function getDomains($file, &$array, $action){
$file->rewind();
foreach ($file as $line) {
// Strip newline (and possibly carriage return) from end of key
$key = rtrim($line);
// if $action = true -> we want that domain to be ADDED to the list
// doesn't harm to do this if it has already been set before
// (e.g. once in gravity list, once in blacklist)
if($action && strlen($key) > 0)
{
// $action is true (we want to add) *and* key is not empty
$array[$key] = true;
}
elseif(!$action && isset($array[$key]))
{
// $action is false (we want to remove) *and* key is set
unset($array[$key]);
}
}
}
function getGravity() {
global $gravity,$whitelist,$blacklist;
$domains = [];
// ADD (true) preEventHorizon domains
getDomains($gravity, $domains, true);
// ADD (true) blacklist domains
getDomains($blacklist, $domains, true);
// REMOVE (false) whitelist domains
getDomains($whitelist, $domains, false);
return $domains;
}
function getBlockedQueries(\SplFileObject $log) {
$log->rewind();
$lines = [];
foreach ($log as $line) {
$exploded = explode(" ", $line);
if(count($exploded) == 8 || count($exploded) == 10) {
// Structure of data is currently like:
// Array
// (
// [0] => Dec
// [1] => 19
// [2] => 11:21:51
// [3] => dnsmasq[2584]:
// [4] => /etc/pihole/gravity.list
// [5] => doubleclick.com
// [6] => is
// [7] => ip.of.pi.hole
// )
// with extra logging enabled
// Array
// (
// [0] => Dec
// [1] => 19
// [2] => 11:21:51
// [3] => dnsmasq[2584]:
// [4] => 1 (identifier)
// [5] => 1.2.3.4/12345
// [6] => /etc/pihole/gravity.list
// [7] => doubleclick.com
// [8] => is
// [9] => ip.of.pi.hole
// )
$list = $exploded[count($exploded)-4];
$is = $exploded[count($exploded)-2];
// Consider only gravity.list as DNS source (not e.g. hostname.list)
if(substr($list, strlen($list) - 12, 12) === "gravity.list" && $is === "is") {
$lines[] = $line;
};
}
}
return $lines;
}
function countBlockedQueries() {
global $logListName;
return exec("grep \"gravity.list\" $logListName | grep -c \" is \"");
}
function getForwards(\SplFileObject $log) {
$log->rewind();
$lines = [];
foreach ($log as $line) {
if(strpos($line, ": forwarded") !== false) {
$lines[] = $line;
}
}
return $lines;
}
function topItems($queries, $exclude = array(), $qty=10) {
$splitQueries = array();
foreach ($queries as $query) {
$exploded = explode(" ", $query);
$domain = trim($exploded[count($exploded) - 3]);
if (!isset($exclude[$domain])) {
if (isset($splitQueries[$domain])) {
$splitQueries[$domain]++;
}
else {
$splitQueries[$domain] = 1;
}
}
}
global $setupVars;
if(isset($setupVars["API_EXCLUDE_DOMAINS"]))
{
$splitQueries = excludeFromList($splitQueries, "API_EXCLUDE_DOMAINS");
}
arsort($splitQueries);
return array_slice($splitQueries, 0, $qty);
}
function excludeFromList($array,$key)
{
global $setupVars;
$domains = explode(",",$setupVars[$key]);
foreach ($domains as $domain) {
if(isset($array[$domain]))
{
unset($array[$domain]);
}
}
return $array;
}
function overTime($entries) {
$byTime = array();
foreach ($entries as $entry) {
$time = date_create(substr($entry, 0, 16));
$hour = $time->format('G');
if (isset($byTime[$hour])) {
$byTime[$hour]++;
}
else {
$byTime[$hour] = 1;
}
}
return $byTime;
}
function overTime10mins($entries) {
$byTime = array();
foreach ($entries as $entry) {
$time = date_create(substr($entry, 0, 16));
$hour = $time->format('G');
$minute = $time->format('i');
// 00:00 - 00:09 -> 0
// 00:10 - 00:19 -> 1
// ...
// 12:00 - 12:10 -> 72
// ...
// 15:30 - 15:39 -> 93
// etc.
$time = ($minute-$minute%10)/10 + 6*$hour;
if (isset($byTime[$time])) {
$byTime[$time]++;
}
else {
$byTime[$time] = 1;
}
}
return $byTime;
}
function alignTimeArrays(&$times1, &$times2) {
if(count($times1) == 0 || count($times2) < 2) {
return;
}
$max = max(array_merge(array_keys($times1), array_keys($times2)));
$min = min(array_merge(array_keys($times1), array_keys($times2)));
for ($i = $min; $i <= $max; $i++) {
if (!isset($times2[$i])) {
$times2[$i] = 0;
}
if (!isset($times1[$i])) {
$times1[$i] = 0;
}
}
ksort($times1);
ksort($times2);
}
function getRecent($queries, $qty){
$recent = array();
foreach (array_slice($queries, -$qty) as $query) {
$queryArray = array();
$exploded = explode(" ", $query);
$time = date_create(substr($query, 0, 16));
$queryArray['time'] = $time->format('h:i:s a');
$queryArray['domain'] = trim($exploded[count($exploded) - 3]);
$queryArray['ip'] = trim($exploded[count($exploded)-1]);
array_push($recent, $queryArray);
}
return array_reverse($recent);
}
function hasHostName($var){
global $hosts;
foreach ($hosts as $host){
$x = preg_split('/\s+/', $host);
if ( $var == $x[0] ){
$var = $x[1] . "($var)";
}
}
return $var;
}
?>

View File

@@ -0,0 +1,48 @@
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<footer class="main-footer">
<?php
// Check if on a dev branch
$piholeBranch = exec("cd /etc/.pihole/ && git rev-parse --abbrev-ref HEAD");
$webBranch = exec("git rev-parse --abbrev-ref HEAD");
// Use vDev if not on master
if($piholeBranch !== "master") {
$piholeVersion = "vDev";
$piholeCommit = exec("cd /etc/.pihole/ && git describe --long --dirty --tags");
}
else {
$piholeVersion = exec("cd /etc/.pihole/ && git describe --tags --abbrev=0");
}
if($webBranch !== "master") {
$webVersion = "vDev";
$webCommit = exec("git describe --long --dirty --tags");
}
else {
$webVersion = exec("git describe --tags --abbrev=0");
}
?>
<div class="pull-right hidden-xs <?php if(isset($piholeCommit) || isset($webCommit)) { ?>hidden-md<?php } ?>">
<b>Pi-hole Version </b> <span id="piholeVersion"><?php echo $piholeVersion; ?></span><?php if(isset($piholeCommit)) { echo " (".$piholeBranch.", ".$piholeCommit.")"; } ?>
<b>Web Interface Version </b> <span id="webVersion"><?php echo $webVersion; ?></span><?php if(isset($webCommit)) { echo " (".$webBranch.", ".$webCommit.")"; } ?>
</div>
<div><i class="fa fa-github"></i> <strong><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=3J2L3Z4DHW9UY">Donate</a></strong> if you found this useful.</div>
</footer>
</div>
<!-- ./wrapper -->
<script src="scripts/vendor/jquery.min.js"></script>
<script src="scripts/vendor/jquery-ui.min.js"></script>
<script src="style/vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="scripts/vendor/app.min.js"></script>
<script src="scripts/vendor/jquery.dataTables.min.js"></script>
<script src="scripts/vendor/dataTables.bootstrap.min.js"></script>
<script src="scripts/vendor/Chart.bundle.min.js"></script>
<script src="scripts/pi-hole/js/footer.js"></script>
</body>
</html>

View File

@@ -0,0 +1,22 @@
<?php
function is_valid_domain_name($domain_name)
{
return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) && //valid chars check
preg_match("/^.{1,253}$/", $domain_name) && //overall length check
preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); //length of each label
}
function checkfile($filename) {
if(is_readable($filename))
{
return $filename;
}
else
{
// substitute dummy file
return "/dev/null";
}
}
?>

View File

@@ -0,0 +1,35 @@
<?php
if(!isset($_GET['list']))
die();
$type = $_GET['list'];
if($type !== "white" && $type !== "black")
die("Invalid list parameter");
require "func.php";
$rawList = file_get_contents(checkfile("/etc/pihole/${type}list.txt"));
$list = explode("\n", $rawList);
// Get rid of empty lines
for($i = sizeof($list)-1; $i >= 0; $i--) {
if($list[$i] == "")
unset($list[$i]);
}
function filterArray(&$inArray) {
$outArray = array();
foreach ($inArray as $key=>$value) {
if (is_array($value)) {
$outArray[htmlspecialchars($key)] = filterArray($value);
} else {
$outArray[htmlspecialchars($key)] = htmlspecialchars($value);
}
}
return $outArray;
}
// Protect against XSS attacks
$list = filterArray($list);
echo json_encode(array_values($list));

View File

@@ -0,0 +1,23 @@
<?php
require "password.php";
if(!$auth) die("Not authorized");
ob_end_flush();
ini_set("output_buffering", "0");
ob_implicit_flush(true);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
function echoEvent($datatext) {
echo "data: ".implode("\ndata: ", explode("\n", $datatext))."\n\n";
}
// echoEvent("***START***");
$proc = popen("sudo pihole -g", 'r');
while (!feof($proc)) {
echoEvent(fread($proc, 4096));
}
// echoEvent("***END***");
?>

View File

@@ -0,0 +1,496 @@
<?php
require "scripts/pi-hole/php/auth.php";
require "scripts/pi-hole/php/password.php";
check_cors();
// Try to get temperature value from different places (OS dependent)
if(file_exists("/sys/class/thermal/thermal_zone0/temp"))
{
$output = rtrim(file_get_contents("/sys/class/thermal/thermal_zone0/temp"));
}
elseif (file_exists("/sys/class/hwmon/hwmon0/temp1_input"))
{
$output = rtrim(file_get_contents("/sys/class/hwmon/hwmon0/temp1_input"));
}
else
{
$output = "";
}
// Test if we succeeded in getting the temperature
if(is_numeric($output))
{
// $output could be either 4-5 digits or 2-3, and we only divide by 1000 if it's 4-5
// ex. 39007 vs 39
$celsius = intVal($output);
// If celsius is greater than 1 degree and is in the 4-5 digit format
if($celsius > 1000) {
// Use multiplication to get around the division-by-zero error
$celsius *= 1e-3;
}
$kelvin = $celsius + 273.15;
$fahrenheit = ($celsius*9./5)+32.0;
if(isset($setupVars['TEMPERATUREUNIT']))
{
$temperatureunit = $setupVars['TEMPERATUREUNIT'];
}
else
{
$temperatureunit = "C";
}
// Override temperature unit setting if it is changed via Settings page
if(isset($_POST["tempunit"]))
{
$temperatureunit = $_POST["tempunit"];
}
}
else
{
// Nothing can be colder than -273.15 degree Celsius (= 0 Kelvin)
// This is the minimum temperature possible (AKA absolute zero)
$celsius = -273.16;
}
// Get load
$loaddata = sys_getloadavg();
// Get number of processing units available to PHP
// (may be less than the number of online processors)
$nproc = shell_exec('nproc');
// Get memory usage
$data = explode("\n", file_get_contents("/proc/meminfo"));
$meminfo = array();
if(count($data) > 0)
{
foreach ($data as $line) {
$expl = explode(":", trim($line));
if(count($expl) == 2)
{
// remove " kB" from the end of the string and make it an integer
$meminfo[$expl[0]] = intVal(substr($expl[1],0, -3));
}
}
$memory_used = $meminfo["MemTotal"]-$meminfo["MemFree"]-$meminfo["Buffers"]-$meminfo["Cached"];
$memory_total = $meminfo["MemTotal"];
$memory_usage = $memory_used/$memory_total;
}
else
{
$memory_usage = -1;
}
// For session timer
$maxlifetime = ini_get("session.gc_maxlifetime");
// Generate CSRF token
if(empty($_SESSION['token'])) {
$_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32));
}
$token = $_SESSION['token'];
if(isset($setupVars['WEBUIBOXEDLAYOUT']))
{
if($setupVars['WEBUIBOXEDLAYOUT'] === "boxed")
{
$boxedlayout = true;
}
else
{
$boxedlayout = false;
}
}
else
{
$boxedlayout = true;
}
// Override layout setting if layout is changed via Settings page
if(isset($_POST["field"]))
{
if($_POST["field"] === "webUI" && isset($_POST["boxedlayout"]))
{
$boxedlayout = true;
}
elseif($_POST["field"] === "webUI" && !isset($_POST["boxedlayout"]))
{
$boxedlayout = false;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://api.github.com; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'">
<title>Pi-hole Admin Console</title>
<!-- Usually browsers proactively perform domain name resolution on links that the user may choose to follow. We disable DNS prefetching here -->
<meta http-equiv="x-dns-prefetch-control" content="off">
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
<meta name="theme-color" content="#367fa9">
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon.png">
<link rel="icon" type="image/png" sizes="192x192" href="img/logo.svg">
<link rel="icon" type="image/png" sizes="96x96" href="img/logo.svg">
<meta name="msapplication-TileColor" content="#367fa9">
<meta name="msapplication-TileImage" content="img/logo.svg">
<meta name="apple-mobile-web-app-capable" content="yes">
<link href="style/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="style/vendor/font-awesome-4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link href="style/vendor/ionicons-2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css" />
<link href="style/vendor/dataTables.bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="style/vendor/AdminLTE.min.css" rel="stylesheet" type="text/css" />
<link href="style/vendor/skin-blue.min.css" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" sizes="160x160" href="img/logo.svg" />
<style type="text/css">
.glow { text-shadow: 0px 0px 5px #fff; }
h3 { transition-duration: 500ms }
</style>
<!--[if lt IE 9]>
<script src="scripts/vendor/html5shiv.min.js"></script>
<script src="scripts/vendor/respond.min.js"></script>
<![endif]-->
</head>
<body class="skin-blue sidebar-mini <?php if($boxedlayout){ ?>layout-boxed<?php } ?>">
<!-- JS Warning -->
<div>
<link rel="stylesheet" type="text/css" href="style/vendor/js-warn.css">
<input type="checkbox" id="js-hide" />
<div class="js-warn" id="js-warn-exit"><h1>Javascript Is Disabled</h1><p>Javascript seems to be disabled. This will break some site features.</p>
<p>To enable Javascript click <a href="http://www.enable-javascript.com/" target="_blank">here</a></p><label for="js-hide">Close</label></div>
</div>
<!-- /JS Warning -->
<script src="scripts/pi-hole/js/header.js"></script>
<!-- Send token to JS -->
<div id="token" hidden><?php echo $token ?></div>
<div class="wrapper">
<header class="main-header">
<!-- Logo -->
<a href="http://pi-hole.net" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini"><b>P</b>H</span>
<!-- logo for regular state and mobile devices -->
<span class="logo-lg"><b>Pi</b>-hole</span>
</a>
<!-- Header Navbar: style can be found in header.less -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<!-- User Account: style can be found in dropdown.less -->
<li id="dropdown-menu" class="dropdown user user-menu">
<a href="#" class="dropdown-toggle">
<img src="img/logo.svg" class="user-image" style="border-radius: initial" sizes="160x160" alt="Pi-hole logo" />
<span class="hidden-xs">Pi-hole</span>
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header">
<img src="img/logo.svg" sizes="160x160" alt="User Image" />
<p>
Open Source Ad Blocker
<small>Designed For Raspberry Pi</small>
</p>
</li>
<!-- Menu Body -->
<li class="user-body">
<div class="col-xs-4 text-center">
<a href="https://github.com/pi-hole/pi-hole">GitHub</a>
</div>
<div class="col-xs-4 text-center">
<a href="http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0/">Details</a>
</div>
<div class="col-xs-4 text-center">
<a href="https://github.com/pi-hole/pi-hole/releases">Updates</a>
</div>
<div class="col-xs-12 text-center" id="sessiontimer">Session is valid for <span id="sessiontimercounter"><?php if($auth && strlen($pwhash) > 0){echo $maxlifetime;}else{echo "0";} ?></span></div>
</li>
<!-- Menu Footer -->
<li class="user-footer">
<!-- Update alerts -->
<div id="alPiholeUpdate" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
<a class="alert-link" href="https://github.com/pi-hole/pi-hole/releases">There's an update available for this Pi-hole!</a>
</div>
<div id="alWebUpdate" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
<a class="alert-link" href="https://github.com/pi-hole/AdminLTE/releases">There's an update available for this Web Interface!</a>
</div>
<!-- PayPal -->
<div>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="3J2L3Z4DHW9UY">
<input style="display: block; margin: 0 auto;" type="image" src="img/donate.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
</form>
</div>
</li>
</ul>
</li>
</ul>
</div>
</nav>
</header>
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="img/logo.svg" class="img-responsive" alt="Pi-hole logo" />
</div>
<div class="pull-left info">
<p>Status</p>
<?php
$pistatus = exec('sudo pihole status web');
if ($pistatus == "1") {
echo '<a href="#" id="status"><i class="fa fa-circle" style="color:#7FFF00"></i> Active</a>';
} elseif ($pistatus == "0") {
echo '<a href="#" id="status"><i class="fa fa-circle" style="color:#FF0000"></i> Offline</a>';
} else {
echo '<a href="#" id="status"><i class="fa fa-circle" style="color:#ff9900"></i> Starting</a>';
}
// CPU Temp
if ($celsius >= -273.15) {
echo "<a href=\"#\" id=\"temperature\"><i class=\"fa fa-fire\" style=\"color:";
if ($celsius > 60) {
echo "#FF0000";
}
else
{
echo "#3366FF";
}
echo "\"></i> Temp:&nbsp;";
if($temperatureunit === "F")
{
echo round($fahrenheit,1) . "&deg;F";
}
elseif($temperatureunit === "K")
{
echo round($kelvin,1) . "K";
}
else
{
echo round($celsius,1) . "&deg;C";
}
echo "</a>";
}
?>
<br/>
<?php
echo '<a href="#"><i class="fa fa-circle" style="color:';
if ($loaddata[0] > $nproc) {
echo '#FF0000';
}
else
{
echo '#7FFF00';
}
echo '""></i> Load:&nbsp;&nbsp;' . $loaddata[0] . '&nbsp;&nbsp;' . $loaddata[1] . '&nbsp;&nbsp;'. $loaddata[2] . '</a>';
?>
<br/>
<?php
echo '<a href="#"><i class="fa fa-circle" style="color:';
if ($memory_usage > 0.75 || $memory_usage < 0.0) {
echo '#FF0000';
}
else
{
echo '#7FFF00';
}
if($memory_usage > 0.0)
{
echo '""></i> Memory usage:&nbsp;&nbsp;' . sprintf("%.1f",100.0*$memory_usage) . '%</a>';
}
else
{
echo '""></i> Memory usage:&nbsp;&nbsp; N/A</a>';
}
?>
</div>
</div>
<!-- sidebar menu: : style can be found in sidebar.less -->
<?php
$scriptname = basename($_SERVER['SCRIPT_FILENAME']);
if($scriptname === "list.php")
{
if($_GET["l"] === "white")
{
$scriptname = "whitelist";
}
elseif($_GET["l"] === "black")
{
$scriptname = "blacklist";
}
}
?>
<ul class="sidebar-menu">
<li class="header">MAIN NAVIGATION</li>
<!-- Home Page -->
<li<?php if($scriptname === "index.php"){ ?> class="active"<?php } ?>>
<a href="index.php">
<i class="fa fa-home"></i> <span>Main Page</span>
</a>
</li>
<?php if($auth){ ?>
<!-- Query Log -->
<li<?php if($scriptname === "queries.php"){ ?> class="active"<?php } ?>>
<a href="queries.php">
<i class="fa fa-file-text-o"></i> <span>Query Log</span>
</a>
</li>
<!-- Whitelist -->
<li<?php if($scriptname === "whitelist"){ ?> class="active"<?php } ?>>
<a href="list.php?l=white">
<i class="fa fa-pencil-square-o"></i> <span>Whitelist</span>
</a>
</li>
<!-- Blacklist -->
<li<?php if($scriptname === "blacklist"){ ?> class="active"<?php } ?>>
<a href="list.php?l=black">
<i class="fa fa-ban"></i> <span>Blacklist</span>
</a>
</li>
<!-- Toggle -->
<li id="pihole-disable" class="treeview"<?php if ($pistatus == "0") { ?> hidden="true"<?php } ?>>
<a href="#">
<i class="fa fa-stop"></i> <span>Disable</span>&nbsp;&nbsp;&nbsp;<span id="flip-status-disable"></span>
<span class="pull-right-container">
<i class="fa fa-angle-down pull-right" style="padding-right: 5px;"></i>
</span>
</a>
<ul class="treeview-menu">
<li>
<a href="#" id="pihole-disable-permanently">
<i class="fa fa-stop"></i> <span>Permanently</span>
</a>
</li>
<li>
<a href="#" id="pihole-disable-10s">
<i class="fa fa-clock-o"></i> <span>For 10 seconds</span>
</a>
</li>
<li>
<a href="#" id="pihole-disable-30s">
<i class="fa fa-clock-o"></i> <span>For 30 seconds</span>
</a>
</li>
<li>
<a href="#" id="pihole-disable-5m">
<i class="fa fa-clock-o"></i> <span>For 5 minutes</span>
</a>
</li>
</ul>
<!-- <a href="#" id="flip-status"><i class="fa fa-stop"></i> <span>Disable</span></a> -->
</li>
<li id="pihole-enable" class="treeview"<?php if ($pistatus == "1") { ?> hidden="true"<?php } ?>>
<a href="#"><i class="fa fa-play"></i> <span>Enable</span>&nbsp;&nbsp;&nbsp;<span id="flip-status-enable"></span></a>
</li>
<!-- Tools -->
<li class="treeview <?php if($scriptname === "gravity.php" || $scriptname === "queryads.php"){ ?>active<?php } ?>">
<a href="#">
<i class="fa fa-folder"></i> <span>Tools</span>
<span class="pull-right-container">
<i class="fa fa-angle-down pull-right" style="padding-right: 5px;"></i>
</span>
</a>
<ul class="treeview-menu">
<!-- Run gravity.sh -->
<li<?php if($scriptname === "gravity.php"){ ?> class="active"<?php } ?>>
<a href="gravity.php">
<i class="fa fa-arrow-circle-down"></i> <span>Update Lists</span>
</a>
</li>
<!-- Query adlists -->
<li<?php if($scriptname === "queryads.php"){ ?> class="active"<?php } ?>>
<a href="queryads.php">
<i class="fa fa-search"></i> <span>Query adlists</span>
</a>
</li>
<!-- Tail pihole.log -->
<li<?php if($scriptname === "taillog.php"){ ?> class="active"<?php } ?>>
<a href="taillog.php">
<i class="fa fa-list-ul"></i> <span>Tail pihole.log</span>
</a>
</li>
</ul>
</li>
<!-- Settings -->
<li<?php if($scriptname === "settings.php"){ ?> class="active"<?php } ?>>
<a href="settings.php">
<i class="fa fa-gears"></i> <span>Settings</span>
</a>
</li>
<!-- Logout -->
<?php
// Show Logout button if $auth is set and authorization is required
if(strlen($pwhash) > 0) { ?>
<li>
<a href="index.php?logout">
<i class="fa fa-user-times"></i> <span>Logout</span>
</a>
</li>
<?php } ?>
<?php } ?>
<!-- Login -->
<?php
// Show Login button if $auth is *not* set and authorization is required
if(strlen($pwhash) > 0 && !$auth) { ?>
<li>
<a href="index.php?login">
<i class="fa fa-user"></i> <span>Login</span>
</a>
</li>
<?php } ?>
<!-- Donate -->
<li>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">
<i class="fa fa-paypal"></i> <span>Donate</span>
</a>
</li>
<?php if($auth){ ?>
<!-- Help -->
<li<?php if($scriptname === "help.php"){ ?> class="active"<?php } ?>>
<a href="help.php">
<i class="fa fa-question-circle"></i> <span>Help</span>
</a>
</li>
<?php } ?>
</ul>
</section>
<!-- /.sidebar -->
</aside>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Main content -->
<section class="content">
<?php
// If password is not equal to the password set
// in the setupVars.conf file, then we skip any
// content and just complete the page. If no
// password is set at all, we keep the current
// behavior: everything is always authorized
// and will be displayed
//
// If auth is required and not set, i.e. no successfully logged in,
// we show the reduced version of the summary (index) page
if(!$auth && (!isset($indexpage) || isset($_GET['login']))){
require "scripts/pi-hole/php/loginpage.php";
require "footer.php";
exit();
}
?>

View File

@@ -0,0 +1,54 @@
<div class="mainbox col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3">
<div class="panel panel-default">
<div class="panel-heading">
<div style="text-align: center;"><img src="img/logo.svg" width="<?php if ($boxedlayout) { ?>50%<?php } else { ?>30%<?php } ?>"></div><br>
<div class="panel-title text-center"><span class="logo-lg" style="font-size: 25px;"><b>Pi</b>-hole</span></div>
<p class="login-box-msg">Sign in to start your session</p>
<?php if ($wrongpassword) { ?>
<div class="form-group has-error login-box-msg">
<label class="control-label"><i class="fa fa-times-circle-o"></i> Wrong password!</label>
</div>
<?php } ?>
</div>
<div class="panel-body">
<form action="" method="post">
<div class="form-group has-feedback <?php if ($wrongpassword) { ?>has-error<?php } ?> ">
<input type="password" name="pw" class="form-control" placeholder="Password" autofocus>
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-8">
<button type="submit" href="#" class="btn btn-primary pull-right"><i class="glyphicon glyphicon-log-in"></i>&nbsp;&nbsp;&nbsp;Log in</button>
</div>
</div>
<br>
<div class="row">
<div class="col-xs-12">
<div class="box box-<?php if (!$wrongpassword) { ?>info<?php } else { ?>danger<?php }
if (!$wrongpassword) { ?> collapsed-box<?php } ?> box-solid">
<div class="box-header with-border">
<h3 class="box-title">Forgot password</h3>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i
class="fa <?php if ($wrongpassword) { ?>fa-minus<?php } else { ?>fa-plus<?php } ?>"></i>
</button>
</div>
</div>
<div class="box-body">
After installing Pi-Hole for the first time, a password is generated and displayed to the user. The
password cannot be retrived later on, but it is possible to set a new password (or explicitly disable
the
password by setting an empty password) using the command
<pre>sudo pihole -a -p newpassword</pre>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,65 @@
<?php
// Start a new PHP session (or continue an existing one)
session_start();
// Read setupVars.conf file
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
// Try to read password hash from setupVars.conf
if(isset($setupVars['WEBPASSWORD']))
{
$pwhash = $setupVars['WEBPASSWORD'];
}
else
{
$pwhash = "";
}
// If the user wants to log out, we free all session variables currently registered
if(isset($_GET["logout"]))
{
session_unset();
}
$wrongpassword = false;
// Test if password is set
if(strlen($pwhash) > 0)
{
// Compare doubly hashes password input with saved hash
if(isset($_POST["pw"]))
{
$postinput = hash('sha256',hash('sha256',$_POST["pw"]));
if($postinput == $pwhash)
{
$_SESSION["hash"] = $pwhash;
$auth = true;
}
else
{
$wrongpassword = true;
}
}
// Compare auth hash with saved hash
else if (isset($_SESSION["hash"]))
{
if($_SESSION["hash"] == $pwhash)
$auth = true;
}
// API can use the hash to get data without logging in via plain-text password
else if (isset($api) && isset($_GET["auth"]))
{
if($_GET["auth"] == $pwhash)
$auth = true;
}
else
{
// Password or hash wrong
$auth = false;
}
}
else
{
// No password set
$auth = true;
}
?>

View File

@@ -0,0 +1,50 @@
<?php
ob_end_flush();
ini_set("output_buffering", "0");
ob_implicit_flush(true);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
function echoEvent($datatext) {
echo "data: ".implode("\ndata: ", explode("\n", $datatext))."\n\n";
}
// Credit: http://stackoverflow.com/a/4694816/2087442
function is_valid_domain_name($domain_name)
{
return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
&& preg_match("/^.{1,253}$/", $domain_name) //overall length check
&& preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name) ); //length of each label
}
// Test if domain is set
if(isset($_GET["domain"]))
{
// Is this a valid domain?
$url = $_GET["domain"];
if(!is_valid_domain_name($url))
{
echoEvent("Invalid domain!");
die();
}
}
else
{
echoEvent("No domain provided");
die();
}
if(isset($_GET["exact"]))
{
$exact = "-exact";
}
else
{
$exact = "";
}
$proc = popen("sudo pihole -q ".$url." ".$exact, 'r');
while (!feof($proc)) {
echoEvent(fread($proc, 4096));
}
?>

View File

@@ -0,0 +1,477 @@
<?php
if(basename($_SERVER['SCRIPT_FILENAME']) !== "settings.php")
{
die("Direct access to this script is forbidden!");
}
function validIP($address){
return !filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false;
}
// Check for existance of variable
// and test it only if it exists
function istrue(&$argument) {
$ret = false;
if(isset($argument))
{
if($argument)
{
$ret = true;
}
}
return $ret;
}
// Credit: http://stackoverflow.com/a/4694816/2087442
function validDomain($domain_name)
{
$validChars = preg_match("/^([_a-z\d](-*[_a-z\d])*)(\.([_a-z\d](-*[a-z\d])*))*(\.([a-z\d])*)*$/i", $domain_name);
$lengthCheck = preg_match("/^.{1,253}$/", $domain_name);
$labelLengthCheck = preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name);
return ( $validChars && $lengthCheck && $labelLengthCheck ); //length of each label
}
$primaryDNSservers = [
"8.8.8.8" => "Google",
"208.67.222.222" => "OpenDNS",
"4.2.2.1" => "Level3",
"199.85.126.10" => "Norton",
"8.26.56.26" => "Comodo"
];
$secondaryDNSservers = [
"8.8.4.4" => "Google",
"208.67.220.220" => "OpenDNS",
"4.2.2.2" => "Level3",
"199.85.127.10" => "Norton",
"8.20.247.20" => "Comodo"
];
$adlistsdefault = [];
$adlistsuser = [];
function readAdlists($listname)
{
// Reset list
$list = [];
$handle = @fopen("/etc/pihole/adlists.".$listname, "r");
if ($handle)
{
while (($line = fgets($handle)) !== false)
{
if(substr($line, 0, 5) === "#http")
{
// Commented list
array_push($list, [false,rtrim(substr($line, 1))]);
}
elseif(substr($line, 0, 4) === "http")
{
// Active list
array_push($list, [true,rtrim($line)]);
}
}
fclose($handle);
}
return $list;
}
// Read available adlists
$adlistsdefault = readAdlists("default");
$adlistsuser = readAdlists("user");
$error = "";
$success = "";
if(isset($_POST["field"]))
{
// Process request
switch ($_POST["field"]) {
// Set DNS server
case "DNS":
$primaryDNS = $_POST["primaryDNS"];
$secondaryDNS = $_POST["secondaryDNS"];
// Get primary DNS server IP address
if($primaryDNS === "Custom")
{
$primaryIP = $_POST["DNS1IP"];
}
else
{
$primaryIP = array_flip($primaryDNSservers)[$primaryDNS];
}
// Validate primary IP
if (!validIP($primaryIP))
{
$error .= "Primary IP (".$primaryIP.") is invalid!<br>";
}
// Get secondary DNS server IP address
if($secondaryDNS === "Custom")
{
if(strlen($_POST["DNS2IP"]) > 0)
{
$secondaryIP = $_POST["DNS2IP"];
}
else
{
$secondaryIP = "none";
}
}
else
{
$secondaryIP = array_flip($secondaryDNSservers)[$secondaryDNS];
}
// Validate secondary IP
if (!validIP($secondaryIP) && $secondaryIP != "none" && strlen($secondaryIP) > 0)
{
$error .= "Secondary IP (".$secondaryIP.") is invalid!<br>";
}
// Check if domain-needed is requested
if(isset($_POST["DNSrequiresFQDN"]))
{
$extra = "domain-needed ";
}
else
{
$extra = "domain-not-needed ";
}
// Check if domain-needed is requested
if(isset($_POST["DNSbogusPriv"]))
{
$extra .= "bogus-priv";
}
else
{
$extra .= "no-bogus-priv";
}
// If there has been no error we can save the new DNS server IPs
if(!strlen($error))
{
exec("sudo pihole -a setdns ".$primaryIP." ".$secondaryIP." ".$extra);
$success .= "The DNS settings have been updated";
}
else
{
$error .= "The settings have been reset to their previous values";
}
break;
// Set query logging
case "Logging":
if($_POST["action"] === "Disable")
{
exec("sudo pihole -l off");
$success .= "Logging has been disabled";
}
else
{
exec("sudo pihole -l on");
$success .= "Logging has been enabled";
}
break;
// Set domains to be excluded from being shown in Top Domains (or Ads) and Top Clients
case "API":
// Explode the contents of the textareas into PHP arrays
// \n (Unix) and \r\n (Win) will be considered as newline
// array_filter( ... ) will remove any empty lines
$domains = array_filter(preg_split('/\r\n|[\r\n]/', $_POST["domains"]));
$clients = array_filter(preg_split('/\r\n|[\r\n]/', $_POST["clients"]));
$domainlist = "";
$first = true;
foreach($domains as $domain)
{
if(!validDomain($domain))
{
$error .= "Top Domains/Ads entry ".$domain." is invalid!<br>";
}
if(!$first)
{
$domainlist .= ",";
}
else
{
$first = false;
}
$domainlist .= $domain;
}
$clientlist = "";
$first = true;
foreach($clients as $client)
{
if(!validIP($client))
{
$error .= "Top Clients entry ".$client." is invalid (use only IP addresses)!<br>";
}
if(!$first)
{
$clientlist .= ",";
}
else
{
$first = false;
}
$clientlist .= $client;
}
// Set Top Lists options
if(!strlen($error))
{
// All entries are okay
exec("sudo pihole -a setexcludedomains ".$domainlist);
exec("sudo pihole -a setexcludeclients ".$clientlist);
$success .= "The API settings have been updated<br>";
}
else
{
$error .= "The settings have been reset to their previous values";
}
// Set query log options
if(isset($_POST["querylog-permitted"]) && isset($_POST["querylog-blocked"]))
{
exec("sudo pihole -a setquerylog all");
if(!isset($_POST["privacyMode"]))
{
$success .= "All entries will be shown in Query Log";
}
else
{
$success .= "Only blocked entries will be shown in Query Log";
}
}
elseif(isset($_POST["querylog-permitted"]))
{
exec("sudo pihole -a setquerylog permittedonly");
if(!isset($_POST["privacyMode"]))
{
$success .= "Only permitted will be shown in Query Log";
}
else
{
$success .= "No entries will be shown in Query Log";
}
}
elseif(isset($_POST["querylog-blocked"]))
{
exec("sudo pihole -a setquerylog blockedonly");
$success .= "Only blocked entries will be shown in Query Log";
}
else
{
exec("sudo pihole -a setquerylog nothing");
$success .= "No entries will be shown in Query Log";
}
if(isset($_POST["privacyMode"]))
{
exec("sudo pihole -a privacymode true");
$success .= " (privacy mode enabled)";
}
else
{
exec("sudo pihole -a privacymode false");
}
if(isset($_POST["resolve-forward"]))
{
exec("sudo pihole -a resolve forward true");
}
else
{
exec("sudo pihole -a resolve forward false");
}
if(isset($_POST["resolve-clients"]))
{
exec("sudo pihole -a resolve clients true");
}
else
{
exec("sudo pihole -a resolve clients false");
}
break;
case "webUI":
if($_POST["tempunit"] == "F")
{
exec('sudo pihole -a -f');
}
elseif($_POST["tempunit"] == "K")
{
exec('sudo pihole -a -k');
}
else
{
exec('sudo pihole -a -c');
}
if(isset($_POST["boxedlayout"]))
{
exec('sudo pihole -a layout boxed');
}
else
{
exec('sudo pihole -a layout traditional');
}
$success .= "The webUI settings have been updated";
break;
case "reboot":
exec("sudo pihole -a reboot");
$success = "The system will reboot in 5 seconds...";
break;
case "restartdns":
exec("sudo pihole -a restartdns");
$success = "The DNS server has been restarted";
break;
case "flushlogs":
exec("sudo pihole -f");
$success = "The Pi-Hole log file has been flushed";
break;
case "DHCP":
if(isset($_POST["active"]))
{
// Validate from IP
$from = $_POST["from"];
if (!validIP($from))
{
$error .= "From IP (".$from.") is invalid!<br>";
}
// Validate to IP
$to = $_POST["to"];
if (!validIP($to))
{
$error .= "To IP (".$to.") is invalid!<br>";
}
// Validate router IP
$router = $_POST["router"];
if (!validIP($router))
{
$error .= "Router IP (".$router.") is invalid!<br>";
}
$domain = $_POST["domain"];
// Validate Domain name
if(!validDomain($domain))
{
$error .= "Domain name ".$domain." is invalid!<br>";
}
if(!strlen($error))
{
exec("sudo pihole -a enabledhcp ".$from." ".$to." ".$router);
exec("sudo pihole -a domainname ".$domain);
$success .= "The DHCP server has been activated";
}
}
else
{
exec("sudo pihole -a disabledhcp");
$success = "The DHCP server has been deactivated";
}
break;
case "adlists":
foreach ($adlistsdefault as $key => $value)
{
if(isset($_POST["adlist-".$key]) && !$value[0])
{
// Is not enabled, but should be
exec("sudo pihole -a adlist enable default ".escapeshellcmd ($value[1]));
}
elseif(!isset($_POST["adlist-".$key]) && $value[0])
{
// Is enabled, but shouldn't be
exec("sudo pihole -a adlist disable default ".escapeshellcmd ($value[1]));
}
}
foreach ($adlistsuser as $key => $value)
{
if(isset($_POST["userlist-".$key]) && !$value[0])
{
// Is not enabled, but should be
exec("sudo pihole -a adlist enable user ".escapeshellcmd ($value[1]));
}
elseif(!isset($_POST["userlist-".$key]) && $value[0])
{
// Is enabled, but shouldn't be
exec("sudo pihole -a adlist disable user ".escapeshellcmd ($value[1]));
}
}
if(strlen($_POST["newuserlists"]) > 1)
{
$domains = array_filter(preg_split('/\r\n|[\r\n]/', $_POST["newuserlists"]));
foreach($domains as $domain)
{
exec("sudo pihole -a adlist add user ".escapeshellcmd($domain));
}
}
// Reread available adlists
$adlistsdefault = readAdlists("default");
$adlistsuser = readAdlists("user");
break;
default:
// Option not found
$debug = true;
break;
}
}
// Credit: http://stackoverflow.com/a/5501447/2087442
function formatSizeUnits($bytes)
{
if ($bytes >= 1073741824)
{
$bytes = number_format($bytes / 1073741824, 2) . ' GB';
}
elseif ($bytes >= 1048576)
{
$bytes = number_format($bytes / 1048576, 2) . ' MB';
}
elseif ($bytes >= 1024)
{
$bytes = number_format($bytes / 1024, 2) . ' kB';
}
elseif ($bytes > 1)
{
$bytes = $bytes . ' bytes';
}
elseif ($bytes == 1)
{
$bytes = $bytes . ' byte';
}
else
{
$bytes = '0 bytes';
}
return $bytes;
}
?>

View File

@@ -0,0 +1,18 @@
<?php
require('auth.php');
$type = $_POST['list'];
// All of the verification for list editing
list_verify($type);
switch($type) {
case "white":
exec("sudo pihole -w -q -d ${_POST['domain']}");
break;
case "black":
exec("sudo pihole -b -q -d ${_POST['domain']}");
break;
}
?>