diff --git a/configs/ath79-tiny.config b/configs/ath79-tiny.config index 765edea2..948f1d6a 100644 --- a/configs/ath79-tiny.config +++ b/configs/ath79-tiny.config @@ -14,6 +14,7 @@ CONFIG_PACKAGE_ATH_SPECTRAL=n CONFIG_PACKAGE_ethtool=m CONFIG_PACKAGE_iperf3=m CONFIG_PACKAGE_libustream-mbedtls=m +CONFIG_PACKAGE_kmod-wireguard=m CONFIG_PACKAGE_vtun=m CONFIG_PACKAGE_wireguard=m CONFIG_PACKAGE_wireguard-tools=m diff --git a/configs/common.config b/configs/common.config index bbbadf2b..1289997d 100644 --- a/configs/common.config +++ b/configs/common.config @@ -86,7 +86,7 @@ CONFIG_PACKAGE_kmod-usb-storage=m CONFIG_PACKAGE_kmod-usb-storage-uas=m CONFIG_PACKAGE_kmod-usb-uhci=m CONFIG_PACKAGE_kmod-usb-xhci-hcd=m -CONFIG_PACKAGE_kmod-wireguard=m +CONFIG_PACKAGE_kmod-wireguard=y CONFIG_PACKAGE_libblkid=m CONFIG_PACKAGE_libcomerr=m CONFIG_PACKAGE_libcurl=y @@ -150,8 +150,8 @@ CONFIG_PACKAGE_tcpdump-mini=m CONFIG_PACKAGE_ubi-utils=y CONFIG_PACKAGE_uhttpd=y CONFIG_PACKAGE_vtun=y -CONFIG_PACKAGE_wireguard=m -CONFIG_PACKAGE_wireguard-tools=m +CONFIG_PACKAGE_wireguard=y +CONFIG_PACKAGE_wireguard-tools=y CONFIG_PACKAGE_wpad-mini=y CONFIG_PACKAGE_xinetd=n CONFIG_PACKAGE_zlib=m diff --git a/feeds.conf b/feeds.conf index f5711628..c4e5ef47 100644 --- a/feeds.conf +++ b/feeds.conf @@ -1 +1 @@ -src-git arednpackages https://github.com/kn6plv/aredn_packages;working +src-git arednpackages https://github.com/aredn/aredn_packages;develop diff --git a/files/etc/arednsysupgrade.conf b/files/etc/arednsysupgrade.conf index e22b909c..3e0d46c4 100644 --- a/files/etc/arednsysupgrade.conf +++ b/files/etc/arednsysupgrade.conf @@ -10,6 +10,7 @@ /etc/config.mesh/aliases.dmz /etc/config.mesh/aliases.nat /etc/config.mesh/vtun +/etc/config.mesh/wireguard /etc/config.mesh/network_tun /etc/config.mesh/aredn /etc/config.mesh/xlink diff --git a/files/etc/config.mesh/network b/files/etc/config.mesh/network index bb822a3b..d4cbc211 100644 --- a/files/etc/config.mesh/network +++ b/files/etc/config.mesh/network @@ -38,3 +38,6 @@ include /etc/config.mesh/xlink ### Tunnels devices include /etc/config.mesh/network_tun + +### Wireguard + diff --git a/files/etc/local/mesh-firewall/01-tunnels b/files/etc/local/mesh-firewall/01-tunnels index 7c54d33f..ff4e9949 100755 --- a/files/etc/local/mesh-firewall/01-tunnels +++ b/files/etc/local/mesh-firewall/01-tunnels @@ -34,8 +34,8 @@ LICENSE -if [ "$MESHFW_TUNNELS_ENABLED" != "1" ]; then - exit 0; +if [ "$MESHFW_TUNNELS_ENABLED" != "1" -a "$MESHFW_WG_TUNNELS_ENABLED" != "1" ]; then + exit 0; fi # In all cases - restart, flush, clear -- it is necessary to clean up any remenant rules to ensure chain order is correct @@ -66,14 +66,17 @@ nft add chain ip fw4 reject_to_vpn nft insert rule ip fw4 forward iifname "tun*" jump forward_vpn nft add rule ip fw4 input iifname "tun*" jump input_vpn nft add rule ip fw4 output oifname "tun*" jump accept_vpn # instead of creating a output_vpn chain -nft add rule ip fw4 input_vpn icmp type echo-request counter accept -nft add rule ip fw4 input_vpn tcp dport 2222 counter accept -nft add rule ip fw4 input_vpn tcp dport 8080 counter accept -nft add rule ip fw4 input_vpn tcp dport 80 counter accept -nft add rule ip fw4 input_vpn udp dport 698 counter accept -nft add rule ip fw4 input_vpn tcp dport 23 counter accept -nft add rule ip fw4 input_vpn tcp dport 9090 counter accept -nft add rule ip fw4 input_vpn udp dport 161 counter accept +nft insert rule ip fw4 forward iifname "wg*" jump forward_vpn +nft add rule ip fw4 input iifname "wg*" jump input_vpn +nft add rule ip fw4 output oifname "wg*" jump accept_vpn # instead of creating a output_vpn chain +nft add rule ip fw4 input_vpn icmp type echo-request accept +nft add rule ip fw4 input_vpn tcp dport 2222 accept +nft add rule ip fw4 input_vpn tcp dport 8080 accept +nft add rule ip fw4 input_vpn tcp dport 80 accept +nft add rule ip fw4 input_vpn udp dport 698 accept +nft add rule ip fw4 input_vpn tcp dport 23 accept +nft add rule ip fw4 input_vpn tcp dport 9090 accept +nft add rule ip fw4 input_vpn udp dport 161 accept nft add rule ip fw4 input_vpn ct status dnat accept comment \"!vtun: Accept port redirections\" nft add rule ip fw4 input_vpn jump reject_vpn nft insert rule ip fw4 forward_vpn jump forwarding_vpn_rule @@ -92,6 +95,12 @@ nft add rule ip fw4 reject_vpn oifname "tun*" reject nft add rule ip fw4 reject_vpn iifname "tun*" reject nft add rule ip fw4 accept_to_vpn oifname "tun*" accept nft add rule ip fw4 reject_to_vpn oifname "tun*" reject +nft add rule ip fw4 accept_vpn oifname "wg*" accept +nft add rule ip fw4 accept_vpn iifname "wg*" accept +nft add rule ip fw4 reject_vpn oifname "wg*" reject +nft add rule ip fw4 reject_vpn iifname "wg*" reject +nft add rule ip fw4 accept_to_vpn oifname "wg*" accept +nft add rule ip fw4 reject_to_vpn oifname "wg*" reject nft insert rule ip fw4 forward_dtdlink jump accept_to_vpn nft insert rule ip fw4 forward_wifi jump accept_to_vpn nft insert rule ip fw4 forward_lan jump accept_to_vpn diff --git a/files/etc/local/mesh-firewall/04-wireguard b/files/etc/local/mesh-firewall/04-wireguard new file mode 100755 index 00000000..26a7385e --- /dev/null +++ b/files/etc/local/mesh-firewall/04-wireguard @@ -0,0 +1,10 @@ +#!/bin/sh + +vtunduciport=$(uci get vtun.@options[0].port 2>/dev/null) +vtundport=${vtunduciport:-5525} + +nft insert rule ip fw4 input_wan udp dport $vtundport accept comment \"Wireguard\" +if [ "$(/sbin/uci -q get aredn.@tunnel[0].wanonly)" != "0" ]; then + nft insert rule ip fw4 output_wifi udp dport $vtundport reject comment \"Wireguard\" + nft insert rule ip fw4 output_dtdlink udp dport $vtundport reject comment \"Wireguard\" +fi diff --git a/files/etc/uci-defaults/50_wireguard b/files/etc/uci-defaults/50_wireguard new file mode 100755 index 00000000..b85f5591 --- /dev/null +++ b/files/etc/uci-defaults/50_wireguard @@ -0,0 +1,11 @@ +#! /bin/sh +if [ "$(/sbin/uci -c /etc/config.mesh -q get wireguard.@wireguard_server[0].public)" = "" -a -f /usr/bin/wg ]; then + private=$(/usr/bin/wg genkey) + public=$(echo $private | /usr/bin/wg pubkey) + touch /etc/config.mesh/wireguard + /sbin/uci -q -c /etc/config.mesh add wireguard wireguard_server + /sbin/uci -q -c /etc/config.mesh set wireguard.@wireguard_server[0].private=$private + /sbin/uci -q -c /etc/config.mesh set wireguard.@wireguard_server[0].public=$public + /sbin/uci -q -c /etc/config.mesh set wireguard.@wireguard_server[0].masksize=26 + /sbin/uci -q -c /etc/config.mesh commit wireguard +fi diff --git a/files/usr/local/bin/mesh-firewall b/files/usr/local/bin/mesh-firewall index 5afa2702..a73aac19 100755 --- a/files/usr/local/bin/mesh-firewall +++ b/files/usr/local/bin/mesh-firewall @@ -55,6 +55,13 @@ then else export MESHFW_TUNNELS_ENABLED=0 fi +# Is Wireguard 'enabled' +if [ -x "/usr/bin/wg" ] +then + export MESHFW_WG_TUNNELS_ENABLED=1 +else + export MESHFW_WG_TUNNELS_ENABLED=0 +fi # Lets execute each include file diff --git a/files/usr/local/bin/mgr/lqm.lua b/files/usr/local/bin/mgr/lqm.lua index 2cbbe279..c2ccd114 100755 --- a/files/usr/local/bin/mgr/lqm.lua +++ b/files/usr/local/bin/mgr/lqm.lua @@ -193,7 +193,7 @@ function canonical_hostname(hostname) end local cursor = uci.cursor() - +local cursorm = uci.cursor("/etc/config.mesh") local myhostname = canonical_hostname(info.get_nvram("node") or "localnode") local myip = cursor:get("network", "wifi", "ipaddr") @@ -377,6 +377,49 @@ function lqm() end end + -- Wireguard + cursorm:foreach("wireguard", "client", + function(s) + if s.enabled == "1" then + local a, b, c, d = s.clientip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$") + stations[#stations + 1] = { + type = "Tunnel", + device = "wgc", + signal = nil, + ip = s.clientip, + mac = string.format("00:00:%02X:%02X:%02X:%02X", a, b, c, d), + tx_packets = 0, + tx_fail = 0, + tx_retries = 0, + tx_bitrate = 0, + rx_bitrate = 0 + } + end + end + ) + local wgs = 0 + cursorm:foreach("vtun", "server", + function(s) + if s.enabled == "1" and s.netip:match("/") then + local a, b, c, d, m = s.netip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)/(%d+)$") + local d = nixio.bit.band(d, nixio.bit.lshift(255, 32 - m)) + 1 + stations[#stations + 1] = { + type = "Tunnel", + device = "wgs" .. wgs, + signal = nil, + ip = string.format("%d.%d.%d.%d", a, b, c, d), + mac = string.format("00:00:%02X:%02X:%02X:%02X", a, b, c, d), + tx_packets = 0, + tx_fail = 0, + tx_retries = 0, + tx_bitrate = 0, + rx_bitrate = 0 + } + wgs = wgs + 1 + end + end + ) + -- DtD for _, entry in ipairs(arps) do diff --git a/files/usr/local/bin/node-setup b/files/usr/local/bin/node-setup index 00b47dbd..029e10c0 100755 --- a/files/usr/local/bin/node-setup +++ b/files/usr/local/bin/node-setup @@ -70,6 +70,7 @@ end -- helpers end local c = uci.cursor() +local cm = uci.cursor("/etc/config.mesh") -- validate args local auto = false @@ -116,7 +117,9 @@ local cfg = { wan_network_config = "", dtdlink_network_config = "", wifi_network_config = "", - olsrd_dtd_interface_mode = "ether" + olsrd_dtd_interface_mode = "ether", + tun_network_config = "", + wireguard_network_config = "" } function expand_vars(lines) @@ -187,7 +190,7 @@ end -- Supernode options -local is_supernode = (uci.cursor("/etc/config.mesh"):get("aredn", "@supernode[0]", "enable") == "1") +local is_supernode = (cm:get("aredn", "@supernode[0]", "enable") == "1") if is_supernode then cfg.olsrd_dtd_interface_mode = "isolated" end @@ -295,7 +298,7 @@ if do_basic then list[port:gsub("%..*$", "")] = true end end - local config = "config device\n option name 'br0'\n option type 'bridge'\n" + local config = "config device\n option name 'br0'\n option type 'bridge'\n option vlan_filtering '1'\n" for port, _ in pairs(list) do config = config .. " list ports '" .. port .. "'\n" @@ -415,9 +418,13 @@ if do_basic then end if not wireless then - for _, port in ipairs(ports) - do - config = config .. " list ports '" .. port .. "'\n" + if #ports == 0 then + config = config .. " option bridge_empty '1'\n" + else + for _, port in ipairs(ports) + do + config = config .. " list ports '" .. port .. "'\n" + end end else config = config .. " option name '" .. ports[1] .. "'\n" @@ -454,13 +461,86 @@ if do_basic then cfg[net .. "_network_config"] = config end + -- Generate the tunnel configurations + local tun_port = cm:get("vtun", "@options[0]", "port") + if tun_port then + cfg.tun_network_config = cfg.tun_network_config .. "config options\n\toption port '" .. tun_port .. "'\n\n" + end + local tun_start = cm:get("vtun", "@network[0]", "start") + local tun_dns = cm:get("vtun", "@network[0]", "dns") + if tun_start or tun_dns then + cfg.tun_network_config = cfg.tun_network_config .. "config network\n" + if tun_start then + cfg.tun_network_config = cfg.tun_network_config .. "\toption start '" .. tun_start .. "'\n" + end + if tun_dns then + cfg.tun_network_config = cfg.tun_network_config .. "\toption dns '" .. tun_dns .. "'\n" + end + cfg.tun_network_config = cfg.tun_network_config .. "\n" + end + cm:foreach("vtun", "client", + function(s) + if s.enabled == "1" then + cfg.tun_network_config = cfg.tun_network_config .. string.format("config client\n\toption enabled '1'\n\toption node '%s'\n\toption passwd '%s'\n\toption clientip '%s'\n\toption serverip '%s'\n\toption netip '%s'\n\n", + s.node, s.passwd, s.clientip, s.serverip, s.netip) + end + end + ) + local wgclients = 0 + cm:foreach("wireguard", "client", + function(s) + if s.enabled == "1" then + local client_priv, client_pub = s.key:match("^(.+=)(.+=)$") + cfg.wireguard_network_config = cfg.wireguard_network_config .. + string.format("config wireguard_wgc\n\toption public_key '%s'\n\toption persistent_keepalive '25'\n\tlist allowed_ips '0.0.0.0/0'\n\n", + client_pub) + wgclients = wgclients + 1 + end + end + ) + if wgclients > 0 then + local private = cm:get("wireguard", "@wireguard_server[0]", "private") + local mask_size = tonumber(cm:get("wireguard", "@wireguard_server[0]", "masksize") or 26) + local ab, c, d = tun_start:match("^(%d+%.%d+%.)(%d+)%.(%d+)$") + c = tonumber(c) + 1 + if c > 255 then + c = 0 + end + d = nixio.bit.band(tonumber(d), nixio.bit.lshift(255, 32 - mask_size)) + 1 + cfg.wireguard_network_config = + string.format("config interface 'wgc'\n\toption proto 'wireguard'\n\toption private_key '%s'\n\toption nohostroute '1'\n\toption listen_port '%s'\n\tlist addresses '%s'\n\n", + private, (tun_port or 5525), (ab .. c .. "." .. d)) .. + cfg.wireguard_network_config + end + local wgservers = 0 + cm:foreach("vtun", "server", + function(s) + if s.enabled == "1" then + if s.netip:match("/") then + local server_pub, client_priv, client_pub = s.passwd:match("^(.+=)(.+=)(.+=)$") + cfg.wireguard_network_config = cfg.wireguard_network_config .. + string.format("config interface 'wgs%d'\n\toption proto 'wireguard'\n\toption private_key '%s'\n\toption nohostroute '1'\n\tlist addresses '%s'\n\n", + wgservers, client_priv, s.netip:match("^(.+)/")) + cfg.wireguard_network_config = cfg.wireguard_network_config .. + string.format("config wireguard_wgs%d\n\toption public_key '%s'\n\toption endpoint_host '%s'\n\toption endpoint_port '%s'\n\toption persistent_keepalive '25'\n\tlist allowed_ips '0.0.0.0/0'\n\n", + wgservers, server_pub, s.host, (tun_port or 5525)) + wgservers = wgservers + 1 + else + cfg.tun_network_config = cfg.tun_network_config .. + string.format("config server\n\toption enabled '1'\n\toption host '%s'\n\toption node '%s'\n\toption passwd '%s'\n\toption clientip '%s'\n\toption serverip '%s'\n\toption netip '%s'\n\n", + s.host, s.node, s.passwd, s.clientip, s.serverip, s.netip) + end + end + end + ) + remove_all("/tmp/new_config") nixio.fs.mkdir("/tmp/new_config") for file in nixio.fs.glob("/etc/config.mesh/*") do local bfile = nixio.fs.basename(file) - if not (bfile:match("^_setup") or bfile:match("^firewall.user") or bfile:match("^olsrd")) then + if not (bfile:match("^_setup") or bfile:match("^firewall.user") or bfile:match("^olsrd") or bfile == "vtun") then local f = io.open("/tmp/new_config/" .. bfile, "w") if f then f:write(expand_vars(read_all(file))) @@ -469,6 +549,9 @@ if do_basic then end end + -- Tunnels + write_all("/tmp/new_config/vtun", expand_vars("")) + -- make it official for file in nixio.fs.glob("/etc/config/*") do diff --git a/files/usr/local/bin/olsrd-config b/files/usr/local/bin/olsrd-config index 94c51c77..f31949e2 100755 --- a/files/usr/local/bin/olsrd-config +++ b/files/usr/local/bin/olsrd-config @@ -63,11 +63,13 @@ if uci_conf_file == "olsrd6" then end local cursor = uci.cursor() +local cursorm = uci.cursor("/etc/config.mesh") local names = {} local hosts = {} local services = {} local tunnels = {} +local wgtunnels = {} function ip_to_hostname(ip) if ip and ip ~= "" and ip ~= "none" then @@ -304,11 +306,20 @@ if nixio.fs.stat("/etc/local/mesh-firewall/02-vtund") then maxclients = 10 end tunnum = 50 + maxclients - cursor:foreach("vtun", "server", + local wgtunnum = 0 + if cursor:get("wireguard", "@client[0]", "name") then + tunnels[#tunnels + 1] = "wgc" + end + cursorm:foreach("vtun", "server", function(section) if section.enabled == "1" then - tunnels[#tunnels + 1] = "tun" .. tunnum - tunnum = tunnum + 1 + if section.netip:match("/") then + tunnels[#tunnels + 1] = "wgs" .. wgtunnum + wgtunnum = wgtunnum + 1 + else + tunnels[#tunnels + 1] = "tun" .. tunnum + tunnum = tunnum + 1 + end end end ) diff --git a/files/www/cgi-bin/vpn b/files/www/cgi-bin/vpn index 4c89a64a..f99008ff 100755 --- a/files/www/cgi-bin/vpn +++ b/files/www/cgi-bin/vpn @@ -45,7 +45,7 @@ require("uci") local html = aredn.html -local cursor = uci.cursor(); +local cursor = uci.cursor("/etc/config.mesh"); local node = aredn.info.get_nvram("node") if node == "" then @@ -70,6 +70,11 @@ if os.getenv("REQUEST_METHOD") == "POST" then parms = request:formvalue() end +-- wireguard +local wireguard_mask_size = tonumber(cursor:get("wireguard", "@wireguard_server[0]", "masksize") or 26) +local wireguard_max = nixio.bit.lshift(1, 32 - wireguard_mask_size) +local wireguard_alive_time = 300 -- 5 minutes + -- helpers start local cli_err = {} @@ -102,6 +107,22 @@ function get_active_tun() return tuns end +function get_active_wgtun() + local tuns = {} + local f = io.popen("/usr/bin/wg show all latest-handshakes") + if f then + for line in f:lines() + do + local k,v = line:match("^%S+%s+(%S+)%s+(%S+)%s*$") + if k then + tuns[k] = tonumber(v) -- time in seconds + end + end + f:close() + end + return tuns +end + function is_tunnel_active(ip, tunnels) for _, aip in ipairs(tunnels) do @@ -112,6 +133,15 @@ function is_tunnel_active(ip, tunnels) return false end +function is_wgtunnel_active(key, wgtunnels) + local key = key:match("^.*=(.*=)$") + local v = wgtunnels[key] + if v and v + wireguard_alive_time > os.time() then + return true + end + return false +end + function get_server_network_address() local server_net = cursor:get("vtun", "@network[0]", "start") if not server_net then @@ -127,11 +157,25 @@ function get_server_network_address() return { a, b, c, d } end +function get_wireguard_network_address(netw) + local c = netw[3] + 1 + if c > 255 then + c = 0 + end + local d = nixio.bit.band(netw[4], nixio.bit.lshift(255, 32 - wireguard_mask_size)) + return { netw[1], netw[2], c, d, wireguard_mask_size } +end + function get_server_dns() local dns = cursor:get("vtun", "@network[0]", "dns") return dns and dns or "" end +function get_wireguard_public() + local wg = cursor:get("wireguard", "@wireguard_server[0]", "public") + return wg or "" +end + -- helper end -- load client info from uci @@ -153,6 +197,25 @@ function get_client_info() ) parms.client_num = c end +-- wireguard +local gci_vars = { "enabled", "name", "key", "clientip", "contact" } +function get_wgclient_info() + local c = 0 + cursor:foreach("wireguard", "client", + function(section) + for _, var in ipairs(gci_vars) + do + local key = "wgclient" .. c .. "_" .. var + parms[key] = section[var] + if not parms[key] then + parms[key] = "" + end + end + c = c + 1 + end + ) + parms.wgclient_num = c +end if parms.button_reboot then os.execute("reboot >/dev/null 2>&1") @@ -186,24 +249,30 @@ if parms.button_reset then cursor:delete("vtun", "@options[0]", "port") cursor:delete("vtun", "@network[0]", "start") cursor:delete("vtun", "@network[0]", "dns") - cursor:commit("vtun") end -- get vtun network address local netw = get_server_network_address() +local netwg = get_wireguard_network_address(netw) local dns = get_server_dns() +local wireguard_public = get_wireguard_public() -- if RESET or FIRST TIME load client/servers from file into parms if parms.button_reset or not parms.reload then cursor:revert("vtun") get_client_info() + get_wgclient_info() parms.server_net1 = netw[3] parms.server_net2 = netw[4] parms.dns = dns - -- initialzie the "add" entries to clear them + parms.wireguard_public = wireguard_public + -- initialize the "add" entries to clear them parms.client_add_enabled = "0" parms.client_add_name = "" parms.client_add_passwd = "" + parms.wgclient_add_enabled = "0" + parms.wgclient_add_name = "" + parms.wgclient_add_key = "" end local list = {} @@ -239,13 +308,16 @@ do end if val == "_add" and not ((enabled ~= "0" or name ~= "" or passwd ~= "" or contact ~= "") and (parms.client_add or parms.button_save)) then - break + break end if val == "_add" and parms.button_save then err(val .. " this client must be added or cleared out before saving changes") break end + if passwd == "" then + err("A client password is required") + end if passwd:match("[^%w@]") then err("The password cannot contain non-alphanumeric characters (#" .. client_num .. ")") end @@ -255,9 +327,6 @@ do if name == "" then err("A client name is required") end - if passwd == "" then - err("A client password is required") - end if val == "_add" and #cli_err > 0 and cli_err[#cli_err]:match("^" .. val .. " ") then break @@ -281,9 +350,79 @@ do end end end - parms.client_num = client_num +-- wireguard +local vars = { "enabled", "name", "key", "clientip", "contact" } +local wgclient_num = 0 +for val = 0, parms.wgclient_num +do + if val == tonumber(parms.wgclient_num) then + val = "_add" + end + for _ = 1,1 + do + for _, var in ipairs(vars) + do + local varname = "wgclient" .. val .. "_" .. var + if var == "enabled" and not parms[varname] then + parms[varname] = "0" + elseif not parms[varname] then + parms[varname] = "" + elseif var == "contact" then + parms[varname] = parms[varname]:gsub("^%s+", ""):gsub("%s+$", ""):sub(1,210):gsub('"',"""):gsub("'","'"):gsub("<","<"):gsub(">",">") + else + parms[varname] = parms[varname]:gsub("^%s+", ""):gsub("%s+$", "") + end + if val ~= "_add" and parms[varname] == "" and var == "enabled" then + parms[varname] = "0" + end + _G[var] = parms[varname] + end + + if val == "_add" and not ((enabled ~= "0" or name ~= "" or contact ~= "") and (parms.wgclient_add or parms.button_save)) then + break + end + + if val == "_add" and parms.button_save then + err(val .. " this wireguard client must be added or cleared out before saving changes") + break + end + if name == "" then + err("A client name is required") + end + + if val == "_add" and #cli_err > 0 and cli_err[#cli_err]:match("^" .. val .. " ") then + break + end + + if key == "" then + local priv = capture("/usr/bin/wg genkey"):match("(%S+)") + local pub = capture("echo " .. priv .. " | /usr/bin/wg pubkey"):match("(%S+)") + key = priv .. pub + end + + parms["wgclient" .. wgclient_num .. "_enabled"] = enabled + parms["wgclient" .. wgclient_num .. "_name"] = name:upper() + parms["wgclient" .. wgclient_num .. "_key"] = key + parms["wgclient" .. wgclient_num .. "_clientip"] = clientip + parms["wgclient" .. wgclient_num .. "_contact"] = contact + + -- commit the data from this client + wgclient_num = wgclient_num + 1 + + -- clear out the ADD values + if val == "_add" then + for _, var in ipairs(vars) + do + parms["wgclient_add_" .. var] = "" + end + end + end +end +parms.wgclient_num = wgclient_num + + -- SAVE the server network numbers and dns into the UCI netw[3] = parms.server_net1 netw[4] = parms.server_net2 @@ -343,6 +482,22 @@ do enabled_count = enabled_count + 1 end end +-- wireguard +for i = 0,wgclient_num-1 +do + local clientx = "wgclient" .. i + local client_x = "client_" .. i + + if not cursor:get("wireguard", client_x) then + cursor:set("wireguard", client_x, 'client') + end + + cursor:set("wireguard", client_x, "enabled", parms[clientx .. "_enabled"]) + cursor:set("wireguard", client_x, "name", parms[clientx .. "_name"]) + cursor:set("wireguard", client_x, "contact", parms[clientx .. "_contact"]) + cursor:set("wireguard", client_x, "key", parms[clientx .. "_key"]) + cursor:set("wireguard", client_x, "clientip", parms[clientx .. "_clientip"]) +end local maxclients = tonumber(cursor:get("aredn", "@tunnel[0]", "maxclients")) if not maxclients then @@ -355,16 +510,15 @@ end -- save configuration (commit) if parms.button_save and #cli_err == 0 then cursor:commit("vtun") - write_all("/etc/config.mesh/vtun", read_all("/etc/config/vtun")) - if os.execute("/etc/init.d/olsrd restart > /dev/null 2>&1") ~= 0 then - err2("Problem restarting olsrd") - end - if os.execute("/etc/init.d/vtundsrv restart > /dev/null 2>&1") ~= 0 then - err2("Problem restaring vtundsrv") - end + cursor:commit("wireguard") + os.execute("/usr/local/bin/node-setup -a mesh > /dev/null 2>&1") + os.execute("/etc/init.d/olsrd restart > /dev/null 2>&1") + os.execute("/etc/init.d/vtundsrv restart > /dev/null 2>&1") + os.execute("/etc/init.d/network restart > /dev/null 2>&1") end local active_tun = get_active_tun() +local active_wgtun = get_active_wgtun() -- generate the page @@ -377,7 +531,7 @@ html.print("
Tunnel Server Network:") html.print(netw[1] .. "." .. netw[2] .. "..") - + html.print("
Wireguard Server Network:
") + html.print(netwg[1] .. "." .. netwg[2] .. "." .. netwg[3] .. "." .. netwg[4] .. "/" .. netwg[5]) html.print("

Tunnel Server DNS Name: ") html.print("") + html.print("") html.print("") html.print("") @@ -462,9 +618,6 @@ if config == "mesh" then do _G[var] = parms["client" .. val .. "_" .. var] end - if val == "_add" and #list > 1 then - html.print("") - end html.print("") html.print("") - html.print("") + html.print("") -- handle rollover of netw local net @@ -498,8 +652,8 @@ if config == "mesh" then end local lastnet = netw[4] + net * 4 local fullnet = netw[1] .. "." .. netw[2] .. "." .. netw[3] .. "." .. lastnet - html.print("") + html.print("") html.print("") else - html.print("") + html.print("") end html.print("") - cli_err:remove(1) + html.print("") + table.remove(cli_err) + end + + html.print("") + cnum = cnum + 1 + end + + -- Wireguard + html.print("") + html.print("") + html.print("") + html.print("") + + local keys = { "enabled", "name", "contact", "key" } + local cnum = 1 + for val = 0, wgclient_num + do + if val == wgclient_num then + val = "_add" + end + for _, var in ipairs(keys) + do + _G[var] = parms["wgclient" .. val .. "_" .. var] + end + html.print("") + html.print("") + html.print("") + html.print("") + + local fullnet = netwg[1] .. "." .. netwg[2] .. "." .. netwg[3] .. "." .. (netwg[4] + 1 + cnum) .. "/" .. netwg[5] + html.print("") + html.print("") + if val == "_add" then + html.print("") + else + html.print("") + end + html.print("") + + -- display any errors + while #cli_err > 0 and cli_err[1]:match("^" .. val .. " ") + do + html.print("") + table.remove(cli_err) end html.print("") @@ -535,6 +761,7 @@ if config == "mesh" then end html.print("
") html.print("") + html.print(" " .. fullnet) - html.print("") + html.print(" ") if val ~= "_add" and is_tunnel_active(fullnet, active_tun) then html.print("") @@ -510,7 +664,9 @@ if config == "mesh" then if val == "_add" then html.print("") + html.print("") + html.print("
Contact Info/Comment (Optional): 0 and cli_err[1]:match("^" .. val .. " ") do - html.print("
" .. err:gsub("^%S+ ", "") .. "
" .. cli_err[1]:gsub("^%S+ ", "") .. "
Allow the following clients to connect to this Wireguard server:

Enabled?ClientKeyClientActive Action
") + html.print("") + html.print("") + html.print("") + html.print(" ") + if val ~= "_add" and is_wgtunnel_active(key, active_wgtun) then + html.print("") + else + html.print("") + end + html.print("") + html.print("") + html.print("
Contact Info/Comment (Optional):
" .. cli_err[1]:gsub("^%S+ ", "") .. "

Tunnel v" .. VPNVER .. "

") hide("") +hide("") -- add hidden forms fields for _, h in ipairs(hidden) diff --git a/files/www/cgi-bin/vpnc b/files/www/cgi-bin/vpnc index 4e38139f..ad58d857 100755 --- a/files/www/cgi-bin/vpnc +++ b/files/www/cgi-bin/vpnc @@ -45,7 +45,7 @@ require("uci") local html = aredn.html -local cursor = uci.cursor(); +local cursor = uci.cursor("/etc/config.mesh"); local node = aredn.info.get_nvram("node") if node == "" then @@ -74,6 +74,9 @@ if os.getenv("REQUEST_METHOD") == "POST" then parms = request:formvalue() end +-- wireguard +local wireguard_alive_time = 300 -- 5 minutes + -- helpers start local hidden = {} @@ -106,6 +109,22 @@ function get_active_tun() return tuns end +function get_active_wgtun() + local tuns = {} + local f = io.popen("/usr/bin/wg show all latest-handshakes") + if f then + for line in f:lines() + do + local k,v = line:match("^%S+%s+(%S+)%s+(%S+)%s*$") + if k then + tuns[k] = tonumber(v) -- time in seconds + end + end + f:close() + end + return tuns +end + function is_tunnel_active(ip, tunnels) for _, aip in ipairs(tunnels) do @@ -116,6 +135,15 @@ function is_tunnel_active(ip, tunnels) return false end +function is_wgtunnel_active(key, wgtunnels) + local key = key:match("^(.*=).*=.*=$") + local v = wgtunnels[key] + if v and v + wireguard_alive_time > os.time() then + return true + end + return false +end + -- helpers end local gci_vars = { "enabled", "host", "passwd", "netip", "contact" } @@ -242,7 +270,11 @@ do err(val .. " this connection must be added or cleared out before saving changes") break end - if passwd:match("[^%w@]") then + if netip:match("/") then + if not passwd:match("^.+=.+=.+=$") then + err("The password is not a wireguard key") + end + elseif passwd:match("[^%w@]") then err("The password cannot contain non-alphanumeric characters (#" .. conn_num .. ")") end if host == "" then @@ -326,23 +358,51 @@ end -- save the connections the uci vtun file if parms.button_save and #conn_err == 0 then cursor:commit("vtun") - write_all("/etc/config.mesh/vtun", read_all("/etc/config/vtun")) - if os.execute("/etc/init.d/olsrd restart > /dev/null 2>&1") ~= 0 then - err2("Problem restarting olsrd") - end - if os.execute("/etc/init.d/vtund restart > /dev/null 2>&1") ~= 0 then - err2("Problem restaring vtund") - end - + os.execute("/usr/local/bin/node-setup -a mesh > /dev/null 2>&1") + os.execute("/etc/init.d/olsrd restart > /dev/null 2>&1") + os.execute("/etc/init.d/vtund restart > /dev/null 2>&1") + os.execute("/etc/init.d/network restart > /dev/null 2>&1") end local active_tun = get_active_tun() +local active_wgtun = get_active_wgtun() -- generate page http_header() -html.header(node .. " setup", true) +html.header(node .. " setup", false) -html.print("
") +html.print([[ + +]]) + +html.print("
") html.alert_banner() html.print("") @@ -440,12 +500,16 @@ if config == "mesh" then html.print("") html.print("") @@ -453,6 +517,8 @@ if config == "mesh" then html.print("") @@ -460,7 +526,7 @@ if config == "mesh" then html.print(" ") if val ~= "_add" then - if is_tunnel_active(netip, active_tun) then + if is_tunnel_active(netip, active_tun) or is_wgtunnel_active(passwd, active_wgtun) then html.print("") else html.print("") @@ -480,7 +546,7 @@ if config == "mesh" then html.print("") html.print("Contact Info/Comment (Optional): ") diff --git a/patches/709-iperf-fw-restart.patch b/patches/709-iperf-fw-restart.patch index 78e711e0..c03bb85d 100644 --- a/patches/709-iperf-fw-restart.patch +++ b/patches/709-iperf-fw-restart.patch @@ -36,11 +36,11 @@ Index: openwrt/feeds/packages/net/iperf3/files/iperf.firewall +++ openwrt/feeds/packages/net/iperf3/files/iperf.firewall @@ -0,0 +1,9 @@ +#!/bin/sh -+nft insert rule ip fw4 input_wifi udp dport 5201 counter accept -+nft insert rule ip fw4 input_wifi tcp dport 5201 counter accept -+nft insert rule ip fw4 input_dtdlink udp dport 5201 counter accept -+nft insert rule ip fw4 input_dtdlink tcp dport 5201 counter accept -+if [ "$MESHFW_TUNNELS_ENABLED" == "1" ]; then -+ nft insert rule ip fw4 input_vpn udp dport 5201 counter accept -+ nft insert rule ip fw4 input_vpn tcp dport 5201 counter accept ++nft insert rule ip fw4 input_wifi udp dport 5201 accept ++nft insert rule ip fw4 input_wifi tcp dport 5201 accept ++nft insert rule ip fw4 input_dtdlink udp dport 5201 accept ++nft insert rule ip fw4 input_dtdlink tcp dport 5201 accept ++if [ "$MESHFW_TUNNELS_ENABLED" == "1" -o "$MESHFW_WG_TUNNELS_ENABLED" == "1" ]; then ++ nft insert rule ip fw4 input_vpn udp dport 5201 accept ++ nft insert rule ip fw4 input_vpn tcp dport 5201 accept +fi