Merge branch 'development-v6' into tweak/settings_changed_only

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2024-02-11 10:14:49 +01:00
17 changed files with 172 additions and 164 deletions

View File

@@ -22,7 +22,7 @@ jobs:
uses: actions/checkout@v4.1.1 uses: actions/checkout@v4.1.1
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v4.0.1 uses: actions/setup-node@v4.0.2
with: with:
node-version: "20.x" node-version: "20.x"
cache: npm cache: npm

36
package-lock.json generated
View File

@@ -29,11 +29,11 @@
"select2": "4.0.13" "select2": "4.0.13"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.17",
"eslint-plugin-compat": "^4.2.0", "eslint-plugin-compat": "^4.2.0",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"postcss-cli": "^11.0.0", "postcss-cli": "^11.0.0",
"prettier": "^3.1.1", "prettier": "^3.2.5",
"xo": "^0.56.0" "xo": "^0.56.0"
} }
}, },
@@ -1318,9 +1318,9 @@
} }
}, },
"node_modules/autoprefixer": { "node_modules/autoprefixer": {
"version": "10.4.16", "version": "10.4.17",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz",
"integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -1337,9 +1337,9 @@
} }
], ],
"dependencies": { "dependencies": {
"browserslist": "^4.21.10", "browserslist": "^4.22.2",
"caniuse-lite": "^1.0.30001538", "caniuse-lite": "^1.0.30001578",
"fraction.js": "^4.3.6", "fraction.js": "^4.3.7",
"normalize-range": "^0.1.2", "normalize-range": "^0.1.2",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
@@ -1771,9 +1771,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001572", "version": "1.0.30001579",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001572.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
"integrity": "sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==", "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -5734,9 +5734,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.33", "version": "8.4.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -5861,9 +5861,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.1.1", "version": "3.2.5",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
"integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"

View File

@@ -25,11 +25,11 @@
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo:check" "testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo:check"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.17",
"eslint-plugin-compat": "^4.2.0", "eslint-plugin-compat": "^4.2.0",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"postcss-cli": "^11.0.0", "postcss-cli": "^11.0.0",
"prettier": "^3.1.1", "prettier": "^3.2.5",
"xo": "^0.56.0" "xo": "^0.56.0"
}, },
"browserslist": [ "browserslist": [

View File

@@ -37,10 +37,16 @@ function secondsTimeSpanToHMS(s) {
return h + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s); //zero padding on minutes and seconds return h + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s); //zero padding on minutes and seconds
} }
function piholeChanged(blocking) { function piholeChanged(blocking, timer = null) {
var status = $("#status"); const status = $("#status");
var ena = $("#pihole-enable"); const ena = $("#pihole-enable");
var dis = $("#pihole-disable"); const dis = $("#pihole-disable");
const enaT = $("#enableTimer");
if (timer !== null && parseFloat(timer) > 0) {
enaT.html(Date.now() + parseFloat(timer) * 1000);
setTimeout(countDown, 100);
}
switch (blocking) { switch (blocking) {
case "enabled": { case "enabled": {
@@ -81,7 +87,7 @@ function piholeChanged(blocking) {
function countDown() { function countDown() {
var ena = $("#enableLabel"); var ena = $("#enableLabel");
var enaT = $("#enableTimer"); var enaT = $("#enableTimer");
var target = new Date(parseInt(enaT.html(), 10)); var target = new Date(parseInt(enaT.text(), 10));
var seconds = Math.round((target.getTime() - Date.now()) / 1000); var seconds = Math.round((target.getTime() - Date.now()) / 1000);
//Stop and remove timer when user enabled early //Stop and remove timer when user enabled early
@@ -95,7 +101,7 @@ function countDown() {
ena.text("Enable Blocking (" + secondsTimeSpanToHMS(seconds) + ")"); ena.text("Enable Blocking (" + secondsTimeSpanToHMS(seconds) + ")");
} else { } else {
ena.text("Enable Blocking"); ena.text("Enable Blocking");
piholeChanged("enabled"); piholeChanged("enabled", null);
if (localStorage) { if (localStorage) {
localStorage.removeItem("countDownTarget"); localStorage.removeItem("countDownTarget");
} }
@@ -114,7 +120,7 @@ function checkBlocking() {
method: "GET", method: "GET",
}) })
.done(function (data) { .done(function (data) {
piholeChanged(data.blocking); piholeChanged(data.blocking, data.timer);
utils.setTimer(checkBlocking, REFRESH_INTERVAL.blocking); utils.setTimer(checkBlocking, REFRESH_INTERVAL.blocking);
}) })
.fail(function (data) { .fail(function (data) {
@@ -124,8 +130,7 @@ function checkBlocking() {
} }
function piholeChange(action, duration) { function piholeChange(action, duration) {
var enaT = $("#enableTimer"); let btnStatus = null;
var btnStatus;
switch (action) { switch (action) {
case "enable": case "enable":
@@ -153,11 +158,7 @@ function piholeChange(action, duration) {
.done(function (data) { .done(function (data) {
if (data.blocking === action + "d") { if (data.blocking === action + "d") {
btnStatus.html(""); btnStatus.html("");
piholeChanged(data.blocking); piholeChanged(data.blocking, data.timer);
if (duration > 0) {
enaT.html(Date.now() + duration * 1000);
setTimeout(countDown, 100);
}
} }
}) })
.fail(function (data) { .fail(function (data) {

View File

@@ -66,6 +66,7 @@ function delGroupItems(type, ids, table) {
$.ajax({ $.ajax({
url: url, url: url,
data: JSON.stringify(ids), data: JSON.stringify(ids),
contentType: "application/json",
method: "POST", method: "POST",
}) })
.done(function () { .done(function () {

View File

@@ -7,8 +7,7 @@
/* global utils:false, apiFailure:false, updateFtlInfo:false, processGroupResult:false, delGroupItems:false */ /* global utils:false, apiFailure:false, updateFtlInfo:false, processGroupResult:false, delGroupItems:false */
var table, var table;
idNames = {};
function handleAjaxError(xhr, textStatus) { function handleAjaxError(xhr, textStatus) {
if (textStatus === "timeout") { if (textStatus === "timeout") {
@@ -73,20 +72,20 @@ $(function () {
"\nDatabase ID: " + "\nDatabase ID: " +
data.id; data.id;
$("td:eq(1)", row).html( $("td:eq(1)", row).html(
'<input id="name_' + data.id + '" title="' + tooltip + '" class="form-control">' '<input id="name_' + dataId + '" title="' + tooltip + '" class="form-control">'
); );
var nameEl = $("#name_" + data.id, row); var nameEl = $("#name_" + dataId, row);
nameEl.val(data.name); nameEl.val(data.name);
nameEl.on("change", editGroup); nameEl.on("change", editGroup);
$("td:eq(2)", row).html( $("td:eq(2)", row).html(
'<input type="checkbox" id="enabled_' + '<input type="checkbox" id="enabled_' +
data.id + dataId +
'"' + '"' +
(data.enabled ? " checked" : "") + (data.enabled ? " checked" : "") +
">" ">"
); );
var enabledEl = $("#enabled_" + data.id, row); var enabledEl = $("#enabled_" + dataId, row);
enabledEl.bootstrapToggle({ enabledEl.bootstrapToggle({
on: "Enabled", on: "Enabled",
off: "Disabled", off: "Disabled",
@@ -96,9 +95,9 @@ $(function () {
}); });
enabledEl.on("change", editGroup); enabledEl.on("change", editGroup);
$("td:eq(3)", row).html('<input id="comment_' + data.id + '" class="form-control">'); $("td:eq(3)", row).html('<input id="comment_' + dataId + '" class="form-control">');
var comment = data.comment !== null ? data.comment : ""; var comment = data.comment !== null ? data.comment : "";
var commentEl = $("#comment_" + data.id, row); var commentEl = $("#comment_" + dataId, row);
commentEl.val(comment); commentEl.val(comment);
commentEl.on("change", editGroup); commentEl.on("change", editGroup);
@@ -292,7 +291,7 @@ function editGroup() {
const elem = $(this).attr("id"); const elem = $(this).attr("id");
const tr = $(this).closest("tr"); const tr = $(this).closest("tr");
const id = tr.attr("data-id"); const id = tr.attr("data-id");
const oldName = idNames[id]; const oldName = utils.hexDecode(id);
const name = tr.find("#name_" + id).val(); const name = tr.find("#name_" + id).val();
const enabled = tr.find("#enabled_" + id).is(":checked"); const enabled = tr.find("#enabled_" + id).is(":checked");
const comment = tr.find("#comment_" + id).val(); const comment = tr.find("#comment_" + id).val();

View File

@@ -200,6 +200,13 @@ function parseQueryStatus(data) {
buttontext = buttontext =
'<button type="button" class="btn btn-default btn-sm text-red btn-blacklist"><i class="fa fa-ban"></i> Deny</button>'; '<button type="button" class="btn btn-default btn-sm text-red btn-blacklist"><i class="fa fa-ban"></i> Deny</button>';
break; break;
case "SPECIAL_DOMAIN":
colorClass = "text-red";
icon = "fa-solid fa-ban";
fieldtext = data.status;
buttontext = "";
blocked = true;
break;
default: default:
colorClass = "text-orange"; colorClass = "text-orange";
icon = "fa-solid fa-question"; icon = "fa-solid fa-question";
@@ -276,17 +283,16 @@ function formatInfo(data) {
"</span></strong></div>"; "</span></strong></div>";
} }
var regexInfo = "", var listInfo = "",
cnameInfo = ""; cnameInfo = "";
if (data.regex_id !== null && data.regex_id > -1) { if (data.list_id !== null && data.list_id !== -1) {
var regexLink = // Some list matched - add link to search page
'<a href="groups/domains?domainid=' +
data.regex_id + var listLink =
'" target="_blank">entry with ID ' + '<a href="search?domain=' +
data.regex_id + encodeURIComponent(data.domain) +
"</a>"; '" target="_blank">search lists</a>';
regexInfo = listInfo = divStart + "Query was " + queryStatus.matchText + ", " + listLink + "</div>";
divStart + "Query was " + queryStatus.matchText + " by </td><td>" + regexLink + "</div>";
} }
if (queryStatus.isCNAME) { if (queryStatus.isCNAME) {
@@ -349,7 +355,7 @@ function formatInfo(data) {
dnssecInfo + dnssecInfo +
statusInfo + statusInfo +
cnameInfo + cnameInfo +
regexInfo + listInfo +
ttlInfo + ttlInfo +
replyInfo + replyInfo +
dbInfo + dbInfo +

View File

@@ -6,6 +6,18 @@
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false */ /* global utils:false, apiFailure:false */
var GETDict = {};
$(function () {
GETDict = utils.parseQueryString();
if (GETDict.domain !== undefined) {
$("input[id^='domain']").val(GETDict.domain);
}
if (GETDict.N !== undefined) {
$("#number").val(GETDict.number);
}
});
function eventsource(partial) { function eventsource(partial) {
const ta = $("#output"); const ta = $("#output");

View File

@@ -58,7 +58,7 @@ function generateRow(topic, key, value) {
: "") + : "") +
"</h3>" + "</h3>" +
"<p>" + "<p>" +
utils.escapeHtml(value.description).replace("\n", "<br>") + utils.escapeHtml(value.description).replaceAll("\n", "<br>") +
"</p>" + "</p>" +
"</div>" + "</div>" +
'<div class="box-body">' + '<div class="box-body">' +

View File

@@ -51,7 +51,7 @@ function importZIP() {
$("#modal-import-success-title").text("Import successful"); $("#modal-import-success-title").text("Import successful");
var text = "<p>Processed files:</p><ul>"; var text = "<p>Processed files:</p><ul>";
for (var i = 0; i < data.files.length; i++) { for (var i = 0; i < data.files.length; i++) {
text += "<li>/" + utils.escapeHtml(data.files[i]) + "</li>"; text += "<li>" + utils.escapeHtml(data.files[i]) + "</li>";
} }
text += "</ul>"; text += "</ul>";

View File

@@ -152,6 +152,10 @@ function showAlert(type, icon, title, message) {
} }
function datetime(date, html, humanReadable) { function datetime(date, html, humanReadable) {
if (date === 0 && humanReadable) {
return "Never";
}
var format = html === false ? "Y-MM-DD HH:mm:ss z" : "Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z"; var format = html === false ? "Y-MM-DD HH:mm:ss z" : "Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z";
var timestr = moment.unix(Math.floor(date)).format(format).trim(); var timestr = moment.unix(Math.floor(date)).format(format).trim();
return humanReadable return humanReadable
@@ -391,7 +395,7 @@ function checkMessages() {
}) })
.done(function (data) { .done(function (data) {
if (data.count > 0) { if (data.count > 0) {
var more = '\nAccess "Tools/Pi-hole diganosis" for further details.'; var more = '\nAccess "Tools/Pi-hole diagnosis" for further details.';
var title = var title =
data.count > 1 data.count > 1
? "There are " + data.count + " warnings." + more ? "There are " + data.count + " warnings." + more

View File

@@ -24,14 +24,19 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
<div class="box-body"> <div class="box-body">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<p><strong>Domains to be excluded from Top Domains / Ads Lists</strong></p> <p><strong>Domains to be excluded from Top Domain Lists and Query Log</strong></p>
<textarea class="form-control" rows="4" id="webserver.api.excludeDomains" data-key="webserver.api.excludeDomains" placeholder="Enter domains, one per line" style="resize: vertical;"></textarea> <textarea class="form-control" rows="4" id="webserver.api.excludeDomains" data-key="webserver.api.excludeDomains" placeholder="Enter regex domains, one per line" style="resize: vertical;"></textarea>
<p class="help-block">Domains may be described by their domain name (like <code>example.com</code>)</p> <p class="help-block">Domains may be described by their domain name (like <code>^example\.com$</code>)</p>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<p><strong>Clients to be excluded from Top Clients List</strong></p> <p><strong>Clients to be excluded from Top Client Lists and Query Log </strong></p>
<textarea class="form-control" rows="4" id="webserver.api.excludeClients" data-key="webserver.api.excludeClients" placeholder="Enter clients, one per line" style="resize: vertical;"></textarea> <textarea class="form-control" rows="4" id="webserver.api.excludeClients" data-key="webserver.api.excludeClients" placeholder="Enter regex clients, one per line" style="resize: vertical;"></textarea>
<p class="help-block">Clients may be described either by their IP addresses (IPv4 and IPv6 are supported), or hostnames (like <code>laptop.lan</code>).</p> <p class="help-block">Clients may be described either by their IP addresses (IPv4 and IPv6 are supported), or hostnames (like <code>^laptop\.lan$</code>).</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p><strong>Important:</strong> Those input fields accept regex entries only. Please refer to <a href="https://docs.pi-hole.net/regex/tutorial/" rel="noopener" target="_blank">our guide</a> how to construct valid regex entries.
</div> </div>
</div> </div>
</div> </div>

View File

@@ -61,16 +61,19 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-6 col-md-12 col-lg-6"> <div class="col-xs-12 col-sm-6 col-md-12 col-lg-6">
<label>Netmask (<code>0.0.0.0</code> = auto)</label> <label>Netmask</label>
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">
<div class="input-group-addon">Netmask</div> <div class="input-group-addon">Netmask</div>
<input type="text" class="form-control DHCPgroup" id="dhcp.netmask" data-key="dhcp.netmask" <input type="text" class="form-control DHCPgroup" id="dhcp.netmask" data-key="dhcp.netmask"
autocomplete="off" spellcheck="false" autocapitalize="none" autocomplete="off" spellcheck="false" autocapitalize="none"
autocorrect="off" value=""> autocorrect="off" value="" placeholder="automatic">
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-12">
<p>Leave the netmask field empty to have Pi-hole infer it from the configured IP address of your device. If you want to specify a netmask, you can use the format <code>255.255.255.0</code>.</p>
</div>
<div class="col-md-12"> <div class="col-md-12">
<div><input type="checkbox" id="dhcp.ipv6" data-key="dhcp.ipv6" class="DHCPgroup">&nbsp;<label for="dhcp.ipv6"><strong>Enable additional IPv6 support (SLAAC + RA)</strong></label></div> <div><input type="checkbox" id="dhcp.ipv6" data-key="dhcp.ipv6" class="DHCPgroup">&nbsp;<label for="dhcp.ipv6"><strong>Enable additional IPv6 support (SLAAC + RA)</strong></label></div>
<p>Enable this option to enable IPv6 support for the Pi-hole DHCP server. This will allow the Pi-hole to hand out IPv6 addresses to clients and also provide IPv6 router advertisements (RA) to clients. This option is only useful if the Pi-hole is configured with an IPv6 address.</p> <p>Enable this option to enable IPv6 support for the Pi-hole DHCP server. This will allow the Pi-hole to hand out IPv6 addresses to clients and also provide IPv6 router advertisements (RA) to clients. This option is only useful if the Pi-hole is configured with an IPv6 address.</p>

View File

@@ -59,64 +59,48 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
</div> </div>
<div class="box box-warning settings-level-expert"> <div class="box box-warning settings-level-expert">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title" data-configkeys="dns.revServer.active dns.revServer.cidr dns.revServer.target dns.revServer.domain">Conditional forwarding</h3> <h3 class="box-title" data-configkeys="dns.domain dns.expandHosts">DNS domain settings</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<label>Pi-hole domain name</label>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">Domain</div>
<input type="text" class="form-control" id="dns.domain" data-key="dns.domain" value="">
</div>
</div>
<p>The DNS domains for your Pi-hole. If no domain is specified and you are using Pi-hole's DHCP server, then any hostnames with a domain part (i.e., with a period) will be disallowed. If a domain is specified, then hostnames with a domain parts matching the domain here are allowed. In addition, when a suffix is set then hostnames without a domain part have the suffix added as an optional domain part.</p>
<div>
<input type="checkbox" id="dns.expandHosts" data-key="dns.expandHosts" title="domain-needed">
<label for="dns.expandHosts"><strong>Expand hostnames</strong></label>
<p>If set, the domain is added to simple names (without a period) in /etc/hosts in the same way as for DHCP-derived names.</p>
</div>
</div>
</div>
</div>
</div>
<div class="box box-warning settings-level-expert">
<div class="box-header with-border">
<h3 class="box-title" data-configkeys="dns.rateLimit.count dns.rateLimit.interval">Rate-limiting</h3>
</div> </div>
<div class="box-body"> <div class="box-body">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<p>If not configured as your DHCP server, Pi-hole typically won't be able to <p>Block clients making more than <input type="number" id="dns.rateLimit.count" data-key="dns.rateLimit.count" data-type="integer" value="" min="0" step="10" style="width: 5em;"> queries within
determine the names of devices on your local network. As a <input type="number" id="dns.rateLimit.interval" data-key="dns.rateLimit.interval" data-type="integer" value="" min="0" step="10" style="width: 4em;"> seconds.</p>
result, tables such as Top Clients will only show IP addresses.</p> <p>When a client makes too many queries in too short time, it
<p>One solution for this is to configure Pi-hole to forward these gets rate-limited. Rate-limited queries are answered with a
requests to your DHCP server (most likely your router), but only for devices on your <code>REFUSED</code> reply and not further processed by FTL
home network. To configure this we will need to know the IP and prevent Pi-holes getting overwhelmed by rogue clients.
address of your DHCP server and which addresses belong to your local network. It is important to note that rate-limiting is happening on a
Exemplary input is given below as placeholder in the text boxes (if empty).</p> per-client basis. Other clients can continue to use FTL while
<p>If your local network spans 192.168.0.1 - 192.168.0.255, then you will have to input rate-limited clients are short-circuited at the same time.</p>
<code>192.168.0.0/24</code>. If your local network is 192.168.47.1 - 192.168.47.255, it will <p>Rate-limiting may be disabled altogether by setting both
be <code>192.168.47.0/24</code> and similar. If your network is larger, the CIDR has to be values to zero. See
different, for instance a range of 10.8.0.1 - 10.8.255.255 results in <code>10.8.0.0/16</code>, <a href="https://docs.pi-hole.net/ftldns/configfile/#rate_limit" target="_blank">our documentation</a>
whereas an even wider network of 10.0.0.1 - 10.255.255.255 results in <code>10.0.0.0/8</code>. for further details.</p>
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" rel="noopener" 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>
<p>Enabling Conditional Forwarding will also forward all hostnames (i.e., non-FQDNs) to the router
when "Never forward non-FQDNs" is <em>not</em> enabled.</p>
<div class="form-group">
<div>
<input type="checkbox" id="dns.revServer.active" data-key="dns.revServer.active">
<label for="dns.revServer.active"><strong>Use Conditional Forwarding</strong></label>
</div>
<div class="input-group">
<table class="table table-bordered">
<thead>
<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>
</thead>
<tbody>
<tr>
<td>
<input type="text" id="dns.revServer.cidr" data-key="dns.revServer.cidr" placeholder="192.168.0.0/16" class="form-control" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off" value="">
</td>
<td>
<input type="text" id="dns.revServer.target" data-key="dns.revServer.target" placeholder="192.168.0.1" class="form-control" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off" value="">
</td>
<td>
<input type="text" id="dns.revServer.domain" data-key="dns.revServer.domain" placeholder="local" class="form-control" data-mask autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off" value="">
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -164,30 +148,6 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
</div> </div>
</div> </div>
</div> </div>
<div class="box box-warning">
<div class="box-header with-border">
<h3 class="box-title" data-configkeys="dns.domain dns.expandHosts">DNS domain settings</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12">
<label>Pi-hole domain name</label>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">Domain</div>
<input type="text" class="form-control" id="dns.domain" data-key="dns.domain" value="">
</div>
</div>
<p>The DNS domains for your Pi-hole. If no domain is specified and you are using Pi-hole's DHCP server, then any hostnames with a domain part (i.e., with a period) will be disallowed. If a domain is specified, then hostnames with a domain parts matching the domain here are allowed. In addition, when a suffix is set then hostnames without a domain part have the suffix added as an optional domain part.</p>
<div>
<input type="checkbox" id="dns.expandHosts" data-key="dns.expandHosts" title="domain-needed">
<label for="dns.expandHosts"><strong>Expand hostnames</strong></label>
<p>If set, the domain is added to simple names (without a period) in /etc/hosts in the same way as for DHCP-derived names.</p>
</div>
</div>
</div>
</div>
</div>
<div class="box box-warning"> <div class="box box-warning">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title" data-configkeys="dns.domainNeeded dns.bogusPriv dns.dnssec">Advanced DNS settings</h3> <h3 class="box-title" data-configkeys="dns.domainNeeded dns.bogusPriv dns.dnssec">Advanced DNS settings</h3>
@@ -233,26 +193,40 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="col-lg-12">
<div class="box box-warning settings-level-expert"> <div class="box box-warning settings-level-expert">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title" data-configkeys="dns.rateLimit.count dns.rateLimit.interval">Rate-limiting</h3> <h3 class="box-title" data-configkeys="dns.revServers">Conditional forwarding</h3>
</div> </div>
<div class="box-body"> <div class="box-body">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<p>Block clients making more than <input type="number" id="dns.rateLimit.count" data-key="dns.rateLimit.count" data-type="integer" value="" min="0" step="10" style="width: 5em;"> queries within <p>If not configured as your DHCP server, Pi-hole typically won't be able to
<input type="number" id="dns.rateLimit.interval" data-key="dns.rateLimit.interval" data-type="integer" value="" min="0" step="10" style="width: 4em;"> seconds.</p> determine the names of devices on your local network. As a
<p>When a client makes too many queries in too short time, it result, tables such as Top Clients will only show IP addresses.</p>
gets rate-limited. Rate-limited queries are answered with a <p>One solution for this is to configure Pi-hole to forward these
<code>REFUSED</code> reply and not further processed by FTL requests to your DHCP server (most likely your router), but only for devices on your
and prevent Pi-holes getting overwhelmed by rogue clients. home network. To configure this we will need to know the IP
It is important to note that rate-limiting is happening on a address of your DHCP server and which addresses belong to your local network.
per-client basis. Other clients can continue to use FTL while Exemplary input is given below as placeholder in the text boxes (if empty).</p>
rate-limited clients are short-circuited at the same time.</p> <p>If your local network spans 192.168.0.1 - 192.168.0.255, then you will have to input
<p>Rate-limiting may be disabled altogether by setting both <code>192.168.0.0/24</code>. If your local network is 192.168.47.1 - 192.168.47.255, it will
values to zero. See be <code>192.168.47.0/24</code> and similar. If your network is larger, the CIDR has to be
<a href="https://docs.pi-hole.net/ftldns/configfile/#rate_limit" target="_blank">our documentation</a> different, for instance a range of 10.8.0.1 - 10.8.255.255 results in <code>10.8.0.0/16</code>,
for further details.</p> 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" rel="noopener" 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>
<p>Enabling Conditional Forwarding will also forward all hostnames (i.e., non-FQDNs) to the router
when "Never forward non-FQDNs" is <em>not</em> enabled.</p>
<p>The following list contains all reverse servers you want to add. The expected format is one server per line in form of <code>&lt;enabled&gt;,&lt;ip-address&gt;[/&lt;prefix-len&gt;],&lt;server&gt;[#&lt;port&gt;][,&lt;domain&gt;]</code>. A valid config line could look like <code>true,192.168.0.0/24,192.168.0.1,fritz.box</code></p>
<textarea class="form-control" rows="3" id="dns.revServers" data-key="dns.revServers" placeholder="Enter reverse DNS servers, one per line" style="resize: vertical;"></textarea>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -20,8 +20,8 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
<h3 class="box-title">Export your Pi-hole's configuration</h3> <h3 class="box-title">Export your Pi-hole's configuration</h3>
</div> </div>
<div class="box-body"> <div class="box-body">
<p>Warning: This archive contains sensitive information about your Pi-hole installation, e.g. the API token and the 2FA-TOTP secret (if enabled). Please be careful with this file and do not share it with anyone even if they claim to help you.</p> <p>Warning: This archive contains sensitive information about your Pi-hole installation, e.g. your 2FA-TOTP secret (if enabled). Please be careful with this file and do not share it with anyone even if they claim to help you.</p>
<? if not is_secure then ?><p class='text-danger'>Warning: You are currently not using an end-to-end encryption. This means that your API token and 2FA-TOTP secret will be transmitted in plain text. We recommend to use HTTPS when exporting your configuration.</p><? end ?> <? if not is_secure then ?><p class='text-danger'>Warning: You are currently not using an end-to-end encryption. This means that secrets like your 2FA-TOTP secret will be transmitted in plain text. We recommend to use HTTPS when exporting your configuration.</p><? end ?>
<div class="pull-right"> <div class="pull-right">
<a class="btn btn-app btn-success" id="GETTeleporter" target="_blank"> <a class="btn btn-app btn-success" id="GETTeleporter" target="_blank">
<i class="fa fa-save"></i><br>Export <i class="fa fa-save"></i><br>Export
@@ -38,7 +38,7 @@ mg.include('scripts/pi-hole/lua/settings_header.lp','r')
<div class="box-body"> <div class="box-body">
<div class="form-group"> <div class="form-group">
<label for="file">File input</label> <label for="file">File input</label>
<input type="file" name="file" id="file" accept=".zip"> <input type="file" name="file" id="file" accept=".zip,.tar.gz">
<p class="help-block">When importing settings from a <em>newer</em> version of Pi-hole, not yet existing settings will be ignored. When importing from an <em>older</em> version of Pi-hole, settings for newer features will be initialized with their default values.</p> <p class="help-block">When importing settings from a <em>newer</em> version of Pi-hole, not yet existing settings will be ignored. When importing from an <em>older</em> version of Pi-hole, settings for newer features will be initialized with their default values.</p>
</div> </div>
<div class="pull-right"> <div class="pull-right">

View File

@@ -1068,12 +1068,15 @@ table.dataTable tbody > tr > .selected {
#output { #output {
position: relative; position: relative;
display: grid;
margin: 5px 0; margin: 5px 0;
min-height: 36px; min-height: 36px;
padding: 4px 8px; padding: 4px 8px;
} }
#output.pre-taillog {
display: grid;
}
.loading::before { .loading::before {
content: " "; content: " ";
position: absolute; position: absolute;

View File

@@ -25,7 +25,7 @@ mg.include('scripts/pi-hole/lua/header_authenticated.lp','r')
<div class="box-body"> <div class="box-body">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<pre id="output" class="pre pre-scrollable"></pre> <pre id="output" class="pre pre-scrollable pre-taillog"></pre>
</div> </div>
</div> </div>
</div> </div>