Project

General

Profile

Download (48.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2

    
3
/*
4
	vpn.inc
5
	Copyright (C) 2004 Scott Ullrich
6
	Copyright (C) 2008 Shrew Soft Inc
7
	Copyright (C) 2008 Ermal Lu?i
8
	All rights reserved.
9

    
10
	originally part of m0n0wall (http://m0n0.ch/wall)
11
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
12
	All rights reserved.
13

    
14
	Redistribution and use in source and binary forms, with or without
15
	modification, are permitted provided that the following conditions are met:
16

    
17
	1. Redistributions of source code must retain the above copyright notice,
18
	   this list of conditions and the following disclaimer.
19

    
20
	2. Redistributions in binary form must reproduce the above copyright
21
	   notice, this list of conditions and the following disclaimer in the
22
	   documentation and/or other materials provided with the distribution.
23

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

    
36
/*
37
	pfSense_BUILDER_BINARIES:	/usr/bin/killall	/usr/local/sbin/sasyncd	/sbin/ifconfig	/sbin/sysctl
38
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/setkey	/usr/bin/netstat	/sbin/route	/bin/mkdir
39
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/racoonctl	/usr/local/sbin/racoon
40
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/filterdns	/usr/local/sbin/mpd4	
41
	pfSense_MODULE:	vpn
42
*/
43

    
44
/* include all configuration functions */
45

    
46
function vpn_ipsec_failover_configure() {
47
	global $config, $g;
48

    
49

    
50
	if (is_array($config['installedpackages']['sasyncd'])) {
51
		$sasyncd_text = "";
52
		foreach ($config['installedpackages']['sasyncd']['config'] as $sasyncd) {
53
			$enabled = isset ($sasyncd['enable']);
54
			if (!$enabled)
55
				return;
56
			if ($sasyncd['peerip'] <> "")
57
				$sasyncd_text .= "peer {$sasyncd['peerip']}\n";
58
			if ($sasyncd['interface'])
59
				$sasyncd_text .= "carp interface {$sasyncd['interface']}\n";
60
			if ($sasyncd['sharedkey'] <> "")
61
				$sasyncd_text .= "sharedkey {$sasyncd['sharedkey']}\n";
62
			if ($sasyncd['mode'] <> "")
63
				$sasyncd_text .= "mode {$sasyncd['mode']}\n";
64
			if ($sasyncd['listenon'] <> "")
65
				$sasyncd_text .= "listen on {$sasyncd['listenon']}\n";
66
			if ($sasyncd['flushmodesync'] <> "")
67
				$sasyncd_text .= "flushmode sync {$sasyncd['flushmodesync']}\n";
68
		}
69

    
70
		file_put_contents("{$g['varetc_path']}/sasyncd.conf", $sasyncd_text);
71
		chmod("{$g['varetc_path']}/sasyncd.conf", 0600);
72

    
73
		if(is_process_running("sasyncd"))
74
			mwexec("killall sasyncd", true);
75

    
76
		/* launch sasyncd, oh wise one */
77
		mwexec_bg("/usr/local/sbin/sasyncd -d -v -v -v");
78
	}
79
}
80

    
81
function vpn_ipsec_configure($ipchg = false)
82
{
83
	global $config, $g, $sa, $sn, $p1_ealgos, $p2_ealgos;
84

    
85
	/* get the automatic ping_hosts.sh ready */
86
	unlink_if_exists("{$g['vardb_path']}/ipsecpinghosts");
87
	touch("{$g['vardb_path']}/ipsecpinghosts");
88

    
89
	vpn_ipsec_configure_preferoldsa();
90

    
91
	$syscfg = $config['system'];
92
	$ipseccfg = $config['ipsec'];
93
	$a_phase1 = $config['ipsec']['phase1'];
94
	$a_phase2 = $config['ipsec']['phase2'];
95
	$a_client = $config['ipsec']['client'];
96

    
97
	if (!isset($ipseccfg['enable'])) {
98
		mwexec("/sbin/ifconfig enc0 down");
99

    
100
		/* send a SIGKILL to be sure */
101
		sigkillbypid("{$g['varrun_path']}/racoon.pid", "KILL");
102

    
103
		/* kill racoon */
104
		if(is_process_running("racoon"))
105
			mwexec("/usr/bin/killall racoon", true);
106
		killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
107

    
108
		/* wait for racoon process to die */
109
		sleep(2);
110

    
111
		/* flush SPD and SAD */
112
		mwexec("/usr/local/sbin/setkey -F");
113
		mwexec("/usr/local/sbin/setkey -FP");
114

    
115
		/* disallow IPSEC, it is off */
116
		exec("/sbin/sysctl net.inet.ip.ipsec_in_use=0");
117

    
118
		return true;
119
	} else {
120
		mwexec("/sbin/ifconfig enc0 up");
121
		mwexec("/sbin/sysctl net.inet.ip.ipsec_in_use=1");
122

    
123
		if ($g['booting'])
124
			echo "Configuring IPsec VPN... ";
125

    
126
		/* fastforwarding is not compatible with ipsec tunnels */
127
		mwexec("/sbin/sysctl net.inet.ip.fastforwarding=0");
128

    
129
		/* this loads a route table which is used to determine if a route needs to be removed. */
130
		exec("/usr/bin/netstat -rnf inet", $route_arr, $retval);
131
		$route_str = implode("\n", $route_arr);
132

    
133
		/* resolve all local, peer addresses and setup pings */
134
		$ipmap = array();
135
		$rgmap = array();
136
		$filterdns_list = array();
137
		if (is_array($a_phase1) && count($a_phase1)) {
138

    
139
			$ipsecpinghosts = "";
140
			/* step through each phase1 entry */
141
			foreach ($a_phase1 as $ph1ent) {
142
				if (isset($ph1ent['disabled']))
143
					continue;
144

    
145
				$ep = ipsec_get_phase1_src($ph1ent);
146
				if (!$ep)
147
					continue;
148

    
149
				if(!in_array($ep,$ipmap))
150
					$ipmap[] = $ep;
151

    
152
				/* see if this tunnel has a hostname for the remote-gateway. If so,
153
				   try to resolve it now and add it to the list for filterdns */
154

    
155
				if (isset ($ph1ent['mobile']))
156
					continue;
157

    
158
				$rg = $ph1ent['remote-gateway'];
159

    
160
				if (!is_ipaddr($rg)) {
161
					$filterdns_list[] = "{$rg}";
162
					add_hostname_to_watch($rg);
163
					if(! $g['booting'])
164
						$rg = resolve_retry($rg);
165
					if (!is_ipaddr($rg))
166
						continue;
167
				}
168
				if(array_search($rg, $rgmap)) {
169
					log_error("The remote gateway {$rg} already exists on another phase 1 entry");
170
					continue;
171
				}
172
				$rgmap[$ph1ent['remote-gateway']] = $rg;
173

    
174
				/* step through each phase2 entry */
175
				foreach ($a_phase2 as $ph2ent) {
176

    
177
					$ikeid = $ph2ent['ikeid'];
178

    
179
					if (isset($ph2ent['disabled']))
180
						continue;
181

    
182
					if ($ikeid != $ph1ent['ikeid'])
183
						continue;
184

    
185
					/* add an ipsec pinghosts entry */
186
					if ($ph2ent['pinghost']) {
187
						$iflist = get_configured_interface_list();
188
						foreach ($iflist as $ifent => $ifname) {
189
							$interface_ip = get_interface_ip($ifent);
190
							$local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid'], true);
191
							if (ip_in_subnet($interface_ip, $local_subnet)) {
192
								$srcip = $interface_ip;
193
								break;
194
							}
195
						}
196
						$dstip = $ph2ent['pinghost'];
197
						if (is_ipaddr($srcip))
198
							$ipsecpinghosts .= "{$srcip}|{$dstip}|3\n";
199
					}
200
				}
201
				$pfd = fopen("{$g['vardb_path']}/ipsecpinghosts", "w");
202
				if ($pfd) {
203
					fwrite($pfd, $ipsecpinghosts);
204
					fclose($pfd);
205
				}
206
				
207
			}
208
		}
209

    
210
		/* generate CA certificates files */
211
		if (is_array($config['ca']) && count($config['ca'])) {
212
			foreach ($config['ca'] as $ca) {
213
				if (!isset($ca['crt'])) {
214
					log_error("Error: Invalid certificate info for {$ca['descr']}");
215
					continue;
216
				}
217
				$cert = base64_decode($ca['crt']);
218
				$x509cert = openssl_x509_parse(openssl_x509_read($cert));
219
				if (!is_array($x509cert) || !isset($x509cert['hash'])) {
220
					log_error("Error: Invalid certificate hash info for {$ca['descr']}");
221
					continue;
222
				}
223
				$fname = $g['varetc_path']."/".$x509cert['hash'].".0";
224
				if (!file_put_contents($fname, $cert)) {
225
					log_error("Error: Cannot write IPsec CA file for {$ca['descr']}");
226
					continue;
227
				}
228
			}
229
		}
230
		
231
		/* generate psk.txt */
232
		$fd = fopen("{$g['varetc_path']}/psk.txt", "w");
233
		if (!$fd) {
234
			printf("Error: cannot open psk.txt in vpn_ipsec_configure().\n");
235
			return 1;
236
		}
237

    
238
		$pskconf = "";
239

    
240
		if (is_array($a_phase1) && count($a_phase1)) {
241
			foreach ($a_phase1 as $ph1ent) {
242

    
243
				if (isset($ph1ent['disabled']))
244
					continue;
245

    
246
				if (strstr($ph1ent['authentication_method'],'rsa'))
247
					continue;
248

    
249
				$peerid_type = $ph1ent['peerid_type'];
250

    
251
				switch ($peerid_type) {
252
					case "peeraddress":
253
						$peerid_type = "address";
254
						$peerid_data = $rgmap[$ph1ent['remote-gateway']];
255
						break;
256

    
257
					case "address";
258
						$peerid_data = $ph1ent['peerid_data'];
259
						break;
260

    
261
					case "fqdn";
262
					case "keyid tag";
263
					case "user_fqdn";
264
						$peerid_data = $ph1ent['peerid_data'];
265
						break;
266
				}
267

    
268
				$pskconf .= "{$peerid_data}\t{$ph1ent['pre-shared-key']}\n";
269
			}
270
		}
271

    
272
		/* Add user PSKs */
273
		foreach ($config['system']['user'] as $user) {
274
			if (!empty($user['ipsecpsk'])) {
275
				$pskconf .= "{$user['name']}\t{$user['ipsecpsk']}\n";
276
			}
277
		}
278

    
279
		/* add PSKs for mobile clients */
280
		if (is_array($ipseccfg['mobilekey'])) {
281
			foreach ($ipseccfg['mobilekey'] as $key) {
282
				$pskconf .= "{$key['ident']}\t{$key['pre-shared-key']}\n";
283
			}
284
		}
285

    
286
		fwrite($fd, $pskconf);
287
		fclose($fd);
288
		chmod("{$g['varetc_path']}/psk.txt", 0600);
289
			
290
		/* begin racoon.conf */
291
		if ((is_array($a_phase1) && count($a_phase1)) ||
292
			(is_array($a_phase2) && count($a_phase2))) {
293

    
294
			$fd = fopen("{$g['varetc_path']}/racoon.conf", "w");
295
			if (!$fd) {
296
				printf("Error: cannot open racoon.conf in vpn_ipsec_configure().\n");
297
				return 1;
298
			}
299

    
300
			$racoonconf = "# This file is automatically generated. Do not edit\n";			
301
			$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
302
			$racoonconf .= "path certificate  \"{$g['varetc_path']}\";\n\n";
303

    
304
			/* begin listen section */
305
			if (count($ipmap)) {
306
				$racoonconf .= "\nlisten\n";
307
				$racoonconf .= "{\n";
308
				$racoonconf .= "	adminsock \"/var/db/racoon/racoon.sock\" \"root\" \"wheel\" 0660;\n";
309
				foreach ($ipmap as $addr) {
310
					$racoonconf .= "\tisakmp {$addr} [500];\n";
311
					$racoonconf .= "\tisakmp_natt {$addr} [4500];\n";
312
				}
313
				$racoonconf .= "}\n\n";
314
			}
315

    
316
			/* begin mode_cfg section */
317
			if (is_array($a_client) && isset($a_client['enable'])) {
318

    
319
				$racoonconf .= "\nmode_cfg\n";
320
				$racoonconf .= "{\n";
321

    
322
				if ($a_client['user_source'])
323
					$racoonconf .= "\tauth_source {$a_client['user_source']};\n";
324
				if ($a_client['group_source'])
325
					$racoonconf .= "\tgroup_source {$a_client['group_source']};\n";
326

    
327
				if ($a_client['pool_address'] && $a_client['pool_netbits']) {
328
					$pool_address = $a_client['pool_address'];
329
					$pool_netmask = gen_subnet_mask($a_client['pool_netbits']);
330

    
331
					$pool_address = long2ip32(ip2long($pool_address)+1);
332
					$pool_size = (~ip2long($pool_netmask) & 0xFFFFFFFF) - 2;
333

    
334
					$racoonconf .= "\tpool_size {$pool_size};\n";
335
					$racoonconf .= "\tnetwork4 {$pool_address};\n";
336
					$racoonconf .= "\tnetmask4 {$pool_netmask};\n";
337
				}
338

    
339
				if (isset($a_client['net_list'])) {
340

    
341
					$net_list = '';
342

    
343
					foreach ($a_phase2 as $ph2ent) {
344

    
345
						if (isset($ph2ent['disabled']))
346
							continue;
347

    
348
						if (!isset($ph2ent['mobile']))
349
							continue;
350

    
351
						$localid = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
352

    
353
						if ($net_list)
354
							$net_list .= ", ";
355
						$net_list .= $localid;
356
					}
357

    
358
					if ($net_list)
359
						$racoonconf .= "\tsplit_network include {$net_list};\n";
360
				}
361

    
362
				if ($a_client['dns_server1'])
363
					$racoonconf .= "\tdns4 {$a_client['dns_server1']};\n";
364
				if ($a_client['dns_server2'])
365
					$racoonconf .= "\tdns4 {$a_client['dns_server2']};\n";
366
				if ($a_client['dns_server3'])
367
					$racoonconf .= "\tdns4 {$a_client['dns_server3']};\n";
368
				if ($a_client['dns_server4'])
369
					$racoonconf .= "\tdns4 {$a_client['dns_server4']};\n";
370

    
371
				if ($a_client['wins_server1'])
372
					$racoonconf .= "\twins4 {$a_client['wins_server1']};\n";
373
				if ($a_client['wins_server2'])
374
					$racoonconf .= "\twins4 {$a_client['wins_server2']};\n";
375

    
376
				if ($a_client['dns_domain']) {
377
					$racoonconf .= "\tdefault_domain \"{$a_client['dns_domain']}\";\n";
378
					$racoonconf .= "\tsplit_dns \"{$a_client['dns_domain']}\";\n";
379
				}
380

    
381
				if ($a_client['pfs_group'])
382
					$racoonconf .= "\tpfs_group {$a_client['pfs_group']};\n";
383

    
384
				if ($a_client['login_banner']) {
385
					$fn = "{$g['varetc_path']}/racoon.motd";
386
					$fd1 = fopen($fn, "w");
387
					if (!$fd1) {
388
						printf("Error: cannot open server{$fn} in vpn.\n");
389
						return 1;
390
					}
391

    
392
					fwrite($fd1, $a_client['login_banner']);
393
					fclose($fd1);
394

    
395
					$racoonconf .= "\tbanner \"{$fn}\";\n";
396
				}
397

    
398
				if (isset($a_client['save_passwd']))
399
					$racoonconf .= "\tsave_passwd on;\n";
400

    
401
				$racoonconf .= "}\n\n";
402
			}
403
			/* end mode_cfg section */
404

    
405
			/* begin remote sections */
406
			if (is_array($a_phase1) && count($a_phase1)) {
407
				/* begin remote */
408
				foreach ($a_phase1 as $ph1ent) {
409

    
410
					if (isset($ph1ent['disabled']))
411
						continue;
412

    
413
					if (isset($ph1ent['mobile']) && !isset($a_client['enable']))
414
						continue;
415

    
416
					$ikeid = $ph1ent['ikeid'];
417

    
418
					$ep = ipsec_get_phase1_src($ph1ent);
419
					if (!$ep)
420
						continue;
421

    
422
					if (!isset($ph1ent['mobile'])) {
423
						$rgip = $rgmap[$ph1ent['remote-gateway']];
424
						if (!$rgip)
425
							continue;
426
					}
427

    
428
					$myid_type = $ph1ent['myid_type'];
429

    
430
					switch ($myid_type) {
431

    
432
						case "myaddress":
433
							$myid_type = "address";
434
							$myid_data = $ep;
435
							break;
436

    
437
						case "dyn_dns":
438
							$myid_type = "address";
439
							$myid_data = gethostbyname($ph1ent['myid_data']);
440
							break;
441

    
442
						case "address";
443
							$myid_data = $ph1ent['myid_data'];
444
							break;
445

    
446
						case "fqdn";
447
						case "keyid tag";
448
						case "user_fqdn";
449
						case "asn1dn";
450
							$myid_data = $ph1ent['myid_data'];
451
							if( $myid_data )
452
								$myid_data = "\"".$myid_data."\"";
453
							break;
454
					}
455

    
456
					$peerid_type = $ph1ent['peerid_type'];
457

    
458
					switch ($peerid_type) {
459
						case "peeraddress":
460
							$peerid_type = "address";
461
							$peerid_data = $rgip;
462
							break;
463

    
464
						case "address";
465
							$peerid_data = $ph1ent['peerid_data'];
466
							break;
467

    
468
						case "fqdn";
469
						case "keyid tag";
470
						case "user_fqdn";
471
						case "asn1dn";
472
							$peerid_data = $ph1ent['peerid_data'];
473
							if( $peerid_data )
474
								$peerid_data = "\"".$peerid_data."\"";
475
							break;
476
					}
477

    
478
					$natt = "off";
479
					if (isset($ph1ent['nat_traversal']))
480
						$natt = $ph1ent['nat_traversal'];
481

    
482
					$init = "on";
483
					$genp = "off";
484
					$pcheck = !empty($ph1ent['proposal_check']) ? $ph1ent['proposal_check'] : $pcheck = "claim";
485
					$passive = "";
486
					if (isset($ph1ent['mobile'])) {
487
						$rgip = "anonymous";
488
						/* Mimic 1.2.3's behavior for pure-psk mobile tunnels */
489
						if ($ph1ent['authentication_method'] == "pre_shared_key") {
490
							$passive = "passive on;";
491
							$pcheck = !empty($ph1ent['proposal_check']) ? $ph1ent['proposal_check'] : $pcheck = "obey";
492
							$genp = "on";
493
						} else {
494
							$init = "off";
495
							$genp = "unique";
496
						}
497
					}
498

    
499
					$dpdline1 = '';
500
					$dpdline2 = '';
501
					if ($ph1ent['dpd_delay'] && $ph1ent['dpd_maxfail']) {
502
						$dpdline1 = "dpd_delay = {$ph1ent['dpd_delay']};";
503
						$dpdline2 = "dpd_maxfail = {$ph1ent['dpd_maxfail']};";
504
					}
505

    
506
					if (isset ($ph1ent['authentication_method']))
507
						$authmethod = $ph1ent['authentication_method'];
508
					else
509
						$authmethod = 'pre_shared_key';
510

    
511
					$certline = '';
512

    
513
					if (strstr($authmethod,'rsa')) {
514

    
515
						$cert = lookup_cert($ph1ent['certref']);
516

    
517
						if (!$cert)
518
						{
519
							log_error("Error: Invalid phase1 certificate reference for {$ph1ent['name']}");
520
							continue;
521
						}
522

    
523
						$certfile = "cert-".$ikeid.".crt";
524
						$certpath = $g['varetc_path']."/".$certfile;
525

    
526
						if (!file_put_contents($certpath, base64_decode($cert['crt'])))
527
						{
528
							log_error("Error: Cannot write phase1 certificate file for {$ph1ent['name']}");
529
							continue;
530
						}
531

    
532
						chmod($certpath, 0600);
533

    
534
						$keyfile = "cert-".$ikeid.".key";
535
						$keypath = $g['varetc_path']."/".$keyfile;
536

    
537
						if (!file_put_contents($keypath, base64_decode($cert['prv'])))
538
						{
539
							log_error("Error: Cannot write phase1 key file for {$ph1ent['name']}");
540
							continue;
541
						}
542

    
543
						chmod($keypath, 0600);
544

    
545
						$ca = lookup_ca($ph1ent['caref']);
546
						if ($ca) {
547
							$cafile = "ca-".$ikeid.".crt";
548
							$capath = $g['varetc_path']."/".$cafile;
549

    
550
							if (!file_put_contents($capath, base64_decode($ca['crt'])))
551
							{
552
								log_error("Error: Cannot write phase1 CA certificate file for {$ph1ent['name']}");
553
								continue;
554
							}
555

    
556
							chmod($capath, 0600);
557
							$caline = "ca_type x509 \"".basename($capath)."\";";
558
						}
559

    
560
						$certline = "certificate_type x509 \"".basename($certpath)."\" \"".basename($keypath)."\";";
561

    
562
					}
563

    
564
					$ealgos = '';
565
					$ealg_id = $ph1ent['encryption-algorithm']['name'];
566
					$ealg_kl = $ph1ent['encryption-algorithm']['keylen'];
567
					if ($ealg_kl)
568
						$ealgos = $ealgos.$ealg_id." ".$ealg_kl;
569
					else
570
						$ealgos = $ealgos.$ealg_id;
571

    
572
					$lifeline = '';
573
					if ($ph1ent['lifetime'])
574
						$lifeline = "lifetime time {$ph1ent['lifetime']} secs;";
575

    
576
					/* Only specify peer ID if we are not dealing with a mobile PSK-only tunnel */
577
					if (!(($ph1ent['authentication_method'] == "pre_shared_key") && isset($ph1ent['mobile']))) {
578
						$peerid_spec = "peers_identifier {$peerid_type} {$peerid_data};";
579
					}
580

    
581
					/* add remote section to configuration */
582

    
583
					$racoonconf .=<<<EOD
584

    
585
remote {$rgip}
586
{
587
	ph1id {$ikeid};
588
	exchange_mode {$ph1ent['mode']};
589
	my_identifier {$myid_type} {$myid_data};
590
	{$peerid_spec}
591
	ike_frag on;
592
	generate_policy = {$genp};
593
	initial_contact = {$init};
594
	nat_traversal = {$natt};
595
	{$certline}
596
	{$caline}
597
	{$dpdline1}
598
	{$dpdline2}
599
	support_proxy on;
600
	proposal_check {$pcheck};
601
	{$passive}
602

    
603
	proposal
604
	{
605
		authentication_method {$authmethod};
606
		encryption_algorithm ${ealgos};
607
		hash_algorithm {$ph1ent['hash-algorithm']};
608
		dh_group {$ph1ent['dhgroup']};
609
		${lifeline}
610
	}
611
}
612

    
613
EOD;
614
				}
615
				/* end remote */
616
			}
617
			/* end remote sections */
618
		
619
			/* begin sainfo sections */
620
			if (is_array($a_phase2) && count($a_phase2)) {
621

    
622
				/* begin sainfo */
623
				foreach ($a_phase2 as $ph2ent) {
624

    
625
					$ikeid = $ph2ent['ikeid'];
626

    
627
					if( !ipsec_lookup_phase1($ph2ent,$ph1ent))
628
						continue;
629

    
630
					if (isset($ph1ent['disabled']))
631
						continue;
632

    
633
					if (isset($ph2ent['disabled']))
634
						continue;
635

    
636
					if (isset($ph2ent['mobile']) && !isset($a_client['enable']))
637
						continue;
638

    
639
					if ($ph2ent['mode'] == 'tunnel') {
640

    
641
						$localid_type = $ph2ent['localid']['type'];
642
						$localid_data = ipsec_idinfo_to_cidr($ph2ent['localid']);
643
						/* Do not print localid in some cases, such as a pure-psk or psk/xauth single phase2 mobile tunnel */
644
						if (($localid_type == "none") ||
645
							(($ph1ent['authentication_method'] == "xauth_psk_server") ||
646
							($ph1ent['authentication_method'] == "pre_shared_key"))
647
							&& isset($ph1ent['mobile'])
648
							&& (ipsec_get_number_of_phase2($ikeid)==1))
649
							$localid_spec = " ";
650
						else {
651
							if ($localid_type != "address") {
652
								$localid_type = "subnet";
653
							}
654
							$localid_spec = $localid_type." ".$localid_data." any";
655
						}
656

    
657
						if (!isset($ph2ent['mobile'])) {
658
							$remoteid_type = $ph2ent['remoteid']['type'];
659
							if ($remoteid_type != "address")
660
								$remoteid_type = "subnet";
661

    
662
							$remoteid_data = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
663
							$remoteid_spec = $remoteid_type." ".$remoteid_data." any";
664
						} else
665
							$remoteid_spec = "anonymous";
666

    
667
					} else {
668
						$rgip = $rgmap[$ph1ent['remote-gateway']];
669

    
670
						if ((($ph1ent['authentication_method'] == "xauth_psk_server") ||
671
							($ph1ent['authentication_method'] == "pre_shared_key"))
672
							&& isset($ph1ent['mobile']))
673
							$localid_spec = " ";
674
						else {
675
							$localid_data = ipsec_get_phase1_src($ph1ent);
676
							if($ph2ent['mode'] == 'transport') { $localid_data="$localid_data any"; }
677
							$localid_spec = "address {$localid_data}";
678
						}
679
						if (!isset($ph2ent['mobile'])) {
680
							$remoteid_data = $rgmap[$ph1ent['remote-gateway']];
681
							if($ph2ent['mode'] == 'transport') { $remoteid_data="$remoteid_data any"; }
682
							$remoteid_spec = "address {$remoteid_data}";
683
						} else
684
							$remoteid_spec = "anonymous";
685
					}
686

    
687
					if($ph2ent['protocol'] == 'esp') {
688

    
689
						$ealgos = '';
690

    
691
						foreach ($ph2ent['encryption-algorithm-option'] as $ealg) {
692

    
693
							$ealg_id = $ealg['name'];
694
							$ealg_kl = $ealg['keylen'];
695

    
696
							if ($ealg_kl) {
697
								if( $ealg_kl == "auto" ) {
698
									/*   This seems to be required on my system and was not reproducable
699
									 *   on other systems.   For some reason $p2_ealgos is not defined
700
									 *   and needs to be read back in!?  -sullrich Aug 26, 2009 
701
									 */
702
									if(!$p2_ealgos)
703
										require("ipsec.inc");
704
									$key_hi = $p2_ealgos[$ealg_id]['keysel']['hi'];
705
									$key_lo = $p2_ealgos[$ealg_id]['keysel']['lo'];
706
									$key_step = $p2_ealgos[$ealg_id]['keysel']['step'];
707
									/* in some cases where include ordering is suspect these variables
708
									   are somehow 0 and we enter this loop forever and timeout after 900
709
									   seconds wrecking bootup */
710
									if($key_hi != 0 and $key_lo !=0 and $key_step !=0) {
711
										for ($keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step) {
712
//											Uncomment the next line if you want to test the comment 5 lines up.											
713
//											echo "$keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step \n";
714
											if ($ealgos)
715
												$ealgos = $ealgos.", ";
716
											$ealgos = $ealgos.$ealg_id." ".$keylen;
717
										}
718
									}
719
								} else {
720
									if ($ealgos)
721
										$ealgos = $ealgos.", ";
722
									$ealgos = $ealgos.$ealg_id." ".$ealg_kl;
723
								}
724
							} else {
725
								if ($ealgos)
726
									$ealgos = $ealgos.", ";
727
								$ealgos = $ealgos.$ealg_id;
728
							}
729
						}
730

    
731
						$ealgosline = "encryption_algorithm {$ealgos};";
732

    
733
					} else {
734

    
735
						$ealgosline = "encryption_algorithm null_enc;";
736
					}
737

    
738
					$halgos = join(",", $ph2ent['hash-algorithm-option']);
739
					$halgosline = "authentication_algorithm {$halgos};";
740

    
741
					$pfsline = '';
742
					if ($ph2ent['pfsgroup'])
743
						$pfsline = "pfs_group {$ph2ent['pfsgroup']};";
744
					if (isset($a_client['pfs_group'])) {
745
						$pfsline = '';
746
						if ($a_client['pfs_group'])
747
							$pfsline = "pfs_group {$a_client['pfs_group']};";
748
					}
749

    
750
					$lifeline = '';
751
					if ($ph2ent['lifetime'])
752
						$lifeline = "lifetime time {$ph2ent['lifetime']} secs;";
753

    
754
					/* add sainfo section to configuration */
755
					
756
					$racoonconf .=<<<EOD
757
					
758
sainfo {$localid_spec} {$remoteid_spec}
759
{
760
	remoteid {$ikeid};
761
	{$ealgosline}
762
	{$halgosline}
763
	{$pfsline}
764
	{$lifeline}
765
	compression_algorithm deflate;
766
}
767

    
768
EOD;
769
				}
770
				/* end sainfo */
771
			}
772
			/* end sainfo sections */
773

    
774
			fwrite($fd, $racoonconf);
775
			fclose($fd);
776
		}
777
		/* end racoon.conf */
778

    
779
		/* generate IPsec policies */
780
		if (is_array($a_phase2) && count($a_phase2)) {
781
			/* generate spd.conf */
782
			$fd = fopen("{$g['varetc_path']}/spd.conf", "w");
783
			if (!$fd) {
784
				printf("Error: cannot open spd.conf in vpn_ipsec_configure().\n");
785
				return 1;
786
			}
787

    
788
			$spdconf = "";
789

    
790
			/* Try to prevent people from locking themselves out of webgui. Just in case. */
791
			if ($config['interfaces']['lan']) {
792
				$lanip = get_interface_ip("lan");
793
				if (!empty($lanip) && is_ipaddr($lanip)) {
794
					$lansn = get_interface_subnet("lan");
795
					$lansa = gen_subnet($lanip, $lansn);
796
					$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
797
					$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
798
				}
799
			}
800

    
801
			foreach ($a_phase2 as $ph2ent) {
802

    
803
				if( !ipsec_lookup_phase1($ph2ent,$ph1ent))
804
					continue;
805

    
806
				if (isset($ph1ent['mobile']))
807
					continue;
808

    
809
				if (isset($ph1ent['disabled']))
810
					continue;
811

    
812
				if (isset($ph2ent['disabled']))
813
					continue;
814

    
815
				$ep = ipsec_get_phase1_src($ph1ent);
816
				if (!$ep)
817
					continue;
818

    
819
				$rgip = $rgmap[$ph1ent['remote-gateway']];
820
				if(!is_ipaddr($rgip))
821
					continue;
822

    
823
				$localid = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
824
				$remoteid = ipsec_idinfo_to_cidr($ph2ent['remoteid'],true);
825

    
826
				if($ph2ent['mode'] == "tunnel") {
827

    
828
					$spdconf .= "spdadd {$localid} {$remoteid} any -P out ipsec " .
829
						"{$ph2ent['protocol']}/tunnel/{$ep}-{$rgip}/unique;\n";
830

    
831
					$spdconf .= "spdadd {$remoteid} {$localid} any -P in ipsec " .
832
						"{$ph2ent['protocol']}/tunnel/{$rgip}-{$ep}/unique;\n";
833

    
834
				} else {
835

    
836
					$localid_data = ipsec_get_phase1_src($ph1ent);
837
					$remoteid_data = $rgmap[$ph1ent['remote-gateway']];
838

    
839
					$spdconf .= "spdadd {$localid_data} {$remoteid_data} any -P out ipsec " .
840
						"{$ph2ent['protocol']}/transport//require;\n";
841

    
842
					$spdconf .= "spdadd {$remoteid_data} {$localid_data} any -P in ipsec " .
843
						"{$ph2ent['protocol']}/transport//require;\n";
844

    
845
				}
846

    
847
				/* static route needed? */
848
				if (preg_match("/^carp|^vip/i", $ph1ent['interface']))
849
					$parentinterface = link_carp_interface_to_parent($ph1ent['interface']);
850
				else
851
					$parentinterface = $ph1ent['interface'];
852

    
853
				if (($parentinterface <> "wan") && (is_ipaddr($rgip))) {
854
					/* add endpoint routes to correct gateway on interface */
855
					if (interface_has_gateway($parentinterface)) {
856
						$gatewayip = get_interface_gateway("$parentinterface");
857
						$interfaceip = get_interface_ip($parentinterface);
858
						$subnet_bits = get_interface_subnet($parentinterface);
859
						$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
860
						/* if the remote gateway is in the local subnet, then don't add a route */
861
						if (! ip_in_subnet($rgip, "{$subnet_ip}/{$subnet_bits}")) {
862
							if(is_ipaddr($gatewayip)) {
863
								/* FIXME: does adding route-to and reply-to on the in/outbound
864
								 * rules fix this? smos@ 13-01-2009 */
865
								log_error("IPSEC interface is not WAN but {$parentinterface}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
866
								mwexec("/sbin/route delete -host {$rgip}");
867
								mwexec("/sbin/route add -host {$rgip} {$gatewayip}");
868
							}
869
						}
870
					}
871
				} elseif(is_ipaddr($rgip)) {
872
					if(stristr($route_str, "{$rgip}")) {
873
						mwexec("/sbin/route delete -host {$rgip}", true);
874
					}
875
				}
876
			}
877

    
878
			fwrite($fd, $spdconf);
879
			fclose($fd);
880
		}
881

    
882
		/* needed for racoonctl admin socket */
883
		if (!is_dir("/var/db/racoon"))
884
			mkdir("/var/db/racoon/");
885
		
886
		/* mange racoon process */
887
		if (is_process_running("racoon")) {
888
			sleep("0.1");
889
			mwexec("/usr/local/sbin/racoonctl -s /var/db/racoon/racoon.sock reload-config", false);
890
			/* load SPD without flushing to be safe on config additions or changes. */
891
			mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf", false);
892
		} else {
893
			/* flush SA + SPD entries */
894
			mwexec("/usr/local/sbin/setkey -FP", false);
895
 			sleep("0.1");
896
			mwexec("/usr/local/sbin/setkey -F", false);
897
 			sleep("0.1");
898
 			/* start racoon */
899
			mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf", false);
900
 			sleep("0.1");
901
 			/* load SPD */
902
			mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf", false);
903

    
904
		}
905
		/* start filterdns, if necessary */
906
		if (count($filterdns_list) > 0) {
907
			$interval = 60;
908
			if (!empty($ipseccfg['dns-interval']) && is_numeric($ipseccfg['dns-interval']))
909
				$interval = $ipseccfg['dns-interval'];
910

    
911
			$hostnames = "";
912
			array_unique($filterdns_list);
913
			foreach ($filterdns_list as $hostname)
914
				$hostnames .= "cmd {$hostname} '/etc/rc.newipsecdns'\n";
915
			file_put_contents("{$g['varetc_path']}/filterdns-ipsec.hosts", $hostnames);
916

    
917
			killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
918
			mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-ipsec.pid -i {$interval} -c {$g['varetc_path']}/filterdns-ipsec.hosts -d 1");
919
		}
920
	
921
		vpn_ipsec_failover_configure();
922

    
923
		if ($g['booting'])
924
			echo "done\n";
925
	}
926

    
927
	return 0;
928
}
929

    
930
/* Forcefully restart IPsec
931
 * This is required for when dynamic interfaces reload
932
 * For all other occasions the normal vpn_ipsec_configure()
933
 * will gracefully reload the settings without restarting
934
 */
935
function vpn_ipsec_force_reload() {
936
	global $config;
937
	global $g;
938

    
939
	$ipseccfg = $config['ipsec'];
940

    
941
	/* kill racoon */
942
	if(is_process_running("racoon"))
943
		mwexec("/usr/bin/killall racoon", true);
944

    
945
	/* wait for process to die */
946
	sleep(4);
947

    
948
	/* send a SIGKILL to be sure */
949
	sigkillbypid("{$g['varrun_path']}/racoon.pid", "KILL");
950

    
951
	/* wait for flushing to finish */
952
	sleep(1);
953

    
954
	/* if ipsec is enabled, start up again */
955
	if (isset($ipseccfg['enable'])) {
956
		log_error("Forcefully reloading IPsec racoon daemon");
957
		vpn_ipsec_configure();
958
	}
959

    
960
}
961

    
962
/* master setup for vpn (mpd) */
963
function vpn_setup() {
964
	/* start pptpd */
965
	vpn_pptpd_configure();
966

    
967
	/* start pppoe server */
968
	vpn_pppoes_configure();
969

    
970
	/* setup l2tp */
971
	vpn_l2tp_configure();
972
}
973

    
974
function vpn_netgraph_support() {
975
	$iflist = get_configured_interface_list();
976
	foreach ($iflist as $iface) {
977
		$realif = get_real_interface($iface);
978
		/* Get support for netgraph(4) from the nic */
979
		$ifinfo = pfSense_get_interface_addresses($realif);
980
		if (!empty($ifinfo) && in_array($ifinfo['iftype'], array("ether", "vlan", "bridge")))
981
                	pfSense_ngctl_attach(".", $realif);
982
	}
983
}
984

    
985
function vpn_pptpd_configure() {
986
	global $config, $g;
987

    
988
	$syscfg = $config['system'];
989
	$pptpdcfg = $config['pptpd'];
990

    
991
	if ($g['booting']) {
992
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
993
			return 0;
994

    
995
		echo "Configuring PPTP VPN service... ";
996
	} else {
997
		/* kill mpd */
998
		killbypid("{$g['varrun_path']}/pptp-vpn.pid");
999

    
1000
		/* wait for process to die */
1001
		sleep(3);
1002

    
1003
		if (is_process_running("mpd -b")) {
1004
			killbypid("{$g['varrun_path']}/pptp-vpn.pid");
1005
			log_error("Could not kill mpd within 3 seconds.   Trying again.");
1006
		}
1007

    
1008
		/* remove mpd.conf, if it exists */
1009
		unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.conf");
1010
		unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.links");
1011
		unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.secret");
1012
	}
1013

    
1014
	/* make sure pptp-vpn directory exists */
1015
	if (!file_exists("{$g['varetc_path']}/pptp-vpn"))
1016
		mkdir("{$g['varetc_path']}/pptp-vpn");
1017

    
1018
	switch ($pptpdcfg['mode']) {
1019
		case 'server' :
1020
			/* write mpd.conf */
1021
			$fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.conf", "w");
1022
			if (!$fd) {
1023
				printf("Error: cannot open mpd.conf in vpn_pptpd_configure().\n");
1024
				return 1;
1025
			}
1026

    
1027
			$mpdconf = <<<EOD
1028
pptps:
1029

    
1030
EOD;
1031

    
1032
			for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
1033
				$mpdconf .= "	load pt{$i}\n";
1034
			}
1035

    
1036
			for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
1037

    
1038
				$clientip = long2ip32(ip2long($pptpdcfg['remoteip']) + $i);
1039

    
1040
				$mpdconf .= <<<EOD
1041

    
1042
pt{$i}:
1043
	new -i pptpd{$i} pt{$i} pt{$i}
1044
	set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
1045
	load pts
1046

    
1047
EOD;
1048
			}
1049

    
1050
			$mpdconf .=<<<EOD
1051

    
1052
pts:
1053
	set iface disable on-demand
1054
	set iface enable proxy-arp
1055
	set iface enable tcpmssfix
1056
	set iface idle 1800
1057
	set iface up-script /usr/local/sbin/vpn-linkup
1058
	set iface down-script /usr/local/sbin/vpn-linkdown
1059
	set bundle enable multilink
1060
	set bundle enable crypt-reqd
1061
	set link yes acfcomp protocomp
1062
	set link no pap chap
1063
	set link enable chap-msv2
1064
	set link mtu 1460
1065
	set link keep-alive 10 60
1066
	set ipcp yes vjcomp
1067
	set bundle enable compression
1068
	set ccp yes mppc
1069
	set ccp yes mpp-e128
1070
	set ccp yes mpp-stateless
1071

    
1072
EOD;
1073

    
1074
			if (!isset ($pptpdcfg['req128'])) {
1075
				$mpdconf .=<<<EOD
1076
	set ccp yes mpp-e40
1077
	set ccp yes mpp-e56
1078

    
1079
EOD;
1080
			}
1081

    
1082
			if  (isset($pptpdcfg["wins"]) && $pptpdcfg['wins'] != "")
1083
				$mpdconf  .=  "	set ipcp nbns {$pptpdcfg['wins']}\n";
1084

    
1085
			if (!empty($pptpdcfg['dns1'])) {
1086
				$mpdconf .= "	set ipcp dns " . $pptpdcfg['dns1'];
1087
				if (!empty($pptpdcfg['dns2']))
1088
					$mpdconf .= " " . $pptpdcfg['dns2'];
1089
				$mpdconf .= "\n";
1090
			} elseif (isset ($config['dnsmasq']['enable'])) {
1091
				$mpdconf .= "	set ipcp dns " . get_interface_ip("lan");
1092
				if ($syscfg['dnsserver'][0])
1093
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1094
				$mpdconf .= "\n";
1095
			} elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1096
					$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1097
			}
1098

    
1099
			if (isset ($pptpdcfg['radius']['server']['enable'])) {
1100
				$authport = (isset($pptpdcfg['radius']['server']['port']) && strlen($pptpdcfg['radius']['server']['port']) > 1) ? $pptpdcfg['radius']['server']['port'] : 1812;
1101
				$acctport = $authport + 1;
1102
				$mpdconf .=<<<EOD
1103
	set radius server {$pptpdcfg['radius']['server']['ip']} "{$pptpdcfg['radius']['server']['secret']}" {$authport} {$acctport}
1104

    
1105
EOD;
1106
			if (isset ($pptpdcfg['radius']['server2']['enable'])) {
1107
				$authport = (isset($pptpdcfg['radius']['server2']['port']) && strlen($pptpdcfg['radius']['server2']['port']) > 1) ? $pptpdcfg['radius']['server2']['port'] : 1812;
1108
				$acctport = $authport + 1;
1109
				$mpdconf .=<<<EOD
1110
	set radius server {$pptpdcfg['radius']['server2']['ip']} "{$pptpdcfg['radius']['server2']['secret']}" {$authport} {$acctport}
1111

    
1112
EOD;
1113
			}
1114
			$mpdconf .=<<<EOD
1115
	set radius retries 3
1116
	set radius timeout 10
1117
	set auth enable radius-auth
1118

    
1119
EOD;
1120

    
1121
				if (isset ($pptpdcfg['radius']['accounting'])) {
1122
					$mpdconf .=<<<EOD
1123
	set auth enable radius-acct
1124
	set radius acct-update 300
1125

    
1126
EOD;
1127
				}
1128
			}
1129

    
1130
			fwrite($fd, $mpdconf);
1131
			fclose($fd);
1132

    
1133
			/* write mpd.links */
1134
			$fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.links", "w");
1135
			if (!$fd) {
1136
				printf("Error: cannot open mpd.links in vpn_pptpd_configure().\n");
1137
				return 1;
1138
			}
1139

    
1140
			$mpdlinks = "";
1141

    
1142
			for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
1143
				$mpdlinks .=<<<EOD
1144

    
1145
pt{$i}:
1146
	set link type pptp
1147
	set pptp enable incoming
1148
	set pptp disable originate
1149
	set pptp disable windowing
1150

    
1151
EOD;
1152
			}
1153

    
1154
			fwrite($fd, $mpdlinks);
1155
			fclose($fd);
1156

    
1157
			/* write mpd.secret */
1158
			$fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.secret", "w");
1159
			if (!$fd) {
1160
				printf("Error: cannot open mpd.secret in vpn_pptpd_configure().\n");
1161
				return 1;
1162
			}
1163

    
1164
			$mpdsecret = "";
1165

    
1166
			if (is_array($pptpdcfg['user'])) {
1167
				foreach ($pptpdcfg['user'] as $user)
1168
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
1169
			}
1170

    
1171
			fwrite($fd, $mpdsecret);
1172
			fclose($fd);
1173
			chmod("{$g['varetc_path']}/pptp-vpn/mpd.secret", 0600);
1174

    
1175
			vpn_netgraph_support();
1176

    
1177
			/* fire up mpd */
1178
			mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/pptp-vpn -p {$g['varrun_path']}/pptp-vpn.pid -s pptps pptps");
1179

    
1180
			break;
1181

    
1182
		case 'redir' :
1183
			break;
1184
	}
1185

    
1186
	if ($g['booting'])
1187
		echo "done\n";
1188

    
1189
	return 0;
1190
}
1191

    
1192
function vpn_pppoes_configure() {
1193
	global $config;
1194

    
1195
	if (is_array($config['pppoes']['pppoe'])) {
1196
		foreach ($config['pppoes']['pppoe'] as $pppoe)
1197
			vpn_pppoe_configure($pppoe);
1198
	}
1199
}
1200

    
1201
function vpn_pppoe_configure(&$pppoecfg) {
1202
	global $config, $g;
1203

    
1204
	$syscfg = $config['system'];
1205

    
1206
	/* create directory if it does not exist */
1207
	if (!is_dir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn"))
1208
		mkdir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn");
1209

    
1210
	if ($g['booting']) {
1211
		if (!$pppoecfg['mode'] || ($pppoecfg['mode'] == "off"))
1212
			return 0;
1213

    
1214
		echo "Configuring PPPoE VPN service... ";
1215
	} else {
1216
		/* kill mpd */
1217
		killbypid("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid");
1218

    
1219
		/* wait for process to die */
1220
		sleep(2);
1221

    
1222
	}
1223

    
1224
	switch ($pppoecfg['mode']) {
1225

    
1226
		case 'server' :
1227

    
1228
			$pppoe_interface = get_real_interface($pppoecfg['interface']);
1229

    
1230
			if ($pppoecfg['paporchap'] == "chap")
1231
				$paporchap = "set link enable chap";
1232
			else
1233
				$paporchap = "set link enable pap";
1234

    
1235
			/* write mpd.conf */
1236
			$fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.conf", "w");
1237
			if (!$fd) {
1238
				printf("Error: cannot open mpd.conf in vpn_pppoe_configure().\n");
1239
				return 1;
1240
			}
1241
			$mpdconf = "\n\n";
1242
			$mpdconf .= "poes:\n";
1243

    
1244
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1245
				$mpdconf .= "	load poes{$pppoecfg['pppoeid']}{$i}\n";
1246
			}
1247

    
1248
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1249

    
1250
				$clientip = long2ip32(ip2long($pppoecfg['remoteip']) + $i);
1251

    
1252
				if (isset ($pppoecfg['radius']['radiusissueips']) && isset ($pppoecfg['radius']['server']['enable'])) {
1253
					$isssue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 0.0.0.0/0";
1254
				} else {
1255
					$isssue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 {$clientip}/32";
1256
				}
1257

    
1258
				$mpdconf .=<<<EOD
1259

    
1260
poes{$pppoecfg['pppoeid']}{$i}:
1261
	new -i poes{$pppoecfg['pppoeid']}{$i} poes{$pppoecfg['pppoeid']}{$i} poes{$pppoecfg['pppoeid']}{$i}
1262
	{$isssue_ip_type}
1263
	load pppoe_standard
1264

    
1265
EOD;
1266
			}
1267

    
1268
			$mpdconf .=<<<EOD
1269

    
1270
pppoe_standard:
1271
	set bundle no multilink
1272
	set bundle enable compression
1273
	set auth max-logins 1
1274
	set iface up-script /usr/local/sbin/vpn-linkup
1275
	set iface down-script /usr/local/sbin/vpn-linkdown
1276
	set iface idle 0
1277
	set iface disable on-demand
1278
	set iface disable proxy-arp
1279
	set iface enable tcpmssfix
1280
	set iface mtu 1500
1281
	set link no pap chap
1282
	{$paporchap}
1283
	set link keep-alive 60 180
1284
	set ipcp yes vjcomp
1285
	set ipcp no vjcomp
1286
	set link max-redial -1
1287
	set link mtu 1492
1288
	set link mru 1492
1289
	set ccp yes mpp-e40
1290
	set ccp yes mpp-e128
1291
	set ccp yes mpp-stateless
1292
	set link latency 1
1293
	#set ipcp dns 10.10.1.3
1294
	#set bundle accept encryption
1295

    
1296
EOD;
1297

    
1298
			if (!empty($pppoecfg['dns1'])) {
1299
				$mpdconf .= "	set ipcp dns " . $pppoecfg['dns1'];
1300
				if (!empty($pppoecfg['dns2']))
1301
					$mpdconf .= " " . $pppoecfg['dns2'];
1302
				$mpdconf .= "\n";
1303
			} elseif (isset ($config['dnsmasq']['enable'])) {
1304
				$mpdconf .= "	set ipcp dns " . get_interface_ip("lan");
1305
				if ($syscfg['dnsserver'][0])
1306
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1307
				$mpdconf .= "\n";
1308
			} elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1309
					$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1310
			}
1311

    
1312
			if (isset ($pppoecfg['radius']['server']['enable'])) {
1313
				$radiusport = "";
1314
				$radiusacctport = "";
1315
				if (isset($pppoecfg['radius']['server']['port']))
1316
					$radiusport = $pppoecfg['radius']['server']['port'];
1317
				if (isset($pppoecfg['radius']['server']['acctport']))
1318
					$radiusacctport = $pppoecfg['radius']['server']['acctport'];
1319
				$mpdconf .=<<<EOD
1320
	set radius server {$pppoecfg['radius']['server']['ip']} "{$pppoecfg['radius']['server']['secret']} {$radiusport} {$radiusacctport}" 
1321
	set radius retries 3
1322
	set radius timeout 10
1323
	set auth enable radius-auth
1324

    
1325
EOD;
1326

    
1327
				if (isset ($pppoecfg['radius']['accounting'])) {
1328
					$mpdconf .=<<<EOD
1329
	set auth enable radius-acct
1330

    
1331
EOD;
1332
				}
1333
			}
1334

    
1335
			fwrite($fd, $mpdconf);
1336
			fclose($fd);
1337

    
1338
			/* write mpd.links */
1339
			$fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.links", "w");
1340
			if (!$fd) {
1341
				printf("Error: cannot open mpd.links in vpn_pppoe_configure().\n");
1342
				return 1;
1343
			}
1344

    
1345
			$mpdlinks = "";
1346

    
1347
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1348
				$mpdlinks .=<<<EOD
1349
			
1350
poes{$pppoecfg['pppoeid']}{$i}:
1351
	set phys type pppoe
1352
        set pppoe iface {$pppoe_interface}
1353
        set pppoe service "*"
1354
        set pppoe disable originate
1355
        set pppoe enable incoming
1356

    
1357
EOD;
1358
			}
1359

    
1360
			fwrite($fd, $mpdlinks);
1361
			fclose($fd);
1362

    
1363
			if ($pppoecfg['username']) {
1364
				/* write mpd.secret */
1365
				$fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", "w");
1366
				if (!$fd) {
1367
					printf("Error: cannot open mpd.secret in vpn_pppoe_configure().\n");
1368
					return 1;
1369
				}
1370

    
1371
				$mpdsecret = "\n\n";
1372

    
1373
				if (!empty($pppoecfg['username'])) {
1374
					$item = explode(" ", $pppoecfg['username']);
1375
					foreach($item as $userdata) {
1376
						$data = explode(":", $userdata);
1377
						$mpdsecret .= "{$data[0]} \"" . base64_decode($data[1]) . "\" {$data[2]}\n";
1378
					}
1379
				}
1380

    
1381
				fwrite($fd, $mpdsecret);
1382
				fclose($fd);
1383
				chmod("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", 0600);
1384
			}
1385

    
1386
			/* Get support for netgraph(4) from the nic */
1387
			pfSense_ngctl_attach(".", $pppoe_interface);
1388
			/* fire up mpd */
1389
			mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn -p {$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid -s poes poes");
1390

    
1391
			break;
1392
	}
1393

    
1394
	if ($g['booting'])
1395
		echo "done\n";
1396

    
1397
	return 0;
1398
}
1399

    
1400
function vpn_l2tp_configure() {
1401
	global $config, $g;
1402

    
1403
	$syscfg = $config['system'];
1404
	$l2tpcfg = $config['l2tp'];
1405

    
1406
	/* create directory if it does not exist */
1407
	if (!is_dir("{$g['varetc_path']}/l2tp-vpn"))
1408
		mkdir("{$g['varetc_path']}/l2tp-vpn");
1409

    
1410
	if ($g['booting']) {
1411
		if (!$l2tpcfg['mode'] || ($l2tpcfg['mode'] == "off"))
1412
			return 0;
1413

    
1414
		echo "Configuring l2tp VPN service... ";
1415
	} else {
1416
		/* kill mpd */
1417
		killbypid("{$g['varrun_path']}/l2tp-vpn.pid");
1418

    
1419
		/* wait for process to die */
1420
		sleep(8);
1421

    
1422
	}
1423

    
1424
	/* make sure l2tp-vpn directory exists */
1425
	if (!file_exists("{$g['varetc_path']}/l2tp-vpn"))
1426
		mkdir("{$g['varetc_path']}/l2tp-vpn");
1427

    
1428
	switch ($l2tpcfg['mode']) {
1429

    
1430
		case 'server' :
1431
			if ($l2tpcfg['paporchap'] == "chap")
1432
				$paporchap = "set link enable chap";
1433
			else
1434
				$paporchap = "set link enable pap";
1435

    
1436
			/* write mpd.conf */
1437
			$fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.conf", "w");
1438
			if (!$fd) {
1439
				printf("Error: cannot open mpd.conf in vpn_l2tp_configure().\n");
1440
				return 1;
1441
			}
1442
			$mpdconf = "\n\n";
1443
			$mpdconf .=<<<EOD
1444
l2tps:
1445

    
1446
EOD;
1447

    
1448
			for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
1449
				$mpdconf .= "	load l2tp{$i}\n";
1450
			}
1451

    
1452
			for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
1453

    
1454
				$clientip = long2ip32(ip2long($l2tpcfg['remoteip']) + $i);
1455

    
1456
				if (isset ($l2tpcfg['radius']['radiusissueips']) && isset ($l2tpcfg['radius']['enable'])) {
1457
					$isssue_ip_type = "set ipcp ranges {$l2tpcfg['localip']}/32 0.0.0.0/0";
1458
				} else {
1459
					$isssue_ip_type = "set ipcp ranges {$l2tpcfg['localip']}/32 {$clientip}/32";
1460
				}
1461

    
1462
				$mpdconf .=<<<EOD
1463

    
1464
l2tp{$i}:
1465
	new -i l2tp{$i} l2tp{$i} l2tp{$i}
1466
	{$isssue_ip_type}
1467
	load l2tp_standard
1468

    
1469
EOD;
1470
			}
1471

    
1472
			$mpdconf .=<<<EOD
1473

    
1474
l2tp_standard:
1475
        set bundle disable multilink
1476
        set bundle enable compression
1477
        set bundle yes crypt-reqd
1478
        set ipcp yes vjcomp
1479
        # set ipcp ranges 131.188.69.161/32 131.188.69.170/28
1480
        set ccp yes mppc
1481
        set iface disable on-demand
1482
        set iface enable proxy-arp
1483
	set iface up-script /usr/local/sbin/vpn-linkup
1484
	set iface down-script /usr/local/sbin/vpn-linkdown
1485
        set link yes acfcomp protocomp
1486
        set link no pap chap
1487
        set link enable chap
1488
        set link keep-alive 10 180
1489

    
1490
EOD;
1491

    
1492
			if (!empty($l2tpcfg['dns1'])) {
1493
				$mpdconf .= "	set ipcp dns " . $l2tpcfg['dns1'];
1494
				if (!empty($l2tpcfg['dns2']))
1495
					$mpdconf .= " " . $l2tpcfg['dns2'];
1496
				$mpdconf .= "\n";
1497
			} elseif (isset ($config['dnsmasq']['enable'])) {
1498
				$mpdconf .= "	set ipcp dns " . get_interface_ip("lan");
1499
				if ($syscfg['dnsserver'][0])
1500
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1501
				$mpdconf .= "\n";
1502
			} elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1503
					$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1504
			}
1505

    
1506
			if (isset ($l2tpcfg['radius']['enable'])) {
1507
				$mpdconf .=<<<EOD
1508
	set radius server {$l2tpcfg['radius']['server']} "{$l2tpcfg['radius']['secret']}"
1509
	set radius retries 3
1510
	set radius timeout 10
1511
	set auth enable radius-auth
1512

    
1513
EOD;
1514

    
1515
				if (isset ($l2tpcfg['radius']['accounting'])) {
1516
					$mpdconf .=<<<EOD
1517
	set auth enable radius-acct
1518

    
1519
EOD;
1520
				}
1521
			}
1522

    
1523
			fwrite($fd, $mpdconf);
1524
			fclose($fd);
1525

    
1526
			/* write mpd.links */
1527
			$fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.links", "w");
1528
			if (!$fd) {
1529
				printf("Error: cannot open mpd.links in vpn_l2tp_configure().\n");
1530
				return 1;
1531
			}
1532

    
1533
			$mpdlinks = "";
1534

    
1535
			for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
1536
				$mpdlinks .=<<<EOD
1537

    
1538
l2tp{$i}:
1539
	set link type l2tp
1540
        set l2tp enable incoming
1541
        set l2tp disable originate
1542

    
1543
EOD;
1544
			if (!empty($l2tpcfg['secret']))
1545
					$mpdlinks .= "set l2tp secret {$l2tpcfg['secret']}\n";
1546
			}
1547

    
1548
			fwrite($fd, $mpdlinks);
1549
			fclose($fd);
1550

    
1551
			/* write mpd.secret */
1552
			$fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.secret", "w");
1553
			if (!$fd) {
1554
				printf("Error: cannot open mpd.secret in vpn_l2tp_configure().\n");
1555
				return 1;
1556
			}
1557

    
1558
			$mpdsecret = "\n\n";
1559

    
1560
			if (is_array($l2tpcfg['user'])) {
1561
				foreach ($l2tpcfg['user'] as $user)
1562
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
1563
			}
1564

    
1565
			fwrite($fd, $mpdsecret);
1566
			fclose($fd);
1567
			chmod("{$g['varetc_path']}/l2tp-vpn/mpd.secret", 0600);
1568

    
1569
			vpn_netgraph_support();
1570

    
1571
			/* fire up mpd */
1572
			mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/l2tp-vpn -p {$g['varrun_path']}/l2tp-vpn.pid -s l2tps l2tps");
1573

    
1574
			break;
1575

    
1576
		case 'redir' :
1577
			break;
1578
	}
1579

    
1580
	if ($g['booting'])
1581
		echo "done\n";
1582

    
1583
	return 0;
1584
}
1585

    
1586
/* Walk the tunnels for hostname endpoints. If the hostnames 
1587
 * resolve to a different IP now compared to the DNS cache
1588
 * we reload the policies if the endpoint has changed */
1589
function vpn_ipsec_refresh_policies() {
1590
	global $config;
1591
	global $g;
1592

    
1593
	$ipseccfg = $config['ipsec'];
1594
	$a_phase1 = $config['ipsec']['phase1'];
1595
	$a_phase2 = $config['ipsec']['phase2'];
1596

    
1597
	if (isset($ipseccfg['disable'])) {
1598
		return true;
1599
	}
1600

    
1601
	/* Walk the Ipsec tunnel array */
1602
	if (!is_array($a_phase1) || (!count($a_phase1))) {
1603
		return;
1604
	}
1605

    
1606
	foreach ($a_phase1 as $phase1) {
1607
		if (isset($phase1['disabled'])) {
1608
			continue;
1609
		}
1610
		if (is_ipaddr($phase1['remote-gateway'])) {
1611
			continue;
1612
		}
1613
		if (!is_ipaddr($phase1['remote-gateway'])) {
1614
			$dnscache = compare_hostname_to_dnscache($phase1['remote-gateway']);
1615
			$dnscache = trim($dnscache);
1616
			/* we should have the old IP addresses in the dnscache now */
1617
			if($dnscache <> "") {
1618
				$oldphase1 = $phase1;
1619
				$oldphase1['remote-gateway'] = trim($dnscache);
1620
				/* now we need to find all tunnels for this host */
1621
				if (!is_array($a_phase2) || (!count($a_phase2))) {
1622
					continue;
1623
				}
1624
				foreach ($a_phase2 as $phase2) {
1625
					if($phase2['ikeid'] == $phase1['ikeid']) {
1626
						reload_tunnel_spd_policy ($phase1, $phase2, $oldphase1, $oldphase2);
1627
					}
1628
				}
1629
			}
1630
		}
1631
	}
1632

    
1633
	/* process all generated spd.conf files from tmp which are left behind
1634
	 * behind by either changes of dynamic tunnels or manual edits
1635
	 * scandir() is only available in PHP5 */
1636
	$tmpfiles = array();
1637
	$dh  = opendir($g['tmp_path']);
1638
	while (false !== ($filename = readdir($dh))) {
1639
		if(preg_match("/^spd.conf.reload./", $filename)) {
1640
			$tmpfiles[] = $filename;
1641
		}
1642
	}
1643
	sort($tmpfiles);
1644
	foreach($tmpfiles as $tmpfile) {
1645
		$ret = mwexec("/usr/local/sbin/setkey -f {$g['tmp_path']}/{$tmpfile} 2>&1", false);
1646
		if($ret == 0) {
1647
			unlink_if_exists("{$g['tmp_path']}/{$tmpfile}");
1648
		} else {
1649
			rename("{$g['tmp_path']}/{$tmpfile}", ("{$g['tmp_path']}/failed.{$tmpfile}"));
1650
		}
1651
	}
1652
}
1653

    
1654
/* reloads the tunnel configuration for a tunnel item
1655
 * Will remove and add SPD polices */
1656
function reload_tunnel_spd_policy($phase1, $phase2, $old_phase1, $old_phase2) {
1657
	global $config;
1658
	global $g;
1659

    
1660
	/* if we are not passed a old tunnel array we create one */
1661
	if(empty($old_phase1)) {
1662
		$old_phase1 = $phase1;
1663
	}
1664
	if(empty($old_phase2)) {
1665
		$old_phase2 = $phase2;
1666
	}
1667

    
1668
	$sad_arr = ipsec_dump_sad();
1669

    
1670
	$ep = ipsec_get_phase1_src($phase1);
1671
	$local_subnet = ipsec_idinfo_to_cidr($phase2['localid']);
1672
	$remote_subnet = ipsec_idinfo_to_cidr($phase2['remoteid']);
1673

    
1674
	/* make sure we pass the oldtunnel array with a IP for the remote gw */
1675
	$old_gw = trim($old_phase1['remote-gateway']);
1676

    
1677
	$old_ep = ipsec_get_phase1_src($old_phase1);
1678
	$old_local_subnet = ipsec_idinfo_to_cidr($old_phase2['localid']);
1679
	$old_remote_subnet = ipsec_idinfo_to_cidr($old_phase2['remoteid']);
1680

    
1681
	/* see if this tunnel has a hostname for the remote-gateway, and if so,
1682
	 * try to resolve it now and add it to the list for filterdns */
1683
	$rgip = "";
1684
	if (!is_ipaddr($phase1['remote-gateway'])) {
1685
		if(! $g['booting']) {
1686
			$rgip = resolve_retry($phase1['remote-gateway']);
1687
			add_hostname_to_watch($phase1['remote-gateway']);
1688
		} else {
1689
			add_hostname_to_watch($phase1['remote-gateway']);
1690
		}
1691
		if (!is_ipaddr($rgip)) {
1692
			log_error("Could not determine VPN endpoint for '{$phase1['descr']}'");
1693
			return false;
1694
		}
1695
	} else {
1696
		$rgip = $phase1['remote-gateway'];
1697
	}
1698
	if (!$ep) {
1699
		log_error("Could not determine VPN endpoint for '{$phase1['descr']}'");
1700
		return false;
1701
	}
1702

    
1703
	if((!is_ipaddr($old_ep)) || (! is_ipaddr($ep))) {
1704
		log_error("IPSEC: ERROR: One of the endpoints is not a IP address. Old EP '{$old_ep}' new EP '{$ep}'");
1705
	}
1706
	if((! is_ipaddr($rgip)) || (! is_ipaddr($old_gw))) {
1707
		log_error("IPSEC: ERROR: One of the remote endpoints is not a IP address. Old RG '{$old_gw}' new RG '{$rgip}'");
1708
	}
1709

    
1710
	$spdconf = "";
1711
	/* Delete old SPD policies if there are changes between the old and new */
1712
	if(($phase1 != $old_phase1) || ($phase2 != $old_phase2)) {
1713
		$spdconf .= "spddelete {$old_local_subnet} " .
1714
			"{$old_remote_subnet} any -P out ipsec " .
1715
			"{$old_phase2['protocol']}/tunnel/{$old_ep}-" .
1716
			"{$old_gw}/unique;\n";
1717
		$spdconf .= "spddelete {$old_remote_subnet} " .
1718
			"{$old_local_subnet} any -P in ipsec " .
1719
			"{$old_phase2['protocol']}/tunnel/{$old_gw}-" .
1720
			"{$old_ep}/unique;\n";
1721

    
1722
		/* zap any existing SA entries */
1723
		foreach($sad_arr as $sad) {
1724
			if(($sad['dst'] == $old_ep) && ($sad['src'] == $old_gw)) {
1725
				$spdconf .= "delete {$old_ep} {$old_gw} {$old_phase2['protocol']} 0x{$sad['spi']};\n";
1726
			}
1727
			if(($sad['src'] == $oldep) && ($sad['dst'] == $old_gw)) {
1728
				$spdconf .= "delete {$old_gw} {$old_ep} {$old_phase2['protocol']} 0x{$sad['spi']};\n";
1729
			}
1730
		}
1731
	}
1732

    
1733
	/* Create new SPD entries for the new configuration */
1734
	/* zap any existing SA entries beforehand */
1735
	foreach($sad_arr as $sad) {
1736
		if(($sad['dst'] == $ep) && ($sad['src'] == $rgip)) {
1737
			$spdconf .= "delete {$rgip} {$ep} {$phase2['protocol']} 0x{$sad['spi']};\n";
1738
		}
1739
		if(($sad['src'] == $ep) && ($sad['dst'] == $rgip)) {
1740
			$spdconf .= "delete {$ep} {$rgip} {$phase2['protocol']} 0x{$sad['spi']};\n";
1741
		}
1742
	}
1743
	/* add new SPD policies to replace them */
1744
	$spdconf .= "spdadd {$local_subnet} " .
1745
		"{$remote_subnet} any -P out ipsec " .
1746
		"{$phase2['protocol']}/tunnel/{$ep}-" .
1747
		"{$rgip}/unique;\n";
1748
	$spdconf .= "spdadd {$remote_subnet} " .
1749
		"{$local_subnet} any -P in ipsec " .
1750
		"{$phase2['protocol']}/tunnel/{$rgip}-" .
1751
		"{$ep}/unique;\n";
1752

    
1753
	log_error("Reloading IPsec tunnel '{$phase1['descr']}'. Previous IP '{$old_gw}', current IP '{$rgip}'. Reloading policy");
1754

    
1755
	$now = time();
1756
	$spdfile = tempnam("{$g['tmp_path']}", "spd.conf.reload.{$now}.");
1757
	/* generate temporary spd.conf */
1758
	file_put_contents($spdfile, $spdconf);
1759
	return true;
1760
}
1761

    
1762
function vpn_ipsec_configure_preferoldsa() {
1763
	global $config;
1764
	if(isset($config['ipsec']['preferoldsa']))
1765
		mwexec("/sbin/sysctl -w net.key.preferred_oldsa=-30");
1766
	else
1767
		mwexec("/sbin/sysctl net.key.preferred_oldsa=0");
1768
}
1769

    
1770
?>
(52-52/61)