mirror of
https://github.com/pi-hole/web.git
synced 2025-12-20 02:38:28 +00:00
Add live-tail of all log files as well as local DNS and CNAME records handling (add new and delete existing records is still TODO at this point)
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -1,139 +0,0 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global utils:false */
|
||||
|
||||
var table;
|
||||
var token = $("#token").text();
|
||||
|
||||
$(function () {
|
||||
$("#btnAdd").on("click", addCustomCNAME);
|
||||
|
||||
table = $("#customCNAMETable").DataTable({
|
||||
ajax: {
|
||||
url: "scripts/pi-hole/php/customcname.php",
|
||||
data: { action: "get", token: token },
|
||||
type: "POST",
|
||||
},
|
||||
columns: [{}, {}, { orderable: false, searchable: false }],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 2,
|
||||
render: function (data, type, row) {
|
||||
return (
|
||||
'<button type="button" class="btn btn-danger btn-xs deleteCustomCNAME" data-domain=\'' +
|
||||
row[0] +
|
||||
"' data-target='" +
|
||||
row[1] +
|
||||
"'>" +
|
||||
'<span class="far fa-trash-alt"></span>' +
|
||||
"</button>"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
targets: "_all",
|
||||
render: $.fn.dataTable.render.text(),
|
||||
},
|
||||
],
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"],
|
||||
],
|
||||
order: [[0, "asc"]],
|
||||
stateSave: true,
|
||||
stateDuration: 0,
|
||||
stateSaveCallback: function (settings, data) {
|
||||
utils.stateSaveCallback("LocalCNAMETable", data);
|
||||
},
|
||||
stateLoadCallback: function () {
|
||||
return utils.stateLoadCallback("LocalCNAMETable");
|
||||
},
|
||||
drawCallback: function () {
|
||||
$(".deleteCustomCNAME").on("click", deleteCustomCNAME);
|
||||
},
|
||||
});
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
function addCustomCNAME() {
|
||||
var domain = utils.escapeHtml($("#domain").val());
|
||||
var target = utils.escapeHtml($("#target").val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Adding custom CNAME record...", "");
|
||||
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customcname.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "add", domain: domain, target: target, token: token },
|
||||
success: function (response) {
|
||||
utils.enableAll();
|
||||
if (response.success) {
|
||||
utils.showAlert(
|
||||
"success",
|
||||
"far fa-check-circle",
|
||||
"Custom CNAME added",
|
||||
domain + ": " + target
|
||||
);
|
||||
|
||||
// Clean up field values and reload table data
|
||||
$("#domain").val("");
|
||||
$("#target").val("");
|
||||
table.ajax.reload();
|
||||
$("#domain").focus();
|
||||
} else {
|
||||
utils.showAlert("error", "fas fa-times", "Failure! Something went wrong", response.message);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
utils.enableAll();
|
||||
utils.showAlert("error", "fas fa-times", "Error while adding custom CNAME record", "");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function deleteCustomCNAME() {
|
||||
var domain = $(this).attr("data-domain");
|
||||
var target = $(this).attr("data-target");
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting custom CNAME record...", "");
|
||||
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customcname.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "delete", domain: domain, target: target, token: token },
|
||||
success: function (response) {
|
||||
utils.enableAll();
|
||||
if (response.success) {
|
||||
utils.showAlert(
|
||||
"success",
|
||||
"far fa-check-circle",
|
||||
"Custom CNAME deleted",
|
||||
domain + ": " + target
|
||||
);
|
||||
table.ajax.reload();
|
||||
} else {
|
||||
utils.showAlert("error", "fas fa-times", "Failure! Something went wrong", response.message);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
utils.enableAll();
|
||||
utils.showAlert("error", "fas fa-times", "Error while deleting custom CNAME record", "");
|
||||
console.log(exception); // eslint-disable-line no-console
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global utils:false */
|
||||
|
||||
var table;
|
||||
var token = $("#token").text();
|
||||
|
||||
$(function () {
|
||||
$("#btnAdd").on("click", addCustomDNS);
|
||||
|
||||
table = $("#customDNSTable").DataTable({
|
||||
ajax: {
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
data: { action: "get", token: token },
|
||||
type: "POST",
|
||||
},
|
||||
columns: [{}, { type: "ip-address" }, { orderable: false, searchable: false }],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 2,
|
||||
render: function (data, type, row) {
|
||||
return (
|
||||
'<button type="button" class="btn btn-danger btn-xs deleteCustomDNS" data-domain=\'' +
|
||||
row[0] +
|
||||
"' data-ip='" +
|
||||
row[1] +
|
||||
"'>" +
|
||||
'<span class="far fa-trash-alt"></span>' +
|
||||
"</button>"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
targets: "_all",
|
||||
render: $.fn.dataTable.render.text(),
|
||||
},
|
||||
],
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"],
|
||||
],
|
||||
order: [[0, "asc"]],
|
||||
stateSave: true,
|
||||
stateDuration: 0,
|
||||
stateSaveCallback: function (settings, data) {
|
||||
utils.stateSaveCallback("LocalDNSTable", data);
|
||||
},
|
||||
stateLoadCallback: function () {
|
||||
return utils.stateLoadCallback("LocalDNSTable");
|
||||
},
|
||||
drawCallback: function () {
|
||||
$(".deleteCustomDNS").on("click", deleteCustomDNS);
|
||||
},
|
||||
});
|
||||
// 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);
|
||||
});
|
||||
|
||||
function addCustomDNS() {
|
||||
var ip = utils.escapeHtml($("#ip").val());
|
||||
var domain = utils.escapeHtml($("#domain").val());
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Adding custom DNS entry...", "");
|
||||
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "add", ip: ip, domain: domain, token: token },
|
||||
success: function (response) {
|
||||
utils.enableAll();
|
||||
if (response.success) {
|
||||
utils.showAlert("success", "far fa-check-circle", "Custom DNS added", domain + ": " + ip);
|
||||
|
||||
// Clean up field values and reload table data
|
||||
$("#domain").val("");
|
||||
$("#ip").val("");
|
||||
table.ajax.reload();
|
||||
$("#domain").focus();
|
||||
} else {
|
||||
utils.showAlert("error", "fas fa-times", "Failure! Something went wrong", response.message);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
utils.enableAll();
|
||||
utils.showAlert("error", "fas fa-times", "Error while adding custom DNS entry", "");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function deleteCustomDNS() {
|
||||
var ip = $(this).attr("data-ip");
|
||||
var domain = $(this).attr("data-domain");
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting custom DNS entry...", "");
|
||||
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "delete", domain: domain, ip: ip, token: token },
|
||||
success: function (response) {
|
||||
utils.enableAll();
|
||||
if (response.success) {
|
||||
utils.showAlert("success", "far fa-check-circle", "Custom DNS deleted", domain + ": " + ip);
|
||||
table.ajax.reload();
|
||||
} else {
|
||||
utils.showAlert("error", "fas fa-times", "Failure! Something went wrong", response.message);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
utils.enableAll();
|
||||
utils.showAlert("error", "fas fa-times", "Error while deleting custom DNS entry", "");
|
||||
console.log(exception); // eslint-disable-line no-console
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -136,7 +136,7 @@ $(function () {
|
||||
[10, 25, 50, 100, "All"],
|
||||
],
|
||||
language: {
|
||||
emptyTable: "No issues found.",
|
||||
emptyTable: "No DHCP leases found.",
|
||||
},
|
||||
stateSave: true,
|
||||
stateDuration: 0,
|
||||
|
||||
244
scripts/pi-hole/js/settings-dns-records.js
Normal file
244
scripts/pi-hole/js/settings-dns-records.js
Normal file
@@ -0,0 +1,244 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2023 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Precord see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global utils: false */
|
||||
|
||||
var dnsRecordsTable = null;
|
||||
var customCNAMETable = null;
|
||||
|
||||
$(function () {
|
||||
dnsRecordsTable = $("#dnsRecordsTable").DataTable({
|
||||
ajax: {
|
||||
url: "/api/config/dns/hosts",
|
||||
type: "GET",
|
||||
dataSrc: "config.dns.hosts",
|
||||
},
|
||||
order: [[0, "asc"]],
|
||||
columns: [
|
||||
{ data: null },
|
||||
{ data: null, type: "ip-address" },
|
||||
{ data: null, width: "22px", orderable: false },
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: "_all",
|
||||
render: $.fn.dataTable.render.text(),
|
||||
},
|
||||
],
|
||||
drawCallback: function () {
|
||||
$('button[id^="deleteRecord"]').on("click", deleteRecord);
|
||||
|
||||
// Remove visible dropdown to prevent orphaning
|
||||
$("body > .bootstrap-select.dropdown").remove();
|
||||
},
|
||||
rowCallback: function (row, data) {
|
||||
$(row).attr("data-id", data.ip);
|
||||
var button =
|
||||
'<button type="button" class="btn btn-danger btn-xs" id="deleteRecord' +
|
||||
data.ip +
|
||||
'" data-del-ip="' +
|
||||
data.ip +
|
||||
'">' +
|
||||
'<span class="far fa-trash-alt"></span>' +
|
||||
"</button>";
|
||||
$("td:eq(2)", row).html(button);
|
||||
// Split record in format IP NAME1 [NAME2 [NAME3 [NAME...]]]
|
||||
var ip = data.substring(0, data.indexOf(" "));
|
||||
// The name can be mulitple domains separated by spaces
|
||||
var name = data.substring(data.indexOf(" ") + 1);
|
||||
$("td:eq(0)", row).text(name);
|
||||
$("td:eq(1)", row).text(ip);
|
||||
},
|
||||
dom:
|
||||
"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-12'i>>",
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"],
|
||||
],
|
||||
language: {
|
||||
emptyTable: "No local DNS records defined.",
|
||||
},
|
||||
stateSave: true,
|
||||
stateDuration: 0,
|
||||
stateSaveCallback: function (settings, data) {
|
||||
utils.stateSaveCallback("dns-records-table", data);
|
||||
},
|
||||
stateLoadCallback: function () {
|
||||
var data = utils.stateLoadCallback("dns-records-table");
|
||||
// Return if not available
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
dnsRecordsTable = $("#customCNAMETable").DataTable({
|
||||
ajax: {
|
||||
url: "/api/config/dns/cnameRecords",
|
||||
type: "GET",
|
||||
dataSrc: "config.dns.cnameRecords",
|
||||
},
|
||||
order: [[0, "asc"]],
|
||||
columns: [
|
||||
{ data: null },
|
||||
{ data: null },
|
||||
{ data: null },
|
||||
{ data: null, width: "22px", orderable: false },
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: "_all",
|
||||
render: $.fn.dataTable.render.text(),
|
||||
},
|
||||
],
|
||||
drawCallback: function () {
|
||||
$('button[id^="deleteCNAME"]').on("click", delCNAMERecord);
|
||||
|
||||
// Remove visible dropdown to prevent orphaning
|
||||
$("body > .bootstrap-select.dropdown").remove();
|
||||
},
|
||||
rowCallback: function (row, data) {
|
||||
$(row).attr("data-id", data.ip);
|
||||
var button =
|
||||
'<button type="button" class="btn btn-danger btn-xs" id="deleteCNAME' +
|
||||
data.ip +
|
||||
'" data-del-ip="' +
|
||||
data.ip +
|
||||
'">' +
|
||||
'<span class="far fa-trash-alt"></span>' +
|
||||
"</button>";
|
||||
$("td:eq(3)", row).html(button);
|
||||
// Split record in format <cname>,<target>[,<TTL>]
|
||||
var splitted = data.split(",");
|
||||
$("td:eq(0)", row).text(splitted[0]);
|
||||
$("td:eq(1)", row).text(splitted[1]);
|
||||
if (splitted.length > 2) $("td:eq(2)", row).text(splitted[2]);
|
||||
else $("td:eq(2)", row).text("-");
|
||||
},
|
||||
dom:
|
||||
"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-12'i>>",
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"],
|
||||
],
|
||||
language: {
|
||||
emptyTable: "No local CNAME records defined.",
|
||||
},
|
||||
stateSave: true,
|
||||
stateDuration: 0,
|
||||
stateSaveCallback: function (settings, data) {
|
||||
utils.stateSaveCallback("dns-cname-records-table", data);
|
||||
},
|
||||
stateLoadCallback: function () {
|
||||
var data = utils.stateLoadCallback("dns-cname-records-table");
|
||||
// Return if not available
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
function deleteRecord() {
|
||||
// Passes the button data-del-id attribute as IP
|
||||
var ips = [$(this).attr("data-del-ip")];
|
||||
|
||||
// Check input validity
|
||||
if (!Array.isArray(ips)) return;
|
||||
|
||||
// Exploit prevention: Return early for non-numeric IDs
|
||||
for (var ip in ips) {
|
||||
if (Object.hasOwnProperty.call(ips, ip)) {
|
||||
delRecord(ips);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delRecord(ip) {
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting DNS record...");
|
||||
|
||||
$.ajax({
|
||||
url: "/api/dns/records/" + ip /* TODO */,
|
||||
method: "DELETE",
|
||||
})
|
||||
.done(function (response) {
|
||||
utils.enableAll();
|
||||
if (response === undefined) {
|
||||
utils.showAlert("success", "far fa-trash-alt", "Successfully deleted DNS record", "");
|
||||
dnsRecordsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
utils.showAlert("error", "", "Error while deleting DNS record: " + ip, response.record);
|
||||
}
|
||||
})
|
||||
.done(
|
||||
utils.checkrecords // Update icon warnings count
|
||||
)
|
||||
.fail(function (jqXHR, exception) {
|
||||
utils.enableAll();
|
||||
utils.showAlert("error", "", "Error while deleting DNS record: " + ip, jqXHR.responseText);
|
||||
console.log(exception); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
|
||||
function delCNAMERecord(ip) {
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting local CNAME record...");
|
||||
|
||||
$.ajax({
|
||||
url: "/api/CNAME/records/" + ip /* TODO */,
|
||||
method: "DELETE",
|
||||
})
|
||||
.done(function (response) {
|
||||
utils.enableAll();
|
||||
if (response === undefined) {
|
||||
utils.showAlert(
|
||||
"success",
|
||||
"far fa-trash-alt",
|
||||
"Successfully deleted local CNAME record",
|
||||
""
|
||||
);
|
||||
customCNAMETable.ajax.reload(null, false);
|
||||
} else {
|
||||
utils.showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting local CNAME record: " + ip,
|
||||
response.record
|
||||
);
|
||||
}
|
||||
})
|
||||
.done(
|
||||
utils.checkrecords // Update icon warnings count
|
||||
)
|
||||
.fail(function (jqXHR, exception) {
|
||||
utils.enableAll();
|
||||
utils.showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting local CNAME record: " + ip,
|
||||
jqXHR.responseText
|
||||
);
|
||||
console.log(exception); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
$(document).ready(function () {
|
||||
processDNSRecordsConfig();
|
||||
});
|
||||
*/
|
||||
@@ -6,7 +6,6 @@
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global apiFailure:false */
|
||||
/* exported updateHostInfo, updateCacheInfo */
|
||||
|
||||
var hostinfoTimer = null;
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
var offset,
|
||||
timer,
|
||||
pre,
|
||||
scrolling = true;
|
||||
|
||||
// Check every 200msec for fresh data
|
||||
var interval = 200;
|
||||
|
||||
// Function that asks the API for new data
|
||||
function reloadData() {
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL&offset=" + offset, function (data) {
|
||||
pre.append(data.lines);
|
||||
|
||||
if (scrolling && offset !== data.offset) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
|
||||
offset = data.offset;
|
||||
});
|
||||
|
||||
timer = setTimeout(reloadData, interval);
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL", function (data) {
|
||||
offset = data.offset;
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
});
|
||||
|
||||
$("#chk1").on("click", function () {
|
||||
$("#chk2").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").on("click", function () {
|
||||
$("#chk1").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
@@ -5,45 +5,124 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
var offset,
|
||||
timer,
|
||||
pre,
|
||||
scrolling = true;
|
||||
/* global moment: false, apiFailure: false */
|
||||
|
||||
// Check every 200msec for fresh data
|
||||
var interval = 200;
|
||||
var nextID = 0;
|
||||
|
||||
// Check every 0.5s for fresh data
|
||||
const interval = 500;
|
||||
|
||||
// Maximum number of lines to display
|
||||
const maxlines = 5000;
|
||||
|
||||
// Fade in new lines
|
||||
const fadeIn = true;
|
||||
|
||||
// Mark new lines with a red line above them
|
||||
const markUpdates = true;
|
||||
|
||||
// Function that asks the API for new data
|
||||
function reloadData() {
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?offset=" + offset, function (data) {
|
||||
pre.append(data.lines);
|
||||
function getData() {
|
||||
// Only update when spinner is spinning
|
||||
if (!$("#feed-icon").hasClass("fa-play")) {
|
||||
// Restart timer
|
||||
setTimeout(getData, interval);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scrolling && offset !== data.offset) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
var GETDict = {};
|
||||
window.location.search
|
||||
.substr(1)
|
||||
.split("&")
|
||||
.forEach(function (item) {
|
||||
GETDict[item.split("=")[0]] = item.split("=")[1];
|
||||
});
|
||||
if (!("file" in GETDict)) {
|
||||
window.location.href += "?file=dnsmasq";
|
||||
return;
|
||||
}
|
||||
|
||||
offset = data.offset;
|
||||
});
|
||||
$.ajax({
|
||||
url: "/api/logs/" + GETDict.file + "?nextID=" + nextID,
|
||||
method: "GET",
|
||||
})
|
||||
.done(function (data) {
|
||||
if (data.log.length === 0) {
|
||||
if (nextID === 0) {
|
||||
$("#output").html("<i>*** Log file is empty ***</i>");
|
||||
}
|
||||
|
||||
timer = setTimeout(reloadData, interval);
|
||||
// Restart timer
|
||||
setTimeout(getData, interval);
|
||||
return;
|
||||
}
|
||||
|
||||
// We have new lines
|
||||
if (markUpdates && nextID > 0) {
|
||||
// Add red fading out background to new lines
|
||||
$("#output").append('<hr class="hr-small">').children(":last").fadeOut(2000);
|
||||
}
|
||||
|
||||
data.log.forEach(function (line) {
|
||||
// Add new line to output
|
||||
$("#output").append(
|
||||
'<span><span style="border-left: 2px red" class="left-line"> </span><span class="text-muted">' +
|
||||
moment(1000 * line.timestamp).format("YYYY-MM-DD HH:mm:ss.SSS") +
|
||||
"</span> " +
|
||||
line.message +
|
||||
"<br></span>"
|
||||
);
|
||||
if (fadeIn) {
|
||||
//$(".left-line:last").fadeOut(2000);
|
||||
$("#output").children(":last").hide().fadeIn("fast");
|
||||
}
|
||||
});
|
||||
|
||||
// Limit output to <maxlines> lines
|
||||
var lines = $("#output").val().split("\n");
|
||||
if (lines.length > maxlines) {
|
||||
lines.splice(0, lines.length - maxlines);
|
||||
$("#output").val(lines.join("\n"));
|
||||
}
|
||||
|
||||
// Scroll to bottom of output
|
||||
$("#output").scrollTop($("#output")[0].scrollHeight);
|
||||
|
||||
// Update nextID
|
||||
nextID = data.nextID;
|
||||
|
||||
// Set filename
|
||||
$("#filename").text(data.file);
|
||||
|
||||
// Restart timer
|
||||
setTimeout(getData, interval);
|
||||
})
|
||||
.fail(function (data) {
|
||||
apiFailure(data);
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php", function (data) {
|
||||
offset = data.offset;
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
});
|
||||
getData();
|
||||
|
||||
$("#chk1").on("click", function () {
|
||||
$("#chk2").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").on("click", function () {
|
||||
$("#chk1").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
// Clicking on the element with class "fa-spinner" will toggle the play/pause state
|
||||
$("#live-feed").on("click", function () {
|
||||
if ($("#feed-icon").hasClass("fa-play")) {
|
||||
// Toggle button color
|
||||
$("#feed-icon").addClass("fa-pause");
|
||||
$("#feed-icon").removeClass("fa-fade");
|
||||
$("#feed-icon").removeClass("fa-play");
|
||||
$(this).addClass("btn-danger");
|
||||
$(this).removeClass("btn-success");
|
||||
$("#title").text("Paused");
|
||||
} else {
|
||||
// Toggle button color
|
||||
$("#feed-icon").addClass("fa-play");
|
||||
$("#feed-icon").addClass("fa-fade");
|
||||
$("#feed-icon").removeClass("fa-pause");
|
||||
$(this).addClass("btn-success");
|
||||
$(this).removeClass("btn-danger");
|
||||
$("#title").text("Live");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -162,12 +162,7 @@
|
||||
</li>
|
||||
<li class="<?php if ($scriptname === 'settings-dns-records.php') { ?> active<?php } ?>">
|
||||
<a href="settings-dns-records.php">
|
||||
<i class="fa-fw menu-icon fa-solid fa-address-book"></i> DNS Records
|
||||
</a>
|
||||
</li>
|
||||
<li class="<?php if ($scriptname === 'settings-cname-records.php') { ?> active<?php } ?>">
|
||||
<a href="settings-cname-records.php">
|
||||
<i class="fa-fw menu-icon fa-solid fa-address-book"></i> CNAME Records
|
||||
<i class="fa-fw menu-icon fa-solid fa-address-book"></i> Local DNS Records
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -189,6 +184,41 @@
|
||||
<span class="pull-right-container warning-count hidden"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail log files -->
|
||||
<li class="treeview <?php if ($scriptname === 'taillog.php') { ?> active<?php } ?>">
|
||||
<a href="#">
|
||||
<i class="fa-fw menu-icon fa-solid fa-list-ul"></i> Tail log files
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<!-- Tail pihole.log -->
|
||||
<li class="<?php if ($scriptname === 'taillog.php' && $_GET["file"] == "dnsmasq") { ?> active<?php } ?>">
|
||||
<a href="taillog.php?file=dnsmasq">
|
||||
<i class="fa-fw menu-icon fa-solid fa-list-ul"></i> <code>pihole.log</code>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail FTL.log -->
|
||||
<li class="<?php if ($scriptname === 'taillog.php' && $_GET["file"] == "ftl") { ?> active<?php } ?>">
|
||||
<a href="taillog.php?file=ftl">
|
||||
<i class="fa-fw menu-icon fa-solid fa-list-ul"></i> <code>FTL.log</code>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail civetweb.log -->
|
||||
<li class="<?php if ($scriptname === 'taillog.php' && $_GET["file"] == "http") { ?> active<?php } ?>">
|
||||
<a href="taillog.php?file=http">
|
||||
<i class="fa-fw menu-icon fa-solid fa-list-ul"></i> <code>civetweb.log</code>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail ph7.log -->
|
||||
<li class="<?php if ($scriptname === 'taillog.php' && $_GET["file"] == "ph7") { ?> active<?php } ?>">
|
||||
<a href="taillog.php?file=ph7">
|
||||
<i class="fa-fw menu-icon fa-solid fa-list-ul"></i> <code>ph7.log</code>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Run gravity.sh -->
|
||||
<li class="<?php if ($scriptname === 'gravity.php') { ?> active<?php } ?>">
|
||||
<a href="gravity.php">
|
||||
@@ -201,20 +231,6 @@
|
||||
<i class="fa fa-fw menu-icon fa-search"></i> Search Adlists
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail pihole.log -->
|
||||
<li class="<?php if ($scriptname === 'taillog.php') { ?> active<?php } ?>">
|
||||
<a href="taillog.php">
|
||||
<svg class="svg-inline--fa fa-fw menu-icon" style="height: 1.25em"><use xlink:href="img/pihole_icon.svg#pihole-svg-logo"/></svg>
|
||||
Tail pihole.log
|
||||
</a>
|
||||
</li>
|
||||
<!-- Tail FTL.log -->
|
||||
<li class="<?php if ($scriptname === 'taillog-FTL.php') { ?> active<?php } ?>">
|
||||
<a href="taillog-FTL.php">
|
||||
<svg class="svg-inline--fa fa-fw menu-icon" style="height: 1.25em"><use xlink:href="img/pihole_icon.svg#pihole-svg-logo"/></svg>
|
||||
Tail FTL.log
|
||||
</a>
|
||||
</li>
|
||||
<!-- Generate debug log -->
|
||||
<li class="<?php if ($scriptname === 'debug.php') { ?> active<?php } ?>">
|
||||
<a href="debug.php">
|
||||
|
||||
141
settings-dns-records.php
Normal file
141
settings-dns-records.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/*
|
||||
* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2023 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license.
|
||||
*/
|
||||
|
||||
require 'scripts/pi-hole/php/header_authenticated.php';
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Local DNS records</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box collapsed-box">
|
||||
<!-- /.box-header -->
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
Add new DNS record
|
||||
</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>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="domain">Domain:</label>
|
||||
<input id="domain" type="url" class="form-control" placeholder="Add a domain (example.com or sub.example.com)" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="target">IP address:</label>
|
||||
<input id="ip" type="text" class="form-control" placeholder="Associated IP address" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer clearfix">
|
||||
<strong>Note:</strong>
|
||||
<p>The target of a <code>CNAME</code> must be a domain that the Pi-hole already has in its cache or is authoritative for. This is a universal limitation of <code>CNAME</code> records.</p>
|
||||
<p>The reason for this is that Pi-hole will not send additional queries upstream when serving <code>CNAME</code> replies. As consequence, if you set a target that isn't already known, the reply to the client may be incomplete. Pi-hole just returns the information it knows at the time of the query. This results in certain limitations for <code>CNAME</code> targets,
|
||||
for instance, only <i>active</i> DHCP leases work as targets - mere DHCP <i>leases</i> aren't sufficient as they aren't (yet) valid DNS records.</p>
|
||||
<p>Additionally, you can't <code>CNAME</code> external domains (<code>bing.com</code> to <code>google.com</code>) successfully as this could result in invalid SSL certificate errors when the target server does not serve content for the requested domain.</p>
|
||||
<button type="button" id="btnAdd" class="btn btn-primary pull-right">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<h3 class="box-title">List of local DNS records</h3>
|
||||
<!-- /.box-header -->
|
||||
<table id="dnsRecordsTable" class="table table-striped table-bordered" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>IP</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<button type="button" id="resetButton" class="btn btn-default btn-sm text-red hidden">Clear Filters</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Local CNAME records records</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box collapsed-box">
|
||||
<!-- /.box-header -->
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
Add new CNAME record
|
||||
</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>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="domain">Domain:</label>
|
||||
<input id="domain" type="url" class="form-control" placeholder="Add a domain (example.com or sub.example.com)" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="target">Target Domain:</label>
|
||||
<input id="target" type="url" class="form-control" placeholder="Associated Target Domain" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer clearfix">
|
||||
<strong>Note:</strong>
|
||||
<p>The target of a <code>CNAME</code> must be a domain that the Pi-hole already has in its cache or is authoritative for. This is a universal limitation of <code>CNAME</code> records.</p>
|
||||
<p>The reason for this is that Pi-hole will not send additional queries upstream when serving <code>CNAME</code> replies. As consequence, if you set a target that isn't already known, the reply to the client may be incomplete. Pi-hole just returns the information it knows at the time of the query. This results in certain limitations for <code>CNAME</code> targets,
|
||||
for instance, only <i>active</i> DHCP leases work as targets - mere DHCP <i>leases</i> aren't sufficient as they aren't (yet) valid DNS records.</p>
|
||||
<p>Additionally, you can't <code>CNAME</code> external domains (<code>bing.com</code> to <code>google.com</code>) successfully as this could result in invalid SSL certificate errors when the target server does not serve content for the requested domain.</p>
|
||||
<button type="button" id="btnAdd" class="btn btn-primary pull-right">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<h3 class="box-title">List of local CNAME records</h3>
|
||||
<!-- /.box-header -->
|
||||
<table id="customCNAMETable" class="table table-striped table-bordered" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>Target</th>
|
||||
<th>TTL</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<button type="button" id="resetButton" class="btn btn-default btn-sm text-red hidden">Clear Filters</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="<?php echo fileversion('scripts/vendor/jquery.confirm.min.js'); ?>"></script>
|
||||
<script src="<?php echo fileversion('scripts/pi-hole/js/settings-dns-records.js'); ?>"></script>
|
||||
<script src="<?php echo fileversion('scripts/pi-hole/js/ip-address-sorting.js'); ?>"></script>
|
||||
<script src="<?php echo fileversion('scripts/pi-hole/js/settings.js'); ?>"></script>
|
||||
|
||||
<?php
|
||||
require 'scripts/pi-hole/php/footer.php';
|
||||
?>
|
||||
@@ -1055,3 +1055,14 @@ table.dataTable tbody > tr > .selected {
|
||||
.faint-border {
|
||||
border-color: rgba(127, 127, 127, 0.1);
|
||||
}
|
||||
|
||||
.pre-scrollable {
|
||||
max-height: calc(100vh - 300px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.hr-small {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
border-top: 1px solid #ff0000aa;
|
||||
}
|
||||
|
||||
@@ -190,10 +190,6 @@ h4 {
|
||||
.box > .box-header {
|
||||
color: #bec5cb;
|
||||
}
|
||||
.box-solid > .box-header .btn,
|
||||
.box > .box-header .btn {
|
||||
color: #bec5cb;
|
||||
}
|
||||
.box.box-info,
|
||||
.box.box-primary,
|
||||
.box.box-success,
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license.
|
||||
*/
|
||||
|
||||
require 'scripts/pi-hole/php/header_authenticated.php';
|
||||
?>
|
||||
<!-- Title -->
|
||||
<div class="page-header">
|
||||
<h1>Output the last lines of the FTL.log file (live)</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="checkbox" checked id="chk1">
|
||||
<label for="chk1">Automatic scrolling on update</label>
|
||||
</div>
|
||||
|
||||
<pre id="output" style="width: 100%; height: 100%; max-height:650px; overflow-y:scroll;"></pre>
|
||||
|
||||
<div>
|
||||
<input type="checkbox" checked id="chk2">
|
||||
<label for="chk2">Automatic scrolling on update</label>
|
||||
</div>
|
||||
|
||||
<script src="<?php echo fileversion('scripts/pi-hole/js/taillog-FTL.js'); ?>"></script>
|
||||
|
||||
<?php
|
||||
require 'scripts/pi-hole/php/footer.php';
|
||||
?>
|
||||
36
taillog.php
36
taillog.php
@@ -10,21 +10,27 @@
|
||||
|
||||
require 'scripts/pi-hole/php/header_authenticated.php';
|
||||
?>
|
||||
<!-- Title -->
|
||||
<div class="page-header">
|
||||
<h1>Output the last lines of the pihole.log file (live)</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="checkbox" checked id="chk1">
|
||||
<label for="chk1">Automatic scrolling on update</label>
|
||||
</div>
|
||||
|
||||
<pre id="output" style="width: 100%; height: 100%; max-height:650px; overflow-y:scroll;"></pre>
|
||||
|
||||
<div>
|
||||
<input type="checkbox" checked id="chk2">
|
||||
<label for="chk2">Automatic scrolling on update</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><code>tail -F <span id="filename">...</span></code></h3>
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-success" id="live-feed">
|
||||
<span id="title">Live</span>
|
||||
<i id="feed-icon" class="fa-solid fa-fw fa-play fa-fade"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<pre id="output" class="pre pre-scrollable"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="<?php echo fileversion('scripts/pi-hole/js/taillog.js'); ?>"></script>
|
||||
|
||||
Reference in New Issue
Block a user