Project

General

Profile

Download (34.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	openvpn.inc part of pfSense
4
	
5
	Copyright (C) 2008 Scott Ullrich <sullrich@gmail.com>
6
	All rights reserved.
7
	
8
	Copyright (C) 2006  Fernando Lemos
9
	All rights reserved.
10

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

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

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

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

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

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

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

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

    
52
$openvpn_prots = array("UDP", "UDP6", "TCP", "TCP6");
53

    
54
$openvpn_dev_mode = array("tun", "tap");
55

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

    
69
$openvpn_dh_lengths = array(
70
	1024, 2048, 4096 );
71

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

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

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

    
91
function openvpn_create_key() {
92

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

    
97
	$rslt = stream_get_contents($fp);
98
	pclose($fp);
99

    
100
	return $rslt;
101
}
102

    
103
function openvpn_create_dhparams($bits) {
104

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

    
109
	$rslt = stream_get_contents($fp);
110
	pclose($fp);
111

    
112
	return $rslt;
113
}
114

    
115
function openvpn_vpnid_used($vpnid) {
116
	global $config;
117

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

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

    
128
	return false;
129
}
130

    
131
function openvpn_vpnid_next() {
132

    
133
	$vpnid = 1;
134
	while(openvpn_vpnid_used($vpnid))
135
		$vpnid++;
136

    
137
	return $vpnid;
138
}
139

    
140
function openvpn_port_used($prot, $port) {
141
	global $config;
142

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

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

    
155
	return 0;
156
}
157

    
158
function openvpn_port_next($prot) {
159

    
160
	$port = 1194;
161
	while(openvpn_port_used($prot, $port))
162
		$port++;
163

    
164
	return $port;
165
}
166

    
167
function openvpn_get_cipherlist() {
168

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

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

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

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

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

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

    
222
function openvpn_add_dhcpopts(& $settings, & $conf) {
223

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

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

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

    
241
	if ($settings['netbios_enable']) {
242

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

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

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

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

    
261
function openvpn_add_custom(& $settings, & $conf) {
262

    
263
	if ($settings['custom_options']) {
264

    
265
		$options = explode(';', $settings['custom_options']);
266

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

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

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

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

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

    
291
	if (empty($settings))
292
		return;
293
	if (isset($settings['disable'])) 
294
		return;
295
	openvpn_create_dirs();
296
	/*
297
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
298
	 * we use a vpnid number which is allocated for a particular client
299
	 * or server configuration. ( see openvpn_vpnid_next() )
300
	 */
301

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

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

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

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

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

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

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

    
331
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
332
	$proto = strtolower($settings['protocol']);
333
	if (substr($settings['protocol'], 0, 3) == "TCP")
334
			$proto = "{$proto}-{$mode}";
335
	$dev_mode = $settings['dev_mode'];
336
	$cipher = $settings['crypto'];
337

    
338
	$interface = get_failover_interface($settings['interface']);
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
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
392
	if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
393
		$conf .= "local {$iface_ip}\n";
394
	} elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
395
		$conf .= "local {$iface_ipv6}\n";
396
	}
397

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

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

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

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

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

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

    
513
		// The local port to listen on
514
		$conf .= "lport {$settings['local_port']}\n";
515

    
516
		// The management port to listen on
517
		// Use unix socket to overcome the problem on any type of server
518
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
519
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
520

    
521
		if ($settings['maxclients'])
522
			$conf .= "max-clients {$settings['maxclients']}\n";
523

    
524
		// Can we push routes
525
		if ($settings['local_network']) {
526
			list($ip, $mask) = explode('/', $settings['local_network']);
527
			$mask = gen_subnet_mask($mask);
528
			$conf .= "push \"route $ip $mask\"\n";
529
		}
530
		if ($settings['local_networkv6']) {
531
			list($ipv6, $prefix) = explode('/', $settings['local_networkv6']);
532
			if (empty($prefix))
533
				$prefix = "128";
534
			$conf .= "push \"route-ipv6 $ipv6/$prefix\"\n";
535
		}
536

    
537
		switch($settings['mode']) {
538
			case 'server_tls':
539
			case 'server_user':
540
			case 'server_tls_user':
541
				// Configure client dhcp options
542
				openvpn_add_dhcpopts($settings, $conf);
543
				if ($settings['client2client'])
544
					$conf .= "client-to-client\n";
545
				break;
546
		}
547
		if (isset($settings['duplicate_cn']))
548
			$conf .= "duplicate-cn\n";
549
	}
550

    
551
	// client specific settings
552

    
553
	if ($mode == 'client') {
554

    
555
		// configure p2p mode
556
		switch($settings['mode']) {
557
			case 'p2p_tls':
558
				$conf .= "tls-client\n";
559
			case 'shared_key':
560
				$conf .= "client\n";
561
				break;
562
		}
563

    
564
		// If there is no bind option at all (ip and/or port), add "nobind" directive
565
		//  Otherwise, use the local port if defined, failing that, use lport 0 to 
566
		//  ensure a random source port.
567
		if ((empty($iface_ip)) && (!$settings['local_port']))
568
			$conf .= "nobind\n";
569
		elseif ($settings['local_port'])
570
			$conf .= "lport {$settings['local_port']}\n";
571
		else
572
			$conf .= "lport 0\n";
573

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

    
577
		// The remote server
578
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
579

    
580
		if (!empty($settings['use_shaper']))
581
			$conf .= "shaper {$settings['use_shaper']}\n";
582

    
583
		if (!empty($settings['tunnel_network'])) {
584
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
585
			$mask = gen_subnet_mask($mask);
586
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
587
			if ($settings['dev_mode'] == 'tun')
588
				$conf .= "ifconfig {$ip2} {$ip1}\n";
589
			else
590
				$conf .= "ifconfig {$ip2} {$mask}\n";
591
		}
592

    
593
		if (!empty($settings['tunnel_networkv6'])) {
594
			list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
595
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
596
			if ($settings['dev_mode'] == 'tun')
597
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
598
			else
599
				$conf .= "ifconfig {$ipv6_2} {$prefix}\n";
600
		}
601

    
602
		if ($settings['proxy_addr']) {
603
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
604
			if ($settings['proxy_authtype'] != "none") {
605
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
606
				$proxypas = "{$settings['proxy_user']}\n";
607
				$proxypas .= "{$settings['proxy_passwd']}\n";
608
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
609
			}
610
			$conf .= " \n";
611
		}
612
	}
613

    
614
	// Add a remote network route if set, and only for p2p modes.
615
	if ((substr($settings['mode'], 0, 3) == "p2p") && is_subnet($settings['remote_network'])) {
616
		list($ip, $mask) = explode('/', $settings['remote_network']);
617
		$mask = gen_subnet_mask($mask);
618
		$conf .= "route $ip $mask\n";
619
	}
620
	// Add a remote network route if set, and only for p2p modes.
621
	if ((substr($settings['mode'], 0, 3) == "p2p") && is_subnet($settings['remote_networkv6'])) {
622
		list($ipv6, $prefix) = explode('/', $settings['remote_networkv6']);
623
		if (empty($prefix))
624
			$prefix = "128";
625
		$conf .= "route-ipv6 ${ipv6}/${prefix}\n";
626
	}
627

    
628
	// Write the settings for the keys
629
	switch($settings['mode']) {
630
		case 'p2p_shared_key':
631
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
632
			break;
633
		case 'p2p_tls':
634
		case 'server_tls':
635
		case 'server_tls_user':
636
		case 'server_user':
637
			$ca = lookup_ca($settings['caref']);
638
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
639
			$cert = lookup_cert($settings['certref']);
640
			openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
641
			openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
642
			if ($mode == 'server')
643
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
644
			if (!empty($settings['crlref'])) {
645
				$crl = lookup_crl($settings['crlref']);
646
				crl_update($crl);
647
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
648
			}
649
			if ($settings['tls']) {
650
				if ($mode == "server") 
651
					$tlsopt = 0;
652
				else
653
					$tlsopt = 1;
654
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
655
			}
656
			break;
657
	}
658

    
659
	if ($settings['compression'])
660
		$conf .= "comp-lzo\n";
661

    
662
	if ($settings['passtos'])
663
		$conf .= "passtos\n";
664

    
665
	if ($settings['resolve_retry'])
666
		$conf .= "resolv-retry infinite\n";
667

    
668
	if ($settings['dynamic_ip']) {
669
		$conf .= "persist-remote-ip\n";
670
		$conf .= "float\n";
671
	}
672

    
673
	openvpn_add_custom($settings, $conf);
674

    
675
	openvpn_create_dirs();
676
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
677
	file_put_contents($fpath, $conf);
678
	unset($conf);
679
	//chown($fpath, 'nobody');
680
	//chgrp($fpath, 'nobody');
681
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
682
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
683
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
684
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
685
}
686

    
687
function openvpn_restart($mode, $settings) {
688
	global $g, $config;
689

    
690
	$vpnid = $settings['vpnid'];
691
	$mode_id = $mode.$vpnid;
692

    
693
	/* kill the process if running */
694
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
695
	if (file_exists($pfile)) {
696

    
697
		/* read the pid file */
698
		$pid = rtrim(file_get_contents($pfile));
699
		unlink($pfile);
700

    
701
		/* send a term signal to the process */
702
		posix_kill($pid, SIGTERM);
703

    
704
		/* wait until the process exits */
705
		while(posix_kill($pid, 0))
706
			usleep(250000);
707
	}
708

    
709
	if (isset($settings['disable']))
710
		return;
711

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

    
716
	/* start the new process */
717
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
718
	openvpn_clear_route($mode, $settings);
719
	mwexec_bg("/usr/local/sbin/openvpn --config {$fpath}");
720

    
721
	if (!$g['booting'])
722
		send_event("filter reload");
723
}
724

    
725
function openvpn_delete($mode, & $settings) {
726
	global $g, $config;
727

    
728
	$vpnid = $settings['vpnid'];
729
	$mode_id = $mode.$vpnid;
730

    
731
	if (isset($settings['dev_mode']))
732
		$tunname = "{$settings['dev_mode']}{$vpnid}";
733
	else {  /* defaults to tun */
734
		$tunname = "tun{$vpnid}";
735
	}
736

    
737
	if ($mode == "server")
738
		$devname = "ovpns{$vpnid}";
739
	else
740
		$devname = "ovpnc{$vpnid}";
741

    
742
	/* kill the process if running */
743
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
744
	if (file_exists($pfile)) {
745

    
746
		/* read the pid file */
747
		$pid = trim(file_get_contents($pfile));
748
		unlink($pfile);
749

    
750
		/* send a term signal to the process */
751
		posix_kill($pid, SIGTERM);
752
	}
753

    
754
	/* remove the device from the openvpn group */
755
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
756

    
757
	/* restore the original adapter name */
758
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
759

    
760
	/* remove the configuration files */
761
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
762
}
763

    
764
function openvpn_resync_csc(& $settings) {
765
	global $g, $config;
766

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

    
769
	if (isset($settings['disable'])) {
770
		unlink_if_exists($fpath);
771
		return;
772
	}
773
	openvpn_create_dirs();
774

    
775
	$conf = '';
776
	if ($settings['block'])
777
		$conf .= "disable\n";
778

    
779
	if ($settings['push_reset'])
780
		$conf .= "push-reset\n";
781

    
782
	if (!empty($settings['tunnel_network'])) {
783
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
784
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
785
		$serverip = long2ip32($baselong + 1);
786
		$clientip = long2ip32($baselong + 2);
787
		/* Because this is being pushed, the order from the client's point of view. */
788
		if ($settings['dev_mode'] != 'tap')
789
			$conf .= "ifconfig-push {$clientip} {$serverip}\n";
790
		else
791
			$conf .= "ifconfig-push {$clientip} {$mask}\n";
792
	}
793

    
794
	openvpn_add_dhcpopts($settings, $conf);
795

    
796
	if ($settings['gwredir'])
797
		$conf .= "push \"redirect-gateway def1\"\n";
798

    
799
	openvpn_add_custom($settings, $conf);
800

    
801
	file_put_contents($fpath, $conf);
802
	chown($fpath, 'nobody');
803
	chgrp($fpath, 'nobody');
804
}
805

    
806
function openvpn_delete_csc(& $settings) {
807
	global $g, $config;
808

    
809
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
810
	unlink_if_exists($fpath);
811
}
812

    
813
// Resync the configuration and restart the VPN
814
function openvpn_resync($mode, $settings) {
815
	openvpn_reconfigure($mode, $settings);
816
	openvpn_restart($mode, $settings);
817
}
818

    
819
// Resync and restart all VPNs
820
function openvpn_resync_all($interface = "") {
821
	global $g, $config;
822

    
823
	if ($g['platform'] == 'jail')
824
		return;
825
	openvpn_create_dirs();
826

    
827
	if (!is_array($config['openvpn']))
828
		$config['openvpn'] = array();
829

    
830
/*
831
	if (!$config['openvpn']['dh-parameters']) {
832
		echo "Configuring OpenVPN Parameters ...\n";
833
		$dh_parameters = openvpn_create_dhparams(1024);
834
		$dh_parameters = base64_encode($dh_parameters);
835
		$config['openvpn']['dh-parameters'] = $dh_parameters;
836
		write_config("OpenVPN DH parameters");
837
	}
838

    
839
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
840
	if (!file_exists($path_ovdh)) {
841
		$dh_parameters = $config['openvpn']['dh-parameters'];
842
		$dh_parameters = base64_decode($dh_parameters);
843
		file_put_contents($path_ovdh, $dh_parameters);
844
	}
845
*/
846
	if ($interface <> "")
847
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
848
	else
849
		log_error("Resyncing OpenVPN instances."); 
850

    
851
	if (is_array($config['openvpn']['openvpn-server'])) {
852
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
853
			if ($interface <> "" && $interface != $settings['interface'])
854
				continue;
855
			openvpn_resync('server', $settings);
856
		}
857
	}
858

    
859
	if (is_array($config['openvpn']['openvpn-client'])) {
860
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
861
			if ($interface <> "" && $interface != $settings['interface'])
862
				continue;
863
			openvpn_resync('client', $settings);
864
		}
865
	}
866

    
867
	if (is_array($config['openvpn']['openvpn-csc']))
868
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
869
			openvpn_resync_csc($settings);
870

    
871
}
872

    
873
function openvpn_get_active_servers($type="multipoint") {
874
	global $config, $g;
875

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

    
882
			$prot = $settings['protocol'];
883
			$port = $settings['local_port'];
884
	
885
			$server = array();
886
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
887
			$server['mode'] = $settings['mode'];
888
			if ($settings['description'])
889
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
890
			else
891
				$server['name'] = "Server {$prot}:{$port}";
892
			$server['conns'] = array();
893
	
894
			$vpnid = $settings['vpnid'];
895
			$mode_id = "server{$vpnid}";
896
			$server['mgmt'] = $mode_id;
897
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
898
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
899

    
900
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
901
				$servers[] = openvpn_get_client_status($server, $socket);
902
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
903
				$servers[] = openvpn_get_server_status($server, $socket);
904

    
905
		}
906
	}
907
	return $servers;
908
}
909

    
910
function openvpn_get_server_status($server, $socket) {
911
	$errval;
912
	$errstr;
913
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
914
	if ($fp) {
915
		stream_set_timeout($fp, 1);
916

    
917
		/* send our status request */
918
		fputs($fp, "status 2\n");
919

    
920
		/* recv all response lines */
921
		while (!feof($fp)) {
922

    
923
			/* read the next line */
924
			$line = fgets($fp, 1024);
925

    
926
			$info = stream_get_meta_data($fp);
927
			if ($info['timed_out'])
928
				break;
929

    
930
			/* parse header list line */
931
			if (strstr($line, "HEADER"))
932
				continue;
933

    
934
			/* parse end of output line */
935
			if (strstr($line, "END") || strstr($line, "ERROR"))
936
				break;
937

    
938
			/* parse client list line */
939
			if (strstr($line, "CLIENT_LIST")) {
940
				$list = explode(",", $line);
941
				$conn = array();
942
				$conn['common_name'] = $list[1];
943
				$conn['remote_host'] = $list[2];
944
				$conn['virtual_addr'] = $list[3];
945
				$conn['bytes_recv'] = $list[4];
946
				$conn['bytes_sent'] = $list[5];
947
				$conn['connect_time'] = $list[6];
948
				$server['conns'][] = $conn;
949
			}
950
		}
951

    
952
		/* cleanup */
953
		fclose($fp);
954
	} else {
955
		$conn = array();
956
		$conn['common_name'] = "[error]";
957
		$conn['remote_host'] = "Management Daemon Unreachable";
958
		$conn['virtual_addr'] = "";
959
		$conn['bytes_recv'] = 0;
960
		$conn['bytes_sent'] = 0;
961
		$conn['connect_time'] = 0;
962
		$server['conns'][] = $conn;
963
	}
964
	return $server;
965
}
966

    
967
function openvpn_get_active_clients() {
968
	global $config, $g;
969

    
970
	$clients = array();
971
	if (is_array($config['openvpn']['openvpn-client'])) {
972
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
973
	
974
			if (empty($settings) || isset($settings['disable']))
975
				continue;
976

    
977
			$prot = $settings['protocol'];
978
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
979
	
980
			$client = array();
981
			$client['port'] = $settings['local_port'];
982
			if ($settings['description'])
983
				$client['name'] = "{$settings['description']} {$prot}{$port}";
984
			else
985
				$client['name'] = "Client {$prot}{$port}";
986
	
987
			$vpnid = $settings['vpnid'];
988
			$mode_id = "client{$vpnid}";
989
			$client['mgmt'] = $mode_id;
990
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
991
			$client['status']="down";
992

    
993
			$clients[] = openvpn_get_client_status($client, $socket);
994
		}
995
	}
996
	return $clients;
997
}
998

    
999
function openvpn_get_client_status($client, $socket) {
1000
	$errval;
1001
	$errstr;
1002
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1003
	if ($fp) {
1004
		stream_set_timeout($fp, 1);
1005
		/* send our status request */
1006
		fputs($fp, "state 1\n");
1007

    
1008
		/* recv all response lines */
1009
		while (!feof($fp)) {
1010
			/* read the next line */
1011
			$line = fgets($fp, 1024);
1012

    
1013
			$info = stream_get_meta_data($fp);
1014
			if ($info['timed_out'])
1015
				break;
1016

    
1017
			/* Get the client state */
1018
			if (strstr($line,"CONNECTED")) {
1019
				$client['status']="up";
1020
				$list = explode(",", $line);
1021

    
1022
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1023
				$client['virtual_addr']  = $list[3];
1024
				$client['remote_host'] = $list[4];
1025
			}
1026
			if (strstr($line,"CONNECTING")) {
1027
				$client['status']="connecting";
1028
			}
1029
			if (strstr($line,"ASSIGN_IP")) {
1030
				$client['status']="waiting";
1031
				$list = explode(",", $line);
1032

    
1033
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1034
				$client['virtual_addr']  = $list[3];
1035
			}
1036
			if (strstr($line,"RECONNECTING")) {
1037
				$client['status']="reconnecting";
1038
				$list = explode(",", $line);
1039

    
1040
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1041
				$client['status'] .= "; " . $list[2];
1042
			}
1043
			/* parse end of output line */
1044
			if (strstr($line, "END") || strstr($line, "ERROR"))
1045
				break;
1046
		}
1047

    
1048
		/* If up, get read/write stats */
1049
		if (strcmp($client['status'], "up") == 0) {
1050
			fputs($fp, "status 2\n");
1051
			/* recv all response lines */
1052
			while (!feof($fp)) {
1053
				/* read the next line */
1054
				$line = fgets($fp, 1024);
1055

    
1056
				$info = stream_get_meta_data($fp);
1057
				if ($info['timed_out'])
1058
					break;
1059

    
1060
				if (strstr($line,"TCP/UDP read bytes")) {
1061
					$list = explode(",", $line);
1062
					$client['bytes_recv'] = $list[1];
1063
				}
1064

    
1065
				if (strstr($line,"TCP/UDP write bytes")) {
1066
					$list = explode(",", $line);
1067
					$client['bytes_sent'] = $list[1];
1068
				}
1069

    
1070
				/* parse end of output line */
1071
				if (strstr($line, "END"))
1072
					break;
1073
			}
1074
		}
1075

    
1076
		fclose($fp);
1077

    
1078
	} else {
1079
		$DisplayNote=true;
1080
		$client['remote_host'] = "No Management Daemon";
1081
		$client['virtual_addr'] = "See Note Below";
1082
		$client['bytes_recv'] = 0;
1083
		$client['bytes_sent'] = 0;
1084
		$client['connect_time'] = 0;
1085
	}
1086
	return $client;
1087
}
1088

    
1089
function openvpn_refresh_crls() {
1090
	global $g, $config;
1091

    
1092
	openvpn_create_dirs();
1093

    
1094
	if (is_array($config['openvpn']['openvpn-server'])) {
1095
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1096
			if (empty($settings))
1097
				continue;
1098
			if (isset($settings['disable']))
1099
				continue;
1100
			// Write the settings for the keys
1101
			switch($settings['mode']) {
1102
				case 'p2p_tls':
1103
				case 'server_tls':
1104
				case 'server_tls_user':
1105
				case 'server_user':
1106
					if (!empty($settings['crlref'])) {
1107
						$crl = lookup_crl($settings['crlref']);
1108
						crl_update($crl);
1109
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1110
						file_put_contents($fpath, base64_decode($crl['text']));
1111
						@chmod($fpath, 0644);
1112
					}
1113
					break;
1114
			}
1115
		}
1116
	}
1117
}
1118

    
1119
function openvpn_create_dirs() {
1120
	global $g;
1121
	if (!is_dir("{$g['varetc_path']}/openvpn"))
1122
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1123
	if (!is_dir("{$g['varetc_path']}/openvpn-csc"))
1124
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1125
}
1126

    
1127
function openvpn_get_interface_ip($ip, $mask) {
1128
	$baselong = ip2long32($ip) & ip2long($mask);
1129
	$ip1 = long2ip32($baselong + 1);
1130
	$ip2 = long2ip32($baselong + 2);
1131
	return array($ip1, $ip2);
1132
}
1133

    
1134
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1135
	$basev6 = gen_subnetv6($ipv6, $prefix);
1136
	// Is there a better way to do this math?
1137
	$ipv6_arr = explode(':', $basev6);
1138
	$last = hexdec(array_pop($ipv6_arr));
1139
	$ipv6_1 = Net_IPv6::compress(implode(':', $ipv6_arr) . ':' . dechex($last + 1));
1140
	$ipv6_2 = Net_IPv6::compress(implode(':', $ipv6_arr) . ':' . dechex($last + 2));
1141
	return array($ipv6_1, $ipv6_2);
1142
}
1143

    
1144
function openvpn_clear_route($mode, $settings) {
1145
	if (empty($settings['tunnel_network']))
1146
		return;
1147
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1148
	$mask = gen_subnet_mask($cidr);
1149
	switch($settings['mode']) {
1150
		case 'p2p_tls':
1151
		case 'p2p_shared_key':
1152
		case 'shared_key':
1153
			if (!empty($ip) && !empty($mask) && ($cidr == 30)) {
1154
				list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1155
				$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1156
				mwexec("/sbin/route -q delete {$ip_to_clear}");
1157
			}
1158
			break;
1159
	}
1160
}
1161

    
1162
?>
(37-37/67)