Project

General

Profile

Download (14.2 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
	pfSense_BUILDER_BINARIES:
32
	pfSense_MODULE:	filter
33
*/
34

    
35
$blockaliasname = 'EasyRuleBlockHosts';
36
$protocols_with_ports = array('tcp', 'udp');
37
require_once("functions.inc");
38
require_once("util.inc");
39
require_once("config.inc");
40

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

    
46
	if ($config['pptpd']['mode'] == "server")
47
		$iflist['pptp'] = "PPTP VPN";
48

    
49
	if ($config['pppoe']['mode'] == "server")
50
		$iflist['pppoe'] = "PPPoE Server";
51

    
52
	if ($config['l2tp']['mode'] == "server")
53
                $iflist['l2tp'] = "L2TP VPN";
54

    
55
	/* add ipsec interfaces */
56
	if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])){
57
		$iflist["enc0"] = "IPSEC";
58
	}
59

    
60
	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

    
68
	if (substr($int, 0, 4) == "ovpn")
69
		return "openvpn";
70

    
71
	return false;
72
}
73

    
74
function easyrule_block_rule_exists($int = 'wan', $ipproto = "inet") {
75
	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
	foreach ($config['filter']['rule'] as $rule) {
83
		if (!is_array($rule) || !is_array($rule['source']))
84
			continue;
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
	return false;
90
}
91

    
92
function easyrule_block_rule_create($int = 'wan', $ipproto = "inet") {
93
	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
	if (easyrule_block_rule_exists($int, $ipproto))
101
		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
	$filterent['interface'] = $int;
115
	$filterent['ipprotocol'] = $ipproto;
116
	$filterent['source']['address'] = $blockaliasname . strtoupper($int);
117
	$filterent['destination']['any'] = '';
118
	$filterent['descr'] = gettext("Easy Rule: Blocked from Firewall Log View");
119
	$filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
120

    
121
	array_splice($a_filter, 0, 0, array($filterent));
122

    
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
	$host = trim($host, "[]");
143
	if (!is_ipaddr($host) && !is_subnet($host))
144
		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
	if (is_subnet($host)) {
160
		list($host, $mask) = explode("/", $host);
161
	} elseif (is_specialnet($host)) {
162
		$mask = 0;
163
	} elseif (is_ipaddrv6($host)) {
164
		$mask = 128;
165
	} else {
166
		$mask = 32;
167
	}
168

    
169
	if (isset($id) && $a_aliases[$id]) {
170

    
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
		/* 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
		$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
	} else {
197
		/* Create a new alias with all the proper information */
198
	 	$alias['name']    = $blockaliasname . strtoupper($int);
199
	 	$alias['type']    = 'network';
200
		$alias['descr']   = gettext("Hosts blocked from Firewall Log view");
201

    
202
		$alias['address'] = $host . '/' . $mask;
203
		$alias['detail']  = gettext('Entry added') . ' ' . date('r') . '||';
204
	}
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

    
212
	// Sort list
213
	$a_aliases = msort($a_aliases, "name");
214

    
215
	return true;
216
}
217

    
218
function easyrule_block_host_add($host, $int = 'wan', $ipproto = "inet") {
219
	global $retval;
220
	/* Bail if the supplied host is not a valid IP address */
221
	$host = trim($host, "[]");
222
	if (!is_ipaddr($host) && !is_subnet($host))
223
		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
	if (!easyrule_block_rule_exists($int, $ipproto)) {
242
		if (easyrule_block_rule_create($int, $ipproto)) {
243
			$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
		if (!empty($_SERVER['DOCUMENT_ROOT'])) {
254
			header("Location: firewall_aliases.php");
255
			exit;
256
		} else {
257
			return true;
258
		}
259
	} else {
260
		return false;
261
	}
262
}
263

    
264
function easyrule_pass_rule_add($int, $proto, $srchost, $dsthost, $dstport, $ipproto) {
265
	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
	$filterent['ipprotocol'] = $ipproto;
280
	$filterent['descr'] = gettext("Easy Rule: Passed from Firewall Log View");
281

    
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
	if ((strtolower($proto) == "icmp6") || (strtolower($proto) == "icmpv6"))
293
		$filterent['protocol'] = "icmp";
294

    
295
	if (is_subnet($srchost)) {
296
		list($srchost, $srcmask) = explode("/", $srchost);
297
	} elseif (is_specialnet($srchost)) {
298
		$srcmask = 0;
299
	} elseif (is_ipaddrv6($srchost)) {
300
		$srcmask = 128;
301
	} 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
	} elseif (is_ipaddrv6($dsthost)) {
310
		$dstmask = 128;
311
	} 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

    
318
	$filterent['created'] = make_config_revision_entry(null, gettext("Easy Rule"));
319
	$a_filter[] = $filterent;
320

    
321
	write_config($filterent['descr']);
322
	$retval = filter_configure();
323
	if (!empty($_SERVER['DOCUMENT_ROOT'])) {
324
		header("Location: firewall_rules.php?if={$int}");
325
		exit;
326
	} else {
327
		return true;
328
	}
329
}
330

    
331
function easyrule_parse_block($int, $src, $ipproto = "inet") {
332
	if (!empty($src) && !empty($int)) {
333
		$src = trim($src, "[]");
334
		if (!is_ipaddr($src) && !is_subnet($src)) {
335
			return gettext("Tried to block invalid IP:") . ' ' . htmlspecialchars($src);
336
		}
337
		$int = easyrule_find_rule_interface($int);
338
		if ($int === false) {
339
			return gettext("Invalid interface for block rule:") . ' ' . htmlspecialchars($int);
340
		}
341
		if (easyrule_block_host_add($src, $int, $ipproto)) {
342
			return gettext("Host added successfully");
343
		} else {
344
			return gettext("Failed to create block rule, alias, or add host.");
345
		}
346
	} else {
347
		return gettext("Tried to block but had no host IP or interface");
348
	}
349
	return gettext("Unknown block error.");
350
}
351

    
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
function easyrule_parse_pass($int, $proto, $src, $dst, $dstport = 0, $ipproto = "inet") {
433
	/* Check for valid int, srchost, dsthost, dstport, and proto */
434
	global $protocols_with_ports;
435
	$src = trim($src, "[]");
436
	$dst = trim($dst, "[]");
437

    
438
	if (!empty($int) && !empty($proto) && !empty($src) && !empty($dst)) {
439
		$int = easyrule_find_rule_interface($int);
440
		if ($int === false) {
441
			return gettext("Invalid interface for pass rule:") . ' ' . htmlspecialchars($int);
442
		}
443
		if (getprotobyname($proto) == -1) {
444
			return gettext("Invalid protocol for pass rule:") . ' ' . htmlspecialchars($proto);
445
		}
446
		if (!is_ipaddr($src) && !is_subnet($src) && !is_ipaddroralias($src) && !is_specialnet($src)) {
447
			return gettext("Tried to pass invalid source IP:") . ' ' . htmlspecialchars($src);
448
		}
449
		if (!is_ipaddr($dst) && !is_subnet($dst) && !is_ipaddroralias($dst) && !is_specialnet($dst)) {
450
			return gettext("Tried to pass invalid destination IP:") . ' ' . htmlspecialchars($dst);
451
		}
452
		if (in_array($proto, $protocols_with_ports)) {
453
			if (empty($dstport)) {
454
				return gettext("Missing destination port:") . ' ' . htmlspecialchars($dstport);
455
			}
456
			if (!is_port($dstport) && ($dstport != "any")) {
457
				return gettext("Tried to pass invalid destination port:") . ' ' . htmlspecialchars($dstport);
458
			}
459
		} else {
460
			$dstport = 0;
461
		}
462
		/* Should have valid input... */
463
		if (easyrule_pass_rule_add($int, $proto, $src, $dst, $dstport, $ipproto)) {
464
			return gettext("Successfully added pass rule!");
465
		} else {
466
			return gettext("Failed to add pass rule.");
467
		}
468
	} else {
469
		return gettext("Missing parameters for pass rule.");
470
	}
471
	return gettext("Unknown pass error.");
472
}
473

    
474
?>
(18-18/68)