Skip to content

Improve DHCP static leases management GUI#3565

Open
DL6ER wants to merge 20 commits intodevelopmentfrom
new/simple-dhcp-static-leases
Open

Improve DHCP static leases management GUI#3565
DL6ER wants to merge 20 commits intodevelopmentfrom
new/simple-dhcp-static-leases

Conversation

@DL6ER
Copy link
Copy Markdown
Member

@DL6ER DL6ER commented Jul 15, 2025

What does this implement/fix?

See title. This adds a easy accessible table that is kept in sync with the <textarea> which still allows for any advanced configuration.

Please see this movie for a demonstration:

Screencast.From.2025-07-15.12-41-22.webm

You can test all of that even without having the DHCP server enabled. What will be saved in the end is always the content of said <textarea> which is getting stores as dhcp.hosts in pihole.toml.


Related issue or feature (if applicable): N/A

Pull request in docs with documentation (if applicable): N/A


By submitting this pull request, I confirm the following:

  1. I have read and understood the contributors guide, as well as this entire template. I understand which branch to base my commits and Pull Requests against.
  2. I have commented my proposed changes within the code.
  3. I am willing to help maintain this change if there are issues with it later.
  4. It is compatible with the EUPL 1.2 license
  5. I have squashed any insignificant commits. (git rebase)

Checklist:

  • The code change is tested and works locally.
  • I based my code and PRs against the repositories development branch.
  • I signed off all commits. Pi-hole enforces the DCO for all contributions
  • I signed all my commits. Pi-hole requires signatures to verify authorship
  • I have read the above and my PR is ready for review.

DL6ER added 3 commits July 15, 2025 11:55
…xtarea below

Signed-off-by: DL6ER <dl6er@dl6er.de>
Signed-off-by: DL6ER <dl6er@dl6er.de>
Signed-off-by: DL6ER <dl6er@dl6er.de>
DL6ER added 2 commits July 15, 2025 12:48
Signed-off-by: DL6ER <dl6er@dl6er.de>
…t any possibility for code injection)

Signed-off-by: DL6ER <dl6er@dl6er.de>
@smithbill17
Copy link
Copy Markdown

The video looks good to me, but unfortunately I'm not able to test this as I have now stopped using PiHole (partly due to this very issue).

However, two comments based on the video:
a) the 'advanced config' line shows nothing in the easy text grid - can't it still show MAC, IP & name but with an expansion arrow (or some kind of indicator) for the additional fields?
b) in PiHole v5, it didn't seem to matter if MACs were entered with hyphens ('-') rather than colons (':'). Is this the case with v6? And does it matter if IPs fall out-with the DHCP scope?

Signed-off-by: DL6ER <dl6er@dl6er.de>
@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented Jul 15, 2025

a) the 'advanced config' line shows nothing in the easy text grid - can't it still show MAC, IP & name but with an expansion arrow (or some kind of indicator) for the additional fields?

Yes, this is expected and per design. Advanced config lines may include set and id and other identifiers and it'd be very complicated (= error-prone) to edit the "simple" parts of it without damaging the advanced config. Not trying to edit these lines but instead showing where they are in the text area (where the user initially created them) seems the most straightforward and most robust way

b) in PiHole v5, it didn't seem to matter if MACs were entered with hyphens ('-') rather than colons (':'). Is this the case with v6? And does it matter if IPs fall out-with the DHCP scope?

I did add - as separators now. It doesn't matter if IP addresses are within the set DHCP scope.

Signed-off-by: DL6ER <dl6er@dl6er.de>
@yubiuser
Copy link
Copy Markdown
Member

If something invalid is entered in the advanced box (e.g. 00:20:e0:3b:13:af,8.8.8.8.7,laptop) the corresponding field in the table is empty (IP). Maybe we should show invald instead?

The live-editing is cool but only shown advanced > table, not the other way round. Is this by design?

Advanced settings present in line 3

This could be hard to find if n is big. Could we show line numbers in the advanced text box?

Signed-off-by: DL6ER <dl6er@dl6er.de>
@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented Jul 16, 2025

Could we show line numbers in the advanced text box?

Yes.

Screenshot From 2025-07-16 08-27-16

If something invalid is entered in the advanced box (e.g. 00:20:e0:3b:13:af,8.8.8.8.7,laptop) the corresponding field in the table is empty (IP). Maybe we should show invald instead?

The code is written such that it parses the same way dnsmasq parses this line. If the IP address is not valid, it is taken as hostname.

The live-editing is cool but only shown advanced > table, not the other way round. Is this by design?

Yes. First, I implemented it both ways but as soon as you edit the IP address, e.g., 192.168.0. (because you are editing the last digit), it'd immediately be dropped from the IP column as it is now invalid. This prevents further editing. Hence, I decided we let the user finish what they want and then click save.

@yubiuser
Copy link
Copy Markdown
Member

If the IP address is not valid, it is taken as hostname.

Except when a hostname is also given
2025-07-16_09-09

@rdwebdesign
Copy link
Copy Markdown
Member

I tested using an invalid IP (192.168.0.300) and a hostname:

00:20:e0:3b:13:af,192.168.0.300,laptop

When saved, the invalid IP is ignored, resulting in 00:20:e0:3b:13:af,laptop.

I think this is the correct behavior, but no warning was returned to the user, to inform something was wrong and the entry was "fixed" to fit the valid input fields. Maybe we need a warning/alert for cases like this.

Signed-off-by: DL6ER <dl6er@dl6er.de>
@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented Jul 20, 2025

Like so?

Screencast.From.2025-07-20.1.webm

@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented Jul 20, 2025

Screencast.From.2025-07-20.20-39-42.webm

@yubiuser
Copy link
Copy Markdown
Member

I think the colors for invalid IP/MAC need a bit adjustment.
When using the light theme, the white color of the text has low contrast to the rosè background. When using a dark theme, the red color of the cell is almost invisible.

2025-07-22_15-38 2025-07-22_15-38_1

Comment thread style/pi-hole.css
Comment on lines +1616 to +1624
#StaticDHCPTable td.table-danger {
background-color: #ff000022 !important;
color: #fff !important;
}

#StaticDHCPTable td.table-success {
background-color: #74c70022 !important;
color: #fff !important;
}
Copy link
Copy Markdown
Member

@rdwebdesign rdwebdesign Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick suggestion just to improve the colors:

Suggested change
#StaticDHCPTable td.table-danger {
background-color: #ff000022 !important;
color: #fff !important;
}
#StaticDHCPTable td.table-success {
background-color: #74c70022 !important;
color: #fff !important;
}
#StaticDHCPTable .table-danger {
background-color: #d337;
}
#StaticDHCPTable .table-success {
background-color: #2c24;
}

Still using semi-transparent colors, but now the contrast is good enough when using the original text color, so I think we don't need to change color:.

Also, we should use !important only in cases where we really need it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I did not see this before. I pushed non-transparent suggestions that should be the same on all variants, otherwise. Not overly pretty but it may suffice. Otherwise, we'll theme-dependent colors and this PR already became a lot more involved than I had hoped initially.

image

…hemes

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
@rdwebdesign
Copy link
Copy Markdown
Member

I added one commit to change the high contrast themes. On these themes the colors are not as important as the contrast/readability.

@rdwebdesign
Copy link
Copy Markdown
Member

Note:

I was testing with DHCP server disabled, so I'm not sure if we need to fix this, but when you use the textearea to enter a line, if there are invalid values on this line, the values are not checked and the API accepts everything, including the invalid values.

The first line contains an invalid IP:

00:20:e0:3b:13:af,192.168.0.300,laptop,infinite
00:20:e0:3b:13:af,192.168.0.123,laptop

DL6ER added 2 commits July 23, 2025 20:49
Signed-off-by: DL6ER <dl6er@dl6er.de>
Signed-off-by: DL6ER <dl6er@dl6er.de>
@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented Jul 24, 2025

I was testing with DHCP server disabled, so I'm not sure if we need to fix this, but when you use the textearea to enter a line, if there are invalid values on this line, the values are not checked and the API accepts everything, including the invalid values.

Yes, invalid dhcp-host lines are fine for dnsmasq. It just goes on when no useful content was found (like 0,0,0). Invalid IP addresses, like in your example, will simply be interpreted as host names (just like the table does).

Signed-off-by: DL6ER <dl6er@dl6er.de>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 1, 2026

Conflicts have been resolved.

@PromoFaux
Copy link
Copy Markdown
Member

I've rebased this branch on development and (hopefully) fixed the merge conflict.

Docker Tag 2025.11.1Core v6.3FTL v6.4.1Web interface v6.4

If you would like to try this branch on docker, you can bake your own local image utilising this FTL branch by following these instructions:

https://docs.pi-hole.net/docker/build-image/

@derchrisuk
Copy link
Copy Markdown

I have been running on this branch for last 2-3 days.
Works like a charm.
One change I would like to suggest, right now when you add additional options, it removes the entry from the gui view.
Not sure what else you can add, but i added the infinite option as per the examples.
Maybe this can be added as an option once you copy the lease.
Because the overview is much nicer than just the textarea box

@github-actions
Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

…ew feedback

Resolve merge conflict in style/pi-hole.css (keep both StaticDHCPTable
styles and DNSSEC query log styles).

Address outstanding reviewer feedback:
- Change save button icon from floppy-disk to checkmark to clarify it
  confirms the row edit, not a final save
- Update hint text to mention "Save & Apply" is still needed
- Add hostname validation on the hostname cell (rejects spaces, commas,
  and other characters invalid in DNS names)

Signed-off-by: Dominik <dl6er@dl6er.de>
@DL6ER DL6ER force-pushed the new/simple-dhcp-static-leases branch from 59c85c3 to 79c4c14 Compare March 25, 2026 06:28
@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented Mar 25, 2026

I rebased on current development and resolved the merge conflict.

I also addressed the two outstanding review items:

  1. Save button UX: Changed the row save icon from floppy-disk to a checkmark, and updated the hint text to: "Please confirm changes using the green button, then click 'Save & Apply' before leaving the page." This makes the two-step flow clearer — the green button confirms the row edit, "Save & Apply" persists to the config.

  2. Hostname validation: Added input validation on the hostname cell, matching the existing MAC/IP validation pattern. Invalid hostnames (containing spaces, commas, or other characters not allowed in DNS names) are highlighted in red with a tooltip. Valid DNS hostname characters: letters, digits, hyphens, and dots.

When using the `v` flag, hyphens need to be escaped inside a character class.

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
@rdwebdesign
Copy link
Copy Markdown
Member

This is the explanation for my commit:

From developer.mozilla.org - Regular expressions - Character class: [...], [^...]: v-mode character class:

In addition to ] and \, the following characters must be escaped in character classes if they represent literal characters: (, ), [, {, }, /, -, |.

@rdwebdesign
Copy link
Copy Markdown
Member

I added buttons to lines containing advanced settings. It will allow to delete these lines and add lines after them, like we do on other rows. Only the "Save" button will be disabled:

newDHCP_delete_button_advanced

tbody.append(tr);
}

tbody.find(".save-static-row, .delete-static-row, .add-static-row").prop("disabled", false);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DL6ER

Why are you enabling all buttons here?
Are you sure this line is needed?

If the line is needed, we can enable the buttons, except Save buttons created with .disabled CSS class:

Suggested change
tbody.find(".save-static-row, .delete-static-row, .add-static-row").prop("disabled", false);
tbody.find(".save-static-row:not(.disabled), .delete-static-row, .add-static-row").prop("disabled", false);

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
Copilot AI review requested due to automatic review settings March 29, 2026 01:43
@rdwebdesign rdwebdesign force-pushed the new/simple-dhcp-static-leases branch from 17be95d to 02f143a Compare March 29, 2026 01:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
@github-actions
Copy link
Copy Markdown
Contributor

Conflicts have been resolved.

@rdwebdesign rdwebdesign force-pushed the new/simple-dhcp-static-leases branch from 0e48a16 to 13dedfe Compare March 29, 2026 14:26
Fix regex adding `v` flag and fix line breaks to respect maximum lenght

Note: these issues were not previously reported because there was a merge
conflict. The prettier test was only executed after the merge conflict was
resolved.

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +256 to +280
const parts = line.split(",").map(s => s.trim());

// If there are more than 3 parts or less than 2, it's considered advanced
if (parts.length > 3 || parts.length < 2) return "advanced";

// Check if first part is a valid MAC address
const haveMAC = parts.length > 0 && utils.validateMAC(parts[0]);
const hwaddr = haveMAC ? parts[0].trim() : "";

// Check if the first or second part is a valid IPv4 or IPv6 address
const hasSquareBrackets0 = parts[0][0] === "[" && parts[0].at(-1) === "]";
const ipv60 = hasSquareBrackets0 ? parts[0].slice(1, -1) : parts[0];
const hasSquareBrackets1 = parts.length > 1 && parts[1][0] === "[" && parts[1].at(-1) === "]";
const ipv61 = hasSquareBrackets1 ? parts[1].slice(1, -1) : parts.length > 1 ? parts[1] : "";
const firstIsValidIP = utils.validateIPv4(parts[0]) || utils.validateIPv6(ipv60);
const secondIsValidIP =
parts.length > 1 && (utils.validateIPv4(parts[1]) || utils.validateIPv6(ipv61));
const ipaddr = firstIsValidIP ? parts[0].trim() : secondIsValidIP ? parts[1].trim() : "";
const haveIP = ipaddr.length > 0;

// Check if the second or third part is a valid hostname
let hostname = "";
if (parts.length > 2 && parts[2].length > 0) hostname = parts[2].trim();
else if (parts.length > 1 && parts[1].length > 0 && (!haveIP || !haveMAC))
hostname = parts[1].trim();
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseStaticDHCPLine() can mis-parse valid dnsmasq lines like 00:11:22:33:44:55,laptop,infinite (MAC, hostname, lease_time). With parts.length === 3 and no IP present, the code treats the 3rd token as hostname, and saving from the table would drop the real hostname and corrupt the line. Consider only treating 3-part lines as editable when they match the unambiguous pattern MAC,IP,HOST (or otherwise classify them as "advanced" to keep them read-only).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a valid remark. --dhcp-host has only optional arguments so things can be quite fast 'advanced'
https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html

Comment on lines +511 to +521
$(document).on("input blur paste", "#StaticDHCPTable td.static-ipaddr", function () {
const val = $(this).text().trim();
if (val && !(utils.validateIPv4(val) || utils.validateIPv6(val))) {
$(this).addClass("table-danger");
$(this).removeClass("table-success");
$(this).attr("title", "Invalid IP address format");
} else {
$(this).addClass("table-success");
$(this).removeClass("table-danger");
$(this).attr("title", "");
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IPv6 entries in dhcp.hosts are documented as requiring square brackets (e.g. [2001:db8::1]), but the table validation uses utils.validateIPv6(val) directly. Since validateIPv6() doesn't accept bracketed values, valid bracketed IPv6 addresses will be flagged invalid and blocked from saving. Adjust validation (and save-time checks) to accept bracketed IPv6 by stripping surrounding [] before calling validateIPv6*, and/or normalize stored values consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +310 to +316
const lines = $("#dhcp-hosts").val().split(/\r?\n/v);
// Only update if at least one field is non-empty
lines[rowIdx] =
hwaddr || ipaddr || hostname ? [hwaddr, ipaddr, hostname].filter(Boolean).join(",") : "";
$("#dhcp-hosts").val(lines.join("\n"));
// Optionally, re-render the table to reflect changes
renderStaticDHCPTable();
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After updating #dhcp-hosts via the table actions (save/delete/add), the code sets .val(...) but does not trigger an input event. This leaves the new line-number gutter (and any other input listeners) out of sync because the line-number updater listens to the textarea's input event. Consider triggering input (or calling the line-number updater) after programmatic updates to the textarea.

Copilot uses AI. Check for mistakes.
tbody.append(tr);
}

tbody.find(".save-static-row, .delete-static-row, .add-static-row").prop("disabled", false);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderStaticDHCPTable() re-enables all action buttons unconditionally. This overrides the earlier prop("disabled", true) on save buttons for "advanced" rows, making them clickable again (even though they still have the .disabled class). Update this to avoid re-enabling .save-static-row.disabled (or keep the disabled state set when rendering advanced rows) so advanced rows remain truly non-interactive.

Suggested change
tbody.find(".save-static-row, .delete-static-row, .add-static-row").prop("disabled", false);
tbody
.find(".save-static-row:not(.disabled), .delete-static-row, .add-static-row")
.prop("disabled", false);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@rdwebdesign rdwebdesign Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was already requested.

Comment on lines +77 to +90
// Create buttons without data-* attributes in HTML
const $deleteBtn = $(
'<button type="button" class="btn btn-danger btn-xs"><span class="far fa-trash-alt"></span></button>'
)
.attr("id", "deleteLease_" + data.ip)
.attr("data-del-ip", data.ip)
.attr("title", "Delete lease")
.attr("data-toggle", "tooltip");
const $copyBtn = $(
'<button type="button" class="btn btn-secondary btn-xs copy-to-static"><i class="fa fa-fw fa-copy"></i></button>'
)
.attr("title", "Copy to static leases")
.attr("data-toggle", "tooltip")
.data("hwaddr", data.hwaddr || "")
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buttons are created dynamically with data-toggle="tooltip", but the tooltip initializer ($('[data-toggle="tooltip"]').tooltip(...)) only runs once on DOM ready. Newly inserted buttons (DataTables rows and StaticDHCPTable buttons) won't get Bootstrap tooltips unless tooltips are re-initialized after render/draw or initialized via delegated selector on body.

Copilot uses AI. Check for mistakes.
Comment on lines +297 to +307
// Validate MAC and IP before saving
const macValid = !hwaddr || utils.validateMAC(hwaddr);
const ipValid = !ipaddr || utils.validateIPv4(ipaddr) || utils.validateIPv6(ipaddr);
if (!macValid || !ipValid) {
utils.showAlert(
"error",
"fa-times",
"Cannot save: Invalid MAC or IP address",
"Please correct the highlighted fields before saving."
);
return;
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI marks invalid hostnames with .table-danger, but the per-row save handler only validates MAC/IP and will still write an invalid hostname back into the textarea. Either validate hostname in the save path as well (blocking save when invalid), or avoid presenting the red/green validity state as an error if it won't be enforced.

Copilot uses AI. Check for mistakes.
Comment on lines +389 to +394
#StaticDHCPTable .table-danger,
.blocked-row td {
background-color: rgba(230, 160, 160, 0.3);
}

#StaticDHCPTable .table-success,
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new theme overrides use #StaticDHCPTable .table-danger/.table-success, but base pi-hole.css defines #StaticDHCPTable td.table-danger/.table-success with higher specificity. That means the base colors will still win even when the high-contrast theme is loaded, so these theme rules likely won't take effect. Match the selector specificity (e.g. include td as in the base rule) and/or use !important so the theme can actually override the base styling.

Suggested change
#StaticDHCPTable .table-danger,
.blocked-row td {
background-color: rgba(230, 160, 160, 0.3);
}
#StaticDHCPTable .table-success,
#StaticDHCPTable td.table-danger,
.blocked-row td {
background-color: rgba(230, 160, 160, 0.3);
}
#StaticDHCPTable td.table-success,

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@rdwebdesign rdwebdesign Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be fixed if my previous suggestion to change pi-hole.css is used.

We don't need the higher specificity on pi-hole.css. A better fix would be to remove td from pi-hole.css, as suggested before.

Comment on lines +917 to 924
#StaticDHCPTable .table-danger,
.blocked-row td {
background-color: rgba(56, 0, 40, 0.35);
}

#StaticDHCPTable .table-success,
.allowed-row td {
background-color: rgba(0, 64, 64, 0.35);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These overrides use #StaticDHCPTable .table-danger/.table-success, but base pi-hole.css sets #StaticDHCPTable td.table-danger/.table-success (more specific). As a result, the base colors will override the theme and these rules may never apply. Increase specificity (e.g. target td.table-danger / td.table-success) and/or add !important so the high-contrast-dark theme can override the base table cell styling.

Suggested change
#StaticDHCPTable .table-danger,
.blocked-row td {
background-color: rgba(56, 0, 40, 0.35);
}
#StaticDHCPTable .table-success,
.allowed-row td {
background-color: rgba(0, 64, 64, 0.35);
#StaticDHCPTable td.table-danger,
.blocked-row td {
background-color: rgba(56, 0, 40, 0.35) !important;
}
#StaticDHCPTable td.table-success,
.allowed-row td {
background-color: rgba(0, 64, 64, 0.35) !important;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@rdwebdesign rdwebdesign Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be fixed if my previous suggestion to change pi-hole.css is used.

We don't need the higher specificity on pi-hole.css. A better fix would be to remove td from pi-hole.css, as suggested before.

@markusdd
Copy link
Copy Markdown

markusdd commented Apr 8, 2026

Hi all, was directed here based on issue #6593. Very encouraging to see the work on this. Have a couple suggestions, questions:

a) Would it make sense to also mark which of the static leases are active? This is usually a convenient way of finding out if a specific device is online and has accepted the static lease already. This is something many router UIs offer.
b) I am not sure if and how this is covered based on the videos posted, but is there now an easy way to make a dynamic lease into a static one again?
c) Many good router UIs also have the feature to be able to click either the hostname and/or ip to get to the web page of a given device if it exposes one. This is super handy especially when dealing with printers, scanners or smart home devices to configure them and find them in the network.

Other than that this looks very good and would v6 bring back to what v5 had already done nicely.

@darkexplosiveqwx
Copy link
Copy Markdown
Contributor

Hi all, was directed here based on issue #6593. Very encouraging to see the work on this. Have a couple suggestions, questions:

a) Would it make sense to also mark which of the static leases are active? This is usually a convenient way of finding out if a specific device is online and has accepted the static lease already. This is something many router UIs offer. b) I am not sure if and how this is covered based on the videos posted, but is there now an easy way to make a dynamic lease into a static one again? c) Many good router UIs also have the feature to be able to click either the hostname and/or ip to get to the web page of a given device if it exposes one. This is super handy especially when dealing with printers, scanners or smart home devices to configure them and find them in the network.

Other than that this looks very good and would v6 bring back to what v5 had already done nicely.

Quick note:
Pi-hole is not a router.

I can already tell you that a) is not really possible. Pi-hole can detect when a device renews its DHCP lease, but most of the time the DHCP lease time is one week or longer. When Pi-hole only sees a sign of life from the device every week or so, I dont think that it would result in useful data. Routers can track whether a device is online or not by looking at the IP packets it sends to the internet, since the router is the gateway. This allows much more accurate online tracking. For the vast majority, Pi-hole is not the gateway device, and even if it were, Pi-hole is restricted to DNS and DHCP and not routing.

Regarding c), it could be possible, but I don't see it realistically being in Pi-hole. The goal of Pi-holes DHCP server has never been being a full-featured router.

Like Dan Schaper (Pi-hole co-founder) said on the Discourse feature request:

I'll remind everyone that the DHCP server in Pi-hole was intended to be a fallback for people that had routers from their ISPs that locked out the ability to modify the DNS servers provided to the LAN clients.

b) is already possible with this PR (you can test it with pihole checkout web new/simple-dhcp-static-leases and go back to the stable release with pihole checkout web master, for docker see https://docs.pi-hole.net/docker/build-image/)

@markusdd
Copy link
Copy Markdown

markusdd commented Apr 8, 2026

I'm aware of the scope. Nevertheless the DHCP function is a core functionality as the correct DNS'es are also being broadcast by it and I, and I assume many others, have decided to use pihole for exactly that purpose - because it makes you independent of whatever your router/modem/gateway/whatever provider thinks is good for you.
I could also do DHCP using my Unifi gateway, but that makes things much less easy to overlook in the end. Having dns entries and dhcp at one location just makes sense from an administration standpoint.

Happy to see b) addressed because that is actually most important.
The linking to the devices is of course nice to have a but it is a great convencience.

As for the lease activeness from a): Yes, that is kind of a heuristic. Probably also the least 'important' point.

As for c): I think that has no bearing on whether pihole is a router or not, it's just a useful convenience feature. It does not require any router capabilities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.