Project

General

Profile

Download (84 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * ipsec.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2008 Shrew Soft Inc.
7
 * Copyright (c) 2007-2013 BSD Perimeter
8
 * Copyright (c) 2013-2016 Electric Sheep Fencing
9
 * Copyright (c) 2014-2020 Rubicon Communications, LLC (Netgate)
10
 * All rights reserved.
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24

    
25
require_once("filter.inc");
26
require_once("auth.inc");
27
require_once("certs.inc");
28
require_once("interfaces.inc");
29

    
30
/* IPsec defines */
31
global $ipsec_loglevels;
32
$ipsec_loglevels = array(
33
	"dmn" => gettext("Daemon"),
34
	"mgr" => gettext("SA Manager"),
35
	"ike" => gettext("IKE SA"),
36
	"chd" => gettext("IKE Child SA"),
37
	"job" => gettext("Job Processing"),
38
	"cfg" => gettext("Configuration backend"),
39
	"knl" => gettext("Kernel Interface"),
40
	"net" => gettext("Networking"),
41
	"asn" => gettext("ASN encoding"),
42
	"enc" => gettext("Message encoding"),
43
	"imc" => gettext("Integrity checker"),
44
	"imv" => gettext("Integrity Verifier"),
45
	"pts" => gettext("Platform Trust Service"),
46
	"tls" => gettext("TLS handler"),
47
	"esp" => gettext("IPsec traffic"),
48
	"lib" => gettext("StrongSwan Lib")
49
);
50

    
51
global $ipsec_log_sevs;
52
$ipsec_log_sevs = array(
53
	'-1' => gettext('Silent'),
54
	'0' => gettext('Audit'),
55
	'1' => gettext('Control'),
56
	'2' => gettext('Diag'),
57
	'3' => gettext('Raw'),
58
	'4' => gettext('Highest')
59
);
60

    
61
global $ipsec_log_cats;
62
$ipsec_log_cats = array(
63
	"dmn" => gettext("Daemon"),
64
	"mgr" => gettext("SA Manager"),
65
	"ike" => gettext("IKE SA"),
66
	"chd" => gettext("IKE Child SA"),
67
	"job" => gettext("Job Processing"),
68
	"cfg" => gettext("Configuration backend"),
69
	"knl" => gettext("Kernel Interface"),
70
	"net" => gettext("Networking"),
71
	"asn" => gettext("ASN encoding"),
72
	"enc" => gettext("Message encoding"),
73
	"imc" => gettext("Integrity checker"),
74
	"imv" => gettext("Integrity Verifier"),
75
	"pts" => gettext("Platform Trust Service"),
76
	"tls" => gettext("TLS handler"),
77
	"esp" => gettext("IPsec traffic"),
78
	"lib" => gettext("StrongSwan Lib")
79
);
80

    
81
global $ipsec_identifier_list;
82
$ipsec_identifier_list = array(
83
	// 'ipv4' => array('desc' => gettext('IPv4 address'), 'mobile' => true),
84
	// 'ipv6' => array('desc' => gettext('IPv6 address'), 'mobile' => true),
85
	// 'rfc822' => array('desc' => gettext('RFC822'), 'mobile' => true),
86
	'none' => array('desc' => '', 'mobile' => true),
87
	'email' => array('desc' => gettext('E-mail address'), 'mobile' => true),
88
	'userfqdn' => array('desc' => gettext('User Fully Qualified Domain Name'), 'mobile' => true)
89
	// 'fqdn' => array('desc' => gettext('Fully Qualified Domain Name'), 'mobile' => true),
90
	// 'dns' => array('desc' => gettext('DNS'), 'mobile' => true),
91
	// 'asn1dn' => array('desc' => gettext('ASN.1 Distinguished Name'), 'mobile' => true),
92
	// 'asn1gn' => array('desc' => gettext('ASN.1 GN'), 'mobile' => true),
93
	// 'keyid' => array('desc' => gettext('KeyID'), 'mobile' => true)
94
);
95

    
96
global $my_identifier_list;
97
$my_identifier_list = array(
98
	'myaddress' => array('desc' => gettext('My IP address'), 'mobile' => true),
99
	'address' => array('desc' => gettext('IP address'), 'mobile' => true),
100
	'fqdn' => array('desc' => gettext('Distinguished name'), 'mobile' => true),
101
	'user_fqdn' => array('desc' => gettext('User distinguished name'), 'mobile' => true),
102
	'asn1dn' => array('desc' => gettext('ASN.1 distinguished Name'), 'mobile' => true),
103
	'keyid tag' => array('desc' => gettext('KeyID tag'), 'mobile' => true),
104
	'dyn_dns' => array('desc' => gettext('Dynamic DNS'), 'mobile' => true)
105
);
106

    
107
global $peer_identifier_list;
108
$peer_identifier_list = array(
109
	'any' => array('desc' => gettext('Any'), 'mobile' => true),
110
	'peeraddress' => array('desc' => gettext('Peer IP address'), 'mobile' => false),
111
	'address' => array('desc' => gettext('IP address'), 'mobile' => false),
112
	'fqdn' => array('desc' => gettext('Distinguished name'), 'mobile' => true),
113
	'user_fqdn' => array('desc' => gettext('User distinguished name'), 'mobile' => true),
114
	'asn1dn' => array('desc' => gettext('ASN.1 distinguished Name'), 'mobile' => true),
115
	'keyid tag' => array('desc' =>gettext('KeyID tag'), 'mobile' => true)
116
);
117

    
118
global $ipsec_idhandling;
119
$ipsec_idhandling = array(
120
	'replace' => 'Yes (Replace)', 'no' => 'No', 'never' => 'Never', 'keep' => 'Keep'
121
);
122

    
123
global $p1_ealgos;
124
$p1_ealgos = array(
125
	'aes' => array('name' => 'AES', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
126
	'aes128gcm' => array('name' => 'AES128-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
127
	'aes192gcm' => array('name' => 'AES192-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
128
	'aes256gcm' => array('name' => 'AES256-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
129
	'blowfish' => array('name' => 'Blowfish', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
130
	'3des' => array('name' => '3DES'),
131
	'cast128' => array('name' => 'CAST128')
132
);
133

    
134
global $p2_ealgos;
135
$p2_ealgos = array(
136
	'aes' => array('name' => 'AES', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
137
	'aes128gcm' => array('name' => 'AES128-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
138
	'aes192gcm' => array('name' => 'AES192-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
139
	'aes256gcm' => array('name' => 'AES256-GCM', 'keysel' => array('lo' => 64, 'hi' => 128, 'step' => 32)),
140
	'blowfish' => array('name' => 'Blowfish', 'keysel' => array('lo' => 128, 'hi' => 256, 'step' => 64)),
141
	'3des' => array('name' => '3DES'),
142
	'cast128' => array('name' => 'CAST128')
143
);
144

    
145
global $p1_halgos;
146
$p1_halgos = array(
147
	'md5' => 'MD5',
148
	'sha1' => 'SHA1',
149
	'sha256' => 'SHA256',
150
	'sha384' => 'SHA384',
151
	'sha512' => 'SHA512',
152
	'aesxcbc' => 'AES-XCBC'
153
);
154

    
155
global $p1_dhgroups;
156
$p1_dhgroups = array(
157
	1  => '1 (768 bit)',
158
	2  => '2 (1024 bit)',
159
	5  => '5 (1536 bit)',
160
	14 => '14 (2048 bit)',
161
	15 => '15 (3072 bit)',
162
	16 => '16 (4096 bit)',
163
	17 => '17 (6144 bit)',
164
	18 => '18 (8192 bit)',
165
	19 => '19 (nist ecp256)',
166
	20 => '20 (nist ecp384)',
167
	21 => '21 (nist ecp521)',
168
	22 => '22 (1024(sub 160) bit)',
169
	23 => '23 (2048(sub 224) bit)',
170
	24 => '24 (2048(sub 256) bit)',
171
	25 => '25 (nist ecp192)',
172
	26 => '26 (nist ecp224)',
173
	27 => '27 (brainpool ecp224)',
174
	28 => '28 (brainpool ecp256)',
175
	29 => '29 (brainpool ecp384)',
176
	30 => '30 (brainpool ecp512)',
177
	31 => '31 (Elliptic Curve 25519, 256 bit)',
178
	32 => '32 (Elliptic Curve 25519, 448 bit)',
179
);
180

    
181
global $p2_halgos;
182
$p2_halgos = array(
183
	'hmac_md5' => 'MD5',
184
	'hmac_sha1' => 'SHA1',
185
	'hmac_sha256' => 'SHA256',
186
	'hmac_sha384' => 'SHA384',
187
	'hmac_sha512' => 'SHA512',
188
	'aesxcbc' => 'AES-XCBC'
189
);
190

    
191
global $p1_authentication_methods;
192
$p1_authentication_methods = array(
193
	'hybrid_cert_server' => array('name' => gettext('Hybrid Certificate + Xauth'), 'mobile' => true),
194
	'xauth_cert_server' => array('name' => gettext('Mutual Certificate + Xauth'), 'mobile' => true),
195
	'xauth_psk_server' => array('name' => gettext('Mutual PSK + Xauth'), 'mobile' => true),
196
	'eap-tls' => array('name' => gettext('EAP-TLS'), 'mobile' => true),
197
	'eap-radius' => array('name' => gettext('EAP-RADIUS'), 'mobile' => true),
198
	'eap-mschapv2' => array('name' => gettext('EAP-MSChapv2'), 'mobile' => true),
199
	'cert' => array('name' => gettext('Mutual Certificate'), 'mobile' => false),
200
	'pkcs11' => array('name' => gettext('Mutual Certificate (PKCS#11)'), 'mobile' => false),
201
	'pre_shared_key' => array('name' => gettext('Mutual PSK'), 'mobile' => false)
202
);
203

    
204
global $ipsec_preshared_key_type;
205
$ipsec_preshared_key_type = array(
206
	'PSK' => 'PSK',
207
	'EAP' => 'EAP'
208
);
209

    
210
global $ipsec_closeactions;
211
$ipsec_closeactions = array(
212
	'' => gettext('Default'),
213
	'none' => gettext('No action'),
214
	'restart' => gettext('Restart/Reconnect'),
215
	'clear' => gettext('Close connection and clear SA'),
216
	'hold' => gettext('Close connection and reconnect on demand'),
217
);
218

    
219
global $p2_modes;
220
$p2_modes = array(
221
	'tunnel' => gettext('Tunnel IPv4'),
222
	'tunnel6' => gettext('Tunnel IPv6'),
223
	'transport' => gettext('Transport'),
224
	'vti' => gettext('Routed (VTI)')
225
);
226

    
227
global $p2_protos;
228
$p2_protos = array(
229
	'esp' => 'ESP',
230
	'ah' => 'AH'
231
);
232

    
233
global $p2_pfskeygroups;
234
$p2_pfskeygroups = array(
235
	0 => gettext('off'),
236
	1  => gettext('1 (768 bit)'),
237
	2  => gettext('2 (1024 bit)'),
238
	5  => gettext('5 (1536 bit)'),
239
	14 => gettext('14 (2048 bit)'),
240
	15 => gettext('15 (3072 bit)'),
241
	16 => gettext('16 (4096 bit)'),
242
	17 => gettext('17 (6144 bit)'),
243
	18 => gettext('18 (8192 bit)'),
244
	19 => gettext('19 (nist ecp256)'),
245
	20 => gettext('20 (nist ecp384)'),
246
	21 => gettext('21 (nist ecp521)'),
247
	22 => gettext('22 (1024(sub 160) bit)'),
248
	23 => gettext('23 (2048(sub 224) bit)'),
249
	24 => gettext('24 (2048(sub 256) bit)'),
250
	25 => gettext('25 (nist ecp192)'),
251
	26 => gettext('26 (nist ecp224)'),
252
	27 => gettext('27 (brainpool ecp224)'),
253
	28 => gettext('28 (brainpool ecp256)'),
254
	29 => gettext('29 (brainpool ecp384)'),
255
	30 => gettext('30 (brainpool ecp512)'),
256
	31 => gettext('31 (Elliptic Curve 25519, 256 bit)'),
257
	32 => gettext('32 (Elliptic Curve 25519, 448 bit)'),
258
);
259

    
260
function ipsec_enabled() {
261
	global $config;
262

    
263
	if (!isset($config['ipsec']) || !is_array($config['ipsec'])) {
264
		return false;
265
	}
266

    
267
	/* Check if we have at least one phase 1 entry. */
268
	if (!isset($config['ipsec']['phase1']) ||
269
	    !is_array($config['ipsec']['phase1']) ||
270
	    empty($config['ipsec']['phase1'])) {
271
		return false;
272
	}
273
	/* Check if at least one phase 1 entry is enabled. */
274
	foreach ($config['ipsec']['phase1'] as $phase1) {
275
		if (!isset($phase1['disabled'])) {
276
			return true;
277
		}
278
	}
279

    
280
	return false;
281
}
282

    
283
/*
284
 * ikeid management functions
285
 */
286

    
287
function ipsec_ikeid_used($ikeid) {
288
	global $config;
289

    
290
	foreach ($config['ipsec']['phase1'] as $ph1ent) {
291
		if ($ikeid == $ph1ent['ikeid']) {
292
			return true;
293
		}
294
	}
295

    
296
	return false;
297
}
298

    
299
function ipsec_ikeid_next() {
300

    
301
	$ikeid = 1;
302
	while (ipsec_ikeid_used($ikeid)) {
303
		$ikeid++;
304
	}
305

    
306
	return $ikeid;
307
}
308

    
309
/*
310
 * Return phase1 local address
311
 */
312
function ipsec_get_phase1_src(& $ph1ent) {
313

    
314
	if ($ph1ent['interface']) {
315
		if (substr($ph1ent['interface'], 0, 4) == "_vip") {
316
			$if = $ph1ent['interface'];
317
		} else {
318
			$if = get_failover_interface($ph1ent['interface']);
319
		}
320
	} else {
321
		$if = "wan";
322
	}
323
	$ip6 = get_interface_ipv6($if);
324
	$ip4 = get_interface_ip($if);
325
	if ($ph1ent['protocol'] == "inet6") {
326
		$interfaceip = $ip6;
327
	} elseif ($ph1ent['protocol'] == "inet") {
328
		$interfaceip = $ip4;
329
	} elseif ($ph1ent['protocol'] == "both") {
330
		$ifips = array();
331
		if (!empty($ip4)) {
332
			$ifips[] = $ip4;
333
		}
334
		if (!empty($ip6)) {
335
			$ifips[] = $ip6;
336
		}
337
		$interfaceip = implode(',', $ifips);
338
	}
339

    
340
	return $interfaceip;
341
}
342

    
343
/*
344
 * Return phase1 local address
345
 */
346
function ipsec_get_phase1_dst(& $ph1ent) {
347
	global $g;
348

    
349
	if (empty($ph1ent['remote-gateway'])) {
350
		return false;
351
	}
352
	$rg = $ph1ent['remote-gateway'];
353
	if (!is_ipaddr($rg)) {
354
		if (!platform_booting()) {
355
			return resolve_retry($rg, $ph1ent['protocol']);
356
		}
357
	}
358
	if (!is_ipaddr($rg)) {
359
		return false;
360
	}
361

    
362
	return $rg;
363
}
364

    
365
/*
366
 * Return phase2 idinfo in cidr format
367
 */
368
function ipsec_idinfo_to_cidr(& $idinfo, $addrbits = false, $mode = "") {
369
	global $config;
370

    
371
	switch ($idinfo['type']) {
372
		case "address":
373
			if ($addrbits) {
374
				if ($mode == "tunnel6") {
375
					return $idinfo['address']."/128";
376
				} elseif (($mode == "vti") && is_ipaddrv6($idinfo['address'])) {
377
					return $idinfo['address']."/64";
378
				} else {
379
					return $idinfo['address']."/32";
380
				}
381
			} else {
382
				return $idinfo['address'];
383
			}
384
			break; /* NOTREACHED */
385
		case "network":
386
			return "{$idinfo['address']}/{$idinfo['netbits']}";
387
			break; /* NOTREACHED */
388
		case "none":
389
		case "mobile":
390
			return '0.0.0.0/0';
391
			break; /* NOTREACHED */
392
		default:
393
			if (empty($mode) && !empty($idinfo['mode'])) {
394
				$mode = $idinfo['mode'];
395
			}
396

    
397
			if ($mode == "tunnel6") {
398
				$address = get_interface_ipv6($idinfo['type']);
399
				$netbits = get_interface_subnetv6($idinfo['type']);
400
				$address = gen_subnetv6($address, $netbits);
401
				return "{$address}/{$netbits}";
402
			} else {
403
				$address = get_interface_ip($idinfo['type']);
404
				$netbits = get_interface_subnet($idinfo['type']);
405
				$address = gen_subnet($address, $netbits);
406
				return "{$address}/{$netbits}";
407
			}
408
			break; /* NOTREACHED */
409
	}
410
}
411

    
412
/*
413
 * Return phase2 idinfo in address/netmask format
414
 */
415
function ipsec_idinfo_to_subnet(& $idinfo, $addrbits = false) {
416
	global $config;
417

    
418
	switch ($idinfo['type']) {
419
		case "address":
420
			if ($addrbits) {
421
				if ($idinfo['mode'] == "tunnel6") {
422
					return $idinfo['address']."/128";
423
				} else {
424
					return $idinfo['address']."/255.255.255.255";
425
				}
426
			} else {
427
				return $idinfo['address'];
428
			}
429
			break; /* NOTREACHED */
430
		case "none":
431
		case "network":
432
			return $idinfo['address']."/".gen_subnet_mask($idinfo['netbits']);
433
			break; /* NOTREACHED */
434
		case "mobile":
435
			return "0.0.0.0/0";
436
			break; /* NOTREACHED */
437
		default:
438
			if ($idinfo['mode'] == "tunnel6") {
439
				$address = get_interface_ipv6($idinfo['type']);
440
				$netbits = get_interface_subnetv6($idinfo['type']);
441
				$address = gen_subnetv6($address, $netbits);
442
				return $address."/".$netbits;
443
			} else {
444
				$address = get_interface_ip($idinfo['type']);
445
				$netbits = get_interface_subnet($idinfo['type']);
446
				$address = gen_subnet($address, $netbits);
447
				return $address."/".$netbits;
448
			}
449
			break; /* NOTREACHED */
450
	}
451
}
452

    
453
/*
454
 *  Return phase2 idinfo in text format
455
 */
456
function ipsec_idinfo_to_text(& $idinfo) {
457
	global $config;
458

    
459
	switch ($idinfo['type']) {
460
		case "address":
461
			return $idinfo['address'];
462
			break; /* NOTREACHED */
463
		case "network":
464
			return $idinfo['address']."/".$idinfo['netbits'];
465
			break; /* NOTREACHED */
466
		case "mobile":
467
			return gettext("Mobile Client");
468
			break; /* NOTREACHED */
469
		case "none":
470
			return gettext("None");
471
			break; /* NOTREACHED */
472
		default:
473
			if (!empty($config['interfaces'][$idinfo['type']])) {
474
				return convert_friendly_interface_to_friendly_descr($idinfo['type']);
475
			} else {
476
				return strtoupper($idinfo['type']);
477
			}
478
			break; /* NOTREACHED */
479
	}
480
}
481

    
482
/*
483
 * Return phase1 association for phase2
484
 */
485
function ipsec_lookup_phase1(& $ph2ent, & $ph1ent) {
486
	global $config;
487

    
488
	if (!is_array($config['ipsec'])) {
489
		return false;
490
	}
491
	if (!is_array($config['ipsec']['phase1'])) {
492
		return false;
493
	}
494
	if (empty($config['ipsec']['phase1'])) {
495
		return false;
496
	}
497

    
498
	foreach ($config['ipsec']['phase1'] as $ph1tmp) {
499
		if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
500
			$ph1ent = $ph1tmp;
501
			return $ph1ent;
502
		}
503
	}
504

    
505
	return false;
506
}
507

    
508
/*
509
 * Check phase1 communications status
510
 */
511
function ipsec_phase1_status(&$ipsec_status, $ikeid) {
512

    
513
	foreach ($ipsec_status as $ike) {
514
		if ($ike['id'] == $ikeid) {
515
			if ($ike['status'] == 'established') {
516
				return true;
517
			}
518
		}
519
	}
520

    
521
	return false;
522
}
523

    
524
/*
525
 * Check phase2 communications status
526
 */
527
function ipsec_phase2_status(&$ipsec_status, &$phase2) {
528

    
529
	if (ipsec_lookup_phase1($ph2ent, $ph1ent)) {
530
		return ipsec_phase1_status($ipsec_status, $ph1ent['ikeid']);
531
	}
532

    
533
	return false;
534
}
535

    
536
/*
537
 * Wrapper to call pfSense_ipsec_list_sa() when IPsec is enabled
538
 */
539
function ipsec_list_sa() {
540

    
541
	if (ipsec_enabled()) {
542
		return pfSense_ipsec_list_sa();
543
	}
544

    
545
	return array();
546
}
547

    
548
/*
549
 * Return dump of SPD table
550
 */
551
function ipsec_dump_spd() {
552
	$fd = @popen("/sbin/setkey -DP", "r");
553
	$spd = array();
554
	if ($fd) {
555
		while (!feof($fd)) {
556
			$line = chop(fgets($fd));
557
			if (!$line) {
558
				continue;
559
			}
560
			if ($line == "No SPD entries.") {
561
				break;
562
			}
563
			if ($line[0] != "\t") {
564
				if (is_array($cursp)) {
565
					$spd[] = $cursp;
566
				}
567
				$cursp = array();
568
				$linea = explode(" ", $line);
569
				$cursp['srcid'] = substr($linea[0], 0, strpos($linea[0], "["));
570
				$cursp['dstid'] = substr($linea[1], 0, strpos($linea[1], "["));
571
				$i = 0;
572
			} else if (is_array($cursp)) {
573
				$line = trim($line, "\t\r\n ");
574
				$linea = explode(" ", $line);
575
				switch ($i) {
576
					case 1:
577
						if ($linea[1] == "none")	/* don't show default anti-lockout rule */ {
578
							unset($cursp);
579
						} else {
580
							$cursp['dir'] = $linea[0];
581
						}
582
						break;
583
					case 2:
584
						$upperspec = explode("/", $linea[0]);
585
						$cursp['proto'] = $upperspec[0];
586
						list($cursp['src'], $cursp['dst']) = explode("-", $upperspec[2]);
587
						$cursp['reqid'] = substr($upperspec[3], strpos($upperspec[3], "#")+1);
588
						break;
589
				}
590
			}
591
			$i++;
592
		}
593
		if (is_array($cursp) && count($cursp)) {
594
			$spd[] = $cursp;
595
		}
596
		pclose($fd);
597
	}
598

    
599
	return $spd;
600
}
601

    
602
/*
603
 * Return dump of SAD table
604
 */
605
function ipsec_dump_sad() {
606
	$fd = @popen("/sbin/setkey -D", "r");
607
	$sad = array();
608
	if ($fd) {
609
		while (!feof($fd)) {
610
			$line = chop(fgets($fd));
611
			if (!$line || $line[0] == " ") {
612
				continue;
613
			}
614
			if ($line == "No SAD entries.") {
615
				break;
616
			}
617
			if ($line[0] != "\t") {
618
				if (is_array($cursa)) {
619
					$sad[] = $cursa;
620
				}
621
				$cursa = array();
622
				list($cursa['src'], $cursa['dst']) = explode(" ", $line);
623
			} else {
624
				$line = trim($line, "\t\n\r ");
625
				$linea = explode(" ", $line);
626
				foreach ($linea as $idx => $linee) {
627
					if ($linee == 'esp' || $linee == 'ah' || $linee[0] == '#') {
628
						$cursa['proto'] = $linee;
629
					} else if (substr($linee, 0, 3) == 'spi') {
630
						$cursa['spi'] = substr($linee, strpos($linee, 'x') + 1, -1);
631
					} else if (substr($linee, 0, 5) == 'reqid') {
632
						$cursa['reqid'] = substr($linee, strpos($linee, 'x') + 1, -1);
633
					} else if (substr($linee, 0, 2) == 'E:') {
634
						$cursa['ealgo'] = $linea[$idx + 1];
635
						break;
636
					} else if (substr($linee, 0, 2) == 'A:') {
637
						$cursa['aalgo'] = $linea[$idx + 1];
638
						break;
639
					} else if (substr($linee, 0, 8) == 'current:') {
640
						$cursa['data'] = substr($linea[$idx + 1], 0, strpos($linea[$idx + 1], 'bytes') - 1) . ' B';
641
						break;
642
					}
643
				}
644
			}
645
		}
646
		if (is_array($cursa) && count($cursa)) {
647
			$sad[] = $cursa;
648
		}
649
		pclose($fd);
650
	}
651

    
652
	return $sad;
653
}
654

    
655
/*
656
 * Return dump of mobile user list
657
 */
658
function ipsec_dump_mobile() {
659
	global $g, $config;
660

    
661
	if(!isset($config['ipsec']['client']['enable'])) {
662
		return array();
663
	}
664

    
665
	/* Fetch the pool contents and leases from swanctl. */
666
	$_gb = exec("/usr/local/sbin/swanctl --list-pools --leases 2>/dev/null", $output, $rc);
667

    
668
	if ($rc != 0) {
669
		log_error(gettext("Unable to find IPsec daemon leases file. Could not display mobile user stats!"));
670
		return array();
671
	}
672

    
673
	$response = array(
674
		'pool' => array(),
675
	);
676

    
677
	/* swanctl --list-pools --leases example output, field names can be confirmed by
678
	 * looking at --raw or --pretty output. */
679
	/* mobile-pool          10.7.200.0                          0 / 1 / 254 */
680
	$pool_regex='/^(?P<name>\S+)\s+(?P<base>\S+)\s+(?P<online>\d+) \/ (?P<offline>\d+) \/ (?P<size>\d+)/';
681
	/*   10.7.200.1                     online   'jimp' */
682
	$lease_regex='/\s*(?P<host>[\d\.]+)\s+(?P<status>online|offline)\s+\'(?P<id>.*)\'/';
683
	foreach ($output as $line) {
684
		if (preg_match($pool_regex, $line, $matches)) {
685
			$id++;
686
			$response['pool'][$id] = array(
687
			    'name'   => $matches['name'],
688
			    'base'   => $matches['base'],
689
			    'online' => $matches['online'],
690
			    'offline'  => $matches['offline'],
691
			    'size'   => $matches['size'],
692
			);
693
		} elseif (preg_match($lease_regex, $line, $matches)) {
694
			$response['pool'][$id]['lease'][] = array(
695
			    'host'   => $matches['host'],
696
			    'status' => $matches['status'],
697
			    'id'     => $matches['id']
698
			);
699
		}
700
	}
701

    
702
	unset($_gb, $output, $rc, $pool_regex);
703

    
704
	return $response;
705
}
706

    
707
function ipsec_mobilekey_sort() {
708
	global $config;
709

    
710
	function mobilekeycmp($a, $b) {
711
		return strcmp($a['ident'][0], $b['ident'][0]);
712
	}
713

    
714
	usort($config['ipsec']['mobilekey'], "mobilekeycmp");
715
}
716

    
717
function ipsec_get_number_of_phase2($ikeid) {
718
	global $config;
719
	$a_phase2 = $config['ipsec']['phase2'];
720

    
721
	$nbph2 = 0;
722

    
723
	if (is_array($a_phase2) && count($a_phase2)) {
724
		foreach ($a_phase2 as $ph2tmp) {
725
			if ($ph2tmp['ikeid'] == $ikeid) {
726
				$nbph2++;
727
			}
728
		}
729
	}
730

    
731
	return $nbph2;
732
}
733

    
734
function ipsec_get_descr($ikeid) {
735
	global $config;
736

    
737
	if (!isset($config['ipsec']['phase1']) ||
738
	    !is_array($config['ipsec']['phase1'])) {
739
		return '';
740
	}
741

    
742
	foreach ($config['ipsec']['phase1'] as $p1) {
743
		if ($p1['ikeid'] == $ikeid) {
744
			return $p1['descr'];
745
		}
746
	}
747

    
748
	return '';
749
}
750

    
751
function ipsec_get_phase1($ikeid) {
752
		global $config;
753

    
754
		if (!isset($config['ipsec']['phase1']) ||
755
		    !is_array($config['ipsec']['phase1'])) {
756
			return '';
757
		}
758

    
759
		$a_phase1 = $config['ipsec']['phase1'];
760
		foreach ($a_phase1 as $p1) {
761
			if ($p1['ikeid'] == $ikeid) {
762
				return $p1;
763
			}
764
		}
765
		unset($a_phase1);
766
}
767

    
768
function ipsec_fixup_ip($ipaddr) {
769
	if (is_ipaddrv6($ipaddr) || is_subnetv6($ipaddr)) {
770
		return text_to_compressed_ip6($ipaddr);
771
	} else {
772
		return $ipaddr;
773
	}
774
}
775

    
776
function ipsec_find_id(& $ph1ent, $side = "local", $rgmap = array()) {
777
	if ($side == "local") {
778
		$id_type = $ph1ent['myid_type'];
779
		$id_data = $ph1ent['myid_data'];
780

    
781
		$addr = ipsec_get_phase1_src($ph1ent);
782
		if (!$addr) {
783
			return array();
784
		}
785
		/* When automatically guessing, use the first address. */
786
		$addr = explode(',', $addr);
787
		$addr = $addr[0];
788
	} elseif ($side == "peer") {
789
		$id_type = $ph1ent['peerid_type'];
790
		$id_data = $ph1ent['peerid_data'];
791

    
792
		if (isset($ph1ent['mobile'])) {
793
			$addr = "%any";
794
		} else {
795
			$addr = $ph1ent['remote-gateway'];
796
		}
797
	} else {
798
		return array();
799
	}
800

    
801

    
802
	$thisid_type = $id_type;
803
	switch ($thisid_type) {
804
		case 'myaddress':
805
			$thisid_type = 'address';
806
			$thisid_data = $addr;
807
			break;
808
		case 'dyn_dns':
809
			$thisid_type = 'dns';
810
			$thisid_data = $id_data;
811
			break;
812
		case 'peeraddress':
813
			$thisid_type = 'address';
814
			$thisid_data = $rgmap[$ph1ent['remote-gateway']];
815
			break;
816
		case 'address':
817
			$thisid_data = $id_data;
818
			break;
819
		case 'fqdn':
820
			$thisid_data = "{$id_data}";
821
			break;
822
		case 'keyid tag':
823
			$thisid_type = 'keyid';
824
			$thisid_data = "{$id_data}";
825
			break;
826
		case 'user_fqdn':
827
			$thisid_type = 'userfqdn';
828
			$thisid_data = "{$id_data}";
829
			break;
830
		case 'asn1dn':
831
			$thisid_data = $id_data;
832
			break;
833
	}
834
	return array($thisid_type, $thisid_data);
835
}
836

    
837
/*
838
 * Fixup ID type/data to include prefix when necessary, add quotes, etc.
839
 */
840
function ipsec_fixup_id($type, $data) {
841
	/* List of types to pass through as-is without changes or adding prefix */
842
	$auto_types = array('address');
843
	/* List of types which need the resulting string double quoted. */
844
	$quote_types = array('keyid', 'asn1dn');
845

    
846
	/* If the first character of asn1dn type data is not #, then rely on
847
	 * automatic parsing https://redmine.pfsense.org/issues/4792 */
848
	if (($type == 'asn1dn') && !empty($data) && ($data[0] != '#')) {
849
		$auto_types[] = 'asn1dn';
850
	}
851

    
852
	if ($type == 'any') {
853
		$idstring = "";
854
	} elseif (!in_array($type, $auto_types)) {
855
		$idstring = "{$type}:{$data}";
856
	} else {
857
		$idstring = $data;
858
	}
859

    
860
	if (in_array($type, $quote_types)) {
861
		$idstring = "\"{$idstring}\"";
862
	}
863

    
864
	return $idstring;
865
}
866

    
867
function ipsec_fixup_network($network) {
868
	if (substr($network, -3) == '|/0') {
869
		$result = substr($network, 0, -3);
870
	} else {
871
		$tmp = explode('|', $network);
872
		if (isset($tmp[1])) {
873
			$result = $tmp[1];
874
		} else {
875
			$result = $tmp[0];
876
		}
877
		unset($tmp);
878
	}
879

    
880
	return $result;
881
}
882

    
883
function ipsec_new_reqid() {
884
	global $config;
885

    
886
	if (!is_array($config['ipsec']) || !is_array($config['ipsec']['phase2'])) {
887
		return;
888
	}
889

    
890
	$ipsecreqid = lock('ipsecreqids', LOCK_EX);
891
	$keyids = array();
892
	$keyid = 1;
893
	foreach ($config['ipsec']['phase2'] as $ph2) {
894
		$keyids[$ph2['reqid']] = $ph2['reqid'];
895
	}
896

    
897
	for ($i = 1; $i < 16000; $i++) {
898
		if (!isset($keyids[$i])) {
899
			$keyid = $i;
900
			break;
901
		}
902
	}
903
	unlock($ipsecreqid);
904

    
905
	return $keyid;
906
}
907

    
908
function ipsec_get_loglevels() {
909
	global $config, $ipsec_log_cats;
910
	$def_loglevel = '1';
911

    
912
	$levels = array();
913

    
914
	foreach (array_keys($ipsec_log_cats) as $cat) {
915
		if (isset($config['ipsec']['logging'][$cat])) {
916
			$levels[$cat] = $config['ipsec']['logging'][$cat];
917
		} elseif (in_array($cat, array('ike', 'chd', 'cfg'))) {
918
			$levels[$cat] = "2";
919
		} else {
920
			$levels[$cat] = $def_loglevel;
921
		}
922
	}
923
	return $levels;
924
}
925

    
926
function ipsec_vti($ph1ent, $returnaddresses = false, $skipdisabled = true) {
927
	global $config;
928
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
929
		return false;
930
	}
931

    
932
	$is_vti = false;
933
	$vtisubnet_spec = array();
934

    
935
	foreach ($config['ipsec']['phase2'] as $ph2ent) {
936
		if ($ph1ent['ikeid'] != $ph2ent['ikeid']) {
937
			continue;
938
		}
939
		if ($ph2ent['mode'] == 'vti') {
940
			if ($returnaddresses) {
941
				$vtisubnet_spec[] = array(
942
					'left' => ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']),
943
					'right' => ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']),
944
					'descr' => $ph2ent['descr'],
945
				);
946
			}
947
			if (!$skipdisabled && isset($ph2ent['disabled'])) {
948
				continue;
949
			} else {
950
				$is_vti = true;
951
			}
952
		}
953
	}
954
	return ($returnaddresses) ? $vtisubnet_spec : $is_vti;
955
}
956

    
957
/* Called when IPsec is reloaded through rc.newipsecdns and similar, gives
958
 * packages an opportunity to execute custom code when IPsec reloads.
959
 */
960
function ipsec_reload_package_hook() {
961
	global $g, $config;
962

    
963
	init_config_arr(array('installedpackages', 'package'));
964
	foreach ($config['installedpackages']['package'] as $package) {
965
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
966
			continue;
967
		}
968

    
969
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
970
		if (!empty($pkg_config['include_file']) &&
971
		    file_exists($pkg_config['include_file'])) {
972
			require_once($pkg_config['include_file']);
973
		}
974
		if (empty($pkg_config['ipsec_reload_function'])) {
975
			continue;
976
		}
977
		$pkg_ipsec_reload = $pkg_config['ipsec_reload_function'];
978
		if (!function_exists($pkg_ipsec_reload)) {
979
			continue;
980
		}
981
		$pkg_ipsec_reload();
982
	}
983
}
984

    
985
/****f* certs/ipsec_convert_to_modp
986
 * NAME
987
 *   ipsec_convert_to_modp - Take a DH Group number value and return the
988
 *                           associated name
989
 * INPUTS
990
 *   $index: DH group index number to look up
991
 * RESULT
992
 *   Returns the Diffie Hellman Group keyword associated with the group number.
993
 ******/
994
function ipsec_convert_to_modp($index) {
995
	$modpmap = array(
996
		'1' => 'modp768',
997
		'2' => 'modp1024',
998
		'5' => 'modp1536',
999
		'14' => 'modp2048',
1000
		'15' => 'modp3072',
1001
		'16' => 'modp4096',
1002
		'17' => 'modp6144',
1003
		'18' => 'modp8192',
1004
		'19' => 'ecp256',
1005
		'20' => 'ecp384',
1006
		'21' => 'ecp521',
1007
		'22' => 'modp1024s160',
1008
		'23' => 'modp2048s224',
1009
		'24' => 'modp2048s256',
1010
		'25' => 'ecp192',
1011
		'26' => 'ecp224',
1012
		'27' => 'ecp224bp',
1013
		'28' => 'ecp256bp',
1014
		'29' => 'ecp384bp',
1015
		'30' => 'ecp512bp',
1016
		'31' => 'curve25519',
1017
		'32' => 'curve448',
1018
	);
1019

    
1020
	return $modpmap[$index];
1021
}
1022

    
1023
/*
1024
 * Forcefully restart IPsec
1025
 * This is required for when dynamic interfaces reload
1026
 * For all other occasions the normal ipsec_configure()
1027
 * will gracefully reload the settings without restarting
1028
 */
1029
function ipsec_force_reload($interface = "") {
1030
	global $g, $config;
1031

    
1032
	if (!ipsec_enabled()) {
1033
		return;
1034
	}
1035

    
1036
	$ipseccfg = $config['ipsec'];
1037

    
1038
	if (!empty($interface) && is_array($ipseccfg['phase1'])) {
1039
		$found = false;
1040
		foreach ($ipseccfg['phase1'] as $ipsec) {
1041
			if (!isset($ipsec['disabled']) && ($ipsec['interface'] == $interface)) {
1042
				$found = true;
1043
				break;
1044
			}
1045
		}
1046
		if (!$found) {
1047
			log_error(sprintf(gettext("Ignoring IPsec reload since there are no tunnels on interface %s"), $interface));
1048
			return;
1049
		}
1050
	}
1051

    
1052
	/* If we get this far then we need to take action. */
1053
	log_error(gettext("Forcefully reloading IPsec"));
1054
	ipsec_configure();
1055
}
1056

    
1057
/****f* ipsec/ipsec_strongswan_confgen
1058
 * NAME
1059
 *   ipsec_strongswan_confgen - Generate strongswan.conf style formatted output
1060
 *                              From a multi-dimensional array.
1061
 * INPUTS
1062
 *   $confarr: An array of key=value pairs or key=array entries for subsections.
1063
 *   $indent : A string of tabs used when indenting lines.
1064
 * RESULT
1065
 *   Returns a string of key=value pairs with proper indenting, and with named
1066
 *   subsections enclosed in braces.
1067
 * NOTES
1068
 *   Values starting with a "#" (comments) or "include " will be printed
1069
 *   directly without their associated key name.
1070
 ******/
1071
function ipsec_strongswan_confgen($confarr, $indent = "") {
1072
	$confstr = "";
1073
	/* Only process the contents if it's an array. */
1074
	if (is_array($confarr)) {
1075
		foreach ($confarr as $key => $value) {
1076
			if (is_array($value)) {
1077
				/* If the array is empty, do not print anything */
1078
				if (empty($value)) {
1079
					continue;
1080
				}
1081
				/* If this is an array, setup the subsection name
1082
				 * and structure, then call this function
1083
				 * recursively to walk the lower array. */
1084
				$confstr .= "{$indent}{$key} {\n";
1085
				$confstr .= ipsec_strongswan_confgen($value, $indent . "\t");
1086
				$confstr .= "{$indent}}\n";
1087
			} else {
1088
				$confstr .= "{$indent}";
1089
				if ((substr($value, 0 , 1) != '#') &&
1090
				    (substr($value, 0 , 8) != 'include ')) {
1091
					/* Not a comment or include, print the key */
1092
					$confstr .= "{$key} = ";
1093
				}
1094
				$confstr .= "{$value}\n";
1095
			}
1096
		}
1097
	}
1098
	return $confstr;
1099
}
1100

    
1101
global $g, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs;
1102
$ipsec_swanctl_basedir = "{$g['varetc_path']}/ipsec";
1103
$ipsec_swanctl_dirs = array(
1104
	'conf'     => "{$ipsec_swanctl_basedir}/conf.d",
1105
	'certpath' => "{$ipsec_swanctl_basedir}/x509",
1106
	'capath'   => "{$ipsec_swanctl_basedir}/x509ca",
1107
	'aapath'   => "{$ipsec_swanctl_basedir}/x509aa",
1108
	'ocsppath' => "{$ipsec_swanctl_basedir}/x509ocsp",
1109
	'crlpath'  => "{$ipsec_swanctl_basedir}/x509crl",
1110
	'acpath'   => "{$ipsec_swanctl_basedir}/x509ac",
1111
	'rsakeys'  => "{$ipsec_swanctl_basedir}/rsa",
1112
	'eckeys'   => "{$ipsec_swanctl_basedir}/ecdsa",
1113
	'keypath'  => "{$ipsec_swanctl_basedir}/private",
1114
	'pubkpath' => "{$ipsec_swanctl_basedir}/pubkey",
1115
	'blisspath' => "{$ipsec_swanctl_basedir}/bliss",
1116
	'pkcs8path' => "{$ipsec_swanctl_basedir}/pkcs8",
1117
	'pkcs12path' => "{$ipsec_swanctl_basedir}/pkcs12",
1118
);
1119

    
1120
/****f* ipsec/ipsec_create_dirs
1121
 * NAME
1122
 *   ipsec_create_dirs - Create default set of strongSwan configuration directories.
1123
 * INPUTS
1124
 *   None
1125
 * RESULT
1126
 *   Cleans up and creates strongSwan configuration directories and links.
1127
 ******/
1128
function ipsec_create_dirs() {
1129
	global $config, $g, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs;
1130

    
1131
	/* Cleanup base paths to ensure old files are not left behind (#5238) */
1132
	if (!empty($ipsec_swanctl_basedir)) {
1133
		@rmdir_recursive($ipsec_swanctl_basedir, false);
1134
	}
1135
	/* Create directory structure */
1136
	array_map('safe_mkdir', array_values($ipsec_swanctl_dirs));
1137

    
1138
	/* Create and link strongSwan config */
1139
	$ssdpath = "{$g['varetc_path']}/ipsec/strongswan.d";
1140
	if (!file_exists($ssdpath) || !is_link($ssdpath)) {
1141
		if (is_dir($ssdpath) && !is_link($ssdpath)) {
1142
			@rmdir_recursive($ssdpath, false);
1143
		} else {
1144
			@unlink($ssdpath);
1145
		}
1146
		@symlink("/usr/local/etc/strongswan.d",
1147
		    $ssdpath);
1148
	}
1149
	if (!file_exists("/usr/local/etc/strongswan.conf") ||
1150
	    !is_link("/usr/local/etc/strongswan.conf")) {
1151
		@unlink("/usr/local/etc/strongswan.conf");
1152
		@symlink("{$g['varetc_path']}/ipsec/strongswan.conf",
1153
		    "/usr/local/etc/strongswan.conf");
1154
	}
1155
}
1156

    
1157
/****f* ipsec/ipsec_setup_gwifs
1158
 * NAME
1159
 *   ipsec_setup_gwifs - Setup IPsec-related interfaces and gateways
1160
 * INPUTS
1161
 *   None
1162
 * RESULT
1163
 *   Sets up VTI interfaces and gateways, populates ipsecpinghosts
1164
 ******/
1165
function ipsec_setup_gwifs() {
1166
	global $g, $a_phase1, $a_phase2, $rgmap, $filterdns_list,
1167
		$aggressive_mode_psk, $mobile_ipsec_auth, $ifacesuse,
1168
		$ipsecpinghostsactive;
1169
	/* resolve all local, peer addresses and setup pings */
1170
	unset($iflist);
1171
	if (is_array($a_phase1) && count($a_phase1)) {
1172
		$ipsecpinghosts = array();
1173
		/* step through each phase1 entry */
1174
		foreach ($a_phase1 as $ph1ent) {
1175
			if (isset($ph1ent['disabled'])) {
1176
				continue;
1177
			}
1178

    
1179
			if (substr($ph1ent['interface'], 0, 4) == "_vip") {
1180
				$vpninterface = get_configured_vip_interface($ph1ent['interface']);
1181
				$ifacesuse[] = get_real_interface($vpninterface);
1182
			} else {
1183
				$vpninterface = get_failover_interface($ph1ent['interface']);
1184
				if (substr($vpninterface, 0, 4) == "_vip") {
1185
					$vpninterface = get_configured_vip_interface($vpninterface);
1186
					$ifacesuse[] = get_real_interface($vpninterface);
1187
				} elseif (!empty($vpninterface)) {
1188
					$ifacesuse[] = $vpninterface;
1189
				}
1190
			}
1191

    
1192
			if ($ph1ent['mode'] == "aggressive" && ($ph1ent['authentication_method'] == "pre_shared_key" || $ph1ent['authentication_method'] == "xauth_psk_server")) {
1193
				$aggressive_mode_psk = true;
1194
			}
1195

    
1196
			$ikeid = $ph1ent['ikeid'];
1197

    
1198
			$local_spec = ipsec_get_phase1_src($ph1ent);
1199
			/* When automatically guessing, use the first address. */
1200
			$local_spec  = explode(',', $local_spec);
1201
			$local_spec  = $local_spec[0];
1202
			if (!is_ipaddr($local_spec)) {
1203
				log_error(sprintf(gettext("IPsec ERROR: Could not find phase 1 source for connection %s. Omitting from configuration file."), $ph1ent['descr']));
1204
				continue;
1205
			}
1206

    
1207
			if (isset($ph1ent['mobile'])) {
1208
				$mobile_ipsec_auth = $ph1ent['authentication_method'];
1209
				continue;
1210
			}
1211

    
1212
			/* see if this tunnel has a hostname for the remote-gateway. If so,
1213
			   try to resolve it now and add it to the list for filterdns */
1214
			$rg = $ph1ent['remote-gateway'];
1215
			if (!is_ipaddr($rg)) {
1216
				$filterdns_list[] = "{$rg}";
1217
				add_hostname_to_watch($rg);
1218
				if (!platform_booting()) {
1219
					$rg = resolve_retry($rg, $ph1ent['protocol']);
1220
				}
1221
				if (!is_ipaddr($rg)) {
1222
					continue;
1223
				}
1224
			}
1225
			if (array_search($rg, $rgmap)) {
1226
				log_error(sprintf(gettext("The remote gateway %s already exists on another phase 1 entry"), $rg));
1227
				continue;
1228
			}
1229
			$rgmap[$ph1ent['remote-gateway']] = $rg;
1230

    
1231
			$is_vti = false;
1232
			if (is_array($a_phase2)) {
1233
				/* step through each phase2 entry */
1234
				foreach ($a_phase2 as $ph2ent) {
1235
					if ($ph2ent['mode'] == 'vti') {
1236
						$is_vti = true;
1237
					}
1238
					if (isset($ph2ent['disabled']) || ($ikeid != $ph2ent['ikeid'])) {
1239
						continue;
1240
					}
1241

    
1242
					/* add an ipsec pinghosts entry */
1243
					if ($ph2ent['pinghost']) {
1244
						if (!is_array($iflist)) {
1245
							$iflist = get_configured_interface_list();
1246
						}
1247
						$srcip = null;
1248
						$local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']);
1249
						if (is_ipaddrv6($ph2ent['pinghost'])) {
1250
							foreach ($iflist as $ifent => $ifname) {
1251
								$interface_ip = get_interface_ipv6($ifent);
1252
								if (!is_ipaddrv6($interface_ip)) {
1253
									continue;
1254
								}
1255
								if (ip_in_subnet($interface_ip, $local_subnet)) {
1256
									$srcip = $interface_ip;
1257
									break;
1258
								}
1259
							}
1260
						} else {
1261
							foreach ($iflist as $ifent => $ifname) {
1262
								$interface_ip = get_interface_ip($ifent);
1263
								if (!is_ipaddrv4($interface_ip)) {
1264
									continue;
1265
								}
1266
								if ($local_subnet == "0.0.0.0/0" || ip_in_subnet($interface_ip, $local_subnet)) {
1267
									$srcip = $interface_ip;
1268
									break;
1269
								}
1270
							}
1271
						}
1272
						/* if no valid src IP was found in configured interfaces, try the vips */
1273
						if (is_null($srcip)) {
1274
							$viplist = get_configured_vip_list();
1275
							foreach ($viplist as $vip => $address) {
1276
								if (ip_in_subnet($address, $local_subnet)) {
1277
									$srcip = $address;
1278
									break;
1279
								}
1280
							}
1281
						}
1282
						$dstip = $ph2ent['pinghost'];
1283
						$family = "inet" . (is_ipaddrv6($dstip)) ? "6" : "";
1284
						if (is_ipaddr($srcip)) {
1285
							$ipsecpinghosts[] = "{$srcip}|{$dstip}|3|||||{$family}|\n";
1286
							$ipsecpinghostsactive = true;
1287
						}
1288
					}
1289
				}
1290
			}
1291
			if ($is_vti) {
1292
				interface_ipsec_vti_configure($ph1ent);
1293
			}
1294
		}
1295
		@file_put_contents("{$g['vardb_path']}/ipsecpinghosts", $ipsecpinghosts);
1296
		unset($ipsecpinghosts);
1297
	}
1298
	unset($iflist);
1299
}
1300

    
1301
/****f* ipsec/ipsec_logging_config
1302
 * NAME
1303
 *   ipsec_logging_config - Generate an array containing strongSwan logging
1304
 *                          values.
1305
 * INPUTS
1306
 *   None
1307
 * RESULT
1308
 *   Returns an array which can be merged into the strongswan daemon logging
1309
 *   values so that each logging category is represented, even those not listed
1310
 *   in config.xml.
1311
 ******/
1312
function ipsec_logging_config() {
1313
	global $config, $ipsec_log_cats, $ipsec_log_sevs;
1314
	$logcfg = array();
1315
	$log_levels = ipsec_get_loglevels();
1316
	foreach (array_keys($ipsec_log_cats) as $cat) {
1317
		if (is_numeric($log_levels[$cat]) &&
1318
		    in_array(intval($log_levels[$cat]), array_keys($ipsec_log_sevs), true)) {
1319
			$logcfg[$cat] = $log_levels[$cat];
1320
		}
1321
	}
1322
	return $logcfg;
1323
}
1324

    
1325
/****f* ipsec/ipsec_setup_strongswan
1326
 * NAME
1327
 *   ipsec_setup_strongswan - Generate the strongswan.conf configuration file.
1328
 * INPUTS
1329
 *   None
1330
 * RESULT
1331
 *   Determines strongswan.conf values and crafts the configuration file in the
1332
 *   appropriate format.
1333
 * NOTES
1334
 *   Called from ipsec_configure()
1335
 ******/
1336
function ipsec_setup_strongswan() {
1337
	global $config, $g, $mobile_ipsec_auth, $a_client, $a_phase2, $aggressive_mode_psk, $ifacesuse;
1338

    
1339
	/* strongswan.conf array */
1340
	$ssconf = array();
1341
	$ssconf[] = "# Automatically generated config file - DO NOT MODIFY. Changes will be overwritten.";
1342
	$ssconf['starter'] = array();
1343
	$ssconf['starter']['load_warning'] = "no";
1344

    
1345
	$ssconf['charon'] = array();
1346
	$ssconf['charon'][] = '# number of worker threads in charon';
1347
	$ssconf['charon']['threads'] = '16';
1348
	$ssconf['charon']['ikesa_table_size'] = '32';
1349
	$ssconf['charon']['ikesa_table_segments'] = '4';
1350
	$ssconf['charon']['init_limit_half_open'] = '1000';
1351
	$ssconf['charon']['install_routes'] = 'no';
1352
	$ssconf['charon']['load_modular'] = 'yes';
1353
	$ssconf['charon']['ignore_acquire_ts'] = 'yes';
1354

    
1355
	if ($aggressive_mode_psk) {
1356
		$stronconf = '';
1357
		if (file_exists("{$g['varetc_path']}/ipsec/strongswan.conf")) {
1358
			$stronconf = file_get_contents("{$g['varetc_path']}/ipsec/strongswan.conf");
1359
		}
1360
		log_error("WARNING: Setting i_dont_care_about_security_and_use_aggressive_mode_psk option because a phase 1 is configured using aggressive mode with pre-shared keys. This is not a secure configuration.");
1361
		$restart = (!empty($stronconf) && strpos($stronconf, 'i_dont_care_about_security_and_use_aggressive_mode_psk') === FALSE);
1362
		unset($stronconf);
1363
		$ssconf['charon']['i_dont_care_about_security_and_use_aggressive_mode_psk'] = "yes";
1364
	}
1365

    
1366
	if (isset($config['ipsec']['acceptunencryptedmainmode'])) {
1367
		$ssconf['charon']['accept_unencrypted_mainmode_messages'] = "yes";
1368
	}
1369

    
1370
	$unity_enabled = isset($config['ipsec']['unityplugin']) ? 'yes' : 'no';
1371
	$ssconf['charon']['cisco_unity'] = $unity_enabled;
1372

    
1373
	if (isset($config['ipsec']['enableinterfacesuse']) && !empty($ifacesuse)) {
1374
		$ssconf['charon']['interfaces_use'] = implode(',', array_unique($ifacesuse));
1375
	}
1376

    
1377
	if (isset($config['ipsec']['makebeforebreak'])) {
1378
		$ssconf['charon']['make_before_break'] = "yes";
1379
	}
1380

    
1381
	$ssconf['charon']['syslog'] = array();
1382
	$ssconf['charon']['syslog']['identifier'] = 'charon';
1383
	$ssconf['charon']['syslog'][] = "# log everything under daemon since it ends up in the same place regardless with our syslog.conf";
1384
	$ssconf['charon']['syslog']['daemon'] = array();
1385
	$ssconf['charon']['syslog']['daemon']['ike_name'] = 'yes';
1386
	$ssconf['charon']['syslog']['daemon'] = array_merge($ssconf['charon']['syslog']['daemon'], ipsec_logging_config());
1387
	$ssconf['charon']['syslog'][] = '# disable logging under auth so logs aren\'t duplicated';
1388
	$ssconf['charon']['syslog']['auth'] = array();
1389
	$ssconf['charon']['syslog']['auth']['default'] = -1;
1390

    
1391
	$ssconf['charon']['plugins'] = array();
1392
	$ssconf['charon']['plugins'][] = "# Load defaults";
1393
	$ssconf['charon']['plugins'][] = "include {$g['varetc_path']}/ipsec/strongswan.d/charon/*.conf";
1394
	$ssconf['charon']['plugins']['unity'] = array('load' => $unity_enabled);
1395
	$ssconf['charon']['plugins']['curve25519'] = array('load' => "yes");
1396

    
1397
	$ssconf['charon']['plugins']['pkcs11'] = array();
1398
	$ssconf['charon']['plugins']['pkcs11']['load'] = "yes";
1399
	$ssconf['charon']['plugins']['pkcs11']['modules'] = array();
1400
	$ssconf['charon']['plugins']['pkcs11']['modules']['opensc'] = array();
1401
	$ssconf['charon']['plugins']['pkcs11']['modules']['opensc']['load_certs'] = "yes";
1402
	$ssconf['charon']['plugins']['pkcs11']['modules']['opensc']['path'] = "/usr/local/lib/opensc-pkcs11.so";
1403

    
1404
	/* Find RADIUS servers designated for Mobile IPsec user auth */
1405
	$radius_servers = array();
1406
	foreach (explode(',', $config['ipsec']['client']['user_source']) as $user_source) {
1407
		$auth_server = auth_get_authserver($user_source);
1408
		$nice_user_source = strtolower(preg_replace('/[\s\.]+/', '_', $user_source));
1409
		if ($auth_server && ($auth_server['type'] === 'radius')) {
1410
			$radius_servers[$nice_user_source] = array();
1411
			$radius_servers[$nice_user_source]['address'] = $auth_server['host'];
1412
			$radius_servers[$nice_user_source]['secret'] = "\"{$auth_server['radius_secret']}\"";
1413
			$radius_servers[$nice_user_source]['auth_port'] = empty($auth_server['radius_auth_port']) ? 1812 : $auth_server['radius_auth_port'];;
1414
			$radius_servers[$nice_user_source]['acct_port'] = empty($auth_server['radius_acct_port']) ? 1813 : $auth_server['radius_acct_port'];
1415
		}
1416
	}
1417

    
1418
	/* Generate an eap-radius config section if appropriate */
1419
	if (count($radius_servers) && ($mobile_ipsec_auth === "eap-radius")) {
1420
		$ssconf['charon']['plugins']['eap-radius'] = array();
1421
		$ssconf['charon']['plugins']['eap-radius']['load'] = "2";
1422
		$ssconf['charon']['plugins']['eap-radius']['class_group'] = "yes";
1423
		$ssconf['charon']['plugins']['eap-radius']['eap_start'] = "no";
1424
		/* Activate RADIUS accounting only if it was selected on the IPsec Mobile Clients tab */
1425
		if ($auth_server && isset($auth_server['radius_acct_port']) &&
1426
		    (is_array($a_client) && ($a_client['radiusaccounting'] == "enabled"))){
1427
			$ssconf['charon']['plugins']['eap-radius']['accounting'] = "yes";
1428
			$ssconf['charon']['plugins']['eap-radius']['accounting_close_on_timeout'] = "no";
1429
		}
1430
		$ssconf['charon']['plugins']['eap-radius']['servers'] = $radius_servers;
1431
	}
1432

    
1433
	if (is_array($a_client) && isset($a_client['enable'])) {
1434
		if ($a_client['user_source'] != "none") {
1435
			$ssconf['charon']['plugins']['xauth-generic'] = array();
1436
			$ssconf['charon']['plugins']['xauth-generic']['script'] = "/etc/inc/ipsec.auth-user.php";
1437
			$authcfgs = array();
1438
			foreach (explode(",", $a_client['user_source']) as $authcfg) {
1439
				$authcfgs[] = ($authcfg == "system") ? "Local Database" : $authcfg;
1440
			}
1441
			$ssconf['charon']['plugins']['xauth-generic']['authcfg'] = implode(",", $authcfgs);
1442
		}
1443
	}
1444

    
1445
	@file_put_contents("{$g['varetc_path']}/ipsec/strongswan.conf", ipsec_strongswan_confgen($ssconf));
1446
}
1447

    
1448
/****f* ipsec/ipsec_setup_pools
1449
 * NAME
1450
 *   ipsec_setup_pools - Generate primary mobile pool configuration for swanctl
1451
  * INPUTS
1452
 *   None
1453
 * RESULT
1454
 *   Adds configured mobile pool settings to $scconf
1455
 * NOTES
1456
 *   These values were formerly in strongswan.conf but may now be configured in
1457
 *   pools, making future expansion to support multiple pools possible.
1458
 ******/
1459
function ipsec_setup_pools() {
1460
	global $config, $g, $mobile_ipsec_auth, $a_client, $a_phase2, $scconf;
1461
	if (!is_array($a_client) || !isset($a_client['enable'])) {
1462
		return;
1463
	}
1464
	if (($mobile_ipsec_auth == "eap-radius") && empty($a_client['pool_address']) &&
1465
	    empty($a_client['pool_address_v6'])) {
1466
		return;
1467
	}
1468
	$scconf['pools']['mobile-pool'] = array();
1469

    
1470
	$pool_addrs = array();
1471
	if (!empty($a_client['pool_address'])) {
1472
		$pool_addrs[] = "{$a_client['pool_address']}/{$a_client['pool_netbits']}";
1473
	}
1474
	if (!empty($a_client['pool_address_v6'])) {
1475
		$pool_addrs[] = "{$a_client['pool_address_v6']}/{$a_client['pool_netbits_v6']}";
1476
	}
1477
	if (count($pool_addrs)) {
1478
		$scconf['pools']['mobile-pool']['addrs'] = implode(',', $pool_addrs);
1479
	}
1480

    
1481
	$rightdnsservers = array();
1482
	if (!empty($a_client['dns_server1'])) {
1483
		$rightdnsservers[] = $a_client['dns_server1'];
1484
	}
1485
	if (!empty($a_client['dns_server2'])) {
1486
		$rightdnsservers[] = $a_client['dns_server2'];
1487
	}
1488
	if (!empty($a_client['dns_server3'])) {
1489
		$rightdnsservers[] = $a_client['dns_server3'];
1490
	}
1491
	if (!empty($a_client['dns_server4'])) {
1492
		$rightdnsservers[] = $a_client['dns_server4'];
1493
	}
1494
	if (count($rightdnsservers)) {
1495
		$scconf['pools']['mobile-pool']['dns'] = implode(',', $rightdnsservers);
1496
	}
1497

    
1498
	$cfgservers = array();
1499
	if (!empty($a_client['wins_server1'])) {
1500
		$cfgservers[] = $a_client['wins_server1'];
1501
	}
1502
	if (!empty($a_client['wins_server2'])) {
1503
		$cfgservers[] = $a_client['wins_server2'];
1504
	}
1505
	if (!empty($cfgservers)) {
1506
		$scconf['pools']['mobile-pool']['nbns'] = implode(",", $cfgservers);
1507
	}
1508
	unset($cfgservers);
1509

    
1510
	if (isset($a_client['net_list']) && is_array($a_phase2)) {
1511
		$net_list = array();
1512
		foreach ($a_phase2 as $ph2ent) {
1513
			if (isset($ph2ent['disabled']) ||
1514
			    !isset($ph2ent['mobile'])) {
1515
				continue;
1516
			}
1517
			$net_list[] = ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']);
1518
		}
1519
		if (!empty($net_list)) {
1520
			$scconf['pools']['mobile-pool']['subnet'] = implode(",", $net_list);
1521
			$scconf['pools']['mobile-pool']['split_include'] = implode(",", $net_list);
1522
			unset($net_list);
1523
		}
1524
	}
1525
	if (!empty($a_client['dns_domain'])) {
1526
		$scconf['pools']['mobile-pool'][] = "# Search domain and default domain";
1527
		$scconf['pools']['mobile-pool']['28674'] = "\"{$a_client['dns_domain']}\"";
1528
		if (empty($a_client['dns_split'])) {
1529
			$scconf['pools']['mobile-pool']['28675'] = "\"{$a_client['dns_domain']}\"";
1530
		}
1531
	}
1532

    
1533
	if (!empty($a_client['dns_split'])) {
1534
		$scconf['pools']['mobile-pool']['28675'] = "\"{$a_client['dns_split']}\"";
1535
	}
1536

    
1537
	if (!empty($a_client['login_banner'])) {
1538
		$scconf['pools']['mobile-pool']['28672'] = "\"{$a_client['login_banner']}\"";
1539
	}
1540

    
1541
	if (isset($a_client['save_passwd'])) {
1542
		$scconf['pools']['mobile-pool']['28673'] = "1";
1543
	}
1544

    
1545
	if ($a_client['pfs_group']) {
1546
		$scconf['pools']['mobile-pool']['28679'] = "\"{$a_client['pfs_group']}\"";
1547
	}
1548

    
1549
	return;
1550
}
1551

    
1552
/****f* ipsec/ipsec_setup_userpools
1553
 * NAME
1554
 *   ipsec_setup_userpools - Generate per-user custom pool settings for swanctl
1555
  * INPUTS
1556
 *   None
1557
 * RESULT
1558
 *   Adds configured per-user pool settings to $scconf using the primary mobile
1559
 *   pool as a base configuration.
1560
 * NOTES
1561
 *   Given this new flexible format, it is now possible to override any valid
1562
 *   pool setting, so future expansion of per-user settings is possible.
1563
 ******/
1564
function ipsec_setup_userpools() {
1565
	global $config, $scconf;
1566
	$a_mobilekey = $config['ipsec']['mobilekey'];
1567

    
1568
	/* Do not waste time if we do not have all the necessary information. */
1569
	if (!is_array($a_mobilekey) ||
1570
	    empty($a_mobilekey) ||
1571
	    !is_array($scconf['connections']) ||
1572
	    !is_array($scconf['connections']['con-mobile']) ||
1573
	    !is_array($scconf['pools']) ||
1574
	    !is_array($scconf['pools']['mobile-pool'])) {
1575
		return;
1576
	}
1577

    
1578
	$suffix = 1;
1579
	foreach ($a_mobilekey as $mkent) {
1580
		if (($mkent['type'] != "EAP") ||
1581
		    !isset($mkent['ident_type']) ||
1582
		    !isset($mkent['pool_address']) ||
1583
		    !isset($mkent['pool_netbits']) ||
1584
		    (strlen($mkent['pool_address']) < 1) ||
1585
		    !is_ipaddr($mkent['pool_address'])) {
1586
			continue;
1587
		}
1588
		/* The name of just this pool */
1589
		$upbase = "mobile-userpool-{$suffix}";
1590
		/* The full connection name including a reference to the primary
1591
		 * mobile connection */
1592
		$upconn = "con-{$upbase} : con-mobile";
1593
		/* The full pool name including a reference to the primary
1594
		 * mobile pool */
1595
		$upname = "{$upbase} : mobile-pool";
1596

    
1597
		$scconf['connections'][$upconn] = array();
1598
		$scconf['pools'][$upname] = array();
1599

    
1600
		$clientid = ($mkent['ident_type'] == "none") ? "\"{$mkent['ident']}\"" : "{$mkent['ident_type']}:{$mkent['ident']}";
1601
		$clienteapid = ($ph1ent['authentication_method'] == "eap-mschapv2") ? $clientid : '%any';
1602

    
1603
		/* Craft a cloned connection with the ID information to match */
1604
		$scconf['connections'][$upconn]['remote'] = array();
1605
		$scconf['connections'][$upconn]['remote']['id'] = $clientid;
1606
		$scconf['connections'][$upconn]['remote']['eap_id'] = $clienteapid;
1607
		$scconf['connections'][$upconn]['pools'] = $upbase;
1608

    
1609
		/* Craft a cloned pool with pool settings to override for this user */
1610
		$scconf['pools'][$upname]['addrs'] = "{$mkent['pool_address']}/{$mkent['pool_netbits']}";
1611
		if (isset($mkent['dns_address']) && strlen($mkent['dns_address']) > 0 && is_ipaddr($mkent['dns_address'])) {
1612
			$scconf['pools'][$upname]['dns'] = $mkent['dns_address'];
1613
		}
1614
		$suffix++;
1615
	}
1616
	return;
1617
}
1618

    
1619
/****f* ipsec/ipsec_setup_bypasslan
1620
 * NAME
1621
 *   ipsec_setup_bypasslan - Generate a bypass connection for LAN-LAN traffic
1622
 * INPUTS
1623
 *   None
1624
 * RESULT
1625
 *   Sets up a bypass connection to prevent local traffic from being caught by
1626
 *   IPsec policies.
1627
 ******/
1628
function ipsec_setup_bypasslan() {
1629
	global $config, $scconf;
1630
	if (isset($config['ipsec']['noshuntlaninterfaces'])) {
1631
		return array();
1632
	}
1633
	$bypassnets = array();
1634
	/* Locate the LAN IPv4 and IPv6 subnets */
1635
	if ($config['interfaces']['lan']) {
1636
		$lanip = get_interface_ip("lan");
1637
		if (!empty($lanip) && is_ipaddrv4($lanip)) {
1638
			$lansn = get_interface_subnet("lan");
1639
			$lansa = gen_subnetv4($lanip, $lansn);
1640
			if (!empty($lansa) && !empty($lansn)) {
1641
				$bypassnets[] = "{$lansa}/{$lansn}";
1642
			}
1643
		}
1644
		$lanip6 = get_interface_ipv6("lan");
1645
		if (!empty($lanip6) && is_ipaddrv6($lanip6)) {
1646
			$lansn6 = get_interface_subnetv6("lan");
1647
			$lansa6 = gen_subnetv6($lanip6, $lansn6);
1648
			if (!empty($lansa6) && !empty($lansn6)) {
1649
				$bypassnets[] = "{$lansa6}/{$lansn6}";
1650
			}
1651
		}
1652
	}
1653
	/* If we have viable targets, setup a bypass connection */
1654
	if (!empty($bypassnets)) {
1655
		$bypass = implode(',', $bypassnets);
1656
		$scconf['connections']['bypass'] = array();
1657
		/* Prevents the connection from being considered for remote peers */
1658
		$scconf['connections']['bypass']['remote_addrs'] = "127.0.0.1";
1659
		$scconf['connections']['bypass']['children'] = array();
1660
		$scconf['connections']['bypass']['children']['bypass'] = array();
1661
		$scconf['connections']['bypass']['children']['bypass']['local_ts'] = $bypass;
1662
		$scconf['connections']['bypass']['children']['bypass']['remote_ts'] = $bypass;
1663
		$scconf['connections']['bypass']['children']['bypass']['mode'] = "pass";
1664
		$scconf['connections']['bypass']['children']['bypass']['start_action'] = "trap";
1665
	}
1666
	return;
1667
}
1668

    
1669
/****f* ipsec/ipsec_setup_routes
1670
 * NAME
1671
 *   ipsec_setup_routes - Setup OS routing table static routes for remote peers.
1672
 *                        This ensures that IPsec connections are routed out of
1673
 *                        the expected interface on egress.
1674
 * INPUTS
1675
 *   $interface : The interface upon which routes will be configured.
1676
 *   $family    : The address family ('inet' or 'inet6')
1677
 *   $sourcehost: The local source address used for initiating connections.
1678
 * RESULT
1679
 *   Static routes in the OS routing table for IPsec peers
1680
 ******/
1681
function ipsec_setup_routes($interface, $family, $sourcehost) {
1682
	if (substr($interface, 0, 4) == "_vip") {
1683
		$vpninterface = get_configured_vip_interface($interface);
1684
		if (substr($vpninterface, 0, 4) == "_vip") {
1685
			// vips are nested if its a ipalias with a carp parent
1686
			$vpninterface = get_configured_vip_interface($vpninterface);
1687
		}
1688
		$ifacesuse = get_real_interface($vpninterface);
1689
	} else {
1690
		$ifacesuse = get_failover_interface($interface);
1691
		if (substr($ifacesuse, 0, 4) == "_vip") {
1692
			$vpninterface = get_configured_vip_interface($ifacesuse);
1693
			$ifacesuse = get_real_interface($vpninterface);
1694
		} else {
1695
			$vpninterface = convert_real_interface_to_friendly_interface_name($ifacesuse);
1696
		}
1697
	}
1698
	if ($family == 'inet') {
1699
		if (!empty($ifacesuse) && interface_has_gateway($vpninterface)) {
1700
			$gatewayip = get_interface_gateway($vpninterface);
1701
			$interfaceip = get_interface_ip($vpninterface);
1702
			$subnet_bits = get_interface_subnet($vpninterface);
1703
			$subnet_ip = gen_subnetv4($interfaceip, $subnet_bits);
1704
			/* if the remote gateway is in the local subnet, then don't add a route */
1705
			if (is_ipaddrv4($sourcehost) &&
1706
			    !ip_in_subnet($sourcehost, "{$subnet_ip}/{$subnet_bits}")) {
1707
				if (is_ipaddrv4($gatewayip)) {
1708
					// log_error("IPSEC interface is not WAN but {$ifacesuse}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
1709
					route_add_or_change("-host {$sourcehost} {$gatewayip}");
1710
				}
1711
			}
1712
		}
1713
	} else if ($family == 'inet6') {
1714
		if (!empty($ifacesuse) && interface_has_gatewayv6($vpninterface)) {
1715
			$gatewayip = get_interface_gateway_v6($vpninterface);
1716
			$interfaceip = get_interface_ipv6($vpninterface);
1717
			$subnet_bits = get_interface_subnetv6($vpninterface);
1718
			$subnet_ip = gen_subnetv6($interfaceip, $subnet_bits);
1719
			/* if the remote gateway is in the local subnet, then don't add a route */
1720
			if (is_ipaddrv6($sourcehost) &&
1721
			    !ip_in_subnet($sourcehost, "{$subnet_ip}/{$subnet_bits}")) {
1722
				if (is_ipaddrv6($gatewayip)) {
1723
					// log_error("IPSEC interface is not WAN but {$ifacesuse}, adding static route for VPN endpoint {$rgip} via {$gatewayip}");
1724
					route_add_or_change("-inet6 -host {$sourcehost} {$gatewayip}");
1725
				}
1726
			}
1727
		}
1728
	}
1729
	return $ifacesuse;
1730
}
1731

    
1732
/****f* ipsec/ipsec_setup_authentication
1733
 * NAME
1734
 *   ipsec_setup_authentication - Generate an array with local/remote
1735
 *                                authentication information for a given IPsec
1736
 *                                Phase 1.
1737
 * INPUTS
1738
 *   $ph1ent: An IPsec Phase 1 configuration
1739
 *   $conn  : A swanctl connection array corresponding to the IPsec Phase 1.
1740
 * RESULT
1741
 *   Populates $conn with local and remote arrays containing authentication
1742
 *   details.
1743
 ******/
1744
function ipsec_setup_authentication(& $ph1ent, & $conn) {
1745
	global $rgmap, $ipsec_swanctl_dirs;
1746
	$local = array();
1747
	$remote = array();
1748
	$remote2 = array();
1749

    
1750
	list($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local');
1751
	$localid = ipsec_fixup_id($myid_type, $myid_data);
1752
	if (!empty($localid)) {
1753
		$local['id'] = $localid;
1754
	}
1755

    
1756
	// Only specify peer ID if we are not dealing with mobile PSK
1757
	if (!(isset($ph1ent['mobile']) &&
1758
	    in_array($ph1ent['authentication_method'], array("pre_shared_key", "xauth_psk_server")))) {
1759
		list ($remoteid_type, $remoteid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap);
1760
		$remoteid = ipsec_fixup_id($remoteid_type, $remoteid_data);
1761
	}
1762
	if (!empty($remoteid)) {
1763
		$remote['id'] = $remoteid;
1764
	}
1765

    
1766
	if (!empty($ph1ent['caref'])) {
1767
		$ca = lookup_ca($ph1ent['caref']);
1768
		if ($ca) {
1769
			/* Get hash value to use for filename */
1770
			$ca_details = openssl_x509_parse(base64_decode($ca['crt']));
1771
			$cafn = "{$ipsec_swanctl_dirs['capath']}/{$ca_details['hash']}.0";
1772
		}
1773
	}
1774

    
1775
	$authentication = "";
1776
	switch ($ph1ent['authentication_method']) {
1777
		case 'eap-mschapv2':
1778
			if (isset($ph1ent['mobile'])) {
1779
				$local['auth'] = "pubkey";
1780
				$remote['eap_id'] = "%any";
1781
				$remote['auth'] = "eap-mschapv2";
1782
			}
1783
			break;
1784
		case 'eap-tls':
1785
			if (isset($ph1ent['mobile'])) {
1786
				$local['auth'] = "pubkey";
1787
				$remote['eap_id'] = "%any";
1788
			} else {
1789
				$local['auth'] = "eap-tls";
1790
			}
1791
			$remote['auth'] = "eap-tls";
1792
			break;
1793
		case 'eap-radius':
1794
			if (isset($ph1ent['mobile'])) {
1795
				$local['auth'] = "pubkey";
1796
				$remote['eap_id'] = "%any";
1797
			} else {
1798
				$local['auth'] = "eap-radius";
1799
			}
1800
			$remote['auth'] = "eap-radius";
1801
			break;
1802
		case 'xauth_cert_server':
1803
			$local['auth'] = "pubkey";
1804
			$remote['auth'] = "pubkey";
1805
			$remote2['auth'] = "xauth-generic";
1806
			break;
1807
		case 'xauth_psk_server':
1808
			$local['auth'] = "psk";
1809
			$remote['auth'] = "psk";
1810
			$remote2['auth'] = "xauth-generic";
1811
			break;
1812
		case 'pre_shared_key':
1813
			$local['auth'] = "psk";
1814
			$remote['auth'] = "psk";
1815
			break;
1816
		case 'cert':
1817
		case 'pkcs11':
1818
			$local['auth'] = "pubkey";
1819
			$remote['auth'] = "pubkey";
1820
			break;
1821
		case 'hybrid_cert_server':
1822
			$local['auth'] = "pubkey";
1823
			$remote['auth'] = "xauth-generic";
1824
			break;
1825
	}
1826
	if (in_array($ph1ent['authentication_method'], array('eap-mschapv2', 'eap-tls', 'eap-radius', 'xauth_cert_server', 'cert', 'hybrid_cert_server')) &&
1827
	    !empty($ph1ent['certref'])) {
1828
		$local['cert'] = array('file' => "{$ipsec_swanctl_dirs['certpath']}/cert-{$ph1ent['ikeid']}.crt");
1829
		$conn['send_cert'] = "always";
1830
	}
1831
	if ($ph1ent['authentication_method'] == 'pkcs11') {
1832
		$local['cert'] = array('handle' => "{$ph1ent['pkcs11certref']}");
1833
		$conn['send_cert'] = "always";
1834
	}
1835
	if (in_array($ph1ent['authentication_method'], array('eap-tls', 'xauth_cert_server', 'cert', 'pkcs11')) &&
1836
	    isset($cafn)) {
1837
		$remote['cacerts'] = $cafn;
1838
	}
1839

    
1840
	$conn['local'] = $local;
1841
	/* If there is data for a second remote auth round, setup two remote
1842
	 * arrays with unique names, otherwise setup a single remote. */
1843
	if (empty($remote2)) {
1844
		$conn['remote'] = $remote;
1845
	} else {
1846
		$conn['remote-1'] = $remote;
1847
		$conn['remote-2'] = $remote2;
1848
	}
1849
}
1850

    
1851
/****f* ipsec/ipsec_setup_proposal_algo
1852
 * NAME
1853
 *   ipsec_setup_proposal_algo - Form a single proposal algorithm string
1854
 * INPUTS
1855
 *   $ealg_id: Encryption algorithm ID
1856
 *   $keylen : Key length for the encryption algorithm
1857
 *   $halgo  : Hash algorithm
1858
 *   $modp   : DH Group number
1859
 * RESULT
1860
 *   Returns a string using the available information to form a single proposal
1861
 *   algorithm definition.
1862
 * NOTES
1863
 *   Values left empty will not be added to the string. Some combinations may
1864
 *   require one or more parts to be omitted.
1865
 ******/
1866
function ipsec_setup_proposal_algo($ealg_id, $keylen, $halgo, $prfalgo, $modp) {
1867
	$palgo = "";
1868

    
1869
	/* Add the encryption algorithm (if present) */
1870
	if (!empty($ealg_id)) {
1871
		$palgo .= "{$ealg_id}";
1872
	}
1873

    
1874
	/* Add the key length (if present) */
1875
	if (!empty($keylen)) {
1876
		$palgo .= "{$keylen}";
1877
	}
1878

    
1879
	/* Add the hash algorithm (if present) */
1880
	if (!empty($halgo)) {
1881
		/* If there is some content in the propsal already, add a
1882
		 * separator */
1883
		if (!empty($palgo)) {
1884
			$palgo .= "-";
1885
		}
1886
		$halgo = str_replace('hmac_', '', $halgo);
1887
		$palgo .= "{$halgo}";
1888
	}
1889

    
1890
	if (!empty($prfalgo)) {
1891
		$palgo .= "-prf{$prfalgo}";
1892
	}
1893

    
1894
	/* Convert the DH group to its keyword and add (if present) */
1895
	$modp = ipsec_convert_to_modp($modp);
1896
	if (!empty($modp)) {
1897
		$palgo .= "-{$modp}";
1898
	}
1899

    
1900
	return $palgo;
1901
}
1902

    
1903
/****f* ipsec/ipsec_setup_proposal_entry
1904
 * NAME
1905
 *   ipsec_setup_proposal_entry - Generate a full proposal string for an IPsec
1906
 *                                Phase 2 configuration.
1907
 * INPUTS
1908
 *   $ph2ent  : An IPsec Phase 2 configuration
1909
 *   $algo_arr: An array in which all proposal algorithms are collected
1910
 *   $ealg_id : Encryption algorithm ID
1911
 *   $keylen  : Key length for the encryption algorithm
1912
 * RESULT
1913
 *   Returns a string containing all proposal elements, and merges the entries
1914
 *   to $algo_arr as well.
1915
 ******/
1916
function ipsec_setup_proposal_entry(& $ph2ent, & $algo_arr, $ealg_id, $keylen) {
1917
	global $config, $p2_ealgos;
1918
	$proposal = array();
1919

    
1920
	/* If multiple hash algorithms are present, loop through and add them all. */
1921
	if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option']) 
1922
	    && !strpos($ealg_id, "gcm")) {
1923
		foreach ($ph2ent['hash-algorithm-option'] as $halgo) {
1924
			$proposal[] = ipsec_setup_proposal_algo($ealg_id, $keylen, $halgo, false, $ph2ent['pfsgroup']);
1925
		}
1926
	} else {
1927
		$proposal[] = ipsec_setup_proposal_algo($ealg_id, $keylen, false, false, $ph2ent['pfsgroup']);
1928
	}
1929

    
1930
	/* Add to master list */
1931
	$algo_arr = array_merge($algo_arr, $proposal);
1932
	return implode(',', $proposal);
1933
}
1934

    
1935
/****f* ipsec/ipsec_setup_vtireq
1936
 * NAME
1937
 *   ipsec_setup_vtireq - Setup a VTI type IPsec request
1938
 * INPUTS
1939
 *   $child                : A swanctl child array
1940
 *   $ipsec_vti_cleanup_ifs: An array of VTI interface names for later cleanup
1941
 *   $ikeid                : The IKE ID of this child
1942
 *   $idx                  : The index of this child (for split connections/IKEv1)
1943
 * RESULT
1944
 *   Sets up VTI-specific values for a request.
1945
 ******/
1946
function ipsec_setup_vtireq(& $child, & $ipsec_vti_cleanup_ifs, $ikeid, $idx = 0) {
1947
	$child['reqid'] = "{$ikeid}00{$idx}";
1948
	/* This interface will be a valid IPsec interface, so remove it from the cleanup list. */
1949
	$ipsec_vti_cleanup_ifs = array_diff($ipsec_vti_cleanup_ifs, array("ipsec{$child['reqid']}"));
1950
	$child['local_ts'] .= ",0.0.0.0/0";
1951
	$child['remote_ts'] .= ",0.0.0.0/0";
1952
}
1953

    
1954
/****f* ipsec/ipsec_setup_tunnels
1955
 * NAME
1956
 *   ipsec_setup_tunnels - Configure all P1/P2 entries as swanctl connections
1957
 * INPUTS
1958
 *   None
1959
 * RESULT
1960
 *   Sets up a swanctl array for all connections in the configuration along with
1961
 *   their children, authentication, etc.
1962
 ******/
1963
function ipsec_setup_tunnels() {
1964
	global $aggressive_mode_psk, $a_client, $config,
1965
		$filterdns_list, $g, $ifacesuse, $ipsec_idhandling, $ipsec_log_cats,
1966
		$ipsec_log_sevs, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs,
1967
		$ipseccfg, $mobile_ipsec_auth, $natfilterrules, $p1_ealgos,
1968
		$p2_ealgos, $rgmap, $sa, $sn, $scconf, $conn, $tunnels,
1969
		$ipsec_vti_cleanup_ifs, $conn_defaults;
1970

    
1971
	foreach ($tunnels as $ph1ent) {
1972
		/* Skip disabled entries */
1973
		if (isset($ph1ent['disabled'])) {
1974
			continue;
1975
		}
1976
		/* If the local source is invalid, skip this entry. */
1977
		$local_spec = ipsec_get_phase1_src($ph1ent);
1978
		if (!$local_spec) {
1979
			continue;
1980
		}
1981

    
1982
		/* Determine the name of this connection, either con-mobile for
1983
		 * mobile clients, or a name based on the IKE ID otherwise. */
1984
		$cname = isset($ph1ent['mobile']) ? "con-mobile" : "con{$ph1ent['ikeid']}000";
1985
		/* Start with common default values */
1986
		$scconf['connections'][$cname] = $conn_defaults;
1987
		/* Array reference to make things easier */
1988
		$conn =& $scconf['connections'][$cname];
1989

    
1990
		/* Common parameters for all children */
1991
		$child_params = array();
1992
		if (!empty($ph1ent['closeaction'])) {
1993
			$child_params['close_action'] = $ph1ent['closeaction'];
1994
		}
1995

    
1996
		$ikeid = $ph1ent['ikeid'];
1997

    
1998
		/* "trap" adds policies to start a tunnel when interesting
1999
		 * traffic is observed by the host. */
2000
		$start_action = "trap";
2001

    
2002
		/* Set the IKE version appropriately (empty = IKEv1) */
2003
		switch ($ph1ent['iketype']) {
2004
			case 'auto':
2005
				$ikeversion = 0;
2006
				break;
2007
			case 'ikev2':
2008
				$ikeversion = 2;
2009
				break;
2010
			case 'ikev1':
2011
			default:
2012
				$ikeversion = 1;
2013
				break;
2014
		}
2015
		$conn['version'] = $ikeversion;
2016

    
2017
		/* For IKEv1 or auto, setup aggressive mode if configured */
2018
		if ($ikeversion != 2){
2019
			$conn['aggressive'] = ($ph1ent['mode'] == "aggressive") ? "yes" : "no";
2020
		}
2021

    
2022
		if (isset($ph1ent['mobile'])) {
2023
			/* Mobile tunnels allow 'any' as a peer */
2024
			$remote_spec = "0.0.0.0/0,::/0";
2025
			/* Mobile tunnels cannot start automatically */
2026
			$start_action = 'none';
2027
		} else {
2028
			$remote_spec = $ph1ent['remote-gateway'];
2029
			$sourcehost = (is_ipaddr($remote_spec)) ? $remote_spec : $rgmap[$remote_spec];
2030
			$ifacesuse = ipsec_setup_routes($ph1ent['interface'], $ph1ent['protocol'], $sourcehost);
2031
		}
2032

    
2033
		/* Setup IKE proposals */
2034
		if (is_array($ph1ent['encryption']['item'])) {
2035
			$ciphers = array();
2036
			foreach($ph1ent['encryption']['item'] as $p1enc) {
2037
				if (!is_array($p1enc['encryption-algorithm']) ||
2038
						empty($p1enc['encryption-algorithm']['name']) ||
2039
						empty($p1enc['hash-algorithm'])) {
2040
					continue;
2041
				}
2042
				if ($ph1ent['prfselect_enable'] != 'yes') {
2043
					$p1enc['prf-algorithm'] = false;
2044
				}
2045
				$ciphers[] = ipsec_setup_proposal_algo($p1enc['encryption-algorithm']['name'],
2046
									$p1enc['encryption-algorithm']['keylen'],
2047
									$p1enc['hash-algorithm'],
2048
									$p1enc['prf-algorithm'],
2049
									$p1enc['dhgroup']);
2050
			}
2051
			$conn['proposals'] = implode(",", $ciphers);
2052
		}
2053

    
2054
		/* Configure DPD values. The DPD action is a per-child parameter,
2055
		 * not per-connection like the delay and timeout. */
2056
		if ($ph1ent['dpd_delay'] && $ph1ent['dpd_maxfail']) {
2057
			if ($start_action == "trap") {
2058
				$child_params['dpd_action'] = "restart";
2059
			} else {
2060
				$child_params['dpd_action'] = "clear";
2061
			}
2062
			$conn['dpd_delay'] = "{$ph1ent['dpd_delay']}s";
2063
			$conn['dpd_timeout'] =  $ph1ent['dpd_delay'] * ($ph1ent['dpd_maxfail'] + 1) . "s";
2064
		} else {
2065
			$child_params['dpd_action'] = "none";
2066
		}
2067

    
2068
		/* Reauth (Any) */
2069
		$conn['reauth_time'] = (empty($ph1ent['reauth_time']) ? "0" : $ph1ent['reauth_time']) . "s";
2070

    
2071
		/* Rekey (IKEv2 or Auto only, not supported by IKEv1) */
2072
		if (($ikeversion == 0) || ($ikeversion == 2)) {
2073
			$conn['rekey_time'] = (empty($ph1ent['rekey_time']) ? "0" : $ph1ent['rekey_time']) . "s";
2074
		}
2075

    
2076
		/* Over Time */
2077
		if (!empty($ph1ent['over_time'])) {
2078
			$conn['over_time'] = "{$ph1ent['over_time']}s";
2079
		}
2080

    
2081
		/* NAT Traversal */
2082
		$conn['encap'] = ($ph1ent['nat_traversal'] == 'force') ? "yes" : "no";
2083

    
2084
		/* MOBIKE support */
2085
		$conn['mobike'] = ($ph1ent['mobike'] == 'on') ? "yes" : "no";
2086

    
2087
		/* TFC Padding */
2088
		if (isset($ph1ent['tfc_enable'])) {
2089
			$conn['tfc_padding'] = (isset($ph1ent['tfc_bytes']) && is_numericint($ph1ent['tfc_bytes'])) ? $ph1ent['tfc_bytes'] : "mtu";
2090
		}
2091

    
2092
		/* Arrays for P2s/children */
2093
		$children = array();
2094
		$remote_ts_spec = array();
2095
		$local_ts_spec = array();
2096
		$reqids = array();
2097
		$has_vti = false;
2098
		$ealgoAHsp2arr = array();
2099
		$ealgoESPsp2arr = array();
2100
		$suffix = 0;
2101

    
2102
		foreach ($ph1ent['p2'] as $ph2ent) {
2103
			/* If this entry is disabled, or cannot be configured, skip. */
2104
			if (isset($ph2ent['disabled']) ||
2105
			    (isset($ph2ent['mobile']) && !isset($a_client['enable']))) {
2106
				continue;
2107
			}
2108
			$child = array();
2109
			$local_ts = "";
2110
			$remote_ts = "";
2111
			if (($ph2ent['mode'] == 'tunnel') or ($ph2ent['mode'] == 'tunnel6')) {
2112
				/* Normal tunnel child config */
2113
				$child['mode'] = "tunnel";
2114
				$child['policies'] = "yes";
2115

    
2116
				$localid_type = $ph2ent['localid']['type'];
2117
				$localsubnet_data = ipsec_idinfo_to_cidr($ph2ent['localid'], false, $ph2ent['mode']);
2118

    
2119
				/* Do not print localid in some cases, such as a pure-psk or psk/xauth single phase2 mobile tunnel */
2120
				if (($localid_type == "none" || $localid_type == "mobile") &&
2121
				    isset($ph1ent['mobile']) && (ipsec_get_number_of_phase2($ikeid) == 1)) {
2122
					$local_spec = '0.0.0.0/0,::/0';
2123
				} else {
2124
					if ($localid_type != "address") {
2125
						$localid_type = "subnet";
2126
					}
2127
					// Don't let an empty subnet into config, it can cause parse errors. Ticket #2201.
2128
					if (!is_ipaddr($localsubnet_data) && !is_subnet($localsubnet_data) && ($localsubnet_data != "0.0.0.0/0")) {
2129
						log_error("Invalid IPsec Phase 2 \"{$ph2ent['descr']}\" - {$ph2ent['localid']['type']} has no subnet.");
2130
						continue;
2131
					}
2132
					if (!empty($ph2ent['natlocalid'])) {
2133
						$natlocalsubnet_data = ipsec_idinfo_to_cidr($ph2ent['natlocalid'], false, $ph2ent['mode']);
2134
						if ($ph2ent['natlocalid']['type'] != "address") {
2135
							if (is_subnet($natlocalsubnet_data)) {
2136
								$localsubnet_data = "{$natlocalsubnet_data}|{$localsubnet_data}";
2137
							}
2138
						} else {
2139
							if (is_ipaddr($natlocalsubnet_data)) {
2140
								$localsubnet_data = "{$natlocalsubnet_data}|{$localsubnet_data}";
2141
							}
2142
						}
2143
						$natfilterrules = true;
2144
					}
2145
				}
2146

    
2147
				$local_ts = $localsubnet_data;
2148

    
2149
				if (!isset($ph2ent['mobile'])) {
2150
					$remote_ts = ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']);
2151
				} else if (!empty($a_client['pool_address'])) {
2152
					$remote_ts = "{$a_client['pool_address']}/{$a_client['pool_netbits']}";
2153
				}
2154

    
2155
			} elseif ($ph2ent['mode'] == 'vti') {
2156
				/* VTI-specific child config */
2157
				$child['policies'] = "no";
2158
				/* VTI cannot use trap policies, so start automatically instead */
2159
				$start_action = 'start';
2160
				$localid_type = $ph2ent['localid']['type'];
2161
				$localsubnet_data = ipsec_idinfo_to_cidr($ph2ent['localid'], false, $ph2ent['mode']);
2162
				$local_ts = $localsubnet_data;
2163
				$remote_ts = ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']);
2164
				$has_vti = true;
2165
			} else {
2166
				/* Transport mode child config */
2167
				$child['mode'] = "transport";
2168
				$child['policies'] = "yes";
2169

    
2170
				if ((($ph1ent['authentication_method'] == "xauth_psk_server") ||
2171
				    ($ph1ent['authentication_method'] == "pre_shared_key")) &&
2172
				    isset($ph1ent['mobile'])) {
2173
					$local_spec = "0.0.0.0/0,::/0";
2174
				} else {
2175
					$local_ts = ipsec_get_phase1_src($ph1ent);
2176
				}
2177

    
2178
				if (!isset($ph2ent['mobile'])) {
2179
					$remote_ts = $remote_spec;
2180
				}
2181
			}
2182

    
2183
			if (!empty($local_ts)) {
2184
				$local_ts_spec[] = $local_ts;
2185
			}
2186
			if (!empty($remote_ts)) {
2187
				$remote_ts_spec[] = $remote_ts;
2188
			}
2189

    
2190
			/* If a PFS group is configured on the Mobile Clients tab,
2191
			 * and this is a mobile P2, use it here. */
2192
			if (isset($a_client['pfs_group']) && isset($ph2ent['mobile'])) {
2193
				$ph2ent['pfsgroup'] = $a_client['pfs_group'];
2194
			}
2195

    
2196
			$reqids[] = $ph2ent['reqid'];
2197

    
2198
			if (!empty($ph2ent['lifetime'])) {
2199
				$child['life_time'] = intval($ph2ent['lifetime']);
2200
			}
2201

    
2202
			/* If we are to act only as a responder, disable the start action */
2203
			$child['start_action'] = isset($ph1ent['responderonly']) ? 'none' : $start_action;
2204

    
2205
			/* Setup child SA proposals */
2206
			$proposal = array();
2207
			if ($ph2ent['protocol'] == 'esp') {
2208
				if (is_array($ph2ent['encryption-algorithm-option'])) {
2209
					foreach ($ph2ent['encryption-algorithm-option'] as $ealg) {
2210
						$ealg_id = $ealg['name'];
2211
						$ealg_kl = $ealg['keylen'];
2212

    
2213
						if (!empty($ealg_kl) && $ealg_kl == "auto") {
2214
							if (empty($p2_ealgos) || !is_array($p2_ealgos)) {
2215
								require_once("ipsec.inc");
2216
							}
2217
							$key_hi = $p2_ealgos[$ealg_id]['keysel']['hi'];
2218
							$key_lo = $p2_ealgos[$ealg_id]['keysel']['lo'];
2219
							$key_step = $p2_ealgos[$ealg_id]['keysel']['step'];
2220
							/* XXX: in some cases where include ordering is suspect these variables
2221
							 * are somehow 0 and we enter this loop forever and timeout after 900
2222
							 * seconds wrecking bootup */
2223
							if ($key_hi != 0 and $key_lo != 0 and $key_step != 0) {
2224
								for ($keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step) {
2225
									$proposal[] = ipsec_setup_proposal_entry($ph2ent, $ealgoESPsp2arr, $ealg_id, $keylen);
2226
								}
2227
							}
2228
						} else {
2229
							$proposal[] = ipsec_setup_proposal_entry($ph2ent, $ealgoESPsp2arr, $ealg_id, $ealg_kl);
2230
						}
2231
					}
2232
				}
2233
			} else if ($ph2ent['protocol'] == 'ah') {
2234
				$proposal[] = ipsec_setup_proposal_entry($ph2ent, $ealgoAHsp2arr, '', '');
2235
			}
2236

    
2237
			/* Not mobile, and IKEv1 or Split Connections active */
2238
			if (!isset($ph1ent['mobile']) && (($ikeversion == 1) || isset($ph1ent['splitconn']))) {
2239
				if (!empty($remote_ts)) {
2240
					/* Setup child sub-connections using unique names with a suffix */
2241
					$subconname = "con{$ph1ent['ikeid']}00{$suffix}";
2242
					$children[$subconname] = $child;
2243
					$children[$subconname]['local_ts'] = $local_ts;
2244
					$children[$subconname]['remote_ts'] = $remote_ts;
2245
					if ($has_vti) {
2246
						ipsec_setup_vtireq($children[$subconname], $ipsec_vti_cleanup_ifs, $ph1ent['ikeid'], $suffix);
2247
					}
2248
					if (!empty($ph2ent['protocol']) && !empty($proposal)) {
2249
						$children[$subconname][$ph2ent['protocol'] . '_proposals'] = implode(',', $proposal);
2250
					}
2251
				} else {
2252
					log_error(sprintf(gettext("No phase2 specifications for tunnel with REQID = %s"), $ikeid));
2253
				}
2254
			} else {
2255
				/* TODO: Fix this to nicely merge all P2 params for single child case */
2256
				if (!is_array($children[$cname])) {
2257
					$children[$cname] = array();
2258
				}
2259
				$children[$cname] = array_merge($children[$cname], $child);
2260
			}
2261
			$suffix++;
2262
		}
2263

    
2264
		$conn['local_addrs'] = $local_spec;
2265
		$conn['remote_addrs'] = $remote_spec;
2266

    
2267
		if (isset($ph1ent['mobile'])) {
2268
			if (($ph1ent['authentication_method'] == 'eap-radius') && 
2269
			    empty($a_client['pool_address']) && empty($a_client['pool_address_v6'])) {
2270
				$conn['pools'] = "radius";
2271
			} else {
2272
				$conn['pools'] = "mobile-pool";
2273
				if (isset($a_client['radius_ip_priority_enable'])) {
2274
					$conn['pools'] .= ", radius";
2275
				}
2276
			}
2277
		}
2278

    
2279
		/* For IKEv2 without Split Connections, setup combined sets of
2280
		 * local/remote traffic selectors and propsals */
2281
		if (!(!isset($ph1ent['mobile']) && (($ikeversion == 1) || isset($ph1ent['splitconn'])))) {
2282
			if (!isset($ph1ent['mobile']) && !empty($remote_ts_spec)) {
2283
				$children[$cname]['remote_ts'] = implode(",", $remote_ts_spec);
2284
			}
2285
			if (!empty($local_ts_spec)) {
2286
				$children[$cname]['local_ts'] = implode(",", $local_ts_spec);
2287
			}
2288
			if ($has_vti) {
2289
				ipsec_setup_vtireq($children[$cname], $ipsec_vti_cleanup_ifs, $ph1ent['ikeid']);
2290
			}
2291
			if (!empty($ealgoAHsp2arr)) {
2292
				$children[$cname]['ah_proposals'] = implode(',', array_unique($ealgoAHsp2arr));
2293
			}
2294
			if (!empty($ealgoESPsp2arr)) {
2295
				$children[$cname]['esp_proposals'] = implode(',', array_unique($ealgoESPsp2arr));
2296
			}
2297
		}
2298

    
2299
		/* Setup connection authentication */
2300
		ipsec_setup_authentication($ph1ent, $conn);
2301

    
2302
		/* Add children to this connection, including default child parameters */
2303
		if (count($children)) {
2304
			foreach($children as $name => $child) {
2305
				$conn['children'][$name] = array_merge($child_params, $child);
2306
			}
2307
		}
2308

    
2309
	}
2310

    
2311
	return;
2312
}
2313

    
2314
/****f* ipsec/ipsec_setup_secrets
2315
 * NAME
2316
 *   ipsec_setup_secrets - Setup swanctl authentication secrets
2317
 * INPUTS
2318
 *   None
2319
 * RESULT
2320
 *   Returns a swanctl array containing secrets (PSKs, certs, etc) and writes out
2321
 *   necessary CA, CRL, and certificate data.
2322
 ******/
2323
function ipsec_setup_secrets() {
2324
	global $config, $a_phase1, $ipsec_swanctl_dirs, $ipseccfg, $rgmap, $scconf;
2325

    
2326
	$suffix = 0;
2327

    
2328
	/* write out CRL files */
2329
	if (is_array($config['crl']) && count($config['crl'])) {
2330
		foreach ($config['crl'] as $crl) {
2331
			if (!isset($crl['text'])) {
2332
				log_error(sprintf(gettext("Warning: Missing CRL data for %s"), $crl['descr']));
2333
				continue;
2334
			}
2335
			$fpath = "{$ipsec_swanctl_dirs['crlpath']}/{$crl['refid']}.crl";
2336
			if (!@file_put_contents($fpath, base64_decode($crl['text']))) {
2337
				log_error(sprintf(gettext("Error: Cannot write IPsec CRL file for %s"), $crl['descr']));
2338
				continue;
2339
			}
2340
		}
2341
	}
2342

    
2343
	$vpncas = array();
2344
	if (is_array($a_phase1) && count($a_phase1)) {
2345
		foreach ($a_phase1 as $ph1ent) {
2346
			if (isset($ph1ent['disabled'])) {
2347
				continue;
2348
			}
2349

    
2350
			if (strstr($ph1ent['authentication_method'], 'cert') ||
2351
			    in_array($ph1ent['authentication_method'], array('eap-mschapv2', 'eap-tls', 'eap-radius'))) {
2352
				/* Write certificate and private key, point to private key */
2353
				$certline = '';
2354

    
2355
				$ikeid = $ph1ent['ikeid'];
2356
				$cert = lookup_cert($ph1ent['certref']);
2357

    
2358
				if (!$cert) {
2359
					log_error(sprintf(gettext("Error: Invalid phase1 certificate reference for %s"), $ph1ent['name']));
2360
					continue;
2361
				}
2362

    
2363
				/* add signing CA cert chain of server cert
2364
				 * to the list of CAs to write
2365
				 */
2366
				$cachain = ca_chain_array($cert);
2367
				if ($cachain && is_array($cachain)) {
2368
					foreach ($cachain as $cacrt) {
2369
						$vpncas[$cacrt['refid']] = $cacrt;
2370
					}
2371
				}
2372

    
2373
				@chmod($ipsec_swanctl_dirs['certpath'], 0600);
2374

    
2375
				$ph1keyfile = "{$ipsec_swanctl_dirs['keypath']}/cert-{$ikeid}.key";
2376
				if (!file_put_contents($ph1keyfile, base64_decode($cert['prv']))) {
2377
					log_error(sprintf(gettext("Error: Cannot write phase1 key file for %s"), $ph1ent['name']));
2378
					continue;
2379
				}
2380
				@chmod($ph1keyfile, 0600);
2381

    
2382
				$ph1certfile = "{$ipsec_swanctl_dirs['certpath']}/cert-{$ikeid}.crt";
2383
				if (!file_put_contents($ph1certfile, base64_decode($cert['crt']))) {
2384
					log_error(sprintf(gettext("Error: Cannot write phase1 certificate file for %s"), $ph1ent['name']));
2385
					@unlink($ph1keyfile);
2386
					continue;
2387
				}
2388
				@chmod($ph1certfile, 0600);
2389

    
2390
				$scconf['secrets']['private-' . $suffix++] = array('file' => $ph1keyfile);
2391
			} else if (strstr($ph1ent['authentication_method'], 'pkcs11')) {
2392
				$p11_id = array();
2393
				$output = shell_exec('/usr/local/bin/pkcs15-tool -c');
2394
				preg_match_all('/ID\s+: (.*)/', $output, $p11_id);
2395
				if (!empty($ph1ent['pkcs11certref']) && in_array($ph1ent['pkcs11certref'], $p11_id[1])) {
2396
					$scconf['secrets']['token-' . $suffix++] = array(
2397
						'handle' => $ph1ent['pkcs11certref'],
2398
						'pin' => $ph1ent['pkcs11pin'],
2399
					);
2400
				} else {
2401
					log_error(sprintf(gettext("Error: Invalid phase1 PKCS#11 certificate reference or PKCS#11 is not present for %s"), $ph1ent['name']));
2402
					continue;
2403
				}
2404
			} else {
2405
				/* Setup pre-shared keys */
2406
				list($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local');
2407
				list($peerid_type, $peerid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap);
2408
				$myid = trim($myid_data);
2409

    
2410
				if (empty($peerid_data)) {
2411
					continue;
2412
				}
2413

    
2414
				if ($myid_type == 'fqdn' && !empty($myid)) {
2415
					$myid = "@{$myid}";
2416
				}
2417

    
2418
				$myid = isset($ph1ent['mobile']) ? trim($myid_data) : "%any";
2419
				$peerid = ($peerid_data != 'allusers') ? trim($peerid_data) : '';
2420

    
2421
				if ($peerid_type == 'fqdn' && !empty($peerid)) {
2422
					$peerid = "@{$peerid}";
2423
				}
2424

    
2425
				if (!empty($ph1ent['pre-shared-key'])) {
2426
					$scconf['secrets']['ike-' . $suffix++] = array(
2427
						'secret' => '0s' . base64_encode(trim($ph1ent['pre-shared-key'])),
2428
						'id-0' => $myid,
2429
						'id-1' => $peerid,
2430
					);
2431
					if (isset($ph1ent['mobile'])) {
2432
						$scconf['secrets']['ike-' . $suffix++] = array(
2433
							'secret' => '0s' . base64_encode(trim($ph1ent['pre-shared-key'])),
2434
							'id-0' => $myid,
2435
							'id-1' => '%any',
2436
						);
2437
						$scconf['secrets']['ike-' . $suffix++] = array(
2438
							'secret' => '0s' . base64_encode(trim($ph1ent['pre-shared-key'])),
2439
						);
2440
					}
2441
				}
2442
			}
2443

    
2444
			/* if the client authenticates with a cert add the
2445
			 * client cert CA chain to the list of CAs to write
2446
			 */
2447
			if (in_array($ph1ent['authentication_method'],
2448
			    array('cert', 'eap-tls', 'xauth_cert_server', 'pkcs11'))) {
2449
				if (!empty($ph1ent['caref']) && !array_key_exists($ph1ent['caref'], $vpncas)) {
2450
					$thisca = lookup_ca($ph1ent['caref']);
2451
					$vpncas[$ph1ent['caref']] = $thisca;
2452
					/* follow chain up to root */
2453
					$cachain = ca_chain_array($thisca);
2454
					if ($cachain and is_array($cachain)) {
2455
						foreach ($cachain as $cacrt) {
2456
							$vpncas[$cacrt['refid']] = $cacrt;
2457
						}
2458
					}
2459
				}
2460
			}
2461
		}
2462
	}
2463

    
2464
	/* Write the required CAs */
2465
	foreach ($vpncas as $carefid => $cadata) {
2466
		$cacrt = base64_decode($cadata['crt']);
2467
		$cacrtattrs = openssl_x509_parse($cacrt);
2468
		if (!is_array($cacrtattrs) || !isset($cacrtattrs['hash'])) {
2469
			log_error(sprintf(gettext("Error: Invalid certificate hash info for %s"), $cadata['descr']));
2470
			continue;
2471
		}
2472
		$cafilename = "{$ipsec_swanctl_dirs['capath']}/{$cacrtattrs['hash']}.0";
2473
		if (!@file_put_contents($cafilename, $cacrt)) {
2474
				log_error(sprintf(gettext("Error: Cannot write IPsec CA file for %s"), $cadata['descr']));
2475
				continue;
2476
		}
2477
	}
2478

    
2479
	/* Add user PSKs */
2480
	if (is_array($config['system']) && is_array($config['system']['user'])) {
2481
		foreach ($config['system']['user'] as $user) {
2482
			if (!empty($user['ipsecpsk'])) {
2483
				$scconf['secrets']['ike-' . $suffix++] = array(
2484
					'secret' => '0s' . base64_encode(trim($user['ipsecpsk'])),
2485
					'id-0' => $myid,
2486
					'id-1' => $user['name'],
2487
				);
2488
			}
2489
		}
2490
		unset($user);
2491
	}
2492

    
2493
	/* add PSKs for mobile clients */
2494
	if (is_array($ipseccfg['mobilekey'])) {
2495
		foreach ($ipseccfg['mobilekey'] as $key) {
2496
			if (($key['ident'] == 'allusers') ||
2497
			    ($key['ident'] == 'any')) {
2498
				$key['ident'] = '%any';
2499
			}
2500
			$scconf['secrets']['eap-' . $suffix++] = array(
2501
				'secret' => '0s' . base64_encode(trim($key['pre-shared-key'])),
2502
				'id-0' => $key['ident'],
2503
			);
2504
		}
2505
		unset($key);
2506
	}
2507
	return;
2508
}
2509

    
2510
/****f* ipsec/ipsec_configure
2511
 * NAME
2512
 *   ipsec_configure - Configure IPsec
2513
 * INPUTS
2514
 *   $restart: Boolean (default false), whether or not to restart the IPsec
2515
 *             daemons.
2516
 * RESULT
2517
 *   IPsec-related configuration files are written, daemon is started or stopped
2518
 *   appropriately.
2519
 ******/
2520
function ipsec_configure($restart = false) {
2521
	global $aggressive_mode_psk, $a_client, $a_phase1, $a_phase2, $config,
2522
		$filterdns_list, $g, $ifacesuse, $ipsec_idhandling, $ipsec_log_cats,
2523
		$ipsec_log_sevs, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs,
2524
		$ipseccfg, $mobile_ipsec_auth, $natfilterrules, $p1_ealgos,
2525
		$p2_ealgos, $rgmap, $sa, $sn, $scconf, $tunnels, $mobile_configured,
2526
		$ipsec_vti_cleanup_ifs, $conn_defaults, $pool_addrs;
2527

    
2528
	/* service may have been enabled, disabled, or otherwise changed in a
2529
	 *way requiring rule updates */
2530
	filter_configure();
2531

    
2532
	if (!ipsec_enabled()) {
2533
		/* IPsec is disabled */
2534
		/* Stop charon */
2535
		mwexec("/usr/local/sbin/strongswanrc stop");
2536
		/* Stop dynamic monitoring */
2537
		killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
2538
		/* Wait for process to die */
2539
		sleep(2);
2540
		/* Shutdown enc0 interface*/
2541
		mwexec("/sbin/ifconfig enc0 down");
2542
		ipsec_gre_default_mtu(); 
2543
		return 0;
2544
	} else {
2545
		/* Startup enc0 interface */
2546
		mwexec("/sbin/ifconfig enc0 up");
2547
	}
2548

    
2549
	if (platform_booting()) {
2550
		echo gettext("Configuring IPsec VPN... ");
2551
	}
2552

    
2553
	$ipsecstartlock = lock('ipsec', LOCK_EX);
2554

    
2555
	/* Prepare automatic ping_hosts.sh data */
2556
	unlink_if_exists("{$g['vardb_path']}/ipsecpinghosts");
2557
	touch("{$g['vardb_path']}/ipsecpinghosts");
2558
	$ipsecpinghostsactive = false;
2559

    
2560
	/* Populate convenience variables */
2561
	$syscfg = $config['system'];
2562
	init_config_arr(array('ipsec', 'phase1'));
2563
	$ipseccfg = $config['ipsec'];
2564
	$a_phase1 = $config['ipsec']['phase1'];
2565
	init_config_arr(array('ipsec', 'phase2'));
2566
	$a_phase2 = $config['ipsec']['phase2'];
2567
	init_config_arr(array('ipsec', 'client'));
2568
	$a_client = $config['ipsec']['client'];
2569

    
2570
	$mobile_configured = false;
2571

    
2572
	/* Setup a single structured array to process, to avoid repeatedly
2573
	 * looping through the arrays to locate entries later. */
2574
	$tunnels = array();
2575
	foreach ($a_phase1 as $p1) {
2576
		if (isset($p1['mobile']) && !isset($p1['disabled'])) {
2577
			$mobile_configured = true;
2578
		}
2579
		$tunnels[$p1['ikeid']] = $p1;
2580
		$tunnels[$p1['ikeid']]['p2'] = array();
2581
	}
2582
	foreach ($a_phase2 as $p2) {
2583
		$tunnels[$p2['ikeid']]['p2'][] = $p2;
2584
	}
2585

    
2586
	$ipsec_vti_cleanup_ifs = array();
2587
	$rgmap = array();
2588
	$filterdns_list = array();
2589
	$aggressive_mode_psk = false;
2590
	$mobile_ipsec_auth = "";
2591
	$ifacesuse = array();
2592
	$natfilterrules = false;
2593

    
2594
	/* Configure asynchronous crypto. See https://redmine.pfsense.org/issues/8772 */
2595
	set_sysctl(array('net.inet.ipsec.async_crypto' => (int) (isset($ipseccfg['async_crypto']) && ($ipseccfg['async_crypto'] == "enabled"))));
2596

    
2597
	/* Build a list of all IPsec interfaces configured on the firewall at the OS level */
2598
	foreach (get_interface_arr() as $thisif) {
2599
		if (substr($thisif, 0, 5) == "ipsec") {
2600
			$ipsec_vti_cleanup_ifs[] = $thisif;
2601
		}
2602
	}
2603

    
2604
	/* Create directory structure for IPsec */
2605
	ipsec_create_dirs();
2606

    
2607
	/* Setup gateways and interfaces */
2608
	ipsec_setup_gwifs();
2609

    
2610
	/* Setup and write strongswan.conf */
2611
	ipsec_setup_strongswan();
2612

    
2613
	/* Start Global Connection default values */
2614
	$conn_defaults = array();
2615
	/* Fragmentation is on for everyone */
2616
	$conn_defaults['fragmentation'] = "yes";
2617
	/* Default to 'replace' for unique IDs (was 'yes' in ipsec.conf previously) */
2618
	$conn_defaults['unique'] = 'replace';
2619
	/* If the configuration has a valid alternate value for unique ID handling,
2620
	 * use it instead. */
2621
	if (!empty($config['ipsec']['uniqueids']) &&
2622
	    array_key_exists($config['ipsec']['uniqueids'], $ipsec_idhandling)) {
2623
		$conn_defaults['unique'] = $config['ipsec']['uniqueids'];
2624
	}
2625
	if (isset($config['ipsec']['strictcrlpolicy'])) {
2626
		$conn_defaults['strictcrlpolicy'] = "yes";
2627
	}
2628
	/* Disable ipcomp for now. redmine #6167
2629
	if (isset($config['ipsec']['compression'])) {
2630
		$conn_defaults['compress'] = "yes";
2631
	}
2632
	set_single_sysctl('net.inet.ipcomp.ipcomp_enable', (isset($config['ipsec']['compression'])) ? 1 : 0);
2633
	*/
2634
	/* End Global Connection Defaults */
2635

    
2636
	/* Start swanctl configuration (scconf) */
2637
	$scconf = array();
2638
	$scconf[] = "# This file is automatically generated. Do not edit";
2639
	$scconf['connections'] = array();
2640
	/* Setup LAN bypass */
2641
	ipsec_setup_bypasslan();
2642
	/* Setup connections */
2643
	ipsec_setup_tunnels();
2644
	$scconf['pools'] = array();
2645
	if ($mobile_configured) {
2646
		/* Setup mobile address pools */
2647
		ipsec_setup_pools();
2648
		/* Setup per-user pools */
2649
		ipsec_setup_userpools();
2650
	}
2651
	/* Setup secret data */
2652
	$scconf['secrets'] = array();
2653
	ipsec_setup_secrets();
2654

    
2655
	@file_put_contents("{$g['varetc_path']}/ipsec/swanctl.conf", ipsec_strongswan_confgen($scconf));
2656

    
2657
	/* Clean up unused VTI interfaces */
2658
	foreach ($ipsec_vti_cleanup_ifs as $cleanif) {
2659
		if (does_interface_exist($cleanif)) {
2660
			mwexec("/sbin/ifconfig " . escapeshellarg($cleanif) . " destroy", false);
2661
		}
2662
	}
2663

    
2664
	/* set default MTU to 1400 for GRE over IPsec, othewise to 1476 */
2665
	ipsec_gre_default_mtu(); 
2666

    
2667
	/* Manage process */
2668
	if ($restart === true) {
2669
		mwexec_bg("/usr/local/sbin/strongswanrc restart", false);
2670
	} else {
2671
		if (isvalidpid("{$g['varrun_path']}/charon.pid")) {
2672
			mwexec_bg("/usr/local/sbin/strongswanrc reload", false);
2673
		} else {
2674
			mwexec_bg("/usr/local/sbin/strongswanrc start", false);
2675
		}
2676
	}
2677

    
2678
	// Run ping_hosts.sh once if it's enabled to avoid wait for minicron
2679
	if ($ipsecpinghostsactive) {
2680
		mwexec_bg("/usr/local/bin/ping_hosts.sh");
2681
	}
2682

    
2683
	if ($natfilterrules == true) {
2684
		filter_configure();
2685
	}
2686
	/* start filterdns, if necessary */
2687
	if (count($filterdns_list) > 0) {
2688
		$interval = 60;
2689
		if (!empty($ipseccfg['dns-interval']) && is_numeric($ipseccfg['dns-interval'])) {
2690
			$interval = $ipseccfg['dns-interval'];
2691
		}
2692

    
2693
		$hostnames = "";
2694
		array_unique($filterdns_list);
2695
		foreach ($filterdns_list as $hostname) {
2696
			$hostnames .= "cmd {$hostname} '/usr/local/sbin/pfSctl -c \"service reload ipsecdns\"'\n";
2697
		}
2698
		file_put_contents("{$g['varetc_path']}/ipsec/filterdns-ipsec.hosts", $hostnames);
2699
		unset($hostnames);
2700

    
2701
		if (isvalidpid("{$g['varrun_path']}/filterdns-ipsec.pid")) {
2702
			sigkillbypid("{$g['varrun_path']}/filterdns-ipsec.pid", "HUP");
2703
		} else {
2704
			mwexec_bg("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-ipsec.pid -i {$interval} -c {$g['varetc_path']}/ipsec/filterdns-ipsec.hosts -d 1");
2705
		}
2706
	} else {
2707
		killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
2708
		@unlink("{$g['varrun_path']}/filterdns-ipsec.pid");
2709
	}
2710

    
2711
	if (platform_booting()) {
2712
		echo "done\n";
2713
	}
2714

    
2715
	unlock($ipsecstartlock);
2716
	return count($filterdns_list);
2717
}
2718

    
2719
function ipsec_gre_default_mtu() {
2720
	global $config;
2721

    
2722
	foreach ($config['interfaces'] as $if => $ifdetail) { 
2723
		if (interface_is_type($ifdetail['if'], 'gre') && !isset($ifdetail['mtu'])) {
2724
			if (is_greipsec($ifdetail['if'])) {
2725
				set_interface_mtu($ifdetail['if'], 1400);
2726
			} else {
2727
				set_interface_mtu($ifdetail['if'], 1476);
2728
			}
2729
		}
2730
	}
2731
}
2732
?>
(26-26/60)