Supernode support (#938)

* Supernode option

* Change supernode 10/8 route injection.
Identify supernode in sysinfo.json

* Supernode tunnels use port 5526

* Advertise supernode-ness

* Update DNS if supernodes are available

* Open up supernodes DNS service to incoming mesh requests

* Simply nameserver update

* Support supernodes on hap ac2

* Improve supernode nameserver update reliability

* Rework how supernode nameservers are managed

* Improve supernode dns advertising

* Add super mesh button

* User supernode name not ip in advert

* Less intustive way to identify supernode dns

* Add supernode ignore options
Change supernode enabled -> enable

* Improve DNS updates

* Remove tunnels when switching to/from supernode mode

* Blackhole any unknown routes on the supernode to avoid recursing packets

* Add explicit reverse lookup rule for supernode when available

* Just use dnsmasq changes for both forward and reverse names

* Improve supernode detection
So it doesnt keep writing to flash

* Add reverse tunnel ip lookup to supernode

* enabled => enable

* Supernode tunnels start 172.30

* Remove supernode switch

* Simplify supernode check

* Fix nav test
This commit is contained in:
Tim Wilkinson 2023-09-19 20:06:09 -07:00 committed by GitHub
parent 272d53bab5
commit a494a8c374
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 184 additions and 7 deletions

View File

@ -1 +1,2 @@
src-git arednpackages https://github.com/aredn/aredn_packages;develop #src-git arednpackages https://github.com/aredn/aredn_packages;develop
src-git arednpackages https://github.com/kn6plv/aredn_packages;olsr-isolate-mode

View File

@ -39,4 +39,4 @@ config Interface
config Interface config Interface
list interface 'dtdlink' list interface 'dtdlink'
option Mode 'ether' option Mode '<olsrd_dtd_interface_mode>'

View File

@ -0,0 +1,78 @@
#!/usr/bin/lua
--[[
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
Additional Terms:
Additional use restrictions exist on the AREDN(TM) 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
--]]
require("uci")
local olsr = require("aredn.olsr")
local dns_file = "/tmp/dnsmasq.d/supernode.conf"
local c = uci.cursor()
-- Supernodes themselves dont need supernode nameservers
if c:get("aredn", "@supernode[0]", "enable") == "1" then
os.exit(0)
end
-- Ignore supernodes?
if c:get("aredn", "@supernode[0]", "ignore") == "1" then
os.exit(0)
end
-- Find the first supernode to use as a nameserver
local dns = ""
for _, hna in ipairs(olsr.getOLSRHNA())
do
if hna.genmask == 8 and hna.destination == "10.0.0.0" then
dns = "#" .. hna.gateway .. "\nserver=/local.mesh/" .. hna.gateway .. "\nrev-server=10.0.0.0/8," .. hna.gateway .. "\nrev-server=172.31.0.0/16," .. hna.gateway .. "\n"
break
end
end
-- Updae the dns and restart network if necessary
local odns = ""
local f = io.open(dns_file)
if f then
odns = f:read("*a")
f:close()
end
if odns ~= dns then
f = io.open(dns_file, "w+")
if f then
f:write(dns)
f:close()
os.execute("/etc/init.d/dnsmasq restart")
end
end

View File

@ -0,0 +1,41 @@
<<'LICENSE'
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
Additional Terms:
Additional use restrictions exist on the AREDN(TM) 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.
LICENSE
SUPERNODE_ENABLE=$(/sbin/uci -q get aredn.@supernode[0].enable)
if [ "${SUPERNODE_ENABLE}" = "1" ]; then
nft insert rule ip fw4 input_dtdlink udp dport 53 accept comment \"dns access\" 2> /dev/null
nft insert rule ip fw4 input_dtdlink tcp dport 53 accept comment \"dns access\" > /dev/null
ip route add blackhole 10.0.0.0/8 table 30
fi

View File

@ -0,0 +1,8 @@
if nixio.fs.stat("/tmp/dnsmasq.d/supernode.conf") then
local ip = read_all("/tmp/dnsmasq.d/supernode.conf"):match("^#(%S+)")
if ip then
return { href = "http://" .. ip .. "/cgi-bin/mesh", display = "Super Mesh", hint = "See what is on the supernode mesh" }
end
elseif uci.cursor():get("aredn", "@supernode[0]", "enable") == "1" then
return { href = "/cgi-bin/mesh", display = "Super Mesh", hint = "See what is on the supernode mesh" }
end

View File

@ -115,7 +115,8 @@ local cfg = {
lan_network_config = "", lan_network_config = "",
wan_network_config = "", wan_network_config = "",
dtdlink_network_config = "", dtdlink_network_config = "",
wifi_network_config = "" wifi_network_config = "",
olsrd_dtd_interface_mode = "ether"
} }
function expand_vars(lines) function expand_vars(lines)
@ -184,6 +185,13 @@ else
cfg.wifi_intf = "br-nomesh" cfg.wifi_intf = "br-nomesh"
end end
-- Supernode options
local is_supernode = (c:get("aredn", "@supernode[0]", "enable") == "1")
if is_supernode then
cfg.olsrd_dtd_interface_mode = "isolated"
end
-- delete some config lines if necessary -- delete some config lines if necessary
if cfg.wan_proto == "dhcp" then if cfg.wan_proto == "dhcp" then
@ -715,6 +723,10 @@ if nixio.fs.access("/etc/config.mesh/olsrd", "r") then
end end
end end
if is_supernode then
of:write("config Hna4\n\toption netaddr 10.0.0.0\n\toption netmask 255.0.0.0\n\n")
end
if c:get("aredn", "@wan[0]", "olsrd_gw") == "1" then if c:get("aredn", "@wan[0]", "olsrd_gw") == "1" then
of:write("config LoadPlugin\n\toption library 'olsrd_dyn_gw.so.0.5'\n\toption Interval '60'\n\tlist Ping '8.8.8.8'\n\tlist Ping '8.8.4.4'\n\n\n") of:write("config LoadPlugin\n\toption library 'olsrd_dyn_gw.so.0.5'\n\toption Interval '60'\n\tlist Ping '8.8.8.8'\n\tlist Ping '8.8.4.4'\n\n\n")
end end

View File

@ -293,6 +293,13 @@ local settings = {
desc = "<b>Low Memory Max Routes</b> is the maximum number of routes shown on the Mesh Status page when low memory is detected<br><br><small>aredn.@meshstatus[0].lowroutes</small>", desc = "<b>Low Memory Max Routes</b> is the maximum number of routes shown on the Mesh Status page when low memory is detected<br><br><small>aredn.@meshstatus[0].lowroutes</small>",
default = "1000" default = "1000"
}, },
{
category = "Supernode Settings",
key = "aredn.@supernode[0].ignore",
type = "boolean",
desc = "<b>Ignore any Supernodes</b> found on the mesh <br><br><small>aredn.@supernode[0].ignore</small>",
default = "0"
},
{ {
category = "Network Tools", category = "Network Tools",
key = "aredn.olsr.restart", key = "aredn.olsr.restart",
@ -574,6 +581,14 @@ function supportsVLANChange()
return false return false
end end
function canBeSupernode()
local board = aredn.hardware.get_board_type()
if board == "mikrotik,hap-ac2" or board == "qemu-standard-pc-i440fx-piix-1996" then
return true
end
return false
end
-- callbacks -- callbacks
local newval local newval

View File

@ -84,6 +84,11 @@ info['node_details']['firmware_version']=aredn_info.getFirmwareVersion()
-- Mesh Gatway -- Mesh Gatway
info['node_details']['mesh_gateway']=aredn_info.getMeshGatewaySetting() info['node_details']['mesh_gateway']=aredn_info.getMeshGatewaySetting()
-- Supernode
if ctx:get("aredn", "@supernode[0]", "enable") == "1" then
info['node_details']['mesh_supernode']=true
end
-- Mesh RF info -- Mesh RF info
info['meshrf']={} info['meshrf']={}
local radio=aredn_info.getMeshRadioDevice() local radio=aredn_info.getMeshRadioDevice()

View File

@ -117,7 +117,11 @@ function get_server_network_address()
if not server_net then if not server_net then
local mac = aredn.hardware.get_interface_mac("eth0") local mac = aredn.hardware.get_interface_mac("eth0")
local a, b = mac:match("^..:..:..:..:(..):(..)$") local a, b = mac:match("^..:..:..:..:(..):(..)$")
server_net = "172.31." .. tonumber(b, 16) .. "." .. ((tonumber(a, 16) * 4) % 256) local net_base = "172.31."
if cursor:get("aredn", "@supernode[0]", "enable") == "1" then
net_base = "172.30."
end
server_net = net_base .. tonumber(b, 16) .. "." .. ((tonumber(a, 16) * 4) % 256)
cursor:set("vtun", "@network[0]", "start", server_net) cursor:set("vtun", "@network[0]", "start", server_net)
cursor:commit("vtun") cursor:commit("vtun")
@ -182,6 +186,7 @@ end
if parms.button_reset then if parms.button_reset then
cursor:revert("vtun") cursor:revert("vtun")
cursor:delete("vtun", "@options[0]", "port")
cursor:delete("vtun", "@network[0]", "start") cursor:delete("vtun", "@network[0]", "start")
cursor:delete("vtun", "@network[0]", "dns") cursor:delete("vtun", "@network[0]", "dns")
cursor:commit("vtun") cursor:commit("vtun")
@ -299,7 +304,14 @@ if not validate_fqdn(dns) then
err("Not a valid DNS name") err("Not a valid DNS name")
end end
if #cli_err == 0 then if #cli_err == 0 then
local net = "172.31." .. parms.server_net1 .. "." .. parms.server_net2 local net_base = "172.31."
if cursor:get("aredn", "@supernode[0]", "enable") == "1" then
net_base = "172.30."
cursor:set("vtun", "@options[0]", "port", "5526")
else
cursor:delete("vtun", "@options[0]", "port")
end
local net = net_base .. parms.server_net1 .. "." .. parms.server_net2
cursor:set("vtun", "@network[0]", "start", net) cursor:set("vtun", "@network[0]", "start", net)
cursor:set("vtun", "@network[0]", "dns", dns) cursor:set("vtun", "@network[0]", "dns", dns)
end end

View File

@ -280,6 +280,11 @@ end
parms.conn_num = conn_num parms.conn_num = conn_num
-- save the connections -- save the connections
if cursor:get("aredn", "@supernode[0]", "enable") == "1" then
cursor:set("vtun", "@options[0]", "port", "5526")
else
cursor:delete("vtun", "@options[0]", "port")
end
local enabled_count = 0 local enabled_count = 0
for i = 0,parms.conn_num-1 for i = 0,parms.conn_num-1
do do