#!/usr/bin/lua
--[[
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
Copyright (C) 2021 Tim Wilkinson
Original Perl Copyright (C) 2020 - Darryl Quinn
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
aredn.@lqm[0].enable",
default = "1",
postcallback = "lqm_defaults()",
needreboot = true
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].margin_snr",
type = "string",
desc = "SNR Margin in dB above Min SNR a signal must reach to be re-activated
aredn.@lqm[0].margin_snr",
default = "1",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].min_distance",
type = "string",
desc = "Min Distance in meters beyond which a neighbor RF link is allowed
aredn.@lqm[0].min_distance",
default = "0",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].auto_distance",
type = "string",
desc = "Default Distance in meters to use when actual distance cannot be calculated
aredn.@lqm[0].auto_distance",
default = "0",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].margin_quality",
type = "string",
desc = "Quality Margin percentage increase before neighbor can be re-activated
aredn.@lqm[0].margin_quality",
default = "1",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].ping_penalty",
type = "string",
desc = "Ping Penalty quality percentage to add when neighbor cannot be pinged
aredn.@lqm[0].ping_penalty",
default = "5",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].rts_threshold",
type = "string",
desc = "RTS Threshold in bytes before using RTS/CTS when hidden nodes are detected
aredn.@lqm[0].rts_threshold",
default = "1",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].mtu",
type = "string",
desc = "Maximum packet size in bytes sent over WiFi (256 to 1500)
aredn.@lqm[0].mtu",
default = "1500",
postcallback = "changeMTU()",
needreboot = true
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].user_blocks",
type = "string",
desc = "User Blocked comma-separated list of blocked MACs
aredn.@lqm[0].user_blocks",
default = "",
condition = "lqm_enabled()"
},
{
category = "Link Quality Settings",
key = "aredn.@lqm[0].user_allows",
type = "string",
desc = "User Allowed comma-separated list of always allowed MACs
aredn.@lqm[0].user_allows",
default = "",
condition = "lqm_enabled()"
},
{
category = "WAN Settings",
key = "aredn.@wan[0].olsrd_gw",
type = "boolean",
desc = "Allow other MESH nodes to use my WAN - not recommended and OFF by default
aredn.@wan[0].olsrd_gw",
default = "0",
postcallback = "changeWANGW()",
needreboot = true
},
{
category = "WAN Settings",
key = "aredn.@wan[0].lan_dhcp_route",
type = "boolean",
desc = "Allow my LAN devices to access my WAN - ON by default
aredn.@wan[0].lan_dhcp_route",
default = "1",
postcallback = "changeWANGW()",
needreboot = true
},
{
category = "WAN Settings",
key = "aredn.@wan[0].lan_dhcp_defaultroute",
type = "boolean",
desc = "Provide default route to LAN devices even when WAN access is disabled
aredn.@wan[0].lan_dhcp_defaultroute",
default = "0",
postcallback = "changeWANGW()",
needreboot = true
},
{
category = "WAN Settings",
key = "aredn.wan.vlanid",
type = "string",
desc = "WAN VLAN Number - must be an integer in the range [1,4094]
aredn.wan.vlanid",
default = "",
condition = "supportsVLANChange()",
current = "currentWANVLAN()",
postcallback = "changeWANVLAN()",
needreboot = true
},
{
category = "WAN Settings",
key = "aredn.@wan[0].web_access",
type = "boolean",
desc = "Enable web access to the node from the WAN interface
aredn.@wan[0].web_access",
default = "1",
needreboot = true
},
{
category = "WAN Settings",
key = "aredn.@wan[0].ssh_access",
type = "boolean",
desc = "Enable SSH access to the node from the WAN interface
aredn.@wan[0].ssh_access",
default = "1",
needreboot = true
},
{
category = "WAN Settings",
key = "aredn.@wan[0].telnet_access",
type = "boolean",
desc = "Enable TELNET access to the node from the WAN interface
aredn.@wan[0].telnet_access",
default = "1",
needreboot = true
},
{
category = "Power Options",
key = "aredn.@poe[0].passthrough",
type = "boolean",
desc = "PoE Passthrough specifies whether PoE power should be enabled (Not all devices have PoE passthrough ports)
aredn.@poe[0].passthrough",
default = "0",
condition = "hasPOE()",
postcallback = "setPOEOutput()"
},
{
category = "Power Options",
key = "aredn.@usb[0].passthrough",
type = "boolean",
desc = "USB Power Passthrough specifies whether USB power should be enabled (Not all devices have USB powered ports)
aredn.@usb[0].passthrough",
default = "1",
postcallback = "setUSBOutput()",
condition = "hasUSB()"
},
{
category = "Tunnel Options",
key = "aredn.@tunnel[0].maxclients",
type = "string",
desc = "Tunnel Maxclients specifies the maximum number of tunnel clients this node can serve; must be an integer in the range [0,100].
aredn.@tunnel[0].maxclients",
default = "10",
precallback = "restrictTunnelLimitToValidRange()",
postcallback = "adjustTunnelInterfaceCount()"
},
{
category = "Tunnel Options",
key = "aredn.@tunnel[0].maxservers",
type = "string",
desc = "Tunnel Maxservers specifies the maximum number of tunnel servers to which this node can connect; must be an integer in the range [0,100].
aredn.@tunnel[0].maxservers",
default = "10",
precallback = "restrictTunnelLimitToValidRange()",
postcallback = "adjustTunnelInterfaceCount()"
},
{
category = "Tunnel Options",
key = "aredn.@tunnel[0].wanonly",
type = "boolean",
desc = "WAN-Only Tunnel prevents tunnel traffic from being routed over the Mesh network itself
aredn.@tunnel[0].wanonly",
default = "1",
needreboot= true
},
{
category = "Memory Settings",
key = "aredn.@meshstatus[0].lowmem",
type = "string",
desc = "Low Memory Threshold in KB when the Mesh Status page will be truncated
aredn.@meshstatus[0].lowmem",
default = "10000"
},
{
category = "Memory Settings",
key = "aredn.@meshstatus[0].lowroutes",
type = "string",
desc = "Low Memory Max Routes is the maximum number of routes shown on the Mesh Status page when low memory is detected
aredn.@meshstatus[0].lowroutes",
default = "1000"
},
{
category = "Network Tools",
key = "aredn.olsr.restart",
type = "none",
desc = "OLSR Restart will restart OLSR when executed; wait up to 2 or 3 minutes to receive response
aredn.olsr.restart",
default = "0",
postcallback = "olsr_restart()"
},
{
category = "Network Tools",
key = "aredn.@iperf[0].enable",
type = "boolean",
desc = "IPERF Enable allows the included iperf3 client/server
aredn.@iperf[0].enable",
default = "1"
},
{
category = "Map Paths",
key = "aredn.@map[0].maptiles",
type = "string",
desc = "Map Tiles URL
aredn.@map[0].maptiles",
default = "http://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg"
},
{
category = "Map Paths",
key = "aredn.@map[0].leafletcss",
type = "string",
desc = "Leaflet.css URL
aredn.@map[0].leafletcss",
default = "http://unpkg.com/leaflet@0.7.7/dist/leaflet.css"
},
{
category = "Map Paths",
key = "aredn.@map[0].leafletjs",
type = "string",
desc = "Leaflet.js URL
aredn.@map[0].leafletjs",
default = "http://unpkg.com/leaflet@0.7.7/dist/leaflet.js"
},
{
category = "Firmware",
key = "aredn.@downloads[0].firmwarepath",
type = "string",
desc = "Firmware Download URL
aredn.@downloads[0].firmwarepath",
default = "http://downloads.arednmesh.org/firmware"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_core",
type = "string",
desc = "Core Packages Download URL
aredn.@downloads[0].pkgs_core",
default = defaultPackageRepos('aredn_core'),
postcallback = "writePackageRepo('core')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_base",
type = "string",
desc = "Base Packages URL
aredn.@downloads[0].pkgs_base",
default = defaultPackageRepos('base'),
postcallback = "writePackageRepo('base')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_arednpackages",
type = "string",
desc = "AREDN Packages URL
aredn.@downloads[0].pkgs_arednpackages",
default = defaultPackageRepos('arednpackages'),
postcallback = "writePackageRepo('arednpackages')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_luci",
type = "string",
desc = "Luci Packages URL
aredn.@downloads[0].pkgs_luci",
default = defaultPackageRepos('luci'),
postcallback = "writePackageRepo('luci')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_packages",
type = "string",
desc = "Package Download URL for packages not included in the other sections
aredn.@downloads[0].pkgs_packages",
default = defaultPackageRepos('packages'),
postcallback = "writePackageRepo('packages')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_routing",
type = "string",
desc = "Routing Packages URL
aredn.@downloads[0].pkgs_routing",
default = defaultPackageRepos('routing'),
postcallback = "writePackageRepo('routing')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_telephony",
type = "string",
desc = "Telephony Packages URL
aredn.@downloads[0].pkgs_telephony",
default = defaultPackageRepos('telephony'),
postcallback = "writePackageRepo('telephony')"
},
{
category = "Firmware",
key = "aredn.@downloads[0].pkgs_freifunk",
type = "string",
desc = "Freifunk Packages URL
aredn.@downloads[0].pkgs_freifunk",
default = defaultPackageRepos('freifunk'),
postcallback = "writePackageRepo('freifunk')"
},
{
category = "Firmware",
key = "aredn.firmware.dangerous_upgrade",
type = "boolean",
desc = "Dangerous Upgrade Disables all safety checks usually applied when upgrading firmware
aredn.firmware.dangerous_upgrade",
default = "0",
current = "current_force_upgrade()",
postcallback = "update_force_upgrade()"
},
{
category = "AREDN Alert Settings",
key = "aredn.aam.refresh",
type = "none",
desc = "Alert Message Refresh - Execute to pull any AREDN Alert messages
aredn.aam.refresh",
default = "0",
postcallback = "aam_refresh()"
},
{
category = "AREDN Alert Settings",
key = "aredn.@alerts[0].localpath",
type = "string",
desc = "Alert Message Local URL - location from which local AREDN Alerts can be downloaded
aredn.@alerts[0].localpath",
default = ""
},
{
category = "AREDN Alert Settings",
key = "aredn.@alerts[0].groups",
type = "string",
desc = "Alert Message Groups - comma seperated list of group names to check for alert messages
aredn.@alerts[0].groups",
default = ""
},
{
category = "AREDN Alert Settings",
key = "aredn.@alerts[0].pollrate",
type = "string",
desc = "Alert Message Pollrate - how many hours to wait between polling for new AREDN Alerts
aredn.@alerts[0].pollrate",
default = "12",
needreboot = true
},
{
category = "AREDN Alert Settings",
key = "aredn.aam.purge",
type = "none",
desc = "Alert Message Purge - execute to immediately delete all alerts from this node
aredn.aam.purge",
default = "",
postcallback = "alert_purge()"
}
}
local msgs = {}
--
-- helpers
--
function msg(m)
msgs[#msgs + 1] = m
end
-- uci cursor
local cursora = uci.cursor()
local cursorb = uci.cursor("/etc/config.mesh")
function cursor_set(a, b, c, d)
if not cursora:get(a, b) and b:match("@(.+)%[0%]") then
cursora:add(a, b:match("@(.+)%[0%]"))
end
cursora:set(a, b, c, d)
if not cursorb:get(a, b) and b:match("@(.+)%[0%]") then
cursorb:add(a, b:match("@(.+)%[0%]"))
end
cursorb:set(a, b, c, d)
cursora:commit(a)
cursorb:commit(a)
end
function cursor_add(a, b, c)
cursora:set(a, b, c)
cursorb:set(a, b, c)
cursora:commit(a)
cursorb:commit(a)
end
function cursor_delete(a, b)
cursora:delete(a, b)
cursorb:delete(a, b)
cursora:commit(a)
cursorb:commit(a)
end
function cursor_get(a, b, c)
return cursora:get(a, b, c)
end
function reboot()
local node = aredn.info.get_nvram("node")
if node == "" then
node = "Node"
end
local lanip, _, lanmask = aredn.hardware.get_interface_ip4(aredn.hardware.get_iface_name("lan"))
local browser = os.getenv("REMOTE_ADDR")
local browser6 = browser:match("::ffff:([%d%.]+)")
if browser6 then
browser = browser6
end
local fromlan = false
local subnet_change = false
if lanip then
fromlan = validate_same_subnet(browser, lanip, lanmask)
if fromlan then
lanmask = ip_to_decimal(lanmask)
local cfgip = cursor_get("network", "lan", "ipaddr")
local cfgmask = ip_to_decimal(cursor_get("network", "lan", "netmask"))
if lanmask ~= cfgmask or nixio.bit.band(ip_to_decimal(lanip), lanmask) ~= nixio.bit.band(ip_to_decimal(cfgip), cfgmask) then
subnet_change = true
end
end
end
http_header()
if fromlan and subnet_change then
html.header(node .. " rebooting", true)
html.print("