diff --git a/glorytun-udp/Makefile b/glorytun-udp/Makefile new file mode 100644 index 000000000..de0ec258e --- /dev/null +++ b/glorytun-udp/Makefile @@ -0,0 +1,44 @@ +# +# Copyright (C) 2015 OVH +# Copyright (C) 2017 Ycarus (Yannick Chabanois) +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=glorytun-udp +PKG_VERSION:=0.0.93-mud +PKG_RELEASE:=1 +PKG_SOURCE:=glorytun-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://github.com/angt/glorytun/releases/download/v$(PKG_VERSION) +PKG_BUILD_DIR:=$(BUILD_DIR)/glorytun-$(PKG_VERSION) +PKG_HASH:=76849b1568119cf0834749db56d4882966863d31351c21c1b22f373f0c97a498 +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) +SECTION:=net +CATEGORY:=Network +DEPENDS:=+kmod-tun +libsodium +librt +TITLE:=Glorytun +URL:=https://github.com/angt/glorytun +SUBMENU:=VPN +endef + +TARGET_CFLAGS += -std=c99 -D_GNU_SOURCE + +define Package/$(PKG_NAME)/conffiles +/etc/config/glorytun +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/glorytun $(1)/usr/sbin/$(PKG_NAME) + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) init $(1)/etc/init.d/$(PKG_NAME) + $(INSTALL_DIR) $(1)/etc/config + touch $(1)/etc/config/glorytun +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/glorytun-udp/init b/glorytun-udp/init new file mode 100755 index 000000000..470a2e3c7 --- /dev/null +++ b/glorytun-udp/init @@ -0,0 +1,86 @@ +#!/bin/sh /etc/rc.common +# vim: set noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 : +# Copyright (C) 2015 ovh.com +# Copyright (C) 2017 Ycarus (Yannick Chabanois) + +START=90 +STOP=10 + +USE_PROCD=1 +PROG_NAME=glorytun-udp +PROG=/usr/sbin/${PROG_NAME} + +_log() { + logger -p daemon.info -t ${PROG_NAME} "$@" +} + +_err() { + logger -p daemon.err -t ${PROG_NAME} "$@" +} + +validate_section() { + uci_validate_section glorytun glorytun "${1}" \ + 'enable:bool:0' \ + 'mptcp:bool:0' \ + 'key:string' \ + 'host:host' \ + 'port:port' \ + 'proto:string' \ + 'bind:string' \ + 'bindport:port' \ + 'mtu:uinteger:1500' \ + 'mtuauto:bool:0' \ + 'dev:string' +} + +start_instance() { + local enable key host port dev listener mptcp proto bind bindport mtu mtuauto + + validate_section "${1}" || { + _err "validation failed" + return 1 + } + + [ "${enable}" = "1" ] || return 1 + [ "${proto}" = "udp" ] || return 1 + + [ -n "${key}" ] || return 1 + [ -n "${port}" ] || return 1 + [ -n "${dev}" ] || return 1 + + echo "${key}" > /tmp/${PROG_NAME}-${1}.key + key="" + + _log "starting ${PROG_NAME} ${1} instance $*" + + procd_open_instance + + procd_set_param command ${PROG} \ + keyfile /tmp/${PROG_NAME}-${1}.key \ + ${port:+port "$port"} \ + ${host:+host "$host"} \ + ${bind:+bind} + ${bindport:+bind-port} + ${mptcp:+mptcp} \ + ${dev:+dev "$dev"} \ + ${mtu:+mtu "$mtu"} \ + ${mtuauto:+mtu-auto} \ + v4only + + procd_set_param respawn 0 30 0 + procd_set_param file /tmp/${PROG_NAME}-${1}.key + + procd_set_param stdout 1 + procd_set_param stderr 1 + + procd_close_instance +} + +start_service() { + config_load glorytun + config_foreach start_instance glorytun +} + +service_triggers() { + procd_add_reload_trigger glorytun network +} diff --git a/glorytun/Makefile b/glorytun/Makefile new file mode 100644 index 000000000..872df496a --- /dev/null +++ b/glorytun/Makefile @@ -0,0 +1,44 @@ +# +# Copyright (C) 2015 OVH +# Copyright (C) 2017 Ycarus (Yannick Chabanois) +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=glorytun +PKG_VERSION:=0.0.35 +PKG_RELEASE:=5 +PKG_SOURCE:=glorytun-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://github.com/angt/glorytun/releases/download/v$(PKG_VERSION) +PKG_HASH:=49e4d8ea4ff2990300b37947b0bd0da3c8e0985bc6eddf29f4146306188fff64 + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) +SECTION:=net +CATEGORY:=Network +DEPENDS:=+kmod-tun +libsodium +librt +TITLE:=Glorytun +URL:=https://github.com/angt/glorytun +SUBMENU:=VPN +endef + +TARGET_CFLAGS += -std=c99 -D_GNU_SOURCE + +define Package/$(PKG_NAME)/conffiles +/etc/config/glorytun +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/glorytun $(1)/usr/sbin/$(PKG_NAME) + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) init $(1)/etc/init.d/$(PKG_NAME) + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DATA) glorytun.config $(1)/etc/config/glorytun +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/glorytun/glorytun.config b/glorytun/glorytun.config new file mode 100644 index 000000000..eb026aaac --- /dev/null +++ b/glorytun/glorytun.config @@ -0,0 +1,8 @@ +config glorytun 'vpn' + option enable '0' + option host '127.0.0.1' + option port '65001' + option dev 'tun0' + option key 'secretkey' + option mptcp '1' + option proto 'tcp' diff --git a/glorytun/init b/glorytun/init new file mode 100755 index 000000000..2f2103841 --- /dev/null +++ b/glorytun/init @@ -0,0 +1,81 @@ +#!/bin/sh /etc/rc.common +# vim: set noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 : +# Copyright (C) 2015 ovh.com +# Copyright (C) 2017 Ycarus (Yannick Chabanois) + +START=90 +STOP=10 + +USE_PROCD=1 +PROG_NAME=glorytun +PROG=/usr/sbin/${PROG_NAME} + +_log() { + logger -p daemon.info -t ${PROG_NAME} "$@" +} + +_err() { + logger -p daemon.err -t ${PROG_NAME} "$@" +} + +validate_section() { + uci_validate_section glorytun glorytun "${1}" \ + 'enable:bool:0' \ + 'mptcp:bool:0' \ + 'listener:bool:0' \ + 'key:string' \ + 'host:host' \ + 'port:port' \ + 'dev:string' \ + 'proto:string' +} + +start_instance() { + local enable key host port dev listener mptcp proto + + validate_section "${1}" || { + _err "validation failed" + return 1 + } + + [ "${enable}" = "1" ] || return 1 + [ "${proto}" = "tcp" ] || return 1 + [ -n "${key}" ] || return 1 + [ -n "${port}" ] || return 1 + [ -n "${dev}" ] || return 1 + + echo "${key}" > /tmp/${PROG_NAME}-${1}.key + key="" + + _log "starting ${PROG_NAME} ${1} instance $*" + + procd_open_instance + + procd_set_param command ${PROG} \ + keyfile /tmp/${PROG_NAME}-${1}.key \ + ${port:+port "$port"} \ + ${host:+host "$host"} \ + ${listener:+listener} + ${mptcp:+mptcp} \ + ${dev:+dev "$dev"} \ + retry count -1 const 5000000 \ + timeout 5000 \ + keepalive count 3 idle 10 interval 1 + + procd_set_param respawn 0 30 0 + procd_set_param file /tmp/${PROG_NAME}-${1}.key + + procd_set_param stdout 1 + procd_set_param stderr 1 + + procd_close_instance +} + +start_service() { + config_load glorytun + config_foreach start_instance glorytun +} + +service_triggers() { + procd_add_reload_trigger glorytun network +} diff --git a/luci-app-glorytun/Makefile b/luci-app-glorytun/Makefile new file mode 100644 index 000000000..1e0c08402 --- /dev/null +++ b/luci-app-glorytun/Makefile @@ -0,0 +1,20 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# Copyright (C) 2017 Ycarus (Yannick Chabanois) +# +# This is based on OpenVPN LuCI Support. +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI Support for Glorytun +LUCI_DEPENDS:=+glorytun +glorytun-udp +LUCI_PKGARCH:=all +PKG_LICENSE:=GPLv2 + +PKG_MAINTAINER:=Ycarus (Yannick Chabanois) + +include ../luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-glorytun/luasrc/controller/glorytun.lua b/luci-app-glorytun/luasrc/controller/glorytun.lua new file mode 100644 index 000000000..3275211ec --- /dev/null +++ b/luci-app-glorytun/luasrc/controller/glorytun.lua @@ -0,0 +1,12 @@ +-- Copyright 2017 Ycarus (Yannick Chabanois) +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.glorytun", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/glorytun") then + return + end + entry({"admin", "services", "glorytun"}, cbi("glorytun"), _("Glorytun") ) + entry({"admin", "services", "glorytun", "settings"}, cbi("glorytun-settings"), nil ).leaf = true +end diff --git a/luci-app-glorytun/luasrc/model/cbi/glorytun-settings.lua b/luci-app-glorytun/luasrc/model/cbi/glorytun-settings.lua new file mode 100644 index 000000000..5b07d03e9 --- /dev/null +++ b/luci-app-glorytun/luasrc/model/cbi/glorytun-settings.lua @@ -0,0 +1,80 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +require("luci.ip") +require("luci.model.uci") + + +local basicParams = { + -- + -- Widget, Name, Default(s), Description + -- + + { Value,"port",65001, translate("TCP port # for both local and remote") }, + { Value,"dev","tun0", translate("Interface name") }, + { Value,"host","vpnserver.example.org", translate("Remote host name or ip address") }, + { Value,"localip","192.168.99.2", translate("Local tunnel ip address") }, + { Value,"remoteip","192.168.99.1", translate("Remote tunnel ip address") }, + { Value,"key","secretkey", translate("The secret key") }, + { ListValue,"proto",{ "TCP", "UDP" }, translate("Protocol") }, + { Flag,"listener",0, translate("Server mode") }, + + { Value,"bind","", translate("Bind address") }, + --{ Value,"bind-backup","", translate("Bind backup") }, + { Value,"bindport",65002, translate("Bind port") }, + { Value,"mtu",1500, translate("MTU") }, + { Flag,"mtuauto",0, translate("MTU auto") }, + + { Flag,"mptcp",0, translate("MPTCP") } +} + + +local m = Map("glorytun") +local p = m:section( SimpleSection ) + +p.template = "glorytun/pageswitch" +p.mode = "settings" +p.instance = arg[1] + + +local s = m:section( NamedSection, arg[1], "glorytun" ) + +for _, option in ipairs(basicParams) do + local o = s:option( + option[1], option[2], + option[2], option[4] + ) + + o.optional = true + + if option[1] == DummyValue then + o.value = option[3] + else + if option[1] == DynamicList then + function o.cfgvalue(...) + local val = AbstractValue.cfgvalue(...) + return ( val and type(val) ~= "table" ) and { val } or val + end + end + + if type(option[3]) == "table" then + if o.optional then o:value("", "-- remove --") end + for _, v in ipairs(option[3]) do + v = tostring(v) + o:value(v) + end + o.default = tostring(option[3][1]) + else + o.default = tostring(option[3]) + end + end + + for i=5,#option do + if type(option[i]) == "table" then + o:depends(option[i]) + end + end +end + +return m + diff --git a/luci-app-glorytun/luasrc/model/cbi/glorytun.lua b/luci-app-glorytun/luasrc/model/cbi/glorytun.lua new file mode 100644 index 000000000..4055b5cc7 --- /dev/null +++ b/luci-app-glorytun/luasrc/model/cbi/glorytun.lua @@ -0,0 +1,139 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local sys = require "luci.sys" +local uci = require "luci.model.uci".cursor() +local testfullps = luci.sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have +local psstring = (string.len(testfullps)>0) and "ps w" or "ps axfw" --set command we use to get pid + +local m = Map("glorytun", translate("Glorytun")) +local s = m:section( TypedSection, "glorytun", translate("Glorytun instances"), translate("Below is a list of configured Glorytun instances and their current state") ) +s.template = "cbi/tblsection" +s.template_addremove = "glorytun/cbi-select-input-add" +s.addremove = true +s.add_select_options = { } +s.extedit = luci.dispatcher.build_url( + "admin", "services", "glorytun", "settings", "%s" +) + +uci:load("glorytun_recipes") +uci:foreach( "glorytun_recipes", "glorytun_recipe", + function(section) + s.add_select_options[section['.name']] = + section['_description'] or section['.name'] + end +) + +function s.getPID(section) -- Universal function which returns valid pid # or nil + local pid = sys.exec("%s | grep -w %s | grep glorytun | grep -v grep | awk '{print $1}'" % { psstring,section} ) + if pid and #pid > 0 and tonumber(pid) ~= nil then + return tonumber(pid) + else + return nil + end +end + +function s.parse(self, section) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + + if recipe and not s.add_select_options[recipe] then + self.invalid_cts = true + else + TypedSection.parse( self, section ) + end +end + +function s.create(self, name) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + name = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".text" + ) + if string.len(name)>3 and not name:match("[^a-zA-Z0-9_]") then + uci:section( + "glorytun", "glorytun", name, + uci:get_all( "glorytun_recipes", recipe ) + ) + + uci:delete("glorytun", name, "_role") + uci:delete("glorytun", name, "_description") + uci:save("glorytun") + + luci.http.redirect( self.extedit:format(name) ) + else + self.invalid_cts = true + end +end + + +s:option( Flag, "enable", translate("Enabled") ) + +local active = s:option( DummyValue, "_active", translate("Started") ) +function active.cfgvalue(self, section) + local pid = s.getPID(section) + if pid ~= nil then + return (sys.process.signal(pid, 0)) + and translatef("yes (%i)", pid) + or translate("no") + end + return translate("no") +end + +local updown = s:option( Button, "_updown", translate("Start/Stop") ) +updown._state = false +updown.redirect = luci.dispatcher.build_url( + "admin", "services", "glorytun" +) +function updown.cbid(self, section) + local pid = s.getPID(section) + self._state = pid ~= nil and sys.process.signal(pid, 0) + self.option = self._state and "stop" or "start" + return AbstractValue.cbid(self, section) +end +function updown.cfgvalue(self, section) + self.title = self._state and "stop" or "start" + self.inputstyle = self._state and "reset" or "reload" +end + +local port = s:option( DummyValue, "port", translate("Port") ) +function port.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + return val or "65001" +end +local dev = s:option( DummyValue, "dev", translate("Interface") ) +function dev.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + return val or "tun" +end +local proto = s:option( DummyValue, "proto", translate("Protocol") ) +function proto.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + return val or "tcp" +end + +function updown.write(self, section, value) + if self.option == "stop" then + local pid = s.getPID(section) + if pid ~= nil then + sys.process.signal(pid,15) + end + else + local type = proto.cfgvalue(self,section) + if type == 'udp' then + luci.sys.call("/etc/init.d/glorytun-udp start %s" % section) + else + luci.sys.call("/etc/init.d/glorytun start %s" % section) + end + end + luci.http.redirect( self.redirect ) +end + + +return m diff --git a/luci-app-glorytun/luasrc/view/glorytun/cbi-select-input-add.htm b/luci-app-glorytun/luasrc/view/glorytun/cbi-select-input-add.htm new file mode 100644 index 000000000..0166de778 --- /dev/null +++ b/luci-app-glorytun/luasrc/view/glorytun/cbi-select-input-add.htm @@ -0,0 +1,11 @@ +
+ <% if self.invalid_cts then -%>
<% end %> + + + + <% if self.invalid_cts then %>
<%:Invalid%>
<% end %> +
diff --git a/luci-app-glorytun/luasrc/view/glorytun/pageswitch.htm b/luci-app-glorytun/luasrc/view/glorytun/pageswitch.htm new file mode 100644 index 000000000..b27bff6f5 --- /dev/null +++ b/luci-app-glorytun/luasrc/view/glorytun/pageswitch.htm @@ -0,0 +1,12 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +
+ + <%:Overview%> » + <%=luci.i18n.translatef("Instance \"%s\"", self.instance)%> + +
diff --git a/luci-app-glorytun/po/templates/glorytun.pot b/luci-app-glorytun/po/templates/glorytun.pot new file mode 100644 index 000000000..095808f7e --- /dev/null +++ b/luci-app-glorytun/po/templates/glorytun.pot @@ -0,0 +1,87 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Add" +msgstr "" + +msgid "" +"Below is a list of configured Glorytun instances and their current state" +msgstr "" + +msgid "Bind address" +msgstr "" + +msgid "Bind backup" +msgstr "" + +msgid "Bind port" +msgstr "" + +msgid "Enabled" +msgstr "" + +msgid "Glorytun" +msgstr "" + +msgid "Glorytun instances" +msgstr "" + +msgid "Instance \"%s\"" +msgstr "" + +msgid "Interface" +msgstr "" + +msgid "Interface name" +msgstr "" + +msgid "Invalid" +msgstr "" + +msgid "Local tunnel ip address" +msgstr "" + +msgid "MPTCP" +msgstr "" + +msgid "MTU" +msgstr "" + +msgid "MTU auto" +msgstr "" + +msgid "Overview" +msgstr "" + +msgid "Port" +msgstr "" + +msgid "Protocol" +msgstr "" + +msgid "Remote host name or ip address" +msgstr "" + +msgid "Remote tunnel ip address" +msgstr "" + +msgid "Server mode" +msgstr "" + +msgid "Start/Stop" +msgstr "" + +msgid "Started" +msgstr "" + +msgid "TCP port # for both local and remote" +msgstr "" + +msgid "The secret key" +msgstr "" + +msgid "no" +msgstr "" + +msgid "yes (%i)" +msgstr "" diff --git a/luci-app-glorytun/root/etc/config/glorytun_recipes b/luci-app-glorytun/root/etc/config/glorytun_recipes new file mode 100644 index 000000000..919acc2a8 --- /dev/null +++ b/luci-app-glorytun/root/etc/config/glorytun_recipes @@ -0,0 +1,45 @@ +config glorytun_recipe servertcp + option _description "Simple TCP server configuration" + option _role "server" + option port "65001" + option dev "tun0" + option key "secretkey" + option listener "1" + option localip "192.168.99.1" + option remoteip "192.168.99.2" + option proto "tcp" + +config glorytun_recipe clienttcp + option _description "Simple TCP client configuration" + option _role "client" + option port "65001" + option dev "tun0" + option host "vpnserver.example.org" + option key "secretkey" + option localip "192.168.99.2" + option remoteip "192.168.99.1" + option proto "tcp" + +config glorytun_recipe serverudp + option _description "Simple UDP server configuration" + option _role "server" + option dev "tun0" + option bindport "65003" + option bindt "192.168.99.1" + option key "secretkey" + option localip "192.168.99.1" + option remoteip "192.168.99.2" + option proto "udp" + option mtuauto "1" + +config glorytun_recipe clientudp + option _description "Simple UDP client configuration" + option _role "client" + option port "65003" + option dev "tun0" + option host "vpnserver.example.org" + option key "secretkey" + option localip "192.168.99.2" + option remoteip "192.168.99.1" + option proto "udp" + option mtuauto "1" diff --git a/luci-app-glorytun/root/etc/hotplug.d/iface/30-glorytun b/luci-app-glorytun/root/etc/hotplug.d/iface/30-glorytun new file mode 100644 index 000000000..5210639a5 --- /dev/null +++ b/luci-app-glorytun/root/etc/hotplug.d/iface/30-glorytun @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Load the glorytun config +# +# Author: Ycarus (Yannick Chabanois) +# Released under GPL 3 or later + +[ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0 + +. /lib/functions.sh +. /lib/functions/network.sh + +set_default() { + local localip + local remoteip + local config="$1" + local iface + config_get iface "$config" dev + [ "$iface" = "$DEVICE" ] && { + config_get localip "$config" localip + config_get remoteip "$config" remoteip + [ "$remoteip" != "" ] && [ "$localip" != "" ] && ip addr add $localip peer $remoteip dev $DEVICE + } +} + +config_load glorytun +config_foreach set_default glorytun diff --git a/luci-app-glorytun/root/etc/uci-defaults/40_luci-glorytun b/luci-app-glorytun/root/etc/uci-defaults/40_luci-glorytun new file mode 100644 index 000000000..310d95971 --- /dev/null +++ b/luci-app-glorytun/root/etc/uci-defaults/40_luci-glorytun @@ -0,0 +1,31 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@glorytun[-1] + add ucitrack glorytun + set ucitrack.@glorytun[-1].init=glorytun + delete ucitrack.@glorytun-udp[-1] + add ucitrack glorytun-udp + set ucitrack.@glorytun-udp[-1].init=glorytun-udp + commit ucitrack +EOF + +uci -q batch <<-EOF >/dev/null + delete network.glorytun=interface + set network.glorytun=interface + set network.glorytun.ifname=tun0 + set network.glorytun.proto=none + set network.glorytun.ip4table=vpn + set network.glorytun.multipath=off + set network.glorytun.defaultroute=0 + commit network +EOF +uci -q batch <<-EOF >/dev/null + add firewall zone + set firewall.@zone[-1].name=vpn + set firewall.@zone[-1].network='vpn' + commit firewall +EOF + +rm -f /tmp/luci-indexcache +exit 0