{% /* * Part of AREDN® -- Used for creating Amateur Radio Emergency Data Networks * Copyright (C) 2024 Tim Wilkinson * See Contributors file for additional contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Additional Terms: * * Additional use restrictions exist on the AREDN® trademark and logo. * See AREDNLicense.txt for more info. * * Attributions to the AREDN® Project must be retained in the source code. * If importing this code into a new or existing project attribution * to the AREDN® project must be added to the source code. * * You must not misrepresent the origin of the material contained within. * * Modified versions must be modified to attribute to the original source * and be marked in reasonable ways as differentiate it from the original * version */ %} {% if (request.env.REQUEST_METHOD === "PUT") { configuration.prepareChanges(); if ("mesh_ip" in request.args) { if (match(request.args.mesh_ip, constants.reIP)) { configuration.setSetting("wifi_ip", request.args.mesh_ip); } } 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); configuration.setSetting("dmz_mode", mode); if (mode >= 2) { const o_lan_ip = iptoarr(configuration.getSettingAsString("dmz_lan_ip")); const wifi_ip = iptoarr(configuration.getSettingAsString("wifi_ip")); let wifi_shift = (wifi_ip[0] << 24) + (wifi_ip[1] << 16) + (wifi_ip[2] << 8) + wifi_ip[3]; wifi_shift = (wifi_shift << mode) & 0x00ffffff; let dmz_lan_ip = 0x0a000001 + wifi_shift; dmz_lan_ip = arrtoip([ (dmz_lan_ip >> 24) & 0xff, (dmz_lan_ip >> 16) & 0xff, (dmz_lan_ip >> 8) & 0xff, dmz_lan_ip & 0xff ]); let dmz_lan_mask = 0xffffffff << mode; dmz_lan_mask = arrtoip([ (dmz_lan_mask >> 24) & 0xff, (dmz_lan_mask >> 16) & 0xff, (dmz_lan_mask >> 8) & 0xff, dmz_lan_mask & 0xff ]); const dmz_dhcp_start = (wifi_shift + 2) & 0xff; const dmz_dhcp_end = dmz_dhcp_start + (2 << (mode - 1)) - 4; configuration.setSetting("dmz_lan_ip", dmz_lan_ip); configuration.setSetting("dmz_lan_mask", dmz_lan_mask); configuration.setSetting("dmz_dhcp_start", dmz_dhcp_start); configuration.setSetting("dmz_dhcp_end", dmz_dhcp_end); configuration.setSetting("dmz_dhcp_limit", dmz_dhcp_end - dmz_dhcp_start + 1); const dhcp = configuration.getDHCP(); let f = fs.open(dhcp.aliases); if (f) { const aliases = []; const n_lan_ip = iptoarr(configuration.getSettingAsString("dmz_lan_ip")); for (let l = f.read("line"); length(l); l = f.read("line")) { const v = match(trim(l), /^(.+) (.+)$/); if (v) { const octet = max(dmz_dhcp_start, min(dmz_dhcp_end, n_lan_ip[3] + iptoarr(v[1])[3] - o_lan_ip[3])); push(aliases, `${arrtoip([ n_lan_ip[0], n_lan_ip[1], n_lan_ip[2], octet ])} ${v[2]}\n`); } } f.close(); f = fs.open(dhcp.aliases, "w"); if (f) { for (let i = 0; i < length(aliases); i++) { f.write(aliases[i]); } f.close(); } } } } } if ("lan_dhcp_ip" in request.args) { if (match(request.args.lan_dhcp_ip, constants.reIP)) { configuration.setSetting("lan_ip", request.args.lan_dhcp_ip); } } if ("lan_dhcp_netmask" in request.args) { if (match(request.args.lan_dhcp_netmask, constants.reNetmask)) { configuration.setSetting("lan_mask", request.args.lan_dhcp_mask); } } if ("lan_dhcp_start" in request.args) { if (match(request.args.lan_dhcp_start, /^([2-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])$/)) { configuration.setSetting("dhcp_start", request.args.lan_dhcp_start); } } if ("lan_dhcp_end" in request.args) { if (match(request.args.lan_dhcp_end, /^([2-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])$/)) { configuration.setSetting("dhcp_end", request.args.lan_dhcp_end); } } if ("wan_enable" in request.args) { if (request.args.wan_enable === "off") { configuration.setSetting("wan_proto", "disabled"); } else { configuration.setSetting("wan_proto", "dhcp"); } } if ("wan_mode" in request.args) { if (request.args.wan_mode === "0") { configuration.setSetting("wan_proto", "dhcp"); } else { configuration.setSetting("wan_proto", "static"); } } if ("wan_ip" in request.args) { if (match(request.args.wan_ip, /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/)) { configuration.setSetting("wan_ip", request.args.wan_ip); } } if ("wan_mask" in request.args) { if (match(request.args.wan_mask, /^(((255\.){3}(255|254|252|248|240|224|192|128|0+))|((255\.){2}(255|254|252|248|240|224|192|128|0+)\.0)|((255\.)(255|254|252|248|240|224|192|128|0+)(\.0+){2})|((255|254|252|248|240|224|192|128|0+)(\.0+){3}))$/)) { configuration.setSetting("wan_mask", request.args.wan_mask); } } if ("wan_gw" in request.args) { if (match(request.args.wan_gw, /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/)) { configuration.setSetting("wan_gw", request.args.wan_gw); } } if ("wan_dns1" in request.args) { if (match(request.args.wan_dns1, /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/)) { configuration.setSetting("wan_dns1", request.args.wan_dns1); } } if ("wan_dns2" in request.args) { if (match(request.args.wan_dns2, /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/)) { configuration.setSetting("wan_dns2", request.args.wan_dns2); } } if ("wan_vlan" in request.args) { const wan_iface = split(configuration.getSettingAsString("wan_intf", ""), "."); const wan_vlan = int(request.args.wan_vlan || 0); if (wan_vlan === 0) { configuration.setSetting("wan_intf", wan_iface[0]); } else if (wan_vlan >= 3 && wan_vlan <= 4095) { configuration.setSetting("wan_intf", `${wan_iface[0]}.${wan_vlan}`); } } if ("olsrd_gw" in request.args) { uciMesh.set("aredn", "@wan[0]", "olsrd_gw", request.args.olsrd_gw === "on" ? 1 : 0); } if ("lan_dhcp_route" in request.args) { uciMesh.set("aredn", "@wan[0]", "lan_dhcp_route", request.args.lan_dhcp_route === "on" ? 1 : 0); } if ("lan_dhcp_defaultroute" in request.args) { uciMesh.set("aredn", "@wan[0]", "lan_dhcp_defaultroute", request.args.lan_dhcp_defaultroute === "on" ? 1 : 0); } uciMesh.commit("aredn"); configuration.saveSettings(); print(_R("changes")); return; } if (request.env.REQUEST_METHOD === "DELETE") { configuration.revertModalChanges(); print(_R("changes")); return; } const dmz_mode = configuration.getSettingAsInt("dmz_mode", 3); const dhcp = configuration.getDHCP("nat"); const wan_proto = configuration.getSettingAsString("wan_proto", "disabled"); const wan_iface = split(configuration.getSettingAsString("wan_intf", ""), "."); const wan_vlan = wan_iface[1] ? wan_iface[1] : ""; const gateway_nat = dmz_mode !== 1 ? dhcp.gateway : "172.27.0.1"; const gateway_altnet = dmz_mode === 1 ? dhcp.gateway : ""; %}
{{_R("dialog-header", "Network")}}
Mesh A‌ddress
The primary address of this node
{{_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.")}}
LAN Size
Size of LAN subnet
{{_H("Select how many hosts you want to support on this nodes LAN network. This determines the size of the netmask associated with that network. You can also select NAT which allows more hosts, firewalls your LAN hosts from the Mesh network, but requires explicity ports to be forwarded when creating services.")}}
IP A‌ddress
Gateway IP a‌ddress for this LAN network
Netmask
Netmask for this LAN network
DHCP Start
Start of the DHCP range for addresses allocate
DHCP End
Last address of the DHCP range for addresses allocated
AltNET IP A‌ddress
Gateway IP a‌ddress for AltNET LAN network
Netmask
Netmask for AltNET LAN network
DHCP Start
Start of the DHCP range for addresses allocate
DHCP End
Last address of the DHCP range for addresses allocated

WAN Enable
Allow node to directly access the Internet
{{_R("switch", { name: "wan_enable", value: wan_proto === "disabled" ? false : true })}}
{{_H("Enable the WAN interface on this node, to allow it to access the Internet directly.")}}
Mode
Static or DHCP mode
{{_H("The WAN interface can either use DHCP to retrieve an IP address, or it can be set statically.")}}
A‌ddress
WAN IP a‌ddress
{{_H("A fixed IP address to assign to the WAN interace on this node.")}}
Netmask
WAN netmask
{{_H("The netmask (e.g. 255.255.255.0) for this interface.")}}
Gateway
Default gateway
{{_H("The default gateway his node should use to access the Internet.")}}

DNS
Internet DNS servers
{{_H("For hosts not on the Mesh, use these DNS servers to resolve names to IP addresses.")}} {{_R("dialog-advanced")}}
{% if (includeAdvanced) { %} {% if (length(hardware.getEthernetPorts()) < 2) { %}
WAN VLAN
Vlan used for Internet access
{{_H("By default, the WAN uses an untagged VLAN on multi-port devices, and VLAN 1 on single port devices. This can be changed here if your setup requires something different. Enter the VLAN number required, or leave blank for untagged.")}} {% } %}
Mesh to WAN
Allow any mesh device to use local WAN.
{{_R("switch", { name: "olsrd_gw", value: uciMesh.get("aredn", "@wan[0]", "olsrd_gw") !== "0" })}}
{{_H("Allow any node or device on the mesh to use our local Internet connection. This is disabled by default.")}}
LAN to WAN
Allow any LAN device to use local WAN.
{{_R("switch", { name: "lan_dhcp_route", value: uciMesh.get("aredn", "@wan[0]", "lan_dhcp_route") !== "0" })}}
{{_H("Allow LAN devices connected to this node to use our Internet connection. This is enabled by default.")}}
LAN default route
Provide LAN devices with a default route.
{{_R("switch", { name: "lan_dhcp_defaultroute", value: uciMesh.get("aredn", "@wan[0]", "lan_dhcp_defaultroute") !== "0" })}}
{{_H("Provide a default route to a LAN connected device, even if our local WAN is disabled. By default this is only provided to devices if our local WAN is available.")}} {% } %}
{{_R("dialog-footer")}}