mirror of
https://github.com/pi-hole/web.git
synced 2025-12-24 12:48:29 +00:00
Merge branch 'release/v5.2' into new/mac_clients
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
25
.github/workflows/codeql.yml
vendored
Normal file
25
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: "Code Scanning - Action"
|
||||
|
||||
on:
|
||||
push:
|
||||
schedule:
|
||||
- cron: "0 0 * * 0"
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: javascript
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
10
api.php
10
api.php
@@ -52,7 +52,10 @@ elseif (isset($_GET['enable']) && $auth)
|
||||
}
|
||||
pihole_execute('enable');
|
||||
$data = array_merge($data, array("status" => "enabled"));
|
||||
unlink("../custom_disable_timer");
|
||||
if (file_exists("../custom_disable_timer"))
|
||||
{
|
||||
unlink("../custom_disable_timer");
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['disable']) && $auth)
|
||||
{
|
||||
@@ -77,7 +80,10 @@ elseif (isset($_GET['disable']) && $auth)
|
||||
else
|
||||
{
|
||||
pihole_execute('disable');
|
||||
unlink("../custom_disable_timer");
|
||||
if (file_exists("../custom_disable_timer"))
|
||||
{
|
||||
unlink("../custom_disable_timer");
|
||||
}
|
||||
}
|
||||
$data = array_merge($data, array("status" => "disabled"));
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js"></script>
|
||||
<script src="scripts/vendor/daterangepicker.min.js"></script>
|
||||
<script src="scripts/pi-hole/js/db_queries.js"></script>
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js"></script>
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js"></script>
|
||||
<script src="scripts/pi-hole/js/customdns.js"></script>
|
||||
|
||||
|
||||
1398
package-lock.json
generated
1398
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -23,11 +23,11 @@
|
||||
"test": "npm run prettier:check && npm run xo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^9.8.0",
|
||||
"eslint-plugin-compat": "^3.7.0",
|
||||
"autoprefixer": "^9.8.5",
|
||||
"eslint-plugin-compat": "^3.8.0",
|
||||
"postcss-cli": "^7.1.1",
|
||||
"prettier": "2.0.4",
|
||||
"xo": "^0.32.0"
|
||||
"xo": "^0.32.1"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults",
|
||||
|
||||
12
queries.php
12
queries.php
@@ -138,11 +138,11 @@ if(strlen($showing) > 0)
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div>
|
||||
<input type="checkbox" id="autofilter">
|
||||
<label for="autofilter">Apply filtering on click on Type, Domain, and Clients</label>
|
||||
</div>
|
||||
<button type="button" id="resetButton" class="btn btn-default btn-sm text-red hidden">Clear Filters</button>
|
||||
<p><strong>Filtering options:</strong></p>
|
||||
<ul>
|
||||
<li>Use <kbd>Ctrl</kbd> or <kbd>⌘</kbd> + <i class="fas fa-mouse-pointer"></i> to add columns to the current filter</li>
|
||||
<li>Use <kbd>Shift</kbd> + <i class="fas fa-mouse-pointer"></i> to remove columns from the current filter</li>
|
||||
</ul><br/><button type="button" id="resetButton" class="btn btn-default btn-sm text-red hidden">Clear filters</button>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
</div>
|
||||
@@ -150,7 +150,7 @@ if(strlen($showing) > 0)
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js"></script>
|
||||
<script src="scripts/pi-hole/js/queries.js"></script>
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ function add(domain, list) {
|
||||
domain: domain,
|
||||
list: list,
|
||||
token: token,
|
||||
action: "add_domain",
|
||||
action: list === "audit" ? "add_audit" : "add_domain",
|
||||
comment: "Added from Audit Log"
|
||||
},
|
||||
success: function () {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global utils:false */
|
||||
|
||||
var table;
|
||||
var token = $("#token").text();
|
||||
|
||||
@@ -76,8 +78,8 @@ $(function () {
|
||||
});
|
||||
|
||||
function addCustomDNS() {
|
||||
var ip = $("#ip").val();
|
||||
var domain = $("#domain").val();
|
||||
var ip = utils.escapeHtml($("#ip").val());
|
||||
var domain = utils.escapeHtml($("#domain").val());
|
||||
|
||||
showAlert("info");
|
||||
$.ajax({
|
||||
|
||||
@@ -373,7 +373,7 @@ $(function () {
|
||||
},
|
||||
{ width: "10%" },
|
||||
{ width: "40%" },
|
||||
{ width: "20%" },
|
||||
{ width: "20%", type: "ip-address" },
|
||||
{ width: "10%" },
|
||||
{ width: "5%" }
|
||||
],
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
/* global initpage:false */
|
||||
|
||||
//The following functions allow us to display time until pi-hole is enabled after disabling.
|
||||
//Works between all pages
|
||||
@@ -221,10 +220,6 @@ $(function () {
|
||||
initCheckboxRadioStyle();
|
||||
initCPUtemp();
|
||||
|
||||
if (typeof initpage === "function") {
|
||||
setTimeout(initpage, 100);
|
||||
}
|
||||
|
||||
// Run check immediately after page loading ...
|
||||
checkMessages();
|
||||
// ... and once again with five seconds delay
|
||||
|
||||
@@ -55,9 +55,9 @@ function initTable() {
|
||||
$(row).attr("data-id", data.id);
|
||||
var tooltip =
|
||||
"Added: " +
|
||||
utils.datetime(data.date_added) +
|
||||
utils.datetime(data.date_added, false) +
|
||||
"\nLast modified: " +
|
||||
utils.datetime(data.date_modified) +
|
||||
utils.datetime(data.date_modified, false) +
|
||||
"\nDatabase ID: " +
|
||||
data.id;
|
||||
$("td:eq(0)", row).html(
|
||||
@@ -212,8 +212,8 @@ function initTable() {
|
||||
}
|
||||
|
||||
function addAdlist() {
|
||||
var address = $("#new_address").val();
|
||||
var comment = $("#new_comment").val();
|
||||
var address = utils.escapeHtml($("#new_address").val());
|
||||
var comment = utils.escapeHtml($("#new_comment").val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Adding adlist...", address);
|
||||
@@ -258,9 +258,9 @@ function editAdlist() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
|
||||
var comment = tr.find("#comment_" + id).val();
|
||||
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
|
||||
var groups = tr.find("#multiselect_" + id).val();
|
||||
var address = tr.find("#address_" + id).text();
|
||||
var address = utils.escapeHtml(tr.find("#address_" + id).text());
|
||||
|
||||
var done = "edited";
|
||||
var notDone = "editing";
|
||||
@@ -338,7 +338,7 @@ function editAdlist() {
|
||||
function deleteAdlist() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var address = tr.find("#address_" + id).text();
|
||||
var address = utils.escapeHtml(tr.find("#address_" + id).text());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting adlist...", address);
|
||||
|
||||
@@ -106,9 +106,9 @@ function initTable() {
|
||||
$(row).attr("data-id", data.id);
|
||||
var tooltip =
|
||||
"Added: " +
|
||||
utils.datetime(data.date_added) +
|
||||
utils.datetime(data.date_added, false) +
|
||||
"\nLast modified: " +
|
||||
utils.datetime(data.date_modified) +
|
||||
utils.datetime(data.date_modified, false) +
|
||||
"\nDatabase ID: " +
|
||||
data.id;
|
||||
var ipName =
|
||||
@@ -260,7 +260,7 @@ function initTable() {
|
||||
|
||||
function addClient() {
|
||||
var ip = $("#select").val().trim();
|
||||
var comment = $("#new_comment").val();
|
||||
var comment = utils.escapeHtml($("#new_comment").val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Adding client...", ip);
|
||||
@@ -318,9 +318,9 @@ function editClient() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var groups = tr.find("#multiselect_" + id).val();
|
||||
var ip = tr.find("#ip_" + id).text();
|
||||
var name = tr.find("#name_" + id).text();
|
||||
var comment = tr.find("#comment_" + id).val();
|
||||
var ip = utils.escapeHtml(tr.find("#ip_" + id).text());
|
||||
var name = utils.escapeHtml(tr.find("#name_" + id).text());
|
||||
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
|
||||
|
||||
var done = "edited";
|
||||
var notDone = "editing";
|
||||
@@ -385,7 +385,7 @@ function deleteClient() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var ip = tr.find("#ip_" + id).text();
|
||||
var name = tr.find("#name_" + id).text();
|
||||
var name = utils.escapeHtml(tr.find("#name_" + id).text());
|
||||
|
||||
if (name.length > 0) {
|
||||
ip += " (" + name + ")";
|
||||
|
||||
@@ -85,9 +85,9 @@ function initTable() {
|
||||
$(row).attr("data-id", data.id);
|
||||
var tooltip =
|
||||
"Added: " +
|
||||
utils.datetime(data.date_added) +
|
||||
utils.datetime(data.date_added, false) +
|
||||
"\nLast modified: " +
|
||||
utils.datetime(data.date_modified) +
|
||||
utils.datetime(data.date_modified, false) +
|
||||
"\nDatabase ID: " +
|
||||
data.id;
|
||||
$("td:eq(0)", row).html(
|
||||
@@ -318,8 +318,8 @@ function addDomain() {
|
||||
commentEl = $("#new_regex_comment");
|
||||
}
|
||||
|
||||
var domain = domainEl.val();
|
||||
var comment = commentEl.val();
|
||||
var domain = utils.escapeHtml(domainEl.val());
|
||||
var comment = utils.escapeHtml(commentEl.val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Adding " + domainRegex + "...", domain);
|
||||
@@ -385,10 +385,10 @@ function editDomain() {
|
||||
var elem = $(this).attr("id");
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var domain = tr.find("#domain_" + id).text();
|
||||
var domain = utils.escapeHtml(tr.find("#domain_" + id).text());
|
||||
var type = tr.find("#type_" + id).val();
|
||||
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
|
||||
var comment = tr.find("#comment_" + id).val();
|
||||
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
|
||||
|
||||
// Show group assignment field only if in full domain management mode
|
||||
// if not included, just use the row data.
|
||||
@@ -485,7 +485,7 @@ function editDomain() {
|
||||
function deleteDomain() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var domain = tr.find("#domain_" + id).text();
|
||||
var domain = utils.escapeHtml(tr.find("#domain_" + id).text());
|
||||
var type = tr.find("#type_" + id).val();
|
||||
|
||||
var domainRegex;
|
||||
|
||||
@@ -34,9 +34,9 @@ $(function () {
|
||||
$(row).attr("data-id", data.id);
|
||||
var tooltip =
|
||||
"Added: " +
|
||||
utils.datetime(data.date_added) +
|
||||
utils.datetime(data.date_added, false) +
|
||||
"\nLast modified: " +
|
||||
utils.datetime(data.date_modified) +
|
||||
utils.datetime(data.date_modified, false) +
|
||||
"\nDatabase ID: " +
|
||||
data.id;
|
||||
$("td:eq(0)", row).html(
|
||||
@@ -127,8 +127,8 @@ $(function () {
|
||||
});
|
||||
|
||||
function addGroup() {
|
||||
var name = $("#new_name").val();
|
||||
var desc = $("#new_desc").val();
|
||||
var name = utils.escapeHtml($("#new_name").val());
|
||||
var desc = utils.escapeHtml($("#new_desc").val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Adding group...", name);
|
||||
@@ -166,9 +166,9 @@ function editGroup() {
|
||||
var elem = $(this).attr("id");
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var name = tr.find("#name_" + id).val();
|
||||
var name = utils.escapeHtml(tr.find("#name_" + id).val());
|
||||
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
|
||||
var desc = tr.find("#desc_" + id).val();
|
||||
var desc = utils.escapeHtml(tr.find("#desc_" + id).val());
|
||||
|
||||
var done = "edited";
|
||||
var notDone = "editing";
|
||||
@@ -239,7 +239,7 @@ function editGroup() {
|
||||
function deleteGroup() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
var name = tr.find("#name_" + id).val();
|
||||
var name = utils.escapeHtml(tr.find("#name_" + id).val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting group...", name);
|
||||
|
||||
@@ -287,6 +287,7 @@ function updateQueriesOverTime() {
|
||||
});
|
||||
}
|
||||
|
||||
var querytypeids = [];
|
||||
function updateQueryTypesPie() {
|
||||
$.getJSON("api.php?getQueryTypes", function (data) {
|
||||
if ("FTLnotrunning" in data) {
|
||||
@@ -305,10 +306,16 @@ function updateQueryTypesPie() {
|
||||
iter = data;
|
||||
}
|
||||
|
||||
querytypeids = [];
|
||||
Object.keys(iter).forEach(function (key) {
|
||||
v.push(iter[key]);
|
||||
c.push(THEME_COLORS[i++ % THEME_COLORS.length]);
|
||||
k.push(key);
|
||||
if (iter[key] > 0) {
|
||||
v.push(iter[key]);
|
||||
c.push(THEME_COLORS[i % THEME_COLORS.length]);
|
||||
k.push(key);
|
||||
querytypeids.push(i + 1);
|
||||
}
|
||||
|
||||
i++;
|
||||
});
|
||||
|
||||
// Build a single dataset with the data to be pushed
|
||||
@@ -340,7 +347,7 @@ function updateQueryTypesPie() {
|
||||
ci.update();
|
||||
} else if (e.which === 1) {
|
||||
// which == 1 is left mouse button
|
||||
window.open("queries.php?querytype=" + ($(this).index() + 1), "_self");
|
||||
window.open("queries.php?querytype=" + querytypeids[$(this).index()], "_self");
|
||||
}
|
||||
});
|
||||
}).done(function () {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global moment:false, utils:false */
|
||||
/* global utils:false */
|
||||
|
||||
var tableApi;
|
||||
|
||||
@@ -196,7 +196,7 @@ $(function () {
|
||||
width: "8%",
|
||||
render: function (data, type) {
|
||||
if (type === "display") {
|
||||
return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
|
||||
return utils.datetime(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -207,7 +207,7 @@ $(function () {
|
||||
width: "8%",
|
||||
render: function (data, type) {
|
||||
if (type === "display") {
|
||||
return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
|
||||
return utils.datetime(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
@@ -8,6 +8,22 @@
|
||||
/* global moment:false, utils:false */
|
||||
|
||||
var tableApi;
|
||||
var tableFilters = [];
|
||||
|
||||
var replyTypes = [
|
||||
"N/A",
|
||||
"NODATA",
|
||||
"NXDOMAIN",
|
||||
"CNAME",
|
||||
"IP",
|
||||
"DOMAIN",
|
||||
"RRNAME",
|
||||
"SERVFAIL",
|
||||
"REFUSED",
|
||||
"NOTIMP",
|
||||
"upstream error"
|
||||
];
|
||||
var colTypes = ["time", "query type", "domain", "client", "status", "reply type"];
|
||||
|
||||
function add(domain, list) {
|
||||
var token = $("#token").text();
|
||||
@@ -103,10 +119,6 @@ function handleAjaxError(xhr, textStatus) {
|
||||
tableApi.draw();
|
||||
}
|
||||
|
||||
function autofilter() {
|
||||
return $("#autofilter").prop("checked");
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// Do we want to filter queries?
|
||||
var GETDict = {};
|
||||
@@ -140,7 +152,7 @@ $(function () {
|
||||
rowCallback: function (row, data) {
|
||||
// DNSSEC status
|
||||
var dnssecStatus;
|
||||
switch (data[5]) {
|
||||
switch (data[6]) {
|
||||
case "1":
|
||||
dnssecStatus = '<br><span class="text-green">SECURE</span>';
|
||||
break;
|
||||
@@ -162,37 +174,32 @@ $(function () {
|
||||
}
|
||||
|
||||
// Query status
|
||||
var blocked,
|
||||
fieldtext,
|
||||
var fieldtext,
|
||||
buttontext,
|
||||
colorClass,
|
||||
colorClass = false,
|
||||
isCNAME = false,
|
||||
regexLink = false;
|
||||
|
||||
switch (data[4]) {
|
||||
case "1":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked (gravity)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
|
||||
break;
|
||||
case "2":
|
||||
blocked = false;
|
||||
colorClass = "text-green";
|
||||
fieldtext = "OK <br class='hidden-lg'>(forwarded)" + dnssecStatus;
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
|
||||
break;
|
||||
case "3":
|
||||
blocked = false;
|
||||
colorClass = "text-green";
|
||||
fieldtext = "OK <br class='hidden-lg'>(cached)" + dnssecStatus;
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
|
||||
break;
|
||||
case "4":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(regex blacklist)";
|
||||
|
||||
@@ -204,32 +211,27 @@ $(function () {
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
|
||||
break;
|
||||
case "5":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(exact blacklist)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
|
||||
break;
|
||||
case "6":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, IP)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "7":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NULL)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "8":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NXRA)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "9":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked (gravity, CNAME)";
|
||||
buttontext =
|
||||
@@ -237,7 +239,6 @@ $(function () {
|
||||
isCNAME = true;
|
||||
break;
|
||||
case "10":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(regex blacklist, CNAME)";
|
||||
|
||||
@@ -250,7 +251,6 @@ $(function () {
|
||||
isCNAME = true;
|
||||
break;
|
||||
case "11":
|
||||
blocked = true;
|
||||
colorClass = "text-red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(exact blacklist, CNAME)";
|
||||
buttontext =
|
||||
@@ -258,12 +258,13 @@ $(function () {
|
||||
isCNAME = true;
|
||||
break;
|
||||
default:
|
||||
blocked = false;
|
||||
colorClass = false;
|
||||
fieldtext = "Unknown (" + parseInt(data[4], 10) + ")";
|
||||
buttontext = "";
|
||||
}
|
||||
|
||||
fieldtext += '<input type="hidden" name="id" value="' + data[4] + '">';
|
||||
|
||||
if (colorClass !== false) {
|
||||
$(row).addClass(colorClass);
|
||||
}
|
||||
@@ -306,49 +307,17 @@ $(function () {
|
||||
}
|
||||
|
||||
// Check for existence of sixth column and display only if not Pi-holed
|
||||
var replytext;
|
||||
if (data.length > 6 && !blocked) {
|
||||
switch (data[6]) {
|
||||
case "0":
|
||||
replytext = "N/A";
|
||||
break;
|
||||
case "1":
|
||||
replytext = "NODATA";
|
||||
break;
|
||||
case "2":
|
||||
replytext = "NXDOMAIN";
|
||||
break;
|
||||
case "3":
|
||||
replytext = "CNAME";
|
||||
break;
|
||||
case "4":
|
||||
replytext = "IP";
|
||||
break;
|
||||
case "5":
|
||||
replytext = "DOMAIN";
|
||||
break;
|
||||
case "6":
|
||||
replytext = "RRNAME";
|
||||
break;
|
||||
case "7":
|
||||
replytext = "SERVFAIL";
|
||||
break;
|
||||
case "8":
|
||||
replytext = "REFUSED";
|
||||
break;
|
||||
case "9":
|
||||
replytext = "NOTIMP";
|
||||
break;
|
||||
case "10":
|
||||
replytext = "upstream error";
|
||||
break;
|
||||
default:
|
||||
replytext = "? (" + parseInt(data[6], 10) + ")";
|
||||
}
|
||||
var replytext,
|
||||
replyid = data[5];
|
||||
|
||||
if (replyid >= 0 && replyid < replyTypes.length) {
|
||||
replytext = replyTypes[replyid];
|
||||
} else {
|
||||
replytext = "-";
|
||||
replytext = "? (" + replyid + ")";
|
||||
}
|
||||
|
||||
replytext += '<input type="hidden" name="id" value="' + replyid + '">';
|
||||
|
||||
$("td:eq(5)", row).html(replytext);
|
||||
|
||||
if (data.length > 7) {
|
||||
@@ -368,6 +337,10 @@ $(function () {
|
||||
var dataIndex = 0;
|
||||
return data.data.map(function (x) {
|
||||
x[0] = x[0] * 1e6 + dataIndex++;
|
||||
var dnssec = x[5];
|
||||
var reply = x[6];
|
||||
x[5] = reply;
|
||||
x[6] = dnssec;
|
||||
return x;
|
||||
});
|
||||
}
|
||||
@@ -390,7 +363,7 @@ $(function () {
|
||||
},
|
||||
{ width: "4%" },
|
||||
{ width: "36%", render: $.fn.dataTable.render.text() },
|
||||
{ width: "8%", render: $.fn.dataTable.render.text() },
|
||||
{ width: "8%", type: "ip-address", render: $.fn.dataTable.render.text() },
|
||||
{ width: "14%", orderData: 4 },
|
||||
{ width: "8%", orderData: 6 },
|
||||
{ width: "10%", orderData: 4 }
|
||||
@@ -415,77 +388,100 @@ $(function () {
|
||||
],
|
||||
initComplete: function () {
|
||||
var api = this.api();
|
||||
|
||||
// Query type IPv4 / IPv6
|
||||
api.$("td:eq(1)").click(function () {
|
||||
if (autofilter()) {
|
||||
api.search(this.textContent).draw();
|
||||
$("#resetButton").removeClass("hidden");
|
||||
}
|
||||
});
|
||||
api.$("td:eq(1)").hover(
|
||||
function () {
|
||||
if (autofilter()) {
|
||||
this.title = "Click to show only " + this.textContent + " queries";
|
||||
this.style.color = "#72afd2";
|
||||
} else {
|
||||
this.title = "";
|
||||
this.style.color = "";
|
||||
api
|
||||
.$("td:eq(1)")
|
||||
.click(function (event) {
|
||||
addColumnFilter(event, 1, this.textContent);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(1, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
this.style.color = "";
|
||||
}
|
||||
);
|
||||
api.$("td:eq(1)").addClass("pointer");
|
||||
);
|
||||
|
||||
// Domain
|
||||
api.$("td:eq(2)").click(function () {
|
||||
if (autofilter()) {
|
||||
var domain = this.textContent.split("\n")[0];
|
||||
api.search(domain).draw();
|
||||
$("#resetButton").removeClass("hidden");
|
||||
}
|
||||
});
|
||||
api.$("td:eq(2)").hover(
|
||||
function () {
|
||||
if (autofilter()) {
|
||||
var domain = this.textContent.split("\n")[0];
|
||||
this.title = "Click to show only queries with domain " + domain;
|
||||
this.style.color = "#72afd2";
|
||||
} else {
|
||||
this.title = "";
|
||||
this.style.color = "";
|
||||
api
|
||||
.$("td:eq(2)")
|
||||
.click(function (event) {
|
||||
addColumnFilter(event, 2, this.textContent.split("\n")[0]);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(2, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
this.style.color = "";
|
||||
}
|
||||
);
|
||||
api.$("td:eq(2)").addClass("pointer");
|
||||
);
|
||||
|
||||
// Client
|
||||
api.$("td:eq(3)").click(function () {
|
||||
if (autofilter()) {
|
||||
api.search(this.textContent).draw();
|
||||
$("#resetButton").removeClass("hidden");
|
||||
}
|
||||
});
|
||||
api.$("td:eq(3)").hover(
|
||||
function () {
|
||||
if (autofilter()) {
|
||||
this.title = "Click to show only queries made by " + this.textContent;
|
||||
this.style.color = "#72afd2";
|
||||
} else {
|
||||
this.title = "";
|
||||
this.style.color = "";
|
||||
api
|
||||
.$("td:eq(3)")
|
||||
.click(function (event) {
|
||||
addColumnFilter(event, 3, this.textContent);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(3, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
},
|
||||
function () {
|
||||
this.style.color = "";
|
||||
}
|
||||
);
|
||||
api.$("td:eq(3)").addClass("pointer");
|
||||
);
|
||||
|
||||
// Status
|
||||
api
|
||||
.$("td:eq(4)")
|
||||
.click(function (event) {
|
||||
var id = this.children.id.value;
|
||||
var text = this.textContent;
|
||||
addColumnFilter(event, 4, id + "#" + text);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(4, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
);
|
||||
|
||||
// Reply type
|
||||
api
|
||||
.$("td:eq(5)")
|
||||
.click(function (event) {
|
||||
var id = this.children.id.value;
|
||||
var text = this.textContent.split(" ")[0];
|
||||
addColumnFilter(event, 5, id + "#" + text);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(5, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
);
|
||||
|
||||
// Disable autocorrect in the search box
|
||||
var input = $("input[type=search]");
|
||||
if (input !== null) {
|
||||
input.attr("autocomplete", "off");
|
||||
input.attr("autocorrect", "off");
|
||||
input.attr("autocapitalize", "off");
|
||||
input.attr("spellcheck", false);
|
||||
input.attr("placeholder", "Type / Domain / Client");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
resetColumnsFilters();
|
||||
|
||||
$("#all-queries tbody").on("click", "button", function () {
|
||||
var data = tableApi.row($(this).parents("tr")).data();
|
||||
if (data[4] === "2" || data[4] === "3") {
|
||||
@@ -496,28 +492,84 @@ $(function () {
|
||||
});
|
||||
|
||||
$("#resetButton").click(function () {
|
||||
tableApi.search("").draw();
|
||||
$("#resetButton").addClass("hidden");
|
||||
});
|
||||
|
||||
// Disable autocorrect in the search box
|
||||
var input = document.querySelector("input[type=search]");
|
||||
input.setAttribute("autocomplete", "off");
|
||||
input.setAttribute("autocorrect", "off");
|
||||
input.setAttribute("autocapitalize", "off");
|
||||
input.setAttribute("spellcheck", false);
|
||||
|
||||
var chkboxData = localStorage.getItem("query_log_filter_chkbox");
|
||||
if (chkboxData !== null) {
|
||||
// Restore checkbox state
|
||||
$("#autofilter").prop("checked", chkboxData === "true");
|
||||
} else {
|
||||
// Initialize checkbox
|
||||
$("#autofilter").prop("checked", true);
|
||||
localStorage.setItem("query_log_filter_chkbox", true);
|
||||
}
|
||||
|
||||
$("#autofilter").click(function () {
|
||||
localStorage.setItem("query_log_filter_chkbox", $("#autofilter").prop("checked"));
|
||||
tableApi.search("");
|
||||
resetColumnsFilters();
|
||||
});
|
||||
});
|
||||
|
||||
function tooltipText(index, text) {
|
||||
if (index === 5) {
|
||||
// Strip reply time from tooltip text
|
||||
text = text.split(" ")[0];
|
||||
}
|
||||
|
||||
if (index in tableFilters && tableFilters[index].length > 0) {
|
||||
return "Clear filter on " + colTypes[index] + ' "' + text + '" using Shift + Click.';
|
||||
}
|
||||
|
||||
return "Add filter on " + colTypes[index] + ' "' + text + '" using Ctrl + Click.';
|
||||
}
|
||||
|
||||
function addColumnFilter(event, colID, filterstring) {
|
||||
// Don't do anything when NOT explicitly requesting multi-selection functions
|
||||
if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.shiftKey) {
|
||||
filterstring = "";
|
||||
}
|
||||
|
||||
tableFilters[colID] = filterstring;
|
||||
|
||||
applyColumnFiltering();
|
||||
}
|
||||
|
||||
function resetColumnsFilters() {
|
||||
tableFilters.forEach(function (value, index) {
|
||||
tableFilters[index] = "";
|
||||
});
|
||||
|
||||
// Clear filter reset button
|
||||
applyColumnFiltering();
|
||||
}
|
||||
|
||||
function applyColumnFiltering() {
|
||||
var showReset = false;
|
||||
tableFilters.forEach(function (value, index) {
|
||||
// Prepare regex filter string
|
||||
var regex = "";
|
||||
|
||||
// Split filter string if we received a combined ID#Name column
|
||||
var valArr = value.split("#");
|
||||
if (valArr.length > 0) {
|
||||
value = valArr[0];
|
||||
}
|
||||
|
||||
if (value.length > 0) {
|
||||
// Exact matching
|
||||
regex = "^" + value + "$";
|
||||
|
||||
// Add background color
|
||||
tableApi.$("td:eq(" + index + ")").addClass("highlight");
|
||||
|
||||
// Remember to show reset button
|
||||
showReset = true;
|
||||
} else {
|
||||
// Clear background color
|
||||
tableApi.$("td:eq(" + index + ")").removeClass("highlight");
|
||||
}
|
||||
|
||||
// Apply filtering on this column (regex may be empty -> no filtering)
|
||||
tableApi.column(index).search(regex, true, true);
|
||||
});
|
||||
|
||||
if (showReset) {
|
||||
$("#resetButton").removeClass("hidden");
|
||||
} else {
|
||||
$("#resetButton").addClass("hidden");
|
||||
}
|
||||
|
||||
// Trigger table update
|
||||
tableApi.draw();
|
||||
}
|
||||
|
||||
@@ -229,17 +229,6 @@ $(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip({ html: true, container: "body" });
|
||||
});
|
||||
|
||||
// Change "?tab=" parameter in URL for save and reload
|
||||
$(".nav-tabs a").on("shown.bs.tab", function (e) {
|
||||
var tab = e.target.hash.substring(1);
|
||||
window.history.pushState("", "", "?tab=" + tab);
|
||||
if (tab === "piholedhcp") {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
});
|
||||
|
||||
// Auto dismissal for info notifications
|
||||
$(function () {
|
||||
var alInfo = $("#alInfo");
|
||||
@@ -255,6 +244,25 @@ $(function () {
|
||||
input.setAttribute("autocorrect", "off");
|
||||
input.setAttribute("autocapitalize", "off");
|
||||
input.setAttribute("spellcheck", false);
|
||||
|
||||
// En-/disable conditional forwarding input fields based
|
||||
// on the checkbox state
|
||||
$('input[name="rev_server"]').click(function () {
|
||||
$('input[name="rev_server_cidr"]').prop("disabled", !this.checked);
|
||||
$('input[name="rev_server_target"]').prop("disabled", !this.checked);
|
||||
$('input[name="rev_server_domain"]').prop("disabled", !this.checked);
|
||||
});
|
||||
});
|
||||
|
||||
// Change "?tab=" parameter in URL for save and reload
|
||||
$(".nav-tabs a").on("shown.bs.tab", function (e) {
|
||||
var tab = e.target.hash.substring(1);
|
||||
window.history.pushState("", "", "?tab=" + tab);
|
||||
if (tab === "piholedhcp") {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
});
|
||||
|
||||
// Bar/Smooth chart toggle
|
||||
|
||||
@@ -104,8 +104,9 @@ function showAlert(type, icon, title, message) {
|
||||
}
|
||||
}
|
||||
|
||||
function datetime(date) {
|
||||
return moment.unix(Math.floor(date)).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
|
||||
function datetime(date, html) {
|
||||
var format = html === false ? "Y-MM-DD HH:mm:ss z" : "Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z";
|
||||
return moment.unix(Math.floor(date)).format(format);
|
||||
}
|
||||
|
||||
function disableAll() {
|
||||
@@ -208,7 +209,14 @@ function stateLoadCallback(itemName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse JSON string
|
||||
data = JSON.parse(data);
|
||||
|
||||
// Clear possible filtering settings
|
||||
data.columns.forEach(function (value, index) {
|
||||
data.columns[index].search.search = "";
|
||||
});
|
||||
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
// Always start with empty search field
|
||||
|
||||
@@ -161,9 +161,9 @@ function add_to_table($db, $table, $domains, $comment=null, $wildcardstyle=false
|
||||
if($wildcardstyle)
|
||||
$domain = "(\\.|^)".str_replace(".","\\.",$domain)."$";
|
||||
|
||||
$stmt->bindValue(":$field", $domain, SQLITE3_TEXT);
|
||||
$stmt->bindValue(":$field", htmlentities($domain), SQLITE3_TEXT);
|
||||
if($bindcomment) {
|
||||
$stmt->bindValue(":comment", $comment, SQLITE3_TEXT);
|
||||
$stmt->bindValue(":comment", htmlentities($comment), SQLITE3_TEXT);
|
||||
}
|
||||
|
||||
if($stmt->execute() && $stmt->reset())
|
||||
|
||||
@@ -214,31 +214,34 @@ function deleteCustomDNSEntry()
|
||||
|
||||
function deleteAllCustomDNSEntries()
|
||||
{
|
||||
$handle = fopen($customDNSFile, "r");
|
||||
if ($handle)
|
||||
if (isset($customDNSFile))
|
||||
{
|
||||
try
|
||||
$handle = fopen($customDNSFile, "r");
|
||||
if ($handle)
|
||||
{
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
$line = str_replace("\r","", $line);
|
||||
$line = str_replace("\n","", $line);
|
||||
$explodedLine = explode (" ", $line);
|
||||
try
|
||||
{
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
$line = str_replace("\r","", $line);
|
||||
$line = str_replace("\n","", $line);
|
||||
$explodedLine = explode (" ", $line);
|
||||
|
||||
if (count($explodedLine) != 2)
|
||||
continue;
|
||||
if (count($explodedLine) != 2)
|
||||
continue;
|
||||
|
||||
$ip = $explodedLine[0];
|
||||
$domain = $explodedLine[1];
|
||||
$ip = $explodedLine[0];
|
||||
$domain = $explodedLine[1];
|
||||
|
||||
pihole_execute("-a removecustomdns ".$ip." ".$domain);
|
||||
pihole_execute("-a removecustomdns ".$ip." ".$domain);
|
||||
}
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return errorJsonResponse($ex->getMessage());
|
||||
}
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return errorJsonResponse($ex->getMessage());
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
|
||||
return successJsonResponse();
|
||||
|
||||
@@ -58,7 +58,8 @@ if ($_POST['action'] == 'get_groups') {
|
||||
} elseif ($_POST['action'] == 'add_group') {
|
||||
// Add new group
|
||||
try {
|
||||
$names = str_getcsv(trim($_POST['name']), ' ');
|
||||
$input = html_entity_decode(trim($_POST['name']));
|
||||
$names = str_getcsv($input, ' ');
|
||||
$total = count($names);
|
||||
$added = 0;
|
||||
$stmt = $db->prepare('INSERT INTO "group" (name,description) VALUES (:name,:desc)');
|
||||
@@ -96,6 +97,9 @@ if ($_POST['action'] == 'get_groups') {
|
||||
} elseif ($_POST['action'] == 'edit_group') {
|
||||
// Edit group identified by ID
|
||||
try {
|
||||
$name = html_entity_decode($_POST['name']);
|
||||
$desc = html_entity_decode($_POST['desc']);
|
||||
|
||||
$stmt = $db->prepare('UPDATE "group" SET enabled=:enabled, name=:name, description=:desc WHERE id = :id');
|
||||
if (!$stmt) {
|
||||
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
|
||||
@@ -106,11 +110,10 @@ if ($_POST['action'] == 'get_groups') {
|
||||
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
if (!$stmt->bindValue(':name', $_POST['name'], SQLITE3_TEXT)) {
|
||||
if (!$stmt->bindValue(':name', $name, SQLITE3_TEXT)) {
|
||||
throw new Exception('While binding name: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$desc = $_POST['desc'];
|
||||
if (strlen($desc) === 0) {
|
||||
// Store NULL in database for empty descriptions
|
||||
$desc = null;
|
||||
@@ -307,7 +310,7 @@ if ($_POST['action'] == 'get_groups') {
|
||||
throw new Exception('While binding ip: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$comment = $_POST['comment'];
|
||||
$comment = html_entity_decode($_POST['comment']);
|
||||
if (strlen($comment) === 0) {
|
||||
// Store NULL in database for empty comments
|
||||
$comment = null;
|
||||
@@ -337,7 +340,7 @@ if ($_POST['action'] == 'get_groups') {
|
||||
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$comment = $_POST['comment'];
|
||||
$comment = html_entity_decode($_POST['comment']);
|
||||
if (strlen($comment) === 0) {
|
||||
// Store NULL in database for empty comments
|
||||
$comment = null;
|
||||
@@ -497,7 +500,7 @@ if ($_POST['action'] == 'get_groups') {
|
||||
} elseif ($_POST['action'] == 'add_domain') {
|
||||
// Add new domain
|
||||
try {
|
||||
$domains = explode(' ', trim($_POST['domain']));
|
||||
$domains = explode(' ', html_entity_decode(trim($_POST['domain'])));
|
||||
$before = intval($db->querySingle("SELECT COUNT(*) FROM domainlist;"));
|
||||
$total = count($domains);
|
||||
$added = 0;
|
||||
@@ -518,7 +521,7 @@ if ($_POST['action'] == 'get_groups') {
|
||||
throw new Exception('While binding type: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$comment = $_POST['comment'];
|
||||
$comment = html_entity_decode($_POST['comment']);
|
||||
if (strlen($comment) === 0) {
|
||||
// Store NULL in database for empty comments
|
||||
$comment = null;
|
||||
@@ -617,7 +620,7 @@ if ($_POST['action'] == 'get_groups') {
|
||||
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$comment = $_POST['comment'];
|
||||
$comment = html_entity_decode($_POST['comment']);
|
||||
if (strlen($comment) === 0) {
|
||||
// Store NULL in database for empty comments
|
||||
$comment = null;
|
||||
@@ -786,16 +789,16 @@ if ($_POST['action'] == 'get_groups') {
|
||||
} elseif ($_POST['action'] == 'add_adlist') {
|
||||
// Add new adlist
|
||||
try {
|
||||
$addresses = explode(' ', trim($_POST['address']));
|
||||
$addresses = explode(' ', html_entity_decode(trim($_POST['address'])));
|
||||
$total = count($addresses);
|
||||
$added = 0;
|
||||
|
||||
$stmt = $db->prepare('INSERT INTO adlist (address,comment) VALUES (:address,:comment)');
|
||||
$stmt = $db->prepare('INSERT OR IGNORE INTO adlist (address,comment) VALUES (:address,:comment)');
|
||||
if (!$stmt) {
|
||||
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$comment = $_POST['comment'];
|
||||
$comment = html_entity_decode($_POST['comment']);
|
||||
if (strlen($comment) === 0) {
|
||||
// Store NULL in database for empty comments
|
||||
$comment = null;
|
||||
@@ -844,7 +847,7 @@ if ($_POST['action'] == 'get_groups') {
|
||||
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
$comment = $_POST['comment'];
|
||||
$comment = html_entity_decode($_POST['comment']);
|
||||
if (strlen($comment) === 0) {
|
||||
// Store NULL in database for empty comments
|
||||
$comment = null;
|
||||
@@ -934,6 +937,53 @@ if ($_POST['action'] == 'get_groups') {
|
||||
} catch (\Exception $ex) {
|
||||
JSON_error($ex->getMessage());
|
||||
}
|
||||
} elseif ($_POST['action'] == 'add_audit') {
|
||||
// Add new domain
|
||||
try {
|
||||
$domains = explode(' ', html_entity_decode(trim($_POST['domain'])));
|
||||
$before = intval($db->querySingle("SELECT COUNT(*) FROM domain_audit;"));
|
||||
$total = count($domains);
|
||||
$added = 0;
|
||||
$stmt = $db->prepare('REPLACE INTO domain_audit (domain) VALUES (:domain)');
|
||||
if (!$stmt) {
|
||||
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
foreach ($domains as $domain) {
|
||||
$input = $domain;
|
||||
|
||||
if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) {
|
||||
throw new Exception('While binding domain: <strong>' . $db->lastErrorMsg() . '</strong><br>'.
|
||||
'Added ' . $added . " out of ". $total . " domains");
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('While executing: <strong>' . $db->lastErrorMsg() . '</strong><br>'.
|
||||
'Added ' . $added . " out of ". $total . " domains");
|
||||
}
|
||||
$added++;
|
||||
}
|
||||
|
||||
$after = intval($db->querySingle("SELECT COUNT(*) FROM domain_audit;"));
|
||||
$difference = $after - $before;
|
||||
if($total === 1) {
|
||||
if($difference !== 1) {
|
||||
$msg = "Not adding ". htmlentities(utf8_encode($domain)) . " as it is already on the list";
|
||||
} else {
|
||||
$msg = "Added " . htmlentities(utf8_encode($domain));
|
||||
}
|
||||
} else {
|
||||
if($difference !== $total) {
|
||||
$msg = "Added " . ($after-$before) . " out of ". $total . " domains (skipped duplicates)";
|
||||
} else {
|
||||
$msg = "Added " . $total . " domains";
|
||||
}
|
||||
}
|
||||
$reload = true;
|
||||
JSON_success($msg);
|
||||
} catch (\Exception $ex) {
|
||||
JSON_error($ex->getMessage());
|
||||
}
|
||||
} else {
|
||||
log_and_die('Requested action not supported!');
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; base-uri 'none'; child-src 'self'; form-action 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'none'; child-src 'self'; form-action 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self'; manifest-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'">
|
||||
<!-- 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">
|
||||
<meta http-equiv="cache-control" content="max-age=60,private">
|
||||
|
||||
@@ -19,6 +19,30 @@ function validIP($address){
|
||||
return !filter_var($address, FILTER_VALIDATE_IP) === false;
|
||||
}
|
||||
|
||||
function validCIDRIP($address){
|
||||
// This validation strategy has been taken from ../js/groups-common.js
|
||||
$isIPv6 = strpos($address, ":") !== false;
|
||||
if($isIPv6) {
|
||||
// One IPv6 element is 16bit: 0000 - FFFF
|
||||
$v6elem = "[0-9A-Fa-f]{1,4}";
|
||||
// CIDR for IPv6 is any multiple of 4 from 4 up to 128 bit
|
||||
$v6cidr = "(4";
|
||||
for ($i=8; $i <= 128; $i+=4) {
|
||||
$v6cidr .= "|$i";
|
||||
}
|
||||
$v6cidr .= ")";
|
||||
$validator = "/^(((?:$v6elem))((?::$v6elem))*::((?:$v6elem))((?::$v6elem))*|((?:$v6elem))((?::$v6elem)){7})\/$v6cidr$/";
|
||||
return preg_match($validator, $address);
|
||||
} else {
|
||||
// One IPv4 element is 8bit: 0 - 256
|
||||
$v4elem = "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)";
|
||||
// Note that rev-server accepts only /8, /16, /24, and /32
|
||||
$allowedv4cidr = "(8|16|24|32)";
|
||||
$validator = "/^$v4elem\.$v4elem\.$v4elem\.$v4elem\/$allowedv4cidr$/";
|
||||
return preg_match($validator, $address);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for existance of variable
|
||||
// and test it only if it exists
|
||||
function istrue(&$argument) {
|
||||
@@ -263,25 +287,27 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
|
||||
{
|
||||
$exploded = explode("#", $_POST["custom".$i."val"], 2);
|
||||
$IP = trim($exploded[0]);
|
||||
if(count($exploded) > 1)
|
||||
{
|
||||
$port = trim($exploded[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$port = "53";
|
||||
}
|
||||
|
||||
if(!validIP($IP))
|
||||
{
|
||||
$error .= "IP (".htmlspecialchars($IP).") is invalid!<br>";
|
||||
}
|
||||
elseif(!is_numeric($port))
|
||||
{
|
||||
$error .= "Port (".htmlspecialchars($port).") is invalid!<br>";
|
||||
}
|
||||
else
|
||||
{
|
||||
array_push($DNSservers,$IP."#".$port);
|
||||
if(count($exploded) > 1)
|
||||
{
|
||||
$port = trim($exploded[1]);
|
||||
if(!is_numeric($port))
|
||||
{
|
||||
$error .= "Port (".htmlspecialchars($port).") is invalid!<br>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$IP .= "#".$port;
|
||||
}
|
||||
}
|
||||
|
||||
array_push($DNSservers,$IP);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,28 +349,35 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
|
||||
$extra .= "no-dnssec";
|
||||
}
|
||||
|
||||
// Check if Conditional Forwarding is requested
|
||||
if(isset($_POST["conditionalForwarding"]))
|
||||
// Check if rev-server is requested
|
||||
if(isset($_POST["rev_server"]))
|
||||
{
|
||||
$conditionalForwardingIP = trim($_POST["conditionalForwardingIP"]);
|
||||
$conditionalForwardingDomain = trim($_POST["conditionalForwardingDomain"]);
|
||||
|
||||
// Validate conditional forwarding IP
|
||||
if (!validIP($conditionalForwardingIP))
|
||||
// Validate CIDR IP
|
||||
$cidr = trim($_POST["rev_server_cidr"]);
|
||||
if (!validCIDRIP($cidr))
|
||||
{
|
||||
$error .= "Conditional forwarding IP (".htmlspecialchars($conditionalForwardingIP).") is invalid!<br>";
|
||||
$error .= "Conditional forwarding subnet (\"".htmlspecialchars($cidr)."\") is invalid!<br>".
|
||||
"This field requires CIDR notation for local subnets (e.g., 192.168.0.0/16).<br>".
|
||||
"Please use only subnets /8, /16, /24, and /32.<br>";
|
||||
}
|
||||
|
||||
// Validate conditional forwarding domain name
|
||||
if(!validDomain($conditionalForwardingDomain))
|
||||
// Validate target IP
|
||||
$target = trim($_POST["rev_server_target"]);
|
||||
if (!validIP($target))
|
||||
{
|
||||
$error .= "Conditional forwarding domain name (".htmlspecialchars($conditionalForwardingDomain).") is invalid!<br>";
|
||||
$error .= "Conditional forwarding target IP (\"".htmlspecialchars($target)."\") is invalid!<br>";
|
||||
}
|
||||
|
||||
// Validate conditional forwarding domain name (empty is okay)
|
||||
$domain = trim($_POST["rev_server_domain"]);
|
||||
if(strlen($domain) > 0 && !validDomain($domain))
|
||||
{
|
||||
$error .= "Conditional forwarding domain name (\"".htmlspecialchars($domain)."\") is invalid!<br>";
|
||||
}
|
||||
|
||||
if(!$error)
|
||||
{
|
||||
$addressArray = explode(".", $conditionalForwardingIP);
|
||||
$reverseAddress = $addressArray[2].".".$addressArray[1].".".$addressArray[0].".in-addr.arpa";
|
||||
$extra .= " conditional_forwarding ".$conditionalForwardingIP." ".$conditionalForwardingDomain." $reverseAddress";
|
||||
$extra .= " rev-server ".$cidr." ".$target." ".$domain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,16 +409,8 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
|
||||
{
|
||||
$IPs = implode (",", $DNSservers);
|
||||
$return = pihole_execute("-a setdns \"".$IPs."\" ".$extra);
|
||||
if(!empty($return))
|
||||
{
|
||||
$success .= htmlspecialchars(end($return))."<br>";
|
||||
$success .= "The DNS settings have been updated (using ".$DNSservercount." DNS servers)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$success .= "Updating DNS settings failed. Result:";
|
||||
$success .= implode($return);
|
||||
}
|
||||
$success .= htmlspecialchars(end($return))."<br>";
|
||||
$success .= "The DNS settings have been updated (using ".$DNSservercount." DNS servers)";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -712,7 +737,8 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
|
||||
break;
|
||||
// Flush network table
|
||||
case "flusharp":
|
||||
pihole_execute("arpflush quiet", $output);
|
||||
$output = pihole_execute("arpflush quiet");
|
||||
$error = "";
|
||||
if(is_array($output))
|
||||
{
|
||||
$error = implode("<br>", $output);
|
||||
|
||||
@@ -173,7 +173,7 @@ function archive_restore_table($file, $table, $flush=false)
|
||||
foreach($contents as $row)
|
||||
{
|
||||
// Limit max length for a domain entry to 253 chars
|
||||
if(strlen($row[$field]) > 253)
|
||||
if(isset($field) && strlen($row[$field]) > 253)
|
||||
continue;
|
||||
|
||||
// Bind properties from JSON data
|
||||
@@ -196,7 +196,7 @@ function archive_restore_table($file, $table, $flush=false)
|
||||
default:
|
||||
$sqltype = "UNK";
|
||||
}
|
||||
$stmt->bindValue(":".$key, $value, $sqltype);
|
||||
$stmt->bindValue(":".$key, htmlentities($value), $sqltype);
|
||||
}
|
||||
|
||||
if($stmt->execute() && $stmt->reset() && $stmt->clear())
|
||||
@@ -540,7 +540,7 @@ if(isset($_POST["action"]))
|
||||
}
|
||||
else
|
||||
{
|
||||
$hostname = gethostname() ? gethostname()."-" : "";
|
||||
$hostname = gethostname() ? str_replace(".", "_", gethostname())."-" : "";
|
||||
$tarname = "pi-hole-".$hostname."teleporter_".date("Y-m-d_H-i-s").".tar";
|
||||
$filename = $tarname.".gz";
|
||||
$archive_file_name = sys_get_temp_dir() ."/". $tarname;
|
||||
|
||||
19
scripts/vendor/iCheck.min.js
vendored
19
scripts/vendor/iCheck.min.js
vendored
@@ -1,19 +0,0 @@
|
||||
/*! iCheck v2.0.0 rc1 - http://git.io/arlzeA, (c) Damir Sultanov - http://fronteed.com */
|
||||
(function(r,x,m){r.ichecked||(r.ichecked=function(){m=r.jQuery||r.Zepto;var A={autoInit:!0,autoAjax:!1,tap:!0,checkboxClass:"icheckbox",radioClass:"iradio",checkedClass:"checked",disabledClass:"disabled",indeterminateClass:"indeterminate",hoverClass:"hover",callbacks:{ifCreated:!1},classes:{base:"icheck",div:"#-item",area:"#-area-",input:"#-input",label:"#-label"}};r.icheck=m.extend(A,r.icheck);var l=r.navigator.userAgent,ca=/MSIE [5-8]/.test(l)||9>x.documentMode,D=/Opera Mini/.test(l),E=A.classes.base,
|
||||
O=A.classes.div.replace("#",E),da=A.classes.area.replace("#",E),P=A.classes.input.replace("#",E),Q=A.classes.label.replace("#",E);delete A.classes;var ea={},p={},la=new RegExp(E+"\\[(.*?)\\]"),I=function(a,c,e){a&&(c=la.exec(a))&&p[c[1]]&&(e=c[1]);return e},fa=r.getComputedStyle,X=r.PointerEvent||r.MSPointerEvent,y="ontouchend"in r,F=/mobile|tablet|phone|ip(ad|od)|android|silk|webos/i.test(l),l=["mouse","down","up","over","out"],u=r.PointerEvent?["pointer",l[1],l[2],l[3],l[4]]:["MSPointer","Down",
|
||||
"Up","Over","Out"],R=["touch","start","end"],S=y&&F||X,T=S?y?R[0]+R[1]:u[0]+u[3]:l[0]+l[3],Y=S?y?R[0]+R[2]:u[0]+u[4]:l[0]+l[4],M=S?y?!1:u[0]+u[1]:l[0]+l[1],Z=S?y?!1:u[0]+u[2]:l[0]+l[2],l=D?"":T+".i "+Y+".i ",u=!D&&M?M+".i "+Z+".i":"",J,U,ga=!1!==A.areaStyle?'position:absolute;display:block;content:"";top:#;bottom:#;left:#;right:#;':0,V=function(a,c,e){J||(J=x.createElement("style"),(x.head||x.getElementsByTagName("head")[0]).appendChild(J),r.createPopup||J.appendChild(x.createTextNode("")),U=J.sheet||
|
||||
J.styleSheet);c||(c="div."+(e?da+e+":after":O+" input."+P));a=a.replace(/!/g," !important");U.addRule?U.addRule(c,a,0):U.insertRule(c+"{"+a+"}",0)};V("position:absolute!;display:block!;outline:none!;"+(A.debug?"":"opacity:0!;z-index:-99!;clip:rect(0 0 0 0)!;"));(y&&F||D)&&V("cursor:pointer!;","label."+Q+",div."+O);V("display:none!","iframe.icheck-frame");var G=function(a,c,e,b,f,d,k){if(b=a.className)return f=" "+b+" ",1===e?d=c:0===e?k=c:(d=c[0],k=c[1]),d&&0>f.indexOf(" "+d+" ")&&(f+=d+" "),k&&~f.indexOf(" "+
|
||||
k+" ")&&(f=f.replace(" "+k+" "," ")),f=f.replace(/^\s+|\s+$/g,""),f!==b&&(a.className=f),f},ha=function(a,c,e,b,f,d){p[c]&&(b=p[c],f=b.className,d=m(K(a,"div",f)),d.length&&(m(a).removeClass(P+" "+f).attr("style",b.style),m("label."+b.esc).removeClass(Q+" "+f),m(d).replaceWith(m(a)),e&&N(a,c,e)),p[c]=!1)},ia=function(a,c,e,b,f){e=[];for(b=a.length;b--;)if(c=a[b],c.type)~"input[type=checkbox],input[type=radio]".indexOf(c.type)&&e.push(c);else for(c=m(c).find("input[type=checkbox],input[type=radio]"),
|
||||
f=c.length;f--;)e.push(c[f]);return e},K=function(a,c,e,b){for(;a&&9!==a.nodeType;)if((a=a.parentNode)&&a.tagName==c.toUpperCase()&&~a.className.indexOf(e)){b=a;break}return b},N=function(a,c,e){e="if"+e;if(p[c].callbacks&&!1!==p[c].callbacks[e]&&(m(a).trigger(e),"function"==typeof p[c].callbacks[e]))p[c].callbacks[e](a,p[c])},ja=function(a,c,e,b){a=ia(a);for(var f=a.length;f--;){var d=a[f],k=d.attributes,l={},g=k.length,h,n,u={},y={},t,q=d.id,w=d.className,z,D=d.type,aa=m.cache?m.cache[d[m.expando]]:
|
||||
0,B=I(w),L,v,C="",H=!1;v=[];for(var F=r.FastClick?" needsclick":"";g--;)h=k[g].name,n=k[g].value,~h.indexOf("data-")&&(u[h.substr(5)]=n),"style"==h&&(z=n),l[h]=n;aa&&aa.data&&(u=m.extend(u,aa.data));for(t in u){n=u[t];if("true"==n||"false"==n)n="true"==n;y[t.replace(/checkbox|radio|class|id|label/g,function(a,b){return 0===b?a:a.charAt(0).toUpperCase()+a.slice(1)})]=n}k=m.extend({},A,r.icheck,y,c);g=k.handle;"checkbox"!==g&&"radio"!==g&&(g="input[type=checkbox],input[type=radio]");if(!1!==k.init&&
|
||||
~g.indexOf(D)){for(B&&ha(d,B);!p[B];)if(B=Math.random().toString(36).substr(2,5),!p[B]){L=E+"["+B+"]";break}delete k.autoInit;delete k.autoAjax;k.style=z||"";k.className=L;k.esc=L.replace(/(\[|\])/g,"\\$1");p[B]=k;if(g=K(d,"label",""))!g.htmlFor&&q&&(g.htmlFor=q),v.push(g);if(q)for(h=m('label[for="'+q+'"]');h.length--;)q=h[h.length],q!==g&&v.push(q);for(n=v.length;n--;)q=v[n],h=q.className,h=(g=I(h))?G(q,E+"["+g+"]",0):(h?h+" ":"")+Q,q.className=h+" "+L+F;v=x.createElement("div");if(k.inherit)for(q=
|
||||
k.inherit.split(/\s*,\s*/),h=q.length;h--;)g=q[h],void 0!==l[g]&&("class"==g?C+=l[g]+" ":v.setAttribute(g,"id"==g?E+"-"+l[g]:l[g]));C+=k[D+"Class"];C+=" "+O+" "+L;k.area&&ga&&(H=(""+k.area).replace(/%|px|em|\+|-/g,"")|0)&&(ea[H]||(V(ga.replace(/#/g,"-"+H+"%"),!1,H),ea[H]=!0),C+=" "+da+H);v.className=C+F;d.className=(w?w+" ":"")+P+" "+L;d.parentNode.replaceChild(v,d);v.appendChild(d);k.insert&&m(v).append(k.insert);H&&(l=fa?fa(v,null).getPropertyValue("position"):v.currentStyle.position,"static"==
|
||||
l&&(v.style.position="relative"));W(d,v,B,"updated",!0,!1,e);p[B].done=!0;b||N(d,B,"Created")}}},W=function(a,c,e,b,f,d,k){var m=p[e],g={},h={};g.checked=[a.checked,"Checked","Unchecked"];d&&!k||"click"===b||(g.disabled=[a.disabled,"Disabled","Enabled"],g.indeterminate=["true"==a.getAttribute("indeterminate")||!!a.indeterminate,"Indeterminate","Determinate"]);"updated"==b||"click"==b?(h.checked=d?!g.checked[0]:g.checked[0],d&&!k||"click"===b||(h.disabled=g.disabled[0],h.indeterminate=g.indeterminate[0])):
|
||||
"checked"==b||"unchecked"==b?h.checked="checked"==b:"disabled"==b||"enabled"==b?h.disabled="disabled"==b:"indeterminate"==b||"determinate"==b?h.indeterminate="determinate"!==b:h.checked=!g.checked[0];ka(a,c,g,h,e,m,b,f,d,k)},ka=function(a,c,e,b,f,d,k,l,g,h,n){var r=a.type,u="radio"==r?"Radio":"Checkbox",t,q,w,z,y,x,B,A,v,C;c||(c=K(a,"div",d.className));if(c){for(t in b)if(q=b[t],e[t][0]!==q&&"updated"!==k&&"click"!==k&&(a[t]=q),h&&(q?a.setAttribute(t,t):a.removeAttribute(t)),d[t]!==q){d[t]=q;v=!0;
|
||||
if("checked"==t&&(C=!0,!n&&q&&(p[f].done||h)&&"radio"==r&&a.name))for(z=K(a,"form",""),w='input[name="'+a.name+'"]',w=z&&!h?m(z).find(w):m(w),z=w.length;z--;)y=w[z],x=I(y.className),a!==y&&p[x]&&p[x].checked&&(B={checked:[!0,"Checked","Unchecked"]},A={checked:!1},ka(y,!1,B,A,x,p[x],"updated",l,g,h,!0));w=[d[t+"Class"],d[t+u+"Class"],d[e[t][1]+"Class"],d[e[t][1]+u+"Class"],d[t+"LabelClass"]];z=[w[3]||w[2],w[1]||w[0]];q&&z.reverse();G(c,z);if(d.mirror&&w[4])for(z=m("label."+d.esc);z.length--;)G(z[z.length],
|
||||
w[4],q?1:0);l&&!n||N(a,f,e[t][q?1:2])}if(!l||n)v&&N(a,f,"Changed"),C&&N(a,f,"Toggled");d.cursor&&!F&&(d.disabled||d.pointer?d.disabled&&d.pointer&&(c.style.cursor="default",d.pointer=!1):(c.style.cursor="pointer",d.pointer=!0));p[f]=d}};m.fn.icheck=function(a,c){if(/^(checked|unchecked|indeterminate|determinate|disabled|enabled|updated|toggle|destroy|data|styler)$/.test(a))for(var e=ia(this),b=e.length;b--;){var f=e[b],d=I(f.className);if(d){if("data"==a)return p[d];if("styler"==a)return K(f,"div",
|
||||
p[d].className);"destroy"==a?ha(f,d,"Destroyed"):W(f,!1,d,a);"function"==typeof c&&c(f)}}else"object"!=typeof a&&a||ja(this,a||{});return this};var ba;m(x).on("click.i "+l+u,"label."+Q+",div."+O,function(a){var c=this,e=I(c.className);if(e){var b=a.type,f=p[e],d=f.esc,e="DIV"==c.tagName,k,l,g,h,n=[["label",f.activeLabelClass,f.hoverLabelClass],["div",f.activeClass,f.hoverClass]];e&&n.reverse();if(b==M||b==Z){n[0][1]&&G(c,n[0][1],b==M?1:0);if(f.mirror&&n[1][1])for(g=m(n[1][0]+"."+d);g.length--;)G(g[g.length],
|
||||
n[1][1],b==M?1:0);e&&b==Z&&f.tap&&F&&X&&!D&&(h=!0)}else if(b==T||b==Y){n[0][2]&&G(c,n[0][2],b==T?1:0);if(f.mirror&&n[1][2])for(g=m(n[1][0]+"."+d);g.length--;)G(g[g.length],n[1][2],b==T?1:0);e&&b==Y&&f.tap&&F&&y&&!D&&(h=!0)}else e&&(F&&(y||X)&&f.tap&&!D||(h=!0));h&&setTimeout(function(){l=a.currentTarget||{};"LABEL"!==l.tagName&&(!f.change||100<+new Date-f.change)&&(k=m(c).find("input."+d).click(),(ca||D)&&k.change())},2)}}).on("click.i change.i focusin.i focusout.i keyup.i keydown.i","input."+P,function(a){var c=
|
||||
I(this.className);if(c){var e=a.type,b=p[c],f=b.esc,d="click"==e?!1:K(this,"div",b.className);if("click"==e)p[c].change=+new Date,a.stopPropagation();else if("change"==e)d&&!this.disabled&&W(this,d,c,"click");else if(~e.indexOf("focus")){if(a=[b.focusClass,b.focusLabelClass],a[0]&&d&&G(d,a[0],"focusin"==e?1:0),b.mirror&&a[1])for(b=m("label."+f);b.length--;)G(b[b.length],a[1],"focusin"==e?1:0)}else d&&!this.disabled&&("keyup"==e?(("checkbox"==this.type&&32==a.keyCode&&b.keydown||"radio"==this.type&&
|
||||
!this.checked)&&W(this,d,c,"click",!1,!0),p[c].keydown=!1,p[ba]&&(p[ba].keydown=!1)):(ba=c,p[c].keydown=!0))}}).ready(function(){r.icheck.autoInit&&m("."+E).icheck();if(r.jQuery){var a=x.body||x.getElementsByTagName("body")[0];m.ajaxSetup({converters:{"text html":function(c){if(r.icheck.autoAjax&&a){var e=x.createElement("iframe"),b;ca||(e.style="display:none");e.className="iframe.icheck-frame";e.src="about:blank";a.appendChild(e);b=e.contentDocument?e.contentDocument:e.contentWindow.document;b.open();
|
||||
b.write(c);b.close();a.removeChild(e);b=m(b);ja(b.find("."+E),{},!0);b=b[0];c=(b.body||b.getElementsByTagName("body")[0]).innerHTML}return c}}})}})},"function"==typeof define&&define.amd?define("icheck",[r.jQuery?"jquery":"zepto"],r.ichecked):r.ichecked())})(window,document);
|
||||
106
settings.php
106
settings.php
@@ -164,12 +164,13 @@ if (isset($setupVars["DNSMASQ_LISTENING"])) {
|
||||
} else {
|
||||
$DNSinterface = "single";
|
||||
}
|
||||
if (isset($setupVars["CONDITIONAL_FORWARDING"]) && ($setupVars["CONDITIONAL_FORWARDING"] == 1)) {
|
||||
$conditionalForwarding = true;
|
||||
$conditionalForwardingDomain = $setupVars["CONDITIONAL_FORWARDING_DOMAIN"];
|
||||
$conditionalForwardingIP = $setupVars["CONDITIONAL_FORWARDING_IP"];
|
||||
if (isset($setupVars["REV_SERVER"]) && ($setupVars["REV_SERVER"] == 1)) {
|
||||
$rev_server = true;
|
||||
$rev_server_cidr = $setupVars["REV_SERVER_CIDR"];
|
||||
$rev_server_target = $setupVars["REV_SERVER_TARGET"];
|
||||
$rev_server_domain = $setupVars["REV_SERVER_DOMAIN"];
|
||||
} else {
|
||||
$conditionalForwarding = false;
|
||||
$rev_server = false;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -714,7 +715,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "adlists", "
|
||||
title="Lease type: IPv<?php echo $lease["type"]; ?><br/>Remaining lease time: <?php echo $lease["TIME"]; ?><br/>DHCP UID: <?php echo $lease["clid"]; ?>">
|
||||
<td id="MAC"><?php echo $lease["hwaddr"]; ?></td>
|
||||
<td id="IP" data-order="<?php echo bin2hex(inet_pton($lease["IP"])); ?>"><?php echo $lease["IP"]; ?></td>
|
||||
<td id="HOST"><?php echo $lease["host"]; ?></td>
|
||||
<td id="HOST"><?php echo htmlentities($lease["host"]); ?></td>
|
||||
<td>
|
||||
<button type="button" id="button" class="btn btn-warning btn-xs" data-static="alert">
|
||||
<span class="fas fas fa-file-import"></span>
|
||||
@@ -742,9 +743,9 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "adlists", "
|
||||
<tr>
|
||||
<td><?php echo $lease["hwaddr"]; ?></td>
|
||||
<td data-order="<?php echo bin2hex(inet_pton($lease["IP"])); ?>"><?php echo $lease["IP"]; ?></td>
|
||||
<td><?php echo $lease["host"]; ?></td>
|
||||
<td><?php echo htmlentities($lease["host"]); ?></td>
|
||||
<td><?php if (strlen($lease["hwaddr"]) > 0) { ?>
|
||||
<button type="button" class="btn btn-danger btn-xs" name="removestatic"
|
||||
<button type="submit" class="btn btn-danger btn-xs" name="removestatic"
|
||||
value="<?php echo $lease["hwaddr"]; ?>">
|
||||
<span class="far fa-trash-alt"></span>
|
||||
</button>
|
||||
@@ -975,38 +976,69 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "adlists", "
|
||||
when enabling DNSSEC. A DNSSEC resolver test can be found
|
||||
<a href="https://dnssec.vs.uni-due.de/" rel="noopener" target="_blank">here</a>.</p>
|
||||
</div>
|
||||
<strong>Conditional Forwarding</strong>
|
||||
<p>If not configured as your DHCP server, Pi-hole won't be able to
|
||||
<p>Validate DNS replies and cache DNSSEC data. When forwarding DNS
|
||||
queries, Pi-hole requests the DNSSEC records needed to validate
|
||||
the replies. If a domain fails validation or the upstream does not
|
||||
support DNSSEC, this setting can cause issues resolving domains.
|
||||
Use Google, Cloudflare, DNS.WATCH, Quad9, or another DNS
|
||||
server which supports DNSSEC when activating DNSSEC. Note that
|
||||
the size of your log might increase significantly
|
||||
when enabling DNSSEC. A DNSSEC resolver test can be found
|
||||
<a href="https://dnssec.vs.uni-due.de/" rel="noopener" target="_blank">here</a>.</p>
|
||||
<br>
|
||||
<h4>Conditional forwarding</h4>
|
||||
<p>If not configured as your DHCP server, Pi-hole typically won't be able to
|
||||
determine the names of devices on your local network. As a
|
||||
result, tables such as Top Clients will only show IP addresses.</p>
|
||||
<p>One solution for this is to configure Pi-hole to forward these
|
||||
requests to your DHCP server (most likely your router), but only for devices on your
|
||||
home network. To configure this we will need to know the IP
|
||||
address of your DHCP server and the name of your local network.</p>
|
||||
<p>Note: The local domain name must match the domain name specified
|
||||
in your DHCP server, likely found within the DHCP settings.</p>
|
||||
<div>
|
||||
<input type="checkbox" name="conditionalForwarding" id="conditionalForwarding" value="conditionalForwarding" <?php if(isset($conditionalForwarding) && ($conditionalForwarding == true)){ ?>checked<?php } ?>>
|
||||
<label for="conditionalForwarding"><strong>Use Conditional Forwarding</strong></label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>IP of your router</th>
|
||||
<th>Local domain name</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<div class="input-group">
|
||||
<td>
|
||||
<input type="text" name="conditionalForwardingIP" class="form-control" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off"
|
||||
<?php if(isset($conditionalForwardingIP)){ ?>value="<?php echo $conditionalForwardingIP; ?>"<?php } ?>>
|
||||
</td>
|
||||
<td><input type="text" name="conditionalForwardingDomain" class="form-control" data-mask autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off"
|
||||
<?php if(isset($conditionalForwardingDomain)){ ?>value="<?php echo $conditionalForwardingDomain; ?>"<?php } ?>>
|
||||
</td>
|
||||
</div>
|
||||
</tr>
|
||||
</table>
|
||||
requests to your DHCP server (most likely your router), but only for devices on your
|
||||
home network. To configure this we will need to know the IP
|
||||
address of your DHCP server and which addresses belong to your local network.
|
||||
Exemplary inout is given below as placeholder in the text boxes (if empty).</p>
|
||||
<p>If your local network spans 192.168.0.1 - 192.168.0.255, then you will have to input
|
||||
<code>192.168.0.0/24</code>. If your local network is 192.168.47.1 - 192.168.47.255, it will
|
||||
be <code>192.168.47.0/24</code> and similar. If your network is larger, the CIDR has to be
|
||||
different, for instance a range of 10.8.0.1 - 10.8.255.255 results in <code>10.8.0.0/16</code>,
|
||||
whereas an even wider network of 10.0.0.1 - 10.255.255.255 results in <code>10.0.0.0/8</code>.
|
||||
Setting up IPv6 ranges is exactly similar to setting up IPv4 here and fully supported.
|
||||
Feel free to reach out to us on our
|
||||
<a href="https://discourse.pi-hole.net" target="_blank">Discourse forum</a>
|
||||
in case you need any assistance setting up local host name resolution for your particular system.</p>
|
||||
<p>You can also specify a local domain name (like <code>fritz.box</code>) to ensure queries to
|
||||
devices ending in your local domain name will not leave your network, however, this is optional.
|
||||
The local domain name must match the domain name specified
|
||||
in your DHCP server for this to work. You can likely find it within the DHCP settings.</p>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<input type="checkbox" name="rev_server" id="rev_server" value="rev_server" <?php if(isset($rev_server) && ($rev_server == true)){ ?>checked<?php } ?>>
|
||||
<label for="rev_server"><strong>Use Conditional Forwarding</strong></label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>Local network in <a href="https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing" target="_blank">CIDR notation</a></th>
|
||||
<th>IP address of your DHCP server (router)</th>
|
||||
<th>Local domain name (optional)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="text" name="rev_server_cidr" placeholder="192.168.0.0/16" class="form-control" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off"
|
||||
<?php if(isset($rev_server_cidr)){ ?>value="<?php echo $rev_server_cidr; ?>"<?php } ?>
|
||||
<?php if(!isset($rev_server) || !$rev_server){ ?>disabled<?php } ?>>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="rev_server_target" placeholder="192.168.0.1" class="form-control" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off"
|
||||
<?php if(isset($rev_server_target)){ ?>value="<?php echo $rev_server_target; ?>"<?php } ?>
|
||||
<?php if(!isset($rev_server) || !$rev_server){ ?>disabled<?php } ?>>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="rev_server_domain" placeholder="local" class="form-control" data-mask autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off"
|
||||
<?php if(isset($rev_server_domain)){ ?>value="<?php echo $rev_server_domain; ?>"<?php } ?>
|
||||
<?php if(!isset($rev_server) || !$rev_server){ ?>disabled<?php } ?>>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -385,7 +385,7 @@ pre {
|
||||
color: #007997 !important;
|
||||
}
|
||||
td.highlight {
|
||||
background-color: yellow;
|
||||
background-color: rgba(255, 204, 0, 0.333);
|
||||
}
|
||||
.btn-default {
|
||||
box-shadow: none;
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
}
|
||||
|
||||
td.highlight {
|
||||
background-color: #ff0 !important;
|
||||
background-color: rgba(255, 204, 0, 0.333);
|
||||
}
|
||||
|
||||
.network-never {
|
||||
|
||||
Reference in New Issue
Block a user