Project

General

Profile

Download (32.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' => gettext("Peer to Peer ( SSL/TLS )"),
84
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
85
	'server_tls' => gettext("Remote Access ( SSL/TLS )"),
86
	'server_user' => gettext("Remote Access ( User Auth )"),
87
	'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
88

    
89
$openvpn_client_modes = array(
90
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
91
	'p2p_shared_key' => gettext("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"] = gettext("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 sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $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 sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
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 sprintf(gettext("The field '%s' must contain a valid CIDR range."), $name);
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 = get_failover_interface($settings['interface']);
338
	/* we will fill out these variables below. */
339
	// $ipaddr = $settings['ipaddr'];
340
	// $ipaddrv6 = $settings['ipaddrv6'];
341

    
342
	// If a specific ip address (VIP) is requested, use it.
343
	// Otherwise, if a specific interface is requested, use it
344
	// If "any" interface was selected, local directive will be ommited.
345
	if (is_ipaddrv4($ipaddr)) {
346
		$iface_ip=$ipaddr;
347
	} else {
348
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
349
			$iface_ip=get_interface_ip($interface);
350
		}
351
	}
352
	if (is_ipaddrv6($ipaddrv6)) {
353
		$iface_ipv6=$ipaddrv6;
354
	} else {
355
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
356
			$iface_ipv6=get_interface_ipv6($interface);
357
		}
358
	}
359

    
360
	$conf  = "dev {$devname}\n";
361
	$conf .= "dev-type {$settings['dev_mode']}\n";
362
	switch($settings['dev_mode']) {
363
		case "tun":
364
			$conf .= "tun-ipv6\n";
365
			break;
366
	}
367
	$conf .= "dev-node /dev/{$tunname}\n";
368
	$conf .= "writepid {$pfile}\n";
369
	$conf .= "#user nobody\n";
370
	$conf .= "#group nobody\n";
371
	$conf .= "script-security 3\n";
372
	$conf .= "daemon\n";
373
	$conf .= "keepalive 10 60\n";
374
	$conf .= "ping-timer-rem\n";
375
	$conf .= "persist-tun\n";
376
	$conf .= "persist-key\n";
377
	$conf .= "proto {$proto}\n";
378
	$conf .= "cipher {$cipher}\n";
379
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
380
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
381
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
382
		switch($settings['mode']) {
383
			case 'server_user':
384
			case 'server_tls_user':
385
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
386
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
387
				break;
388
		}
389
	}
390

    
391
	if (is_ipaddrv4($iface_ip)) {
392
		$conf .= "local {$iface_ip}\n";	
393
	} elseif (is_ipaddrv6($iface_ipv6)) {
394
		$conf .= "local {$iface_ipv6}\n";	
395
	}
396

    
397
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none"))
398
		$conf .= "engine {$settings['engine']}\n";
399

    
400
	// server specific settings
401
	if ($mode == 'server') {
402

    
403
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
404
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
405
		$mask = gen_subnet_mask($cidr);
406

    
407
		// configure tls modes
408
		switch($settings['mode']) {
409
			case 'p2p_tls':
410
			case 'server_tls':
411
			case 'server_user':
412
			case 'server_tls_user':
413
				$conf .= "tls-server\n";
414
				break;
415
		}
416

    
417
		// configure p2p/server modes
418
		switch($settings['mode']) {
419
			case 'p2p_tls':
420
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
421
				//  use the server directive. It works for a single client without it.
422
				//  See ticket #1417
423
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
424
					$conf .= "server {$ip} {$mask}\n";
425
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
426
				}
427
			case 'p2p_shared_key':
428
				if (!empty($ip) && !empty($mask)) {
429
					$baselong = ip2long32($ip) & ip2long($mask);
430
					$ip1 = long2ip32($baselong + 1);
431
					$ip2 = long2ip32($baselong + 2);
432
					if ($settings['dev_mode'] == 'tun')
433
						$conf .= "ifconfig {$ip1} {$ip2}\n";
434
					else
435
						$conf .= "ifconfig {$ip1} {$mask}\n";
436
				}
437
				break;
438
			case 'server_tls':
439
			case 'server_user':
440
			case 'server_tls_user':
441
				if (!empty($ip) && !empty($mask)) {
442
					$conf .= "server {$ip} {$mask}\n";
443
					if(is_ipaddr($ipv6))
444
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
445
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
446
				} else {
447
					if ($settings['serverbridge_dhcp']) {
448
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
449
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
450
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
451
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
452
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
453
							} else {
454
								$conf .= "mode server\n";
455
							}
456
						} else {
457
							$conf .= "mode server\n";
458
						}
459
					}
460
				}
461
				break;
462
		}
463

    
464
		// configure user auth modes
465
		switch($settings['mode']) {
466
			case 'server_user':
467
				$conf .= "client-cert-not-required\n";
468
			case 'server_tls_user':
469
				/* username-as-common-name is not compatible with server-bridge */
470
				if (stristr($conf, "server-bridge") === false)
471
					$conf .= "username-as-common-name\n";
472
				if (!empty($settings['authmode'])) {
473
					$authcfgs = explode(",", $settings['authmode']);
474
					$sed = "\$authmodes=array(";
475
					$firstsed = 0;
476
					foreach ($authcfgs as $authcfg) {
477
						if ($firstsed > 0)
478
							$sed .= ",";
479
						$firstsed = 1;
480
						$sed .= "\"{$authcfg}\"";
481
					}
482
					$sed .= ");\\\n";
483
					if ($settings['strictusercn'])
484
						$sed .= "\$strictusercn = true;";
485
					$sed .= " \$modeid = \"{$mode_id}\";";
486
					mwexec("/bin/cat /etc/inc/openvpn.auth-user.php | /usr/bin/sed 's/\/\/<template>/{$sed}/g' >  {$g['varetc_path']}/openvpn/{$mode_id}.php");
487
					mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.php");
488
					$conf .= "auth-user-pass-verify {$g['varetc_path']}/openvpn/{$mode_id}.php via-env\n";
489
				}
490
				break;
491
		}
492
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls')))
493
			$settings['cert_depth'] = 1;
494
		if (is_numeric($settings['cert_depth'])) {
495
			$sed = "";
496
			$cert = lookup_cert($settings['certref']);
497
			$servercn = cert_get_cn($cert['crt']);
498
			$sed .= "\$server_cn = \"{$servercn}\";\\\n";
499
			$sed .= "\$allowed_depth = {$settings['cert_depth']};\\\n";
500
			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");
501
			mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php");
502
			$conf .= "tls-verify {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php\n";
503
		}
504

    
505
		// The local port to listen on
506
		$conf .= "lport {$settings['local_port']}\n";
507

    
508
		// The management port to listen on
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
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
512

    
513
		if ($settings['maxclients'])
514
			$conf .= "max-clients {$settings['maxclients']}\n";
515

    
516
		// Can we push routes
517
		if ($settings['local_network']) {
518
			list($ip, $mask) = explode('/', $settings['local_network']);
519
			$mask = gen_subnet_mask($mask);
520
			$conf .= "push \"route $ip $mask\"\n";
521
		}
522
		if ($settings['local_networkv6']) {
523
			list($ipv6, $prefix) = explode('/', $settings['local_networkv6']);
524
			if (empty($prefix))
525
				$prefix = "128";
526
			$conf .= "push \"route-ipv6 $ipv6/$prefix\"\n";
527
		}
528

    
529
		switch($settings['mode']) {
530
			case 'server_tls':
531
			case 'server_user':
532
			case 'server_tls_user':
533
				// Configure client dhcp options
534
				openvpn_add_dhcpopts($settings, $conf);
535
				if ($settings['client2client'])
536
					$conf .= "client-to-client\n";
537
				break;
538
		}
539
		if (isset($settings['duplicate_cn']))
540
			$conf .= "duplicate-cn\n";
541
	}
542

    
543
	// client specific settings
544

    
545
	if ($mode == 'client') {
546

    
547
		// configure p2p mode
548
		switch($settings['mode']) {
549
			case 'p2p_tls':
550
				$conf .= "tls-client\n";
551
			case 'shared_key':
552
				$conf .= "client\n";
553
				break;
554
		}
555

    
556
		// If there is no bind option at all (ip and/or port), add "nobind" directive
557
		//  Otherwise, use the local port if defined, failing that, use lport 0 to 
558
		//  ensure a random source port.
559
		if ((empty($iface_ip)) && (!$settings['local_port']))
560
			$conf .= "nobind\n";
561
		elseif ($settings['local_port'])
562
			$conf .= "lport {$settings['local_port']}\n";
563
		else
564
			$conf .= "lport 0\n";
565

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

    
569
		// The remote server
570
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
571

    
572
		if (!empty($settings['use_shaper']))
573
			$conf .= "shaper {$settings['use_shaper']}\n";
574

    
575
		if (!empty($settings['tunnel_network'])) {
576
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
577
			$mask = gen_subnet_mask($mask);
578
			$baselong = ip2long32($ip) & ip2long($mask);
579
			$ip1 = long2ip32($baselong + 1);
580
			$ip2 = long2ip32($baselong + 2);
581
			if ($settings['dev_mode'] == 'tun')
582
				$conf .= "ifconfig {$ip2} {$ip1}\n";
583
			else
584
				$conf .= "ifconfig {$ip2} {$mask}\n";
585
		}
586

    
587
		if ($settings['proxy_addr']) {
588
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
589
			if ($settings['proxy_authtype'] != "none") {
590
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
591
				$proxypas = "{$settings['proxy_user']}\n";
592
				$proxypas .= "{$settings['proxy_passwd']}\n";
593
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
594
			}
595
			$conf .= " \n";
596
		}
597
	}
598

    
599
	// Add a remote network route if set, and only for p2p modes.
600
	if ((substr($settings['mode'], 0, 3) == "p2p") && is_subnet($settings['remote_network'])) {
601
		list($ip, $mask) = explode('/', $settings['remote_network']);
602
		$mask = gen_subnet_mask($mask);
603
		$conf .= "route $ip $mask\n";
604
	}
605
	// Add a remote network route if set, and only for p2p modes.
606
	if ((substr($settings['mode'], 0, 3) == "p2p") && is_subnet($settings['remote_networkv6'])) {
607
		list($ipv6, $prefix) = explode('/', $settings['remote_networkv6']);
608
		if (empty($prefix))
609
			$prefix = "128";
610
		$conf .= "route-ipv6 ${ipv6}/${prefix}\n";
611
	}
612

    
613
	// Write the settings for the keys
614
	switch($settings['mode']) {
615
		case 'p2p_shared_key':
616
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
617
			break;
618
		case 'p2p_tls':
619
		case 'server_tls':
620
		case 'server_tls_user':
621
		case 'server_user':
622
			$ca = lookup_ca($settings['caref']);
623
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
624
			$cert = lookup_cert($settings['certref']);
625
			openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
626
			openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
627
			if ($mode == 'server')
628
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
629
			if (!empty($settings['crlref'])) {
630
				$crl = lookup_crl($settings['crlref']);
631
				crl_update($crl);
632
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
633
			}
634
			if ($settings['tls']) {
635
				if ($mode == "server") 
636
					$tlsopt = 0;
637
				else
638
					$tlsopt = 1;
639
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
640
			}
641
			break;
642
	}
643

    
644
	if ($settings['compression'])
645
		$conf .= "comp-lzo\n";
646

    
647
	if ($settings['passtos'])
648
		$conf .= "passtos\n";
649

    
650
	if ($settings['resolve_retry'])
651
		$conf .= "resolv-retry infinite\n";
652

    
653
	if ($settings['dynamic_ip']) {
654
		$conf .= "persist-remote-ip\n";
655
		$conf .= "float\n";
656
	}
657

    
658
	openvpn_add_custom($settings, $conf);
659

    
660
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
661
	file_put_contents($fpath, $conf);
662
	//chown($fpath, 'nobody');
663
	//chgrp($fpath, 'nobody');
664
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
665
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
666
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
667
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
668
}
669

    
670
function openvpn_restart($mode, $settings) {
671
	global $g, $config;
672

    
673
	$vpnid = $settings['vpnid'];
674
	$mode_id = $mode.$vpnid;
675

    
676
	/* kill the process if running */
677
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
678
	if (file_exists($pfile)) {
679

    
680
		/* read the pid file */
681
		$pid = rtrim(file_get_contents($pfile));
682
		unlink($pfile);
683

    
684
		/* send a term signal to the process */
685
		posix_kill($pid, SIGTERM);
686

    
687
		/* wait until the process exits */
688
		while(posix_kill($pid, 0))
689
			usleep(250000);
690
	}
691

    
692
	if (isset($settings['disable']))
693
		return;
694

    
695
	/* Do not start a client if we are a CARP backup on this vip! */
696
	if (($mode == "client") && strstr($settings['interface'], "_vip") && (get_carp_interface_status($settings['interface']) == "BACKUP"))
697
		return;
698

    
699
	/* start the new process */
700
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
701
	mwexec_bg("/usr/local/sbin/openvpn --config {$fpath}");
702

    
703
	if (!$g['booting'])
704
		send_event("filter reload");
705
}
706

    
707
function openvpn_delete($mode, & $settings) {
708
	global $g, $config;
709

    
710
	$vpnid = $settings['vpnid'];
711
	$mode_id = $mode.$vpnid;
712

    
713
	if (isset($settings['dev_mode']))
714
		$tunname = "{$settings['dev_mode']}{$vpnid}";
715
	else {  /* defaults to tun */
716
		$tunname = "tun{$vpnid}";
717
	}
718

    
719
	if ($mode == "server")
720
		$devname = "ovpns{$vpnid}";
721
	else
722
		$devname = "ovpnc{$vpnid}";
723

    
724
	/* kill the process if running */
725
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
726
	if (file_exists($pfile)) {
727

    
728
		/* read the pid file */
729
		$pid = trim(file_get_contents($pfile));
730
		unlink($pfile);
731

    
732
		/* send a term signal to the process */
733
		posix_kill($pid, SIGTERM);
734
	}
735

    
736
	/* remove the device from the openvpn group */
737
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
738

    
739
	/* restore the original adapter name */
740
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
741

    
742
	/* remove the configuration files */
743
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
744
}
745

    
746
function openvpn_resync_csc(& $settings) {
747
	global $g, $config;
748

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

    
751
	if (isset($settings['disable'])) {
752
		unlink_if_exists($fpath);
753
		return;
754
	}
755

    
756
	$conf = '';
757
	if ($settings['block'])
758
		$conf .= "disable\n";
759

    
760
	if ($settings['push_reset'])
761
		$conf .= "push-reset\n";
762

    
763
	if (!empty($settings['tunnel_network'])) {
764
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
765
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
766
		$serverip = long2ip32($baselong + 1);
767
		$clientip = long2ip32($baselong + 2);
768
		/* Because this is being pushed, the order from the client's point of view. */
769
		if ($settings['dev_mode'] != 'tap')
770
			$conf .= "ifconfig-push {$clientip} {$serverip}\n";
771
		else
772
			$conf .= "ifconfig-push {$clientip} {$mask}\n";
773
	}
774

    
775
	openvpn_add_dhcpopts($settings, $conf);
776

    
777
	if ($settings['gwredir'])
778
		$conf .= "push \"redirect-gateway def1\"\n";
779

    
780
	openvpn_add_custom($settings, $conf);
781

    
782
	file_put_contents($fpath, $conf);
783
	chown($fpath, 'nobody');
784
	chgrp($fpath, 'nobody');
785
}
786

    
787
function openvpn_delete_csc(& $settings) {
788
	global $g, $config;
789

    
790
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
791
	unlink_if_exists($fpath);
792
}
793

    
794
// Resync the configuration and restart the VPN
795
function openvpn_resync($mode, $settings) {
796
	openvpn_reconfigure($mode, $settings);
797
	openvpn_restart($mode, $settings);
798
}
799

    
800
// Resync and restart all VPNs
801
function openvpn_resync_all($interface = "") {
802
	global $g, $config;
803

    
804
	if ($g['platform'] == 'jail')
805
		return;
806
	// delay our setup until the system
807
	// has a chance to init our paths
808
	if (!file_exists($g['varetc_path']."/openvpn") ||
809
		!file_exists($g['varetc_path']."/openvpn-csc"))
810
		return;
811

    
812
	if (!is_array($config['openvpn']))
813
		$config['openvpn'] = array();
814

    
815
/*
816
	if (!$config['openvpn']['dh-parameters']) {
817
		echo "Configuring OpenVPN Parameters ...\n";
818
		$dh_parameters = openvpn_create_dhparams(1024);
819
		$dh_parameters = base64_encode($dh_parameters);
820
		$config['openvpn']['dh-parameters'] = $dh_parameters;
821
		write_config("OpenVPN DH parameters");
822
	}
823

    
824
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
825
	if (!file_exists($path_ovdh)) {
826
		$dh_parameters = $config['openvpn']['dh-parameters'];
827
		$dh_parameters = base64_decode($dh_parameters);
828
		file_put_contents($path_ovdh, $dh_parameters);
829
	}
830
*/
831
	if ($interface <> "")
832
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
833
	else
834
		log_error("Resyncing OpenVPN instances."); 
835

    
836
	if (is_array($config['openvpn']['openvpn-server'])) {
837
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
838
			if ($interface <> "" && $interface != $settings['interface'])
839
				continue;
840
			openvpn_resync('server', $settings);
841
		}
842
	}
843

    
844
	if (is_array($config['openvpn']['openvpn-client'])) {
845
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
846
			if ($interface <> "" && $interface != $settings['interface'])
847
				continue;
848
			openvpn_resync('client', $settings);
849
		}
850
	}
851

    
852
	if (is_array($config['openvpn']['openvpn-csc']))
853
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
854
			openvpn_resync_csc($settings);
855

    
856
}
857

    
858
function openvpn_get_active_servers($type="multipoint") {
859
	global $config, $g;
860

    
861
	$servers = array();
862
	if (is_array($config['openvpn']['openvpn-server'])) {
863
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
864
			if (empty($settings) || isset($settings['disable']))
865
				continue;
866

    
867
			$prot = $settings['protocol'];
868
			$port = $settings['local_port'];
869
	
870
			$server = array();
871
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
872
			$server['mode'] = $settings['mode'];
873
			if ($settings['description'])
874
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
875
			else
876
				$server['name'] = "Server {$prot}:{$port}";
877
			$server['conns'] = array();
878
	
879
			$vpnid = $settings['vpnid'];
880
			$mode_id = "server{$vpnid}";
881
			$server['mgmt'] = $mode_id;
882
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
883
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
884

    
885
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
886
				$servers[] = openvpn_get_client_status($server, $socket);
887
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
888
				$servers[] = openvpn_get_server_status($server, $socket);
889

    
890
		}
891
	}
892
	return $servers;
893
}
894

    
895
function openvpn_get_server_status($server, $socket) {
896
	$errval;
897
	$errstr;
898
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
899
	if ($fp) {
900
		stream_set_timeout($fp, 1);
901

    
902
		/* send our status request */
903
		fputs($fp, "status 2\n");
904

    
905
		/* recv all response lines */
906
		while (!feof($fp)) {
907

    
908
			/* read the next line */
909
			$line = fgets($fp, 1024);
910

    
911
			$info = stream_get_meta_data($fp);
912
			if ($info['timed_out'])
913
				break;
914

    
915
			/* parse header list line */
916
			if (strstr($line, "HEADER"))
917
				continue;
918

    
919
			/* parse end of output line */
920
			if (strstr($line, "END") || strstr($line, "ERROR"))
921
				break;
922

    
923
			/* parse client list line */
924
			if (strstr($line, "CLIENT_LIST")) {
925
				$list = explode(",", $line);
926
				$conn = array();
927
				$conn['common_name'] = $list[1];
928
				$conn['remote_host'] = $list[2];
929
				$conn['virtual_addr'] = $list[3];
930
				$conn['bytes_recv'] = $list[4];
931
				$conn['bytes_sent'] = $list[5];
932
				$conn['connect_time'] = $list[6];
933
				$server['conns'][] = $conn;
934
			}
935
		}
936

    
937
		/* cleanup */
938
		fclose($fp);
939
	} else {
940
		$conn = array();
941
		$conn['common_name'] = "[error]";
942
		$conn['remote_host'] = "Management Daemon Unreachable";
943
		$conn['virtual_addr'] = "";
944
		$conn['bytes_recv'] = 0;
945
		$conn['bytes_sent'] = 0;
946
		$conn['connect_time'] = 0;
947
		$server['conns'][] = $conn;
948
	}
949
	return $server;
950
}
951

    
952
function openvpn_get_active_clients() {
953
	global $config, $g;
954

    
955
	$clients = array();
956
	if (is_array($config['openvpn']['openvpn-client'])) {
957
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
958
	
959
			if (empty($settings) || isset($settings['disable']))
960
				continue;
961

    
962
			$prot = $settings['protocol'];
963
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
964
	
965
			$client = array();
966
			$client['port'] = $settings['local_port'];
967
			if ($settings['description'])
968
				$client['name'] = "{$settings['description']} {$prot}{$port}";
969
			else
970
				$client['name'] = "Client {$prot}{$port}";
971
	
972
			$vpnid = $settings['vpnid'];
973
			$mode_id = "client{$vpnid}";
974
			$client['mgmt'] = $mode_id;
975
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
976
			$client['status']="down";
977

    
978
			$clients[] = openvpn_get_client_status($client, $socket);
979
		}
980
	}
981
	return $clients;
982
}
983

    
984
function openvpn_get_client_status($client, $socket) {
985
	$errval;
986
	$errstr;
987
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
988
	if ($fp) {
989
		stream_set_timeout($fp, 1);
990
		/* send our status request */
991
		fputs($fp, "state 1\n");
992

    
993
		/* recv all response lines */
994
		while (!feof($fp)) {
995
			/* read the next line */
996
			$line = fgets($fp, 1024);
997

    
998
			$info = stream_get_meta_data($fp);
999
			if ($info['timed_out'])
1000
				break;
1001

    
1002
			/* Get the client state */
1003
			if (strstr($line,"CONNECTED")) {
1004
				$client['status']="up";
1005
				$list = explode(",", $line);
1006

    
1007
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1008
				$client['virtual_addr']  = $list[3];
1009
				$client['remote_host'] = $list[4];
1010
			}
1011
			if (strstr($line,"CONNECTING")) {
1012
				$client['status']="connecting";
1013
			}
1014
			if (strstr($line,"ASSIGN_IP")) {
1015
				$client['status']="waiting";
1016
				$list = explode(",", $line);
1017

    
1018
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1019
				$client['virtual_addr']  = $list[3];
1020
			}
1021
			if (strstr($line,"RECONNECTING")) {
1022
				$client['status']="reconnecting";
1023
				$list = explode(",", $line);
1024

    
1025
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1026
				$client['status'] .= "; " . $list[2];
1027
			}
1028
			/* parse end of output line */
1029
			if (strstr($line, "END") || strstr($line, "ERROR"))
1030
				break;
1031
		}
1032

    
1033
		/* If up, get read/write stats */
1034
		if (strcmp($client['status'], "up") == 0) {
1035
			fputs($fp, "status 2\n");
1036
			/* recv all response lines */
1037
			while (!feof($fp)) {
1038
				/* read the next line */
1039
				$line = fgets($fp, 1024);
1040

    
1041
				$info = stream_get_meta_data($fp);
1042
				if ($info['timed_out'])
1043
					break;
1044

    
1045
				if (strstr($line,"TCP/UDP read bytes")) {
1046
					$list = explode(",", $line);
1047
					$client['bytes_recv'] = $list[1];
1048
				}
1049

    
1050
				if (strstr($line,"TCP/UDP write bytes")) {
1051
					$list = explode(",", $line);
1052
					$client['bytes_sent'] = $list[1];
1053
				}
1054

    
1055
				/* parse end of output line */
1056
				if (strstr($line, "END"))
1057
					break;
1058
			}
1059
		}
1060

    
1061
		fclose($fp);
1062

    
1063
	} else {
1064
		$DisplayNote=true;
1065
		$client['remote_host'] = "No Management Daemon";
1066
		$client['virtual_addr'] = "See Note Below";
1067
		$client['bytes_recv'] = 0;
1068
		$client['bytes_sent'] = 0;
1069
		$client['connect_time'] = 0;
1070
	}
1071
	return $client;
1072
}
1073

    
1074
function openvpn_refresh_crls() {
1075
	global $g, $config;
1076

    
1077
	if (!file_exists($g['varetc_path']."/openvpn"))
1078
		return;
1079

    
1080
	if (is_array($config['openvpn']['openvpn-server'])) {
1081
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1082
			if (empty($settings))
1083
				continue;
1084
			if (isset($settings['disable']))
1085
				continue;
1086
			// Write the settings for the keys
1087
			switch($settings['mode']) {
1088
				case 'p2p_tls':
1089
				case 'server_tls':
1090
				case 'server_tls_user':
1091
				case 'server_user':
1092
					if (!empty($settings['crlref'])) {
1093
						$crl = lookup_crl($settings['crlref']);
1094
						crl_update($crl);
1095
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1096
						file_put_contents($fpath, base64_decode($crl['text']));
1097
						@chmod($fpath, 0644);
1098
					}
1099
					break;
1100
			}
1101
		}
1102
	}
1103
}
1104

    
1105
?>
(36-36/66)