Project

General

Profile

Download (38.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	vpn.inc
4
	Copyright (C) 2004-2006 Scott Ullrich
5
	All rights reserved.
6

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

    
11
	Redistribution and use in source and binary forms, with or without
12
	modification, are permitted provided that the following conditions are met:
13

    
14
	1. Redistributions of source code must retain the above copyright notice,
15
	   this list of conditions and the following disclaimer.
16

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

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

    
33
/* include all configuration functions */
34
require_once("functions.inc");
35

    
36
/* master setup for vpn (mpd) */
37
function vpn_setup() {
38
	/* start pptpd */
39
	vpn_pptpd_configure();
40

    
41
	/* start pppoe server */
42
	vpn_pppoe_configure();
43
}
44

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

    
48
	$sasyncd_text = "";
49

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

    
69
	$fd = fopen("{$g['varetc_path']}/sasyncd.conf", "w");
70
	fwrite($fd, $sasyncd_text);
71
	fclose($fd);
72
	chmod("{$g['varetc_path']}/sasyncd.conf", 0600);
73

    
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
function find_last_gif_device() {
81
	 	$regs = "";
82
        $last_gif_found = -1;
83
        if (!($fp = popen("/sbin/ifconfig -l", "r"))) return -1;
84
        $ifconfig_data = fread($fp, 4096);
85
        pclose($fp);
86
        $ifconfig_array = split(" ", $ifconfig_data);
87
        foreach ($ifconfig_array as $ifconfig) {
88
                ereg("gif(.)", $ifconfig, $regs);
89
                if($regs[0]) {
90
                        if($regs[0] > $last_gif_found)
91
                                $last_gif_found = $regs[1];
92
                }
93
        }
94
        return $last_gif_found;
95
}
96

    
97
function vpn_ipsec_configure($ipchg = false) {
98
	global $config, $g, $sa, $sn;
99

    
100
	mwexec("/sbin/ifconfig enc0 create", true);
101
	mwexec("/sbin/ifconfig enc0 up", true);
102
	
103
	exec("/sbin/sysctl net.enc.out.ipsec_bpf_mask=0x00000001");
104
	exec("/sbin/sysctl net.enc.out.ipsec_filter_mask=0x00000001");
105
	exec("/sbin/sysctl net.enc.in.ipsec_bpf_mask=0x00000002");
106
	exec("/sbin/sysctl net.enc.in.ipsec_filter_mask=0x00000002");
107

    
108
	/* get the automatic /etc/ping_hosts.sh ready */
109
	unlink_if_exists("/var/db/ipsecpinghosts");
110
	touch("/var/db/ipsecpinghosts");
111

    
112
	if(isset($config['ipsec']['preferoldsa'])) {
113
		mwexec("/sbin/sysctl net.key.preferred_oldsa=0");
114
	} else {
115
		mwexec("/sbin/sysctl -w net.key.preferred_oldsa=-30");
116
	}
117

    
118
	$number_of_gifs = find_last_gif_device();
119
	for($x=0; $x<$number_of_gifs; $x++) {
120
		mwexec("/sbin/ifconfig gif" . $x . " delete");
121
	}
122

    
123
	$curwanip = get_current_wan_address();
124

    
125
	$syscfg = $config['system'];
126
	$ipseccfg = $config['ipsec'];
127
	$lancfg = $config['interfaces']['lan'];
128
	$lanip = $lancfg['ipaddr'];
129
	$lansa = gen_subnet($lancfg['ipaddr'], $lancfg['subnet']);
130
	$lansn = $lancfg['subnet'];
131

    
132
	if (!isset($ipseccfg['enable'])) {
133
		mwexec("/sbin/ifconfig enc0 down");
134
		mwexec("/sbin/ifconfig enc0 destroy");
135

    
136
		/* kill racoon */
137
		if(is_process_running("racoon"))
138
			mwexec("/usr/bin/killall racoon", true);
139
		killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
140

    
141

    
142
		/* wait for process to die */
143
		sleep(2);
144

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

    
148
		/* flush SPD and SAD */
149
		mwexec("/usr/local/sbin/setkey -FP");
150
		mwexec("/usr/local/sbin/setkey -F");
151

    
152
		return true;
153
	}
154

    
155
	if ($g['booting']) {
156
		echo "Configuring IPsec VPN... ";
157
	}
158

    
159
	if (isset($ipseccfg['enable'])) {
160

    
161
		/* fastforwarding is not compatible with ipsec tunnels */
162
		mwexec("/sbin/sysctl net.inet.ip.fastforwarding=0");
163

    
164
		if (!$curwanip) {
165
			/* IP address not configured yet, exit */
166
			if ($g['booting'])
167
				echo "done\n";
168
			return 0;
169
		}
170

    
171
		/* this loads a route table which is used to determine if a route needs to be removed. */
172
		exec("/usr/bin/netstat -rn", $route_arr, $retval);
173
		$route_str = implode("\n", $route_arr);
174

    
175
		if ((is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) ||
176
				isset($ipseccfg['mobileclients']['enable'])) {
177

    
178
			$dnswatch_list = array();
179
			$rgmap = array();
180

    
181
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
182

    
183
				/* generate spd.conf */
184
				$fd = fopen("{$g['varetc_path']}/spd.conf", "w");
185
				if (!$fd) {
186
					printf("Error: cannot open spd.conf in vpn_ipsec_configure().\n");
187
					return 1;
188
				}
189

    
190
				$spdconf = "";
191

    
192
				$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
193
				$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
194

    
195
				foreach ($ipseccfg['tunnel'] as $tunnel) {
196

    
197
					if (isset($tunnel['disabled']))
198
						continue;
199

    
200
					$ep = vpn_endpoint_determine($tunnel, $curwanip);
201
					/* see if this tunnel has a hostname for the remote-gateway, and if so,
202
					 * try to resolve it now and add it to the list for dnswatch */
203
					if (!is_ipaddr($tunnel['remote-gateway'])) {
204
						$dnswatch_list[] = $tunnel['remote-gateway'];
205
						$rgip = resolve_retry($tunnel['remote-gateway']);
206
						add_hostname_to_watch($tunnel['remote-gateway']);
207
						if (!$rgip) {
208
							log_error("Could not deterimine VPN endpoint for {$tunnel['descr']}");
209
							continue;
210
						}
211
					} else {
212
						$rgip = $tunnel['remote-gateway'];
213
					}
214
					$rgmap[$tunnel['remote-gateway']] = $rgip;
215
					if (!$ep) {
216
						log_error("Could not deterimine VPN endpoint for {$tunnel['descr']}");
217
						continue;	
218
					}
219

    
220

    
221
					vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
222

    
223
					if(is_domain($tunnel['remote-gateway'])) {
224
						$tmp = gethostbyname($tunnel['remote-gateway']);
225
						if($tmp) {
226
							$tunnel['remote-gateway'] = $tmp;
227
						}
228
					}
229

    
230
					/* add entry to host pinger */
231
					if ($tunnel['pinghost']) {
232
						$pfd = fopen("/var/db/ipsecpinghosts", "a");
233
						$iflist = array("lan" => "lan", "wan" => "wan");
234
				          	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
235
							$iflist['opt' . $i] = "opt{$i}";
236

    
237
						foreach ($iflist as $ifent => $ifname) {
238
							$interface_ip = find_interface_ip($config['interfaces'][$ifname]['if']);
239
							if (ip_in_subnet($interface_ip, $sa . "/" . $sn))
240
							$srcip = find_interface_ip($config['interfaces'][$ifname]['if']);
241
						}
242
						$dstip = $tunnel['pinghost'];
243
						fwrite($pfd, "$srcip|$dstip|3\n");
244
						fclose($pfd);
245
					}
246
					if(isset($tunnel['creategif'])) {
247
						$number_of_gifs = find_last_gif_device();
248
						$number_of_gifs++;
249
						$curwanip = get_current_wan_address();
250

    
251
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " tunnel" . $curwanip . " " . $tunnel['remote-gateway']);
252
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " {$lansa}/{$lansn} {$lanip}/32");
253
					}
254

    
255
					$spdconf .= "spdadd {$sa}/{$sn} " .
256
						"{$tunnel['remote-subnet']} any -P out ipsec " .
257
						"{$tunnel['p2']['protocol']}/tunnel/{$ep}-" .
258
						"{$tunnel['remote-gateway']}/unique;\n";
259

    
260
					$spdconf .= "spdadd {$tunnel['remote-subnet']} " .
261
						"{$sa}/{$sn} any -P in ipsec " .
262
						"{$tunnel['p2']['protocol']}/tunnel/{$tunnel['remote-gateway']}-" .
263
						"{$ep}/unique;\n";
264
				
265
					/* static route needed? */
266
					if(preg_match("/^carp/i", $tunnel['interface'])) {
267
						$parentinterface = link_carp_interface_to_parent($tunnel['interface']);
268
					} else {
269
						$parentinterface = $tunnel['interface'];
270
					}
271
					if($parentinterface <> "wan") {
272
						/* add endpoint routes to correct gateway on interface */
273
						if(interface_has_gateway($parentinterface)) {
274
							$gatewayip = get_interface_gateway("$parentinterface");
275
							$interfaceip = $config['interfaces'][$parentinterface]['ipaddr'];
276
							$subnet_bits = $config['interfaces'][$parentinterface]['subnet'];
277
							$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
278
							/* if the remote gateway is in the local subnet, then don't add a route */
279
							if(! ip_in_subnet($tunnel['remote-gateway'], "{$subnet_ip}/{$subnet_bits}")) {
280
								if(is_ipaddr($gatewayip)) {
281
									if($g['debug']) {
282
										log_error("IPSEC interface is not WAN but {$parentinterface}, adding static route for VPN endpoint {$tunnel['remote-gateway']} via {$gatewayip}");
283
									}
284
									mwexec("/sbin/route delete -host {$tunnel['remote-gateway']}");
285
                                                                        mwexec("/sbin/route add -host {$tunnel['remote-gateway']} {$gatewayip}");
286
								}
287
							}
288
						}
289
					} else {
290
						if(stristr($route_str, "{$tunnel['remote-gateway']}")) {
291
							mwexec("/sbin/route delete -host {$tunnel['remote-gateway']}");
292
						}
293
					}
294
				}
295

    
296
				fwrite($fd, $spdconf);
297
				fclose($fd);
298
			}
299

    
300
			/* generate racoon.conf */
301
			$fd = fopen("{$g['varetc_path']}/racoon.conf", "w");
302
			if (!$fd) {
303
				printf("Error: cannot open racoon.conf in vpn_ipsec_configure().\n");
304
				return 1;
305
			}
306

    
307
			$racoonconf = "# This file is automatically generated. Do not edit\n";
308
			$racoonconf .= "listen {\n";
309
			$racoonconf .= "	adminsock \"/var/db/racoon/racoon.sock\" \"root\" \"wheel\" 0660;\n";
310
			$racoonconf .= "}\n";
311

    
312
			$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
313
			$racoonconf .= "path certificate  \"{$g['varetc_path']}\";\n\n";
314

    
315
			/* generate CA certificates files */
316
			$cacertnum = 0;
317
			if (is_array($ipseccfg['cacert']) && count($ipseccfg['cacert']))
318
				foreach ($ipseccfg['cacert'] as $cacert) {
319
					++$cacertnum;
320
					if (isset($cacert['cert'])) {
321
						$cert = base64_decode($cacert['cert']);
322
						$x509cert = openssl_x509_parse(openssl_x509_read($cert));
323
						if(is_array($x509cert) && isset($x509cert['hash'])) {
324
							$fd1 = fopen("{$g['varetc_path']}/{$x509cert['hash']}.0", "w");
325
							if (!$fd1) {
326
								printf("Error: cannot open {$x509cert['hash']}.0 in vpn.\n");
327
								return 1;
328
							}
329
							chmod("{$g['varetc_path']}/{$x509cert['hash']}.0", 0600);
330
							fwrite($fd1, $cert);
331
							fclose($fd1);
332
						}
333
					}
334
				}
335

    
336
			$tunnelnumber = 0;
337
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel']))
338
				foreach ($ipseccfg['tunnel'] as $tunnel) {
339

    
340
				++$tunnelnumber;
341

    
342
				if (isset($tunnel['disabled']))
343
					continue;
344

    
345
				$rgip = $rgmap[$tunnel['remote-gateway']];
346
				if (!$rgip)
347
					continue;
348

    
349
				$ep = vpn_endpoint_determine($tunnel, $curwanip);
350
				if (!$ep)
351
					continue;
352

    
353
				vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
354

    
355
				if (isset($tunnel['p1']['myident']['myaddress'])) {
356
					$myidentt = "address";
357
					$myident = $ep;
358
				} else if (isset($tunnel['p1']['myident']['address'])) {
359
					$myidentt = "address";
360
					$myident = $tunnel['p1']['myident']['address'];
361
				} else if (isset($tunnel['p1']['myident']['fqdn'])) {
362
					$myidentt = "fqdn";
363
					$myident = $tunnel['p1']['myident']['fqdn'];
364
				} else if (isset($tunnel['p1']['myident']['ufqdn'])) {
365
					$myidentt = "user_fqdn";
366
					$myident = $tunnel['p1']['myident']['ufqdn'];
367
 				} else if (isset($tunnel['p1']['myident']['dyn_dns'])) {
368
					$myidentt = "dyn_dns";
369
					$myident = gethostbyname($tunnel['p1']['myident']['dyn_dns']);
370
 				}
371

    
372
				if (!($myidentt == "asn1dn" && $myident == "")) {
373
					$myident = " \"".$myident."\"";
374
				}
375
				
376
				$nattline = '';
377
				if (isset($tunnel['natt'])) {
378
					//$nattline = "nat_traversal on;";
379
				}
380

    
381
				$dpdline = '';
382
				if (is_numeric($tunnel['dpddelay'])) {
383
					$dpdline = "dpd_delay {$tunnel['dpddelay']};";
384
				}
385

    
386
				if (isset($tunnel['p1']['authentication_method'])) {
387
					$authmethod = $tunnel['p1']['authentication_method'];
388
				} else {$authmethod = 'pre_shared_key';}
389

    
390
				$certline = '';
391

    
392
				if ($authmethod == 'rsasig') {
393
					if ($tunnel['p1']['cert'] && $tunnel['p1']['private-key']) {
394
						$cert = base64_decode($tunnel['p1']['cert']);
395
						$private_key = base64_decode($tunnel['p1']['private-key']);
396
					} else {
397
						/* null certificate/key */
398
						$cert = '';
399
						$private_key = '';
400
					}
401

    
402
					if ($tunnel['p1']['peercert'])
403
						$peercert = base64_decode($tunnel['p1']['peercert']);
404
					else
405
						$peercert = '';
406

    
407
					$fd1 = fopen("{$g['varetc_path']}/server{$tunnelnumber}-signed.pem", "w");
408
					if (!$fd1) {
409
						printf("Error: cannot open server{$tunnelnumber}-signed.pem in vpn.\n");
410
						return 1;
411
					}
412
					chmod("{$g['varetc_path']}/server{$tunnelnumber}-signed.pem", 0600);
413
					fwrite($fd1, $cert);
414
					fclose($fd1);
415

    
416
					$fd1 = fopen("{$g['varetc_path']}/server{$tunnelnumber}-key.pem", "w");
417
					if (!$fd1) {
418
						printf("Error: cannot open server{$tunnelnumber}-key.pem in vpn.\n");
419
						return 1;
420
					}
421
					chmod("{$g['varetc_path']}/server{$tunnelnumber}-key.pem", 0600);
422
					fwrite($fd1, $private_key);
423
					fclose($fd1);
424

    
425
					$certline = "certificate_type x509 \"server{$tunnelnumber}-signed.pem\" \"server{$tunnelnumber}-key.pem\";";
426

    
427
					if ($peercert!=''){
428
						$fd1 = fopen("{$g['varetc_path']}/peer{$tunnelnumber}-signed.pem", "w");
429
						if (!$fd1) {
430
							printf("Error: cannot open server{$tunnelnumber}-signed.pem in vpn.\n");
431
							return 1;
432
						}
433
						chmod("{$g['varetc_path']}/peer{$tunnelnumber}-signed.pem", 0600);
434
						fwrite($fd1, $peercert);
435
						fclose($fd1);
436
						$certline .= <<<EOD
437

    
438
	peers_certfile "peer{$tunnelnumber}-signed.pem";
439
EOD;
440
					}
441
				}
442
				$racoonconf .= <<<EOD
443
remote {$rgmap[$tunnel['remote-gateway']]} \{
444
	exchange_mode {$tunnel['p1']['mode']};
445
	my_identifier {$myidentt}{$myident};
446
	{$nattline}
447
	{$certline}
448
	peers_identifier address {$rgmap[$tunnel['remote-gateway']]};
449
	initial_contact on;
450
	{$dpdline}
451
	ike_frag on;
452
	support_proxy on;
453
	proposal_check obey;
454

    
455
	proposal \{
456
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
457
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
458
		authentication_method {$authmethod};
459
		dh_group {$tunnel['p1']['dhgroup']};
460

    
461
EOD;
462
				if ($tunnel['p1']['lifetime'])
463
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
464

    
465
				$racoonconf .= "	}\n";
466

    
467
				if ($tunnel['p1']['lifetime'])
468
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
469

    
470
				$racoonconf .= "}\n\n";
471

    
472
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
473
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
474

    
475
				$racoonconf .= <<<EOD
476
sainfo address {$sa}/{$sn} any address {$tunnel['remote-subnet']} any \{
477
	encryption_algorithm {$p2ealgos};
478
	authentication_algorithm {$p2halgos};
479
	compression_algorithm deflate;
480

    
481
EOD;
482

    
483
				if ($tunnel['p2']['pfsgroup'])
484
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
485

    
486
				if ($tunnel['p2']['lifetime'])
487
					$racoonconf .= "	lifetime time {$tunnel['p2']['lifetime']} secs;\n";
488

    
489
				$racoonconf .= "}\n\n";
490
			}
491

    
492
			/* mobile clients? */
493
			if (isset($ipseccfg['mobileclients']['enable'])) {
494

    
495
				$tunnel = $ipseccfg['mobileclients'];
496

    
497
				if (isset($tunnel['p1']['myident']['myaddress'])) {
498
					$myidentt = "address ";
499
					$myident = $curwanip;
500
				} else if (isset($tunnel['p1']['myident']['address'])) {
501
					$myidentt = "address ";
502
					$myident = $tunnel['p1']['myident']['address'];
503
				} else if (isset($tunnel['p1']['myident']['fqdn'])) {
504
					$myidentt = "fqdn ";
505
					$myident = $tunnel['p1']['myident']['fqdn'];
506
				} else if (isset($tunnel['p1']['myident']['ufqdn'])) {
507
					$myidentt = "user_fqdn ";
508
					$myident = $tunnel['p1']['myident']['ufqdn'];
509
 				}
510
				
511
				$nattline = '';
512
				if (isset($tunnel['natt'])) {
513
					//$nattline = "nat_traversal on;";
514
				}
515

    
516
				$dpdline = '';
517
				if (is_numeric($tunnel['dpddelay'])) {
518
					$dpdline = "dpd_delay {$tunnel['dpddelay']};";
519
				}
520

    
521
				if (isset($tunnel['p1']['authentication_method'])) {
522
					$authmethod = $tunnel['p1']['authentication_method'];
523
				} else {$authmethod = 'pre_shared_key';}
524

    
525
				$certline = '';
526
				if ($authmethod == 'rsasig') {
527
					if ($tunnel['p1']['cert'] && $tunnel['p1']['private-key']) {
528
						$cert = base64_decode($tunnel['p1']['cert']);
529
						$private_key = base64_decode($tunnel['p1']['private-key']);
530
					} else {
531
						/* null certificate/key */
532
						$cert = '';
533
						$private_key = '';
534
					}
535

    
536
					if ($tunnel['p1']['peercert'])
537
						$peercert = base64_decode($tunnel['p1']['peercert']);
538
					else
539
						$peercert = '';
540

    
541
					$fd1 = fopen("{$g['varetc_path']}/server-mobile{$tunnelnumber}-signed.pem", "w");
542
					if (!$fd1) {
543
						printf("Error: cannot open server-mobile{$tunnelnumber}-signed.pem in vpn.\n");
544
						return 1;
545
					}
546
					chmod("{$g['varetc_path']}/server-mobile{$tunnelnumber}-signed.pem", 0600);
547
					fwrite($fd1, $cert);
548
					fclose($fd1);
549

    
550
					$fd1 = fopen("{$g['varetc_path']}/server-mobile{$tunnelnumber}-key.pem", "w");
551
					if (!$fd1) {
552
						printf("Error: cannot open server-mobile{$tunnelnumber}-key.pem in vpn.\n");
553
						return 1;
554
					}
555
					chmod("{$g['varetc_path']}/server-mobile{$tunnelnumber}-key.pem", 0600);
556
					fwrite($fd1, $private_key);
557
					fclose($fd1);
558

    
559
					$certline = "certificate_type x509 \"server-mobile{$tunnelnumber}-signed.pem\" \"server-mobile{$tunnelnumber}-key.pem\";";
560
				}
561
				$racoonconf .= <<<EOD
562
remote anonymous \{
563
	exchange_mode {$tunnel['p1']['mode']};
564
	my_identifier {$myidentt}"{$myident}";	
565
	{$nattline}
566
	{$certline}
567
	initial_contact on;
568
	{$dpdline}
569
	ike_frag on;
570
	passive on;
571
	generate_policy on;
572
	support_proxy on;
573
	proposal_check obey;
574

    
575
	proposal \{
576
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
577
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
578
		authentication_method {$authmethod};
579
		dh_group {$tunnel['p1']['dhgroup']};
580

    
581
EOD;
582
				if ($tunnel['p1']['lifetime'])
583
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
584

    
585
				$racoonconf .= "	}\n";
586

    
587
				if ($tunnel['p1']['lifetime'])
588
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
589

    
590
				$racoonconf .= "}\n\n";
591

    
592
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
593
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
594

    
595
				$racoonconf .= <<<EOD
596
sainfo anonymous \{
597
	encryption_algorithm {$p2ealgos};
598
	authentication_algorithm {$p2halgos};
599
	compression_algorithm deflate;
600

    
601
EOD;
602

    
603
				if ($tunnel['p2']['pfsgroup'])
604
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
605

    
606
				if ($tunnel['p2']['lifetime'])
607
					$racoonconf .= "	lifetime time {$tunnel['p2']['lifetime']} secs;\n";
608

    
609
				$racoonconf .= "}\n\n";
610
			}
611

    
612
			fwrite($fd, $racoonconf);
613
			fclose($fd);
614

    
615
			/* generate psk.txt */
616
			$fd = fopen("{$g['varetc_path']}/psk.txt", "w");
617
			if (!$fd) {
618
				printf("Error: cannot open psk.txt in vpn_ipsec_configure().\n");
619
				return 1;
620
			}
621

    
622
			$pskconf = "";
623

    
624
			if (is_array($ipseccfg['tunnel'])) {
625
				foreach ($ipseccfg['tunnel'] as $tunnel) {
626
					if (isset($tunnel['disabled']))
627
						continue;
628

    
629
					$rgip = $rgmap[$tunnel['remote-gateway']];
630
					if (!$rgip)
631
						continue;
632

    
633
					$pskconf .= "{$rgip}     {$tunnel['p1']['pre-shared-key']}\n";
634
				}
635
			}
636

    
637
			/* add PSKs for mobile clients */
638
			if (is_array($ipseccfg['mobilekey'])) {
639
				foreach ($ipseccfg['mobilekey'] as $key) {
640
					$pskconf .= "{$key['ident']}	{$key['pre-shared-key']}\n";
641
				}
642
			}
643

    
644
			fwrite($fd, $pskconf);
645
			fclose($fd);
646
			chmod("{$g['varetc_path']}/psk.txt", 0600);
647

    
648
			exec("/bin/mkdir -p /var/db/racoon");
649

    
650
			if(is_process_running("racoon")) {
651
				log_error("IPSEC: Send a reload signal to the IPsec process");
652
				sleep("0.1");
653
				mwexec("/usr/local/sbin/racoonctl -s /var/db/racoon/racoon.sock reload-config", false);
654
				// mwexec("/usr/bin/killall -HUP racoon", false);
655
			} else {
656
				/* flush SA + SPD entries */
657
				mwexec("/usr/local/sbin/setkey -FP", false);
658
				sleep("0.1");
659
				mwexec("/usr/local/sbin/setkey -F", false);
660
				sleep("0.1");
661
				/* start racoon */
662
				mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf", false);
663
				sleep("0.1");
664
				/* load SPD */
665
				mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf", false);
666
				/* We are already online, reload */
667
				sleep("0.1");
668
				mwexec("/usr/local/sbin/racoonctl -s /var/db/racoon/racoon.sock reload-config", false);
669
			}
670

    
671
			/* start dnswatch, if necessary */
672
			if (count($dnswatch_list) > 0) {
673
				$interval = 60;
674
				if ($ipseccfg['dns-interval'])
675
					$interval = $ipseccfg['dns-interval'];
676

    
677
				$hostnames = "";
678
				array_unique($dnswatch_list);
679
				$hostnames = implode("\n", $dnswatch_list);
680
				$hostnames .= "\n";
681
				file_put_contents("{$g['varetc_path']}/dnswatch-ipsec.hosts", $hostnames);
682
				killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
683
				mwexec("/usr/local/sbin/dnswatch {$g['varrun_path']}/dnswatch-ipsec.pid $interval /etc/rc.newipsecdns {$g['varetc_path']}/dnswatch-ipsec.hosts", false);
684
			}
685

    
686

    
687
		}
688
	}
689

    
690
	vpn_ipsec_failover_configure();
691

    
692
	if (!$g['booting']) {
693
		/* reload the filter */
694
		touch("{$g["tmp_path"]}/filter_dirty");
695
	}
696

    
697
	if ($g['booting'])
698
		echo "done\n";
699

    
700
	return 0;
701
}
702

    
703
function vpn_pptpd_configure() {
704
	global $config, $g;
705

    
706
	$syscfg = $config['system'];
707
	$pptpdcfg = $config['pptpd'];
708

    
709
	if ($g['booting']) {
710
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
711
			return 0;
712

    
713
		echo "Configuring PPTP VPN service... ";
714
	} else {
715
		/* kill mpd */
716
		killbypid("{$g['varrun_path']}/mpd-vpn.pid");
717

    
718
		/* wait for process to die */
719
		sleep(3);
720

    
721
		if(is_process_running("mpd -b")) {
722
			killbypid("{$g['varrun_path']}/mpd-vpn.pid");
723
			log_error("Could not kill mpd within 3 seconds.   Trying again.");
724
		}
725

    
726
		/* remove mpd.conf, if it exists */
727
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.conf");
728
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.links");
729
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.secret");
730
	}
731

    
732
	/* make sure mpd-vpn directory exists */
733
	if (!file_exists("{$g['varetc_path']}/mpd-vpn"))
734
		mkdir("{$g['varetc_path']}/mpd-vpn");
735

    
736
	switch ($pptpdcfg['mode']) {
737

    
738
		case 'server':
739

    
740
			/* write mpd.conf */
741
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.conf", "w");
742
			if (!$fd) {
743
				printf("Error: cannot open mpd.conf in vpn_pptpd_configure().\n");
744
				return 1;
745
			}
746

    
747
			$mpdconf = <<<EOD
748
pptpd:
749

    
750
EOD;
751

    
752
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
753
				$mpdconf .= "	load pt{$i}\n";
754
			}
755

    
756
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
757

    
758
				$clientip = long2ip(ip2long($pptpdcfg['remoteip']) + $i);
759
				$ngif = "ng" . ($i+1);
760

    
761
				$mpdconf .= <<<EOD
762

    
763
pt{$i}:
764
	new -i {$ngif} pt{$i} pt{$i}
765
	set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
766
	load pts
767

    
768
EOD;
769
			}
770

    
771
			$mpdconf .= <<<EOD
772

    
773
pts:
774
	set iface disable on-demand
775
	set iface enable proxy-arp
776
	set iface enable tcpmssfix
777
	set iface idle 1800
778
	set iface up-script /usr/local/sbin/vpn-linkup
779
	set iface down-script /usr/local/sbin/vpn-linkdown
780
	set bundle enable multilink
781
	set bundle enable crypt-reqd
782
	set link yes acfcomp protocomp
783
	set link no pap chap
784
	set link enable chap-msv2
785
	set link mtu 1460
786
	set link keep-alive 10 60
787
	set ipcp yes vjcomp
788
	set bundle enable compression
789
	set ccp yes mppc
790
	set ccp yes mpp-e128
791
	set ccp yes mpp-stateless
792

    
793
EOD;
794

    
795
			if (!isset($pptpdcfg['req128'])) {
796
				$mpdconf .= <<<EOD
797
	set ccp yes mpp-e40
798
	set ccp yes mpp-e56
799

    
800
EOD;
801
			}
802
			if  (isset($pptpdcfg["wins"]))
803
				$mpdconf  .=  "	set ipcp nbns {$pptpdcfg['wins']}\n";
804
			if (is_array($pptpdcfg['dnsserver']) && ($pptpdcfg['dnsserver'][0])) {
805
				$mpdconf .= "	set ipcp dns " . join(" ", $pptpdcfg['dnsserver']) . "\n";
806
			} else if (isset($config['dnsmasq']['enable'])) {
807
				$mpdconf .= "	set ipcp dns " . $config['interfaces']['lan']['ipaddr'];
808
				if ($syscfg['dnsserver'][0])
809
					$mpdconf .= " " . $syscfg['dnsserver'][0];
810
				$mpdconf .= "\n";
811
			} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
812
				$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
813
			}
814

    
815
			if (isset($pptpdcfg['radius']['enable'])) {
816
				$mpdconf .= <<<EOD
817
	set radius server {$pptpdcfg['radius']['server']} "{$pptpdcfg['radius']['secret']}"
818
	set radius retries 3
819
	set radius timeout 10
820
	set bundle enable radius-auth
821
	set bundle disable radius-fallback
822

    
823
EOD;
824

    
825
				if (isset($pptpdcfg['radius']['accounting'])) {
826
					$mpdconf .= <<<EOD
827
	set bundle enable radius-acct
828

    
829
EOD;
830
				}
831
			}
832

    
833
			fwrite($fd, $mpdconf);
834
			fclose($fd);
835

    
836
			/* write mpd.links */
837
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.links", "w");
838
			if (!$fd) {
839
				printf("Error: cannot open mpd.links in vpn_pptpd_configure().\n");
840
				return 1;
841
			}
842

    
843
			$mpdlinks = "";
844

    
845
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
846
				$mpdlinks .= <<<EOD
847

    
848
pt{$i}:
849
	set link type pptp
850
	set pptp enable incoming
851
	set pptp disable originate
852
	set pptp disable windowing
853
	set pptp self 127.0.0.1
854

    
855
EOD;
856
			}
857

    
858
			fwrite($fd, $mpdlinks);
859
			fclose($fd);
860

    
861
			/* write mpd.secret */
862
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.secret", "w");
863
			if (!$fd) {
864
				printf("Error: cannot open mpd.secret in vpn_pptpd_configure().\n");
865
				return 1;
866
			}
867

    
868
			$mpdsecret = "";
869

    
870
			if (is_array($pptpdcfg['user'])) {
871
				foreach ($pptpdcfg['user'] as $user)
872
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
873
			}
874

    
875
			fwrite($fd, $mpdsecret);
876
			fclose($fd);
877
			chmod("{$g['varetc_path']}/mpd-vpn/mpd.secret", 0600);
878

    
879
			/* fire up mpd */
880
			mwexec("/usr/local/sbin/mpd -b -d {$g['varetc_path']}/mpd-vpn -p {$g['varrun_path']}/mpd-vpn.pid pptpd");
881

    
882
			break;
883

    
884
		case 'redir':
885
			break;
886
	}
887

    
888
	if (!$g['booting']) {
889
		/* reload the filter */
890
		filter_configure();
891
	}
892

    
893
	if ($g['booting'])
894
		echo "done\n";
895

    
896
	return 0;
897
}
898

    
899
function vpn_localnet_determine($adr, &$sa, &$sn) {
900
	global $config, $g;
901

    
902
	if (isset($adr)) {
903
		if ($adr['network']) {
904
			switch ($adr['network']) {
905
				case 'lan':
906
					$sn = $config['interfaces']['lan']['subnet'];
907
					$sa = gen_subnet($config['interfaces']['lan']['ipaddr'], $sn);
908
					break;
909
			}
910
		} else if ($adr['address']) {
911
			list($sa,$sn) = explode("/", $adr['address']);
912
			if (is_null($sn))
913
				$sn = 32;
914
		}
915
	} else {
916
		$sn = $config['interfaces']['lan']['subnet'];
917
		$sa = gen_subnet($config['interfaces']['lan']['ipaddr'], $sn);
918
	}
919
}
920

    
921
function vpn_endpoint_determine($tunnel, $curwanip) {
922
	global $g, $config;
923

    
924
	if(!$tunnel['interface']) {
925
		return null;
926
	}
927
	if(is_ipaddr($curwanip)) {
928
		if(preg_match("/^carp/i", $tunnel['interface'])) {
929
			$iface = $tunnel['interface'];
930
		} else {
931
			if($config['interfaces'][$tunnel['interface']]['ipaddr'] == "pppoe" OR 
932
				$config['interfaces'][$tunnel['interface']]['ipaddr'] == "pptp") {
933
				$iface = "ng0";
934
			} else {
935
				$iface = $config['interfaces'][$tunnel['interface']]['if'];
936
			}
937
		}
938
		$oc = $config['interfaces'][$tunnel['interface']];
939
		/* carp ips, etc */
940
		$ip = find_interface_ip($iface);
941
		if($ip)
942
			return $ip;
943

    
944
		if (isset($oc['enable']) && $oc['if']) {
945
			return $oc['ipaddr'];
946
		}
947
	}
948
	return null;
949
}
950

    
951
function vpn_pppoe_configure() {
952
	global $config, $g;
953

    
954
	$syscfg = $config['system'];
955
	$pppoecfg = $config['pppoe'];
956

    
957
	/* create directory if it does not exist */
958
	if(!is_dir("{$g['varetc_path']}/mpd-vpn"))
959
		mkdir("{$g['varetc_path']}/mpd-vpn");
960

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

    
965
		echo "Configuring PPPoE VPN service... ";
966
	}
967

    
968
	/* make sure mpd-vpn directory exists */
969
	if (!file_exists("{$g['varetc_path']}/mpd-vpn"))
970
		mkdir("{$g['varetc_path']}/mpd-vpn");
971

    
972
	switch ($pppoecfg['mode']) {
973

    
974
		case 'server':
975

    
976
			$pppoe_interface = filter_translate_type_to_real_interface($pppoecfg['interface']);
977

    
978
			/* write mpd.conf */
979
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.conf", "a");
980
			if (!$fd) {
981
				printf("Error: cannot open mpd.conf in vpn_pppoe_configure().\n");
982
				return 1;
983
			}
984
			$mpdconf = "\n\n";
985
			$mpdconf .= <<<EOD
986
pppoe:
987

    
988
EOD;
989

    
990
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
991
				$mpdconf .= "	load pppoe{$i}\n";
992
			}
993

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

    
996
				$clientip = long2ip(ip2long($pppoecfg['remoteip']) + $i);
997
				$ngif = "ng" . ($i+1);
998

    
999
				if(isset($pppoecfg['radius']['radiusissueips']) && isset($pppoecfg['radius']['enable'])) {
1000
					$isssue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 0.0.0.0/0";
1001
					$isssue_ip_type .="\n\tset ipcp yes radius-ip";
1002
				} else {
1003
					$isssue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 {$clientip}/32";
1004
				}
1005

    
1006
				$mpdconf .= <<<EOD
1007

    
1008
pppoe{$i}:
1009
	new -i {$ngif} pppoe{$i} pppoe{$i}
1010
	{$isssue_ip_type}
1011
	load pppoe_standart
1012

    
1013
EOD;
1014
			}
1015

    
1016
			$mpdconf .= <<<EOD
1017

    
1018
pppoe_standart:
1019
	set link type pppoe
1020
	set pppoe iface {$pppoe_interface}
1021
	set pppoe service "*"
1022
	set pppoe disable originate
1023
	set pppoe enable incoming
1024
	set bundle no multilink
1025
	set bundle enable compression
1026
	set bundle max-logins 1
1027
	set iface idle 0
1028
	set iface disable on-demand
1029
	set iface disable proxy-arp
1030
	set iface enable tcpmssfix
1031
	set iface mtu 1500
1032
	set link no pap chap
1033
	set link enable chap
1034
	set link keep-alive 60 180
1035
	set ipcp yes vjcomp
1036
	set ipcp no vjcomp
1037
	set link max-redial -1
1038
	set link mtu 1492
1039
	set link mru 1492
1040
	set ccp yes mpp-e40
1041
	set ccp yes mpp-e128
1042
	set ccp yes mpp-stateless
1043
	set link latency 1
1044
	#set ipcp dns 10.10.1.3
1045
	#set bundle accept encryption
1046

    
1047
EOD;
1048

    
1049
			if (isset($config['dnsmasq']['enable'])) {
1050
				$mpdconf .= "	set ipcp dns " . $config['interfaces']['lan']['ipaddr'];
1051
				if ($syscfg['dnsserver'][0])
1052
					$mpdconf .= " " . $syscfg['dnsserver'][0];
1053
				$mpdconf .= "\n";
1054
			} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1055
				$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
1056
			}
1057

    
1058
			if (isset($pppoecfg['radius']['enable'])) {
1059
				$mpdconf .= <<<EOD
1060
	set radius server {$pppoecfg['radius']['server']} "{$pppoecfg['radius']['secret']}"
1061
	set radius retries 3
1062
	set radius timeout 10
1063
	set bundle enable radius-auth
1064
	set bundle disable radius-fallback
1065

    
1066
EOD;
1067

    
1068
				if (isset($pppoecfg['radius']['accounting'])) {
1069
					$mpdconf .= <<<EOD
1070
	set bundle enable radius-acct
1071
	set radius acct-update 300
1072
EOD;
1073
				}
1074
			}
1075

    
1076
			fwrite($fd, $mpdconf);
1077
			fclose($fd);
1078

    
1079
			/* write mpd.links */
1080
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.links", "a");
1081
			if (!$fd) {
1082
				printf("Error: cannot open mpd.links in vpn_pppoe_configure().\n");
1083
				return 1;
1084
			}
1085

    
1086
			$mpdlinks = "";
1087

    
1088
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1089
				$mpdlinks .= <<<EOD
1090

    
1091
pppoe:
1092
	set link type pppoe
1093
	set pppoe iface {$pppoe_interface}
1094

    
1095
EOD;
1096
			}
1097

    
1098
			fwrite($fd, $mpdlinks);
1099
			fclose($fd);
1100

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

    
1108
			$mpdsecret = "\n\n";
1109

    
1110
			if (is_array($pppoecfg['user'])) {
1111
				foreach ($pppoecfg['user'] as $user)
1112
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
1113
			}
1114

    
1115
			fwrite($fd, $mpdsecret);
1116
			fclose($fd);
1117
			chmod("{$g['varetc_path']}/mpd-vpn/mpd.secret", 0600);
1118

    
1119
			/* fire up mpd */
1120
			mwexec("/usr/local/sbin/mpd -b -d {$g['varetc_path']}/mpd-vpn -p {$g['varrun_path']}/mpd-vpn.pid pppoe");
1121

    
1122
			break;
1123

    
1124
		case 'redir':
1125
			break;
1126
	}
1127

    
1128
	touch("{$g["tmp_path"]}/filter_dirty");
1129

    
1130
	if ($g['booting'])
1131
		echo "done\n";
1132

    
1133
	return 0;
1134
}
1135

    
1136
/* Forcefully restart IPSEC
1137
 * This is required for when dynamic interfaces reload
1138
 * For all other occasions the normal vpn_ipsec_configure()
1139
 * will gracefully reload the settings without restarting
1140
 */
1141
function vpn_ipsec_force_reload() {
1142
	global $config;
1143
	global $g;
1144

    
1145
	$ipseccfg = $config['ipsec'];
1146

    
1147
	/* kill racoon */
1148
	mwexec("/usr/bin/killall racoon", true);
1149

    
1150
	/* wait for process to die */
1151
	sleep(4);
1152

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

    
1156
	/* wait for flushing to finish */
1157
	sleep(1);
1158

    
1159
	/* if ipsec is enabled, start up again */
1160
	if (isset($ipseccfg['enable'])) {
1161
		log_error("Forcefully reloading IPSEC racoon daemon");
1162
		vpn_ipsec_configure();
1163
	}
1164

    
1165
}
1166

    
1167
/* Walk the tunnels for hostname endpoints. If the hostnames 
1168
 * resolve to a different IP now compared to the DNS cache
1169
 * we reload the policies if the endpoint has changed */
1170
function vpn_ipsec_refresh_policies() {
1171
	global $config;
1172
	global $g;
1173

    
1174
	$ipseccfg = $config['ipsec'];
1175

    
1176
	if (! isset($ipseccfg['enable'])) {
1177
		return true;
1178
	}
1179

    
1180
	/* Walk the Ipsec tunnel array */
1181
	if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
1182
		foreach ($ipseccfg['tunnel'] as $tunnel) {
1183
			if (isset($tunnel['disabled'])) {
1184
				continue;
1185
			}
1186
			if (is_ipaddr($tunnel['remote-gateway'])) {
1187
				continue;
1188
			}
1189

    
1190
			if (!is_ipaddr($tunnel['remote-gateway'])) {
1191
				$dnscache = compare_hostname_to_dnscache($tunnel['remote-gateway']);
1192
				$dnscache = trim($dnscache);
1193
				/* we should have the old IP addresses in the dnscache now */
1194
				if($dnscache <> "") {
1195
					$oldtunnel = $tunnel;
1196
					$oldtunnel['remote-gateway'] = trim($dnscache);
1197
					reload_tunnel_spd_policy ($tunnel, $oldtunnel);
1198
				}
1199
			}
1200
		}
1201
	}
1202

    
1203
	/* process all generated spd.conf files from tmp which are left behind
1204
	 * behind by either changes of dynamic tunnels or manual edits
1205
	 * scandir() is only available in PHP5 */
1206
	$tmpfiles = array();
1207
	$dh  = opendir($g['tmp_path']);
1208
	while (false !== ($filename = readdir($dh))) {
1209
		$tmpfiles[] = $filename;
1210
	}
1211
	sort($tmpfiles);
1212
	foreach($tmpfiles as $tmpfile) {
1213
		if(preg_match("/^spd.conf./", $tmpfile)) {
1214
			$ret = mwexec("/usr/local/sbin/setkey -f {$g['tmp_path']}/{$tmpfile} 2>&1", false);
1215
			if($ret == 0) {
1216
				unlink("{$g['tmp_path']}/{$tmpfile}");
1217
			} else {
1218
				rename("{$g['tmp_path']}/{$tmpfile}", ("{$g['tmp_path']}/failed.{$tmpfile}"));
1219
			}
1220
		}
1221
	}
1222
}
1223

    
1224
function reload_tunnel_spd_policy($tunnel, $oldtunnel) {
1225
	global $config;
1226
	global $g;
1227

    
1228
	/* if we are not passed a old tunnel array we create one */
1229
	if(empty($oldtunnel)) {
1230
		$oldtunnel = $tunnel;
1231
	}
1232

    
1233
	$curwanip = get_current_wan_address();
1234
	$sad_arr = return_ipsec_sad_array();
1235

    
1236
	$ep = vpn_endpoint_determine($tunnel, $curwanip);
1237
	vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
1238

    
1239
	/* make sure we pass the oldtunnel array with a IP for the remote gw */
1240
	$oldgw = trim($oldtunnel['remote-gateway']);
1241
	$oldep = vpn_endpoint_determine($oldtunnel, $curwanip);
1242
	vpn_localnet_determine($oldtunnel['local-subnet'], $oldsa, $oldsn);
1243

    
1244
	/* see if this tunnel has a hostname for the remote-gateway, and if so,
1245
	 * try to resolve it now and add it to the list for dnswatch */
1246
	if (!is_ipaddr($tunnel['remote-gateway'])) {
1247
		$rgip = resolve_retry($tunnel['remote-gateway']);
1248
		if (!$rgip) {
1249
			log_error("Could not determine VPN endpoint for {$tunnel['descr']}");
1250
			return false;
1251
		}
1252
	} else {
1253
		$rgip = $tunnel['remote-gateway'];
1254
	}
1255
	if (!$ep) {
1256
		log_error("Could not determine VPN endpoint for {$tunnel['descr']}");
1257
		return false;
1258
	}
1259

    
1260
	$spdconf = "";
1261

    
1262
	/* Delete old SPD policies if there are changes between the old and new */
1263
 	if(($tunnel != $oldtunnel) && (is_ipaddr($oldgw)) || $tunnel['disabled']) {
1264
		$spdconf .= "spddelete {$oldsa}/{$oldsn} " .
1265
			"{$oldtunnel['remote-subnet']} any -P out ipsec " .
1266
			"{$oldtunnel['p2']['protocol']}/tunnel/{$oldep}-" .
1267
			"{$oldgw}/unique;\n";
1268
		$spdconf .= "spddelete {$oldtunnel['remote-subnet']} " .
1269
			"{$oldsa}/{$oldsn} any -P in ipsec " .
1270
			"{$oldtunnel['p2']['protocol']}/tunnel/{$oldgw}-" .
1271
			"{$oldep}/unique;\n";
1272

    
1273
		/* zap any existing SA entries */
1274
		foreach($sad_arr as $sad) {
1275
			if(($sad['dst'] == $oldep) && ($sad['src'] == $oldgw)) {
1276
				$spdconf .= "delete {$oldep} {$oldgw} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
1277
			}
1278
			if(($sad['src'] == $oldep) && ($sad['dst'] == $oldgw)) {
1279
				$spdconf .= "delete {$oldgw} {$oldep} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
1280
			}
1281
		}
1282
	}
1283

    
1284
	if (!$tunnel['disabled']){
1285
		/* Create new SPD entries for the new configuration */
1286
		/* zap any existing SA entries beforehand */
1287
		foreach($sad_arr as $sad) {
1288
			if(($sad['dst'] == $ep) && ($sad['src'] == $rgip)) {
1289
				$spdconf .= "delete {$rgip} {$ep} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
1290
			}
1291
			if(($sad['src'] == $ep) && ($sad['dst'] == $rgip)) {
1292
				$spdconf .= "delete {$ep} {$rgip} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
1293
			}
1294
		}
1295
		/* add new SPD policies to replace them */
1296
		$spdconf .= "spdadd {$sa}/{$sn} " .
1297
			"{$tunnel['remote-subnet']} any -P out ipsec " .
1298
			"{$tunnel['p2']['protocol']}/tunnel/{$ep}-" .
1299
			"{$rgip}/unique;\n";
1300
		$spdconf .= "spdadd {$tunnel['remote-subnet']} " .
1301
			"{$sa}/{$sn} any -P in ipsec " .
1302
			"{$tunnel['p2']['protocol']}/tunnel/{$rgip}-" .
1303
			"{$ep}/unique;\n";
1304
	}
1305

    
1306
	log_error("Reloading IPsec tunnel '{$tunnel['descr']}'. Previous IP '{$oldgw}', current IP '{$rgip}'. Reloading policy");
1307

    
1308
	$now = time();
1309
	$spdfile = tempnam("{$g['tmp_path']}", "spd.conf.reload.{$now}.");
1310
	/* generate temporary spd.conf */
1311
	file_put_contents($spdfile, $spdconf);
1312
	return true;
1313
}
1314

    
1315
/* Dump SAD database to array */
1316
function return_ipsec_sad_array() {
1317
	/* query SAD */
1318
	$fd = @popen("/usr/local/sbin/setkey -D", "r");
1319
	$sad = array();
1320
	if ($fd) {
1321
	        while (!feof($fd)) {
1322
	                $line = chop(fgets($fd));
1323
       	         if (!$line)
1324
       	                 continue;
1325
       	         if ($line == "No SAD entries.")
1326
       	                 break;
1327
       	         if ($line[0] != "\t") {
1328
       	                 if (is_array($cursa))
1329
       	                         $sad[] = $cursa;
1330
       	                 $cursa = array();
1331
       	                 list($cursa['src'],$cursa['dst']) = explode(" ", $line);
1332
        	                $i = 0;
1333
        		        } else {
1334
                        $linea = explode(" ", trim($line));
1335
                        if ($i == 1) {
1336
                                $cursa['proto'] = $linea[0];
1337
                                $cursa['spi'] = substr($linea[2], strpos($linea[2], "x")+1, -1);
1338
                        } else if ($i == 2) {
1339
                                $cursa['ealgo'] = $linea[1];
1340
                        } else if ($i == 3) {
1341
                                $cursa['aalgo'] = $linea[1];
1342
                        }
1343
                }
1344
                $i++;
1345
        }
1346
        if (is_array($cursa) && count($cursa))
1347
                $sad[] = $cursa;
1348
        pclose($fd);
1349
	}
1350
	return($sad);
1351
}
1352

    
1353
?>
(22-22/27)