summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2014-10-29 22:40:04 +0100
committerJo-Philipp Wich <jow@openwrt.org>2014-10-29 22:40:04 +0100
commitf77b1111e4e413b383295dc2c4afd95ae4b0b9a5 (patch)
tree5a281252f50e27cfd3bfbb32c2e6c534588bf27c
parent517ba7dadb1a05aa1f0b0950d64b87270cddbbba (diff)
parent8df4e5d2192c1425a69cac0575732a74846a99b4 (diff)
Merge pull request #226 from nmav/openconnect
Openconnect
-rw-r--r--applications/luci-ocserv/Makefile4
-rw-r--r--applications/luci-ocserv/luasrc/controller/ocserv.lua88
-rw-r--r--applications/luci-ocserv/luasrc/model/cbi/ocserv/main.lua148
-rw-r--r--applications/luci-ocserv/luasrc/model/cbi/ocserv/user-config.lua149
-rw-r--r--applications/luci-ocserv/luasrc/model/cbi/ocserv/users.lua85
-rw-r--r--applications/luci-ocserv/luasrc/view/admin_status/index/ocserv.htm1
-rw-r--r--applications/luci-ocserv/luasrc/view/ocserv_status.htm76
-rw-r--r--contrib/package/luci/Makefile6
-rw-r--r--protocols/openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua78
-rw-r--r--protocols/openconnect/luasrc/model/network/proto_openconnect.lua61
10 files changed, 694 insertions, 2 deletions
diff --git a/applications/luci-ocserv/Makefile b/applications/luci-ocserv/Makefile
new file mode 100644
index 000000000..74cd597d6
--- /dev/null
+++ b/applications/luci-ocserv/Makefile
@@ -0,0 +1,4 @@
+PO = ocserv
+
+include ../../build/config.mk
+include ../../build/module.mk
diff --git a/applications/luci-ocserv/luasrc/controller/ocserv.lua b/applications/luci-ocserv/luasrc/controller/ocserv.lua
new file mode 100644
index 000000000..229102da6
--- /dev/null
+++ b/applications/luci-ocserv/luasrc/controller/ocserv.lua
@@ -0,0 +1,88 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2014 Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
+
+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
+
+]]--
+
+module("luci.controller.ocserv", package.seeall)
+
+function index()
+ if not nixio.fs.access("/etc/config/ocserv") then
+ return
+ end
+
+ local page
+
+ page = entry({"admin", "services", "ocserv"}, alias("admin", "services", "ocserv", "main"),
+ _("OpenConnect VPN"))
+ page.dependent = true
+
+ page = entry({"admin", "services", "ocserv", "main"},
+ cbi("ocserv/main"),
+ _("Server Settings"), 200)
+ page.dependent = true
+
+ page = entry({"admin", "services", "ocserv", "users"},
+ cbi("ocserv/users"),
+ _("User Settings"), 300)
+ page.dependent = true
+
+ entry({"admin", "services", "ocserv", "status"},
+ call("ocserv_status")).leaf = true
+
+ entry({"admin", "services", "ocserv", "disconnect"},
+ call("ocserv_disconnect")).leaf = true
+
+end
+
+function ocserv_status()
+ local ipt = io.popen("/usr/bin/occtl show users");
+
+ if ipt then
+
+ local fwd = { }
+ while true do
+
+ local ln = ipt:read("*l")
+ if not ln then break end
+
+ local id, user, group, vpn_ip, ip, device, time, cipher, status =
+ ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+).*")
+ if id then
+ fwd[#fwd+1] = {
+ id = id,
+ user = user,
+ group = group,
+ vpn_ip = vpn_ip,
+ ip = ip,
+ device = device,
+ time = time,
+ cipher = cipher,
+ status = status
+ }
+ end
+ end
+ ipt:close()
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(fwd)
+ end
+end
+
+function ocserv_disconnect(num)
+ local idx = tonumber(num)
+
+ if idx and idx > 0 then
+ luci.sys.call("/usr/bin/occtl disconnect id %d" % idx)
+ luci.http.status(200, "OK")
+
+ return
+ end
+ luci.http.status(400, "Bad request")
+end
diff --git a/applications/luci-ocserv/luasrc/model/cbi/ocserv/main.lua b/applications/luci-ocserv/luasrc/model/cbi/ocserv/main.lua
new file mode 100644
index 000000000..a909649df
--- /dev/null
+++ b/applications/luci-ocserv/luasrc/model/cbi/ocserv/main.lua
@@ -0,0 +1,148 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2014 Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
+
+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
+
+]]--
+
+local fs = require "nixio.fs"
+local has_ipv6 = fs.access("/proc/net/ipv6_route")
+
+m = Map("ocserv", translate("OpenConnect VPN"))
+
+s = m:section(TypedSection, "ocserv", "OpenConnect")
+s.anonymous = true
+
+s:tab("general", translate("General Settings"))
+s:tab("ca", translate("CA certificate"))
+s:tab("template", translate("Edit Template"))
+
+local e = s:taboption("general", Flag, "enable", translate("Enable server"))
+e.rmempty = false
+e.default = "1"
+
+function m.on_commit(map)
+ luci.sys.call("/usr/bin/occtl reload >/dev/null 2>&1")
+end
+
+function e.write(self, section, value)
+ if value == "0" then
+ luci.sys.call("/etc/init.d/ocserv stop >/dev/null 2>&1")
+ luci.sys.call("/etc/init.d/ocserv disable >/dev/null 2>&1")
+ else
+ luci.sys.call("/etc/init.d/ocserv enable >/dev/null 2>&1")
+ luci.sys.call("/etc/init.d/ocserv restart >/dev/null 2>&1")
+ end
+ Flag.write(self, section, value)
+end
+
+local o
+
+o = s:taboption("general", ListValue, "auth", translate("User Authentication"),
+ translate("The authentication method for the users. The simplest is plain with a single username-password pair. Use PAM modules to authenticate using another server (e.g., LDAP, Radius)."))
+o.rmempty = false
+o.default = "plain"
+o:value("plain")
+o:value("PAM")
+
+o = s:taboption("general", Value, "zone", translate("Firewall Zone"),
+ translate("The firewall zone that the VPN clients will be set to"))
+o.nocreate = true
+o.default = "lan"
+o.template = "cbi/firewall_zonelist"
+
+s:taboption("general", Value, "port", translate("Port"),
+ translate("The same UDP and TCP ports will be used"))
+s:taboption("general", Value, "max_clients", translate("Max clients"))
+s:taboption("general", Value, "max_same", translate("Max same clients"))
+s:taboption("general", Value, "dpd", translate("Dead peer detection time (secs)"))
+
+local pip = s:taboption("general", Flag, "predictable_ips", translate("Predictable IPs"),
+ translate("The assigned IPs will be selected deterministically"))
+pip.default = "1"
+
+local udp = s:taboption("general", Flag, "udp", translate("Enable UDP"),
+ translate("Enable UDP channel support; this must be enabled unless you know what you are doing"))
+udp.default = "1"
+
+local cisco = s:taboption("general", Flag, "cisco_compat", translate("AnyConnect client compatibility"),
+ translate("Enable support for CISCO AnyConnect clients"))
+cisco.default = "1"
+
+ipaddr = s:taboption("general", Value, "ipaddr", translate("VPN <abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Network-Address"))
+ipaddr.datatype = "ip4addr"
+ipaddr.default = "192.168.100.1"
+
+nm = s:taboption("general", Value, "netmask", translate("VPN <abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
+nm.datatype = "ip4addr"
+nm.default = "255.255.255.0"
+nm:value("255.255.255.0")
+nm:value("255.255.0.0")
+nm:value("255.0.0.0")
+
+if has_ipv6 then
+ ip6addr = s:taboption("general", Value, "ip6addr", translate("VPN <abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Network-Address"), translate("<abbr title=\"Classless Inter-Domain Routing\">CIDR</abbr>-Notation: address/prefix"))
+ ip6addr.datatype = "ip6addr"
+end
+
+
+tmpl = s:taboption("template", Value, "_tmpl",
+ translate("Edit the template that is used for generating the ocserv configuration."))
+
+tmpl.template = "cbi/tvalue"
+tmpl.rows = 20
+
+function tmpl.cfgvalue(self, section)
+ return nixio.fs.readfile("/etc/ocserv/ocserv.conf.template")
+end
+
+function tmpl.write(self, section, value)
+ value = value:gsub("\r\n?", "\n")
+ nixio.fs.writefile("/etc/ocserv/ocserv.conf.template", value)
+end
+
+ca = s:taboption("ca", Value, "_ca",
+ translate("View the CA certificate used by this server. You will need to save it as 'ca.pem' and import it into the clients."))
+
+ca.template = "cbi/tvalue"
+ca.rows = 20
+
+function ca.cfgvalue(self, section)
+ return nixio.fs.readfile("/etc/ocserv/ca.pem")
+end
+
+--[[DNS]]--
+
+s = m:section(TypedSection, "dns", translate("DNS servers"),
+ translate("The DNS servers to be provided to clients; can be either IPv6 or IPv4"))
+s.anonymous = true
+s.addremove = true
+s.template = "cbi/tblsection"
+
+s:option(Value, "ip", translate("IP Address")).rmempty = true
+s.datatype = "ipaddr"
+
+--[[Routes]]--
+
+s = m:section(TypedSection, "routes", translate("Routing table"),
+ translate("The routing table to be provided to clients; you can mix IPv4 and IPv6 routes, the server will send only the appropriate. Leave empty to set a default route"))
+s.anonymous = true
+s.addremove = true
+s.template = "cbi/tblsection"
+
+s:option(Value, "ip", translate("IP Address")).rmempty = true
+
+o = s:option(Value, "netmask", translate("Netmask (or IPv6-prefix)"))
+o.default = "255.255.255.0"
+o:value("255.255.255.0")
+o:value("255.255.0.0")
+o:value("255.0.0.0")
+
+
+return m
diff --git a/applications/luci-ocserv/luasrc/model/cbi/ocserv/user-config.lua b/applications/luci-ocserv/luasrc/model/cbi/ocserv/user-config.lua
new file mode 100644
index 000000000..3e241cb67
--- /dev/null
+++ b/applications/luci-ocserv/luasrc/model/cbi/ocserv/user-config.lua
@@ -0,0 +1,149 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2014 Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
+
+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
+
+]]--
+
+local fs = require "nixio.fs"
+local has_ipv6 = fs.access("/proc/net/ipv6_route")
+
+m = Map("ocserv", translate("OpenConnect VPN"))
+
+s = m:section(TypedSection, "ocserv", "OpenConnect")
+s.anonymous = true
+
+s:tab("general", translate("General Settings"))
+s:tab("ca", translate("CA certificate"))
+s:tab("template", translate("Edit Template"))
+
+local e = s:taboption("general", Flag, "enable", translate("Enable server"))
+e.rmempty = false
+e.default = "1"
+
+function m.on_commit(map)
+ luci.sys.call("/usr/bin/occtl reload >/dev/null 2>&1")
+end
+
+function e.write(self, section, value)
+ if value == "0" then
+ luci.sys.call("/etc/init.d/ocserv stop >/dev/null 2>&1")
+ luci.sys.call("/etc/init.d/ocserv disable >/dev/null 2>&1")
+ else
+ luci.sys.call("/etc/init.d/ocserv enable >/dev/null 2>&1")
+ luci.sys.call("/etc/init.d/ocserv restart >/dev/null 2>&1")
+ end
+ Flag.write(self, section, value)
+end
+
+local o
+
+o = s:taboption("general", ListValue, "auth", translate("User Authentication"),
+ translate("The authentication method for the users. The simplest is plain with a single username-password pair. Use PAM modules to authenticate using another server (e.g., LDAP, Radius)."))
+o.rmempty = false
+o.default = "plain"
+o:value("plain")
+o:value("PAM")
+
+o = s:taboption("general", Value, "zone", translate("Firewall Zone"),
+ translate("The firewall zone that the VPN clients will be set to"))
+o.nocreate = true
+o.default = "lan"
+o.template = "cbi/firewall_zonelist"
+
+s:taboption("general", Value, "port", translate("Port"),
+ translate("The same UDP and TCP ports will be used"))
+s:taboption("general", Value, "max_clients", translate("Max clients"))
+s:taboption("general", Value, "max_same", translate("Max same clients"))
+s:taboption("general", Value, "dpd", translate("Dead peer detection time (secs)"))
+
+local pip = s:taboption("general", Flag, "predictable_ips", translate("Predictable IPs"),
+ translate("The assigned IPs will be selected deterministically"))
+pip.default = "1"
+
+local udp = s:taboption("general", Flag, "udp", translate("Enable UDP"),
+ translate("Enable UDP channel support; this must be enabled unless you know what you are doing"))
+udp.default = "1"
+
+local cisco = s:taboption("general", Flag, "cisco_compat", translate("AnyConnect client compatibility"),
+ translate("Enable support for CISCO AnyConnect clients"))
+cisco.default = "1"
+
+ipaddr = s:taboption("general", Value, "ipaddr", translate("VPN <abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Network-Address"))
+ipaddr.default = "192.168.100.1"
+ipaddr.datatype = "ip4addr"
+
+nm = s:taboption("general", Value, "netmask", translate("VPN <abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
+nm.default = "255.255.255.0"
+nm.datatype = "ip4addr"
+nm:value("255.255.255.0")
+nm:value("255.255.0.0")
+nm:value("255.0.0.0")
+
+if has_ipv6 then
+ ip6addr = s:taboption("general", Value, "ip6addr", translate("VPN <abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Network-Address"), translate("<abbr title=\"Classless Inter-Domain Routing\">CIDR</abbr>-Notation: address/prefix"))
+end
+
+
+tmpl = s:taboption("template", Value, "_tmpl",
+ translate("Edit the template that is used for generating the ocserv configuration."))
+
+tmpl.template = "cbi/tvalue"
+tmpl.rows = 20
+
+function tmpl.cfgvalue(self, section)
+ return nixio.fs.readfile("/etc/ocserv/ocserv.conf.template")
+end
+
+function tmpl.write(self, section, value)
+ value = value:gsub("\r\n?", "\n")
+ nixio.fs.writefile("/etc/ocserv/ocserv.conf.template", value)
+end
+
+ca = s:taboption("ca", Value, "_ca",
+ translate("View the CA certificate used by this server. You will need to save it as 'ca.pem' and import it into the clients."))
+
+ca.template = "cbi/tvalue"
+ca.rows = 20
+
+function ca.cfgvalue(self, section)
+ return nixio.fs.readfile("/etc/ocserv/ca.pem")
+end
+
+--[[DNS]]--
+
+s = m:section(TypedSection, "dns", translate("DNS servers"),
+ translate("The DNS servers to be provided to clients; can be either IPv6 or IPv4"))
+s.anonymous = true
+s.addremove = true
+s.template = "cbi/tblsection"
+
+s:option(Value, "ip", translate("IP Address")).rmempty = true
+s.datatype = "ipaddr"
+
+--[[Routes]]--
+
+s = m:section(TypedSection, "routes", translate("Routing table"),
+ translate("The routing table to be provided to clients; you can mix IPv4 and IPv6 routes, the server will send only the appropriate. Leave empty to set a default route"))
+s.anonymous = true
+s.addremove = true
+s.template = "cbi/tblsection"
+
+s:option(Value, "ip", translate("IP Address")).rmempty = true
+s.datatype = "ipaddr"
+
+o = s:option(Value, "netmask", translate("Netmask (or IPv6-prefix)"))
+o.default = "255.255.255.0"
+
+o:value("255.255.255.0")
+o:value("255.255.0.0")
+o:value("255.0.0.0")
+
+
+return m
diff --git a/applications/luci-ocserv/luasrc/model/cbi/ocserv/users.lua b/applications/luci-ocserv/luasrc/model/cbi/ocserv/users.lua
new file mode 100644
index 000000000..2f69c014e
--- /dev/null
+++ b/applications/luci-ocserv/luasrc/model/cbi/ocserv/users.lua
@@ -0,0 +1,85 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2014 Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
+
+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
+
+]]--
+
+local dsp = require "luci.dispatcher"
+local nixio = require "nixio"
+
+m = Map("ocserv", translate("OpenConnect VPN"))
+
+if m.uci:get("ocserv", "config", "auth") == "plain" then
+
+--[[Users]]--
+
+function m.on_commit(map)
+ luci.sys.call("/etc/init.d/ocserv restart >/dev/null 2>&1")
+end
+
+s = m:section(TypedSection, "ocservusers", translate("Available users"))
+s.anonymous = true
+s.addremove = true
+s.template = "cbi/tblsection"
+
+s:option(Value, "name", translate("Name")).rmempty = true
+s:option(DummyValue, "group", translate("Group")).rmempty = true
+pwd = s:option(Value, "password", translate("Password"))
+pwd.password = false
+
+function pwd.write(self, section, value)
+ local pass
+ if string.match(value, "^\$%d\$.*") then
+ pass = value
+ else
+ local t = tonumber(nixio.getpid()*os.time())
+ local salt = "$5$" .. t .. "$"
+ pass = nixio.crypt(value, salt)
+ end
+ Value.write(self, section, pass)
+end
+
+--[[if plain]]--
+end
+
+local lusers = { }
+local fd = io.popen("/usr/bin/occtl show users", "r")
+if fd then local ln
+ repeat
+ ln = fd:read("*l")
+ if not ln then break end
+
+ local id, user, group, vpn_ip, ip, device, time, cipher, status =
+ ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+).*")
+ if id then
+ table.insert(lusers, {id, user, group, vpn_ip, ip, device, time, cipher, status})
+ end
+ until not ln
+ fd:close()
+end
+
+
+--[[Active Users]]--
+
+local s = m:section(Table, lusers, translate("Active users"))
+s.anonymous = true
+s.template = "cbi/tblsection"
+
+s:option(DummyValue, 1, translate("ID"))
+s:option(DummyValue, 2, translate("Username"))
+s:option(DummyValue, 3, translate("Group"))
+s:option(DummyValue, 4, translate("IP"))
+s:option(DummyValue, 5, translate("VPN IP"))
+s:option(DummyValue, 6, translate("Device"))
+s:option(DummyValue, 7, translate("Time"))
+s:option(DummyValue, 8, translate("Cipher"))
+s:option(DummyValue, 9, translate("Status"))
+
+return m
diff --git a/applications/luci-ocserv/luasrc/view/admin_status/index/ocserv.htm b/applications/luci-ocserv/luasrc/view/admin_status/index/ocserv.htm
new file mode 100644
index 000000000..457580695
--- /dev/null
+++ b/applications/luci-ocserv/luasrc/view/admin_status/index/ocserv.htm
@@ -0,0 +1 @@
+<%+ocserv_status%>
diff --git a/applications/luci-ocserv/luasrc/view/ocserv_status.htm b/applications/luci-ocserv/luasrc/view/ocserv_status.htm
new file mode 100644
index 000000000..fabc1bca9
--- /dev/null
+++ b/applications/luci-ocserv/luasrc/view/ocserv_status.htm
@@ -0,0 +1,76 @@
+<script type="text/javascript">//<![CDATA[
+
+ function ocserv_disconnect(idx) {
+ XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ocserv", "disconnect")%>/' + idx, null,
+ function(x)
+ {
+ var tb = document.getElementById('ocserv_status_table');
+ if (tb && (idx < tb.rows.length))
+ tb.rows[0].parentNode.removeChild(tb.rows[idx]);
+ }
+ );
+ }
+
+ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "services", "ocserv", "status")%>', null,
+ function(x, st)
+ {
+ var tb = document.getElementById('ocserv_status_table');
+ if (st && tb)
+ {
+ /* clear all rows */
+ while( tb.rows.length > 1 )
+ tb.deleteRow(1);
+
+ for( var i = 0; i < st.length; i++ )
+ {
+ var tr = tb.insertRow(-1);
+ tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
+
+ tr.insertCell(-1).innerHTML = st[i].user;
+ tr.insertCell(-1).innerHTML = st[i].group;
+ tr.insertCell(-1).innerHTML = st[i].vpn_ip;
+ tr.insertCell(-1).innerHTML = st[i].ip;
+ tr.insertCell(-1).innerHTML = st[i].device;
+ tr.insertCell(-1).innerHTML = st[i].time;
+ tr.insertCell(-1).innerHTML = st[i].cipher;
+ tr.insertCell(-1).innerHTML = st[i].status;
+
+ tr.insertCell(-1).innerHTML = String.format(
+ '<input class="cbi-button cbi-input-remove" type="button" value="<%:Disconnect%>" onclick="ocserv_disconnect(%d)" />',
+ st[i].id
+ );
+ }
+
+ if( tb.rows.length == 1 )
+ {
+ var tr = tb.insertRow(-1);
+ tr.className = 'cbi-section-table-row';
+
+ var td = tr.insertCell(-1);
+ td.colSpan = 5;
+ td.innerHTML = '<em><br /><%:There are no active users.%></em>';
+ }
+ }
+ }
+ );
+//]]></script>
+
+<fieldset class="cbi-section">
+ <legend><%:Active OpenConnect Users%></legend>
+ <table class="cbi-section-table" id="ocserv_status_table">
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:User%></th>
+ <th class="cbi-section-table-cell"><%:Group%></th>
+ <th class="cbi-section-table-cell"><%:IP Address%></th>
+ <th class="cbi-section-table-cell"><%:VPN IP Address%></th>
+ <th class="cbi-section-table-cell"><%:Device%></th>
+ <th class="cbi-section-table-cell"><%:Time%></th>
+ <th class="cbi-section-table-cell"><%:Cipher%></th>
+ <th class="cbi-section-table-cell"><%:Status%></th>
+ <th class="cbi-section-table-cell">&#160;</th>
+ </tr>
+ <tr class="cbi-section-table-row">
+ <td colspan="5"><em><br /><%:Collecting data...%></em></td>
+ </tr>
+ </table>
+</fieldset>
diff --git a/contrib/package/luci/Makefile b/contrib/package/luci/Makefile
index 5ee13d4d4..3d2581a83 100644
--- a/contrib/package/luci/Makefile
+++ b/contrib/package/luci/Makefile
@@ -193,7 +193,7 @@ $(eval $(call protocol,ppp,Support for PPP/PPPoE/PPPoA/PPtP))
$(eval $(call protocol,ipv6,Support for DHCPv6/6in4/6to4/6rd/DS-Lite))
$(eval $(call protocol,3g,Support for 3G,+PACKAGE_luci-proto-3g:comgt))
$(eval $(call protocol,relay,Support for relayd pseudo bridges,+PACKAGE_luci-proto-relay:relayd))
-
+$(eval $(call protocol,openconnect,Support for OpenConnect VPN,+openconnect))
### Modules ###
define module
@@ -251,13 +251,15 @@ define application
LUCI_BUILD_PACKAGES += luci-app-$(1)
endef
-
$(eval $(call application,firewall,Firewall and Portforwarding application,\
+PACKAGE_luci-app-firewall:firewall))
$(eval $(call application,qos,Quality of Service configuration module,\
+PACKAGE_luci-app-qos:qos-scripts))
+$(eval $(call application,ocserv,LuCI Support for OpenConnect VPN,\
+ +PACKAGE_luci-app-ocserv:ocserv certtool))
+
$(eval $(call application,commands,LuCI Shell Command Module))
diff --git a/protocols/openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua b/protocols/openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
new file mode 100644
index 000000000..2e2eacee0
--- /dev/null
+++ b/protocols/openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
@@ -0,0 +1,78 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2014 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+
+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
+]]--
+
+local map, section, net = ...
+
+local server, username, password, cert, ca
+local oc_cert_file, oc_key_file, oc_ca_file
+
+local ifc = net:get_interface():name()
+
+oc_cert_file = "/etc/openconnect/user-cert-" .. ifc .. ".pem"
+oc_key_file = "/etc/openconnect/user-key-" .. ifc .. ".pem"
+oc_ca_file = "/etc/openconnect/ca-" .. ifc .. ".pem"
+
+server = section:taboption("general", Value, "server", translate("VPN Server"))
+server.datatype = "host"
+
+port = section:taboption("general", Value, "port", translate("VPN Server port"))
+port.placeholder = "443"
+port.datatype = "port"
+
+section:taboption("general", Value, "serverhash", translate("VPN Server's certificate SHA1 hash"))
+
+section:taboption("general", Value, "authgroup", translate("AuthGroup"))
+
+username = section:taboption("general", Value, "username", translate("Username"))
+password = section:taboption("general", Value, "password", translate("Password"))
+password.password = true
+
+
+cert = section:taboption("advanced", Value, "usercert", translate("User certificate (PEM encoded)"))
+cert.template = "cbi/tvalue"
+cert.rows = 10
+
+function cert.cfgvalue(self, section)
+ return nixio.fs.readfile(oc_cert_file)
+end
+
+function cert.write(self, section, value)
+ value = value:gsub("\r\n?", "\n")
+ nixio.fs.writefile(oc_cert_file, value)
+end
+
+cert = section:taboption("advanced", Value, "userkey", translate("User key (PEM encoded)"))
+cert.template = "cbi/tvalue"
+cert.rows = 10
+
+function cert.cfgvalue(self, section)
+ return nixio.fs.readfile(oc_key_file)
+end
+
+function cert.write(self, section, value)
+ value = value:gsub("\r\n?", "\n")
+ nixio.fs.writefile(oc_key_file, value)
+end
+
+
+ca = section:taboption("advanced", Value, "ca", translate("CA certificate; if empty it will be saved after the first connection."))
+ca.template = "cbi/tvalue"
+ca.rows = 10
+
+function ca.cfgvalue(self, section)
+ return nixio.fs.readfile(oc_ca_file)
+end
+
+function ca.write(self, section, value)
+ value = value:gsub("\r\n?", "\n")
+ nixio.fs.writefile(oc_ca_file, value)
+end
diff --git a/protocols/openconnect/luasrc/model/network/proto_openconnect.lua b/protocols/openconnect/luasrc/model/network/proto_openconnect.lua
new file mode 100644
index 000000000..26744cde8
--- /dev/null
+++ b/protocols/openconnect/luasrc/model/network/proto_openconnect.lua
@@ -0,0 +1,61 @@
+--[[
+LuCI - Network model - openconnect protocol extension
+
+Copyright 2012 David Woodhouse
+
+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
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+]]--
+
+local netmod = luci.model.network
+local interface = luci.model.network.interface
+local proto = netmod:register_protocol("openconnect")
+
+function proto.get_i18n(self)
+ return luci.i18n.translate("OpenConnect (CISCO AnyConnect)")
+end
+
+function proto.ifname(self)
+ return "vpn-" .. self.sid
+end
+
+function proto.get_interface(self)
+ return interface(self:ifname(), self)
+end
+
+function proto.opkg_package(self)
+ return "openconnect"
+end
+
+function proto.is_installed(self)
+ return nixio.fs.access("/lib/netifd/proto/openconnect.sh")
+end
+
+function proto.is_floating(self)
+ return true
+end
+
+function proto.is_virtual(self)
+ return true
+end
+
+function proto.get_interfaces(self)
+ return nil
+end
+
+function proto.contains_interface(self, ifc)
+ return (netmod:ifnameof(ifc) == self:ifname())
+
+end
+
+netmod:register_pattern_virtual("^vpn-%w")