Project

General

Profile

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

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

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

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

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

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

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

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

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

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

    
42
require_once('config.inc');
43
require_once("certs.inc");
44
require_once('pfsense-utils.inc');
45
require_once("auth.inc");
46

    
47
global $openvpn_prots;
48
$openvpn_prots = array("UDP", "UDP6", "TCP", "TCP6");
49

    
50
global $openvpn_dev_mode;
51
$openvpn_dev_mode = array("tun", "tap");
52

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

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

    
82
global $openvpn_dh_lengths;
83
$openvpn_dh_lengths = array(
84
	1024, 2048, 4096);
85

    
86
global $openvpn_cert_depths;
87
$openvpn_cert_depths = array(
88
	1 => "One (Client+Server)",
89
	2 => "Two (Client+Intermediate+Server)",
90
	3 => "Three (Client+2xIntermediate+Server)",
91
	4 => "Four (Client+3xIntermediate+Server)",
92
	5 => "Five (Client+4xIntermediate+Server)"
93
);
94

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

    
103
global $openvpn_tls_server_modes;
104
$openvpn_tls_server_modes = array('p2p_tls', 'server_tls', 'server_user', 'server_tls_user');
105

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

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

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

    
125
function openvpn_build_mode_list() {
126
	global $openvpn_server_modes;
127

    
128
	$list = array();
129

    
130
	foreach ($openvpn_server_modes as $name => $desc) {
131
		$list[$name] = $desc;
132
	}
133

    
134
	return($list);
135
}
136

    
137
function openvpn_build_if_list() {
138
	$list = array();
139

    
140
	$interfaces = get_configured_interface_with_descr();
141
	$carplist = get_configured_carp_interface_list();
142

    
143
	foreach ($carplist as $cif => $carpip) {
144
		$interfaces[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")";
145
	}
146

    
147
	$aliaslist = get_configured_ip_aliases_list();
148

    
149
	foreach ($aliaslist as $aliasip => $aliasif) {
150
		$interfaces[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
151
	}
152

    
153
	$grouplist = return_gateway_groups_array();
154

    
155
	foreach ($grouplist as $name => $group) {
156
		if ($group['ipprotocol'] != inet) {
157
			continue;
158
		}
159

    
160
		if ($group[0]['vip'] != "") {
161
			$vipif = $group[0]['vip'];
162
		} else {
163
			$vipif = $group[0]['int'];
164
		}
165

    
166
		$interfaces[$name] = "GW Group {$name}";
167
	}
168

    
169
	$interfaces['lo0'] = "Localhost";
170
	$interfaces['any'] = "any";
171

    
172
	foreach ($interfaces as $iface => $ifacename) {
173
	   $list[$iface] = $ifacename;
174
	}
175

    
176
	return($list);
177
}
178

    
179
function openvpn_build_crl_list() {
180
	global $a_crl;
181

    
182
	$list = array('' => 'None');
183

    
184
	foreach ($a_crl as $crl) {
185
		$caname = "";
186
		$ca = lookup_ca($crl['caref']);
187

    
188
		if ($ca) {
189
			$caname = " (CA: {$ca['descr']})";
190
		}
191

    
192
		$list[$crl['refid']] = $crl['descr'] . $caname;
193
	}
194

    
195
	return($list);
196
}
197

    
198
function openvpn_build_cert_list($include_none = false, $prioritize_server_certs = false) {
199
	global $a_cert;
200

    
201
	if ($include_none) {
202
		$list = array('' => 'None (Username and/or Password required)');
203
	} else {
204
		$list = array();
205
	}
206

    
207
	$non_server_list = array();
208

    
209
	if ($prioritize_server_certs) {
210
		$list[' '] = "===== Server Certificates =====";
211
		$non_server_list['  '] = "===== Non-Server Certificates =====";
212
	}
213

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

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

    
235
		if (!empty($properties)) {
236
			$propstr = " (" . implode(", ", $properties) . ")";
237
		}
238

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

    
250
	return(array('server' => $list, 'non-server' => $non_server_list));
251
}
252

    
253
function openvpn_build_bridge_list() {
254
	$list = array();
255

    
256
	$serverbridge_interface['none'] = "none";
257
	$serverbridge_interface = array_merge($serverbridge_interface, get_configured_interface_with_descr());
258
	$carplist = get_configured_carp_interface_list();
259

    
260
	foreach ($carplist as $cif => $carpip) {
261
		$serverbridge_interface[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")";
262
	}
263

    
264
	$aliaslist = get_configured_ip_aliases_list();
265

    
266
	foreach ($aliaslist as $aliasip => $aliasif) {
267
		$serverbridge_interface[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
268
	}
269

    
270
	foreach ($serverbridge_interface as $iface => $ifacename) {
271
		$list[$iface] = htmlspecialchars($ifacename);
272
	}
273

    
274
	return($list);
275
}
276

    
277
function openvpn_create_key() {
278

    
279
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
280
	if (!$fp) {
281
		return false;
282
	}
283

    
284
	$rslt = stream_get_contents($fp);
285
	pclose($fp);
286

    
287
	return $rslt;
288
}
289

    
290
function openvpn_create_dhparams($bits) {
291

    
292
	$fp = popen("/usr/bin/openssl dhparam {$bits} 2>/dev/null", "r");
293
	if (!$fp) {
294
		return false;
295
	}
296

    
297
	$rslt = stream_get_contents($fp);
298
	pclose($fp);
299

    
300
	return $rslt;
301
}
302

    
303
function openvpn_vpnid_used($vpnid) {
304
	global $config;
305

    
306
	if (is_array($config['openvpn']['openvpn-server'])) {
307
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
308
			if ($vpnid == $settings['vpnid']) {
309
				return true;
310
			}
311
		}
312
	}
313

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

    
322
	return false;
323
}
324

    
325
function openvpn_vpnid_next() {
326

    
327
	$vpnid = 1;
328
	while (openvpn_vpnid_used($vpnid)) {
329
		$vpnid++;
330
	}
331

    
332
	return $vpnid;
333
}
334

    
335
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
336
	global $config;
337

    
338
	if (is_array($config['openvpn']['openvpn-server'])) {
339
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
340
			if (isset($settings['disable'])) {
341
				continue;
342
			}
343

    
344
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
345
				continue;
346
			}
347

    
348
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
349
			    ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
350
				return $settings['vpnid'];
351
			}
352
		}
353
	}
354

    
355
	if (is_array($config['openvpn']['openvpn-client'])) {
356
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
357
			if (isset($settings['disable'])) {
358
				continue;
359
			}
360

    
361
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
362
				continue;
363
			}
364

    
365
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
366
			    ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
367
				return $settings['vpnid'];
368
			}
369
		}
370
	}
371

    
372
	return 0;
373
}
374

    
375
function openvpn_port_next($prot, $interface = "wan") {
376

    
377
	$port = 1194;
378
	while (openvpn_port_used($prot, $interface, $port)) {
379
		$port++;
380
	}
381
	while (openvpn_port_used($prot, "any", $port)) {
382
		$port++;
383
	}
384

    
385
	return $port;
386
}
387

    
388
function openvpn_get_cipherlist() {
389

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

    
402
function openvpn_get_digestlist() {
403

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

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

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

    
453
function openvpn_validate_engine($engine) {
454
	$engines = openvpn_get_engines();
455
	return array_key_exists($engine, $engines);
456
}
457

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

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

    
474
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
475
	$value = trim($value);
476
	$error = false;
477
	if (empty($value)) {
478
		return false;
479
	}
480
	$networks = explode(',', $value);
481

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

    
486
	foreach ($networks as $network) {
487
		if ($ipproto == "ipv4") {
488
			$error = !openvpn_validate_cidr_ipv4($network);
489
		} else {
490
			$error = !openvpn_validate_cidr_ipv6($network);
491
		}
492
		if ($error) {
493
			break;
494
		}
495
	}
496

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

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

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

    
529
function openvpn_add_dhcpopts(& $settings, & $conf) {
530

    
531
	if (!empty($settings['dns_domain'])) {
532
		$conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
533
	}
534

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

    
548
	if (!empty($settings['push_register_dns'])) {
549
		$conf .= "push \"register-dns\"\n";
550
	}
551

    
552
	if (!empty($settings['ntp_server1'])) {
553
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
554
	}
555
	if (!empty($settings['ntp_server2'])) {
556
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
557
	}
558

    
559
	if ($settings['netbios_enable']) {
560

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

    
568
		if (!empty($settings['wins_server1'])) {
569
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
570
		}
571
		if (!empty($settings['wins_server2'])) {
572
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
573
		}
574

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

    
580
	if ($settings['gwredir']) {
581
		$conf .= "push \"redirect-gateway def1\"\n";
582
	}
583
}
584

    
585
function openvpn_add_custom(& $settings, & $conf) {
586

    
587
	if ($settings['custom_options']) {
588

    
589
		$options = explode(';', $settings['custom_options']);
590

    
591
		if (is_array($options)) {
592
			foreach ($options as $option) {
593
				$conf .= "$option\n";
594
			}
595
		} else {
596
			$conf .= "{$settings['custom_options']}\n";
597
		}
598
	}
599
}
600

    
601
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
602
	global $g;
603

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

    
611
	$conf .= "{$directive} {$fpath} {$opt}\n";
612
}
613

    
614
function openvpn_reconfigure($mode, $settings) {
615
	global $g, $config, $openvpn_tls_server_modes;
616

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

    
630
	$vpnid = $settings['vpnid'];
631
	$mode_id = $mode.$vpnid;
632

    
633
	if (isset($settings['dev_mode'])) {
634
		$tunname = "{$settings['dev_mode']}{$vpnid}";
635
	} else {
636
		/* defaults to tun */
637
		$tunname = "tun{$vpnid}";
638
		$settings['dev_mode'] = "tun";
639
	}
640

    
641
	if ($mode == "server") {
642
		$devname = "ovpns{$vpnid}";
643
	} else {
644
		$devname = "ovpnc{$vpnid}";
645
	}
646

    
647
	/* is our device already configured */
648
	if (!does_interface_exist($devname)) {
649

    
650
		/* create the tap device if required */
651
		if (!file_exists("/dev/{$tunname}")) {
652
			exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
653
		}
654

    
655
		/* rename the device */
656
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
657

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

    
661
		$ifname = convert_real_interface_to_friendly_interface_name($devname);
662
		$grouptmp = link_interface_to_group($ifname);
663
		if (!empty($grouptmp)) {
664
			array_walk($grouptmp, 'interface_group_add_member');
665
		}
666
		unset($grouptmp, $ifname);
667
	}
668

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

    
679
	$interface = get_failover_interface($settings['interface']);
680
	// The IP address in the settings can be an IPv4 or IPv6 address associated with the interface
681
	$ipaddr = $settings['ipaddr'];
682

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

    
701

    
702
	$conf = "dev {$devname}\n";
703
	if (isset($settings['verbosity_level'])) {
704
		$conf .= "verb {$settings['verbosity_level']}\n";
705
	}
706

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

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

    
747
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
748
		$conf .= "engine {$settings['engine']}\n";
749
	}
750

    
751
	// server specific settings
752
	if ($mode == 'server') {
753

    
754
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
755
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
756
		$mask = gen_subnet_mask($cidr);
757

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

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

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

    
859
		// The local port to listen on
860
		$conf .= "lport {$settings['local_port']}\n";
861

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

    
867
		if ($settings['maxclients']) {
868
			$conf .= "max-clients {$settings['maxclients']}\n";
869
		}
870

    
871
		// Can we push routes
872
		if ($settings['local_network']) {
873
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
874
		}
875
		if ($settings['local_networkv6']) {
876
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
877
		}
878

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

    
895
	// client specific settings
896

    
897
	if ($mode == 'client') {
898

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

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

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

    
922
		// The remote server
923
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
924

    
925
		if (!empty($settings['use_shaper'])) {
926
			$conf .= "shaper {$settings['use_shaper']}\n";
927
		}
928

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

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

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

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

    
980
	// Add a remote network route if set, and only for p2p modes.
981
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
982
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
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_networkv6'], "", true, "ipv6") === FALSE)) {
986
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
987
	}
988

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

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

    
1025
	if (!empty($settings['compression'])) {
1026
		$conf .= "comp-lzo {$settings['compression']}\n";
1027
	}
1028

    
1029
	if ($settings['passtos']) {
1030
		$conf .= "passtos\n";
1031
	}
1032

    
1033
	if ($settings['resolve_retry']) {
1034
		$conf .= "resolv-retry infinite\n";
1035
	} else if ($mode == 'clie} nt') {
1036
		$conf .= "resolv-retry infinite\n";
1037
	}
1038

    
1039
	if ($settings['dynamic_ip']) {
1040
		$conf .= "persist-remote-ip\n";
1041
		$conf .= "float\n";
1042
	}
1043

    
1044
	if (in_array($settings['mode'], $openvpn_tls_server_modes)) {
1045
		if (empty($settings['topology'])) {
1046
			$settings['topology'] = "subnet";
1047
		}
1048
		$conf .= "topology {$settings['topology']}\n";
1049
	}
1050

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

    
1058
		// Dont add/remove routes checkbox
1059
		if ($settings['route_no_exec']) {
1060
			$conf .= "route-noexec\n";
1061
		}
1062
	}
1063

    
1064
	openvpn_add_custom($settings, $conf);
1065

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

    
1081
function openvpn_restart($mode, $settings) {
1082
	global $g, $config;
1083

    
1084
	$vpnid = $settings['vpnid'];
1085
	$mode_id = $mode.$vpnid;
1086

    
1087
	/* kill the process if running */
1088
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
1089
	if (file_exists($pfile)) {
1090

    
1091
		/* read the pid file */
1092
		$pid = rtrim(file_get_contents($pfile));
1093
		unlink($pfile);
1094

    
1095
		/* send a term signal to the process */
1096
		posix_kill($pid, SIGTERM);
1097

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

    
1111
	if (isset($settings['disable'])) {
1112
		return;
1113
	}
1114

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

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

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

    
1134
	if (!platform_booting()) {
1135
		send_event("filter reload");
1136
	}
1137
}
1138

    
1139
function openvpn_delete($mode, & $settings) {
1140
	global $g, $config;
1141

    
1142
	$vpnid = $settings['vpnid'];
1143
	$mode_id = $mode.$vpnid;
1144

    
1145
	if (isset($settings['dev_mode'])) {
1146
		$tunname = "{$settings['dev_mode']}{$vpnid}";
1147
	} else {
1148
		/* defaults to tun */
1149
		$tunname = "tun{$vpnid}";
1150
	}
1151

    
1152
	if ($mode == "server") {
1153
		$devname = "ovpns{$vpnid}";
1154
	} else {
1155
		$devname = "ovpnc{$vpnid}";
1156
	}
1157

    
1158
	/* kill the process if running */
1159
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
1160
	if (file_exists($pfile)) {
1161

    
1162
		/* read the pid file */
1163
		$pid = trim(file_get_contents($pfile));
1164
		unlink($pfile);
1165

    
1166
		/* send a term signal to the process */
1167
		posix_kill($pid, SIGTERM);
1168
	}
1169

    
1170
	/* remove the device from the openvpn group */
1171
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
1172

    
1173
	/* restore the original adapter name */
1174
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
1175

    
1176
	/* remove the configuration files */
1177
	@array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
1178
}
1179

    
1180
function openvpn_resync_csc(& $settings) {
1181
	global $g, $config, $openvpn_tls_server_modes;
1182

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

    
1185
	if (isset($settings['disable'])) {
1186
		openvpn_delete_csc($settings);
1187
		return;
1188
	}
1189
	openvpn_create_dirs();
1190

    
1191
	if (empty($settings['server_list'])) {
1192
		$csc_server_list = array();
1193
	} else {
1194
		$csc_server_list = explode(",", $settings['server_list']);
1195
	}
1196

    
1197
	$conf = '';
1198
	if ($settings['block']) {
1199
		$conf .= "disable\n";
1200
	}
1201

    
1202
	if ($settings['push_reset']) {
1203
		$conf .= "push-reset\n";
1204
	}
1205

    
1206
	if ($settings['local_network']) {
1207
		$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
1208
	}
1209
	if ($settings['local_networkv6']) {
1210
		$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
1211
	}
1212

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

    
1222
	openvpn_add_dhcpopts($settings, $conf);
1223

    
1224
	if ($settings['gwredir']) {
1225
		$conf .= "push \"redirect-gateway def1\"\n";
1226
	}
1227

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

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

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

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

    
1286
// Resync the configuration and restart the VPN
1287
function openvpn_resync($mode, $settings) {
1288
	openvpn_reconfigure($mode, $settings);
1289
	openvpn_restart($mode, $settings);
1290
}
1291

    
1292
// Resync and restart all VPNs
1293
function openvpn_resync_all($interface = "") {
1294
	global $g, $config;
1295

    
1296
	openvpn_create_dirs();
1297

    
1298
	if (!is_array($config['openvpn'])) {
1299
		$config['openvpn'] = array();
1300
	}
1301

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

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

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

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

    
1342
	if (is_array($config['openvpn']['openvpn-csc'])) {
1343
		foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
1344
			openvpn_resync_csc($settings);
1345
		}
1346
	}
1347

    
1348
}
1349

    
1350
// Resync and restart all VPNs using a gateway group.
1351
function openvpn_resync_gwgroup($gwgroupname = "") {
1352
	global $g, $config;
1353

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

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

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

    
1375
	} else {
1376
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter.");
1377
	}
1378
}
1379

    
1380
function openvpn_get_active_servers($type="multipoint") {
1381
	global $config, $g;
1382

    
1383
	$servers = array();
1384
	if (is_array($config['openvpn']['openvpn-server'])) {
1385
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1386
			if (empty($settings) || isset($settings['disable'])) {
1387
				continue;
1388
			}
1389

    
1390
			$prot = $settings['protocol'];
1391
			$port = $settings['local_port'];
1392

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

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

    
1417
function openvpn_get_server_status($server, $socket) {
1418
	$errval = null;
1419
	$errstr = null;
1420
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1421
	if ($fp) {
1422
		stream_set_timeout($fp, 1);
1423

    
1424
		/* send our status request */
1425
		fputs($fp, "status 2\n");
1426

    
1427
		/* recv all response lines */
1428
		while (!feof($fp)) {
1429

    
1430
			/* read the next line */
1431
			$line = fgets($fp, 1024);
1432

    
1433
			$info = stream_get_meta_data($fp);
1434
			if ($info['timed_out']) {
1435
				break;
1436
			}
1437

    
1438
			/* parse header list line */
1439
			if (strstr($line, "HEADER")) {
1440
				continue;
1441
			}
1442

    
1443
			/* parse end of output line */
1444
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1445
				break;
1446
			}
1447

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

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

    
1487
function openvpn_get_active_clients() {
1488
	global $config, $g;
1489

    
1490
	$clients = array();
1491
	if (is_array($config['openvpn']['openvpn-client'])) {
1492
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1493

    
1494
			if (empty($settings) || isset($settings['disable'])) {
1495
				continue;
1496
			}
1497

    
1498
			$prot = $settings['protocol'];
1499
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1500

    
1501
			$client = array();
1502
			$client['port'] = $settings['local_port'];
1503
			if ($settings['description']) {
1504
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1505
			} else {
1506
				$client['name'] = "Client {$prot}{$port}";
1507
			}
1508

    
1509
			$client['vpnid'] = $settings['vpnid'];
1510
			$client['mgmt'] = "client{$client['vpnid']}";
1511
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1512
			$client['status']="down";
1513

    
1514
			$clients[] = openvpn_get_client_status($client, $socket);
1515
		}
1516
	}
1517
	return $clients;
1518
}
1519

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

    
1529
		/* recv all response lines */
1530
		while (!feof($fp)) {
1531
			/* read the next line */
1532
			$line = fgets($fp, 1024);
1533

    
1534
			$info = stream_get_meta_data($fp);
1535
			if ($info['timed_out']) {
1536
				break;
1537
			}
1538

    
1539
			/* Get the client state */
1540
			if (strstr($line, "CONNECTED")) {
1541
				$client['status'] = "up";
1542
				$list = explode(",", $line);
1543

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

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

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

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

    
1579
				$info = stream_get_meta_data($fp);
1580
				if ($info['timed_out']) {
1581
					break;
1582
				}
1583

    
1584
				if (strstr($line, "TCP/UDP read bytes")) {
1585
					$list = explode(",", $line);
1586
					$client['bytes_recv'] = $list[1];
1587
				}
1588

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

    
1594
				/* parse end of output line */
1595
				if (strstr($line, "END")) {
1596
					break;
1597
				}
1598
			}
1599
		}
1600

    
1601
		fclose($fp);
1602

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

    
1614
function openvpn_kill_client($port, $remipp) {
1615
	global $g;
1616

    
1617
	//$tcpsrv = "tcp://127.0.0.1:{$port}";
1618
	$tcpsrv = "unix://{$g['varetc_path']}/openvpn/{$port}.sock";
1619
	$errval = null;
1620
	$errstr = null;
1621

    
1622
	/* open a tcp connection to the management port of each server */
1623
	$fp = @stream_socket_client($tcpsrv, $errval, $errstr, 1);
1624
	$killed = -1;
1625
	if ($fp) {
1626
		stream_set_timeout($fp, 1);
1627
		fputs($fp, "kill {$remipp}\n");
1628
		while (!feof($fp)) {
1629
			$line = fgets($fp, 1024);
1630

    
1631
			$info = stream_get_meta_data($fp);
1632
			if ($info['timed_out']) {
1633
				break;
1634
			}
1635

    
1636
			/* parse header list line */
1637
			if (strpos($line, "INFO:") !== false) {
1638
				continue;
1639
			}
1640
			if (strpos($line, "SUCCESS") !== false) {
1641
				$killed = 0;
1642
			}
1643
			break;
1644
		}
1645
		fclose($fp);
1646
	}
1647
	return $killed;
1648
}
1649

    
1650
function openvpn_refresh_crls() {
1651
	global $g, $config;
1652

    
1653
	openvpn_create_dirs();
1654

    
1655
	if (is_array($config['openvpn']['openvpn-server'])) {
1656
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1657
			if (empty($settings)) {
1658
				continue;
1659
			}
1660
			if (isset($settings['disable'])) {
1661
				continue;
1662
			}
1663
			// Write the settings for the keys
1664
			switch ($settings['mode']) {
1665
				case 'p2p_tls':
1666
				case 'server_tls':
1667
				case 'server_tls_user':
1668
				case 'server_user':
1669
					if (!empty($settings['crlref'])) {
1670
						$crl = lookup_crl($settings['crlref']);
1671
						crl_update($crl);
1672
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1673
						file_put_contents($fpath, base64_decode($crl['text']));
1674
						@chmod($fpath, 0644);
1675
					}
1676
					break;
1677
			}
1678
		}
1679
	}
1680
}
1681

    
1682
function openvpn_create_dirs() {
1683
	global $g, $config, $openvpn_tls_server_modes;
1684
	if (!is_dir("{$g['varetc_path']}/openvpn")) {
1685
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1686
	}
1687
	if (!is_dir("{$g['varetc_path']}/openvpn-csc")) {
1688
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1689
	}
1690

    
1691
	/* Check for enabled servers and create server-specific CSC dirs */
1692
	if (is_array($config['openvpn']['openvpn-server'])) {
1693
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1694
			if (isset($settings['disable'])) {
1695
				continue;
1696
			}
1697
			if (in_array($settings['mode'], $openvpn_tls_server_modes)) {
1698
				if ($settings['vpnid']) {
1699
					safe_mkdir("{$g['varetc_path']}/openvpn-csc/server{$settings['vpnid']}");
1700
				}
1701
			}
1702
		}
1703
	}
1704
}
1705

    
1706
function openvpn_get_interface_ip($ip, $mask) {
1707
	$baselong = ip2long32($ip) & ip2long($mask);
1708
	$ip1 = long2ip32($baselong + 1);
1709
	$ip2 = long2ip32($baselong + 2);
1710
	return array($ip1, $ip2);
1711
}
1712

    
1713
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1714
	$basev6 = gen_subnetv6($ipv6, $prefix);
1715
	// Is there a better way to do this math?
1716
	$ipv6_arr = explode(':', $basev6);
1717
	$last = hexdec(array_pop($ipv6_arr));
1718
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1719
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1720
	return array($ipv6_1, $ipv6_2);
1721
}
1722

    
1723
function openvpn_clear_route($mode, $settings) {
1724
	if (empty($settings['tunnel_network'])) {
1725
		return;
1726
	}
1727
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1728
	$mask = gen_subnet_mask($cidr);
1729
	$clear_route = false;
1730

    
1731
	switch ($settings['mode']) {
1732
		case 'shared_key':
1733
			$clear_route = true;
1734
			break;
1735
		case 'p2p_tls':
1736
		case 'p2p_shared_key':
1737
			if ($cidr == 30) {
1738
				$clear_route = true;
1739
			}
1740
			break;
1741
	}
1742

    
1743
	if ($clear_route && !empty($ip) && !empty($mask)) {
1744
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1745
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1746
		/* XXX: Family for route? */
1747
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1748
	}
1749
}
1750

    
1751
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
1752
	$routes = "";
1753
	if (empty($value)) {
1754
		return "";
1755
	}
1756
	$networks = explode(',', $value);
1757

    
1758
	foreach ($networks as $network) {
1759
		if ($ipproto == "ipv4") {
1760
			$route = openvpn_gen_route_ipv4($network, $iroute);
1761
		} else {
1762
			$route = openvpn_gen_route_ipv6($network, $iroute);
1763
		}
1764

    
1765
		if ($push) {
1766
			$routes .= "push \"{$route}\"\n";
1767
		} else {
1768
			$routes .= "{$route}\n";
1769
		}
1770
	}
1771
	return $routes;
1772
}
1773

    
1774
function openvpn_gen_route_ipv4($network, $iroute = false) {
1775
	$i = ($iroute) ? "i" : "";
1776
	list($ip, $mask) = explode('/', trim($network));
1777
	$mask = gen_subnet_mask($mask);
1778
	return "{$i}route $ip $mask";
1779
}
1780

    
1781
function openvpn_gen_route_ipv6($network, $iroute = false) {
1782
	$i = ($iroute) ? "i" : "";
1783
	list($ipv6, $prefix) = explode('/', trim($network));
1784
	if (empty($prefix)) {
1785
		$prefix = "128";
1786
	}
1787
	return "{$i}route-ipv6 ${ipv6}/${prefix}";
1788
}
1789

    
1790
function openvpn_get_settings($mode, $vpnid) {
1791
	global $config;
1792

    
1793
	if (is_array($config['openvpn']['openvpn-server'])) {
1794
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1795
			if (isset($settings['disable'])) {
1796
				continue;
1797
			}
1798

    
1799
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1800
				return $settings;
1801
			}
1802
		}
1803
	}
1804

    
1805
	if (is_array($config['openvpn']['openvpn-client'])) {
1806
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1807
			if (isset($settings['disable'])) {
1808
				continue;
1809
			}
1810

    
1811
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1812
				return $settings;
1813
			}
1814
		}
1815
	}
1816

    
1817
	return array();
1818
}
1819

    
1820
function openvpn_restart_by_vpnid($mode, $vpnid) {
1821
	$settings = openvpn_get_settings($mode, $vpnid);
1822
	openvpn_restart($mode, $settings);
1823
}
1824

    
1825
?>
(37-37/65)