diff --git a/.codespellignore b/.codespellignore index f99608035..ec502f02e 100644 --- a/.codespellignore +++ b/.codespellignore @@ -1,2 +1,3 @@ ede EDE +prefered diff --git a/interfaces.lp b/interfaces.lp new file mode 100644 index 000000000..b4341c99a --- /dev/null +++ b/interfaces.lp @@ -0,0 +1,36 @@ + --[[ +* Pi-hole: A black hole for Internet advertisements +* (c) 2024 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. +--]] + +mg.include('scripts/pi-hole/lua/header_authenticated.lp','r') +?> + +
" + utils.escapeHtml(master.name) + "
",
+ icon: "fa fa-network-wired fa-fw",
+ });
+ }
+ }
+
+ if (interface.speed) {
+ obj.nodes.push({
+ text: "Speed: " + intl.format(interface.speed) + " Mbit/s",
+ icon: "fa fa-tachometer-alt fa-fw",
+ });
+ }
+
+ if (interface.type !== undefined) {
+ obj.nodes.push({
+ text: "Type: " + utils.escapeHtml(interface.type),
+ icon: "fa fa-network-wired fa-fw",
+ });
+ }
+
+ if (interface.flags !== undefined && interface.flags.length > 0) {
+ obj.nodes.push({
+ text: "Flags: " + utils.escapeHtml(interface.flags.join(", ")),
+ icon: "fa fa-flag fa-fw",
+ });
+ }
+
+ if (interface.address !== undefined) {
+ let extra = "";
+ if (interface.perm_address !== undefined && interface.perm_address !== interface.address) {
+ extra = " (permanent: " + utils.escapeHtml(interface.perm_address) + "
)";
+ }
+
+ obj.nodes.push({
+ text:
+ "Hardware address: " + utils.escapeHtml(interface.address) + "
" + extra,
+ icon: "fa fa-map-marker-alt fa-fw",
+ });
+ }
+
+ if (interface.addresses !== undefined) {
+ const addrs = {
+ text:
+ interface.addresses.length +
+ (interface.addresses.length === 1 ? " address" : " addresses") +
+ " connected to interface",
+ icon: "fa fa-map-marker-alt fa-fw",
+ nodes: [],
+ };
+
+ for (const addr of interface.addresses) {
+ let extraaddr = "";
+ if (addr.prefixlen !== undefined) {
+ extraaddr += " / " + addr.prefixlen + "
";
+ }
+
+ if (addr.address_type !== undefined) {
+ let familyextra = "";
+ if (addr.family !== undefined) {
+ if (addr.family === "inet") {
+ familyextra = "IPv4 ";
+ } else if (addr.family === "inet6") {
+ familyextra = "IPv6 ";
+ }
+ }
+
+ extraaddr += " (" + familyextra + utils.escapeHtml(addr.address_type) + ")";
+ }
+
+ let family = "";
+ if (addr.family !== undefined) {
+ family = addr.family + " ";
+ }
+
+ const jaddr = {
+ text:
+ "Address: " + family + utils.escapeHtml(addr.address) + "
" + extraaddr,
+ icon: "fa fa-map-marker-alt fa-fw",
+ nodes: [],
+ };
+ if (addr.local !== undefined) {
+ jaddr.nodes.push({
+ text: "Local: " + utils.escapeHtml(addr.local) + "
",
+ icon: "fa fa-map-marker-alt fa-fw",
+ });
+ }
+
+ if (addr.broadcast !== undefined) {
+ jaddr.nodes.push({
+ text: "Broadcast: " + utils.escapeHtml(addr.broadcast) + "
",
+ icon: "fa fa-map-marker-alt fa-fw",
+ });
+ }
+
+ if (addr.scope !== undefined) {
+ jaddr.nodes.push({
+ text: "Scope: " + utils.escapeHtml(addr.scope),
+ icon: "fa fa-map-marker-alt fa-fw",
+ });
+ }
+
+ if (addr.flags !== undefined && addr.flags.length > 0) {
+ jaddr.nodes.push({
+ text: "Flags: " + utils.escapeHtml(addr.flags.join(", ")),
+ icon: "fa fa-map-marker-alt fa-fw",
+ });
+ }
+
+ if (addr.prefered !== undefined) {
+ const pref =
+ addr.prefered === 4294967295 ? "forever" : intl.format(addr.prefered) + " s";
+ jaddr.nodes.push({
+ text: "Preferred lifetime: " + pref,
+ icon: "fa fa-clock fa-fw",
+ });
+ }
+
+ if (addr.valid !== undefined) {
+ const valid = addr.valid === 4294967295 ? "forever" : intl.format(addr.valid) + " s";
+ jaddr.nodes.push({
+ text: "Valid lifetime: " + valid,
+ icon: "fa fa-clock fa-fw",
+ });
+ }
+
+ if (addr.cstamp !== undefined) {
+ jaddr.nodes.push({
+ text: "Created: " + new Date(addr.cstamp * 1000).toLocaleString(),
+ icon: "fa fa-clock fa-fw",
+ });
+ }
+
+ if (addr.tstamp !== undefined) {
+ jaddr.nodes.push({
+ text: "Last updated: " + new Date(addr.tstamp * 1000).toLocaleString(),
+ icon: "fa fa-clock fa-fw",
+ });
+ }
+
+ addrs.nodes.push(jaddr);
+ }
+
+ obj.nodes.push(addrs);
+ }
+
+ if (interface.stats !== undefined) {
+ const stats = {
+ text: "Statistics",
+ icon: "fa fa-chart-line fa-fw",
+ expanded: false,
+ nodes: [],
+ };
+ if (interface.stats.rx_bytes !== undefined) {
+ stats.nodes.push({
+ text:
+ "RX bytes: " +
+ intl.format(interface.stats.rx_bytes.value) +
+ " " +
+ interface.stats.rx_bytes.unit,
+ icon: "fa fa-download fa-fw",
+ });
+ }
+
+ if (interface.stats.tx_bytes !== undefined) {
+ stats.nodes.push({
+ text:
+ "TX bytes: " +
+ intl.format(interface.stats.tx_bytes.value) +
+ " " +
+ interface.stats.tx_bytes.unit,
+ icon: "fa fa-upload fa-fw",
+ });
+ }
+
+ if (interface.stats.rx_packets !== undefined) {
+ stats.nodes.push({
+ text: "RX packets: " + intl.format(interface.stats.rx_packets),
+ icon: "fa fa-download fa-fw",
+ });
+ }
+
+ if (interface.stats.rx_errors !== undefined) {
+ stats.nodes.push({
+ text:
+ "RX errors: " +
+ intl.format(interface.stats.rx_errors) +
+ " (" +
+ ((interface.stats.rx_errors / interface.stats.rx_packets) * 100).toFixed(1) +
+ "%)",
+ icon: "fa fa-download fa-fw",
+ });
+ }
+
+ if (interface.stats.rx_dropped !== undefined) {
+ stats.nodes.push({
+ text:
+ "RX dropped: " +
+ intl.format(interface.stats.rx_dropped) +
+ " (" +
+ ((interface.stats.rx_dropped / interface.stats.rx_packets) * 100).toFixed(1) +
+ "%)",
+ icon: "fa fa-download fa-fw",
+ });
+ }
+
+ if (interface.stats.tx_packets !== undefined) {
+ stats.nodes.push({
+ text: "TX packets: " + intl.format(interface.stats.tx_packets),
+ icon: "fa fa-upload fa-fw",
+ });
+ }
+
+ if (interface.stats.tx_errors !== undefined) {
+ stats.nodes.push({
+ text:
+ "TX errors: " +
+ intl.format(interface.stats.tx_errors) +
+ " (" +
+ ((interface.stats.tx_errors / interface.stats.tx_packets) * 100).toFixed(1) +
+ "%)",
+ icon: "fa fa-upload fa-fw",
+ });
+ }
+
+ if (interface.stats.tx_dropped !== undefined) {
+ stats.nodes.push({
+ text:
+ "TX dropped: " +
+ intl.format(interface.stats.tx_dropped) +
+ " (" +
+ ((interface.stats.tx_dropped / interface.stats.tx_packets) * 100).toFixed(1) +
+ "%)",
+ icon: "fa fa-upload fa-fw",
+ });
+ }
+
+ if (interface.stats.multicast !== undefined) {
+ stats.nodes.push({
+ text: "Multicast: " + intl.format(interface.stats.multicast),
+ icon: "fa fa-broadcast-tower fa-fw",
+ });
+ }
+
+ if (interface.stats.collisions !== undefined) {
+ stats.nodes.push({
+ text: "Collisions: " + intl.format(interface.stats.collisions),
+ icon: "fa fa-exchange-alt fa-fw",
+ });
+ }
+
+ obj.nodes.push(stats);
+ }
+
+ const furtherDetails = {
+ text: "Further details",
+ icon: "fa fa-info-circle fa-fw",
+ expanded: false,
+ nodes: [],
+ };
+
+ if (interface.parent_dev_name !== undefined) {
+ let extra = "";
+ if (interface.parent_dev_bus_name !== undefined) {
+ extra = " @ " + utils.escapeHtml(interface.parent_dev_bus_name);
+ }
+
+ furtherDetails.nodes.push({
+ text:
+ "Parent device: " +
+ utils.escapeHtml(interface.parent_dev_name) +
+ extra +
+ "
",
+ icon: "fa fa-network-wired fa-fw",
+ });
+ }
+
+ if (interface.carrier_changes !== undefined) {
+ furtherDetails.nodes.push({
+ text: "Carrier changes: " + intl.format(interface.carrier_changes),
+ icon: "fa fa-exchange-alt fa-fw",
+ });
+ }
+
+ if (interface.broadcast) {
+ furtherDetails.nodes.push({
+ text: "Broadcast: " + utils.escapeHtml(interface.broadcast) + "
",
+ icon: "fa fa-broadcast-tower fa-fw",
+ });
+ }
+
+ if (interface.mtu) {
+ let extra = "";
+ if (interface.min_mtu !== undefined && interface.max_mtu !== undefined) {
+ extra +=
+ " (min: " +
+ intl.format(interface.min_mtu) +
+ " bytes, max: " +
+ intl.format(interface.max_mtu) +
+ " bytes)";
+ }
+
+ furtherDetails.nodes.push({
+ text: "MTU: " + intl.format(interface.mtu) + " bytes" + extra,
+ icon: "fa fa-arrows-alt-h fa-fw",
+ });
+ }
+
+ if (interface.txqlen) {
+ furtherDetails.nodes.push({
+ text: "TX queue length: " + intl.format(interface.txqlen),
+ icon: "fa fa-file-upload fa-fw",
+ });
+ }
+
+ if (interface.promiscuity !== undefined) {
+ furtherDetails.nodes.push({
+ text: "Promiscuity mode: " + (interface.promiscuity ? "Yes" : "No"),
+ icon: "fa fa-eye fa-fw",
+ });
+ }
+
+ if (interface.qdisc !== undefined) {
+ furtherDetails.nodes.push({
+ text: "Scheduler: " + utils.escapeHtml(interface.qdisc),
+ icon: "fa fa-network-wired fa-fw",
+ });
+ }
+
+ if (furtherDetails.nodes.length > 0) {
+ obj.nodes.push(furtherDetails);
+ }
+
+ json.push(obj);
+ });
+
+ $("#tree").bstreeview({
+ data: json,
+ expandIcon: "fa fa-angle-down fa-fw",
+ collapseIcon: "fa fa-angle-right fa-fw",
+ indent: 1.25,
+ });
+ $("#spinner").hide();
+
+ // Expand gateway interfaces by default
+ for (const gw of gateways) {
+ const div = $("#tree").find("div:contains('" + gw + "')");
+ div.removeClass("collapsed");
+ div.next("div").collapse("show");
+ // Change expand icon to collapse icon
+ div.find("i:first").removeClass("fa-angle-right").addClass("fa-angle-down");
+ }
+ });
+});
diff --git a/scripts/pi-hole/js/settings-system.js b/scripts/pi-hole/js/settings-system.js
index 5bbe4e1a2..06e7d8d19 100644
--- a/scripts/pi-hole/js/settings-system.js
+++ b/scripts/pi-hole/js/settings-system.js
@@ -362,4 +362,23 @@ $(function () {
},
},
});
+
+ $.ajax({
+ url: "/api/network/gateway",
+ })
+ .done(function (data) {
+ const gateway = data.gateway;
+ // Get first object in gateway that has family == "inet"
+ const inet = gateway.find(obj => obj.family === "inet");
+ // Get first object in gateway that has family == "inet6"
+ const inet6 = gateway.find(obj => obj.family === "inet6");
+
+ $("#sysinfo-gw-v4-addr").text(inet ? inet.local.join("\n") : "N/A");
+ $("#sysinfo-gw-v4-iface").text(inet ? inet.interface : "N/A");
+ $("#sysinfo-gw-v6-addr").text(inet6 ? inet6.local.join("\n") : "N/A");
+ $("#sysinfo-gw-v6-iface").text(inet6 ? inet6.interface : "N/A");
+ })
+ .fail(function (data) {
+ apiFailure(data);
+ });
});
diff --git a/scripts/pi-hole/lua/header.lp b/scripts/pi-hole/lua/header.lp
index 6244dc4e8..1c5fb0268 100644
--- a/scripts/pi-hole/lua/header.lp
+++ b/scripts/pi-hole/lua/header.lp
@@ -92,6 +92,7 @@ is_authenticated = mg.request_info.is_authenticated
+
if startsWith(scriptname, 'groups') then
-- Group management styles
diff --git a/scripts/pi-hole/lua/header_authenticated.lp b/scripts/pi-hole/lua/header_authenticated.lp
index fb2f96d33..61105c759 100644
--- a/scripts/pi-hole/lua/header_authenticated.lp
+++ b/scripts/pi-hole/lua/header_authenticated.lp
@@ -19,6 +19,7 @@ mg.include('header.lp','r')
+