Move the LAN DHCP enable/disable option into the LAN DHCP panel (#1788)

This commit is contained in:
Tim Wilkinson 2024-12-27 22:20:49 -08:00 committed by GitHub
parent b2c5c25961
commit f5b2da0d8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 175 additions and 155 deletions

View File

@ -34,6 +34,11 @@
%}
{%
if (request.env.REQUEST_METHOD === "PUT") {
if ("dhcp_server" in request.args) {
configuration.prepareChanges();
configuration.setSetting("lan_dhcp", request.args.dhcp_server === "on" ? 1 : 0);
configuration.saveSettings();
}
if ("options" in request.args) {
configuration.prepareChanges();
const options = json(request.args.options);
@ -237,163 +242,179 @@ const dhcpOptionTypes = {
<div class="dialog">
{{_R("dialog-header", "LAN DHCP")}}
<div>
<div class="dhcp">
<div>
<div class="cols">
<div>
<div class="o">Address Reservations</div>
<div class="m">Hostnames with fixed addresses</div>
</div>
<button class="plus" {{length(options) === reservations ? "disabled" : ""}}>+</button>
<div class="hideable" data-hideable='{{dhcp.enabled ? "on" : "off"}}'>
<div class="cols">
<div>
<div class="o">DHCP Server</div>
<div class="m">Provide addresses to devices on the LAN network</div>
</div>
<div style="flex:0">
{{_R("hideable-switch", { name: "dhcp_server", value: dhcp.enabled })}}
</div>
</div>
{{_H("Creates a permenant mapping between a device MAC address and an IP address on the LAN network.
The given hostname is available to everyone on the mesh unless the entry is marked as <b>do not propagate</b>")}}
<form>
<div id="dhcp-reservations">
<div class="reservation-label adr">
{{_H("When enabled, provide addresses to devices attached to this node's LAN network. If disabled, the LAN network
is still active, but addresses will not be automatically provided. Multiple DHCP servers can be active on the same
LAN network (e.g. if you have multiple nodes connected together) but it is not defined which DHCP server will provide
what address to which device even when address reservations are configured.")}}
<div class="dhcp hideable1">
<hr>
<div>
<div class="cols">
<div>
<div>hostname</div>
<div>ip address</div>
<div>mac a&zwnj;ddress</div>
<div>do not propagate</div>
<div class="o">Address Reservations</div>
<div class="m">Hostnames with fixed addresses</div>
</div>
<div></div>
<button class="plus" {{length(options) === reservations ? "disabled" : ""}}>+</button>
</div>
{% if (reservations > 0) {
for (let i = 0; i < length(options); i++) {
const o = options[i];
if (o.reserved) {
%}
<div class="reservation adr" data-ip="{{o.ip}}">
<div>
<input name="hostname" type="text" required placeholder="hostname" value="{{o.name}}">
<select class="dhcp-addresses">
</select>
<input name="mac" type="text" required placeholder="mac a&zwnj;ddress" pattern="([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]" value="{{o.mac}}">
<label><input type="checkbox" {{o.noprop ? "checked" : ""}}></label>
</div>
<button>-</button>
</div>
{% }
}
} %}
</div>
</form>
<hr>
<div class="o">Active Leases</div>
<div class="m">Addresses currently in use</div>
{{_H("The list of active leases currently allocated to LAN devices. Any of these leases can be promoted
to a permanent mapping to allow IP Addresses to be fixed to specific devices.")}}
{% if (active > 0) {
%}
<div class="lease-label adr">
{{_H("Creates a permenant mapping between a device MAC address and an IP address on the LAN network.
The given hostname is available to everyone on the mesh unless the entry is marked as <b>do not propagate</b>")}}
<form>
<div id="dhcp-reservations">
<div class="reservation-label adr">
<div>
<div>hostname</div>
<div>ip address</div>
<div>mac a&zwnj;ddress</div>
<div>do not propagate</div>
</div>
<div></div>
</div>
{%
for (let i = 0; i < length(options); i++) {
const o = options[i];
if (o.leased) {
%}
<div class="lease adr" data-ip="{{o.ip}}">
<div>
<input readonly type="text" value="{{o.name}}">
<input readonly type="text" value="{{o.ip}}">
<input readonly type="text" value="{{o.mac}}">
</div>
<button {{o.reserved ? "disabled" : ""}}>+</button>
</div>
{% }
}
} %}
</div>
{{_R("dialog-advanced")}}
<div>
{% if (includeAdvanced) { %}
<form>
<div class="dhcp-tags">
<div class="cols">
<div>
<div class="o">Tags</div>
<div class="m">Tags for advanced options</div>
</div>
<button>+</button>
{% if (reservations > 0) {
for (let i = 0; i < length(options); i++) {
const o = options[i];
if (o.reserved) {
%}
<div class="reservation adr" data-ip="{{o.ip}}">
<div>
<input name="hostname" type="text" required placeholder="hostname" value="{{o.name}}">
<select class="dhcp-addresses">
</select>
<input name="mac" type="text" required placeholder="mac a&zwnj;ddress" pattern="([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]" value="{{o.mac}}">
<label><input type="checkbox" {{o.noprop ? "checked" : ""}}></label>
</div>
<button>-</button>
</div>
{% }
}
} %}
</div>
<div class="dhcptag-label adr">
<div class="row">
<div>tag</div>
<div>type</div>
<div>match</div>
<div></div>
</div>
<div></div>
</div>
<div class="list noborder">{%
for (let i = 0; i < length(advtags); i++) {
const t = advtags[i];
%}<div class="tag adr">
<div class="row">
<input name="tag_name" type="text" required value="{{t.name}}">
<select name="tag_type" required>
<option value="">-</option>
<option value="vendorclass" {{t.type == "vendorclass" ? "selected": ""}}>Vendor Class</option>
<option value="userclass" {{t.type == "userclass" ? "selected": ""}}>User Class</option>
<option value="mac" {{t.type == "mac" ? "selected": ""}}>MAC Address</option>
<option value="circuitid" {{t.type == "circuitid" ? "selected": ""}}>Agent Circuit ID</option>
<option value="remoteid" {{t.type == "remoteid" ? "selected": ""}}>Agent Remote ID</option>
<option value="subscriberid" {{t.type == "subscriberid" ? "selected": ""}}>Subscriber-ID</option>
</select>
<input name="tag_match" type="text" required value="{{t.match}}">
</form>
<hr>
<div class="o">Active Leases</div>
<div class="m">Addresses currently in use</div>
{{_H("The list of active leases currently allocated to LAN devices. Any of these leases can be promoted
to a permanent mapping to allow IP Addresses to be fixed to specific devices.")}}
{% if (active > 0) {
%}
<div class="lease-label adr">
<div>
<div>hostname</div>
<div>ip address</div>
<div>mac a&zwnj;ddress</div>
</div>
<div></div>
</div>
<button>-</button>
</div>{%
}
%}</div>
</div>
</form>
<form>
<div class="dhcp-options">
<div class="cols">
<div>
<div class="o">Options</div>
<div class="m">Advanced options</div>
</div>
<button>+</button>
</div>
<div class="dhcpoption-label adr">
<div class="row">
<div>tag</div>
<div>option</div>
<div>value</div>
<div>always</div>
</div>
<div></div>
</div>
<div class="list noborder">{%
for (let i = 0; i < length(advoptions); i++) {
const o = advoptions[i];
%}<div class="option adr">
<div class="row">
<select name="option_name">
<option value="{{o.name}}" selected>{{o.name}}</option>
</select>
<input name="option_type" type="text" required list="dhcp-option-type-list" value="{{dhcpOptionTypes[o.type] ? `${o.type}: ${dhcpOptionTypes[o.type][0]}` : o.type}}" pattern="([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(: .+)?">
<input name="option_value" type="text" required value="{{o.value}}">
<label><input name="option_always" type="checkbox" {{o.always ? "checked" : ""}}></label>
{%
for (let i = 0; i < length(options); i++) {
const o = options[i];
if (o.leased) {
%}
<div class="lease adr" data-ip="{{o.ip}}">
<div>
<input readonly type="text" value="{{o.name}}">
<input readonly type="text" value="{{o.ip}}">
<input readonly type="text" value="{{o.mac}}">
</div>
<button {{o.reserved ? "disabled" : ""}}>+</button>
</div>
<button>-</button>
</div>{%
{% }
}
%}</div>
} %}
{{_R("dialog-advanced")}}
<div>
{% if (includeAdvanced) { %}
<form>
<div class="dhcp-tags">
<div class="cols">
<div>
<div class="o">Tags</div>
<div class="m">Tags for advanced options</div>
</div>
<button>+</button>
</div>
<div class="dhcptag-label adr">
<div class="row">
<div>tag</div>
<div>type</div>
<div>match</div>
<div></div>
</div>
<div></div>
</div>
<div class="list noborder">{%
for (let i = 0; i < length(advtags); i++) {
const t = advtags[i];
%}<div class="tag adr">
<div class="row">
<input name="tag_name" type="text" required value="{{t.name}}">
<select name="tag_type" required>
<option value="">-</option>
<option value="vendorclass" {{t.type == "vendorclass" ? "selected": ""}}>Vendor Class</option>
<option value="userclass" {{t.type == "userclass" ? "selected": ""}}>User Class</option>
<option value="mac" {{t.type == "mac" ? "selected": ""}}>MAC Address</option>
<option value="circuitid" {{t.type == "circuitid" ? "selected": ""}}>Agent Circuit ID</option>
<option value="remoteid" {{t.type == "remoteid" ? "selected": ""}}>Agent Remote ID</option>
<option value="subscriberid" {{t.type == "subscriberid" ? "selected": ""}}>Subscriber-ID</option>
</select>
<input name="tag_match" type="text" required value="{{t.match}}">
<div></div>
</div>
<button>-</button>
</div>{%
}
%}</div>
</div>
</form>
<form>
<div class="dhcp-options">
<div class="cols">
<div>
<div class="o">Options</div>
<div class="m">Advanced options</div>
</div>
<button>+</button>
</div>
<div class="dhcpoption-label adr">
<div class="row">
<div>tag</div>
<div>option</div>
<div>value</div>
<div>always</div>
</div>
<div></div>
</div>
<div class="list noborder">{%
for (let i = 0; i < length(advoptions); i++) {
const o = advoptions[i];
%}<div class="option adr">
<div class="row">
<select name="option_name">
<option value="{{o.name}}" selected>{{o.name}}</option>
</select>
<input name="option_type" type="text" required list="dhcp-option-type-list" value="{{dhcpOptionTypes[o.type] ? `${o.type}: ${dhcpOptionTypes[o.type][0]}` : o.type}}" pattern="([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(: .+)?">
<input name="option_value" type="text" required value="{{o.value}}">
<label><input name="option_always" type="checkbox" {{o.always ? "checked" : ""}}></label>
</div>
<button>-</button>
</div>{%
}
%}</div>
</div>
</form>
{% } %}
</div>
</form>
{% } %}
</div>
</div>
</div>
<datalist id="dhcp-option-type-list">

View File

@ -42,11 +42,7 @@ if (request.env.REQUEST_METHOD === "PUT") {
}
if ("dhcp_mode" in request.args) {
const mode = int(request.args.dhcp_mode || 3);
if (mode === -1) {
configuration.setSetting("lan_dhcp", 0);
}
else if (mode >= 0 && mode <= 5) {
configuration.setSetting("lan_dhcp", 1);
if (mode >= 0 && mode <= 5) {
configuration.setSetting("dmz_mode", mode);
if (mode >= 2) {
const o_lan_ip = iptoarr(configuration.getSettingAsString("dmz_lan_ip"));
@ -208,21 +204,20 @@ const gateway_altnet = dmz_mode === 1 ? dhcp.gateway : "";
{{_H("The primary address of this AREDN node. This will always be of the form 10.X.X.X. The address is generated automatically based on hardware information so it will
always be the same even if you reinstall this node from scratch. You shouldn't have to change it.")}}
<hr>
<div class="hideable" data-hideable="{{dhcp.enabled ? dmz_mode : -1}}">
<div class="hideable" data-hideable="{{dmz_mode}}">
<div class="cols">
<div>
<div class="o">LAN Size</div>
<div class="m">Size of LAN subnet</div>
<div class="o">LAN Type</div>
<div class="m">Type and size of LAN subnet</div>
</div>
<div style="flex:0">
<select hx-put="{{request.env.REQUEST_URI}}" hx-swap="none" name="dhcp_mode" {{_R("hideable-onselect")}}>
<option value="-1" {{!dhcp.enabled ? "selected" : ""}}>Disabled</option>
<option value="0" {{dhcp.enabled && dmz_mode == 0 ? "selected" : ""}}>NAT</option>
<option value="1" {{dhcp.enabled && dmz_mode == 1 ? "selected" : ""}}>44Net</option>
<option value="2" {{dhcp.enabled && dmz_mode == 2 ? "selected" : ""}}>1 host</option>
<option value="3" {{dhcp.enabled && dmz_mode == 3 ? "selected" : ""}}>5 hosts</option>
<option value="4" {{dhcp.enabled && dmz_mode == 4 ? "selected" : ""}}>13 hosts</option>
<option value="5" {{dhcp.enabled && dmz_mode == 5 ? "selected" : ""}}>29 hosts</option>
<option value="0" {dmz_mode == 0 ? "selected" : ""}}>NAT</option>
<option value="1" {{dmz_mode == 1 ? "selected" : ""}}>44Net</option>
<option value="2" {{dmz_mode == 2 ? "selected" : ""}}>1 host</option>
<option value="3" {{dmz_mode == 3 ? "selected" : ""}}>5 hosts</option>
<option value="4" {{dmz_mode == 4 ? "selected" : ""}}>13 hosts</option>
<option value="5" {{dmz_mode == 5 ? "selected" : ""}}>29 hosts</option>
</select>
</div>
</div>
@ -248,6 +243,7 @@ const gateway_altnet = dmz_mode === 1 ? dhcp.gateway : "";
<input name="lan_dhcp_netmask" type="text" size="15" required pattern="255\.255\.(((0|128|192|224|240|248|252|254)\.0)|255\.(0|128|192|224|240|248|252))" value="{{dhcp.mask}}">
</div>
</div>
{% if (dhcp.enabled) { %}
<div class="cols">
<div>
<div class="o">DHCP Start</div>
@ -266,6 +262,7 @@ const gateway_altnet = dmz_mode === 1 ? dhcp.gateway : "";
<input name="lan_dhcp_end" type="text" size="4" required pattern="[]" value="{{dhcp_end}}">
</div>
</div>
{% } %}
</div>
<div class="compact hideable1">
<div class="cols">
@ -286,6 +283,7 @@ const gateway_altnet = dmz_mode === 1 ? dhcp.gateway : "";
<input name="lan44_dhcp_netmask" type="text" size="15" required pattern="255\.255\.255\.(0|128|192|224|240|248|252)" value="{{dhcp.mask}}">
</div>
</div>
{% if (dhcp.enabled) { %}
<div class="cols">
<div>
<div class="o">DHCP Start</div>
@ -304,6 +302,7 @@ const gateway_altnet = dmz_mode === 1 ? dhcp.gateway : "";
<input name="lan44_dhcp_end" type="text" size="4" required pattern="[]" value="{{dhcp_end}}">
</div>
</div>
{% } %}
</div>
</div>
<hr>

View File

@ -92,7 +92,7 @@
</div>
</div>
{% } else { %}
<div class="noctrl">
<div class="ctrl" hx-get="status/e/dhcp" hx-target="#ctrl-modal">
<div class="section-title">LAN DHCP</div>
<div class="section">
<div class="t">Disabled</div>

View File

@ -35,7 +35,7 @@
<div class="ctrl-modal-footer">
<hr/>
{% if (inner !== "nocancel" && auth.isAdmin) { %}
<button id="dialog-cancel" hx-delete="{{request.env.REQUEST_URI}}" onclick="setTimeout(_ => document.getElementById('ctrl-modal').close(), 10)">Cancel</button>
<button id="dialog-cancel" hx-delete="{{request.env.REQUEST_URI}}" hx-target="#changes" onclick="setTimeout(_ => document.getElementById('ctrl-modal').close(), 10)">Cancel</button>
{% } %}
<button id="dialog-done" onclick="setTimeout(_ => document.getElementById('ctrl-modal').close(), 10)">Done</button>
</div>