Project

General

Profile

Download (44.2 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

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

    
129
	return $rslt;
130
}
131

    
132
function openvpn_create_dhparams($bits) {
133

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

    
139
	$rslt = stream_get_contents($fp);
140
	pclose($fp);
141

    
142
	return $rslt;
143
}
144

    
145
function openvpn_vpnid_used($vpnid) {
146
	global $config;
147

    
148
	if (is_array($config['openvpn']['openvpn-server'])) {
149
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
150
			if ($vpnid == $settings['vpnid']) {
151
				return true;
152
			}
153
		}
154
	}
155

    
156
	if (is_array($config['openvpn']['openvpn-client'])) {
157
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
158
			if ($vpnid == $settings['vpnid']) {
159
				return true;
160
			}
161
		}
162
	}
163

    
164
	return false;
165
}
166

    
167
function openvpn_vpnid_next() {
168

    
169
	$vpnid = 1;
170
	while (openvpn_vpnid_used($vpnid)) {
171
		$vpnid++;
172
	}
173

    
174
	return $vpnid;
175
}
176

    
177
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
178
	global $config;
179

    
180
	if (is_array($config['openvpn']['openvpn-server'])) {
181
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
182
			if (isset($settings['disable'])) {
183
				continue;
184
			}
185

    
186
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
187
				continue;
188
			}
189

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

    
197
	if (is_array($config['openvpn']['openvpn-client'])) {
198
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
199
			if (isset($settings['disable'])) {
200
				continue;
201
			}
202

    
203
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
204
				continue;
205
			}
206

    
207
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
208
			    ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
209
				return $settings['vpnid'];
210
			}
211
		}
212
	}
213

    
214
	return 0;
215
}
216

    
217
function openvpn_port_next($prot, $interface = "wan") {
218

    
219
	$port = 1194;
220
	while (openvpn_port_used($prot, $interface, $port)) {
221
		$port++;
222
	}
223
	while (openvpn_port_used($prot, "any", $port)) {
224
		$port++;
225
	}
226

    
227
	return $port;
228
}
229

    
230
function openvpn_get_cipherlist() {
231

    
232
	$ciphers = array();
233
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
234
	$cipher_lines = explode("\n", trim($cipher_out));
235
	sort($cipher_lines);
236
	foreach ($cipher_lines as $line) {
237
		$words = explode(' ', $line);
238
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
239
	}
240
	$ciphers["none"] = gettext("None (No Encryption)");
241
	return $ciphers;
242
}
243

    
244
function openvpn_get_digestlist() {
245

    
246
	$digests = array();
247
	$digest_out = shell_exec('/usr/local/sbin/openvpn --show-digests | /usr/bin/grep "digest size" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
248
	$digest_lines = explode("\n", trim($digest_out));
249
	sort($digest_lines);
250
	foreach ($digest_lines as $line) {
251
		$words = explode(' ', $line);
252
		$digests[$words[0]] = "{$words[0]} {$words[1]}";
253
	}
254
	$digests["none"] = gettext("None (No Authentication)");
255
	return $digests;
256
}
257

    
258
function openvpn_get_engines() {
259
	$openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
260
	exec("/usr/bin/openssl engine -t -c", $openssl_engine_output);
261
	$openssl_engine_output = implode("\n", $openssl_engine_output);
262
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
263
	$openssl_engine_output = explode("\n", $openssl_engine_output);
264

    
265
	foreach ($openssl_engine_output as $oeo) {
266
		$keep = true;
267
		$details = explode("|", $oeo);
268
		$engine = array_shift($details);
269
		$linematch = array();
270
		preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
271
		foreach ($details as $dt) {
272
			if (strpos($dt, "unavailable") !== FALSE) {
273
				$keep = false;
274
			}
275
			if (strpos($dt, "available") !== FALSE) {
276
				continue;
277
			}
278
			if (strpos($dt, "[") !== FALSE) {
279
				$ciphers = trim($dt, "[]");
280
			}
281
		}
282
		if (!empty($ciphers)) {
283
			$ciphers = " - " . $ciphers;
284
		}
285
		if (strlen($ciphers) > 60) {
286
			$ciphers = substr($ciphers, 0, 60) . " ... ";
287
		}
288
		if ($keep) {
289
			$openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
290
		}
291
	}
292
	return $openssl_engines;
293
}
294

    
295
function openvpn_validate_engine($engine) {
296
	$engines = openvpn_get_engines();
297
	return array_key_exists($engine, $engines);
298
}
299

    
300
function openvpn_validate_host($value, $name) {
301
	$value = trim($value);
302
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value))) {
303
		return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
304
	}
305
	return false;
306
}
307

    
308
function openvpn_validate_port($value, $name) {
309
	$value = trim($value);
310
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535)) {
311
		return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
312
	}
313
	return false;
314
}
315

    
316
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
317
	$value = trim($value);
318
	$error = false;
319
	if (empty($value)) {
320
		return false;
321
	}
322
	$networks = explode(',', $value);
323

    
324
	if (!$multiple && (count($networks) > 1)) {
325
		return sprintf(gettext("The field '%s' must contain a single valid %s CIDR range."), $name, $ipproto);
326
	}
327

    
328
	foreach ($networks as $network) {
329
		if ($ipproto == "ipv4") {
330
			$error = !openvpn_validate_cidr_ipv4($network);
331
		} else {
332
			$error = !openvpn_validate_cidr_ipv6($network);
333
		}
334
		if ($error) {
335
			break;
336
		}
337
	}
338

    
339
	if ($error) {
340
		return sprintf(gettext("The field '%s' must contain only valid %s CIDR range(s) separated by commas."), $name, $ipproto);
341
	} else {
342
		return false;
343
	}
344
}
345

    
346
function openvpn_validate_cidr_ipv4($value) {
347
	$value = trim($value);
348
	if (!empty($value)) {
349
		list($ip, $mask) = explode('/', $value);
350
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0)) {
351
			return false;
352
		}
353
	}
354
	return true;
355
}
356

    
357
function openvpn_validate_cidr_ipv6($value) {
358
	$value = trim($value);
359
	if (!empty($value)) {
360
		list($ipv6, $prefix) = explode('/', $value);
361
		if (empty($prefix)) {
362
			$prefix = "128";
363
		}
364
		if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0)) {
365
			return false;
366
		}
367
	}
368
	return true;
369
}
370

    
371
function openvpn_add_dhcpopts(& $settings, & $conf) {
372

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

    
377
	if (!empty($settings['dns_server1'])) {
378
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
379
	}
380
	if (!empty($settings['dns_server2'])) {
381
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
382
	}
383
	if (!empty($settings['dns_server3'])) {
384
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
385
	}
386
	if (!empty($settings['dns_server4'])) {
387
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
388
	}
389

    
390
	if (!empty($settings['push_register_dns'])) {
391
		$conf .= "push \"register-dns\"\n";
392
	}
393

    
394
	if (!empty($settings['ntp_server1'])) {
395
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
396
	}
397
	if (!empty($settings['ntp_server2'])) {
398
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
399
	}
400

    
401
	if ($settings['netbios_enable']) {
402

    
403
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0)) {
404
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
405
		}
406
		if (!empty($settings['dhcp_nbtscope'])) {
407
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
408
		}
409

    
410
		if (!empty($settings['wins_server1'])) {
411
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
412
		}
413
		if (!empty($settings['wins_server2'])) {
414
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
415
		}
416

    
417
		if (!empty($settings['nbdd_server1'])) {
418
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
419
		}
420
	}
421

    
422
	if ($settings['gwredir']) {
423
		$conf .= "push \"redirect-gateway def1\"\n";
424
	}
425
}
426

    
427
function openvpn_add_custom(& $settings, & $conf) {
428

    
429
	if ($settings['custom_options']) {
430

    
431
		$options = explode(';', $settings['custom_options']);
432

    
433
		if (is_array($options)) {
434
			foreach ($options as $option) {
435
				$conf .= "$option\n";
436
			}
437
		} else {
438
			$conf .= "{$settings['custom_options']}\n";
439
		}
440
	}
441
}
442

    
443
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
444
	global $g;
445

    
446
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
447
	openvpn_create_dirs();
448
	file_put_contents($fpath, base64_decode($data));
449
	//chown($fpath, 'nobody');
450
	//chgrp($fpath, 'nobody');
451
	@chmod($fpath, 0600);
452

    
453
	$conf .= "{$directive} {$fpath} {$opt}\n";
454
}
455

    
456
function openvpn_reconfigure($mode, $settings) {
457
	global $g, $config;
458

    
459
	if (empty($settings)) {
460
		return;
461
	}
462
	if (isset($settings['disable'])) {
463
		return;
464
	}
465
	openvpn_create_dirs();
466
	/*
467
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
468
	 * we use a vpnid number which is allocated for a particular client
469
	 * or server configuration. ( see openvpn_vpnid_next() )
470
	 */
471

    
472
	$vpnid = $settings['vpnid'];
473
	$mode_id = $mode.$vpnid;
474

    
475
	if (isset($settings['dev_mode'])) {
476
		$tunname = "{$settings['dev_mode']}{$vpnid}";
477
	} else {
478
		/* defaults to tun */
479
		$tunname = "tun{$vpnid}";
480
		$settings['dev_mode'] = "tun";
481
	}
482

    
483
	if ($mode == "server") {
484
		$devname = "ovpns{$vpnid}";
485
	} else {
486
		$devname = "ovpnc{$vpnid}";
487
	}
488

    
489
	/* is our device already configured */
490
	if (!does_interface_exist($devname)) {
491

    
492
		/* create the tap device if required */
493
		if (!file_exists("/dev/{$tunname}")) {
494
			exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
495
		}
496

    
497
		/* rename the device */
498
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
499

    
500
		/* add the device to the openvpn group and make sure it's UP*/
501
		mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " group openvpn up");
502

    
503
		$ifname = convert_real_interface_to_friendly_interface_name($devname);
504
		$grouptmp = link_interface_to_group($ifname);
505
		if (!empty($grouptmp)) {
506
			array_walk($grouptmp, 'interface_group_add_member');
507
		}
508
		unset($grouptmp, $ifname);
509
	}
510

    
511
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
512
	$proto = strtolower($settings['protocol']);
513
	if (substr($settings['protocol'], 0, 3) == "TCP") {
514
			$proto = "{$proto}-{$mode}";
515
	}
516
	$dev_mode = $settings['dev_mode'];
517
	$cipher = $settings['crypto'];
518
	// OpenVPN defaults to SHA1, so use it when unset to maintain compatibility.
519
	$digest = !empty($settings['digest']) ? $settings['digest'] : "SHA1";
520

    
521
	$interface = get_failover_interface($settings['interface']);
522
	// The IP address in the settings can be an IPv4 or IPv6 address associated with the interface
523
	$ipaddr = $settings['ipaddr'];
524

    
525
	// If a specific ip address (VIP) is requested, use it.
526
	// Otherwise, if a specific interface is requested, use it
527
	// If "any" interface was selected, local directive will be omitted.
528
	if (is_ipaddrv4($ipaddr)) {
529
		$iface_ip = $ipaddr;
530
	} else {
531
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
532
			$iface_ip=get_interface_ip($interface);
533
		}
534
	}
535
	if (is_ipaddrv6($ipaddr)) {
536
		$iface_ipv6 = $ipaddr;
537
	} else {
538
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
539
			$iface_ipv6=get_interface_ipv6($interface);
540
		}
541
	}
542

    
543

    
544
	$conf = "dev {$devname}\n";
545
	if (isset($settings['verbosity_level'])) {
546
		$conf .= "verb {$settings['verbosity_level']}\n";
547
	}
548

    
549
	$conf .= "dev-type {$settings['dev_mode']}\n";
550
	switch ($settings['dev_mode']) {
551
		case "tun":
552
			if (!$settings['no_tun_ipv6']) {
553
				$conf .= "tun-ipv6\n";
554
			}
555
			break;
556
	}
557
	$conf .= "dev-node /dev/{$tunname}\n";
558
	$conf .= "writepid {$pfile}\n";
559
	$conf .= "#user nobody\n";
560
	$conf .= "#group nobody\n";
561
	$conf .= "script-security 3\n";
562
	$conf .= "daemon\n";
563
	$conf .= "keepalive 10 60\n";
564
	$conf .= "ping-timer-rem\n";
565
	$conf .= "persist-tun\n";
566
	$conf .= "persist-key\n";
567
	$conf .= "proto {$proto}\n";
568
	$conf .= "cipher {$cipher}\n";
569
	$conf .= "auth {$digest}\n";
570
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
571
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
572
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
573
		switch ($settings['mode']) {
574
			case 'server_user':
575
			case 'server_tls_user':
576
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
577
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
578
				break;
579
		}
580
	}
581

    
582
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
583
	if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
584
		$conf .= "local {$iface_ip}\n";
585
	} elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
586
		$conf .= "local {$iface_ipv6}\n";
587
	}
588

    
589
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
590
		$conf .= "engine {$settings['engine']}\n";
591
	}
592

    
593
	// server specific settings
594
	if ($mode == 'server') {
595

    
596
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
597
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
598
		$mask = gen_subnet_mask($cidr);
599

    
600
		// configure tls modes
601
		switch ($settings['mode']) {
602
			case 'p2p_tls':
603
			case 'server_tls':
604
			case 'server_user':
605
			case 'server_tls_user':
606
				$conf .= "tls-server\n";
607
				break;
608
		}
609

    
610
		// configure p2p/server modes
611
		switch ($settings['mode']) {
612
			case 'p2p_tls':
613
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
614
				//  use the server directive. It works for a single client without it.
615
				//  See ticket #1417
616
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
617
					$conf .= "server {$ip} {$mask}\n";
618
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
619
					if (is_ipaddr($ipv6)) {
620
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
621
					}
622
				}
623
			case 'p2p_shared_key':
624
				if (!empty($ip) && !empty($mask)) {
625
					list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
626
					if ($settings['dev_mode'] == 'tun') {
627
						$conf .= "ifconfig {$ip1} {$ip2}\n";
628
					} else {
629
						$conf .= "ifconfig {$ip1} {$mask}\n";
630
					}
631
				}
632
				if (!empty($ipv6) && !empty($prefix)) {
633
					list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
634
					if ($settings['dev_mode'] == 'tun') {
635
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
636
					} else {
637
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
638
					}
639
				}
640
				break;
641
			case 'server_tls':
642
			case 'server_user':
643
			case 'server_tls_user':
644
				if (!empty($ip) && !empty($mask)) {
645
					$conf .= "server {$ip} {$mask}\n";
646
					if (is_ipaddr($ipv6)) {
647
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
648
					}
649
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
650
				} else {
651
					if ($settings['serverbridge_dhcp']) {
652
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
653
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
654
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
655
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
656
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
657
								$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
658
							} else {
659
								$conf .= "mode server\n";
660
							}
661
						} else {
662
							$conf .= "mode server\n";
663
						}
664
					}
665
				}
666
				break;
667
		}
668

    
669
		// configure user auth modes
670
		switch ($settings['mode']) {
671
			case 'server_user':
672
				$conf .= "client-cert-not-required\n";
673
			case 'server_tls_user':
674
				/* username-as-common-name is not compatible with server-bridge */
675
				if (stristr($conf, "server-bridge") === false) {
676
					$conf .= "username-as-common-name\n";
677
				}
678
				if (!empty($settings['authmode'])) {
679
					$strictusercn = "false";
680
					if ($settings['strictusercn']) {
681
						$strictusercn = "true";
682
					}
683
					$conf .= "auth-user-pass-verify \"/usr/local/sbin/ovpn_auth_verify user '{$settings['authmode']}' {$strictusercn} {$mode_id}\" via-env\n";
684
				}
685
				break;
686
		}
687
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls'))) {
688
			$settings['cert_depth'] = 1;
689
		}
690
		if (is_numeric($settings['cert_depth'])) {
691
			if (($mode == 'client') && empty($settings['certref'])) {
692
				$cert = "";
693
			} else {
694
				$cert = lookup_cert($settings['certref']);
695
				/* XXX: Seems not used at all! */
696
				$servercn = urlencode(cert_get_cn($cert['crt']));
697
				$conf .= "tls-verify \"/usr/local/sbin/ovpn_auth_verify tls '{$servercn}' {$settings['cert_depth']}\"\n";
698
			}
699
		}
700

    
701
		// The local port to listen on
702
		$conf .= "lport {$settings['local_port']}\n";
703

    
704
		// The management port to listen on
705
		// Use unix socket to overcome the problem on any type of server
706
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
707
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
708

    
709
		if ($settings['maxclients']) {
710
			$conf .= "max-clients {$settings['maxclients']}\n";
711
		}
712

    
713
		// Can we push routes
714
		if ($settings['local_network']) {
715
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
716
		}
717
		if ($settings['local_networkv6']) {
718
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
719
		}
720

    
721
		switch ($settings['mode']) {
722
			case 'server_tls':
723
			case 'server_user':
724
			case 'server_tls_user':
725
				// Configure client dhcp options
726
				openvpn_add_dhcpopts($settings, $conf);
727
				if ($settings['client2client']) {
728
					$conf .= "client-to-client\n";
729
				}
730
				break;
731
		}
732
		if (isset($settings['duplicate_cn'])) {
733
			$conf .= "duplicate-cn\n";
734
		}
735
	}
736

    
737
	// client specific settings
738

    
739
	if ($mode == 'client') {
740

    
741
		// configure p2p mode
742
		switch ($settings['mode']) {
743
			case 'p2p_tls':
744
				$conf .= "tls-client\n";
745
			case 'shared_key':
746
				$conf .= "client\n";
747
				break;
748
		}
749

    
750
		// If there is no bind option at all (ip and/or port), add "nobind" directive
751
		//  Otherwise, use the local port if defined, failing that, use lport 0 to
752
		//  ensure a random source port.
753
		if ((empty($iface_ip)) && (!$settings['local_port'])) {
754
			$conf .= "nobind\n";
755
		} elseif ($settings['local_port']) {
756
			$conf .= "lport {$settings['local_port']}\n";
757
		} else {
758
			$conf .= "lport 0\n";
759
		}
760

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

    
764
		// The remote server
765
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
766

    
767
		if (!empty($settings['use_shaper'])) {
768
			$conf .= "shaper {$settings['use_shaper']}\n";
769
		}
770

    
771
		if (!empty($settings['tunnel_network'])) {
772
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
773
			$mask = gen_subnet_mask($mask);
774
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
775
			if ($settings['dev_mode'] == 'tun') {
776
				$conf .= "ifconfig {$ip2} {$ip1}\n";
777
			} else {
778
				$conf .= "ifconfig {$ip2} {$mask}\n";
779
			}
780
		}
781

    
782
		if (!empty($settings['tunnel_networkv6'])) {
783
			list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
784
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
785
			if ($settings['dev_mode'] == 'tun') {
786
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
787
			} else {
788
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
789
			}
790
		}
791

    
792
		if ($settings['auth_user'] || $settings['auth_pass']) {
793
			$up_file = "{$g['varetc_path']}/openvpn/{$mode_id}.up";
794
			$conf .= "auth-user-pass {$up_file}\n";
795
			if ($settings['auth_user']) {
796
				$userpass = "{$settings['auth_user']}\n";
797
			} else {
798
				$userpass = "";
799
			}
800
			if ($settings['auth_pass']) {
801
				$userpass .= "{$settings['auth_pass']}\n";
802
			}
803
			// If only auth_pass is given, then it acts like a user name and we put a blank line where pass would normally go.
804
			if (!($settings['auth_user'] && $settings['auth_pass'])) {
805
				$userpass .= "\n";
806
			}
807
			file_put_contents($up_file, $userpass);
808
		}
809

    
810
		if ($settings['proxy_addr']) {
811
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
812
			if ($settings['proxy_authtype'] != "none") {
813
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
814
				$proxypas = "{$settings['proxy_user']}\n";
815
				$proxypas .= "{$settings['proxy_passwd']}\n";
816
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
817
			}
818
			$conf .= " \n";
819
		}
820
	}
821

    
822
	// Add a remote network route if set, and only for p2p modes.
823
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
824
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
825
	}
826
	// Add a remote network route if set, and only for p2p modes.
827
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
828
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
829
	}
830

    
831
	// Write the settings for the keys
832
	switch ($settings['mode']) {
833
		case 'p2p_shared_key':
834
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
835
			break;
836
		case 'p2p_tls':
837
		case 'server_tls':
838
		case 'server_tls_user':
839
		case 'server_user':
840
			$ca = lookup_ca($settings['caref']);
841
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
842

    
843
			if (!empty($settings['certref'])) {
844
				$cert = lookup_cert($settings['certref']);
845
				openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
846
				openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
847
			}
848
			if ($mode == 'server') {
849
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
850
			}
851
			if (!empty($settings['crlref'])) {
852
				$crl = lookup_crl($settings['crlref']);
853
				crl_update($crl);
854
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
855
			}
856
			if ($settings['tls']) {
857
				if ($mode == "server") {
858
					$tlsopt = 0;
859
				} else {
860
					$tlsopt = 1;
861
				}
862
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
863
			}
864
			break;
865
	}
866

    
867
	if (!empty($settings['compression'])) {
868
		$conf .= "comp-lzo {$settings['compression']}\n";
869
	}
870

    
871
	if ($settings['passtos']) {
872
		$conf .= "passtos\n";
873
	}
874

    
875
	if ($settings['resolve_retry']) {
876
		$conf .= "resolv-retry infinite\n";
877
	} else if ($mode == 'clie} nt') {
878
		$conf .= "resolv-retry infinite\n";
879
	}
880

    
881
	if ($settings['dynamic_ip']) {
882
		$conf .= "persist-remote-ip\n";
883
		$conf .= "float\n";
884
	}
885

    
886
	if ($settings['topology_subnet']) {
887
		$conf .= "topology subnet\n";
888
	}
889

    
890
	// New client features
891
	if ($mode == "client") {
892
		// Dont pull routes checkbox
893
		if ($settings['route_no_pull']) {
894
			$conf .= "route-nopull\n";
895
		}
896

    
897
		// Dont add/remove routes checkbox
898
		if ($settings['route_no_exec']) {
899
			$conf .= "route-noexec\n";
900
		}
901
	}
902

    
903
	openvpn_add_custom($settings, $conf);
904

    
905
	openvpn_create_dirs();
906
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
907
	file_put_contents($fpath, $conf);
908
	unset($conf);
909
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
910
	file_put_contents($fpath, $interface);
911
	//chown($fpath, 'nobody');
912
	//chgrp($fpath, 'nobody');
913
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
914
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
915
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
916
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
917
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
918
}
919

    
920
function openvpn_restart($mode, $settings) {
921
	global $g, $config;
922

    
923
	$vpnid = $settings['vpnid'];
924
	$mode_id = $mode.$vpnid;
925

    
926
	/* kill the process if running */
927
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
928
	if (file_exists($pfile)) {
929

    
930
		/* read the pid file */
931
		$pid = rtrim(file_get_contents($pfile));
932
		unlink($pfile);
933

    
934
		/* send a term signal to the process */
935
		posix_kill($pid, SIGTERM);
936

    
937
		/* wait until the process exits, or timeout and kill it */
938
		$i = 0;
939
		while (posix_kill($pid, 0)) {
940
			usleep(250000);
941
			if ($i > 10) {
942
				log_error("OpenVPN ID $mode_id PID $pid still running, killing.");
943
				posix_kill($pid, SIGKILL);
944
				usleep(500000);
945
			}
946
			$i++;
947
		}
948
	}
949

    
950
	if (isset($settings['disable'])) {
951
		return;
952
	}
953

    
954
	/* Do not start a client if we are a CARP backup on this vip! */
955
	if (($mode == "client") && (strstr($settings['interface'], "_vip") && get_carp_interface_status($settings['interface']) != "MASTER")) {
956
		return;
957
	}
958

    
959
	/* Check if client is bound to a gateway group */
960
	$a_groups = return_gateway_groups_array();
961
	if (is_array($a_groups[$settings['interface']])) {
962
		/* the interface is a gateway group. If a vip is defined and its a CARP backup then do not start */
963
		if (($a_groups[$settings['interface']][0]['vip'] <> "") && (get_carp_interface_status($a_groups[$settings['interface']][0]['vip']) != "MASTER")) {
964
			return;
965
		}
966
	}
967

    
968
	/* start the new process */
969
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
970
	openvpn_clear_route($mode, $settings);
971
	mwexec_bg("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
972

    
973
	if (!platform_booting()) {
974
		send_event("filter reload");
975
	}
976
}
977

    
978
function openvpn_delete($mode, & $settings) {
979
	global $g, $config;
980

    
981
	$vpnid = $settings['vpnid'];
982
	$mode_id = $mode.$vpnid;
983

    
984
	if (isset($settings['dev_mode'])) {
985
		$tunname = "{$settings['dev_mode']}{$vpnid}";
986
	} else {
987
		/* defaults to tun */
988
		$tunname = "tun{$vpnid}";
989
	}
990

    
991
	if ($mode == "server") {
992
		$devname = "ovpns{$vpnid}";
993
	} else {
994
		$devname = "ovpnc{$vpnid}";
995
	}
996

    
997
	/* kill the process if running */
998
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
999
	if (file_exists($pfile)) {
1000

    
1001
		/* read the pid file */
1002
		$pid = trim(file_get_contents($pfile));
1003
		unlink($pfile);
1004

    
1005
		/* send a term signal to the process */
1006
		posix_kill($pid, SIGTERM);
1007
	}
1008

    
1009
	/* remove the device from the openvpn group */
1010
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
1011

    
1012
	/* restore the original adapter name */
1013
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
1014

    
1015
	/* remove the configuration files */
1016
	@array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
1017
}
1018

    
1019
function openvpn_cleanup_csc($common_name) {
1020
	global $g, $config;
1021
	if (empty($common_name)) {
1022
		return;
1023
	}
1024
	$fpath = "{$g['varetc_path']}/openvpn-csc/" . basename($common_name);
1025
	if (is_file($fpath)) {
1026
		unlink_if_exists($fpath);
1027
	}
1028
	return;
1029
}
1030

    
1031
function openvpn_resync_csc(& $settings) {
1032
	global $g, $config;
1033

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

    
1036
	if (isset($settings['disable'])) {
1037
		unlink_if_exists($fpath);
1038
		return;
1039
	}
1040
	openvpn_create_dirs();
1041

    
1042
	$conf = '';
1043
	if ($settings['block']) {
1044
		$conf .= "disable\n";
1045
	}
1046

    
1047
	if ($settings['push_reset']) {
1048
		$conf .= "push-reset\n";
1049
	}
1050

    
1051
	if (!empty($settings['tunnel_network'])) {
1052
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
1053
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
1054
		$serverip = long2ip32($baselong + 1);
1055
		$clientip = long2ip32($baselong + 2);
1056
		/* Because this is being pushed, the order from the client's point of view. */
1057
		if ($settings['dev_mode'] != 'tap') {
1058
			$conf .= "ifconfig-push {$clientip} {$serverip}\n";
1059
		} else {
1060
			$conf .= "ifconfig-push {$clientip} {$mask}\n";
1061
		}
1062
	}
1063

    
1064
	if ($settings['local_network']) {
1065
		$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
1066
	}
1067
	if ($settings['local_networkv6']) {
1068
		$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
1069
	}
1070

    
1071
	// Add a remote network iroute if set
1072
	if (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE) {
1073
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false, true);
1074
	}
1075
	// Add a remote network iroute if set
1076
	if (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE) {
1077
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false, true);
1078
	}
1079

    
1080
	openvpn_add_dhcpopts($settings, $conf);
1081

    
1082
	if ($settings['gwredir']) {
1083
		$conf .= "push \"redirect-gateway def1\"\n";
1084
	}
1085

    
1086
	openvpn_add_custom($settings, $conf);
1087

    
1088
	file_put_contents($fpath, $conf);
1089
	chown($fpath, 'nobody');
1090
	chgrp($fpath, 'nobody');
1091
}
1092

    
1093
function openvpn_delete_csc(& $settings) {
1094
	global $g, $config;
1095

    
1096
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
1097
	unlink_if_exists($fpath);
1098
}
1099

    
1100
// Resync the configuration and restart the VPN
1101
function openvpn_resync($mode, $settings) {
1102
	openvpn_reconfigure($mode, $settings);
1103
	openvpn_restart($mode, $settings);
1104
}
1105

    
1106
// Resync and restart all VPNs
1107
function openvpn_resync_all($interface = "") {
1108
	global $g, $config;
1109

    
1110
	openvpn_create_dirs();
1111

    
1112
	if (!is_array($config['openvpn'])) {
1113
		$config['openvpn'] = array();
1114
	}
1115

    
1116
/*
1117
	if (!$config['openvpn']['dh-parameters']) {
1118
		echo "Configuring OpenVPN Parameters ...\n";
1119
		$dh_parameters = openvpn_create_dhparams(1024);
1120
		$dh_parameters = base64_encode($dh_parameters);
1121
		$config['openvpn']['dh-parameters'] = $dh_parameters;
1122
		write_config("OpenVPN DH parameters");
1123
	}
1124

    
1125
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
1126
	if (!file_exists($path_ovdh)) {
1127
		$dh_parameters = $config['openvpn']['dh-parameters'];
1128
		$dh_parameters = base64_decode($dh_parameters);
1129
		file_put_contents($path_ovdh, $dh_parameters);
1130
	}
1131
*/
1132
	if ($interface <> "") {
1133
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
1134
	} else {
1135
		log_error("Resyncing OpenVPN instances.");
1136
	}
1137

    
1138
	if (is_array($config['openvpn']['openvpn-server'])) {
1139
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1140
			if ($interface <> "" && $interface != $settings['interface']) {
1141
				continue;
1142
			}
1143
			openvpn_resync('server', $settings);
1144
		}
1145
	}
1146

    
1147
	if (is_array($config['openvpn']['openvpn-client'])) {
1148
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1149
			if ($interface <> "" && $interface != $settings['interface']) {
1150
				continue;
1151
			}
1152
			openvpn_resync('client', $settings);
1153
		}
1154
	}
1155

    
1156
	if (is_array($config['openvpn']['openvpn-csc'])) {
1157
		foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
1158
			openvpn_resync_csc($settings);
1159
		}
1160
	}
1161

    
1162
}
1163

    
1164
// Resync and restart all VPNs using a gateway group.
1165
function openvpn_resync_gwgroup($gwgroupname = "") {
1166
	global $g, $config;
1167

    
1168
	if ($gwgroupname <> "") {
1169
		if (is_array($config['openvpn']['openvpn-server'])) {
1170
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1171
				if ($gwgroupname == $settings['interface']) {
1172
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " server " . $settings["description"] . ".");
1173
					openvpn_resync('server', $settings);
1174
				}
1175
			}
1176
		}
1177

    
1178
		if (is_array($config['openvpn']['openvpn-client'])) {
1179
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1180
				if ($gwgroupname == $settings['interface']) {
1181
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " client " . $settings["description"] . ".");
1182
					openvpn_resync('client', $settings);
1183
				}
1184
			}
1185
		}
1186

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

    
1189
	} else {
1190
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter.");
1191
	}
1192
}
1193

    
1194
function openvpn_get_active_servers($type="multipoint") {
1195
	global $config, $g;
1196

    
1197
	$servers = array();
1198
	if (is_array($config['openvpn']['openvpn-server'])) {
1199
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1200
			if (empty($settings) || isset($settings['disable'])) {
1201
				continue;
1202
			}
1203

    
1204
			$prot = $settings['protocol'];
1205
			$port = $settings['local_port'];
1206

    
1207
			$server = array();
1208
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
1209
			$server['mode'] = $settings['mode'];
1210
			if ($settings['description']) {
1211
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
1212
			} else {
1213
				$server['name'] = "Server {$prot}:{$port}";
1214
			}
1215
			$server['conns'] = array();
1216
			$server['vpnid'] = $settings['vpnid'];
1217
			$server['mgmt'] = "server{$server['vpnid']}";
1218
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
1219
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
1220

    
1221
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30)) && ($type == "p2p")) {
1222
				$servers[] = openvpn_get_client_status($server, $socket);
1223
			} elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30)) {
1224
				$servers[] = openvpn_get_server_status($server, $socket);
1225
			}
1226
		}
1227
	}
1228
	return $servers;
1229
}
1230

    
1231
function openvpn_get_server_status($server, $socket) {
1232
	$errval = null;
1233
	$errstr = null;
1234
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1235
	if ($fp) {
1236
		stream_set_timeout($fp, 1);
1237

    
1238
		/* send our status request */
1239
		fputs($fp, "status 2\n");
1240

    
1241
		/* recv all response lines */
1242
		while (!feof($fp)) {
1243

    
1244
			/* read the next line */
1245
			$line = fgets($fp, 1024);
1246

    
1247
			$info = stream_get_meta_data($fp);
1248
			if ($info['timed_out']) {
1249
				break;
1250
			}
1251

    
1252
			/* parse header list line */
1253
			if (strstr($line, "HEADER")) {
1254
				continue;
1255
			}
1256

    
1257
			/* parse end of output line */
1258
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1259
				break;
1260
			}
1261

    
1262
			/* parse client list line */
1263
			if (strstr($line, "CLIENT_LIST")) {
1264
				$list = explode(",", $line);
1265
				$conn = array();
1266
				$conn['common_name'] = $list[1];
1267
				$conn['remote_host'] = $list[2];
1268
				$conn['virtual_addr'] = $list[3];
1269
				$conn['bytes_recv'] = $list[4];
1270
				$conn['bytes_sent'] = $list[5];
1271
				$conn['connect_time'] = $list[6];
1272
				$server['conns'][] = $conn;
1273
			}
1274
			/* parse routing table lines */
1275
			if (strstr($line, "ROUTING_TABLE")) {
1276
				$list = explode(",", $line);
1277
				$conn = array();
1278
				$conn['virtual_addr'] = $list[1];
1279
				$conn['common_name'] = $list[2];
1280
				$conn['remote_host'] = $list[3];
1281
				$conn['last_time'] = $list[4];
1282
				$server['routes'][] = $conn;
1283
			}
1284
		}
1285

    
1286
		/* cleanup */
1287
		fclose($fp);
1288
	} else {
1289
		$conn = array();
1290
		$conn['common_name'] = "[error]";
1291
		$conn['remote_host'] = "Unable to contact daemon";
1292
		$conn['virtual_addr'] = "Service not running?";
1293
		$conn['bytes_recv'] = 0;
1294
		$conn['bytes_sent'] = 0;
1295
		$conn['connect_time'] = 0;
1296
		$server['conns'][] = $conn;
1297
	}
1298
	return $server;
1299
}
1300

    
1301
function openvpn_get_active_clients() {
1302
	global $config, $g;
1303

    
1304
	$clients = array();
1305
	if (is_array($config['openvpn']['openvpn-client'])) {
1306
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1307

    
1308
			if (empty($settings) || isset($settings['disable'])) {
1309
				continue;
1310
			}
1311

    
1312
			$prot = $settings['protocol'];
1313
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1314

    
1315
			$client = array();
1316
			$client['port'] = $settings['local_port'];
1317
			if ($settings['description']) {
1318
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1319
			} else {
1320
				$client['name'] = "Client {$prot}{$port}";
1321
			}
1322

    
1323
			$client['vpnid'] = $settings['vpnid'];
1324
			$client['mgmt'] = "client{$client['vpnid']}";
1325
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1326
			$client['status']="down";
1327

    
1328
			$clients[] = openvpn_get_client_status($client, $socket);
1329
		}
1330
	}
1331
	return $clients;
1332
}
1333

    
1334
function openvpn_get_client_status($client, $socket) {
1335
	$errval = null;
1336
	$errstr = null;
1337
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1338
	if ($fp) {
1339
		stream_set_timeout($fp, 1);
1340
		/* send our status request */
1341
		fputs($fp, "state 1\n");
1342

    
1343
		/* recv all response lines */
1344
		while (!feof($fp)) {
1345
			/* read the next line */
1346
			$line = fgets($fp, 1024);
1347

    
1348
			$info = stream_get_meta_data($fp);
1349
			if ($info['timed_out']) {
1350
				break;
1351
			}
1352

    
1353
			/* Get the client state */
1354
			if (strstr($line, "CONNECTED")) {
1355
				$client['status'] = "up";
1356
				$list = explode(",", $line);
1357

    
1358
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1359
				$client['virtual_addr'] = $list[3];
1360
				$client['remote_host'] = $list[4];
1361
			}
1362
			if (strstr($line, "CONNECTING")) {
1363
				$client['status'] = "connecting";
1364
			}
1365
			if (strstr($line, "ASSIGN_IP")) {
1366
				$client['status'] = "waiting";
1367
				$list = explode(",", $line);
1368

    
1369
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1370
				$client['virtual_addr'] = $list[3];
1371
			}
1372
			if (strstr($line, "RECONNECTING")) {
1373
				$client['status'] = "reconnecting";
1374
				$list = explode(",", $line);
1375

    
1376
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1377
				$client['status'] .= "; " . $list[2];
1378
			}
1379
			/* parse end of output line */
1380
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1381
				break;
1382
			}
1383
		}
1384

    
1385
		/* If up, get read/write stats */
1386
		if (strcmp($client['status'], "up") == 0) {
1387
			fputs($fp, "status 2\n");
1388
			/* recv all response lines */
1389
			while (!feof($fp)) {
1390
				/* read the next line */
1391
				$line = fgets($fp, 1024);
1392

    
1393
				$info = stream_get_meta_data($fp);
1394
				if ($info['timed_out']) {
1395
					break;
1396
				}
1397

    
1398
				if (strstr($line, "TCP/UDP read bytes")) {
1399
					$list = explode(",", $line);
1400
					$client['bytes_recv'] = $list[1];
1401
				}
1402

    
1403
				if (strstr($line, "TCP/UDP write bytes")) {
1404
					$list = explode(",", $line);
1405
					$client['bytes_sent'] = $list[1];
1406
				}
1407

    
1408
				/* parse end of output line */
1409
				if (strstr($line, "END")) {
1410
					break;
1411
				}
1412
			}
1413
		}
1414

    
1415
		fclose($fp);
1416

    
1417
	} else {
1418
		$DisplayNote=true;
1419
		$client['remote_host'] = "Unable to contact daemon";
1420
		$client['virtual_addr'] = "Service not running?";
1421
		$client['bytes_recv'] = 0;
1422
		$client['bytes_sent'] = 0;
1423
		$client['connect_time'] = 0;
1424
	}
1425
	return $client;
1426
}
1427

    
1428
function openvpn_refresh_crls() {
1429
	global $g, $config;
1430

    
1431
	openvpn_create_dirs();
1432

    
1433
	if (is_array($config['openvpn']['openvpn-server'])) {
1434
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1435
			if (empty($settings)) {
1436
				continue;
1437
			}
1438
			if (isset($settings['disable'])) {
1439
				continue;
1440
			}
1441
			// Write the settings for the keys
1442
			switch ($settings['mode']) {
1443
				case 'p2p_tls':
1444
				case 'server_tls':
1445
				case 'server_tls_user':
1446
				case 'server_user':
1447
					if (!empty($settings['crlref'])) {
1448
						$crl = lookup_crl($settings['crlref']);
1449
						crl_update($crl);
1450
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1451
						file_put_contents($fpath, base64_decode($crl['text']));
1452
						@chmod($fpath, 0644);
1453
					}
1454
					break;
1455
			}
1456
		}
1457
	}
1458
}
1459

    
1460
function openvpn_create_dirs() {
1461
	global $g;
1462
	if (!is_dir("{$g['varetc_path']}/openvpn")) {
1463
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1464
	}
1465
	if (!is_dir("{$g['varetc_path']}/openvpn-csc")) {
1466
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1467
	}
1468
}
1469

    
1470
function openvpn_get_interface_ip($ip, $mask) {
1471
	$baselong = ip2long32($ip) & ip2long($mask);
1472
	$ip1 = long2ip32($baselong + 1);
1473
	$ip2 = long2ip32($baselong + 2);
1474
	return array($ip1, $ip2);
1475
}
1476

    
1477
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1478
	$basev6 = gen_subnetv6($ipv6, $prefix);
1479
	// Is there a better way to do this math?
1480
	$ipv6_arr = explode(':', $basev6);
1481
	$last = hexdec(array_pop($ipv6_arr));
1482
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1483
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1484
	return array($ipv6_1, $ipv6_2);
1485
}
1486

    
1487
function openvpn_clear_route($mode, $settings) {
1488
	if (empty($settings['tunnel_network'])) {
1489
		return;
1490
	}
1491
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1492
	$mask = gen_subnet_mask($cidr);
1493
	$clear_route = false;
1494

    
1495
	switch ($settings['mode']) {
1496
		case 'shared_key':
1497
			$clear_route = true;
1498
			break;
1499
		case 'p2p_tls':
1500
		case 'p2p_shared_key':
1501
			if ($cidr == 30) {
1502
				$clear_route = true;
1503
			}
1504
			break;
1505
	}
1506

    
1507
	if ($clear_route && !empty($ip) && !empty($mask)) {
1508
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1509
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1510
		/* XXX: Family for route? */
1511
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1512
	}
1513
}
1514

    
1515
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
1516
	$routes = "";
1517
	if (empty($value)) {
1518
		return "";
1519
	}
1520
	$networks = explode(',', $value);
1521

    
1522
	foreach ($networks as $network) {
1523
		if ($ipproto == "ipv4") {
1524
			$route = openvpn_gen_route_ipv4($network, $iroute);
1525
		} else {
1526
			$route = openvpn_gen_route_ipv6($network, $iroute);
1527
		}
1528

    
1529
		if ($push) {
1530
			$routes .= "push \"{$route}\"\n";
1531
		} else {
1532
			$routes .= "{$route}\n";
1533
		}
1534
	}
1535
	return $routes;
1536
}
1537

    
1538
function openvpn_gen_route_ipv4($network, $iroute = false) {
1539
	$i = ($iroute) ? "i" : "";
1540
	list($ip, $mask) = explode('/', trim($network));
1541
	$mask = gen_subnet_mask($mask);
1542
	return "{$i}route $ip $mask";
1543
}
1544

    
1545
function openvpn_gen_route_ipv6($network, $iroute = false) {
1546
	$i = ($iroute) ? "i" : "";
1547
	list($ipv6, $prefix) = explode('/', trim($network));
1548
	if (empty($prefix)) {
1549
		$prefix = "128";
1550
	}
1551
	return "{$i}route-ipv6 ${ipv6}/${prefix}";
1552
}
1553

    
1554
function openvpn_get_settings($mode, $vpnid) {
1555
	global $config;
1556

    
1557
	if (is_array($config['openvpn']['openvpn-server'])) {
1558
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1559
			if (isset($settings['disable'])) {
1560
				continue;
1561
			}
1562

    
1563
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1564
				return $settings;
1565
			}
1566
		}
1567
	}
1568

    
1569
	if (is_array($config['openvpn']['openvpn-client'])) {
1570
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1571
			if (isset($settings['disable'])) {
1572
				continue;
1573
			}
1574

    
1575
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1576
				return $settings;
1577
			}
1578
		}
1579
	}
1580

    
1581
	return array();
1582
}
1583

    
1584
function openvpn_restart_by_vpnid($mode, $vpnid) {
1585
	$settings = openvpn_get_settings($mode, $vpnid);
1586
	openvpn_restart($mode, $settings);
1587
}
1588

    
1589
?>
(38-38/67)