Project

General

Profile

Download (29.2 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
	/* Do not start if we are a CARP backup on this vip! */
629
	if ((substr($settings['interface'], 0, 3) == "vip") && (get_carp_interface_status($settings['interface']) == "BACKUP"))
630
		return;
631

    
632
	/* start the new process */
633
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
634
	mwexec_bg("/usr/local/sbin/openvpn --config {$fpath}");
635

    
636
	if (!$g['booting'])
637
		send_event("filter reload");
638
}
639

    
640
function openvpn_delete($mode, & $settings) {
641
	global $g, $config;
642

    
643
	$vpnid = $settings['vpnid'];
644
	$mode_id = $mode.$vpnid;
645

    
646
	$tunname = "tun{$vpnid}";
647
	if ($mode == "server")
648
		$devname = "ovpns{$vpnid}";
649
	else
650
		$devname = "ovpnc{$vpnid}";
651

    
652
	/* kill the process if running */
653
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
654
	if (file_exists($pfile)) {
655

    
656
		/* read the pid file */
657
		$pid = trim(file_get_contents($pfile));
658
		unlink($pfile);
659

    
660
		/* send a term signal to the process */
661
		posix_kill($pid, SIGTERM);
662
	}
663

    
664
	/* remove the device from the openvpn group */
665
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
666

    
667
	/* restore the original adapter name */
668
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
669

    
670
	/* remove the configuration files */
671
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
672
}
673

    
674
function openvpn_resync_csc(& $settings) {
675
	global $g, $config;
676

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

    
679
	if (isset($settings['disable'])) {
680
		unlink_if_exists($fpath);
681
		return;
682
	}
683

    
684
	$conf = '';
685
	if ($settings['block'])
686
		$conf .= "disable\n";
687

    
688
	if ($settings['push_reset'])
689
		$conf .= "push-reset\n";
690

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

    
700
	openvpn_add_dhcpopts($settings, $conf);
701

    
702
	if ($settings['gwredir'])
703
		$conf .= "push \"redirect-gateway def1\"\n";
704

    
705
	openvpn_add_custom($settings, $conf);
706

    
707
	file_put_contents($fpath, $conf);
708
	chown($fpath, 'nobody');
709
	chgrp($fpath, 'nobody');
710
}
711

    
712
function openvpn_delete_csc(& $settings) {
713
	global $g, $config;
714

    
715
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
716
	unlink_if_exists($fpath);
717
}
718

    
719
// Resync the configuration and restart the VPN
720
function openvpn_resync($mode, $settings) {
721
	openvpn_reconfigure($mode, $settings);
722
	openvpn_restart($mode, $settings);
723
}
724

    
725
// Resync and restart all VPNs
726
function openvpn_resync_all($interface = "") {
727
	global $g, $config;
728

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

    
735
	if (!is_array($config['openvpn']))
736
		$config['openvpn'] = array();
737

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

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

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

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

    
775
	if (is_array($config['openvpn']['openvpn-csc']))
776
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
777
			openvpn_resync_csc($settings);
778

    
779
}
780

    
781
function openvpn_get_active_servers($type="multipoint") {
782
	global $config, $g;
783

    
784
	$servers = array();
785
	if (is_array($config['openvpn']['openvpn-server'])) {
786
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
787
			if (empty($settings) || isset($settings['disable']))
788
				continue;
789

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

    
808
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
809
				$servers[] = openvpn_get_client_status($server, $socket);
810
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
811
				$servers[] = openvpn_get_server_status($server, $socket);
812

    
813
		}
814
	}
815
	return $servers;
816
}
817

    
818
function openvpn_get_server_status($server, $socket) {
819
	$errval;
820
	$errstr;
821
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
822
	if ($fp) {
823
		stream_set_timeout($fp, 1);
824

    
825
		/* send our status request */
826
		fputs($fp, "status 2\n");
827

    
828
		/* recv all response lines */
829
		while (!feof($fp)) {
830

    
831
			/* read the next line */
832
			$line = fgets($fp, 1024);
833

    
834
			$info = stream_get_meta_data($fp);
835
			if ($info['timed_out'])
836
				break;
837

    
838
			/* parse header list line */
839
			if (strstr($line, "HEADER"))
840
				continue;
841

    
842
			/* parse end of output line */
843
			if (strstr($line, "END") || strstr($line, "ERROR"))
844
				break;
845

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

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

    
875
function openvpn_get_active_clients() {
876
	global $config, $g;
877

    
878
	$clients = array();
879
	if (is_array($config['openvpn']['openvpn-client'])) {
880
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
881
	
882
			if (empty($settings) || isset($settings['disable']))
883
				continue;
884

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

    
901
			$clients[] = openvpn_get_client_status($client, $socket);
902
		}
903
	}
904
	return $clients;
905
}
906

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

    
916
		/* recv all response lines */
917
		while (!feof($fp)) {
918
			/* read the next line */
919
			$line = fgets($fp, 1024);
920

    
921
			$info = stream_get_meta_data($fp);
922
			if ($info['timed_out'])
923
				break;
924

    
925
			/* Get the client state */
926
			if (strstr($line,"CONNECTED")) {
927
				$client['status']="up";
928
				$list = explode(",", $line);
929

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

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

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

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

    
964
				$info = stream_get_meta_data($fp);
965
				if ($info['timed_out'])
966
					break;
967

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

    
973
				if (strstr($line,"TCP/UDP write bytes")) {
974
					$list = explode(",", $line);
975
					$client['bytes_sent'] = $list[1];
976
				}
977

    
978
				/* parse end of output line */
979
				if (strstr($line, "END"))
980
					break;
981
			}
982
		}
983

    
984
		fclose($fp);
985

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

    
997
function openvpn_refresh_crls() {
998
	global $g, $config;
999

    
1000
	if (!file_exists($g['varetc_path']."/openvpn"))
1001
		return;
1002

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

    
1028
?>
(34-34/62)