Project

General

Profile

Download (25 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-2019 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
/* IPsec defines */
26
global $ipsec_loglevels;
27
$ipsec_loglevels = array(
28
	"dmn" => gettext("Daemon"),
29
	"mgr" => gettext("SA Manager"),
30
	"ike" => gettext("IKE SA"),
31
	"chd" => gettext("IKE Child SA"),
32
	"job" => gettext("Job Processing"),
33
	"cfg" => gettext("Configuration backend"),
34
	"knl" => gettext("Kernel Interface"),
35
	"net" => gettext("Networking"),
36
	"asn" => gettext("ASN encoding"),
37
	"enc" => gettext("Message encoding"),
38
	"imc" => gettext("Integrity checker"),
39
	"imv" => gettext("Integrity Verifier"),
40
	"pts" => gettext("Platform Trust Service"),
41
	"tls" => gettext("TLS handler"),
42
	"esp" => gettext("IPsec traffic"),
43
	"lib" => gettext("StrongSwan Lib")
44
);
45

    
46
global $ipsec_log_sevs;
47
$ipsec_log_sevs = array(
48
	'-1' => gettext('Silent'),
49
	'0' => gettext('Audit'),
50
	'1' => gettext('Control'),
51
	'2' => gettext('Diag'),
52
	'3' => gettext('Raw'),
53
	'4' => gettext('Highest')
54
);
55

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

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

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

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

    
113
global $ipsec_idhandling;
114
$ipsec_idhandling = array(
115
	'yes' => 'YES', 'no' => 'NO', 'never' => 'NEVER', 'keep' => 'KEEP'
116
);
117

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

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

    
140
global $p1_halgos;
141
$p1_halgos = array(
142
	'md5' => 'MD5',
143
	'sha1' => 'SHA1',
144
	'sha256' => 'SHA256',
145
	'sha384' => 'SHA384',
146
	'sha512' => 'SHA512',
147
	'aesxcbc' => 'AES-XCBC'
148
);
149

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

    
176
global $p2_halgos;
177
$p2_halgos = array(
178
	'hmac_md5' => 'MD5',
179
	'hmac_sha1' => 'SHA1',
180
	'hmac_sha256' => 'SHA256',
181
	'hmac_sha384' => 'SHA384',
182
	'hmac_sha512' => 'SHA512',
183
	'aesxcbc' => 'AES-XCBC'
184
);
185

    
186
global $p1_authentication_methods;
187
$p1_authentication_methods = array(
188
	'hybrid_cert_server' => array('name' => gettext('Hybrid Certificate + Xauth'), 'mobile' => true),
189
	'xauth_cert_server' => array('name' => gettext('Mutual Certificate + Xauth'), 'mobile' => true),
190
	'xauth_psk_server' => array('name' => gettext('Mutual PSK + Xauth'), 'mobile' => true),
191
	'eap-tls' => array('name' => gettext('EAP-TLS'), 'mobile' => true),
192
	'eap-radius' => array('name' => gettext('EAP-RADIUS'), 'mobile' => true),
193
	'eap-mschapv2' => array('name' => gettext('EAP-MSChapv2'), 'mobile' => true),
194
	'cert' => array('name' => gettext('Mutual Certificate'), 'mobile' => false),
195
	'pre_shared_key' => array('name' => gettext('Mutual PSK'), 'mobile' => false)
196
);
197

    
198
global $ipsec_preshared_key_type;
199
$ipsec_preshared_key_type = array(
200
	'PSK' => 'PSK',
201
	'EAP' => 'EAP'
202
);
203

    
204
global $ipsec_closeactions;
205
$ipsec_closeactions = array(
206
	'' => gettext('Default'),
207
	'none' => gettext('No action'),
208
	'restart' => gettext('Restart/Reconnect'),
209
	'clear' => gettext('Close connection and clear SA'),
210
	'hold' => gettext('Close connection and reconnect on demand'),
211
);
212

    
213
global $p2_modes;
214
$p2_modes = array(
215
	'tunnel' => gettext('Tunnel IPv4'),
216
	'tunnel6' => gettext('Tunnel IPv6'),
217
	'transport' => gettext('Transport'),
218
	'vti' => gettext('Routed (VTI)')
219
);
220

    
221
global $p2_protos;
222
$p2_protos = array(
223
	'esp' => 'ESP',
224
	'ah' => 'AH'
225
);
226

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

    
254
function ipsec_enabled() {
255
	global $config;
256

    
257
	if (!isset($config['ipsec']) || !is_array($config['ipsec'])) {
258
		return false;
259
	}
260

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

    
274
	return false;
275
}
276

    
277
/*
278
 * ikeid management functions
279
 */
280

    
281
function ipsec_ikeid_used($ikeid) {
282
	global $config;
283

    
284
	foreach ($config['ipsec']['phase1'] as $ph1ent) {
285
		if ($ikeid == $ph1ent['ikeid']) {
286
			return true;
287
		}
288
	}
289

    
290
	return false;
291
}
292

    
293
function ipsec_ikeid_next() {
294

    
295
	$ikeid = 1;
296
	while (ipsec_ikeid_used($ikeid)) {
297
		$ikeid++;
298
	}
299

    
300
	return $ikeid;
301
}
302

    
303
/*
304
 * Return phase1 local address
305
 */
306
function ipsec_get_phase1_src(& $ph1ent) {
307

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

    
334
	return $interfaceip;
335
}
336

    
337
/*
338
 * Return phase1 local address
339
 */
340
function ipsec_get_phase1_dst(& $ph1ent) {
341
	global $g;
342

    
343
	if (empty($ph1ent['remote-gateway'])) {
344
		return false;
345
	}
346
	$rg = $ph1ent['remote-gateway'];
347
	if (!is_ipaddr($rg)) {
348
		if (!platform_booting()) {
349
			return resolve_retry($rg);
350
		}
351
	}
352
	if (!is_ipaddr($rg)) {
353
		return false;
354
	}
355

    
356
	return $rg;
357
}
358

    
359
/*
360
 * Return phase2 idinfo in cidr format
361
 */
362
function ipsec_idinfo_to_cidr(& $idinfo, $addrbits = false, $mode = "") {
363
	global $config;
364

    
365
	switch ($idinfo['type']) {
366
		case "address":
367
			if ($addrbits) {
368
				if ($mode == "tunnel6") {
369
					return $idinfo['address']."/128";
370
				} else {
371
					return $idinfo['address']."/32";
372
				}
373
			} else {
374
				return $idinfo['address'];
375
			}
376
			break; /* NOTREACHED */
377
		case "network":
378
			return "{$idinfo['address']}/{$idinfo['netbits']}";
379
			break; /* NOTREACHED */
380
		case "none":
381
		case "mobile":
382
			return '0.0.0.0/0';
383
			break; /* NOTREACHED */
384
		default:
385
			if (empty($mode) && !empty($idinfo['mode'])) {
386
				$mode = $idinfo['mode'];
387
			}
388

    
389
			if ($mode == "tunnel6") {
390
				$address = get_interface_ipv6($idinfo['type']);
391
				$netbits = get_interface_subnetv6($idinfo['type']);
392
				$address = gen_subnetv6($address, $netbits);
393
				return "{$address}/{$netbits}";
394
			} else {
395
				$address = get_interface_ip($idinfo['type']);
396
				$netbits = get_interface_subnet($idinfo['type']);
397
				$address = gen_subnet($address, $netbits);
398
				return "{$address}/{$netbits}";
399
			}
400
			break; /* NOTREACHED */
401
	}
402
}
403

    
404
/*
405
 * Return phase2 idinfo in address/netmask format
406
 */
407
function ipsec_idinfo_to_subnet(& $idinfo, $addrbits = false) {
408
	global $config;
409

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

    
445
/*
446
 *  Return phase2 idinfo in text format
447
 */
448
function ipsec_idinfo_to_text(& $idinfo) {
449
	global $config;
450

    
451
	switch ($idinfo['type']) {
452
		case "address":
453
			return $idinfo['address'];
454
			break; /* NOTREACHED */
455
		case "network":
456
			return $idinfo['address']."/".$idinfo['netbits'];
457
			break; /* NOTREACHED */
458
		case "mobile":
459
			return gettext("Mobile Client");
460
			break; /* NOTREACHED */
461
		case "none":
462
			return gettext("None");
463
			break; /* NOTREACHED */
464
		default:
465
			if (!empty($config['interfaces'][$idinfo['type']])) {
466
				return convert_friendly_interface_to_friendly_descr($idinfo['type']);
467
			} else {
468
				return strtoupper($idinfo['type']);
469
			}
470
			break; /* NOTREACHED */
471
	}
472
}
473

    
474
/*
475
 * Return phase1 association for phase2
476
 */
477
function ipsec_lookup_phase1(& $ph2ent, & $ph1ent) {
478
	global $config;
479

    
480
	if (!is_array($config['ipsec'])) {
481
		return false;
482
	}
483
	if (!is_array($config['ipsec']['phase1'])) {
484
		return false;
485
	}
486
	if (empty($config['ipsec']['phase1'])) {
487
		return false;
488
	}
489

    
490
	foreach ($config['ipsec']['phase1'] as $ph1tmp) {
491
		if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
492
			$ph1ent = $ph1tmp;
493
			return $ph1ent;
494
		}
495
	}
496

    
497
	return false;
498
}
499

    
500
/*
501
 * Check phase1 communications status
502
 */
503
function ipsec_phase1_status(&$ipsec_status, $ikeid) {
504

    
505
	foreach ($ipsec_status as $ike) {
506
		if ($ike['id'] == $ikeid) {
507
			if ($ike['status'] == 'established') {
508
				return true;
509
			}
510
		}
511
	}
512

    
513
	return false;
514
}
515

    
516
/*
517
 * Check phase2 communications status
518
 */
519
function ipsec_phase2_status(&$ipsec_status, &$phase2) {
520

    
521
	if (ipsec_lookup_phase1($ph2ent, $ph1ent)) {
522
		return ipsec_phase1_status($ipsec_status, $ph1ent['ikeid']);
523
	}
524

    
525
	return false;
526
}
527

    
528
/*
529
 * Wrapper to call pfSense_ipsec_list_sa() when IPsec is enabled
530
 */
531
function ipsec_list_sa() {
532

    
533
	if (ipsec_enabled()) {
534
		return pfSense_ipsec_list_sa();
535
	}
536

    
537
	return array();
538
}
539

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

    
591
	return $spd;
592
}
593

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

    
644
	return $sad;
645
}
646

    
647
/*
648
 * Return dump of mobile user list
649
 */
650
function ipsec_dump_mobile() {
651
	global $g, $config;
652

    
653
	if(!isset($config['ipsec']['client']['enable'])) {
654
		return array();
655
	}
656

    
657
	$_gb = exec("/usr/local/sbin/ipsec leases 2>/dev/null", $output, $rc);
658

    
659
	if ($rc != 0) {
660
		log_error(gettext("Unable to find IPsec daemon leases file. Could not display mobile user stats!"));
661
		return array();
662
	}
663

    
664
	$response = array();
665
	$id = -1;
666

    
667
	/* Leases in pool '10.7.200.0/24', usage: 1/254, 1 online */
668
	$lease_regex='/^Leases *in *pool *\'(?P<name>.+)\', *usage: *(?P<usage>\d+)\/(?P<size>\d+), *(?P<online>\d+) *online/';
669
	/* 10.7.200.1   online   'jimp' */
670
	$pool_regex='/\s*(?P<host>[\d\.]+)\s+(?P<status>online|offline)\s+\'(?P<id>.*)\'/';
671
	/* no matching leases found */
672
	$nopool_regex='/no *matching *leases *found/';
673

    
674
	$lease=false;
675
	foreach ($output as $line) {
676
		if (preg_match($lease_regex, $line, $matches)) {
677
			$id++;
678
			$response['pool'][$id] = array(
679
			    'name'   => $matches['name'],
680
			    'usage'  => $matches['usage'],
681
			    'size'   => $matches['size'],
682
			    'online' => $matches['online'],
683
			);
684
			$lease=true;
685
		} else if ($lease) {
686
			if (preg_match($nopool_regex, $line)) {
687
				$response['pool'][$id]['lease'][] = array();
688
				$lease=false;
689
			} else if (preg_match($pool_regex, $line, $matches)) {
690
				$response['pool'][$id]['lease'][] = array(
691
				    'host'   => $matches['host'],
692
				    'status' => $matches['status'],
693
				    'id'     => $matches['id']
694
				);
695
			}
696
		}
697
	}
698

    
699
	unset($_gb, $lease, $output, $rc, $id, $lease_regex, $pool_regex,
700
	    $nopool_regex);
701

    
702
	return $response;
703
}
704

    
705
function ipsec_mobilekey_sort() {
706
	global $config;
707

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

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

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

    
719
	$nbph2 = 0;
720

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

    
729
	return $nbph2;
730
}
731

    
732
function ipsec_get_descr($ikeid) {
733
	global $config;
734

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

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

    
746
	return '';
747
}
748

    
749
function ipsec_get_phase1($ikeid) {
750
		global $config;
751

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

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

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

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

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

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

    
799

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

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

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

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

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

    
862
	return $idstring;
863
}
864

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

    
878
	return $result;
879
}
880

    
881
function ipsec_new_reqid() {
882
	global $config;
883

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

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

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

    
903
	return $keyid;
904
}
905

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

    
910
	$levels = array();
911

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

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

    
930
	$is_vti = false;
931
	$vtisubnet_spec = array();
932

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

    
951
/* Called when IPsec is reloaded through rc.newipsecdns and similar, gives
952
 * packages an opportunity to execute custom code when IPsec reloads.
953
 */
954
function ipsec_reload_package_hook() {
955
	global $g, $config;
956

    
957
	init_config_arr(array('installedpackages', 'package'));
958
	foreach ($config['installedpackages']['package'] as $package) {
959
		if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
960
			continue;
961
		}
962

    
963
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], 'packagegui');
964
		if (!empty($pkg_config['include_file']) &&
965
		    file_exists($pkg_config['include_file'])) {
966
			require_once($pkg_config['include_file']);
967
		}
968
		if (empty($pkg_config['ipsec_reload_function'])) {
969
			continue;
970
		}
971
		$pkg_ipsec_reload = $pkg_config['ipsec_reload_function'];
972
		if (!function_exists($pkg_ipsec_reload)) {
973
			continue;
974
		}
975
		$pkg_ipsec_reload();
976
	}
977
}
978

    
979
?>
(26-26/60)