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
	$non_server_list = array();
212

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

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

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

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

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

    
254
	return(array('server' => $list, 'non-server' => $non_server_list));
255
}
256

    
257
function openvpn_build_bridge_list() {
258
	$list = array();
259

    
260
	$serverbridge_interface['none'] = "none";
261
	$serverbridge_interface = array_merge($serverbridge_interface, get_configured_interface_with_descr());
262
	$carplist = get_configured_carp_interface_list();
263

    
264
	foreach ($carplist as $cif => $carpip) {
265
		$serverbridge_interface[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")";
266
	}
267

    
268
	$aliaslist = get_configured_ip_aliases_list();
269

    
270
	foreach ($aliaslist as $aliasip => $aliasif) {
271
		$serverbridge_interface[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
272
	}
273

    
274
	foreach ($serverbridge_interface as $iface => $ifacename) {
275
		$list[$iface] = htmlspecialchars($ifacename);
276
	}
277

    
278
	return($list);
279
}
280

    
281
function openvpn_create_key() {
282

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

    
288
	$rslt = stream_get_contents($fp);
289
	pclose($fp);
290

    
291
	return $rslt;
292
}
293

    
294
function openvpn_create_dhparams($bits) {
295

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

    
301
	$rslt = stream_get_contents($fp);
302
	pclose($fp);
303

    
304
	return $rslt;
305
}
306

    
307
function openvpn_vpnid_used($vpnid) {
308
	global $config;
309

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

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

    
326
	return false;
327
}
328

    
329
function openvpn_vpnid_next() {
330

    
331
	$vpnid = 1;
332
	while (openvpn_vpnid_used($vpnid)) {
333
		$vpnid++;
334
	}
335

    
336
	return $vpnid;
337
}
338

    
339
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
340
	global $config;
341

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

    
348
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
349
				continue;
350
			}
351

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

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

    
365
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
366
				continue;
367
			}
368

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

    
376
	return 0;
377
}
378

    
379
function openvpn_port_next($prot, $interface = "wan") {
380

    
381
	$port = 1194;
382
	while (openvpn_port_used($prot, $interface, $port)) {
383
		$port++;
384
	}
385
	while (openvpn_port_used($prot, "any", $port)) {
386
		$port++;
387
	}
388

    
389
	return $port;
390
}
391

    
392
function openvpn_get_cipherlist() {
393

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

    
406
function openvpn_get_digestlist() {
407

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

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

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

    
457
function openvpn_validate_engine($engine) {
458
	$engines = openvpn_get_engines();
459
	return array_key_exists($engine, $engines);
460
}
461

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

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

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

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

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

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

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

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

    
533
function openvpn_add_dhcpopts(& $settings, & $conf) {
534

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

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

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

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

    
563
	if ($settings['netbios_enable']) {
564

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

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

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

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

    
589
function openvpn_add_custom(& $settings, & $conf) {
590

    
591
	if ($settings['custom_options']) {
592

    
593
		$options = explode(';', $settings['custom_options']);
594

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

    
605
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
606
	global $g;
607

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

    
615
	$conf .= "{$directive} {$fpath} {$opt}\n";
616
}
617

    
618
function openvpn_reconfigure($mode, $settings) {
619
	global $g, $config, $openvpn_tls_server_modes;
620

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

    
634
	$vpnid = $settings['vpnid'];
635
	$mode_id = $mode.$vpnid;
636

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

    
645
	if ($mode == "server") {
646
		$devname = "ovpns{$vpnid}";
647
	} else {
648
		$devname = "ovpnc{$vpnid}";
649
	}
650

    
651
	/* is our device already configured */
652
	if (!does_interface_exist($devname)) {
653

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

    
659
		/* rename the device */
660
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
661

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

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

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

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

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

    
705

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

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

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

    
751
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
752
		$conf .= "engine {$settings['engine']}\n";
753
	}
754

    
755
	// server specific settings
756
	if ($mode == 'server') {
757

    
758
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
759
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
760
		$mask = gen_subnet_mask($cidr);
761

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

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

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

    
863
		// The local port to listen on
864
		$conf .= "lport {$settings['local_port']}\n";
865

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

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

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

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

    
899
	// client specific settings
900

    
901
	if ($mode == 'client') {
902

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

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

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

    
926
		// The remote server
927
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
928

    
929
		if (!empty($settings['use_shaper'])) {
930
			$conf .= "shaper {$settings['use_shaper']}\n";
931
		}
932

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

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

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

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

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

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

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

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

    
1033
	if ($settings['passtos']) {
1034
		$conf .= "passtos\n";
1035
	}
1036

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

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

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

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

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

    
1068
	openvpn_add_custom($settings, $conf);
1069

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

    
1085
function openvpn_restart($mode, $settings) {
1086
	global $g, $config;
1087

    
1088
	$vpnid = $settings['vpnid'];
1089
	$mode_id = $mode.$vpnid;
1090

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

    
1095
		/* read the pid file */
1096
		$pid = rtrim(file_get_contents($pfile));
1097
		unlink($pfile);
1098

    
1099
		/* send a term signal to the process */
1100
		posix_kill($pid, SIGTERM);
1101

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

    
1115
	if (isset($settings['disable'])) {
1116
		return;
1117
	}
1118

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

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

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

    
1138
	if (!platform_booting()) {
1139
		send_event("filter reload");
1140
	}
1141
}
1142

    
1143
function openvpn_delete($mode, & $settings) {
1144
	global $g, $config;
1145

    
1146
	$vpnid = $settings['vpnid'];
1147
	$mode_id = $mode.$vpnid;
1148

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

    
1156
	if ($mode == "server") {
1157
		$devname = "ovpns{$vpnid}";
1158
	} else {
1159
		$devname = "ovpnc{$vpnid}";
1160
	}
1161

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

    
1166
		/* read the pid file */
1167
		$pid = trim(file_get_contents($pfile));
1168
		unlink($pfile);
1169

    
1170
		/* send a term signal to the process */
1171
		posix_kill($pid, SIGTERM);
1172
	}
1173

    
1174
	/* remove the device from the openvpn group */
1175
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
1176

    
1177
	/* restore the original adapter name */
1178
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
1179

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

    
1184
function openvpn_resync_csc(& $settings) {
1185
	global $g, $config, $openvpn_tls_server_modes;
1186

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

    
1189
	if (isset($settings['disable'])) {
1190
		openvpn_delete_csc($settings);
1191
		return;
1192
	}
1193
	openvpn_create_dirs();
1194

    
1195
	if (empty($settings['server_list'])) {
1196
		$csc_server_list = array();
1197
	} else {
1198
		$csc_server_list = explode(",", $settings['server_list']);
1199
	}
1200

    
1201
	$conf = '';
1202
	if ($settings['block']) {
1203
		$conf .= "disable\n";
1204
	}
1205

    
1206
	if ($settings['push_reset']) {
1207
		$conf .= "push-reset\n";
1208
	}
1209

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

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

    
1226
	openvpn_add_dhcpopts($settings, $conf);
1227

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

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

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

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

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

    
1290
// Resync the configuration and restart the VPN
1291
function openvpn_resync($mode, $settings) {
1292
	openvpn_reconfigure($mode, $settings);
1293
	openvpn_restart($mode, $settings);
1294
}
1295

    
1296
// Resync and restart all VPNs
1297
function openvpn_resync_all($interface = "") {
1298
	global $g, $config;
1299

    
1300
	openvpn_create_dirs();
1301

    
1302
	if (!is_array($config['openvpn'])) {
1303
		$config['openvpn'] = array();
1304
	}
1305

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

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

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

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

    
1346
	if (is_array($config['openvpn']['openvpn-csc'])) {
1347
		foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
1348
			openvpn_resync_csc($settings);
1349
		}
1350
	}
1351

    
1352
}
1353

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

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

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

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

    
1379
	} else {
1380
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter.");
1381
	}
1382
}
1383

    
1384
function openvpn_get_active_servers($type="multipoint") {
1385
	global $config, $g;
1386

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

    
1394
			$prot = $settings['protocol'];
1395
			$port = $settings['local_port'];
1396

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

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

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

    
1428
		/* send our status request */
1429
		fputs($fp, "status 2\n");
1430

    
1431
		/* recv all response lines */
1432
		while (!feof($fp)) {
1433

    
1434
			/* read the next line */
1435
			$line = fgets($fp, 1024);
1436

    
1437
			$info = stream_get_meta_data($fp);
1438
			if ($info['timed_out']) {
1439
				break;
1440
			}
1441

    
1442
			/* parse header list line */
1443
			if (strstr($line, "HEADER")) {
1444
				continue;
1445
			}
1446

    
1447
			/* parse end of output line */
1448
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1449
				break;
1450
			}
1451

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

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

    
1491
function openvpn_get_active_clients() {
1492
	global $config, $g;
1493

    
1494
	$clients = array();
1495
	if (is_array($config['openvpn']['openvpn-client'])) {
1496
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1497

    
1498
			if (empty($settings) || isset($settings['disable'])) {
1499
				continue;
1500
			}
1501

    
1502
			$prot = $settings['protocol'];
1503
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1504

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

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

    
1518
			$clients[] = openvpn_get_client_status($client, $socket);
1519
		}
1520
	}
1521
	return $clients;
1522
}
1523

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

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

    
1538
			$info = stream_get_meta_data($fp);
1539
			if ($info['timed_out']) {
1540
				break;
1541
			}
1542

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

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

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

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

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

    
1583
				$info = stream_get_meta_data($fp);
1584
				if ($info['timed_out']) {
1585
					break;
1586
				}
1587

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

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

    
1598
				/* parse end of output line */
1599
				if (strstr($line, "END")) {
1600
					break;
1601
				}
1602
			}
1603
		}
1604

    
1605
		fclose($fp);
1606

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

    
1618
function openvpn_refresh_crls() {
1619
	global $g, $config;
1620

    
1621
	openvpn_create_dirs();
1622

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

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

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

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

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

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

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

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

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

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

    
1733
		if ($push) {
1734
			$routes .= "push \"{$route}\"\n";
1735
		} else {
1736
			$routes .= "{$route}\n";
1737
		}
1738
	}
1739
	return $routes;
1740
}
1741

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

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

    
1758
function openvpn_get_settings($mode, $vpnid) {
1759
	global $config;
1760

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

    
1767
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1768
				return $settings;
1769
			}
1770
		}
1771
	}
1772

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

    
1779
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1780
				return $settings;
1781
			}
1782
		}
1783
	}
1784

    
1785
	return array();
1786
}
1787

    
1788
function openvpn_restart_by_vpnid($mode, $vpnid) {
1789
	$settings = openvpn_get_settings($mode, $vpnid);
1790
	openvpn_restart($mode, $settings);
1791
}
1792

    
1793
?>
(37-37/65)