Project

General

Profile

« Previous | Next » 

Revision a93e56c5

Added by Matthew Grooms almost 17 years ago

Overhaul IPsec related code. Shared functions have been consolidated into
a new file named /etc/ipsec.inc. Tunnel definitions have been split into
phase1 and phase2. This allows any number of phase2 definitions to be
created for a single phase1 definition. Several facets of configuration
have also been improved. The key size for variable length algorithms can
now be selected and the phase1 ID options have been extended to allow for
more flexible configuration. Several NAT-T related issues have also been
resolved.

Please note, IPsec remote access functionality has been temporarily
disabled. An improved implementation will be included in a follow up
commit.

View differences:

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

  
8 9
	originally part of m0n0wall (http://m0n0.ch/wall)
......
34 35
/* include all configuration functions */
35 36
require_once ("functions.inc");
36 37

  
38
/* IPsec defines */
39
$my_identifier_list = array('myaddress' => 'My IP address',
40
                                'address' => 'IP address',
41
                                'keyid tag' => 'KeyID Tag',
42
                                'fqdn' => 'Domain name',
43
                                'user_fqdn' => 'User FQDN',
44
                                'asn1dn' => 'Distinguished Name',
45
                                'dyn_dns' => 'Dynamic DNS');
46

  
47
$peer_identifier_list = array('peeraddress' => 'Peer IP address',
48
                                'address' => 'IP address',
49
                                'keyid tag' => 'KeyID Tag',
50
                                'fqdn' => 'Domain name',
51
                                'user_fqdn' => 'User FQDN',
52
                                'asn1dn' => 'Distinguished Name');
53

  
54
$p1_ealgos = array(
55
                'aes' => array( 'name' => 'AES', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 64 ) ),
56
                'blowfish' => array( 'name' => 'Blowfish', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 8 ) ),
57
                '3des' => array( 'name' => '3DES' ),
58
                'cast128' => array( 'name' => 'CAST128' ),
59
                'des' => array( 'name' => 'DES' ) );
60

  
61
$p2_ealgos = array(
62
                'aes' => array( 'name' => 'AES', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 64 ) ),
63
                'blowfish' => array( 'name' => 'Blowfish', 'keysel' => array( 'lo' => 128, 'hi' => 256, 'step' => 8 ) ),
64
                '3des' => array( 'name' => '3DES' ),
65
                'cast128' => array( 'name' => 'CAST128' ),
66
                'des' => array( 'name' => 'DES' ) );
67

  
68
$p1_halgos = array('sha1' => 'SHA1', 'md5' => 'MD5');
69
$p1_authentication_methods = array('pre_shared_key' => 'Pre-shared key', 'rsasig' => 'RSA signature');
70
$p2_halgos = array('hmac_sha1' => 'SHA1', 'hmac_md5' => 'MD5');
71
$p2_protos = array('esp' => 'ESP', 'ah' => 'AH');
72
$p2_pfskeygroups = array('0' => 'off', '1' => '1', '2' => '2', '5' => '5');
73

  
37 74
/* master setup for vpn (mpd) */
38 75
function vpn_setup() {
39 76
	/* start pptpd */
......
98 135
	return $last_gif_found;
99 136
}
100 137

  
101
function vpn_ipsec_configure($ipchg = false) {
102
	global $config, $g, $sa, $sn;
138
function vpn_ipsec_configure($ipchg = false)
139
{
140
	global $config, $g, $sa, $sn, $p1_ealgos, $p2_ealgos;
103 141

  
104 142
	mwexec("/sbin/ifconfig enc0 up");
105 143

  
......
120 158
		}
121 159
	}
122 160

  
123
	if(isset($config['ipsec']['preferredoldsa'])) {
161
	if(isset($config['ipsec']['preferredoldsa']))
124 162
		mwexec("/sbin/sysctl net.key.preferred_oldsa=0");
125
	} else {
163
	else
126 164
		mwexec("/sbin/sysctl -w net.key.preferred_oldsa=-30");
127
	}
128 165

  
129 166
	$number_of_gifs = find_last_gif_device();
130
	for ($x = 0; $x < $number_of_gifs; $x++) {
167
	for ($x = 0; $x < $number_of_gifs; $x++)
131 168
		mwexec("/sbin/ifconfig gif" . $x . " delete");
132
	}
133 169

  
134 170
	$curwanip = get_current_wan_address();
135 171

  
136 172
	$syscfg = $config['system'];
137 173
	$ipseccfg = $config['ipsec'];
174
	$a_phase1 = $config['ipsec']['phase1'];
175
	$a_phase2 = $config['ipsec']['phase2'];
138 176
	$lancfg = $config['interfaces']['lan'];
139 177
	$lanip = $lancfg['ipaddr'];
140 178
	$lansa = gen_subnet($lancfg['ipaddr'], $lancfg['subnet']);
141 179
	$lansn = $lancfg['subnet'];
142 180

  
143

  
144 181
	if (!isset($ipseccfg['enable'])) {
145 182
		mwexec("/sbin/ifconfig enc0 down");
146 183
		mwexec("/sbin/ifconfig enc0 destroy");
......
162 199
		return true;
163 200
	}
164 201

  
165
	if ($g['booting']) {
202
	if ($g['booting'])
166 203
		echo "Configuring IPsec VPN... ";
167
	}
168 204

  
169 205
	if (isset ($ipseccfg['enable'])) {
170 206
		/* fastforwarding is not compatible with ipsec tunnels */
......
177 213
			return 0;
178 214
		}
179 215

  
180
		if ((is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) ||
181
		  isset ($ipseccfg['mobileclients']['enable'])) {
182
		  
183
			$dnswatch_list = array();
184
			$rgmap = array();
185
		  
186
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
187
				/* generate spd.conf */
188
				$fd = fopen("{$g['varetc_path']}/spd.conf", "w");
189
				if (!$fd) {
190
					printf("Error: cannot open spd.conf in vpn_ipsec_configure().\n");
191
					return 1;
192
				}
216
		/* resolve all local, peer addresses and setup pings */
217
		$ipmap = array();
218
		$rgmap = array();
219
		$dnswatch_list = array();
220
		if (is_array($a_phase1) && count($a_phase1)) {
221
			foreach ($a_phase1 as $ph1ent) {
222
				if (isset($ph1ent['disabled']))
223
					continue;
193 224

  
194
				$spdconf = "";
225
				$ep = vpn_endpoint_determine($ph1ent, $curwanip);
226
				if (!$ep)
227
					continue;
195 228

  
196
				$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
197
				$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
229
				if(!in_array($ep,$ipmap))
230
					$ipmap[] = $ep;
198 231

  
199
				foreach ($ipseccfg['tunnel'] as $tunnel) {
200
					if (isset ($tunnel['disabled']))
201
						continue;
232
				/* see if this tunnel has a hostname for the remote-gateway. If so,
233
				   try to resolve it now and add it to the list for dnswatch */
202 234

  
203
				   /* see if this tunnel has a hostname for the remote-gateway, and if so,
204
				      try to resolve it now and add it to the list for dnswatch */
205
				   if (!is_ipaddr($tunnel['remote-gateway'])) {
206
				           $dnswatch_list[] = $tunnel['remote-gateway'];
207
				           $rgip = resolve_retry($tunnel['remote-gateway']);
208
				
209
				           if (!$rgip)
210
				                   continue;
211
				
212
				   } else {
213
				           $rgip = $tunnel['remote-gateway'];
214
				   }
215
				   $rgmap[$tunnel['remote-gateway']] = $rgip;
235
				$rg = $ph1ent['remote-gateway'];
216 236

  
217
					$ep = vpn_endpoint_determine($tunnel, $curwanip);
218
					if (!$ep)
237
				if (!is_ipaddr($rg)) {
238
					$dnswatch_list[] = $rg;
239
					$rg = resolve_retry($rg);
240

  
241
					if (!$rgip)
219 242
						continue;
243
				}
220 244

  
221
					vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
245
				$rgmap[$ph1ent['remote-gateway']] = $rg;
222 246

  
223
					if (is_domain($tunnel['remote-gateway'])) {
224
						$tmp = gethostbyname($tunnel['remote-gateway']);
225
						if ($tmp)
226
							$tunnel['remote-gateway'] = $tmp;
227
					}
247
				/* add an ipsec pinghosts entry */
228 248

  
229
					/* add entry to host pinger */
230
					if ($tunnel['pinghost']) {
231
						$pfd = fopen("/var/db/ipsecpinghosts", "a");
232

  
233
					/* if list */
234
        				$iflist = get_configured_interface_list();
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

  
246
					if (isset ($tunnel['creategif'])) {
247
						$number_of_gifs = find_last_gif_device();
248
						$number_of_gifs++;
249
						$curwanip = get_current_wan_address();
250
						if ($config['installedpackages']['sasyncd']['config'] <> "")
251
							foreach ($config['installedpackages']['sasyncd']['config'] as $sasyncd) {
252
								if ($sasyncd['ip'] <> "")
253
									$curwanip = $sasyncd['ip'];
254
							}
255
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " tunnel" . $curwanip . " " . $tunnel['remote-gateway']);
256
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " {$lansa}/{$lansn} {$lanip}/32");
249
				if ($ph1ent['pinghost']) {
250
					$pfd = fopen("/var/db/ipsecpinghosts", "a");
251
					$iflist = array("lan" => "lan", "wan" => "wan");
252
					for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
253
						$iflist['opt' . $i] = "opt{$i}";
254
					foreach ($iflist as $ifent => $ifname) {
255
						$interface_ip = find_interface_ip($config['interfaces'][$ifname]['if']);
256
						if (ip_in_subnet($interface_ip, $sa . "/" . $sn))
257
						$srcip = find_interface_ip($config['interfaces'][$ifname]['if']);
257 258
					}
259
					$dstip = $ph1ent['pinghost'];
260
					fwrite($pfd, "$srcip|$dstip|3\n");
261
					fclose($pfd);
262
				}
263
			}
264
		}
258 265

  
259
					$spdconf .= "spdadd {$sa}/{$sn} " .
260
					  "{$tunnel['remote-subnet']} any -P out ipsec " .
261
					  "{$tunnel['p2']['protocol']}/tunnel/{$ep}-" .
262
					  "{$rgip}/unique;\n";
263

  
264
					$spdconf .= "spdadd {$tunnel['remote-subnet']} " .
265
					  "{$sa}/{$sn} any -P in ipsec " .
266
					  "{$tunnel['p2']['protocol']}/tunnel/{$rgip}-" .
267
					  "{$ep}/unique;\n";
268

  
269
					/* static route needed? */
270
					if(preg_match("/^carp/i", $tunnel['interface'])) {
271
						$parentinterface = link_carp_interface_to_parent($tunnel['interface']);
272
					} else {
273
						$parentinterface = $tunnel['interface'];
274
					}
275
					if($parentinterface <> "wan") {
276
						/* add endpoint routes to correct gateway on interface */
277
						if(interface_has_gateway($parentinterface)) {
278
							$gatewayip = get_interface_gateway("$parentinterface");
279
							$interfaceip = $config['interfaces'][$parentinterface]['ipaddr'];
280
							$subnet_bits = $config['interfaces'][$parentinterface]['subnet'];
281
							$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
282
							/* if the remote gateway is in the local subnet, then don't add a route */
283
							if(! ip_in_subnet($tunnel['remote-gateway'], "{$subnet_ip}/{$subnet_bits}")) {
284
								if(is_ipaddr($gatewayip)) {
285
									log_error("IPSEC interface is not WAN but {$tunnel['interface']}, adding static route for VPN endpoint {$tunnel['remote-gateway']} via {$gatewayip}");
286
									mwexec("/sbin/route delete -host {$tunnel['remote-gateway']};/sbin/route add -host {$tunnel['remote-gateway']} {$gatewayip}");
287
								}
288
							}
266
		/* generate CA certificates files */
267
		$cacertnum = 0;
268
		if (is_array($ipseccfg['cacert']) && count($ipseccfg['cacert'])) {
269
			foreach ($ipseccfg['cacert'] as $cacert) {
270
				++ $cacertnum;
271
				if (isset ($cacert['cert'])) {
272
					$cert = base64_decode($cacert['cert']);
273
					$x509cert = openssl_x509_parse(openssl_x509_read($cert));
274
					if (is_array($x509cert) && isset ($x509cert['hash'])) {
275
						$fd1 = fopen("{$g['varetc_path']}/{$x509cert['hash']}.0", "w");
276
						if (!$fd1) {
277
							printf("Error: cannot open {$x509cert['hash']}.0 in vpn.\n");
278
							return 1;
289 279
						}
290
					} else {
291
						mwexec("/sbin/route delete -host {$tunnel['remote-gateway']}");
280
						chmod("{$g['varetc_path']}/{$x509cert['hash']}.0", 0600);
281
						fwrite($fd1, $cert);
282
						fclose($fd1);
292 283
					}
284
				}
285
			}
286
		}
287
		
288
		/* generate psk.txt */
289
		$fd = fopen("{$g['varetc_path']}/psk.txt", "w");
290
		if (!$fd) {
291
			printf("Error: cannot open psk.txt in vpn_ipsec_configure().\n");
292
			return 1;
293
		}
294

  
295
		$pskconf = "";
293 296

  
297
		if (is_array($a_phase1) && count($a_phase1)) {
298
			foreach ($a_phase1 as $ph1ent) {
299

  
300
				if (isset($ph1ent['disabled']))
301
					continue;
302

  
303
				$rgip = $rgmap[$ph1ent['remote-gateway']];
304
					if (!$rgip)
305
						continue;
306

  
307
				$peerid_type = $ph1ent['peerid_type'];
308

  
309
				switch ($peerid_type) {
310
					case "peeraddress":
311
						$peerid_type = "address";
312
						$peerid_data = $rgip;
313
						break;
314

  
315
					case "address";
316
						$peerid_data = $ph1ent['peerid_data'];
317
						break;
318

  
319
					case "fqdn";
320
					case "keyid tag";
321
					case "user_fqdn";
322
						$peerid_data = $ph1ent['peerid_data'];
323
						break;
294 324
				}
295 325

  
296
				fwrite($fd, $spdconf);
297
				fclose($fd);
326
				$pskconf .= "{$peerid_data}\t\t\t{$ph1ent['pre-shared-key']}\n";
298 327
			}
328
		}
329

  
330
		fwrite($fd, $pskconf);
331
		fclose($fd);
332
		chmod("{$g['varetc_path']}/psk.txt", 0600);
333
			
334
		/* begin racoon.conf */
335
		if ((is_array($a_phase1) && count($a_phase1)) ||
336
			(is_array($a_phase2) && count($a_phase2))) {
299 337

  
300
			/* generate racoon.conf */
301 338
			$fd = fopen("{$g['varetc_path']}/racoon.conf", "w");
302 339
			if (!$fd) {
303 340
				printf("Error: cannot open racoon.conf in vpn_ipsec_configure().\n");
......
309 346
			$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
310 347
			$racoonconf .= "path certificate  \"{$g['varetc_path']}\";\n\n";
311 348

  
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
					}
349
			/* begin listen section */
350
			if (count($ipmap)) {
351
				$racoonconf .= "\nlisten\n";
352
				$racoonconf .= "{\n";
353
				foreach ($ipmap as $addr) {
354
					$racoonconf .= "\tisakmp {$addr} [500];\n";
355
					$racoonconf .= "\tisakmp_natt {$addr} [4500];\n";
331 356
				}
357
				$racoonconf .= "}\n\n";
358
			}
332 359

  
333
			$tunnelnumber = 0;
334
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel']))
335
				foreach ($ipseccfg['tunnel'] as $tunnel) {
360
			/* begin remote sections */
361
			if (is_array($a_phase1) && count($a_phase1)) {
362
				/* begin remote */
363
				foreach ($a_phase1 as $ph1ent) {
364
					if (isset($ph1ent['disabled']))
365
						continue;
336 366

  
337
					++ $tunnelnumber;
367
					$ikeid = $ph1ent['ikeid'];
338 368

  
339
					if (isset ($tunnel['disabled']))
369
					$ep = vpn_endpoint_determine($ph1ent, $curwanip);
370
					if (!$ep)
340 371
						continue;
341 372

  
373
					$myid_type = $ph1ent['myid_type'];
342 374

  
343
					  $rgip = $rgmap[$tunnel['remote-gateway']];
344
					   if (!$rgip)
345
					           continue;
375
					switch ($myid_type) {
346 376

  
347
					$ep = vpn_endpoint_determine($tunnel, $curwanip);
348
					if (!$ep)
349
						continue;
377
						case "myaddress":
378
							$myid_type = "address";
379
							$myid_data = $ep;
380
							break;
381

  
382
						case "dyn_dns":
383
							$myid_data = gethostbyname($ph1ent['myid_data']);
384
							break;
350 385

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

  
353
					if (isset ($tunnel['p1']['myident']['myaddress'])) {
354
						$myidentt = "address";
355
						$myident = $ep;
356
					} elseif (isset ($tunnel['p1']['myident']['address'])) {
357
						$myidentt = "address";
358
						$myident = $tunnel['p1']['myident']['address'];
359
					} elseif (isset ($tunnel['p1']['myident']['fqdn'])) {
360
						$myidentt = "fqdn";
361
						$myident = $tunnel['p1']['myident']['fqdn'];
362
					} elseif (isset ($tunnel['p1']['myident']['ufqdn'])) {
363
						$myidentt = "user_fqdn";
364
						$myident = $tunnel['p1']['myident']['ufqdn'];
365
					} else if (isset($tunnel['p1']['myident']['asn1dn'])) {
366
						$myidentt = "asn1dn";
367
						$myident = $tunnel['p1']['myident']['asn1dn'];					
368
					} else if (isset($tunnel['p1']['myident']['asn1dn'])) {
369
						$myidentt = "asn1dn";
370
						$myident = $tunnel['p1']['myident']['asn1dn'];						
371
					} elseif (isset ($tunnel['p1']['myident']['dyn_dns'])) {
372
						$myidentt = "dyn_dns";
373
						$myident = gethostbyname($tunnel['p1']['myident']['dyn_dns']);
386
						case "address";
387
							$myid_data = $ph1ent['myid_data'];
388
							break;
389

  
390
						case "fqdn";
391
						case "keyid tag";
392
						case "user_fqdn";
393
						case "asn1dn";
394
							$myid_data = $ph1ent['myid_data'];
395
							if( $myid_data )
396
								$myid_data = "\"".$myid_data."\"";
397
							break;
374 398
					}
375 399

  
376
					if (!($myidentt == "asn1dn" && $myident == "")) {
377
						$myident = " \"{$myident}\"";
400
					$rgip = $rgmap[$ph1ent['remote-gateway']];
401
						if (!$rgip)
402
							continue;
403

  
404
					$peerid_type = $ph1ent['peerid_type'];
405

  
406
					switch ($peerid_type) {
407
						case "peeraddress":
408
							$peerid_type = "address";
409
							$peerid_data = $rgip;
410
							break;
411

  
412
						case "address";
413
							$peerid_data = $ph1ent['peerid_data'];
414
							break;
415

  
416
						case "fqdn";
417
						case "keyid tag";
418
						case "user_fqdn";
419
						case "asn1dn";
420
							$peerid_data = $ph1ent['peerid_data'];
421
							if( $peerid_data )
422
								$peerid_data = "\"".$peerid_data."\"";
423
							break;
378 424
					}
379 425

  
380 426
					$nattline = '';
381
					if (isset($tunnel['natt'])) {
382
						$nattline = "nat_traversal on;";
383
					}
427
					if (isset($ph1ent['nat_traversal']))
428
						$nattline = "nat_traversal {$ph1ent['nat_traversal']};";
384 429

  
385
					if (isset ($tunnel['p1']['authentication_method'])) {
386
						$authmethod = $tunnel['p1']['authentication_method'];
387
					} else {
430
					if (isset ($ph1ent['authentication_method']))
431
						$authmethod = $ph1ent['authentication_method'];
432
					else
388 433
						$authmethod = 'pre_shared_key';
389
					}
390 434

  
391 435
					$certline = '';
392 436

  
393 437
					if ($authmethod == 'rsasig') {
394
						if ($tunnel['p1']['cert'] && $tunnel['p1']['private-key']) {
395
							$cert = base64_decode($tunnel['p1']['cert']);
396
							$private_key = base64_decode($tunnel['p1']['private-key']);
438
						if ($ph1ent['cert'] && $ph1ent['private-key']) {
439
							$cert = base64_decode($ph1ent['cert']);
440
							$private_key = base64_decode($ph1ent['private-key']);
397 441
						} else {
398 442
							/* null certificate/key */
399 443
							$cert = '';
400 444
							$private_key = '';
401 445
						}
402 446

  
403
						if ($tunnel['p1']['peercert'])
404
							$peercert = base64_decode($tunnel['p1']['peercert']);
447
						if ($ph1ent['peercert'])
448
							$peercert = base64_decode($ph1ent['peercert']);
405 449
						else
406 450
							$peercert = '';
407 451

  
408
						$fd1 = fopen("{$g['varetc_path']}/server{$tunnelnumber}-signed.pem", "w");
452
						$fd1 = fopen("{$g['varetc_path']}/server{$ikeid}-signed.pem", "w");
409 453
						if (!$fd1) {
410
							printf("Error: cannot open server{$tunnelnumber}-signed.pem in vpn.\n");
454
							printf("Error: cannot open server{$ikeid}-signed.pem in vpn.\n");
411 455
							return 1;
412 456
						}
413
						chmod("{$g['varetc_path']}/server{$tunnelnumber}-signed.pem", 0600);
457
						
458
						chmod("{$g['varetc_path']}/server{$ikeid}-signed.pem", 0600);
414 459
						fwrite($fd1, $cert);
415 460
						fclose($fd1);
416 461

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

  
426
						$certline = "certificate_type x509 \"server{$tunnelnumber}-signed.pem\" \"server{$tunnelnumber}-key.pem\";";
471
						$certline = "certificate_type x509 \"server{$ikeid}-signed.pem\" \"server{$ikeid}-key.pem\";";
427 472

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

  
439
	peers_certfile "peer{$tunnelnumber}-signed.pem";
440
EOD;
482
							$certline .="peers_certfile \"peer{$ikeid}-signed.pem\"";
441 483
						}
442 484
					}
443
					$myidentifier = $myidentt;
444
					if (!empty($myident)) 
445
						$myidentifier .= ' "' . $myident . '"';					
485

  
486
					$ealgos = '';
487
					$ealg_id = $ph1ent['encryption-algorithm']['name'];
488
					$ealg_kl = $ph1ent['encryption-algorithm']['keylen'];
489
					if ($ealg_kl)
490
						$ealgos = $ealgos.$ealg_id." ".$ealg_kl;
491
					else
492
						$ealgos = $ealgos.$ealg_id;
493

  
494
					$lifeline = '';
495
					if ($ph1ent['lifetime'])
496
						$lifeline = "lifetime time {$ph1ent['lifetime']} secs;";
497
						
498
					/* add remote section to configuration */
499

  
446 500
					$racoonconf .=<<<EOD
447
remote {$tunnel['remote-gateway']} {
448
	exchange_mode {$tunnel['p1']['mode']};
449
	my_identifier {$myidentt}{$myident};
501
				
502
remote {$rgip}
503
{
504
	ph1id {$ikeid};
505
	exchange_mode {$ph1ent['mode']};
506
	my_identifier {$myid_type} {$myid_data};
507
	peers_identifier {$peerid_type} {$peerid_data};
508
	ike_frag on;
450 509
	{$nattline}
451 510
	{$certline}
452
	peers_identifier address {$rgip};
453 511
	initial_contact on;
454
	dpd_delay 120;                   # DPD poll every 120 seconds
455
	ike_frag on;
456 512
	support_proxy on;
457
	proposal_check obey;
513
	proposal_check claim;
458 514

  
459
	proposal \{
460
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
461
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
515
	proposal
516
	{
462 517
		authentication_method {$authmethod};
463
		dh_group {$tunnel['p1']['dhgroup']};
518
		encryption_algorithm ${ealgos};
519
		hash_algorithm {$ph1ent['hash-algorithm']};
520
		dh_group {$ph1ent['dhgroup']};
521
		${lifeline}
522
	}
523
}
464 524

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

  
469
					$racoonconf .= "	}\n";
526
				}
527
				/* end remote */
528
			}
529
			/* end remote sections */
530
		
531
			/* begin sainfo sections */
532
			if (is_array($a_phase2) && count($a_phase2)) {
533
				/* begin sainfo */
534
				foreach ($a_phase2 as $ph2ent) {
470 535

  
471
					if ($tunnel['p1']['lifetime'])
472
						$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
536
					$ikeid = $ph2ent['ikeid'];
473 537

  
474
					$racoonconf .= "}\n\n";
538
					$localid_type = $ph2ent['localid']['type'];
539
					if ($localid_type != "address")
540
						$localid_type = "subnet";
475 541

  
476
					$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
477
					$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
542
					$remoteid_type = $ph2ent['remoteid']['type'];
543
					if ($remoteid_type != "address")
544
						$remoteid_type = "subnet";
478 545

  
479
					$racoonconf .=<<<EOD
480
sainfo address {$sa}/{$sn} any address {$tunnel['remote-subnet']} any \{
481
	encryption_algorithm {$p2ealgos};
482
	authentication_algorithm {$p2halgos};
483
	compression_algorithm deflate;
546
					$localid_data = ipsec_idinfo_to_cidr($ph2ent['localid']);
547
					$remoteid_data = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
484 548

  
485
EOD;
549
					$ealgos = '';
550
					$halgos = join(",", $ph2ent['hash-algorithm-option']);
486 551

  
487
					if ($tunnel['p2']['pfsgroup'])
488
						$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
552
					$pfsline = '';
553
					if ($ph2ent['pfsgroup'])
554
						$pfsline = "pfs_group {$ph2ent['pfsgroup']};";
489 555

  
490
					if ($tunnel['p2']['lifetime'])
491
						$racoonconf .= "	lifetime time {$tunnel['p2']['lifetime']} secs;\n";
556
					$lifeline = '';
557
					if ($ph2ent['lifetime'])
558
						$lifeline = "lifetime time {$ph2ent['lifetime']} secs;";
492 559

  
493
					$racoonconf .= "}\n\n";
494
				}
560
					foreach ($ph2ent['encryption-algorithm-option'] as $ealg) {
495 561

  
496
			/* mobile clients? */
497
			if (isset ($ipseccfg['mobileclients']['enable'])) {
562
						$ealg_id = $ealg['name'];
563
						$ealg_kl = $ealg['keylen'];
498 564

  
499
				$tunnel = $ipseccfg['mobileclients'];
565
						if ($ealg_kl) {
566
							if( $ealg_kl == "auto" ) {
567
								$key_hi = $p2_ealgos[$ealg_id]['keysel']['hi'];
568
								$key_lo = $p2_ealgos[$ealg_id]['keysel']['lo'];
569
								$key_step = $p2_ealgos[$ealg_id]['keysel']['step'];
500 570

  
501
				if (isset ($tunnel['p1']['myident']['myaddress'])) {
502
					$myidentt = "address";
503
					$myident = $curwanip;
504
				} else
505
					if (isset ($tunnel['p1']['myident']['address'])) {
506
						$myidentt = "address";
507
						$myident = $tunnel['p1']['myident']['address'];
508
					} else
509
						if (isset ($tunnel['p1']['myident']['fqdn'])) {
510
							$myidentt = "fqdn";
511
							$myident = $tunnel['p1']['myident']['fqdn'];
512
						} else
513
							if (isset ($tunnel['p1']['myident']['ufqdn'])) {
514
								$myidentt = "user_fqdn";
515
								$myident = $tunnel['p1']['myident']['ufqdn'];
571
								for ($keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step) {
572
									if( $ealgos )
573
										$ealgos = $ealgos.", ";
574
									$ealgos = $ealgos.$ealg_id." ".$keylen;
575
								}
576
							} else {
577
								if ($ealgos)
578
									$ealgos = $ealgos.", ";
579
								$ealgos = $ealgos.$ealg_id." ".$ealg_kl;
516 580
							}
517

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

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

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

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

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

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

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

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

  
583
				$racoonconf .= "	}\n";
584 587

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

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

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

  
593
				$racoonconf .=<<<EOD
594
sainfo anonymous \{
595
	encryption_algorithm {$p2ealgos};
596
	authentication_algorithm {$p2halgos};
588
					/* add sainfo section to configuration */
589
					
590
					$racoonconf .=<<<EOD
591
					
592
sainfo {$localid_type} {$localid_data} any {$remoteid_type} {$remoteid_data} any
593
{
594
	remoteid {$ikeid};
595
	encryption_algorithm {$ealgos};
596
	authentication_algorithm {$halgos};
597 597
	compression_algorithm deflate;
598
	${pfsline}
599
	${lifeline}
600
}
598 601

  
599 602
EOD;
600

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

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

  
607
				$racoonconf .= "}\n\n";
603
				}
604
				/* end sainfo */
608 605
			}
606
			/* end sainfo sections */
609 607

  
610 608
			fwrite($fd, $racoonconf);
611 609
			fclose($fd);
610
		}
611
		/* end racoon.conf */
612 612

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

  
620
			$pskconf = "";
622
			$spdconf = "";
621 623

  
622
			if (is_array($ipseccfg['tunnel'])) {
623
				foreach ($ipseccfg['tunnel'] as $tunnel) {
624
					if (isset ($tunnel['disabled']))
625
						continue;
626
                   $rgip = $rgmap[$tunnel['remote-gateway']];
627
                   if (!$rgip)
628
                           continue;
629
                   $pskconf .= "{$rgip}     {$tunnel['p1']['pre-shared-key']}\n";
630
				}
631
			}
624
			/* What are these SPD entries for?
625
			 * -mgrooms 07/10/2008
626
			 */
627
			$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
628
			$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
632 629

  
633
			/* add PSKs for mobile clients */
634
			if (is_array($ipseccfg['mobilekey'])) {
635
				foreach ($ipseccfg['mobilekey'] as $key) {
636
					$pskconf .= "{$key['ident']}	{$key['pre-shared-key']}\n";
637
				}
638
			}
630
			foreach ($a_phase2 as $ph2ent) {
631
				if( !ipsec_lookup_phase1($ph2ent,$ph1ent))
632
					continue;
639 633

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

  
644

  
645
			if(is_process_running("racoon")) {
646
				/* We are already online, reload */
647
				mwexec("/usr/bin/killall -HUP racoon");
648
				/* flush SPD entries */
649
				mwexec("/usr/local/sbin/setkey -FP");
650
				mwexec("/usr/local/sbin/setkey -F");
651
				/* load SPD */
652
				mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf");
653
				sleep(1);
654
				/* We are already online, reload */
655
				mwexec("/usr/bin/killall -HUP racoon");
656
				sleep(1);
657
				mwexec("/usr/bin/killall -HUP racoon");
658
			} else {
659
				/* start racoon */
660
				mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf");
661
				/* flush SA + SPD  entries*/
662
				mwexec("/usr/local/sbin/setkey -FP");
663
				mwexec("/usr/local/sbin/setkey -F");
664
				/* load SPD */
665
				mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf");
666
				sleep(1);
667
				/* We are already online, reload */
668
				mwexec("/usr/bin/killall -HUP racoon");
669
				sleep(1);
670
				mwexec("/usr/bin/killall -HUP racoon");
671

  
672
				/* start dnswatch, if necessary */
673
				if (count($dnswatch_list) > 0) {
674
					$interval = 60;
675
					if ($ipseccfg['dns-interval']) {
676
						$interval = $ipseccfg['dns-interval'];
677
					}
678
			
679
					$hostnames = "";
680
					foreach ($dnswatch_list as $dns) {
681
						$hostnames .= " " . escapeshellarg($dns);
634
				if (isset ($ph1ent['disabled']))
635
					continue;
636

  
637
				if (isset ($ph2ent['disabled']))
638
					continue;
639

  
640
				$ep = vpn_endpoint_determine($ph1ent, $curwanip);
641
				if (!$ep)
642
					continue;
643

  
644
				$rgip = $rgmap[$ph1ent['remote-gateway']];
645

  
646
				$localid = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
647
				$remoteid = ipsec_idinfo_to_cidr($ph2ent['remoteid'],true);
648

  
649
				if (isset ($ph2ent['creategif'])) {
650
					$number_of_gifs = find_last_gif_device();
651
					$number_of_gifs++;
652
					$curwanip = get_current_wan_address();
653
					if ($config['installedpackages']['sasyncd']['config'] <> "") {
654
						foreach ($config['installedpackages']['sasyncd']['config'] as $sasyncd) {
655
							if ($sasyncd['ip'] <> "")
656
								$curwanip = $sasyncd['ip'];
657
						}
682 658
					}
683
					mwexec("/usr/local/bin/dnswatch {$g['varrun_path']}/dnswatch-ipsec.pid $interval " .
684
					escapeshellarg("/etc/rc.newipsecdns") . $hostnames);
659
					mwexec("/sbin/ifconfig gif" . $number_of_gifs . " tunnel" . $curwanip . " " . $rgip);
660
					mwexec("/sbin/ifconfig gif" . $number_of_gifs . " {$lansa}/{$lansn} {$lanip}/32");
685 661
				}
686
			}
687 662

  
688
			if (is_array($ipseccfg['tunnel'])) {
689
				foreach ($ipseccfg['tunnel'] as $tunnel) {
690
					if (isset ($tunnel['auto'])) {
691
						$remotehost = substr($tunnel['remote-subnet'], 0, strpos($tunnel['remote-subnet'], "/"));
692
						$srchost = vpn_endpoint_determine($tunnel, $curwanip);
693
						if ($srchost)
694
							mwexec_bg("/sbin/ping -c 10 -S {$srchost} {$remotehost}");
663
				$spdconf .= "spdadd {$localid} {$remoteid} any -P out ipsec " .
664
					"{$ph2ent['protocol']}/tunnel/{$ep}-{$rgip}/unique;\n";
665

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

  
669
				/* static route needed? */
670
				if (preg_match("/^carp/i", $ph1ent['interface']))
671
					$parentinterface = link_carp_interface_to_parent($ph1ent['interface']);
672
				else
673
					$parentinterface = $ph1ent['interface'];
674

  
675
				if ($parentinterface <> "wan") {
676
					/* add endpoint routes to correct gateway on interface */
677
					if (interface_has_gateway($parentinterface)) {
678
						$gatewayip = get_interface_gateway("$parentinterface");
679
						$interfaceip = $config['interfaces'][$parentinterface]['ipaddr'];
680
						$subnet_bits = $config['interfaces'][$parentinterface]['subnet'];
681
						$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
682
						/* if the remote gateway is in the local subnet, then don't add a route */
683
						if (! ip_in_subnet($rgip, "{$subnet_ip}/{$subnet_bits}")) {
684
							if(is_ipaddr($gatewayip)) {
685
								log_error("IPSEC interface is not WAN but {$parentinterface}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
686
								mwexec("/sbin/route delete -host {$rgip};/sbin/route add -host {$rgip} {$gatewayip}");
687
							}
688
						}
695 689
					}
696 690
				}
691
				else
692
					mwexec("/sbin/route delete -host {$rgip}");
693
			}
694

  
695
			fwrite($fd, $spdconf);
696
			fclose($fd);
697
		}
698

  
699
		/* mange racoon process */
700
		if (is_process_running("racoon")) {
701
			/* We are already online, reload */
702
			mwexec("/usr/bin/killall -HUP racoon");
703
			/* flush SPD entries */
704
			mwexec("/usr/local/sbin/setkey -FP");
705
			mwexec("/usr/local/sbin/setkey -F");
706
			/* load SPD */
707
			mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf");
708
			sleep(1);
709
			/* We are already online, reload */
710
			mwexec("/usr/bin/killall -HUP racoon");
711
			sleep(1);
712
			mwexec("/usr/bin/killall -HUP racoon");
713
		} else {
714
			/* start racoon */
715
			mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf");
716
			/* flush SA + SPD entries */
717
			mwexec("/usr/local/sbin/setkey -FP");
718
			mwexec("/usr/local/sbin/setkey -F");
719
			/* load SPD */
720
			mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf");
721
			sleep(1);
722
			/* We are already online, reload */
723
			mwexec("/usr/bin/killall -HUP racoon");
724
			sleep(1);
725
			mwexec("/usr/bin/killall -HUP racoon");
726

  
727
			/* start dnswatch, if necessary */
728
			if (count($dnswatch_list) > 0) {
729
				$interval = 60;
730
				if ($ipseccfg['dns-interval'])
731
					$interval = $ipseccfg['dns-interval'];
732

  
733
				$hostnames = "";
734
				foreach ($dnswatch_list as $dns)
735
					$hostnames .= " " . escapeshellarg($dns);
736

  
737
				mwexec("/usr/local/bin/dnswatch {$g['varrun_path']}/dnswatch-ipsec.pid $interval " .
738
				escapeshellarg("/etc/rc.newipsecdns") . $hostname);
697 739
			}
698 740
		}
699 741
	}
700

  
742
	
701 743
	vpn_ipsec_failover_configure();
702 744

  
703 745
	if (!$g['booting']) {
......
943 985
	}
944 986
}
945 987

  
946
function vpn_endpoint_determine($tunnel, $curwanip) {
988
function vpn_endpoint_determine($ph1ent, $curwanip) {
947 989

  
948 990
	global $g, $config;
949 991

  
950
	if ((!$tunnel['interface']) || ($tunnel['interface'] == "wan")) {
992
	if ((!$ph1ent['interface']) || ($ph1ent['interface'] == "wan")) {
951 993
		if ($curwanip)
952 994
			return $curwanip;
953 995
		else
954 996
			return null;
955
	} elseif ($tunnel['interface'] == "lan") {
997
	} elseif ($ph1ent['interface'] == "lan") {
956 998
		return $config['interfaces']['lan']['ipaddr'];
957 999
	} else {
958
		$iface = $config['interfaces'][$tunnel['interface']]['if'];
959
		$oc = $config['interfaces'][$tunnel['interface']];
1000
		$iface = $config['interfaces'][$ph1ent['interface']]['if'];
1001
		$oc = $config['interfaces'][$ph1ent['interface']];
960 1002
		/* carp ips, etc */
961 1003
		$ip = find_interface_ip($iface);
962 1004
		if($ip) 

Also available in: Unified diff