fixes, fully translated tomato, with english dictionary and Polish translation
[tomato.git] / release / src / router / www / vpn-client.asp
blob77aed1aac7b650c2579e0489f4f70b077193eabe
1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN'>
2 <!--
3 Tomato GUI
4 Copyright (C) 2006-2008 Jonathan Zarate
5 http://www.polarcloud.com/tomato/
7 Portions Copyright (C) 2008-2010 Keith Moyer, tomatovpn@keithmoyer.com
9 For use with Tomato Firmware only.
10 No part of this file may be used without permission.
11 -->
12 <html>
13 <head>
14 <meta http-equiv='content-type' content='text/html;charset=utf-8'>
15 <meta name='robots' content='noindex,nofollow'>
16 <title>[<% ident(); %>] <% translate("VPN"); %>: <% translate("Client"); %></title>
17 <link rel='stylesheet' type='text/css' href='tomato.css'>
18 <link rel='stylesheet' type='text/css' href='color.css'>
19 <script type='text/javascript' src='tomato.js'></script>
20 <script type='text/javascript' src='vpn.js'></script>
21 <script type='text/javascript'>
23 // <% nvram("vpn_client_eas,vpn_client1_poll,vpn_client1_if,vpn_client1_bridge,vpn_client1_nat,vpn_client1_proto,vpn_client1_addr,vpn_client1_port,vpn_client1_retry,vpn_client1_firewall,vpn_client1_crypt,vpn_client1_comp,vpn_client1_cipher,vpn_client1_local,vpn_client1_remote,vpn_client1_nm,vpn_client1_reneg,vpn_client1_hmac,vpn_client1_adns,vpn_client1_rgw,vpn_client1_gw,vpn_client1_custom,vpn_client1_static,vpn_client1_ca,vpn_client1_crt,vpn_client1_key,vpn_client2_poll,vpn_client2_if,vpn_client2_bridge,vpn_client2_nat,vpn_client2_proto,vpn_client2_addr,vpn_client2_port,vpn_client2_retry,vpn_client2_firewall,vpn_client2_crypt,vpn_client2_comp,vpn_client2_cipher,vpn_client2_local,vpn_client2_remote,vpn_client2_nm,vpn_client2_reneg,vpn_client2_hmac,vpn_client2_adns,vpn_client2_rgw,vpn_client2_gw,vpn_client2_custom,vpn_client2_static,vpn_client2_ca,vpn_client2_crt,vpn_client2_key"); %>
25 tabs = [['client1', '<% translate("Client"); %> 1'],['client2', '<% translate("Client"); %> 2']];
26 sections = [['basic', '<% translate("Basic"); %>'],['advanced', '<% translate("Advanced"); %>'],['keys','<% translate("Keys"); %>'],['status','<% translate("Status"); %>']];
27 statusUpdaters = [];
28 for (i = 0; i < tabs.length; ++i) statusUpdaters.push(new StatusUpdater());
29 ciphers = [['default','<% translate("Use Default"); %>'],['none','<% translate("None"); %>']];
30 for (i = 0; i < vpnciphers.length; ++i) ciphers.push([vpnciphers[i],vpnciphers[i]]);
32 changed = 0;
33 vpn1up = parseInt('<% psup("vpnclient1"); %>');
34 vpn2up = parseInt('<% psup("vpnclient2"); %>');
36 function updateStatus(num)
38 var xob = new XmlHttp();
39 xob.onCompleted = function(text, xml)
41 statusUpdaters[num].update(text);
42 xob = null;
44 xob.onError = function(ex)
46 statusUpdaters[num].errors.innerHTML += 'ERROR! '+ex+'<br>';
47 xob = null;
50 xob.post('/vpnstatus.cgi', 'client=' + (num+1));
53 function tabSelect(name)
55 tgHideIcons();
57 tabHigh(name);
59 for (var i = 0; i < tabs.length; ++i)
61 var on = (name == tabs[i][0]);
62 elem.display(tabs[i][0] + '-tab', on);
65 cookie.set('vpn_client_tab', name);
68 function sectSelect(tab, section)
70 tgHideIcons();
72 for (var i = 0; i < sections.length; ++i)
74 if (section == sections[i][0])
76 elem.addClass(tabs[tab][0]+'-'+sections[i][0]+'-tab', 'active');
77 elem.display(tabs[tab][0]+'-'+sections[i][0], true);
79 else
81 elem.removeClass(tabs[tab][0]+'-'+sections[i][0]+'-tab', 'active');
82 elem.display(tabs[tab][0]+'-'+sections[i][0], false);
86 cookie.set('vpn_client'+tab+'_section', section);
89 function toggle(service, isup)
91 if (changed && !confirm("<% translate("Unsaved changes will be lost. Continue anyway"); %>?")) return;
93 E('_' + service + '_button').disabled = true;
94 form.submitHidden('service.cgi', {
95 _redirect: 'vpn-client.asp',
96 _sleep: '3',
97 _service: service + (isup ? '-stop' : '-start')
98 });
101 function verifyFields(focused, quiet)
103 tgHideIcons();
105 var ret = 1;
107 // When settings change, make sure we restart the right client
108 if (focused)
110 changed = 1;
112 var clientindex = focused.name.indexOf("client");
113 if (clientindex >= 0)
115 var clientnumber = focused.name.substring(clientindex+6,clientindex+7);
116 var stripped = focused.name.substring(0,clientindex+6)+focused.name.substring(clientindex+7);
118 if (stripped == 'vpn_client_local')
119 E('_f_vpn_client'+clientnumber+'_local').value = focused.value;
120 else if (stripped == 'f_vpn_client_local')
121 E('_vpn_client'+clientnumber+'_local').value = focused.value;
123 var fom = E('_fom');
124 if (eval('vpn'+clientnumber+'up') && fom._service.value.indexOf('client'+clientnumber) < 0)
126 if ( fom._service.value != "" ) fom._service.value += ",";
127 fom._service.value += 'vpnclient'+clientnumber+'-restart';
132 // Element varification
133 for (i = 0; i < tabs.length; ++i)
135 t = tabs[i][0];
137 if (!v_range('_vpn_'+t+'_poll', quiet, 0, 1440)) ret = 0;
138 if (!v_ip('_vpn_'+t+'_addr', true) && !v_domain('_vpn_'+t+'_addr', true)) { ferror.set(E('_vpn_'+t+'_addr'), "<% translate("Invalid server address"); %>.", quiet); ret = 0; }
139 if (!v_port('_vpn_'+t+'_port', quiet)) ret = 0;
140 if (!v_ip('_vpn_'+t+'_local', quiet, 1)) ret = 0;
141 if (!v_ip('_f_vpn_'+t+'_local', true, 1)) ret = 0;
142 if (!v_ip('_vpn_'+t+'_remote', quiet, 1)) ret = 0;
143 if (!v_netmask('_vpn_'+t+'_nm', quiet)) ret = 0;
144 if (!v_range('_vpn_'+t+'_retry', quiet, -1, 32767)) ret = 0;
145 if (!v_range('_vpn_'+t+'_reneg', quiet, -1, 2147483647)) ret = 0;
146 if (E('_vpn_'+t+'_gw').value.length > 0 && !v_ip('_vpn_'+t+'_gw', quiet, 1)) ret = 0;
149 // Visability changes
150 for (i = 0; i < tabs.length; ++i)
152 t = tabs[i][0];
154 fw = E('_vpn_'+t+'_firewall');
155 auth = E('_vpn_'+t+'_crypt');
156 iface = E('_vpn_'+t+'_if');
157 bridge = E('_f_vpn_'+t+'_bridge');
158 nat = E('_f_vpn_'+t+'_nat');
159 hmac = E('_vpn_'+t+'_hmac');
160 rgw = E('_f_vpn_'+t+'_rgw');
162 elem.display(PR('_vpn_'+t+'_ca'), PR('_vpn_'+t+'_crt'), PR('_vpn_'+t+'_key'), PR('_vpn_'+t+'_hmac'),
163 PR('_vpn_'+t+'_adns'), PR('_vpn_'+t+'_reneg'), auth.value == "tls");
164 elem.display(PR('_vpn_'+t+'_static'), auth.value == "secret" || (auth.value == "tls" && hmac.value >= 0));
165 elem.display(E(t+'_custom_crypto_text'), auth.value == "custom");
166 elem.display(PR('_f_vpn_'+t+'_bridge'), iface.value == "tap");
167 elem.display(E(t+'_bridge_warn_text'), !bridge.checked);
168 elem.display(PR('_f_vpn_'+t+'_nat'), fw.value != "custom" && (iface.value == "tun" || !bridge.checked));
169 elem.display(E(t+'_nat_warn_text'), fw.value != "custom" && (!nat.checked || (auth.value == "secret" && iface.value == "tun")));
170 elem.display(PR('_vpn_'+t+'_local'), auth.value == "secret" && iface.value == "tun");
171 elem.display(PR('_f_vpn_'+t+'_local'), auth.value == "secret" && (iface.value == "tap" && !bridge.checked));
172 elem.display(E(t+'_gateway'), iface.value == "tap" && rgw.checked);
174 keyHelp = E(t+'-keyhelp');
175 switch (auth.value)
177 case "tls":
178 keyHelp.href = helpURL['TLSKeys'];
179 break;
180 case "secret":
181 keyHelp.href = helpURL['staticKeys'];
182 break;
183 default:
184 keyHelp.href = helpURL['howto'];
185 break;
189 return ret;
192 function save()
194 if (!verifyFields(null, false)) return;
196 var fom = E('_fom');
198 E('vpn_client_eas').value = '';
200 for (i = 0; i < tabs.length; ++i)
202 t = tabs[i][0];
204 if ( E('_f_vpn_'+t+'_eas').checked )
205 E('vpn_client_eas').value += ''+(i+1)+',';
207 E('vpn_'+t+'_bridge').value = E('_f_vpn_'+t+'_bridge').checked ? 1 : 0;
208 E('vpn_'+t+'_nat').value = E('_f_vpn_'+t+'_nat').checked ? 1 : 0;
209 E('vpn_'+t+'_rgw').value = E('_f_vpn_'+t+'_rgw').checked ? 1 : 0;
212 form.submit(fom, 1);
214 changed = 0;
217 function init()
219 tabSelect(cookie.get('vpn_client_tab') || tabs[0][0]);
221 for (i = 0; i < tabs.length; ++i)
223 sectSelect(i, cookie.get('vpn_client'+i+'_section') || sections[i][0]);
225 t = tabs[i][0];
227 statusUpdaters[i].init(null,null,t+'-status-stats-table',t+'-status-time',t+'-status-content',t+'-no-status',t+'-status-errors');
228 updateStatus(i);
231 verifyFields(null, true);
233 </script>
235 <style type='text/css'>
236 textarea {
237 width: 98%;
238 height: 10em;
240 p.keyhelp
242 font-size: smaller;
243 font-style: italic;
245 div.status-header p
247 font-weight: bold;
248 padding-bottom: 4px;
250 table.status-table
252 width: auto;
253 margin-left: auto;
254 margin-right: auto;
255 text-align: center;
257 </style>
259 </head>
260 <body>
261 <form id='_fom' method='post' action='tomato.cgi'>
262 <table id='container' cellspacing=0>
263 <tr><td colspan=2 id='header'>
264 <div class='title'>Tomato</div>
265 <div class='version'><% translate("Version"); %> <% version(); %></div>
266 </td></tr>
267 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
268 <td id='content'>
269 <div id='ident'><% ident(); %></div>
271 <input type='hidden' name='_nextpage' value='vpn-client.asp'>
272 <input type='hidden' name='_nextwait' value='5'>
273 <input type='hidden' name='_service' value=''>
274 <input type='hidden' name='vpn_client_eas' id='vpn_client_eas' value=''>
276 <div class='section-title'><% translate("VPN Client Configuration"); %></div>
277 <div class='section'>
278 <script type='text/javascript'>
279 tabCreate.apply(this, tabs);
281 for (i = 0; i < tabs.length; ++i)
283 t = tabs[i][0];
284 W('<div id=\''+t+'-tab\'>');
285 W('<input type=\'hidden\' id=\'vpn_'+t+'_bridge\' name=\'vpn_'+t+'_bridge\'>');
286 W('<input type=\'hidden\' id=\'vpn_'+t+'_nat\' name=\'vpn_'+t+'_nat\'>');
287 W('<input type=\'hidden\' id=\'vpn_'+t+'_rgw\' name=\'vpn_'+t+'_rgw\'>');
289 W('<ul class="tabs">');
290 for (j = 0; j < sections.length; j++)
292 W('<li><a href="javascript:sectSelect('+i+', \''+sections[j][0]+'\')" id="'+t+'-'+sections[j][0]+'-tab">'+sections[j][1]+'</a></li>');
294 W('</ul><div class=\'tabs-bottom\'></div>');
296 W('<div id=\''+t+'-basic\'>');
297 createFieldTable('', [
298 { title: '<% translate("Start with WAN"); %>', name: 'f_vpn_'+t+'_eas', type: 'checkbox', value: nvram.vpn_client_eas.indexOf(''+(i+1)) >= 0 },
299 { title: '<% translate("Interface Type"); %>', name: 'vpn_'+t+'_if', type: 'select', options: [ ['tap','TAP'], ['tun','TUN'] ], value: eval( 'nvram.vpn_'+t+'_if' ) },
300 { title: '<% translate("Protocol"); %>', name: 'vpn_'+t+'_proto', type: 'select', options: [ ['udp','UDP'], ['tcp-client','TCP'] ], value: eval( 'nvram.vpn_'+t+'_proto' ) },
301 { title: '<% translate("Server Address/Port"); %>', multi: [
302 { name: 'vpn_'+t+'_addr', type: 'text', size: 17, value: eval( 'nvram.vpn_'+t+'_addr' ) },
303 { name: 'vpn_'+t+'_port', type: 'text', maxlen: 5, size: 7, value: eval( 'nvram.vpn_'+t+'_port' ) } ] },
304 { title: '<% translate("Firewall"); %>', name: 'vpn_'+t+'_firewall', type: 'select', options: [ ['auto', '<% translate("Automatic"); %>'], ['custom', '<% translate("Custom"); %>'] ], value: eval( 'nvram.vpn_'+t+'_firewall' ) },
305 { title: '<% translate("Authorization Mode"); %>', name: 'vpn_'+t+'_crypt', type: 'select', options: [ ['tls', 'TLS'], ['secret', '<% translate("Static Key"); %>'], ['custom', '<% translate("Custom"); %>'] ], value: eval( 'nvram.vpn_'+t+'_crypt' ),
306 suffix: '<span id=\''+t+'_custom_crypto_text\'>&nbsp;<small>(<% translate("must configure manually"); %>...)</small></span>' },
307 { title: '<% translate("Extra HMAC authorization"); %> (tls-auth)', name: 'vpn_'+t+'_hmac', type: 'select', options: [ [-1, '<% translate("Disabled"); %>'], [2, '<% translate("Bi-directional"); %>'], [0, '<% translate("Incoming"); %> (0)'], [1, '<% translate("Outgoing"); %> (1)'] ], value: eval( 'nvram.vpn_'+t+'_hmac' ) },
308 { title: '<% translate("Server is on the same subnet"); %>', name: 'f_vpn_'+t+'_bridge', type: 'checkbox', value: eval( 'nvram.vpn_'+t+'_bridge' ) != 0,
309 suffix: '<span style="color: red" id=\''+t+'_bridge_warn_text\'>&nbsp<small><% translate("Warning: Cannot bridge distinct subnets. Defaulting to routed mode"); %>.<small></span>' },
310 { title: '<% translate("Create NAT on tunnel"); %>', name: 'f_vpn_'+t+'_nat', type: 'checkbox', value: eval( 'nvram.vpn_'+t+'_nat' ) != 0,
311 suffix: '<span style="font-style: italic" id=\''+t+'_nat_warn_text\'>&nbsp<small><% translate("Routes must be configured manually"); %>.<small></span>' },
312 { title: '<% translate("Local/remote endpoint addresses"); %>', multi: [
313 { name: 'vpn_'+t+'_local', type: 'text', maxlen: 15, size: 17, value: eval( 'nvram.vpn_'+t+'_local' ) },
314 { name: 'vpn_'+t+'_remote', type: 'text', maxlen: 15, size: 17, value: eval( 'nvram.vpn_'+t+'_remote' ) } ] },
315 { title: '<% translate("Tunnel address/netmask"); %>', multi: [
316 { name: 'f_vpn_'+t+'_local', type: 'text', maxlen: 15, size: 17, value: eval( 'nvram.vpn_'+t+'_local' ) },
317 { name: 'vpn_'+t+'_nm', type: 'text', maxlen: 15, size: 17, value: eval( 'nvram.vpn_'+t+'_nm' ) } ] }
319 W('</div>');
320 W('<div id=\''+t+'-advanced\'>');
321 createFieldTable('', [
322 { title: '<% translate("Poll Interval"); %>', name: 'vpn_'+t+'_poll', type: 'text', maxlen: 4, size: 5, value: eval( 'nvram.vpn_'+t+'_poll' ), suffix: '&nbsp;<small>(<% translate("in minutes, 0 to disable"); %>)</small>' },
323 { title: '<% translate("Redirect Internet traffic"); %>', multi: [
324 { name: 'f_vpn_'+t+'_rgw', type: 'checkbox', value: eval( 'nvram.vpn_'+t+'_rgw' ) != 0 },
325 { name: 'vpn_'+t+'_gw', type: 'text', maxlen: 15, size: 17, value: eval( 'nvram.vpn_'+t+'_gw' ), prefix: '<span id=\''+t+'_gateway\'><% translate("Gateway"); %>:&nbsp', suffix: '</span>'} ] },
326 { title: '<% translate("Accept DNS configuration"); %>', name: 'vpn_'+t+'_adns', type: 'select', options: [[0, '<% translate("Disabled"); %>'],[1, '<% translate("Relaxed"); %>'],[2, '<% translate("Strict"); %>'],[3, '<% translate("Exclusive"); %>']], value: eval( 'nvram.vpn_'+t+'_adns' ) },
327 { title: '<% translate("Encryption cipher"); %>', name: 'vpn_'+t+'_cipher', type: 'select', options: ciphers, value: eval( 'nvram.vpn_'+t+'_cipher' ) },
328 { title: '<% translate("Compression"); %>', name: 'vpn_'+t+'_comp', type: 'select', options: [ ['-1', '<% translate("Disabled"); %>'], ['no', '<% translate("None"); %>'], ['yes', '<% translate("Enabled"); %>'], ['adaptive', '<% translate("Adaptive"); %>'] ], value: eval( 'nvram.vpn_'+t+'_comp' ) },
329 { title: '<% translate("TLS Renegotiation Time"); %>', name: 'vpn_'+t+'_reneg', type: 'text', maxlen: 10, size: 7, value: eval( 'nvram.vpn_'+t+'_reneg' ),
330 suffix: '&nbsp;<small>(<% translate("in seconds, -1 for default"); %>)</small>' },
331 { title: '<% translate("Connection retry"); %>', name: 'vpn_'+t+'_retry', type: 'text', maxlen: 5, size: 7, value: eval( 'nvram.vpn_'+t+'_retry' ),
332 suffix: '&nbsp;<small>(<% translate("in seconds; -1 for infinite"); %>)</small>' },
333 { title: '<% translate("Custom Configuration"); %>', name: 'vpn_'+t+'_custom', type: 'textarea', value: eval( 'nvram.vpn_'+t+'_custom' ) }
335 W('</div>');
336 W('<div id=\''+t+'-keys\'>');
337 W('<p class=\'keyhelp\'><% translate("For help generating keys, refer to the OpenVPN"); %> <a id=\''+t+'-keyhelp\'><% translate("HOWTO"); %></a>.</p>');
338 createFieldTable('', [
339 { title: '<% translate("Static Key"); %>', name: 'vpn_'+t+'_static', type: 'textarea', value: eval( 'nvram.vpn_'+t+'_static' ) },
340 { title: '<% translate("Certificate Authority"); %>', name: 'vpn_'+t+'_ca', type: 'textarea', value: eval( 'nvram.vpn_'+t+'_ca' ) },
341 { title: '<% translate("Client Certificate"); %>', name: 'vpn_'+t+'_crt', type: 'textarea', value: eval( 'nvram.vpn_'+t+'_crt' ) },
342 { title: '<% translate("Client Key"); %>', name: 'vpn_'+t+'_key', type: 'textarea', value: eval( 'nvram.vpn_'+t+'_key' ) }
344 W('</div>');
345 W('<div id=\''+t+'-status\'>');
346 W('<div id=\''+t+'-no-status\'><p><% translate("Client is not running or status could not be read"); %>.</p></div>');
347 W('<div id=\''+t+'-status-content\' style=\'display:none\' class=\'status-content\'>');
348 W('<div id=\''+t+'-status-header\' class=\'status-header\'><p><% translate("Data current as of"); %> <span id=\''+t+'-status-time\'></span>.</p></div>');
349 W('<div id=\''+t+'-status-stats\'><div class=\'section-title\'><% translate("General Statistics"); %></div><table class=\'tomato-grid status-table\' id=\''+t+'-status-stats-table\'></table><br></div>');
350 W('<div id=\''+t+'-status-errors\' class=\'error\'></div>');
351 W('</div>');
352 W('<div style=\'text-align:right\'><a href=\'javascript:updateStatus('+i+')\'><% translate("Refresh Status"); %></a></div>');
353 W('</div>');
354 W('<input type="button" value="' + (eval('vpn'+(i+1)+'up') ? '<% translate("Stop"); %>' : '<% translate("Start"); %>') + ' <% translate("Now"); %>" onclick="toggle(\'vpn'+t+'\', vpn'+(i+1)+'up)" id="_vpn'+t+'_button">');
355 W('</div>');
358 </script>
359 </div>
361 </td></tr>
362 <tr><td id='footer' colspan=2>
363 <span id='footer-msg'></span>
364 <input type='button' value='<% translate("Save"); %>' id='save-button' onclick='save()'>
365 <input type='button' value='<% translate("Cancel"); %>' id='cancel-button' onclick='javascript:reloadPage();'>
366 </td></tr>
367 </table>
368 </form>
369 <script type='text/javascript'>init();</script>
370 </body>
371 </html>