diff --git a/package/gluon-p2p-vpn-fastd/Makefile b/package/gluon-p2p-vpn-fastd/Makefile new file mode 100644 index 00000000..e7a70ecb --- /dev/null +++ b/package/gluon-p2p-vpn-fastd/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-p2p-vpn-fastd +PKG_VERSION:=3 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-p2p-vpn-fastd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Support for connecting batman-adv meshes via p2p fastd + DEPENDS:=+gluon-core +gluon-mesh-vpn-fastd +endef + +define Package/gluon-p2p-vpn-fastd/description + Gluon community wifi mesh firmware framework: fastd support for p2p connections +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-p2p-vpn-fastd/install + $(CP) ./files/* $(1)/ +endef + +define Package/gluon-p2p-vpn-fastd/postinst +#!/bin/sh +$(call GluonCheckSite,check_site.lua) +endef + +$(eval $(call BuildPackage,gluon-p2p-vpn-fastd)) diff --git a/package/gluon-p2p-vpn-fastd/check_site.lua b/package/gluon-p2p-vpn-fastd/check_site.lua new file mode 100644 index 00000000..7a2c4913 --- /dev/null +++ b/package/gluon-p2p-vpn-fastd/check_site.lua @@ -0,0 +1,26 @@ +need_string_array('fastd_mesh_vpn.methods') +need_number('fastd_mesh_vpn.mtu') +need_boolean('fastd_mesh_vpn.enabled', false) +need_boolean('fastd_mesh_vpn.configurable', false) + + +local function check_peer(prefix) + return function(k, _) + local table = string.format('%s[%q].', prefix, k) + + need_string(table .. 'key') + need_string_array(table .. 'remotes') + end +end + +local function check_group(prefix) + return function(k, _) + local table = string.format('%s[%q].', prefix, k) + + need_number(table .. 'limit', false) + need_table(table .. 'peers', check_peer(table .. 'peers'), false) + need_table(table .. 'groups', check_group(table .. 'groups'), false) + end +end + +need_table('fastd_mesh_vpn.groups', check_group('fastd_mesh_vpn.groups')) diff --git a/package/gluon-p2p-vpn-fastd/files/lib/gluon/upgrade/420-p2p-vpn-fastd-add-group b/package/gluon-p2p-vpn-fastd/files/lib/gluon/upgrade/420-p2p-vpn-fastd-add-group new file mode 100644 index 00000000..cc884a4c --- /dev/null +++ b/package/gluon-p2p-vpn-fastd/files/lib/gluon/upgrade/420-p2p-vpn-fastd-add-group @@ -0,0 +1,18 @@ +#!/usr/bin/lua + +local uci = require('luci.model.uci').cursor() + +local e = uci:get('fastd', 'mesh_vpn', 'enabled') +if not e then + e = '0' +end + +uci:section('fastd', 'peer_group', 'p2p_vpn', + { + enabled = e, + net = 'mesh_vpn', + } +) + +uci:save('fastd') +uci:commit('fastd') diff --git a/package/gluon-p2p-vpn-fastd/files/usr/lib/lua/luci/controller/admin/p2pvpn.lua b/package/gluon-p2p-vpn-fastd/files/usr/lib/lua/luci/controller/admin/p2pvpn.lua new file mode 100644 index 00000000..dfedec2b --- /dev/null +++ b/package/gluon-p2p-vpn-fastd/files/usr/lib/lua/luci/controller/admin/p2pvpn.lua @@ -0,0 +1,19 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2013 Nils Schneider + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.p2pvpn", package.seeall) + +function index() + entry({"admin", "p2pvpn"}, cbi("admin/p2pvpn"), _("P2P VPN"), 80) +end diff --git a/package/gluon-p2p-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/p2pvpn.lua b/package/gluon-p2p-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/p2pvpn.lua new file mode 100644 index 00000000..0439dab1 --- /dev/null +++ b/package/gluon-p2p-vpn-fastd/files/usr/lib/lua/luci/model/cbi/admin/p2pvpn.lua @@ -0,0 +1,128 @@ +local f, s, o +local uci = luci.model.uci.cursor() +local config = 'fastd' +local groupname = 'p2p_vpn' +local vpnname = 'mesh_vpn' + +function splitRemoteEntry(p) + local host, port, x + + p = p:gsub("["..'"'.."]", '') + + x = p:find(" ") or (#p + 1) + host = p:sub(1, x-1) + + p = p:sub(x+1) + x = p:find(" ") or (#p + 1) + port = p:sub(x+1) + + return host, port +end + +function splitPeerString(p) + local host, port, key, x + + x = p:find(':') or (#p + 1) + host = p:sub(1,x-1) + + p = p:sub(x+1) + x = p:find('/') or (#p + 1) + port = p:sub(1,x-1) + key = p:sub(x+1) + + return host, port, key +end + +function getPeerStrings() + peers = {} + + uci:foreach('fastd', 'peer', + function(s) + if s['group'] == groupname then + local host, port = splitRemoteEntry(table.concat(s['remote'])) + peers[#peers+1] = host .. ':' .. port .. '/' .. s['key'] + end + end + ) + + return peers +end + + +f = SimpleForm(groupname, translate("Peer-to-peer Mesh VPN")) +f.template = "admin/expertmode" + +s = f:section(SimpleSection, nil, translate( + 'Your node can additionally connect to other nodes in a Peer-to-peer fashion.' +)) + +o = s:option(Flag, "enabled", translate("Enabled")) +o.default = uci:get_bool(config, groupname, "enabled") and o.enabled or o.disabled +o.rmempty = false + +o = s:option(DynamicList, "hostname", translate("Remote"), translate("Format") ..": HOSTNAME:PORT/KEY") +o:write(nil, getPeerStrings()) +o:depends("enabled", '1') + + +s = f:section(SimpleSection, nil, translate( + 'One of the participating nodes of a P2P connection has to be configured with a fixed fastd port.' + ..'This port then has to be forwarded in the local home router which the node is using for Mesh VPN.' +)) +o:depends("enabled", '1') + +o = s:option(Flag, "fixedport", translate("Fixed VPN Port")) +o.default = (uci:get(config, vpnname, "bind")) and o.enabled or o.disabled +o.rmempty = false + +p = uci:get(config, vpnname, "bind") +x = p:find(":") or (#p + 1) + +o = s:option(Value, "localport", translate("Port")) +o:write('', p:sub(x+1)) +o:depends("fixedport", '1') + + +function f.handle(self, state, data) + if state == FORM_VALID then + -- delete all existin p2p peers + uci:foreach('fastd', 'peer', + function(s) + if s['group'] == groupname then + uci:delete(config, s['.name']) + end + end + ) + + -- iterate over dynamic list if enabled + if data.enabled == '1' and #data.hostname > 0 then + for v,peer in pairs(data.hostname) do + -- TODO: add sanity checks + local host, port, key = splitPeerString(peer) + + -- hostname is cleaned to be valid as a section name + uci:section(config, 'peer', groupname .. '_' .. host:gsub('%W',''), + { + net = vpnname, + key = key, + group = groupname, + remote = { '"'..host..'"'..' port '..port }, + enabled = 1, + } + ) + end + end + + if data.fixedport == '1' and #data.localport > 0 then + -- TODO: add sanity checks + uci:set(config, vpnname, 'bind', 'any:'..data.localport) + else + uci:delete(config, vpnname, 'bind') + end + + uci:save("fastd") + uci:commit("fastd") + end +end + +return f