Project

General

Profile

Download (13.8 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2 b1ad443d Scott Ullrich
3
/* $Id$ */
4
/*
5
	$RCSfile$
6
	Copyright (C) 2006  Fernando Lemos
7
	All rights reserved.
8
9
	Copyright (C) 2005 Peter Allgeyer <allgeyer_AT_web.de>
10
	All rights reserved.
11
12
	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
13
	All rights reserved.
14
15
	Redistribution and use in source and binary forms, with or without
16
	modification, are permitted provided that the following conditions are met:
17
18
	1. Redistributions of source code must retain the above copyright notices,
19
	   this list of conditions and the following disclaimer.
20
21
	2. Redistributions in binary form must reproduce the above copyright
22
	   notices, this list of conditions and the following disclaimer in the
23
	   documentation and/or other materials provided with the distribution.
24
25
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
	POSSIBILITY OF SUCH DAMAGE.
35
*/
36
37 8dc3ef67 Scott Ullrich
require_once('config.inc');
38
require_once('util.inc');
39
40 add2e3f7 Scott Ullrich
// Return the list of ciphers OpenVPN supports
41
function openvpn_get_ciphers($pkg) {
42 8dc3ef67 Scott Ullrich
		foreach ($pkg['fields']['field'] as $i => $field) {
43
			if ($field['fieldname'] == 'crypto') break;
44
		}
45
		$option_array = &$pkg['fields']['field'][$i]['options']['option'];
46
		$ciphers_out = shell_exec('openvpn --show-ciphers | grep "default key" | awk \'{print $1, "(" $2 "-" $3 ")";}\'');
47
		$ciphers = explode("\n", trim($ciphers_out));
48 add2e3f7 Scott Ullrich
		sort($ciphers);
49 8dc3ef67 Scott Ullrich
		foreach ($ciphers as $cipher) {
50
			$value = explode(' ', $cipher);
51
			$value = $value[0];
52
			$option_array[] = array('value' => $value, 'name' => $cipher);
53
		}
54
}
55
56
57
function openvpn_validate_port($value, $name) {
58
	$value = trim($value);
59
	if (!empty($value) && !(is_numeric($value) && ($value > 0) && ($value < 65535)))
60
		return "The field '$name' must contain a valid port, ranging from 0 to 65535.";
61
	return false;
62
}
63
64
65
function openvpn_validate_cidr($value, $name) {
66
	$value = trim($value);
67
	if (!empty($value)) {
68
		list($ip, $mask) = explode('/', $value);
69
		if (!is_ipaddr($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
70
			return "The field '$name' must contain a valid CIDR range.";
71
	}
72
	return false;
73 afb07cf1 Scott Ullrich
}
74
75
76 add2e3f7 Scott Ullrich
// Do the input validation
77
function openvpn_validate_input($mode, $post, $input_errors) {
78
	$Mode = ucfirst($mode);
79
80 8dc3ef67 Scott Ullrich
	if ($mode == 'server') {
81
		if ($result = openvpn_validate_port($post['local_port'], 'Local port'))
82
			$input_errors[] = $result;
83
84
		if ($result = openvpn_validate_cidr($post['addresspool'], 'Address pool'))
85
			$input_errors[] = $result;
86
87
		if ($result = openvpn_validate_cidr($post['local_network'], 'Local network'))
88
			$input_errors[] = $result;
89 add2e3f7 Scott Ullrich
	}
90
91 8dc3ef67 Scott Ullrich
	else { // Client mode
92
		if ($result = openvpn_validate_port($post['serverport'], 'Server port'))
93
			$input_errors[] = $result;
94
95 add2e3f7 Scott Ullrich
		$server_addr = trim($post['serveraddr']);
96 8dc3ef67 Scott Ullrich
		if (!empty($value) && !(is_domain($server_addr) || is_ipaddr($server_addr)))
97 add2e3f7 Scott Ullrich
			$input_errors[] = 'The field \'Server address\' must contain a valid IP address or domain name.';
98
99 8dc3ef67 Scott Ullrich
		if ($result = openvpn_validate_cidr($post['interface_ip'], 'Interface IP'))
100
			$input_errors[] = $result;
101
102
		if ($post['auth_method'] == 'shared_key') {
103
			if (empty($post['interface_ip']))
104
				$input_errors[] = 'The field \'Interface IP\' is required.';
105
		}
106
		if (isset($post['proxy_hostname']) && $post['proxy_hostname'] != "") {
107
			if (!is_domain($post['proxy_hostname']) || is_ipaddr($post['proxy_hostname']))
108
				$input_errors[] = 'The field \'Proxy Host\' must contain a valid IP address or domain name.';
109
			if (!is_port($post['proxy_port']))
110
				$input_errors[] = 'The field \'Proxy port\' must contain a valid port number.';
111 24012690 Scott Ullrich
			if ($post['protocol'] != "TCP")
112 8dc3ef67 Scott Ullrich
				$input_errors[] = 'The protocol must be TCP to use a HTTP proxy server.';
113
		}
114 24012690 Scott Ullrich
115 add2e3f7 Scott Ullrich
	}
116
117 8dc3ef67 Scott Ullrich
	if ($result = openvpn_validate_cidr($post['remote_network'], 'Remote network'))
118
		$input_errors[] = $result;
119
120 add2e3f7 Scott Ullrich
	if ($_POST['auth_method'] == 'shared_key') {
121
		$reqfields[] = 'shared_key';
122
		$reqfieldsn[] = 'Shared key';
123
	}
124
	else {
125
		$req = explode(' ', "ca_cert {$mode}_cert {$mode}_key");
126
		$reqn = array(	'CA certificate',
127
				ucfirst($mode) . ' certificate',
128
				ucfirst($mode) . ' key');
129
		$reqfields = array_merge($reqfields, $req);
130
		$reqfieldsn = array_merge($reqfieldsn, $reqn);
131
		if ($mode == 'server') {
132
			$reqfields[] = 'dh_params';
133
			$reqfieldsn[] = 'DH parameters';
134
		}
135
	}
136
	do_input_validation($post, $reqfields, $reqfieldsn, &$input_errors);
137
138
	$value = trim($post['shared_key']);
139
	$items = array();
140
	if ($_POST['auth_method'] == 'shared_key') {
141
		$items[] = array(	'field' => 'shared_key',
142
					'string' => 'OpenVPN Static key V1',
143
					'name' => 'Shared key');
144
	}
145
	else {
146
		$items[] = array(	'field' => 'ca_cert',
147
					'string' => 'CERTIFICATE',
148
					'name' => 'CA certificate');
149
		$items[] = array(	'field' => "{$mode}_cert",
150
					'string' => 'CERTIFICATE',
151
					'name' => "$Mode certificate");
152
		$items[] = array(	'field' => "{$mode}_key",
153
					'string' => 'RSA PRIVATE KEY',
154
					'name' => "$Mode key");
155
		if ($mode == 'server') {
156
			$items[] = array(	'field' => 'dh_params',
157
						'string' => 'DH PARAMETERS',
158
						'name' => 'DH parameters');
159
			$items[] = array(	'field' => 'crl',
160
						'string' => 'X509 CRL',
161
						'name' => 'CRL');
162
		}
163
	}
164
	foreach ($items as $item) {
165
		$value = trim($_POST[$item['field']]);
166
		$string = $item['string'];
167
		if ($value && (!strstr($value, "-----BEGIN {$string}-----") || !strstr($value, "-----END {$string}-----")))
168
			$input_errors[] = "The field '{$item['name']}' does not appear to be valid";
169
	}
170
}
171
172
173 8dc3ef67 Scott Ullrich
function openvpn_validate_input_csc($post, $input_errors) {
174
	if ($result = openvpn_validate_cidr($post['ifconfig_push'], 'Interface IP'))
175
		$input_errors[] = $result;
176
}
177
178
179 add2e3f7 Scott Ullrich
// Rewrite the settings
180
function openvpn_reconfigure($mode, $id) {
181
	global $g, $config;
182 afb07cf1 Scott Ullrich
183 add2e3f7 Scott Ullrich
	$settings = $config['installedpackages']["openvpn$mode"]['config'][$id];
184
	if ($settings['disable']) return;
185
186 8dc3ef67 Scott Ullrich
	// Set the keys up
187
	// Note that the keys' extension is also the directive that goes to the config file
188 add2e3f7 Scott Ullrich
	$base_file = $g['varetc_path'] . "/openvpn_{$mode}{$id}.";
189
	$keys = array();
190
	if ($settings['auth_method'] == 'shared_key')
191
		$keys[] = array('field' => 'shared_key', 'ext'  => 'secret', 'directive' => 'secret');
192
	else {
193
		$keys[] = array('field' => 'ca_cert', 'ext' => 'ca', 'directive' => 'ca');
194
		$keys[] = array('field' => "{$mode}_cert", 'ext' => 'cert', 'directive' => 'cert');
195
		$keys[] = array('field' => "{$mode}_key", 'ext' => 'key', 'directive' => 'key');
196
		if ($mode == 'server')
197
			$keys[] = array('field' => 'dh_params', 'ext' => 'dh', 'directive' => 'dh');
198
		if ($settings['crl'])
199
			$keys[] = array('field' => 'crl', 'ext' => 'crl', 'directive' => 'crl-verify');
200
	}
201
	foreach($keys as $key) {
202
		$filename = $base_file . $key['ext'];
203
		file_put_contents($filename, base64_decode($settings[$key['field']]));
204
		chown($filename, 'nobody');
205
		chgrp($filename, 'nobody');
206
	}
207
208 8dc3ef67 Scott Ullrich
	$pidfile = $g['varrun_path'] . "/openvpn_{$mode}{$id}.pid";
209 add2e3f7 Scott Ullrich
	$proto = ($settings['protocol'] == 'UDP' ? 'udp' : "tcp-{$mode}");
210
	$cipher = $settings['crypto'];
211
	$openvpn_conf = <<<EOD
212 8dc3ef67 Scott Ullrich
writepid $pidfile
213 344b0230 Scott Ullrich
#user nobody
214
#group nobody
215 add2e3f7 Scott Ullrich
daemon
216
keepalive 10 60
217
ping-timer-rem
218 afb07cf1 Scott Ullrich
persist-tun
219
persist-key
220 add2e3f7 Scott Ullrich
dev tun
221
proto $proto
222
cipher $cipher
223 afb07cf1 Scott Ullrich
224
EOD;
225 8dc3ef67 Scott Ullrich
226
	// Mode-specific stuff
227
	if ($mode == 'server') {
228
		list($ip, $mask) = explode('/', $settings['addresspool']);
229
		$mask = gen_subnet_mask($mask);
230
231
		// Using a shared key or not dynamically assigning IPs to the clients
232
		if (($settings['auth_method'] == 'shared_key') || ($settings['nopool'] == 'on')) {
233
			if ($settings['auth_method'] == 'pki') $openvpn_conf .= "tls-server\n";
234
235
			$baselong = ip2long($ip) & ip2long($mask);
236
			$ip1 = long2ip($baselong + 1);
237
			$ip2 = long2ip($baselong + 2);
238
			$openvpn_conf .= "ifconfig $ip1 $ip2\n";
239
		}
240
		// Using a PKI
241
		else if ($settings['auth_method'] == 'pki') {
242
			if ($settings['client2client']) $openvpn_conf .= "client-to-client\n";
243
			$openvpn_conf .= "server $ip $mask\n";
244
			$csc_dir = "{$g['varetc_path']}/openvpn_csc";
245
			$openvpn_conf .= "client-config-dir $csc_dir\n";
246
		}
247
248
		// We can push routes
249
		if (!empty($settings['local_network'])) {
250
			list($ip, $mask) = explode('/', $settings['local_network']);
251
			$mask = gen_subnet_mask($mask);
252
			$openvpn_conf .= "push \"route $ip $mask\"\n";
253
		}
254
255
		// The port we'll listen at
256
		$openvpn_conf .= "lport {$settings['local_port']}\n";
257
	}
258
259
	else { // $mode == client
260
		// The remote server
261
		$openvpn_conf .= "remote {$settings['serveraddr']} {$settings['serverport']}\n";
262
263
		if ($settings['auth_method'] == 'pki') $openvpn_conf .= "client\n";
264
265
		if (!empty($settings['interface_ip'])) {
266
			// Configure the IPs according to the address pool
267
			list($ip, $mask) = explode('/', $settings['interface_ip']);
268
			$mask = gen_subnet_mask($mask);
269
			$baselong = ip2long($ip) & ip2long($mask);
270
			$ip1 = long2ip($baselong + 1);
271
			$ip2 = long2ip($baselong + 2);
272
			$openvpn_conf .= "ifconfig $ip2 $ip1\n";
273
		}
274
		if (isset($settings['proxy_hostname']) && $settings['proxy_hostname'] != "") {
275
			/* ;http-proxy-retry # retry on connection failures */
276
			$openvpn_conf .= "http-proxy {$settings['proxy_hostname']} {$settings['proxy_port']}\n";
277
		}
278
	}
279
280
	// Add the routes if they're set
281
	if (!empty($settings['remote_network'])) {
282
		list($ip, $mask) = explode('/', $settings['remote_network']);
283
		$mask = gen_subnet_mask($mask);
284
		$openvpn_conf .= "route $ip $mask\n";
285
	}
286 afb07cf1 Scott Ullrich
287 add2e3f7 Scott Ullrich
	// Write the settings for the keys
288
	foreach ($keys as $key)
289
		$openvpn_conf .= $key['directive'] . ' ' . $base_file . $key['ext'] . "\n";
290 707e9964 Scott Ullrich
291 add2e3f7 Scott Ullrich
	if ($settings['use_lzo']) $openvpn_conf .= "comp-lzo\n";
292 8dc3ef67 Scott Ullrich
293
	if ($settings['dynamic_ip']) {
294
		$openvpn_conf .= "persist-remote-ip\n";
295
		$openvpn_conf .= "float\n";
296
	}
297
298
	if (!empty($settings['custom_options'])) {
299
		$options = explode(';', $settings['custom_options']);
300
		if (is_array($options)) {
301
			foreach ($options as $option)
302
				$openvpn_conf .= "$option\n";
303
		}
304
		else {
305
			$openvpn_conf .= "{$settings['custom_options']}\n";
306
		}
307
	}
308 afb07cf1 Scott Ullrich
309 add2e3f7 Scott Ullrich
	file_put_contents($g['varetc_path'] . "/openvpn_{$mode}{$id}.conf", $openvpn_conf);
310 afb07cf1 Scott Ullrich
}
311
312
313 8dc3ef67 Scott Ullrich
function openvpn_resync_csc($id) {
314
	global $g, $config;
315
316
	$settings = $config['installedpackages']['openvpncsc']['config'][$id];
317
318
	if ($settings['disable'] == 'on') return;
319
320
	$conf = '';
321
	if ($settings['block'] == 'on') $conf .= "disable\n";
322
	if ($settings['push_reset'] == 'on') $conf .= "push-reset\n";
323
	if (!empty($settings['ifconfig_push'])) {
324
		list($ip, $mask) = explode('/', $settings['ifconfig_push']);
325
		$baselong = ip2long($ip) & gen_subnet_mask_long($mask);
326
		$conf .= 'ifconfig-push ' . long2ip($baselong + 1) . ' ' . long2ip($baselong + 2) . "\n";
327
	}
328
	if (!empty($settings['custom_options'])) {
329
		$options = explode(';', $settings['custom_options']);
330
		if (is_array($options)) {
331
			foreach ($options as $option)
332
				$conf .= "$option\n";
333
		}
334
		else {
335
			$conf .= "{$settings['custom_options']}\n";
336
		}
337
	}
338
339
	openvpn_create_cscdir();
340
	$filename = "{$g['varetc_path']}/openvpn_csc/{$settings['commonname']}";
341
	file_put_contents($filename, $conf);
342
	chown($filename, 'nobody');
343
	chgrp($filename, 'nogroup');
344
}
345
346
347 add2e3f7 Scott Ullrich
function openvpn_restart($mode, $id) {
348
	global $g, $config;
349 3c2e5528 Scott Ullrich
350 add2e3f7 Scott Ullrich
	$pidfile = $g['varrun_path'] . "/openvpn_{$mode}{$id}.pid";
351
	killbypid($pidfile);
352
	sleep(2);
353 afb07cf1 Scott Ullrich
354 add2e3f7 Scott Ullrich
	$settings = $config['installedpackages']["openvpn$mode"]['config'][$id];
355
	if ($settings['disable']) return;
356 afb07cf1 Scott Ullrich
357 add2e3f7 Scott Ullrich
	$configfile = $g['varetc_path'] . "/openvpn_{$mode}{$id}.conf";
358 24012690 Scott Ullrich
	mwexec("openvpn --down \"touch /tmp/filter_dirty\" --ipchange \"touch /tmp/filter_dirty\" --learn-address \"touch /tmp/filter_dirty\" --route-up \"touch /tmp/filter_dirty\" --up touch \"/tmp/filter_dirty\" --config $configfile");
359 ffb47da1 Scott Ullrich
	touch("{$g['tmp_path']}/filter_dirty");
360 afb07cf1 Scott Ullrich
}
361
362
363 24012690 Scott Ullrich
// Resync the configuration and restart the VPN
364 add2e3f7 Scott Ullrich
function openvpn_resync($mode, $id) {
365
	openvpn_reconfigure($mode, $id);
366
	openvpn_restart($mode, $id);
367 afb07cf1 Scott Ullrich
}
368
369 8dc3ef67 Scott Ullrich
function openvpn_create_cscdir() {
370
	global $g;
371
372
	$csc_dir = "{$g['varetc_path']}/openvpn_csc";
373
	if (!is_dir($csc_dir)) {
374
		mkdir($csc_dir);
375
		chown($csc_dir, 'nobody');
376
		chgrp($csc_dir, 'nobody');
377
	}
378
}
379 afb07cf1 Scott Ullrich
380 add2e3f7 Scott Ullrich
// Resync and restart all VPNs
381
function openvpn_resync_all() {
382 3c2e5528 Scott Ullrich
	global $config;
383 afb07cf1 Scott Ullrich
384 add2e3f7 Scott Ullrich
	foreach (array('server', 'client') as $mode) {
385
		if (is_array($config['installedpackages']["openvpn$mode"]['config'])) {
386
			foreach ($config['installedpackages']["openvpn$mode"]['config'] as $id => $settings)
387
				openvpn_resync($mode, $id);
388 3c2e5528 Scott Ullrich
		}
389
	}
390 8dc3ef67 Scott Ullrich
391
	openvpn_create_cscdir();
392
	if (is_array($config['installedpackages']['openvpncsc']['config'])) {
393
		foreach ($config['installedpackages']['openvpncsc']['config'] as $id => $csc)
394
			openvpn_resync_csc($id);
395
	}
396 afb07cf1 Scott Ullrich
}
397
398
399 add2e3f7 Scott Ullrich
function openvpn_print_javascript($mode) {
400
	$javascript = <<<EOD
401
<script language="JavaScript">
402
<!--
403
function onAuthMethodChanged() {
404 83305ae3 Scott Ullrich
	var method = document.iform.auth_method;
405
	var endis = (method.options[method.selectedIndex].value == 'shared_key');
406
407 add2e3f7 Scott Ullrich
	document.iform.shared_key.disabled = !endis;
408
	document.iform.ca_cert.disabled = endis;
409
	document.iform.{$mode}_cert.disabled = endis;
410
	document.iform.{$mode}_key.disabled = endis;
411 afb07cf1 Scott Ullrich
412
EOD;
413 add2e3f7 Scott Ullrich
	if ($mode == 'server') {
414 8dc3ef67 Scott Ullrich
		$javascript .= <<<EOD
415
	document.iform.dh_params.disabled = endis;
416
	document.iform.crl.disabled = endis;
417
	document.iform.nopool.disabled = endis;
418
	document.iform.local_network.disabled = endis;
419
	document.iform.client2client.disabled = endis;
420
421
EOD;
422
	}
423
424
	else { // Client mode
425
		$javascript .= "\tdocument.iform.remote_network.disabled = !endis;\n";
426 afb07cf1 Scott Ullrich
	}
427 8dc3ef67 Scott Ullrich
428 add2e3f7 Scott Ullrich
	$javascript .= <<<EOD
429 5b237745 Scott Ullrich
}
430 add2e3f7 Scott Ullrich
//-->
431
</script>
432 5b237745 Scott Ullrich
433 add2e3f7 Scott Ullrich
EOD;
434
	print($javascript);
435 afb07cf1 Scott Ullrich
}
436
437
438 add2e3f7 Scott Ullrich
function openvpn_print_javascript2() {
439
	$javascript = <<<EOD
440
<script language="JavaScript">
441
<!--
442
	onAuthMethodChanged();
443
//-->
444
</script>
445 5b237745 Scott Ullrich
446 add2e3f7 Scott Ullrich
EOD;
447
	print($javascript);
448 5b237745 Scott Ullrich
}
449 b1ad443d Scott Ullrich
?>