Project

General

Profile

Download (54.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * openvpn.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2006 Fernando Lemos
7
 * Copyright (c) 2006-2016 Rubicon Communications, LLC (Netgate)
8
 * All rights reserved.
9
 *
10
 * This file was rewritten from scratch by Fernando Lemos but
11
 * *MIGHT* contain code previously written by:
12
 *
13
 * Copyright (c) 2005 Peter Allgeyer <allgeyer_AT_web.de>
14
 * Copyright (c) 2004 Peter Curran (peter@closeconsultants.com).
15
 * All rights reserved.
16
 *
17
 * Licensed under the Apache License, Version 2.0 (the "License");
18
 * you may not use this file except in compliance with the License.
19
 * You may obtain a copy of the License at
20
 *
21
 * http://www.apache.org/licenses/LICENSE-2.0
22
 *
23
 * Unless required by applicable law or agreed to in writing, software
24
 * distributed under the License is distributed on an "AS IS" BASIS,
25
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
 * See the License for the specific language governing permissions and
27
 * limitations under the License.
28
 */
29

    
30
require_once('config.inc');
31
require_once("certs.inc");
32
require_once('pfsense-utils.inc');
33
require_once("auth.inc");
34

    
35
global $openvpn_prots;
36
$openvpn_prots = array(
37
	"UDP4" => "UDP on IPv4 only",
38
	"UDP6" => "UDP on IPv6 only",
39
	"TCP4" => "TCP on IPv4 only",
40
	"TCP6" => "TCP on IPv6 only",
41
	"UDP" => "UDP IPv4 and IPv6 on all interfaces (multihome)",
42
	"TCP" => "TCP IPv4 and IPv6 on all interfaces (multihome)"
43
);
44

    
45
global $openvpn_dev_mode;
46
$openvpn_dev_mode = array(
47
	"tun" => "tun - Layer 3 Tunnel Mode",
48
	"tap" => "tap - Layer 2 Tap Mode"
49
);
50

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

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

    
80
global $openvpn_dh_lengths;
81
$openvpn_dh_lengths = array(
82
	1024 => "1024 bit",
83
	2048 => "2048 bit",
84
	3072 => "3072 bit",
85
	4096 => "4096 bit",
86
	7680 => "7680 bit",
87
	8192 => "8192 bit",
88
	15360 => "15360 bit",
89
	16384 => "16384 bit",
90
	"none" => "ECDH Only"
91
);
92
foreach ($openvpn_dh_lengths as $idx => $dhlen) {
93
	if (is_numeric($idx) && !file_exists("/etc/dh-parameters.{$idx}")) {
94
		unset($openvpn_dh_lengths[$idx]);
95
	}
96
}
97

    
98
global $openvpn_cert_depths;
99
$openvpn_cert_depths = array(
100
	1 => gettext("One (Client+Server)"),
101
	2 => gettext("Two (Client+Intermediate+Server)"),
102
	3 => gettext("Three (Client+2xIntermediate+Server)"),
103
	4 => gettext("Four (Client+3xIntermediate+Server)"),
104
	5 => gettext("Five (Client+4xIntermediate+Server)")
105
);
106

    
107
global $openvpn_server_modes;
108
$openvpn_server_modes = array(
109
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
110
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
111
	'server_tls' => gettext("Remote Access ( SSL/TLS )"),
112
	'server_user' => gettext("Remote Access ( User Auth )"),
113
	'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
114

    
115
global $openvpn_tls_server_modes;
116
$openvpn_tls_server_modes = array('p2p_tls', 'server_tls', 'server_user', 'server_tls_user');
117

    
118
global $openvpn_client_modes;
119
$openvpn_client_modes = array(
120
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
121
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"));
122

    
123
global $openvpn_compression_modes;
124
$openvpn_compression_modes = array(
125
	'' => gettext("Omit Preference (Use OpenVPN Default)"),
126
	'lz4' => gettext("LZ4 Compression [compress lz4]"),
127
	'lz4-v2' => gettext("LZ4 Comression v2 [compress lz4-v2]"),
128
	'lzo' => gettext("LZO Compression [compress lzo, equivalent to comp-lzo yes for compatibility]"),
129
	'stub' => gettext("Enable Compression (stub) [compress]"),
130
	'noadapt' => gettext("Omit Preference, + Disable Adaptive LZO Compression [Legacy style, comp-noadapt]"),
131
	'adaptive' => gettext("Adaptive LZO Compression [Legacy style, comp-lzo adaptive]"),
132
	'yes' => gettext("LZO Compression [Legacy style, comp-lzo yes]"),
133
	'no' => gettext("No LZO Compression [Legacy style, comp-lzo no]"),
134
);
135

    
136
global $openvpn_topologies;
137
$openvpn_topologies = array(
138
	'subnet' => gettext("Subnet -- One IP address per client in a common subnet"),
139
	'net30' => gettext("net30 -- Isolated /30 network per client")
140
//	'p2p => gettext("Peer to Peer -- One IP address per client peer-to-peer style. Does not work on Windows.")
141
);
142

    
143
global $openvpn_tls_modes;
144
$openvpn_tls_modes = array(
145
	'auth' => gettext("TLS Authentication"),
146
	'crypt' => gettext("TLS Encryption and Authentication"),
147
);
148

    
149
function openvpn_build_mode_list() {
150
	global $openvpn_server_modes;
151

    
152
	$list = array();
153

    
154
	foreach ($openvpn_server_modes as $name => $desc) {
155
		$list[$name] = $desc;
156
	}
157

    
158
	return($list);
159
}
160

    
161
function openvpn_build_if_list() {
162
	$list = array();
163

    
164
	$interfaces = get_configured_interface_with_descr();
165
	$viplist = get_configured_vip_list();
166
	foreach ($viplist as $vip => $address) {
167
		$interfaces[$vip.'|'.$address] = $address;
168
		if (get_vip_descr($address)) {
169
			$interfaces[$vip.'|'.$address] .= " (";
170
			$interfaces[$vip.'|'.$address] .= get_vip_descr($address);
171
			$interfaces[$vip.'|'.$address] .= ")";
172
		}
173
	}
174

    
175
	$grouplist = return_gateway_groups_array();
176
	foreach ($grouplist as $name => $group) {
177
		if ($group[0]['vip'] != "") {
178
			$vipif = $group[0]['vip'];
179
		} else {
180
			$vipif = $group[0]['int'];
181
		}
182

    
183
		$interfaces[$name] = "GW Group {$name}";
184
	}
185

    
186
	$interfaces['lo0'] = "Localhost";
187
	$interfaces['any'] = "any";
188

    
189
	foreach ($interfaces as $iface => $ifacename) {
190
	   $list[$iface] = $ifacename;
191
	}
192

    
193
	return($list);
194
}
195

    
196
function openvpn_build_crl_list() {
197
	global $a_crl;
198

    
199
	$list = array('' => 'None');
200

    
201
	foreach ($a_crl as $crl) {
202
		$caname = "";
203
		$ca = lookup_ca($crl['caref']);
204

    
205
		if ($ca) {
206
			$caname = " (CA: {$ca['descr']})";
207
		}
208

    
209
		$list[$crl['refid']] = $crl['descr'] . $caname;
210
	}
211

    
212
	return($list);
213
}
214

    
215
function openvpn_build_cert_list($include_none = false, $prioritize_server_certs = false) {
216
	global $a_cert;
217

    
218
	if ($include_none) {
219
		$list = array('' => gettext('None (Username and/or Password required)'));
220
	} else {
221
		$list = array();
222
	}
223

    
224
	$non_server_list = array();
225

    
226
	if ($prioritize_server_certs) {
227
		$list[' '] = gettext("===== Server Certificates =====");
228
		$non_server_list['  '] = gettext("===== Non-Server Certificates =====");
229
	}
230

    
231
	foreach ($a_cert as $cert) {
232
		$properties = array();
233
		$propstr = "";
234
		$ca = lookup_ca($cert['caref']);
235
		$purpose = cert_get_purpose($cert['crt'], true);
236

    
237
		if ($purpose['server'] == "Yes") {
238
			$properties[] = gettext("Server: Yes");
239
		} elseif ($prioritize_server_certs) {
240
			$properties[] = gettext("Server: NO");
241
		}
242
		if ($ca) {
243
			$properties[] = sprintf(gettext("CA: %s"), $ca['descr']);
244
		}
245
		if (cert_in_use($cert['refid'])) {
246
			$properties[] = gettext("In Use");
247
		}
248
		if (is_cert_revoked($cert)) {
249
			$properties[] = gettext("Revoked");
250
		}
251

    
252
		if (!empty($properties)) {
253
			$propstr = " (" . implode(", ", $properties) . ")";
254
		}
255

    
256
		if ($prioritize_server_certs) {
257
			if ($purpose['server'] == "Yes") {
258
				$list[$cert['refid']] = $cert['descr'] . $propstr;
259
			} else {
260
				$non_server_list[$cert['refid']] = $cert['descr'] . $propstr;
261
			}
262
		} else {
263
			$list[$cert['refid']] = $cert['descr'] . $propstr;
264
		}
265
	}
266

    
267
	return(array('server' => $list, 'non-server' => $non_server_list));
268
}
269

    
270
function openvpn_build_bridge_list() {
271
	$list = array();
272

    
273
	$serverbridge_interface['none'] = "none";
274
	$serverbridge_interface = array_merge($serverbridge_interface, get_configured_interface_with_descr());
275
	$viplist = get_configured_vip_list();
276

    
277
	foreach ($viplist as $vip => $address) {
278
		$serverbridge_interface[$vip.'|'.$address] = $address;
279
		if (get_vip_descr($address)) {
280
			$serverbridge_interface[$vip.'|'.$address] .= " (". get_vip_descr($address) .")";
281
		}
282
	}
283

    
284
	foreach ($serverbridge_interface as $iface => $ifacename) {
285
		$list[$iface] = htmlspecialchars($ifacename);
286
	}
287

    
288
	return($list);
289
}
290

    
291
function openvpn_create_key() {
292

    
293
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
294
	if (!$fp) {
295
		return false;
296
	}
297

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

    
301
	return $rslt;
302
}
303

    
304
function openvpn_create_dhparams($bits) {
305

    
306
	$fp = popen("/usr/bin/openssl dhparam {$bits} 2>/dev/null", "r");
307
	if (!$fp) {
308
		return false;
309
	}
310

    
311
	$rslt = stream_get_contents($fp);
312
	pclose($fp);
313

    
314
	return $rslt;
315
}
316

    
317
function openvpn_vpnid_used($vpnid) {
318
	global $config;
319

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

    
328
	if (is_array($config['openvpn']['openvpn-client'])) {
329
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
330
			if ($vpnid == $settings['vpnid']) {
331
				return true;
332
			}
333
		}
334
	}
335

    
336
	return false;
337
}
338

    
339
function openvpn_vpnid_next() {
340

    
341
	$vpnid = 1;
342
	while (openvpn_vpnid_used($vpnid)) {
343
		$vpnid++;
344
	}
345

    
346
	return $vpnid;
347
}
348

    
349
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
350
	global $config;
351

    
352
	if (is_array($config['openvpn']['openvpn-server'])) {
353
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
354
			if (isset($settings['disable'])) {
355
				continue;
356
			}
357

    
358
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
359
				continue;
360
			}
361

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

    
369
	if (is_array($config['openvpn']['openvpn-client'])) {
370
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
371
			if (isset($settings['disable'])) {
372
				continue;
373
			}
374

    
375
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid']) {
376
				continue;
377
			}
378

    
379
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
380
			    ($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any")) {
381
				return $settings['vpnid'];
382
			}
383
		}
384
	}
385

    
386
	return 0;
387
}
388

    
389
function openvpn_port_next($prot, $interface = "wan") {
390

    
391
	$port = 1194;
392
	while (openvpn_port_used($prot, $interface, $port)) {
393
		$port++;
394
	}
395
	while (openvpn_port_used($prot, "any", $port)) {
396
		$port++;
397
	}
398

    
399
	return $port;
400
}
401

    
402
function openvpn_get_cipherlist() {
403

    
404
	$ciphers = array();
405
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep \'(.*key\' | sed \'s/, TLS client\/server mode only//\'');
406
	$cipher_lines = explode("\n", trim($cipher_out));
407
	sort($cipher_lines);
408
	foreach ($cipher_lines as $line) {
409
		$words = explode(' ', $line, 2);
410
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
411
	}
412
	$ciphers["none"] = gettext("None (No Encryption)");
413
	return $ciphers;
414
}
415

    
416
function openvpn_get_curvelist() {
417

    
418
	$curves = array();
419
	$curves["none"] = gettext("Use Default");
420
	$curve_out = shell_exec('/usr/local/sbin/openvpn --show-curves | /usr/bin/grep -v \'Available Elliptic curves\'');
421
	$curve_lines = explode("\n", trim($curve_out));
422
	sort($curve_lines);
423
	foreach ($curve_lines as $line) {
424
		$line = trim($line);
425
		$curves[$line] = $line;
426
	}
427
	return $curves;
428
}
429

    
430
function openvpn_validate_curve($curve) {
431
	$curves = openvpn_get_curvelist();
432
	return array_key_exists($curve, $curves);
433
}
434

    
435
function openvpn_get_digestlist() {
436

    
437
	$digests = array();
438
	$digest_out = shell_exec('/usr/local/sbin/openvpn --show-digests | /usr/bin/grep "digest size" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
439
	$digest_lines = explode("\n", trim($digest_out));
440
	sort($digest_lines);
441
	foreach ($digest_lines as $line) {
442
		$words = explode(' ', $line);
443
		$digests[$words[0]] = "{$words[0]} {$words[1]}";
444
	}
445
	$digests["none"] = gettext("None (No Authentication)");
446
	return $digests;
447
}
448

    
449
function openvpn_get_engines() {
450
	$openssl_engines = array('none' => gettext('No Hardware Crypto Acceleration'));
451
	exec("/usr/bin/openssl engine -t -c", $openssl_engine_output);
452
	$openssl_engine_output = implode("\n", $openssl_engine_output);
453
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
454
	$openssl_engine_output = explode("\n", $openssl_engine_output);
455

    
456
	foreach ($openssl_engine_output as $oeo) {
457
		$keep = true;
458
		$details = explode("|", $oeo);
459
		$engine = array_shift($details);
460
		$linematch = array();
461
		preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
462
		foreach ($details as $dt) {
463
			if (strpos($dt, "unavailable") !== FALSE) {
464
				$keep = false;
465
			}
466
			if (strpos($dt, "available") !== FALSE) {
467
				continue;
468
			}
469
			if (strpos($dt, "[") !== FALSE) {
470
				$ciphers = trim($dt, "[]");
471
			}
472
		}
473
		if (!empty($ciphers)) {
474
			$ciphers = " - " . $ciphers;
475
		}
476
		if (strlen($ciphers) > 60) {
477
			$ciphers = substr($ciphers, 0, 60) . " ... ";
478
		}
479
		if ($keep) {
480
			$openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
481
		}
482
	}
483
	return $openssl_engines;
484
}
485

    
486
function openvpn_validate_engine($engine) {
487
	$engines = openvpn_get_engines();
488
	return array_key_exists($engine, $engines);
489
}
490

    
491
function openvpn_validate_host($value, $name) {
492
	$value = trim($value);
493
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value))) {
494
		return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
495
	}
496
	return false;
497
}
498

    
499
function openvpn_validate_port($value, $name) {
500
	$value = trim($value);
501
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535)) {
502
		return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
503
	}
504
	return false;
505
}
506

    
507
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
508
	$value = trim($value);
509
	$error = false;
510
	if (empty($value)) {
511
		return false;
512
	}
513
	$networks = explode(',', $value);
514

    
515
	if (!$multiple && (count($networks) > 1)) {
516
		return sprintf(gettext("The field '%1\$s' must contain a single valid %2\$s CIDR range."), $name, $ipproto);
517
	}
518

    
519
	foreach ($networks as $network) {
520
		if ($ipproto == "ipv4") {
521
			$error = !openvpn_validate_cidr_ipv4($network);
522
		} else {
523
			$error = !openvpn_validate_cidr_ipv6($network);
524
		}
525
		if ($error) {
526
			break;
527
		}
528
	}
529

    
530
	if ($error) {
531
		return sprintf(gettext("The field '%1\$s' must contain only valid %2\$s CIDR range(s) separated by commas."), $name, $ipproto);
532
	} else {
533
		return false;
534
	}
535
}
536

    
537
function openvpn_validate_cidr_ipv4($value) {
538
	$value = trim($value);
539
	if (!empty($value)) {
540
		list($ip, $mask) = explode('/', $value);
541
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0)) {
542
			return false;
543
		}
544
	}
545
	return true;
546
}
547

    
548
function openvpn_validate_cidr_ipv6($value) {
549
	$value = trim($value);
550
	if (!empty($value)) {
551
		list($ipv6, $prefix) = explode('/', $value);
552
		if (empty($prefix)) {
553
			$prefix = "128";
554
		}
555
		if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0)) {
556
			return false;
557
		}
558
	}
559
	return true;
560
}
561

    
562
function openvpn_add_dhcpopts(& $settings, & $conf) {
563

    
564
	if (!empty($settings['dns_domain'])) {
565
		$conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
566
	}
567

    
568
	if (!empty($settings['dns_server1'])) {
569
		$dnstype = (is_ipaddrv6($settings['dns_server1'])) ? "DNS6" : "DNS";
570
		$conf .= "push \"dhcp-option {$dnstype} {$settings['dns_server1']}\"\n";
571
	}
572
	if (!empty($settings['dns_server2'])) {
573
		$dnstype = (is_ipaddrv6($settings['dns_server2'])) ? "DNS6" : "DNS";
574
		$conf .= "push \"dhcp-option {$dnstype} {$settings['dns_server2']}\"\n";
575
	}
576
	if (!empty($settings['dns_server3'])) {
577
		$dnstype = (is_ipaddrv6($settings['dns_server3'])) ? "DNS6" : "DNS";
578
		$conf .= "push \"dhcp-option {$dnstype} {$settings['dns_server3']}\"\n";
579
	}
580
	if (!empty($settings['dns_server4'])) {
581
		$dnstype = (is_ipaddrv6($settings['dns_server4'])) ? "DNS6" : "DNS";
582
		$conf .= "push \"dhcp-option {$dnstype} {$settings['dns_server4']}\"\n";
583
	}
584

    
585
	if (!empty($settings['push_blockoutsidedns'])) {
586
		$conf .= "push \"block-outside-dns\"\n";
587
	}
588
	if (!empty($settings['push_register_dns'])) {
589
		$conf .= "push \"register-dns\"\n";
590
	}
591

    
592
	if (!empty($settings['ntp_server1'])) {
593
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
594
	}
595
	if (!empty($settings['ntp_server2'])) {
596
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
597
	}
598

    
599
	if ($settings['netbios_enable']) {
600

    
601
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0)) {
602
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
603
		}
604
		if (!empty($settings['dhcp_nbtscope'])) {
605
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
606
		}
607

    
608
		if (!empty($settings['wins_server1'])) {
609
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
610
		}
611
		if (!empty($settings['wins_server2'])) {
612
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
613
		}
614

    
615
		if (!empty($settings['nbdd_server1'])) {
616
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
617
		}
618
	}
619

    
620
	if ($settings['gwredir']) {
621
		$conf .= "push \"redirect-gateway def1\"\n";
622
	}
623
}
624

    
625
function openvpn_add_custom(& $settings, & $conf) {
626

    
627
	if ($settings['custom_options']) {
628

    
629
		$options = explode(';', $settings['custom_options']);
630

    
631
		if (is_array($options)) {
632
			foreach ($options as $option) {
633
				$conf .= "$option\n";
634
			}
635
		} else {
636
			$conf .= "{$settings['custom_options']}\n";
637
		}
638
	}
639
}
640

    
641
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
642
	global $g;
643

    
644
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
645
	openvpn_create_dirs();
646
	file_put_contents($fpath, base64_decode($data));
647
	//chown($fpath, 'nobody');
648
	//chgrp($fpath, 'nobody');
649
	@chmod($fpath, 0600);
650

    
651
	$conf .= "{$directive} {$fpath} {$opt}\n";
652
}
653

    
654
function openvpn_reconfigure($mode, $settings) {
655
	global $g, $config, $openvpn_tls_server_modes, $openvpn_dh_lengths;
656

    
657
	if (empty($settings)) {
658
		return;
659
	}
660
	if (isset($settings['disable'])) {
661
		return;
662
	}
663
	openvpn_create_dirs();
664
	/*
665
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
666
	 * we use a vpnid number which is allocated for a particular client
667
	 * or server configuration. ( see openvpn_vpnid_next() )
668
	 */
669

    
670
	$vpnid = $settings['vpnid'];
671
	$mode_id = $mode.$vpnid;
672

    
673
	if (isset($settings['dev_mode'])) {
674
		$tunname = "{$settings['dev_mode']}{$vpnid}";
675
	} else {
676
		/* defaults to tun */
677
		$tunname = "tun{$vpnid}";
678
		$settings['dev_mode'] = "tun";
679
	}
680

    
681
	if ($mode == "server") {
682
		$devname = "ovpns{$vpnid}";
683
	} else {
684
		$devname = "ovpnc{$vpnid}";
685
	}
686

    
687
	/* is our device already configured */
688
	if (!does_interface_exist($devname)) {
689

    
690
		/* create the tap device if required */
691
		if (!file_exists("/dev/{$tunname}")) {
692
			exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
693
		}
694

    
695
		/* rename the device */
696
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
697

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

    
701
		$ifname = convert_real_interface_to_friendly_interface_name($devname);
702
		$grouptmp = link_interface_to_group($ifname);
703
		if (!empty($grouptmp)) {
704
			array_walk($grouptmp, 'interface_group_add_member');
705
		}
706
		unset($grouptmp, $ifname);
707
	}
708

    
709
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
710
	$proto = strtolower($settings['protocol']);
711
	if (substr($settings['protocol'], 0, 3) == "TCP") {
712
			$proto = "{$proto}-{$mode}";
713
	}
714
	$dev_mode = $settings['dev_mode'];
715
	$cipher = $settings['crypto'];
716
	// OpenVPN defaults to SHA1, so use it when unset to maintain compatibility.
717
	$digest = !empty($settings['digest']) ? $settings['digest'] : "SHA1";
718

    
719
	$interface = get_failover_interface($settings['interface']);
720
	// The IP address in the settings can be an IPv4 or IPv6 address associated with the interface
721
	$ipaddr = $settings['ipaddr'];
722

    
723
	// If a specific ip address (VIP) is requested, use it.
724
	// Otherwise, if a specific interface is requested, use it
725
	// If "any" interface was selected, local directive will be omitted.
726
	if (is_ipaddrv4($ipaddr)) {
727
		$iface_ip = $ipaddr;
728
	} else {
729
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
730
			$iface_ip=get_interface_ip($interface);
731
		}
732
	}
733
	if (is_ipaddrv6($ipaddr)) {
734
		$iface_ipv6 = $ipaddr;
735
	} else {
736
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
737
			$iface_ipv6=get_interface_ipv6($interface);
738
		}
739
	}
740

    
741

    
742
	$conf = "dev {$devname}\n";
743
	if (isset($settings['verbosity_level'])) {
744
		$conf .= "verb {$settings['verbosity_level']}\n";
745
	}
746

    
747
	$conf .= "dev-type {$settings['dev_mode']}\n";
748
	$conf .= "dev-node /dev/{$tunname}\n";
749
	$conf .= "writepid {$pfile}\n";
750
	$conf .= "#user nobody\n";
751
	$conf .= "#group nobody\n";
752
	$conf .= "script-security 3\n";
753
	$conf .= "daemon\n";
754
	$conf .= "keepalive 10 60\n";
755
	$conf .= "ping-timer-rem\n";
756
	$conf .= "persist-tun\n";
757
	$conf .= "persist-key\n";
758
	$conf .= "proto {$proto}\n";
759
	$conf .= "cipher {$cipher}\n";
760
	$conf .= "auth {$digest}\n";
761
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
762
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
763
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
764
		switch ($settings['mode']) {
765
			case 'server_user':
766
			case 'server_tls_user':
767
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
768
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
769
				break;
770
		}
771
	}
772

    
773
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
774
	switch ($settings['protocol']) {
775
		case 'UDP':
776
		case 'TCP':
777
			$conf .= "multihome\n";
778
			break;
779
		case 'UDP4':
780
		case 'TCP4':
781
			if (is_ipaddrv4($iface_ip)) {
782
				$conf .= "local {$iface_ip}\n";
783
			}
784
			if ($settings['interface'] == "any") {
785
				$conf .= "multihome\n";
786
			}
787
			break;
788
		case 'UDP6':
789
		case 'TCP6':
790
			if (is_ipaddrv6($iface_ipv6)) {
791
				$conf .= "local {$iface_ipv6}\n";
792
			}
793
			if ($settings['interface'] == "any") {
794
				$conf .= "multihome\n";
795
			}
796
			break;
797
		default:
798
	}
799

    
800
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
801
		$conf .= "engine {$settings['engine']}\n";
802
	}
803

    
804
	// server specific settings
805
	if ($mode == 'server') {
806

    
807
		list($ip, $cidr) = explode('/', trim($settings['tunnel_network']));
808
		list($ipv6, $prefix) = explode('/', trim($settings['tunnel_networkv6']));
809
		$mask = gen_subnet_mask($cidr);
810

    
811
		// configure tls modes
812
		switch ($settings['mode']) {
813
			case 'p2p_tls':
814
			case 'server_tls':
815
			case 'server_user':
816
			case 'server_tls_user':
817
				$conf .= "tls-server\n";
818
				break;
819
		}
820

    
821
		// configure p2p/server modes
822
		switch ($settings['mode']) {
823
			case 'p2p_tls':
824
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
825
				//  use the server directive. It works for a single client without it.
826
				//  See ticket #1417
827
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
828
					$conf .= "server {$ip} {$mask}\n";
829
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc/server{$vpnid}\n";
830
					if (is_ipaddr($ipv6)) {
831
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
832
					}
833
				}
834
			case 'p2p_shared_key':
835
				if (!empty($ip) && !empty($mask)) {
836
					list($ip1, $ip2) = openvpn_get_interface_ip($ip, $cidr);
837
					if ($settings['dev_mode'] == 'tun') {
838
						$conf .= "ifconfig {$ip1} {$ip2}\n";
839
					} else {
840
						$conf .= "ifconfig {$ip1} {$mask}\n";
841
					}
842
				}
843
				if (!empty($ipv6) && !empty($prefix)) {
844
					list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
845
					if ($settings['dev_mode'] == 'tun') {
846
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
847
					} else {
848
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
849
					}
850
				}
851
				break;
852
			case 'server_tls':
853
			case 'server_user':
854
			case 'server_tls_user':
855
				if (!empty($ip) && !empty($mask)) {
856
					$conf .= "server {$ip} {$mask}\n";
857
					if (is_ipaddr($ipv6)) {
858
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
859
					}
860
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc/server{$vpnid}\n";
861
				} else {
862
					if ($settings['serverbridge_dhcp']) {
863
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
864
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
865
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
866
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
867
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
868
								$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc/server{$vpnid}\n";
869
							} else {
870
								$conf .= "mode server\n";
871
							}
872
						} else {
873
							$conf .= "mode server\n";
874
						}
875
					}
876
				}
877
				break;
878
		}
879

    
880
		// configure user auth modes
881
		switch ($settings['mode']) {
882
			case 'server_user':
883
				$conf .= "verify-client-cert none\n";
884
			case 'server_tls_user':
885
				/* username-as-common-name is not compatible with server-bridge */
886
				if (stristr($conf, "server-bridge") === false) {
887
					$conf .= "username-as-common-name\n";
888
				}
889
				if (!empty($settings['authmode'])) {
890
					$strictusercn = "false";
891
					if ($settings['strictusercn']) {
892
						$strictusercn = "true";
893
					}
894
					$conf .= "auth-user-pass-verify \"/usr/local/sbin/ovpn_auth_verify user " . base64_encode($settings['authmode']) . " {$strictusercn} {$mode_id} {$settings['local_port']}\" via-env\n";
895
				}
896
				break;
897
		}
898
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls'))) {
899
			$settings['cert_depth'] = 1;
900
		}
901
		if (is_numeric($settings['cert_depth'])) {
902
			if (($mode == 'client') && empty($settings['certref'])) {
903
				$cert = "";
904
			} else {
905
				$cert = lookup_cert($settings['certref']);
906
				/* XXX: Seems not used at all! */
907
				$servercn = urlencode(cert_get_cn($cert['crt']));
908
				$conf .= "tls-verify \"/usr/local/sbin/ovpn_auth_verify tls '{$servercn}' {$settings['cert_depth']}\"\n";
909
			}
910
		}
911

    
912
		// The local port to listen on
913
		$conf .= "lport {$settings['local_port']}\n";
914

    
915
		// The management port to listen on
916
		// Use unix socket to overcome the problem on any type of server
917
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
918
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
919

    
920
		if ($settings['maxclients']) {
921
			$conf .= "max-clients {$settings['maxclients']}\n";
922
		}
923

    
924
		// Can we push routes
925
		if ($settings['local_network']) {
926
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
927
		}
928
		if ($settings['local_networkv6']) {
929
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
930
		}
931

    
932
		switch ($settings['mode']) {
933
			case 'server_tls':
934
			case 'server_user':
935
			case 'server_tls_user':
936
				// Configure client dhcp options
937
				openvpn_add_dhcpopts($settings, $conf);
938
				if ($settings['client2client']) {
939
					$conf .= "client-to-client\n";
940
				}
941
				break;
942
		}
943
		if (isset($settings['duplicate_cn'])) {
944
			$conf .= "duplicate-cn\n";
945
		}
946
	}
947

    
948
	// client specific settings
949

    
950
	if ($mode == 'client') {
951

    
952
		// configure p2p mode
953
		switch ($settings['mode']) {
954
			case 'p2p_tls':
955
				$conf .= "tls-client\n";
956
			case 'shared_key':
957
				$conf .= "client\n";
958
				break;
959
		}
960

    
961
		// If there is no bind option at all (ip and/or port), add "nobind" directive
962
		//  Otherwise, use the local port if defined, failing that, use lport 0 to
963
		//  ensure a random source port.
964
		if ((empty($iface_ip)) && (!$settings['local_port'])) {
965
			$conf .= "nobind\n";
966
		} elseif ($settings['local_port']) {
967
			$conf .= "lport {$settings['local_port']}\n";
968
		} else {
969
			$conf .= "lport 0\n";
970
		}
971

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

    
975
		// The remote server
976
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
977

    
978
		if (!empty($settings['use_shaper'])) {
979
			$conf .= "shaper {$settings['use_shaper']}\n";
980
		}
981

    
982
		if (!empty($settings['tunnel_network'])) {
983
			list($ip, $cidr) = explode('/', trim($settings['tunnel_network']));
984
			$mask = gen_subnet_mask($cidr);
985
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $cidr);
986
			if ($settings['dev_mode'] == 'tun') {
987
				$conf .= "ifconfig {$ip2} {$ip1}\n";
988
			} else {
989
				$conf .= "ifconfig {$ip2} {$mask}\n";
990
			}
991
		}
992

    
993
		if (!empty($settings['tunnel_networkv6'])) {
994
			list($ipv6, $prefix) = explode('/', trim($settings['tunnel_networkv6']));
995
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
996
			if ($settings['dev_mode'] == 'tun') {
997
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
998
			} else {
999
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
1000
			}
1001
		}
1002

    
1003
		if (($settings['auth_user'] || $settings['auth_pass']) && $settings['mode'] == "p2p_tls") {
1004
			$up_file = "{$g['varetc_path']}/openvpn/{$mode_id}.up";
1005
			$conf .= "auth-user-pass {$up_file}\n";
1006
			if ($settings['auth_user']) {
1007
				$userpass = "{$settings['auth_user']}\n";
1008
			} else {
1009
				$userpass = "";
1010
			}
1011
			if ($settings['auth_pass']) {
1012
				$userpass .= "{$settings['auth_pass']}\n";
1013
			}
1014
			// If only auth_pass is given, then it acts like a user name and we put a blank line where pass would normally go.
1015
			if (!($settings['auth_user'] && $settings['auth_pass'])) {
1016
				$userpass .= "\n";
1017
			}
1018
			file_put_contents($up_file, $userpass);
1019
		}
1020

    
1021
		if ($settings['proxy_addr']) {
1022
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
1023
			if ($settings['proxy_authtype'] != "none") {
1024
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
1025
				$proxypas = "{$settings['proxy_user']}\n";
1026
				$proxypas .= "{$settings['proxy_passwd']}\n";
1027
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
1028
			}
1029
			$conf .= " \n";
1030
		}
1031
	}
1032

    
1033
	// Add a remote network route if set, and only for p2p modes.
1034
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
1035
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
1036
	}
1037
	// Add a remote network route if set, and only for p2p modes.
1038
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
1039
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
1040
	}
1041

    
1042
	// Write the settings for the keys
1043
	switch ($settings['mode']) {
1044
		case 'p2p_shared_key':
1045
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
1046
			break;
1047
		case 'p2p_tls':
1048
		case 'server_tls':
1049
		case 'server_tls_user':
1050
		case 'server_user':
1051
			// ca_chain() expects parameter to be passed by reference. 
1052
			// avoid passing the whole settings array, as param names or 
1053
			// types might change in future releases. 
1054
			$param = array('caref' => $settings['caref']);	
1055
			$ca = ca_chain($param);
1056
			$ca = base64_encode($ca);
1057
			
1058
			openvpn_add_keyfile($ca, $conf, $mode_id, "ca");
1059
			
1060
			unset($ca, $param);
1061

    
1062
			if (!empty($settings['certref'])) {
1063
				$cert = lookup_cert($settings['certref']);
1064
				openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
1065
				openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
1066
			}
1067
			if ($mode == 'server') {
1068
				if (is_numeric($settings['dh_length'])) {
1069
					if (!in_array($settings['dh_length'], array_keys($openvpn_dh_lengths))) {
1070
						/* The user selected a DH parameter length that does not have a corresponding file. */
1071
						log_error(gettext("Failed to construct OpenVPN server configuration. The selected DH Parameter length cannot be used."));
1072
						return;
1073
					}
1074
					$dh_file = "{$g['etc_path']}/dh-parameters.{$settings['dh_length']}";
1075
				} else {
1076
					$dh_file = $settings['dh_length'];
1077
				}
1078
				$conf .= "dh {$dh_file}\n";
1079
				if (!empty($settings['ecdh_curve']) && ($settings['ecdh_curve'] != "none") && openvpn_validate_curve($settings['ecdh_curve'])) {
1080
					$conf .= "ecdh-curve {$settings['ecdh_curve']}\n";
1081
				}
1082
			}
1083
			if (!empty($settings['crlref'])) {
1084
				$crl = lookup_crl($settings['crlref']);
1085
				crl_update($crl);
1086
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
1087
			}
1088
			if ($settings['tls']) {
1089
				if ($settings['tls_type'] == "crypt") {
1090
					$tls_directive = "tls-crypt";
1091
					$tlsopt = "";
1092
				} else {
1093
					$tls_directive = "tls-auth";
1094
					if ($mode == "server") {
1095
						$tlsopt = 0;
1096
					} else {
1097
						$tlsopt = 1;
1098
					}
1099
				}
1100
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, $tls_directive, $tlsopt);
1101
			}
1102
			break;
1103
	}
1104

    
1105
	$compression = "";
1106
	switch ($settings['compression']) {
1107
		case 'lz4':
1108
		case 'lz4-v2':
1109
		case 'lzo':
1110
		case 'stub':
1111
			$compression .= "compress {$settings['compression']}";
1112
			break;
1113
		case 'noadapt':
1114
			$compression .= "comp-noadapt";
1115
			break;
1116
		case 'adaptive':
1117
		case 'yes':
1118
		case 'no':
1119
			$compression .= "comp-lzo {$settings['compression']}";
1120
			break;
1121
		default:
1122
			/* Add nothing to the configuration */
1123
			break;
1124
	}
1125

    
1126
	if (!empty($compression)) {
1127
		$conf .= "{$compression}\n";
1128
		if ($settings['compression_push']) {
1129
			$conf .= "push \"{$compression}\"\n";
1130
		}
1131
	}
1132

    
1133
	if ($settings['passtos']) {
1134
		$conf .= "passtos\n";
1135
	}
1136

    
1137
	if ($settings['resolve_retry']) {
1138
		$conf .= "resolv-retry infinite\n";
1139
	} else if ($mode == 'client') {
1140
		$conf .= "resolv-retry infinite\n";
1141
	}
1142

    
1143
	if ($settings['dynamic_ip']) {
1144
		$conf .= "persist-remote-ip\n";
1145
		$conf .= "float\n";
1146
	}
1147

    
1148
	// If the server is not a TLS server or it has a tunnel network CIDR less than a /30, skip this.
1149
	if (in_array($settings['mode'], $openvpn_tls_server_modes) && (!empty($ip) && !empty($mask) && ($cidr < 30)) && $settings['dev_mode'] != "tap") {
1150
		if (empty($settings['topology'])) {
1151
			$settings['topology'] = "subnet";
1152
		}
1153
		$conf .= "topology {$settings['topology']}\n";
1154
	}
1155

    
1156
	// New client features
1157
	if ($mode == "client") {
1158
		// Dont pull routes checkbox
1159
		if ($settings['route_no_pull']) {
1160
			$conf .= "route-nopull\n";
1161
		}
1162

    
1163
		// Dont add/remove routes checkbox
1164
		if ($settings['route_no_exec']) {
1165
			$conf .= "route-noexec\n";
1166
		}
1167
	}
1168

    
1169
	openvpn_add_custom($settings, $conf);
1170

    
1171
	openvpn_create_dirs();
1172
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
1173
	file_put_contents($fpath, $conf);
1174
	unset($conf);
1175
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
1176
	file_put_contents($fpath, $interface);
1177
	//chown($fpath, 'nobody');
1178
	//chgrp($fpath, 'nobody');
1179
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
1180
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
1181
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
1182
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
1183
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
1184
}
1185

    
1186
function openvpn_restart($mode, $settings) {
1187
	global $g, $config;
1188

    
1189
	$vpnid = $settings['vpnid'];
1190
	$mode_id = $mode.$vpnid;
1191
	$lockhandle = lock("openvpnservice{$mode_id}", LOCK_EX);
1192
	/* kill the process if running */
1193
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
1194
	if (file_exists($pfile)) {
1195

    
1196
		/* read the pid file */
1197
		$pid = rtrim(file_get_contents($pfile));
1198
		unlink($pfile);
1199

    
1200
		/* send a term signal to the process */
1201
		posix_kill($pid, SIGTERM);
1202

    
1203
		/* wait until the process exits, or timeout and kill it */
1204
		$i = 0;
1205
		while (posix_kill($pid, 0)) {
1206
			usleep(250000);
1207
			if ($i > 10) {
1208
				log_error(sprintf(gettext('OpenVPN ID %1$s PID %2$s still running, killing.'), $mode_id, $pid));
1209
				posix_kill($pid, SIGKILL);
1210
				usleep(500000);
1211
			}
1212
			$i++;
1213
		}
1214
	}
1215

    
1216
	if (isset($settings['disable'])) {
1217
		unlock($lockhandle);
1218
		return;
1219
	}
1220

    
1221
	/* Do not start an instance if we are not CARP master on this vip! */
1222
	if (strstr($settings['interface'], "_vip") && get_carp_interface_status($settings['interface']) != "MASTER") {
1223
		unlock($lockhandle);
1224
		return;
1225
	}
1226

    
1227
	/* Check if client is bound to a gateway group */
1228
	$a_groups = return_gateway_groups_array();
1229
	if (is_array($a_groups[$settings['interface']])) {
1230
		/* the interface is a gateway group. If a vip is defined and its a CARP backup then do not start */
1231
		if (($a_groups[$settings['interface']][0]['vip'] <> "") && (get_carp_interface_status($a_groups[$settings['interface']][0]['vip']) != "MASTER")) {
1232
			unlock($lockhandle);
1233
			return;
1234
		}
1235
	}
1236

    
1237
	/* start the new process */
1238
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
1239
	openvpn_clear_route($mode, $settings);
1240
	mwexec("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
1241

    
1242
	if (!platform_booting()) {
1243
		send_event("filter reload");
1244
	}
1245
	unlock($lockhandle);
1246
}
1247

    
1248
function openvpn_delete($mode, & $settings) {
1249
	global $g, $config;
1250

    
1251
	$vpnid = $settings['vpnid'];
1252
	$mode_id = $mode.$vpnid;
1253

    
1254
	if (isset($settings['dev_mode'])) {
1255
		$tunname = "{$settings['dev_mode']}{$vpnid}";
1256
	} else {
1257
		/* defaults to tun */
1258
		$tunname = "tun{$vpnid}";
1259
	}
1260

    
1261
	if ($mode == "server") {
1262
		$devname = "ovpns{$vpnid}";
1263
	} else {
1264
		$devname = "ovpnc{$vpnid}";
1265
	}
1266

    
1267
	/* kill the process if running */
1268
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
1269
	if (file_exists($pfile)) {
1270

    
1271
		/* read the pid file */
1272
		$pid = trim(file_get_contents($pfile));
1273
		unlink($pfile);
1274

    
1275
		/* send a term signal to the process */
1276
		posix_kill($pid, SIGTERM);
1277
	}
1278

    
1279
	/* remove the device from the openvpn group */
1280
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
1281

    
1282
	/* restore the original adapter name */
1283
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
1284

    
1285
	/* remove the configuration files */
1286
	@array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
1287
}
1288

    
1289
function openvpn_resync_csc(& $settings) {
1290
	global $g, $config, $openvpn_tls_server_modes;
1291

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

    
1294
	if (isset($settings['disable'])) {
1295
		openvpn_delete_csc($settings);
1296
		return;
1297
	}
1298
	openvpn_create_dirs();
1299

    
1300
	if (empty($settings['server_list'])) {
1301
		$csc_server_list = array();
1302
	} else {
1303
		$csc_server_list = explode(",", $settings['server_list']);
1304
	}
1305

    
1306
	$conf = '';
1307
	if ($settings['block']) {
1308
		$conf .= "disable\n";
1309
	}
1310

    
1311
	if ($settings['push_reset']) {
1312
		$conf .= "push-reset\n";
1313
	}
1314

    
1315
	if ($settings['local_network']) {
1316
		$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
1317
	}
1318
	if ($settings['local_networkv6']) {
1319
		$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
1320
	}
1321

    
1322
	// Add a remote network iroute if set
1323
	if (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE) {
1324
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false, true);
1325
	}
1326
	// Add a remote network iroute if set
1327
	if (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE) {
1328
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false, true);
1329
	}
1330

    
1331
	openvpn_add_dhcpopts($settings, $conf);
1332

    
1333
	openvpn_add_custom($settings, $conf);
1334
	/* Loop through servers, find which ones can use this CSC */
1335
	if (is_array($config['openvpn']['openvpn-server'])) {
1336
		foreach ($config['openvpn']['openvpn-server'] as $serversettings) {
1337
			if (isset($serversettings['disable'])) {
1338
				continue;
1339
			}
1340
			if (in_array($serversettings['mode'], $openvpn_tls_server_modes)) {
1341
				if ($serversettings['vpnid'] && (empty($csc_server_list) || in_array($serversettings['vpnid'], $csc_server_list))) {
1342
					$csc_path = "{$csc_base_path}/server{$serversettings['vpnid']}/" . basename($settings['common_name']);
1343
					$csc_conf = $conf;
1344

    
1345
					if (!empty($serversettings['tunnel_network']) && !empty($settings['tunnel_network'])) {
1346
						list($ip, $mask) = explode('/', trim($settings['tunnel_network']));
1347
						if (($serversettings['dev_mode'] == 'tap') || ($serversettings['topology'] == "subnet")) {
1348
							$csc_conf .= "ifconfig-push {$ip} " . gen_subnet_mask($mask) . "\n";
1349
						} else {
1350
							/* Because this is being pushed, the order from the client's point of view. */
1351
							$baselong = gen_subnetv4($ip, $mask);
1352
							$serverip = ip_after($baselong, 1);
1353
							$clientip = ip_after($baselong, 2);
1354
							$csc_conf .= "ifconfig-push {$clientip} {$serverip}\n";
1355
						}
1356
					}
1357
					file_put_contents($csc_path, $csc_conf);
1358
					chown($csc_path, 'nobody');
1359
					chgrp($csc_path, 'nobody');
1360
				}
1361
			}
1362
		}
1363
	}
1364
}
1365

    
1366
function openvpn_resync_csc_all() {
1367
	global $config;
1368
	if (is_array($config['openvpn']['openvpn-csc'])) {
1369
		foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
1370
			openvpn_resync_csc($settings);
1371
		}
1372
	}
1373
}
1374

    
1375
function openvpn_delete_csc(& $settings) {
1376
	global $g, $config, $openvpn_tls_server_modes;
1377
	$csc_base_path = "{$g['varetc_path']}/openvpn-csc";
1378
	if (empty($settings['server_list'])) {
1379
		$csc_server_list = array();
1380
	} else {
1381
		$csc_server_list = explode(",", $settings['server_list']);
1382
	}
1383

    
1384
	/* Loop through servers, find which ones used this CSC */
1385
	if (is_array($config['openvpn']['openvpn-server'])) {
1386
		foreach ($config['openvpn']['openvpn-server'] as $serversettings) {
1387
			if (isset($serversettings['disable'])) {
1388
				continue;
1389
			}
1390
			if (in_array($serversettings['mode'], $openvpn_tls_server_modes)) {
1391
				if ($serversettings['vpnid'] && (empty($csc_server_list) || in_array($serversettings['vpnid'], $csc_server_list))) {
1392
					$csc_path = "{$csc_base_path}/server{$serversettings['vpnid']}/" . basename($settings['common_name']);
1393
					unlink_if_exists($csc_path);
1394
				}
1395
			}
1396
		}
1397
	}
1398
}
1399

    
1400
// Resync the configuration and restart the VPN
1401
function openvpn_resync($mode, $settings) {
1402
	openvpn_reconfigure($mode, $settings);
1403
	openvpn_restart($mode, $settings);
1404
}
1405

    
1406
// Resync and restart all VPNs
1407
function openvpn_resync_all($interface = "") {
1408
	global $g, $config;
1409

    
1410
	openvpn_create_dirs();
1411

    
1412
	if (!is_array($config['openvpn'])) {
1413
		$config['openvpn'] = array();
1414
	}
1415

    
1416
/*
1417
	if (!$config['openvpn']['dh-parameters']) {
1418
		echo "Configuring OpenVPN Parameters ...\n";
1419
		$dh_parameters = openvpn_create_dhparams(1024);
1420
		$dh_parameters = base64_encode($dh_parameters);
1421
		$config['openvpn']['dh-parameters'] = $dh_parameters;
1422
		write_config("OpenVPN DH parameters");
1423
	}
1424

    
1425
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
1426
	if (!file_exists($path_ovdh)) {
1427
		$dh_parameters = $config['openvpn']['dh-parameters'];
1428
		$dh_parameters = base64_decode($dh_parameters);
1429
		file_put_contents($path_ovdh, $dh_parameters);
1430
	}
1431
*/
1432
	if ($interface <> "") {
1433
		log_error(sprintf(gettext("Resyncing OpenVPN instances for interface %s."), convert_friendly_interface_to_friendly_descr($interface)));
1434
	} else {
1435
		log_error(gettext("Resyncing OpenVPN instances."));
1436
	}
1437

    
1438
	if (is_array($config['openvpn']['openvpn-server'])) {
1439
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1440
			if ($interface <> "" && $interface != $settings['interface']) {
1441
				continue;
1442
			}
1443
			openvpn_resync('server', $settings);
1444
		}
1445
	}
1446

    
1447
	if (is_array($config['openvpn']['openvpn-client'])) {
1448
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1449
			if ($interface <> "" && $interface != $settings['interface']) {
1450
				continue;
1451
			}
1452
			openvpn_resync('client', $settings);
1453
		}
1454
	}
1455

    
1456
	openvpn_resync_csc_all();
1457

    
1458
}
1459

    
1460
// Resync and restart all VPNs using a gateway group.
1461
function openvpn_resync_gwgroup($gwgroupname = "") {
1462
	global $g, $config;
1463

    
1464
	if ($gwgroupname <> "") {
1465
		if (is_array($config['openvpn']['openvpn-server'])) {
1466
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1467
				if ($gwgroupname == $settings['interface']) {
1468
					log_error(sprintf(gettext('Resyncing OpenVPN for gateway group %1$s server %2$s.'), $gwgroupname, $settings["description"]));
1469
					openvpn_resync('server', $settings);
1470
				}
1471
			}
1472
		}
1473

    
1474
		if (is_array($config['openvpn']['openvpn-client'])) {
1475
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1476
				if ($gwgroupname == $settings['interface']) {
1477
					log_error(sprintf(gettext('Resyncing OpenVPN for gateway group %1$s client %2$s.'), $gwgroupname, $settings["description"]));
1478
					openvpn_resync('client', $settings);
1479
				}
1480
			}
1481
		}
1482

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

    
1485
	} else {
1486
		log_error(gettext("openvpn_resync_gwgroup called with null gwgroup parameter."));
1487
	}
1488
}
1489

    
1490
function openvpn_get_active_servers($type="multipoint") {
1491
	global $config, $g;
1492

    
1493
	$servers = array();
1494
	if (is_array($config['openvpn']['openvpn-server'])) {
1495
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1496
			if (empty($settings) || isset($settings['disable'])) {
1497
				continue;
1498
			}
1499

    
1500
			$prot = $settings['protocol'];
1501
			$port = $settings['local_port'];
1502

    
1503
			$server = array();
1504
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
1505
			$server['mode'] = $settings['mode'];
1506
			if ($settings['description']) {
1507
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
1508
			} else {
1509
				$server['name'] = "Server {$prot}:{$port}";
1510
			}
1511
			$server['conns'] = array();
1512
			$server['vpnid'] = $settings['vpnid'];
1513
			$server['mgmt'] = "server{$server['vpnid']}";
1514
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
1515
			list($tn, $sm) = explode('/', trim($settings['tunnel_network']));
1516

    
1517
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30)) && ($type == "p2p")) {
1518
				$servers[] = openvpn_get_client_status($server, $socket);
1519
			} elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30)) {
1520
				$servers[] = openvpn_get_server_status($server, $socket);
1521
			}
1522
		}
1523
	}
1524
	return $servers;
1525
}
1526

    
1527
function openvpn_get_server_status($server, $socket) {
1528
	$errval = null;
1529
	$errstr = null;
1530
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1531
	if ($fp) {
1532
		stream_set_timeout($fp, 1);
1533

    
1534
		/* send our status request */
1535
		fputs($fp, "status 2\n");
1536

    
1537
		/* recv all response lines */
1538
		while (!feof($fp)) {
1539

    
1540
			/* read the next line */
1541
			$line = fgets($fp, 1024);
1542

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

    
1548
			/* parse header list line */
1549
			if (strstr($line, "HEADER")) {
1550
				continue;
1551
			}
1552

    
1553
			/* parse end of output line */
1554
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1555
				break;
1556
			}
1557

    
1558
			/* parse client list line */
1559
			if (strstr($line, "CLIENT_LIST")) {
1560
				$list = explode(",", $line);
1561
				$conn = array();
1562
				$conn['common_name'] = $list[1];
1563
				$conn['remote_host'] = $list[2];
1564
				$conn['virtual_addr'] = $list[3];
1565
				$conn['virtual_addr6'] = $list[4];
1566
				$conn['bytes_recv'] = $list[5];
1567
				$conn['bytes_sent'] = $list[6];
1568
				$conn['connect_time'] = $list[7];
1569
				$conn['connect_time_unix'] = $list[8];
1570
				$conn['user_name'] = $list[9];
1571
				$conn['client_id'] = $list[10];
1572
				$conn['peer_id'] = $list[11];
1573
				$server['conns'][] = $conn;
1574
			}
1575
			/* parse routing table lines */
1576
			if (strstr($line, "ROUTING_TABLE")) {
1577
				$list = explode(",", $line);
1578
				$conn = array();
1579
				$conn['virtual_addr'] = $list[1];
1580
				$conn['common_name'] = $list[2];
1581
				$conn['remote_host'] = $list[3];
1582
				$conn['last_time'] = $list[4];
1583
				$server['routes'][] = $conn;
1584
			}
1585
		}
1586

    
1587
		/* cleanup */
1588
		fclose($fp);
1589
	} else {
1590
		$conn = array();
1591
		$conn['common_name'] = "[error]";
1592
		$conn['remote_host'] = gettext("Unable to contact daemon");
1593
		$conn['virtual_addr'] = gettext("Service not running?");
1594
		$conn['bytes_recv'] = 0;
1595
		$conn['bytes_sent'] = 0;
1596
		$conn['connect_time'] = 0;
1597
		$server['conns'][] = $conn;
1598
	}
1599
	return $server;
1600
}
1601

    
1602
function openvpn_get_active_clients() {
1603
	global $config, $g;
1604

    
1605
	$clients = array();
1606
	if (is_array($config['openvpn']['openvpn-client'])) {
1607
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1608

    
1609
			if (empty($settings) || isset($settings['disable'])) {
1610
				continue;
1611
			}
1612

    
1613
			$prot = $settings['protocol'];
1614
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1615

    
1616
			$client = array();
1617
			$client['port'] = $settings['local_port'];
1618
			if ($settings['description']) {
1619
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1620
			} else {
1621
				$client['name'] = "Client {$prot}{$port}";
1622
			}
1623

    
1624
			$client['vpnid'] = $settings['vpnid'];
1625
			$client['mgmt'] = "client{$client['vpnid']}";
1626
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1627
			$client['status']="down";
1628

    
1629
			$clients[] = openvpn_get_client_status($client, $socket);
1630
		}
1631
	}
1632
	return $clients;
1633
}
1634

    
1635
function openvpn_get_client_status($client, $socket) {
1636
	$errval = null;
1637
	$errstr = null;
1638
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1639
	if ($fp) {
1640
		stream_set_timeout($fp, 1);
1641
		/* send our status request */
1642
		fputs($fp, "state 1\n");
1643

    
1644
		/* recv all response lines */
1645
		while (!feof($fp)) {
1646
			/* read the next line */
1647
			$line = fgets($fp, 1024);
1648

    
1649
			$info = stream_get_meta_data($fp);
1650
			if ($info['timed_out']) {
1651
				break;
1652
			}
1653

    
1654
			/* Get the client state */
1655
			if (strstr($line, "CONNECTED")) {
1656
				$client['status'] = "up";
1657
				$list = explode(",", $line);
1658

    
1659
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1660
				$client['virtual_addr'] = $list[3];
1661
				$client['remote_host'] = $list[4];
1662
				$client['remote_port'] = $list[5];
1663
				$client['local_host'] = $list[6];
1664
				$client['local_port'] = $list[7];
1665
				$client['virtual_addr6'] = $list[8];
1666
			}
1667
			if (strstr($line, "CONNECTING")) {
1668
				$client['status'] = "connecting";
1669
			}
1670
			if (strstr($line, "ASSIGN_IP")) {
1671
				$client['status'] = "waiting";
1672
				$list = explode(",", $line);
1673

    
1674
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1675
				$client['virtual_addr'] = $list[3];
1676
			}
1677
			if (strstr($line, "RECONNECTING")) {
1678
				$client['status'] = "reconnecting";
1679
				$list = explode(",", $line);
1680

    
1681
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1682
				$client['status'] .= "; " . $list[2];
1683
			}
1684
			/* parse end of output line */
1685
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1686
				break;
1687
			}
1688
		}
1689

    
1690
		/* If up, get read/write stats */
1691
		if (strcmp($client['status'], "up") == 0) {
1692
			fputs($fp, "status 2\n");
1693
			/* recv all response lines */
1694
			while (!feof($fp)) {
1695
				/* read the next line */
1696
				$line = fgets($fp, 1024);
1697

    
1698
				$info = stream_get_meta_data($fp);
1699
				if ($info['timed_out']) {
1700
					break;
1701
				}
1702

    
1703
				if (strstr($line, "TCP/UDP read bytes")) {
1704
					$list = explode(",", $line);
1705
					$client['bytes_recv'] = $list[1];
1706
				}
1707

    
1708
				if (strstr($line, "TCP/UDP write bytes")) {
1709
					$list = explode(",", $line);
1710
					$client['bytes_sent'] = $list[1];
1711
				}
1712

    
1713
				/* parse end of output line */
1714
				if (strstr($line, "END")) {
1715
					break;
1716
				}
1717
			}
1718
		}
1719

    
1720
		fclose($fp);
1721

    
1722
	} else {
1723
		$client['remote_host'] = gettext("Unable to contact daemon");
1724
		$client['virtual_addr'] = gettext("Service not running?");
1725
		$client['bytes_recv'] = 0;
1726
		$client['bytes_sent'] = 0;
1727
		$client['connect_time'] = 0;
1728
	}
1729
	return $client;
1730
}
1731

    
1732
function openvpn_kill_client($port, $remipp) {
1733
	global $g;
1734

    
1735
	//$tcpsrv = "tcp://127.0.0.1:{$port}";
1736
	$tcpsrv = "unix://{$g['varetc_path']}/openvpn/{$port}.sock";
1737
	$errval = null;
1738
	$errstr = null;
1739

    
1740
	/* open a tcp connection to the management port of each server */
1741
	$fp = @stream_socket_client($tcpsrv, $errval, $errstr, 1);
1742
	$killed = -1;
1743
	if ($fp) {
1744
		stream_set_timeout($fp, 1);
1745
		fputs($fp, "kill {$remipp}\n");
1746
		while (!feof($fp)) {
1747
			$line = fgets($fp, 1024);
1748

    
1749
			$info = stream_get_meta_data($fp);
1750
			if ($info['timed_out']) {
1751
				break;
1752
			}
1753

    
1754
			/* parse header list line */
1755
			if (strpos($line, "INFO:") !== false) {
1756
				continue;
1757
			}
1758
			if (strpos($line, "SUCCESS") !== false) {
1759
				$killed = 0;
1760
			}
1761
			break;
1762
		}
1763
		fclose($fp);
1764
	}
1765
	return $killed;
1766
}
1767

    
1768
function openvpn_refresh_crls() {
1769
	global $g, $config;
1770

    
1771
	openvpn_create_dirs();
1772

    
1773
	if (is_array($config['openvpn']['openvpn-server'])) {
1774
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1775
			if (empty($settings)) {
1776
				continue;
1777
			}
1778
			if (isset($settings['disable'])) {
1779
				continue;
1780
			}
1781
			// Write the settings for the keys
1782
			switch ($settings['mode']) {
1783
				case 'p2p_tls':
1784
				case 'server_tls':
1785
				case 'server_tls_user':
1786
				case 'server_user':
1787
					if (!empty($settings['crlref'])) {
1788
						$crl = lookup_crl($settings['crlref']);
1789
						crl_update($crl);
1790
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1791
						file_put_contents($fpath, base64_decode($crl['text']));
1792
						@chmod($fpath, 0644);
1793
					}
1794
					break;
1795
			}
1796
		}
1797
	}
1798
}
1799

    
1800
function openvpn_create_dirs() {
1801
	global $g, $config, $openvpn_tls_server_modes;
1802
	if (!is_dir("{$g['varetc_path']}/openvpn")) {
1803
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1804
	}
1805
	if (!is_dir("{$g['varetc_path']}/openvpn-csc")) {
1806
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1807
	}
1808

    
1809
	/* Check for enabled servers and create server-specific CSC dirs */
1810
	if (is_array($config['openvpn']['openvpn-server'])) {
1811
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1812
			if (isset($settings['disable'])) {
1813
				continue;
1814
			}
1815
			if (in_array($settings['mode'], $openvpn_tls_server_modes)) {
1816
				if ($settings['vpnid']) {
1817
					safe_mkdir("{$g['varetc_path']}/openvpn-csc/server{$settings['vpnid']}");
1818
				}
1819
			}
1820
		}
1821
	}
1822
}
1823

    
1824
function openvpn_get_interface_ip($ip, $cidr) {
1825
	$subnet = gen_subnetv4($ip, $cidr);
1826
	$ip1 = ip_after($subnet);
1827
	$ip2 = ip_after($ip1);
1828
	return array($ip1, $ip2);
1829
}
1830

    
1831
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1832
	$basev6 = gen_subnetv6($ipv6, $prefix);
1833
	// Is there a better way to do this math?
1834
	$ipv6_arr = explode(':', $basev6);
1835
	$last = hexdec(array_pop($ipv6_arr));
1836
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1837
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1838
	return array($ipv6_1, $ipv6_2);
1839
}
1840

    
1841
function openvpn_clear_route($mode, $settings) {
1842
	if (empty($settings['tunnel_network'])) {
1843
		return;
1844
	}
1845
	list($ip, $cidr) = explode('/', trim($settings['tunnel_network']));
1846
	$mask = gen_subnet_mask($cidr);
1847
	$clear_route = false;
1848

    
1849
	switch ($settings['mode']) {
1850
		case 'shared_key':
1851
			$clear_route = true;
1852
			break;
1853
		case 'p2p_tls':
1854
		case 'p2p_shared_key':
1855
			if ($cidr == 30) {
1856
				$clear_route = true;
1857
			}
1858
			break;
1859
	}
1860

    
1861
	if ($clear_route && !empty($ip) && !empty($mask)) {
1862
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $cidr);
1863
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1864
		/* XXX: Family for route? */
1865
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1866
	}
1867
}
1868

    
1869
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
1870
	$routes = "";
1871
	if (empty($value)) {
1872
		return "";
1873
	}
1874
	$networks = explode(',', $value);
1875

    
1876
	foreach ($networks as $network) {
1877
		if ($ipproto == "ipv4") {
1878
			$route = openvpn_gen_route_ipv4($network, $iroute);
1879
		} else {
1880
			$route = openvpn_gen_route_ipv6($network, $iroute);
1881
		}
1882

    
1883
		if ($push) {
1884
			$routes .= "push \"{$route}\"\n";
1885
		} else {
1886
			$routes .= "{$route}\n";
1887
		}
1888
	}
1889
	return $routes;
1890
}
1891

    
1892
function openvpn_gen_route_ipv4($network, $iroute = false) {
1893
	$i = ($iroute) ? "i" : "";
1894
	list($ip, $mask) = explode('/', trim($network));
1895
	$mask = gen_subnet_mask($mask);
1896
	return "{$i}route $ip $mask";
1897
}
1898

    
1899
function openvpn_gen_route_ipv6($network, $iroute = false) {
1900
	$i = ($iroute) ? "i" : "";
1901
	list($ipv6, $prefix) = explode('/', trim($network));
1902
	if (empty($prefix)) {
1903
		$prefix = "128";
1904
	}
1905
	return "{$i}route-ipv6 ${ipv6}/${prefix}";
1906
}
1907

    
1908
function openvpn_get_settings($mode, $vpnid) {
1909
	global $config;
1910

    
1911
	if (is_array($config['openvpn']['openvpn-server'])) {
1912
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1913
			if (isset($settings['disable'])) {
1914
				continue;
1915
			}
1916

    
1917
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1918
				return $settings;
1919
			}
1920
		}
1921
	}
1922

    
1923
	if (is_array($config['openvpn']['openvpn-client'])) {
1924
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1925
			if (isset($settings['disable'])) {
1926
				continue;
1927
			}
1928

    
1929
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1930
				return $settings;
1931
			}
1932
		}
1933
	}
1934

    
1935
	return array();
1936
}
1937

    
1938
function openvpn_restart_by_vpnid($mode, $vpnid) {
1939
	$settings = openvpn_get_settings($mode, $vpnid);
1940
	openvpn_restart($mode, $settings);
1941
}
1942

    
1943
?>
(28-28/51)