Project

General

Profile

Download (14.2 KB) Statistics
| Branch: | Tag: | Revision:
1 c0b6fdde jim-p
<?php
2
/*
3 ce77a9c4 Phil Davis
	easyrule.inc
4 c0b6fdde jim-p
5 998f77a8 jim-p
	Copyright (C) 2009-2010 Jim Pingle (jpingle@gmail.com)
6
	Originally Sponsored By Anathematic @ pfSense Forums
7 c0b6fdde jim-p
	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 7ac5a4cb Scott Ullrich
/*
31 dadad8b3 jim-p
	pfSense_BUILDER_BINARIES:
32 7ac5a4cb Scott Ullrich
	pfSense_MODULE:	filter
33
*/
34 c0b6fdde jim-p
35
$blockaliasname = 'EasyRuleBlockHosts';
36 865ff9b4 jim-p
$protocols_with_ports = array('tcp', 'udp');
37
require_once("functions.inc");
38
require_once("util.inc");
39
require_once("config.inc");
40 4d828a9a Ermal Lu?i
41 c0b6fdde jim-p
function easyrule_find_rule_interface($int) {
42
	global $config;
43
	/* Borrowed from firewall_rules.php */
44 4d828a9a Ermal Lu?i
	$iflist = get_configured_interface_with_descr(false, true);
45 dadad8b3 jim-p
46 c0b6fdde jim-p
	if ($config['pptpd']['mode'] == "server")
47
		$iflist['pptp'] = "PPTP VPN";
48 dadad8b3 jim-p
49 bd40781a Seth Mos
	if ($config['pppoe']['mode'] == "server")
50 d3d23754 Chris Buechler
		$iflist['pppoe'] = "PPPoE Server";
51 dadad8b3 jim-p
52 4d828a9a Ermal Lu?i
	if ($config['l2tp']['mode'] == "server")
53
                $iflist['l2tp'] = "L2TP VPN";
54
55 c0b6fdde jim-p
	/* add ipsec interfaces */
56 c6dfd289 jim-p
	if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])){
57 c0b6fdde jim-p
		$iflist["enc0"] = "IPSEC";
58
	}
59 dadad8b3 jim-p
60 c0b6fdde jim-p
	if (isset($iflist[$int]))
61
		return $int;
62
63
	foreach ($iflist as $if => $ifd) {
64
		if (strtolower($int) == strtolower($ifd))
65
			return $if;
66
	}
67 dadad8b3 jim-p
68 066afaf1 jim-p
	if (substr($int, 0, 4) == "ovpn")
69
		return "openvpn";
70
71 c0b6fdde jim-p
	return false;
72
}
73
74 4475997e jim-p
function easyrule_block_rule_exists($int = 'wan', $ipproto = "inet") {
75 c0b6fdde jim-p
	global $blockaliasname, $config;
76
	/* No rules, we we know it doesn't exist */
77
	if (!is_array($config['filter']['rule'])) {
78
		return false;
79
	}
80
81
	/* Search through the rules for one referencing our alias */
82 28a581b8 jim-p
	foreach ($config['filter']['rule'] as $rule) {
83 f3704cb2 jim-p
		if (!is_array($rule) || !is_array($rule['source']))
84
			continue;
85 4475997e jim-p
		$checkproto = isset($rule['ipprotocol']) ? $rule['ipprotocol'] : "inet";
86
		if ($rule['source']['address'] == $blockaliasname . strtoupper($int) && ($rule['interface'] == $int) && ($checkproto == $ipproto))
87 c0b6fdde jim-p
			return true;
88 28a581b8 jim-p
	}
89 c0b6fdde jim-p
	return false;
90
}
91
92 64eda26c jim-p
function easyrule_block_rule_create($int = 'wan', $ipproto = "inet") {
93 c0b6fdde jim-p
	global $blockaliasname, $config;
94
	/* If the alias doesn't exist, exit.
95
	 * Can't create an empty alias, and we don't know a host */
96
	if (easyrule_block_alias_getid($int) === false)
97
		return false;
98
99
	/* If the rule already exists, no need to do it again */
100 64eda26c jim-p
	if (easyrule_block_rule_exists($int, $ipproto))
101 c0b6fdde jim-p
		return true;
102
103
	/* No rules, start a new array */
104
	if (!is_array($config['filter']['rule'])) {
105
		$config['filter']['rule'] = array();
106
	}
107
108
	filter_rules_sort();
109
	$a_filter = &$config['filter']['rule'];
110
111
	/* Make up a new rule */
112
	$filterent = array();
113
	$filterent['type'] = 'block';
114 dadad8b3 jim-p
	$filterent['interface'] = $int;
115 64eda26c jim-p
	$filterent['ipprotocol'] = $ipproto;
116 c0b6fdde jim-p
	$filterent['source']['address'] = $blockaliasname . strtoupper($int);
117
	$filterent['destination']['any'] = '';
118 5bd033a0 Renato Botelho
	$filterent['descr'] = gettext("Easy Rule: Blocked from Firewall Log View");
119 ba1d9714 jim-p
	$filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
120 c0b6fdde jim-p
121 a0140246 jim-p
	array_splice($a_filter, 0, 0, array($filterent));
122 c0b6fdde jim-p
123
	return true;
124
}
125
126
function easyrule_block_alias_getid($int = 'wan') {
127
	global $blockaliasname, $config;
128
	if (!is_array($config['aliases']))
129
		return false;
130
131
	/* Hunt down an alias with the name we want, return its id */
132
	foreach ($config['aliases']['alias'] as $aliasid => $alias)
133
		if ($alias['name'] == $blockaliasname . strtoupper($int))
134
			return $aliasid;
135
136
	return false;
137
}
138
139
function easyrule_block_alias_add($host, $int = 'wan') {
140
	global $blockaliasname, $config;
141
	/* If the host isn't a valid IP address, bail */
142 b4147482 jim-p
	$host = trim($host, "[]");
143 0c305760 jim-p
	if (!is_ipaddr($host) && !is_subnet($host))
144 c0b6fdde jim-p
		return false;
145
146
	/* If there are no aliases, start an array */
147
	if (!is_array($config['aliases']['alias']))
148
		$config['aliases']['alias'] = array();
149
150
	$a_aliases = &$config['aliases']['alias'];
151
152
	/* Try to get the ID if the alias already exists */
153
	$id = easyrule_block_alias_getid($int);
154
	if ($id === false)
155
	  unset($id);
156
157
	$alias = array();
158
159 0c305760 jim-p
	if (is_subnet($host)) {
160
		list($host, $mask) = explode("/", $host);
161
	} elseif (is_specialnet($host)) {
162
		$mask = 0;
163 b4147482 jim-p
	} elseif (is_ipaddrv6($host)) {
164
		$mask = 128;
165 0c305760 jim-p
	} else {
166
		$mask = 32;
167
	}
168
169 c0b6fdde jim-p
	if (isset($id) && $a_aliases[$id]) {
170 e4d8943c Oliver Welter
171
		// Catch case when the list is empty
172
		if (empty($a_aliases[$id]['address'])) {
173
			$a_address = array();
174
			$a_detail = array();
175
		} else {
176
			$a_address = explode(" ", $a_aliases[$id]['address']);
177
178
			/* Make sure this IP isn't already in the list. */
179
			if (in_array($host.'/'.$mask, $a_address)) {
180
				return true;
181
			}
182
			$a_detail = explode("||", $a_aliases[$id]['detail']);
183
		}
184
185 c0b6fdde jim-p
		/* Since the alias already exists, just add to it. */
186
		$alias['name']    = $a_aliases[$id]['name'];
187
		$alias['type']    = $a_aliases[$id]['type'];
188
		$alias['descr']   = $a_aliases[$id]['descr'];
189
190 e4d8943c Oliver Welter
		$a_address[] = $host.'/'.$mask;
191
		$a_detail[] = gettext('Entry added') . ' ' . date('r');
192
193
		$alias['address'] = join(" ", $a_address);
194
		$alias['detail']  = join("||", $a_detail);
195
196 c0b6fdde jim-p
	} else {
197
		/* Create a new alias with all the proper information */
198
	 	$alias['name']    = $blockaliasname . strtoupper($int);
199
	 	$alias['type']    = 'network';
200 9d3d8d00 Vinicius Coque
		$alias['descr']   = gettext("Hosts blocked from Firewall Log view");
201 c0b6fdde jim-p
202 0c305760 jim-p
		$alias['address'] = $host . '/' . $mask;
203 5bd033a0 Renato Botelho
		$alias['detail']  = gettext('Entry added') . ' ' . date('r') . '||';
204 c0b6fdde jim-p
	}
205
206
	/* Replace the old alias if needed, otherwise tack it on the end */
207
	if (isset($id) && $a_aliases[$id])
208
		$a_aliases[$id] = $alias;
209
	else
210
		$a_aliases[] = $alias;
211 9bb8d542 Ermal Lu?i
212
	// Sort list
213
	$a_aliases = msort($a_aliases, "name");
214 c0b6fdde jim-p
215
	return true;
216
}
217
218 64eda26c jim-p
function easyrule_block_host_add($host, $int = 'wan', $ipproto = "inet") {
219 c0b6fdde jim-p
	global $retval;
220
	/* Bail if the supplied host is not a valid IP address */
221 b4147482 jim-p
	$host = trim($host, "[]");
222 0c305760 jim-p
	if (!is_ipaddr($host) && !is_subnet($host))
223 c0b6fdde jim-p
		return false;
224
225
	/* Flag whether or not we need to reload the filter */
226
	$dirty = false;
227
228
	/* Attempt to add this host to the alias */
229
	if (easyrule_block_alias_add($host, $int)) {
230
		$dirty = true;
231
	} else {
232
		/* Couldn't add the alias, or adding the host failed. */
233
		return false;
234
	}
235
236
	/* Attempt to add the firewall rule if it doesn't exist.
237
	 * Failing to add the rule isn't necessarily an error, it may
238
	 * have been modified by the user in some way. Adding to the
239
	 * Alias is what's important.
240
	 */
241 64eda26c jim-p
	if (!easyrule_block_rule_exists($int, $ipproto)) {
242
		if (easyrule_block_rule_create($int, $ipproto)) {
243 c0b6fdde jim-p
			$dirty = true;
244
		} else {
245
			return false;
246
		}
247
	}
248
249
	/* If needed, write the config and reload the filter */
250
	if ($dirty) {
251
		write_config();
252
		$retval = filter_configure();
253 865ff9b4 jim-p
		if (!empty($_SERVER['DOCUMENT_ROOT'])) {
254
			header("Location: firewall_aliases.php");
255
			exit;
256
		} else {
257
			return true;
258
		}
259 c0b6fdde jim-p
	} else {
260
		return false;
261
	}
262
}
263
264 bd40781a Seth Mos
function easyrule_pass_rule_add($int, $proto, $srchost, $dsthost, $dstport, $ipproto) {
265 c0b6fdde jim-p
	global $config;
266
267
	/* No rules, start a new array */
268
	if (!is_array($config['filter']['rule'])) {
269
		$config['filter']['rule'] = array();
270
	}
271
272
	filter_rules_sort();
273
	$a_filter = &$config['filter']['rule'];
274
275
	/* Make up a new rule */
276
	$filterent = array();
277
	$filterent['type'] = 'pass';
278
	$filterent['interface'] = $int;
279 bd40781a Seth Mos
	$filterent['ipprotocol'] = $ipproto;
280 5bd033a0 Renato Botelho
	$filterent['descr'] = gettext("Easy Rule: Passed from Firewall Log View");
281 c0b6fdde jim-p
282
	if ($proto != "any")
283
		$filterent['protocol'] = $proto;
284
	else
285
		unset($filterent['protocol']);
286
287
	/* Default to only allow echo requests, since that's what most people want and
288
	 *  it should be a safe choice. */
289
	if ($proto == "icmp")
290
		$filterent['icmptype'] = 'echoreq';
291
292 4410f699 jim-p
	if ((strtolower($proto) == "icmp6") || (strtolower($proto) == "icmpv6"))
293 daffbc34 jim-p
		$filterent['protocol'] = "icmp";
294
295 0c305760 jim-p
	if (is_subnet($srchost)) {
296
		list($srchost, $srcmask) = explode("/", $srchost);
297
	} elseif (is_specialnet($srchost)) {
298
		$srcmask = 0;
299 aea83400 Thomas Rieschl
	} elseif (is_ipaddrv6($srchost)) {
300
		$srcmask = 128;
301 0c305760 jim-p
	} else {
302
		$srcmask = 32;
303
	}
304
305
	if (is_subnet($dsthost)) {
306
		list($dsthost, $dstmask) = explode("/", $dsthost);
307
	} elseif (is_specialnet($dsthost)) {
308
		$dstmask = 0;
309 aea83400 Thomas Rieschl
	} elseif (is_ipaddrv6($dsthost)) {
310
		$dstmask = 128;
311 0c305760 jim-p
	} else {
312
		$dstmask = 32;
313
	}
314
315
	pconfig_to_address($filterent['source'], $srchost, $srcmask);
316
	pconfig_to_address($filterent['destination'], $dsthost, $dstmask, '', $dstport, $dstport);
317 c0b6fdde jim-p
318 ba1d9714 jim-p
	$filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
319 c0b6fdde jim-p
	$a_filter[] = $filterent;
320
321 998f77a8 jim-p
	write_config($filterent['descr']);
322 c0b6fdde jim-p
	$retval = filter_configure();
323 865ff9b4 jim-p
	if (!empty($_SERVER['DOCUMENT_ROOT'])) {
324
		header("Location: firewall_rules.php?if={$int}");
325
		exit;
326
	} else {
327
		return true;
328
	}
329
}
330
331 64eda26c jim-p
function easyrule_parse_block($int, $src, $ipproto = "inet") {
332 865ff9b4 jim-p
	if (!empty($src) && !empty($int)) {
333 b4147482 jim-p
		$src = trim($src, "[]");
334 0c305760 jim-p
		if (!is_ipaddr($src) && !is_subnet($src)) {
335 5bd033a0 Renato Botelho
			return gettext("Tried to block invalid IP:") . ' ' . htmlspecialchars($src);
336 865ff9b4 jim-p
		}
337
		$int = easyrule_find_rule_interface($int);
338
		if ($int === false) {
339 5bd033a0 Renato Botelho
			return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
340 865ff9b4 jim-p
		}
341 64eda26c jim-p
		if (easyrule_block_host_add($src, $int, $ipproto)) {
342 5bd033a0 Renato Botelho
			return gettext("Host added successfully");
343 865ff9b4 jim-p
		} else {
344 5bd033a0 Renato Botelho
			return gettext("Failed to create block rule, alias, or add host.");
345 865ff9b4 jim-p
		}
346
	} else {
347 5bd033a0 Renato Botelho
		return gettext("Tried to block but had no host IP or interface");
348 865ff9b4 jim-p
	}
349 5bd033a0 Renato Botelho
	return gettext("Unknown block error.");
350 865ff9b4 jim-p
}
351 4dedce6d Oliver Welter
352
function easyrule_parse_unblock($int, $host, $ipproto = "inet") {
353
	global $blockaliasname, $config;
354
355
	if (!empty($host) && !empty($int)) {
356
		$host = trim($host, "[]");
357
		if (!is_ipaddr($host) && !is_subnet($host)) {
358
			return gettext("Tried to unblock invalid IP:") . ' ' . htmlspecialchars($host);
359
		}
360
		$real_int = easyrule_find_rule_interface($int);
361
		if ($real_int === false) {
362
			return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
363
		}
364
365
		/* Try to get the ID - will fail if there are no rules/alias on this interface */
366
		$id = easyrule_block_alias_getid($real_int);
367
		if ($id === false || !$config['aliases']['alias'][$id]) {
368
			return gettext("No block rules set on interface:") . ' ' . htmlspecialchars($int);
369
		}
370
371
		$alias = &$config['aliases']['alias'][$id];
372
373
		if (is_subnet($host)) {
374
			list($host, $mask) = explode("/", $host);
375
		} elseif (is_specialnet($host)) {
376
			$mask = 0;
377
		} elseif (is_ipaddrv6($host)) {
378
			$mask = 128;
379
		} else {
380
			$mask = 32;
381
		}
382
383
		// Create the expected string representation
384
		$unblock = $host.'/'.$mask;
385
386
		$a_address = explode(" ", $config['aliases']['alias'][$id]['address']);
387
		$a_detail = explode("||", $config['aliases']['alias'][$id]['detail']);
388
389
		if(($key = array_search($unblock, $a_address)) !== false) {
390
			unset($a_address[$key]);
391
			unset($a_detail[$key]);
392
			// Write back the result to the config array
393
			$config['aliases']['alias'][$id]['address'] = join(" ", $a_address);
394
			$config['aliases']['alias'][$id]['detail'] = join("||", $a_detail);
395
396
			// Update config
397
			write_config();
398
			$retval = filter_configure();
399
			if (!empty($_SERVER['DOCUMENT_ROOT'])) {
400
				header("Location: firewall_aliases.php");
401
				exit;
402
			} else {
403
				return gettext("Host unblocked successfully");
404
			}
405
		} else {
406
			return gettext("Host ist not on block list: " . $host);
407
		}
408
	}
409
410
	return gettext("Tried to unblock but had no host IP or interface");
411
412
}
413
414
function easyrule_parse_getblock($int = 'wan', $sep = "\n") {
415
	global $blockaliasname, $config;
416
417
	$real_int = easyrule_find_rule_interface($int);
418
	if ($real_int === false) {
419
		return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
420
	}
421
422
	/* Try to get the ID - will fail if there are no rules/alias on this interface */
423
	$id = easyrule_block_alias_getid($real_int);
424
425
	if ($id === false || !$config['aliases']['alias'][$id] || empty($config['aliases']['alias'][$id]['address'])) {
426
		return gettext("No block rules set on interface:") . ' ' . htmlspecialchars($int);
427
	}
428
	return join($sep, explode(" ", $config['aliases']['alias'][$id]['address']));
429
430
}
431
432 64eda26c jim-p
function easyrule_parse_pass($int, $proto, $src, $dst, $dstport = 0, $ipproto = "inet") {
433 865ff9b4 jim-p
	/* Check for valid int, srchost, dsthost, dstport, and proto */
434
	global $protocols_with_ports;
435 b4147482 jim-p
	$src = trim($src, "[]");
436
	$dst = trim($dst, "[]");
437 865ff9b4 jim-p
438
	if (!empty($int) && !empty($proto) && !empty($src) && !empty($dst)) {
439
		$int = easyrule_find_rule_interface($int);
440
		if ($int === false) {
441 5bd033a0 Renato Botelho
			return gettext("Invalid interface for pass rule:") . ' ' . htmlspecialchars($int);
442 865ff9b4 jim-p
		}
443
		if (getprotobyname($proto) == -1) {
444 5bd033a0 Renato Botelho
			return gettext("Invalid protocol for pass rule:") . ' ' . htmlspecialchars($proto);
445 865ff9b4 jim-p
		}
446 0c305760 jim-p
		if (!is_ipaddr($src) && !is_subnet($src) && !is_ipaddroralias($src) && !is_specialnet($src)) {
447 5bd033a0 Renato Botelho
			return gettext("Tried to pass invalid source IP:") . ' ' . htmlspecialchars($src);
448 865ff9b4 jim-p
		}
449 0c305760 jim-p
		if (!is_ipaddr($dst) && !is_subnet($dst) && !is_ipaddroralias($dst) && !is_specialnet($dst)) {
450 5bd033a0 Renato Botelho
			return gettext("Tried to pass invalid destination IP:") . ' ' . htmlspecialchars($dst);
451 865ff9b4 jim-p
		}
452
		if (in_array($proto, $protocols_with_ports)) {
453
			if (empty($dstport)) {
454 5bd033a0 Renato Botelho
				return gettext("Missing destination port:") . ' ' . htmlspecialchars($dstport);
455 865ff9b4 jim-p
			}
456 0c305760 jim-p
			if (!is_port($dstport) && ($dstport != "any")) {
457 5bd033a0 Renato Botelho
				return gettext("Tried to pass invalid destination port:") . ' ' . htmlspecialchars($dstport);
458 865ff9b4 jim-p
			}
459
		} else {
460
			$dstport = 0;
461
		}
462
		/* Should have valid input... */
463 bd40781a Seth Mos
		if (easyrule_pass_rule_add($int, $proto, $src, $dst, $dstport, $ipproto)) {
464 5bd033a0 Renato Botelho
			return gettext("Successfully added pass rule!");
465 865ff9b4 jim-p
		} else {
466 5bd033a0 Renato Botelho
			return gettext("Failed to add pass rule.");
467 865ff9b4 jim-p
		}
468
	} else {
469 5bd033a0 Renato Botelho
		return gettext("Missing parameters for pass rule.");
470 865ff9b4 jim-p
	}
471 5bd033a0 Renato Botelho
	return gettext("Unknown pass error.");
472 c0b6fdde jim-p
}
473 9734b054 Scott Ullrich
474 bd40781a Seth Mos
?>