Project

General

Profile

Download (14.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	easyrule.inc
4

    
5
	Copyright (C) 2009-2010 Jim Pingle (jpingle@gmail.com)
6
	Originally Sponsored By Anathematic @ pfSense Forums
7
	All rights reserved.
8

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

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

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

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

    
31
$blockaliasname = 'EasyRuleBlockHosts';
32
$protocols_with_ports = array('tcp', 'udp');
33
require_once("functions.inc");
34
require_once("util.inc");
35
require_once("ipsec.inc");
36
require_once("config.inc");
37

    
38
function easyrule_find_rule_interface($int) {
39
	global $config;
40
	/* Borrowed from firewall_rules.php */
41
	$iflist = get_configured_interface_with_descr(false, true);
42

    
43
	if ($config['pppoe']['mode'] == "server") {
44
		$iflist['pppoe'] = "PPPoE Server";
45
	}
46

    
47
	if ($config['l2tp']['mode'] == "server") {
48
		$iflist['l2tp'] = "L2TP VPN";
49
	}
50

    
51
	/* add ipsec interfaces */
52
	if (ipsec_enabled()) {
53
		$iflist["enc0"] = "IPSEC";
54
	}
55

    
56
	if (isset($iflist[$int])) {
57
		return $int;
58
	}
59

    
60
	foreach ($iflist as $if => $ifd) {
61
		if (strtolower($int) == strtolower($ifd)) {
62
			return $if;
63
		}
64
	}
65

    
66
	if (substr($int, 0, 4) == "ovpn") {
67
		return "openvpn";
68
	}
69

    
70
	return false;
71
}
72

    
73
function easyrule_block_rule_exists($int = 'wan', $ipproto = "inet") {
74
	global $blockaliasname, $config;
75
	/* No rules, we we know it doesn't exist */
76
	if (!is_array($config['filter']['rule'])) {
77
		return false;
78
	}
79

    
80
	/* Search through the rules for one referencing our alias */
81
	foreach ($config['filter']['rule'] as $rule) {
82
		if (!is_array($rule) || !is_array($rule['source'])) {
83
			continue;
84
		}
85
		$checkproto = isset($rule['ipprotocol']) ? $rule['ipprotocol'] : "inet";
86
		if ($rule['source']['address'] == $blockaliasname . strtoupper($int) && ($rule['interface'] == $int) && ($checkproto == $ipproto)) {
87
			return true;
88
		}
89
	}
90
	return false;
91
}
92

    
93
function easyrule_block_rule_create($int = 'wan', $ipproto = "inet") {
94
	global $blockaliasname, $config;
95
	/* If the alias doesn't exist, exit.
96
	 * Can't create an empty alias, and we don't know a host */
97
	if (easyrule_block_alias_getid($int) === false) {
98
		return false;
99
	}
100

    
101
	/* If the rule already exists, no need to do it again */
102
	if (easyrule_block_rule_exists($int, $ipproto)) {
103
		return true;
104
	}
105

    
106
	/* No rules, start a new array */
107
	if (!is_array($config['filter']['rule'])) {
108
		$config['filter']['rule'] = array();
109
	}
110

    
111
	filter_rules_sort();
112
	$a_filter = &$config['filter']['rule'];
113

    
114
	/* Make up a new rule */
115
	$filterent = array();
116
	$filterent['type'] = 'block';
117
	$filterent['interface'] = $int;
118
	$filterent['ipprotocol'] = $ipproto;
119
	$filterent['source']['address'] = $blockaliasname . strtoupper($int);
120
	$filterent['destination']['any'] = '';
121
	$filterent['descr'] = gettext("Easy Rule: Blocked from Firewall Log View");
122
	$filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
123

    
124
	array_splice($a_filter, 0, 0, array($filterent));
125

    
126
	return true;
127
}
128

    
129
function easyrule_block_alias_getid($int = 'wan') {
130
	global $blockaliasname, $config;
131
	if (!is_array($config['aliases'])) {
132
		return false;
133
	}
134

    
135
	/* Hunt down an alias with the name we want, return its id */
136
	foreach ($config['aliases']['alias'] as $aliasid => $alias) {
137
		if ($alias['name'] == $blockaliasname . strtoupper($int)) {
138
			return $aliasid;
139
		}
140
	}
141

    
142
	return false;
143
}
144

    
145
function easyrule_block_alias_add($host, $int = 'wan') {
146
	global $blockaliasname, $config;
147
	/* If the host isn't a valid IP address, bail */
148
	$host = trim($host, "[]");
149
	if (!is_ipaddr($host) && !is_subnet($host)) {
150
		return false;
151
	}
152

    
153
	/* If there are no aliases, start an array */
154
	if (!is_array($config['aliases']['alias'])) {
155
		$config['aliases']['alias'] = array();
156
	}
157

    
158
	$a_aliases = &$config['aliases']['alias'];
159

    
160
	/* Try to get the ID if the alias already exists */
161
	$id = easyrule_block_alias_getid($int);
162
	if ($id === false) {
163
	  unset($id);
164
	}
165

    
166
	$alias = array();
167

    
168
	if (is_subnet($host)) {
169
		list($host, $mask) = explode("/", $host);
170
	} elseif (is_specialnet($host)) {
171
		$mask = 0;
172
	} elseif (is_ipaddrv6($host)) {
173
		$mask = 128;
174
	} else {
175
		$mask = 32;
176
	}
177

    
178
	if (isset($id) && $a_aliases[$id]) {
179

    
180
		// Catch case when the list is empty
181
		if (empty($a_aliases[$id]['address'])) {
182
			$a_address = array();
183
			$a_detail = array();
184
		} else {
185
			$a_address = explode(" ", $a_aliases[$id]['address']);
186

    
187
			/* Make sure this IP isn't already in the list. */
188
			if (in_array($host.'/'.$mask, $a_address)) {
189
				return true;
190
			}
191
			$a_detail = explode("||", $a_aliases[$id]['detail']);
192
		}
193

    
194
		/* Since the alias already exists, just add to it. */
195
		$alias['name']    = $a_aliases[$id]['name'];
196
		$alias['type']    = $a_aliases[$id]['type'];
197
		$alias['descr']   = $a_aliases[$id]['descr'];
198

    
199
		$a_address[] = $host.'/'.$mask;
200
		$a_detail[] = gettext('Entry added') . ' ' . date('r');
201

    
202
		$alias['address'] = join(" ", $a_address);
203
		$alias['detail']  = join("||", $a_detail);
204

    
205
	} else {
206
		/* Create a new alias with all the proper information */
207
		$alias['name']    = $blockaliasname . strtoupper($int);
208
		$alias['type']    = 'network';
209
		$alias['descr']   = gettext("Hosts blocked from Firewall Log view");
210

    
211
		$alias['address'] = $host . '/' . $mask;
212
		$alias['detail']  = gettext('Entry added') . ' ' . date('r') . '||';
213
	}
214

    
215
	/* Replace the old alias if needed, otherwise tack it on the end */
216
	if (isset($id) && $a_aliases[$id]) {
217
		$a_aliases[$id] = $alias;
218
	} else {
219
		$a_aliases[] = $alias;
220
	}
221

    
222
	// Sort list
223
	$a_aliases = msort($a_aliases, "name");
224

    
225
	return true;
226
}
227

    
228
function easyrule_block_host_add($host, $int = 'wan', $ipproto = "inet") {
229
	global $retval;
230
	/* Bail if the supplied host is not a valid IP address */
231
	$host = trim($host, "[]");
232
	if (!is_ipaddr($host) && !is_subnet($host)) {
233
		return false;
234
	}
235

    
236
	/* Flag whether or not we need to reload the filter */
237
	$dirty = false;
238

    
239
	/* Attempt to add this host to the alias */
240
	if (easyrule_block_alias_add($host, $int)) {
241
		$dirty = true;
242
	} else {
243
		/* Couldn't add the alias, or adding the host failed. */
244
		return false;
245
	}
246

    
247
	/* Attempt to add the firewall rule if it doesn't exist.
248
	 * Failing to add the rule isn't necessarily an error, it may
249
	 * have been modified by the user in some way. Adding to the
250
	 * Alias is what's important.
251
	 */
252
	if (!easyrule_block_rule_exists($int, $ipproto)) {
253
		if (easyrule_block_rule_create($int, $ipproto)) {
254
			$dirty = true;
255
		} else {
256
			return false;
257
		}
258
	}
259

    
260
	/* If needed, write the config and reload the filter */
261
	if ($dirty) {
262
		write_config();
263
		$retval = filter_configure();
264
		if (!empty($_SERVER['DOCUMENT_ROOT'])) {
265
			header("Location: firewall_aliases.php");
266
			exit;
267
		} else {
268
			return true;
269
		}
270
	} else {
271
		return false;
272
	}
273
}
274

    
275
function easyrule_pass_rule_add($int, $proto, $srchost, $dsthost, $dstport, $ipproto) {
276
	global $config;
277

    
278
	/* No rules, start a new array */
279
	if (!is_array($config['filter']['rule'])) {
280
		$config['filter']['rule'] = array();
281
	}
282

    
283
	filter_rules_sort();
284
	$a_filter = &$config['filter']['rule'];
285

    
286
	/* Make up a new rule */
287
	$filterent = array();
288
	$filterent['type'] = 'pass';
289
	$filterent['interface'] = $int;
290
	$filterent['ipprotocol'] = $ipproto;
291
	$filterent['descr'] = gettext("Easy Rule: Passed from Firewall Log View");
292

    
293
	if ($proto != "any") {
294
		$filterent['protocol'] = $proto;
295
	} else {
296
		unset($filterent['protocol']);
297
	}
298

    
299
	/* Default to only allow echo requests, since that's what most people want and
300
	 *  it should be a safe choice. */
301
	if ($proto == "icmp") {
302
		$filterent['icmptype'] = 'echoreq';
303
	}
304

    
305
	if ((strtolower($proto) == "icmp6") || (strtolower($proto) == "icmpv6")) {
306
		$filterent['protocol'] = "icmp";
307
	}
308

    
309
	if (is_subnet($srchost)) {
310
		list($srchost, $srcmask) = explode("/", $srchost);
311
	} elseif (is_specialnet($srchost)) {
312
		$srcmask = 0;
313
	} elseif (is_ipaddrv6($srchost)) {
314
		$srcmask = 128;
315
	} else {
316
		$srcmask = 32;
317
	}
318

    
319
	if (is_subnet($dsthost)) {
320
		list($dsthost, $dstmask) = explode("/", $dsthost);
321
	} elseif (is_specialnet($dsthost)) {
322
		$dstmask = 0;
323
	} elseif (is_ipaddrv6($dsthost)) {
324
		$dstmask = 128;
325
	} else {
326
		$dstmask = 32;
327
	}
328

    
329
	pconfig_to_address($filterent['source'], $srchost, $srcmask);
330
	pconfig_to_address($filterent['destination'], $dsthost, $dstmask, '', $dstport, $dstport);
331

    
332
	$filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
333
	$a_filter[] = $filterent;
334

    
335
	write_config($filterent['descr']);
336
	$retval = filter_configure();
337
	if (!empty($_SERVER['DOCUMENT_ROOT'])) {
338
		header("Location: firewall_rules.php?if={$int}");
339
		exit;
340
	} else {
341
		return true;
342
	}
343
}
344

    
345
function easyrule_parse_block($int, $src, $ipproto = "inet") {
346
	if (!empty($src) && !empty($int)) {
347
		$src = trim($src, "[]");
348
		if (!is_ipaddr($src) && !is_subnet($src)) {
349
			return gettext("Tried to block invalid IP:") . ' ' . htmlspecialchars($src);
350
		}
351
		$int = easyrule_find_rule_interface($int);
352
		if ($int === false) {
353
			return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
354
		}
355
		if (easyrule_block_host_add($src, $int, $ipproto)) {
356
			return gettext("Host added successfully");
357
		} else {
358
			return gettext("Failed to create block rule, alias, or add host.");
359
		}
360
	} else {
361
		return gettext("Tried to block but had no host IP or interface");
362
	}
363
	return gettext("Unknown block error.");
364
}
365

    
366
function easyrule_parse_unblock($int, $host, $ipproto = "inet") {
367
	global $blockaliasname, $config;
368

    
369
	if (!empty($host) && !empty($int)) {
370
		$host = trim($host, "[]");
371
		if (!is_ipaddr($host) && !is_subnet($host)) {
372
			return gettext("Tried to unblock invalid IP:") . ' ' . htmlspecialchars($host);
373
		}
374
		$real_int = easyrule_find_rule_interface($int);
375
		if ($real_int === false) {
376
			return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
377
		}
378

    
379
		/* Try to get the ID - will fail if there are no rules/alias on this interface */
380
		$id = easyrule_block_alias_getid($real_int);
381
		if ($id === false || !$config['aliases']['alias'][$id]) {
382
			return gettext("No block rules set on interface:") . ' ' . htmlspecialchars($int);
383
		}
384

    
385
		$alias = &$config['aliases']['alias'][$id];
386

    
387
		if (is_subnet($host)) {
388
			list($host, $mask) = explode("/", $host);
389
		} elseif (is_specialnet($host)) {
390
			$mask = 0;
391
		} elseif (is_ipaddrv6($host)) {
392
			$mask = 128;
393
		} else {
394
			$mask = 32;
395
		}
396

    
397
		// Create the expected string representation
398
		$unblock = $host.'/'.$mask;
399

    
400
		$a_address = explode(" ", $config['aliases']['alias'][$id]['address']);
401
		$a_detail = explode("||", $config['aliases']['alias'][$id]['detail']);
402

    
403
		if (($key = array_search($unblock, $a_address)) !== false) {
404
			unset($a_address[$key]);
405
			unset($a_detail[$key]);
406
			// Write back the result to the config array
407
			$config['aliases']['alias'][$id]['address'] = join(" ", $a_address);
408
			$config['aliases']['alias'][$id]['detail'] = join("||", $a_detail);
409

    
410
			// Update config
411
			write_config();
412
			$retval = filter_configure();
413
			if (!empty($_SERVER['DOCUMENT_ROOT'])) {
414
				header("Location: firewall_aliases.php");
415
				exit;
416
			} else {
417
				return gettext("Host unblocked successfully");
418
			}
419
		} else {
420
			return gettext("Host ist not on block list: " . $host);
421
		}
422
	}
423

    
424
	return gettext("Tried to unblock but had no host IP or interface");
425

    
426
}
427

    
428
function easyrule_parse_getblock($int = 'wan', $sep = "\n") {
429
	global $blockaliasname, $config;
430

    
431
	$real_int = easyrule_find_rule_interface($int);
432
	if ($real_int === false) {
433
		return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
434
	}
435

    
436
	/* Try to get the ID - will fail if there are no rules/alias on this interface */
437
	$id = easyrule_block_alias_getid($real_int);
438

    
439
	if ($id === false || !$config['aliases']['alias'][$id] || empty($config['aliases']['alias'][$id]['address'])) {
440
		return gettext("No block rules set on interface:") . ' ' . htmlspecialchars($int);
441
	}
442
	return join($sep, explode(" ", $config['aliases']['alias'][$id]['address']));
443

    
444
}
445

    
446
function easyrule_parse_pass($int, $proto, $src, $dst, $dstport = 0, $ipproto = "inet") {
447
	/* Check for valid int, srchost, dsthost, dstport, and proto */
448
	global $protocols_with_ports;
449
	$src = trim($src, "[]");
450
	$dst = trim($dst, "[]");
451

    
452
	if (!empty($int) && !empty($proto) && !empty($src) && !empty($dst)) {
453
		$int = easyrule_find_rule_interface($int);
454
		if ($int === false) {
455
			return gettext("Invalid interface for pass rule:") . ' ' . htmlspecialchars($int);
456
		}
457
		if (getprotobyname($proto) == -1) {
458
			return gettext("Invalid protocol for pass rule:") . ' ' . htmlspecialchars($proto);
459
		}
460
		if (!is_ipaddr($src) && !is_subnet($src) && !is_ipaddroralias($src) && !is_specialnet($src)) {
461
			return gettext("Tried to pass invalid source IP:") . ' ' . htmlspecialchars($src);
462
		}
463
		if (!is_ipaddr($dst) && !is_subnet($dst) && !is_ipaddroralias($dst) && !is_specialnet($dst)) {
464
			return gettext("Tried to pass invalid destination IP:") . ' ' . htmlspecialchars($dst);
465
		}
466
		if (in_array($proto, $protocols_with_ports)) {
467
			if (empty($dstport)) {
468
				return gettext("Missing destination port:") . ' ' . htmlspecialchars($dstport);
469
			}
470
			if (!is_port($dstport) && ($dstport != "any")) {
471
				return gettext("Tried to pass invalid destination port:") . ' ' . htmlspecialchars($dstport);
472
			}
473
		} else {
474
			$dstport = 0;
475
		}
476
		/* Should have valid input... */
477
		if (easyrule_pass_rule_add($int, $proto, $src, $dst, $dstport, $ipproto)) {
478
			return gettext("Successfully added pass rule!");
479
		} else {
480
			return gettext("Failed to add pass rule.");
481
		}
482
	} else {
483
		return gettext("Missing parameters for pass rule.");
484
	}
485
	return gettext("Unknown pass error.");
486
}
487

    
488
?>
(17-17/65)