Project

General

Profile

Download (34.4 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}")) {
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 remote_host 255.255.255.255 net_gateway\"\n";
529
			$conf .= "push \"route $ip $mask\"\n";
530
		}
531
		if ($settings['local_networkv6']) {
532
			list($ipv6, $prefix) = explode('/', $settings['local_networkv6']);
533
			if (empty($prefix))
534
				$prefix = "128";
535
			$conf .= "push \"route-ipv6 $ipv6/$prefix\"\n";
536
		}
537

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

    
552
	// client specific settings
553

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
675
	openvpn_add_custom($settings, $conf);
676

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

    
689
function openvpn_restart($mode, $settings) {
690
	global $g, $config;
691

    
692
	$vpnid = $settings['vpnid'];
693
	$mode_id = $mode.$vpnid;
694

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

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

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

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

    
711
	if (isset($settings['disable']))
712
		return;
713

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

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

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

    
727
function openvpn_delete($mode, & $settings) {
728
	global $g, $config;
729

    
730
	$vpnid = $settings['vpnid'];
731
	$mode_id = $mode.$vpnid;
732

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

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

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

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

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

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

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

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

    
766
function openvpn_resync_csc(& $settings) {
767
	global $g, $config;
768

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

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

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

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

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

    
796
	openvpn_add_dhcpopts($settings, $conf);
797

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

    
801
	openvpn_add_custom($settings, $conf);
802

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

    
808
function openvpn_delete_csc(& $settings) {
809
	global $g, $config;
810

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

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

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

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

    
829
	if (!is_array($config['openvpn']))
830
		$config['openvpn'] = array();
831

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

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

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

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

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

    
873
}
874

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

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

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

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

    
907
		}
908
	}
909
	return $servers;
910
}
911

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

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

    
922
		/* recv all response lines */
923
		while (!feof($fp)) {
924

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

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

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

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

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

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

    
969
function openvpn_get_active_clients() {
970
	global $config, $g;
971

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1078
		fclose($fp);
1079

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

    
1091
function openvpn_refresh_crls() {
1092
	global $g, $config;
1093

    
1094
	openvpn_create_dirs();
1095

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

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

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

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

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

    
1164
?>
(38-38/68)