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
	$interfaceip = get_interface_ip($if);
128

    
129
	return $interfaceip;
130
}
131

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

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

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

    
144
	return $rg;
145
}
146

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

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

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

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

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

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

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

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

    
233
    return false;
234
}
235

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

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

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

    
247
	return false;
248
}
249

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

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

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

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

    
266
	return false;
267
}
268

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

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

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

    
284
	foreach($spd as $sp) {
285

    
286
		/* match direction */
287

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

    
291
		/* match IPs */
292

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

    
298
		/* add netbits for address IDs */
299

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

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

    
308
		/* match IDs */
309

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

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

    
317
		foreach($sad as $sa) {
318

    
319
			/* match REQIDs */
320

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

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

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

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

    
334
			/* match IPs */
335

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

    
341
			return $sa;
342
		}
343
	}
344

    
345
	return NULL;
346
}
347

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

    
395
	return $spd;
396
}
397

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

    
445
	return $sad;
446
}
447

    
448
?>
(18-18/43)