Project

General

Profile

Download (30.6 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
				list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
403
				$conf .= "ifconfig $ip1 $ip2\n";
404
				break;
405
			case 'server_tls':
406
			case 'server_user':
407
			case 'server_tls_user':
408
				$conf .= "server {$ip} {$mask}\n";
409
				$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
410
				break;
411
		}
412

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

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

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

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

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

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

    
484
	// client specific settings
485

    
486
	if ($mode == 'client') {
487

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

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

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

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

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

    
516
		if (!empty($settings['tunnel_network'])) {
517
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
518
			$mask = gen_subnet_mask($mask);
519
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
520
			$conf .= "ifconfig $ip2 $ip1\n";
521
		}
522

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

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

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

    
573
	if ($settings['compression'])
574
		$conf .= "comp-lzo\n";
575

    
576
	if ($settings['passtos'])
577
		$conf .= "passtos\n";
578

    
579
	if ($settings['resolve_retry'])
580
		$conf .= "resolv-retry infinite\n";
581

    
582
	if ($settings['dynamic_ip']) {
583
		$conf .= "persist-remote-ip\n";
584
		$conf .= "float\n";
585
	}
586

    
587
	openvpn_add_custom($settings, $conf);
588

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

    
599
function openvpn_restart($mode, $settings) {
600
	global $g, $config;
601

    
602
	$vpnid = $settings['vpnid'];
603
	$mode_id = $mode.$vpnid;
604

    
605
	/* kill the process if running */
606
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
607
	if (file_exists($pfile)) {
608

    
609
		/* read the pid file */
610
		$pid = rtrim(file_get_contents($pfile));
611
		unlink($pfile);
612

    
613
		/* send a term signal to the process */
614
		posix_kill($pid, SIGTERM);
615

    
616
		/* wait until the process exits */
617
		while(posix_kill($pid, 0))
618
			usleep(250000);
619
	}
620

    
621
	if (isset($settings['disable']))
622
		return;
623

    
624
	/* Do not start a client if we are a CARP backup on this vip! */
625
	if (($mode == "client") && (substr($settings['interface'], 0, 3) == "vip") && (get_carp_interface_status($settings['interface']) == "BACKUP"))
626
		return;
627

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
697
	openvpn_add_dhcpopts($settings, $conf);
698

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

    
702
	openvpn_add_custom($settings, $conf);
703

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

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

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

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

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

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

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

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

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

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

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

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

    
776
}
777

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
981
		fclose($fp);
982

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

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

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

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

    
1025
function openvpn_get_interface_ip($ip, $mask) {
1026
	$baselong = ip2long32($ip) & ip2long($mask);
1027
	$ip1 = long2ip32($baselong + 1);
1028
	$ip2 = long2ip32($baselong + 2);
1029
	return array($ip1, $ip2);
1030
}
1031

    
1032
function openvpn_clear_route($mode, $settings) {
1033
	if (empty($settings['tunnel_network']))
1034
		return;
1035
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1036
	$mask = gen_subnet_mask($cidr);
1037
	switch($settings['mode']) {
1038
		case 'p2p_tls':
1039
		case 'p2p_shared_key':
1040
		case 'shared_key':
1041
			if (!empty($ip) && !empty($mask) && ($cidr == 30)) {
1042
				list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1043
				$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1044
				mwexec("/sbin/route -q delete {$ip_to_clear}");
1045
			}
1046
			break;
1047
	}
1048
}
1049

    
1050
function openvpn_get_settings($mode, $vpnid) {
1051
	global $config;
1052

    
1053
	if (is_array($config['openvpn']['openvpn-server'])) {
1054
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1055
			if (isset($settings['disable']))
1056
				continue;
1057

    
1058
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1059
				return $settings;
1060
		}
1061
	}
1062

    
1063
	if (is_array($config['openvpn']['openvpn-client'])) {
1064
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1065
			if (isset($settings['disable']))
1066
				continue;
1067

    
1068
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1069
				return $settings;
1070
		}
1071
	}
1072

    
1073
	return array();
1074
}
1075

    
1076
function openvpn_restart_by_vpnid($mode, $vpnid) {
1077
	$settings = openvpn_get_settings($mode, $vpnid);
1078
	openvpn_restart($mode, $settings);
1079
}
1080

    
1081
?>
(33-33/61)