Project

General

Profile

Download (34.7 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
	if ($settings['topology_subnet']) {
674
		$conf .= "topology subnet\n";
675
	}
676

    
677
	openvpn_add_custom($settings, $conf);
678

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

    
691
function openvpn_restart($mode, $settings) {
692
	global $g, $config;
693

    
694
	$vpnid = $settings['vpnid'];
695
	$mode_id = $mode.$vpnid;
696

    
697
	/* kill the process if running */
698
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
699
	if (file_exists($pfile)) {
700

    
701
		/* read the pid file */
702
		$pid = rtrim(file_get_contents($pfile));
703
		unlink($pfile);
704

    
705
		/* send a term signal to the process */
706
		posix_kill($pid, SIGTERM);
707

    
708
		/* wait until the process exits */
709
		while(posix_kill($pid, 0))
710
			usleep(250000);
711
	}
712

    
713
	if (isset($settings['disable']))
714
		return;
715

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

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

    
725
	if (!$g['booting'])
726
		send_event("filter reload");
727
}
728

    
729
function openvpn_delete($mode, & $settings) {
730
	global $g, $config;
731

    
732
	$vpnid = $settings['vpnid'];
733
	$mode_id = $mode.$vpnid;
734

    
735
	if (isset($settings['dev_mode']))
736
		$tunname = "{$settings['dev_mode']}{$vpnid}";
737
	else {  /* defaults to tun */
738
		$tunname = "tun{$vpnid}";
739
	}
740

    
741
	if ($mode == "server")
742
		$devname = "ovpns{$vpnid}";
743
	else
744
		$devname = "ovpnc{$vpnid}";
745

    
746
	/* kill the process if running */
747
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
748
	if (file_exists($pfile)) {
749

    
750
		/* read the pid file */
751
		$pid = trim(file_get_contents($pfile));
752
		unlink($pfile);
753

    
754
		/* send a term signal to the process */
755
		posix_kill($pid, SIGTERM);
756
	}
757

    
758
	/* remove the device from the openvpn group */
759
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
760

    
761
	/* restore the original adapter name */
762
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
763

    
764
	/* remove the configuration files */
765
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
766
}
767

    
768
function openvpn_resync_csc(& $settings) {
769
	global $g, $config;
770

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

    
773
	if (isset($settings['disable'])) {
774
		unlink_if_exists($fpath);
775
		return;
776
	}
777
	openvpn_create_dirs();
778

    
779
	$conf = '';
780
	if ($settings['block'])
781
		$conf .= "disable\n";
782

    
783
	if ($settings['push_reset'])
784
		$conf .= "push-reset\n";
785

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

    
798
	openvpn_add_dhcpopts($settings, $conf);
799

    
800
	if ($settings['gwredir'])
801
		$conf .= "push \"redirect-gateway def1\"\n";
802

    
803
	openvpn_add_custom($settings, $conf);
804

    
805
	file_put_contents($fpath, $conf);
806
	chown($fpath, 'nobody');
807
	chgrp($fpath, 'nobody');
808
}
809

    
810
function openvpn_delete_csc(& $settings) {
811
	global $g, $config;
812

    
813
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
814
	unlink_if_exists($fpath);
815
}
816

    
817
// Resync the configuration and restart the VPN
818
function openvpn_resync($mode, $settings) {
819
	openvpn_reconfigure($mode, $settings);
820
	openvpn_restart($mode, $settings);
821
}
822

    
823
// Resync and restart all VPNs
824
function openvpn_resync_all($interface = "") {
825
	global $g, $config;
826

    
827
	if ($g['platform'] == 'jail')
828
		return;
829
	openvpn_create_dirs();
830

    
831
	if (!is_array($config['openvpn']))
832
		$config['openvpn'] = array();
833

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

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

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

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

    
871
	if (is_array($config['openvpn']['openvpn-csc']))
872
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
873
			openvpn_resync_csc($settings);
874

    
875
}
876

    
877
function openvpn_get_active_servers($type="multipoint") {
878
	global $config, $g;
879

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

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

    
904
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
905
				$servers[] = openvpn_get_client_status($server, $socket);
906
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
907
				$servers[] = openvpn_get_server_status($server, $socket);
908

    
909
		}
910
	}
911
	return $servers;
912
}
913

    
914
function openvpn_get_server_status($server, $socket) {
915
	$errval;
916
	$errstr;
917
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
918
	if ($fp) {
919
		stream_set_timeout($fp, 1);
920

    
921
		/* send our status request */
922
		fputs($fp, "status 2\n");
923

    
924
		/* recv all response lines */
925
		while (!feof($fp)) {
926

    
927
			/* read the next line */
928
			$line = fgets($fp, 1024);
929

    
930
			$info = stream_get_meta_data($fp);
931
			if ($info['timed_out'])
932
				break;
933

    
934
			/* parse header list line */
935
			if (strstr($line, "HEADER"))
936
				continue;
937

    
938
			/* parse end of output line */
939
			if (strstr($line, "END") || strstr($line, "ERROR"))
940
				break;
941

    
942
			/* parse client list line */
943
			if (strstr($line, "CLIENT_LIST")) {
944
				$list = explode(",", $line);
945
				$conn = array();
946
				$conn['common_name'] = $list[1];
947
				$conn['remote_host'] = $list[2];
948
				$conn['virtual_addr'] = $list[3];
949
				$conn['bytes_recv'] = $list[4];
950
				$conn['bytes_sent'] = $list[5];
951
				$conn['connect_time'] = $list[6];
952
				$server['conns'][] = $conn;
953
			}
954
			/* parse routing table lines */
955
			if (strstr($line, "ROUTING_TABLE")) {
956
				$list = explode(",", $line);
957
				$conn = array();
958
				$conn['virtual_addr'] = $list[1];
959
				$conn['common_name'] = $list[2];
960
				$conn['remote_host'] = $list[3];
961
				$conn['last_time'] = $list[4];
962
				$server['routes'][] = $conn;
963
			}
964
		}
965

    
966
		/* cleanup */
967
		fclose($fp);
968
	} else {
969
		$conn = array();
970
		$conn['common_name'] = "[error]";
971
		$conn['remote_host'] = "Management Daemon Unreachable";
972
		$conn['virtual_addr'] = "";
973
		$conn['bytes_recv'] = 0;
974
		$conn['bytes_sent'] = 0;
975
		$conn['connect_time'] = 0;
976
		$server['conns'][] = $conn;
977
	}
978
	return $server;
979
}
980

    
981
function openvpn_get_active_clients() {
982
	global $config, $g;
983

    
984
	$clients = array();
985
	if (is_array($config['openvpn']['openvpn-client'])) {
986
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
987
	
988
			if (empty($settings) || isset($settings['disable']))
989
				continue;
990

    
991
			$prot = $settings['protocol'];
992
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
993
	
994
			$client = array();
995
			$client['port'] = $settings['local_port'];
996
			if ($settings['description'])
997
				$client['name'] = "{$settings['description']} {$prot}{$port}";
998
			else
999
				$client['name'] = "Client {$prot}{$port}";
1000
	
1001
			$vpnid = $settings['vpnid'];
1002
			$mode_id = "client{$vpnid}";
1003
			$client['mgmt'] = $mode_id;
1004
			$socket = "unix://{$g['varetc_path']}/openvpn/{$mode_id}.sock";
1005
			$client['status']="down";
1006

    
1007
			$clients[] = openvpn_get_client_status($client, $socket);
1008
		}
1009
	}
1010
	return $clients;
1011
}
1012

    
1013
function openvpn_get_client_status($client, $socket) {
1014
	$errval;
1015
	$errstr;
1016
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1017
	if ($fp) {
1018
		stream_set_timeout($fp, 1);
1019
		/* send our status request */
1020
		fputs($fp, "state 1\n");
1021

    
1022
		/* recv all response lines */
1023
		while (!feof($fp)) {
1024
			/* read the next line */
1025
			$line = fgets($fp, 1024);
1026

    
1027
			$info = stream_get_meta_data($fp);
1028
			if ($info['timed_out'])
1029
				break;
1030

    
1031
			/* Get the client state */
1032
			if (strstr($line,"CONNECTED")) {
1033
				$client['status']="up";
1034
				$list = explode(",", $line);
1035

    
1036
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1037
				$client['virtual_addr']  = $list[3];
1038
				$client['remote_host'] = $list[4];
1039
			}
1040
			if (strstr($line,"CONNECTING")) {
1041
				$client['status']="connecting";
1042
			}
1043
			if (strstr($line,"ASSIGN_IP")) {
1044
				$client['status']="waiting";
1045
				$list = explode(",", $line);
1046

    
1047
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1048
				$client['virtual_addr']  = $list[3];
1049
			}
1050
			if (strstr($line,"RECONNECTING")) {
1051
				$client['status']="reconnecting";
1052
				$list = explode(",", $line);
1053

    
1054
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1055
				$client['status'] .= "; " . $list[2];
1056
			}
1057
			/* parse end of output line */
1058
			if (strstr($line, "END") || strstr($line, "ERROR"))
1059
				break;
1060
		}
1061

    
1062
		/* If up, get read/write stats */
1063
		if (strcmp($client['status'], "up") == 0) {
1064
			fputs($fp, "status 2\n");
1065
			/* recv all response lines */
1066
			while (!feof($fp)) {
1067
				/* read the next line */
1068
				$line = fgets($fp, 1024);
1069

    
1070
				$info = stream_get_meta_data($fp);
1071
				if ($info['timed_out'])
1072
					break;
1073

    
1074
				if (strstr($line,"TCP/UDP read bytes")) {
1075
					$list = explode(",", $line);
1076
					$client['bytes_recv'] = $list[1];
1077
				}
1078

    
1079
				if (strstr($line,"TCP/UDP write bytes")) {
1080
					$list = explode(",", $line);
1081
					$client['bytes_sent'] = $list[1];
1082
				}
1083

    
1084
				/* parse end of output line */
1085
				if (strstr($line, "END"))
1086
					break;
1087
			}
1088
		}
1089

    
1090
		fclose($fp);
1091

    
1092
	} else {
1093
		$DisplayNote=true;
1094
		$client['remote_host'] = "No Management Daemon";
1095
		$client['virtual_addr'] = "See Note Below";
1096
		$client['bytes_recv'] = 0;
1097
		$client['bytes_sent'] = 0;
1098
		$client['connect_time'] = 0;
1099
	}
1100
	return $client;
1101
}
1102

    
1103
function openvpn_refresh_crls() {
1104
	global $g, $config;
1105

    
1106
	openvpn_create_dirs();
1107

    
1108
	if (is_array($config['openvpn']['openvpn-server'])) {
1109
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1110
			if (empty($settings))
1111
				continue;
1112
			if (isset($settings['disable']))
1113
				continue;
1114
			// Write the settings for the keys
1115
			switch($settings['mode']) {
1116
				case 'p2p_tls':
1117
				case 'server_tls':
1118
				case 'server_tls_user':
1119
				case 'server_user':
1120
					if (!empty($settings['crlref'])) {
1121
						$crl = lookup_crl($settings['crlref']);
1122
						crl_update($crl);
1123
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1124
						file_put_contents($fpath, base64_decode($crl['text']));
1125
						@chmod($fpath, 0644);
1126
					}
1127
					break;
1128
			}
1129
		}
1130
	}
1131
}
1132

    
1133
function openvpn_create_dirs() {
1134
	global $g;
1135
	if (!is_dir("{$g['varetc_path']}/openvpn"))
1136
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1137
	if (!is_dir("{$g['varetc_path']}/openvpn-csc"))
1138
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1139
}
1140

    
1141
function openvpn_get_interface_ip($ip, $mask) {
1142
	$baselong = ip2long32($ip) & ip2long($mask);
1143
	$ip1 = long2ip32($baselong + 1);
1144
	$ip2 = long2ip32($baselong + 2);
1145
	return array($ip1, $ip2);
1146
}
1147

    
1148
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1149
	$basev6 = gen_subnetv6($ipv6, $prefix);
1150
	// Is there a better way to do this math?
1151
	$ipv6_arr = explode(':', $basev6);
1152
	$last = hexdec(array_pop($ipv6_arr));
1153
	$ipv6_1 = Net_IPv6::compress(implode(':', $ipv6_arr) . ':' . dechex($last + 1));
1154
	$ipv6_2 = Net_IPv6::compress(implode(':', $ipv6_arr) . ':' . dechex($last + 2));
1155
	return array($ipv6_1, $ipv6_2);
1156
}
1157

    
1158
function openvpn_clear_route($mode, $settings) {
1159
	if (empty($settings['tunnel_network']))
1160
		return;
1161
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1162
	$mask = gen_subnet_mask($cidr);
1163
	switch($settings['mode']) {
1164
		case 'p2p_tls':
1165
		case 'p2p_shared_key':
1166
		case 'shared_key':
1167
			if (!empty($ip) && !empty($mask) && ($cidr == 30)) {
1168
				list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1169
				$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1170
				mwexec("/sbin/route -q delete {$ip_to_clear}");
1171
			}
1172
			break;
1173
	}
1174
}
1175

    
1176
?>
(37-37/67)