Merge pull request #239 from pi-hole/settings

Settings page for the web UI
This commit is contained in:
Adam Warner
2016-12-14 19:12:26 +00:00
committed by GitHub
10 changed files with 2744 additions and 46 deletions
+36 -16
View File
@@ -4,26 +4,11 @@
check_cors();
// Web based change of temperature unit
if (isset($_GET['tempunit']))
{
if($_GET['tempunit'] == "fahrenheit")
{
exec('sudo pihole -a -f');
}
else
{
exec('sudo pihole -a -c');
}
}
$cmd = "echo $((`cat /sys/class/thermal/thermal_zone0/temp | cut -c1-2`))";
$output = shell_exec($cmd);
$celsius = str_replace(array("\r\n","\r","\n"),"", $output);
$fahrenheit = round(str_replace(["\r\n","\r","\n"],"", $output*9./5)+32);
// Reparse setupVars.conf here, as we might have switched temperature units above
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
if(isset($setupVars['TEMPERATUREUNIT']))
{
$temperatureunit = $setupVars['TEMPERATUREUNIT'];
@@ -58,6 +43,35 @@
$_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 page3
if(isset($_POST["field"]))
{
if($_POST["field"] === "webUI" && isset($_POST["boxedlayout"]))
{
$boxedlayout = true;
}
elseif($_POST["field"] === "webUI" && !isset($_POST["boxedlayout"]))
{
$boxedlayout = false;
}
}
?>
<!DOCTYPE html>
@@ -95,7 +109,7 @@
<script src="js/other/respond.min.js"></script>
<![endif]-->
</head>
<body class="skin-blue sidebar-mini">
<body class="skin-blue sidebar-mini <?php if($boxedlayout){ ?>layout-boxed<?php } ?>">
<!-- JS Warning -->
<div>
<link rel="stylesheet" type="text/css" href="css/js-warn.css">
@@ -288,6 +302,12 @@
echo ' <li><a href="#" id="flip-status"><i class="fa fa-play"></i> <span>Enable</span></a></li>';
}
?>
<!-- Settings -->
<li>
<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
+11 -27
View File
@@ -19,20 +19,7 @@
<p>Shows different status messages:</p>
<ul>
<li>Status: Current status of the Pi-hole - Active (<i class="fa fa-circle" style="color:#7FFF00"></i>), Offline (<i class="fa fa-circle" style="color:#FF0000"></i>), or Starting (<i class="fa fa-circle" style="color:#ff9900"></i>)</li>
<li>Temp: Current CPU temperature
<?php
if($temperatureunit != "F"){
?>
(switch unit to <a href="help.php?tempunit=fahrenheit">Fahrenheit</a>)
<?php
}
else
{
?>
(switch unit to <a href="help.php?tempunit=celsius">Celsius</a>)
<?php
}
?></li>
<li>Temp: Current CPU temperature</li>
<li>Load: load averages for the last minute, 5 minutes and 15 minutes, respectively. A load average of 1 reflects the full workload of a single processor on the system. We show a red icon if the current load exceeds the number of available processors on this machine (which is <?php echo $nproc; ?>)</li>
<li>Memory usage: Shows the percentage of memory actually blocked by applications. We show a red icon if the memory usage exceeds 75%</li>
</ul>
@@ -104,6 +91,16 @@
Disables/enables Pi-Hole blocking completely. You may have to wait a few minutes for the changes to reach all of your devices. The change will be reflected by a changed status (top left)
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Setings</h2>
Change settings for the Pi-Hole
<h4>Networking</h4>
Displays information about the interfaces of the Pi-Hole. No changes possible
<h4>Pi-Hole DHCP Server</h4>
Using this setting you can enable/disable the DHCP server of the Pi-Hole. Note that you should disable any other DHCP server on your network to avoid IP addresses being used more than once. You have to give the range of IPs that DHCP will serve and the IP of the local router (gateway). If the DHCP server is active, the current leases are shown on the settings page.
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Donate</h2>
@@ -136,21 +133,8 @@
Shows the currently installed Pi-hole and Web Interface version. If an update is available, this will be indicated here
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Emergency help</h2>
Depending on your system and how heavily your Pi-hole is used, you may want to flush the log throughout the day by clicking on <a href="#" id="flush">FLUSH</a>. By default, the log if flushed at the end of the day via cron, but a very large log file can slow down the Web interface, so flushing it can be useful.
Note that your statistics will be reset and you lose the statistics up to this point.
</div>
</div>
<?php
// Web based flushing of pi-hole log file
if (isset($_GET["flush"]))
{
exec("sudo pihole -f");
}
require "footer.php";
?>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

+13 -3
View File
@@ -117,8 +117,18 @@
</div>
</div>
<?php
if($boxedlayout)
{
$tablelayout = "col-md-6";
}
else
{
$tablelayout = "col-md-6 col-lg-4";
}
?>
<div class="row">
<div class="col-md-4">
<div class="<?php echo $tablelayout; ?>">
<div class="box" id="domain-frequency">
<div class="box-header with-border">
<h3 class="box-title">Top Domains</h3>
@@ -145,7 +155,7 @@
<!-- /.box -->
</div>
<!-- /.col -->
<div class="col-md-4">
<div class="<?php echo $tablelayout; ?>">
<div class="box" id="ad-frequency">
<div class="box-header with-border">
<h3 class="box-title">Top Advertisers</h3>
@@ -172,7 +182,7 @@
<!-- /.box -->
</div>
<!-- /.col -->
<div class="col-md-4">
<div class="<?php echo $tablelayout; ?>">
<div class="box" id="client-frequency">
<div class="box-header with-border">
<h3 class="box-title">Top Clients</h3>
+14
View File
@@ -0,0 +1,14 @@
/*!
* jquery.confirm
*
* @version 2.3.1
*
* @author My C-Labs
* @author Matthieu Napoli <matthieu@mnapoli.fr>
* @author Russel Vela
* @author Marcus Schwarz <msspamfang@gmx.de>
*
* @license MIT
* @url https://myclabs.github.io/jquery.confirm/
*/
(function(a){a.fn.confirm=function(b){if(typeof b==="undefined"){b={}}this.click(function(c){c.preventDefault();var d=a.extend({button:a(this)},b);a.confirm(d,c)});return this};a.confirm=function(k,g){if(typeof k=="undefined"){console.error("No options given.");return}if(a(".confirmation-modal").length>0){return}var j={};if(k.button){var c={title:"title",text:"text","confirm-button":"confirmButton","submit-form":"submitForm","cancel-button":"cancelButton","confirm-button-class":"confirmButtonClass","cancel-button-class":"cancelButtonClass","dialog-class":"dialogClass","modal-options-backdrop":"modalOptionsBackdrop","modal-options-keyboard":"modalOptionsKeyboard"};a.each(c,function(e,l){var m=k.button.data(e);if(typeof m!="undefined"){j[l]=m}})}var d=a.extend({},a.confirm.options,{confirm:function(){if(j.submitForm||(typeof j.submitForm=="undefined"&&k.submitForm)||(typeof j.submitForm=="undefined"&&typeof k.submitForm=="undefined"&&a.confirm.options.submitForm)){g.target.closest("form").submit()}else{var e=g&&(("string"===typeof g&&g)||(g.currentTarget&&g.currentTarget.attributes.href.value));if(e){if(k.post){var l=a('<form method="post" class="hide" action="'+e+'"></form>');a("body").append(l);l.submit()}else{window.location=e}}}},cancel:function(e){},button:null},k,j);var b="";if(d.title!==""){b='<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button><h4 class="modal-title">'+d.title+"</h4></div>"}var h="";if(d.cancelButton){h='<button class="cancel btn '+d.cancelButtonClass+'" type="button" data-dismiss="modal">'+d.cancelButton+"</button>"}var f='<div class="confirmation-modal modal fade" tabindex="-1" role="dialog"><div class="'+d.dialogClass+'"><div class="modal-content">'+b+'<div class="modal-body">'+d.text+'</div><div class="modal-footer"><button class="confirm btn '+d.confirmButtonClass+'" type="button" data-dismiss="modal">'+d.confirmButton+"</button>"+h+"</div></div></div></div>";var i=a(f);if(typeof d.modalOptionsBackdrop!="undefined"||typeof d.modalOptionsKeyboard!="undefined"){i.modal({backdrop:d.modalOptionsBackdrop,keyboard:d.modalOptionsKeyboard})}i.on("shown.bs.modal",function(){i.find(".btn-primary:first").focus()});i.on("hidden.bs.modal",function(){i.remove()});i.find(".confirm").click(function(){d.confirm(d.button)});i.find(".cancel").click(function(){d.cancel(d.button)});a("body").append(i);i.modal("show")};a.confirm.options={text:"Are you sure?",title:"",confirmButton:"Yes",cancelButton:"Cancel",post:false,submitForm:false,confirmButtonClass:"btn-primary",cancelButtonClass:"btn-default",dialogClass:"modal-dialog",modalOptionsBackdrop:true,modalOptionsKeyboard:true}})(jQuery);
+122
View File
@@ -0,0 +1,122 @@
/*
Input Mask plugin extensions
http://github.com/RobinHerbots/jquery.inputmask
Copyright (c) 2010 - 2014 Robin Herbots
Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
Version: 0.0.0
Optional extensions on the jquery.inputmask base
*/
(function ($) {
//extra definitions
$.extend($.inputmask.defaults.definitions, {
'A': {
validator: "[A-Za-z]",
cardinality: 1,
casing: "upper" //auto uppercasing
},
'#': {
validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]",
cardinality: 1,
casing: "upper"
}
});
$.extend($.inputmask.defaults.aliases, {
'url': {
mask: "ir",
placeholder: "",
separator: "",
defaultPrefix: "http://",
regex: {
urlpre1: new RegExp("[fh]"),
urlpre2: new RegExp("(ft|ht)"),
urlpre3: new RegExp("(ftp|htt)"),
urlpre4: new RegExp("(ftp:|http|ftps)"),
urlpre5: new RegExp("(ftp:/|ftps:|http:|https)"),
urlpre6: new RegExp("(ftp://|ftps:/|http:/|https:)"),
urlpre7: new RegExp("(ftp://|ftps://|http://|https:/)"),
urlpre8: new RegExp("(ftp://|ftps://|http://|https://)")
},
definitions: {
'i': {
validator: function (chrs, buffer, pos, strict, opts) {
return true;
},
cardinality: 8,
prevalidator: (function () {
var result = [], prefixLimit = 8;
for (var i = 0; i < prefixLimit; i++) {
result[i] = (function () {
var j = i;
return {
validator: function (chrs, buffer, pos, strict, opts) {
if (opts.regex["urlpre" + (j + 1)]) {
var tmp = chrs, k;
if (((j + 1) - chrs.length) > 0) {
tmp = buffer.join('').substring(0, ((j + 1) - chrs.length)) + "" + tmp;
}
var isValid = opts.regex["urlpre" + (j + 1)].test(tmp);
if (!strict && !isValid) {
pos = pos - j;
for (k = 0; k < opts.defaultPrefix.length; k++) {
buffer[pos] = opts.defaultPrefix[k]; pos++;
}
for (k = 0; k < tmp.length - 1; k++) {
buffer[pos] = tmp[k]; pos++;
}
return { "pos": pos };
}
return isValid;
} else {
return false;
}
}, cardinality: j
};
})();
}
return result;
})()
},
"r": {
validator: ".",
cardinality: 50
}
},
insertMode: false,
autoUnmask: false
},
"ip": { //ip-address mask
mask: ["[[x]y]z.[[x]y]z.[[x]y]z.x[yz]", "[[x]y]z.[[x]y]z.[[x]y]z.[[x]y][z]"],
definitions: {
'x': {
validator: "[012]",
cardinality: 1,
definitionSymbol: "i"
},
'y': {
validator: function (chrs, buffer, pos, strict, opts) {
if (pos - 1 > -1 && buffer[pos - 1] != ".")
chrs = buffer[pos - 1] + chrs;
else chrs = "0" + chrs;
return new RegExp("2[0-5]|[01][0-9]").test(chrs);
},
cardinality: 1,
definitionSymbol: "i"
},
'z': {
validator: function (chrs, buffer, pos, strict, opts) {
if (pos - 1 > -1 && buffer[pos - 1] != ".") {
chrs = buffer[pos - 1] + chrs;
if (pos - 2 > -1 && buffer[pos - 2] != ".") {
chrs = buffer[pos - 2] + chrs;
} else chrs = "0" + chrs;
} else chrs = "00" + chrs;
return new RegExp("25[0-5]|2[0-4][0-9]|[01][0-9][0-9]").test(chrs);
},
cardinality: 1,
definitionSymbol: "i"
}
}
}
});
})(jQuery);
File diff suppressed because it is too large Load Diff
+77
View File
@@ -0,0 +1,77 @@
$(function () {
$("[data-mask]").inputmask();
});
$(".confirm-reboot").confirm({
text: "Are you sure you want to send a reboot command to your Pi-Hole?",
title: "Confirmation required",
confirm(button) {
$("#rebootform").submit();
},
cancel(button) {
// nothing to do
},
confirmButton: "Yes, reboot",
cancelButton: "No, go back",
post: true,
confirmButtonClass: "btn-danger",
cancelButtonClass: "btn-success",
dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
});
$(".confirm-restartdns").confirm({
text: "Are you sure you want to send a restart command to your DNS server?",
title: "Confirmation required",
confirm(button) {
$("#restartdnsform").submit();
},
cancel(button) {
// nothing to do
},
confirmButton: "Yes, restart DNS",
cancelButton: "No, go back",
post: true,
confirmButtonClass: "btn-danger",
cancelButtonClass: "btn-success",
dialogClass: "modal-dialog modal-mg"
});
$(".confirm-flushlogs").confirm({
text: "By default, the log is flushed at the end of the day via cron, but a very large log file can slow down the Web interface, so flushing it can be useful. Note that your statistics will be reset and you lose the statistics up to this point. Are you sure you want to flush your logs?",
title: "Confirmation required",
confirm(button) {
$("#flushlogsform").submit();
},
cancel(button) {
// nothing to do
},
confirmButton: "Yes, flush logs",
cancelButton: "No, go back",
post: true,
confirmButtonClass: "btn-danger",
cancelButtonClass: "btn-success",
dialogClass: "modal-dialog modal-mg"
});
$("#DHCPchk").click(function() {
$("input.DHCPgroup").prop("disabled", !this.checked);
});
$(document).ready(function() {
if(document.getElementById("DHCPLeasesTable"))
{
$("#DHCPLeasesTable").DataTable({
dom: "<'row'<'col-sm-12'i>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-5'f><'col-sm-7'p>>",
"pageLength": 5
});
}
} );
// Handle hiding of alerts
$(function(){
$("[data-hide]").on("click", function(){
$(this).closest("." + $(this).attr("data-hide")).hide();
});
});
+334
View File
@@ -0,0 +1,334 @@
<?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;
}
// 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);
$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"
];
if(isset($_POST["field"]))
{
$error = "";
$success = "";
// 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")
{
$secondaryIP = $_POST["DNS2IP"];
}
else
{
$secondaryIP = array_flip($secondaryDNSservers)[$secondaryDNS];
}
// Validate secondary IP
if (!validIP($secondaryIP) && 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");
$success .= "All 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";
}
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 none");
$success .= "No entries will be shown in Query Log";
}
break;
case "webUI":
if($_POST["tempunit"] == "F")
{
exec('sudo pihole -a -f');
$success .= "The webUI settings have been updated";
}
else
{
exec('sudo pihole -a -c');
$success .= "The webUI settings have been updated";
}
if(isset($_POST["boxedlayout"]))
{
exec('sudo pihole -a layout boxed');
}
else
{
exec('sudo pihole -a layout traditional');
}
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;
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;
}
?>
+510
View File
@@ -0,0 +1,510 @@
<?php
require "header.php";
require "php/savesettings.php";
// Reread ini file as things might have been changed
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
?>
<?php if(isset($debug)){ ?>
<div id="alDebug" class="alert alert-warning alert-dismissible fade in" role="alert">
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4><i class="icon fa fa-warning"></i> Debug</h4>
<?php print_r($_POST); ?>
</div>
<?php } ?>
<?php if(strlen($success) > 0){ ?>
<div id="alInfo" class="alert alert-info alert-dismissible fade in" role="alert">
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4><i class="icon fa fa-info"></i> Info</h4>
<?php echo $success; ?>
</div>
<?php } ?>
<?php if(strlen($error) > 0){ ?>
<div id="alError" class="alert alert-danger alert-dismissible fade in" role="alert">
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4><i class="icon fa fa-ban"></i> Error</h4>
<?php echo $error; ?>
</div>
<?php } ?>
<div class="row">
<div class="col-md-6">
<?php
// Networking
if(isset($setupVars["PIHOLE_INTERFACE"])){
$piHoleInterface = $setupVars["PIHOLE_INTERFACE"];
} else {
$piHoleInterface = "unknown";
}
if(isset($setupVars["IPV4_ADDRESS"])){
$piHoleIPv4 = $setupVars["IPV4_ADDRESS"];
} else {
$piHoleIPv4 = "unknown";
}
if(isset($setupVars["IPV6_ADDRESS"])){
$piHoleIPv6 = $setupVars["IPV6_ADDRESS"];
} else {
$piHoleIPv6 = "unknown";
}
$hostname = trim(file_get_contents("/etc/hostname"), "\x00..\x1F");
?>
<div class="box box-warning">
<div class="box-header with-border">
<h3 class="box-title">Networking</h3>
</div>
<div class="box-body">
<div class="form-group">
<label>Pi-Hole Ethernet Interface</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-plug"></i></div>
<input type="text" class="form-control" disabled value="<?php echo $piHoleInterface; ?>">
</div>
</div>
<div class="form-group">
<label>Pi-Hole IPv4 address</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-plug"></i></div>
<input type="text" class="form-control" disabled value="<?php echo $piHoleIPv4; ?>">
</div>
</div>
<div class="form-group">
<label>Pi-Hole IPv6 address</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-plug"></i></div>
<input type="text" class="form-control" disabled value="<?php echo $piHoleIPv6; ?>">
</div>
</div>
<div class="form-group">
<label>Pi-Hole hostname</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-laptop"></i></div>
<input type="text" class="form-control" disabled value="<?php echo $hostname; ?>">
</div>
</div>
</div>
</div>
<?php
// Pi-Hole DHCP server
if(isset($setupVars["DHCP_ACTIVE"]))
{
if($setupVars["DHCP_ACTIVE"] == 1)
{
$DHCP = true;
}
else
{
$DHCP = false;
}
// Read setings from config file
$DHCPstart = $setupVars["DHCP_START"];
$DHCPend = $setupVars["DHCP_END"];
$DHCProuter = $setupVars["DHCP_ROUTER"];
}
else
{
$DHCP = false;
// Try to guess initial settings
$DHCPdomain = explode(".",$piHoleIPv4);
$DHCPstart = $DHCPdomain[0].".".$DHCPdomain[1].".".$DHCPdomain[2].".201";
$DHCPend = $DHCPdomain[0].".".$DHCPdomain[1].".".$DHCPdomain[2].".251";
$DHCProuter = $DHCPdomain[0].".".$DHCPdomain[1].".".$DHCPdomain[2].".1";
}
if(isset($setupVars["PIHOLE_DOMAIN"])){
$piHoleDomain = $setupVars["PIHOLE_DOMAIN"];
} else {
$piHoleDomain = "local";
}
?>
<div class="box box-warning">
<div class="box-header with-border">
<h3 class="box-title">Pi-Hole DHCP Server</h3>
</div>
<div class="box-body">
<form role="form" method="post">
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="active" <?php if($DHCP){ ?>checked<?php } ?> id="DHCPchk"> DHCP server enabled</label></div>
</div>
<label>Range of IP addresses to hand out</label>
<div class="form-group">
<div class="col-md-6">
<div class="input-group">
<div class="input-group-addon">From</div>
<input type="text" class="form-control DHCPgroup" name="from" value="<?php echo $DHCPstart; ?>" data-inputmask="'alias': 'ip'" data-mask <?php if(!$DHCP){ ?>disabled<?php } ?>>
</div>
</div>
<div class="col-md-6">
<div class="input-group">
<div class="input-group-addon">To</div>
<input type="text" class="form-control DHCPgroup" name="to" value="<?php echo $DHCPend; ?>" data-inputmask="'alias': 'ip'" data-mask <?php if(!$DHCP){ ?>disabled<?php } ?>>
</div>
</div>
<label>Router IP address</label>
<div class="col-md-12">
<div class="input-group">
<div class="input-group-addon">Router</div>
<input type="text" class="form-control DHCPgroup" name="router" value="<?php echo $DHCProuter; ?>" data-inputmask="'alias': 'ip'" data-mask <?php if(!$DHCP){ ?>disabled<?php } ?>>
</div>
</div><br/>
<label>Pi-Hole domain name</label>
<div class="col-md-12">
<div class="input-group">
<div class="input-group-addon">Domain</div>
<input type="text" class="form-control DHCPgroup" name="domain" value="<?php echo $piHoleDomain; ?>" <?php if(!$DHCP){ ?>disabled<?php } ?>>
</div>
</div>
<br/>
<?php if($DHCP) {
// Read leases file
$leasesfile = true;
$dhcpleases = fopen('/etc/pihole/dhcp.leases', 'r') or $leasesfile = false;
$dhcp_leases = [];
while(!feof($dhcpleases) && $leasesfile)
{
$line = explode(" ",trim(fgets($dhcpleases)));
if(count($line) > 1)
{
array_push($dhcp_leases,["MAC"=>$line[1], "IP"=>$line[2], "NAME"=>$line[3]]);
}
}
?>
<label>DHCP leases</label>
<div class="col-md-12">
<table id="DHCPLeasesTable" class="table table-striped table-bordered dt-responsive nowrap" cellspacing="0" width="100%">
<thead>
<tr>
<th>IP address</th>
<th>Hostname</th>
<th>MAC address</th>
</tr>
</thead>
<tbody>
<?php foreach($dhcp_leases as $lease) { ?><tr><td><?php echo $lease["IP"]; ?></td><td><?php echo $lease["NAME"]; ?></td><td><?php echo $lease["MAC"]; ?></td></tr><?php } ?>
</tbody>
</table>
</div>
<?php } ?>
</div>
</div>
<div class="box-footer">
<input type="hidden" name="field" value="DHCP">
<button type="submit" class="btn btn-primary pull-right">Save</button>
</div>
</form>
</div>
<?php
// DNS settings
if(isset($setupVars["PIHOLE_DNS_1"])){
if(isset($primaryDNSservers[$setupVars["PIHOLE_DNS_1"]]))
{
$piHoleDNS1 = $primaryDNSservers[$setupVars["PIHOLE_DNS_1"]];
}
else
{
$piHoleDNS1 = "Custom";
}
} else {
$piHoleDNS1 = "unknown";
}
if(isset($setupVars["PIHOLE_DNS_2"])){
if(isset($secondaryDNSservers[$setupVars["PIHOLE_DNS_2"]]))
{
$piHoleDNS2 = $secondaryDNSservers[$setupVars["PIHOLE_DNS_2"]];
}
else
{
$piHoleDNS2 = "Custom";
}
} else {
$piHoleDNS2 = "unknown";
}
if(isset($setupVars["DNS_FQDN_REQUIRED"])){
if($setupVars["DNS_FQDN_REQUIRED"])
{
$DNSrequiresFQDN = true;
}
else
{
$DNSrequiresFQDN = false;
}
} else {
$DNSrequiresFQDN = true;
}
if(isset($setupVars["DNS_BOGUS_PRIV"])){
if($setupVars["DNS_BOGUS_PRIV"])
{
$DNSbogusPriv = true;
}
else
{
$DNSbogusPriv = false;
}
} else {
$DNSbogusPriv = true;
}
?>
<div class="box box-warning">
<div class="box-header with-border">
<h3 class="box-title">Upstream DNS Servers</h3>
</div>
<div class="box-body">
<form role="form" method="post">
<div class="col-lg-6">
<label>Primary DNS Server</label>
<div class="form-group">
<?php foreach ($primaryDNSservers as $key => $value) { ?> <div class="radio"><label><input type="radio" name="primaryDNS" value="<?php echo $value;?>" <?php if($piHoleDNS1 === $value){ ?>checked<?php } ?> ><?php echo $value;?> (<?php echo $key;?>)</label></div> <?php } ?>
<label>Custom</label>
<div class="input-group">
<div class="input-group-addon"><input type="radio" name="primaryDNS" value="Custom"
<?php if($piHoleDNS1 === "Custom"){ ?>checked<?php } ?>></div>
<input type="text" name="DNS1IP" class="form-control" data-inputmask="'alias': 'ip'" data-mask
<?php if($piHoleDNS1 === "Custom"){ ?>value="<?php echo $setupVars["PIHOLE_DNS_1"]; ?>"<?php } ?>>
</div>
</div>
</div>
<div class="col-lg-6">
<label>Secondary DNS Server</label>
<div class="form-group">
<?php foreach ($secondaryDNSservers as $key => $value) { ?> <div class="radio"><label><input type="radio" name="secondaryDNS" value="<?php echo $value;?>" <?php if($piHoleDNS2 === $value){ ?>checked<?php } ?> ><?php echo $value;?> (<?php echo $key;?>)</label></div> <?php } ?>
<label>Custom</label>
<div class="input-group">
<div class="input-group-addon"><input type="radio" name="secondaryDNS" value="Custom"
<?php if($piHoleDNS2 === "Custom"){ ?>checked<?php } ?>></div>
<input type="text" name="DNS2IP" class="form-control" data-inputmask="'alias': 'ip'" data-mask
<?php if($piHoleDNS2 === "Custom"){ ?>value="<?php echo $setupVars["PIHOLE_DNS_2"]; ?>"<?php } ?>>
</div>
</div>
</div>
<div class="col-lg-12">
<div class="box box-warning collapsed-box">
<div class="box-header with-border">
<h3 class="box-title">Advanced DNS settings</h3>
<div class="box-tools pull-right"><button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button></div>
</div>
<div class="box-body">
<div class="col-lg-12">
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="DNSrequiresFQDN" <?php if($DNSrequiresFQDN){ ?>checked<?php } ?>> never forward non-FQDNs</label></div>
</div>
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="DNSbogusPriv" <?php if($DNSbogusPriv){ ?>checked<?php } ?>> never forward reverse lookups for private IP ranges</label></div>
</div>
<p>Note that enabling these two options may increase your privacy slightly, but may also prevent you from being able to access local hostnames if the Pi-Hole is not used as DHCP server</p>
</div>
</div>
</div>
</div>
</div>
<div class="box-footer">
<input type="hidden" name="field" value="DNS">
<button type="submit" class="btn btn-primary pull-right">Save</button>
</div>
</form>
</div>
</div>
<div class="col-md-6">
<?php
// Query logging
if(isset($setupVars["QUERY_LOGGING"]))
{
if($setupVars["QUERY_LOGGING"] == 1)
{
$piHoleLogging = true;
}
else
{
$piHoleLogging = false;
}
} else {
$piHoleLogging = true;
}
?>
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Query Logging (size of log <?php echo formatSizeUnits(filesize("/var/log/pihole.log")); ?>)</h3>
</div>
<div class="box-body">
<p>Current status:
<?php if($piHoleLogging) { ?>
Enabled (recommended)
<?php }else{ ?>
Disabled
<?php } ?></p>
<?php if($piHoleLogging) { ?>
<p>Note that disabling will render graphs on the web user interface useless</p>
<?php } ?>
</div>
<div class="box-footer">
<form role="form" method="post">
<input type="hidden" name="field" value="Logging">
<?php if($piHoleLogging) { ?>
<input type="hidden" name="action" value="Disable">
<button type="submit" class="btn btn-primary pull-right">Disable query logging</button>
<?php } else { ?>
<input type="hidden" name="action" value="Enable">
<button type="submit" class="btn btn-primary pull-right">Enable query logging</button>
<?php } ?>
</form>
</div>
</div>
<?php
// Excluded domains in API Query Log call
if(isset($setupVars["API_EXCLUDE_DOMAINS"]))
{
$excludedDomains = explode(",", $setupVars["API_EXCLUDE_DOMAINS"]);
} else {
$excludedDomains = "";
}
// Exluded clients in API Query Log call
if(isset($setupVars["API_EXCLUDE_CLIENTS"]))
{
$excludedClients = explode(",", $setupVars["API_EXCLUDE_CLIENTS"]);
} else {
$excludedClients = "";
}
// Exluded clients
if(isset($setupVars["API_QUERY_LOG_SHOW"]))
{
$queryLog = $setupVars["API_QUERY_LOG_SHOW"];
} else {
$queryLog = "all";
}
?>
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">API</h3>
</div>
<form role="form" method="post">
<div class="box-body">
<h4>Top Lists</h4>
<p>Exclude the following domains from being shown in</p>
<div class="col-lg-6">
<div class="form-group">
<label>Top Domains / Top Advertisers</label>
<textarea name="domains" class="form-control" rows="4" placeholder="Enter one domain per line"><?php foreach ($excludedDomains as $domain) { echo $domain."\n"; } ?></textarea>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>Top Clients</label>
<textarea name="clients" class="form-control" rows="4" placeholder="Enter one IP address per line"><?php foreach ($excludedClients as $client) { echo $client."\n"; } ?></textarea>
</div>
</div>
<h4>Query Log</h4>
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="querylog-permitted" <?php if($queryLog === "permittedonly" || $queryLog === "all"){ ?>checked<?php } ?>> Show permitted queries</label></div>
<div class="checkbox"><label><input type="checkbox" name="querylog-blocked" <?php if($queryLog === "blockedonly" || $queryLog === "all"){ ?>checked<?php } ?>> Show blocked queries</label></div>
</div>
</div>
<div class="box-footer">
<input type="hidden" name="field" value="API">
<button type="submit" class="btn btn-primary pull-right">Save</button>
</div>
</form>
</div>
<?php
// CPU temperature unit
if(isset($setupVars["TEMPERATUREUNIT"]))
{
$temperatureunit = $setupVars["TEMPERATUREUNIT"];
}
else
{
$temperatureunit = "C";
}
// Use $boxedlayout value determined in header.php
?>
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">Web User Interface</h3>
</div>
<form role="form" method="post">
<div class="box-body">
<?php /*
<h4>Query Log Page</h4>
<div class="col-lg-6">
<div class="form-group">
<label>Default value for <em>Show XX entries</em></label>
<select class="form-control" disabled>
<option>10</option>
<option>25</option>
<option>50</option>
<option>100</option>
<option>All</option>
</select>
</div>
</div>
*/ ?>
<h4>Interface appearance</h4>
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="boxedlayout" value="yes" <?php if($boxedlayout){ ?>checked<?php } ?> >Use boxed layout (helpful when working on large screens)</label></div>
</div>
<h4>CPU Temperature Unit</h4>
<div class="form-group">
<div class="radio"><label><input type="radio" name="tempunit" value="C" <?php if($temperatureunit === "C"){ ?>checked<?php } ?> >Celsius</label></div>
<div class="radio"><label><input type="radio" name="tempunit" value="F" <?php if($temperatureunit === "F"){ ?>checked<?php } ?> >Fahrenheit</label></div>
</div>
</div>
<div class="box-footer">
<input type="hidden" name="field" value="webUI">
<button type="submit" class="btn btn-primary pull-right">Save</button>
</div>
</form>
</div>
<?php /*
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">Blocking Page</h3>
</div>
<div class="box-body">
<p>Show page with details if a site is blocked</p>
<div class="form-group">
<div class="radio"><label><input type="radio" name="blockingPage" value="Yes" <?php if($pishowBlockPage){ ?>checked<?php } ?> disabled>Yes</label></div>
<div class="radio"><label><input type="radio" name="blockingPage" value="No" <?php if(!$pishowBlockPage){ ?>checked<?php } ?> disabled>No</label></div>
<p>If Yes: Hide content for in page ads?</p>
<div class="checkbox"><label><input type="checkbox" <?php if($pishowBlockPageInpage) { ?>checked<?php } ?> disabled>Enabled (recommended)</label></div>
</div>
</div>
</div>
*/ ?>
<div class="box box-danger">
<div class="box-header with-border">
<h3 class="box-title">System Administration</h3>
</div>
<div class="box-body">
<button type="button" class="btn btn-default confirm-reboot">Restart system</button>
<button type="button" class="btn btn-default confirm-restartdns">Restart DNS server</button>
<button type="button" class="btn btn-default confirm-flushlogs">Flush logs</button>
<form role="form" method="post" id="rebootform">
<input type="hidden" name="field" value="reboot">
</form>
<form role="form" method="post" id="restartdnsform">
<input type="hidden" name="field" value="restartdns">
</form>
<form role="form" method="post" id="flushlogsform">
<input type="hidden" name="field" value="flushlogs">
</form>
</div>
</div>
</div>
</div>
<?php
require "footer.php";
?>
<script src="js/other/jquery.inputmask.js"></script>
<script src="js/other/jquery.inputmask.extensions.js"></script>
<script src="js/other/jquery.confirm.min.js"></script>
<script src="js/pihole/settings.js"></script>