Projet

Général

Profil

Télécharger (121 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / filter.inc @ e792ac36

1
<?php
2
/* $Id$ */
3
/*
4
	filter.inc
5
	Copyright (C) 2004-2006 Scott Ullrich
6
	Copyright (C) 2005		Bill Marquette
7
	Copyright (C) 2006		Peter Allgeyer
8
	Copyright (C) 2008-2010		Ermal Luci
9
	All rights reserved.
10

    
11
	originally part of m0n0wall (http://m0n0.ch/wall)
12
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
13
	All rights reserved.
14

    
15
	Redistribution and use in source and binary forms, with or without
16
	modification, are permitted provided that the following conditions are met:
17

    
18
	1. Redistributions of source code must retain the above copyright notice,
19
	   this list of conditions and the following disclaimer.
20

    
21
	2. Redistributions in binary form must reproduce the above copyright
22
	   notice, this list of conditions and the following disclaimer in the
23
	   documentation and/or other materials provided with the distribution.
24

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

    
36
	pfSense_BUILDER_BINARIES:	/sbin/sysctl	/sbin/kldload	/usr/sbin/tcpdump	/sbin/pfctl	/bin/rm
37
	pfSense_BUILDER_BINARIES:	/usr/sbin/inetd
38
	pfSense_MODULE:	filter
39
*/
40

    
41
/* DISABLE_PHP_LINT_CHECKING */
42

    
43
/* holds the items that will be executed *AFTER* the filter is fully loaded */
44
$after_filter_configure_run = array();
45

    
46
/* For installing cron job of schedules */
47
$time_based_rules = false;
48

    
49
/* Used to hold the interface list that will be used on ruleset creation. */
50
$FilterIflist = array();
51

    
52
/* Create a global array to avoid errors on rulesets. */
53
$GatewaysList = array();
54

    
55
/* Used for the hostname dns resolver */
56
$filterdns = array(); 
57

    
58
/* Used for aliases and interface macros */
59
$aliases = "";
60

    
61
function fix_rule_label($descr) {
62
	$descr = str_replace('"', '', $descr);
63
	if (strlen($descr) > 63)
64
		return substr($descr, 0, 60) . "...";
65
	else
66
		return $descr;
67
}
68

    
69
function is_bogonsv6_used() {
70
	global $config, $g;
71
	# Only use bogonsv6 table if IPv6 Allow is on, and at least 1 enabled interface also has "blockbogons" enabled.
72
	$usebogonsv6 = false;
73
	if (isset($config['system']['ipv6allow'])) {
74
		foreach ($config['interfaces'] as $ifacedata) {
75
			if(isset($ifacedata['enable']) && isset($ifacedata['blockbogons'])) {
76
				$usebogonsv6 = true;
77
				break;
78
			}
79
		}
80
	}
81
	return $usebogonsv6;
82
}
83

    
84
function flowtable_configure() {
85
	global $config, $g;
86

    
87
	if (empty($config['system']['flowtable'])) {
88
		mwexec("/sbin/sysctl net.inet.flowtable.enable=0", true);
89
		return;
90
	}
91

    
92
	// Figure out how many flows we should reserve
93
	// sized 2x larger than the number of unique connection destinations.
94
	if($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates']))
95
		$maxstates = $config['system']['maximumstates'];
96
	else
97
		$maxstates = 150000;
98
	// nmbflows cpu count * ($maxstates * 2)
99
	$cpus = trim(`/sbin/sysctl -n kern.smp.cpus`, " \n");
100
	$nmbflows = ($cpus*($maxstates*2));
101
	// Flowtable currently only works on 8.0
102
	if(get_freebsd_version() == "8") {
103
		mwexec("/sbin/sysctl net.inet.flowtable.nmbflows={$nmbflows}");
104
		mwexec("/sbin/sysctl net.inet.ip.output_flowtable_size={$maxstates}");
105
		mwexec("/sbin/sysctl net.inet.flowtable.enable=1");
106
	}
107
}
108

    
109
function filter_pflog_start($kill_first = false) {
110
	global $config, $g;
111
	if ($g['platform'] == 'jail')
112
		return;
113
	if(isset($config['system']['developerspew'])) {
114
		$mt = microtime();
115
		echo "filter_pflog_start() being called $mt\n";
116
	}
117
	mute_kernel_msgs();
118
	$output = 0;
119
	$tcpdump_cmd = "tcpdump -s 256 -v -S -l -n -e -ttt -i pflog0";
120
	exec("/bin/pgrep -af '{$tcpdump_cmd}'", $output, $retval);
121
	if ($kill_first && ($output[0] > 1)) {
122
		mwexec("/bin/kill {$output[0]}");
123
		usleep(1000);
124
		/* Ensure the restart below runs */
125
		$retval = 1;
126
	}
127
	if($retval != 0)
128
		mwexec_bg("/usr/sbin/{$tcpdump_cmd} | logger -t pf -p local0.info");
129
	unmute_kernel_msgs();
130
}
131

    
132
/* reload filter async */
133
function filter_configure() {
134
	global $g;
135

    
136
	if(isset($config['system']['developerspew'])) {
137
		$mt = microtime();
138
		echo "filter_configure() being called $mt\n";
139
	}
140

    
141
	/*
142
	 * NOTE: Check here for bootup status since this should not be triggered during bootup.
143
	 *	 The reason is that rc.bootup calls filter_configure_sync directly which does this too.
144
	 */
145
	if (!$g['booting'])
146
		send_event("filter reload");
147
}
148

    
149
function filter_delete_states_for_down_gateways() {
150
	global $config, $GatewaysList;
151

    
152
	if (isset($config['system']['kill_states']))
153
		return;
154

    
155
	$any_gateway_down = false;
156
	$a_gateways = return_gateways_status();
157
	if (is_array($GatewaysList)) {
158
		foreach ($GatewaysList as $gwname => $gateway) {
159
			if (empty($gateway['monitor']))
160
				continue;
161
			if (!is_ipaddr($gateway['monitor']))
162
				continue;
163
			if (strstr($gateway['monitor'], "127.0.0."))
164
				continue;
165
			if (empty($a_gateways[$gateway['monitor']]))
166
				continue;
167
			$gwstatus =& $a_gateways[$gateway['monitor']];
168
			if (strstr($gwstatus['status'], "down")) {
169
				$any_gateway_down = true;
170
				break;
171
			}
172
		}
173
	}
174
	if ($any_gateway_down == true)
175
		mwexec("/sbin/pfctl -Fs");
176
}
177

    
178
/* reload filter sync */
179
function filter_configure_sync($delete_states_if_needed = true) {
180
	global $config, $g, $after_filter_configure_run, $FilterIflist;
181
	global $time_based_rules, $filterdns, $aliases, $dummynet_name_list;
182

    
183
	/* Use filter lock to not allow concurrent filter reloads during this run. */
184
	$filterlck = lock('filter', LOCK_EX);
185

    
186

    
187
	filter_pflog_start();
188
	update_filter_reload_status(gettext("Initializing"));
189

    
190
	/* invalidate interface cache */
191
	get_interface_arr(true);
192

    
193
	if(isset($config['system']['developerspew'])) {
194
		$mt = microtime();
195
		echo "filter_configure_sync() being called $mt\n";
196
	}
197
	/* Get interface list to work with. */
198
	filter_generate_optcfg_array();
199
	if($g['booting'] == true)
200
		echo gettext("Configuring firewall");
201

    
202
	/* generate aliases */
203
	if($g['booting'] == true)
204
		echo ".";
205
	update_filter_reload_status(gettext("Creating aliases"));
206
	$aliases = filter_generate_aliases();
207
	$gateways = filter_generate_gateways();
208
	if($g['booting'] == true)
209
		echo ".";
210
	update_filter_reload_status(gettext("Generating Limiter rules"));
211
	$dummynet_rules = filter_generate_dummynet_rules();
212
	$dummynet_name_list = get_unique_dnqueue_list();
213
	update_filter_reload_status(gettext("Generating NAT rules"));
214
	/* generate nat rules */
215
	$natrules = filter_nat_rules_generate();
216
	if($g['booting'] == true)
217
		echo ".";
218
	update_filter_reload_status(gettext("Generating filter rules"));
219
	/* generate pfctl rules */
220
	$pfrules = filter_rules_generate();
221
	/* generate altq, limiter */
222
	if($g['booting'] == true)
223
		echo ".";
224
	update_filter_reload_status(gettext("Generating ALTQ queues"));
225
	$altq_queues = filter_generate_altq_queues();
226
	update_filter_reload_status(gettext("Generating Layer7 rules"));
227
	generate_layer7_files();
228
	if($g['booting'] == true)
229
		echo ".";
230
	update_filter_reload_status(gettext("Loading filter rules"));
231
	/* enable pf if we need to, otherwise disable */
232
	if(!isset ($config['system']['disablefilter'])) {
233
		mwexec("/sbin/pfctl -e", true);
234
	} else {
235
		mwexec("/sbin/pfctl -d", true);
236
		unlink_if_exists("{$g['tmp_path']}/filter_loading");
237
		update_filter_reload_status(gettext("Filter is disabled.  Not loading rules."));
238
		if($g['booting'] == true)
239
			echo gettext("done.") . "\n";
240
		unlock($filterlck);
241
		return;
242
	}
243

    
244
	$limitrules = "";
245
	/* Define the maximum number of tables the system can handle (should be at least aliases*2+some spare) */
246
	$maxtables = is_numeric($config['system']['maximumtables']) ? $config['system']['maximumtables'] : "3000";
247
	$limitrules .= "set limit tables {$maxtables}\n";
248
	/* User defined maximum table entries in Advanced menu. */
249
	if ($config['system']['maximumtableentries'] <> "" && is_numeric($config['system']['maximumtableentries']))
250
		$limitrules .= "set limit table-entries {$config['system']['maximumtableentries']}\n";
251

    
252
	if ($config['system']['optimization'] <> "") {
253
		$limitrules .= "set optimization {$config['system']['optimization']}\n";
254
		if($config['system']['optimization'] == "conservative") {
255
			$limitrules .= "set timeout { udp.first 300, udp.single 150, udp.multiple 900 }\n";
256
		}
257
	} else
258
		$limitrules .= "set optimization normal\n";
259

    
260
	if (!empty($config['system']['adaptivestart']) && !empty($config['system']['adaptiveend']))
261
		$limitrules .= "set timeout { adaptive.start {$config['system']['adaptivestart']}, adaptive.end {$config['system']['adaptiveend']} }\n";
262
	else
263
		$limitrules .= "set timeout { adaptive.start 0, adaptive.end 0 }\n";
264

    
265
	if ($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates'])) {
266
		/* User defined maximum states in Advanced menu. */
267
		$limitrules .= "set limit states {$config['system']['maximumstates']}\n";
268
		$limitrules .= "set limit src-nodes {$config['system']['maximumstates']}\n";
269
	} else {
270
		$max_states = pfsense_default_state_size();
271
		$limitrules .= "set limit states {$max_states}\n";
272
		$limitrules .= "set limit src-nodes {$max_states}\n";
273
	}
274

    
275
	if (isset($config['system']['lb_use_sticky']) && is_numeric($config['system']['srctrack']) && ($config['system']['srctrack'] > 0))
276
		$limitrules .= "set timeout src.track {$config['system']['srctrack']}\n";
277

    
278
	// Configure flowtable support if enabled.
279
	flowtable_configure();
280

    
281
	$rules = "";
282
	$rules = "{$limitrules}\n";
283
	$rules .= "{$aliases} \n";
284
	$rules .= "{$gateways} \n";
285
	update_filter_reload_status(gettext("Setting up logging information"));
286
	$rules .= filter_setup_logging_interfaces();
287
	$rules .= "\n";
288
	$rules .= "set skip on pfsync0\n";
289
	$rules .= "\n";
290
	update_filter_reload_status(gettext("Setting up SCRUB information"));
291
	$rules .= filter_generate_scrubing();
292
	$rules .= "\n";
293
	$rules .= "{$altq_queues}\n";
294
	$rules .= "{$natrules}\n";
295
	$rules .= "{$pfrules}\n";
296
	$rules .= discover_pkg_rules("filter");
297

    
298
	unset($aliases, $gateways, $altq_queues, $natrules, $pfrules);
299

    
300
	// Copy rules.debug to rules.debug.old
301
	if(file_exists("{$g['tmp_path']}/rules.debug"))
302
		@copy("{$g['tmp_path']}/rules.debug", "{$g['tmp_path']}/rules.debug.old");
303

    
304
	if (!@file_put_contents("{$g['tmp_path']}/rules.debug", $rules, LOCK_EX)) {
305
		log_error("WARNING: Could not write new rules!");
306
		unlock($filterlck);
307
		return;
308
	}
309

    
310
	@file_put_contents("{$g['tmp_path']}/rules.limits", $limitrules);
311
	mwexec("/sbin/pfctl -Of {$g['tmp_path']}/rules.limits");
312
	unset($rules, $limitrules);
313

    
314
	if(isset($config['system']['developerspew'])) {
315
		$mt = microtime();
316
		echo "pfctl being called at $mt\n";
317
	}
318
	unset($rules_loading, $rules_error);
319
	$_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug 2>&1", $rules_error, $rules_loading);
320
	if(isset($config['system']['developerspew'])) {
321
		$mt = microtime();
322
		echo "pfctl done at $mt\n";
323
	}
324
	/*
325
	 * check for a error while loading the rules file.	if an error has occurred
326
	 * then output the contents of the error to the caller
327
	 */
328
	if($rules_loading <> 0) {
329
		$saved_line_error = $rules_error[0];
330
		$line_error = explode(":", $rules_error[0]);
331
		$line_number = $line_error[1];
332
		$line_split = file("{$g['tmp_path']}/rules.debug");
333
		if(is_array($line_split))
334
			$line_error = sprintf(gettext('The line in question reads [%1$d]: %2$s'), $line_number, $line_split[$line_number-1]);
335
		unset($line_split);
336

    
337
		/* Brutal ugly hack but required -- PF is stuck, unwedge */
338
		if (strstr("$rules_error[0]", "busy")) {
339
			exec("/sbin/pfctl -d; /sbin/pfctl -e; /sbin/pfctl -f {$g['tmp_path']}/rules.debug");
340
			$error_msg = gettext("PF was wedged/busy and has been reset.");
341
			file_notice("pf_busy", $error_msg, "pf_busy", "");
342
		} else {
343
			$_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug.old 2>&1");
344
		}
345
		unset($rules_loading, $rules_error);
346

    
347
		if ($line_error and $line_number) {
348
			file_notice("filter_load", sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error), "Filter Reload", "");
349
			update_filter_reload_status(sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error));
350
			unlock($filterlck);
351
			return;
352
		}
353
	}
354

    
355
	# If we are not using bogonsv6 then we can remove any bogonsv6 table from the running pf (if the table is not there, the kill is still fine).
356
	if (!is_bogonsv6_used())
357
		$_grbg = exec("/sbin/pfctl -t bogonsv6 -T kill 2>/dev/null");
358

    
359
	update_filter_reload_status(gettext("Starting up layer7 daemon"));
360
	layer7_start_l7daemon();
361

    
362
	if(!empty($filterdns)) {
363
		@file_put_contents("{$g['varetc_path']}/filterdns.conf", implode("", $filterdns));
364
		unset($filterdns);
365
		if (isvalidpid("{$g['varrun_path']}/filterdns.pid"))
366
			sigkillbypid("{$g['varrun_path']}/filterdns.pid", "HUP");
367
		else {
368
			/*
369
			 * FilterDNS has three debugging levels. The default choosen is 1.
370
			 * Availabe are level 2 and greater then 2.
371
			 */
372
			if (isset($config['system']['aliasesresolveinterval']) && is_numeric($config['system']['aliasesresolveinterval']))
373
				$resolve_interval = $config['system']['aliasesresolveinterval'];
374
			else
375
				$resolve_interval = 300;
376
			mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns.pid -i {$resolve_interval} -c {$g['varetc_path']}/filterdns.conf -d 1");
377
		}
378
	} else {
379
		killbypid("{$g['varrun_path']}/filterdns.pid");
380
		@unlink("{$g['varrun_path']}/filterdns.pid");
381
	}
382

    
383
	/* run items scheduled for after filter configure run */
384
	$fda = fopen("{$g['tmp_path']}/commands.txt", "w");
385
	if($fda) {
386
		if($after_filter_configure_run) {
387
			foreach($after_filter_configure_run as $afcr)
388
				fwrite($fda, $afcr . "\n");
389
			unset($after_filter_configure_run);
390
		}
391

    
392
		/*
393
		 *      we need a way to let a user run a shell cmd after each
394
		 *      filter_configure() call.  run this xml command after
395
		 *      each change.
396
		 */
397
		if($config['system']['afterfilterchangeshellcmd'] <> "")
398
			fwrite($fda, $config['system']['afterfilterchangeshellcmd'] . "\n");
399

    
400
		fclose($fda);
401
	}
402

    
403
	if(file_exists("{$g['tmp_path']}/commands.txt")) {
404
		mwexec("sh {$g['tmp_path']}/commands.txt &");
405
		unlink("{$g['tmp_path']}/commands.txt");
406
	}
407

    
408
	/* if time based rules are enabled then swap in the set */
409
	if($time_based_rules == true)
410
		filter_tdr_install_cron(true);
411
	else
412
		filter_tdr_install_cron(false);
413

    
414
	if($g['booting'] == true)
415
		echo ".";
416

    
417
	if($delete_states_if_needed) {
418
		update_filter_reload_status(gettext("Processing down interface states"));
419
		filter_delete_states_for_down_gateways();
420
	}
421

    
422
	update_filter_reload_status(gettext("Running plugins"));
423

    
424
	if(is_dir("/usr/local/pkg/pf/")) {
425
		/* process packager manager custom rules */
426
		update_filter_reload_status(gettext("Running plugins (pf)"));
427
		run_plugins("/usr/local/pkg/pf/");
428
		update_filter_reload_status(gettext("Plugins completed."));
429
	}
430

    
431
	update_filter_reload_status(gettext("Done"));
432
	if($g['booting'] == true)
433
		echo gettext("done.") . "\n";
434

    
435
	unlock($filterlck);
436
	return 0;
437
}
438

    
439
function filter_generate_scrubing() {
440
	global $config, $FilterIflist;
441
	$scrubrules = "";
442

    
443
	if (isset($config['system']['maxmss_enable'])) {
444
		$maxmss = 1400;
445
		if (!empty($config['system']['maxmss']))
446
			$maxmss = $config['system']['maxmss'];
447

    
448
		$scrubrules .= "scrub from any to <vpn_networks> max-mss {$maxmss}\n";
449
	}
450
	/* disable scrub option */
451
	foreach ($FilterIflist as $scrubif => $scrubcfg) {
452
		if(isset($scrubcfg['virtual']) || empty($scrubcfg['descr']))
453
			continue;
454
		/* set up MSS clamping */
455
		if($scrubcfg['mss'] <> "" && is_numeric($scrubcfg['mss']) && $scrubcfg['if'] != "pppoe" && $scrubcfg['if'] != "pptp" &&
456
			$scrubif['if'] != "l2tp")
457
			$mssclamp = "max-mss " . (intval($scrubcfg['mss'] - 40));
458
		else
459
			$mssclamp = "";
460
		/* configure no-df for linux nfs and others */
461
		if($config['system']['scrubnodf'])
462
			$scrubnodf = "no-df";
463
		else
464
			$scrubnodf = "";
465
		if($config['system']['scrubrnid'])
466
			$scrubrnid = "random-id";
467
		else
468
			$scrubrnid = "";
469
		if(!isset($config['system']['disablescrub']))
470
			$scrubrules .= "scrub on \${$scrubcfg['descr']} all {$scrubnodf} {$scrubrnid} {$mssclamp} fragment reassemble\n"; // reassemble all directions
471
		else if(!empty($mssclamp))
472
			$scrubrules .= "scrub on \${$scrubcfg['descr']} {$mssclamp}\n";
473
	}
474
	return $scrubrules;
475
}
476

    
477
function filter_generate_nested_alias($name, $alias, &$aliasnesting, &$aliasaddrnesting, $all = false) {
478
	global $aliastable, $filterdns;
479

    
480
	$addresses = explode(" ", $alias);
481
	$finallist = "";
482
	$builtlist = "";
483
	$urltable_nesting = "";
484
	$aliasnesting[$name] = $name;
485
	foreach ($addresses as $address) {
486
		if (empty($address))
487
			continue;
488
		$linelength = strlen($builtlist);
489
		$tmpline = "";
490
		if(is_alias($address)) {
491
			if (alias_get_type($address) == 'urltable') {
492
				// Feature#1603. For this type of alias we do not need to recursively call filter_generate_nested_alias. Just load IPs from the file.
493
				$urltable_netsting = alias_expand_urltable($address);
494
				if (!empty($urltable_nesting)) {
495
					$urlfile_as_arr = file($urltable_nesting);
496
					foreach($urlfile_as_arr as $line) {
497
						$address= rtrim($line);
498
						if ((strlen($tmpline) + $linelength) > 4036) {
499
							$finallist .= "{$tmpline} \\\n";
500
							$tmpline = "";
501
						}
502
						$tmpline .= " {$address}";
503
					}
504
				}
505
			}
506
			/* We already expanded this alias so there is no neccessity to do it again. */
507
			else if(!isset($aliasnesting[$address]))
508
				$tmpline = filter_generate_nested_alias($name, $aliastable[$address], $aliasnesting, $aliasaddrnesting, $all);
509
		} else if(!isset($aliasaddrnesting[$address])) {
510
			if ($all === false && !is_ipaddr($address) && !is_subnet($address) && !is_port($address) && is_hostname($address)) {
511
				if (!isset($filterdns["{$address}{$name}"]))
512
					$filterdns["{$address}{$name}"] = "pf {$address} {$name}\n";
513
				continue;
514
			}
515
			$aliasaddrnesting[$address] = $address;
516
			$tmpline = " {$address}";
517
		}
518
		if ((strlen($tmpline)+ $linelength) > 4036) {
519
			$finallist .= "{$builtlist} \\\n";
520
			$builtlist = "";
521
		}
522
		if (!empty($tmpline))
523
			$builtlist .= " {$tmpline}";
524
	}
525
	$finallist .= $builtlist;
526
	return $finallist;
527
}
528

    
529
function filter_expand_alias($alias_name, $all = false)
530
{
531
	global $config;
532

    
533
	if(isset($config['aliases']['alias'])) {
534
		foreach ($config['aliases']['alias'] as $aliased) {
535
			if($aliased['name'] == $alias_name) {
536
				$aliasnesting = array();
537
				$aliasaddrnesting = array();
538
				return filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting, $all);
539
			}
540
		}
541
	}
542
}
543

    
544
function filter_expand_alias_array($alias_name, $all = false) {
545
	$expansion = filter_expand_alias($alias_name, $all);
546
	return explode(" ", preg_replace('/\s+/', ' ', trim($expansion)));
547
}
548

    
549
function filter_generate_aliases() {
550
	global $config, $FilterIflist, $after_filter_configure_run;
551

    
552
	if(isset($config['system']['developerspew'])) {
553
		$mt = microtime();
554
		echo "filter_generate_aliases() being called $mt\n";
555
	}
556

    
557
	$alias = "#System aliases\n ";
558
	$aliases = "loopback = \"{ lo0 }\"\n";
559

    
560
	foreach ($FilterIflist as $if => $ifcfg) {
561
		if (is_array($ifcfg[0])) {
562
			if ($ifcfg[0]['if'] == 'pppoe') {
563
				$aliases .= "{$ifcfg[0]['descr']} = \"{ {$ifcfg[0]['if']}";
564
				$aliases .= " }\"\n";
565
			}
566
		} elseif (!empty($ifcfg['descr']) && !empty($ifcfg['if'])) {
567
			if ($ifcfg['type6'] == '6rd')
568
				$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
569
			else if ($ifcfg['type6'] == '6to4')
570
				$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
571
			else {
572
				$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']}";
573

    
574
				if ($ifcfg['type'] == 'pptp') {
575
					foreach (get_parent_interface($ifcfg['if']) as $parent_if) {
576
						if ($parent_if != $ifcfg['if']) {
577
							$aliases .= " {$parent_if}";
578
						}
579
					}
580
				}
581
			}
582
			$aliases .= " }\"\n";
583
		}
584
	}
585

    
586
	$aliases .= "\n#SSH Lockout Table\n";
587
	$aliases .= "table <sshlockout> persist\n";
588
	$aliases .= "table <webConfiguratorlockout> persist\n";
589

    
590
	$aliases .= "#Snort tables\n";
591
	$aliases .= "table <snort2c>\n";
592
	$aliases .= "table <virusprot>\n";
593
	if (!file_exists("/etc/bogons"))
594
		@file_put_contents("/etc/bogons", "");
595
	if (!file_exists("/etc/bogonsv6"))
596
		@file_put_contents("/etc/bogonsv6", "");
597
	$aliases .= "table <bogons> persist file \"/etc/bogons\"\n";
598
	if (is_bogonsv6_used())
599
		$aliases .= "table <bogonsv6> persist file \"/etc/bogonsv6\"\n";
600

    
601
	$vpns_list = filter_get_vpns_list();
602
	if($vpns_list)
603
		$aliases .= "table <vpn_networks> { $vpns_list }\n";
604

    
605
	/* add a Negate_networks table */
606
	$aliases .= "table <negate_networks> ";
607
	if($vpns_list)
608
		$aliases .= "{ $vpns_list }";
609
	$aliases .= "\n";
610

    
611
	$aliases .= "\n# User Aliases \n";
612
	/* Setup pf groups */
613
	if(isset($config['aliases']['alias'])) {
614
		foreach ($config['aliases']['alias'] as $aliased) {
615
			$extralias = "";
616
			/*
617
			 * XXX: i am not sure what this does so i am commenting it out for now, because as it is
618
			 * its quite dangerous!
619
			 * $ip = find_interface_ip($aliased['address']);
620
			 * $extraalias = " " . link_ip_to_carp_interface($ip);
621
			 */
622
			$aliasnesting = array();
623
			$aliasaddrnesting = array();
624
			$addrlist = filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
625
			switch ($aliased['type']) {
626
			case "host":
627
			case "network":
628
			case "url":
629
				$tableaddrs = "{$addrlist}{$extralias}";
630
				if(empty($tableaddrs)) {
631
					$aliases .= "table <{$aliased['name']}> persist\n";
632
					if (empty($aliased['address']))
633
						$after_filter_configure_run[] = "/sbin/pfctl -T flush -t " . escapeshellarg($aliased['name']);
634
				} else
635
					$aliases .= "table <{$aliased['name']}> { {$addrlist}{$extralias} } \n";
636

    
637
				$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
638
				break;
639
			case "openvpn":
640
				$openvpncfg = array();
641
				if($config['openvpn']['user']) {
642
					/* XXX: Check if we have a correct ip? */
643
					foreach ($config['openvpn']['user'] as $openvpn)
644
						$openvpncfg[$openvpn['name']] = $openvpn['ip'];
645
				}
646
				$vpn_lines = explode("\n", $addrlist);
647
				foreach ($vpn_lines as $vpn_line) {
648
					$vpn_address_split = explode(" ", $vpn_line);
649
					foreach($vpn_address_split as $vpnsplit) {
650
						if(isset($openvpncfg[$vpnsplit])) {
651
							$newaddress .= " ";
652
							$newaddress .= $openvpn[$vpnsplit];
653
							break;
654
						}
655
					}
656
				}
657
				$aliases .= "table <{$aliased['name']}> { {$newaddress}{$extralias} } \n";
658
				$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
659
				break;
660
			case "urltable":
661
				$urlfn = alias_expand_urltable($aliased['name']);
662
				if ($urlfn) {
663
					$aliases .= "table <{$aliased['name']}> persist file \"{$urlfn}\"\n";
664
					$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
665
				}
666
				break;
667
			case "port":
668
				$aliases .= "{$aliased['name']} = \"{ {$addrlist} }\"\n";
669
				break;
670
			default:
671
				$aliases .= "{$aliased['name']} = \"{ {$aliased['address']}{$extralias} }\"\n";
672
				break;
673
			}
674
		}
675
	}
676
	$result = "{$alias} \n";
677
	$result .= "{$aliases}";
678

    
679
	return $result;
680
}
681

    
682
function filter_generate_gateways() {
683
	global $config, $g, $GatewaysList;
684

    
685
	$rules = "# Gateways\n";
686

    
687
	update_filter_reload_status(gettext("Creating gateway group item..."));
688

    
689
	/* Lookup Gateways to be used in filter rules once */
690
	$GatewaysList = return_gateways_array();
691
	$GatewayGroupsList = return_gateway_groups_array();
692

    
693
	if (is_array($GatewaysList)) {
694
		foreach ($GatewaysList as $gwname => $gateway) {
695
			$int = $gateway['interface'];
696
			$gwip = $gateway['gateway'];
697
			$route = "";
698
			if (!is_ipaddr($gwip))
699
				$gwip = get_interface_gateway($gateway['friendlyiface']);
700
			if (is_ipaddr($gwip) && !empty($int))
701
				$route = "route-to ( {$int} {$gwip} )";
702
			if (($route === "") && isset($config['system']['skip_rules_gw_down']))
703
				unset($GatewaysList[$gwname]);
704
			else
705
				$rules .= "GW{$gwname} = \" {$route} \"\n";
706
		}
707
	}
708

    
709
	if (is_array($GatewayGroupsList)) {
710
		foreach ($GatewayGroupsList as $gateway => $members) {
711
			$route = "";
712
			/* hey, that's not a group member! */
713
			unset($members['ipprotocol']);
714
			if (count($members) > 0) {
715
				$foundlb = 0;
716
				$routeto = "";
717
				foreach($members as $idx => $member) {
718
					$int = $member['int'];
719
					$gatewayip = $member['gwip'];
720
					if (($int <> "") && is_ipaddr($gatewayip)) {
721
						if ($g['debug'])
722
							log_error(sprintf(gettext('Setting up route with %1$s on %2$s'), $gatewayip, $int));
723
						if ($member['weight'] > 1) {
724
							$routeto .= str_repeat("( {$int} {$gatewayip} ) ", $member['weight']);
725
						} else
726
							$routeto .= "( {$int} {$gatewayip} ) ";
727
						$foundlb++;
728
					} else
729
						log_error(sprintf(gettext("An error occurred while trying to find the interface got %s .  The rule has not been added."), $gatewayip));
730
				}
731
				$route = "";
732
				if ($foundlb > 0) {
733
					$route = " route-to { {$routeto} } ";
734
					if($foundlb > 1) {
735
						$route .= " round-robin ";
736
						if (isset($config['system']['lb_use_sticky']))
737
							$route .= " sticky-address ";
738
					}
739
				}
740
			}
741
			if (($route === "") && isset($config['system']['skip_rules_gw_down']))
742
				unset($GatewayGroupsList[$gateway]);
743
			else
744
				$rules .= "GW{$gateway} = \" {$route} \"\n";
745
		}
746
	}
747

    
748
	/* Create a global array to avoid errors on rulesets. */
749
	$GatewaysList = $GatewaysList + $GatewayGroupsList;
750

    
751
	$rules .= "\n";
752

    
753
	return $rules;
754
}
755

    
756
/* returns space separated list of vpn subnets */
757
function filter_get_vpns_list() {
758
	global $config;
759

    
760
	$vpns = "";
761
	$vpns_arr = array();
762

    
763
	/* ipsec */
764
	if (isset($config['ipsec']['enable'])) {
765
		if (is_array($config['ipsec']['phase2'])) {
766
			foreach ($config['ipsec']['phase2'] as $ph2ent) {
767
				if ((!$ph2ent['mobile']) && ($ph2ent['mode'] != 'transport')) {
768
					if (!function_exists('ipsec_idinfo_to_cidr'))
769
						require_once("ipsec.inc");
770
					if (!is_array($ph2ent['remoteid']))
771
						continue;
772
					$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
773
					$vpns_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
774
					if ($vpns_subnet == "0.0.0.0/0")
775
						continue;
776
					$vpns_arr[] = $vpns_subnet;
777
				}
778
			}
779
		}
780
	}
781

    
782
	/* openvpn */
783
	foreach (array('client', 'server') as $type) {
784
		if(is_array($config['openvpn']["openvpn-$type"])) {
785
			foreach ($config['openvpn']["openvpn-$type"] as $settings) {
786
				if(is_array($settings)) {
787
					if (!isset($settings['disable'])) {
788
						$remote_networks = explode(',', $settings['remote_network']);
789
						foreach ($remote_networks as $remote_network) {
790
							if (is_subnet($remote_network) && ($remote_network <> "0.0.0.0/0"))
791
								$vpns_arr[] = $remote_network;
792
						}
793
						if (is_subnet($settings['tunnel_network']) && $settings['tunnel_network'] <> "0.0.0.0/0")
794
							$vpns_arr[] = $settings['tunnel_network'];
795
					}
796
				}
797
			}
798
		}
799
	}
800
	/* pppoe */
801
	if (is_array($config['pppoes']['pppoe'])) {
802
		foreach($config['pppoes']['pppoe'] as $pppoe) {
803
			if ($pppoe['mode'] == "server") {
804
				if(is_ipaddr($pppoe['remoteip'])) {
805
					$pppoesub = gen_subnet($pppoe['remoteip'], $pppoe['pppoe_subnet']);
806
					if (is_subnet($pppoesub))
807
						$vpns_arr[] = $pppoesub;
808
				}
809
			}
810
		}
811
	}
812

    
813
	if (!empty($vpns_arr))
814
		$vpns = implode(" ", $vpns_arr);
815

    
816
	return $vpns;
817
}
818

    
819
/* returns space separated list of directly connected networks
820
 * optionally returns an array instead, including friendly interface and gateway (if applicable)
821
 */
822
function filter_get_direct_networks_list($returnsubnetsonly = true) {
823
	global $config, $FilterIflist, $GatewaysList;
824
	/* build list of directly connected interfaces and networks */
825
	$networks = "";
826
	$networks_arr = array();
827
	if(empty($FilterIflist)) {
828
		filter_generate_optcfg_array();
829
	}
830
	foreach ($FilterIflist as $ifent => $ifcfg) {
831
		$subnet = "{$ifcfg['sa']}/{$ifcfg['sn']}";
832
		if(is_subnet($subnet)) {
833
			if($returnsubnetsonly) {
834
				$networks_arr[] = $subnet;
835
			} else {
836
				$networks_arr[] = array(
837
					'subnet' => $subnet,
838
					'if' => $ifent,
839
					'ip' => $ifcfg['ip']);
840
			}
841
		}
842
	}
843
	foreach(get_configured_ip_aliases_list(true) as $vip) {
844
		$subnet = "{$vip['subnet']}/{$vip['subnet_bits']}";
845
		if(is_subnet($subnet) && !(is_subnetv4($subnet) && $vip['subnet_bits'] == 32) && !(is_subnetv6($subnet) && $vip['subnet_bits'] == 128)) {
846
			if(is_subnetv4($subnet))
847
				$subnet = gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
848
			else if(is_subnetv6($subnet))
849
				$subnet = gen_subnetv6($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
850
			if($returnsubnetsonly) {
851
				$networks_arr[] = $subnet;
852
			} else {
853
				$networks_arr[] = array(
854
					'subnet' => $subnet,
855
					'if' => $vip['interface'],
856
					'ip' => $vip['subnet']);
857
			}
858
		}
859
	}
860
	foreach(get_staticroutes() as $netent) {
861
		if(is_subnet($netent['network'])) {
862
			if($returnsubnetsonly) {
863
				$networks_arr[] = $netent['network'];
864
			} else if(isset($GatewaysList[$netent['gateway']])) {
865
				$networks_arr[] = array(
866
					'subnet' => $netent['network'],
867
					'if' => $GatewaysList[$netent['gateway']]['friendlyiface'],
868
					'gateway' => $GatewaysList[$netent['gateway']]['gateway']);
869
			}
870
		}
871
	}
872
	if($returnsubnetsonly) {
873
		if(!empty($networks_arr)) {
874
			$networks = implode(" ", $networks_arr);
875
		}
876
		return $networks;
877
	} else {
878
		return $networks_arr;
879
	}
880
}
881

    
882
function filter_generate_optcfg_array() {
883
	global $config, $FilterIflist;
884
	if(isset($config['system']['developerspew'])) {
885
		$mt = microtime();
886
		echo "filter_generate_optcfg_array() being called $mt\n";
887
	}
888

    
889
	read_layer7_config();
890
	/* if list */
891
	$iflist = get_configured_interface_with_descr();
892
	foreach ($iflist as $if => $ifdetail) {
893
		$oc = $config['interfaces'][$if];
894
		$oic = array();
895
		$oic['if'] = get_real_interface($if);
896
		if (!does_interface_exist($oic['if']))
897
			continue;
898
		$oic['ifv6'] = get_real_interface($if, "inet6");
899
		$oic['ip'] = get_interface_ip($if);
900
		$oic['ipv6'] = get_interface_ipv6($if);
901
		if(!is_ipaddrv4($oc['ipaddr']) && !empty($oc['ipaddr']))
902
			$oic['type'] = $oc['ipaddr'];
903
		if(!is_ipaddrv6($oc['ipaddrv6']) && !empty($oc['ipaddrv6']))
904
			$oic['type6'] = $oc['ipaddrv6'];
905
		if (!empty($oc['track6-interface']))
906
			$oic['track6-interface'] = $oc['track6-interface'];
907
		$oic['sn'] = get_interface_subnet($if);
908
		$oic['snv6'] = get_interface_subnetv6($if);
909
		$oic['mtu'] = empty($oc['mtu']) ? 1500 : $oc['mtu'];
910
		$oic['mss'] = empty($oc['mss']) ? '' : $oc['mss'];
911
		$oic['descr'] = $ifdetail;
912
		$oic['sa'] = gen_subnet($oic['ip'], $oic['sn']);
913
		$oic['sav6'] = gen_subnetv6($oic['ipv6'], $oic['snv6']);
914
		$oic['nonat'] = $oc['nonat'];
915
		$oic['alias-address'] = $oc['alias-address'];
916
		$oic['alias-subnet'] = $oc['alias-subnet'];
917
		$oic['gateway'] = $oc['gateway'];
918
		$oic['gatewayv6'] = $oc['gatewayv6'];
919
		$oic['spoofcheck'] = "yes";
920
		$oic['bridge'] = link_interface_to_bridge($if);
921
		$vips = link_interface_to_vips($if);
922
		if (!empty($vips)) {
923
			foreach ($vips as $vipidx => $vip) {
924
				if (is_ipaddrv4($vip['subnet'])) {
925
					if (!is_array($oic['vips']))
926
						$oic['vips'] = array();
927
					$oic['vips'][$vipidx]['ip'] = $vip['subnet'];
928
					if (empty($vip['subnet_bits']))
929
						$oic['vips'][$vipidx]['sn'] = 32;
930
					else
931
						$oic['vips'][$vipidx]['sn'] = $vip['subnet_bits'];
932
				} else if (is_ipaddrv6($vip['subnet'])) {
933
					if (!is_array($oic['vips6']))
934
						$oic['vips6'] = array();
935
					$oic['vips6'][$vipidx]['ip'] = $vip['subnet'];
936
					if (empty($vip['subnet_bits']))
937
						$oic['vips6'][$vipidx]['sn'] = 128;
938
					else
939
						$oic['vips6'][$vipidx]['sn'] = $vip['subnet_bits'];
940
				}
941
			}
942
		}
943
		unset($vips);
944
		$FilterIflist[$if] = $oic;
945
	}
946

    
947
	if($config['pptpd']['mode'] == "server" || $config['pptpd']['mode'] == "redir") {
948
		$oic = array();
949
		$oic['if'] = 'pptp';
950
		$oic['descr'] = 'pptp';
951
		$oic['ip'] = $config['pptpd']['localip'];
952
		$oic['sa'] = $config['pptpd']['remoteip'];
953
		$oic['mode'] = $config['pptpd']['mode'];
954
		$oic['virtual'] = true;
955
		if($config['pptpd']['pptp_subnet'] <> "")
956
			$oic['sn'] = $config['pptpd']['pptp_subnet'];
957
		else
958
			$oic['sn'] = "32";
959
		$FilterIflist['pptp'] = $oic;
960
	}
961
	if($config['l2tp']['mode'] == "server") {
962
		$oic = array();
963
		$oic['if'] = 'l2tp';
964
		$oic['descr'] = 'L2TP';
965
		$oic['ip'] = $config['l2tp']['localip'];
966
		$oic['sa'] = $config['l2tp']['remoteip'];
967
		if($config['l2tp']['l2tp_subnet'] <> "")
968
			$oic['sn'] = $config['l2tp']['l2tp_subnet'];
969
		else
970
			$oic['sn'] = "32";
971
		$oic['mode'] = $config['l2tp']['mode'];
972
		$oic['virtual'] = true;
973
		$FilterIflist['l2tp'] = $oic;
974
	}
975
	if (is_array($config['pppoes']['pppoe']) && (count($config['pppoes']['pppoe']) > 0)) {
976
		$pppoeifs = array();
977
		foreach($config['pppoes']['pppoe'] as $pppoe) {
978
			if ($pppoe['mode'] == "server") {
979
				$oic = array();
980
				$oic['if'] = 'pppoe';
981
				$oic['descr'] = 'pppoe';
982
				$oic['ip'] = $pppoe['localip'];
983
				$oic['sa'] = $pppoe['remoteip'];
984
				$oic['mode'] = $pppoe['mode'];
985
				$oic['virtual'] = true;
986
				if($pppoe['pppoe_subnet'] <> "")
987
					$oic['sn'] = $pppoe['pppoe_subnet'];
988
				else
989
					$oic['sn'] = "32";
990
				$pppoeifs[] = $oic;
991
			}
992
		}
993
		if (count($pppoeifs))
994
			$FilterIflist['pppoe'] = $pppoeifs;
995
	}
996
	/* add ipsec interfaces */
997
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
998
		$oic = array();
999
		$oic['if'] = 'enc0';
1000
		$oic['descr'] = 'IPsec';
1001
		$oic['type'] = "none";
1002
		$oic['virtual'] = true;
1003
		$FilterIflist['enc0'] = $oic;
1004
	}
1005
	/* add openvpn interfaces */
1006
	if($config['openvpn']['openvpn-server'] || $config['openvpn']['openvpn-client']) {
1007
		$oic = array();
1008
		$oic['if'] = "openvpn";
1009
		$oic['descr'] = 'OpenVPN';
1010
		$oic['type'] = "none";
1011
		$oic['virtual'] = true;
1012
		$FilterIflist['openvpn'] = $oic;
1013
	}
1014
	/* add interface groups */
1015
	if(is_array($config['ifgroups']['ifgroupentry'])) {
1016
		foreach($config['ifgroups']['ifgroupentry'] as $ifgen) {
1017
			$oc = array();
1018
			$oc['if'] = $ifgen['ifname'];
1019
			$oc['descr'] = $ifgen['ifname'];
1020
			$oc['virtual'] = true;
1021
			$FilterIflist[$ifgen['ifname']] = $oc;
1022
		}
1023
	}
1024
}
1025

    
1026
function filter_flush_nat_table() {
1027
	global $config, $g;
1028
	if(isset($config['system']['developerspew'])) {
1029
		$mt = microtime();
1030
		echo "filter_flush_nat_table() being called $mt\n";
1031
	}
1032
	return mwexec("/sbin/pfctl -F nat");
1033
}
1034

    
1035
function filter_flush_state_table() {
1036
	return mwexec("/sbin/pfctl -F state");
1037
}
1038

    
1039
function filter_get_reflection_interfaces($natif = "") {
1040
	global $FilterIflist;
1041

    
1042
	$nat_if_list = array();
1043

    
1044
	foreach ($FilterIflist as $ifent => $ifname) {
1045
		if($ifname['if'] == $natif)
1046
			continue;
1047

    
1048
		/* Do not add reflection redirects for interfaces with gateways */
1049
		if(interface_has_gateway($ifent))
1050
			continue;
1051

    
1052
		$nat_if_list[] = $ifname['if'];
1053
	}
1054

    
1055
	return $nat_if_list;
1056
}
1057

    
1058
function filter_generate_reflection_nat($rule, &$route_table, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = "") {
1059
	global $config, $FilterIflist;
1060

    
1061
	if(!isset($config['system']['enablenatreflectionhelper']))
1062
		return "";
1063

    
1064
	// Initialize natrules holder string
1065
	$natrules = "";
1066

    
1067
	update_filter_reload_status(sprintf(gettext("Creating reflection NAT rule for %s..."), $rule['descr']));
1068

    
1069
	/* TODO: Add this option to port forwards page. */
1070
	if(isset($rule['staticnatport'])) {
1071
		$static_port = " static-port";
1072
	} else {
1073
		$static_port = " port 1024:65535";
1074
	}
1075

    
1076
	if(!empty($protocol)) {
1077
		$protocol_text = " proto {$protocol}";
1078
	} else {
1079
		$protocol_text = "";
1080
	}
1081

    
1082
	if(empty($target_subnet) || !is_numeric($target_subnet))
1083
		$target_subnet = 32;
1084

    
1085
	if(!is_array($route_table)) {
1086
		/* get a simulated IPv4-only route table based on the config */
1087
		$route_table = filter_get_direct_networks_list(false);
1088
		foreach($route_table as $rt_key => $rt_ent) {
1089
			if(!is_subnetv4($rt_ent['subnet']))
1090
				unset($route_table[$rt_key]);
1091
			if(isset($route_table[$rt_key]) && isset($FilterIflist[$rt_ent['if']]['if']))
1092
				$route_table[$rt_key]['if'] = $FilterIflist[$rt_ent['if']]['if'];
1093
		}
1094
	}
1095

    
1096
	/* Check if the target is accessed through a static route */
1097
	foreach($route_table as $route) {
1098
		if(isset($route['gateway']) && is_ipaddr($route['gateway'])) {
1099
			$subnet_split = explode("/", $route['subnet']);
1100
			if(in_array($route['if'], $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
1101
				$target_ip = $route['gateway'];
1102
				$target_subnet = 32;
1103
				break;
1104
			}
1105
		}
1106
	}
1107

    
1108
	/* Search for matching subnets in the routing table */
1109
	foreach($route_table as $route) {
1110
		$subnet = $route['subnet'];
1111
		$subnet_split = explode("/", $subnet);
1112
		$subnet_if = $route['if'];
1113
		if(in_array($subnet_if, $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
1114
			$ifsubnet_ip = "";
1115
			/* Find interface IP to use for NAT */
1116
			foreach ($route_table as $ifnetwork) {
1117
				if(isset($ifnetwork['ip']) && is_ipaddr($ifnetwork['ip']) && $ifnetwork['if'] == $subnet_if && ip_in_subnet($ifnetwork['ip'], $subnet)) {
1118
					$ifsubnet_ip = $ifnetwork['ip'];
1119
					break;
1120
				}
1121
			}
1122
			if(!empty($ifsubnet_ip)) {
1123
				$subnets = array($subnet);
1124
				/* Find static routes that also need to be referenced in the NAT rule */
1125
				foreach($route_table as $rtentry) {
1126
					if(isset($rtentry['gateway']) && is_ipaddr($rtentry['gateway']) && $rtentry['if'] == $subnet_if && ip_in_subnet($rtentry['gateway'], $subnet))
1127
						$subnets[] = $rtentry['subnet'];
1128
				}
1129
				if(count($subnets) > 1)
1130
					$subnet = "{ " . implode(" ", $subnets) . " }";
1131
				$natrules .= "no nat on {$subnet_if}{$protocol_text} from {$subnet_if} to {$target}\n";
1132
				$natrules .= "nat on {$subnet_if}{$protocol_text} from {$subnet} to {$target} -> {$ifsubnet_ip}{$static_port}\n";
1133
			}
1134
		}
1135
	}
1136

    
1137
	if(!empty($natrules))
1138
		$natrules .= "\n";
1139

    
1140
	return $natrules;
1141
}
1142

    
1143
function filter_generate_reflection_proxy($rule, $nordr, $rdr_ifs, $srcaddr, $dstaddr_port, &$starting_localhost_port, &$reflection_txt) {
1144
	global $FilterIflist, $config;
1145

    
1146
	// Initialize natrules holder string
1147
	$natrules = "";
1148
	$reflection_txt = array();
1149

    
1150
	if(!empty($rdr_ifs)) {
1151
		if($config['system']['reflectiontimeout'])
1152
			$reflectiontimeout = $config['system']['reflectiontimeout'];
1153
		else
1154
			$reflectiontimeout = "2000";
1155

    
1156
		update_filter_reload_status(sprintf(gettext("Creating reflection rule for %s..."), $rule['descr']));
1157

    
1158
		$rdr_if_list = implode(" ", $rdr_ifs);
1159
		if(count($rdr_ifs) > 1)
1160
			$rdr_if_list = "{ {$rdr_if_list} }";
1161

    
1162
		$natrules .= "\n# Reflection redirects\n";
1163

    
1164
		$localport = $rule['local-port'];
1165
		if(!empty($localport) && is_alias($localport)) {
1166
			$localport = filter_expand_alias($localport);
1167
			$localport = explode(" ", trim($localport));
1168
			// The translation port for rdr, when specified, does not support more than one port or range.
1169
			// Emulating for behavior consistent with the original port forward.
1170
			$localport = $localport[0];
1171
		}
1172

    
1173
		if(is_alias($rule['destination']['port'])) {
1174
			if(empty($localport) || $rule['destination']['port'] == $rule['local-port']) {
1175
				$dstport = filter_expand_alias($rule['destination']['port']);
1176
				$dstport = array_filter(explode(" ", trim($dstport)));
1177
				$localport = "";
1178
			} else if(!empty($localport)) {
1179
				$dstport = array($localport);
1180
			}
1181
		} else {
1182
			$dstport = array(str_replace("-", ":", $rule['destination']['port']));
1183
			$dstport_split = explode(":", $dstport[0]);
1184

    
1185
			if(!empty($localport) && $dstport_split[0] != $rule['local-port']) {
1186
				if(!is_alias($rule['local-port']) && $dstport_split[1] && $dstport_split[0] != $dstport_split[1]) {
1187
					$localendport = $localport + ($dstport_split[1] - $dstport_split[0]);
1188
					$localport .= ":$localendport";
1189
				}
1190

    
1191
				$dstport = array($localport);
1192
			} else
1193
				$localport = "";
1194
		}
1195

    
1196
		$dstaddr = explode(" ", $dstaddr_port);
1197
		if($dstaddr[2]) {
1198
			$rflctintrange = array_pop($dstaddr);
1199
			array_pop($dstaddr);
1200
		} else
1201
			return "";
1202
		$dstaddr = implode(" ", $dstaddr);
1203
		if(empty($dstaddr) || trim($dstaddr) == "0.0.0.0" || strtolower(trim($dstaddr)) == "port")
1204
			return "";
1205

    
1206
		if(isset($rule['destination']['any'])) {
1207
			if(!$rule['interface'])
1208
				$natif = "wan";
1209
			else
1210
				$natif = $rule['interface'];
1211

    
1212
			if(!isset($FilterIflist[$natif]))
1213
				return "";
1214
			if(is_ipaddr($FilterIflist[$natif]['ip']))
1215
				$dstaddr = $FilterIflist[$natif]['ip'];
1216
			else
1217
				return "";
1218

    
1219
			if(!empty($FilterIflist[$natif]['sn']))
1220
				$dstaddr = gen_subnet($dstaddr, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
1221
		}
1222

    
1223
		switch($rule['protocol']) {
1224
		case "tcp/udp":
1225
			$protocol = "{ tcp udp }";
1226
			$reflect_protos = array('tcp', 'udp');
1227
			break;
1228
		case "tcp":
1229
		case "udp":
1230
			$protocol = $rule['protocol'];
1231
			$reflect_protos = array($rule['protocol']);
1232
			break;
1233
		default:
1234
			return "";
1235
			break;
1236
		}
1237

    
1238
		if(!empty($nordr)) {
1239
			$natrules .= "no rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange}\n";
1240
			return $natrules;
1241
		}
1242

    
1243
		if (is_alias($rule['target']))
1244
			$target = filter_expand_alias($rule['target']);
1245
		else if(is_ipaddr($rule['target']))
1246
			$target = $rule['target'];
1247
		else if (is_ipaddr($FilterIflist[$rule['target']]['ip']))
1248
			$target = $FilterIflist[$rule['target']]['ip'];
1249
		else
1250
			return "";
1251
		$starting_localhost_port_tmp = $starting_localhost_port;
1252
		$toomanyports = false;
1253
		/* only install reflection rules for < 19991 items */
1254
		foreach($dstport as $loc_pt) {
1255
			if($starting_localhost_port < 19991) {
1256
				$toadd_array = array();
1257
				$inetdport = $starting_localhost_port;
1258
				$rflctrange = $starting_localhost_port;
1259

    
1260
				$loc_pt = explode(":", $loc_pt);
1261
				if($loc_pt[1] && $loc_pt[1] > $loc_pt[0])
1262
					$delta = $loc_pt[1] - $loc_pt[0];
1263
				else
1264
					$delta = 0;
1265

    
1266
				if(($inetdport + $delta + 1) - $starting_localhost_port_tmp > 500) {
1267
					log_error("Not installing NAT reflection rules for a port range > 500");
1268
					$inetdport = $starting_localhost_port;
1269
					$toadd_array = array();
1270
					$toomanyports = true;
1271
					break;
1272
				} else if(($inetdport + $delta) > 19990) {
1273
					log_error("Installing partial NAT reflection rules. Maximum 1,000 reached.");
1274
					$delta = 19990 - $inetdport;
1275
					$loc_pt[1] = $loc_pt[0] + $delta;
1276
					if($delta == 0)
1277
						unset($loc_pt[1]);
1278
					$toomanyports = true;
1279

    
1280
					if(!empty($localport)) {
1281
						if(is_alias($rule['destination']['port'])) {
1282
							$rflctintrange = alias_expand($rule['destination']['port']);
1283
						} else {
1284
							if($dstport_split[1])
1285
								$dstport_split[1] = $dstport_split[0] + $inetdport + $delta - $starting_localhost_port;
1286
							$rflctintrange = implode(":", $dstport_split);
1287
						}
1288
					}
1289
				}
1290

    
1291
				if(empty($localport))
1292
					$rflctintrange = implode(":", $loc_pt);
1293
				if($inetdport + $delta > $starting_localhost_port)
1294
					$rflctrange .= ":" . ($inetdport + $delta);
1295
				$starting_localhost_port = $inetdport + $delta + 1;
1296
				$toadd_array = array_merge($toadd_array, range($loc_pt[0], $loc_pt[0] + $delta));
1297

    
1298
				if(!empty($toadd_array)) {
1299
					$rtarget = explode(" ", trim($target));
1300
					foreach($toadd_array as $tda) {
1301
						if (empty($tda))
1302
							continue;
1303
						foreach($reflect_protos as $reflect_proto) {
1304
							if($reflect_proto == "udp") {
1305
								$socktype = "dgram";
1306
								$dash_u = "-u ";
1307
								$wait = "wait\t";
1308
							} else {
1309
								$socktype = "stream";
1310
								$dash_u = "";
1311
								$wait = "nowait/0";
1312
							}
1313
							foreach ($rtarget as $targip) {
1314
								if (empty($targip))
1315
									continue;
1316
								$reflection_txt[] = "{$inetdport}\t{$socktype}\t{$reflect_proto}\t{$wait}\tnobody\t/usr/bin/nc\tnc {$dash_u}-w {$reflectiontimeout} {$targip} {$tda}\n";
1317
							}
1318
						}
1319
						$inetdport++;
1320
					}
1321
					$natrules .= "rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange} tag PFREFLECT -> 127.0.0.1 port {$rflctrange}\n";
1322
				}
1323
			}
1324

    
1325
			if($toomanyports)
1326
				break;
1327
		}
1328

    
1329
		$reflection_txt = array_unique($reflection_txt);
1330
	}
1331

    
1332
	return $natrules;
1333
}
1334

    
1335
/* Generate a 'nat on' or 'no nat on' rule for given interface */
1336
function filter_nat_rules_generate_if($if, $src = "any", $srcport = "", $dst = "any", $dstport = "", $natip = "", $natport = "", $nonat = false, $staticnatport = false, $proto = "", $poolopts = "") {
1337
	global $config, $FilterIflist;
1338
	/* XXX: billm - any idea if this code is needed? */
1339
	if($src == "/32" || $src{0} == "/")
1340
		return "# src incorrectly specified\n";
1341
	if($natip != "") {
1342
		if (is_subnet($natip))
1343
			$tgt = $natip;
1344
		elseif (is_alias($natip))
1345
			$tgt = "\${$natip}";
1346
		else
1347
			$tgt = "{$natip}/32";
1348
	} else {
1349
		$natip = get_interface_ip($if);
1350
		if(is_ipaddr($natip))
1351
			$tgt = "{$natip}/32";
1352
		else
1353
			$tgt = "(" . $FilterIflist[$if]['if'] . ")";
1354
	}
1355
	/* Add the protocol, if defined */
1356
	if (!empty($proto) && $proto != "any") {
1357
		if ($proto == "tcp/udp")
1358
			$protocol = " proto { tcp udp }";
1359
		else
1360
			$protocol = " proto {$proto}";
1361
	} else
1362
		$protocol = "";
1363
	/* Set tgt for IPv6 */ 
1364
	if ($proto == "ipv6") {
1365
		$natip = get_interface_ipv6($if);
1366
		if(is_ipaddrv6($natip))
1367
			$tgt = "{$natip}/128";
1368
	}
1369
	/* Add the hard set source port (useful for ISAKMP) */
1370
	if($natport != "")
1371
		$tgt .= " port {$natport}";
1372
	/* sometimes this gets called with "" instead of a value */
1373
	if($src == "")
1374
		$src = "any";
1375
	/* Match on this source port */
1376
	if($srcport != "") {
1377
		$srcportexpand = alias_expand($srcport);
1378
		if(!$srcportexpand)
1379
			$srcportexpand = $srcport;
1380
		$src .= " port {$srcportexpand}";
1381
	}
1382
	/* sometimes this gets called with "" instead of a value */
1383
	if($dst == "")
1384
		$dst = "any";
1385
	/* Match on this dest port */
1386
	if($dstport != "") {
1387
		$dstportexpand = alias_expand($dstport);
1388
		if(!$dstportexpand)
1389
			$dstportexpand = $dstport;
1390
		$dst .= " port {$dstportexpand}";
1391
	}
1392
	/* outgoing static-port option, hamachi, Grandstream, VOIP, etc */
1393
	$staticnatport_txt = "";
1394
	if($staticnatport)
1395
		$staticnatport_txt = "static-port";
1396
	elseif(!$natport)
1397
		$tgt .= " port 1024:65535"; // set source port range
1398
	/* Allow for negating NAT entries */
1399
	if($nonat) {
1400
		$nat = "no nat";
1401
		$target = "";
1402
		$staticnatport_txt = "";
1403
		$poolopts = "";
1404
	} else {
1405
		$nat = "nat";
1406
		$target = "-> {$tgt}";
1407
	}
1408
	$if_friendly = $FilterIflist[$if]['descr'];
1409
	/* Put all the pieces together */
1410
	if($if_friendly)
1411
		$natrule = "{$nat} on \${$if_friendly} {$protocol} from {$src} to {$dst} {$target} {$poolopts} {$staticnatport_txt}\n";
1412
	else
1413
		$natrule .= "# Could not convert {$if} to friendly name(alias)\n";
1414
	return $natrule;
1415
}
1416

    
1417
function filter_nat_rules_generate() {
1418
	global $config, $g, $after_filter_configure_run, $FilterIflist, $GatewaysList, $aliases;
1419

    
1420
	$natrules = "no nat proto carp\n";
1421
	$natrules .= "no rdr proto carp\n";
1422
	$natrules .= "nat-anchor \"natearly/*\"\n";
1423

    
1424
	$natrules .= "nat-anchor \"natrules/*\"\n\n";
1425
	update_filter_reload_status(gettext("Creating 1:1 rules..."));
1426

    
1427
	$reflection_txt = "";
1428
	$route_table = "";
1429

    
1430
	/* any 1:1 mappings? */
1431
	if(is_array($config['nat']['onetoone'])) {
1432
		foreach ($config['nat']['onetoone'] as $rule) {
1433
			if (isset($rule['disabled']))
1434
				continue;
1435

    
1436
			$sn = "";
1437
			$sn1 = "";
1438
			$target = alias_expand($rule['external']);
1439
			if (!$target) {
1440
				$natrules .= "# Unresolvable alias {$rule['target']}\n";
1441
				continue;               /* unresolvable alias */
1442
			}
1443

    
1444
			if (!$rule['interface'])
1445
				$natif = "wan";
1446
			else
1447
				$natif = $rule['interface'];
1448
			if (!isset($FilterIflist[$natif]))
1449
				continue;
1450

    
1451
			$srcaddr = filter_generate_address($rule, 'source');
1452
			$dstaddr = filter_generate_address($rule, 'destination');
1453
			if(!$dstaddr)
1454
				$dstaddr = $FilterIflist[$natif]['ip'];
1455

    
1456
			$srcaddr = trim($srcaddr);
1457
			$dstaddr = trim($dstaddr);
1458

    
1459
			$tmp = explode('/', $srcaddr);
1460
			$srcip = $tmp[0];
1461
			if (!empty($tmp[1]) && is_numeric($tmp[1])) {
1462
				$sn = $tmp[1];
1463
				$sn1 = "/{$sn}";
1464
			}
1465

    
1466
			$natif = $FilterIflist[$natif]['if'];
1467

    
1468
			/*
1469
			 * If reflection is enabled, turn on extra redirections
1470
			 * for this rule by adding other interfaces to an rdr rule.
1471
			 */
1472
			if ((isset($config['system']['enablebinatreflection']) || $rule['natreflection'] == "enable")
1473
			   && $rule['natreflection'] != "disable")
1474
				$nat_if_list = filter_get_reflection_interfaces($natif);
1475
			else
1476
				$nat_if_list = array();
1477

    
1478
			$natrules .= "binat on {$natif} from {$srcaddr} to {$dstaddr} -> {$target}{$sn1}\n";
1479
			if (!empty($nat_if_list)) {
1480
				$binat_if_list = implode(" ", $nat_if_list);
1481
				$binat_if_list = "{ {$binat_if_list} }";
1482
				$reflection_txt .= "rdr on {$binat_if_list} from {$dstaddr} to {$target}{$sn1} -> {$srcaddr} bitmask\n";
1483
			}
1484

    
1485
			$nat_if_list = array_merge(array($natif), $nat_if_list);
1486
			$reflection_txt .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, "", $srcaddr, $srcip, $sn);
1487
		}
1488
	}
1489

    
1490
	/* Add binat rules for Network Prefix translation */
1491
	if(is_array($config['nat']['npt'])) {
1492
		foreach ($config['nat']['npt'] as $rule) {
1493
			if (isset($rule['disabled']))
1494
				continue;
1495

    
1496
			if (!$rule['interface'])
1497
				$natif = "wan";
1498
			else
1499
				$natif = $rule['interface'];
1500
			if (!isset($FilterIflist[$natif]))
1501
				continue;
1502

    
1503
			$srcaddr = filter_generate_address($rule, 'source');
1504
			$dstaddr = filter_generate_address($rule, 'destination');
1505

    
1506
			$srcaddr = trim($srcaddr);
1507
			$dstaddr = trim($dstaddr);
1508

    
1509
			$natif = $FilterIflist[$natif]['descr'];
1510

    
1511
			$natrules .= "binat on \${$natif} from {$srcaddr} to any -> {$dstaddr}\n";
1512
			$natrules .= "binat on \${$natif} from any to {$dstaddr} -> {$srcaddr}\n";
1513

    
1514
		}
1515
	}
1516

    
1517
	/* ipsec nat */
1518
	if (is_array($config['ipsec']) && isset($config['ipsec']['enable'])) {
1519
		if (is_array($config['ipsec']['phase2'])) {
1520
			foreach ($config['ipsec']['phase2'] as $ph2ent) {
1521
				if ($ph2ent['mode'] != 'transport' && !empty($ph2ent['natlocalid'])) {
1522
					if (!function_exists('ipsec_idinfo_to_cidr'))
1523
						require_once("ipsec.inc");
1524
					if (!is_array($ph2ent['localid']))
1525
						$ph2ent['localid'] = array();
1526
					$ph2ent['localid']['mode'] = $ph2ent['mode'];
1527
					$local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid']);
1528
					if (empty($local_subnet) || $local_subnet == "0.0.0.0/0")
1529
						continue;
1530
					if (!is_subnet($local_subnet) && !is_ipaddr($local_subnet))
1531
						continue;
1532
					if (!is_array($ph2ent['natlocalid']))
1533
						$ph2ent['natlocalid'] = array();
1534
					$ph2ent['natlocalid']['mode'] = $ph2ent['mode'];
1535
					$natlocal_subnet = ipsec_idinfo_to_cidr($ph2ent['natlocalid']);
1536
					if (empty($natlocal_subnet) || $natlocal_subnet == "0.0.0.0/0")
1537
						continue;
1538
					if (!is_subnet($natlocal_subnet) && !is_ipaddr($natlocal_subnet))
1539
						continue;
1540
					if (!is_array($ph2ent['remoteid']))
1541
						$ph2ent['remoteid'] = array();
1542
					$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
1543
					$remote_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
1544
					if (empty($remote_subnet))
1545
						continue;
1546
					if (!is_subnet($remote_subnet) && !is_ipaddr($remote_subnet))
1547
						continue;
1548
					if ($remote_subnet == "0.0.0.0/0")
1549
						$remote_subnet = "any";
1550
					if (is_ipaddr($natlocal_subnet) && !is_ipaddr($local_subnet) )
1551
						$nattype = "nat";
1552
					else
1553
						$nattype = "binat";
1554
					$natrules .= "{$nattype} on enc0 from {$local_subnet} to {$remote_subnet} -> {$natlocal_subnet}\n";
1555
				}
1556
			}
1557
		}
1558
	}
1559

    
1560
	$natrules .= "\n# Outbound NAT rules\n";
1561
	/* outbound rules - advanced or standard */
1562
	if(isset($config['nat']['advancedoutbound']['enable'])) {
1563
		/* advanced outbound rules */
1564
		if(is_array($config['nat']['advancedoutbound']['rule'])) {
1565
			foreach ($config['nat']['advancedoutbound']['rule'] as $obent) {
1566
				update_filter_reload_status(sprintf(gettext("Creating advanced outbound rule %s"), $obent['descr']));
1567
				$src = alias_expand($obent['source']['network']);
1568
				if(!$src)
1569
					$src = $obent['source']['network'];
1570
				$dst = alias_expand($obent['destination']['address']);
1571
				if(!$dst)
1572
					$dst = $obent['destination']['address'];
1573
				if(isset($obent['destination']['not']) && !isset($obent['destination']['any']))
1574
					$dst = "!" . $dst;
1575

    
1576
				if(!$obent['interface'] || !isset($FilterIflist[$obent['interface']]))
1577
					continue;
1578

    
1579
				$obtarget = ($obent['target'] == "other-subnet") ? $obent['targetip'] . '/' . $obent['targetip_subnet']: $obent['target'];
1580
				$poolopts = (is_subnet($obtarget) || is_alias($obtarget)) ? $obent['poolopts'] : "";
1581

    
1582
				$natrules .= filter_nat_rules_generate_if($obent['interface'],
1583
					$src,
1584
					$obent['sourceport'],
1585
					$dst,
1586
					$obent['dstport'],
1587
					$obtarget,
1588
					$obent['natport'],
1589
					isset($obent['nonat']),
1590
					isset($obent['staticnatport']),
1591
					$obent['protocol'],
1592
					$poolopts
1593
				);
1594
			}
1595
		}
1596
	} else {
1597
		/* standard outbound rules (one for each interface) */
1598
		update_filter_reload_status(gettext("Creating outbound NAT rules"));
1599
		$tonathosts = "";
1600
		$numberofnathosts = 0;
1601

    
1602
		foreach (get_staticroutes() as $route) {
1603
			$netip = explode("/", $route['network']);
1604
			if (isset($GatewaysList[$route['gateway']])) {
1605
				$gateway =& $GatewaysList[$route['gateway']];
1606
				if(!interface_has_gateway($gateway['interface']) && is_private_ip($netip[0])) {
1607
					$numberofnathosts++;
1608
					$tonathosts .= "{$route['network']} ";
1609
				}
1610
			}
1611
		}
1612
		/* create outbound nat entries for all local networks */
1613
		foreach($FilterIflist as $ocname => $oc) {
1614
			if(!interface_has_gateway($ocname)) {
1615
				if(is_ipaddr($oc['alias-address'])) {
1616
					$numberofnathosts++;
1617
					$tonathosts .= "{$oc['alias-address']}/{$oc['alias-subnet']} ";
1618
				}
1619
				if($oc['sa']) {
1620
					$tonathosts .= "{$oc['sa']}/{$oc['sn']} ";
1621
					$numberofnathosts++;
1622
				}
1623
			}
1624
		}
1625
		/* PPTP subnet */
1626
		if(($config['pptpd']['mode'] == "server" ) && is_private_ip($config['pptpd']['remoteip'])) {
1627
			if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
1628
				$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
1629
			else
1630
				$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
1631
			$numberofnathosts += count($pptp_subnets);
1632
			$tonathosts .= implode(" ", $pptp_subnets) . " ";
1633
		}
1634
		/* PPPoE subnet */
1635
		if (is_array($FilterIflist['pppoe'])) {
1636
			foreach ($FilterIflist['pppoe'] as $pppoe) {
1637
				if(is_private_ip($pppoe['ip'])) {
1638
					$numberofnathosts++;
1639
					$tonathosts .= "{$pppoe['sa']}/{$pppoe['sn']} ";
1640
				}
1641
			}
1642
		}
1643
		/* L2TP subnet */
1644
		if(isset($FilterIflist['l2tp']) && $FilterIflist['l2tp']['mode'] == "server") {
1645
			$l2tp_subnet = $FilterIflist['l2tp']['sn'];
1646
			if(is_private_ip($FilterIflist['l2tp']['sa']) && !empty($l2tp_subnet)) {
1647
				$numberofnathosts++;
1648
				$tonathosts .= "{$FilterIflist['l2tp']['sa']}/{$l2tp_subnet} ";
1649
			}
1650
		}
1651
		/* add openvpn interfaces */
1652
		if(is_array($config['openvpn']['openvpn-server'])) {
1653
			foreach ($config['openvpn']['openvpn-server'] as $ovpnsrv) {
1654
				if (!empty($ovpnsrv['tunnel_network'])) {
1655
					$numberofnathosts++;
1656
					$tonathosts .= "{$ovpnsrv['tunnel_network']} ";
1657
				}
1658
			}
1659
		}
1660
		if(is_array($config['openvpn']['openvpn-client'])) {
1661
			foreach ($config['openvpn']['openvpn-client'] as $ovpnsrv) {
1662
				if (!empty($ovpnsrv['tunnel_network'])) {
1663
					$numberofnathosts++;
1664
					$tonathosts .= "{$ovpnsrv['tunnel_network']} ";
1665
				}
1666
			}
1667
		}
1668
		/* IPsec mode_cfg subnet */
1669
		if (isset($config['ipsec']['client']['enable']) &&
1670
			!empty($config['ipsec']['client']['pool_address']) &&
1671
			!empty($config['ipsec']['client']['pool_netbits'])) {
1672
			$tonathosts .= "{$config['ipsec']['client']['pool_address']}/{$config['ipsec']['client']['pool_netbits']} ";
1673
			$numberofnathosts++;
1674
		}
1675
		$natrules .= "\n# Subnets to NAT \n";
1676
		$tonathosts .= "127.0.0.0/8 ";
1677
		if($numberofnathosts > 4) {
1678
			$natrules .= "table <tonatsubnets> { {$tonathosts} }\n";
1679
			$macroortable = "<tonatsubnets>";
1680
		} else if($numberofnathosts > 0) {
1681
			$natrules .= "tonatsubnets	= \"{ {$tonathosts} }\"\n";
1682
			$macroortable = "\$tonatsubnets";
1683
		}
1684
		if($numberofnathosts > 0):
1685
			foreach ($FilterIflist as $if => $ifcfg) {
1686
				if (substr($ifcfg['if'], 0, 4) == "ovpn")
1687
					continue;
1688
				update_filter_reload_status(sprintf(gettext('Creating outbound rules %1$s - (%2$s)'), $if, $ifcfg['descr']));
1689
				if(interface_has_gateway($if)) {
1690
					$target = $ifcfg['ip'];
1691
					/* create outbound nat entries for all local networks */
1692
					$natrules .= filter_nat_rules_generate_if($if,
1693
						"{$macroortable}", 500, "", 500, $target, 500, false);
1694
					$natrules .= filter_nat_rules_generate_if($if,
1695
						"{$macroortable}", null, "", null, $target, null, isset($ifcfg['nonat']));
1696
					$natrules .= "\n";
1697
				}
1698
			}
1699
		endif;
1700
	}
1701

    
1702
	/* load balancer anchor */
1703
	$natrules .= "\n# Load balancing anchor\n";
1704
	$natrules .= "rdr-anchor \"relayd/*\"\n";
1705

    
1706
	update_filter_reload_status(gettext("Setting up TFTP helper"));
1707
	$natrules .= "# TFTP proxy\n";
1708
	$natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
1709

    
1710
	if (!empty($config['system']['tftpinterface'])) {
1711
		$tftpifs = explode(",", $config['system']['tftpinterface']);
1712
		foreach($tftpifs as $tftpif) {
1713
			if ($FilterIflist[$tftpif])
1714
				$natrules .= "rdr pass on {$FilterIflist[$tftpif]['if']} proto udp from any to any port tftp -> 127.0.0.1 port 6969\n";
1715
		}
1716
	}
1717

    
1718
	/* DIAG: add ipv6 NAT, if requested */
1719
	if(isset($config['diag']['ipv6nat']['enable']) &&
1720
		is_ipaddr($config['diag']['ipv6nat']['ipaddr']) &&
1721
		is_array($FilterIflist['wan'])) {
1722
		/* XXX: FIX ME!	 IPV6 */
1723
		$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto ipv6 from any to any -> {$config['diag']['ipv6nat']['ipaddr']}\n";
1724
	}
1725

    
1726
	if(file_exists("/var/etc/inetd.conf"))
1727
		@unlink("/var/etc/inetd.conf");
1728
	// Open inetd.conf write handle
1729
	$inetd_fd = fopen("/var/etc/inetd.conf","w");
1730
	/* add tftp protocol helper */
1731
	fwrite($inetd_fd, "tftp-proxy\tdgram\tudp\twait\t\troot\t/usr/libexec/tftp-proxy\ttftp-proxy -v\n");
1732

    
1733
	if(isset($config['nat']['rule'])) {
1734
		/* start reflection redirects on port 19000 of localhost */
1735
		$starting_localhost_port = 19000;
1736
		$natrules .= "# NAT Inbound Redirects\n";
1737
		foreach ($config['nat']['rule'] as $rule) {
1738
			update_filter_reload_status(sprintf(gettext("Creating NAT rule %s"), $rule['descr']));
1739

    
1740
			if(isset($rule['disabled']))
1741
				continue;
1742

    
1743
			/* if item is an alias, expand */
1744
			$dstport = "";
1745
			$dstport[0] = alias_expand($rule['destination']['port']);
1746
			if(!$dstport[0])
1747
				$dstport = explode("-", $rule['destination']['port']);
1748

    
1749
			/* if item is an alias, expand */
1750
			$localport = alias_expand($rule['local-port']);
1751
			if(!$localport || $dstport[0] == $localport) {
1752
				$localport = "";
1753
			} else if(is_alias($rule['local-port'])) {
1754
				$localport = filter_expand_alias($rule['local-port']);
1755
				if($localport) {
1756
					$localport = explode(" ", trim($localport));
1757
					$localport = $localport[0];
1758
					$localport = " port {$localport}";
1759
				}
1760
			} else if(is_alias($rule['destination']['port'])) {
1761
				$localport = " port {$localport}";
1762
			} else {
1763
				if(($dstport[1]) && ($dstport[0] != $dstport[1])) {
1764
					$localendport = $localport + ($dstport[1] - $dstport[0]);
1765

    
1766
					$localport .= ":$localendport";
1767
				}
1768

    
1769
				$localport = " port {$localport}";
1770
			}
1771

    
1772
			switch(strtolower($rule['protocol'])) {
1773
			case "tcp/udp":
1774
				$protocol = "{ tcp udp }";
1775
				break;
1776
			case "tcp":
1777
			case "udp":
1778
				$protocol = strtolower($rule['protocol']);
1779
				break;
1780
			default:
1781
				$protocol = strtolower($rule['protocol']);
1782
				$localport = "";
1783
				break;
1784
			}
1785

    
1786
			$target = alias_expand($rule['target']);
1787
			if(!$target && !isset($rule['nordr'])) {
1788
				$natrules .= "# Unresolvable alias {$rule['target']}\n";
1789
				continue;		/* unresolvable alias */
1790
			}
1791

    
1792
			if(is_alias($rule['target']))
1793
				$target_ip = filter_expand_alias($rule['target']);
1794
			else if(is_ipaddr($rule['target']))
1795
				$target_ip = $rule['target'];
1796
			else if(is_ipaddr($FilterIflist[$rule['target']]['ip']))
1797
				$target_ip = $FilterIflist[$rule['target']]['ip'];
1798
			else
1799
				$target_ip = $rule['target'];
1800
			$target_ip = trim($target_ip);
1801

    
1802
			if($rule['associated-rule-id'] == "pass")
1803
				$rdrpass = "pass ";
1804
			else
1805
				$rdrpass = "";
1806

    
1807
			if (isset($rule['nordr'])) {
1808
				$nordr = "no ";
1809
				$rdrpass = "";
1810
			} else
1811
				$nordr = "";
1812

    
1813
			if(!$rule['interface'])
1814
				$natif = "wan";
1815
			else
1816
				$natif = $rule['interface'];
1817

    
1818
			if (!isset($FilterIflist[$natif]))
1819
				continue;
1820

    
1821
			$srcaddr = filter_generate_address($rule, 'source', true);
1822
			$dstaddr = filter_generate_address($rule, 'destination', true);
1823
			$srcaddr = trim($srcaddr);
1824
			$dstaddr = trim($dstaddr);
1825

    
1826
			if(!$dstaddr)
1827
				$dstaddr = $FilterIflist[$natif]['ip'];
1828

    
1829
			$dstaddr_port = explode(" ", $dstaddr);
1830
			if(empty($dstaddr_port[0]) || strtolower(trim($dstaddr_port[0])) == "port")
1831
				continue; // Skip port forward if no destination address found
1832
			$dstaddr_reflect = $dstaddr;
1833
			if(isset($rule['destination']['any'])) {
1834
				/* With reflection enabled, destination of 'any' has side effects
1835
				 * that most people would not expect, so change it on reflection rules. */
1836
				$dstaddr_reflect = $FilterIflist[$natif]['ip'];
1837
				if(!empty($FilterIflist[$natif]['sn']))
1838
					$dstaddr_reflect = gen_subnet($dstaddr_reflect, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
1839

    
1840
				if($dstaddr_port[2])
1841
					$dstaddr_reflect .= " port " . $dstaddr_port[2];
1842
			}
1843

    
1844
			$natif = $FilterIflist[$natif]['if'];
1845

    
1846
			$reflection_type = "none";
1847
			if($rule['natreflection'] != "disable" && $dstaddr_port[0] != "0.0.0.0") {
1848
				if($rule['natreflection'] == "enable")
1849
					$reflection_type = "proxy";
1850
				else if($rule['natreflection'] == "purenat")
1851
					$reflection_type = "purenat";
1852
				else if(!isset($config['system']['disablenatreflection'])) {
1853
					if(isset($config['system']['enablenatreflectionpurenat']))
1854
						$reflection_type = "purenat";
1855
					else
1856
						$reflection_type = "proxy";
1857
				}
1858
			}
1859

    
1860
			if($reflection_type != "none")
1861
				$nat_if_list = filter_get_reflection_interfaces($natif);
1862
			else
1863
				$nat_if_list = array();
1864

    
1865
			if(empty($nat_if_list))
1866
				$reflection_type = "none";
1867

    
1868
			$localport_nat = $localport;
1869
			if(empty($localport_nat) && $dstaddr_port[2])
1870
				$localport_nat = " port " . $dstaddr_port[2];
1871

    
1872
			if($srcaddr <> "" && $dstaddr <> "" && $natif) {
1873
				$natrules .= "{$nordr}rdr {$rdrpass}on {$natif} proto {$protocol} from {$srcaddr} to {$dstaddr}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
1874

    
1875
				/* Does this rule redirect back to a internal host? */
1876
				if(isset($rule['destination']['any']) && !isset($rule['nordr']) && !isset($config['system']['enablenatreflectionhelper']) && !interface_has_gateway($rule['interface'])) {
1877
					$rule_interface_ip = find_interface_ip($natif);
1878
					$rule_interface_subnet = find_interface_subnet($natif);
1879
					if(!empty($rule_interface_ip) && !empty($rule_interface_subnet)) {
1880
						$rule_subnet = gen_subnet($rule_interface_ip, $rule_interface_subnet);
1881
						$natrules .= "\n";
1882
						$natrules .= "no nat on {$natif} proto tcp from ({$natif}) to {$rule_subnet}/{$rule_interface_subnet}\n";
1883
						$natrules .= "nat on {$natif} proto tcp from {$rule_subnet}/{$rule_interface_subnet} to {$target} port {$dstport[0]} -> ({$natif})\n";
1884
					}
1885
				}
1886

    
1887
				if ($reflection_type != "none") {
1888
					if($reflection_type == "proxy" && !isset($rule['nordr'])) {
1889
						$natrules .= filter_generate_reflection_proxy($rule, $nordr, $nat_if_list, $srcaddr, $dstaddr, $starting_localhost_port, $reflection_rules);
1890
						$nat_if_list = array($natif);
1891
						foreach ($reflection_rules as $txtline)
1892
							fwrite($inetd_fd, $txtline);
1893
					} else if($reflection_type == "purenat" || isset($rule['nordr'])) {
1894
						$rdr_if_list = implode(" ", $nat_if_list);
1895
						if(count($nat_if_list) > 1)
1896
							$rdr_if_list = "{ {$rdr_if_list} }";
1897
						$natrules .= "\n# Reflection redirect\n";
1898
						$natrules .= "{$nordr}rdr {$rdrpass}on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr_reflect}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
1899
						$nat_if_list = array_merge(array($natif), $nat_if_list);
1900
					}
1901
				}
1902

    
1903
				if(empty($nat_if_list))
1904
					$nat_if_list = array($natif);
1905

    
1906
				$natrules .= "\n";
1907
				if(!isset($rule['nordr']))
1908
					$natrules .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, $protocol, "{$target}{$localport_nat}", $target_ip);
1909
			}
1910
		}
1911
	}
1912
	fclose($inetd_fd);		// Close file handle
1913

    
1914
	if (isset($config['pptpd']['mode']) && ($config['pptpd']['mode'] != "off")) {
1915
		if ($config['pptpd']['mode'] == "redir") {
1916
			$pptpdtarget = $config['pptpd']['redir'];
1917
			$natrules .= "# PPTP\n";
1918
			$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto gre from any to any -> {$pptpdtarget}\n";
1919
			$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto tcp from any to any port 1723 -> {$pptpdtarget}\n";
1920
		}
1921
	}
1922

    
1923
	$natrules .= discover_pkg_rules("nat");
1924

    
1925
	$natrules .= "# UPnPd rdr anchor\n";
1926
	$natrules .= "rdr-anchor \"miniupnpd\"\n";
1927

    
1928
	if(!empty($reflection_txt))
1929
		$natrules .= "\n# Reflection redirects and NAT for 1:1 mappings\n" . $reflection_txt;
1930

    
1931
	// Check if inetd is running, if not start it.	If so, restart it gracefully.
1932
	$helpers = isvalidproc("inetd");
1933
	if(file_exists("/var/etc/inetd.conf")) {
1934
		if(!$helpers)
1935
			mwexec("/usr/sbin/inetd -wW -R 0 -a 127.0.0.1 /var/etc/inetd.conf");
1936
		else
1937
			sigkillbypid("/var/run/inetd.pid", "HUP");
1938
	}
1939

    
1940
	return $natrules;
1941
}
1942

    
1943
function filter_generate_user_rule_arr($rule) {
1944
	global $config;
1945
	update_filter_reload_status(sprintf(gettext("Creating filter rule %s ..."), $rule['descr']));
1946
	$ret = array();
1947
	$line = filter_generate_user_rule($rule);
1948
	$ret['rule'] = $line;
1949
	$ret['interface'] = $rule['interface'];
1950
	if($rule['descr'] != "" and $line != "")
1951
		$ret['descr'] = "label \"" . fix_rule_label("USER_RULE: {$rule['descr']}") . "\"";
1952
	else
1953
		$ret['descr'] = "label \"USER_RULE\"";
1954

    
1955
	return $ret;
1956
}
1957

    
1958
function filter_generate_port(& $rule, $target = "source", $isnat = false) {
1959

    
1960
	$src = "";
1961

    
1962
	$rule['protocol'] = strtolower($rule['protocol']);
1963
	if(in_array($rule['protocol'], array("tcp","udp","tcp/udp"))) {
1964
		if($rule[$target]['port']) {
1965
			$srcport = explode("-", $rule[$target]['port']);
1966
			$srcporta = alias_expand($srcport[0]);
1967
			if(!$srcporta)
1968
				log_error(sprintf(gettext("filter_generate_port: %s is not a valid {$target} port."), $srcport[0]));
1969
			else if((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
1970
				$src .= " port {$srcporta} ";
1971
			} else if(($srcport[0] == 1) && ($srcport[1] == 65535)) {
1972
			/* no need for a port statement here */
1973
			} else if ($isnat) {
1974
				$src .= " port {$srcport[0]}:{$srcport[1]}";
1975
			} else {
1976
				if(is_port($srcporta) && $srcport[1] == 65535) {
1977
					$src .= " port >= {$srcporta} ";
1978
				} else if($srcport[0] == 1) {
1979
					$src .= " port <= {$srcport[1]} ";
1980
				} else {
1981
					$srcport[0]--;
1982
					$srcport[1]++;
1983
					$src .= " port {$srcport[0]} >< {$srcport[1]} ";
1984
				}
1985
			}
1986
		}
1987
	}
1988

    
1989
	return $src;
1990
}
1991

    
1992
function filter_generate_address(& $rule, $target = "source", $isnat = false) {
1993
	global $FilterIflist, $config;
1994
	$src = "";
1995

    
1996
	if(isset($rule[$target]['any'])) {
1997
		$src = "any";
1998
	} else if($rule[$target]['network']) {
1999
		if(strstr($rule[$target]['network'], "opt")) {
2000
			$optmatch = "";
2001
			$matches = "";
2002
			if($rule['ipprotocol'] == "inet6") {
2003
				if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
2004
					$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ipv6'];
2005
					if(!is_ipaddrv6($opt_ip))
2006
						return "";
2007
					$src = $opt_ip . "/" .
2008
					$FilterIflist["opt{$optmatch[1]}"]['snv6'];
2009
				/* check for opt$NUMip here */
2010
				} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
2011
					$src = $FilterIflist["opt{$matches[1]}"]['ipv6'];
2012
					if(!is_ipaddrv6($src))
2013
						return "";
2014
				}
2015
				if(isset($rule[$target]['not']))
2016
					$src = " !{$src}";
2017
			} else {
2018
				if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
2019
					$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ip'];
2020
					if(!is_ipaddrv4($opt_ip))
2021
						return "";
2022
					$src = $opt_ip . "/" .
2023
					$FilterIflist["opt{$optmatch[1]}"]['sn'];
2024
				/* check for opt$NUMip here */
2025
				} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
2026
					$src = $FilterIflist["opt{$matches[1]}"]['ip'];
2027
					if(!is_ipaddrv4($src))
2028
						return "";
2029
				}
2030
				if(isset($rule[$target]['not']))
2031
					$src = " !{$src}";
2032
			}
2033
		} else {
2034
			if($rule['ipprotocol'] == "inet6") {
2035
				switch ($rule[$target]['network']) {
2036
					case 'wan':
2037
						$wansa = $FilterIflist['wan']['sav6'];
2038
						if (!is_ipaddrv6($wansa))
2039
							return "";
2040
						$wansn = $FilterIflist['wan']['snv6'];
2041
						$src = "{$wansa}/{$wansn}";
2042
						break;
2043
					case 'wanip':
2044
						$src = $FilterIflist["wan"]['ipv6'];
2045
						if (!is_ipaddrv6($src))
2046
							return "";
2047
						break;
2048
					case 'lanip':
2049
						$src = $FilterIflist["lan"]['ipv6'];
2050
						if (!is_ipaddrv6($src))
2051
							return "";
2052
						break;
2053
					case 'lan':
2054
						$lansa = $FilterIflist['lan']['sav6'];
2055
						if (!is_ipaddrv6($lansa))
2056
							return "";
2057
						$lansn = $FilterIflist['lan']['snv6'];
2058
						$src = "{$lansa}/{$lansn}";
2059
						break;
2060
					case 'pptp':
2061
						$pptpsav6 = gen_subnetv6($FilterIflist['pptp']['sav6'], $FilterIflist['pptp']['snv6']);
2062
						$pptpsnv6 = $FilterIflist['pptp']['snv6'];
2063
						$src = "{$pptpsav6}/{$pptpsnv6}";
2064
						break;
2065
					case 'pppoe':
2066
						if (is_array($FilterIflist['pppoe'])) {
2067
							$pppoesav6 = gen_subnetv6($FilterIflist['pppoe'][0]['ipv6'], $FilterIflist['pppoe'][0]['snv6']);
2068
							$pppoesnv6 = $FilterIflist['pppoe'][0]['snv6'];
2069
							$src = "{$pppoesav6}/{$pppoesnv6}";
2070
						}
2071
					}
2072
				if(isset($rule[$target]['not']))
2073
					$src = " !{$src}";
2074
			} else {
2075
				switch ($rule[$target]['network']) {
2076
					case 'wan':
2077
						$wansa = $FilterIflist['wan']['sa'];
2078
						if (!is_ipaddrv4($wansa))
2079
							return "";
2080
						$wansn = $FilterIflist['wan']['sn'];
2081
						$src = "{$wansa}/{$wansn}";
2082
						break;
2083
					case 'wanip':
2084
						$src = $FilterIflist["wan"]['ip'];
2085
						break;
2086
					case 'lanip':
2087
						$src = $FilterIflist["lan"]['ip'];
2088
						break;
2089
					case 'lan':
2090
						$lansa = $FilterIflist['lan']['sa'];
2091
						if (!is_ipaddrv4($lansa))
2092
							return "";
2093
						$lansn = $FilterIflist['lan']['sn'];
2094
						$src = "{$lansa}/{$lansn}";
2095
						break;
2096
					case 'pptp':
2097
						if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
2098
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
2099
						else
2100
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
2101
						if (empty($pptp_subnets))
2102
							return "";
2103
						$src = "{ " . implode(" ", $pptp_subnets) . " }";
2104
						break;
2105
					case 'pppoe':
2106
						/* XXX: This needs to be fixed somehow! */
2107
						if (is_array($FilterIflist['pppoe'])) {
2108
							$pppoesa = gen_subnet($FilterIflist['pppoe'][0]['ip'], $FilterIflist['pppoe'][0]['sn']);
2109
							$pppoesn = $FilterIflist['pppoe'][0]['sn'];
2110
							$src = "{$pppoesa}/{$pppoesn}";
2111
						}
2112
						break;
2113
				}
2114
				if(isset($rule[$target]['not']))
2115
					$src = " !{$src}";
2116
			}
2117
		}
2118
	} else if($rule[$target]['address']) {
2119
		$expsrc = alias_expand($rule[$target]['address']);
2120
		if(isset($rule[$target]['not']))
2121
			$not = "!";
2122
		else
2123
			$not = "";
2124
		$src = " {$not} {$expsrc}";
2125
	}
2126

    
2127
	$src .= filter_generate_port($rule, $target, $isnat);
2128

    
2129
	return $src;
2130
}
2131

    
2132
function filter_generate_user_rule($rule) {
2133
	global $config, $g, $FilterIflist, $GatewaysList;
2134
	global $layer7_rules_list, $dummynet_name_list;
2135

    
2136
	if(isset($config['system']['developerspew'])) {
2137
		$mt = microtime();
2138
		echo "filter_generate_user_rule() being called $mt\n";
2139
	}
2140
	/* don't include disabled rules */
2141
	if(isset($rule['disabled'])) {
2142
		return "# rule " . $rule['descr'] . " disabled \n";
2143
	}
2144
	update_filter_reload_status("Creating filter rules {$rule['descr']} ...");
2145
	$pptpdcfg = $config['pptpd'];
2146
	$int = "";
2147
	$aline = array();
2148

    
2149
	/* Check to see if the interface is in our list */
2150
	if(isset($rule['floating'])) {
2151
		if(isset($rule['interface']) && $rule['interface'] <> "") {
2152
			$interfaces = explode(",", $rule['interface']);
2153
			$ifliste = "";
2154
			foreach ($interfaces as $iface) {
2155
				if(array_key_exists($iface, $FilterIflist))
2156
					$ifliste .= " " . $FilterIflist[$iface]['if'] . " ";
2157
			}
2158
			if($ifliste <> "")
2159
				$aline['interface'] = " on { {$ifliste} } ";
2160
			else
2161
				$aline['interface'] = "";
2162
		} else
2163
			$aline['interface'] = "";
2164
	} else if(!array_key_exists($rule['interface'], $FilterIflist)) {
2165
			foreach($FilterIflist as $oc)
2166
				$items .= $oc['descr'] . " ";
2167
			return "# array key \"{$rule['interface']}\" does not exist for \"" . $rule['descr'] . "\" in array: {{$items}}";
2168
	} else if((array_key_exists($rule['interface'], $FilterIflist))
2169
		&& (is_array($FilterIflist[$rule['interface']]))
2170
		&& (is_array($FilterIflist[$rule['interface']][0]))) {
2171
		/* Currently this only case for this is the pppoe server. There should be an existing macro with this name. */
2172
		$aline['interface'] = " on \$" . $rule['interface'] . " ";
2173
	} else
2174
		$aline['interface'] = " on \$" . $FilterIflist[$rule['interface']]['descr'] . " ";
2175
	$ifcfg = $FilterIflist[$rule['interface']];
2176
	if($pptpdcfg['mode'] != "server") {
2177
		if(($rule['source']['network'] == "pptp") ||
2178
			($rule['destination']['network'] == "pptp"))
2179
				return "# source network or destination network == pptp on " . $rule['descr'];
2180
	}
2181

    
2182
	switch($rule['ipprotocol']) {
2183
	case "inet":
2184
		$aline['ipprotocol'] = "inet";
2185
		break;
2186
	case "inet6":
2187
		$aline['ipprotocol'] = "inet6";
2188
		break;
2189
	default:
2190
		$aline['ipprotocol'] = "";
2191
		break;
2192
	}
2193

    
2194
	/* check for unresolvable aliases */
2195
	if($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
2196
		$error_text = "Unresolvable source alias '{$rule['source']['address']}' for rule '{$rule['descr']}'";
2197
		file_notice("Filter_Reload", $error_text);
2198
		return "# {$error_text}";
2199
	}
2200
	if($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
2201
		$error_text = "Unresolvable destination alias '{$rule['destination']['address']}' for rule '{$rule['descr']}'";
2202
		file_notice("Filter_Reload", $error_text);
2203
		return "# {$error_text}";
2204
	}
2205
	update_filter_reload_status("Setting up pass/block rules");
2206
	$type = $rule['type'];
2207
	if($type != "pass" && $type != "block" && $type != "reject" && $type != "match") {
2208
		/* default (for older rules) is pass */
2209
		$type = "pass";
2210
	}
2211
	if($type == "reject") {
2212
		$aline['type'] = "block return ";
2213
	} else
2214
		$aline['type'] = $type . " ";
2215
	if(isset($rule['floating']) && $rule['floating'] == "yes") {
2216
		if($rule['direction'] != "any")
2217
			$aline['direction'] = " " . $rule['direction'] . " ";
2218
	} else {
2219
		/* ensure the direction is in */
2220
		$aline['direction'] = " in ";
2221
	}
2222
	if(isset($rule['log']))
2223
		$aline['log'] = "log ";
2224
	if(!isset($rule['floating']) || isset($rule['quick']))
2225
		$aline['quick'] = " quick ";
2226

    
2227
	/* set the gateway interface */
2228
	update_filter_reload_status(sprintf(gettext("Setting up pass/block rules %s"), $rule['descr']));
2229

    
2230
	/* do not process reply-to for gateway'd rules */
2231
	if($rule['gateway'] == "" && $aline['direction'] <> "" && interface_has_gateway($rule['interface']) && !isset($config['system']['disablereplyto']) && !isset($rule['disablereplyto']) && $type != "match") {
2232
		if ($rule['ipprotocol'] == "inet6") {
2233
			$rg = get_interface_gateway_v6($rule['interface']);
2234
			if (is_ipaddrv6($rg))
2235
				$aline['reply'] = "reply-to ( {$ifcfg['ifv6']} {$rg} ) ";
2236
			else if ($rule['interface'] <> "pptp")
2237
				log_error("Could not find IPv6 gateway for interface({$rule['interface']}).");
2238
		} else {
2239
			$rg = get_interface_gateway($rule['interface']);
2240
			if (is_ipaddrv4($rg))
2241
				$aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) ";
2242
			else if ($rule['interface'] <> "pptp")
2243
				log_error(sprintf(gettext("Could not find IPv4 gateway for interface (%s)."), $rule['interface']));
2244
		}
2245
	}
2246
	/* if user has selected a custom gateway, lets work with it */
2247
	else if($rule['gateway'] <> "" && $type == "pass") {
2248
		if (isset($GatewaysList[$rule['gateway']]))
2249
			/* Add the load balanced gateways */
2250
			$aline['route'] = " \$GW{$rule['gateway']} ";
2251
		else if (isset($config['system']['skip_rules_gw_down']))
2252
			return "# rule " . $rule['descr'] . " disabled because gateway " . $rule['gateway'] . " is down ";
2253
		else
2254
			log_error("The gateway: {$rule['gateway']} is invalid or unknown, not using it.");
2255
	}
2256

    
2257
	if (isset($rule['protocol']) && !empty($rule['protocol'])) {
2258
		if($rule['protocol'] == "tcp/udp")
2259
			$aline['prot'] = " proto { tcp udp } ";
2260
		elseif(($rule['protocol'] == "icmp") && ($rule['ipprotocol'] == "inet6"))
2261
			$aline['prot'] = " proto ipv6-icmp ";
2262
		elseif($rule['protocol'] == "icmp")
2263
			$aline['prot'] = " proto icmp ";
2264
		else
2265
			$aline['prot'] = " proto {$rule['protocol']} ";
2266
	} else {
2267
		if($rule['source']['port'] <> "" || $rule['destination']['port'] <> "")
2268
			$aline['prot'] = " proto tcp ";
2269
	}
2270
	update_filter_reload_status(sprintf(gettext("Creating rule %s"), $rule['descr']));
2271

    
2272
	/* source address */
2273
	$src = trim(filter_generate_address($rule, "source"));
2274
	if (empty($src) || ($src == "/")) {
2275
		return "# at the break!";
2276
	}
2277
	$aline['src'] = " from $src ";
2278

    
2279
	/* OS signatures */
2280
	if(($rule['protocol'] == "tcp") && ($rule['os'] <> ""))
2281
		$aline['os'] = " os {$rule['os']} ";
2282

    
2283
	/* destination address */
2284
	$dst = trim(filter_generate_address($rule, "destination"));
2285
	if (empty($dst) || ($dst == "/")) {
2286
		return "# returning at dst $dst == \"/\"";
2287
	}
2288
	$aline['dst'] = "to $dst ";
2289

    
2290
	//Layer7 support
2291
	$l7_present = false;
2292
	$l7_structures = array();
2293
	if(isset($rule['l7container']) && $rule['l7container'] != "none") {
2294
		$l7_present = true;
2295
		$l7rule =& $layer7_rules_list[$rule['l7container']];
2296
		$l7_structures = $l7rule->get_unique_structures();
2297
		$aline['divert'] = "divert " . $l7rule->GetRPort() . " ";
2298
	}
2299
	if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet"))
2300
		$aline['icmp-type'] = "icmp-type {$rule['icmptype']} ";
2301
	if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet6"))
2302
		$aline['icmp6-type'] = "icmp6-type {$rule['icmptype']} ";
2303
	if (!empty($rule['tag']))
2304
		$aline['tag'] = " tag " .$rule['tag']. " ";
2305
	if (!empty($rule['tagged']))
2306
		$aline['tagged'] = " tagged " .$rule['tagged'] . " ";
2307
	if (!empty($rule['dscp'])) {
2308
		switch (strtolower($rule['dscp'])) {
2309
			case 'va':  $aline['dscp'] = " dscp 44 "; break;
2310
			case 'cs1': $aline['dscp'] = " dscp 8 ";  break;
2311
			case 'cs2': $aline['dscp'] = " dscp 16 "; break;
2312
			case 'cs3': $aline['dscp'] = " dscp 24 "; break;
2313
			case 'cs4': $aline['dscp'] = " dscp 32 "; break;
2314
			case 'cs5': $aline['dscp'] = " dscp 40 "; break;
2315
			case 'cs6': $aline['dscp'] = " dscp 48 "; break;
2316
			case 'cs7': $aline['dscp'] = " dscp 56 "; break;
2317
			default:    $aline['dscp'] = " dscp " . preg_replace('/\s.*$/', '', $rule['dscp']) . " "; break;
2318
		}
2319
	}
2320
	if (!empty($rule['vlanprio']) && ($rule['vlanprio'] != "none"))
2321
		$aline['vlanprio'] = " ieee8021q-pcp " . $rule['vlanprio'] . " ";
2322
	if (!empty($rule['vlanprioset']) && ($rule['vlanprioset'] != "none"))
2323
		$aline['vlanprioset'] = " ieee8021q-setpcp " . $rule['vlanprioset'] . " ";
2324
	if ($type == "pass") {
2325
		if (isset($rule['allowopts']))
2326
			$aline['allowopts'] = " allow-opts ";
2327
	}
2328
	$aline['flags'] = "";
2329
	if ($rule['protocol'] == "tcp") {
2330
		if (isset($rule['tcpflags_any']))
2331
			$aline['flags'] = "flags any ";
2332
		else if (!empty($rule['tcpflags2'])) {
2333
			$aline['flags'] = "flags ";
2334
			if (!empty($rule['tcpflags1'])) {
2335
				$flags1 = explode(",", $rule['tcpflags1']);
2336
				foreach ($flags1 as $flag1) {
2337
					// CWR flag needs special treatment
2338
					if($flag1[0] == "c")
2339
						$aline['flags'] .= "W";
2340
					else
2341
						$aline['flags'] .= strtoupper($flag1[0]);
2342
				}
2343
			}
2344
			$aline['flags'] .= "/";
2345
			if (!empty($rule['tcpflags2'])) {
2346
				$flags2 = explode(",", $rule['tcpflags2']);
2347
				foreach ($flags2 as $flag2) {
2348
					// CWR flag needs special treatment
2349
					if($flag2[0] == "c")
2350
						$aline['flags'] .= "W";
2351
					else
2352
						$aline['flags'] .= strtoupper($flag2[0]);
2353
				}
2354
			}
2355
			$aline['flags'] .= " ";
2356
		} else {
2357
			$aline['flags'] = "flags S/SA ";
2358
		}
2359
	}
2360
	if ($type == "pass") {
2361
		/*
2362
		 *	# keep state
2363
		 *		works with TCP, UDP, and ICMP.
2364
		 *	# modulate state
2365
		 *		works only with TCP. pfSense will generate strong Initial Sequence Numbers (ISNs)
2366
		 *		for packets matching this rule.
2367
		 *	# synproxy state
2368
		 *		proxies incoming TCP connections to help protect servers from spoofed TCP SYN floods.
2369
		 *		This option includes the functionality of keep state and modulate state combined.
2370
		 *	# none
2371
		 *		do not use state mechanisms to keep track. this is only useful if your doing advanced
2372
		 *		queueing in certain situations. please check the faq.
2373
		 */
2374
		$noadvoptions = false;
2375
		if (isset($rule['statetype']) && $rule['statetype'] <> "") {
2376
			switch($rule['statetype']) {
2377
				case "none":
2378
					$noadvoptions = true;
2379
					$aline['flags'] .= " no state ";
2380
					break;
2381
				case "modulate state":
2382
				case "synproxy state":
2383
					if ($rule['protocol'] == "tcp")
2384
						$aline['flags'] .= "{$rule['statetype']} ";
2385
					break;
2386
				case "sloppy state":
2387
					$aline['flags'] .= "keep state ";
2388
					$rule['sloppy'] = true;
2389
					break;
2390
				default:
2391
					$aline['flags'] .= "{$rule['statetype']} ";
2392
					break;
2393
			}
2394
		} else
2395
			$aline['flags'] .= "keep state ";
2396

    
2397
		if ($noadvoptions == false || $l7_present)
2398
			if ((isset($rule['source-track']) and $rule['source-track'] <> "") or
2399
			    (isset($rule['max']) and $rule['max'] <> "") or
2400
			    (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") or
2401
			    (isset($rule['max-src-states']) and $rule['max-src-states'] <> "") or
2402
			    ((in_array($rule['protocol'], array("tcp","tcp/udp"))) and
2403
			     ((isset($rule['statetimeout']) and $rule['statetimeout'] <> "") or
2404
			      (isset($rule['max-src-conn']) and $rule['max-src-conn'] <> "") or
2405
			      (isset($rule['max-src-conn-rate']) and $rule['max-src-conn-rate'] <> "") or
2406
			      (isset($rule['max-src-conn-rates']) and $rule['max-src-conn-rates'] <> ""))) or
2407
			    isset($rule['sloppy']) or $l7_present) {
2408
					$aline['flags'] .= "( ";
2409
					if (isset($rule['sloppy']))
2410
						$aline['flags'] .= "sloppy ";
2411
					if (isset($rule['source-track']) and $rule['source-track'] <> "")
2412
						$aline['flags'] .= "source-track rule ";
2413
					if (isset($rule['max']) and $rule['max'] <> "")
2414
						$aline['flags'] .= "max " . $rule['max'] . " ";
2415
					if (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "")
2416
						$aline['flags'] .= "max-src-nodes " . $rule['max-src-nodes'] . " ";
2417
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2418
							and isset($rule['max-src-conn']) 
2419
							and $rule['max-src-conn'] <> "")
2420
						$aline['flags'] .= "max-src-conn " . $rule['max-src-conn'] . " ";
2421
					if (isset($rule['max-src-states']) and $rule['max-src-states'] <> "")
2422
						$aline['flags'] .= "max-src-states " . $rule['max-src-states'] . " ";
2423
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2424
							and isset($rule['statetimeout']) 
2425
							and $rule['statetimeout'] <> "")
2426
						$aline['flags'] .= "tcp.established " . $rule['statetimeout'] . " ";
2427
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2428
							and isset($rule['max-src-conn-rate'])
2429
							and $rule['max-src-conn-rate'] <> ""
2430
							and isset($rule['max-src-conn-rates'])
2431
							and $rule['max-src-conn-rates'] <> "") {
2432
						$aline['flags'] .= "max-src-conn-rate " . $rule['max-src-conn-rate'] . " ";
2433
						$aline['flags'] .= "/" . $rule['max-src-conn-rates'] . ", overload <virusprot> flush global ";
2434
					}
2435

    
2436
					if(!empty($aline['divert']))
2437
						$aline['flags'] .= "max-packets 8 ";
2438

    
2439
					$aline['flags'] .= " ) ";
2440
				}
2441
	}
2442
	if($rule['defaultqueue'] <> "") {
2443
		$aline['queue'] = " queue (".$rule['defaultqueue'];
2444
		if($rule['ackqueue'] <> "")
2445
			$aline['queue'] .= ",".$rule['ackqueue'];
2446
		$aline['queue'] .= ") ";
2447
	}
2448
	if($rule['dnpipe'] <> "") {
2449
		if (!empty($dummynet_name_list[$rule['dnpipe']])) {
2450
			if($dummynet_name_list[$rule['dnpipe']][0] == "?") {
2451
				$aline['dnpipe'] = " dnqueue( ";
2452
				$aline['dnpipe'] .= substr($dummynet_name_list[$rule['dnpipe']],1);
2453
				if($rule['pdnpipe'] <> "")
2454
					$aline['dnpipe'] .= ",".substr($dummynet_name_list[$rule['pdnpipe']], 1);
2455
			} else {
2456
				$aline['dnpipe'] = " dnpipe ( " . $dummynet_name_list[$rule['dnpipe']];
2457
				if($rule['pdnpipe'] <> "")
2458
					$aline['dnpipe'] .= "," . $dummynet_name_list[$rule['pdnpipe']];
2459
			}
2460
			$aline['dnpipe'] .= ") ";
2461
		}
2462
	}
2463

    
2464
	/* is a time based rule schedule attached? */
2465
	if(!empty($rule['sched']) && !empty($config['schedules'])) {
2466
		$aline['schedlabel'] = "";
2467
		foreach ($config['schedules']['schedule'] as $sched) {
2468
			if($sched['name'] == $rule['sched']) {
2469
				if(!filter_get_time_based_rule_status($sched)) {
2470
					if(!isset($config['system']['schedule_states']))
2471
						mwexec("/sbin/pfctl -y {$sched['schedlabel']}");
2472
					return "# schedule finished - {$rule['descr']}";
2473
				} else if($g['debug'])
2474
					log_error("[TDR DEBUG] status true -- rule type '$type'");
2475

    
2476
				$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
2477
				break;
2478
			}
2479
		}
2480
	}
2481

    
2482
	$line = "";
2483
	/* exception(s) to a user rules can go here. */
2484
	/* rules with a gateway or pool should create another rule for routing to vpns */
2485
	if((($aline['route'] <> "") && (trim($aline['type']) == "pass") && strstr($dst, "any")) && (!isset($config['system']['disablenegate']))) {
2486
		/* negate VPN/PPTP/PPPoE/Static Route networks for load balancer/gateway rules */
2487
		$negate_networks = " to <negate_networks> " . filter_generate_port($rule, "destination");
2488
		$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] .
2489
			$aline['interface'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] .
2490
			$negate_networks . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] .
2491
			$aline['vlanprio'] . $aline['vlanprioset'] . $aline['dscp'] . $aline['allowopts'] . $aline['flags'] .
2492
			$aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'] .
2493
			" label \"NEGATE_ROUTE: Negate policy routing for destination\"\n";
2494

    
2495
	}
2496
	/* piece together the actual user rule */
2497
	$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
2498
		$aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
2499
		$aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] .
2500
		$aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
2501

    
2502
	unset($aline);
2503

    
2504
	return $line;
2505
}
2506

    
2507
function filter_rules_generate() {
2508
	global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList;
2509

    
2510
	$fix_rule_label = 'fix_rule_label';
2511

    
2512
	update_filter_reload_status(gettext("Creating default rules"));
2513
	if(isset($config['system']['developerspew'])) {
2514
		$mt = microtime();
2515
		echo "filter_rules_generate() being called $mt\n";
2516
	}
2517

    
2518
	$pptpdcfg = $config['pptpd'];
2519

    
2520
	$ipfrules = "";
2521
	$ipfrules .= discover_pkg_rules("pfearly");
2522

    
2523
	/* relayd */
2524
	$ipfrules .= "anchor \"relayd/*\"\n";
2525
	/* OpenVPN user rules from radius */
2526
	$ipfrules .= "anchor \"openvpn/*\"\n";
2527
	/* IPSec user rules from radius */
2528
	$ipfrules .= "anchor \"ipsec/*\"\n";
2529
	# BEGIN OF firewall rules
2530
	/* default block logging? */
2531
	if(!isset($config['syslog']['nologdefaultblock']))
2532
		$log = "log";
2533
	else
2534
		$log = "";
2535
		
2536
	if(!isset($config['system']['ipv6allow'])) {
2537
		$ipfrules .= "# Block all IPv6\n";
2538
		$ipfrules .= "block in {$log} quick inet6 all label \"Block all IPv6\"\n";
2539
		$ipfrules .= "block out {$log} quick inet6 all label \"Block all IPv6\"\n";
2540
	}
2541
	
2542
	$ipfrules .= <<<EOD
2543
#---------------------------------------------------------------------------
2544
# default deny rules
2545
#---------------------------------------------------------------------------
2546
block in $log inet all label "Default deny rule IPv4"
2547
block out $log inet all label "Default deny rule IPv4"
2548
block in $log inet6 all label "Default deny rule IPv6"
2549
block out $log inet6 all label "Default deny rule IPv6"
2550

    
2551
# IPv6 ICMP is not auxilary, it is required for operation
2552
# See man icmp6(4)
2553
# 1    unreach         Destination unreachable
2554
# 2    toobig          Packet too big
2555
# 128  echoreq         Echo service request
2556
# 129  echorep         Echo service reply
2557
# 133  routersol       Router solicitation
2558
# 134  routeradv       Router advertisement
2559
# 135  neighbrsol      Neighbor solicitation
2560
# 136  neighbradv      Neighbor advertisement
2561
pass quick inet6 proto ipv6-icmp from any to any icmp6-type {1,2,135,136} keep state
2562

    
2563
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
2564
pass out quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {129,133,134,135,136} keep state
2565
pass out quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {129,133,134,135,136} keep state
2566
pass in quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {128,133,134,135,136} keep state
2567
pass in quick inet6 proto ipv6-icmp from ff02::/16 to fe80::/10 icmp6-type {128,133,134,135,136} keep state
2568
pass in quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {128,133,134,135,136} keep state
2569

    
2570
# We use the mighty pf, we cannot be fooled.
2571
block quick inet proto { tcp, udp } from any port = 0 to any
2572
block quick inet proto { tcp, udp } from any to any port = 0
2573
block quick inet6 proto { tcp, udp } from any port = 0 to any
2574
block quick inet6 proto { tcp, udp } from any to any port = 0
2575

    
2576
# Snort package
2577
block quick from <snort2c> to any label "Block snort2c hosts"
2578
block quick from any to <snort2c> label "Block snort2c hosts"
2579

    
2580
EOD;
2581

    
2582
	$ipfrules .= filter_process_carp_rules($log);
2583

    
2584
	$ipfrules .= "\n# SSH lockout\n";
2585
	if(is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
2586
		$ipfrules .= "block in log quick proto tcp from <sshlockout> to (self) port ";
2587
		$ipfrules .= $config['system']['ssh']['port'];
2588
		$ipfrules .= " label \"sshlockout\"\n";
2589
	} else {
2590
		if($config['system']['ssh']['port'] <> "")
2591
			$sshport = $config['system']['ssh']['port'];
2592
		else
2593
			$sshport = 22;
2594
		if($sshport)
2595
			$ipfrules .= "block in log quick proto tcp from <sshlockout> to (self) port {$sshport} label \"sshlockout\"\n";
2596
	}
2597

    
2598
	$ipfrules .= "\n# webConfigurator lockout\n";
2599
	if(!$config['system']['webgui']['port']) {
2600
		if($config['system']['webgui']['protocol'] == "http")
2601
			$webConfiguratorlockoutport = "80";
2602
		else
2603
			$webConfiguratorlockoutport = "443";
2604
	} else {
2605
		$webConfiguratorlockoutport = $config['system']['webgui']['port'];
2606
	}
2607
	if($webConfiguratorlockoutport)
2608
		$ipfrules .= "block in log quick proto tcp from <webConfiguratorlockout> to (self) port {$webConfiguratorlockoutport} label \"webConfiguratorlockout\"\n";
2609

    
2610
	/*
2611
	 * Support for allow limiting of TCP connections by establishment rate
2612
	 * Useful for protecting against sudden outburts, etc.
2613
	 */
2614
	$ipfrules .= "block in quick from <virusprot> to any label \"virusprot overload table\"\n";
2615

    
2616
	/* if captive portal is enabled, ensure that access to this port
2617
	 * is allowed on a locked down interface
2618
	 */
2619
	if(is_array($config['captiveportal'])) {
2620
		foreach ($config['captiveportal'] as $cpcfg) {
2621
			if(!isset($cpcfg['enable']))
2622
				continue;
2623
			$cpinterfaces = explode(",", $cpcfg['interface']);
2624
			$cpiflist = array();
2625
			$cpiplist = array();
2626
			foreach ($cpinterfaces as $cpifgrp) {
2627
				if(!isset($FilterIflist[$cpifgrp]))
2628
					continue;
2629
				$tmpif = get_real_interface($cpifgrp);
2630
				if(!empty($tmpif)) {
2631
					$cpiflist[] = "{$tmpif}";
2632
					$cpipm = get_interface_ip($cpifgrp);
2633
					if(is_ipaddr($cpipm)) {
2634
						$carpif = link_ip_to_carp_interface($cpipm);
2635
						if (!empty($carpif)) {
2636
							$cpiflist[] = $carpif;
2637
							$carpsif = explode(" ", $carpif);
2638
							foreach ($carpsif as $cpcarp) {
2639
								$carpip = find_interface_ip($cpcarp);
2640
								if (is_ipaddr($carpip))
2641
									$cpiplist[] = $carpip;
2642
							}
2643
						}
2644
						$cpiplist[] = $cpipm;
2645
					}
2646
				}
2647
			}
2648
			if (count($cpiplist) > 0 && count($cpiflist) > 0) {
2649
				$cpinterface = implode(" ", $cpiflist);
2650
				$cpaddresses = implode(" ", $cpiplist);
2651
				$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
2652
				$listenporthttp  = $cpcfg['listenporthttp']  ? $cpcfg['listenporthttp']  : $cpcfg['zoneid'];
2653
				$portalias = $listenporthttps;
2654
				$portalias .= " {$listenporthttp}";
2655
				$ipfrules .= "pass in quick on { {$cpinterface} } proto tcp from any to { {$cpaddresses} } port { {$portalias} } keep state(sloppy)\n";
2656
				$ipfrules .= "pass out quick on { {$cpinterface} } proto tcp from any to any flags any keep state(sloppy)\n";
2657
			}
2658
		}
2659
	}
2660

    
2661
	$bogontableinstalled = 0;
2662
	foreach ($FilterIflist as $on => $oc) {
2663
		/* block bogon networks */
2664
		/* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
2665
		/* file is automatically in cron every 3000 minutes */
2666
		if(!isset($config['syslog']['nologbogons']))
2667
			$bogonlog = "log";
2668
		else
2669
			$bogonlog = "";
2670

    
2671
		if(isset($config['interfaces'][$on]['blockbogons'])) {
2672
			$ipfrules .= <<<EOD
2673
# block bogon networks (IPv4)
2674
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
2675
block in $bogonlog quick on \${$oc['descr']} from <bogons> to any label "{$fix_rule_label("block bogon IPv4 networks from {$oc['descr']}")}"
2676

    
2677
EOD;
2678
		}
2679

    
2680
		if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
2681
			$ipfrules .= <<<EOD
2682
# allow our DHCPv6 client out to the {$oc['descr']}
2683
pass in quick on \${$oc['descr']} proto udp from fe80::/10 port = 546 to fe80::/10 port = 546 label "{$fix_rule_label("allow dhcpv6 client in {$oc['descr']}")}"
2684
pass in quick on \${$oc['descr']} proto udp from any port = 547 to any port = 546 label "{$fix_rule_label("allow dhcpv6 client in {$oc['descr']}")}"
2685
pass out quick on \${$oc['descr']} proto udp from any port = 546 to any port = 547 label "{$fix_rule_label("allow dhcpv6 client out {$oc['descr']}")}"
2686

    
2687
EOD;
2688
		}
2689

    
2690
		if(isset($config['interfaces'][$on]['blockbogons']) && isset($config['system']['ipv6allow'])) {
2691
			$ipfrules .= <<<EOD
2692
# block bogon networks (IPv6)
2693
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
2694
block in $bogonlog quick on \${$oc['descr']} from <bogonsv6> to any label "{$fix_rule_label("block bogon IPv6 networks from {$oc['descr']}")}"
2695

    
2696
EOD;
2697
		}
2698

    
2699
		$isbridged = false;
2700
		if(is_array($config['bridges']['bridged'])) {
2701
			foreach ($config['bridges']['bridged'] as $oc2) {
2702
				if(stristr($oc2['members'], $on)) {
2703
					$isbridged = true;
2704
					break;
2705
				}
2706
			}
2707
		}
2708
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2709
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc['if'], $oc['sa'], $oc['sn'], $log);
2710
		/* block private networks ? */
2711
		if(!isset($config['syslog']['nologprivatenets']))
2712
			$privnetlog = "log";
2713
		else
2714
			$privnetlog = "";
2715

    
2716
		if(isset($config['interfaces'][$on]['blockpriv'])) {
2717
			if($isbridged == false) {
2718
				$ipfrules .= <<<EOD
2719
# block anything from private networks on interfaces with the option set
2720
antispoof for \${$oc['descr']}
2721
block in $privnetlog quick on \${$oc['descr']} from 10.0.0.0/8 to any label "{$fix_rule_label("Block private networks from {$oc['descr']} block 10/8")}"
2722
block in $privnetlog quick on \${$oc['descr']} from 127.0.0.0/8 to any label "{$fix_rule_label("Block private networks from {$oc['descr']} block 127/8")}"
2723
block in $privnetlog quick on \${$oc['descr']} from 100.64.0.0/10 to any label "{$fix_rule_label("Block private networks from {$oc['descr']} block 100.64/10")}"
2724
block in $privnetlog quick on \${$oc['descr']} from 172.16.0.0/12 to any label "{$fix_rule_label("Block private networks from {$oc['descr']} block 172.16/12")}"
2725
block in $privnetlog quick on \${$oc['descr']} from 192.168.0.0/16 to any label "{$fix_rule_label("Block private networks from {$oc['descr']} block 192.168/16")}"
2726
block in $privnetlog quick on \${$oc['descr']} from fc00::/7 to any label "{$fix_rule_label("Block ULA networks from {$oc['descr']} block fc00::/7")}"
2727

    
2728
EOD;
2729
			}
2730
		}
2731
		switch ($oc['type']) {
2732
		case "pptp":
2733
				$ipfrules .= <<<EOD
2734
# allow PPTP client
2735
pass in on \${$oc['descr']} proto tcp from any to any port = 1723 flags S/SA modulate state label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
2736
pass in on \${$oc['descr']} proto gre from any to any keep state label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
2737

    
2738
EOD;
2739
			break;
2740
		case "dhcp":
2741
			$ipfrules .= <<<EOD
2742
# allow our DHCP client out to the {$oc['descr']}
2743
pass in on \${$oc['descr']} proto udp from any port = 67 to any port = 68 label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
2744
pass out on \${$oc['descr']} proto udp from any port = 68 to any port = 67 label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
2745
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2746

    
2747
EOD;
2748

    
2749
			break;
2750
		case "pppoe":
2751
		case "none":
2752
			/* XXX: Nothing to do in this case?! */
2753
			break;
2754
		default:
2755
			/* allow access to DHCP server on interfaces */
2756
			if(isset($config['dhcpd'][$on]['enable'])) {
2757
				$ipfrules .= <<<EOD
2758
# allow access to DHCP server on {$oc['descr']}
2759
pass in quick on \${$oc['descr']} proto udp from any port = 68 to 255.255.255.255 port = 67 label "allow access to DHCP server"
2760

    
2761
EOD;
2762
				if (is_ipaddrv4($oc['ip'])) {
2763
					$ipfrules .= <<<EOD
2764
pass in quick on \${$oc['descr']} proto udp from any port = 68 to {$oc['ip']} port = 67 label "allow access to DHCP server"
2765
pass out quick on \${$oc['descr']} proto udp from {$oc['ip']} port = 67 to any port = 68 label "allow access to DHCP server"
2766

    
2767
EOD;
2768
				}
2769

    
2770
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2771
					$ipfrules .= <<<EOD
2772
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2773
pass in quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 519 label "allow access to DHCP failover"
2774
pass in quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 520 label "allow access to DHCP failover"
2775

    
2776
EOD;
2777
				}
2778

    
2779
			}
2780
			break;
2781
		}
2782
		switch($oc['type6']) {
2783
		case "6rd":
2784
			$ipfrules .= <<<EOD
2785
# allow our proto 41 traffic from the 6RD border relay in
2786
pass in on \${$oc['descr']} proto 41 from {$config['interfaces'][$on]['gateway-6rd']} to any label "{$fix_rule_label("Allow 6in4 traffic in for 6rd on {$oc['descr']}")}"
2787
pass out on \${$oc['descr']} proto 41 from any to {$config['interfaces'][$on]['gateway-6rd']} label "{$fix_rule_label("Allow 6in4 traffic out for 6rd on {$oc['descr']}")}"
2788

    
2789
EOD;
2790
		/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
2791
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2792
			$ipfrules .= <<<EOD
2793
pass in on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} label "{$fix_rule_label("Allow 6rd traffic in for 6rd on {$oc['descr']}")}"
2794
pass out on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any label "{$fix_rule_label("Allow 6rd traffic out for 6rd on {$oc['descr']}")}"
2795

    
2796
EOD;
2797
		}
2798
			break;
2799
		case "6to4":
2800
			if (is_ipaddrv4($oc['ip'])) {
2801
			$ipfrules .= <<<EOD
2802
# allow our proto 41 traffic from the 6to4 border relay in
2803
pass in on \${$oc['descr']} proto 41 from any to {$oc['ip']} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
2804
pass out on \${$oc['descr']} proto 41 from {$oc['ip']} to any label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
2805

    
2806
EOD;
2807
		}
2808
		/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
2809
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2810
			$ipfrules .= <<<EOD
2811
pass in on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
2812
pass out on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
2813

    
2814
EOD;
2815
		}
2816
			break;
2817
		default:
2818
			if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface']) 
2819
				|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
2820
				$ipfrules .= <<<EOD
2821
# allow access to DHCPv6 server on {$oc['descr']}
2822
# We need inet6 icmp for stateless autoconfig and dhcpv6
2823
pass quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to fe80::/10 port = 546 label "allow access to DHCPv6 server"
2824
pass quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 546 label "allow access to DHCPv6 server"
2825
pass quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 547 label "allow access to DHCPv6 server"
2826
pass quick on \${$oc['descr']} inet6 proto udp from ff02::/16 to fe80::/10 port = 547 label "allow access to DHCPv6 server"
2827

    
2828
EOD;
2829
				if (is_ipaddrv6($oc['ipv6'])) {
2830
					$ipfrules .= <<<EOD
2831
pass in quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to {$oc['ipv6']} port = 546 label "allow access to DHCPv6 server"
2832
pass out quick on \${$oc['descr']} inet6 proto udp from {$oc['ipv6']} port = 547 to fe80::/10 label "allow access to DHCPv6 server"
2833

    
2834
EOD;
2835
				}
2836
			}
2837
			break;
2838
		}
2839
	}
2840
	/*
2841
	 * NB: The loopback rules are needed here since the antispoof would take precedence then.
2842
	 *	If you ever add the 'quick' keyword to the antispoof rules above move the looback
2843
	 *	rules before them.
2844
	 */
2845
	$ipfrules .= <<<EOD
2846

    
2847
# loopback
2848
pass in on \$loopback inet all label "pass IPv4 loopback"
2849
pass out on \$loopback inet all label "pass IPv4 loopback"
2850
pass in on \$loopback inet6 all label "pass IPv6 loopback"
2851
pass out on \$loopback inet6 all label "pass IPv6 loopback"
2852

    
2853
EOD;
2854

    
2855
	$ipfrules .= <<<EOD
2856
# let out anything from the firewall host itself and decrypted IPsec traffic
2857
pass out inet all keep state allow-opts label "let out anything IPv4 from firewall host itself"
2858
pass out inet6 all keep state allow-opts label "let out anything IPv6 from firewall host itself"
2859

    
2860
EOD;
2861

    
2862
	foreach ($FilterIflist as $ifdescr => $ifcfg) {
2863
		if(isset($ifcfg['virtual']))
2864
			continue;
2865

    
2866
		$gw = get_interface_gateway($ifdescr);
2867
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
2868
			$ipfrules .= "pass out route-to ( {$ifcfg['if']} {$gw} ) from {$ifcfg['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} keep state allow-opts label \"let out anything from firewall host itself\"\n";
2869
			if (is_array($ifcfg['vips'])) {
2870
				foreach ($ifcfg['vips'] as $vip)
2871
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
2872
						$ipfrules .= "pass out route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} keep state allow-opts label \"let out anything from firewall host itself\"\n";
2873
					else
2874
						$ipfrules .= "pass out route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !" . gen_subnet($vip['ip'], $vip['sn']) . "/{$vip['sn']} keep state allow-opts label \"let out anything from firewall host itself\"\n";
2875
			}
2876
		}
2877

    
2878
		$gwv6 = get_interface_gateway_v6($ifdescr);
2879
		$stf = get_real_interface($ifdescr, "inet6");
2880
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
2881
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
2882
			$ipfrules .= "pass out route-to ( {$stf} {$gwv6} ) inet6 from {$ifcfg['ipv6']} to !{$ifcfg['ipv6']}/{$pdlen} keep state allow-opts label \"let out anything from firewall host itself\"\n";
2883
			if (is_array($ifcfg['vips6'])) {
2884
				foreach ($ifcfg['vips6'] as $vip)
2885
					$ipfrules .= "pass out route-to ( {$stf} {$gwv6} ) inet6 from {$vip['ip']} to !{$vip['ip']}/{$pdlen} keep state allow-opts label \"let out anything from firewall host itself\"\n";
2886
			}
2887
		}
2888
	}
2889

    
2890

    
2891
	/* add ipsec interfaces */
2892
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
2893
		$ipfrules .= "pass out on \$IPsec all keep state label \"IPsec internal host to host\"\n";
2894

    
2895
	if(is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
2896
		$alports = filter_get_antilockout_ports();
2897

    
2898
		if(count($config['interfaces']) > 1 && !empty($FilterIflist['lan']['if'])) {
2899
				/* if antilockout is enabled, LAN exists and has
2900
				 * an IP and subnet mask assigned
2901
				 */
2902
				$lanif = $FilterIflist['lan']['if'];
2903
				$ipfrules .= <<<EOD
2904
# make sure the user cannot lock himself out of the webConfigurator or SSH
2905
pass in quick on {$lanif} proto tcp from any to ({$lanif}) port { {$alports} } keep state label "anti-lockout rule"
2906

    
2907
EOD;
2908
		} else if (count($config['interfaces']) == 1) {
2909
			/* single-interface deployment, add to WAN	*/
2910
			$wanif = $FilterIflist["wan"]['if'];
2911
			$ipfrules .= <<<EOD
2912
# make sure the user cannot lock himself out of the webConfigurator or SSH
2913
pass in quick on {$wanif} proto tcp from any to ({$wanif}) port { {$alports} } keep state label "anti-lockout rule"
2914

    
2915
EOD;
2916
		}
2917
		unset($alports);
2918
	}
2919

    
2920
	/* PPTPd enabled? */
2921
	if($pptpdcfg['mode'] && ($pptpdcfg['mode'] != "off") && !isset($config['system']['disablevpnrules'])) {
2922
		if($pptpdcfg['mode'] == "server")
2923
			$pptpdtarget = get_interface_ip();
2924
		else
2925
			$pptpdtarget = $pptpdcfg['redir'];
2926
		if(is_ipaddr($pptpdtarget) and is_array($FilterIflist['wan'])) {
2927
			$ipfrules .= <<<EOD
2928
# PPTPd rules
2929
pass in on \${$FilterIflist['wan']['descr']} proto tcp from any to $pptpdtarget port = 1723 modulate state label "{$fix_rule_label("allow pptpd {$pptpdtarget}")}"
2930
pass in on \${$FilterIflist['wan']['descr']} proto gre from any to any keep state label "allow gre pptpd"
2931

    
2932
EOD;
2933

    
2934
		} else {
2935
			/*	  this shouldnt ever happen but instead of breaking the clients ruleset
2936
			 *	  log an error.
2937
			 */
2938
			log_error("ERROR!  PPTP enabled but could not resolve the \$pptpdtarget");
2939
		}
2940
	}
2941

    
2942
	if(isset($config['nat']['rule']) && is_array($config['nat']['rule'])) {
2943
		foreach ($config['nat']['rule'] as $rule) {
2944
			if((!isset($config['system']['disablenatreflection']) || $rule['natreflection'] == "enable")
2945
			   && $rule['natreflection'] != "disable") {
2946
				$ipfrules .= "# NAT Reflection rules\n";
2947
				$ipfrules .= <<<EOD
2948
pass in inet tagged PFREFLECT keep state label "NAT REFLECT: Allow traffic to localhost"
2949

    
2950
EOD;
2951
				break;
2952
			}
2953
		}
2954
	}
2955

    
2956
	if (isset($config['filter']['rule'])) {
2957
		/* Pre-cache all our rules so we only have to generate them once */
2958
		$rule_arr1 = array();
2959
		$rule_arr2 = array();
2960
		$rule_arr3 = array();
2961
		$vpn_and_ppp_ifs = array("l2tp", "pptp", "pppoe", "enc0", "openvpn");
2962
		/*
2963
		 * NB: The order must be: Floating rules, then interface group and then regular ones.
2964
		 */
2965
		foreach ($config['filter']['rule'] as $rule) {
2966
			update_filter_reload_status("Pre-caching {$rule['descr']}...");
2967
			if (isset ($rule['disabled']))
2968
				continue;
2969

    
2970
			if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
2971
				if (isset($rule['floating'])) {
2972
					$rule['ipprotocol'] = "inet";
2973
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
2974
					$rule['ipprotocol'] = "inet6";
2975
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
2976
				} else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
2977
					$rule['ipprotocol'] = "inet";
2978
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
2979
					$rule['ipprotocol'] = "inet6";
2980
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
2981
				} else {
2982
					$rule['ipprotocol'] = "inet";
2983
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
2984
					$rule['ipprotocol'] = "inet6";
2985
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
2986
				}
2987
				$rule['ipprotocol'] = "inet46";
2988
			} else {
2989
				if (isset($rule['floating']))
2990
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
2991
				else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs))
2992
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
2993
				else
2994
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
2995
			}
2996
			if ($rule['sched'])
2997
				$time_based_rules = true;
2998
		}
2999

    
3000
		$ipfrules .= "\n# User-defined rules follow\n";
3001
		$ipfrules .= "\nanchor \"userrules/*\"\n";
3002
		/* Generate user rule lines */
3003
		foreach($rule_arr1 as $rule) {
3004
			if (isset($rule['disabled']))
3005
				continue;
3006
			if (!$rule['rule'])
3007
				continue;
3008
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3009
		}
3010
		foreach($rule_arr2 as $rule) {
3011
			if (isset($rule['disabled']))
3012
				continue;
3013
			if (!$rule['rule'])
3014
				continue;
3015
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3016
		}
3017
		foreach($rule_arr3 as $rule) {
3018
			if (isset($rule['disabled']))
3019
				continue;
3020
			if (!$rule['rule'])
3021
				continue;
3022
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3023
		}
3024
		unset($rule_arr1, $rule_arr2, $rule_arr3);
3025
	}
3026

    
3027
	/*  pass traffic between statically routed subnets and the subnet on the
3028
	 *  interface in question to avoid problems with complicated routing
3029
	 *  topologies
3030
	 */
3031
	if(isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
3032
		$ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
3033
		foreach (get_staticroutes() as $route) {
3034
			$friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
3035
			if(is_array($FilterIflist[$friendly])) {
3036
				$oc = $FilterIflist[$friendly];
3037
				$routeent = explode("/", $route['network']);
3038
				unset($sa);
3039
				if (is_ipaddrv4($oc['ip'])) {
3040
					$sa = $oc['sa'];
3041
					$sn = $oc['sn'];
3042
				}
3043
				if ($sa && is_ipaddrv4($routeent[0])) {
3044
					$ipfrules .= <<<EOD
3045
pass quick on \${$oc['descr']} proto tcp from {$sa}/{$sn} to {$route['network']} flags any keep state(sloppy) label "pass traffic between statically routed subnets"
3046
pass quick on \${$oc['descr']} from {$sa}/{$sn} to {$route['network']} keep state(sloppy) label "pass traffic between statically routed subnets"
3047
pass quick on \${$oc['descr']} proto tcp from {$route['network']} to {$sa}/{$sn} flags any keep state(sloppy) label "pass traffic between statically routed subnets"
3048
pass quick on \${$oc['descr']} from {$route['network']} to {$sa}/{$sn} keep state(sloppy) label "pass traffic between statically routed subnets"
3049

    
3050
EOD;
3051
				}
3052
				unset($sa);
3053
				if (is_ipaddrv6($oc['ipv6'])) {
3054
					$sa = $oc['sav6'];
3055
					$sn = $oc['snv6'];
3056
				}
3057
				if ($sa && is_ipaddrv6($routeent[0])) {
3058
					$ipfrules .= <<<EOD
3059
pass quick on \${$oc['descr']} inet6 proto tcp from {$sa}/{$sn} to {$route['network']} flags any keep state(sloppy) label "pass traffic between statically routed subnets"
3060
pass quick on \${$oc['descr']} inet6 from {$sa}/{$sn} to {$route['network']} keep state(sloppy) label "pass traffic between statically routed subnets"
3061
pass quick on \${$oc['descr']} inet6 proto tcp from {$route['network']} to {$sa}/{$sn} flags any keep state(sloppy) label "pass traffic between statically routed subnets"
3062
pass quick on \${$oc['descr']} inet6 from {$route['network']} to {$sa}/{$sn} keep state(sloppy) label "pass traffic between statically routed subnets"
3063

    
3064
EOD;
3065
				}
3066
			}
3067
		}
3068
	}
3069

    
3070
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3071
	$ipfrules .= filter_generate_ipsec_rules();
3072

    
3073
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3074

    
3075
	update_filter_reload_status("Creating uPNP rules...");
3076
	if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
3077
		if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable']))
3078
			$ipfrules .= "anchor \"miniupnpd\"\n";
3079

    
3080
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3081
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3082
			foreach($upnp_interfaces as $upnp_if) {
3083
				if (is_array($FilterIflist[$upnp_if])) {
3084
					$oc = $FilterIflist[$upnp_if];
3085
					unset($sa);
3086
					if($oc['ip']) {
3087
						$sa = $oc['sa'];
3088
						$sn = $oc['sn'];
3089
					}
3090
					if($sa) {
3091
						$ipfrules .= <<<EOD
3092
pass in on \${$oc['descr']} proto tcp from {$sa}/{$sn} to 239.255.255.250/32 port 1900 keep state label "pass multicast traffic to miniupnpd"
3093

    
3094
EOD;
3095
					}
3096
				}
3097
			}
3098
		}
3099
	}
3100

    
3101

    
3102
	return $ipfrules;
3103
}
3104

    
3105
function filter_rules_spoofcheck_generate($ifname, $if, $sa, $sn, $log) {
3106
	global $g, $config;
3107
	if(isset($config['system']['developerspew'])) {
3108
		$mt = microtime();
3109
		echo "filter_rules_spoofcheck_generate() being called $mt\n";
3110
	}
3111
	$ipfrules = "antispoof for {$if}\n";
3112
	return $ipfrules;
3113
}
3114

    
3115
/* COMPAT Function */
3116
function tdr_install_cron($should_install) {
3117
	log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
3118
	filter_tdr_install_cron($should_install);
3119
}
3120

    
3121
/****f* filter/filter_tdr_install_cron
3122
 * NAME
3123
 *   filter_tdr_install_cron
3124
 * INPUTS
3125
 *   $should_install true if the cron entry should be installed, false
3126
 *   if the entry should be removed if it is present
3127
 * RESULT
3128
 *   none
3129
 ******/
3130
function filter_tdr_install_cron($should_install) {
3131
	global $config, $g;
3132

    
3133
	if($g['booting']==true)
3134
		return;
3135

    
3136
	if (!is_array($config['cron']))
3137
		$config['cron'] = array();
3138
	if (!is_array($config['cron']['item']))
3139
		$config['cron']['item'] = array();
3140

    
3141
	$x=0;
3142
	$is_installed = false;
3143
	foreach($config['cron']['item'] as $item) {
3144
		if (strstr($item['command'], "filter_configure_sync")) {
3145
			$is_installed = true;
3146
			break;
3147
		}
3148
		$x++;
3149
	}
3150

    
3151
	switch($should_install) {
3152
		case true:
3153
			if (!$is_installed) {
3154
				$cron_item = array();
3155
				$cron_item['minute'] = "0,15,30,45";
3156
				$cron_item['hour'] = "*";
3157
				$cron_item['mday'] = "*";
3158
				$cron_item['month'] = "*";
3159
				$cron_item['wday'] = "*";
3160
				$cron_item['who'] = "root";
3161
				$cron_item['command'] = "/etc/rc.filter_configure_sync";
3162
				$config['cron']['item'][] = $cron_item;
3163
				write_config(gettext("Installed 15 minute filter reload for Time Based Rules"));
3164
				configure_cron();
3165
			}
3166
			break;
3167
		case false:
3168
			if ($is_installed == true) {
3169
				unset($config['cron']['item'][$x]);
3170
				write_config(gettext("Removed 15 minute filter reload for Time Based Rules"));
3171
				configure_cron();
3172
			}
3173
			break;
3174
	}
3175
}
3176

    
3177
/****f* filter/filter_get_time_based_rule_status
3178
 * NAME
3179
 *   filter_get_time_based_rule_status
3180
 * INPUTS
3181
 *   xml schedule block
3182
 * RESULT
3183
 *   true/false - true if the rule should be installed
3184
 ******/
3185
/*
3186
 <schedules>
3187
   <schedule>
3188
     <name>ScheduleMultipleTime</name>
3189
     <descr>main descr</descr>
3190
     <time>
3191
       <position>0,1,2</position>
3192
       <hour>0:0-24:0</hour>
3193
       <desc>time range 2</desc>
3194
     </time>
3195
     <time>
3196
       <position>4,5,6</position>
3197
       <hour>0:0-24:0</hour>
3198
       <desc>time range 1</desc>
3199
     </time>
3200
   </schedule>
3201
 </schedules>
3202
*/
3203
function filter_get_time_based_rule_status($schedule) {
3204

    
3205
	/* no schedule? rule should be installed */
3206
	if (empty($schedule))
3207
		return true;
3208
	/*
3209
	 * iterate through time blocks and determine
3210
	 * if the rule should be installed or not.
3211
	 */
3212
	foreach($schedule['timerange'] as $timeday) {
3213
		if (empty($timeday['month']))
3214
			$monthstatus = true;
3215
		else
3216
			$monthstatus = filter_tdr_month($timeday['month']);
3217
		if (empty($timeday['day']))
3218
			$daystatus = true;
3219
		else
3220
			$daystatus = filter_tdr_day($timeday['day']);
3221
		if (empty($timeday['hour']))
3222
			$hourstatus = true;
3223
		else
3224
			$hourstatus = filter_tdr_hour($timeday['hour']);
3225
		if (empty($timeday['position']))
3226
			$positionstatus = true;
3227
		else
3228
			$positionstatus = filter_tdr_position($timeday['position']);
3229

    
3230
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3231
			return true;
3232
	}
3233

    
3234
	return false;
3235
}
3236

    
3237
function filter_tdr_day($schedule) {
3238
	global $g;
3239

    
3240
	if($g['debug'])
3241
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3242

    
3243
	/*
3244
	 * Calculate day of month.
3245
	 * IE: 29th of may
3246
	 */
3247
	$date = date("d");
3248
	$defined_days = explode(",", $schedule);
3249
	foreach($defined_days as $dd) {
3250
		if ($date == $dd)
3251
			return true;
3252
	}
3253
	return false;
3254
}
3255
function filter_tdr_hour($schedule) {
3256
	global $g;
3257

    
3258
	/* $schedule should be a string such as 16:00-19:00 */
3259
	$tmp = explode("-", $schedule);
3260
	$starting_time = strtotime($tmp[0]);
3261
	$ending_time = strtotime($tmp[1]);
3262
	$now = strtotime("now");
3263
	if($g['debug'])
3264
		log_error("[TDR DEBUG] S: $starting_time E: $ending_time N: $now");
3265
	if($now >= $starting_time and $now <= $ending_time)
3266
		return true;
3267
	return false;
3268
}
3269

    
3270
function filter_tdr_position($schedule) {
3271
	global $g;
3272

    
3273
	/*
3274
	 * Calculate position, ie: day of week.
3275
	 * Sunday = 7, Monday = 1, Tuesday = 2
3276
	 * Weds = 3, Thursday = 4, Friday = 5,
3277
	 * Saturday = 6
3278
	 * ...
3279
	 */
3280
	$weekday = date("w");
3281
	if($g['debug'])
3282
		log_error("[TDR DEBUG] filter_tdr_position($schedule) $weekday");
3283
	if($weekday == 0)
3284
		$weekday = 7;
3285
	$schedule_days = explode(",", $schedule);
3286
	foreach($schedule_days as $day) {
3287
		if($day == $weekday)
3288
			return true;
3289
	}
3290
	return false;
3291
}
3292

    
3293
function filter_tdr_month($schedule) {
3294
	global $g;
3295

    
3296
	/*
3297
	 * Calculate month
3298
	 */
3299
	$todays_month = date("n");
3300
	$months = explode(",", $schedule);
3301
	if($g['debug'])
3302
		log_error("[TDR DEBUG] filter_tdr_month($schedule)");
3303
	foreach($months as $month) {
3304
		if($month == $todays_month)
3305
			return true;
3306
	}
3307
	return false;
3308
}
3309

    
3310
function filter_setup_logging_interfaces() {
3311
	global $config, $FilterIflist;
3312

    
3313
	if(isset($config['system']['developerspew'])) {
3314
		$mt = microtime();
3315
		echo "filter_setup_logging_interfaces() being called $mt\n";
3316
	}
3317
	$rules = "";
3318
	if (isset($FilterIflist['lan']))
3319
		$rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
3320
	else if (isset($FilterIflist['wan']))
3321
		$rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
3322

    
3323
	return $rules;
3324
}
3325

    
3326
function filter_process_carp_rules($log) {
3327
	global $g, $config;
3328

    
3329
	if(isset($config['system']['developerspew'])) {
3330
		$mt = microtime();
3331
		echo "filter_process_carp_rules($log) being called $mt\n";
3332
	}
3333
	$lines = "";
3334
	/* return if there are no carp configured items */
3335
	if (!empty($config['hasync']) or !empty($config['virtualip']['vip'])) {
3336
		$lines .= "block in $log quick proto carp from (self) to any\n";
3337
		$lines .= "pass quick proto carp\n";
3338
	}
3339
	return $lines;
3340
}
3341

    
3342
/* Generate IPSEC Filter Items */
3343
function filter_generate_ipsec_rules() {
3344
	global $config, $g, $FilterIflist;
3345

    
3346
	if(isset($config['system']['developerspew'])) {
3347
		$mt = microtime();
3348
		echo "filter_generate_ipsec_rules() being called $mt\n";
3349
	}
3350

    
3351
	if (isset($config['system']['disablevpnrules']))
3352
		return "\n# VPN Rules not added disabled in System->Advanced.\n";
3353

    
3354
	$ipfrules = "\n# VPN Rules\n";
3355
	/* Is IP Compression enabled? */
3356
	if(isset($config['ipsec']['ipcomp']))
3357
		exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=1");
3358
	else
3359
		exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=0");
3360

    
3361
	if(isset($config['ipsec']['enable']) &&
3362
		is_array($config['ipsec']['phase1'])) {
3363
		/* step through all phase1 entries */
3364
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
3365
			if(isset ($ph1ent['disabled']))
3366
				continue;
3367
			/* determine local and remote peer addresses */
3368
			if(!isset($ph1ent['mobile'])) {
3369
				if (!function_exists('ipsec_get_phase1_dst'))
3370
					require_once("ipsec.inc");
3371
				$rgip = ipsec_get_phase1_dst($ph1ent);
3372
				if(!$rgip) {
3373
					$ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n";
3374
					continue;
3375
				}
3376
			} else
3377
				$rgip = " any ";
3378
			/* Determine best description */
3379
			if($ph1ent['descr'])
3380
				$descr = $ph1ent['descr'];
3381
			else
3382
				$descr = $rgip;
3383
			/*
3384
			 * Step through all phase2 entries and determine
3385
			 * which protocols are in use with this peer
3386
			 */
3387
			$prot_used_esp = false;
3388
			$prot_used_ah  = false;
3389
			if(is_array($config['ipsec']['phase2'])) {
3390
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
3391
					/* only evaluate ph2's bound to our ph1 */
3392
					if($ph2ent['ikeid'] != $ph1ent['ikeid'])
3393
						continue;
3394
					if($ph2ent['protocol'] == 'esp')
3395
						$prot_used_esp = true;
3396
					if($ph2ent['protocol'] == 'ah')
3397
						$prot_used_ah = true;
3398
				}
3399
			}
3400

    
3401
			if(preg_match("/^[a-z0-9]+_vip/i", $ph1ent['interface'])) {
3402
				$parentinterface = link_carp_interface_to_parent($ph1ent['interface']);
3403
			} else {
3404
				$parentinterface = $ph1ent['interface'];
3405
			}
3406
			if (empty($FilterIflist[$parentinterface]['descr'])) {
3407
				$ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
3408
				continue;
3409
			}
3410

    
3411
			unset($gateway);
3412
			/* add endpoint routes to correct gateway on interface */
3413
			if((is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
3414
				$gateway = get_interface_gateway($parentinterface);
3415
				$interface = $FilterIflist[$parentinterface]['if'];
3416

    
3417
				$route_to = " route-to ( $interface $gateway ) ";
3418
				$reply_to = " reply-to ( $interface $gateway ) ";
3419

    
3420
			}
3421
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3422
				$gateway = get_interface_gateway_v6($parentinterface);
3423
				$interface = $FilterIflist[$parentinterface]['if'];
3424

    
3425
				$route_to = " route-to ( $interface $gateway ) ";
3426
				$reply_to = " reply-to ( $interface $gateway ) ";
3427
			}
3428

    
3429
			/* Just in case */
3430
			if((!is_ipaddr($gateway) || empty($interface))) {
3431
				$route_to = " ";
3432
				$reply_to = " ";
3433
			}
3434

    
3435
			/* Add rules to allow IKE to pass */
3436
			$shorttunneldescr = substr($descr, 0, 35);
3437
				$ipfrules .= <<<EOD
3438
pass out on \${$FilterIflist[$parentinterface]['descr']} $route_to proto udp from any to {$rgip} port = 500 keep state label "IPsec: {$shorttunneldescr} - outbound isakmp"
3439
pass in on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto udp from {$rgip} to any port = 500 keep state label "IPsec: {$shorttunneldescr} - inbound isakmp"
3440

    
3441
EOD;
3442
			/* If NAT-T is enabled, add additional rules */
3443
			if($ph1ent['nat_traversal'] != "off" ) {
3444
				$ipfrules .= <<<EOD
3445
pass out on \${$FilterIflist[$parentinterface]['descr']} $route_to proto udp from any to {$rgip} port = 4500 keep state label "IPsec: {$shorttunneldescr} - outbound nat-t"
3446
pass in on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto udp from {$rgip} to any port = 4500 keep state label "IPsec: {$shorttunneldescr} - inbound nat-t"
3447

    
3448
EOD;
3449
			}
3450
			/* Add rules to allow the protocols in use */
3451
			if($prot_used_esp == true) {
3452
				$ipfrules .= <<<EOD
3453
pass out on \${$FilterIflist[$parentinterface]['descr']} $route_to proto esp from any to {$rgip} keep state label "IPsec: {$shorttunneldescr} - outbound esp proto"
3454
pass in on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto esp from {$rgip} to any keep state label "IPsec: {$shorttunneldescr} - inbound esp proto"
3455

    
3456
EOD;
3457
			}
3458
			if($prot_used_ah == true) {
3459
				$ipfrules .= <<<EOD
3460
pass out on \${$FilterIflist[$parentinterface]['descr']} $route_to proto ah from any to {$rgip} keep state label "IPsec: {$shorttunneldescr} - outbound ah proto"
3461
pass in on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto ah from {$rgip} to any keep state label "IPsec: {$shorttunneldescr} - inbound ah proto"
3462

    
3463
EOD;
3464
			}
3465
		}
3466

    
3467
	}
3468
	return($ipfrules);
3469
}
3470

    
3471
function discover_pkg_rules($ruletype) {
3472
	global $config, $g, $aliases;
3473

    
3474
	/* Bail if there is no pkg directory, or if the package files might be out of sync. */
3475
	if(!is_dir("/usr/local/pkg") || file_exists('/conf/needs_package_sync'))
3476
		return "";
3477

    
3478
	$rules = "";
3479
	$files = glob("/usr/local/pkg/*.inc");
3480
	foreach($files as $pkg_inc) {
3481
		update_filter_reload_status(sprintf(gettext('Checking for %1$s PF hooks in package %2$s'), $ruletype, $pkg_inc));
3482
		$pkg = basename($pkg_inc, ".inc");
3483
		$pkg_generate_rules = "{$pkg}_generate_rules";
3484
		if (!function_exists($pkg_generate_rules))
3485
			require_once($pkg_inc);
3486
		if(function_exists($pkg_generate_rules)) {
3487
			update_filter_reload_status(sprintf(gettext('Processing early %1$s rules for package %2$s'), $ruletype, $pkg_inc));
3488
			$tmprules = $pkg_generate_rules("$ruletype");
3489
			file_put_contents("{$g['tmp_path']}/rules.test.packages", $aliases . $tmprules);
3490
			$status = mwexec("/sbin/pfctl -nf {$g['tmp_path']}/rules.test.packages");
3491
			if ($status <> 0) {
3492
				$errorrules = sprintf(gettext("There was an error while parsing the package filter rules for %s."), $pkg_inc) . "\n";
3493
				log_error($errorrules);
3494
				file_put_contents("{$g['tmp_path']}/rules.packages.{$pkg}", "#{$errorrules}\n{$tmprules}\n");
3495
				continue;
3496
			}
3497
			$rules .= $tmprules;
3498
		}
3499
	}
3500
	return $rules;
3501
}
3502

    
3503
function filter_get_antilockout_ports($wantarray = false) {
3504
	global $config;
3505
	$lockoutports = array();
3506
	$guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
3507
	$guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
3508
	$lockoutports[] = $guiport;
3509

    
3510
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3511
		$lockoutports[] = "80";
3512

    
3513
	if (isset($config['system']['enablesshd']))
3514
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3515

    
3516
	if ($wantarray)
3517
		return $lockoutports;
3518
	else
3519
		return implode(" ", $lockoutports);
3520

    
3521
}
3522

    
3523
?>
(19-19/66)