Project

General

Profile

Download (7.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
/*
34
 * Return phase1 local address
35
 */
36
function ipsec_get_phase1_src(& $ph1ent) {
37

    
38
	if ($ph1ent['interface'])
39
		$if = $ph1ent['interface'];
40
	else
41
		$if = "WAN";
42

    
43
	$realinterface = convert_friendly_interface_to_real_interface_name($if);
44
	$interfaceip = find_interface_ip($realinterface);
45

    
46
	return $interfaceip;
47
}
48

    
49
/*
50
 * Return phase2 idinfo in cidr format
51
 */
52
function ipsec_idinfo_to_cidr(& $idinfo,$addrbits = false) {
53
	global $config;
54

    
55
	switch ($idinfo['type'])
56
	{
57
		case "address":
58
			if ($addrbits)
59
				return $idinfo['address']."/32";
60
			else
61
				return $idinfo['address'];
62
		case "network":
63
			return $idinfo['address']."/".$idinfo['netbits'];
64
        default:
65
			$address = $config['interfaces']['lan']['ipaddr'];
66
			$netbits = $config['interfaces'][$idinfo['type']]['subnet'];
67
			$address = gen_subnet($address,$netbits);
68
			return $address."/".$netbits;
69
    }
70
}
71

    
72
/*
73
 * Return phase2 idinfo in address/netmask format
74
 */
75
function ipsec_idinfo_to_subnet(& $idinfo,$addrbits = false) {
76
	global $config;
77

    
78
	switch ($idinfo['type'])
79
	{
80
		case "address":
81
			if ($addrbits)
82
				return $idinfo['address']."/255.255.255.255";
83
			else
84
				return $idinfo['address'];
85
		case "network":
86
			return $idinfo['address']."/".gen_subnet_mask($idinfo['netbits']);
87
        default:
88
			$address = $config['interfaces']['lan']['ipaddr'];
89
			$netbits = $config['interfaces'][$idinfo['type']]['subnet'];
90
			$address = gen_subnet($address,$netbits);
91
			$netbits = gen_subnet_mask($netbits);
92
			return $address."/".netbits;
93
    }
94
}
95

    
96
/*
97
 *  Return phase2 idinfo in text format
98
 */
99
function ipsec_idinfo_to_text(& $idinfo) {
100

    
101
    switch ($idinfo['type'])
102
    {
103
        case "address":
104
            return $idinfo['address'];
105
        case "network":
106
            return $idinfo['address']."/".$idinfo['netbits'];
107
        default:
108
            return strtoupper($idinfo['type']);
109
    }
110
}
111

    
112
/*
113
 * Return phase1 association for phase2
114
 */
115
function ipsec_lookup_phase1(& $ph2ent,& $ph1ent)
116
{
117
    global $config;
118
    $a_phase1 = $config['ipsec']['phase1'];
119

    
120
    if (is_array($a_phase1) && count($a_phase1)) {
121
        foreach ($a_phase1 as $ph1tmp) {
122
            if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
123
                $ph1ent = $ph1tmp;
124
                return $ph1ent;
125
            }
126
        }
127
    }
128

    
129
    return false;
130
}
131

    
132
/*
133
 * Check phase1 communications status
134
 */
135
function ipsec_phase1_status(& $ph1ent) {
136

    
137
	$loc_ip = get_ipsec_tunnel_src($ph1ent);
138
	$rmt_ip = $ph1ent['remote-gateway'];
139

    
140
	if(ipsec_lookup_ipsakmp_sa($loc_ip,$rmt_ip))
141
		return true;
142

    
143
	return false;
144
}
145

    
146
/*
147
 * Check phase2 communications status
148
 */
149
function ipsec_phase2_status(& $spd,& $sad,& $ph1ent,& $ph2ent) {
150

    
151
	$loc_ip = ipsec_get_phase1_src($ph1ent);
152
	$rmt_ip = $ph1ent['remote-gateway'];
153

    
154
	$loc_id = ipsec_idinfo_to_cidr($ph2ent['localid'],true);
155
	$rmt_id = ipsec_idinfo_to_cidr($ph2ent['remoteid'],true);
156

    
157
	/* check for established SA in both directions */
158
	if( ipsec_lookup_ipsec_sa($spd,$sad,"out",$loc_ip,$rmt_ip,$loc_id,$rmt_id) &&
159
		ipsec_lookup_ipsec_sa($spd,$sad,"in",$rmt_ip,$loc_ip,$rmt_id,$loc_id))
160
		return true;
161

    
162
	return false;
163
}
164

    
165
/*
166
 * Return ISAKMP SA details
167
 */
168
function ipsec_lookup_isakmp_sa($in_srcip,$in_dstip) {
169
	/* TODO : use racconctl to lookup iskamp SA */
170
	return NULL;
171
}
172

    
173
/*
174
 * Return IPsec SA details
175
 */
176
function ipsec_lookup_ipsec_sa(& $spd,& $sad,$dir,$in_srcip,$in_dstip,$in_srcid,$in_dstid) {
177

    
178
	/* match the phase1/2 to an SP */
179

    
180
	foreach($spd as $sp) {
181

    
182
		/* match direction */
183

    
184
		if($dir != $sp['dir'])
185
			continue;
186

    
187
		/* match IPs */
188

    
189
		if($in_srcip != $sp['src'])
190
			continue;
191
		if($in_dstip != $sp['dst'])
192
			continue;
193

    
194
		/* add netbits for address IDs */
195

    
196
		$sp_srcid = $sp['srcid'];
197
		$sp_dstid = $sp['dstid'];
198

    
199
		if (!strstr($sp_srcid,"/"))
200
			$sp_srcid .= '/32';
201
		if (!strstr($sp_dstid,"/"))
202
			$sp_dstid .= '/32';
203

    
204
		/* match IDs */
205

    
206
		if($in_srcid != $sp_srcid)
207
			continue;
208
		if($in_dstid != $sp_dstid)
209
			continue;
210

    
211
		/* match the SP to a unique SA by reqid */
212

    
213
		foreach($sad as $sa) {
214

    
215
			/* match REQIDs */
216

    
217
			if($sa[reqid] != $sp[reqid])
218
				continue;
219

    
220
			/* sanitize for NAT-T ports */
221

    
222
			$sa_srcip = $sa['src'];
223
			$sa_dstip = $sa['dst'];
224

    
225
			if (strstr($sa_srcip,"["))
226
				$sa_srcip = substr($sa_srcip,0,strcspn($sa_srcip,"["));
227
			if (strstr($sa_dstip,"["))
228
				$sa_dstip = substr($sa_dstip,0,strcspn($sa_dstip,"["));
229

    
230
			/* match IPs */
231

    
232
			if($in_srcip != $sa_srcip)
233
				continue;
234
			if($in_dstip != $sa_dstip)
235
				continue;
236

    
237
			return $sa;
238
		}
239
	}
240

    
241
	return NULL;
242
}
243

    
244
/*
245
 * Return dump of SPD table
246
 */
247
function ipsec_dump_spd()
248
{
249
	$fd = @popen("/usr/local/sbin/setkey -DP", "r");
250
	$spd = array();
251
	if ($fd) {
252
		while (!feof($fd)) {
253
			$line = chop(fgets($fd));
254
			if (!$line)
255
				continue;
256
			if ($line == "No SPD entries.")
257
				break;
258
			if ($line[0] != "\t") {
259
				if (is_array($cursp))
260
					$spd[] = $cursp;
261
				$cursp = array();
262
				$linea = explode(" ", $line);
263
				$cursp['srcid'] = substr($linea[0], 0, strpos($linea[0], "["));
264
				$cursp['dstid'] = substr($linea[1], 0, strpos($linea[1], "["));
265
				$i = 0;
266
			} else if (is_array($cursp)) {
267
				$linea = explode(" ", trim($line));
268
				switch($i)
269
				{
270
					case 1:
271
						if ($linea[1] == "none")	/* don't show default anti-lockout rule */
272
							unset($cursp);
273
						else
274
							$cursp['dir'] = $linea[0];
275
						break;
276
					case 2:
277
						$upperspec = explode("/", $linea[0]);
278
						$cursp['proto'] = $upperspec[0];
279
						list($cursp['src'], $cursp['dst']) = explode("-", $upperspec[2]);
280
						$cursp['reqid'] =  substr($upperspec[3], strpos($upperspec[3], "#")+1);
281
						break;
282
				}
283
			}
284
			$i++;
285
		}
286
		if (is_array($cursp) && count($cursp))
287
			$spd[] = $cursp;
288
		pclose($fd);
289
	}
290

    
291
	return $spd;
292
}
293

    
294
/*
295
 * Return dump of SAD table
296
 */
297
function ipsec_dump_sad()
298
{
299
	$fd = @popen("/usr/local/sbin/setkey -D", "r");
300
	$sad = array();
301
	if ($fd) {
302
		while (!feof($fd)) {
303
			$line = chop(fgets($fd));
304
			if (!$line)
305
				continue;
306
			if ($line == "No SAD entries.")
307
				break;
308
			if ($line[0] != "\t")
309
			{
310
				if (is_array($cursa))
311
					$sad[] = $cursa;
312
				$cursa = array();
313
				list($cursa['src'],$cursa['dst']) = explode(" ", $line);
314
				$i = 0;
315
			}
316
			else
317
			{
318
				$linea = explode(" ", trim($line));
319
				switch ($i) {
320
					case 1:
321
						$cursa['proto'] = $linea[0];
322
						$cursa['spi'] = substr($linea[2], strpos($linea[2], "x")+1, -1);
323
						$reqid = substr($linea[3], strpos($linea[3], "=")+1);
324
						$cursa['reqid'] = substr($reqid, 0, strcspn($reqid,"("));
325
						break;
326
					case 2:
327
						$cursa['ealgo'] = $linea[1];
328
						break;
329
					case 3:
330
						$cursa['aalgo'] = $linea[1];
331
						break;
332
				}
333
			}
334
			$i++;
335
		}
336
		if (is_array($cursa) && count($cursa))
337
			$sad[] = $cursa;
338
		pclose($fd);
339
	}
340

    
341
	return $sad;
342
}
343

    
344
?>
(13-13/30)