Project

General

Profile

Download (9.63 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	easyrule.inc.php
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 VPN";
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']['mobileclients']['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') {
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
		if ($rule['source']['address'] == $blockaliasname . strtoupper($int) && ($rule['interface'] == $int))
86
			return true;
87
	return false;
88
}
89

    
90
function easyrule_block_rule_create($int = 'wan') {
91
	global $blockaliasname, $config;
92
	/* If the alias doesn't exist, exit.
93
	 * Can't create an empty alias, and we don't know a host */
94
	if (easyrule_block_alias_getid($int) === false)
95
		return false;
96

    
97
	/* If the rule already exists, no need to do it again */
98
	if (easyrule_block_rule_exists($int))
99
		return true;
100

    
101
	/* No rules, start a new array */
102
	if (!is_array($config['filter']['rule'])) {
103
		$config['filter']['rule'] = array();
104
	}
105

    
106
	filter_rules_sort();
107
	$a_filter = &$config['filter']['rule'];
108

    
109
	/* Make up a new rule */
110
	$filterent = array();
111
	$filterent['type'] = 'block';
112
	$filterent['interface'] = $int;
113
	$filterent['source']['address'] = $blockaliasname . strtoupper($int);
114
	$filterent['destination']['any'] = '';
115
	$filterent['descr'] = "Easy Rule: Blocked from Firewall Log View";
116

    
117
	$a_filter[] = $filterent;
118

    
119
	return true;
120
}
121

    
122
function easyrule_block_alias_getid($int = 'wan') {
123
	global $blockaliasname, $config;
124
	if (!is_array($config['aliases']))
125
		return false;
126

    
127
	/* Hunt down an alias with the name we want, return its id */
128
	foreach ($config['aliases']['alias'] as $aliasid => $alias)
129
		if ($alias['name'] == $blockaliasname . strtoupper($int))
130
			return $aliasid;
131

    
132
	return false;
133
}
134

    
135
function easyrule_block_alias_add($host, $int = 'wan') {
136
	global $blockaliasname, $config;
137
	/* If the host isn't a valid IP address, bail */
138
	if (!is_ipaddr($host))
139
		return false;
140

    
141
	/* If there are no aliases, start an array */
142
	if (!is_array($config['aliases']['alias']))
143
		$config['aliases']['alias'] = array();
144

    
145
	$a_aliases = &$config['aliases']['alias'];
146

    
147
	/* Try to get the ID if the alias already exists */
148
	$id = easyrule_block_alias_getid($int);
149
	if ($id === false)
150
	  unset($id);
151

    
152
	$alias = array();
153

    
154
	if (isset($id) && $a_aliases[$id]) {
155
		/* Make sure this IP isn't already in the list. */
156
		if (in_array($host.'/32', explode(" ", $a_aliases[$id]['address'])))
157
			return true;
158
		/* Since the alias already exists, just add to it. */
159
		$alias['name']    = $a_aliases[$id]['name'];
160
		$alias['type']    = $a_aliases[$id]['type'];
161
		$alias['descr']   = $a_aliases[$id]['descr'];
162

    
163
		$alias['address'] = $a_aliases[$id]['address'] . ' ' . $host . '/32';
164
	 	$alias['detail']  = $a_aliases[$id]['detail'] . 'Entry added ' . date('r') . '||';
165
	} else {
166
		/* Create a new alias with all the proper information */
167
	 	$alias['name']    = $blockaliasname . strtoupper($int);
168
	 	$alias['type']    = 'network';
169
	 	$alias['descr']   = mb_convert_encoding("Hosts blocked from Firewall Log view","HTML-ENTITIES","auto");
170

    
171
		$alias['address'] = $host . '/32';
172
	 	$alias['detail']  = 'Entry added ' . date('r') . '||';
173
	}
174

    
175
	/* Replace the old alias if needed, otherwise tack it on the end */
176
	if (isset($id) && $a_aliases[$id])
177
		$a_aliases[$id] = $alias;
178
	else
179
		$a_aliases[] = $alias;
180

    
181
	// Sort list
182
	$a_aliases = msort($a_aliases, "name");
183

    
184
	return true;
185
}
186

    
187
function easyrule_block_host_add($host, $int = 'wan') {
188
	global $retval;
189
	/* Bail if the supplied host is not a valid IP address */
190
	if (!is_ipaddr($host))
191
		return false;
192

    
193
	/* Flag whether or not we need to reload the filter */
194
	$dirty = false;
195

    
196
	/* Attempt to add this host to the alias */
197
	if (easyrule_block_alias_add($host, $int)) {
198
		$dirty = true;
199
	} else {
200
		/* Couldn't add the alias, or adding the host failed. */
201
		return false;
202
	}
203

    
204
	/* Attempt to add the firewall rule if it doesn't exist.
205
	 * Failing to add the rule isn't necessarily an error, it may
206
	 * have been modified by the user in some way. Adding to the
207
	 * Alias is what's important.
208
	 */
209
	if (!easyrule_block_rule_exists($int)) {
210
		if (easyrule_block_rule_create($int)) {
211
			$dirty = true;
212
		} else {
213
			return false;
214
		}
215
	}
216

    
217
	/* If needed, write the config and reload the filter */
218
	if ($dirty) {
219
		write_config();
220
		$retval = filter_configure();
221
		if (!empty($_SERVER['DOCUMENT_ROOT'])) {
222
			header("Location: firewall_aliases.php");
223
			exit;
224
		} else {
225
			return true;
226
		}
227
	} else {
228
		return false;
229
	}
230
}
231

    
232
function easyrule_pass_rule_add($int, $proto, $srchost, $dsthost, $dstport) {
233
	global $config;
234

    
235
	/* No rules, start a new array */
236
	if (!is_array($config['filter']['rule'])) {
237
		$config['filter']['rule'] = array();
238
	}
239

    
240
	filter_rules_sort();
241
	$a_filter = &$config['filter']['rule'];
242

    
243
	/* Make up a new rule */
244
	$filterent = array();
245
	$filterent['type'] = 'pass';
246
	$filterent['interface'] = $int;
247
	$filterent['descr'] = "Easy Rule: Passed from Firewall Log View";
248

    
249
	if ($proto != "any")
250
		$filterent['protocol'] = $proto;
251
	else
252
		unset($filterent['protocol']);
253

    
254
	/* Default to only allow echo requests, since that's what most people want and
255
	 *  it should be a safe choice. */
256
	if ($proto == "icmp")
257
		$filterent['icmptype'] = 'echoreq';
258

    
259
	pconfig_to_address($filterent['source'], $srchost, 32);
260
	pconfig_to_address($filterent['destination'], $dsthost, 32, '', $dstport, $dstport);
261

    
262
	$a_filter[] = $filterent;
263

    
264
	write_config($filterent['descr']);
265
	$retval = filter_configure();
266
	if (!empty($_SERVER['DOCUMENT_ROOT'])) {
267
		header("Location: firewall_rules.php?if={$int}");
268
		exit;
269
	} else {
270
		return true;
271
	}
272
}
273

    
274
function easyrule_parse_block($int, $src) {
275
	if (!empty($src) && !empty($int)) {
276
		if (!is_ipaddr($src)) {
277
			return "Tried to block invalid IP: " . htmlspecialchars($src);
278
		}
279
		$int = easyrule_find_rule_interface($int);
280
		if ($int === false) {
281
			return "Invalid interface for block rule: " . htmlspecialchars($int);
282
		}
283
		if (easyrule_block_host_add($src, $int)) {
284
			return "Host added successfully";
285
		} else {
286
			return "Failed to create block rule, alias, or add host.";
287
		}
288
	} else {
289
		return "Tried to block but had no host IP or interface";
290
	}
291
	return "Unknown block error.";
292
}
293
function easyrule_parse_pass($int, $proto, $src, $dst, $dstport = 0) {
294
	/* Check for valid int, srchost, dsthost, dstport, and proto */
295
	global $protocols_with_ports;
296

    
297
	if (!empty($int) && !empty($proto) && !empty($src) && !empty($dst)) {
298
		$int = easyrule_find_rule_interface($int);
299
		if ($int === false) {
300
			return "Invalid interface for pass rule: " . htmlspecialchars($int);
301
		}
302
		if (getprotobyname($proto) == -1) {
303
			return "Invalid protocol for pass rule: " . htmlspecialchars($proto);
304
		}
305
		if (!is_ipaddr($src)) {
306
			return "Tried to pass invalid source IP: " . htmlspecialchars($src);
307
		}
308
		if (!is_ipaddr($dst)) {
309
			return "Tried to pass invalid destination IP: " . htmlspecialchars($dst);
310
		}
311
		if (in_array($proto, $protocols_with_ports)) {
312
			if (empty($dstport)) {
313
				return "Missing destination port: " . htmlspecialchars($dstport);
314
			}
315
			if (!is_port($dstport)) {
316
				return "Tried to pass invalid destination port: " . htmlspecialchars($dstport);
317
			}
318
		} else {
319
			$dstport = 0;
320
		}
321
		/* Should have valid input... */
322
		if (easyrule_pass_rule_add($int, $proto, $src, $dst, $dstport)) {
323
			return "Successfully added pass rule!";
324
		} else {
325
			return "Failed to add pass rule.";
326
		}
327
	} else {
328
		return "Missing parameters for pass rule.";
329
	}
330
	return "Unknown pass error.";
331
}
332

    
333
?>
(15-15/54)