Project

General

Profile

Download (42.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

    
42
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/openvpn	/usr/bin/openssl	/sbin/ifconfig
43
	pfSense_MODULE:	openvpn
44

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

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

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

    
57
global $openvpn_verbosity_level;
58
$openvpn_verbosity_level = array(
59
	0 =>	"none",
60
	1 =>	"default",
61
	2 =>	"2",
62
	3 =>	"3 (recommended)",
63
	4 =>	"4",
64
	5 => 	"5",
65
	6 => 	"6",
66
	7 => 	"7",
67
	8 => 	"8",
68
	9 => 	"9",
69
	10 => 	"10",
70
	11 => 	"11"
71
);
72

    
73
/*
74
 * The User Auth mode below is disabled because
75
 * OpenVPN erroneously requires that we provide
76
 * a CA configuration parameter. In this mode,
77
 * clients don't send a certificate so there is
78
 * no need for a CA. If we require that admins
79
 * provide one in the pfSense UI due to a bogus
80
 * requirement imposed by OpenVPN, it could be
81
 * considered very confusing ( I know I was ).
82
 *
83
 * -mgrooms
84
 */
85

    
86
global $openvpn_dh_lengths;
87
$openvpn_dh_lengths = array(
88
	1024, 2048, 4096 );
89

    
90
global $openvpn_cert_depths;
91
$openvpn_cert_depths = array(
92
	1 => "One (Client+Server)",
93
	2 => "Two (Client+Intermediate+Server)",
94
	3 => "Three (Client+2xIntermediate+Server)",
95
	4 => "Four (Client+3xIntermediate+Server)",
96
	5 => "Five (Client+4xIntermediate+Server)"
97
);
98

    
99
global $openvpn_server_modes;
100
$openvpn_server_modes = array(
101
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
102
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
103
	'server_tls' => gettext("Remote Access ( SSL/TLS )"),
104
	'server_user' => gettext("Remote Access ( User Auth )"),
105
	'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
106

    
107
global $openvpn_client_modes;
108
$openvpn_client_modes = array(
109
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
110
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )") );
111

    
112
global $openvpn_compression_modes;
113
$openvpn_compression_modes = array(
114
	'' =>	gettext("No Preference"),
115
	'no' =>		gettext("Disabled - No Compression"),
116
	'adaptive' =>	gettext("Enabled with Adaptive Compression"),
117
	'yes' =>	gettext("Enabled without Adaptive Compression"));
118

    
119
function openvpn_create_key() {
120

    
121
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
122
	if (!$fp)
123
		return false;
124

    
125
	$rslt = stream_get_contents($fp);
126
	pclose($fp);
127

    
128
	return $rslt;
129
}
130

    
131
function openvpn_create_dhparams($bits) {
132

    
133
	$fp = popen("/usr/bin/openssl dhparam {$bits} 2>/dev/null", "r");
134
	if (!$fp)
135
		return false;
136

    
137
	$rslt = stream_get_contents($fp);
138
	pclose($fp);
139

    
140
	return $rslt;
141
}
142

    
143
function openvpn_vpnid_used($vpnid) {
144
	global $config;
145

    
146
	if (is_array($config['openvpn']['openvpn-server']))
147
		foreach ($config['openvpn']['openvpn-server'] as & $settings)
148
			if ($vpnid == $settings['vpnid'])
149
				return true;
150

    
151
	if (is_array($config['openvpn']['openvpn-client']))
152
		foreach ($config['openvpn']['openvpn-client'] as & $settings)
153
			if ($vpnid == $settings['vpnid'])
154
				return true;
155

    
156
	return false;
157
}
158

    
159
function openvpn_vpnid_next() {
160

    
161
	$vpnid = 1;
162
	while(openvpn_vpnid_used($vpnid))
163
		$vpnid++;
164

    
165
	return $vpnid;
166
}
167

    
168
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
169
	global $config;
170

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

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

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

    
185
	if (is_array($config['openvpn']['openvpn-client'])) {
186
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
187
			if (isset($settings['disable']))
188
				continue;
189

    
190
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid'])
191
				continue;
192

    
193
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
194
				($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any"))
195
				return $settings['vpnid'];
196
		}
197
	}
198

    
199
	return 0;
200
}
201

    
202
function openvpn_port_next($prot, $interface = "wan") {
203

    
204
	$port = 1194;
205
	while(openvpn_port_used($prot, $interface, $port))
206
		$port++;
207
	while(openvpn_port_used($prot, "any", $port))
208
		$port++;
209

    
210
	return $port;
211
}
212

    
213
function openvpn_get_cipherlist() {
214

    
215
	$ciphers = array();
216
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
217
	$cipher_lines = explode("\n", trim($cipher_out));
218
	sort($cipher_lines);
219
	foreach ($cipher_lines as $line) {
220
		$words = explode(' ', $line);
221
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
222
	}
223
	$ciphers["none"] = gettext("None (No Encryption)");
224
	return $ciphers;
225
}
226

    
227
function openvpn_get_digestlist() {
228

    
229
	$digests = array();
230
	$digest_out = shell_exec('/usr/local/sbin/openvpn --show-digests | /usr/bin/grep "digest size" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
231
	$digest_lines = explode("\n", trim($digest_out));
232
	sort($digest_lines);
233
	foreach ($digest_lines as $line) {
234
		$words = explode(' ', $line);
235
		$digests[$words[0]] = "{$words[0]} {$words[1]}";
236
	}
237
	$digests["none"] = gettext("None (No Authentication)");
238
	return $digests;
239
}
240

    
241
function openvpn_get_engines() {
242
	$openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
243
	exec("/usr/bin/openssl engine -t -c", $openssl_engine_output);
244
	$openssl_engine_output = implode("\n", $openssl_engine_output);
245
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
246
	$openssl_engine_output = explode("\n", $openssl_engine_output);
247

    
248
	foreach ($openssl_engine_output as $oeo) {
249
		$keep = true;
250
		$details = explode("|", $oeo);
251
		$engine = array_shift($details);
252
		$linematch = array();
253
		preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
254
		foreach ($details as $dt) {
255
			if (strpos($dt, "unavailable") !== FALSE)
256
				$keep = false;
257
			if (strpos($dt, "available") !== FALSE)
258
				continue;
259
			if (strpos($dt, "[") !== FALSE)
260
				$ciphers = trim($dt, "[]");
261
		}
262
		if (!empty($ciphers))
263
			$ciphers = " - " . $ciphers;
264
		if (strlen($ciphers) > 60)
265
			$ciphers = substr($ciphers, 0, 60) . " ... ";
266
		if ($keep)
267
			$openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
268
	}
269
	return $openssl_engines;
270
}
271

    
272
function openvpn_validate_engine($engine) {
273
	$engines = openvpn_get_engines();
274
	return array_key_exists($engine, $engines);
275
}
276

    
277
function openvpn_validate_host($value, $name) {
278
	$value = trim($value);
279
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value)))
280
		return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
281
	return false;
282
}
283

    
284
function openvpn_validate_port($value, $name) {
285
	$value = trim($value);
286
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535))
287
		return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
288
	return false;
289
}
290

    
291
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
292
	$value = trim($value);
293
	$error = false;
294
	if (empty($value))
295
		return false;
296
	$networks = explode(',', $value);
297

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

    
301
	foreach ($networks as $network) {
302
		if ($ipproto == "ipv4")
303
			$error = !openvpn_validate_cidr_ipv4($network);
304
		else
305
			$error = !openvpn_validate_cidr_ipv6($network);
306
		if ($error)
307
			break;
308
	}
309

    
310
	if ($error)
311
		return sprintf(gettext("The field '%s' must contain only valid %s CIDR range(s) separated by commas."), $name, $ipproto);
312
	else
313
		return false;
314
}
315

    
316
function openvpn_validate_cidr_ipv4($value) {
317
	$value = trim($value);
318
	if (!empty($value)) {
319
		list($ip, $mask) = explode('/', $value);
320
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
321
			return false;
322
	}
323
	return true;
324
}
325

    
326
function openvpn_validate_cidr_ipv6($value) {
327
	$value = trim($value);
328
	if (!empty($value)) {
329
		list($ipv6, $prefix) = explode('/', $value);
330
		if (empty($prefix))
331
			$prefix = "128";
332
		if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0))
333
			return false;
334
	}
335
	return true;
336
}
337

    
338
function openvpn_add_dhcpopts(& $settings, & $conf) {
339

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

    
343
	if (!empty($settings['dns_server1']))
344
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
345
	if (!empty($settings['dns_server2']))
346
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
347
	if (!empty($settings['dns_server3']))
348
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
349
	if (!empty($settings['dns_server4']))
350
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
351

    
352
	if (!empty($settings['push_register_dns']))
353
		$conf .= "push \"register-dns\"\n";
354

    
355
	if (!empty($settings['ntp_server1']))
356
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
357
	if (!empty($settings['ntp_server2']))
358
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
359

    
360
	if ($settings['netbios_enable']) {
361

    
362
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0))
363
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
364
		if (!empty($settings['dhcp_nbtscope']))
365
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
366

    
367
		if (!empty($settings['wins_server1']))
368
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
369
		if (!empty($settings['wins_server2']))
370
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
371

    
372
		if (!empty($settings['nbdd_server1']))
373
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
374
	}
375

    
376
	if ($settings['gwredir'])
377
		$conf .= "push \"redirect-gateway def1\"\n";
378
}
379

    
380
function openvpn_add_custom(& $settings, & $conf) {
381

    
382
	if ($settings['custom_options']) {
383

    
384
		$options = explode(';', $settings['custom_options']);
385

    
386
		if (is_array($options)) {
387
			foreach ($options as $option)
388
				$conf .= "$option\n";
389
		} else
390
			$conf .= "{$settings['custom_options']}\n";
391
	}
392
}
393

    
394
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
395
	global $g;
396

    
397
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
398
	openvpn_create_dirs();
399
	file_put_contents($fpath, base64_decode($data));
400
	//chown($fpath, 'nobody');
401
	//chgrp($fpath, 'nobody');
402
	@chmod($fpath, 0600);
403

    
404
	$conf .= "{$directive} {$fpath} {$opt}\n";
405
}
406

    
407
function openvpn_reconfigure($mode, $settings) {
408
	global $g, $config;
409

    
410
	if (empty($settings))
411
		return;
412
	if (isset($settings['disable']))
413
		return;
414
	openvpn_create_dirs();
415
	/*
416
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
417
	 * we use a vpnid number which is allocated for a particular client
418
	 * or server configuration. ( see openvpn_vpnid_next() )
419
	 */
420

    
421
	$vpnid = $settings['vpnid'];
422
	$mode_id = $mode.$vpnid;
423

    
424
	if (isset($settings['dev_mode']))
425
		$tunname = "{$settings['dev_mode']}{$vpnid}";
426
	else {	/* defaults to tun */
427
		$tunname = "tun{$vpnid}";
428
		$settings['dev_mode'] = "tun";
429
	}
430

    
431
	if ($mode == "server")
432
		$devname = "ovpns{$vpnid}";
433
	else
434
		$devname = "ovpnc{$vpnid}";
435

    
436
	/* is our device already configured */
437
	if (!does_interface_exist($devname)) {
438

    
439
		/* create the tap device if required */
440
		if (!file_exists("/dev/{$tunname}"))
441
			exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
442

    
443
		/* rename the device */
444
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
445

    
446
		/* add the device to the openvpn group */
447
		mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " group openvpn");
448
	}
449

    
450
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
451
	$proto = strtolower($settings['protocol']);
452
	if (substr($settings['protocol'], 0, 3) == "TCP")
453
			$proto = "{$proto}-{$mode}";
454
	$dev_mode = $settings['dev_mode'];
455
	$cipher = $settings['crypto'];
456
	// OpenVPN defaults to SHA1, so use it when unset to maintain compatibility.
457
	$digest = !empty($settings['digest']) ? $settings['digest'] : "SHA1";
458

    
459
	$interface = get_failover_interface($settings['interface']);
460
	$ipaddr = $settings['ipaddr'];
461
	$ipaddrv6 = $settings['ipaddrv6'];
462

    
463
	// If a specific ip address (VIP) is requested, use it.
464
	// Otherwise, if a specific interface is requested, use it
465
	// If "any" interface was selected, local directive will be ommited.
466
	if (is_ipaddrv4($ipaddr)) {
467
		$iface_ip=$ipaddr;
468
	} else {
469
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
470
			$iface_ip=get_interface_ip($interface);
471
		}
472
	}
473
	if (is_ipaddrv6($ipaddrv6)) {
474
		$iface_ipv6=$ipaddrv6;
475
	} else {
476
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
477
			$iface_ipv6=get_interface_ipv6($interface);
478
		}
479
	}
480

    
481

    
482
	$conf = "dev {$devname}\n";
483
	if (isset($settings['verbosity_level'])) {
484
		$conf .= "verb {$settings['verbosity_level']}\n";
485
	}
486

    
487
	$conf .= "dev-type {$settings['dev_mode']}\n";
488
	switch($settings['dev_mode']) {
489
		case "tun":
490
			if (!$settings['no_tun_ipv6']) {
491
				$conf .= "tun-ipv6\n";
492
			}
493
			break;
494
	}
495
	$conf .= "dev-node /dev/{$tunname}\n";
496
	$conf .= "writepid {$pfile}\n";
497
	$conf .= "#user nobody\n";
498
	$conf .= "#group nobody\n";
499
	$conf .= "script-security 3\n";
500
	$conf .= "daemon\n";
501
	$conf .= "keepalive 10 60\n";
502
	$conf .= "ping-timer-rem\n";
503
	$conf .= "persist-tun\n";
504
	$conf .= "persist-key\n";
505
	$conf .= "proto {$proto}\n";
506
	$conf .= "cipher {$cipher}\n";
507
	$conf .= "auth {$digest}\n";
508
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
509
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
510
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
511
		switch($settings['mode']) {
512
			case 'server_user':
513
			case 'server_tls_user':
514
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
515
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
516
				break;
517
		}
518
	}
519

    
520
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
521
	if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
522
		$conf .= "local {$iface_ip}\n";
523
	} elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
524
		$conf .= "local {$iface_ipv6}\n";
525
	}
526

    
527
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none"))
528
		$conf .= "engine {$settings['engine']}\n";
529

    
530
	// server specific settings
531
	if ($mode == 'server') {
532

    
533
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
534
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
535
		$mask = gen_subnet_mask($cidr);
536

    
537
		// configure tls modes
538
		switch($settings['mode']) {
539
			case 'p2p_tls':
540
			case 'server_tls':
541
			case 'server_user':
542
			case 'server_tls_user':
543
				$conf .= "tls-server\n";
544
				break;
545
		}
546

    
547
		// configure p2p/server modes
548
		switch($settings['mode']) {
549
			case 'p2p_tls':
550
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
551
				//  use the server directive. It works for a single client without it.
552
				//  See ticket #1417
553
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
554
					$conf .= "server {$ip} {$mask}\n";
555
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
556
					if(is_ipaddr($ipv6))
557
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
558
				}
559
			case 'p2p_shared_key':
560
				if (!empty($ip) && !empty($mask)) {
561
					list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
562
					if ($settings['dev_mode'] == 'tun')
563
						$conf .= "ifconfig {$ip1} {$ip2}\n";
564
					else
565
						$conf .= "ifconfig {$ip1} {$mask}\n";
566
				}
567
				if (!empty($ipv6) && !empty($prefix)) {
568
					list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
569
					if ($settings['dev_mode'] == 'tun')
570
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
571
					else
572
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
573
				}
574
				break;
575
			case 'server_tls':
576
			case 'server_user':
577
			case 'server_tls_user':
578
				if (!empty($ip) && !empty($mask)) {
579
					$conf .= "server {$ip} {$mask}\n";
580
					if(is_ipaddr($ipv6))
581
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
582
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
583
				} else {
584
					if ($settings['serverbridge_dhcp']) {
585
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
586
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
587
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
588
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
589
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
590
								$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
591
							} else {
592
								$conf .= "mode server\n";
593
							}
594
						} else {
595
							$conf .= "mode server\n";
596
						}
597
					}
598
				}
599
				break;
600
		}
601

    
602
		// configure user auth modes
603
		switch($settings['mode']) {
604
			case 'server_user':
605
				$conf .= "client-cert-not-required\n";
606
			case 'server_tls_user':
607
				/* username-as-common-name is not compatible with server-bridge */
608
				if (stristr($conf, "server-bridge") === false)
609
					$conf .= "username-as-common-name\n";
610
				if (!empty($settings['authmode'])) {
611
					$strictusercn = "false";
612
					if ($settings['strictusercn'])
613
						$strictusercn = "true";
614
					$conf .= "auth-user-pass-verify \"/usr/local/sbin/ovpn_auth_verify user '{$settings['authmode']}' {$strictusercn} {$mode_id}\" via-env\n";
615
				}
616
				break;
617
		}
618
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls')))
619
			$settings['cert_depth'] = 1;
620
		if (is_numeric($settings['cert_depth'])) {
621
			if (($mode == 'client') && empty($settings['certref']))
622
				$cert = "";
623
			else {
624
				$cert = lookup_cert($settings['certref']);
625
				/* XXX: Seems not used at all! */
626
				$servercn = urlencode(cert_get_cn($cert['crt']));
627
				$conf .= "tls-verify \"/usr/local/sbin/ovpn_auth_verify tls '{$servercn}' {$settings['cert_depth']}\"\n";
628
			}
629
		}
630

    
631
		// The local port to listen on
632
		$conf .= "lport {$settings['local_port']}\n";
633

    
634
		// The management port to listen on
635
		// Use unix socket to overcome the problem on any type of server
636
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
637
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
638

    
639
		if ($settings['maxclients'])
640
			$conf .= "max-clients {$settings['maxclients']}\n";
641

    
642
		// Can we push routes
643
		if ($settings['local_network']) {
644
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
645
		}
646
		if ($settings['local_networkv6']) {
647
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
648
		}
649

    
650
		switch($settings['mode']) {
651
			case 'server_tls':
652
			case 'server_user':
653
			case 'server_tls_user':
654
				// Configure client dhcp options
655
				openvpn_add_dhcpopts($settings, $conf);
656
				if ($settings['client2client'])
657
					$conf .= "client-to-client\n";
658
				break;
659
		}
660
		if (isset($settings['duplicate_cn']))
661
			$conf .= "duplicate-cn\n";
662
	}
663

    
664
	// client specific settings
665

    
666
	if ($mode == 'client') {
667

    
668
		// configure p2p mode
669
		switch($settings['mode']) {
670
			case 'p2p_tls':
671
				$conf .= "tls-client\n";
672
			case 'shared_key':
673
				$conf .= "client\n";
674
				break;
675
		}
676

    
677
		// If there is no bind option at all (ip and/or port), add "nobind" directive
678
		//  Otherwise, use the local port if defined, failing that, use lport 0 to
679
		//  ensure a random source port.
680
		if ((empty($iface_ip)) && (!$settings['local_port']))
681
			$conf .= "nobind\n";
682
		elseif ($settings['local_port'])
683
			$conf .= "lport {$settings['local_port']}\n";
684
		else
685
			$conf .= "lport 0\n";
686

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

    
690
		// The remote server
691
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
692

    
693
		if (!empty($settings['use_shaper']))
694
			$conf .= "shaper {$settings['use_shaper']}\n";
695

    
696
		if (!empty($settings['tunnel_network'])) {
697
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
698
			$mask = gen_subnet_mask($mask);
699
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
700
			if ($settings['dev_mode'] == 'tun')
701
				$conf .= "ifconfig {$ip2} {$ip1}\n";
702
			else
703
				$conf .= "ifconfig {$ip2} {$mask}\n";
704
		}
705

    
706
		if (!empty($settings['tunnel_networkv6'])) {
707
			list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
708
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
709
			if ($settings['dev_mode'] == 'tun')
710
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
711
			else
712
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
713
		}
714

    
715
		if ($settings['auth_user'] && $settings['auth_pass']) {
716
			$up_file = "{$g['varetc_path']}/openvpn/{$mode_id}.up";
717
			$conf .= "auth-user-pass {$up_file}\n";
718
			$userpass = "{$settings['auth_user']}\n";
719
			$userpass .= "{$settings['auth_pass']}\n";
720
			file_put_contents($up_file, $userpass);
721
		}
722

    
723
		if ($settings['proxy_addr']) {
724
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
725
			if ($settings['proxy_authtype'] != "none") {
726
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
727
				$proxypas = "{$settings['proxy_user']}\n";
728
				$proxypas .= "{$settings['proxy_passwd']}\n";
729
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
730
			}
731
			$conf .= " \n";
732
		}
733
	}
734

    
735
	// Add a remote network route if set, and only for p2p modes.
736
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
737
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
738
	}
739
	// Add a remote network route if set, and only for p2p modes.
740
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
741
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
742
	}
743

    
744
	// Write the settings for the keys
745
	switch($settings['mode']) {
746
		case 'p2p_shared_key':
747
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
748
			break;
749
		case 'p2p_tls':
750
		case 'server_tls':
751
		case 'server_tls_user':
752
		case 'server_user':
753
			$ca = lookup_ca($settings['caref']);
754
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
755

    
756
			if (!empty($settings['certref'])) {
757
				$cert = lookup_cert($settings['certref']);
758
				openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
759
				openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
760
			}
761
			if ($mode == 'server')
762
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
763
			if (!empty($settings['crlref'])) {
764
				$crl = lookup_crl($settings['crlref']);
765
				crl_update($crl);
766
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
767
			}
768
			if ($settings['tls']) {
769
				if ($mode == "server")
770
					$tlsopt = 0;
771
				else
772
					$tlsopt = 1;
773
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
774
			}
775
			break;
776
	}
777

    
778
	if (!empty($settings['compression']))
779
		$conf .= "comp-lzo {$settings['compression']}\n";
780

    
781
	if ($settings['passtos'])
782
		$conf .= "passtos\n";
783

    
784
	if ($settings['resolve_retry'])
785
		$conf .= "resolv-retry infinite\n";
786
	else if ($mode == 'client')
787
		$conf .= "resolv-retry 2\n";
788

    
789
	if ($settings['dynamic_ip']) {
790
		$conf .= "persist-remote-ip\n";
791
		$conf .= "float\n";
792
	}
793

    
794
	if ($settings['topology_subnet']) {
795
		$conf .= "topology subnet\n";
796
	}
797

    
798
	// New client features
799
	if ($mode == "client") {
800
		// Dont pull routes checkbox
801
		if ($settings['route_no_pull']) {
802
			$conf .= "route-nopull\n";
803
		}
804

    
805
		// Dont add/remove routes checkbox
806
		if ($settings['route_no_exec']) {
807
			$conf .= "route-noexec\n";
808
		}
809
	}
810

    
811
	openvpn_add_custom($settings, $conf);
812

    
813
	openvpn_create_dirs();
814
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
815
	file_put_contents($fpath, $conf);
816
	unset($conf);
817
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
818
	file_put_contents($fpath, $interface);
819
	//chown($fpath, 'nobody');
820
	//chgrp($fpath, 'nobody');
821
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
822
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
823
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
824
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
825
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
826
}
827

    
828
function openvpn_restart($mode, $settings) {
829
	global $g, $config;
830

    
831
	$vpnid = $settings['vpnid'];
832
	$mode_id = $mode.$vpnid;
833

    
834
	/* kill the process if running */
835
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
836
	if (file_exists($pfile)) {
837

    
838
		/* read the pid file */
839
		$pid = rtrim(file_get_contents($pfile));
840
		unlink($pfile);
841

    
842
		/* send a term signal to the process */
843
		posix_kill($pid, SIGTERM);
844

    
845
		/* wait until the process exits, or timeout and kill it */
846
		$i = 0;
847
		while(posix_kill($pid, 0)) {
848
			usleep(250000);
849
			if ($i > 10) {
850
				log_error("OpenVPN ID $mode_id PID $pid still running, killing.");
851
				posix_kill($pid, SIGKILL);
852
				usleep(500000);
853
			}
854
			$i++;
855
		}
856
	}
857

    
858
	if (isset($settings['disable']))
859
		return;
860

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

    
865
	/* Check if client is bound to a gateway group */
866
	$a_groups = return_gateway_groups_array();
867
	if (is_array($a_groups[$settings['interface']])) {
868
	/* the interface is a gateway group. If a vip is defined and its a CARP backup then do not start */
869
		if (($a_groups[$settings['interface']][0]['vip'] <> "") && (get_carp_interface_status($a_groups[$settings['interface']][0]['vip']) == "BACKUP"))
870
			return;
871
	}
872

    
873
	/* start the new process */
874
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
875
	openvpn_clear_route($mode, $settings);
876
	mwexec_bg("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
877

    
878
	if (!platform_booting())
879
		send_event("filter reload");
880
}
881

    
882
function openvpn_delete($mode, & $settings) {
883
	global $g, $config;
884

    
885
	$vpnid = $settings['vpnid'];
886
	$mode_id = $mode.$vpnid;
887

    
888
	if (isset($settings['dev_mode']))
889
		$tunname = "{$settings['dev_mode']}{$vpnid}";
890
	else {  /* defaults to tun */
891
		$tunname = "tun{$vpnid}";
892
	}
893

    
894
	if ($mode == "server")
895
		$devname = "ovpns{$vpnid}";
896
	else
897
		$devname = "ovpnc{$vpnid}";
898

    
899
	/* kill the process if running */
900
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
901
	if (file_exists($pfile)) {
902

    
903
		/* read the pid file */
904
		$pid = trim(file_get_contents($pfile));
905
		unlink($pfile);
906

    
907
		/* send a term signal to the process */
908
		posix_kill($pid, SIGTERM);
909
	}
910

    
911
	/* remove the device from the openvpn group */
912
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
913

    
914
	/* restore the original adapter name */
915
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
916

    
917
	/* remove the configuration files */
918
	@array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
919
}
920

    
921
function openvpn_cleanup_csc($common_name) {
922
	global $g, $config;
923
	if (empty($common_name))
924
		return;
925
	$fpath = "{$g['varetc_path']}/openvpn-csc/" . basename($common_name);
926
	if (is_file($fpath))
927
		unlink_if_exists($fpath);
928
	return;
929
}
930

    
931
function openvpn_resync_csc(& $settings) {
932
	global $g, $config;
933

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

    
936
	if (isset($settings['disable'])) {
937
		unlink_if_exists($fpath);
938
		return;
939
	}
940
	openvpn_create_dirs();
941

    
942
	$conf = '';
943
	if ($settings['block'])
944
		$conf .= "disable\n";
945

    
946
	if ($settings['push_reset'])
947
		$conf .= "push-reset\n";
948

    
949
	if (!empty($settings['tunnel_network'])) {
950
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
951
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
952
		$serverip = long2ip32($baselong + 1);
953
		$clientip = long2ip32($baselong + 2);
954
		/* Because this is being pushed, the order from the client's point of view. */
955
		if ($settings['dev_mode'] != 'tap')
956
			$conf .= "ifconfig-push {$clientip} {$serverip}\n";
957
		else
958
			$conf .= "ifconfig-push {$clientip} {$mask}\n";
959
	}
960

    
961
	if ($settings['local_network']) {
962
		$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
963
	}
964
	if ($settings['local_networkv6']) {
965
		$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
966
	}
967

    
968
	// Add a remote network iroute if set
969
	if (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE) {
970
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false, true);
971
	}
972
	// Add a remote network iroute if set
973
	if (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE) {
974
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false, true);
975
	}
976

    
977
	openvpn_add_dhcpopts($settings, $conf);
978

    
979
	if ($settings['gwredir'])
980
		$conf .= "push \"redirect-gateway def1\"\n";
981

    
982
	openvpn_add_custom($settings, $conf);
983

    
984
	file_put_contents($fpath, $conf);
985
	chown($fpath, 'nobody');
986
	chgrp($fpath, 'nobody');
987
}
988

    
989
function openvpn_delete_csc(& $settings) {
990
	global $g, $config;
991

    
992
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
993
	unlink_if_exists($fpath);
994
}
995

    
996
// Resync the configuration and restart the VPN
997
function openvpn_resync($mode, $settings) {
998
	openvpn_reconfigure($mode, $settings);
999
	openvpn_restart($mode, $settings);
1000
}
1001

    
1002
// Resync and restart all VPNs
1003
function openvpn_resync_all($interface = "") {
1004
	global $g, $config;
1005

    
1006
	if ($g['platform'] == 'jail')
1007
		return;
1008
	openvpn_create_dirs();
1009

    
1010
	if (!is_array($config['openvpn']))
1011
		$config['openvpn'] = array();
1012

    
1013
/*
1014
	if (!$config['openvpn']['dh-parameters']) {
1015
		echo "Configuring OpenVPN Parameters ...\n";
1016
		$dh_parameters = openvpn_create_dhparams(1024);
1017
		$dh_parameters = base64_encode($dh_parameters);
1018
		$config['openvpn']['dh-parameters'] = $dh_parameters;
1019
		write_config("OpenVPN DH parameters");
1020
	}
1021

    
1022
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
1023
	if (!file_exists($path_ovdh)) {
1024
		$dh_parameters = $config['openvpn']['dh-parameters'];
1025
		$dh_parameters = base64_decode($dh_parameters);
1026
		file_put_contents($path_ovdh, $dh_parameters);
1027
	}
1028
*/
1029
	if ($interface <> "")
1030
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
1031
	else
1032
		log_error("Resyncing OpenVPN instances.");
1033

    
1034
	if (is_array($config['openvpn']['openvpn-server'])) {
1035
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1036
			if ($interface <> "" && $interface != $settings['interface'])
1037
				continue;
1038
			openvpn_resync('server', $settings);
1039
		}
1040
	}
1041

    
1042
	if (is_array($config['openvpn']['openvpn-client'])) {
1043
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1044
			if ($interface <> "" && $interface != $settings['interface'])
1045
				continue;
1046
			openvpn_resync('client', $settings);
1047
		}
1048
	}
1049

    
1050
	if (is_array($config['openvpn']['openvpn-csc']))
1051
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
1052
			openvpn_resync_csc($settings);
1053

    
1054
}
1055

    
1056
// Resync and restart all VPNs using a gateway group.
1057
function openvpn_resync_gwgroup($gwgroupname = "") {
1058
	global $g, $config;
1059

    
1060
	if ($gwgroupname <> "") {
1061
		if (is_array($config['openvpn']['openvpn-server'])) {
1062
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1063
				if ($gwgroupname == $settings['interface']) {
1064
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " server " . $settings["description"] . ".");
1065
					openvpn_resync('server', $settings);
1066
				}
1067
			}
1068
		}
1069

    
1070
		if (is_array($config['openvpn']['openvpn-client'])) {
1071
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1072
				if ($gwgroupname == $settings['interface']) {
1073
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " client " . $settings["description"] . ".");
1074
					openvpn_resync('client', $settings);
1075
				}
1076
			}
1077
		}
1078

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

    
1081
	} else
1082
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter.");
1083
}
1084

    
1085
function openvpn_get_active_servers($type="multipoint") {
1086
	global $config, $g;
1087

    
1088
	$servers = array();
1089
	if (is_array($config['openvpn']['openvpn-server'])) {
1090
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1091
			if (empty($settings) || isset($settings['disable']))
1092
				continue;
1093

    
1094
			$prot = $settings['protocol'];
1095
			$port = $settings['local_port'];
1096

    
1097
			$server = array();
1098
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
1099
			$server['mode'] = $settings['mode'];
1100
			if ($settings['description'])
1101
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
1102
			else
1103
				$server['name'] = "Server {$prot}:{$port}";
1104
			$server['conns'] = array();
1105
			$server['vpnid'] = $settings['vpnid'];
1106
			$server['mgmt'] = "server{$server['vpnid']}";
1107
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
1108
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
1109

    
1110
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
1111
				$servers[] = openvpn_get_client_status($server, $socket);
1112
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
1113
				$servers[] = openvpn_get_server_status($server, $socket);
1114

    
1115
		}
1116
	}
1117
	return $servers;
1118
}
1119

    
1120
function openvpn_get_server_status($server, $socket) {
1121
	$errval;
1122
	$errstr;
1123
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1124
	if ($fp) {
1125
		stream_set_timeout($fp, 1);
1126

    
1127
		/* send our status request */
1128
		fputs($fp, "status 2\n");
1129

    
1130
		/* recv all response lines */
1131
		while (!feof($fp)) {
1132

    
1133
			/* read the next line */
1134
			$line = fgets($fp, 1024);
1135

    
1136
			$info = stream_get_meta_data($fp);
1137
			if ($info['timed_out'])
1138
				break;
1139

    
1140
			/* parse header list line */
1141
			if (strstr($line, "HEADER"))
1142
				continue;
1143

    
1144
			/* parse end of output line */
1145
			if (strstr($line, "END") || strstr($line, "ERROR"))
1146
				break;
1147

    
1148
			/* parse client list line */
1149
			if (strstr($line, "CLIENT_LIST")) {
1150
				$list = explode(",", $line);
1151
				$conn = array();
1152
				$conn['common_name'] = $list[1];
1153
				$conn['remote_host'] = $list[2];
1154
				$conn['virtual_addr'] = $list[3];
1155
				$conn['bytes_recv'] = $list[4];
1156
				$conn['bytes_sent'] = $list[5];
1157
				$conn['connect_time'] = $list[6];
1158
				$server['conns'][] = $conn;
1159
			}
1160
			/* parse routing table lines */
1161
			if (strstr($line, "ROUTING_TABLE")) {
1162
				$list = explode(",", $line);
1163
				$conn = array();
1164
				$conn['virtual_addr'] = $list[1];
1165
				$conn['common_name'] = $list[2];
1166
				$conn['remote_host'] = $list[3];
1167
				$conn['last_time'] = $list[4];
1168
				$server['routes'][] = $conn;
1169
			}
1170
		}
1171

    
1172
		/* cleanup */
1173
		fclose($fp);
1174
	} else {
1175
		$conn = array();
1176
		$conn['common_name'] = "[error]";
1177
		$conn['remote_host'] = "Unable to contact daemon";
1178
		$conn['virtual_addr'] = "Service not running?";
1179
		$conn['bytes_recv'] = 0;
1180
		$conn['bytes_sent'] = 0;
1181
		$conn['connect_time'] = 0;
1182
		$server['conns'][] = $conn;
1183
	}
1184
	return $server;
1185
}
1186

    
1187
function openvpn_get_active_clients() {
1188
	global $config, $g;
1189

    
1190
	$clients = array();
1191
	if (is_array($config['openvpn']['openvpn-client'])) {
1192
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1193

    
1194
			if (empty($settings) || isset($settings['disable']))
1195
				continue;
1196

    
1197
			$prot = $settings['protocol'];
1198
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1199

    
1200
			$client = array();
1201
			$client['port'] = $settings['local_port'];
1202
			if ($settings['description'])
1203
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1204
			else
1205
				$client['name'] = "Client {$prot}{$port}";
1206

    
1207
			$client['vpnid'] = $settings['vpnid'];
1208
			$client['mgmt'] = "client{$client['vpnid']}";
1209
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1210
			$client['status']="down";
1211

    
1212
			$clients[] = openvpn_get_client_status($client, $socket);
1213
		}
1214
	}
1215
	return $clients;
1216
}
1217

    
1218
function openvpn_get_client_status($client, $socket) {
1219
	$errval;
1220
	$errstr;
1221
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1222
	if ($fp) {
1223
		stream_set_timeout($fp, 1);
1224
		/* send our status request */
1225
		fputs($fp, "state 1\n");
1226

    
1227
		/* recv all response lines */
1228
		while (!feof($fp)) {
1229
			/* read the next line */
1230
			$line = fgets($fp, 1024);
1231

    
1232
			$info = stream_get_meta_data($fp);
1233
			if ($info['timed_out'])
1234
				break;
1235

    
1236
			/* Get the client state */
1237
			if (strstr($line,"CONNECTED")) {
1238
				$client['status']="up";
1239
				$list = explode(",", $line);
1240

    
1241
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1242
				$client['virtual_addr']  = $list[3];
1243
				$client['remote_host'] = $list[4];
1244
			}
1245
			if (strstr($line,"CONNECTING")) {
1246
				$client['status']="connecting";
1247
			}
1248
			if (strstr($line,"ASSIGN_IP")) {
1249
				$client['status']="waiting";
1250
				$list = explode(",", $line);
1251

    
1252
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1253
				$client['virtual_addr']  = $list[3];
1254
			}
1255
			if (strstr($line,"RECONNECTING")) {
1256
				$client['status']="reconnecting";
1257
				$list = explode(",", $line);
1258

    
1259
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1260
				$client['status'] .= "; " . $list[2];
1261
			}
1262
			/* parse end of output line */
1263
			if (strstr($line, "END") || strstr($line, "ERROR"))
1264
				break;
1265
		}
1266

    
1267
		/* If up, get read/write stats */
1268
		if (strcmp($client['status'], "up") == 0) {
1269
			fputs($fp, "status 2\n");
1270
			/* recv all response lines */
1271
			while (!feof($fp)) {
1272
				/* read the next line */
1273
				$line = fgets($fp, 1024);
1274

    
1275
				$info = stream_get_meta_data($fp);
1276
				if ($info['timed_out'])
1277
					break;
1278

    
1279
				if (strstr($line,"TCP/UDP read bytes")) {
1280
					$list = explode(",", $line);
1281
					$client['bytes_recv'] = $list[1];
1282
				}
1283

    
1284
				if (strstr($line,"TCP/UDP write bytes")) {
1285
					$list = explode(",", $line);
1286
					$client['bytes_sent'] = $list[1];
1287
				}
1288

    
1289
				/* parse end of output line */
1290
				if (strstr($line, "END"))
1291
					break;
1292
			}
1293
		}
1294

    
1295
		fclose($fp);
1296

    
1297
	} else {
1298
		$DisplayNote=true;
1299
		$client['remote_host'] = "Unable to contact daemon";
1300
		$client['virtual_addr'] = "Service not running?";
1301
		$client['bytes_recv'] = 0;
1302
		$client['bytes_sent'] = 0;
1303
		$client['connect_time'] = 0;
1304
	}
1305
	return $client;
1306
}
1307

    
1308
function openvpn_refresh_crls() {
1309
	global $g, $config;
1310

    
1311
	openvpn_create_dirs();
1312

    
1313
	if (is_array($config['openvpn']['openvpn-server'])) {
1314
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1315
			if (empty($settings))
1316
				continue;
1317
			if (isset($settings['disable']))
1318
				continue;
1319
			// Write the settings for the keys
1320
			switch($settings['mode']) {
1321
				case 'p2p_tls':
1322
				case 'server_tls':
1323
				case 'server_tls_user':
1324
				case 'server_user':
1325
					if (!empty($settings['crlref'])) {
1326
						$crl = lookup_crl($settings['crlref']);
1327
						crl_update($crl);
1328
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1329
						file_put_contents($fpath, base64_decode($crl['text']));
1330
						@chmod($fpath, 0644);
1331
					}
1332
					break;
1333
			}
1334
		}
1335
	}
1336
}
1337

    
1338
function openvpn_create_dirs() {
1339
	global $g;
1340
	if (!is_dir("{$g['varetc_path']}/openvpn"))
1341
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1342
	if (!is_dir("{$g['varetc_path']}/openvpn-csc"))
1343
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1344
}
1345

    
1346
function openvpn_get_interface_ip($ip, $mask) {
1347
	$baselong = ip2long32($ip) & ip2long($mask);
1348
	$ip1 = long2ip32($baselong + 1);
1349
	$ip2 = long2ip32($baselong + 2);
1350
	return array($ip1, $ip2);
1351
}
1352

    
1353
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1354
	$basev6 = gen_subnetv6($ipv6, $prefix);
1355
	// Is there a better way to do this math?
1356
	$ipv6_arr = explode(':', $basev6);
1357
	$last = hexdec(array_pop($ipv6_arr));
1358
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1359
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1360
	return array($ipv6_1, $ipv6_2);
1361
}
1362

    
1363
function openvpn_clear_route($mode, $settings) {
1364
	if (empty($settings['tunnel_network']))
1365
		return;
1366
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1367
	$mask = gen_subnet_mask($cidr);
1368
	$clear_route = false;
1369

    
1370
	switch($settings['mode']) {
1371
		case 'shared_key':
1372
			$clear_route = true;
1373
			break;
1374
		case 'p2p_tls':
1375
		case 'p2p_shared_key':
1376
			if ($cidr == 30)
1377
				$clear_route = true;
1378
			break;
1379
	}
1380

    
1381
	if ($clear_route && !empty($ip) && !empty($mask)) {
1382
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1383
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1384
		/* XXX: Family for route? */
1385
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1386
	}
1387
}
1388

    
1389
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
1390
	$routes = "";
1391
	if (empty($value))
1392
		return "";
1393
	$networks = explode(',', $value);
1394

    
1395
	foreach ($networks as $network) {
1396
		if ($ipproto == "ipv4")
1397
			$route = openvpn_gen_route_ipv4($network, $iroute);
1398
		else
1399
			$route = openvpn_gen_route_ipv6($network, $iroute);
1400

    
1401
		if ($push)
1402
			$routes .= "push \"{$route}\"\n";
1403
		else
1404
			$routes .= "{$route}\n";
1405
	}
1406
	return $routes;
1407
}
1408

    
1409
function openvpn_gen_route_ipv4($network, $iroute = false) {
1410
	$i = ($iroute) ? "i" : "";
1411
	list($ip, $mask) = explode('/', trim($network));
1412
	$mask = gen_subnet_mask($mask);
1413
	return "{$i}route $ip $mask";
1414
}
1415

    
1416
function openvpn_gen_route_ipv6($network, $iroute = false) {
1417
	$i = ($iroute) ? "i" : "";
1418
	list($ipv6, $prefix) = explode('/', trim($network));
1419
	if (empty($prefix))
1420
		$prefix = "128";
1421
	return "{$i}route-ipv6 ${ipv6}/${prefix}";
1422
}
1423

    
1424
function openvpn_get_settings($mode, $vpnid) {
1425
	global $config;
1426

    
1427
	if (is_array($config['openvpn']['openvpn-server'])) {
1428
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1429
			if (isset($settings['disable']))
1430
				continue;
1431

    
1432
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1433
				return $settings;
1434
		}
1435
	}
1436

    
1437
	if (is_array($config['openvpn']['openvpn-client'])) {
1438
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1439
			if (isset($settings['disable']))
1440
				continue;
1441

    
1442
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1443
				return $settings;
1444
		}
1445
	}
1446

    
1447
	return array();
1448
}
1449

    
1450
function openvpn_restart_by_vpnid($mode, $vpnid) {
1451
	$settings = openvpn_get_settings($mode, $vpnid);
1452
	openvpn_restart($mode, $settings);
1453
}
1454

    
1455
?>
(38-38/68)