diff --git a/webui/static/hoover/components/modal.js b/webui/static/hoover/components/modal.js
index 98806f6..6570d50 100644
--- a/webui/static/hoover/components/modal.js
+++ b/webui/static/hoover/components/modal.js
@@ -243,6 +243,7 @@ export function QuickModal(props = {}) {
];
}
formModal(inner, title, fields, actions);
+ if (props.postRender) props.postRender(inner, data);
});
};
}
diff --git a/webui/static/pages/dhcp.js b/webui/static/pages/dhcp.js
index 94431ce..93c106f 100644
--- a/webui/static/pages/dhcp.js
+++ b/webui/static/pages/dhcp.js
@@ -1,6 +1,6 @@
import { html, PageHeader, ConfirmDelete, Tabs, Table, ServiceStatus, renderGuardMulti, esc, enc, $val, apiFetch, toast, definePage, getModel, ActionButton, ActionGroup, QuickModal } from '/static/hoover/index.js?v=7';
-function makeAddRange(activeZones) {
+function makeAddRange(activeZones, interfaces) {
const opts = [
['', '(global)'],
...Object.entries(activeZones || {})
@@ -13,6 +13,27 @@ function makeAddRange(activeZones) {
}),
];
+ const ranges = {};
+ (interfaces || []).forEach(iface => {
+ for (const cidr of (iface.ips || [])) {
+ if (cidr.indexOf('/') === -1) continue;
+ const parts = cidr.split('/');
+ const addr = parts[0].split('.').map(Number);
+ const prefix = parseInt(parts[1], 10);
+ if (prefix > 30 || prefix < 8) continue;
+ const mask = (0xFFFFFFFF << (32 - prefix)) >>> 0;
+ const netA = ((addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]) & mask;
+ const broadcast = (netA | (~mask >>> 0)) >>> 0;
+ const s = (netA + 100) >>> 0;
+ const e = Math.min((netA + 200) >>> 0, broadcast - 1);
+ const toIp = (n) => [n >> 24 & 0xFF, n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF].join('.');
+ if (s <= e) {
+ ranges[iface.name] = { start: toIp(s), end: toIp(e) };
+ }
+ break;
+ }
+ });
+
return QuickModal({
title: 'Add DHCP Range',
fields: [
@@ -21,6 +42,23 @@ function makeAddRange(activeZones) {
{ label: 'End IP', id: 'r-end', placeholder: '192.168.1.200' },
{ label: 'Lease Time', id: 'r-lease', placeholder: '12h' },
],
+ postRender: (inner) => {
+ const select = inner.querySelector('#r-iface');
+ const startInput = inner.querySelector('#r-start');
+ const endInput = inner.querySelector('#r-end');
+ if (select && startInput && endInput) {
+ select.addEventListener('change', () => {
+ const r = ranges[select.value];
+ if (r) {
+ startInput.value = r.start;
+ endInput.value = r.end;
+ } else {
+ startInput.value = '';
+ endInput.value = '';
+ }
+ });
+ }
+ },
submit: {
url: '/api/dhcp/ranges',
body: () => ({
@@ -131,7 +169,7 @@ export default definePage({
const tabNames = ['ranges', 'leases', 'dns', 'active'];
const actions = ActionGroup(
- html``,
+ html``,
html``,
html``,
ActionButton({