Project

General

Profile

Download (93.1 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-2021 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('Close connection and clear SA'),
214
	'start' => gettext('Restart/Reconnect'),
215
	'trap' => gettext('Close connection and reconnect on demand'),
216
);
217

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

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

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

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

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

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

    
279
	return false;
280
}
281

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

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

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

    
295
	return false;
296
}
297

    
298
function ipsec_ikeid_next() {
299

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

    
305
	return $ikeid;
306
}
307

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

    
313
	if ($ph1ent['interface']) {
314
		if (substr($ph1ent['interface'], 0, 4) == "_vip") {
315
			$if = $ph1ent['interface'];
316
		} else {
317
			$if = get_failover_interface($ph1ent['interface']);
318
		}
319
	} else {
320
		$if = "wan";
321
	}
322
	/* get correct interface name for 6RD/6to4 interfaces
323
	 * see https://redmine.pfsense.org/issues/11643 */
324
	if (is_stf_interface($ph1ent['interface'])) {
325
		$ip6 = get_interface_ipv6($ph1ent['interface']);
326
	} else {
327
		$ip6 = get_interface_ipv6($if);
328
	}
329
	$ip4 = get_interface_ip($if);
330
	if ($ph1ent['protocol'] == "inet6") {
331
		$interfaceip = $ip6;
332
	} elseif ($ph1ent['protocol'] == "inet") {
333
		$interfaceip = $ip4;
334
	} elseif ($ph1ent['protocol'] == "both") {
335
		$ifips = array();
336
		if (!empty($ip4)) {
337
			$ifips[] = $ip4;
338
		}
339
		if (!empty($ip6)) {
340
			$ifips[] = $ip6;
341
		}
342
		$interfaceip = implode(',', $ifips);
343
	}
344

    
345
	return $interfaceip;
346
}
347

    
348
/*
349
 * Return phase1 local address
350
 */
351
function ipsec_get_phase1_dst(& $ph1ent) {
352
	global $g;
353

    
354
	if (empty($ph1ent['remote-gateway'])) {
355
		return false;
356
	}
357
	$rg = $ph1ent['remote-gateway'];
358
	if (!is_ipaddr($rg)) {
359
		if (!platform_booting()) {
360
			return resolve_retry($rg, $ph1ent['protocol']);
361
		}
362
	}
363
	if (!is_ipaddr($rg)) {
364
		return false;
365
	}
366

    
367
	return $rg;
368
}
369

    
370
/*
371
 * Return phase2 idinfo in cidr format
372
 */
373
function ipsec_idinfo_to_cidr(& $idinfo, $addrbits = false, $mode = "") {
374
	global $config;
375

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

    
404
			if ($mode == "tunnel6") {
405
				$address = get_interface_ipv6($idinfo['type']);
406
				$netbits = get_interface_subnetv6($idinfo['type']);
407
				$address = gen_subnetv6($address, $netbits);
408
				return "{$address}/{$netbits}";
409
			} else {
410
				$address = get_interface_ip($idinfo['type']);
411
				$netbits = get_interface_subnet($idinfo['type']);
412
				$address = gen_subnet($address, $netbits);
413
				return "{$address}/{$netbits}";
414
			}
415
			break; /* NOTREACHED */
416
	}
417
}
418

    
419
/*
420
 * Return phase2 idinfo in address/netmask format
421
 */
422
function ipsec_idinfo_to_subnet(& $idinfo, $addrbits = false) {
423
	global $config;
424

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

    
460
/*
461
 *  Return phase2 idinfo in text format
462
 */
463
function ipsec_idinfo_to_text(& $idinfo) {
464
	global $config;
465

    
466
	switch ($idinfo['type']) {
467
		case "address":
468
			return $idinfo['address'];
469
			break; /* NOTREACHED */
470
		case "network":
471
			return $idinfo['address']."/".$idinfo['netbits'];
472
			break; /* NOTREACHED */
473
		case "mobile":
474
			return gettext("Mobile Client");
475
			break; /* NOTREACHED */
476
		case "none":
477
			return gettext("None");
478
			break; /* NOTREACHED */
479
		default:
480
			if (!empty($config['interfaces'][$idinfo['type']])) {
481
				return convert_friendly_interface_to_friendly_descr($idinfo['type']);
482
			} else {
483
				return strtoupper($idinfo['type']);
484
			}
485
			break; /* NOTREACHED */
486
	}
487
}
488

    
489
/*
490
 * Return phase1 association for phase2
491
 */
492
function ipsec_lookup_phase1(& $ph2ent, & $ph1ent) {
493
	global $config;
494

    
495
	if (!is_array($config['ipsec'])) {
496
		return false;
497
	}
498
	if (!is_array($config['ipsec']['phase1'])) {
499
		return false;
500
	}
501
	if (empty($config['ipsec']['phase1'])) {
502
		return false;
503
	}
504

    
505
	foreach ($config['ipsec']['phase1'] as $ph1tmp) {
506
		if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
507
			$ph1ent = $ph1tmp;
508
			return $ph1ent;
509
		}
510
	}
511

    
512
	return false;
513
}
514

    
515
/*
516
 * Check phase1 communications status
517
 */
518
function ipsec_phase1_status(&$ipsec_status, $ikeid) {
519

    
520
	foreach ($ipsec_status as $ike) {
521
		if ($ike['id'] == $ikeid) {
522
			if ($ike['status'] == 'established') {
523
				return true;
524
			}
525
		}
526
	}
527

    
528
	return false;
529
}
530

    
531
/*
532
 * Check phase2 communications status
533
 */
534
function ipsec_phase2_status(&$ipsec_status, &$phase2) {
535

    
536
	if (ipsec_lookup_phase1($ph2ent, $ph1ent)) {
537
		return ipsec_phase1_status($ipsec_status, $ph1ent['ikeid']);
538
	}
539

    
540
	return false;
541
}
542

    
543
/*
544
 * Wrapper to call pfSense_ipsec_list_sa() when IPsec is enabled
545
 */
546
function ipsec_list_sa() {
547

    
548
	if (ipsec_enabled()) {
549
		return pfSense_ipsec_list_sa();
550
	}
551

    
552
	return array();
553
}
554

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

    
606
	return $spd;
607
}
608

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

    
659
	return $sad;
660
}
661

    
662
/*
663
 * Return dump of mobile user list
664
 */
665
function ipsec_dump_mobile() {
666
	global $g, $config;
667

    
668
	if(!isset($config['ipsec']['client']['enable'])) {
669
		return array();
670
	}
671

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

    
675
	if ($rc != 0) {
676
		log_error(gettext("Unable to find IPsec daemon leases file. Could not display mobile user stats!"));
677
		return array();
678
	}
679

    
680
	$response = array(
681
		'pool' => array(),
682
	);
683

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

    
709
	unset($_gb, $output, $rc, $pool_regex);
710

    
711
	return $response;
712
}
713

    
714
function ipsec_mobilekey_sort() {
715
	global $config;
716

    
717
	function mobilekeycmp($a, $b) {
718
		return strcmp($a['ident'][0], $b['ident'][0]);
719
	}
720

    
721
	usort($config['ipsec']['mobilekey'], "mobilekeycmp");
722
}
723

    
724
function ipsec_get_number_of_phase2($ikeid) {
725
	global $config;
726
	$a_phase2 = $config['ipsec']['phase2'];
727

    
728
	$nbph2 = 0;
729

    
730
	if (is_array($a_phase2) && count($a_phase2)) {
731
		foreach ($a_phase2 as $ph2tmp) {
732
			if ($ph2tmp['ikeid'] == $ikeid) {
733
				$nbph2++;
734
			}
735
		}
736
	}
737

    
738
	return $nbph2;
739
}
740

    
741
function ipsec_get_descr($ikeid) {
742
	global $config;
743

    
744
	if (!isset($config['ipsec']['phase1']) ||
745
	    !is_array($config['ipsec']['phase1'])) {
746
		return '';
747
	}
748

    
749
	foreach ($config['ipsec']['phase1'] as $p1) {
750
		if ($p1['ikeid'] == $ikeid) {
751
			return $p1['descr'];
752
		}
753
	}
754

    
755
	return '';
756
}
757

    
758
function ipsec_get_phase1($ikeid) {
759
		global $config;
760

    
761
		if (!isset($config['ipsec']['phase1']) ||
762
		    !is_array($config['ipsec']['phase1'])) {
763
			return '';
764
		}
765

    
766
		$a_phase1 = $config['ipsec']['phase1'];
767
		foreach ($a_phase1 as $p1) {
768
			if ($p1['ikeid'] == $ikeid) {
769
				return $p1;
770
			}
771
		}
772
		unset($a_phase1);
773
}
774

    
775
function ipsec_fixup_ip($ipaddr) {
776
	if (is_ipaddrv6($ipaddr) || is_subnetv6($ipaddr)) {
777
		return text_to_compressed_ip6($ipaddr);
778
	} else {
779
		return $ipaddr;
780
	}
781
}
782

    
783
function ipsec_find_id(& $ph1ent, $side = "local", $rgmap = array()) {
784
	if ($side == "local") {
785
		$id_type = $ph1ent['myid_type'];
786
		$id_data = $ph1ent['myid_data'];
787

    
788
		$addr = ipsec_get_phase1_src($ph1ent);
789
		if (!$addr) {
790
			return array();
791
		}
792
		/* When automatically guessing, use the first address. */
793
		$addr = explode(',', $addr);
794
		$addr = $addr[0];
795
	} elseif ($side == "peer") {
796
		$id_type = $ph1ent['peerid_type'];
797
		$id_data = $ph1ent['peerid_data'];
798

    
799
		if (isset($ph1ent['mobile'])) {
800
			$addr = "%any";
801
		} else {
802
			$addr = $ph1ent['remote-gateway'];
803
		}
804
	} else {
805
		return array();
806
	}
807

    
808

    
809
	$thisid_type = $id_type;
810
	switch ($thisid_type) {
811
		case 'myaddress':
812
			$thisid_type = 'address';
813
			$thisid_data = $addr;
814
			break;
815
		case 'dyn_dns':
816
			$thisid_type = 'dns';
817
			$thisid_data = $id_data;
818
			break;
819
		case 'peeraddress':
820
			$thisid_type = 'address';
821
			$thisid_data = $rgmap[$ph1ent['remote-gateway']];
822
			break;
823
		case 'address':
824
			$thisid_data = $id_data;
825
			break;
826
		case 'fqdn':
827
			$thisid_data = "{$id_data}";
828
			break;
829
		case 'keyid tag':
830
			$thisid_type = 'keyid';
831
			$thisid_data = "{$id_data}";
832
			break;
833
		case 'user_fqdn':
834
			$thisid_type = 'userfqdn';
835
			$thisid_data = "{$id_data}";
836
			break;
837
		case 'asn1dn':
838
			$thisid_data = $id_data;
839
			break;
840
		case 'any':
841
			$thisid_data = '%any';
842
			break;
843
		default:
844
			break;
845
	}
846
	return array($thisid_type, $thisid_data);
847
}
848

    
849
/*
850
 * Fixup ID type/data to include prefix when necessary, add quotes, etc.
851
 */
852
function ipsec_fixup_id($type, $data) {
853
	/* List of types to pass through as-is without changes or adding prefix */
854
	$auto_types = array('address');
855
	/* List of types which need the resulting string double quoted. */
856
	$quote_types = array('keyid', 'asn1dn');
857

    
858
	/* If the first character of asn1dn type data is not #, then rely on
859
	 * automatic parsing https://redmine.pfsense.org/issues/4792 */
860
	if (($type == 'asn1dn') && !empty($data) && ($data[0] != '#')) {
861
		$auto_types[] = 'asn1dn';
862
	}
863

    
864
	if ($type == 'any') {
865
		$idstring = "%any";
866
	} elseif (!in_array($type, $auto_types)) {
867
		$idstring = "{$type}:{$data}";
868
	} else {
869
		$idstring = $data;
870
	}
871

    
872
	if (in_array($type, $quote_types)) {
873
		$idstring = "\"{$idstring}\"";
874
	}
875

    
876
	return $idstring;
877
}
878

    
879
function ipsec_fixup_network($network) {
880
	if (substr($network, -3) == '|/0') {
881
		$result = substr($network, 0, -3);
882
	} else {
883
		$tmp = explode('|', $network);
884
		if (isset($tmp[1])) {
885
			$result = $tmp[1];
886
		} else {
887
			$result = $tmp[0];
888
		}
889
		unset($tmp);
890
	}
891

    
892
	return $result;
893
}
894

    
895
function ipsec_new_reqid() {
896
	global $config;
897

    
898
	if (!is_array($config['ipsec']) || !is_array($config['ipsec']['phase2'])) {
899
		return;
900
	}
901

    
902
	$ipsecreqid = lock('ipsecreqids', LOCK_EX);
903
	$keyids = array();
904
	$keyid = 1;
905
	foreach ($config['ipsec']['phase2'] as $ph2) {
906
		$keyids[$ph2['reqid']] = $ph2['reqid'];
907
	}
908

    
909
	for ($i = 1; $i < 16000; $i++) {
910
		if (!isset($keyids[$i])) {
911
			$keyid = $i;
912
			break;
913
		}
914
	}
915
	unlock($ipsecreqid);
916

    
917
	return $keyid;
918
}
919

    
920
function ipsec_get_loglevels() {
921
	global $config, $ipsec_log_cats;
922
	$def_loglevel = '1';
923

    
924
	$levels = array();
925

    
926
	foreach (array_keys($ipsec_log_cats) as $cat) {
927
		if (isset($config['ipsec']['logging'][$cat])) {
928
			$levels[$cat] = $config['ipsec']['logging'][$cat];
929
		} elseif (in_array($cat, array('ike', 'chd', 'cfg'))) {
930
			$levels[$cat] = "2";
931
		} else {
932
			$levels[$cat] = $def_loglevel;
933
		}
934
	}
935
	return $levels;
936
}
937

    
938
function ipsec_vti($ph1ent, $returnaddresses = false, $skipdisabled = true) {
939
	global $config;
940
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
941
		return false;
942
	}
943

    
944
	$is_vti = false;
945
	$vtisubnet_spec = array();
946

    
947
	foreach ($config['ipsec']['phase2'] as $ph2ent) {
948
		if ($ph1ent['ikeid'] != $ph2ent['ikeid']) {
949
			continue;
950
		}
951
		if ($ph2ent['mode'] == 'vti') {
952
			if ($returnaddresses) {
953
				$vtisubnet_spec[] = array(
954
					'left' => ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']),
955
					'right' => ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']),
956
					'descr' => $ph2ent['descr'],
957
				);
958
			}
959
			if (!$skipdisabled && isset($ph2ent['disabled'])) {
960
				continue;
961
			} else {
962
				$is_vti = true;
963
			}
964
		}
965
	}
966
	return ($returnaddresses) ? $vtisubnet_spec : $is_vti;
967
}
968

    
969
/* Called when IPsec is reloaded through rc.newipsecdns and similar, gives
970
 * packages an opportunity to execute custom code when IPsec reloads.
971
 */
972
function ipsec_reload_package_hook() {
973
	global $g, $config;
974

    
975
	init_config_arr(array('installedpackages', 'package'));
976
	foreach ($config['installedpackages']['package'] as $package) {
977
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
978
			continue;
979
		}
980

    
981
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
982
		if (!empty($pkg_config['include_file']) &&
983
		    file_exists($pkg_config['include_file'])) {
984
			require_once($pkg_config['include_file']);
985
		}
986
		if (empty($pkg_config['ipsec_reload_function'])) {
987
			continue;
988
		}
989
		$pkg_ipsec_reload = $pkg_config['ipsec_reload_function'];
990
		if (!function_exists($pkg_ipsec_reload)) {
991
			continue;
992
		}
993
		$pkg_ipsec_reload();
994
	}
995
}
996

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

    
1032
	return $modpmap[$index];
1033
}
1034

    
1035
/*
1036
 * Forcefully restart IPsec
1037
 * This is required for when dynamic interfaces reload
1038
 * For all other occasions the normal ipsec_configure()
1039
 * will gracefully reload the settings without restarting
1040
 */
1041
function ipsec_force_reload($interface = "") {
1042
	global $g, $config;
1043

    
1044
	if (!ipsec_enabled()) {
1045
		return;
1046
	}
1047

    
1048
	$ipseccfg = $config['ipsec'];
1049

    
1050
	if (!empty($interface) && is_array($ipseccfg['phase1'])) {
1051
		$found = false;
1052
		foreach ($ipseccfg['phase1'] as $ipsec) {
1053
			if (!isset($ipsec['disabled']) && ($ipsec['interface'] == $interface)) {
1054
				$found = true;
1055
				break;
1056
			}
1057
		}
1058
		if (!$found) {
1059
			log_error(sprintf(gettext("Ignoring IPsec reload since there are no tunnels on interface %s"), $interface));
1060
			return;
1061
		}
1062
	}
1063

    
1064
	/* If we get this far then we need to take action. */
1065
	log_error(gettext("Forcefully reloading IPsec"));
1066
	ipsec_configure();
1067
}
1068

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

    
1113
global $g, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs;
1114
$ipsec_swanctl_basedir = "{$g['varetc_path']}/ipsec";
1115
$ipsec_swanctl_dirs = array(
1116
	'conf'     => "{$ipsec_swanctl_basedir}/conf.d",
1117
	'certpath' => "{$ipsec_swanctl_basedir}/x509",
1118
	'capath'   => "{$ipsec_swanctl_basedir}/x509ca",
1119
	'aapath'   => "{$ipsec_swanctl_basedir}/x509aa",
1120
	'ocsppath' => "{$ipsec_swanctl_basedir}/x509ocsp",
1121
	'crlpath'  => "{$ipsec_swanctl_basedir}/x509crl",
1122
	'acpath'   => "{$ipsec_swanctl_basedir}/x509ac",
1123
	'rsakeys'  => "{$ipsec_swanctl_basedir}/rsa",
1124
	'eckeys'   => "{$ipsec_swanctl_basedir}/ecdsa",
1125
	'keypath'  => "{$ipsec_swanctl_basedir}/private",
1126
	'pubkpath' => "{$ipsec_swanctl_basedir}/pubkey",
1127
	'blisspath' => "{$ipsec_swanctl_basedir}/bliss",
1128
	'pkcs8path' => "{$ipsec_swanctl_basedir}/pkcs8",
1129
	'pkcs12path' => "{$ipsec_swanctl_basedir}/pkcs12",
1130
);
1131

    
1132
/****f* ipsec/ipsec_create_dirs
1133
 * NAME
1134
 *   ipsec_create_dirs - Create default set of strongSwan configuration directories.
1135
 * INPUTS
1136
 *   None
1137
 * RESULT
1138
 *   Cleans up and creates strongSwan configuration directories and links.
1139
 ******/
1140
function ipsec_create_dirs() {
1141
	global $config, $g, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs;
1142

    
1143
	/* Cleanup base paths to ensure old files are not left behind (#5238) */
1144
	if (!empty($ipsec_swanctl_basedir)) {
1145
		@rmdir_recursive($ipsec_swanctl_basedir, false);
1146
	}
1147
	/* Create directory structure */
1148
	array_map('safe_mkdir', array_values($ipsec_swanctl_dirs));
1149

    
1150
	/* Create and link strongSwan config */
1151
	$ssdpath = "{$g['varetc_path']}/ipsec/strongswan.d";
1152
	if (!file_exists($ssdpath) || !is_link($ssdpath)) {
1153
		if (is_dir($ssdpath) && !is_link($ssdpath)) {
1154
			@rmdir_recursive($ssdpath, false);
1155
		} else {
1156
			@unlink($ssdpath);
1157
		}
1158
		@symlink("/usr/local/etc/strongswan.d",
1159
		    $ssdpath);
1160
	}
1161
	if (!file_exists("/usr/local/etc/strongswan.conf") ||
1162
	    !is_link("/usr/local/etc/strongswan.conf")) {
1163
		@unlink("/usr/local/etc/strongswan.conf");
1164
		@symlink("{$g['varetc_path']}/ipsec/strongswan.conf",
1165
		    "/usr/local/etc/strongswan.conf");
1166
	}
1167
}
1168

    
1169
/****f* ipsec/ipsec_setup_gwifs
1170
 * NAME
1171
 *   ipsec_setup_gwifs - Setup IPsec-related interfaces and gateways
1172
 * INPUTS
1173
 *   None
1174
 * RESULT
1175
 *   Sets up VTI interfaces and gateways, populates ipsecpinghosts
1176
 ******/
1177
function ipsec_setup_gwifs() {
1178
	global $g, $a_phase1, $a_phase2, $rgmap, $filterdns_list,
1179
		$aggressive_mode_psk, $mobile_ipsec_auth, $ifacesuse,
1180
		$ipsecpinghostsactive;
1181
	/* resolve all local, peer addresses and setup pings */
1182
	unset($iflist);
1183
	if (is_array($a_phase1) && count($a_phase1)) {
1184
		$ipsecpinghosts = array();
1185
		/* step through each phase1 entry */
1186
		foreach ($a_phase1 as $ph1ent) {
1187
			if (isset($ph1ent['disabled'])) {
1188
				continue;
1189
			}
1190

    
1191
			if (substr($ph1ent['interface'], 0, 4) == "_vip") {
1192
				$vpninterface = get_configured_vip_interface($ph1ent['interface']);
1193
				$ifacesuse[] = get_real_interface($vpninterface);
1194
			} else {
1195
				$vpninterface = get_failover_interface($ph1ent['interface']);
1196
				if (substr($vpninterface, 0, 4) == "_vip") {
1197
					$vpninterface = get_configured_vip_interface($vpninterface);
1198
					$ifacesuse[] = get_real_interface($vpninterface);
1199
				} elseif (!empty($vpninterface)) {
1200
					$ifacesuse[] = $vpninterface;
1201
				}
1202
			}
1203

    
1204
			if ($ph1ent['mode'] == "aggressive" && ($ph1ent['authentication_method'] == "pre_shared_key" || $ph1ent['authentication_method'] == "xauth_psk_server")) {
1205
				$aggressive_mode_psk = true;
1206
			}
1207

    
1208
			$ikeid = $ph1ent['ikeid'];
1209

    
1210
			$local_spec = ipsec_get_phase1_src($ph1ent);
1211
			/* When automatically guessing, use the first address. */
1212
			$local_spec  = explode(',', $local_spec);
1213
			$local_spec  = $local_spec[0];
1214
			if (!is_ipaddr($local_spec)) {
1215
				log_error(sprintf(gettext("IPsec ERROR: Could not find phase 1 source for connection %s. Omitting from configuration file."), $ph1ent['descr']));
1216
				continue;
1217
			}
1218

    
1219
			if (isset($ph1ent['mobile'])) {
1220
				$mobile_ipsec_auth = $ph1ent['authentication_method'];
1221
				continue;
1222
			}
1223

    
1224
			/* see if this tunnel has a hostname for the remote-gateway. If so,
1225
			   try to resolve it now and add it to the list for filterdns */
1226
			$rg = $ph1ent['remote-gateway'];
1227
			if (!is_ipaddr($rg)) {
1228
				$filterdns_list[] = "{$rg}";
1229
				add_hostname_to_watch($rg);
1230
				if (!platform_booting()) {
1231
					$rg = resolve_retry($rg, $ph1ent['protocol']);
1232
				}
1233
				if (!is_ipaddr($rg)) {
1234
					continue;
1235
				}
1236
			}
1237
			if (!isset($ph1ent['gw_duplicates']) && array_search($rg, $rgmap)) {
1238
				log_error(sprintf(gettext("The remote gateway %s already exists on another phase 1 entry"), $rg));
1239
				continue;
1240
			}
1241
			$rgmap[$ph1ent['remote-gateway']] = $rg;
1242

    
1243
			$is_vti = false;
1244
			if (is_array($a_phase2)) {
1245
				/* step through each phase2 entry */
1246
				foreach ($a_phase2 as $ph2ent) {
1247
					if ($ph2ent['mode'] == 'vti') {
1248
						$is_vti = true;
1249
					}
1250
					if (isset($ph2ent['disabled']) || ($ikeid != $ph2ent['ikeid'])) {
1251
						continue;
1252
					}
1253

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

    
1313
/****f* ipsec/ipsec_logging_config
1314
 * NAME
1315
 *   ipsec_logging_config - Generate an array containing strongSwan logging
1316
 *                          values.
1317
 * INPUTS
1318
 *   None
1319
 * RESULT
1320
 *   Returns an array which can be merged into the strongswan daemon logging
1321
 *   values so that each logging category is represented, even those not listed
1322
 *   in config.xml.
1323
 ******/
1324
function ipsec_logging_config() {
1325
	global $config, $ipsec_log_cats, $ipsec_log_sevs;
1326
	$logcfg = array();
1327
	$log_levels = ipsec_get_loglevels();
1328
	foreach (array_keys($ipsec_log_cats) as $cat) {
1329
		if (is_numeric($log_levels[$cat]) &&
1330
		    in_array(intval($log_levels[$cat]), array_keys($ipsec_log_sevs), true)) {
1331
			$logcfg[$cat] = $log_levels[$cat];
1332
		}
1333
	}
1334
	return $logcfg;
1335
}
1336

    
1337
/****f* ipsec/ipsec_setup_strongswan
1338
 * NAME
1339
 *   ipsec_setup_strongswan - Generate the strongswan.conf configuration file.
1340
 * INPUTS
1341
 *   None
1342
 * RESULT
1343
 *   Determines strongswan.conf values and crafts the configuration file in the
1344
 *   appropriate format.
1345
 * NOTES
1346
 *   Called from ipsec_configure()
1347
 ******/
1348
function ipsec_setup_strongswan() {
1349
	global $config, $g, $mobile_ipsec_auth, $a_client, $a_phase2, $aggressive_mode_psk, $ifacesuse;
1350

    
1351
	/* strongswan.conf array */
1352
	$ssconf = array();
1353
	$ssconf[] = "# Automatically generated config file - DO NOT MODIFY. Changes will be overwritten.";
1354
	$ssconf['starter'] = array();
1355
	$ssconf['starter']['load_warning'] = "no";
1356

    
1357
	$ssconf['charon'] = array();
1358
	$ssconf['charon'][] = '# number of worker threads in charon';
1359
	$ssconf['charon']['threads'] = '16';
1360
	$ssconf['charon']['ikesa_table_size'] = '32';
1361
	$ssconf['charon']['ikesa_table_segments'] = '4';
1362
	$ssconf['charon']['init_limit_half_open'] = '1000';
1363
	$ssconf['charon']['install_routes'] = 'no';
1364
	$ssconf['charon']['load_modular'] = 'yes';
1365
	$ssconf['charon']['ignore_acquire_ts'] = 'yes';
1366

    
1367
	if ($aggressive_mode_psk) {
1368
		$stronconf = '';
1369
		if (file_exists("{$g['varetc_path']}/ipsec/strongswan.conf")) {
1370
			$stronconf = file_get_contents("{$g['varetc_path']}/ipsec/strongswan.conf");
1371
		}
1372
		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.");
1373
		$restart = (!empty($stronconf) && strpos($stronconf, 'i_dont_care_about_security_and_use_aggressive_mode_psk') === FALSE);
1374
		unset($stronconf);
1375
		$ssconf['charon']['i_dont_care_about_security_and_use_aggressive_mode_psk'] = "yes";
1376
	}
1377

    
1378
	if (isset($config['ipsec']['acceptunencryptedmainmode'])) {
1379
		$ssconf['charon']['accept_unencrypted_mainmode_messages'] = "yes";
1380
	}
1381

    
1382
	if (isset($config['ipsec']['maxexchange'])) {
1383
		$ssconf['charon']['max_ikev1_exchanges'] = $config['ipsec']['maxexchange'];
1384
	}
1385

    
1386
	$unity_enabled = isset($config['ipsec']['unityplugin']) ? 'yes' : 'no';
1387
	$ssconf['charon']['cisco_unity'] = $unity_enabled;
1388

    
1389
	if (isset($config['ipsec']['enableinterfacesuse']) && !empty($ifacesuse)) {
1390
		$ssconf['charon']['interfaces_use'] = implode(',', array_unique($ifacesuse));
1391
	}
1392

    
1393
	if (isset($config['ipsec']['makebeforebreak'])) {
1394
		$ssconf['charon']['make_before_break'] = "yes";
1395
	}
1396

    
1397
	if (isset($config['ipsec']['port'])) {
1398
		$ssconf['charon']['port'] = $config['ipsec']['port'];
1399
	}
1400

    
1401
	if (isset($config['ipsec']['port_nat_t'])) {
1402
		$ssconf['charon']['port_nat_t'] = $config['ipsec']['port_nat_t'];
1403
	}
1404

    
1405
	$ssconf['charon']['syslog'] = array();
1406
	$ssconf['charon']['syslog']['identifier'] = 'charon';
1407
	$ssconf['charon']['syslog'][] = "# log everything under daemon since it ends up in the same place regardless with our syslog.conf";
1408
	$ssconf['charon']['syslog']['daemon'] = array();
1409
	$ssconf['charon']['syslog']['daemon']['ike_name'] = 'yes';
1410
	$ssconf['charon']['syslog']['daemon'] = array_merge($ssconf['charon']['syslog']['daemon'], ipsec_logging_config());
1411
	$ssconf['charon']['syslog'][] = '# disable logging under auth so logs aren\'t duplicated';
1412
	$ssconf['charon']['syslog']['auth'] = array();
1413
	$ssconf['charon']['syslog']['auth']['default'] = -1;
1414

    
1415
	$ssconf['charon']['plugins'] = array();
1416
	$ssconf['charon']['plugins'][] = "# Load defaults";
1417
	$ssconf['charon']['plugins'][] = "include {$g['varetc_path']}/ipsec/strongswan.d/charon/*.conf";
1418
	$ssconf['charon']['plugins']['unity'] = array('load' => $unity_enabled);
1419
	$ssconf['charon']['plugins']['curve25519'] = array('load' => "yes");
1420

    
1421
	$ssconf['charon']['plugins']['pkcs11'] = array();
1422
	$ssconf['charon']['plugins']['pkcs11']['load'] = "yes";
1423
	$ssconf['charon']['plugins']['pkcs11']['modules'] = array();
1424
	$ssconf['charon']['plugins']['pkcs11']['modules']['opensc'] = array();
1425
	$ssconf['charon']['plugins']['pkcs11']['modules']['opensc']['load_certs'] = "yes";
1426
	$ssconf['charon']['plugins']['pkcs11']['modules']['opensc']['path'] = "/usr/local/lib/opensc-pkcs11.so";
1427

    
1428
	/* Find RADIUS servers designated for Mobile IPsec user auth */
1429
	$radius_servers = array();
1430
	foreach (explode(',', $config['ipsec']['client']['user_source']) as $user_source) {
1431
		$auth_server = auth_get_authserver($user_source);
1432
		$nice_user_source = strtolower(preg_replace('/[\s\.]+/', '_', $user_source));
1433
		if ($auth_server && ($auth_server['type'] === 'radius')) {
1434
			$radius_servers[$nice_user_source] = array();
1435
			$radius_servers[$nice_user_source]['address'] = $auth_server['host'];
1436
			$radius_servers[$nice_user_source]['secret'] = "\"{$auth_server['radius_secret']}\"";
1437
			$radius_servers[$nice_user_source]['auth_port'] = empty($auth_server['radius_auth_port']) ? 1812 : $auth_server['radius_auth_port'];;
1438
			$radius_servers[$nice_user_source]['acct_port'] = empty($auth_server['radius_acct_port']) ? 1813 : $auth_server['radius_acct_port'];
1439
		}
1440
	}
1441

    
1442
	/* Generate an eap-radius config section if appropriate */
1443
	if (count($radius_servers) && ($mobile_ipsec_auth === "eap-radius")) {
1444
		$ssconf['charon']['plugins']['eap-radius'] = array();
1445
		$ssconf['charon']['plugins']['eap-radius']['load'] = "2";
1446
		$ssconf['charon']['plugins']['eap-radius']['class_group'] = "yes";
1447
		$ssconf['charon']['plugins']['eap-radius']['eap_start'] = "no";
1448
		/* Activate RADIUS accounting only if it was selected on the IPsec Mobile Clients tab */
1449
		if ($auth_server && isset($auth_server['radius_acct_port']) &&
1450
		    (is_array($a_client) && ($a_client['radiusaccounting'] == "enabled"))) {
1451
			$ssconf['charon']['plugins']['eap-radius']['accounting'] = "yes";
1452
			$ssconf['charon']['plugins']['eap-radius']['accounting_close_on_timeout'] = "no";
1453
		}
1454
		/* advanced parameters, see https://redmine.pfsense.org/issues/11211 */
1455
		if (isset($a_client['radius_retransmit_base'])) {
1456
			$ssconf['charon']['plugins']['eap-radius']['retransmit_base'] = $a_client['radius_retransmit_base'];
1457
		}
1458
		if (isset($a_client['radius_retransmit_timeout'])) {
1459
			$ssconf['charon']['plugins']['eap-radius']['retransmit_timeout'] = $a_client['radius_retransmit_timeout'];
1460
		}
1461
		if (isset($a_client['radius_retransmit_tries'])) {
1462
			$ssconf['charon']['plugins']['eap-radius']['retransmit_tries'] = $a_client['radius_retransmit_tries'];
1463
		}
1464
		if (isset($a_client['radius_sockets'])) {
1465
			$ssconf['charon']['plugins']['eap-radius']['sockets'] = $a_client['radius_sockets'];
1466
		}
1467
		$ssconf['charon']['plugins']['eap-radius']['servers'] = $radius_servers;
1468
	}
1469

    
1470
	if (is_array($a_client) && isset($a_client['enable'])) {
1471
		if ($a_client['user_source'] != "none") {
1472
			$ssconf['charon']['plugins']['xauth-generic'] = array();
1473
			$ssconf['charon']['plugins']['xauth-generic']['script'] = "/etc/inc/ipsec.auth-user.php";
1474
			$authcfgs = array();
1475
			foreach (explode(",", $a_client['user_source']) as $authcfg) {
1476
				$authcfgs[] = ($authcfg == "system") ? "Local Database" : $authcfg;
1477
			}
1478
			$ssconf['charon']['plugins']['xauth-generic']['authcfg'] = implode(",", $authcfgs);
1479
		}
1480
	}
1481

    
1482
	@file_put_contents("{$g['varetc_path']}/ipsec/strongswan.conf", ipsec_strongswan_confgen($ssconf));
1483
}
1484

    
1485
/****f* ipsec/ipsec_setup_pools
1486
 * NAME
1487
 *   ipsec_setup_pools - Generate primary mobile pool configuration for swanctl
1488
  * INPUTS
1489
 *   None
1490
 * RESULT
1491
 *   Adds configured mobile pool settings to $scconf
1492
 * NOTES
1493
 *   These values were formerly in strongswan.conf but may now be configured in
1494
 *   pools, making future expansion to support multiple pools possible.
1495
 ******/
1496
function ipsec_setup_pools() {
1497
	global $config, $g, $mobile_ipsec_auth, $a_client, $a_phase2, $scconf;
1498
	if (!is_array($a_client) || !isset($a_client['enable'])) {
1499
		return;
1500
	}
1501

    
1502
	$scconf['mobile-pool'] = array();
1503
	$scconf['pools'] = array();
1504
	$pool_common =& $scconf['mobile-pool'];
1505

    
1506
	$rightdnsservers = array();
1507
	if (!empty($a_client['dns_server1'])) {
1508
		$rightdnsservers[] = $a_client['dns_server1'];
1509
	}
1510
	if (!empty($a_client['dns_server2'])) {
1511
		$rightdnsservers[] = $a_client['dns_server2'];
1512
	}
1513
	if (!empty($a_client['dns_server3'])) {
1514
		$rightdnsservers[] = $a_client['dns_server3'];
1515
	}
1516
	if (!empty($a_client['dns_server4'])) {
1517
		$rightdnsservers[] = $a_client['dns_server4'];
1518
	}
1519
	if (count($rightdnsservers)) {
1520
		$pool_common['dns'] = implode(',', $rightdnsservers);
1521
	}
1522

    
1523
	$cfgservers = array();
1524
	if (!empty($a_client['wins_server1'])) {
1525
		$cfgservers[] = $a_client['wins_server1'];
1526
	}
1527
	if (!empty($a_client['wins_server2'])) {
1528
		$cfgservers[] = $a_client['wins_server2'];
1529
	}
1530
	if (!empty($cfgservers)) {
1531
		$pool_common['nbns'] = implode(",", $cfgservers);
1532
	}
1533
	unset($cfgservers);
1534

    
1535
	$net_list4 = array();
1536
	$net_list6 = array();
1537
	if (isset($a_client['net_list']) && is_array($a_phase2)) {
1538
		foreach ($a_phase2 as $ph2ent) {
1539
			if (isset($ph2ent['disabled']) ||
1540
			    !isset($ph2ent['mobile'])) {
1541
				continue;
1542
			}
1543
			$nlent = ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']);
1544
			if (is_subnetv4($nlent)) {
1545
				$net_list4[] = $nlent;
1546
			} elseif (is_subnetv6($nlent)) {
1547
				$net_list6[] = $nlent;
1548
			}
1549
			unset($nlent);
1550
		}
1551
	}
1552
	if (!empty($a_client['dns_domain'])) {
1553
		$pool_common[] = "# Search domain and default domain";
1554
		$pool_common['28674'] = "\"{$a_client['dns_domain']}\"";
1555
		if (empty($a_client['dns_split'])) {
1556
			$pool_common['28675'] = "\"{$a_client['dns_domain']}\"";
1557
		}
1558
	}
1559

    
1560
	if (!empty($a_client['dns_split'])) {
1561
		$pool_common['28675'] = "\"{$a_client['dns_split']}\"";
1562
	}
1563

    
1564
	if (!empty($a_client['login_banner'])) {
1565
		$pool_common['28672'] = "\"{$a_client['login_banner']}\"";
1566
	}
1567

    
1568
	if (isset($a_client['save_passwd'])) {
1569
		$pool_common['28673'] = "1";
1570
	}
1571

    
1572
	if ($a_client['pfs_group']) {
1573
		$pool_common['28679'] = "\"{$a_client['pfs_group']}\"";
1574
	}
1575

    
1576
	if (!empty($a_client['pool_address'])) {
1577
		$scconf['pools']['mobile-pool-v4 : mobile-pool'] = array();
1578
		$v4pool =& $scconf['pools']['mobile-pool-v4 : mobile-pool'];
1579
		$v4pool['addrs'] = "{$a_client['pool_address']}/{$a_client['pool_netbits']}";
1580
		if (!empty($net_list4)) {
1581
			$v4pool['subnet'] = implode(",", $net_list4);
1582
			$v4pool['split_include'] = implode(",", $net_list4);
1583
			unset($net_list4);
1584
		}
1585
	}
1586
	if (!empty($a_client['pool_address_v6'])) {
1587
		$scconf['pools']['mobile-pool-v6 : mobile-pool'] = array();
1588
		$v6pool =& $scconf['pools']['mobile-pool-v6 : mobile-pool'];
1589
		$v6pool['addrs'] = "{$a_client['pool_address_v6']}/{$a_client['pool_netbits_v6']}";
1590
		if (!empty($net_list6)) {
1591
			$v6pool['subnet'] = implode(",", $net_list6);
1592
			$v6pool['split_include'] = implode(",", $net_list6);
1593
			unset($net_list6);
1594
		}
1595
	}
1596
	if ($mobile_ipsec_auth == "eap-radius") {
1597
		$scconf['pools']['radius-pool : mobile-pool'] = array();
1598
		$radpool =& $scconf['pools']['radius-pool : mobile-pool'];
1599
		if (!empty($net_list4) || !empty($net_list6)) {
1600
			$radpool['subnet'] = implode(",", array_merge($net_list4, $net_list6));
1601
			$radpool['split_include'] = implode(",", array_merge($net_list4, $net_list6));
1602
			unset($net_list4);
1603
			unset($net_list6);
1604
		}
1605
	}
1606

    
1607
	return;
1608
}
1609

    
1610
/****f* ipsec/ipsec_setup_userpools
1611
 * NAME
1612
 *   ipsec_setup_userpools - Generate per-user custom pool settings for swanctl
1613
  * INPUTS
1614
 *   None
1615
 * RESULT
1616
 *   Adds configured per-user pool settings to $scconf using the primary mobile
1617
 *   pool as a base configuration.
1618
 * NOTES
1619
 *   Given this new flexible format, it is now possible to override any valid
1620
 *   pool setting, so future expansion of per-user settings is possible.
1621
 ******/
1622
function ipsec_setup_userpools() {
1623
	global $config, $scconf;
1624
	$a_mobilekey = $config['ipsec']['mobilekey'];
1625

    
1626
	/* Do not waste time if we do not have all the necessary information. */
1627
	if (!is_array($a_mobilekey) ||
1628
	    empty($a_mobilekey) ||
1629
	    !is_array($scconf['connections']) ||
1630
	    !is_array($scconf['con-mobile-defaults']) ||
1631
	    !is_array($scconf['pools']) ||
1632
	    !is_array($scconf['mobile-pool'])) {
1633
		return;
1634
	}
1635

    
1636
	$suffix = 1;
1637
	foreach ($a_mobilekey as $mkent) {
1638
		if (($mkent['type'] != "EAP") ||
1639
		    !isset($mkent['ident_type']) ||
1640
		    !isset($mkent['pool_address']) ||
1641
		    !isset($mkent['pool_netbits']) ||
1642
		    (strlen($mkent['pool_address']) < 1) ||
1643
		    !is_ipaddr($mkent['pool_address'])) {
1644
			continue;
1645
		}
1646
		/* The name of just this pool */
1647
		$upbase = "mobile-userpool-{$suffix}";
1648
		/* The full connection name including a reference to the primary
1649
		 * mobile connection */
1650
		$upconn = "con-{$upbase} : con-mobile-defaults";
1651
		/* The full pool name including a reference to the primary
1652
		 * mobile pool */
1653
		$upname = "{$upbase} : mobile-pool";
1654

    
1655
		$scconf['connections'][$upconn] = array();
1656
		$scconf['pools'][$upname] = array();
1657

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

    
1661
		/* Craft a cloned connection with the ID information to match */
1662
		$scconf['connections'][$upconn]['remote'] = array();
1663
		$scconf['connections'][$upconn]['remote']['id'] = $clientid;
1664
		$scconf['connections'][$upconn]['remote']['eap_id'] = $clienteapid;
1665
		$scconf['connections'][$upconn]['pools'] = $upbase;
1666

    
1667
		/* Craft a cloned pool with pool settings to override for this user */
1668
		$scconf['pools'][$upname]['addrs'] = "{$mkent['pool_address']}/{$mkent['pool_netbits']}";
1669
		if (isset($mkent['dns_address']) && strlen($mkent['dns_address']) > 0 && is_ipaddr($mkent['dns_address'])) {
1670
			$scconf['pools'][$upname]['dns'] = $mkent['dns_address'];
1671
		}
1672
		$suffix++;
1673
	}
1674
	return;
1675
}
1676

    
1677
/****f* ipsec/ipsec_setup_bypass
1678
 * NAME
1679
 *   ipsec_setup_bypass - Generate a bypass connection for LAN-LAN and custom rules traffic
1680
 * INPUTS
1681
 *   None
1682
 * RESULT
1683
 *   Sets up a bypass connection to prevent local traffic from being caught by
1684
 *   IPsec policies.
1685
 ******/
1686
function ipsec_setup_bypass() {
1687
	global $config, $scconf;
1688

    
1689
	$scconf['connections']['bypass'] = array();
1690
	/* Prevents the connection from being considered for remote peers */
1691
	$scconf['connections']['bypass']['remote_addrs'] = "127.0.0.1";
1692
	$scconf['connections']['bypass']['children'] = array();
1693

    
1694
	/* Locate the LAN IPv4 and IPv6 subnets */
1695
	$bypassnets = array();
1696
	if ($config['interfaces']['lan']) {
1697
		$lanip = get_interface_ip("lan");
1698
		if (!empty($lanip) && is_ipaddrv4($lanip)) {
1699
			$lansn = get_interface_subnet("lan");
1700
			$lansa = gen_subnetv4($lanip, $lansn);
1701
			if (!empty($lansa) && !empty($lansn)) {
1702
				$bypassnets[] = "{$lansa}/{$lansn}";
1703
			}
1704
		}
1705
		$lanip6 = get_interface_ipv6("lan");
1706
		if (!empty($lanip6) && is_ipaddrv6($lanip6)) {
1707
			$lansn6 = get_interface_subnetv6("lan");
1708
			$lansa6 = gen_subnetv6($lanip6, $lansn6);
1709
			if (!empty($lansa6) && !empty($lansn6)) {
1710
				$bypassnets[] = "{$lansa6}/{$lansn6}";
1711
			}
1712
		}
1713
	}
1714
	/* If we have viable targets, setup a bypass LAN connection */
1715
	if (!empty($bypassnets) && !isset($config['ipsec']['noshuntlaninterfaces'])) {
1716
		$bypass = implode(',', $bypassnets);
1717
		$scconf['connections']['bypass']['children']['bypasslan'] = array();
1718
		$scconf['connections']['bypass']['children']['bypasslan']['local_ts'] = $bypass;
1719
		$scconf['connections']['bypass']['children']['bypasslan']['remote_ts'] = $bypass;
1720
		$scconf['connections']['bypass']['children']['bypasslan']['mode'] = "pass";
1721
		$scconf['connections']['bypass']['children']['bypasslan']['start_action'] = "trap";
1722
	}
1723

    
1724
	/* Setup custom bypass rules */
1725
	if ((isset($config['ipsec']['ipsecbypass']) && $config['ipsec']['bypassrules']) &&
1726
	    is_array($config['ipsec']['bypassrules'])) {
1727
		foreach ($config['ipsec']['bypassrules']['rule'] as $id => $rule) {
1728
			$scconf['connections']['bypass']['children']["rule{$id}"] = array();
1729
			$scconf['connections']['bypass']['children']["rule{$id}"]["local_ts"] = $rule['source'] .
1730
			       	"/" . $rule['srcmask'];
1731
			$scconf['connections']['bypass']['children']["rule{$id}"]["remote_ts"] = $rule['destination'] .
1732
			       	"/" . $rule['dstmask'];
1733
			$scconf['connections']['bypass']['children']["rule{$id}"]["mode"] = "pass";
1734
			$scconf['connections']['bypass']['children']["rule{$id}"]["start_action"] = "trap";
1735
		}
1736
	}
1737

    
1738
	return;
1739
}
1740

    
1741
/****f* ipsec/ipsec_setup_routes
1742
 * NAME
1743
 *   ipsec_setup_routes - Setup OS routing table static routes for remote peers.
1744
 *                        This ensures that IPsec connections are routed out of
1745
 *                        the expected interface on egress.
1746
 * INPUTS
1747
 *   $interface : The interface upon which routes will be configured.
1748
 *   $family    : The address family ('inet' or 'inet6')
1749
 *   $sourcehost: The local source address used for initiating connections.
1750
 *   $duplicates: If the ipsec tunnel allows duplicates remote peers
1751
 * RESULT
1752
 *   Static routes in the OS routing table for IPsec peers
1753
 ******/
1754
function ipsec_setup_routes($interface, $family, $sourcehost, $duplicates) {
1755
	if (substr($interface, 0, 4) == "_vip") {
1756
		$vpninterface = get_configured_vip_interface($interface);
1757
		if (substr($vpninterface, 0, 4) == "_vip") {
1758
			// vips are nested if its a ipalias with a carp parent
1759
			$vpninterface = get_configured_vip_interface($vpninterface);
1760
		}
1761
		$ifacesuse = get_real_interface($vpninterface);
1762
	} else {
1763
		$ifacesuse = get_failover_interface($interface);
1764
		if (substr($ifacesuse, 0, 4) == "_vip") {
1765
			$vpninterface = get_configured_vip_interface($ifacesuse);
1766
			$ifacesuse = get_real_interface($vpninterface);
1767
		} else {
1768
			$vpninterface = convert_real_interface_to_friendly_interface_name($ifacesuse);
1769
		}
1770
	}
1771
	if ($family == 'inet' && !empty($ifacesuse) &&
1772
	    interface_has_gateway($vpninterface)) {
1773
		$gatewayip = get_interface_gateway($vpninterface);
1774
		$interfaceip = get_interface_ip($vpninterface);
1775
		$subnet_bits = get_interface_subnet($vpninterface);
1776
		$subnet_ip = gen_subnetv4($interfaceip, $subnet_bits);
1777
		/*
1778
		 * if the remote gateway is in the local subnet, then don't add
1779
		 * a route
1780
		 */
1781
		if (is_ipaddrv4($sourcehost) &&
1782
		    !ip_in_subnet($sourcehost, "{$subnet_ip}/{$subnet_bits}") &&
1783
		    is_ipaddrv4($gatewayip) && !$duplicates) {
1784
			route_add_or_change($sourcehost, $gatewayip);
1785
		}
1786
	} else if ($family == 'inet6' && !empty($ifacesuse) &&
1787
	    interface_has_gatewayv6($vpninterface)) {
1788
		$gatewayip = get_interface_gateway_v6($vpninterface);
1789
		$interfaceip = get_interface_ipv6($vpninterface);
1790
		$subnet_bits = get_interface_subnetv6($vpninterface);
1791
		$subnet_ip = gen_subnetv6($interfaceip, $subnet_bits);
1792
		/*
1793
		 * if the remote gateway is in the local subnet, then don't add
1794
		 * a route
1795
		 */
1796
		if (is_ipaddrv6($sourcehost) &&
1797
		    !ip_in_subnet($sourcehost, "{$subnet_ip}/{$subnet_bits}") &&
1798
		    is_ipaddrv6($gatewayip) && !$duplicates) {
1799
			route_add_or_change($sourcehost, $gatewayip);
1800
		}
1801
	}
1802
	return $ifacesuse;
1803
}
1804

    
1805
/****f* ipsec/ipsec_setup_authentication
1806
 * NAME
1807
 *   ipsec_setup_authentication - Generate an array with local/remote
1808
 *                                authentication information for a given IPsec
1809
 *                                Phase 1.
1810
 * INPUTS
1811
 *   $ph1ent: An IPsec Phase 1 configuration
1812
 *   $conn  : A swanctl connection array corresponding to the IPsec Phase 1.
1813
 * RESULT
1814
 *   Populates $conn with local and remote arrays containing authentication
1815
 *   details.
1816
 ******/
1817
function ipsec_setup_authentication(& $ph1ent, & $conn) {
1818
	global $rgmap, $ipsec_swanctl_dirs, $config;
1819
	$local = array();
1820
	$remote = array();
1821
	$remote2 = array();
1822

    
1823
	list($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local');
1824
	$localid = ipsec_fixup_id($myid_type, $myid_data);
1825
	if (!empty($localid)) {
1826
		$local['id'] = $localid;
1827
	}
1828

    
1829
	// Only specify peer ID if we are not dealing with mobile PSK
1830
	if (!(isset($ph1ent['mobile']) &&
1831
	    in_array($ph1ent['authentication_method'], array("pre_shared_key", "xauth_psk_server")))) {
1832
		list ($remoteid_type, $remoteid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap);
1833
		$remoteid = ipsec_fixup_id($remoteid_type, $remoteid_data);
1834
	}
1835
	if (!empty($remoteid)) {
1836
		$remote['id'] = $remoteid;
1837
	}
1838

    
1839
	if (!empty($ph1ent['caref'])) {
1840
		$ca = lookup_ca($ph1ent['caref']);
1841
		if ($ca) {
1842
			/* Get hash value to use for filename */
1843
			$ca_details = openssl_x509_parse(base64_decode($ca['crt']));
1844
			$cafn = "{$ipsec_swanctl_dirs['capath']}/{$ca_details['hash']}.0";
1845
		}
1846
	}
1847

    
1848
	$authentication = "";
1849
	switch ($ph1ent['authentication_method']) {
1850
		case 'eap-mschapv2':
1851
			if (isset($ph1ent['mobile'])) {
1852
				$local['auth'] = "pubkey";
1853
				$remote['eap_id'] = "%any";
1854
				$remote['auth'] = "eap-mschapv2";
1855
			}
1856
			break;
1857
		case 'eap-tls':
1858
			if (isset($ph1ent['mobile'])) {
1859
				$local['auth'] = "pubkey";
1860
				$remote['eap_id'] = "%any";
1861
			} else {
1862
				$local['auth'] = "eap-tls";
1863
			}
1864
			$remote['auth'] = "eap-tls";
1865
			break;
1866
		case 'eap-radius':
1867
			if (isset($ph1ent['mobile'])) {
1868
				$local['auth'] = "pubkey";
1869
				$remote['eap_id'] = "%any";
1870
			} else {
1871
				$local['auth'] = "eap-radius";
1872
			}
1873
			if (($config['ipsec']['client']['group_source'] == 'enabled') &&
1874
			    !empty($config['ipsec']['client']['auth_groups'])) {
1875
				$remote['groups'] = $config['ipsec']['client']['auth_groups'];
1876
			}
1877
			$remote['auth'] = "eap-radius";
1878
			break;
1879
		case 'xauth_cert_server':
1880
			$local['auth'] = "pubkey";
1881
			$remote['auth'] = "pubkey";
1882
			$remote2['auth'] = "xauth-generic";
1883
			break;
1884
		case 'xauth_psk_server':
1885
			$local['auth'] = "psk";
1886
			$remote['auth'] = "psk";
1887
			$remote2['auth'] = "xauth-generic";
1888
			break;
1889
		case 'pre_shared_key':
1890
			$local['auth'] = "psk";
1891
			$remote['auth'] = "psk";
1892
			break;
1893
		case 'cert':
1894
		case 'pkcs11':
1895
			$local['auth'] = "pubkey";
1896
			$remote['auth'] = "pubkey";
1897
			break;
1898
		case 'hybrid_cert_server':
1899
			$local['auth'] = "pubkey";
1900
			$remote['auth'] = "xauth-generic";
1901
			break;
1902
	}
1903
	if (in_array($ph1ent['authentication_method'], array('eap-mschapv2', 'eap-tls', 'eap-radius', 'xauth_cert_server', 'cert', 'hybrid_cert_server')) &&
1904
	    !empty($ph1ent['certref'])) {
1905
		$local['cert'] = array('file' => "{$ipsec_swanctl_dirs['certpath']}/cert-{$ph1ent['ikeid']}.crt");
1906
		$conn['send_cert'] = "always";
1907
	}
1908
	if ($ph1ent['authentication_method'] == 'pkcs11') {
1909
		$local['cert'] = array('handle' => "{$ph1ent['pkcs11certref']}");
1910
		$conn['send_cert'] = "always";
1911
	}
1912
	if (in_array($ph1ent['authentication_method'], array('eap-tls', 'xauth_cert_server', 'cert', 'pkcs11')) &&
1913
	    isset($cafn)) {
1914
		$remote['cacerts'] = $cafn;
1915
		if (isset($config['ipsec']['strictcrlpolicy'])) {
1916
			$remote['revocation'] = "strict";
1917
		}
1918
	}
1919

    
1920
	$conn['local'] = $local;
1921
	/* If there is data for a second remote auth round, setup two remote
1922
	 * arrays with unique names, otherwise setup a single remote. */
1923
	if (empty($remote2)) {
1924
		$conn['remote'] = $remote;
1925
	} else {
1926
		$conn['remote-1'] = $remote;
1927
		$conn['remote-2'] = $remote2;
1928
	}
1929
}
1930

    
1931
/****f* ipsec/ipsec_setup_proposal_algo
1932
 * NAME
1933
 *   ipsec_setup_proposal_algo - Form a single proposal algorithm string
1934
 * INPUTS
1935
 *   $ealg_id: Encryption algorithm ID
1936
 *   $keylen : Key length for the encryption algorithm
1937
 *   $halgo  : Hash algorithm
1938
 *   $modp   : DH Group number
1939
 * RESULT
1940
 *   Returns a string using the available information to form a single proposal
1941
 *   algorithm definition.
1942
 * NOTES
1943
 *   Values left empty will not be added to the string. Some combinations may
1944
 *   require one or more parts to be omitted.
1945
 ******/
1946
function ipsec_setup_proposal_algo($ealg_id, $keylen, $halgo, $prfalgo, $modp) {
1947
	$palgo = "";
1948

    
1949
	/* Add the encryption algorithm (if present) */
1950
	if (!empty($ealg_id)) {
1951
		$palgo .= "{$ealg_id}";
1952
	}
1953

    
1954
	/* Add the key length (if present) */
1955
	if (!empty($keylen)) {
1956
		$palgo .= "{$keylen}";
1957
	}
1958

    
1959
	/* Add the hash algorithm (if present) */
1960
	if (!empty($halgo)) {
1961
		/* If there is some content in the propsal already, add a
1962
		 * separator */
1963
		if (!empty($palgo)) {
1964
			$palgo .= "-";
1965
		}
1966
		$halgo = str_replace('hmac_', '', $halgo);
1967
		$palgo .= "{$halgo}";
1968
	}
1969

    
1970
	if (!empty($prfalgo)) {
1971
		$palgo .= "-prf{$prfalgo}";
1972
	}
1973

    
1974
	/* Convert the DH group to its keyword and add (if present) */
1975
	$modp = ipsec_convert_to_modp($modp);
1976
	if (!empty($modp)) {
1977
		$palgo .= "-{$modp}";
1978
	}
1979

    
1980
	return $palgo;
1981
}
1982

    
1983
/****f* ipsec/ipsec_setup_proposal_entry
1984
 * NAME
1985
 *   ipsec_setup_proposal_entry - Generate a full proposal string for an IPsec
1986
 *                                Phase 2 configuration.
1987
 * INPUTS
1988
 *   $ph2ent  : An IPsec Phase 2 configuration
1989
 *   $algo_arr: An array in which all proposal algorithms are collected
1990
 *   $ealg_id : Encryption algorithm ID
1991
 *   $keylen  : Key length for the encryption algorithm
1992
 * RESULT
1993
 *   Returns a string containing all proposal elements, and merges the entries
1994
 *   to $algo_arr as well.
1995
 ******/
1996
function ipsec_setup_proposal_entry(& $ph2ent, & $algo_arr, $ealg_id, $keylen) {
1997
	global $config, $p2_ealgos;
1998
	$proposal = array();
1999

    
2000
	/* If multiple hash algorithms are present, loop through and add them all. */
2001
	if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option']) 
2002
	    && !strpos($ealg_id, "gcm")) {
2003
		foreach ($ph2ent['hash-algorithm-option'] as $halgo) {
2004
			$proposal[] = ipsec_setup_proposal_algo($ealg_id, $keylen, $halgo, false, $ph2ent['pfsgroup']);
2005
		}
2006
	} else {
2007
		$proposal[] = ipsec_setup_proposal_algo($ealg_id, $keylen, false, false, $ph2ent['pfsgroup']);
2008
	}
2009

    
2010
	/* Add to master list */
2011
	$algo_arr = array_merge($algo_arr, $proposal);
2012
	return implode(',', $proposal);
2013
}
2014

    
2015
/****f* ipsec/ipsec_setup_vtireq
2016
 * NAME
2017
 *   ipsec_setup_vtireq - Setup a VTI type IPsec request
2018
 * INPUTS
2019
 *   $child                : A swanctl child array
2020
 *   $ipsec_vti_cleanup_ifs: An array of VTI interface names for later cleanup
2021
 *   $ikeid                : The IKE ID of this child
2022
 *   $idx                  : The index of this child (for split connections/IKEv1)
2023
 * RESULT
2024
 *   Sets up VTI-specific values for a request.
2025
 ******/
2026
function ipsec_setup_vtireq(& $child, & $ipsec_vti_cleanup_ifs, $ikeid, $idx = 0) {
2027
	$child['reqid'] = get_ipsecifnum($ikeid, $idx);
2028
	/* This interface will be a valid IPsec interface, so remove it from the cleanup list. */
2029
	$ipsec_vti_cleanup_ifs = array_diff($ipsec_vti_cleanup_ifs, array("ipsec{$child['reqid']}"));
2030
	$child['local_ts'] .= ",0.0.0.0/0";
2031
	$child['remote_ts'] .= ",0.0.0.0/0";
2032
}
2033

    
2034
/****f* ipsec/ipsec_setup_tunnels
2035
 * NAME
2036
 *   ipsec_setup_tunnels - Configure all P1/P2 entries as swanctl connections
2037
 * INPUTS
2038
 *   None
2039
 * RESULT
2040
 *   Sets up a swanctl array for all connections in the configuration along with
2041
 *   their children, authentication, etc.
2042
 ******/
2043
function ipsec_setup_tunnels() {
2044
	global $aggressive_mode_psk, $a_client, $config,
2045
		$filterdns_list, $g, $ifacesuse, $ipsec_idhandling, $ipsec_log_cats,
2046
		$ipsec_log_sevs, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs,
2047
		$ipseccfg, $mobile_ipsec_auth, $natfilterrules, $p1_ealgos,
2048
		$p2_ealgos, $rgmap, $sa, $sn, $scconf, $conn, $tunnels,
2049
		$ipsec_vti_cleanup_ifs, $conn_defaults;
2050

    
2051
	foreach ($tunnels as $ph1ent) {
2052
		/* Skip disabled entries */
2053
		if (isset($ph1ent['disabled'])) {
2054
			continue;
2055
		}
2056
		/* If the local source is invalid, skip this entry. */
2057
		$local_spec = ipsec_get_phase1_src($ph1ent);
2058
		if (!$local_spec) {
2059
			continue;
2060
		}
2061

    
2062
		/* Determine the name of this connection, either con-mobile for
2063
		 * mobile clients, or a name based on the IKE ID otherwise. */
2064
		if (isset($ph1ent['mobile'])) {
2065
			$cname = "con-mobile";
2066
			/* Start with common default values */
2067
			$scconf["{$cname}-defaults"] = $conn_defaults;
2068
			/* Array reference to make things easier */
2069
			$conn =& $scconf["{$cname}-defaults"];
2070
			$scconf['connections']["{$cname} : {$cname}-defaults"] = array("# Stub to load con-mobile-defaults");
2071
		} else {
2072
			if (get_ipsecifnum($ph1ent['ikeid'], 0)) {
2073
				$cname = "con" . get_ipsecifnum($ph1ent['ikeid'], 0);
2074
			} else {
2075
				$cname = "con{$ph1ent['ikeid']}00000";
2076
			}
2077
			/* Start with common default values */
2078
			$scconf['connections'][$cname] = $conn_defaults;
2079
			/* Array reference to make things easier */
2080
			$conn =& $scconf['connections'][$cname];
2081
		}
2082

    
2083
		/* Common parameters for all children */
2084
		$child_params = array();
2085
		if (!empty($ph1ent['closeaction'])) {
2086
			$child_params['close_action'] = $ph1ent['closeaction'];
2087
		}
2088

    
2089
		$ikeid = $ph1ent['ikeid'];
2090

    
2091
		/* "trap" adds policies to start a tunnel when interesting
2092
		 * traffic is observed by the host. */
2093
		$start_action = "trap";
2094

    
2095
		/* Set the IKE version appropriately (empty = IKEv1) */
2096
		switch ($ph1ent['iketype']) {
2097
			case 'auto':
2098
				$ikeversion = 0;
2099
				break;
2100
			case 'ikev2':
2101
				$ikeversion = 2;
2102
				break;
2103
			case 'ikev1':
2104
			default:
2105
				$ikeversion = 1;
2106
				break;
2107
		}
2108
		$conn['version'] = $ikeversion;
2109

    
2110
		/* For IKEv1 or auto, setup aggressive mode if configured */
2111
		if ($ikeversion != 2){
2112
			$conn['aggressive'] = ($ph1ent['mode'] == "aggressive") ? "yes" : "no";
2113
		}
2114

    
2115
		if (isset($ph1ent['mobile'])) {
2116
			/* Mobile tunnels allow 'any' as a peer */
2117
			$remote_spec = "0.0.0.0/0,::/0";
2118
			/* Mobile tunnels cannot start automatically */
2119
			$start_action = 'none';
2120
		} else {
2121
			$remote_spec = $ph1ent['remote-gateway'];
2122
			$sourcehost = (is_ipaddr($remote_spec)) ? $remote_spec : $rgmap[$remote_spec];
2123
			$ifacesuse = ipsec_setup_routes($ph1ent['interface'], $ph1ent['protocol'], $sourcehost, isset($ph1ent['gw_duplicates']));
2124
		}
2125

    
2126
		/* Setup IKE proposals */
2127
		if (is_array($ph1ent['encryption']['item'])) {
2128
			$ciphers = array();
2129
			foreach($ph1ent['encryption']['item'] as $p1enc) {
2130
				if (!is_array($p1enc['encryption-algorithm']) ||
2131
						empty($p1enc['encryption-algorithm']['name']) ||
2132
						empty($p1enc['hash-algorithm'])) {
2133
					continue;
2134
				}
2135
				if ($ph1ent['prfselect_enable'] != 'yes') {
2136
					$p1enc['prf-algorithm'] = false;
2137
				}
2138
				$ciphers[] = ipsec_setup_proposal_algo($p1enc['encryption-algorithm']['name'],
2139
									$p1enc['encryption-algorithm']['keylen'],
2140
									$p1enc['hash-algorithm'],
2141
									$p1enc['prf-algorithm'],
2142
									$p1enc['dhgroup']);
2143
			}
2144
			$conn['proposals'] = implode(",", $ciphers);
2145
		}
2146

    
2147
		/* Configure DPD values. The DPD action is a per-child parameter,
2148
		 * not per-connection like the delay and timeout. */
2149
		if ($ph1ent['dpd_delay'] && $ph1ent['dpd_maxfail']) {
2150
			if ($start_action == "trap") {
2151
				$child_params['dpd_action'] = "trap";
2152
			} else {
2153
				$child_params['dpd_action'] = "clear";
2154
			}
2155
			$conn['dpd_delay'] = "{$ph1ent['dpd_delay']}s";
2156
			$conn['dpd_timeout'] =  $ph1ent['dpd_delay'] * ($ph1ent['dpd_maxfail'] + 1) . "s";
2157

    
2158
			/* Adjust dpd_action if the close_action is explicitly set */
2159
			if (!empty($child_params['close_action'])) {
2160
				switch ($ph1ent['closeaction']) {
2161
					case 'trap':
2162
						$child_params['dpd_action'] = 'trap';
2163
						break;
2164
					case 'start':
2165
						$child_params['dpd_action'] = 'restart';
2166
						break;
2167
					case 'none':
2168
					default:
2169
						$child_params['dpd_action'] = 'clear';
2170
				}
2171
			}
2172
		} else {
2173
			$child_params['dpd_action'] = "clear";
2174
		}
2175

    
2176
		/* Rekey (IKEv2 or Auto only, not supported by IKEv1) */
2177
		if (($ikeversion == 0) || ($ikeversion == 2)) {
2178
			$conn['rekey_time'] = ipsec_get_rekey_time($ph1ent) . "s";
2179
		}
2180

    
2181
		/* Reauth (Any) */
2182
		$conn['reauth_time'] = ipsec_get_reauth_time($ph1ent) . "s";
2183

    
2184
		/* Over Time */
2185
		$conn['over_time'] = ipsec_get_over_time($ph1ent) . "s";
2186

    
2187
		/* Rand Time */
2188
		$conn['rand_time'] = ipsec_get_rand_time($ph1ent) . "s";
2189

    
2190
		/* NAT Traversal */
2191
		$conn['encap'] = ($ph1ent['nat_traversal'] == 'force') ? "yes" : "no";
2192

    
2193
		/* MOBIKE support */
2194
		$conn['mobike'] = ($ph1ent['mobike'] == 'on') ? "yes" : "no";
2195

    
2196
		/* TFC Padding */
2197
		if (isset($ph1ent['tfc_enable'])) {
2198
			$conn['tfc_padding'] = (isset($ph1ent['tfc_bytes']) && is_numericint($ph1ent['tfc_bytes'])) ? $ph1ent['tfc_bytes'] : "mtu";
2199
		}
2200

    
2201
		/* Custom Ports */
2202
		if (isset($ph1ent['ikeport'])) {
2203
			/* For a connection without encapsulation, do not set local_port */
2204
			$conn['remote_port'] = $ph1ent['ikeport'];
2205
		} elseif (isset($ph1ent['nattport'])) {
2206
			/* For an encapsulated connection,
2207
			 * set local_port to the server NAT-T port value or default (4500) */
2208
			$conn['local_port'] = isset($config['ipsec']['port_nat_t']) ? $config['ipsec']['port_nat_t'] : 4500;
2209
			$conn['remote_port'] = $ph1ent['nattport'];
2210
		}
2211

    
2212
		/* Arrays for P2s/children */
2213
		$children = array();
2214
		$remote_ts_spec = array();
2215
		$local_ts_spec = array();
2216
		$reqids = array();
2217
		$has_vti = false;
2218
		$ealgoAHsp2arr = array();
2219
		$ealgoESPsp2arr = array();
2220
		$suffix = 0;
2221

    
2222
		foreach ($ph1ent['p2'] as $ph2ent) {
2223
			/* If this entry is disabled, or cannot be configured, skip. */
2224
			if (isset($ph2ent['disabled']) ||
2225
			    (isset($ph2ent['mobile']) && !isset($a_client['enable']))) {
2226
				continue;
2227
			}
2228
			$child = array();
2229
			$local_ts = "";
2230
			$remote_ts = "";
2231
			if (($ph2ent['mode'] == 'tunnel') or ($ph2ent['mode'] == 'tunnel6')) {
2232
				/* Normal tunnel child config */
2233
				$child['mode'] = "tunnel";
2234
				$child['policies'] = "yes";
2235

    
2236
				$localid_type = $ph2ent['localid']['type'];
2237
				$localsubnet_data = ipsec_idinfo_to_cidr($ph2ent['localid'], false, $ph2ent['mode']);
2238

    
2239
				/* Do not print localid in some cases, such as a pure-psk or psk/xauth single phase2 mobile tunnel */
2240
				if (($localid_type == "none" || $localid_type == "mobile") &&
2241
				    isset($ph1ent['mobile']) && (ipsec_get_number_of_phase2($ikeid) == 1)) {
2242
					$local_spec = '0.0.0.0/0,::/0';
2243
				} else {
2244
					if ($localid_type != "address") {
2245
						$localid_type = "subnet";
2246
					}
2247
					// Don't let an empty subnet into config, it can cause parse errors. Ticket #2201.
2248
					if (!is_ipaddr($localsubnet_data) && !is_subnet($localsubnet_data) && ($localsubnet_data != "0.0.0.0/0")) {
2249
						log_error("Invalid IPsec Phase 2 \"{$ph2ent['descr']}\" - {$ph2ent['localid']['type']} has no subnet.");
2250
						continue;
2251
					}
2252
					if (!empty($ph2ent['natlocalid'])) {
2253
						$natlocalsubnet_data = ipsec_idinfo_to_cidr($ph2ent['natlocalid'], false, $ph2ent['mode']);
2254
						if ($ph2ent['natlocalid']['type'] != "address") {
2255
							if (is_subnet($natlocalsubnet_data)) {
2256
								$localsubnet_data = "{$natlocalsubnet_data}|{$localsubnet_data}";
2257
							}
2258
						} else {
2259
							if (is_ipaddr($natlocalsubnet_data)) {
2260
								$localsubnet_data = "{$natlocalsubnet_data}|{$localsubnet_data}";
2261
							}
2262
						}
2263
						$natfilterrules = true;
2264
					}
2265
				}
2266

    
2267
				$local_ts = $localsubnet_data;
2268

    
2269
				if (!isset($ph2ent['mobile'])) {
2270
					$remote_ts = ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']);
2271
				} else if (!empty($a_client['pool_address'])) {
2272
					$remote_ts = "{$a_client['pool_address']}/{$a_client['pool_netbits']}";
2273
				}
2274

    
2275
			} elseif ($ph2ent['mode'] == 'vti') {
2276
				/* VTI-specific child config */
2277
				$child['policies'] = "no";
2278
				/* VTI cannot use trap policies, so start automatically instead */
2279
				$start_action = 'start';
2280
				if ($child_params['dpd_action'] == "trap") {
2281
					$child_params['dpd_action'] = "restart";
2282
				}
2283
				$localid_type = $ph2ent['localid']['type'];
2284
				$localsubnet_data = ipsec_idinfo_to_cidr($ph2ent['localid'], false, $ph2ent['mode']);
2285
				$local_ts = $localsubnet_data;
2286
				$remote_ts = ipsec_idinfo_to_cidr($ph2ent['remoteid'], false, $ph2ent['mode']);
2287
				$has_vti = true;
2288
			} else {
2289
				/* Transport mode child config */
2290
				$child['mode'] = "transport";
2291
				$child['policies'] = "yes";
2292

    
2293
				if ((($ph1ent['authentication_method'] == "xauth_psk_server") ||
2294
				    ($ph1ent['authentication_method'] == "pre_shared_key")) &&
2295
				    isset($ph1ent['mobile'])) {
2296
					$local_spec = "0.0.0.0/0,::/0";
2297
				} else {
2298
					$local_ts = ipsec_get_phase1_src($ph1ent);
2299
				}
2300

    
2301
				if (!isset($ph2ent['mobile'])) {
2302
					$remote_ts = $remote_spec;
2303
				}
2304
			}
2305

    
2306
			if (!empty($local_ts)) {
2307
				$local_ts_spec[] = $local_ts;
2308
			}
2309
			if (!empty($remote_ts)) {
2310
				$remote_ts_spec[] = $remote_ts;
2311
			}
2312

    
2313
			/* If a PFS group is configured on the Mobile Clients tab,
2314
			 * and this is a mobile P2, use it here. */
2315
			if (isset($a_client['pfs_group']) && isset($ph2ent['mobile'])) {
2316
				$ph2ent['pfsgroup'] = $a_client['pfs_group'];
2317
			}
2318

    
2319
			$reqids[] = $ph2ent['reqid'];
2320

    
2321
			if (!empty($ph2ent['lifetime'])) {
2322
				$child['life_time'] = ipsec_get_life_time($ph2ent) . "s";
2323
				/* Rekey at 90% of lifetime */
2324
				$child['rekey_time'] = ipsec_get_rekey_time($ph2ent) . "s";
2325
				/* Random rekey fuzz time */
2326
				$child['rand_time'] = ipsec_get_rand_time($ph2ent) . "s";
2327
			}
2328

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

    
2332
			/* Setup child SA proposals */
2333
			$proposal = array();
2334
			$ph2ent_ealgos = array();
2335
			$ph2ent_ealgos_aead = array();
2336
			if ($ph2ent['protocol'] == 'esp') {
2337
				if (is_array($ph2ent['encryption-algorithm-option'])) {
2338
					foreach ($ph2ent['encryption-algorithm-option'] as $ealg) {
2339
						if (strpos($ealg['name'], "gcm")) {
2340
							/* put AEAD ciphers on top, 
2341
							*  see https://redmine.pfsense.org/issues/11078 */
2342
							$ph2ent_ealgos_aead[] = $ealg;
2343
						} else {
2344
							$ph2ent_ealgos[] = $ealg;
2345
						}
2346
					}
2347
					$ph2ent_ealgos = array_merge(array_reverse($ph2ent_ealgos_aead), $ph2ent_ealgos);
2348
					foreach ($ph2ent_ealgos as $ealg) {
2349
						$ealg_id = $ealg['name'];
2350
						$ealg_kl = $ealg['keylen'];
2351

    
2352
						if (!empty($ealg_kl) && $ealg_kl == "auto") {
2353
							if (empty($p2_ealgos) || !is_array($p2_ealgos)) {
2354
								require_once("ipsec.inc");
2355
							}
2356
							$key_hi = $p2_ealgos[$ealg_id]['keysel']['hi'];
2357
							$key_lo = $p2_ealgos[$ealg_id]['keysel']['lo'];
2358
							$key_step = $p2_ealgos[$ealg_id]['keysel']['step'];
2359
							/* XXX: in some cases where include ordering is suspect these variables
2360
							 * are somehow 0 and we enter this loop forever and timeout after 900
2361
							 * seconds wrecking bootup */
2362
							if ($key_hi != 0 and $key_lo != 0 and $key_step != 0) {
2363
								for ($keylen = $key_hi; $keylen >= $key_lo; $keylen -= $key_step) {
2364
									$proposal[] = ipsec_setup_proposal_entry($ph2ent, $ealgoESPsp2arr, $ealg_id, $keylen);
2365
								}
2366
							}
2367
						} else {
2368
							$proposal[] = ipsec_setup_proposal_entry($ph2ent, $ealgoESPsp2arr, $ealg_id, $ealg_kl);
2369
						}
2370
					}
2371
				}
2372
			} else if ($ph2ent['protocol'] == 'ah') {
2373
				$proposal[] = ipsec_setup_proposal_entry($ph2ent, $ealgoAHsp2arr, '', '');
2374
			}
2375

    
2376
			/* Not mobile, and IKEv1 or Split Connections active */
2377
			if (!isset($ph1ent['mobile']) && (($ikeversion == 1) || isset($ph1ent['splitconn']))) {
2378
				if (!empty($remote_ts)) {
2379
					/* Setup child sub-connections using unique names with a suffix */
2380
					if (get_ipsecifnum($ph1ent['ikeid'], $idx)) {
2381
						$subconnum = get_ipsecifnum($ph1ent['ikeid'], $idx);
2382
					} else {
2383
						$subconnum = "{$ph1ent['ikeid']}00000";
2384
					}
2385

    
2386
					$subconname = "con" . ($subconnum + $suffix);
2387
					$children[$subconname] = $child;
2388
					$children[$subconname]['local_ts'] = $local_ts;
2389
					$children[$subconname]['remote_ts'] = $remote_ts;
2390
					if ($has_vti) {
2391
						ipsec_setup_vtireq($children[$subconname], $ipsec_vti_cleanup_ifs, $ph1ent['ikeid'], $suffix);
2392
					}
2393
					if (!empty($ph2ent['protocol']) && !empty($proposal)) {
2394
						$children[$subconname][$ph2ent['protocol'] . '_proposals'] = implode(',', $proposal);
2395
					}
2396
				} else {
2397
					log_error(sprintf(gettext("No phase2 specifications for tunnel with REQID = %s"), $ikeid));
2398
				}
2399
			} else {
2400
				/* TODO: Fix this to nicely merge all P2 params for single child case */
2401
				if (!is_array($children[$cname])) {
2402
					$children[$cname] = array();
2403
				}
2404
				$children[$cname] = array_merge($children[$cname], $child);
2405
			}
2406
			$suffix++;
2407
		}
2408

    
2409
		$conn['local_addrs'] = $local_spec;
2410
		$conn['remote_addrs'] = $remote_spec;
2411

    
2412
		$pools = array();
2413
		if (isset($ph1ent['mobile'])) {
2414
			if (($ph1ent['authentication_method'] == 'eap-radius') && 
2415
			    empty($a_client['pool_address']) && empty($a_client['pool_address_v6'])) {
2416
				$pools[] = "radius-pool";
2417
				$pools[] = "radius";
2418
			} else {
2419
				if (!empty($a_client['pool_address'])) {
2420
					$pools[] = "mobile-pool-v4";
2421
				}
2422
				if (!empty($a_client['pool_address_v6'])) {
2423
					$pools[] = "mobile-pool-v6";
2424
				}
2425
				if (isset($a_client['radius_ip_priority_enable'])) {
2426
					$pools[] .= "radius";
2427
				}
2428
			}
2429
		}
2430
		if (!empty($pools)) {
2431
			$conn['pools'] = implode(', ', $pools);
2432
		}
2433

    
2434
		/* For IKEv2 without Split Connections, setup combined sets of
2435
		 * local/remote traffic selectors and propsals */
2436
		if (!(!isset($ph1ent['mobile']) && (($ikeversion == 1) || isset($ph1ent['splitconn'])))) {
2437
			if (!isset($ph1ent['mobile']) && !empty($remote_ts_spec)) {
2438
				$children[$cname]['remote_ts'] = implode(",", $remote_ts_spec);
2439
			}
2440
			if (!empty($local_ts_spec)) {
2441
				$children[$cname]['local_ts'] = implode(",", $local_ts_spec);
2442
			}
2443
			if ($has_vti) {
2444
				ipsec_setup_vtireq($children[$cname], $ipsec_vti_cleanup_ifs, $ph1ent['ikeid']);
2445
			}
2446
			if (!empty($ealgoAHsp2arr)) {
2447
				$children[$cname]['ah_proposals'] = implode(',', array_unique($ealgoAHsp2arr));
2448
			}
2449
			if (!empty($ealgoESPsp2arr)) {
2450
				$children[$cname]['esp_proposals'] = implode(',', array_unique($ealgoESPsp2arr));
2451
			}
2452
		}
2453

    
2454
		/* Setup connection authentication */
2455
		ipsec_setup_authentication($ph1ent, $conn);
2456

    
2457
		/* Add children to this connection, including default child parameters */
2458
		if (count($children)) {
2459
			foreach($children as $name => $child) {
2460
				$conn['children'][$name] = array_merge($child_params, $child);
2461
			}
2462
		}
2463

    
2464
	}
2465

    
2466
	return;
2467
}
2468

    
2469
/****f* ipsec/ipsec_setup_secrets
2470
 * NAME
2471
 *   ipsec_setup_secrets - Setup swanctl authentication secrets
2472
 * INPUTS
2473
 *   None
2474
 * RESULT
2475
 *   Returns a swanctl array containing secrets (PSKs, certs, etc) and writes out
2476
 *   necessary CA, CRL, and certificate data.
2477
 ******/
2478
function ipsec_setup_secrets() {
2479
	global $config, $a_phase1, $ipsec_swanctl_dirs, $ipseccfg, $rgmap, $scconf;
2480

    
2481
	$suffix = 0;
2482

    
2483
	/* write out CRL files */
2484
	if (is_array($config['crl']) && count($config['crl'])) {
2485
		foreach ($config['crl'] as $crl) {
2486
			if (!isset($crl['text'])) {
2487
				log_error(sprintf(gettext("Warning: Missing CRL data for %s"), $crl['descr']));
2488
				continue;
2489
			}
2490
			$fpath = "{$ipsec_swanctl_dirs['crlpath']}/{$crl['refid']}.crl";
2491
			if (!@file_put_contents($fpath, base64_decode($crl['text']))) {
2492
				log_error(sprintf(gettext("Error: Cannot write IPsec CRL file for %s"), $crl['descr']));
2493
				continue;
2494
			}
2495
		}
2496
	}
2497

    
2498
	$vpncas = array();
2499
	if (is_array($a_phase1) && count($a_phase1)) {
2500
		foreach ($a_phase1 as $ph1ent) {
2501
			if (isset($ph1ent['disabled'])) {
2502
				continue;
2503
			}
2504

    
2505
			if (isset($ph1ent['mobile'])) {
2506
				if ($ph1ent['authentication_method'] == 'pre_shared_key') {
2507
					$mobilepsk = true;
2508
				} elseif ($ph1ent['authentication_method'] == 'eap-mschapv2') {
2509
					$mobileeap = true;
2510
				}
2511
			}
2512

    
2513
			if (strstr($ph1ent['authentication_method'], 'cert') ||
2514
			    in_array($ph1ent['authentication_method'], array('eap-mschapv2', 'eap-tls', 'eap-radius'))) {
2515
				/* Write certificate and private key, point to private key */
2516
				$certline = '';
2517

    
2518
				$ikeid = $ph1ent['ikeid'];
2519
				$cert = lookup_cert($ph1ent['certref']);
2520

    
2521
				if (!$cert) {
2522
					log_error(sprintf(gettext("Error: Invalid phase1 certificate reference for %s"), $ph1ent['name']));
2523
					continue;
2524
				}
2525

    
2526
				/* add signing CA cert chain of server cert
2527
				 * to the list of CAs to write
2528
				 */
2529
				$cachain = ca_chain_array($cert);
2530
				if ($cachain && is_array($cachain)) {
2531
					foreach ($cachain as $cacrt) {
2532
						$vpncas[$cacrt['refid']] = $cacrt;
2533
					}
2534
				}
2535

    
2536
				@chmod($ipsec_swanctl_dirs['certpath'], 0600);
2537

    
2538
				$ph1keyfile = "{$ipsec_swanctl_dirs['keypath']}/cert-{$ikeid}.key";
2539
				if (!file_put_contents($ph1keyfile, base64_decode($cert['prv']))) {
2540
					log_error(sprintf(gettext("Error: Cannot write phase1 key file for %s"), $ph1ent['name']));
2541
					continue;
2542
				}
2543
				@chmod($ph1keyfile, 0600);
2544

    
2545
				$ph1certfile = "{$ipsec_swanctl_dirs['certpath']}/cert-{$ikeid}.crt";
2546
				if (!file_put_contents($ph1certfile, base64_decode($cert['crt']))) {
2547
					log_error(sprintf(gettext("Error: Cannot write phase1 certificate file for %s"), $ph1ent['name']));
2548
					@unlink($ph1keyfile);
2549
					continue;
2550
				}
2551
				@chmod($ph1certfile, 0600);
2552

    
2553
				$scconf['secrets']['private-' . $suffix++] = array('file' => $ph1keyfile);
2554
			} else if (strstr($ph1ent['authentication_method'], 'pkcs11')) {
2555
				$p11_id = array();
2556
				$output = shell_exec('/usr/local/bin/pkcs15-tool -c');
2557
				preg_match_all('/ID\s+: (.*)/', $output, $p11_id);
2558
				if (!empty($ph1ent['pkcs11certref']) && in_array($ph1ent['pkcs11certref'], $p11_id[1])) {
2559
					$scconf['secrets']['token-' . $suffix++] = array(
2560
						'handle' => $ph1ent['pkcs11certref'],
2561
						'pin' => $ph1ent['pkcs11pin'],
2562
					);
2563
				} else {
2564
					log_error(sprintf(gettext("Error: Invalid phase1 PKCS#11 certificate reference or PKCS#11 is not present for %s"), $ph1ent['name']));
2565
					continue;
2566
				}
2567
			} else {
2568
				/* Setup pre-shared keys */
2569
				list($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local');
2570
				list($peerid_type, $peerid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap);
2571
				$myid = trim($myid_data);
2572

    
2573
				if (empty($peerid_data)) {
2574
					continue;
2575
				}
2576

    
2577
				$myid = isset($ph1ent['mobile']) ? ipsec_fixup_id($myid_type, trim($myid_data)) : "%any";
2578
				$peerid = ($peerid_data != 'allusers') ? ipsec_fixup_id($peerid_type, trim($peerid_data)) : '';
2579

    
2580
				if (!empty($ph1ent['pre-shared-key'])) {
2581
					$scconf['secrets']['ike-' . $suffix++] = array(
2582
						'secret' => '0s' . base64_encode(trim($ph1ent['pre-shared-key'])),
2583
						'id-0' => $myid,
2584
						'id-1' => $peerid,
2585
					);
2586
					if (isset($ph1ent['mobile'])) {
2587
						$scconf['secrets']['ike-' . $suffix++] = array(
2588
							'secret' => '0s' . base64_encode(trim($ph1ent['pre-shared-key'])),
2589
							'id-0' => $myid,
2590
							'id-1' => '%any',
2591
						);
2592
						$scconf['secrets']['ike-' . $suffix++] = array(
2593
							'secret' => '0s' . base64_encode(trim($ph1ent['pre-shared-key'])),
2594
						);
2595
					}
2596
				}
2597
			}
2598

    
2599
			/* if the client authenticates with a cert add the
2600
			 * client cert CA chain to the list of CAs to write
2601
			 */
2602
			if (in_array($ph1ent['authentication_method'],
2603
			    array('cert', 'eap-tls', 'xauth_cert_server', 'pkcs11'))) {
2604
				if (!empty($ph1ent['caref']) && !array_key_exists($ph1ent['caref'], $vpncas)) {
2605
					$thisca = lookup_ca($ph1ent['caref']);
2606
					$vpncas[$ph1ent['caref']] = $thisca;
2607
					/* follow chain up to root */
2608
					$cachain = ca_chain_array($thisca);
2609
					if ($cachain and is_array($cachain)) {
2610
						foreach ($cachain as $cacrt) {
2611
							$vpncas[$cacrt['refid']] = $cacrt;
2612
						}
2613
					}
2614
				}
2615
			}
2616
		}
2617
	}
2618

    
2619
	/* Write the required CAs */
2620
	foreach ($vpncas as $carefid => $cadata) {
2621
		$cacrt = base64_decode($cadata['crt']);
2622
		$cacrtattrs = openssl_x509_parse($cacrt);
2623
		if (!is_array($cacrtattrs) || !isset($cacrtattrs['hash'])) {
2624
			log_error(sprintf(gettext("Error: Invalid certificate hash info for %s"), $cadata['descr']));
2625
			continue;
2626
		}
2627
		$cafilename = "{$ipsec_swanctl_dirs['capath']}/{$cacrtattrs['hash']}.0";
2628
		if (!@file_put_contents($cafilename, $cacrt)) {
2629
				log_error(sprintf(gettext("Error: Cannot write IPsec CA file for %s"), $cadata['descr']));
2630
				continue;
2631
		}
2632
	}
2633

    
2634
	/* Add user PSKs */
2635
	if ($mobilepsk && is_array($config['system']) && is_array($config['system']['user'])) {
2636
		foreach ($config['system']['user'] as $user) {
2637
			if (!empty($user['ipsecpsk'])) {
2638
				$scconf['secrets']['ike-' . $suffix++] = array(
2639
					'secret' => '0s' . base64_encode(trim($user['ipsecpsk'])),
2640
					'id-0' => $myid,
2641
					'id-1' => $user['name'],
2642
				);
2643
			}
2644
		}
2645
		unset($user);
2646
	}
2647

    
2648
	/* add PSKs/EAPs for mobile clients */
2649
	if (is_array($ipseccfg['mobilekey'])) {
2650
		foreach ($ipseccfg['mobilekey'] as $key) {
2651
			if (($mobileeap && ($key['type'] == 'EAP')) ||
2652
			    ($key['type'] == 'PSK')) {
2653
				if (($key['ident'] == 'allusers') ||
2654
				    ($key['ident'] == 'any')) {
2655
					$key['ident'] = '%any';
2656
				}
2657
				$userkeyprefix = (strtolower($key['type']) == 'eap') ? 'eap' : 'ike';
2658
				$scconf['secrets'][$userkeyprefix . '-' . $suffix++] = array(
2659
					'secret' => '0s' . base64_encode(trim($key['pre-shared-key'])),
2660
					'id-0' => $key['ident'],
2661
				);
2662
			}
2663
		}
2664
		unset($key);
2665
	}
2666
	return;
2667
}
2668

    
2669
/****f* ipsec/ipsec_configure
2670
 * NAME
2671
 *   ipsec_configure - Configure IPsec
2672
 * INPUTS
2673
 *   $restart: Boolean (default false), whether or not to restart the IPsec
2674
 *             daemons.
2675
 * RESULT
2676
 *   IPsec-related configuration files are written, daemon is started or stopped
2677
 *   appropriately.
2678
 ******/
2679
function ipsec_configure($restart = false) {
2680
	global $aggressive_mode_psk, $a_client, $a_phase1, $a_phase2, $config,
2681
		$filterdns_list, $g, $ifacesuse, $ipsec_idhandling, $ipsec_log_cats,
2682
		$ipsec_log_sevs, $ipsec_swanctl_basedir, $ipsec_swanctl_dirs,
2683
		$ipseccfg, $mobile_ipsec_auth, $natfilterrules, $p1_ealgos,
2684
		$p2_ealgos, $rgmap, $sa, $sn, $scconf, $tunnels, $mobile_configured,
2685
		$ipsec_vti_cleanup_ifs, $conn_defaults, $pool_addrs;
2686

    
2687
	/* service may have been enabled, disabled, or otherwise changed in a
2688
	 *way requiring rule updates */
2689
	filter_configure();
2690

    
2691
	if (!ipsec_enabled()) {
2692
		/* IPsec is disabled */
2693
		/* Stop charon */
2694
		mwexec("/usr/local/sbin/strongswanrc stop");
2695
		/* Stop dynamic monitoring */
2696
		killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
2697
		/* Wait for process to die */
2698
		sleep(2);
2699
		/* Shutdown enc0 interface*/
2700
		mwexec("/sbin/ifconfig enc0 down");
2701
		ipsec_gre_default_mtu(); 
2702
		return 0;
2703
	} else {
2704
		/* Startup enc0 interface */
2705
		mwexec("/sbin/ifconfig enc0 up");
2706
	}
2707

    
2708
	if (platform_booting()) {
2709
		echo gettext("Configuring IPsec VPN... ");
2710
	}
2711

    
2712
	$ipsecstartlock = lock('ipsec', LOCK_EX);
2713

    
2714
	/* Prepare automatic ping_hosts.sh data */
2715
	unlink_if_exists("{$g['vardb_path']}/ipsecpinghosts");
2716
	touch("{$g['vardb_path']}/ipsecpinghosts");
2717
	$ipsecpinghostsactive = false;
2718

    
2719
	/* Populate convenience variables */
2720
	$syscfg = $config['system'];
2721
	init_config_arr(array('ipsec', 'phase1'));
2722
	$ipseccfg = $config['ipsec'];
2723
	$a_phase1 = $config['ipsec']['phase1'];
2724
	init_config_arr(array('ipsec', 'phase2'));
2725
	$a_phase2 = $config['ipsec']['phase2'];
2726
	init_config_arr(array('ipsec', 'client'));
2727
	$a_client = $config['ipsec']['client'];
2728

    
2729
	$mobile_configured = false;
2730

    
2731
	/* Setup a single structured array to process, to avoid repeatedly
2732
	 * looping through the arrays to locate entries later. */
2733
	$tunnels = array();
2734
	foreach ($a_phase1 as $p1) {
2735
		if (empty($p1)) {
2736
			continue;
2737
		}
2738
		if (isset($p1['mobile']) && !isset($p1['disabled'])) {
2739
			$mobile_configured = true;
2740
		}
2741
		$tunnels[$p1['ikeid']] = $p1;
2742
		$tunnels[$p1['ikeid']]['p2'] = array();
2743
	}
2744
	foreach ($a_phase2 as $p2) {
2745
		$tunnels[$p2['ikeid']]['p2'][] = $p2;
2746
	}
2747

    
2748
	$ipsec_vti_cleanup_ifs = array();
2749
	$rgmap = array();
2750
	$filterdns_list = array();
2751
	$aggressive_mode_psk = false;
2752
	$mobile_ipsec_auth = "";
2753
	$ifacesuse = array();
2754
	$natfilterrules = false;
2755

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

    
2759
	/* Build a list of all IPsec interfaces configured on the firewall at the OS level */
2760
	foreach (get_interface_arr() as $thisif) {
2761
		if (substr($thisif, 0, 5) == "ipsec") {
2762
			$ipsec_vti_cleanup_ifs[] = $thisif;
2763
		}
2764
	}
2765

    
2766
	/* Create directory structure for IPsec */
2767
	ipsec_create_dirs();
2768

    
2769
	/* Setup gateways and interfaces */
2770
	ipsec_setup_gwifs();
2771

    
2772
	/* Setup and write strongswan.conf */
2773
	ipsec_setup_strongswan();
2774

    
2775
	/* Start Global Connection default values */
2776
	$conn_defaults = array();
2777
	/* Fragmentation is on for everyone */
2778
	$conn_defaults['fragmentation'] = "yes";
2779
	/* Default to 'replace' for unique IDs (was 'yes' in ipsec.conf previously) */
2780
	$conn_defaults['unique'] = 'replace';
2781
	/* If the configuration has a valid alternate value for unique ID handling,
2782
	 * use it instead. */
2783
	if (!empty($config['ipsec']['uniqueids']) &&
2784
	    array_key_exists($config['ipsec']['uniqueids'], $ipsec_idhandling)) {
2785
		$conn_defaults['unique'] = $config['ipsec']['uniqueids'];
2786
	}
2787
	/* Disable ipcomp for now. redmine #6167
2788
	if (isset($config['ipsec']['compression'])) {
2789
		$conn_defaults['compress'] = "yes";
2790
	}
2791
	set_single_sysctl('net.inet.ipcomp.ipcomp_enable', (isset($config['ipsec']['compression'])) ? 1 : 0);
2792
	*/
2793
	/* End Global Connection Defaults */
2794

    
2795
	/* Start swanctl configuration (scconf) */
2796
	$scconf = array();
2797
	$scconf[] = "# This file is automatically generated. Do not edit";
2798
	$scconf['connections'] = array();
2799
	/* Setup IPsec bypass */
2800
	ipsec_setup_bypass();
2801
	/* Setup connections */
2802
	ipsec_setup_tunnels();
2803
	$scconf['pools'] = array();
2804
	if ($mobile_configured) {
2805
		/* Setup mobile address pools */
2806
		ipsec_setup_pools();
2807
		/* Setup per-user pools */
2808
		ipsec_setup_userpools();
2809
	}
2810
	/* Setup secret data */
2811
	$scconf['secrets'] = array();
2812
	ipsec_setup_secrets();
2813

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

    
2816
	/* Clean up unused VTI interfaces */
2817
	foreach ($ipsec_vti_cleanup_ifs as $cleanif) {
2818
		if (does_interface_exist($cleanif)) {
2819
			mwexec("/sbin/ifconfig " . escapeshellarg($cleanif) . " destroy", false);
2820
		}
2821
	}
2822

    
2823
	/* set default MTU to 1400 for GRE over IPsec, othewise to 1476 */
2824
	ipsec_gre_default_mtu(); 
2825

    
2826
	/* Manage process */
2827
	if ($restart === true) {
2828
		mwexec_bg("/usr/local/sbin/strongswanrc restart", false);
2829
	} else {
2830
		if (isvalidpid("{$g['varrun_path']}/charon.pid")) {
2831
			mwexec_bg("/usr/local/sbin/strongswanrc reload", false);
2832
		} else {
2833
			mwexec_bg("/usr/local/sbin/strongswanrc start", false);
2834
		}
2835
	}
2836

    
2837
	// Run ping_hosts.sh once if it's enabled to avoid wait for minicron
2838
	if ($ipsecpinghostsactive) {
2839
		mwexec_bg("/usr/local/bin/ping_hosts.sh");
2840
	}
2841

    
2842
	if ($natfilterrules == true) {
2843
		filter_configure();
2844
	}
2845
	/* start filterdns, if necessary */
2846
	if (count($filterdns_list) > 0) {
2847
		$interval = 60;
2848
		if (!empty($ipseccfg['dns-interval']) && is_numeric($ipseccfg['dns-interval'])) {
2849
			$interval = $ipseccfg['dns-interval'];
2850
		}
2851

    
2852
		$hostnames = "";
2853
		array_unique($filterdns_list);
2854
		foreach ($filterdns_list as $hostname) {
2855
			$hostnames .= "cmd {$hostname} '/usr/local/sbin/pfSctl -c \"service reload ipsecdns\"'\n";
2856
		}
2857
		file_put_contents("{$g['varetc_path']}/ipsec/filterdns-ipsec.hosts", $hostnames);
2858
		unset($hostnames);
2859

    
2860
		if (isvalidpid("{$g['varrun_path']}/filterdns-ipsec.pid")) {
2861
			sigkillbypid("{$g['varrun_path']}/filterdns-ipsec.pid", "HUP");
2862
		} else {
2863
			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");
2864
		}
2865
	} else {
2866
		killbypid("{$g['varrun_path']}/filterdns-ipsec.pid");
2867
		@unlink("{$g['varrun_path']}/filterdns-ipsec.pid");
2868
	}
2869

    
2870
	if (platform_booting()) {
2871
		echo "done\n";
2872
	}
2873

    
2874
	unlock($ipsecstartlock);
2875
	return count($filterdns_list);
2876
}
2877

    
2878
function ipsec_gre_default_mtu() {
2879
	global $config;
2880

    
2881
	foreach ($config['interfaces'] as $if => $ifdetail) { 
2882
		if (interface_is_type($ifdetail['if'], 'gre') && !isset($ifdetail['mtu'])) {
2883
			if (is_greipsec($ifdetail['if'])) {
2884
				set_interface_mtu($ifdetail['if'], 1400);
2885
			} else {
2886
				set_interface_mtu($ifdetail['if'], 1476);
2887
			}
2888
		}
2889
	}
2890
}
2891

    
2892
/* Return the larger of derived SA rekey time and reauth time */
2893
function ipsec_get_renewmax($entry) {
2894
	if (empty($entry) || !is_array($entry)) {
2895
		return 0;
2896
	}
2897
	return max(ipsec_get_rekey_time($entry), ipsec_get_reauth_time($entry));
2898
}
2899

    
2900
/* Determine the life time of an SA entry (Hard upper total time limit for SA before it is removed) */
2901
function ipsec_get_life_time($entry) {
2902
	if (empty($entry) || !is_array($entry)) {
2903
		return 0;
2904
	}
2905
	/* Use a hardcoded value if present in the configuration */
2906
	if ($entry['lifetime'] > 0) {
2907
		return $entry['lifetime'];
2908
	}
2909
	/* If rekey or reauth are enabled, attempt to derive a lifetime from one of those */
2910
	$renewmax = ipsec_get_renewmax($entry);
2911
	if ($renewmax > 0) {
2912
		return intval($renewmax / 0.9);
2913
	}
2914
	/* To reach here, rekey_time and lifetime are both 0 which is invalid
2915
	 * Default to 16000 for p1 and 4000 for p2 */
2916
	if ($entry['iketype']) {
2917
		return 16000;
2918
	} else {
2919
		return 4000;
2920
	}
2921
}
2922

    
2923
/* Determine the rekey time of an SA entry (Time at which to rekey IKEv2 or Child SA entries) */
2924
function ipsec_get_rekey_time($entry) {
2925
	if (empty($entry) || !is_array($entry)) {
2926
		return 0;
2927
	}
2928
	/* Use a hardcoded value if present in the configuration */
2929
	if (strlen($entry['rekey_time'])) {
2930
		/* Check via strlen since 0 is a valid value */
2931
		return $entry['rekey_time'];
2932
	} elseif ($entry['lifetime'] > 0) {
2933
		/* If rekey_time is empty and lifetime is non-zero, use 90% lifetime */
2934
		return intval($entry['lifetime'] * 0.9);
2935
	}
2936
	/* To reach here, rekey_time and lifetime are empty
2937
	 * Default to 14400 for p1 and 3600 for p2 */
2938
	if ($entry['iketype']) {
2939
		return 14400;
2940
	} else {
2941
		return 3600;
2942
	}
2943
}
2944

    
2945
/* Determine the reauth time of an SA entry (IKE SA tear-down/reauthenticate) */
2946
function ipsec_get_reauth_time($entry) {
2947
	if (empty($entry) || !is_array($entry)) {
2948
		return 0;
2949
	}
2950
	/* Use a hardcoded value if present in the configuration */
2951
	if (strlen($entry['reauth_time'])) {
2952
		/* Check via strlen since 0 is a valid value */
2953
		return $entry['reauth_time'];
2954
	} elseif ($entry['lifetime'] > 0) {
2955
		/* If reauth_time is empty and lifetime is non-zero,
2956
		 * use 90% lifetime for IKEv1, disable for IKEv2/auto */
2957
		if ($entry['iketype'] == 'ikev1') {
2958
			return intval($entry['lifetime'] * 0.9);
2959
		} else {
2960
			return 0;
2961
		}
2962
	}
2963
	/* To reach here, rekey_time and lifetime are empty
2964
	 * Default to disabled (0) */
2965
	return 0;
2966
}
2967

    
2968
/* Determine the over time of an SA entry (Hard upper IKE SA time limit, relative to rekey/reauth time) */
2969
function ipsec_get_over_time($entry) {
2970
	if (empty($entry) || !is_array($entry)) {
2971
		return 0;
2972
	}
2973
	/* Automatically derive the value for rand_time */
2974
	$lifetime = ipsec_get_life_time($entry);
2975
	$renewmax = ipsec_get_renewmax($entry);
2976
	if (($lifetime > 0) && ($renewmax > 0)) {
2977
		/* If life time and rekey/reauth time both have values, subtract to get rand time */
2978
		return $lifetime - $renewmax;
2979
	} elseif ($lifetime > 0) {
2980
		/* If only life time has a value, use 10% of that */
2981
		return intval($lifetime * 0.1);
2982
	} elseif ($renewmax > 0) {
2983
		/* If only rekey/reauth time has a value, use 10% of that */
2984
		return intval($renewmax * 0.1);
2985
	}
2986
	/* No value can be determined, default to 0 */
2987
	return 0;
2988
}
2989

    
2990
/* Determine the rand time of an SA entry (random value subtracted from renewal time to prevent collisions) */
2991
function ipsec_get_rand_time($entry) {
2992
	if (empty($entry) || !is_array($entry)) {
2993
		return 0;
2994
	}
2995
	/* Use a hardcoded value if present in the configuration */
2996
	if (strlen($entry['rand_time'])) {
2997
		/* Check via strlen since 0 is a valid value */
2998
		return $entry['rand_time'];
2999
	}
3000
	/* Logic to automatically determine rand time is identical to calculating over time */
3001
	return ipsec_get_over_time($entry);
3002
}
3003

    
3004
?>
(26-26/61)