Project

General

Profile

Download (41.1 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/local/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
global $openvpn_prots;
53
$openvpn_prots = array("UDP", "UDP6", "TCP", "TCP6");
54

    
55
global $openvpn_dev_mode;
56
$openvpn_dev_mode = array("tun", "tap");
57

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

    
71
global $openvpn_dh_lengths;
72
$openvpn_dh_lengths = array(
73
	1024, 2048, 4096 );
74

    
75
global $openvpn_cert_depths;
76
$openvpn_cert_depths = array(
77
	1 => "One (Client+Server)",
78
	2 => "Two (Client+Intermediate+Server)",
79
	3 => "Three (Client+2xIntermediate+Server)",
80
	4 => "Four (Client+3xIntermediate+Server)",
81
	5 => "Five (Client+4xIntermediate+Server)"
82
);
83

    
84
global $openvpn_server_modes;
85
$openvpn_server_modes = array(
86
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
87
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
88
	'server_tls' => gettext("Remote Access ( SSL/TLS )"),
89
	'server_user' => gettext("Remote Access ( User Auth )"),
90
	'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
91

    
92
global $openvpn_client_modes;
93
$openvpn_client_modes = array(
94
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
95
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )") );
96

    
97
global $openvpn_compression_modes;
98
$openvpn_compression_modes = array(
99
	'' =>	gettext("No Preference"),
100
	'no' =>		gettext("Disabled - No Compression"),
101
	'adaptive' =>	gettext("Enabled with Adaptive Compression"),
102
	'yes' =>	gettext("Enabled without Adaptive Compression"));
103

    
104
function openvpn_create_key() {
105

    
106
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
107
	if (!$fp)
108
		return false;
109

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

    
113
	return $rslt;
114
}
115

    
116
function openvpn_create_dhparams($bits) {
117

    
118
	$fp = popen("/usr/local/bin/openssl dhparam {$bits} 2>/dev/null", "r");
119
	if (!$fp)
120
		return false;
121

    
122
	$rslt = stream_get_contents($fp);
123
	pclose($fp);
124

    
125
	return $rslt;
126
}
127

    
128
function openvpn_vpnid_used($vpnid) {
129
	global $config;
130

    
131
	if (is_array($config['openvpn']['openvpn-server']))
132
		foreach ($config['openvpn']['openvpn-server'] as & $settings)
133
			if ($vpnid == $settings['vpnid'])
134
				return true;
135

    
136
	if (is_array($config['openvpn']['openvpn-client']))
137
		foreach ($config['openvpn']['openvpn-client'] as & $settings)
138
			if ($vpnid == $settings['vpnid'])
139
				return true;
140

    
141
	return false;
142
}
143

    
144
function openvpn_vpnid_next() {
145

    
146
	$vpnid = 1;
147
	while(openvpn_vpnid_used($vpnid))
148
		$vpnid++;
149

    
150
	return $vpnid;
151
}
152

    
153
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
154
	global $config;
155

    
156
	if (is_array($config['openvpn']['openvpn-server'])) {
157
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
158
			if (isset($settings['disable']))
159
				continue;
160

    
161
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid'])
162
				continue;
163

    
164
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
165
				($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any"))
166
				return $settings['vpnid'];
167
		}
168
	}
169

    
170
	if (is_array($config['openvpn']['openvpn-client'])) {
171
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
172
			if (isset($settings['disable']))
173
				continue;
174

    
175
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid'])
176
				continue;
177

    
178
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
179
				($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any"))
180
				return $settings['vpnid'];
181
		}
182
	}
183

    
184
	return 0;
185
}
186

    
187
function openvpn_port_next($prot, $interface = "wan") {
188

    
189
	$port = 1194;
190
	while(openvpn_port_used($prot, $interface, $port))
191
		$port++;
192
	while(openvpn_port_used($prot, "any", $port))
193
		$port++;
194

    
195
	return $port;
196
}
197

    
198
function openvpn_get_cipherlist() {
199

    
200
	$ciphers = array();
201
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
202
	$cipher_lines = explode("\n", trim($cipher_out));
203
	sort($cipher_lines);
204
	foreach ($cipher_lines as $line) {
205
		$words = explode(' ', $line);
206
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
207
	}
208
	$ciphers["none"] = gettext("None (No Encryption)");
209
	return $ciphers;
210
}
211

    
212
function openvpn_get_digestlist() {
213

    
214
	$digests = array();
215
	$digest_out = shell_exec('/usr/local/sbin/openvpn --show-digests | /usr/bin/grep "digest size" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
216
	$digest_lines = explode("\n", trim($digest_out));
217
	sort($digest_lines);
218
	foreach ($digest_lines as $line) {
219
		$words = explode(' ', $line);
220
		$digests[$words[0]] = "{$words[0]} {$words[1]}";
221
	}
222
	$digests["none"] = gettext("None (No Authentication)");
223
	return $digests;
224
}
225

    
226
function openvpn_get_engines() {
227
	$openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
228
	exec("/usr/local/bin/openssl engine -t -c", $openssl_engine_output);
229
	$openssl_engine_output = implode("\n", $openssl_engine_output);
230
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
231
	$openssl_engine_output = explode("\n", $openssl_engine_output);
232

    
233
	foreach ($openssl_engine_output as $oeo) {
234
		$keep = true;
235
		$details = explode("|", $oeo);
236
		$engine = array_shift($details);
237
		$linematch = array();
238
		preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
239
		foreach ($details as $dt) {
240
			if (strpos($dt, "unavailable") !== FALSE)
241
				$keep = false;
242
			if (strpos($dt, "available") !== FALSE)
243
				continue;
244
			if (strpos($dt, "[") !== FALSE)
245
				$ciphers = trim($dt, "[]");
246
		}
247
		if (!empty($ciphers))
248
			$ciphers = " - " . $ciphers;
249
		if (strlen($ciphers) > 60)
250
			$ciphers = substr($ciphers, 0, 60) . " ... ";
251
		if ($keep)
252
			$openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
253
	}
254
	return $openssl_engines;
255
}
256

    
257
function openvpn_validate_engine($engine) {
258
	$engines = openvpn_get_engines();
259
	return array_key_exists($engine, $engines);
260
}
261

    
262
function openvpn_validate_host($value, $name) {
263
	$value = trim($value);
264
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value)))
265
		return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
266
	return false;
267
}
268

    
269
function openvpn_validate_port($value, $name) {
270
	$value = trim($value);
271
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535))
272
		return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
273
	return false;
274
}
275

    
276
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
277
	$value = trim($value);
278
	$error = false;
279
	if (empty($value))
280
		return false;
281
	$networks = explode(',', $value);
282

    
283
	if (!$multiple && (count($networks) > 1))
284
		return sprintf(gettext("The field '%s' must contain a single valid %s CIDR range."), $name, $ipproto);
285

    
286
	foreach ($networks as $network) {
287
		if ($ipproto == "ipv4")
288
			$error = !openvpn_validate_cidr_ipv4($network);
289
		else
290
			$error = !openvpn_validate_cidr_ipv6($network);
291
		if ($error)
292
			break;
293
	}
294

    
295
	if ($error)
296
		return sprintf(gettext("The field '%s' must contain only valid %s CIDR range(s) separated by commas."), $name, $ipproto);
297
	else
298
		return false;
299
}
300

    
301
function openvpn_validate_cidr_ipv4($value) {
302
	$value = trim($value);
303
	if (!empty($value)) {
304
		list($ip, $mask) = explode('/', $value);
305
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
306
			return false;
307
	}
308
	return true;
309
}
310

    
311
function openvpn_validate_cidr_ipv6($value) {
312
	$value = trim($value);
313
	if (!empty($value)) {
314
		list($ipv6, $prefix) = explode('/', $value);
315
		if (empty($prefix))
316
			$prefix = "128";
317
		if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0))
318
			return false;
319
	}
320
	return true;
321
}
322

    
323
function openvpn_add_dhcpopts(& $settings, & $conf) {
324

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

    
328
	if (!empty($settings['dns_server1']))
329
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
330
	if (!empty($settings['dns_server2']))
331
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
332
	if (!empty($settings['dns_server3']))
333
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
334
	if (!empty($settings['dns_server4']))
335
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
336

    
337
	if (!empty($settings['ntp_server1']))
338
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
339
	if (!empty($settings['ntp_server2']))
340
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
341

    
342
	if ($settings['netbios_enable']) {
343

    
344
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0))
345
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
346
		if (!empty($settings['dhcp_nbtscope'])) 
347
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
348

    
349
		if (!empty($settings['wins_server1']))
350
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
351
		if (!empty($settings['wins_server2']))
352
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
353

    
354
		if (!empty($settings['nbdd_server1']))
355
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
356
	}
357

    
358
	if ($settings['gwredir']) 
359
		$conf .= "push \"redirect-gateway def1\"\n";
360
}
361

    
362
function openvpn_add_custom(& $settings, & $conf) {
363

    
364
	if ($settings['custom_options']) {
365

    
366
		$options = explode(';', $settings['custom_options']);
367

    
368
		if (is_array($options)) {
369
			foreach ($options as $option)
370
				$conf .= "$option\n";
371
		} else
372
			$conf .= "{$settings['custom_options']}\n";
373
	}
374
}
375

    
376
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
377
	global $g;
378

    
379
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
380
	openvpn_create_dirs();
381
	file_put_contents($fpath, base64_decode($data));
382
	//chown($fpath, 'nobody');
383
	//chgrp($fpath, 'nobody');
384
	@chmod($fpath, 0600);
385

    
386
	$conf .= "{$directive} {$fpath} {$opt}\n";
387
}
388

    
389
function openvpn_reconfigure($mode, $settings) {
390
	global $g, $config;
391

    
392
	if (empty($settings))
393
		return;
394
	if (isset($settings['disable'])) 
395
		return;
396
	openvpn_create_dirs();
397
	/*
398
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
399
	 * we use a vpnid number which is allocated for a particular client
400
	 * or server configuration. ( see openvpn_vpnid_next() )
401
	 */
402

    
403
	$vpnid = $settings['vpnid'];
404
	$mode_id = $mode.$vpnid;
405

    
406
	if (isset($settings['dev_mode']))
407
		$tunname = "{$settings['dev_mode']}{$vpnid}";
408
	else {	/* defaults to tun */
409
		$tunname = "tun{$vpnid}";
410
		$settings['dev_mode'] = "tun";
411
	}
412

    
413
	if ($mode == "server")
414
		$devname = "ovpns{$vpnid}";
415
	else
416
		$devname = "ovpnc{$vpnid}";
417

    
418
	/* is our device already configured */
419
	if (mwexec("/sbin/ifconfig {$devname}", true)) {
420

    
421
		/* create the tap device if required */
422
		if (!file_exists("/dev/{$tunname}"))
423
			exec("/sbin/ifconfig {$tunname} create");
424

    
425
		/* rename the device */
426
		mwexec("/sbin/ifconfig {$tunname} name {$devname}");
427

    
428
		/* add the device to the openvpn group */
429
		mwexec("/sbin/ifconfig {$devname} group openvpn");
430
	}
431

    
432
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
433
	$proto = strtolower($settings['protocol']);
434
	if (substr($settings['protocol'], 0, 3) == "TCP")
435
			$proto = "{$proto}-{$mode}";
436
	$dev_mode = $settings['dev_mode'];
437
	$cipher = $settings['crypto'];
438
	// OpenVPN defaults to SHA1, so use it when unset to maintain compatibility.
439
	$digest = !empty($settings['digest']) ? $settings['digest'] : "SHA1";
440

    
441
	$interface = get_failover_interface($settings['interface']);
442
	$ipaddr = $settings['ipaddr'];
443
	$ipaddrv6 = $settings['ipaddrv6'];
444

    
445
	// If a specific ip address (VIP) is requested, use it.
446
	// Otherwise, if a specific interface is requested, use it
447
	// If "any" interface was selected, local directive will be ommited.
448
	if (is_ipaddrv4($ipaddr)) {
449
		$iface_ip=$ipaddr;
450
	} else {
451
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
452
			$iface_ip=get_interface_ip($interface);
453
		}
454
	}
455
	if (is_ipaddrv6($ipaddrv6)) {
456
		$iface_ipv6=$ipaddrv6;
457
	} else {
458
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
459
			$iface_ipv6=get_interface_ipv6($interface);
460
		}
461
	}
462

    
463
	$conf  = "dev {$devname}\n";
464
	$conf .= "dev-type {$settings['dev_mode']}\n";
465
	switch($settings['dev_mode']) {
466
		case "tun":
467
			$conf .= "tun-ipv6\n";
468
			break;
469
	}
470
	$conf .= "dev-node /dev/{$tunname}\n";
471
	$conf .= "writepid {$pfile}\n";
472
	$conf .= "#user nobody\n";
473
	$conf .= "#group nobody\n";
474
	$conf .= "script-security 3\n";
475
	$conf .= "daemon\n";
476
	$conf .= "keepalive 10 60\n";
477
	$conf .= "ping-timer-rem\n";
478
	$conf .= "persist-tun\n";
479
	$conf .= "persist-key\n";
480
	$conf .= "proto {$proto}\n";
481
	$conf .= "cipher {$cipher}\n";
482
	$conf .= "auth {$digest}\n";
483
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
484
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
485
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
486
		switch($settings['mode']) {
487
			case 'server_user':
488
			case 'server_tls_user':
489
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
490
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
491
				break;
492
		}
493
	}
494

    
495
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
496
	if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
497
		$conf .= "local {$iface_ip}\n";
498
	} elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
499
		$conf .= "local {$iface_ipv6}\n";
500
	}
501

    
502
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none"))
503
		$conf .= "engine {$settings['engine']}\n";
504

    
505
	// server specific settings
506
	if ($mode == 'server') {
507

    
508
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
509
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
510
		$mask = gen_subnet_mask($cidr);
511

    
512
		// configure tls modes
513
		switch($settings['mode']) {
514
			case 'p2p_tls':
515
			case 'server_tls':
516
			case 'server_user':
517
			case 'server_tls_user':
518
				$conf .= "tls-server\n";
519
				break;
520
		}
521

    
522
		// configure p2p/server modes
523
		switch($settings['mode']) {
524
			case 'p2p_tls':
525
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
526
				//  use the server directive. It works for a single client without it.
527
				//  See ticket #1417
528
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
529
					$conf .= "server {$ip} {$mask}\n";
530
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
531
					if(is_ipaddr($ipv6))
532
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
533
				}
534
			case 'p2p_shared_key':
535
				if (!empty($ip) && !empty($mask)) {
536
					list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
537
					if ($settings['dev_mode'] == 'tun')
538
						$conf .= "ifconfig {$ip1} {$ip2}\n";
539
					else
540
						$conf .= "ifconfig {$ip1} {$mask}\n";
541
				}
542
				if (!empty($ipv6) && !empty($prefix)) {
543
					list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
544
					if ($settings['dev_mode'] == 'tun')
545
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
546
					else
547
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
548
				}
549
				break;
550
			case 'server_tls':
551
			case 'server_user':
552
			case 'server_tls_user':
553
				if (!empty($ip) && !empty($mask)) {
554
					$conf .= "server {$ip} {$mask}\n";
555
					if(is_ipaddr($ipv6))
556
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
557
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
558
				} else {
559
					if ($settings['serverbridge_dhcp']) {
560
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
561
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
562
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
563
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
564
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
565
							} else {
566
								$conf .= "mode server\n";
567
							}
568
						} else {
569
							$conf .= "mode server\n";
570
						}
571
					}
572
				}
573
				break;
574
		}
575

    
576
		// configure user auth modes
577
		switch($settings['mode']) {
578
			case 'server_user':
579
				$conf .= "client-cert-not-required\n";
580
			case 'server_tls_user':
581
				/* username-as-common-name is not compatible with server-bridge */
582
				if (stristr($conf, "server-bridge") === false)
583
					$conf .= "username-as-common-name\n";
584
				if (!empty($settings['authmode'])) {
585
					$authcfgs = explode(",", $settings['authmode']);
586
					$sed = "\$authmodes=array(";
587
					$firstsed = 0;
588
					foreach ($authcfgs as $authcfg) {
589
						if ($firstsed > 0)
590
							$sed .= ",";
591
						$firstsed = 1;
592
						$sed .= "\"{$authcfg}\"";
593
					}
594
					$sed .= ");\\\n";
595
					if ($settings['strictusercn'])
596
						$sed .= "\$strictusercn = true;";
597
					$sed .= " \$modeid = \"{$mode_id}\";";
598
					mwexec("/bin/cat /etc/inc/openvpn.auth-user.php | /usr/bin/sed 's/\/\/<template>/{$sed}/g' >  {$g['varetc_path']}/openvpn/{$mode_id}.php");
599
					mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.php");
600
					$conf .= "auth-user-pass-verify {$g['varetc_path']}/openvpn/{$mode_id}.php via-env\n";
601
				}
602
				break;
603
		}
604
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls')))
605
			$settings['cert_depth'] = 1;
606
		if (is_numeric($settings['cert_depth'])) {
607
			$sed = "";
608
			$cert = lookup_cert($settings['certref']);
609
			$servercn = cert_get_cn($cert['crt']);
610
			$sed .= "\$server_cn = \"{$servercn}\";\\\n";
611
			$sed .= "\$allowed_depth = {$settings['cert_depth']};\\\n";
612
			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");
613
			mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php");
614
			$conf .= "tls-verify {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php\n";
615
		}
616

    
617
		// The local port to listen on
618
		$conf .= "lport {$settings['local_port']}\n";
619

    
620
		// The management port to listen on
621
		// Use unix socket to overcome the problem on any type of server
622
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
623
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
624

    
625
		if ($settings['maxclients'])
626
			$conf .= "max-clients {$settings['maxclients']}\n";
627

    
628
		// Can we push routes
629
		if ($settings['local_network']) {
630
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
631
		}
632
		if ($settings['local_networkv6']) {
633
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
634
		}
635

    
636
		switch($settings['mode']) {
637
			case 'server_tls':
638
			case 'server_user':
639
			case 'server_tls_user':
640
				// Configure client dhcp options
641
				openvpn_add_dhcpopts($settings, $conf);
642
				if ($settings['client2client'])
643
					$conf .= "client-to-client\n";
644
				break;
645
		}
646
		if (isset($settings['duplicate_cn']))
647
			$conf .= "duplicate-cn\n";
648
	}
649

    
650
	// client specific settings
651

    
652
	if ($mode == 'client') {
653

    
654
		// configure p2p mode
655
		switch($settings['mode']) {
656
			case 'p2p_tls':
657
				$conf .= "tls-client\n";
658
			case 'shared_key':
659
				$conf .= "client\n";
660
				break;
661
		}
662

    
663
		// If there is no bind option at all (ip and/or port), add "nobind" directive
664
		//  Otherwise, use the local port if defined, failing that, use lport 0 to 
665
		//  ensure a random source port.
666
		if ((empty($iface_ip)) && (!$settings['local_port']))
667
			$conf .= "nobind\n";
668
		elseif ($settings['local_port'])
669
			$conf .= "lport {$settings['local_port']}\n";
670
		else
671
			$conf .= "lport 0\n";
672

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

    
676
		// The remote server
677
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
678

    
679
		if (!empty($settings['use_shaper']))
680
			$conf .= "shaper {$settings['use_shaper']}\n";
681

    
682
		if (!empty($settings['tunnel_network'])) {
683
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
684
			$mask = gen_subnet_mask($mask);
685
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
686
			if ($settings['dev_mode'] == 'tun')
687
				$conf .= "ifconfig {$ip2} {$ip1}\n";
688
			else
689
				$conf .= "ifconfig {$ip2} {$mask}\n";
690
		}
691

    
692
		if (!empty($settings['tunnel_networkv6'])) {
693
			list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
694
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
695
			if ($settings['dev_mode'] == 'tun')
696
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
697
			else
698
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
699
		}
700

    
701
		if ($settings['proxy_addr']) {
702
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
703
			if ($settings['proxy_authtype'] != "none") {
704
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
705
				$proxypas = "{$settings['proxy_user']}\n";
706
				$proxypas .= "{$settings['proxy_passwd']}\n";
707
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
708
			}
709
			$conf .= " \n";
710
		}
711
	}
712

    
713
	// Add a remote network route if set, and only for p2p modes.
714
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
715
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
716
	}
717
	// Add a remote network route if set, and only for p2p modes.
718
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
719
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
720
	}
721

    
722
	// Write the settings for the keys
723
	switch($settings['mode']) {
724
		case 'p2p_shared_key':
725
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
726
			break;
727
		case 'p2p_tls':
728
		case 'server_tls':
729
		case 'server_tls_user':
730
		case 'server_user':
731
			$ca = lookup_ca($settings['caref']);
732
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
733
			$cert = lookup_cert($settings['certref']);
734
			openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
735
			openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
736
			if ($mode == 'server')
737
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
738
			if (!empty($settings['crlref'])) {
739
				$crl = lookup_crl($settings['crlref']);
740
				crl_update($crl);
741
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
742
			}
743
			if ($settings['tls']) {
744
				if ($mode == "server") 
745
					$tlsopt = 0;
746
				else
747
					$tlsopt = 1;
748
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
749
			}
750
			break;
751
	}
752

    
753
	if (!empty($settings['compression']))
754
		$conf .= "comp-lzo {$settings['compression']}\n";
755

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

    
759
	if ($settings['resolve_retry'])
760
		$conf .= "resolv-retry infinite\n";
761

    
762
	if ($settings['dynamic_ip']) {
763
		$conf .= "persist-remote-ip\n";
764
		$conf .= "float\n";
765
	}
766

    
767
	if ($settings['topology_subnet']) {
768
		$conf .= "topology subnet\n";
769
	}
770

    
771
	openvpn_add_custom($settings, $conf);
772

    
773
	openvpn_create_dirs();
774
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
775
	file_put_contents($fpath, $conf);
776
	unset($conf);
777
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
778
	file_put_contents($fpath, $interface);
779
	//chown($fpath, 'nobody');
780
	//chgrp($fpath, 'nobody');
781
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
782
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
783
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
784
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
785
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
786
}
787

    
788
function openvpn_restart($mode, $settings) {
789
	global $g, $config;
790

    
791
	$vpnid = $settings['vpnid'];
792
	$mode_id = $mode.$vpnid;
793

    
794
	/* kill the process if running */
795
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
796
	if (file_exists($pfile)) {
797

    
798
		/* read the pid file */
799
		$pid = rtrim(file_get_contents($pfile));
800
		unlink($pfile);
801

    
802
		/* send a term signal to the process */
803
		posix_kill($pid, SIGTERM);
804

    
805
		/* wait until the process exits */
806
		while(posix_kill($pid, 0))
807
			usleep(250000);
808
	}
809

    
810
	if (isset($settings['disable']))
811
		return;
812

    
813
	/* Do not start a client if we are a CARP backup on this vip! */
814
	if (($mode == "client") && strstr($settings['interface'], "_vip") && (get_carp_interface_status($settings['interface']) == "BACKUP"))
815
		return;
816
		
817
	/* Check if client is bound to a gateway group */    
818
	$a_groups = return_gateway_groups_array();
819
	if (is_array($a_groups[$settings['interface']])) {
820
	/* the interface is a gateway group. If a vip is defined and its a CARP backup then do not start */
821
		if (($a_groups[$settings['interface']][0]['vip'] <> "") && (get_carp_interface_status($a_groups[$settings['interface']][0]['vip']) == "BACKUP"))
822
			return;
823
	}
824

    
825
	/* start the new process */
826
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
827
	openvpn_clear_route($mode, $settings);
828
	mwexec_bg("/usr/local/sbin/openvpn --config {$fpath}");
829

    
830
	if (!$g['booting'])
831
		send_event("filter reload");
832
}
833

    
834
function openvpn_delete($mode, & $settings) {
835
	global $g, $config;
836

    
837
	$vpnid = $settings['vpnid'];
838
	$mode_id = $mode.$vpnid;
839

    
840
	if (isset($settings['dev_mode']))
841
		$tunname = "{$settings['dev_mode']}{$vpnid}";
842
	else {  /* defaults to tun */
843
		$tunname = "tun{$vpnid}";
844
	}
845

    
846
	if ($mode == "server")
847
		$devname = "ovpns{$vpnid}";
848
	else
849
		$devname = "ovpnc{$vpnid}";
850

    
851
	/* kill the process if running */
852
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
853
	if (file_exists($pfile)) {
854

    
855
		/* read the pid file */
856
		$pid = trim(file_get_contents($pfile));
857
		unlink($pfile);
858

    
859
		/* send a term signal to the process */
860
		posix_kill($pid, SIGTERM);
861
	}
862

    
863
	/* remove the device from the openvpn group */
864
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
865

    
866
	/* restore the original adapter name */
867
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
868

    
869
	/* remove the configuration files */
870
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
871
}
872

    
873
function openvpn_cleanup_csc($common_name) {
874
	global $g, $config;
875
	if (empty($common_name))
876
		return;
877
	$fpath = "{$g['varetc_path']}/openvpn-csc/" . basename($common_name);
878
	if (is_file($fpath))
879
		unlink_if_exists($fpath);
880
	return;
881
}
882

    
883
function openvpn_resync_csc(& $settings) {
884
	global $g, $config;
885

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

    
888
	if (isset($settings['disable'])) {
889
		unlink_if_exists($fpath);
890
		return;
891
	}
892
	openvpn_create_dirs();
893

    
894
	$conf = '';
895
	if ($settings['block'])
896
		$conf .= "disable\n";
897

    
898
	if ($settings['push_reset'])
899
		$conf .= "push-reset\n";
900

    
901
	if (!empty($settings['tunnel_network'])) {
902
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
903
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
904
		$serverip = long2ip32($baselong + 1);
905
		$clientip = long2ip32($baselong + 2);
906
		/* Because this is being pushed, the order from the client's point of view. */
907
		if ($settings['dev_mode'] != 'tap')
908
			$conf .= "ifconfig-push {$clientip} {$serverip}\n";
909
		else
910
			$conf .= "ifconfig-push {$clientip} {$mask}\n";
911
	}
912

    
913
	openvpn_add_dhcpopts($settings, $conf);
914

    
915
	if ($settings['gwredir'])
916
		$conf .= "push \"redirect-gateway def1\"\n";
917

    
918
	openvpn_add_custom($settings, $conf);
919

    
920
	file_put_contents($fpath, $conf);
921
	chown($fpath, 'nobody');
922
	chgrp($fpath, 'nobody');
923
}
924

    
925
function openvpn_delete_csc(& $settings) {
926
	global $g, $config;
927

    
928
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
929
	unlink_if_exists($fpath);
930
}
931

    
932
// Resync the configuration and restart the VPN
933
function openvpn_resync($mode, $settings) {
934
	openvpn_reconfigure($mode, $settings);
935
	openvpn_restart($mode, $settings);
936
}
937

    
938
// Resync and restart all VPNs
939
function openvpn_resync_all($interface = "") {
940
	global $g, $config;
941

    
942
	if ($g['platform'] == 'jail')
943
		return;
944
	openvpn_create_dirs();
945

    
946
	if (!is_array($config['openvpn']))
947
		$config['openvpn'] = array();
948

    
949
/*
950
	if (!$config['openvpn']['dh-parameters']) {
951
		echo "Configuring OpenVPN Parameters ...\n";
952
		$dh_parameters = openvpn_create_dhparams(1024);
953
		$dh_parameters = base64_encode($dh_parameters);
954
		$config['openvpn']['dh-parameters'] = $dh_parameters;
955
		write_config("OpenVPN DH parameters");
956
	}
957

    
958
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
959
	if (!file_exists($path_ovdh)) {
960
		$dh_parameters = $config['openvpn']['dh-parameters'];
961
		$dh_parameters = base64_decode($dh_parameters);
962
		file_put_contents($path_ovdh, $dh_parameters);
963
	}
964
*/
965
	if ($interface <> "")
966
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
967
	else
968
		log_error("Resyncing OpenVPN instances."); 
969

    
970
	if (is_array($config['openvpn']['openvpn-server'])) {
971
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
972
			if ($interface <> "" && $interface != $settings['interface'])
973
				continue;
974
			openvpn_resync('server', $settings);
975
		}
976
	}
977

    
978
	if (is_array($config['openvpn']['openvpn-client'])) {
979
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
980
			if ($interface <> "" && $interface != $settings['interface'])
981
				continue;
982
			openvpn_resync('client', $settings);
983
		}
984
	}
985

    
986
	if (is_array($config['openvpn']['openvpn-csc']))
987
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
988
			openvpn_resync_csc($settings);
989

    
990
}
991

    
992
// Resync and restart all VPNs using a gateway group.
993
function openvpn_resync_gwgroup($gwgroupname = "") {
994
	global $g, $config;
995

    
996
	if ($gwgroupname <> "") {
997
		if (is_array($config['openvpn']['openvpn-server'])) {
998
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
999
				if ($gwgroupname == $settings['interface']) {
1000
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " server " . $settings["description"] . ".");
1001
					openvpn_resync('server', $settings);
1002
				}
1003
			}
1004
		}
1005

    
1006
		if (is_array($config['openvpn']['openvpn-client'])) {
1007
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1008
				if ($gwgroupname == $settings['interface']) {
1009
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " client " . $settings["description"] . ".");
1010
					openvpn_resync('client', $settings);
1011
				}
1012
			}
1013
		}
1014

    
1015
		// Note: no need to resysnc Client Specific (csc) here, as changes to the OpenVPN real interface do not effect these.
1016

    
1017
	} else
1018
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter."); 
1019
}
1020

    
1021
function openvpn_get_active_servers($type="multipoint") {
1022
	global $config, $g;
1023

    
1024
	$servers = array();
1025
	if (is_array($config['openvpn']['openvpn-server'])) {
1026
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1027
			if (empty($settings) || isset($settings['disable']))
1028
				continue;
1029

    
1030
			$prot = $settings['protocol'];
1031
			$port = $settings['local_port'];
1032
	
1033
			$server = array();
1034
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
1035
			$server['mode'] = $settings['mode'];
1036
			if ($settings['description'])
1037
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
1038
			else
1039
				$server['name'] = "Server {$prot}:{$port}";
1040
			$server['conns'] = array();
1041
			$server['vpnid'] = $settings['vpnid'];
1042
			$server['mgmt'] = "server{$server['vpnid']}";
1043
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
1044
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
1045

    
1046
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
1047
				$servers[] = openvpn_get_client_status($server, $socket);
1048
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
1049
				$servers[] = openvpn_get_server_status($server, $socket);
1050

    
1051
		}
1052
	}
1053
	return $servers;
1054
}
1055

    
1056
function openvpn_get_server_status($server, $socket) {
1057
	$errval;
1058
	$errstr;
1059
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1060
	if ($fp) {
1061
		stream_set_timeout($fp, 1);
1062

    
1063
		/* send our status request */
1064
		fputs($fp, "status 2\n");
1065

    
1066
		/* recv all response lines */
1067
		while (!feof($fp)) {
1068

    
1069
			/* read the next line */
1070
			$line = fgets($fp, 1024);
1071

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

    
1076
			/* parse header list line */
1077
			if (strstr($line, "HEADER"))
1078
				continue;
1079

    
1080
			/* parse end of output line */
1081
			if (strstr($line, "END") || strstr($line, "ERROR"))
1082
				break;
1083

    
1084
			/* parse client list line */
1085
			if (strstr($line, "CLIENT_LIST")) {
1086
				$list = explode(",", $line);
1087
				$conn = array();
1088
				$conn['common_name'] = $list[1];
1089
				$conn['remote_host'] = $list[2];
1090
				$conn['virtual_addr'] = $list[3];
1091
				$conn['bytes_recv'] = $list[4];
1092
				$conn['bytes_sent'] = $list[5];
1093
				$conn['connect_time'] = $list[6];
1094
				$server['conns'][] = $conn;
1095
			}
1096
			/* parse routing table lines */
1097
			if (strstr($line, "ROUTING_TABLE")) {
1098
				$list = explode(",", $line);
1099
				$conn = array();
1100
				$conn['virtual_addr'] = $list[1];
1101
				$conn['common_name'] = $list[2];
1102
				$conn['remote_host'] = $list[3];
1103
				$conn['last_time'] = $list[4];
1104
				$server['routes'][] = $conn;
1105
			}
1106
		}
1107

    
1108
		/* cleanup */
1109
		fclose($fp);
1110
	} else {
1111
		$conn = array();
1112
		$conn['common_name'] = "[error]";
1113
		$conn['remote_host'] = "Unable to contact daemon";
1114
		$conn['virtual_addr'] = "Service not running?";
1115
		$conn['bytes_recv'] = 0;
1116
		$conn['bytes_sent'] = 0;
1117
		$conn['connect_time'] = 0;
1118
		$server['conns'][] = $conn;
1119
	}
1120
	return $server;
1121
}
1122

    
1123
function openvpn_get_active_clients() {
1124
	global $config, $g;
1125

    
1126
	$clients = array();
1127
	if (is_array($config['openvpn']['openvpn-client'])) {
1128
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1129
	
1130
			if (empty($settings) || isset($settings['disable']))
1131
				continue;
1132

    
1133
			$prot = $settings['protocol'];
1134
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1135
	
1136
			$client = array();
1137
			$client['port'] = $settings['local_port'];
1138
			if ($settings['description'])
1139
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1140
			else
1141
				$client['name'] = "Client {$prot}{$port}";
1142
	
1143
			$client['vpnid'] = $settings['vpnid'];
1144
			$client['mgmt'] = "client{$client['vpnid']}";
1145
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1146
			$client['status']="down";
1147

    
1148
			$clients[] = openvpn_get_client_status($client, $socket);
1149
		}
1150
	}
1151
	return $clients;
1152
}
1153

    
1154
function openvpn_get_client_status($client, $socket) {
1155
	$errval;
1156
	$errstr;
1157
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1158
	if ($fp) {
1159
		stream_set_timeout($fp, 1);
1160
		/* send our status request */
1161
		fputs($fp, "state 1\n");
1162

    
1163
		/* recv all response lines */
1164
		while (!feof($fp)) {
1165
			/* read the next line */
1166
			$line = fgets($fp, 1024);
1167

    
1168
			$info = stream_get_meta_data($fp);
1169
			if ($info['timed_out'])
1170
				break;
1171

    
1172
			/* Get the client state */
1173
			if (strstr($line,"CONNECTED")) {
1174
				$client['status']="up";
1175
				$list = explode(",", $line);
1176

    
1177
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1178
				$client['virtual_addr']  = $list[3];
1179
				$client['remote_host'] = $list[4];
1180
			}
1181
			if (strstr($line,"CONNECTING")) {
1182
				$client['status']="connecting";
1183
			}
1184
			if (strstr($line,"ASSIGN_IP")) {
1185
				$client['status']="waiting";
1186
				$list = explode(",", $line);
1187

    
1188
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1189
				$client['virtual_addr']  = $list[3];
1190
			}
1191
			if (strstr($line,"RECONNECTING")) {
1192
				$client['status']="reconnecting";
1193
				$list = explode(",", $line);
1194

    
1195
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1196
				$client['status'] .= "; " . $list[2];
1197
			}
1198
			/* parse end of output line */
1199
			if (strstr($line, "END") || strstr($line, "ERROR"))
1200
				break;
1201
		}
1202

    
1203
		/* If up, get read/write stats */
1204
		if (strcmp($client['status'], "up") == 0) {
1205
			fputs($fp, "status 2\n");
1206
			/* recv all response lines */
1207
			while (!feof($fp)) {
1208
				/* read the next line */
1209
				$line = fgets($fp, 1024);
1210

    
1211
				$info = stream_get_meta_data($fp);
1212
				if ($info['timed_out'])
1213
					break;
1214

    
1215
				if (strstr($line,"TCP/UDP read bytes")) {
1216
					$list = explode(",", $line);
1217
					$client['bytes_recv'] = $list[1];
1218
				}
1219

    
1220
				if (strstr($line,"TCP/UDP write bytes")) {
1221
					$list = explode(",", $line);
1222
					$client['bytes_sent'] = $list[1];
1223
				}
1224

    
1225
				/* parse end of output line */
1226
				if (strstr($line, "END"))
1227
					break;
1228
			}
1229
		}
1230

    
1231
		fclose($fp);
1232

    
1233
	} else {
1234
		$DisplayNote=true;
1235
		$client['remote_host'] = "Unable to contact daemon";
1236
		$client['virtual_addr'] = "Service not running?";
1237
		$client['bytes_recv'] = 0;
1238
		$client['bytes_sent'] = 0;
1239
		$client['connect_time'] = 0;
1240
	}
1241
	return $client;
1242
}
1243

    
1244
function openvpn_refresh_crls() {
1245
	global $g, $config;
1246

    
1247
	openvpn_create_dirs();
1248

    
1249
	if (is_array($config['openvpn']['openvpn-server'])) {
1250
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1251
			if (empty($settings))
1252
				continue;
1253
			if (isset($settings['disable']))
1254
				continue;
1255
			// Write the settings for the keys
1256
			switch($settings['mode']) {
1257
				case 'p2p_tls':
1258
				case 'server_tls':
1259
				case 'server_tls_user':
1260
				case 'server_user':
1261
					if (!empty($settings['crlref'])) {
1262
						$crl = lookup_crl($settings['crlref']);
1263
						crl_update($crl);
1264
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1265
						file_put_contents($fpath, base64_decode($crl['text']));
1266
						@chmod($fpath, 0644);
1267
					}
1268
					break;
1269
			}
1270
		}
1271
	}
1272
}
1273

    
1274
function openvpn_create_dirs() {
1275
	global $g;
1276
	if (!is_dir("{$g['varetc_path']}/openvpn"))
1277
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1278
	if (!is_dir("{$g['varetc_path']}/openvpn-csc"))
1279
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1280
}
1281

    
1282
function openvpn_get_interface_ip($ip, $mask) {
1283
	$baselong = ip2long32($ip) & ip2long($mask);
1284
	$ip1 = long2ip32($baselong + 1);
1285
	$ip2 = long2ip32($baselong + 2);
1286
	return array($ip1, $ip2);
1287
}
1288

    
1289
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1290
	$basev6 = gen_subnetv6($ipv6, $prefix);
1291
	// Is there a better way to do this math?
1292
	$ipv6_arr = explode(':', $basev6);
1293
	$last = hexdec(array_pop($ipv6_arr));
1294
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1295
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1296
	return array($ipv6_1, $ipv6_2);
1297
}
1298

    
1299
function openvpn_clear_route($mode, $settings) {
1300
	if (empty($settings['tunnel_network']))
1301
		return;
1302
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1303
	$mask = gen_subnet_mask($cidr);
1304
	$clear_route = false;
1305

    
1306
	switch($settings['mode']) {
1307
		case 'shared_key':
1308
			$clear_route = true;
1309
			break;
1310
		case 'p2p_tls':
1311
		case 'p2p_shared_key':
1312
			if ($cidr == 30)
1313
				$clear_route = true;
1314
			break;
1315
	}
1316

    
1317
	if ($clear_route && !empty($ip) && !empty($mask)) {
1318
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1319
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1320
		/* XXX: Family for route? */
1321
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1322
	}
1323
}
1324

    
1325
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false) {
1326
	$routes = "";
1327
	if (empty($value))
1328
		return "";
1329
	$networks = explode(',', $value);
1330

    
1331
	foreach ($networks as $network) {
1332
		if ($ipproto == "ipv4")
1333
			$route = openvpn_gen_route_ipv4($network);
1334
		else
1335
			$route = openvpn_gen_route_ipv6($network);
1336

    
1337
		if ($push)
1338
			$routes .= "push \"{$route}\"\n";
1339
		else
1340
			$routes .= "{$route}\n";
1341
	}
1342
	return $routes;
1343
}
1344

    
1345
function openvpn_gen_route_ipv4($network) {
1346
	list($ip, $mask) = explode('/', trim($network));
1347
	$mask = gen_subnet_mask($mask);
1348
	return "route $ip $mask";
1349
}
1350

    
1351
function openvpn_gen_route_ipv6($network) {
1352
	list($ipv6, $prefix) = explode('/', trim($network));
1353
	if (empty($prefix))
1354
		$prefix = "128";
1355
	return "route-ipv6 ${ipv6}/${prefix}";
1356
}
1357

    
1358
function openvpn_get_settings($mode, $vpnid) {
1359
	global $config;
1360

    
1361
	if (is_array($config['openvpn']['openvpn-server'])) {
1362
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1363
			if (isset($settings['disable']))
1364
				continue;
1365

    
1366
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1367
				return $settings;
1368
		}
1369
	}
1370

    
1371
	if (is_array($config['openvpn']['openvpn-client'])) {
1372
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1373
			if (isset($settings['disable']))
1374
				continue;
1375

    
1376
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1377
				return $settings;
1378
		}
1379
	}
1380

    
1381
	return array();
1382
}
1383

    
1384
function openvpn_restart_by_vpnid($mode, $vpnid) {
1385
	$settings = openvpn_get_settings($mode, $vpnid);
1386
	openvpn_restart($mode, $settings);
1387
}
1388

    
1389
?>
(37-37/66)