Project

General

Profile

Download (47.1 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/dnswatch	/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']}/dnswatch-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

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

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

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

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

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

    
143
				$ep = ipsec_get_phase1_src($ph1ent);
144
				if (!$ep)
145
					continue;
146

    
147
				if(!in_array($ep,$ipmap))
148
					$ipmap[] = $ep;
149

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

    
153
				if (isset ($ph1ent['mobile']))
154
					continue;
155

    
156
				$rg = $ph1ent['remote-gateway'];
157

    
158
				if (!is_ipaddr($rg)) {
159
					$dnswatch_list[] = "{$rg}=value";
160
					add_hostname_to_watch($rg);
161
					$rg = resolve_retry($rg);
162
					if (!$rg)
163
						continue;
164
				}
165

    
166
				$rgmap[$ph1ent['remote-gateway']] = $rg;
167

    
168
				/* step through each phase2 entry */
169
				$ipsecpinghosts = "";
170
				foreach ($a_phase2 as $ph2ent) {
171

    
172
					$ikeid = $ph2ent['ikeid'];
173

    
174
					if (isset($ph2ent['disabled']))
175
						continue;
176

    
177
					if ($ikeid != $ph1ent['ikeid'])
178
						continue;
179

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

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

    
233
		$pskconf = "";
234

    
235
		if (is_array($a_phase1) && count($a_phase1)) {
236
			foreach ($a_phase1 as $ph1ent) {
237

    
238
				if (isset($ph1ent['disabled']))
239
					continue;
240

    
241
				if (strstr($ph1ent['authentication_method'],'rsa'))
242
					continue;
243

    
244
				$peerid_type = $ph1ent['peerid_type'];
245

    
246
				switch ($peerid_type) {
247
					case "peeraddress":
248
						$peerid_type = "address";
249
						$peerid_data = $rgmap[$ph1ent['remote-gateway']];
250
						break;
251

    
252
					case "address";
253
						$peerid_data = $ph1ent['peerid_data'];
254
						break;
255

    
256
					case "fqdn";
257
					case "keyid tag";
258
					case "user_fqdn";
259
						$peerid_data = $ph1ent['peerid_data'];
260
						break;
261
				}
262

    
263
				$pskconf .= "{$peerid_data}\t{$ph1ent['pre-shared-key']}\n";
264
			}
265
		}
266

    
267
		/* Add user PSKs */
268
		foreach ($config['system']['user'] as $user) {
269
			if (!empty($user['ipsecpsk'])) {
270
				$pskconf .= "{$user['name']}\t{$user['ipsecpsk']}\n";
271
			}
272
		}
273

    
274
		/* add PSKs for mobile clients */
275
		if (is_array($ipseccfg['mobilekey'])) {
276
			foreach ($ipseccfg['mobilekey'] as $key) {
277
				$pskconf .= "{$key['ident']}\t{$key['pre-shared-key']}\n";
278
			}
279
		}
280

    
281
		fwrite($fd, $pskconf);
282
		fclose($fd);
283
		chmod("{$g['varetc_path']}/psk.txt", 0600);
284
			
285
		/* begin racoon.conf */
286
		if ((is_array($a_phase1) && count($a_phase1)) ||
287
			(is_array($a_phase2) && count($a_phase2))) {
288

    
289
			$fd = fopen("{$g['varetc_path']}/racoon.conf", "w");
290
			if (!$fd) {
291
				printf("Error: cannot open racoon.conf in vpn_ipsec_configure().\n");
292
				return 1;
293
			}
294

    
295
			$racoonconf = "# This file is automatically generated. Do not edit\n";			
296
			$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
297
			$racoonconf .= "path certificate  \"{$g['varetc_path']}\";\n\n";
298

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

    
311
			/* begin mode_cfg section */
312
			if (is_array($a_client) && isset($a_client['enable'])) {
313

    
314
				$racoonconf .= "\nmode_cfg\n";
315
				$racoonconf .= "{\n";
316

    
317
				if ($a_client['user_source'])
318
					$racoonconf .= "\tauth_source {$a_client['user_source']};\n";
319
				if ($a_client['group_source'])
320
					$racoonconf .= "\tgroup_source {$a_client['group_source']};\n";
321

    
322
				if ($a_client['pool_address'] && $a_client['pool_netbits']) {
323
					$pool_address = $a_client['pool_address'];
324
					$pool_netmask = gen_subnet_mask($a_client['pool_netbits']);
325

    
326
					$pool_address = long2ip32(ip2long($pool_address)+1);
327
					$pool_size = (~ip2long($pool_netmask) & 0xFFFFFFFF) - 2;
328

    
329
					$racoonconf .= "\tpool_size {$pool_size};\n";
330
					$racoonconf .= "\tnetwork4 {$pool_address};\n";
331
					$racoonconf .= "\tnetmask4 {$pool_netmask};\n";
332
				}
333

    
334
				if (isset($a_client['net_list'])) {
335

    
336
					$net_list = '';
337

    
338
					foreach ($a_phase2 as $ph2ent) {
339

    
340
						if (isset($ph2ent['disabled']))
341
							continue;
342

    
343
						if (!isset($ph2ent['mobile']))
344
							continue;
345

    
346
						$localid = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
347

    
348
						if ($net_list)
349
							$net_list .= ", ";
350
						$net_list .= $localid;
351
					}
352

    
353
					if ($net_list)
354
						$racoonconf .= "\tsplit_network include {$net_list};\n";
355
				}
356

    
357
				if ($a_client['dns_server1'])
358
					$racoonconf .= "\tdns4 {$a_client['dns_server1']};\n";
359
				if ($a_client['dns_server2'])
360
					$racoonconf .= "\tdns4 {$a_client['dns_server2']};\n";
361
				if ($a_client['dns_server3'])
362
					$racoonconf .= "\tdns4 {$a_client['dns_server3']};\n";
363
				if ($a_client['dns_server4'])
364
					$racoonconf .= "\tdns4 {$a_client['dns_server4']};\n";
365

    
366
				if ($a_client['wins_server1'])
367
					$racoonconf .= "\twins4 {$a_client['wins_server1']};\n";
368
				if ($a_client['wins_server2'])
369
					$racoonconf .= "\twins4 {$a_client['wins_server2']};\n";
370

    
371
				if ($a_client['dns_domain']) {
372
					$racoonconf .= "\tdefault_domain \"{$a_client['dns_domain']}\";\n";
373
					$racoonconf .= "\tsplit_dns \"{$a_client['dns_domain']}\";\n";
374
				}
375

    
376
				if ($a_client['pfs_group'])
377
					$racoonconf .= "\tpfs_group {$a_client['pfs_group']};\n";
378

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

    
387
					fwrite($fd1, $a_client['login_banner']);
388
					fclose($fd1);
389

    
390
					$racoonconf .= "\tbanner \"{$fn}\";\n";
391
				}
392

    
393
				if (isset($a_client['save_passwd']))
394
					$racoonconf .= "\tsave_passwd on;\n";
395

    
396
				$racoonconf .= "}\n\n";
397
			}
398
			/* end mode_cfg section */
399

    
400
			/* begin remote sections */
401
			if (is_array($a_phase1) && count($a_phase1)) {
402
				/* begin remote */
403
				foreach ($a_phase1 as $ph1ent) {
404

    
405
					if (isset($ph1ent['disabled']))
406
						continue;
407

    
408
					if (isset($ph1ent['mobile']) && !isset($a_client['enable']))
409
						continue;
410

    
411
					$ikeid = $ph1ent['ikeid'];
412

    
413
					$ep = ipsec_get_phase1_src($ph1ent);
414
					if (!$ep)
415
						continue;
416

    
417
					if (!isset($ph1ent['mobile'])) {
418
						$rgip = $rgmap[$ph1ent['remote-gateway']];
419
						if (!$rgip)
420
							continue;
421
					}
422

    
423
					$myid_type = $ph1ent['myid_type'];
424

    
425
					switch ($myid_type) {
426

    
427
						case "myaddress":
428
							$myid_type = "address";
429
							$myid_data = $ep;
430
							break;
431

    
432
						case "dyn_dns":
433
							$myid_type = "address";
434
							$myid_data = gethostbyname($ph1ent['myid_data']);
435
							break;
436

    
437
						case "address";
438
							$myid_data = $ph1ent['myid_data'];
439
							break;
440

    
441
						case "fqdn";
442
						case "keyid tag";
443
						case "user_fqdn";
444
						case "asn1dn";
445
							$myid_data = $ph1ent['myid_data'];
446
							if( $myid_data )
447
								$myid_data = "\"".$myid_data."\"";
448
							break;
449
					}
450

    
451
					$peerid_type = $ph1ent['peerid_type'];
452

    
453
					switch ($peerid_type) {
454
						case "peeraddress":
455
							$peerid_type = "address";
456
							$peerid_data = $rgip;
457
							break;
458

    
459
						case "address";
460
							$peerid_data = $ph1ent['peerid_data'];
461
							break;
462

    
463
						case "fqdn";
464
						case "keyid tag";
465
						case "user_fqdn";
466
						case "asn1dn";
467
							$peerid_data = $ph1ent['peerid_data'];
468
							if( $peerid_data )
469
								$peerid_data = "\"".$peerid_data."\"";
470
							break;
471
					}
472

    
473
					$natt = "off";
474
					if (isset($ph1ent['nat_traversal']))
475
						$natt = $ph1ent['nat_traversal'];
476

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

    
494
					$dpdline1 = '';
495
					$dpdline2 = '';
496
					if ($ph1ent['dpd_delay'] && $ph1ent['dpd_maxfail']) {
497
						$dpdline1 = "dpd_delay = {$ph1ent['dpd_delay']};";
498
						$dpdline2 = "dpd_maxfail = {$ph1ent['dpd_maxfail']};";
499
					}
500

    
501
					if (isset ($ph1ent['authentication_method']))
502
						$authmethod = $ph1ent['authentication_method'];
503
					else
504
						$authmethod = 'pre_shared_key';
505

    
506
					$certline = '';
507

    
508
					if (strstr($authmethod,'rsa')) {
509

    
510
						$cert = lookup_cert($ph1ent['certref']);
511

    
512
						if (!$cert)
513
						{
514
							log_error("Error: Invalid phase1 certificate reference for {$ph1ent['name']}");
515
							continue;
516
						}
517

    
518
						$certfile = "cert-".$ikeid.".crt";
519
						$certpath = $g['varetc_path']."/".$certfile;
520

    
521
						if (!file_put_contents($certpath, base64_decode($cert['crt'])))
522
						{
523
							log_error("Error: Cannot write phase1 certificate file for {$ph1ent['name']}");
524
							continue;
525
						}
526

    
527
						chmod($certpath, 0600);
528

    
529
						$keyfile = "cert-".$ikeid.".key";
530
						$keypath = $g['varetc_path']."/".$keyfile;
531

    
532
						if (!file_put_contents($keypath, base64_decode($cert['prv'])))
533
						{
534
							log_error("Error: Cannot write phase1 key file for {$ph1ent['name']}");
535
							continue;
536
						}
537

    
538
						chmod($keypath, 0600);
539

    
540
						$ca = lookup_ca($ph1ent['caref']);
541
						if ($ca) {
542
							$cafile = "ca-".$ikeid.".crt";
543
							$capath = $g['varetc_path']."/".$cafile;
544

    
545
							if (!file_put_contents($capath, base64_decode($ca['crt'])))
546
							{
547
								log_error("Error: Cannot write phase1 CA certificate file for {$ph1ent['name']}");
548
								continue;
549
							}
550

    
551
							chmod($capath, 0600);
552
							$caline = "ca_type x509 \"".basename($capath)."\";";
553
						}
554

    
555
						$certline = "certificate_type x509 \"".basename($certpath)."\" \"".basename($keypath)."\";";
556

    
557
					}
558

    
559
					$ealgos = '';
560
					$ealg_id = $ph1ent['encryption-algorithm']['name'];
561
					$ealg_kl = $ph1ent['encryption-algorithm']['keylen'];
562
					if ($ealg_kl)
563
						$ealgos = $ealgos.$ealg_id." ".$ealg_kl;
564
					else
565
						$ealgos = $ealgos.$ealg_id;
566

    
567
					$lifeline = '';
568
					if ($ph1ent['lifetime'])
569
						$lifeline = "lifetime time {$ph1ent['lifetime']} secs;";
570

    
571
					/* Only specify peer ID if we are not dealing with a mobile PSK-only tunnel */
572
					if (!(($ph1ent['authentication_method'] == "pre_shared_key") && isset($ph1ent['mobile']))) {
573
						$peerid_spec = "peers_identifier {$peerid_type} {$peerid_data};";
574
					}
575

    
576
					/* add remote section to configuration */
577

    
578
					$racoonconf .=<<<EOD
579

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

    
598
	proposal
599
	{
600
		authentication_method {$authmethod};
601
		encryption_algorithm ${ealgos};
602
		hash_algorithm {$ph1ent['hash-algorithm']};
603
		dh_group {$ph1ent['dhgroup']};
604
		${lifeline}
605
	}
606
}
607

    
608
EOD;
609
				}
610
				/* end remote */
611
			}
612
			/* end remote sections */
613
		
614
			/* begin sainfo sections */
615
			if (is_array($a_phase2) && count($a_phase2)) {
616

    
617
				/* begin sainfo */
618
				foreach ($a_phase2 as $ph2ent) {
619

    
620
					$ikeid = $ph2ent['ikeid'];
621

    
622
					if( !ipsec_lookup_phase1($ph2ent,$ph1ent))
623
						continue;
624

    
625
					if (isset($ph1ent['disabled']))
626
						continue;
627

    
628
					if (isset($ph2ent['disabled']))
629
						continue;
630

    
631
					if (isset($ph2ent['mobile']) && !isset($a_client['enable']))
632
						continue;
633

    
634
					if ($ph2ent['mode'] == 'tunnel') {
635

    
636
						$localid_type = $ph2ent['localid']['type'];
637
						$localid_data = ipsec_idinfo_to_cidr($ph2ent['localid']);
638
						/* Do not print localid in some cases, such as a pure-psk mobile tunnel */
639
						if (($localid_type == "none") || ($ph1ent['authentication_method'] == "pre_shared_key") && isset($ph1ent['mobile']))
640
							$localid_spec = " ";
641
						else if ($localid_type != "address") {
642
							$localid_type = "subnet";
643
							$localid_spec = $localid_type." ".$localid_data." any";
644
						}
645

    
646
						if (!isset($ph2ent['mobile'])) {
647
							$remoteid_type = $ph2ent['remoteid']['type'];
648
							if ($remoteid_type != "address")
649
								$remoteid_type = "subnet";
650

    
651
							$remoteid_data = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
652
							$remoteid_spec = $remoteid_type." ".$remoteid_data." any";
653
						} else
654
							$remoteid_spec = "anonymous";
655

    
656
					} else {
657

    
658
						$rgip = $rgmap[$ph1ent['remote-gateway']];
659

    
660
						$localid_data = ipsec_get_phase1_src($ph1ent);
661
						if($ph2ent['mode'] == 'transport') { $localid_data="$localid_data any"; }
662
						$localid_spec = "address {$localid_data}";
663

    
664
						$remoteid_data = $rgmap[$ph1ent['remote-gateway']];
665
						if($ph2ent['mode'] == 'transport') { $remoteid_data="$remoteid_data any"; }
666
						$remoteid_spec = "address {$remoteid_data}";
667
					}
668

    
669
					if($ph2ent['protocol'] == 'esp') {
670

    
671
						$ealgos = '';
672

    
673
						foreach ($ph2ent['encryption-algorithm-option'] as $ealg) {
674

    
675
							$ealg_id = $ealg['name'];
676
							$ealg_kl = $ealg['keylen'];
677

    
678
							if ($ealg_kl) {
679
								if( $ealg_kl == "auto" ) {
680
									/*   This seems to be required on my system and was not reproducable
681
									 *   on other systems.   For some reason $p2_ealgos is not defined
682
									 *   and needs to be read back in!?  -sullrich Aug 26, 2009 
683
									 */
684
									if(!$p2_ealgos)
685
										require("ipsec.inc");
686
									$key_hi = $p2_ealgos[$ealg_id]['keysel']['hi'];
687
									$key_lo = $p2_ealgos[$ealg_id]['keysel']['lo'];
688
									$key_step = $p2_ealgos[$ealg_id]['keysel']['step'];
689
									/* in some cases where include ordering is suspect these variables
690
									   are somehow 0 and we enter this loop forever and timeout after 900
691
									   seconds wrecking bootup */
692
									if($key_hi != 0 and $key_lo !=0 and $key_step !=0) {
693
										for ($keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step) {
694
//											Uncomment the next line if you want to test the comment 5 lines up.											
695
//											echo "$keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step \n";
696
											if ($ealgos)
697
												$ealgos = $ealgos.", ";
698
											$ealgos = $ealgos.$ealg_id." ".$keylen;
699
										}
700
									}
701
								} else {
702
									if ($ealgos)
703
										$ealgos = $ealgos.", ";
704
									$ealgos = $ealgos.$ealg_id." ".$ealg_kl;
705
								}
706
							} else {
707
								if ($ealgos)
708
									$ealgos = $ealgos.", ";
709
								$ealgos = $ealgos.$ealg_id;
710
							}
711
						}
712

    
713
						$ealgosline = "encryption_algorithm {$ealgos};";
714

    
715
					} else {
716

    
717
						$ealgosline = "encryption_algorithm null_enc;";
718
					}
719

    
720
					$halgos = join(",", $ph2ent['hash-algorithm-option']);
721
					$halgosline = "authentication_algorithm {$halgos};";
722

    
723
					$pfsline = '';
724
					if ($ph2ent['pfsgroup'])
725
						$pfsline = "pfs_group {$ph2ent['pfsgroup']};";
726
					if (isset($a_client['pfs_group'])) {
727
						$pfsline = '';
728
						if ($a_client['pfs_group'])
729
							$pfsline = "pfs_group {$a_client['pfs_group']};";
730
					}
731

    
732
					$lifeline = '';
733
					if ($ph2ent['lifetime'])
734
						$lifeline = "lifetime time {$ph2ent['lifetime']} secs;";
735

    
736
					/* add sainfo section to configuration */
737
					
738
					$racoonconf .=<<<EOD
739
					
740
sainfo {$localid_spec} {$remoteid_spec}
741
{
742
	remoteid {$ikeid};
743
	{$ealgosline}
744
	{$halgosline}
745
	{$pfsline}
746
	{$lifeline}
747
	compression_algorithm deflate;
748
}
749

    
750
EOD;
751
				}
752
				/* end sainfo */
753
			}
754
			/* end sainfo sections */
755

    
756
			fwrite($fd, $racoonconf);
757
			fclose($fd);
758
		}
759
		/* end racoon.conf */
760

    
761
		/* generate IPsec policies */
762
		if (is_array($a_phase2) && count($a_phase2)) {
763
			/* generate spd.conf */
764
			$fd = fopen("{$g['varetc_path']}/spd.conf", "w");
765
			if (!$fd) {
766
				printf("Error: cannot open spd.conf in vpn_ipsec_configure().\n");
767
				return 1;
768
			}
769

    
770
			$spdconf = "";
771

    
772
			/* Try to prevent people from locking themselves out of webgui. Just in case. */
773
			if ($config['interfaces']['lan']) {
774
				$lanip = get_interface_ip("lan");
775
				if (!empty($lanip) && is_ipaddr($lanip)) {
776
					$lansn = get_interface_subnet("lan");
777
					$lansa = gen_subnet($lanip, $lansn);
778
					$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
779
					$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
780
				}
781
			}
782

    
783
			foreach ($a_phase2 as $ph2ent) {
784

    
785
				if( !ipsec_lookup_phase1($ph2ent,$ph1ent))
786
					continue;
787

    
788
				if (isset($ph1ent['mobile']))
789
					continue;
790

    
791
				if (isset($ph1ent['disabled']))
792
					continue;
793

    
794
				if (isset($ph2ent['disabled']))
795
					continue;
796

    
797
				$ep = ipsec_get_phase1_src($ph1ent);
798
				if (!$ep)
799
					continue;
800

    
801
				$rgip = $rgmap[$ph1ent['remote-gateway']];
802

    
803
				$localid = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
804
				$remoteid = ipsec_idinfo_to_cidr($ph2ent['remoteid'],true);
805

    
806
				if($ph2ent['mode'] == "tunnel") {
807

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

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

    
814
				} else {
815

    
816
					$localid_data = ipsec_get_phase1_src($ph1ent);
817
					$remoteid_data = $rgmap[$ph1ent['remote-gateway']];
818

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

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

    
825
				}
826

    
827
				/* static route needed? */
828
				if (preg_match("/^carp|^vip/i", $ph1ent['interface']))
829
					$parentinterface = link_carp_interface_to_parent($ph1ent['interface']);
830
				else
831
					$parentinterface = $ph1ent['interface'];
832

    
833
				if ($parentinterface <> "wan") {
834
					/* add endpoint routes to correct gateway on interface */
835
					if (interface_has_gateway($parentinterface)) {
836
						$gatewayip = get_interface_gateway("$parentinterface");
837
						$interfaceip = get_interface_ip($parentinterface);
838
						$subnet_bits = get_interface_subnet($parentinterface);
839
						$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
840
						/* if the remote gateway is in the local subnet, then don't add a route */
841
						if (! ip_in_subnet($rgip, "{$subnet_ip}/{$subnet_bits}")) {
842
							if(is_ipaddr($gatewayip)) {
843
								/* FIXME: does adding route-to and reply-to on the in/outbound
844
								 * rules fix this? smos@ 13-01-2009 */
845
								log_error("IPSEC interface is not WAN but {$parentinterface}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
846
								mwexec("/sbin/route delete -host {$rgip}");
847
								mwexec("/sbin/route add -host {$rgip} {$gatewayip}");
848
							}
849
						}
850
					}
851
				} else {
852
					if(stristr($route_str, "{$rgip}")) {
853
						mwexec("/sbin/route delete -host {$rgip}", true);
854
					}
855
				}
856
			}
857

    
858
			fwrite($fd, $spdconf);
859
			fclose($fd);
860
		}
861

    
862
		/* needed for racoonctl admin socket */
863
		if (!is_dir("/var/db/racoon"))
864
			mkdir("/var/db/racoon/");
865
		
866
		/* mange racoon process */
867
		if (is_process_running("racoon")) {
868
			sleep("0.1");
869
			mwexec("/usr/local/sbin/racoonctl -s /var/db/racoon/racoon.sock reload-config", false);
870
			/* load SPD without flushing to be safe on config additions or changes. */
871
			mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf", false);
872
		} else {
873
			/* flush SA + SPD entries */
874
			mwexec("/usr/local/sbin/setkey -FP", false);
875
 			sleep("0.1");
876
			mwexec("/usr/local/sbin/setkey -F", false);
877
 			sleep("0.1");
878
//			exec("/sbin/sysctl net.inet.ip.ipsec_in_use=1");
879
 			/* start racoon */
880
			mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf", false);
881
 			sleep("0.1");
882
 			/* load SPD */
883
			mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf", false);
884

    
885
			/* start dnswatch, if necessary */
886
			if (count($dnswatch_list) > 0) {
887
				$interval = 60;
888
				if (!empty($ipseccfg['dns-interval']) && is_numeric($ipseccfg['dns-interval']))
889
					$interval = $ipseccfg['dns-interval'];
890

    
891
				$hostnames = "";
892
				array_unique($dnswatch_list);
893
				$hostnames = implode("\n", $dnswatch_list);
894
				file_put_contents("{$g['varetc_path']}/dnswatch-ipsec.hosts", $hostnames);
895

    
896
				killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
897
				mwexec("/usr/local/sbin/dnswatch {$g['varrun_path']}/dnswatch-ipsec.pid $interval /etc/rc.newipsecdns {$g['varetc_path']}/dnswatch-ipsec.hosts");
898
			}
899
		}
900
	
901
		vpn_ipsec_failover_configure();
902

    
903
		if ($g['booting'])
904
			echo "done\n";
905
	}
906

    
907
	return 0;
908
}
909

    
910
/* Forcefully restart IPsec
911
 * This is required for when dynamic interfaces reload
912
 * For all other occasions the normal vpn_ipsec_configure()
913
 * will gracefully reload the settings without restarting
914
 */
915
function vpn_ipsec_force_reload() {
916
	global $config;
917
	global $g;
918

    
919
	$ipseccfg = $config['ipsec'];
920

    
921
	/* kill racoon */
922
	if(is_process_running("racoon"))
923
		mwexec("/usr/bin/killall racoon", true);
924

    
925
	/* wait for process to die */
926
	sleep(4);
927

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

    
931
	/* wait for flushing to finish */
932
	sleep(1);
933

    
934
	/* if ipsec is enabled, start up again */
935
	if (isset($ipseccfg['enable'])) {
936
		log_error("Forcefully reloading IPsec racoon daemon");
937
		vpn_ipsec_configure();
938
	}
939

    
940
}
941

    
942
/* master setup for vpn (mpd) */
943
function vpn_setup() {
944
	/* start pptpd */
945
	vpn_pptpd_configure();
946

    
947
	/* start pppoe server */
948
	vpn_pppoes_configure();
949

    
950
	/* setup l2tp */
951
	vpn_l2tp_configure();
952
}
953

    
954
function vpn_pptpd_configure() {
955
	global $config, $g;
956

    
957
	$syscfg = $config['system'];
958
	$pptpdcfg = $config['pptpd'];
959

    
960
	if ($g['booting']) {
961
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
962
			return 0;
963

    
964
		echo "Configuring PPTP VPN service... ";
965
	} else {
966
		/* kill mpd */
967
		killbypid("{$g['varrun_path']}/pptp-vpn.pid");
968

    
969
		/* wait for process to die */
970
		sleep(3);
971

    
972
		if (is_process_running("mpd -b")) {
973
			killbypid("{$g['varrun_path']}/pptp-vpn.pid");
974
			log_error("Could not kill mpd within 3 seconds.   Trying again.");
975
		}
976

    
977
		/* remove mpd.conf, if it exists */
978
		unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.conf");
979
		unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.links");
980
		unlink_if_exists("{$g['varetc_path']}/pptp-vpn/mpd.secret");
981
	}
982

    
983
	/* make sure pptp-vpn directory exists */
984
	if (!file_exists("{$g['varetc_path']}/pptp-vpn"))
985
		mkdir("{$g['varetc_path']}/pptp-vpn");
986

    
987
	switch ($pptpdcfg['mode']) {
988
		case 'server' :
989
			/* write mpd.conf */
990
			$fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.conf", "w");
991
			if (!$fd) {
992
				printf("Error: cannot open mpd.conf in vpn_pptpd_configure().\n");
993
				return 1;
994
			}
995

    
996
			$mpdconf = <<<EOD
997
pptpd:
998

    
999
EOD;
1000

    
1001
			for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
1002
				$mpdconf .= "	load pt{$i}\n";
1003
			}
1004

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

    
1007
				$clientip = long2ip32(ip2long($pptpdcfg['remoteip']) + $i);
1008

    
1009
				$mpdconf .= <<<EOD
1010

    
1011
pt{$i}:
1012
	new -i pptpd{$i} pt{$i} pt{$i}
1013
	set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
1014
	load pts
1015

    
1016
EOD;
1017
			}
1018

    
1019
			$mpdconf .=<<<EOD
1020

    
1021
pts:
1022
	set iface disable on-demand
1023
	set iface enable proxy-arp
1024
	set iface enable tcpmssfix
1025
	set iface idle 1800
1026
	set iface up-script /usr/local/sbin/pptp-linkup
1027
	set iface down-script /usr/local/sbin/vpn-linkdown
1028
	set bundle enable multilink
1029
	set bundle enable crypt-reqd
1030
	set link yes acfcomp protocomp
1031
	set link no pap chap
1032
	set link enable chap-msv2
1033
	set link mtu 1460
1034
	set link keep-alive 10 60
1035
	set ipcp yes vjcomp
1036
	set bundle enable compression
1037
	set ccp yes mppc
1038
	set ccp yes mpp-e128
1039
	set ccp yes mpp-stateless
1040

    
1041
EOD;
1042

    
1043
			if (!isset ($pptpdcfg['req128'])) {
1044
				$mpdconf .=<<<EOD
1045
	set ccp yes mpp-e40
1046
	set ccp yes mpp-e56
1047

    
1048
EOD;
1049
			}
1050

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

    
1054
			if (!empty($pptpdcfg['dns1'])) {
1055
				$mpdconf .= "	set ipcp dns " . $pptpdcfg['dns1'];
1056
				if (!empty($pptpdcfg['dns2']))
1057
					$mpdconf .= " " . $pptpdcfg['dns2'];
1058
				$mpdconf .= "\n";
1059
			} elseif (isset ($config['dnsmasq']['enable'])) {
1060
				$mpdconf .= "	set ipcp dns " . get_interface_ip("lan");
1061
				if ($syscfg['dnsserver'][0])
1062
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1063
				$mpdconf .= "\n";
1064
			} elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1065
					$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1066
			}
1067

    
1068
			if (isset ($pptpdcfg['radius']['server']['enable'])) {
1069
				$authport = (isset($pptpdcfg['radius']['server']['port']) && strlen($pptpdcfg['radius']['server']['port']) > 1) ? $pptpdcfg['radius']['server']['port'] : 1812;
1070
				$acctport = $authport + 1;
1071
				$mpdconf .=<<<EOD
1072
	set radius server {$pptpdcfg['radius']['server']['ip']} "{$pptpdcfg['radius']['server']['secret']}" {$authport} {$acctport}
1073

    
1074
EOD;
1075
			if (isset ($pptpdcfg['radius']['server2']['enable'])) {
1076
				$authport = (isset($pptpdcfg['radius']['server2']['port']) && strlen($pptpdcfg['radius']['server2']['port']) > 1) ? $pptpdcfg['radius']['server2']['port'] : 1812;
1077
				$acctport = $authport + 1;
1078
				$mpdconf .=<<<EOD
1079
	set radius server {$pptpdcfg['radius']['server2']['ip']} "{$pptpdcfg['radius']['server2']['secret']}" {$authport} {$acctport}
1080

    
1081
EOD;
1082
			}
1083
			$mpdconf .=<<<EOD
1084
	set radius retries 3
1085
	set radius timeout 10
1086
	set auth enable radius-auth
1087

    
1088
EOD;
1089

    
1090
				if (isset ($pptpdcfg['radius']['accounting'])) {
1091
					$mpdconf .=<<<EOD
1092
	set auth enable radius-acct
1093
	set radius acct-update 300
1094

    
1095
EOD;
1096
				}
1097
			}
1098

    
1099
			fwrite($fd, $mpdconf);
1100
			fclose($fd);
1101

    
1102
			/* write mpd.links */
1103
			$fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.links", "w");
1104
			if (!$fd) {
1105
				printf("Error: cannot open mpd.links in vpn_pptpd_configure().\n");
1106
				return 1;
1107
			}
1108

    
1109
			$mpdlinks = "";
1110

    
1111
			for ($i = 0; $i < $pptpdcfg['n_pptp_units']; $i++) {
1112
				$mpdlinks .=<<<EOD
1113

    
1114
pt{$i}:
1115
	set link type pptp
1116
	set pptp enable incoming
1117
	set pptp disable originate
1118
	set pptp disable windowing
1119

    
1120
EOD;
1121
			}
1122

    
1123
			fwrite($fd, $mpdlinks);
1124
			fclose($fd);
1125

    
1126
			/* write mpd.secret */
1127
			$fd = fopen("{$g['varetc_path']}/pptp-vpn/mpd.secret", "w");
1128
			if (!$fd) {
1129
				printf("Error: cannot open mpd.secret in vpn_pptpd_configure().\n");
1130
				return 1;
1131
			}
1132

    
1133
			$mpdsecret = "";
1134

    
1135
			if (is_array($pptpdcfg['user'])) {
1136
				foreach ($pptpdcfg['user'] as $user)
1137
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
1138
			}
1139

    
1140
			fwrite($fd, $mpdsecret);
1141
			fclose($fd);
1142
			chmod("{$g['varetc_path']}/pptp-vpn/mpd.secret", 0600);
1143

    
1144
			/* fire up mpd */
1145
			mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/pptp-vpn -p {$g['varrun_path']}/pptp-vpn.pid -s pptp -f mpd.conf pptpd");
1146

    
1147
			break;
1148

    
1149
		case 'redir' :
1150
			break;
1151
	}
1152

    
1153
	if ($g['booting'])
1154
		echo "done\n";
1155

    
1156
	return 0;
1157
}
1158

    
1159
function vpn_pppoes_configure() {
1160
	global $config;
1161

    
1162
	if (is_array($config['pppoes']['pppoe'])) {
1163
		foreach ($config['pppoes']['pppoe'] as $pppoe)
1164
			vpn_pppoe_configure($pppoe);
1165
	}
1166
}
1167

    
1168
function vpn_pppoe_configure(&$pppoecfg) {
1169
	global $config, $g;
1170

    
1171
	$syscfg = $config['system'];
1172

    
1173
	/* create directory if it does not exist */
1174
	if (!is_dir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn"))
1175
		mkdir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn");
1176

    
1177
	if ($g['booting']) {
1178
		if (!$pppoecfg['mode'] || ($pppoecfg['mode'] == "off"))
1179
			return 0;
1180

    
1181
		echo "Configuring PPPoE VPN service... ";
1182
	} else {
1183
		/* kill mpd */
1184
		killbypid("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid");
1185

    
1186
		/* wait for process to die */
1187
		sleep(2);
1188

    
1189
	}
1190

    
1191
	switch ($pppoecfg['mode']) {
1192

    
1193
		case 'server' :
1194

    
1195
			$pppoe_interface = get_real_interface($pppoecfg['interface']);
1196

    
1197
			if ($pppoecfg['paporchap'] == "chap")
1198
				$paporchap = "set link enable chap";
1199
			else
1200
				$paporchap = "set link enable pap";
1201

    
1202
			/* write mpd.conf */
1203
			$fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.conf", "w");
1204
			if (!$fd) {
1205
				printf("Error: cannot open mpd.conf in vpn_pppoe_configure().\n");
1206
				return 1;
1207
			}
1208
			$mpdconf = "\n\n";
1209
			$mpdconf .= "pppoe:\n";
1210

    
1211
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1212
				$mpdconf .= "	load poes{$pppoecfg['pppoeid']}{$i}\n";
1213
			}
1214

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

    
1217
				$clientip = long2ip32(ip2long($pppoecfg['remoteip']) + $i);
1218

    
1219
				if (isset ($pppoecfg['radius']['radiusissueips']) && isset ($pppoecfg['radius']['server']['enable'])) {
1220
					$isssue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 0.0.0.0/0";
1221
				} else {
1222
					$isssue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 {$clientip}/32";
1223
				}
1224

    
1225
				$mpdconf .=<<<EOD
1226

    
1227
poes{$pppoecfg['pppoeid']}{$i}:
1228
	new -i poes{$pppoecfg['pppoeid']}{$i} poes{$pppoecfg['pppoeid']}{$i} poes{$pppoecfg['pppoeid']}{$i}
1229
	{$isssue_ip_type}
1230
	load pppoe_standart
1231

    
1232
EOD;
1233
			}
1234

    
1235
			$mpdconf .=<<<EOD
1236

    
1237
pppoe_standart:
1238
	set bundle no multilink
1239
	set bundle enable compression
1240
	set auth max-logins 1
1241
	set iface up-script /usr/local/sbin/pppoe-linkup
1242
        set iface down-script /usr/local/sbin/vpn-linkdown
1243
	set iface idle 0
1244
	set iface disable on-demand
1245
	set iface disable proxy-arp
1246
	set iface enable tcpmssfix
1247
	set iface mtu 1500
1248
	set link no pap chap
1249
	{$paporchap}
1250
	set link keep-alive 60 180
1251
	set ipcp yes vjcomp
1252
	set ipcp no vjcomp
1253
	set link max-redial -1
1254
	set link mtu 1492
1255
	set link mru 1492
1256
	set ccp yes mpp-e40
1257
	set ccp yes mpp-e128
1258
	set ccp yes mpp-stateless
1259
	set link latency 1
1260
	#set ipcp dns 10.10.1.3
1261
	#set bundle accept encryption
1262

    
1263
EOD;
1264

    
1265
			if (!empty($pppoecfg['dns1'])) {
1266
				$mpdconf .= "	set ipcp dns " . $pppoecfg['dns1'];
1267
				if (!empty($pppoecfg['dns2']))
1268
					$mpdconf .= " " . $pppoecfg['dns2'];
1269
				$mpdconf .= "\n";
1270
			} elseif (isset ($config['dnsmasq']['enable'])) {
1271
				$mpdconf .= "	set ipcp dns " . get_interface_ip("lan");
1272
				if ($syscfg['dnsserver'][0])
1273
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1274
				$mpdconf .= "\n";
1275
			} elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1276
					$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1277
			}
1278

    
1279
			if (isset ($pppoecfg['radius']['server']['enable'])) {
1280
				$mpdconf .=<<<EOD
1281
	set radius server {$pppoecfg['radius']['server']['ip']} "{$pppoecfg['radius']['server']['secret']}"
1282
	set radius retries 3
1283
	set radius timeout 10
1284
	set auth enable radius-auth
1285

    
1286
EOD;
1287

    
1288
				if (isset ($pppoecfg['radius']['accounting'])) {
1289
					$mpdconf .=<<<EOD
1290
	set auth enable radius-acct
1291

    
1292
EOD;
1293
				}
1294
			}
1295

    
1296
			fwrite($fd, $mpdconf);
1297
			fclose($fd);
1298

    
1299
			/* write mpd.links */
1300
			$fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.links", "w");
1301
			if (!$fd) {
1302
				printf("Error: cannot open mpd.links in vpn_pppoe_configure().\n");
1303
				return 1;
1304
			}
1305

    
1306
			$mpdlinks = "";
1307

    
1308
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1309
				$mpdlinks .=<<<EOD
1310
			
1311
poes{$pppoecfg['pppoeid']}{$i}:
1312
	set phys type pppoe
1313
        set pppoe iface {$pppoe_interface}
1314
        set pppoe service "*"
1315
        set pppoe disable originate
1316
        set pppoe enable incoming
1317

    
1318
EOD;
1319
			}
1320

    
1321
			fwrite($fd, $mpdlinks);
1322
			fclose($fd);
1323

    
1324
			if ($pppoecfg['username']) {
1325
				/* write mpd.secret */
1326
				$fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", "w");
1327
				if (!$fd) {
1328
					printf("Error: cannot open mpd.secret in vpn_pppoe_configure().\n");
1329
					return 1;
1330
				}
1331

    
1332
				$mpdsecret = "\n\n";
1333

    
1334
				if (!empty($pppoecfg['username'])) {
1335
					$item = explode(" ", $pppoecfg['username']);
1336
					foreach($item as $userdata) {
1337
						$data = explode(":", $userdata);
1338
						$mpdsecret .= "{$data[0]} \"" . base64_decode($data[1]) . "\" {$data[2]}\n";
1339
					}
1340
				}
1341

    
1342
				fwrite($fd, $mpdsecret);
1343
				fclose($fd);
1344
				chmod("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", 0600);
1345
			}
1346

    
1347
			/* fire up mpd */
1348
			mwexec("/usr/local/sbin/mpd4 -b -d {$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn -p {$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid -s pppoe pppoe");
1349

    
1350
			break;
1351
	}
1352

    
1353
	if ($g['booting'])
1354
		echo "done\n";
1355

    
1356
	return 0;
1357
}
1358

    
1359
function vpn_l2tp_configure() {
1360
	global $config, $g;
1361

    
1362
	$syscfg = $config['system'];
1363
	$l2tpcfg = $config['l2tp'];
1364

    
1365
	/* create directory if it does not exist */
1366
	if (!is_dir("{$g['varetc_path']}/l2tp-vpn"))
1367
		mkdir("{$g['varetc_path']}/l2tp-vpn");
1368

    
1369
	if ($g['booting']) {
1370
		if (!$l2tpcfg['mode'] || ($l2tpcfg['mode'] == "off"))
1371
			return 0;
1372

    
1373
		echo "Configuring l2tp VPN service... ";
1374
	} else {
1375
		/* kill mpd */
1376
		killbypid("{$g['varrun_path']}/l2tp-vpn.pid");
1377

    
1378
		/* wait for process to die */
1379
		sleep(8);
1380

    
1381
	}
1382

    
1383
	/* make sure l2tp-vpn directory exists */
1384
	if (!file_exists("{$g['varetc_path']}/l2tp-vpn"))
1385
		mkdir("{$g['varetc_path']}/l2tp-vpn");
1386

    
1387
	switch ($l2tpcfg['mode']) {
1388

    
1389
		case 'server' :
1390
			if ($l2tpcfg['paporchap'] == "chap")
1391
				$paporchap = "set link enable chap";
1392
			else
1393
				$paporchap = "set link enable pap";
1394

    
1395
			/* write mpd.conf */
1396
			$fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.conf", "w");
1397
			if (!$fd) {
1398
				printf("Error: cannot open mpd.conf in vpn_l2tp_configure().\n");
1399
				return 1;
1400
			}
1401
			$mpdconf = "\n\n";
1402
			$mpdconf .=<<<EOD
1403
l2tp:
1404

    
1405
EOD;
1406

    
1407
			for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
1408
				$mpdconf .= "	load l2tp{$i}\n";
1409
			}
1410

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

    
1413
				$clientip = long2ip32(ip2long($l2tpcfg['remoteip']) + $i);
1414

    
1415
				if (isset ($l2tpcfg['radius']['radiusissueips']) && isset ($l2tpcfg['radius']['enable'])) {
1416
					$isssue_ip_type = "set ipcp ranges {$l2tpcfg['localip']}/32 0.0.0.0/0";
1417
				} else {
1418
					$isssue_ip_type = "set ipcp ranges {$l2tpcfg['localip']}/32 {$clientip}/32";
1419
				}
1420

    
1421
				$mpdconf .=<<<EOD
1422

    
1423
l2tp{$i}:
1424
	new l2tp{$i} l2tp{$i}
1425
	{$isssue_ip_type}
1426
	load l2tp_standard
1427

    
1428
EOD;
1429
			}
1430

    
1431
			$mpdconf .=<<<EOD
1432

    
1433
l2tp_standard:
1434
        set bundle disable multilink
1435
        set bundle enable compression
1436
        set bundle yes crypt-reqd
1437
        set ipcp yes vjcomp
1438
        # set ipcp ranges 131.188.69.161/32 131.188.69.170/28
1439
        set ccp yes mppc
1440
        set iface disable on-demand
1441
        set iface enable proxy-arp
1442
	set iface up-script /usr/local/sbin/l2tp-linkup
1443
        set iface down-script /usr/local/sbin/vpn-linkdown
1444
        set link yes acfcomp protocomp
1445
        set link no pap chap
1446
        set link enable chap
1447
        set link keep-alive 10 180
1448

    
1449
EOD;
1450

    
1451
			if (!empty($l2tpcfg['dns1'])) {
1452
				$mpdconf .= "	set ipcp dns " . $l2tpcfg['dns1'];
1453
				if (!empty($l2tpcfg['dns2']))
1454
					$mpdconf .= " " . $l2tpcfg['dns2'];
1455
				$mpdconf .= "\n";
1456
			} elseif (isset ($config['dnsmasq']['enable'])) {
1457
				$mpdconf .= "	set ipcp dns " . get_interface_ip("lan");
1458
				if ($syscfg['dnsserver'][0])
1459
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1460
				$mpdconf .= "\n";
1461
			} elseif (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1462
					$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1463
			}
1464

    
1465
			if (isset ($l2tpcfg['radius']['enable'])) {
1466
				$mpdconf .=<<<EOD
1467
	set radius server {$l2tpcfg['radius']['server']} "{$l2tpcfg['radius']['secret']}"
1468
	set radius retries 3
1469
	set radius timeout 10
1470
	set auth enable radius-auth
1471

    
1472
EOD;
1473

    
1474
				if (isset ($l2tpcfg['radius']['accounting'])) {
1475
					$mpdconf .=<<<EOD
1476
	set auth enable radius-acct
1477

    
1478
EOD;
1479
				}
1480
			}
1481

    
1482
			fwrite($fd, $mpdconf);
1483
			fclose($fd);
1484

    
1485
			/* write mpd.links */
1486
			$fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.links", "w");
1487
			if (!$fd) {
1488
				printf("Error: cannot open mpd.links in vpn_l2tp_configure().\n");
1489
				return 1;
1490
			}
1491

    
1492
			$mpdlinks = "";
1493

    
1494
			for ($i = 0; $i < $l2tpcfg['n_l2tp_units']; $i++) {
1495
				$mpdlinks .=<<<EOD
1496

    
1497
l2tp{$i}:
1498
	set link type l2tp
1499
        set l2tp enable incoming
1500
        set l2tp disable originate
1501

    
1502
EOD;
1503
			if (!empty($l2tpcfg['secret']))
1504
					$mpdlinks .= "set l2tp secret {$l2tpcfg['secret']}\n";
1505
			}
1506

    
1507
			fwrite($fd, $mpdlinks);
1508
			fclose($fd);
1509

    
1510
			/* write mpd.secret */
1511
			$fd = fopen("{$g['varetc_path']}/l2tp-vpn/mpd.secret", "w");
1512
			if (!$fd) {
1513
				printf("Error: cannot open mpd.secret in vpn_l2tp_configure().\n");
1514
				return 1;
1515
			}
1516

    
1517
			$mpdsecret = "\n\n";
1518

    
1519
			if (is_array($l2tpcfg['user'])) {
1520
				foreach ($l2tpcfg['user'] as $user)
1521
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
1522
			}
1523

    
1524
			fwrite($fd, $mpdsecret);
1525
			fclose($fd);
1526
			chmod("{$g['varetc_path']}/l2tp-vpn/mpd.secret", 0600);
1527

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

    
1531
			break;
1532

    
1533
		case 'redir' :
1534
			break;
1535
	}
1536

    
1537
	if ($g['booting'])
1538
		echo "done\n";
1539

    
1540
	return 0;
1541
}
1542

    
1543
/* Walk the tunnels for hostname endpoints. If the hostnames 
1544
 * resolve to a different IP now compared to the DNS cache
1545
 * we reload the policies if the endpoint has changed */
1546
function vpn_ipsec_refresh_policies() {
1547
	global $config;
1548
	global $g;
1549

    
1550
	$ipseccfg = $config['ipsec'];
1551
	$a_phase1 = $config['ipsec']['phase1'];
1552
	$a_phase2 = $config['ipsec']['phase2'];
1553

    
1554
	if (isset($ipseccfg['disable'])) {
1555
		return true;
1556
	}
1557

    
1558
	/* Walk the Ipsec tunnel array */
1559
	if (!is_array($a_phase1) || (!count($a_phase1))) {
1560
		return;
1561
	}
1562

    
1563
	foreach ($a_phase1 as $phase1) {
1564
		if (isset($phase1['disabled'])) {
1565
			continue;
1566
		}
1567
		if (is_ipaddr($phase1['remote-gateway'])) {
1568
			continue;
1569
		}
1570
		if (!is_ipaddr($phase1['remote-gateway'])) {
1571
			$dnscache = compare_hostname_to_dnscache($phase1['remote-gateway']);
1572
			$dnscache = trim($dnscache);
1573
			/* we should have the old IP addresses in the dnscache now */
1574
			if($dnscache <> "") {
1575
				$oldphase1 = $phase1;
1576
				$oldphase1['remote-gateway'] = trim($dnscache);
1577
				/* now we need to find all tunnels for this host */
1578
				if (!is_array($a_phase2) || (!count($a_phase2))) {
1579
					continue;
1580
				}
1581
				foreach ($a_phase2 as $phase2) {
1582
					if($phase2['ikeid'] == $phase1['ikeid']) {
1583
						reload_tunnel_spd_policy ($phase1, $phase2, $oldphase1, $oldphase2);
1584
					}
1585
				}
1586
			}
1587
		}
1588
	}
1589

    
1590
	/* process all generated spd.conf files from tmp which are left behind
1591
	 * behind by either changes of dynamic tunnels or manual edits
1592
	 * scandir() is only available in PHP5 */
1593
	$tmpfiles = array();
1594
	$dh  = opendir($g['tmp_path']);
1595
	while (false !== ($filename = readdir($dh))) {
1596
		if(preg_match("/^spd.conf.reload./", $filename)) {
1597
			$tmpfiles[] = $filename;
1598
		}
1599
	}
1600
	sort($tmpfiles);
1601
	foreach($tmpfiles as $tmpfile) {
1602
		$ret = mwexec("/usr/local/sbin/setkey -f {$g['tmp_path']}/{$tmpfile} 2>&1", false);
1603
		if($ret == 0) {
1604
			unlink_if_exists("{$g['tmp_path']}/{$tmpfile}");
1605
		} else {
1606
			rename("{$g['tmp_path']}/{$tmpfile}", ("{$g['tmp_path']}/failed.{$tmpfile}"));
1607
		}
1608
	}
1609
}
1610

    
1611
/* reloads the tunnel configuration for a tunnel item
1612
 * Will remove and add SPD polices */
1613
function reload_tunnel_spd_policy($phase1, $phase2, $old_phase1, $old_phase2) {
1614
	global $config;
1615
	global $g;
1616

    
1617
	/* if we are not passed a old tunnel array we create one */
1618
	if(empty($old_phase1)) {
1619
		$old_phase1 = $phase1;
1620
	}
1621
	if(empty($old_phase2)) {
1622
		$old_phase2 = $phase2;
1623
	}
1624

    
1625
	$sad_arr = ipsec_dump_sad();
1626

    
1627
	$ep = ipsec_get_phase1_src($phase1);
1628
	$local_subnet = ipsec_idinfo_to_cidr($phase2['localid']);
1629
	$remote_subnet = ipsec_idinfo_to_cidr($phase2['remoteid']);
1630

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

    
1634
	$old_ep = ipsec_get_phase1_src($old_phase1);
1635
	$old_local_subnet = ipsec_idinfo_to_cidr($old_phase2['localid']);
1636
	$old_remote_subnet = ipsec_idinfo_to_cidr($old_phase2['remoteid']);
1637

    
1638
	/* see if this tunnel has a hostname for the remote-gateway, and if so,
1639
	 * try to resolve it now and add it to the list for dnswatch */
1640
	if (!is_ipaddr($phase1['remote-gateway'])) {
1641
		$rgip = resolve_retry($phase1['remote-gateway']);
1642
		add_hostname_to_watch($phase1['remote-gateway']);
1643
		if (!$rgip) {
1644
			log_error("Could not determine VPN endpoint for '{$phase1['descr']}'");
1645
			return false;
1646
		}
1647
	} else {
1648
		$rgip = $phase1['remote-gateway'];
1649
	}
1650
	if (!$ep) {
1651
		log_error("Could not determine VPN endpoint for '{$phase1['descr']}'");
1652
		return false;
1653
	}
1654

    
1655
	if((!is_ipaddr($old_ep)) || (! is_ipaddr($ep))) {
1656
		log_error("IPSEC: ERROR: One of the endpoints is not a IP address. Old EP '{$old_ep}' new EP '{$ep}'");
1657
	}
1658
	if((! is_ipaddr($rgip)) || (! is_ipaddr($old_gw))) {
1659
		log_error("IPSEC: ERROR: One of the remote endpoints is not a IP address. Old RG '{$old_gw}' new RG '{$rgip}'");
1660
	}
1661

    
1662
	$spdconf = "";
1663
	/* Delete old SPD policies if there are changes between the old and new */
1664
	if(($phase1 != $old_phase1) || ($phase2 != $old_phase2)) {
1665
		$spdconf .= "spddelete {$old_local_subnet} " .
1666
			"{$old_remote_subnet} any -P out ipsec " .
1667
			"{$old_phase2['protocol']}/tunnel/{$old_ep}-" .
1668
			"{$old_gw}/unique;\n";
1669
		$spdconf .= "spddelete {$old_remote_subnet} " .
1670
			"{$old_local_subnet} any -P in ipsec " .
1671
			"{$old_phase2['protocol']}/tunnel/{$old_gw}-" .
1672
			"{$old_ep}/unique;\n";
1673

    
1674
		/* zap any existing SA entries */
1675
		foreach($sad_arr as $sad) {
1676
			if(($sad['dst'] == $old_ep) && ($sad['src'] == $old_gw)) {
1677
				$spdconf .= "delete {$old_ep} {$old_gw} {$old_phase2['protocol']} 0x{$sad['spi']};\n";
1678
			}
1679
			if(($sad['src'] == $oldep) && ($sad['dst'] == $old_gw)) {
1680
				$spdconf .= "delete {$old_gw} {$old_ep} {$old_phase2['protocol']} 0x{$sad['spi']};\n";
1681
			}
1682
		}
1683
	}
1684

    
1685
	/* Create new SPD entries for the new configuration */
1686
	/* zap any existing SA entries beforehand */
1687
	foreach($sad_arr as $sad) {
1688
		if(($sad['dst'] == $ep) && ($sad['src'] == $rgip)) {
1689
			$spdconf .= "delete {$rgip} {$ep} {$phase2['protocol']} 0x{$sad['spi']};\n";
1690
		}
1691
		if(($sad['src'] == $ep) && ($sad['dst'] == $rgip)) {
1692
			$spdconf .= "delete {$ep} {$rgip} {$phase2['protocol']} 0x{$sad['spi']};\n";
1693
		}
1694
	}
1695
	/* add new SPD policies to replace them */
1696
	$spdconf .= "spdadd {$local_subnet} " .
1697
		"{$remote_subnet} any -P out ipsec " .
1698
		"{$phase2['protocol']}/tunnel/{$ep}-" .
1699
		"{$rgip}/unique;\n";
1700
	$spdconf .= "spdadd {$remote_subnet} " .
1701
		"{$local_subnet} any -P in ipsec " .
1702
		"{$phase2['protocol']}/tunnel/{$rgip}-" .
1703
		"{$ep}/unique;\n";
1704

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

    
1707
	$now = time();
1708
	$spdfile = tempnam("{$g['tmp_path']}", "spd.conf.reload.{$now}.");
1709
	/* generate temporary spd.conf */
1710
	file_put_contents($spdfile, $spdconf);
1711
	return true;
1712
}
1713

    
1714
function vpn_ipsec_configure_preferoldsa() {
1715
	global $config;
1716
	if(isset($config['ipsec']['preferoldsa']))
1717
		mwexec("/sbin/sysctl -w net.key.preferred_oldsa=-30");
1718
	else
1719
		mwexec("/sbin/sysctl net.key.preferred_oldsa=0");
1720
}
1721
?>
(45-45/54)