Project

General

Profile

Download (50.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	openvpn.inc part of pfSense
4

    
5
	Copyright (C) 2008 Scott Ullrich <sullrich@gmail.com>
6
	All rights reserved.
7

    
8
	Copyright (C) 2006  Fernando Lemos
9
	All rights reserved.
10

    
11
	This file was rewritten from scratch by Fernando Lemos but
12
	*MIGHT* contain code previously written by:
13

    
14
	Copyright (C) 2005 Peter Allgeyer <allgeyer_AT_web.de>
15
	All rights reserved.
16

    
17
	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
18
	All rights reserved.
19

    
20
	Redistribution and use in source and binary forms, with or without
21
	modification, are permitted provided that the following conditions are met:
22

    
23
	1. Redistributions of source code must retain the above copyright notices,
24
	   this list of conditions and the following disclaimer.
25

    
26
	2. Redistributions in binary form must reproduce the above copyright
27
	   notices, this list of conditions and the following disclaimer in the
28
	   documentation and/or other materials provided with the distribution.
29

    
30
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39
	POSSIBILITY OF SUCH DAMAGE.
40

    
41

    
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_tls_server_modes;
108
$openvpn_tls_server_modes = array('p2p_tls', 'server_tls', 'server_user', 'server_tls_user');
109

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

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

    
122
global $openvpn_topologies;
123
$openvpn_topologies = array(
124
	'subnet' => gettext("Subnet -- One IP address per client in a common subnet"),
125
	'net30' => gettext("net30 -- Isolated /30 network per client")
126
//	'p2p => gettext("Peer to Peer -- One IP address per client peer-to-peer style. Does not work on Windows.")
127
);
128

    
129
function openvpn_build_mode_list() {
130
	global $openvpn_server_modes;
131

    
132
	$list = array();
133

    
134
	foreach ($openvpn_server_modes as $name => $desc) {
135
		$list[$name] = $desc;
136
	}
137

    
138
	return($list);
139
}
140

    
141
function openvpn_build_if_list() {
142
	$list = array();
143

    
144
	$interfaces = get_configured_interface_with_descr();
145
	$carplist = get_configured_carp_interface_list();
146

    
147
	foreach ($carplist as $cif => $carpip) {
148
		$interfaces[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")";
149
	}
150

    
151
	$aliaslist = get_configured_ip_aliases_list();
152

    
153
	foreach ($aliaslist as $aliasip => $aliasif) {
154
		$interfaces[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
155
	}
156

    
157
	$grouplist = return_gateway_groups_array();
158

    
159
	foreach ($grouplist as $name => $group) {
160
		if ($group['ipprotocol'] != inet) {
161
			continue;
162
		}
163

    
164
		if ($group[0]['vip'] != "") {
165
			$vipif = $group[0]['vip'];
166
		} else {
167
			$vipif = $group[0]['int'];
168
		}
169

    
170
		$interfaces[$name] = "GW Group {$name}";
171
	}
172

    
173
	$interfaces['lo0'] = "Localhost";
174
	$interfaces['any'] = "any";
175

    
176
	foreach ($interfaces as $iface => $ifacename) {
177
	   $list[$iface] = $ifacename;
178
	}
179

    
180
	return($list);
181
}
182

    
183
function openvpn_build_crl_list() {
184
	global $a_crl;
185

    
186
	$list = array('' => 'None');
187

    
188
	foreach ($a_crl as $crl) {
189
		$caname = "";
190
		$ca = lookup_ca($crl['caref']);
191

    
192
		if ($ca) {
193
			$caname = " (CA: {$ca['descr']})";
194
		}
195

    
196
		$list[$crl['refid']] = $crl['descr'] . $caname;
197
	}
198

    
199
	return($list);
200
}
201

    
202
function openvpn_build_cert_list($include_none = false, $prioritize_server_certs = false) {
203
	global $a_cert;
204

    
205
	if ($include_none) {
206
		$list = array('' => 'None (Username and/or Password required)');
207
	} else {
208
		$list = array();
209
	}
210

    
211
	if ($prioritize_server_certs) {
212
		$list[' '] = "===== Server Certificates =====";
213
		$non_server_list = array();
214
		$non_server_list['  '] = "===== Non-Server Certificates =====";
215
	}
216

    
217
	foreach ($a_cert as $cert) {
218
		$properties = array();
219
		$propstr = "";
220
		$ca = lookup_ca($cert['caref']);
221
		$purpose = cert_get_purpose($cert['crt'], true);
222

    
223
		if ($purpose['server'] == "Yes") {
224
			$properties[] = "Server: Yes";
225
		} elseif ($prioritize_server_certs) {
226
			$properties[] = "Server: NO";
227
		}
228
		if ($ca) {
229
			$properties[] = "CA: {$ca['descr']}";
230
		}
231
		if (cert_in_use($cert['refid'])) {
232
			$properties[] = "In Use";
233
		}
234
		if (is_cert_revoked($cert)) {
235
			$properties[] = "Revoked";
236
		}
237

    
238
		if (!empty($properties)) {
239
			$propstr = " (" . implode(", ", $properties) . ")";
240
		}
241

    
242
		if ($prioritize_server_certs) {
243
			if ($purpose['server'] == "Yes") {
244
				$list[$cert['refid']] = $cert['descr'] . $propstr;
245
			} else {
246
				$non_server_list[$cert['refid']] = $cert['descr'] . $propstr;
247
			}
248
		} else {
249
			$list[$cert['refid']] = $cert['descr'] . $propstr;
250
		}
251
	}
252

    
253
	if ($prioritize_server_certs) {
254
		$list = array_merge($list, $non_server_list);
255
	}
256

    
257
	return($list);
258
}
259

    
260
function openvpn_build_bridge_list() {
261
	$list = array();
262

    
263
	$serverbridge_interface['none'] = "none";
264
	$serverbridge_interface = array_merge($serverbridge_interface, get_configured_interface_with_descr());
265
	$carplist = get_configured_carp_interface_list();
266

    
267
	foreach ($carplist as $cif => $carpip) {
268
		$serverbridge_interface[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")";
269
	}
270

    
271
	$aliaslist = get_configured_ip_aliases_list();
272

    
273
	foreach ($aliaslist as $aliasip => $aliasif) {
274
		$serverbridge_interface[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
275
	}
276

    
277
	foreach ($serverbridge_interface as $iface => $ifacename) {
278
		$list[$iface] = htmlspecialchars($ifacename);
279
	}
280

    
281
	return($list);
282
}
283

    
284
function openvpn_create_key() {
285

    
286
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
287
	if (!$fp) {
288
		return false;
289
	}
290

    
291
	$rslt = stream_get_contents($fp);
292
	pclose($fp);
293

    
294
	return $rslt;
295
}
296

    
297
function openvpn_create_dhparams($bits) {
298

    
299
	$fp = popen("/usr/bin/openssl dhparam {$bits} 2>/dev/null", "r");
300
	if (!$fp) {
301
		return false;
302
	}
303

    
304
	$rslt = stream_get_contents($fp);
305
	pclose($fp);
306

    
307
	return $rslt;
308
}
309

    
310
function openvpn_vpnid_used($vpnid) {
311
	global $config;
312

    
313
	if (is_array($config['openvpn']['openvpn-server'])) {
314
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
315
			if ($vpnid == $settings['vpnid']) {
316
				return true;
317
			}
318
		}
319
	}
320

    
321
	if (is_array($config['openvpn']['openvpn-client'])) {
322
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
323
			if ($vpnid == $settings['vpnid']) {
324
				return true;
325
			}
326
		}
327
	}
328

    
329
	return false;
330
}
331

    
332
function openvpn_vpnid_next() {
333

    
334
	$vpnid = 1;
335
	while (openvpn_vpnid_used($vpnid)) {
336
		$vpnid++;
337
	}
338

    
339
	return $vpnid;
340
}
341

    
342
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
343
	global $config;
344

    
345
	if (is_array($config['openvpn']['openvpn-server'])) {
346
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
347
			if (isset($settings['disable'])) {
348
				continue;
349
			}
350

    
351
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
352
				continue;
353
			}
354

    
355
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
356
			    ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
357
				return $settings['vpnid'];
358
			}
359
		}
360
	}
361

    
362
	if (is_array($config['openvpn']['openvpn-client'])) {
363
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
364
			if (isset($settings['disable'])) {
365
				continue;
366
			}
367

    
368
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
369
				continue;
370
			}
371

    
372
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
373
			    ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
374
				return $settings['vpnid'];
375
			}
376
		}
377
	}
378

    
379
	return 0;
380
}
381

    
382
function openvpn_port_next($prot, $interface = "wan") {
383

    
384
	$port = 1194;
385
	while (openvpn_port_used($prot, $interface, $port)) {
386
		$port++;
387
	}
388
	while (openvpn_port_used($prot, "any", $port)) {
389
		$port++;
390
	}
391

    
392
	return $port;
393
}
394

    
395
function openvpn_get_cipherlist() {
396

    
397
	$ciphers = array();
398
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
399
	$cipher_lines = explode("\n", trim($cipher_out));
400
	sort($cipher_lines);
401
	foreach ($cipher_lines as $line) {
402
		$words = explode(' ', $line);
403
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
404
	}
405
	$ciphers["none"] = gettext("None (No Encryption)");
406
	return $ciphers;
407
}
408

    
409
function openvpn_get_digestlist() {
410

    
411
	$digests = array();
412
	$digest_out = shell_exec('/usr/local/sbin/openvpn --show-digests | /usr/bin/grep "digest size" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
413
	$digest_lines = explode("\n", trim($digest_out));
414
	sort($digest_lines);
415
	foreach ($digest_lines as $line) {
416
		$words = explode(' ', $line);
417
		$digests[$words[0]] = "{$words[0]} {$words[1]}";
418
	}
419
	$digests["none"] = gettext("None (No Authentication)");
420
	return $digests;
421
}
422

    
423
function openvpn_get_engines() {
424
	$openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
425
	exec("/usr/bin/openssl engine -t -c", $openssl_engine_output);
426
	$openssl_engine_output = implode("\n", $openssl_engine_output);
427
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
428
	$openssl_engine_output = explode("\n", $openssl_engine_output);
429

    
430
	foreach ($openssl_engine_output as $oeo) {
431
		$keep = true;
432
		$details = explode("|", $oeo);
433
		$engine = array_shift($details);
434
		$linematch = array();
435
		preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
436
		foreach ($details as $dt) {
437
			if (strpos($dt, "unavailable") !== FALSE) {
438
				$keep = false;
439
			}
440
			if (strpos($dt, "available") !== FALSE) {
441
				continue;
442
			}
443
			if (strpos($dt, "[") !== FALSE) {
444
				$ciphers = trim($dt, "[]");
445
			}
446
		}
447
		if (!empty($ciphers)) {
448
			$ciphers = " - " . $ciphers;
449
		}
450
		if (strlen($ciphers) > 60) {
451
			$ciphers = substr($ciphers, 0, 60) . " ... ";
452
		}
453
		if ($keep) {
454
			$openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
455
		}
456
	}
457
	return $openssl_engines;
458
}
459

    
460
function openvpn_validate_engine($engine) {
461
	$engines = openvpn_get_engines();
462
	return array_key_exists($engine, $engines);
463
}
464

    
465
function openvpn_validate_host($value, $name) {
466
	$value = trim($value);
467
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value))) {
468
		return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
469
	}
470
	return false;
471
}
472

    
473
function openvpn_validate_port($value, $name) {
474
	$value = trim($value);
475
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535)) {
476
		return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
477
	}
478
	return false;
479
}
480

    
481
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
482
	$value = trim($value);
483
	$error = false;
484
	if (empty($value)) {
485
		return false;
486
	}
487
	$networks = explode(',', $value);
488

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

    
493
	foreach ($networks as $network) {
494
		if ($ipproto == "ipv4") {
495
			$error = !openvpn_validate_cidr_ipv4($network);
496
		} else {
497
			$error = !openvpn_validate_cidr_ipv6($network);
498
		}
499
		if ($error) {
500
			break;
501
		}
502
	}
503

    
504
	if ($error) {
505
		return sprintf(gettext("The field '%s' must contain only valid %s CIDR range(s) separated by commas."), $name, $ipproto);
506
	} else {
507
		return false;
508
	}
509
}
510

    
511
function openvpn_validate_cidr_ipv4($value) {
512
	$value = trim($value);
513
	if (!empty($value)) {
514
		list($ip, $mask) = explode('/', $value);
515
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0)) {
516
			return false;
517
		}
518
	}
519
	return true;
520
}
521

    
522
function openvpn_validate_cidr_ipv6($value) {
523
	$value = trim($value);
524
	if (!empty($value)) {
525
		list($ipv6, $prefix) = explode('/', $value);
526
		if (empty($prefix)) {
527
			$prefix = "128";
528
		}
529
		if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0)) {
530
			return false;
531
		}
532
	}
533
	return true;
534
}
535

    
536
function openvpn_add_dhcpopts(& $settings, & $conf) {
537

    
538
	if (!empty($settings['dns_domain'])) {
539
		$conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
540
	}
541

    
542
	if (!empty($settings['dns_server1'])) {
543
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
544
	}
545
	if (!empty($settings['dns_server2'])) {
546
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
547
	}
548
	if (!empty($settings['dns_server3'])) {
549
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
550
	}
551
	if (!empty($settings['dns_server4'])) {
552
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
553
	}
554

    
555
	if (!empty($settings['push_register_dns'])) {
556
		$conf .= "push \"register-dns\"\n";
557
	}
558

    
559
	if (!empty($settings['ntp_server1'])) {
560
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
561
	}
562
	if (!empty($settings['ntp_server2'])) {
563
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
564
	}
565

    
566
	if ($settings['netbios_enable']) {
567

    
568
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0)) {
569
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
570
		}
571
		if (!empty($settings['dhcp_nbtscope'])) {
572
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
573
		}
574

    
575
		if (!empty($settings['wins_server1'])) {
576
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
577
		}
578
		if (!empty($settings['wins_server2'])) {
579
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
580
		}
581

    
582
		if (!empty($settings['nbdd_server1'])) {
583
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
584
		}
585
	}
586

    
587
	if ($settings['gwredir']) {
588
		$conf .= "push \"redirect-gateway def1\"\n";
589
	}
590
}
591

    
592
function openvpn_add_custom(& $settings, & $conf) {
593

    
594
	if ($settings['custom_options']) {
595

    
596
		$options = explode(';', $settings['custom_options']);
597

    
598
		if (is_array($options)) {
599
			foreach ($options as $option) {
600
				$conf .= "$option\n";
601
			}
602
		} else {
603
			$conf .= "{$settings['custom_options']}\n";
604
		}
605
	}
606
}
607

    
608
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
609
	global $g;
610

    
611
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
612
	openvpn_create_dirs();
613
	file_put_contents($fpath, base64_decode($data));
614
	//chown($fpath, 'nobody');
615
	//chgrp($fpath, 'nobody');
616
	@chmod($fpath, 0600);
617

    
618
	$conf .= "{$directive} {$fpath} {$opt}\n";
619
}
620

    
621
function openvpn_reconfigure($mode, $settings) {
622
	global $g, $config, $openvpn_tls_server_modes;
623

    
624
	if (empty($settings)) {
625
		return;
626
	}
627
	if (isset($settings['disable'])) {
628
		return;
629
	}
630
	openvpn_create_dirs();
631
	/*
632
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
633
	 * we use a vpnid number which is allocated for a particular client
634
	 * or server configuration. ( see openvpn_vpnid_next() )
635
	 */
636

    
637
	$vpnid = $settings['vpnid'];
638
	$mode_id = $mode.$vpnid;
639

    
640
	if (isset($settings['dev_mode'])) {
641
		$tunname = "{$settings['dev_mode']}{$vpnid}";
642
	} else {
643
		/* defaults to tun */
644
		$tunname = "tun{$vpnid}";
645
		$settings['dev_mode'] = "tun";
646
	}
647

    
648
	if ($mode == "server") {
649
		$devname = "ovpns{$vpnid}";
650
	} else {
651
		$devname = "ovpnc{$vpnid}";
652
	}
653

    
654
	/* is our device already configured */
655
	if (!does_interface_exist($devname)) {
656

    
657
		/* create the tap device if required */
658
		if (!file_exists("/dev/{$tunname}")) {
659
			exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
660
		}
661

    
662
		/* rename the device */
663
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
664

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

    
668
		$ifname = convert_real_interface_to_friendly_interface_name($devname);
669
		$grouptmp = link_interface_to_group($ifname);
670
		if (!empty($grouptmp)) {
671
			array_walk($grouptmp, 'interface_group_add_member');
672
		}
673
		unset($grouptmp, $ifname);
674
	}
675

    
676
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
677
	$proto = strtolower($settings['protocol']);
678
	if (substr($settings['protocol'], 0, 3) == "TCP") {
679
			$proto = "{$proto}-{$mode}";
680
	}
681
	$dev_mode = $settings['dev_mode'];
682
	$cipher = $settings['crypto'];
683
	// OpenVPN defaults to SHA1, so use it when unset to maintain compatibility.
684
	$digest = !empty($settings['digest']) ? $settings['digest'] : "SHA1";
685

    
686
	$interface = get_failover_interface($settings['interface']);
687
	// The IP address in the settings can be an IPv4 or IPv6 address associated with the interface
688
	$ipaddr = $settings['ipaddr'];
689

    
690
	// If a specific ip address (VIP) is requested, use it.
691
	// Otherwise, if a specific interface is requested, use it
692
	// If "any" interface was selected, local directive will be omitted.
693
	if (is_ipaddrv4($ipaddr)) {
694
		$iface_ip = $ipaddr;
695
	} else {
696
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
697
			$iface_ip=get_interface_ip($interface);
698
		}
699
	}
700
	if (is_ipaddrv6($ipaddr)) {
701
		$iface_ipv6 = $ipaddr;
702
	} else {
703
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
704
			$iface_ipv6=get_interface_ipv6($interface);
705
		}
706
	}
707

    
708

    
709
	$conf = "dev {$devname}\n";
710
	if (isset($settings['verbosity_level'])) {
711
		$conf .= "verb {$settings['verbosity_level']}\n";
712
	}
713

    
714
	$conf .= "dev-type {$settings['dev_mode']}\n";
715
	switch ($settings['dev_mode']) {
716
		case "tun":
717
			if (!$settings['no_tun_ipv6']) {
718
				$conf .= "tun-ipv6\n";
719
			}
720
			break;
721
	}
722
	$conf .= "dev-node /dev/{$tunname}\n";
723
	$conf .= "writepid {$pfile}\n";
724
	$conf .= "#user nobody\n";
725
	$conf .= "#group nobody\n";
726
	$conf .= "script-security 3\n";
727
	$conf .= "daemon\n";
728
	$conf .= "keepalive 10 60\n";
729
	$conf .= "ping-timer-rem\n";
730
	$conf .= "persist-tun\n";
731
	$conf .= "persist-key\n";
732
	$conf .= "proto {$proto}\n";
733
	$conf .= "cipher {$cipher}\n";
734
	$conf .= "auth {$digest}\n";
735
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
736
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
737
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
738
		switch ($settings['mode']) {
739
			case 'server_user':
740
			case 'server_tls_user':
741
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
742
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
743
				break;
744
		}
745
	}
746

    
747
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
748
	if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
749
		$conf .= "local {$iface_ip}\n";
750
	} elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
751
		$conf .= "local {$iface_ipv6}\n";
752
	}
753

    
754
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
755
		$conf .= "engine {$settings['engine']}\n";
756
	}
757

    
758
	// server specific settings
759
	if ($mode == 'server') {
760

    
761
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
762
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
763
		$mask = gen_subnet_mask($cidr);
764

    
765
		// configure tls modes
766
		switch ($settings['mode']) {
767
			case 'p2p_tls':
768
			case 'server_tls':
769
			case 'server_user':
770
			case 'server_tls_user':
771
				$conf .= "tls-server\n";
772
				break;
773
		}
774

    
775
		// configure p2p/server modes
776
		switch ($settings['mode']) {
777
			case 'p2p_tls':
778
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
779
				//  use the server directive. It works for a single client without it.
780
				//  See ticket #1417
781
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
782
					$conf .= "server {$ip} {$mask}\n";
783
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc/server{$vpnid}\n";
784
					if (is_ipaddr($ipv6)) {
785
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
786
					}
787
				}
788
			case 'p2p_shared_key':
789
				if (!empty($ip) && !empty($mask)) {
790
					list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
791
					if ($settings['dev_mode'] == 'tun') {
792
						$conf .= "ifconfig {$ip1} {$ip2}\n";
793
					} else {
794
						$conf .= "ifconfig {$ip1} {$mask}\n";
795
					}
796
				}
797
				if (!empty($ipv6) && !empty($prefix)) {
798
					list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
799
					if ($settings['dev_mode'] == 'tun') {
800
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
801
					} else {
802
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
803
					}
804
				}
805
				break;
806
			case 'server_tls':
807
			case 'server_user':
808
			case 'server_tls_user':
809
				if (!empty($ip) && !empty($mask)) {
810
					$conf .= "server {$ip} {$mask}\n";
811
					if (is_ipaddr($ipv6)) {
812
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
813
					}
814
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc/server{$vpnid}\n";
815
				} else {
816
					if ($settings['serverbridge_dhcp']) {
817
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
818
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
819
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
820
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
821
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
822
								$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc/server{$vpnid}\n";
823
							} else {
824
								$conf .= "mode server\n";
825
							}
826
						} else {
827
							$conf .= "mode server\n";
828
						}
829
					}
830
				}
831
				break;
832
		}
833

    
834
		// configure user auth modes
835
		switch ($settings['mode']) {
836
			case 'server_user':
837
				$conf .= "client-cert-not-required\n";
838
			case 'server_tls_user':
839
				/* username-as-common-name is not compatible with server-bridge */
840
				if (stristr($conf, "server-bridge") === false) {
841
					$conf .= "username-as-common-name\n";
842
				}
843
				if (!empty($settings['authmode'])) {
844
					$strictusercn = "false";
845
					if ($settings['strictusercn']) {
846
						$strictusercn = "true";
847
					}
848
					$conf .= "auth-user-pass-verify \"/usr/local/sbin/ovpn_auth_verify user '{$settings['authmode']}' {$strictusercn} {$mode_id}\" via-env\n";
849
				}
850
				break;
851
		}
852
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls'))) {
853
			$settings['cert_depth'] = 1;
854
		}
855
		if (is_numeric($settings['cert_depth'])) {
856
			if (($mode == 'client') && empty($settings['certref'])) {
857
				$cert = "";
858
			} else {
859
				$cert = lookup_cert($settings['certref']);
860
				/* XXX: Seems not used at all! */
861
				$servercn = urlencode(cert_get_cn($cert['crt']));
862
				$conf .= "tls-verify \"/usr/local/sbin/ovpn_auth_verify tls '{$servercn}' {$settings['cert_depth']}\"\n";
863
			}
864
		}
865

    
866
		// The local port to listen on
867
		$conf .= "lport {$settings['local_port']}\n";
868

    
869
		// The management port to listen on
870
		// Use unix socket to overcome the problem on any type of server
871
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
872
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
873

    
874
		if ($settings['maxclients']) {
875
			$conf .= "max-clients {$settings['maxclients']}\n";
876
		}
877

    
878
		// Can we push routes
879
		if ($settings['local_network']) {
880
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
881
		}
882
		if ($settings['local_networkv6']) {
883
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
884
		}
885

    
886
		switch ($settings['mode']) {
887
			case 'server_tls':
888
			case 'server_user':
889
			case 'server_tls_user':
890
				// Configure client dhcp options
891
				openvpn_add_dhcpopts($settings, $conf);
892
				if ($settings['client2client']) {
893
					$conf .= "client-to-client\n";
894
				}
895
				break;
896
		}
897
		if (isset($settings['duplicate_cn'])) {
898
			$conf .= "duplicate-cn\n";
899
		}
900
	}
901

    
902
	// client specific settings
903

    
904
	if ($mode == 'client') {
905

    
906
		// configure p2p mode
907
		switch ($settings['mode']) {
908
			case 'p2p_tls':
909
				$conf .= "tls-client\n";
910
			case 'shared_key':
911
				$conf .= "client\n";
912
				break;
913
		}
914

    
915
		// If there is no bind option at all (ip and/or port), add "nobind" directive
916
		//  Otherwise, use the local port if defined, failing that, use lport 0 to
917
		//  ensure a random source port.
918
		if ((empty($iface_ip)) && (!$settings['local_port'])) {
919
			$conf .= "nobind\n";
920
		} elseif ($settings['local_port']) {
921
			$conf .= "lport {$settings['local_port']}\n";
922
		} else {
923
			$conf .= "lport 0\n";
924
		}
925

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

    
929
		// The remote server
930
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
931

    
932
		if (!empty($settings['use_shaper'])) {
933
			$conf .= "shaper {$settings['use_shaper']}\n";
934
		}
935

    
936
		if (!empty($settings['tunnel_network'])) {
937
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
938
			$mask = gen_subnet_mask($mask);
939
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
940
			if ($settings['dev_mode'] == 'tun') {
941
				$conf .= "ifconfig {$ip2} {$ip1}\n";
942
			} else {
943
				$conf .= "ifconfig {$ip2} {$mask}\n";
944
			}
945
		}
946

    
947
		if (!empty($settings['tunnel_networkv6'])) {
948
			list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
949
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
950
			if ($settings['dev_mode'] == 'tun') {
951
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
952
			} else {
953
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
954
			}
955
		}
956

    
957
		if ($settings['auth_user'] || $settings['auth_pass']) {
958
			$up_file = "{$g['varetc_path']}/openvpn/{$mode_id}.up";
959
			$conf .= "auth-user-pass {$up_file}\n";
960
			if ($settings['auth_user']) {
961
				$userpass = "{$settings['auth_user']}\n";
962
			} else {
963
				$userpass = "";
964
			}
965
			if ($settings['auth_pass']) {
966
				$userpass .= "{$settings['auth_pass']}\n";
967
			}
968
			// If only auth_pass is given, then it acts like a user name and we put a blank line where pass would normally go.
969
			if (!($settings['auth_user'] && $settings['auth_pass'])) {
970
				$userpass .= "\n";
971
			}
972
			file_put_contents($up_file, $userpass);
973
		}
974

    
975
		if ($settings['proxy_addr']) {
976
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
977
			if ($settings['proxy_authtype'] != "none") {
978
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
979
				$proxypas = "{$settings['proxy_user']}\n";
980
				$proxypas .= "{$settings['proxy_passwd']}\n";
981
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
982
			}
983
			$conf .= " \n";
984
		}
985
	}
986

    
987
	// Add a remote network route if set, and only for p2p modes.
988
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
989
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
990
	}
991
	// Add a remote network route if set, and only for p2p modes.
992
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
993
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
994
	}
995

    
996
	// Write the settings for the keys
997
	switch ($settings['mode']) {
998
		case 'p2p_shared_key':
999
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
1000
			break;
1001
		case 'p2p_tls':
1002
		case 'server_tls':
1003
		case 'server_tls_user':
1004
		case 'server_user':
1005
			$ca = lookup_ca($settings['caref']);
1006
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
1007

    
1008
			if (!empty($settings['certref'])) {
1009
				$cert = lookup_cert($settings['certref']);
1010
				openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
1011
				openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
1012
			}
1013
			if ($mode == 'server') {
1014
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
1015
			}
1016
			if (!empty($settings['crlref'])) {
1017
				$crl = lookup_crl($settings['crlref']);
1018
				crl_update($crl);
1019
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
1020
			}
1021
			if ($settings['tls']) {
1022
				if ($mode == "server") {
1023
					$tlsopt = 0;
1024
				} else {
1025
					$tlsopt = 1;
1026
				}
1027
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
1028
			}
1029
			break;
1030
	}
1031

    
1032
	if (!empty($settings['compression'])) {
1033
		$conf .= "comp-lzo {$settings['compression']}\n";
1034
	}
1035

    
1036
	if ($settings['passtos']) {
1037
		$conf .= "passtos\n";
1038
	}
1039

    
1040
	if ($settings['resolve_retry']) {
1041
		$conf .= "resolv-retry infinite\n";
1042
	} else if ($mode == 'clie} nt') {
1043
		$conf .= "resolv-retry infinite\n";
1044
	}
1045

    
1046
	if ($settings['dynamic_ip']) {
1047
		$conf .= "persist-remote-ip\n";
1048
		$conf .= "float\n";
1049
	}
1050

    
1051
	if (in_array($settings['mode'], $openvpn_tls_server_modes)) {
1052
		if (empty($settings['topology'])) {
1053
			$settings['topology'] = "subnet";
1054
		}
1055
		$conf .= "topology {$settings['topology']}\n";
1056
	}
1057

    
1058
	// New client features
1059
	if ($mode == "client") {
1060
		// Dont pull routes checkbox
1061
		if ($settings['route_no_pull']) {
1062
			$conf .= "route-nopull\n";
1063
		}
1064

    
1065
		// Dont add/remove routes checkbox
1066
		if ($settings['route_no_exec']) {
1067
			$conf .= "route-noexec\n";
1068
		}
1069
	}
1070

    
1071
	openvpn_add_custom($settings, $conf);
1072

    
1073
	openvpn_create_dirs();
1074
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
1075
	file_put_contents($fpath, $conf);
1076
	unset($conf);
1077
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
1078
	file_put_contents($fpath, $interface);
1079
	//chown($fpath, 'nobody');
1080
	//chgrp($fpath, 'nobody');
1081
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
1082
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
1083
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
1084
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
1085
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
1086
}
1087

    
1088
function openvpn_restart($mode, $settings) {
1089
	global $g, $config;
1090

    
1091
	$vpnid = $settings['vpnid'];
1092
	$mode_id = $mode.$vpnid;
1093

    
1094
	/* kill the process if running */
1095
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
1096
	if (file_exists($pfile)) {
1097

    
1098
		/* read the pid file */
1099
		$pid = rtrim(file_get_contents($pfile));
1100
		unlink($pfile);
1101

    
1102
		/* send a term signal to the process */
1103
		posix_kill($pid, SIGTERM);
1104

    
1105
		/* wait until the process exits, or timeout and kill it */
1106
		$i = 0;
1107
		while (posix_kill($pid, 0)) {
1108
			usleep(250000);
1109
			if ($i > 10) {
1110
				log_error("OpenVPN ID $mode_id PID $pid still running, killing.");
1111
				posix_kill($pid, SIGKILL);
1112
				usleep(500000);
1113
			}
1114
			$i++;
1115
		}
1116
	}
1117

    
1118
	if (isset($settings['disable'])) {
1119
		return;
1120
	}
1121

    
1122
	/* Do not start a client if we are a CARP backup on this vip! */
1123
	if (($mode == "client") && (strstr($settings['interface'], "_vip") && get_carp_interface_status($settings['interface']) != "MASTER")) {
1124
		return;
1125
	}
1126

    
1127
	/* Check if client is bound to a gateway group */
1128
	$a_groups = return_gateway_groups_array();
1129
	if (is_array($a_groups[$settings['interface']])) {
1130
		/* the interface is a gateway group. If a vip is defined and its a CARP backup then do not start */
1131
		if (($a_groups[$settings['interface']][0]['vip'] <> "") && (get_carp_interface_status($a_groups[$settings['interface']][0]['vip']) != "MASTER")) {
1132
			return;
1133
		}
1134
	}
1135

    
1136
	/* start the new process */
1137
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
1138
	openvpn_clear_route($mode, $settings);
1139
	mwexec_bg("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
1140

    
1141
	if (!platform_booting()) {
1142
		send_event("filter reload");
1143
	}
1144
}
1145

    
1146
function openvpn_delete($mode, & $settings) {
1147
	global $g, $config;
1148

    
1149
	$vpnid = $settings['vpnid'];
1150
	$mode_id = $mode.$vpnid;
1151

    
1152
	if (isset($settings['dev_mode'])) {
1153
		$tunname = "{$settings['dev_mode']}{$vpnid}";
1154
	} else {
1155
		/* defaults to tun */
1156
		$tunname = "tun{$vpnid}";
1157
	}
1158

    
1159
	if ($mode == "server") {
1160
		$devname = "ovpns{$vpnid}";
1161
	} else {
1162
		$devname = "ovpnc{$vpnid}";
1163
	}
1164

    
1165
	/* kill the process if running */
1166
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
1167
	if (file_exists($pfile)) {
1168

    
1169
		/* read the pid file */
1170
		$pid = trim(file_get_contents($pfile));
1171
		unlink($pfile);
1172

    
1173
		/* send a term signal to the process */
1174
		posix_kill($pid, SIGTERM);
1175
	}
1176

    
1177
	/* remove the device from the openvpn group */
1178
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
1179

    
1180
	/* restore the original adapter name */
1181
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
1182

    
1183
	/* remove the configuration files */
1184
	@array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
1185
}
1186

    
1187
function openvpn_resync_csc(& $settings) {
1188
	global $g, $config, $openvpn_tls_server_modes;
1189

    
1190
	$csc_base_path = "{$g['varetc_path']}/openvpn-csc";
1191

    
1192
	if (isset($settings['disable'])) {
1193
		openvpn_delete_csc($settings);
1194
		return;
1195
	}
1196
	openvpn_create_dirs();
1197

    
1198
	if (empty($settings['server_list'])) {
1199
		$csc_server_list = array();
1200
	} else {
1201
		$csc_server_list = explode(",", $settings['server_list']);
1202
	}
1203

    
1204
	$conf = '';
1205
	if ($settings['block']) {
1206
		$conf .= "disable\n";
1207
	}
1208

    
1209
	if ($settings['push_reset']) {
1210
		$conf .= "push-reset\n";
1211
	}
1212

    
1213
	if ($settings['local_network']) {
1214
		$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
1215
	}
1216
	if ($settings['local_networkv6']) {
1217
		$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
1218
	}
1219

    
1220
	// Add a remote network iroute if set
1221
	if (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE) {
1222
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false, true);
1223
	}
1224
	// Add a remote network iroute if set
1225
	if (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE) {
1226
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false, true);
1227
	}
1228

    
1229
	openvpn_add_dhcpopts($settings, $conf);
1230

    
1231
	if ($settings['gwredir']) {
1232
		$conf .= "push \"redirect-gateway def1\"\n";
1233
	}
1234

    
1235
	openvpn_add_custom($settings, $conf);
1236
	/* Loop through servers, find which ones can use this CSC */
1237
	if (is_array($config['openvpn']['openvpn-server'])) {
1238
		foreach ($config['openvpn']['openvpn-server'] as $serversettings) {
1239
			if (isset($serversettings['disable'])) {
1240
				continue;
1241
			}
1242
			if (in_array($serversettings['mode'], $openvpn_tls_server_modes)) {
1243
				if ($serversettings['vpnid'] && (empty($csc_server_list) || in_array($serversettings['vpnid'], $csc_server_list))) {
1244
					$csc_path = "{$csc_base_path}/server{$serversettings['vpnid']}/" . basename($settings['common_name']);
1245
					$csc_conf = $conf;
1246

    
1247
					if (!empty($serversettings['tunnel_network']) && !empty($settings['tunnel_network'])) {
1248
						list($ip, $mask) = explode('/', $settings['tunnel_network']);
1249
						if (($serversettings['dev_mode'] == 'tap') || ($serversettings['topology'] == "subnet")) {
1250
							$csc_conf .= "ifconfig-push {$ip} " . gen_subnet_mask($mask) . "\n";
1251
						} else {
1252
							/* Because this is being pushed, the order from the client's point of view. */
1253
							$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
1254
							$serverip = long2ip32($baselong + 1);
1255
							$clientip = long2ip32($baselong + 2);
1256
							$csc_conf .= "ifconfig-push {$clientip} {$serverip}\n";
1257
						}
1258
					}
1259
					file_put_contents($csc_path, $csc_conf);
1260
					chown($csc_path, 'nobody');
1261
					chgrp($csc_path, 'nobody');
1262
				}
1263
			}
1264
		}
1265
	}
1266
}
1267

    
1268
function openvpn_delete_csc(& $settings) {
1269
	global $g, $config, $openvpn_tls_server_modes;
1270
	$csc_base_path = "{$g['varetc_path']}/openvpn-csc";
1271
	if (empty($settings['server_list'])) {
1272
		$csc_server_list = array();
1273
	} else {
1274
		$csc_server_list = explode(",", $settings['server_list']);
1275
	}
1276

    
1277
	/* Loop through servers, find which ones used this CSC */
1278
	if (is_array($config['openvpn']['openvpn-server'])) {
1279
		foreach ($config['openvpn']['openvpn-server'] as $serversettings) {
1280
			if (isset($serversettings['disable'])) {
1281
				continue;
1282
			}
1283
			if (in_array($serversettings['mode'], $openvpn_tls_server_modes)) {
1284
				if ($serversettings['vpnid'] && (empty($csc_server_list) || in_array($serversettings['vpnid'], $csc_server_list))) {
1285
					$csc_path = "{$csc_base_path}/server{$serversettings['vpnid']}/" . basename($settings['common_name']);
1286
					unlink_if_exists($csc_path);
1287
				}
1288
			}
1289
		}
1290
	}
1291
}
1292

    
1293
// Resync the configuration and restart the VPN
1294
function openvpn_resync($mode, $settings) {
1295
	openvpn_reconfigure($mode, $settings);
1296
	openvpn_restart($mode, $settings);
1297
}
1298

    
1299
// Resync and restart all VPNs
1300
function openvpn_resync_all($interface = "") {
1301
	global $g, $config;
1302

    
1303
	openvpn_create_dirs();
1304

    
1305
	if (!is_array($config['openvpn'])) {
1306
		$config['openvpn'] = array();
1307
	}
1308

    
1309
/*
1310
	if (!$config['openvpn']['dh-parameters']) {
1311
		echo "Configuring OpenVPN Parameters ...\n";
1312
		$dh_parameters = openvpn_create_dhparams(1024);
1313
		$dh_parameters = base64_encode($dh_parameters);
1314
		$config['openvpn']['dh-parameters'] = $dh_parameters;
1315
		write_config("OpenVPN DH parameters");
1316
	}
1317

    
1318
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
1319
	if (!file_exists($path_ovdh)) {
1320
		$dh_parameters = $config['openvpn']['dh-parameters'];
1321
		$dh_parameters = base64_decode($dh_parameters);
1322
		file_put_contents($path_ovdh, $dh_parameters);
1323
	}
1324
*/
1325
	if ($interface <> "") {
1326
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
1327
	} else {
1328
		log_error("Resyncing OpenVPN instances.");
1329
	}
1330

    
1331
	if (is_array($config['openvpn']['openvpn-server'])) {
1332
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1333
			if ($interface <> "" && $interface != $settings['interface']) {
1334
				continue;
1335
			}
1336
			openvpn_resync('server', $settings);
1337
		}
1338
	}
1339

    
1340
	if (is_array($config['openvpn']['openvpn-client'])) {
1341
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1342
			if ($interface <> "" && $interface != $settings['interface']) {
1343
				continue;
1344
			}
1345
			openvpn_resync('client', $settings);
1346
		}
1347
	}
1348

    
1349
	if (is_array($config['openvpn']['openvpn-csc'])) {
1350
		foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
1351
			openvpn_resync_csc($settings);
1352
		}
1353
	}
1354

    
1355
}
1356

    
1357
// Resync and restart all VPNs using a gateway group.
1358
function openvpn_resync_gwgroup($gwgroupname = "") {
1359
	global $g, $config;
1360

    
1361
	if ($gwgroupname <> "") {
1362
		if (is_array($config['openvpn']['openvpn-server'])) {
1363
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1364
				if ($gwgroupname == $settings['interface']) {
1365
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " server " . $settings["description"] . ".");
1366
					openvpn_resync('server', $settings);
1367
				}
1368
			}
1369
		}
1370

    
1371
		if (is_array($config['openvpn']['openvpn-client'])) {
1372
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1373
				if ($gwgroupname == $settings['interface']) {
1374
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " client " . $settings["description"] . ".");
1375
					openvpn_resync('client', $settings);
1376
				}
1377
			}
1378
		}
1379

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

    
1382
	} else {
1383
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter.");
1384
	}
1385
}
1386

    
1387
function openvpn_get_active_servers($type="multipoint") {
1388
	global $config, $g;
1389

    
1390
	$servers = array();
1391
	if (is_array($config['openvpn']['openvpn-server'])) {
1392
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1393
			if (empty($settings) || isset($settings['disable'])) {
1394
				continue;
1395
			}
1396

    
1397
			$prot = $settings['protocol'];
1398
			$port = $settings['local_port'];
1399

    
1400
			$server = array();
1401
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
1402
			$server['mode'] = $settings['mode'];
1403
			if ($settings['description']) {
1404
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
1405
			} else {
1406
				$server['name'] = "Server {$prot}:{$port}";
1407
			}
1408
			$server['conns'] = array();
1409
			$server['vpnid'] = $settings['vpnid'];
1410
			$server['mgmt'] = "server{$server['vpnid']}";
1411
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
1412
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
1413

    
1414
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30)) && ($type == "p2p")) {
1415
				$servers[] = openvpn_get_client_status($server, $socket);
1416
			} elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30)) {
1417
				$servers[] = openvpn_get_server_status($server, $socket);
1418
			}
1419
		}
1420
	}
1421
	return $servers;
1422
}
1423

    
1424
function openvpn_get_server_status($server, $socket) {
1425
	$errval = null;
1426
	$errstr = null;
1427
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1428
	if ($fp) {
1429
		stream_set_timeout($fp, 1);
1430

    
1431
		/* send our status request */
1432
		fputs($fp, "status 2\n");
1433

    
1434
		/* recv all response lines */
1435
		while (!feof($fp)) {
1436

    
1437
			/* read the next line */
1438
			$line = fgets($fp, 1024);
1439

    
1440
			$info = stream_get_meta_data($fp);
1441
			if ($info['timed_out']) {
1442
				break;
1443
			}
1444

    
1445
			/* parse header list line */
1446
			if (strstr($line, "HEADER")) {
1447
				continue;
1448
			}
1449

    
1450
			/* parse end of output line */
1451
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1452
				break;
1453
			}
1454

    
1455
			/* parse client list line */
1456
			if (strstr($line, "CLIENT_LIST")) {
1457
				$list = explode(",", $line);
1458
				$conn = array();
1459
				$conn['common_name'] = $list[1];
1460
				$conn['remote_host'] = $list[2];
1461
				$conn['virtual_addr'] = $list[3];
1462
				$conn['bytes_recv'] = $list[4];
1463
				$conn['bytes_sent'] = $list[5];
1464
				$conn['connect_time'] = $list[6];
1465
				$server['conns'][] = $conn;
1466
			}
1467
			/* parse routing table lines */
1468
			if (strstr($line, "ROUTING_TABLE")) {
1469
				$list = explode(",", $line);
1470
				$conn = array();
1471
				$conn['virtual_addr'] = $list[1];
1472
				$conn['common_name'] = $list[2];
1473
				$conn['remote_host'] = $list[3];
1474
				$conn['last_time'] = $list[4];
1475
				$server['routes'][] = $conn;
1476
			}
1477
		}
1478

    
1479
		/* cleanup */
1480
		fclose($fp);
1481
	} else {
1482
		$conn = array();
1483
		$conn['common_name'] = "[error]";
1484
		$conn['remote_host'] = "Unable to contact daemon";
1485
		$conn['virtual_addr'] = "Service not running?";
1486
		$conn['bytes_recv'] = 0;
1487
		$conn['bytes_sent'] = 0;
1488
		$conn['connect_time'] = 0;
1489
		$server['conns'][] = $conn;
1490
	}
1491
	return $server;
1492
}
1493

    
1494
function openvpn_get_active_clients() {
1495
	global $config, $g;
1496

    
1497
	$clients = array();
1498
	if (is_array($config['openvpn']['openvpn-client'])) {
1499
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1500

    
1501
			if (empty($settings) || isset($settings['disable'])) {
1502
				continue;
1503
			}
1504

    
1505
			$prot = $settings['protocol'];
1506
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1507

    
1508
			$client = array();
1509
			$client['port'] = $settings['local_port'];
1510
			if ($settings['description']) {
1511
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1512
			} else {
1513
				$client['name'] = "Client {$prot}{$port}";
1514
			}
1515

    
1516
			$client['vpnid'] = $settings['vpnid'];
1517
			$client['mgmt'] = "client{$client['vpnid']}";
1518
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1519
			$client['status']="down";
1520

    
1521
			$clients[] = openvpn_get_client_status($client, $socket);
1522
		}
1523
	}
1524
	return $clients;
1525
}
1526

    
1527
function openvpn_get_client_status($client, $socket) {
1528
	$errval = null;
1529
	$errstr = null;
1530
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1531
	if ($fp) {
1532
		stream_set_timeout($fp, 1);
1533
		/* send our status request */
1534
		fputs($fp, "state 1\n");
1535

    
1536
		/* recv all response lines */
1537
		while (!feof($fp)) {
1538
			/* read the next line */
1539
			$line = fgets($fp, 1024);
1540

    
1541
			$info = stream_get_meta_data($fp);
1542
			if ($info['timed_out']) {
1543
				break;
1544
			}
1545

    
1546
			/* Get the client state */
1547
			if (strstr($line, "CONNECTED")) {
1548
				$client['status'] = "up";
1549
				$list = explode(",", $line);
1550

    
1551
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1552
				$client['virtual_addr'] = $list[3];
1553
				$client['remote_host'] = $list[4];
1554
			}
1555
			if (strstr($line, "CONNECTING")) {
1556
				$client['status'] = "connecting";
1557
			}
1558
			if (strstr($line, "ASSIGN_IP")) {
1559
				$client['status'] = "waiting";
1560
				$list = explode(",", $line);
1561

    
1562
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1563
				$client['virtual_addr'] = $list[3];
1564
			}
1565
			if (strstr($line, "RECONNECTING")) {
1566
				$client['status'] = "reconnecting";
1567
				$list = explode(",", $line);
1568

    
1569
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1570
				$client['status'] .= "; " . $list[2];
1571
			}
1572
			/* parse end of output line */
1573
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1574
				break;
1575
			}
1576
		}
1577

    
1578
		/* If up, get read/write stats */
1579
		if (strcmp($client['status'], "up") == 0) {
1580
			fputs($fp, "status 2\n");
1581
			/* recv all response lines */
1582
			while (!feof($fp)) {
1583
				/* read the next line */
1584
				$line = fgets($fp, 1024);
1585

    
1586
				$info = stream_get_meta_data($fp);
1587
				if ($info['timed_out']) {
1588
					break;
1589
				}
1590

    
1591
				if (strstr($line, "TCP/UDP read bytes")) {
1592
					$list = explode(",", $line);
1593
					$client['bytes_recv'] = $list[1];
1594
				}
1595

    
1596
				if (strstr($line, "TCP/UDP write bytes")) {
1597
					$list = explode(",", $line);
1598
					$client['bytes_sent'] = $list[1];
1599
				}
1600

    
1601
				/* parse end of output line */
1602
				if (strstr($line, "END")) {
1603
					break;
1604
				}
1605
			}
1606
		}
1607

    
1608
		fclose($fp);
1609

    
1610
	} else {
1611
		$DisplayNote=true;
1612
		$client['remote_host'] = "Unable to contact daemon";
1613
		$client['virtual_addr'] = "Service not running?";
1614
		$client['bytes_recv'] = 0;
1615
		$client['bytes_sent'] = 0;
1616
		$client['connect_time'] = 0;
1617
	}
1618
	return $client;
1619
}
1620

    
1621
function openvpn_refresh_crls() {
1622
	global $g, $config;
1623

    
1624
	openvpn_create_dirs();
1625

    
1626
	if (is_array($config['openvpn']['openvpn-server'])) {
1627
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1628
			if (empty($settings)) {
1629
				continue;
1630
			}
1631
			if (isset($settings['disable'])) {
1632
				continue;
1633
			}
1634
			// Write the settings for the keys
1635
			switch ($settings['mode']) {
1636
				case 'p2p_tls':
1637
				case 'server_tls':
1638
				case 'server_tls_user':
1639
				case 'server_user':
1640
					if (!empty($settings['crlref'])) {
1641
						$crl = lookup_crl($settings['crlref']);
1642
						crl_update($crl);
1643
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1644
						file_put_contents($fpath, base64_decode($crl['text']));
1645
						@chmod($fpath, 0644);
1646
					}
1647
					break;
1648
			}
1649
		}
1650
	}
1651
}
1652

    
1653
function openvpn_create_dirs() {
1654
	global $g, $config, $openvpn_tls_server_modes;
1655
	if (!is_dir("{$g['varetc_path']}/openvpn")) {
1656
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1657
	}
1658
	if (!is_dir("{$g['varetc_path']}/openvpn-csc")) {
1659
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1660
	}
1661

    
1662
	/* Check for enabled servers and create server-specific CSC dirs */
1663
	if (is_array($config['openvpn']['openvpn-server'])) {
1664
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1665
			if (isset($settings['disable'])) {
1666
				continue;
1667
			}
1668
			if (in_array($settings['mode'], $openvpn_tls_server_modes)) {
1669
				if ($settings['vpnid']) {
1670
					safe_mkdir("{$g['varetc_path']}/openvpn-csc/server{$settings['vpnid']}");
1671
				}
1672
			}
1673
		}
1674
	}
1675
}
1676

    
1677
function openvpn_get_interface_ip($ip, $mask) {
1678
	$baselong = ip2long32($ip) & ip2long($mask);
1679
	$ip1 = long2ip32($baselong + 1);
1680
	$ip2 = long2ip32($baselong + 2);
1681
	return array($ip1, $ip2);
1682
}
1683

    
1684
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1685
	$basev6 = gen_subnetv6($ipv6, $prefix);
1686
	// Is there a better way to do this math?
1687
	$ipv6_arr = explode(':', $basev6);
1688
	$last = hexdec(array_pop($ipv6_arr));
1689
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1690
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1691
	return array($ipv6_1, $ipv6_2);
1692
}
1693

    
1694
function openvpn_clear_route($mode, $settings) {
1695
	if (empty($settings['tunnel_network'])) {
1696
		return;
1697
	}
1698
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1699
	$mask = gen_subnet_mask($cidr);
1700
	$clear_route = false;
1701

    
1702
	switch ($settings['mode']) {
1703
		case 'shared_key':
1704
			$clear_route = true;
1705
			break;
1706
		case 'p2p_tls':
1707
		case 'p2p_shared_key':
1708
			if ($cidr == 30) {
1709
				$clear_route = true;
1710
			}
1711
			break;
1712
	}
1713

    
1714
	if ($clear_route && !empty($ip) && !empty($mask)) {
1715
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1716
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1717
		/* XXX: Family for route? */
1718
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1719
	}
1720
}
1721

    
1722
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
1723
	$routes = "";
1724
	if (empty($value)) {
1725
		return "";
1726
	}
1727
	$networks = explode(',', $value);
1728

    
1729
	foreach ($networks as $network) {
1730
		if ($ipproto == "ipv4") {
1731
			$route = openvpn_gen_route_ipv4($network, $iroute);
1732
		} else {
1733
			$route = openvpn_gen_route_ipv6($network, $iroute);
1734
		}
1735

    
1736
		if ($push) {
1737
			$routes .= "push \"{$route}\"\n";
1738
		} else {
1739
			$routes .= "{$route}\n";
1740
		}
1741
	}
1742
	return $routes;
1743
}
1744

    
1745
function openvpn_gen_route_ipv4($network, $iroute = false) {
1746
	$i = ($iroute) ? "i" : "";
1747
	list($ip, $mask) = explode('/', trim($network));
1748
	$mask = gen_subnet_mask($mask);
1749
	return "{$i}route $ip $mask";
1750
}
1751

    
1752
function openvpn_gen_route_ipv6($network, $iroute = false) {
1753
	$i = ($iroute) ? "i" : "";
1754
	list($ipv6, $prefix) = explode('/', trim($network));
1755
	if (empty($prefix)) {
1756
		$prefix = "128";
1757
	}
1758
	return "{$i}route-ipv6 ${ipv6}/${prefix}";
1759
}
1760

    
1761
function openvpn_get_settings($mode, $vpnid) {
1762
	global $config;
1763

    
1764
	if (is_array($config['openvpn']['openvpn-server'])) {
1765
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1766
			if (isset($settings['disable'])) {
1767
				continue;
1768
			}
1769

    
1770
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1771
				return $settings;
1772
			}
1773
		}
1774
	}
1775

    
1776
	if (is_array($config['openvpn']['openvpn-client'])) {
1777
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1778
			if (isset($settings['disable'])) {
1779
				continue;
1780
			}
1781

    
1782
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1783
				return $settings;
1784
			}
1785
		}
1786
	}
1787

    
1788
	return array();
1789
}
1790

    
1791
function openvpn_restart_by_vpnid($mode, $vpnid) {
1792
	$settings = openvpn_get_settings($mode, $vpnid);
1793
	openvpn_restart($mode, $settings);
1794
}
1795

    
1796
?>
(37-37/65)