Project

General

Profile

Download (38.3 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=0x00000000");
104
	exec("/sbin/sysctl net.enc.out.ipsec_filter_mask=0x00000001");
105
	exec("/sbin/sysctl net.enc.in.ipsec_bpf_mask=0x00000000");
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']['preferredoldsa'])) {
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
		mwexec("/usr/bin/killall racoon", true);
138
		killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
139

    
140

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

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

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

    
151
		return true;
152
	}
153

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

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

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

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

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

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

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

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

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

    
189
				$spdconf = "";
190

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

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

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

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

    
219

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

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

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

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

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

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

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

    
293
				fwrite($fd, $spdconf);
294
				fclose($fd);
295
			}
296

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

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

    
309
			$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
310
			$racoonconf .= "path certificate  \"{$g['varetc_path']}\";\n\n";
311

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

    
333
			$tunnelnumber = 0;
334
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel']))
335
				foreach ($ipseccfg['tunnel'] as $tunnel) {
336

    
337
				++$tunnelnumber;
338

    
339
				if (isset($tunnel['disabled']))
340
					continue;
341

    
342
				$rgip = $rgmap[$tunnel['remote-gateway']];
343
				if (!$rgip)
344
					continue;
345

    
346
				$ep = vpn_endpoint_determine($tunnel, $curwanip);
347
				if (!$ep)
348
					continue;
349

    
350
				vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
351

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

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

    
378
				$dpdline = '';
379
				if (is_numeric($tunnel['dpddelay'])) {
380
					$dpdline = "dpd_delay {$tunnel['dpddelay']};";
381
				}
382

    
383
				if (isset($tunnel['p1']['authentication_method'])) {
384
					$authmethod = $tunnel['p1']['authentication_method'];
385
				} else {$authmethod = 'pre_shared_key';}
386

    
387
				$certline = '';
388

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

    
399
					if ($tunnel['p1']['peercert'])
400
						$peercert = base64_decode($tunnel['p1']['peercert']);
401
					else
402
						$peercert = '';
403

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

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

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

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

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

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

    
458
EOD;
459
				if ($tunnel['p1']['lifetime'])
460
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
461

    
462
				$racoonconf .= "	}\n";
463

    
464
				if ($tunnel['p1']['lifetime'])
465
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
466

    
467
				$racoonconf .= "}\n\n";
468

    
469
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
470
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
471

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

    
478
EOD;
479

    
480
				if ($tunnel['p2']['pfsgroup'])
481
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
482

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

    
486
				$racoonconf .= "}\n\n";
487
			}
488

    
489
			/* mobile clients? */
490
			if (isset($ipseccfg['mobileclients']['enable'])) {
491

    
492
				$tunnel = $ipseccfg['mobileclients'];
493

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

    
513
				$dpdline = '';
514
				if (is_numeric($tunnel['dpddelay'])) {
515
					$dpdline = "dpd_delay {$tunnel['dpddelay']};";
516
				}
517

    
518
				if (isset($tunnel['p1']['authentication_method'])) {
519
					$authmethod = $tunnel['p1']['authentication_method'];
520
				} else {$authmethod = 'pre_shared_key';}
521

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

    
533
					if ($tunnel['p1']['peercert'])
534
						$peercert = base64_decode($tunnel['p1']['peercert']);
535
					else
536
						$peercert = '';
537

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

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

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

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

    
578
EOD;
579
				if ($tunnel['p1']['lifetime'])
580
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
581

    
582
				$racoonconf .= "	}\n";
583

    
584
				if ($tunnel['p1']['lifetime'])
585
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
586

    
587
				$racoonconf .= "}\n\n";
588

    
589
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
590
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
591

    
592
				$racoonconf .= <<<EOD
593
sainfo anonymous \{
594
	encryption_algorithm {$p2ealgos};
595
	authentication_algorithm {$p2halgos};
596
	compression_algorithm deflate;
597

    
598
EOD;
599

    
600
				if ($tunnel['p2']['pfsgroup'])
601
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
602

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

    
606
				$racoonconf .= "}\n\n";
607
			}
608

    
609
			fwrite($fd, $racoonconf);
610
			fclose($fd);
611

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

    
619
			$pskconf = "";
620

    
621
			if (is_array($ipseccfg['tunnel'])) {
622
				foreach ($ipseccfg['tunnel'] as $tunnel) {
623
					if (isset($tunnel['disabled']))
624
						continue;
625

    
626
					$rgip = $rgmap[$tunnel['remote-gateway']];
627
					if (!$rgip)
628
						continue;
629

    
630
					$pskconf .= "{$rgip}     {$tunnel['p1']['pre-shared-key']}\n";
631
				}
632
			}
633

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

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

    
645
			exec("/bin/mkdir -p /var/db/racoon");
646

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

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

    
674
				$hostnames = "";
675
				foreach ($dnswatch_list as $dns)
676
					$hostnames .= " " . escapeshellarg($dns);
677
				killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
678
				mwexec("/usr/local/sbin/dnswatch {$g['varrun_path']}/dnswatch-ipsec.pid $interval " .
679
				escapeshellarg("/etc/rc.newipsecdns") . $hostnames, false);
680
			}
681

    
682

    
683
		}
684
	}
685

    
686
	vpn_ipsec_failover_configure();
687

    
688
	if (!$g['booting']) {
689
		/* reload the filter */
690
		touch("{$g["tmp_path"]}/filter_dirty");
691
	}
692

    
693
	if ($g['booting'])
694
		echo "done\n";
695

    
696
	return 0;
697
}
698

    
699
function vpn_pptpd_configure() {
700
	global $config, $g;
701

    
702
	$syscfg = $config['system'];
703
	$pptpdcfg = $config['pptpd'];
704

    
705
	if ($g['booting']) {
706
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
707
			return 0;
708

    
709
		echo "Configuring PPTP VPN service... ";
710
	} else {
711
		/* kill mpd */
712
		killbypid("{$g['varrun_path']}/mpd-vpn.pid");
713

    
714
		/* wait for process to die */
715
		sleep(3);
716

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

    
722
		/* remove mpd.conf, if it exists */
723
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.conf");
724
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.links");
725
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.secret");
726
	}
727

    
728
	/* make sure mpd-vpn directory exists */
729
	if (!file_exists("{$g['varetc_path']}/mpd-vpn"))
730
		mkdir("{$g['varetc_path']}/mpd-vpn");
731

    
732
	switch ($pptpdcfg['mode']) {
733

    
734
		case 'server':
735

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

    
743
			$mpdconf = <<<EOD
744
pptpd:
745

    
746
EOD;
747

    
748
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
749
				$mpdconf .= "	load pt{$i}\n";
750
			}
751

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

    
754
				$clientip = long2ip(ip2long($pptpdcfg['remoteip']) + $i);
755
				$ngif = "ng" . ($i+1);
756

    
757
				$mpdconf .= <<<EOD
758

    
759
pt{$i}:
760
	new -i {$ngif} pt{$i} pt{$i}
761
	set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
762
	load pts
763

    
764
EOD;
765
			}
766

    
767
			$mpdconf .= <<<EOD
768

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

    
789
EOD;
790

    
791
			if (!isset($pptpdcfg['req128'])) {
792
				$mpdconf .= <<<EOD
793
	set ccp yes mpp-e40
794
	set ccp yes mpp-e56
795

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

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

    
819
EOD;
820

    
821
				if (isset($pptpdcfg['radius']['accounting'])) {
822
					$mpdconf .= <<<EOD
823
	set bundle enable radius-acct
824

    
825
EOD;
826
				}
827
			}
828

    
829
			fwrite($fd, $mpdconf);
830
			fclose($fd);
831

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

    
839
			$mpdlinks = "";
840

    
841
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
842
				$mpdlinks .= <<<EOD
843

    
844
pt{$i}:
845
	set link type pptp
846
	set pptp enable incoming
847
	set pptp disable originate
848
	set pptp disable windowing
849
	set pptp self 127.0.0.1
850

    
851
EOD;
852
			}
853

    
854
			fwrite($fd, $mpdlinks);
855
			fclose($fd);
856

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

    
864
			$mpdsecret = "";
865

    
866
			if (is_array($pptpdcfg['user'])) {
867
				foreach ($pptpdcfg['user'] as $user)
868
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
869
			}
870

    
871
			fwrite($fd, $mpdsecret);
872
			fclose($fd);
873
			chmod("{$g['varetc_path']}/mpd-vpn/mpd.secret", 0600);
874

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

    
878
			break;
879

    
880
		case 'redir':
881
			break;
882
	}
883

    
884
	if (!$g['booting']) {
885
		/* reload the filter */
886
		filter_configure();
887
	}
888

    
889
	if ($g['booting'])
890
		echo "done\n";
891

    
892
	return 0;
893
}
894

    
895
function vpn_localnet_determine($adr, &$sa, &$sn) {
896
	global $config, $g;
897

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

    
917
function vpn_endpoint_determine($tunnel, $curwanip) {
918
	global $g, $config;
919

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

    
940
		if (isset($oc['enable']) && $oc['if']) {
941
			return $oc['ipaddr'];
942
		}
943
	}
944
	return null;
945
}
946

    
947
function vpn_pppoe_configure() {
948
	global $config, $g;
949

    
950
	$syscfg = $config['system'];
951
	$pppoecfg = $config['pppoe'];
952

    
953
	/* create directory if it does not exist */
954
	if(!is_dir("{$g['varetc_path']}/mpd-vpn"))
955
		mkdir("{$g['varetc_path']}/mpd-vpn");
956

    
957
	if ($g['booting']) {
958
		if (!$pppoecfg['mode'] || ($pppoecfg['mode'] == "off"))
959
			return 0;
960

    
961
		echo "Configuring PPPoE VPN service... ";
962
	}
963

    
964
	/* make sure mpd-vpn directory exists */
965
	if (!file_exists("{$g['varetc_path']}/mpd-vpn"))
966
		mkdir("{$g['varetc_path']}/mpd-vpn");
967

    
968
	switch ($pppoecfg['mode']) {
969

    
970
		case 'server':
971

    
972
			$pppoe_interface = filter_translate_type_to_real_interface($pppoecfg['interface']);
973

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

    
984
EOD;
985

    
986
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
987
				$mpdconf .= "	load pppoe{$i}\n";
988
			}
989

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

    
992
				$clientip = long2ip(ip2long($pppoecfg['remoteip']) + $i);
993
				$ngif = "ng" . ($i+1);
994

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

    
1002
				$mpdconf .= <<<EOD
1003

    
1004
pppoe{$i}:
1005
	new -i {$ngif} pppoe{$i} pppoe{$i}
1006
	{$isssue_ip_type}
1007
	load pppoe_standart
1008

    
1009
EOD;
1010
			}
1011

    
1012
			$mpdconf .= <<<EOD
1013

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

    
1043
EOD;
1044

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

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

    
1062
EOD;
1063

    
1064
				if (isset($pppoecfg['radius']['accounting'])) {
1065
					$mpdconf .= <<<EOD
1066
	set bundle enable radius-acct
1067
	set radius acct-update 300
1068
EOD;
1069
				}
1070
			}
1071

    
1072
			fwrite($fd, $mpdconf);
1073
			fclose($fd);
1074

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

    
1082
			$mpdlinks = "";
1083

    
1084
			for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) {
1085
				$mpdlinks .= <<<EOD
1086

    
1087
pppoe:
1088
	set link type pppoe
1089
	set pppoe iface {$pppoe_interface}
1090

    
1091
EOD;
1092
			}
1093

    
1094
			fwrite($fd, $mpdlinks);
1095
			fclose($fd);
1096

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

    
1104
			$mpdsecret = "\n\n";
1105

    
1106
			if (is_array($pppoecfg['user'])) {
1107
				foreach ($pppoecfg['user'] as $user)
1108
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
1109
			}
1110

    
1111
			fwrite($fd, $mpdsecret);
1112
			fclose($fd);
1113
			chmod("{$g['varetc_path']}/mpd-vpn/mpd.secret", 0600);
1114

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

    
1118
			break;
1119

    
1120
		case 'redir':
1121
			break;
1122
	}
1123

    
1124
	touch("{$g["tmp_path"]}/filter_dirty");
1125

    
1126
	if ($g['booting'])
1127
		echo "done\n";
1128

    
1129
	return 0;
1130
}
1131

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

    
1141
	$ipseccfg = $config['ipsec'];
1142

    
1143
	/* kill racoon */
1144
	mwexec("/usr/bin/killall racoon", true);
1145

    
1146
	/* wait for process to die */
1147
	sleep(4);
1148

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

    
1152
	/* wait for flushing to finish */
1153
	sleep(1);
1154

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

    
1161
}
1162

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

    
1170
	$ipseccfg = $config['ipsec'];
1171

    
1172
	if (! isset($ipseccfg['enable'])) {
1173
		return true;
1174
	}
1175

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

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

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

    
1220
function reload_tunnel_spd_policy($tunnel, $oldtunnel) {
1221
	global $config;
1222
	global $g;
1223

    
1224
	/* if we are not passed a old tunnel array we create one */
1225
	if(empty($oldtunnel)) {
1226
		$oldtunnel = $tunnel;
1227
	}
1228

    
1229
	$curwanip = get_current_wan_address();
1230
	$sad_arr = return_ipsec_sad_array();
1231

    
1232
	$ep = vpn_endpoint_determine($tunnel, $curwanip);
1233
	vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
1234

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

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

    
1257
	$spdconf = "";
1258

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

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

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

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

    
1303
	$now = time();
1304
	$spdfile = tempnam("{$g['tmp_path']}", "spd.conf.reload.{$now}.");
1305
	/* generate temporary spd.conf */
1306
	file_put_contents($spdfile, $spdconf);
1307
	return true;
1308
}
1309

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

    
1348
?>
(22-22/27)