Project

General

Profile

Download (51.9 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 Electric Sheep Fencing, LLC.
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
	All rights reserved.
15

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

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

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

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

    
30
	3. All advertising materials mentioning features or use of this software
31
	   must display the following acknowledgment:
32
	   "This product includes software developed by the pfSense Project
33
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
34

    
35
	4. The names "pfSense" and "pfSense Project" must not be used to
36
	   endorse or promote products derived from this software without
37
	   prior written permission. For written permission, please contact
38
	   coreteam@pfsense.org.
39

    
40
	5. Products derived from this software may not be called "pfSense"
41
	   nor may "pfSense" appear in their names without prior written
42
	   permission of the Electric Sheep Fencing, LLC.
43

    
44
	6. Redistributions of any form whatsoever must retain the following
45
	   acknowledgment:
46

    
47
	"This product includes software developed by the pfSense Project
48
	for use in the pfSense software distribution (http://www.pfsense.org/).
49

    
50
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
51
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
54
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61
	OF THE POSSIBILITY OF SUCH DAMAGE.
62
*/
63

    
64
require_once('config.inc');
65
require_once("certs.inc");
66
require_once('pfsense-utils.inc');
67
require_once("auth.inc");
68

    
69
global $openvpn_prots;
70
$openvpn_prots = array("UDP", "UDP6", "TCP", "TCP6");
71

    
72
global $openvpn_dev_mode;
73
$openvpn_dev_mode = array("tun", "tap");
74

    
75
global $openvpn_verbosity_level;
76
$openvpn_verbosity_level = array(
77
	0 =>	gettext("none"),
78
	1 =>	gettext("default"),
79
	2 =>	"2",
80
	3 =>	gettext("3 (recommended)"),
81
	4 =>	"4",
82
	5 => 	"5",
83
	6 => 	"6",
84
	7 => 	"7",
85
	8 => 	"8",
86
	9 => 	"9",
87
	10 => 	"10",
88
	11 => 	"11"
89
);
90

    
91
/*
92
 * The User Auth mode below is disabled because
93
 * OpenVPN erroneously requires that we provide
94
 * a CA configuration parameter. In this mode,
95
 * clients don't send a certificate so there is
96
 * no need for a CA. If we require that admins
97
 * provide one in the pfSense UI due to a bogus
98
 * requirement imposed by OpenVPN, it could be
99
 * considered very confusing ( I know I was ).
100
 *
101
 * -mgrooms
102
 */
103

    
104
global $openvpn_dh_lengths;
105
$openvpn_dh_lengths = array(
106
	1024, 2048, 4096);
107

    
108
global $openvpn_cert_depths;
109
$openvpn_cert_depths = array(
110
	1 => gettext("One (Client+Server)"),
111
	2 => gettext("Two (Client+Intermediate+Server)"),
112
	3 => gettext("Three (Client+2xIntermediate+Server)"),
113
	4 => gettext("Four (Client+3xIntermediate+Server)"),
114
	5 => gettext("Five (Client+4xIntermediate+Server)")
115
);
116

    
117
global $openvpn_server_modes;
118
$openvpn_server_modes = array(
119
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
120
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
121
	'server_tls' => gettext("Remote Access ( SSL/TLS )"),
122
	'server_user' => gettext("Remote Access ( User Auth )"),
123
	'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
124

    
125
global $openvpn_tls_server_modes;
126
$openvpn_tls_server_modes = array('p2p_tls', 'server_tls', 'server_user', 'server_tls_user');
127

    
128
global $openvpn_client_modes;
129
$openvpn_client_modes = array(
130
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
131
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"));
132

    
133
global $openvpn_compression_modes;
134
$openvpn_compression_modes = array(
135
	'' => gettext("No Preference"),
136
	'no' => gettext("Disabled - No Compression"),
137
	'adaptive' => gettext("Enabled with Adaptive Compression"),
138
	'yes' => gettext("Enabled without Adaptive Compression"));
139

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

    
147
function openvpn_build_mode_list() {
148
	global $openvpn_server_modes;
149

    
150
	$list = array();
151

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

    
156
	return($list);
157
}
158

    
159
function openvpn_build_if_list() {
160
	$list = array();
161

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

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

    
181
		$interfaces[$name] = "GW Group {$name}";
182
	}
183

    
184
	$interfaces['lo0'] = "Localhost";
185
	$interfaces['any'] = "any";
186

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

    
191
	return($list);
192
}
193

    
194
function openvpn_build_crl_list() {
195
	global $a_crl;
196

    
197
	$list = array('' => 'None');
198

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

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

    
207
		$list[$crl['refid']] = $crl['descr'] . $caname;
208
	}
209

    
210
	return($list);
211
}
212

    
213
function openvpn_build_cert_list($include_none = false, $prioritize_server_certs = false) {
214
	global $a_cert;
215

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

    
222
	$non_server_list = array();
223

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

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

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

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

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

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

    
268
function openvpn_build_bridge_list() {
269
	$list = array();
270

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

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

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

    
286
	return($list);
287
}
288

    
289
function openvpn_create_key() {
290

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

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

    
299
	return $rslt;
300
}
301

    
302
function openvpn_create_dhparams($bits) {
303

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

    
309
	$rslt = stream_get_contents($fp);
310
	pclose($fp);
311

    
312
	return $rslt;
313
}
314

    
315
function openvpn_vpnid_used($vpnid) {
316
	global $config;
317

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

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

    
334
	return false;
335
}
336

    
337
function openvpn_vpnid_next() {
338

    
339
	$vpnid = 1;
340
	while (openvpn_vpnid_used($vpnid)) {
341
		$vpnid++;
342
	}
343

    
344
	return $vpnid;
345
}
346

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

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

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

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

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

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

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

    
384
	return 0;
385
}
386

    
387
function openvpn_port_next($prot, $interface = "wan") {
388

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

    
397
	return $port;
398
}
399

    
400
function openvpn_get_cipherlist() {
401

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

    
414
function openvpn_get_digestlist() {
415

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

    
428
function openvpn_get_engines() {
429
	$openssl_engines = array('none' => gettext('No Hardware Crypto Acceleration'));
430
	exec("/usr/bin/openssl engine -t -c", $openssl_engine_output);
431
	$openssl_engine_output = implode("\n", $openssl_engine_output);
432
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
433
	$openssl_engine_output = explode("\n", $openssl_engine_output);
434

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

    
465
function openvpn_validate_engine($engine) {
466
	$engines = openvpn_get_engines();
467
	return array_key_exists($engine, $engines);
468
}
469

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

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

    
486
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
487
	$value = trim($value);
488
	$error = false;
489
	if (empty($value)) {
490
		return false;
491
	}
492
	$networks = explode(',', $value);
493

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

    
498
	foreach ($networks as $network) {
499
		if ($ipproto == "ipv4") {
500
			$error = !openvpn_validate_cidr_ipv4($network);
501
		} else {
502
			$error = !openvpn_validate_cidr_ipv6($network);
503
		}
504
		if ($error) {
505
			break;
506
		}
507
	}
508

    
509
	if ($error) {
510
		return sprintf(gettext("The field '%1\$s' must contain only valid %2\$s CIDR range(s) separated by commas."), $name, $ipproto);
511
	} else {
512
		return false;
513
	}
514
}
515

    
516
function openvpn_validate_cidr_ipv4($value) {
517
	$value = trim($value);
518
	if (!empty($value)) {
519
		list($ip, $mask) = explode('/', $value);
520
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0)) {
521
			return false;
522
		}
523
	}
524
	return true;
525
}
526

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

    
541
function openvpn_add_dhcpopts(& $settings, & $conf) {
542

    
543
	if (!empty($settings['dns_domain'])) {
544
		$conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
545
	}
546

    
547
	if (!empty($settings['dns_server1'])) {
548
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
549
	}
550
	if (!empty($settings['dns_server2'])) {
551
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
552
	}
553
	if (!empty($settings['dns_server3'])) {
554
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
555
	}
556
	if (!empty($settings['dns_server4'])) {
557
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
558
	}
559

    
560
	if (!empty($settings['push_register_dns'])) {
561
		$conf .= "push \"register-dns\"\n";
562
	}
563

    
564
	if (!empty($settings['ntp_server1'])) {
565
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
566
	}
567
	if (!empty($settings['ntp_server2'])) {
568
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
569
	}
570

    
571
	if ($settings['netbios_enable']) {
572

    
573
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0)) {
574
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
575
		}
576
		if (!empty($settings['dhcp_nbtscope'])) {
577
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
578
		}
579

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

    
587
		if (!empty($settings['nbdd_server1'])) {
588
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
589
		}
590
	}
591

    
592
	if ($settings['gwredir']) {
593
		$conf .= "push \"redirect-gateway def1\"\n";
594
	}
595
}
596

    
597
function openvpn_add_custom(& $settings, & $conf) {
598

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

    
601
		$options = explode(';', $settings['custom_options']);
602

    
603
		if (is_array($options)) {
604
			foreach ($options as $option) {
605
				$conf .= "$option\n";
606
			}
607
		} else {
608
			$conf .= "{$settings['custom_options']}\n";
609
		}
610
	}
611
}
612

    
613
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
614
	global $g;
615

    
616
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
617
	openvpn_create_dirs();
618
	file_put_contents($fpath, base64_decode($data));
619
	//chown($fpath, 'nobody');
620
	//chgrp($fpath, 'nobody');
621
	@chmod($fpath, 0600);
622

    
623
	$conf .= "{$directive} {$fpath} {$opt}\n";
624
}
625

    
626
function openvpn_reconfigure($mode, $settings) {
627
	global $g, $config, $openvpn_tls_server_modes;
628

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

    
642
	$vpnid = $settings['vpnid'];
643
	$mode_id = $mode.$vpnid;
644

    
645
	if (isset($settings['dev_mode'])) {
646
		$tunname = "{$settings['dev_mode']}{$vpnid}";
647
	} else {
648
		/* defaults to tun */
649
		$tunname = "tun{$vpnid}";
650
		$settings['dev_mode'] = "tun";
651
	}
652

    
653
	if ($mode == "server") {
654
		$devname = "ovpns{$vpnid}";
655
	} else {
656
		$devname = "ovpnc{$vpnid}";
657
	}
658

    
659
	/* is our device already configured */
660
	if (!does_interface_exist($devname)) {
661

    
662
		/* create the tap device if required */
663
		if (!file_exists("/dev/{$tunname}")) {
664
			exec("/sbin/ifconfig " . escapeshellarg($tunname) . " create");
665
		}
666

    
667
		/* rename the device */
668
		mwexec("/sbin/ifconfig " . escapeshellarg($tunname) . " name " . escapeshellarg($devname));
669

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

    
673
		$ifname = convert_real_interface_to_friendly_interface_name($devname);
674
		$grouptmp = link_interface_to_group($ifname);
675
		if (!empty($grouptmp)) {
676
			array_walk($grouptmp, 'interface_group_add_member');
677
		}
678
		unset($grouptmp, $ifname);
679
	}
680

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

    
691
	$interface = get_failover_interface($settings['interface']);
692
	// The IP address in the settings can be an IPv4 or IPv6 address associated with the interface
693
	$ipaddr = $settings['ipaddr'];
694

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

    
713

    
714
	$conf = "dev {$devname}\n";
715
	if (isset($settings['verbosity_level'])) {
716
		$conf .= "verb {$settings['verbosity_level']}\n";
717
	}
718

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

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

    
759
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none")) {
760
		$conf .= "engine {$settings['engine']}\n";
761
	}
762

    
763
	// server specific settings
764
	if ($mode == 'server') {
765

    
766
		list($ip, $cidr) = explode('/', trim($settings['tunnel_network']));
767
		list($ipv6, $prefix) = explode('/', trim($settings['tunnel_networkv6']));
768
		$mask = gen_subnet_mask($cidr);
769

    
770
		// configure tls modes
771
		switch ($settings['mode']) {
772
			case 'p2p_tls':
773
			case 'server_tls':
774
			case 'server_user':
775
			case 'server_tls_user':
776
				$conf .= "tls-server\n";
777
				break;
778
		}
779

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

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

    
871
		// The local port to listen on
872
		$conf .= "lport {$settings['local_port']}\n";
873

    
874
		// The management port to listen on
875
		// Use unix socket to overcome the problem on any type of server
876
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
877
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
878

    
879
		if ($settings['maxclients']) {
880
			$conf .= "max-clients {$settings['maxclients']}\n";
881
		}
882

    
883
		// Can we push routes
884
		if ($settings['local_network']) {
885
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
886
		}
887
		if ($settings['local_networkv6']) {
888
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
889
		}
890

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

    
907
	// client specific settings
908

    
909
	if ($mode == 'client') {
910

    
911
		// configure p2p mode
912
		switch ($settings['mode']) {
913
			case 'p2p_tls':
914
				$conf .= "tls-client\n";
915
			case 'shared_key':
916
				$conf .= "client\n";
917
				break;
918
		}
919

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

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

    
934
		// The remote server
935
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
936

    
937
		if (!empty($settings['use_shaper'])) {
938
			$conf .= "shaper {$settings['use_shaper']}\n";
939
		}
940

    
941
		if (!empty($settings['tunnel_network'])) {
942
			list($ip, $cidr) = explode('/', trim($settings['tunnel_network']));
943
			$mask = gen_subnet_mask($cidr);
944
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $cidr);
945
			if ($settings['dev_mode'] == 'tun') {
946
				$conf .= "ifconfig {$ip2} {$ip1}\n";
947
			} else {
948
				$conf .= "ifconfig {$ip2} {$mask}\n";
949
			}
950
		}
951

    
952
		if (!empty($settings['tunnel_networkv6'])) {
953
			list($ipv6, $prefix) = explode('/', trim($settings['tunnel_networkv6']));
954
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
955
			if ($settings['dev_mode'] == 'tun') {
956
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
957
			} else {
958
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
959
			}
960
		}
961

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

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

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

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

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

    
1037
	if (!empty($settings['compression'])) {
1038
		$conf .= "comp-lzo {$settings['compression']}\n";
1039
	}
1040

    
1041
	if ($settings['passtos']) {
1042
		$conf .= "passtos\n";
1043
	}
1044

    
1045
	if ($settings['resolve_retry']) {
1046
		$conf .= "resolv-retry infinite\n";
1047
	} else if ($mode == 'client') {
1048
		$conf .= "resolv-retry infinite\n";
1049
	}
1050

    
1051
	if ($settings['dynamic_ip']) {
1052
		$conf .= "persist-remote-ip\n";
1053
		$conf .= "float\n";
1054
	}
1055

    
1056
	// If the server is not a TLS server or it has a tunnel network CIDR less than a /30, skip this.
1057
	if (in_array($settings['mode'], $openvpn_tls_server_modes) && (!empty($ip) && !empty($mask) && ($cidr < 30)) && $settings['dev_mode'] != "tap") {
1058
		if (empty($settings['topology'])) {
1059
			$settings['topology'] = "subnet";
1060
		}
1061
		$conf .= "topology {$settings['topology']}\n";
1062
	}
1063

    
1064
	// New client features
1065
	if ($mode == "client") {
1066
		// Dont pull routes checkbox
1067
		if ($settings['route_no_pull']) {
1068
			$conf .= "route-nopull\n";
1069
		}
1070

    
1071
		// Dont add/remove routes checkbox
1072
		if ($settings['route_no_exec']) {
1073
			$conf .= "route-noexec\n";
1074
		}
1075
	}
1076

    
1077
	openvpn_add_custom($settings, $conf);
1078

    
1079
	openvpn_create_dirs();
1080
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
1081
	file_put_contents($fpath, $conf);
1082
	unset($conf);
1083
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
1084
	file_put_contents($fpath, $interface);
1085
	//chown($fpath, 'nobody');
1086
	//chgrp($fpath, 'nobody');
1087
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
1088
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
1089
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
1090
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
1091
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
1092
}
1093

    
1094
function openvpn_restart($mode, $settings) {
1095
	global $g, $config;
1096

    
1097
	$vpnid = $settings['vpnid'];
1098
	$mode_id = $mode.$vpnid;
1099

    
1100
	/* kill the process if running */
1101
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
1102
	if (file_exists($pfile)) {
1103

    
1104
		/* read the pid file */
1105
		$pid = rtrim(file_get_contents($pfile));
1106
		unlink($pfile);
1107

    
1108
		/* send a term signal to the process */
1109
		posix_kill($pid, SIGTERM);
1110

    
1111
		/* wait until the process exits, or timeout and kill it */
1112
		$i = 0;
1113
		while (posix_kill($pid, 0)) {
1114
			usleep(250000);
1115
			if ($i > 10) {
1116
				log_error(sprintf(gettext('OpenVPN ID %1$s PID %2$s still running, killing.'), $mode_id, $pid));
1117
				posix_kill($pid, SIGKILL);
1118
				usleep(500000);
1119
			}
1120
			$i++;
1121
		}
1122
	}
1123

    
1124
	if (isset($settings['disable'])) {
1125
		return;
1126
	}
1127

    
1128
	/* Do not start a client if we are a CARP backup on this vip! */
1129
	if (($mode == "client") && (strstr($settings['interface'], "_vip") && get_carp_interface_status($settings['interface']) != "MASTER")) {
1130
		return;
1131
	}
1132

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

    
1142
	/* start the new process */
1143
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
1144
	openvpn_clear_route($mode, $settings);
1145
	mwexec_bg("/usr/local/sbin/openvpn --config " . escapeshellarg($fpath));
1146

    
1147
	if (!platform_booting()) {
1148
		send_event("filter reload");
1149
	}
1150
}
1151

    
1152
function openvpn_delete($mode, & $settings) {
1153
	global $g, $config;
1154

    
1155
	$vpnid = $settings['vpnid'];
1156
	$mode_id = $mode.$vpnid;
1157

    
1158
	if (isset($settings['dev_mode'])) {
1159
		$tunname = "{$settings['dev_mode']}{$vpnid}";
1160
	} else {
1161
		/* defaults to tun */
1162
		$tunname = "tun{$vpnid}";
1163
	}
1164

    
1165
	if ($mode == "server") {
1166
		$devname = "ovpns{$vpnid}";
1167
	} else {
1168
		$devname = "ovpnc{$vpnid}";
1169
	}
1170

    
1171
	/* kill the process if running */
1172
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
1173
	if (file_exists($pfile)) {
1174

    
1175
		/* read the pid file */
1176
		$pid = trim(file_get_contents($pfile));
1177
		unlink($pfile);
1178

    
1179
		/* send a term signal to the process */
1180
		posix_kill($pid, SIGTERM);
1181
	}
1182

    
1183
	/* remove the device from the openvpn group */
1184
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " -group openvpn");
1185

    
1186
	/* restore the original adapter name */
1187
	mwexec("/sbin/ifconfig " . escapeshellarg($devname) . " name " . escapeshellarg($tunname));
1188

    
1189
	/* remove the configuration files */
1190
	@array_map('unlink', glob("{$g['varetc_path']}/openvpn/{$mode_id}.*"));
1191
}
1192

    
1193
function openvpn_resync_csc(& $settings) {
1194
	global $g, $config, $openvpn_tls_server_modes;
1195

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

    
1198
	if (isset($settings['disable'])) {
1199
		openvpn_delete_csc($settings);
1200
		return;
1201
	}
1202
	openvpn_create_dirs();
1203

    
1204
	if (empty($settings['server_list'])) {
1205
		$csc_server_list = array();
1206
	} else {
1207
		$csc_server_list = explode(",", $settings['server_list']);
1208
	}
1209

    
1210
	$conf = '';
1211
	if ($settings['block']) {
1212
		$conf .= "disable\n";
1213
	}
1214

    
1215
	if ($settings['push_reset']) {
1216
		$conf .= "push-reset\n";
1217
	}
1218

    
1219
	if ($settings['local_network']) {
1220
		$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
1221
	}
1222
	if ($settings['local_networkv6']) {
1223
		$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
1224
	}
1225

    
1226
	// Add a remote network iroute if set
1227
	if (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE) {
1228
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false, true);
1229
	}
1230
	// Add a remote network iroute if set
1231
	if (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE) {
1232
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false, true);
1233
	}
1234

    
1235
	openvpn_add_dhcpopts($settings, $conf);
1236

    
1237
	if ($settings['gwredir']) {
1238
		$conf .= "push \"redirect-gateway def1\"\n";
1239
	}
1240

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

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

    
1274
function openvpn_delete_csc(& $settings) {
1275
	global $g, $config, $openvpn_tls_server_modes;
1276
	$csc_base_path = "{$g['varetc_path']}/openvpn-csc";
1277
	if (empty($settings['server_list'])) {
1278
		$csc_server_list = array();
1279
	} else {
1280
		$csc_server_list = explode(",", $settings['server_list']);
1281
	}
1282

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

    
1299
// Resync the configuration and restart the VPN
1300
function openvpn_resync($mode, $settings) {
1301
	openvpn_reconfigure($mode, $settings);
1302
	openvpn_restart($mode, $settings);
1303
}
1304

    
1305
// Resync and restart all VPNs
1306
function openvpn_resync_all($interface = "") {
1307
	global $g, $config;
1308

    
1309
	openvpn_create_dirs();
1310

    
1311
	if (!is_array($config['openvpn'])) {
1312
		$config['openvpn'] = array();
1313
	}
1314

    
1315
/*
1316
	if (!$config['openvpn']['dh-parameters']) {
1317
		echo "Configuring OpenVPN Parameters ...\n";
1318
		$dh_parameters = openvpn_create_dhparams(1024);
1319
		$dh_parameters = base64_encode($dh_parameters);
1320
		$config['openvpn']['dh-parameters'] = $dh_parameters;
1321
		write_config("OpenVPN DH parameters");
1322
	}
1323

    
1324
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
1325
	if (!file_exists($path_ovdh)) {
1326
		$dh_parameters = $config['openvpn']['dh-parameters'];
1327
		$dh_parameters = base64_decode($dh_parameters);
1328
		file_put_contents($path_ovdh, $dh_parameters);
1329
	}
1330
*/
1331
	if ($interface <> "") {
1332
		log_error(sprintf(gettext("Resyncing OpenVPN instances for interface %s."), convert_friendly_interface_to_friendly_descr($interface)));
1333
	} else {
1334
		log_error(gettext("Resyncing OpenVPN instances."));
1335
	}
1336

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

    
1346
	if (is_array($config['openvpn']['openvpn-client'])) {
1347
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1348
			if ($interface <> "" && $interface != $settings['interface']) {
1349
				continue;
1350
			}
1351
			openvpn_resync('client', $settings);
1352
		}
1353
	}
1354

    
1355
	if (is_array($config['openvpn']['openvpn-csc'])) {
1356
		foreach ($config['openvpn']['openvpn-csc'] as & $settings) {
1357
			openvpn_resync_csc($settings);
1358
		}
1359
	}
1360

    
1361
}
1362

    
1363
// Resync and restart all VPNs using a gateway group.
1364
function openvpn_resync_gwgroup($gwgroupname = "") {
1365
	global $g, $config;
1366

    
1367
	if ($gwgroupname <> "") {
1368
		if (is_array($config['openvpn']['openvpn-server'])) {
1369
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1370
				if ($gwgroupname == $settings['interface']) {
1371
					log_error(sprintf(gettext('Resyncing OpenVPN for gateway group %1$s server %2$s.'), $gwgroupname, $settings["description"]));
1372
					openvpn_resync('server', $settings);
1373
				}
1374
			}
1375
		}
1376

    
1377
		if (is_array($config['openvpn']['openvpn-client'])) {
1378
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1379
				if ($gwgroupname == $settings['interface']) {
1380
					log_error(sprintf(gettext('Resyncing OpenVPN for gateway group %1$s client %2$s.'), $gwgroupname, $settings["description"]));
1381
					openvpn_resync('client', $settings);
1382
				}
1383
			}
1384
		}
1385

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

    
1388
	} else {
1389
		log_error(gettext("openvpn_resync_gwgroup called with null gwgroup parameter."));
1390
	}
1391
}
1392

    
1393
function openvpn_get_active_servers($type="multipoint") {
1394
	global $config, $g;
1395

    
1396
	$servers = array();
1397
	if (is_array($config['openvpn']['openvpn-server'])) {
1398
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
1399
			if (empty($settings) || isset($settings['disable'])) {
1400
				continue;
1401
			}
1402

    
1403
			$prot = $settings['protocol'];
1404
			$port = $settings['local_port'];
1405

    
1406
			$server = array();
1407
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
1408
			$server['mode'] = $settings['mode'];
1409
			if ($settings['description']) {
1410
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
1411
			} else {
1412
				$server['name'] = "Server {$prot}:{$port}";
1413
			}
1414
			$server['conns'] = array();
1415
			$server['vpnid'] = $settings['vpnid'];
1416
			$server['mgmt'] = "server{$server['vpnid']}";
1417
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
1418
			list($tn, $sm) = explode('/', trim($settings['tunnel_network']));
1419

    
1420
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30)) && ($type == "p2p")) {
1421
				$servers[] = openvpn_get_client_status($server, $socket);
1422
			} elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30)) {
1423
				$servers[] = openvpn_get_server_status($server, $socket);
1424
			}
1425
		}
1426
	}
1427
	return $servers;
1428
}
1429

    
1430
function openvpn_get_server_status($server, $socket) {
1431
	$errval = null;
1432
	$errstr = null;
1433
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1434
	if ($fp) {
1435
		stream_set_timeout($fp, 1);
1436

    
1437
		/* send our status request */
1438
		fputs($fp, "status 2\n");
1439

    
1440
		/* recv all response lines */
1441
		while (!feof($fp)) {
1442

    
1443
			/* read the next line */
1444
			$line = fgets($fp, 1024);
1445

    
1446
			$info = stream_get_meta_data($fp);
1447
			if ($info['timed_out']) {
1448
				break;
1449
			}
1450

    
1451
			/* parse header list line */
1452
			if (strstr($line, "HEADER")) {
1453
				continue;
1454
			}
1455

    
1456
			/* parse end of output line */
1457
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1458
				break;
1459
			}
1460

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

    
1485
		/* cleanup */
1486
		fclose($fp);
1487
	} else {
1488
		$conn = array();
1489
		$conn['common_name'] = "[error]";
1490
		$conn['remote_host'] = gettext("Unable to contact daemon");
1491
		$conn['virtual_addr'] = gettext("Service not running?");
1492
		$conn['bytes_recv'] = 0;
1493
		$conn['bytes_sent'] = 0;
1494
		$conn['connect_time'] = 0;
1495
		$server['conns'][] = $conn;
1496
	}
1497
	return $server;
1498
}
1499

    
1500
function openvpn_get_active_clients() {
1501
	global $config, $g;
1502

    
1503
	$clients = array();
1504
	if (is_array($config['openvpn']['openvpn-client'])) {
1505
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1506

    
1507
			if (empty($settings) || isset($settings['disable'])) {
1508
				continue;
1509
			}
1510

    
1511
			$prot = $settings['protocol'];
1512
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1513

    
1514
			$client = array();
1515
			$client['port'] = $settings['local_port'];
1516
			if ($settings['description']) {
1517
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1518
			} else {
1519
				$client['name'] = "Client {$prot}{$port}";
1520
			}
1521

    
1522
			$client['vpnid'] = $settings['vpnid'];
1523
			$client['mgmt'] = "client{$client['vpnid']}";
1524
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1525
			$client['status']="down";
1526

    
1527
			$clients[] = openvpn_get_client_status($client, $socket);
1528
		}
1529
	}
1530
	return $clients;
1531
}
1532

    
1533
function openvpn_get_client_status($client, $socket) {
1534
	$errval = null;
1535
	$errstr = null;
1536
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1537
	if ($fp) {
1538
		stream_set_timeout($fp, 1);
1539
		/* send our status request */
1540
		fputs($fp, "state 1\n");
1541

    
1542
		/* recv all response lines */
1543
		while (!feof($fp)) {
1544
			/* read the next line */
1545
			$line = fgets($fp, 1024);
1546

    
1547
			$info = stream_get_meta_data($fp);
1548
			if ($info['timed_out']) {
1549
				break;
1550
			}
1551

    
1552
			/* Get the client state */
1553
			if (strstr($line, "CONNECTED")) {
1554
				$client['status'] = "up";
1555
				$list = explode(",", $line);
1556

    
1557
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1558
				$client['virtual_addr'] = $list[3];
1559
				$client['remote_host'] = $list[4];
1560
			}
1561
			if (strstr($line, "CONNECTING")) {
1562
				$client['status'] = "connecting";
1563
			}
1564
			if (strstr($line, "ASSIGN_IP")) {
1565
				$client['status'] = "waiting";
1566
				$list = explode(",", $line);
1567

    
1568
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1569
				$client['virtual_addr'] = $list[3];
1570
			}
1571
			if (strstr($line, "RECONNECTING")) {
1572
				$client['status'] = "reconnecting";
1573
				$list = explode(",", $line);
1574

    
1575
				$client['connect_time'] = date("D M j G:i:s Y", $list[0]);
1576
				$client['status'] .= "; " . $list[2];
1577
			}
1578
			/* parse end of output line */
1579
			if (strstr($line, "END") || strstr($line, "ERROR")) {
1580
				break;
1581
			}
1582
		}
1583

    
1584
		/* If up, get read/write stats */
1585
		if (strcmp($client['status'], "up") == 0) {
1586
			fputs($fp, "status 2\n");
1587
			/* recv all response lines */
1588
			while (!feof($fp)) {
1589
				/* read the next line */
1590
				$line = fgets($fp, 1024);
1591

    
1592
				$info = stream_get_meta_data($fp);
1593
				if ($info['timed_out']) {
1594
					break;
1595
				}
1596

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

    
1602
				if (strstr($line, "TCP/UDP write bytes")) {
1603
					$list = explode(",", $line);
1604
					$client['bytes_sent'] = $list[1];
1605
				}
1606

    
1607
				/* parse end of output line */
1608
				if (strstr($line, "END")) {
1609
					break;
1610
				}
1611
			}
1612
		}
1613

    
1614
		fclose($fp);
1615

    
1616
	} else {
1617
		$client['remote_host'] = gettext("Unable to contact daemon");
1618
		$client['virtual_addr'] = gettext("Service not running?");
1619
		$client['bytes_recv'] = 0;
1620
		$client['bytes_sent'] = 0;
1621
		$client['connect_time'] = 0;
1622
	}
1623
	return $client;
1624
}
1625

    
1626
function openvpn_kill_client($port, $remipp) {
1627
	global $g;
1628

    
1629
	//$tcpsrv = "tcp://127.0.0.1:{$port}";
1630
	$tcpsrv = "unix://{$g['varetc_path']}/openvpn/{$port}.sock";
1631
	$errval = null;
1632
	$errstr = null;
1633

    
1634
	/* open a tcp connection to the management port of each server */
1635
	$fp = @stream_socket_client($tcpsrv, $errval, $errstr, 1);
1636
	$killed = -1;
1637
	if ($fp) {
1638
		stream_set_timeout($fp, 1);
1639
		fputs($fp, "kill {$remipp}\n");
1640
		while (!feof($fp)) {
1641
			$line = fgets($fp, 1024);
1642

    
1643
			$info = stream_get_meta_data($fp);
1644
			if ($info['timed_out']) {
1645
				break;
1646
			}
1647

    
1648
			/* parse header list line */
1649
			if (strpos($line, "INFO:") !== false) {
1650
				continue;
1651
			}
1652
			if (strpos($line, "SUCCESS") !== false) {
1653
				$killed = 0;
1654
			}
1655
			break;
1656
		}
1657
		fclose($fp);
1658
	}
1659
	return $killed;
1660
}
1661

    
1662
function openvpn_refresh_crls() {
1663
	global $g, $config;
1664

    
1665
	openvpn_create_dirs();
1666

    
1667
	if (is_array($config['openvpn']['openvpn-server'])) {
1668
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1669
			if (empty($settings)) {
1670
				continue;
1671
			}
1672
			if (isset($settings['disable'])) {
1673
				continue;
1674
			}
1675
			// Write the settings for the keys
1676
			switch ($settings['mode']) {
1677
				case 'p2p_tls':
1678
				case 'server_tls':
1679
				case 'server_tls_user':
1680
				case 'server_user':
1681
					if (!empty($settings['crlref'])) {
1682
						$crl = lookup_crl($settings['crlref']);
1683
						crl_update($crl);
1684
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1685
						file_put_contents($fpath, base64_decode($crl['text']));
1686
						@chmod($fpath, 0644);
1687
					}
1688
					break;
1689
			}
1690
		}
1691
	}
1692
}
1693

    
1694
function openvpn_create_dirs() {
1695
	global $g, $config, $openvpn_tls_server_modes;
1696
	if (!is_dir("{$g['varetc_path']}/openvpn")) {
1697
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1698
	}
1699
	if (!is_dir("{$g['varetc_path']}/openvpn-csc")) {
1700
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1701
	}
1702

    
1703
	/* Check for enabled servers and create server-specific CSC dirs */
1704
	if (is_array($config['openvpn']['openvpn-server'])) {
1705
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1706
			if (isset($settings['disable'])) {
1707
				continue;
1708
			}
1709
			if (in_array($settings['mode'], $openvpn_tls_server_modes)) {
1710
				if ($settings['vpnid']) {
1711
					safe_mkdir("{$g['varetc_path']}/openvpn-csc/server{$settings['vpnid']}");
1712
				}
1713
			}
1714
		}
1715
	}
1716
}
1717

    
1718
function openvpn_get_interface_ip($ip, $cidr) {
1719
	$subnet = gen_subnetv4($ip, $cidr);
1720
	$ip1 = ip_after($subnet);
1721
	$ip2 = ip_after($ip1);
1722
	return array($ip1, $ip2);
1723
}
1724

    
1725
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1726
	$basev6 = gen_subnetv6($ipv6, $prefix);
1727
	// Is there a better way to do this math?
1728
	$ipv6_arr = explode(':', $basev6);
1729
	$last = hexdec(array_pop($ipv6_arr));
1730
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1731
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1732
	return array($ipv6_1, $ipv6_2);
1733
}
1734

    
1735
function openvpn_clear_route($mode, $settings) {
1736
	if (empty($settings['tunnel_network'])) {
1737
		return;
1738
	}
1739
	list($ip, $cidr) = explode('/', trim($settings['tunnel_network']));
1740
	$mask = gen_subnet_mask($cidr);
1741
	$clear_route = false;
1742

    
1743
	switch ($settings['mode']) {
1744
		case 'shared_key':
1745
			$clear_route = true;
1746
			break;
1747
		case 'p2p_tls':
1748
		case 'p2p_shared_key':
1749
			if ($cidr == 30) {
1750
				$clear_route = true;
1751
			}
1752
			break;
1753
	}
1754

    
1755
	if ($clear_route && !empty($ip) && !empty($mask)) {
1756
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $cidr);
1757
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1758
		/* XXX: Family for route? */
1759
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1760
	}
1761
}
1762

    
1763
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false, $iroute = false) {
1764
	$routes = "";
1765
	if (empty($value)) {
1766
		return "";
1767
	}
1768
	$networks = explode(',', $value);
1769

    
1770
	foreach ($networks as $network) {
1771
		if ($ipproto == "ipv4") {
1772
			$route = openvpn_gen_route_ipv4($network, $iroute);
1773
		} else {
1774
			$route = openvpn_gen_route_ipv6($network, $iroute);
1775
		}
1776

    
1777
		if ($push) {
1778
			$routes .= "push \"{$route}\"\n";
1779
		} else {
1780
			$routes .= "{$route}\n";
1781
		}
1782
	}
1783
	return $routes;
1784
}
1785

    
1786
function openvpn_gen_route_ipv4($network, $iroute = false) {
1787
	$i = ($iroute) ? "i" : "";
1788
	list($ip, $mask) = explode('/', trim($network));
1789
	$mask = gen_subnet_mask($mask);
1790
	return "{$i}route $ip $mask";
1791
}
1792

    
1793
function openvpn_gen_route_ipv6($network, $iroute = false) {
1794
	$i = ($iroute) ? "i" : "";
1795
	list($ipv6, $prefix) = explode('/', trim($network));
1796
	if (empty($prefix)) {
1797
		$prefix = "128";
1798
	}
1799
	return "{$i}route-ipv6 ${ipv6}/${prefix}";
1800
}
1801

    
1802
function openvpn_get_settings($mode, $vpnid) {
1803
	global $config;
1804

    
1805
	if (is_array($config['openvpn']['openvpn-server'])) {
1806
		foreach ($config['openvpn']['openvpn-server'] 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
	if (is_array($config['openvpn']['openvpn-client'])) {
1818
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1819
			if (isset($settings['disable'])) {
1820
				continue;
1821
			}
1822

    
1823
			if ($vpnid != 0 && $vpnid == $settings['vpnid']) {
1824
				return $settings;
1825
			}
1826
		}
1827
	}
1828

    
1829
	return array();
1830
}
1831

    
1832
function openvpn_restart_by_vpnid($mode, $vpnid) {
1833
	$settings = openvpn_get_settings($mode, $vpnid);
1834
	openvpn_restart($mode, $settings);
1835
}
1836

    
1837
?>
(37-37/65)