1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
'use strict';
'require form';
'require fs';
'require rpc';
/* OpenConnect VPN JavaScript for LuCI
Converted from Lua to JavaScript by @systemcrash
Copyright 2014 Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
Licensed to the public under the Apache License 2.0.
*/
const callRcInit = rpc.declare({
object: 'rc',
method: 'init',
params: [ 'name', 'action' ],
});
return L.view.extend({
load() {
return Promise.all([
L.resolveDefault(fs.read('/proc/net/ipv6_route'), null),
L.resolveDefault(fs.exec('/usr/bin/certtool', ['--hash', 'sha256', '--key-id', '--infile', '/etc/ocserv/server-cert.pem']).then(res => res.stdout), null),
L.resolveDefault(fs.read('/etc/ocserv/ca.pem'), ''),
]);
},
render([has_ipv6, pki_hash, ca_content]) {
pki_hash = pki_hash ? 'sha256:' + pki_hash.trim() : '';
const m = new form.Map('ocserv', _('OpenConnect VPN'));
const s = m.section(form.TypedSection, 'ocserv', 'OpenConnect');
s.anonymous = true;
s.addremove = false;
s.tab('general', _('General Settings'));
s.tab('ca', _('CA certificate'));
s.tab('template', _('Edit Template'));
// Enable flag
let o = s.taboption('general', form.Flag, 'enable', _('Enable server'));
o.rmempty = false;
o.default = '1';
// Server's Public Key ID (read-only display)
o = s.taboption('general', form.DummyValue, '_pkid', _("Server's Public Key ID"),
_("The value to be communicated to the client to verify the server's certificate; this value only depends on the public key"));
o.cfgvalue = function(section_id) {
return pki_hash || _('Not available');
};
// Authentication
o = s.taboption('general', form.ListValue, 'auth', _('User Authentication'),
_('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', 'plain');
o.value('PAM', 'PAM');
// Port
o = s.taboption('general', form.Value, 'port', _('Port'),
_('The same UDP and TCP ports will be used'));
o.datatype = 'port';
// Max clients
o = s.taboption('general', form.Value, 'max_clients', _('Max clients'));
o.datatype = 'uinteger';
// Max same clients
o = s.taboption('general', form.Value, 'max_same', _('Max same clients'));
o.datatype = 'uinteger';
// DPD
o = s.taboption('general', form.Value, 'dpd', _('Dead peer detection time (secs)'));
o.datatype = 'uinteger';
// Predictable IPs
o = s.taboption('general', form.Flag, 'predictable_ips', _('Predictable IPs'),
_('The assigned IPs will be selected deterministically'));
o.default = '1';
// Compression
o = s.taboption('general', form.Flag, 'compression', _('Enable compression'),
_('Enable compression'));
o.default = '0';
// UDP
o = s.taboption('general', form.Flag, 'udp', _('Enable UDP'),
_('Enable UDP channel support; this must be enabled unless you know what you are doing'));
o.default = '1';
// Cisco compatibility
o = s.taboption('general', form.Flag, 'cisco_compat', _('AnyConnect client compatibility'),
_('Enable support for CISCO AnyConnect clients'));
o.default = '1';
// Proxy ARP
o = s.taboption('general', form.Flag, 'proxy_arp', _('Enable proxy arp'),
_('Provide addresses to clients from a subnet of LAN; if enabled the network below must be a subnet of LAN. Note that the first address of the specified subnet will be reserved by ocserv, so it should not be in use. If you have a network in LAN covering 192.168.1.0/24 use 192.168.1.192/26 to reserve the upper 62 addresses.'));
o.default = '0';
// IPv4 Address
o = s.taboption('general', form.Value, 'ipaddr', _('VPN <abbr title="Internet Protocol Version 4">IPv4</abbr>-Network-Address'),
_('The IPv4 subnet address to provide to clients; this should be some private network different than the LAN addresses unless proxy ARP is enabled. Leave empty to attempt auto-configuration.'));
o.datatype = 'ip4addr';
o.default = '192.168.100.1';
// IPv4 Netmask
o = s.taboption('general', form.Value, 'netmask', _('VPN <abbr title="Internet Protocol Version 4">IPv4</abbr>-Netmask'),
_('The mask of the subnet above.'));
o.datatype = 'ip4addr';
o.default = '255.255.255.0';
o.value('255.255.255.0');
o.value('255.255.0.0');
o.value('255.0.0.0');
// IPv6 Address (if available)
if (has_ipv6) {
o = s.taboption('general', form.Value, 'ip6addr', _('VPN <abbr title="Internet Protocol Version 6">IPv6</abbr>-Network-Address'),
_('The IPv6 subnet address to provide to clients; leave empty to attempt auto-configuration.') + '<br />' +
_('<abbr title="Classless Inter-Domain Routing">CIDR</abbr>-Notation: address/prefix'));
o.datatype = 'ip6addr';
}
// DNS servers section
const dns = m.section(form.TableSection, 'dns', _('DNS servers'),
_('The DNS servers to be provided to clients; can be either IPv6 or IPv4. Typically you should include the address of this device'));
dns.anonymous = true;
dns.addremove = true;
o = dns.option(form.Value, 'ip', _('IP Address'));
o.datatype = 'ipaddr';
o.rmempty = false;
// Routes section
const routes = m.section(form.TableSection, 'routes', _('Routing table'),
_('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'));
routes.anonymous = true;
routes.addremove = true;
o = routes.option(form.Value, 'ip', _('IP Address'));
o.datatype = 'ipaddr';
o.rmempty = false;
o = routes.option(form.Value, 'netmask', _('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');
// Template editor
o = s.taboption('template', form.TextValue, '_tmpl',
_('Edit the template that is used for generating the ocserv configuration.'));
o.rows = 20;
o.monospace = true;
o.cfgvalue = function(section_id) {
return L.resolveDefault(fs.read('/etc/ocserv/ocserv.conf.template'), '');
};
o.write = function(section_id, formvalue) {
return fs.write('/etc/ocserv/ocserv.conf.template', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
};
// CA certificate viewer
o = s.taboption('ca', form.TextValue, '_ca',
_('View the CA certificate used by this server. You will need to save it as \'ca.pem\' and import it into the clients.'));
o.rows = 20;
o.monospace = true;
o.readonly = true;
o.cfgvalue = function(section_id) {
return ca_content;
};
o.remove = function() { return false; };
o.write = function() { return false; };
return m.render();
},
addFooter() {
// Override to add custom behavior after form render
},
handleSave(ev) {
return this.super('handleSave', [ev]).then(() => {
// Reload occtl after save
return L.resolveDefault(fs.exec('/usr/bin/occtl', ['reload']), null);
});
},
handleSaveApply(ev) {
return this.handleSave(ev).then(() => {
// Get the enable flag value
const mapNode = document.querySelector('[data-name="ocserv"]');
if (!mapNode) return;
const uci = L.uci;
return uci.load('ocserv').then(() => {
const enable = uci.get('ocserv', 'config', 'enable');
if (enable === '0') {
return Promise.all([
callRcInit('ocserv', 'stop'),
callRcInit('ocserv', 'disable')
]);
} else {
return Promise.all([
callRcInit('ocserv', 'enable'),
callRcInit('ocserv', 'restart')
]);
}
});
}).then(() => {
L.ui.addNotification(null, E('p', _('Configuration has been applied.')), 'info');
}).catch(function(e) {
L.ui.addNotification(null, E('p', _('Failed to apply configuration: %s').format(e.message)), 'error');
});
}
});
|