Project

General

Profile

Download (29 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2

    
3
/* $Id$ */
4
/*
5
	$RCSfile$
6
	
7
	Copyright (C) 2008 Scott Ullrich <sullrich@gmail.com>
8
	All rights reserved.
9
	
10
	Copyright (C) 2006  Fernando Lemos
11
	All rights reserved.
12

    
13
	This file was rewritten from scratch by Fernando Lemos but
14
	*MIGHT* contain code previously written by:
15

    
16
	Copyright (C) 2005 Peter Allgeyer <allgeyer_AT_web.de>
17
	All rights reserved.
18

    
19
	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
20
	All rights reserved.
21

    
22
	Redistribution and use in source and binary forms, with or without
23
	modification, are permitted provided that the following conditions are met:
24

    
25
	1. Redistributions of source code must retain the above copyright notices,
26
	   this list of conditions and the following disclaimer.
27

    
28
	2. Redistributions in binary form must reproduce the above copyright
29
	   notices, this list of conditions and the following disclaimer in the
30
	   documentation and/or other materials provided with the distribution.
31

    
32
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
33
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
34
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
35
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
36
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41
	POSSIBILITY OF SUCH DAMAGE.
42
	
43
	DISABLE_PHP_LINT_CHECKING
44
	
45
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/openvpn	/usr/bin/openssl	/sbin/ifconfig
46
	pfSense_MODULE:	openvpn
47

    
48
*/
49
require_once('config.inc');
50
require_once("certs.inc");
51
require_once('pfsense-utils.inc');
52
require_once("auth.inc");
53

    
54
$openvpn_prots = array("UDP", "TCP");
55

    
56
$openvpn_dev_mode = array("tun", "tap");
57

    
58
/* 
59
 * The User Auth mode below is disabled because
60
 * OpenVPN erroneously requires that we provide
61
 * a CA configuration parameter. In this mode,
62
 * clients don't send a certificate so there is
63
 * no need for a CA. If we require that admins
64
 * provide one in the pfSense UI due to a bogus
65
 * requirement imposed by OpenVPN, it could be
66
 * considered very confusing ( I know I was ).
67
 *
68
 * -mgrooms
69
 */
70

    
71
$openvpn_dh_lengths = array(
72
	1024, 2048, 4096 );
73

    
74
$openvpn_cert_depths = array(
75
	1 => "One (Client+Server)",
76
	2 => "Two (Client+Intermediate+Server)",
77
	3 => "Three (Client+2xIntermediate+Server)",
78
	4 => "Four (Client+3xIntermediate+Server)",
79
	5 => "Five (Client+4xIntermediate+Server)"
80
);
81

    
82
$openvpn_server_modes = array(
83
	'p2p_tls' => "Peer to Peer ( SSL/TLS )",
84
	'p2p_shared_key' => "Peer to Peer ( Shared Key )",
85
	'server_tls' => "Remote Access ( SSL/TLS )",
86
	'server_user' => "Remote Access ( User Auth )",
87
	'server_tls_user' => "Remote Access ( SSL/TLS + User Auth )");
88

    
89
$openvpn_client_modes = array(
90
	'p2p_tls' => "Peer to Peer ( SSL/TLS )",
91
	'p2p_shared_key' => "Peer to Peer ( Shared Key )" );
92

    
93
function openvpn_create_key() {
94

    
95
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
96
	if (!$fp)
97
		return false;
98

    
99
	$rslt = stream_get_contents($fp);
100
	pclose($fp);
101

    
102
	return $rslt;
103
}
104

    
105
function openvpn_create_dhparams($bits) {
106

    
107
	$fp = popen("/usr/bin/openssl dhparam {$bits} 2>/dev/null", "r");
108
	if (!$fp)
109
		return false;
110

    
111
	$rslt = stream_get_contents($fp);
112
	pclose($fp);
113

    
114
	return $rslt;
115
}
116

    
117
function openvpn_vpnid_used($vpnid) {
118
	global $config;
119

    
120
	if (is_array($config['openvpn']['openvpn-server']))
121
		foreach ($config['openvpn']['openvpn-server'] as & $settings)
122
			if ($vpnid == $settings['vpnid'])
123
				return true;
124

    
125
	if (is_array($config['openvpn']['openvpn-client']))
126
		foreach ($config['openvpn']['openvpn-client'] as & $settings)
127
			if ($vpnid == $settings['vpnid'])
128
				return true;
129

    
130
	return false;
131
}
132

    
133
function openvpn_vpnid_next() {
134

    
135
	$vpnid = 1;
136
	while(openvpn_vpnid_used($vpnid))
137
		$vpnid++;
138

    
139
	return $vpnid;
140
}
141

    
142
function openvpn_port_used($prot, $port) {
143
	global $config;
144

    
145
	if (is_array($config['openvpn']['openvpn-server']))
146
		foreach ($config['openvpn']['openvpn-server'] as & $settings)
147
			if ($port == $settings['local_port'] &&
148
				$prot == $settings['protocol'] && !isset($settings['disable']))
149
				return $settings['vpnid'];
150

    
151
	if (is_array($config['openvpn']['openvpn-client']))
152
		foreach ($config['openvpn']['openvpn-client'] as & $settings)
153
			if ($port == $settings['local_port'] &&
154
				$prot == $settings['protocol'] && !isset($settings['disable']))
155
				return $settings['vpnid'];
156

    
157
	return 0;
158
}
159

    
160
function openvpn_port_next($prot) {
161

    
162
	$port = 1194;
163
	while(openvpn_port_used($prot, $port))
164
		$port++;
165

    
166
	return $port;
167
}
168

    
169
function openvpn_get_cipherlist() {
170

    
171
	$ciphers = array();
172
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
173
	$cipher_lines = explode("\n", trim($cipher_out));
174
	sort($cipher_lines);
175
	foreach ($cipher_lines as $line) {
176
		$words = explode(' ', $line);
177
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
178
	}
179
	$ciphers["none"] = "None (No Encryption)";
180
	return $ciphers;
181
}
182

    
183
function openvpn_get_engines() {
184
	$openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
185
	exec("/usr/bin/openssl engine", $openssl_engine_output);
186
	foreach ($openssl_engine_output as $oeo) {
187
		$linematch = array();
188
		preg_match("/\((.*)\)\s(.*)/", $oeo, $linematch);
189
		if ($linematch[1] != "dynamic")
190
			$openssl_engines[$linematch[1]] = $linematch[2];
191
	}
192
	return $openssl_engines;
193
}
194

    
195
function openvpn_validate_engine($engine) {
196
	$engines = openvpn_get_engines();
197
	return array_key_exists($engine, $engines);
198
}
199

    
200
function openvpn_validate_host($value, $name) {
201
	$value = trim($value);
202
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value)))
203
		return "The field '$name' must contain a valid IP address or domain name.";
204
	return false;
205
}
206

    
207
function openvpn_validate_port($value, $name) {
208
	$value = trim($value);
209
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535))
210
		return "The field '$name' must contain a valid port, ranging from 0 to 65535.";
211
	return false;
212
}
213

    
214
function openvpn_validate_cidr($value, $name) {
215
	$value = trim($value);
216
	if (!empty($value)) {
217
		list($ip, $mask) = explode('/', $value);
218
		if (!is_ipaddr($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
219
			return "The field '$name' must contain a valid CIDR range.";
220
	}
221
	return false;
222
}
223

    
224
function openvpn_add_dhcpopts(& $settings, & $conf) {
225

    
226
	if (!empty($settings['dns_domain'])) 
227
		$conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
228

    
229
	if (!empty($settings['dns_server1']))
230
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
231
	if (!empty($settings['dns_server2']))
232
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
233
	if (!empty($settings['dns_server3']))
234
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
235
	if (!empty($settings['dns_server4']))
236
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
237

    
238
	if (!empty($settings['ntp_server1']))
239
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
240
	if (!empty($settings['ntp_server2']))
241
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
242

    
243
	if ($settings['netbios_enable']) {
244

    
245
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0))
246
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
247
		if (!empty($settings['dhcp_nbtscope'])) 
248
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
249

    
250
		if (!empty($settings['wins_server1']))
251
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
252
		if (!empty($settings['wins_server2']))
253
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
254

    
255
		if (!empty($settings['nbdd_server1']))
256
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
257
	}
258

    
259
	if ($settings['gwredir']) 
260
		$conf .= "push \"redirect-gateway def1\"\n";
261
}
262

    
263
function openvpn_add_custom(& $settings, & $conf) {
264

    
265
	if ($settings['custom_options']) {
266

    
267
		$options = explode(';', $settings['custom_options']);
268

    
269
		if (is_array($options)) {
270
			foreach ($options as $option)
271
				$conf .= "$option\n";
272
		} else
273
			$conf .= "{$settings['custom_options']}\n";
274
	}
275
}
276

    
277
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
278
	global $g;
279

    
280
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
281
	file_put_contents($fpath, base64_decode($data));
282
	//chown($fpath, 'nobody');
283
	//chgrp($fpath, 'nobody');
284
	@chmod($fpath, 0600);
285

    
286
	$conf .= "{$directive} {$fpath} {$opt}\n";
287
}
288

    
289
function openvpn_reconfigure($mode, $settings) {
290
	global $g, $config;
291

    
292
	if (empty($settings))
293
		return;
294
	if (isset($settings['disable'])) 
295
		return;
296

    
297
	/*
298
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
299
	 * we use a vpnid number which is allocated for a particular client
300
	 * or server configuration. ( see openvpn_vpnid_next() )
301
	 */
302

    
303
	$vpnid = $settings['vpnid'];
304
	$mode_id = $mode.$vpnid;
305

    
306
	if (isset($settings['dev_mode']))
307
		$tunname = "{$settings['dev_mode']}{$vpnid}";
308
	else {	/* defaults to tun */
309
		$tunname = "tun{$vpnid}";
310
		$settings['dev_mode'] = "tun";
311
	}
312

    
313
	if ($mode == "server")
314
		$devname = "ovpns{$vpnid}";
315
	else
316
		$devname = "ovpnc{$vpnid}";
317

    
318
	/* is our device already configured */
319
	if (mwexec("/sbin/ifconfig {$devname}")) {
320

    
321
		/* create the tap device if required */
322
		if (!file_exists("/dev/{$tunname}"))
323
			exec("/sbin/ifconfig {$tunname} create");
324

    
325
		/* rename the device */
326
		mwexec("/sbin/ifconfig {$tunname} name {$devname}");
327

    
328
		/* add the device to the openvpn group */
329
		mwexec("/sbin/ifconfig {$devname} group openvpn");
330
	}
331

    
332
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
333
	$proto = ($settings['protocol'] == 'UDP' ? 'udp' : "tcp-{$mode}");
334
	$dev_mode = $settings['dev_mode'];
335
	$cipher = $settings['crypto'];
336

    
337
	$interface = $settings['interface'];
338
	$ipaddr = $settings['ipaddr'];
339

    
340
	// If a specific ip address (VIP) is requested, use it.
341
	// Otherwise, if a specific interface is requested, use it
342
	// If "any" interface was selected, local directive will be ommited.
343
	if (!empty($ipaddr)) {
344
		$iface_ip=$ipaddr;
345
	} else {
346
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
347
			$iface_ip=get_interface_ip($interface);
348
		}
349
	}
350

    
351
	$conf  = "dev {$devname}\n";
352
	$conf .= "dev-type {$settings['dev_mode']}\n";
353
	$conf .= "dev-node /dev/{$tunname}\n";
354
	$conf .= "writepid {$pfile}\n";
355
	$conf .= "#user nobody\n";
356
	$conf .= "#group nobody\n";
357
	$conf .= "script-security 3\n";
358
	$conf .= "daemon\n";
359
	$conf .= "keepalive 10 60\n";
360
	$conf .= "ping-timer-rem\n";
361
	$conf .= "persist-tun\n";
362
	$conf .= "persist-key\n";
363
	$conf .= "proto {$proto}\n";
364
	$conf .= "cipher {$cipher}\n";
365
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
366
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
367

    
368
	if (!empty($iface_ip)) {
369
		$conf .= "local {$iface_ip}\n";	
370
	}
371

    
372
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none"))
373
		$conf .= "engine {$settings['engine']}\n";
374

    
375
	// server specific settings
376
	if ($mode == 'server') {
377

    
378
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
379
		$mask = gen_subnet_mask($cidr);
380

    
381
		// configure tls modes
382
		switch($settings['mode']) {
383
			case 'p2p_tls':
384
			case 'server_tls':
385
			case 'server_user':
386
			case 'server_tls_user':
387
				$conf .= "tls-server\n";
388
				break;
389
		}
390

    
391
		// configure p2p/server modes
392
		switch($settings['mode']) {
393
			case 'p2p_tls':
394
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
395
				//  use the server directive. It works for a single client without it.
396
				//  See ticket #1417
397
				if ($cidr < 30) {
398
					$conf .= "server {$ip} {$mask}\n";
399
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
400
				}
401
			case 'p2p_shared_key':
402
				$baselong = ip2long32($ip) & ip2long($mask);
403
				$ip1 = long2ip32($baselong + 1);
404
				$ip2 = long2ip32($baselong + 2);
405
				$conf .= "ifconfig $ip1 $ip2\n";
406
				break;
407
			case 'server_tls':
408
			case 'server_user':
409
			case 'server_tls_user':
410
				$conf .= "server {$ip} {$mask}\n";
411
				$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
412
				break;
413
		}
414

    
415
		// configure user auth modes
416
		switch($settings['mode']) {
417
			case 'server_user':
418
				$conf .= "client-cert-not-required\n";
419
			case 'server_tls_user':
420
				$conf .= "username-as-common-name\n";
421
				if (!empty($settings['authmode'])) {
422
					$authcfgs = explode(",", $settings['authmode']);
423
					$sed = "\$authmodes=array(";
424
					$firstsed = 0;
425
					foreach ($authcfgs as $authcfg) {
426
						if ($firstsed > 0)
427
							$sed .= ",";
428
						$firstsed = 1;
429
						$sed .= "\"{$authcfg}\"";
430
					}
431
					$sed .= ");\\\n";
432
					if ($settings['strictusercn'])
433
						$sed .= "\$strictusercn = true;";
434
					$sed .= " \$modeid = \"{$mode_id}\";";
435
					mwexec("/bin/cat /etc/inc/openvpn.auth-user.php | /usr/bin/sed 's/\/\/<template>/{$sed}/g' >  {$g['varetc_path']}/openvpn/{$mode_id}.php");
436
					mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.php");
437
					$conf .= "auth-user-pass-verify {$g['varetc_path']}/openvpn/{$mode_id}.php via-env\n";
438
				}
439
				break;
440
		}
441
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls')))
442
			$settings['cert_depth'] = 1;
443
		if (is_numeric($settings['cert_depth'])) {
444
			$sed = "";
445
			$cert = lookup_cert($settings['certref']);
446
			$servercn = cert_get_cn($cert['crt']);
447
			$sed .= "\$server_cn = \"{$servercn}\";\\\n";
448
			$sed .= "\$allowed_depth = {$settings['cert_depth']};\\\n";
449
			mwexec("/bin/cat /etc/inc/openvpn.tls-verify.php | /usr/bin/sed 's/\/\/<template>/{$sed}/g' >  {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php");
450
			mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php");
451
			$conf .= "tls-verify {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php\n";
452
		}
453

    
454
		// The local port to listen on
455
		$conf .= "lport {$settings['local_port']}\n";
456

    
457
		// The management port to listen on
458
		// Use unix socket to overcome the problem on any type of server
459
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
460
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
461

    
462
		if ($settings['maxclients'])
463
			$conf .= "max-clients {$settings['maxclients']}\n";
464

    
465
		// Can we push routes
466
		if ($settings['local_network']) {
467
			list($ip, $mask) = explode('/', $settings['local_network']);
468
			$mask = gen_subnet_mask($mask);
469
			$conf .= "push \"route $ip $mask\"\n";
470
		}
471

    
472
		switch($settings['mode']) {
473
			case 'server_tls':
474
			case 'server_user':
475
			case 'server_tls_user':
476
				// Configure client dhcp options
477
				openvpn_add_dhcpopts($settings, $conf);
478
				if ($settings['client2client'])
479
					$conf .= "client-to-client\n";
480
				break;
481
		}
482
		if (isset($settings['duplicate_cn']))
483
			$conf .= "duplicate-cn\n";
484
	}
485

    
486
	// client specific settings
487

    
488
	if ($mode == 'client') {
489

    
490
		// configure p2p mode
491
		switch($settings['mode']) {
492
			case 'p2p_tls':
493
				$conf .= "tls-client\n";
494
			case 'shared_key':
495
				$conf .= "client\n";
496
				break;
497
		}
498

    
499
		// If there is no bind option at all (ip and/or port), add "nobind" directive
500
		//  Otherwise, use the local port if defined, failing that, use lport 0 to 
501
		//  ensure a random source port.
502
		if ((empty($iface_ip)) && (!$settings['local_port']))
503
			$conf .= "nobind\n";
504
		elseif ($settings['local_port'])
505
			$conf .= "lport {$settings['local_port']}\n";
506
		else
507
			$conf .= "lport 0\n";
508

    
509
		// Use unix socket to overcome the problem on any type of server
510
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
511

    
512
		// The remote server
513
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
514

    
515
		if (!empty($settings['use_shaper']))
516
			$conf .= "shaper {$settings['use_shaper']}\n";
517

    
518
		if (!empty($settings['tunnel_network'])) {
519
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
520
			$mask = gen_subnet_mask($mask);
521
			$baselong = ip2long32($ip) & ip2long($mask);
522
			$ip1 = long2ip32($baselong + 1);
523
			$ip2 = long2ip32($baselong + 2);
524
			$conf .= "ifconfig $ip2 $ip1\n";
525
		}
526

    
527
		if ($settings['proxy_addr']) {
528
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
529
			if ($settings['proxy_authtype'] != "none") {
530
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
531
				$proxypas = "{$settings['proxy_user']}\n";
532
				$proxypas .= "{$settings['proxy_passwd']}\n";
533
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
534
			}
535
			$conf .= " \n";
536
		}
537
	}
538

    
539
	// Add a remote network route if set, and only for p2p modes.
540
	if ((substr($settings['mode'], 0, 3) == "p2p") && is_subnet($settings['remote_network'])) {
541
		list($ip, $mask) = explode('/', $settings['remote_network']);
542
		$mask = gen_subnet_mask($mask);
543
		$conf .= "route $ip $mask\n";
544
	}
545

    
546
	// Write the settings for the keys
547
	switch($settings['mode']) {
548
		case 'p2p_shared_key':
549
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
550
			break;
551
		case 'p2p_tls':
552
		case 'server_tls':
553
		case 'server_tls_user':
554
		case 'server_user':
555
			$ca = lookup_ca($settings['caref']);
556
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
557
			$cert = lookup_cert($settings['certref']);
558
			openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
559
			openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
560
			if ($mode == 'server')
561
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
562
			if (!empty($settings['crlref'])) {
563
				$crl = lookup_crl($settings['crlref']);
564
				crl_update($crl);
565
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
566
			}
567
			if ($settings['tls']) {
568
				if ($mode == "server") 
569
					$tlsopt = 0;
570
				else
571
					$tlsopt = 1;
572
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
573
			}
574
			break;
575
	}
576

    
577
	if ($settings['compression'])
578
		$conf .= "comp-lzo\n";
579

    
580
	if ($settings['passtos'])
581
		$conf .= "passtos\n";
582

    
583
	if ($settings['resolve_retry'])
584
		$conf .= "resolv-retry infinite\n";
585

    
586
	if ($settings['dynamic_ip']) {
587
		$conf .= "persist-remote-ip\n";
588
		$conf .= "float\n";
589
	}
590

    
591
	openvpn_add_custom($settings, $conf);
592

    
593
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
594
	file_put_contents($fpath, $conf);
595
	//chown($fpath, 'nobody');
596
	//chgrp($fpath, 'nobody');
597
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
598
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
599
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
600
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
601
}
602

    
603
function openvpn_restart($mode, $settings) {
604
	global $g, $config;
605

    
606
	$vpnid = $settings['vpnid'];
607
	$mode_id = $mode.$vpnid;
608

    
609
	/* kill the process if running */
610
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
611
	if (file_exists($pfile)) {
612

    
613
		/* read the pid file */
614
		$pid = rtrim(file_get_contents($pfile));
615
		unlink($pfile);
616

    
617
		/* send a term signal to the process */
618
		posix_kill($pid, SIGTERM);
619

    
620
		/* wait until the process exits */
621
		while(posix_kill($pid, 0))
622
			usleep(250000);
623
	}
624

    
625
	if (isset($settings['disable']))
626
		return;
627

    
628
	/* start the new process */
629
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
630
	mwexec_bg("/usr/local/sbin/openvpn --config {$fpath}");
631

    
632
	if (!$g['booting'])
633
		send_event("filter reload");
634
}
635

    
636
function openvpn_delete($mode, & $settings) {
637
	global $g, $config;
638

    
639
	$vpnid = $settings['vpnid'];
640
	$mode_id = $mode.$vpnid;
641

    
642
	$tunname = "tun{$vpnid}";
643
	if ($mode == "server")
644
		$devname = "ovpns{$vpnid}";
645
	else
646
		$devname = "ovpnc{$vpnid}";
647

    
648
	/* kill the process if running */
649
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
650
	if (file_exists($pfile)) {
651

    
652
		/* read the pid file */
653
		$pid = trim(file_get_contents($pfile));
654
		unlink($pfile);
655

    
656
		/* send a term signal to the process */
657
		posix_kill($pid, SIGTERM);
658
	}
659

    
660
	/* remove the device from the openvpn group */
661
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
662

    
663
	/* restore the original adapter name */
664
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
665

    
666
	/* remove the configuration files */
667
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
668
}
669

    
670
function openvpn_resync_csc(& $settings) {
671
	global $g, $config;
672

    
673
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
674

    
675
	if (isset($settings['disable'])) {
676
		unlink_if_exists($fpath);
677
		return;
678
	}
679

    
680
	$conf = '';
681
	if ($settings['block'])
682
		$conf .= "disable\n";
683

    
684
	if ($settings['push_reset'])
685
		$conf .= "push-reset\n";
686

    
687
	if (!empty($settings['tunnel_network'])) {
688
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
689
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
690
		$serverip = long2ip32($baselong + 1);
691
		$clientip = long2ip32($baselong + 2);
692
		/* Because this is being pushed, the order from the client's point of view. */
693
		$conf .= "ifconfig-push {$clientip} {$serverip}\n";
694
	}
695

    
696
	openvpn_add_dhcpopts($settings, $conf);
697

    
698
	if ($settings['gwredir'])
699
		$conf .= "push \"redirect-gateway def1\"\n";
700

    
701
	openvpn_add_custom($settings, $conf);
702

    
703
	file_put_contents($fpath, $conf);
704
	chown($fpath, 'nobody');
705
	chgrp($fpath, 'nobody');
706
}
707

    
708
function openvpn_delete_csc(& $settings) {
709
	global $g, $config;
710

    
711
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
712
	unlink_if_exists($fpath);
713
}
714

    
715
// Resync the configuration and restart the VPN
716
function openvpn_resync($mode, $settings) {
717
	openvpn_reconfigure($mode, $settings);
718
	openvpn_restart($mode, $settings);
719
}
720

    
721
// Resync and restart all VPNs
722
function openvpn_resync_all($interface = "") {
723
	global $g, $config;
724

    
725
	// delay our setup until the system
726
	// has a chance to init our paths
727
	if (!file_exists($g['varetc_path']."/openvpn") ||
728
		!file_exists($g['varetc_path']."/openvpn-csc"))
729
		return;
730

    
731
	if (!is_array($config['openvpn']))
732
		$config['openvpn'] = array();
733

    
734
/*
735
	if (!$config['openvpn']['dh-parameters']) {
736
		echo "Configuring OpenVPN Parameters ...\n";
737
		$dh_parameters = openvpn_create_dhparams(1024);
738
		$dh_parameters = base64_encode($dh_parameters);
739
		$config['openvpn']['dh-parameters'] = $dh_parameters;
740
		write_config("OpenVPN DH parameters");
741
	}
742

    
743
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
744
	if (!file_exists($path_ovdh)) {
745
		$dh_parameters = $config['openvpn']['dh-parameters'];
746
		$dh_parameters = base64_decode($dh_parameters);
747
		file_put_contents($path_ovdh, $dh_parameters);
748
	}
749
*/
750
	if ($interface <> "")
751
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
752
	else
753
		log_error("Resyncing OpenVPN instances."); 
754

    
755
	if (is_array($config['openvpn']['openvpn-server'])) {
756
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
757
			if ($interface <> "" && $interface != $settings['interface'])
758
				continue;
759
			openvpn_resync('server', $settings);
760
		}
761
	}
762

    
763
	if (is_array($config['openvpn']['openvpn-client'])) {
764
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
765
			if ($interface <> "" && $interface != $settings['interface'])
766
				continue;
767
			openvpn_resync('client', $settings);
768
		}
769
	}
770

    
771
	if (is_array($config['openvpn']['openvpn-csc']))
772
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
773
			openvpn_resync_csc($settings);
774

    
775
}
776

    
777
function openvpn_get_active_servers($type="multipoint") {
778
	global $config, $g;
779

    
780
	$servers = array();
781
	if (is_array($config['openvpn']['openvpn-server'])) {
782
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
783
			if (empty($settings) || isset($settings['disable']))
784
				continue;
785

    
786
			$prot = $settings['protocol'];
787
			$port = $settings['local_port'];
788
	
789
			$server = array();
790
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
791
			$server['mode'] = $settings['mode'];
792
			if ($settings['description'])
793
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
794
			else
795
				$server['name'] = "Server {$prot}:{$port}";
796
			$server['conns'] = array();
797
	
798
			$vpnid = $settings['vpnid'];
799
			$mode_id = "server{$vpnid}";
800
			$server['mgmt'] = $mode_id;
801
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
802
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
803

    
804
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
805
				$servers[] = openvpn_get_client_status($server, $socket);
806
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
807
				$servers[] = openvpn_get_server_status($server, $socket);
808

    
809
		}
810
	}
811
	return $servers;
812
}
813

    
814
function openvpn_get_server_status($server, $socket) {
815
	$errval;
816
	$errstr;
817
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
818
	if ($fp) {
819
		stream_set_timeout($fp, 1);
820

    
821
		/* send our status request */
822
		fputs($fp, "status 2\n");
823

    
824
		/* recv all response lines */
825
		while (!feof($fp)) {
826

    
827
			/* read the next line */
828
			$line = fgets($fp, 1024);
829

    
830
			$info = stream_get_meta_data($fp);
831
			if ($info['timed_out'])
832
				break;
833

    
834
			/* parse header list line */
835
			if (strstr($line, "HEADER"))
836
				continue;
837

    
838
			/* parse end of output line */
839
			if (strstr($line, "END") || strstr($line, "ERROR"))
840
				break;
841

    
842
			/* parse client list line */
843
			if (strstr($line, "CLIENT_LIST")) {
844
				$list = explode(",", $line);
845
				$conn = array();
846
				$conn['common_name'] = $list[1];
847
				$conn['remote_host'] = $list[2];
848
				$conn['virtual_addr'] = $list[3];
849
				$conn['bytes_recv'] = $list[4];
850
				$conn['bytes_sent'] = $list[5];
851
				$conn['connect_time'] = $list[6];
852
				$server['conns'][] = $conn;
853
			}
854
		}
855

    
856
		/* cleanup */
857
		fclose($fp);
858
	} else {
859
		$conn = array();
860
		$conn['common_name'] = "[error]";
861
		$conn['remote_host'] = "Management Daemon Unreachable";
862
		$conn['virtual_addr'] = "";
863
		$conn['bytes_recv'] = 0;
864
		$conn['bytes_sent'] = 0;
865
		$conn['connect_time'] = 0;
866
		$server['conns'][] = $conn;
867
	}
868
	return $server;
869
}
870

    
871
function openvpn_get_active_clients() {
872
	global $config, $g;
873

    
874
	$clients = array();
875
	if (is_array($config['openvpn']['openvpn-client'])) {
876
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
877
	
878
			if (empty($settings) || isset($settings['disable']))
879
				continue;
880

    
881
			$prot = $settings['protocol'];
882
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
883
	
884
			$client = array();
885
			$client['port'] = $settings['local_port'];
886
			if ($settings['description'])
887
				$client['name'] = "{$settings['description']} {$prot}{$port}";
888
			else
889
				$client['name'] = "Client {$prot}{$port}";
890
	
891
			$vpnid = $settings['vpnid'];
892
			$mode_id = "client{$vpnid}";
893
			$client['mgmt'] = $mode_id;
894
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
895
			$client['status']="down";
896

    
897
			$clients[] = openvpn_get_client_status($client, $socket);
898
		}
899
	}
900
	return $clients;
901
}
902

    
903
function openvpn_get_client_status($client, $socket) {
904
	$errval;
905
	$errstr;
906
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
907
	if ($fp) {
908
		stream_set_timeout($fp, 1);
909
		/* send our status request */
910
		fputs($fp, "state 1\n");
911

    
912
		/* recv all response lines */
913
		while (!feof($fp)) {
914
			/* read the next line */
915
			$line = fgets($fp, 1024);
916

    
917
			$info = stream_get_meta_data($fp);
918
			if ($info['timed_out'])
919
				break;
920

    
921
			/* Get the client state */
922
			if (strstr($line,"CONNECTED")) {
923
				$client['status']="up";
924
				$list = explode(",", $line);
925

    
926
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
927
				$client['virtual_addr']  = $list[3];
928
				$client['remote_host'] = $list[4];
929
			}
930
			if (strstr($line,"CONNECTING")) {
931
				$client['status']="connecting";
932
			}
933
			if (strstr($line,"ASSIGN_IP")) {
934
				$client['status']="waiting";
935
				$list = explode(",", $line);
936

    
937
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
938
				$client['virtual_addr']  = $list[3];
939
			}
940
			if (strstr($line,"RECONNECTING")) {
941
				$client['status']="reconnecting";
942
				$list = explode(",", $line);
943

    
944
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
945
				$client['status'] .= "; " . $list[2];
946
			}
947
			/* parse end of output line */
948
			if (strstr($line, "END") || strstr($line, "ERROR"))
949
				break;
950
		}
951

    
952
		/* If up, get read/write stats */
953
		if (strcmp($client['status'], "up") == 0) {
954
			fputs($fp, "status 2\n");
955
			/* recv all response lines */
956
			while (!feof($fp)) {
957
				/* read the next line */
958
				$line = fgets($fp, 1024);
959

    
960
				$info = stream_get_meta_data($fp);
961
				if ($info['timed_out'])
962
					break;
963

    
964
				if (strstr($line,"TCP/UDP read bytes")) {
965
					$list = explode(",", $line);
966
					$client['bytes_recv'] = $list[1];
967
				}
968

    
969
				if (strstr($line,"TCP/UDP write bytes")) {
970
					$list = explode(",", $line);
971
					$client['bytes_sent'] = $list[1];
972
				}
973

    
974
				/* parse end of output line */
975
				if (strstr($line, "END"))
976
					break;
977
			}
978
		}
979

    
980
		fclose($fp);
981

    
982
	} else {
983
		$DisplayNote=true;
984
		$client['remote_host'] = "No Management Daemon";
985
		$client['virtual_addr'] = "See Note Below";
986
		$client['bytes_recv'] = 0;
987
		$client['bytes_sent'] = 0;
988
		$client['connect_time'] = 0;
989
	}
990
	return $client;
991
}
992

    
993
function openvpn_refresh_crls() {
994
	global $g, $config;
995

    
996
	if (!file_exists($g['varetc_path']."/openvpn"))
997
		return;
998

    
999
	if (is_array($config['openvpn']['openvpn-server'])) {
1000
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1001
			if (empty($settings))
1002
				continue;
1003
			if (isset($settings['disable']))
1004
				continue;
1005
			// Write the settings for the keys
1006
			switch($settings['mode']) {
1007
				case 'p2p_tls':
1008
				case 'server_tls':
1009
				case 'server_tls_user':
1010
				case 'server_user':
1011
					if (!empty($settings['crlref'])) {
1012
						$crl = lookup_crl($settings['crlref']);
1013
						crl_update($crl);
1014
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1015
						file_put_contents($fpath, base64_decode($crl['text']));
1016
						@chmod($fpath, 0644);
1017
					}
1018
					break;
1019
			}
1020
		}
1021
	}
1022
}
1023

    
1024
?>
(34-34/62)