merge devel

This commit is contained in:
Promofaux
2016-12-29 19:59:09 +00:00
17 changed files with 658 additions and 143 deletions

View File

@@ -20,26 +20,42 @@ function check_cors() {
// Check CORS
$AUTHORIZED_HOSTNAMES = array(
'http://' . $ipv4,
'http://' . $_SERVER['SERVER_NAME'],
'http://pi.hole',
'http://localhost'
$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, 'http://' . $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.
if(isset($_SERVER['HTTP_HOST']) && !in_array("http://".$_SERVER['HTTP_HOST'], $AUTHORIZED_HOSTNAMES)) {
log_and_die("Failed Host Check: " . $_SERVER['HTTP_HOST'] .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
$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'])) {
if(!in_array($_SERVER['HTTP_ORIGIN'], $AUTHORIZED_HOSTNAMES)) {
log_and_die("Failed CORS: " . $_SERVER['HTTP_ORIGIN'] .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
$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']}");
}

View File

@@ -20,6 +20,15 @@
$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();
@@ -45,6 +54,14 @@
$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,
@@ -59,6 +76,14 @@
$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,
@@ -67,12 +92,19 @@
}
function getTopItems() {
global $log;
global $log,$privacyMode;
$dns_queries = getDnsQueries($log);
$ads_blocked = getBlockedQueries($log);
$topAds = topItems($ads_blocked);
$topQueries = topItems($dns_queries, $topAds);
if(!$privacyMode)
{
$topQueries = topItems($dns_queries, $topAds);
}
else
{
$topQueries = [];
}
return Array(
'top_queries' => $topQueries,
@@ -107,13 +139,36 @@
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;
global $log, $setupVars;
$forwards = getForwards($log);
$destinations = array();
foreach ($forwards as $forward) {
$exploded = explode(" ", trim($forward));
$dest = hasHostName($exploded[count($exploded) - 1]);
$dest = $exploded[count($exploded) - 1];
if (isset($destinations[$dest])) {
$destinations[$dest]++;
}
@@ -122,17 +177,36 @@
}
}
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;
global $log, $setupVars;
$dns_queries = getDnsQueries($log);
$sources = array();
foreach($dns_queries as $query) {
$exploded = explode(" ", $query);
$ip = hasHostName(trim($exploded[count($exploded)-1]));
$ip = trim($exploded[count($exploded)-1]);
if (isset($sources[$ip])) {
$sources[$ip]++;
}
@@ -149,6 +223,12 @@
arsort($sources);
$sources = array_slice($sources, 0, 10);
if(istrue($setupVars["API_GET_CLIENT_HOSTNAME"]))
{
resolveIPs($sources);
}
return Array(
'top_sources' => $sources
);
@@ -197,57 +277,93 @@
}
function getAllQueries($orderBy) {
global $log,$showBlocked,$showPermitted;
global $log,$showBlocked,$showPermitted,$privacyMode;
$allQueries = array("data" => array());
$dns_queries = getDnsQueriesAll($log);
$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];
setShowBlockedPermitted();
if (substr($tmp, 0, 5) == "query")
$status = isset($gravity_domains[$domain]) ? "Pi-holed" : "OK";
if(($status === "Pi-holed" && $showBlocked) || ($status === "OK" && $showPermitted))
{
$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];
$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,
""
));
}
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;
@@ -260,7 +376,7 @@
$log->rewind();
$lines = [];
foreach ($log as $line) {
if(strpos($line, ": query[") !== false) {
if(strpos($line, ": query[A") !== false) {
$lines[] = $line;
}
}
@@ -269,14 +385,14 @@
function countDnsQueries() {
global $logListName;
return exec("grep -c \": query\\[\" $logListName");
return exec("grep -c \": query\\[A\" $logListName");
}
function getDnsQueriesAll(\SplFileObject $log) {
$log->rewind();
$lines = [];
foreach ($log as $line) {
if(strpos($line, ": query[") || strpos($line, "gravity.list") || strpos($line, ": forwarded") !== false) {
if(strpos($line, ": query[A") || strpos($line, "gravity.list") || strpos($line, ": forwarded") !== false) {
$lines[] = $line;
}
}
@@ -323,16 +439,39 @@
function getBlockedQueries(\SplFileObject $log) {
$log->rewind();
$lines = [];
$hostname = trim(file_get_contents("/etc/hostname"), "\x00..\x1F");
foreach ($log as $line) {
$line = preg_replace('/ {2,}/', ' ', $line);
$exploded = explode(" ", $line);
if(count($exploded) == 8) {
$tmp = $exploded[count($exploded) - 4];
$tmp2 = $exploded[count($exploded) - 5];
$tmp3 = $exploded[count($exploded) - 3];
//filter out bad names and host file reloads:
if(substr($tmp, strlen($tmp) - 12, 12) == "gravity.list" && $tmp2 != "read" && $tmp3 != "pi.hole" && $tmp3 != $hostname) {
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;
};
}
@@ -342,8 +481,7 @@
function countBlockedQueries() {
global $logListName;
$hostname = trim(file_get_contents("/etc/hostname"), "\x00..\x1F");
return exec("grep \"gravity.list\" $logListName | grep -v \"pi.hole\" | grep -v \" read \" | grep -v -c \"".$hostname."\"");
return exec("grep \"gravity.list\" $logListName | grep -c \" is \"");
}
function getForwards(\SplFileObject $log) {

View File

@@ -21,7 +21,16 @@
// Test if we succeeded in getting the temperature
if(is_numeric($output))
{
$celsius = intVal($output)*1e-3;
// $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;
@@ -240,7 +249,7 @@
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="img/logo.svg" style="width: 45px; height: 67px;" alt="Pi-hole logo" />
<img src="img/logo.svg" class="img-responsive" alt="Pi-hole logo" />
</div>
<div class="pull-left info">
<p>Status</p>
@@ -257,7 +266,7 @@
// CPU Temp
if ($celsius >= -273.15) {
echo "<a href=\"#\" id=\"temperature\"><i class=\"fa fa-fire\" style=\"color:";
if ($celsius > 45) {
if ($celsius > 60) {
echo "#FF0000";
}
else
@@ -314,55 +323,114 @@
</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>
<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>
<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>
<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>
<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>
<!-- Run gravity.sh -->
<li>
<a href="gravity.php">
<i class="fa fa-arrow-circle-down"></i> <span>Update Lists</span>
</a>
</li>
<!-- Query adlists -->
<li>
<a href="queryads.php">
<i class="fa fa-search"></i> <span>Query adlists</span>
</a>
</li>
<!-- Toggle -->
<?php
if ($pistatus == "1") {
echo ' <li><a href="#" id="flip-status"><i class="fa fa-stop"></i> <span>Disable</span></a></li>';
} else {
echo ' <li><a href="#" id="flip-status"><i class="fa fa-play"></i> <span>Enable</span></a></li>';
}
?>
<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>
<li<?php if($scriptname === "settings.php"){ ?> class="active"<?php } ?>>
<a href="settings.php">
<i class="fa fa-gears"></i> <span>Settings</span>
</a>
@@ -396,7 +464,7 @@
</li>
<?php if($auth){ ?>
<!-- Help -->
<li>
<li<?php if($scriptname === "help.php"){ ?> class="active"<?php } ?>>
<a href="help.php">
<i class="fa fa-question-circle"></i> <span>Help</span>
</a>

View File

@@ -15,7 +15,7 @@
<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">
<input type="password" name="pw" class="form-control" placeholder="Password" autofocus>
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">

View File

@@ -9,10 +9,24 @@ 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])*))*$/i", $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
@@ -198,12 +212,26 @@ function validDomain($domain_name)
if(isset($_POST["querylog-permitted"]) && isset($_POST["querylog-blocked"]))
{
exec("sudo pihole -a setquerylog all");
$success .= "All entries will be shown in Query Log";
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");
$success .= "Only permitted will be shown in Query Log";
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"]))
{
@@ -216,6 +244,35 @@ function validDomain($domain_name)
$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":