Added luci configuration for ocserv

Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
This commit is contained in:
Nikos Mavrogiannopoulos 2014-10-11 23:10:15 +02:00
parent da022f9157
commit a531a7d16e
8 changed files with 554 additions and 2 deletions

View file

@ -0,0 +1,4 @@
PO = ocserv
include ../../build/config.mk
include ../../build/module.mk

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
<%+ocserv_status%>

View file

@ -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>

View file

@ -194,7 +194,6 @@ $(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,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,relay,Support for relayd pseudo bridges,+PACKAGE_luci-proto-relay:relayd))
### Modules ### ### Modules ###
define module define module
define Package/luci-mod-$(1) define Package/luci-mod-$(1)
@ -251,13 +250,15 @@ define application
LUCI_BUILD_PACKAGES += luci-app-$(1) LUCI_BUILD_PACKAGES += luci-app-$(1)
endef endef
$(eval $(call application,firewall,Firewall and Portforwarding application,\ $(eval $(call application,firewall,Firewall and Portforwarding application,\
+PACKAGE_luci-app-firewall:firewall)) +PACKAGE_luci-app-firewall:firewall))
$(eval $(call application,qos,Quality of Service configuration module,\ $(eval $(call application,qos,Quality of Service configuration module,\
+PACKAGE_luci-app-qos:qos-scripts)) +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)) $(eval $(call application,commands,LuCI Shell Command Module))