Project

General

Profile

Download (10.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	ipsec.inc
4
	Copyright (C) 2007 Scott Ullrich
5
	Copyright (C) 2008 Shrew Soft Inc
6
	All rights reserved.
7

    
8
	Parts of this code was originally based on vpn_ipsec_sad.php
9
	Copyright (C) 2003-2004 Manuel Kasper
10

    
11
	Redistribution and use in source and binary forms, with or without
12
	modification, are permitted provided that the following conditions are met:
13

    
14
	1. Redistributions of source code must retain the above copyright notice,
15
	   this list of conditions and the following disclaimer.
16

    
17
	2. Redistributions in binary form must reproduce the above copyright
18
	   notice, this list of conditions and the following disclaimer in the
19
	   documentation and/or other materials provided with the distribution.
20

    
21
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
	POSSIBILITY OF SUCH DAMAGE.
31
*/
32

    
33
/* IPsec defines */
34
$my_identifier_list = array(
35
	'myaddress' => array( 'desc' => 'My IP address', 'mobile' => true ),
36
	'address' => array( 'desc' => 'IP address', 'mobile' => true ),
37
	'fqdn' => array( 'desc' => 'Distinguished name', 'mobile' => true ),
38
	'user_fqdn' => array( 'desc' => 'User distinguished name', 'mobile' => true ),
39
	'asn1dn' => array( 'desc' => 'ASN.1 distinguished Name', 'mobile' => true ),
40
	'keyid tag' => array( 'desc' => 'KeyID tag', 'mobile' => true ),
41
	'dyn_dns' => array( 'desc' => 'Dynamic DNS', 'mobile' => true ));
42

    
43
$peer_identifier_list = array(
44
	'peeraddress' => array( 'desc' => 'Peer IP address', 'mobile' => false ),
45
	'address' => array( 'desc' => 'IP address', 'mobile' => false ),
46
	'fqdn' => array( 'desc' => 'Distinguished name', 'mobile' => true ),
47
	'user_fqdn' => array( 'desc' => 'User distinguished name', 'mobile' => true ),
48
	'asn1dn' => array( 'desc' => 'ASN.1 distinguished Name', 'mobile' => true ),
49
	'keyid tag' => array( 'desc' =>'KeyID tag', 'mobile' => true ));
50

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

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

    
65
$p1_halgos = array(
66
	'sha1' => 'SHA1',
67
	'md5' => 'MD5');
68

    
69
$p2_halgos = array(
70
	'hmac_sha1' => 'SHA1',
71
	'hmac_md5' => 'MD5');
72

    
73
$p1_authentication_methods = array(
74
	'hybrid_rsa_server' => array( 'name' => 'Hybrid RSA + Xauth', 'mobile' => true ),
75
	'xauth_rsa_server' => array( 'name' => 'Mutual RSA + Xauth', 'mobile' => true ),
76
	'xauth_psk_server' => array( 'name' => 'Mutual PSK + Xauth', 'mobile' => true ),
77
	'rsasig' => array( 'name' => 'Mutual RSA', 'mobile' => false ),
78
	'pre_shared_key' => array( 'name' => 'Mutual PSK', 'mobile' => false ) );
79

    
80
$p2_modes = array(
81
	'tunnel' => 'Tunnel',
82
	'transport' => 'Transport');
83

    
84
$p2_protos = array(
85
	'esp' => 'ESP',
86
	'ah' => 'AH');
87

    
88
$p2_pfskeygroups = array(
89
	'0' => 'off',
90
	'1' => '1',
91
	'2' => '2',
92
	'5' => '5');
93

    
94
/*
95
 * ikeid management functions
96
 */
97

    
98
function ipsec_ikeid_used($ikeid) {
99
	global $config;
100

    
101
	foreach ($config['ipsec']['phase1'] as $ph1ent)
102
		if( $ikeid == $ph1ent['ikeid'] )
103
			return true;
104

    
105
	return false;
106
}
107

    
108
function ipsec_ikeid_next() {
109

    
110
	$ikeid = 1;
111
	while(ipsec_ikeid_used($ikeid))
112
		$ikeid++;
113

    
114
	return $ikeid;
115
}
116

    
117
/*
118
 * Return phase1 local address
119
 */
120
function ipsec_get_phase1_src(& $ph1ent) {
121

    
122
	if ($ph1ent['interface'])
123
		$if = $ph1ent['interface'];
124
	else
125
		$if = "WAN";
126

    
127
	$realinterface = convert_friendly_interface_to_real_interface_name($if);
128
	$interfaceip = find_interface_ip($realinterface);
129

    
130
	return $interfaceip;
131
}
132

    
133
/*
134
 * Return phase1 local address
135
 */
136
function ipsec_get_phase1_dst(& $ph1ent) {
137

    
138
	$rg = $ph1ent['remote-gateway'];
139
	if (!is_ipaddr($rg))
140
		return resolve_retry($rg);
141

    
142
	if(!is_ipaddr($rg))
143
		return false;
144

    
145
	return $rg;
146
}
147

    
148
/*
149
 * Return phase2 idinfo in cidr format
150
 */
151
function ipsec_idinfo_to_cidr(& $idinfo,$addrbits = false) {
152
	global $config;
153

    
154
	switch ($idinfo['type'])
155
	{
156
		case "address":
157
			if ($addrbits)
158
				return $idinfo['address']."/32";
159
			else
160
				return $idinfo['address'];
161
		case "network":
162
			return $idinfo['address']."/".$idinfo['netbits'];
163
		case "mobile":
164
			return "0.0.0.0/0";
165
		default:
166
			$address = get_interface_ip($idinfo['type']);
167
			$netbits = get_interface_subnet($idinfo['type']);
168
			$address = gen_subnet($address,$netbits);
169
			return $address."/".$netbits;
170
    }
171
}
172

    
173
/*
174
 * Return phase2 idinfo in address/netmask format
175
 */
176
function ipsec_idinfo_to_subnet(& $idinfo,$addrbits = false) {
177
	global $config;
178

    
179
	switch ($idinfo['type'])
180
	{
181
		case "address":
182
			if ($addrbits)
183
				return $idinfo['address']."/255.255.255.255";
184
			else
185
				return $idinfo['address'];
186
		case "network":
187
			return $idinfo['address']."/".gen_subnet_mask($idinfo['netbits']);
188
		case "mobile":
189
			return "0.0.0.0/0";
190
        default:
191
			$address = get_interface_ip($idinfo['type']);
192
			$netbits = get_interface_subnet($idinfo['type']);
193
			$address = gen_subnet($address,$netbits);
194
			$netbits = gen_subnet_mask($netbits);
195
			return $address."/".netbits;
196
    }
197
}
198

    
199
/*
200
 *  Return phase2 idinfo in text format
201
 */
202
function ipsec_idinfo_to_text(& $idinfo) {
203

    
204
    switch ($idinfo['type'])
205
    {
206
        case "address":
207
            return $idinfo['address'];
208
        case "network":
209
            return $idinfo['address']."/".$idinfo['netbits'];
210
		case "mobile":
211
			return "Mobile Client";
212
        default:
213
            return strtoupper($idinfo['type']);
214
    }
215
}
216

    
217
/*
218
 * Return phase1 association for phase2
219
 */
220
function ipsec_lookup_phase1(& $ph2ent,& $ph1ent)
221
{
222
    global $config;
223
    $a_phase1 = $config['ipsec']['phase1'];
224

    
225
    if (is_array($a_phase1) && count($a_phase1)) {
226
        foreach ($a_phase1 as $ph1tmp) {
227
            if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
228
                $ph1ent = $ph1tmp;
229
                return $ph1ent;
230
            }
231
        }
232
    }
233

    
234
    return false;
235
}
236

    
237
/*
238
 * Check phase1 communications status
239
 */
240
function ipsec_phase1_status(& $ph1ent) {
241

    
242
	$loc_ip = get_ipsec_tunnel_src($ph1ent);
243
	$rmt_ip = $ph1ent['remote-gateway'];
244

    
245
	if(ipsec_lookup_ipsakmp_sa($loc_ip,$rmt_ip))
246
		return true;
247

    
248
	return false;
249
}
250

    
251
/*
252
 * Check phase2 communications status
253
 */
254
function ipsec_phase2_status(& $spd,& $sad,& $ph1ent,& $ph2ent) {
255

    
256
	$loc_ip = ipsec_get_phase1_src($ph1ent);
257
	$rmt_ip = gethostbyname(ipsec_get_phase1_dst($ph1ent));
258

    
259
	$loc_id = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
260
	$rmt_id = ipsec_idinfo_to_cidr($ph2ent['remoteid'],true);
261

    
262
	/* check for established SA in both directions */
263
	if( ipsec_lookup_ipsec_sa($spd,$sad,"out",$loc_ip,$rmt_ip,$loc_id,$rmt_id) &&
264
		ipsec_lookup_ipsec_sa($spd,$sad,"in",$rmt_ip,$loc_ip,$rmt_id,$loc_id))
265
		return true;
266

    
267
	return false;
268
}
269

    
270
/*
271
 * Return ISAKMP SA details
272
 */
273
function ipsec_lookup_isakmp_sa($in_srcip,$in_dstip) {
274
	/* TODO : use racconctl to lookup iskamp SA */
275
	return NULL;
276
}
277

    
278
/*
279
 * Return IPsec SA details
280
 */
281
function ipsec_lookup_ipsec_sa(& $spd,& $sad,$dir,$in_srcip,$in_dstip,$in_srcid,$in_dstid) {
282

    
283
	/* match the phase1/2 to an SP */
284

    
285
	foreach($spd as $sp) {
286

    
287
		/* match direction */
288

    
289
		if($dir != $sp['dir'])
290
			continue;
291

    
292
		/* match IPs */
293

    
294
		if($in_srcip != $sp['src'])
295
			continue;
296
		if($in_dstip != $sp['dst'])
297
			continue;
298

    
299
		/* add netbits for address IDs */
300

    
301
		$sp_srcid = $sp['srcid'];
302
		$sp_dstid = $sp['dstid'];
303

    
304
		if (!strstr($sp_srcid,"/"))
305
			$sp_srcid .= '/32';
306
		if (!strstr($sp_dstid,"/"))
307
			$sp_dstid .= '/32';
308

    
309
		/* match IDs */
310

    
311
		if($in_srcid != $sp_srcid)
312
			continue;
313
		if($in_dstid != $sp_dstid)
314
			continue;
315

    
316
		/* match the SP to a unique SA by reqid */
317

    
318
		foreach($sad as $sa) {
319

    
320
			/* match REQIDs */
321

    
322
			if($sa[reqid] != $sp[reqid])
323
				continue;
324

    
325
			/* sanitize for NAT-T ports */
326

    
327
			$sa_srcip = $sa['src'];
328
			$sa_dstip = $sa['dst'];
329

    
330
			if (strstr($sa_srcip,"["))
331
				$sa_srcip = substr($sa_srcip,0,strcspn($sa_srcip,"["));
332
			if (strstr($sa_dstip,"["))
333
				$sa_dstip = substr($sa_dstip,0,strcspn($sa_dstip,"["));
334

    
335
			/* match IPs */
336

    
337
			if($in_srcip != $sa_srcip)
338
				continue;
339
			if($in_dstip != $sa_dstip)
340
				continue;
341

    
342
			return $sa;
343
		}
344
	}
345

    
346
	return NULL;
347
}
348

    
349
/*
350
 * Return dump of SPD table
351
 */
352
function ipsec_dump_spd()
353
{
354
	$fd = @popen("/usr/local/sbin/setkey -DP", "r");
355
	$spd = array();
356
	if ($fd) {
357
		while (!feof($fd)) {
358
			$line = chop(fgets($fd));
359
			if (!$line)
360
				continue;
361
			if ($line == "No SPD entries.")
362
				break;
363
			if ($line[0] != "\t") {
364
				if (is_array($cursp))
365
					$spd[] = $cursp;
366
				$cursp = array();
367
				$linea = explode(" ", $line);
368
				$cursp['srcid'] = substr($linea[0], 0, strpos($linea[0], "["));
369
				$cursp['dstid'] = substr($linea[1], 0, strpos($linea[1], "["));
370
				$i = 0;
371
			} else if (is_array($cursp)) {
372
				$linea = explode(" ", trim($line));
373
				switch($i)
374
				{
375
					case 1:
376
						if ($linea[1] == "none")	/* don't show default anti-lockout rule */
377
							unset($cursp);
378
						else
379
							$cursp['dir'] = $linea[0];
380
						break;
381
					case 2:
382
						$upperspec = explode("/", $linea[0]);
383
						$cursp['proto'] = $upperspec[0];
384
						list($cursp['src'], $cursp['dst']) = explode("-", $upperspec[2]);
385
						$cursp['reqid'] =  substr($upperspec[3], strpos($upperspec[3], "#")+1);
386
						break;
387
				}
388
			}
389
			$i++;
390
		}
391
		if (is_array($cursp) && count($cursp))
392
			$spd[] = $cursp;
393
		pclose($fd);
394
	}
395

    
396
	return $spd;
397
}
398

    
399
/*
400
 * Return dump of SAD table
401
 */
402
function ipsec_dump_sad()
403
{
404
	$fd = @popen("/usr/local/sbin/setkey -D", "r");
405
	$sad = array();
406
	if ($fd) {
407
		while (!feof($fd)) {
408
			$line = chop(fgets($fd));
409
			if (!$line)
410
				continue;
411
			if ($line == "No SAD entries.")
412
				break;
413
			if ($line[0] != "\t")
414
			{
415
				if (is_array($cursa))
416
					$sad[] = $cursa;
417
				$cursa = array();
418
				list($cursa['src'],$cursa['dst']) = explode(" ", $line);
419
				$i = 0;
420
			}
421
			else
422
			{
423
				$linea = explode(" ", trim($line));
424
				switch ($i) {
425
					case 1:
426
						$cursa['proto'] = $linea[0];
427
						$cursa['spi'] = substr($linea[2], strpos($linea[2], "x")+1, -1);
428
						$reqid = substr($linea[3], strpos($linea[3], "=")+1);
429
						$cursa['reqid'] = substr($reqid, 0, strcspn($reqid,"("));
430
						break;
431
					case 2:
432
						$cursa['ealgo'] = $linea[1];
433
						break;
434
					case 3:
435
						$cursa['aalgo'] = $linea[1];
436
						break;
437
				}
438
			}
439
			$i++;
440
		}
441
		if (is_array($cursa) && count($cursa))
442
			$sad[] = $cursa;
443
		pclose($fd);
444
	}
445

    
446
	return $sad;
447
}
448

    
449
?>
(17-17/40)