Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ a43c5bde

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
global $tracker;
62
$tracker = 1000000000;
63

    
64
function filter_rule_tracker($tracker) {
65
	global $tracker;
66

    
67
	return (++$tracker);
68

    
69
}
70

    
71
function fix_rule_label($descr) {
72
	$descr = str_replace('"', '', $descr);
73
	if (strlen($descr) > 63)
74
		return substr($descr, 0, 60) . "...";
75
	else
76
		return $descr;
77
}
78

    
79
function is_bogonsv6_used() {
80
	global $config, $g;
81
	# Only use bogonsv6 table if IPv6 Allow is on, and at least 1 enabled interface also has "blockbogons" enabled.
82
	$usebogonsv6 = false;
83
	if (isset($config['system']['ipv6allow'])) {
84
		foreach ($config['interfaces'] as $ifacedata) {
85
			if(isset($ifacedata['enable']) && isset($ifacedata['blockbogons'])) {
86
				$usebogonsv6 = true;
87
				break;
88
			}
89
		}
90
	}
91
	return $usebogonsv6;
92
}
93

    
94
function flowtable_configure() {
95
	global $config, $g;
96

    
97
	if (empty($config['system']['flowtable'])) {
98
		mwexec("/sbin/sysctl net.inet.flowtable.enable=0", true);
99
		return;
100
	}
101

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

    
119
function filter_pflog_start($kill_first = false) {
120
	global $config, $g;
121
	if ($g['platform'] == 'jail')
122
		return;
123
	if(isset($config['system']['developerspew'])) {
124
		$mt = microtime();
125
		echo "filter_pflog_start() being called $mt\n";
126
	}
127
	if (!file_exists("{$g['varrun_path']}/filterlog.pid") ||
128
	    !isvalidpid("{$g['varrun_path']}/filterlog.pid"))
129
		mwexec("/usr/local/sbin/filterlog -i pflog0 -p {$g['varrun_path']}/filterlog.pid");
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
	/* User defined maximum table entries in Advanced menu. */
246
	if ($config['system']['maximumtableentries'] <> "" && is_numeric($config['system']['maximumtableentries']))
247
		$limitrules .= "set limit table-entries {$config['system']['maximumtableentries']}\n";
248

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

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

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

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

    
275
	// Configure flowtable support if enabled.
276
	flowtable_configure();
277

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

    
295
	unset($aliases, $gateways, $altq_queues, $natrules, $pfrules);
296

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

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

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

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

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

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

    
352
	# 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).
353
	if (!is_bogonsv6_used())
354
		$_grbg = exec("/sbin/pfctl -t bogonsv6 -T kill 2>/dev/null");
355

    
356
	update_filter_reload_status(gettext("Starting up layer7 daemon"));
357
	layer7_start_l7daemon();
358

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

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

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

    
397
		fclose($fda);
398
	}
399

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

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

    
411
	if($g['booting'] == true)
412
		echo ".";
413

    
414
	if($delete_states_if_needed) {
415
		update_filter_reload_status(gettext("Processing down interface states"));
416
		filter_delete_states_for_down_gateways();
417
	}
418

    
419
	update_filter_reload_status(gettext("Running plugins"));
420

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

    
428
	update_filter_reload_status(gettext("Done"));
429
	if($g['booting'] == true)
430
		echo gettext("done.") . "\n";
431

    
432
	unlock($filterlck);
433
	return 0;
434
}
435

    
436
function filter_generate_scrubing() {
437
	global $config, $FilterIflist;
438
	$scrubrules = "";
439

    
440
	if (isset($config['system']['maxmss_enable'])) {
441
		$maxmss = 1400;
442
		if (!empty($config['system']['maxmss']))
443
			$maxmss = $config['system']['maxmss'];
444

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

    
474
function filter_generate_nested_alias($name, $alias, &$aliasnesting, &$aliasaddrnesting) {
475
	global $aliastable, $filterdns;
476

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

    
526
function filter_expand_alias($alias_name)
527
{
528
	global $config;
529

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

    
541
function filter_expand_alias_array($alias_name) {
542
	$expansion = filter_expand_alias($alias_name);
543
	return explode(" ", preg_replace('/\s+/', ' ', trim($expansion)));
544
}
545

    
546
function filter_generate_aliases() {
547
	global $config, $FilterIflist, $after_filter_configure_run;
548

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

    
554
	$alias = "#System aliases\n ";
555
	$aliases = "loopback = \"{ lo0 }\"\n";
556

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

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

    
583
	$aliases .= "\n#SSH Lockout Table\n";
584
	$aliases .= "table <sshlockout> persist\n";
585
	$aliases .= "table <webConfiguratorlockout> persist\n";
586

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

    
598
	$vpns_list = filter_get_vpns_list();
599
	if($vpns_list)
600
		$aliases .= "table <vpn_networks> { $vpns_list }\n";
601

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

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

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

    
683
	return $result;
684
}
685

    
686
function filter_generate_gateways() {
687
	global $config, $g, $GatewaysList;
688

    
689
	$rules = "# Gateways\n";
690

    
691
	update_filter_reload_status(gettext("Creating gateway group item..."));
692

    
693
	/* Lookup Gateways to be used in filter rules once */
694
	$GatewaysList = return_gateways_array();
695
	$GatewayGroupsList = return_gateway_groups_array();
696

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

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

    
752
	/* Create a global array to avoid errors on rulesets. */
753
	$GatewaysList = $GatewaysList + $GatewayGroupsList;
754

    
755
	$rules .= "\n";
756

    
757
	return $rules;
758
}
759

    
760
/* returns space separated list of vpn subnets */
761
function filter_get_vpns_list() {
762
	global $config;
763

    
764
	$vpns = "";
765
	$vpns_arr = array();
766

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

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

    
817
	if (!empty($vpns_arr))
818
		$vpns = implode(" ", $vpns_arr);
819

    
820
	return $vpns;
821
}
822

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

    
886
function filter_generate_optcfg_array() {
887
	global $config, $FilterIflist;
888
	if(isset($config['system']['developerspew'])) {
889
		$mt = microtime();
890
		echo "filter_generate_optcfg_array() being called $mt\n";
891
	}
892

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

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

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

    
1039
function filter_flush_state_table() {
1040
	return mwexec("/sbin/pfctl -F state");
1041
}
1042

    
1043
function filter_get_reflection_interfaces($natif = "") {
1044
	global $FilterIflist;
1045

    
1046
	$nat_if_list = array();
1047

    
1048
	foreach ($FilterIflist as $ifent => $ifname) {
1049
		if($ifname['if'] == $natif)
1050
			continue;
1051

    
1052
		/* Do not add reflection redirects for interfaces with gateways */
1053
		if(interface_has_gateway($ifent))
1054
			continue;
1055

    
1056
		$nat_if_list[] = $ifname['if'];
1057
	}
1058

    
1059
	return $nat_if_list;
1060
}
1061

    
1062
function filter_generate_reflection_nat($rule, &$route_table, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = "") {
1063
	global $config, $FilterIflist;
1064

    
1065
	if(!isset($config['system']['enablenatreflectionhelper']))
1066
		return "";
1067

    
1068
	// Initialize natrules holder string
1069
	$natrules = "";
1070

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

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

    
1080
	if(!empty($protocol)) {
1081
		$protocol_text = " proto {$protocol}";
1082
	} else {
1083
		$protocol_text = "";
1084
	}
1085

    
1086
	if(empty($target_subnet) || !is_numeric($target_subnet))
1087
		$target_subnet = 32;
1088

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

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

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

    
1141
	if(!empty($natrules))
1142
		$natrules .= "\n";
1143

    
1144
	return $natrules;
1145
}
1146

    
1147
function filter_generate_reflection_proxy($rule, $nordr, $rdr_ifs, $srcaddr, $dstaddr_port, &$starting_localhost_port, &$reflection_txt) {
1148
	global $FilterIflist, $config;
1149

    
1150
	// Initialize natrules holder string
1151
	$natrules = "";
1152
	$reflection_txt = array();
1153

    
1154
	if(!empty($rdr_ifs)) {
1155
		if($config['system']['reflectiontimeout'])
1156
			$reflectiontimeout = $config['system']['reflectiontimeout'];
1157
		else
1158
			$reflectiontimeout = "2000";
1159

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

    
1162
		$rdr_if_list = implode(" ", $rdr_ifs);
1163
		if(count($rdr_ifs) > 1)
1164
			$rdr_if_list = "{ {$rdr_if_list} }";
1165

    
1166
		$natrules .= "\n# Reflection redirects\n";
1167

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

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

    
1189
			if(!empty($localport) && $dstport_split[0] != $rule['local-port']) {
1190
				if(!is_alias($rule['local-port']) && $dstport_split[1] && $dstport_split[0] != $dstport_split[1]) {
1191
					$localendport = $localport + ($dstport_split[1] - $dstport_split[0]);
1192
					$localport .= ":$localendport";
1193
				}
1194

    
1195
				$dstport = array($localport);
1196
			} else
1197
				$localport = "";
1198
		}
1199

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

    
1210
		if(isset($rule['destination']['any'])) {
1211
			if(!$rule['interface'])
1212
				$natif = "wan";
1213
			else
1214
				$natif = $rule['interface'];
1215

    
1216
			if(!isset($FilterIflist[$natif]))
1217
				return "";
1218
			if(is_ipaddr($FilterIflist[$natif]['ip']))
1219
				$dstaddr = $FilterIflist[$natif]['ip'];
1220
			else
1221
				return "";
1222

    
1223
			if(!empty($FilterIflist[$natif]['sn']))
1224
				$dstaddr = gen_subnet($dstaddr, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
1225
		}
1226

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

    
1242
		if(!empty($nordr)) {
1243
			$natrules .= "no rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange}\n";
1244
			return $natrules;
1245
		}
1246

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

    
1264
				$loc_pt = explode(":", $loc_pt);
1265
				if($loc_pt[1] && $loc_pt[1] > $loc_pt[0])
1266
					$delta = $loc_pt[1] - $loc_pt[0];
1267
				else
1268
					$delta = 0;
1269

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

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

    
1295
				if(empty($localport))
1296
					$rflctintrange = implode(":", $loc_pt);
1297
				if($inetdport + $delta > $starting_localhost_port)
1298
					$rflctrange .= ":" . ($inetdport + $delta);
1299
				$starting_localhost_port = $inetdport + $delta + 1;
1300
				$toadd_array = array_merge($toadd_array, range($loc_pt[0], $loc_pt[0] + $delta));
1301

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

    
1329
			if($toomanyports)
1330
				break;
1331
		}
1332

    
1333
		$reflection_txt = array_unique($reflection_txt);
1334
	}
1335

    
1336
	return $natrules;
1337
}
1338

    
1339
function filter_nat_rules_automatic_tonathosts($with_descr = false) {
1340
	global $config, $FilterIflist, $GatewaysList;
1341

    
1342
	$tonathosts = array("127.0.0.0/8");
1343
	$descriptions = array(gettext("localhost"), gettext("localhost"));
1344

    
1345
	foreach (get_staticroutes() as $route) {
1346
		$netip = explode("/", $route['network']);
1347
		if (isset($GatewaysList[$route['gateway']])) {
1348
			$gateway =& $GatewaysList[$route['gateway']];
1349
			if(!interface_has_gateway($gateway['interface']) && is_private_ip($netip[0])) {
1350
				$tonathosts[] = $route['network'];
1351
				$descriptions[] = gettext("static route");
1352
			}
1353
		}
1354
	}
1355

    
1356
	/* create outbound nat entries for all local networks */
1357
	foreach($FilterIflist as $ocname => $oc) {
1358
		if(interface_has_gateway($ocname))
1359
			continue;
1360
		if(is_ipaddr($oc['alias-address'])) {
1361
			$tonathosts[] = "{$oc['alias-address']}/{$oc['alias-subnet']}";
1362
			$descriptions[] = $oc['descr'] . " " . gettext("DHCP alias address");
1363
		}
1364
		if($oc['sa']) {
1365
			$tonathosts[] = "{$oc['sa']}/{$oc['sn']}";
1366
			$descriptions[] = $oc['descr'];
1367
		}
1368
	}
1369

    
1370
	/* PPTP subnet */
1371
	if(($config['pptpd']['mode'] == "server" ) && is_private_ip($config['pptpd']['remoteip'])) {
1372
		if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
1373
			$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
1374
				long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
1375
		else
1376
			$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
1377
				long2ip32(ip2long($config['pptpd']['remoteip'])));
1378

    
1379
		foreach ($pptp_subnets as $subnet) {
1380
			$tonathosts[] = $subnet;
1381
			$descriptions[] = gettext("PPTP server");
1382
		}
1383
	}
1384

    
1385
	/* PPPoE subnet */
1386
	if (is_array($FilterIflist['pppoe']))
1387
		foreach ($FilterIflist['pppoe'] as $pppoe)
1388
			if(is_private_ip($pppoe['ip'])) {
1389
				$tonathosts[] = "{$pppoe['sa']}/{$pppoe['sn']}";
1390
				$descriptions[] = gettext("PPPoE server");
1391
			}
1392

    
1393
	/* L2TP subnet */
1394
	if(isset($FilterIflist['l2tp']) && $FilterIflist['l2tp']['mode'] == "server") {
1395
		$l2tp_sa = $FilterIflist['l2tp']['sa'];
1396
		$l2tp_sn = $FilterIflist['l2tp']['sn'];
1397
		if(is_private_ip($l2tp_sa) && !empty($l2tp_sn)) {
1398
			$tonathosts[] = "{$l2tp_sa}/{$l2tp_sn}";
1399
			$descriptions[] = gettext("L2TP server");
1400
		}
1401
	}
1402

    
1403
	/* add openvpn interfaces */
1404
	if(is_array($config['openvpn']['openvpn-server']))
1405
		foreach ($config['openvpn']['openvpn-server'] as $ovpnsrv)
1406
			if (!empty($ovpnsrv['tunnel_network'])) {
1407
				$tonathosts[] = $ovpnsrv['tunnel_network'];
1408
				$descriptions[] = gettext("OpenVPN server");
1409
			}
1410

    
1411
	if(is_array($config['openvpn']['openvpn-client']))
1412
		foreach ($config['openvpn']['openvpn-client'] as $ovpncli)
1413
			if (!empty($ovpncli['tunnel_network'])) {
1414
				$tonathosts[] = $ovpncli['tunnel_network'];
1415
				$descriptions[] = gettext("OpenVPN client");
1416
			}
1417

    
1418
	/* IPsec mode_cfg subnet */
1419
	if (isset($config['ipsec']['client']['enable']) &&
1420
	    !empty($config['ipsec']['client']['pool_address']) &&
1421
	    !empty($config['ipsec']['client']['pool_netbits'])) {
1422
		$tonathosts[] = "{$config['ipsec']['client']['pool_address']}/{$config['ipsec']['client']['pool_netbits']}";
1423
		$descriptions[] = gettext("IPsec client");
1424
	}
1425

    
1426
	if ($with_descr) {
1427
		$combined = array();
1428
		foreach ($tonathosts as $idx => $subnet) {
1429
			$combined[] = array(
1430
				"subnet" => $subnet,
1431
				"descr" => $descriptions[$idx]);
1432
		}
1433

    
1434
		return $combined;
1435
	} else
1436
		return $tonathosts;
1437
}
1438

    
1439
function filter_nat_rules_outbound_automatic($src) {
1440
	global $config, $FilterIflist;
1441

    
1442
	$rules = array();
1443
	foreach ($FilterIflist as $if => $ifcfg) {
1444
		if (substr($ifcfg['if'], 0, 4) == "ovpn")
1445
			continue;
1446
		if (!interface_has_gateway($if))
1447
			continue;
1448

    
1449
		$natent = array();
1450
		$natent['interface'] = $if;
1451
		$natent['source']['network'] = $src;
1452
		$natent['dstport'] = "500";
1453
		$natent['target'] = $ifcfg['ip'];
1454
		$natent['destination']['any'] = true;
1455
		$natent['staticnatport'] = true;
1456
		$natent['descr'] = gettext('Auto created rule for ISAKMP');
1457
		$rules[] = $natent;
1458

    
1459
		$natent = array();
1460
		$natent['interface'] = $if;
1461
		$natent['source']['network'] = $src;
1462
		$natent['sourceport'] = "";
1463
		$natent['target'] = $ifcfg['ip'];
1464
		$natent['destination']['any'] = true;
1465
		$natent['natport'] = "";
1466
		$natent['descr'] = gettext('Auto created rule');
1467
		if (isset($ifcfg['nonat']))
1468
			$natent['nonat'] = true;
1469
		$rules[] = $natent;
1470
	}
1471

    
1472
	return $rules;
1473
}
1474

    
1475
/* Generate a 'nat on' or 'no nat on' rule for given interface */
1476
function filter_nat_rules_generate_if($if, $src = "any", $srcport = "", $dst = "any", $dstport = "", $natip = "", $natport = "", $nonat = false, $staticnatport = false, $proto = "", $poolopts = "") {
1477
	global $config, $FilterIflist;
1478
	/* XXX: billm - any idea if this code is needed? */
1479
	if($src == "/32" || $src{0} == "/")
1480
		return "# src incorrectly specified\n";
1481
	if($natip != "") {
1482
		if (is_subnet($natip))
1483
			$tgt = $natip;
1484
		elseif (is_alias($natip))
1485
			$tgt = "\${$natip}";
1486
		else
1487
			$tgt = "{$natip}/32";
1488
	} else {
1489
		$natip = get_interface_ip($if);
1490
		if(is_ipaddr($natip))
1491
			$tgt = "{$natip}/32";
1492
		else
1493
			$tgt = "(" . $FilterIflist[$if]['if'] . ")";
1494
	}
1495
	/* Add the protocol, if defined */
1496
	if (!empty($proto) && $proto != "any") {
1497
		if ($proto == "tcp/udp")
1498
			$protocol = " proto { tcp udp }";
1499
		else
1500
			$protocol = " proto {$proto}";
1501
	} else
1502
		$protocol = "";
1503
	/* Set tgt for IPv6 */ 
1504
	if ($proto == "ipv6") {
1505
		$natip = get_interface_ipv6($if);
1506
		if(is_ipaddrv6($natip))
1507
			$tgt = "{$natip}/128";
1508
	}
1509
	/* Add the hard set source port (useful for ISAKMP) */
1510
	if($natport != "")
1511
		$tgt .= " port {$natport}";
1512
	/* sometimes this gets called with "" instead of a value */
1513
	if($src == "")
1514
		$src = "any";
1515
	/* Match on this source port */
1516
	if($srcport != "") {
1517
		$srcportexpand = alias_expand($srcport);
1518
		if(!$srcportexpand)
1519
			$srcportexpand = $srcport;
1520
		$src .= " port {$srcportexpand}";
1521
	}
1522
	/* sometimes this gets called with "" instead of a value */
1523
	if($dst == "")
1524
		$dst = "any";
1525
	/* Match on this dest port */
1526
	if($dstport != "") {
1527
		$dstportexpand = alias_expand($dstport);
1528
		if(!$dstportexpand)
1529
			$dstportexpand = $dstport;
1530
		$dst .= " port {$dstportexpand}";
1531
	}
1532
	/* outgoing static-port option, hamachi, Grandstream, VOIP, etc */
1533
	$staticnatport_txt = "";
1534
	if($staticnatport)
1535
		$staticnatport_txt = "static-port";
1536
	elseif(!$natport)
1537
		$tgt .= " port 1024:65535"; // set source port range
1538
	/* Allow for negating NAT entries */
1539
	if($nonat) {
1540
		$nat = "no nat";
1541
		$target = "";
1542
		$staticnatport_txt = "";
1543
		$poolopts = "";
1544
	} else {
1545
		$nat = "nat";
1546
		$target = "-> {$tgt}";
1547
	}
1548
	$if_friendly = $FilterIflist[$if]['descr'];
1549
	/* Put all the pieces together */
1550
	if($if_friendly)
1551
		$natrule = "{$nat} on \${$if_friendly} {$protocol} from {$src} to {$dst} {$target} {$poolopts} {$staticnatport_txt}\n";
1552
	else
1553
		$natrule .= "# Could not convert {$if} to friendly name(alias)\n";
1554
	return $natrule;
1555
}
1556

    
1557
function filter_nat_rules_generate() {
1558
	global $config, $g, $after_filter_configure_run, $FilterIflist, $GatewaysList, $aliases;
1559

    
1560
	$natrules = "no nat proto carp\n";
1561
	$natrules .= "no rdr proto carp\n";
1562
	$natrules .= "nat-anchor \"natearly/*\"\n";
1563

    
1564
	$natrules .= "nat-anchor \"natrules/*\"\n\n";
1565
	update_filter_reload_status(gettext("Creating 1:1 rules..."));
1566

    
1567
	$reflection_txt = "";
1568
	$route_table = "";
1569

    
1570
	/* any 1:1 mappings? */
1571
	if(is_array($config['nat']['onetoone'])) {
1572
		foreach ($config['nat']['onetoone'] as $rule) {
1573
			if (isset($rule['disabled']))
1574
				continue;
1575

    
1576
			$sn = "";
1577
			$sn1 = "";
1578
			$target = alias_expand($rule['external']);
1579
			if (!$target) {
1580
				$natrules .= "# Unresolvable alias {$rule['target']}\n";
1581
				continue;               /* unresolvable alias */
1582
			}
1583

    
1584
			if (!$rule['interface'])
1585
				$natif = "wan";
1586
			else
1587
				$natif = $rule['interface'];
1588
			if (!isset($FilterIflist[$natif]))
1589
				continue;
1590

    
1591
			$srcaddr = filter_generate_address($rule, 'source');
1592
			$dstaddr = filter_generate_address($rule, 'destination');
1593
			if(!$dstaddr)
1594
				$dstaddr = $FilterIflist[$natif]['ip'];
1595

    
1596
			$srcaddr = trim($srcaddr);
1597
			$dstaddr = trim($dstaddr);
1598

    
1599
			$tmp = explode('/', $srcaddr);
1600
			$srcip = $tmp[0];
1601
			if (!empty($tmp[1]) && is_numeric($tmp[1])) {
1602
				$sn = $tmp[1];
1603
				$sn1 = "/{$sn}";
1604
			}
1605

    
1606
			$natif = $FilterIflist[$natif]['if'];
1607

    
1608
			/*
1609
			 * If reflection is enabled, turn on extra redirections
1610
			 * for this rule by adding other interfaces to an rdr rule.
1611
			 */
1612
			if ((isset($config['system']['enablebinatreflection']) || $rule['natreflection'] == "enable")
1613
			   && $rule['natreflection'] != "disable")
1614
				$nat_if_list = filter_get_reflection_interfaces($natif);
1615
			else
1616
				$nat_if_list = array();
1617

    
1618
			$natrules .= "binat on {$natif} from {$srcaddr} to {$dstaddr} -> {$target}{$sn1}\n";
1619
			if (!empty($nat_if_list)) {
1620
				$binat_if_list = implode(" ", $nat_if_list);
1621
				$binat_if_list = "{ {$binat_if_list} }";
1622
				$reflection_txt .= "rdr on {$binat_if_list} from {$dstaddr} to {$target}{$sn1} -> {$srcaddr} bitmask\n";
1623
			}
1624

    
1625
			$nat_if_list = array_merge(array($natif), $nat_if_list);
1626
			$reflection_txt .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, "", $srcaddr, $srcip, $sn);
1627
		}
1628
	}
1629

    
1630
	/* Add binat rules for Network Prefix translation */
1631
	if(is_array($config['nat']['npt'])) {
1632
		foreach ($config['nat']['npt'] as $rule) {
1633
			if (isset($rule['disabled']))
1634
				continue;
1635

    
1636
			if (!$rule['interface'])
1637
				$natif = "wan";
1638
			else
1639
				$natif = $rule['interface'];
1640
			if (!isset($FilterIflist[$natif]))
1641
				continue;
1642

    
1643
			$srcaddr = filter_generate_address($rule, 'source');
1644
			$dstaddr = filter_generate_address($rule, 'destination');
1645

    
1646
			$srcaddr = trim($srcaddr);
1647
			$dstaddr = trim($dstaddr);
1648

    
1649
			$natif = $FilterIflist[$natif]['descr'];
1650

    
1651
			$natrules .= "binat on \${$natif} from {$srcaddr} to any -> {$dstaddr}\n";
1652
			$natrules .= "binat on \${$natif} from any to {$dstaddr} -> {$srcaddr}\n";
1653

    
1654
		}
1655
	}
1656

    
1657
	/* ipsec nat */
1658
	if (is_array($config['ipsec']) && isset($config['ipsec']['enable'])) {
1659
		if (is_array($config['ipsec']['phase2'])) {
1660
			foreach ($config['ipsec']['phase2'] as $ph2ent) {
1661
				if ($ph2ent['mode'] != 'transport' && !empty($ph2ent['natlocalid'])) {
1662
					if (!function_exists('ipsec_idinfo_to_cidr'))
1663
						require_once("ipsec.inc");
1664
					if (!is_array($ph2ent['localid']))
1665
						$ph2ent['localid'] = array();
1666
					$ph2ent['localid']['mode'] = $ph2ent['mode'];
1667
					$local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid']);
1668
					if (empty($local_subnet) || $local_subnet == "0.0.0.0/0")
1669
						continue;
1670
					if (!is_subnet($local_subnet) && !is_ipaddr($local_subnet))
1671
						continue;
1672
					if (!is_array($ph2ent['natlocalid']))
1673
						$ph2ent['natlocalid'] = array();
1674
					$ph2ent['natlocalid']['mode'] = $ph2ent['mode'];
1675
					$natlocal_subnet = ipsec_idinfo_to_cidr($ph2ent['natlocalid']);
1676
					if (empty($natlocal_subnet) || $natlocal_subnet == "0.0.0.0/0")
1677
						continue;
1678
					if (!is_subnet($natlocal_subnet) && !is_ipaddr($natlocal_subnet))
1679
						continue;
1680
					if (!is_array($ph2ent['remoteid']))
1681
						$ph2ent['remoteid'] = array();
1682
					$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
1683
					$remote_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
1684
					if (empty($remote_subnet))
1685
						continue;
1686
					if (!is_subnet($remote_subnet) && !is_ipaddr($remote_subnet))
1687
						continue;
1688
					if ($remote_subnet == "0.0.0.0/0")
1689
						$remote_subnet = "any";
1690
					if (is_ipaddr($natlocal_subnet) && !is_ipaddr($local_subnet) )
1691
						$nattype = "nat";
1692
					else
1693
						$nattype = "binat";
1694
					$natrules .= "{$nattype} on enc0 from {$local_subnet} to {$remote_subnet} -> {$natlocal_subnet}\n";
1695
				}
1696
			}
1697
		}
1698
	}
1699

    
1700
	if ($config['nat']['outbound']['mode'] == "disabled")
1701
		$natrules .= "\n# Outbound NAT rules are disabled\n";
1702

    
1703
	if ($config['nat']['outbound']['mode'] == "advanced" || $config['nat']['outbound']['mode'] == "hybrid") {
1704
		$natrules .= "\n# Outbound NAT rules (manual)\n";
1705
		/* advanced outbound rules */
1706
		if(is_array($config['nat']['outbound']['rule'])) {
1707
			foreach ($config['nat']['outbound']['rule'] as $obent) {
1708
				if (isset($obent['disabled']))
1709
					continue;
1710
				update_filter_reload_status(sprintf(gettext("Creating advanced outbound rule %s"), $obent['descr']));
1711
				$src = alias_expand($obent['source']['network']);
1712
				if(!$src)
1713
					$src = $obent['source']['network'];
1714
				$dst = alias_expand($obent['destination']['address']);
1715
				if(!$dst)
1716
					$dst = $obent['destination']['address'];
1717
				if(isset($obent['destination']['not']) && !isset($obent['destination']['any']))
1718
					$dst = "!" . $dst;
1719

    
1720
				if(!$obent['interface'] || !isset($FilterIflist[$obent['interface']]))
1721
					continue;
1722

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

    
1726
				$natrules .= filter_nat_rules_generate_if($obent['interface'],
1727
					$src,
1728
					$obent['sourceport'],
1729
					$dst,
1730
					$obent['dstport'],
1731
					$obtarget,
1732
					$obent['natport'],
1733
					isset($obent['nonat']),
1734
					isset($obent['staticnatport']),
1735
					$obent['protocol'],
1736
					$poolopts
1737
				);
1738
			}
1739
		}
1740
	}
1741

    
1742
	/* outbound rules */
1743
	if (!isset($config['nat']['outbound']['mode']) ||
1744
	    $config['nat']['outbound']['mode'] == "automatic" ||
1745
	    $config['nat']['outbound']['mode'] == "hybrid") {
1746
		$natrules .= "\n# Outbound NAT rules (automatic)\n";
1747
		/* standard outbound rules (one for each interface) */
1748
		update_filter_reload_status(gettext("Creating outbound NAT rules"));
1749
		$tonathosts_array = filter_nat_rules_automatic_tonathosts();
1750
		$tonathosts = implode(" ", $tonathosts_array);
1751
		$numberofnathosts = count($tonathosts_array);
1752

    
1753
		$natrules .= "\n# Subnets to NAT \n";
1754
		if ($numberofnathosts > 0) {
1755
			update_filter_reload_status(gettext('Creating automatic outbound rules'));
1756

    
1757
			if ($numberofnathosts > 4) {
1758
				$natrules .= "table <tonatsubnets> { {$tonathosts} }\n";
1759
				$macroortable = "<tonatsubnets>";
1760
			} else {
1761
				$natrules .= "tonatsubnets	= \"{ {$tonathosts} }\"\n";
1762
				$macroortable = "\$tonatsubnets";
1763
			}
1764

    
1765
			$a_outs = filter_nat_rules_outbound_automatic($macroortable);
1766
			foreach ($a_outs as $a_out) {
1767
				$natrules .= filter_nat_rules_generate_if($a_out['interface'],
1768
					$a_out['source']['network'],
1769
					$a_out['sourceport'],
1770
					$a_out['destination']['address'],
1771
					$a_out['dstport'],
1772
					$a_out['target'],
1773
					$a_out['natport'],
1774
					isset($a_out['nonat']),
1775
					isset($a_out['staticnatport']));
1776
			}
1777
		}
1778
		unset($tonathosts, $tonathosts_array, $numberofnathosts);
1779
	}
1780

    
1781
	/* load balancer anchor */
1782
	$natrules .= "\n# Load balancing anchor\n";
1783
	$natrules .= "rdr-anchor \"relayd/*\"\n";
1784

    
1785
	update_filter_reload_status(gettext("Setting up TFTP helper"));
1786
	$natrules .= "# TFTP proxy\n";
1787
	$natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
1788

    
1789
	if (!empty($config['system']['tftpinterface'])) {
1790
		$tftpifs = explode(",", $config['system']['tftpinterface']);
1791
		foreach($tftpifs as $tftpif) {
1792
			if ($FilterIflist[$tftpif])
1793
				$natrules .= "rdr pass on {$FilterIflist[$tftpif]['if']} proto udp from any to any port tftp -> 127.0.0.1 port 6969\n";
1794
		}
1795
	}
1796

    
1797
	/* DIAG: add ipv6 NAT, if requested */
1798
	if(isset($config['diag']['ipv6nat']['enable']) &&
1799
		is_ipaddr($config['diag']['ipv6nat']['ipaddr']) &&
1800
		is_array($FilterIflist['wan'])) {
1801
		/* XXX: FIX ME!	 IPV6 */
1802
		$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto ipv6 from any to any -> {$config['diag']['ipv6nat']['ipaddr']}\n";
1803
	}
1804

    
1805
	if(file_exists("/var/etc/inetd.conf"))
1806
		@unlink("/var/etc/inetd.conf");
1807
	// Open inetd.conf write handle
1808
	$inetd_fd = fopen("/var/etc/inetd.conf","w");
1809
	/* add tftp protocol helper */
1810
	fwrite($inetd_fd, "tftp-proxy\tdgram\tudp\twait\t\troot\t/usr/libexec/tftp-proxy\ttftp-proxy -v\n");
1811

    
1812
	if(isset($config['nat']['rule'])) {
1813
		/* start reflection redirects on port 19000 of localhost */
1814
		$starting_localhost_port = 19000;
1815
		$natrules .= "# NAT Inbound Redirects\n";
1816
		foreach ($config['nat']['rule'] as $rule) {
1817
			update_filter_reload_status(sprintf(gettext("Creating NAT rule %s"), $rule['descr']));
1818

    
1819
			if(isset($rule['disabled']))
1820
				continue;
1821

    
1822
			/* if item is an alias, expand */
1823
			$dstport = "";
1824
			$dstport[0] = alias_expand($rule['destination']['port']);
1825
			if(!$dstport[0])
1826
				$dstport = explode("-", $rule['destination']['port']);
1827

    
1828
			/* if item is an alias, expand */
1829
			$localport = alias_expand($rule['local-port']);
1830
			if(!$localport || $dstport[0] == $localport) {
1831
				$localport = "";
1832
			} else if(is_alias($rule['local-port'])) {
1833
				$localport = filter_expand_alias($rule['local-port']);
1834
				if($localport) {
1835
					$localport = explode(" ", trim($localport));
1836
					$localport = $localport[0];
1837
					$localport = " port {$localport}";
1838
				}
1839
			} else if(is_alias($rule['destination']['port'])) {
1840
				$localport = " port {$localport}";
1841
			} else {
1842
				if(($dstport[1]) && ($dstport[0] != $dstport[1])) {
1843
					$localendport = $localport + ($dstport[1] - $dstport[0]);
1844

    
1845
					$localport .= ":$localendport";
1846
				}
1847

    
1848
				$localport = " port {$localport}";
1849
			}
1850

    
1851
			switch(strtolower($rule['protocol'])) {
1852
			case "tcp/udp":
1853
				$protocol = "{ tcp udp }";
1854
				break;
1855
			case "tcp":
1856
			case "udp":
1857
				$protocol = strtolower($rule['protocol']);
1858
				break;
1859
			default:
1860
				$protocol = strtolower($rule['protocol']);
1861
				$localport = "";
1862
				break;
1863
			}
1864

    
1865
			$target = alias_expand($rule['target']);
1866
			if(!$target && !isset($rule['nordr'])) {
1867
				$natrules .= "# Unresolvable alias {$rule['target']}\n";
1868
				continue;		/* unresolvable alias */
1869
			}
1870

    
1871
			if(is_alias($rule['target']))
1872
				$target_ip = filter_expand_alias($rule['target']);
1873
			else if(is_ipaddr($rule['target']))
1874
				$target_ip = $rule['target'];
1875
			else if(is_ipaddr($FilterIflist[$rule['target']]['ip']))
1876
				$target_ip = $FilterIflist[$rule['target']]['ip'];
1877
			else
1878
				$target_ip = $rule['target'];
1879
			$target_ip = trim($target_ip);
1880

    
1881
			if($rule['associated-rule-id'] == "pass")
1882
				$rdrpass = "pass ";
1883
			else
1884
				$rdrpass = "";
1885

    
1886
			if (isset($rule['nordr'])) {
1887
				$nordr = "no ";
1888
				$rdrpass = "";
1889
			} else
1890
				$nordr = "";
1891

    
1892
			if(!$rule['interface'])
1893
				$natif = "wan";
1894
			else
1895
				$natif = $rule['interface'];
1896

    
1897
			if (!isset($FilterIflist[$natif]))
1898
				continue;
1899

    
1900
			$srcaddr = filter_generate_address($rule, 'source', true);
1901
			$dstaddr = filter_generate_address($rule, 'destination', true);
1902
			$srcaddr = trim($srcaddr);
1903
			$dstaddr = trim($dstaddr);
1904

    
1905
			if(!$dstaddr)
1906
				$dstaddr = $FilterIflist[$natif]['ip'];
1907

    
1908
			$dstaddr_port = explode(" ", $dstaddr);
1909
			if(empty($dstaddr_port[0]) || strtolower(trim($dstaddr_port[0])) == "port")
1910
				continue; // Skip port forward if no destination address found
1911
			$dstaddr_reflect = $dstaddr;
1912
			if(isset($rule['destination']['any'])) {
1913
				/* With reflection enabled, destination of 'any' has side effects
1914
				 * that most people would not expect, so change it on reflection rules. */
1915
				$dstaddr_reflect = $FilterIflist[$natif]['ip'];
1916
				if(!empty($FilterIflist[$natif]['sn']))
1917
					$dstaddr_reflect = gen_subnet($dstaddr_reflect, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
1918

    
1919
				if($dstaddr_port[2])
1920
					$dstaddr_reflect .= " port " . $dstaddr_port[2];
1921
			}
1922

    
1923
			$natif = $FilterIflist[$natif]['if'];
1924

    
1925
			$reflection_type = "none";
1926
			if($rule['natreflection'] != "disable" && $dstaddr_port[0] != "0.0.0.0") {
1927
				if($rule['natreflection'] == "enable")
1928
					$reflection_type = "proxy";
1929
				else if($rule['natreflection'] == "purenat")
1930
					$reflection_type = "purenat";
1931
				else if(!isset($config['system']['disablenatreflection'])) {
1932
					if(isset($config['system']['enablenatreflectionpurenat']))
1933
						$reflection_type = "purenat";
1934
					else
1935
						$reflection_type = "proxy";
1936
				}
1937
			}
1938

    
1939
			if($reflection_type != "none")
1940
				$nat_if_list = filter_get_reflection_interfaces($natif);
1941
			else
1942
				$nat_if_list = array();
1943

    
1944
			if(empty($nat_if_list))
1945
				$reflection_type = "none";
1946

    
1947
			$localport_nat = $localport;
1948
			if(empty($localport_nat) && $dstaddr_port[2])
1949
				$localport_nat = " port " . $dstaddr_port[2];
1950

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

    
1954
				/* Does this rule redirect back to a internal host? */
1955
				if(isset($rule['destination']['any']) && !isset($rule['nordr']) && !isset($config['system']['enablenatreflectionhelper']) && !interface_has_gateway($rule['interface'])) {
1956
					$rule_interface_ip = find_interface_ip($natif);
1957
					$rule_interface_subnet = find_interface_subnet($natif);
1958
					if(!empty($rule_interface_ip) && !empty($rule_interface_subnet)) {
1959
						$rule_subnet = gen_subnet($rule_interface_ip, $rule_interface_subnet);
1960
						$natrules .= "\n";
1961
						$natrules .= "no nat on {$natif} proto tcp from ({$natif}) to {$rule_subnet}/{$rule_interface_subnet}\n";
1962
						$natrules .= "nat on {$natif} proto tcp from {$rule_subnet}/{$rule_interface_subnet} to {$target} port {$dstport[0]} -> ({$natif})\n";
1963
					}
1964
				}
1965

    
1966
				if ($reflection_type != "none") {
1967
					if($reflection_type == "proxy" && !isset($rule['nordr'])) {
1968
						$natrules .= filter_generate_reflection_proxy($rule, $nordr, $nat_if_list, $srcaddr, $dstaddr, $starting_localhost_port, $reflection_rules);
1969
						$nat_if_list = array($natif);
1970
						foreach ($reflection_rules as $txtline)
1971
							fwrite($inetd_fd, $txtline);
1972
					} else if($reflection_type == "purenat" || isset($rule['nordr'])) {
1973
						$rdr_if_list = implode(" ", $nat_if_list);
1974
						if(count($nat_if_list) > 1)
1975
							$rdr_if_list = "{ {$rdr_if_list} }";
1976
						$natrules .= "\n# Reflection redirect\n";
1977
						$natrules .= "{$nordr}rdr {$rdrpass}on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr_reflect}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
1978
						$nat_if_list = array_merge(array($natif), $nat_if_list);
1979
					}
1980
				}
1981

    
1982
				if(empty($nat_if_list))
1983
					$nat_if_list = array($natif);
1984

    
1985
				$natrules .= "\n";
1986
				if(!isset($rule['nordr']))
1987
					$natrules .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, $protocol, "{$target}{$localport_nat}", $target_ip);
1988
			}
1989
		}
1990
	}
1991
	fclose($inetd_fd);		// Close file handle
1992

    
1993
	if (isset($config['pptpd']['mode']) && ($config['pptpd']['mode'] != "off")) {
1994
		if ($config['pptpd']['mode'] == "redir") {
1995
			$pptpdtarget = $config['pptpd']['redir'];
1996
			$natrules .= "# PPTP\n";
1997
			$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto gre from any to any -> {$pptpdtarget}\n";
1998
			$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto tcp from any to any port 1723 -> {$pptpdtarget}\n";
1999
		}
2000
	}
2001

    
2002
	$natrules .= discover_pkg_rules("nat");
2003

    
2004
	$natrules .= "# UPnPd rdr anchor\n";
2005
	$natrules .= "rdr-anchor \"miniupnpd\"\n";
2006

    
2007
	if(!empty($reflection_txt))
2008
		$natrules .= "\n# Reflection redirects and NAT for 1:1 mappings\n" . $reflection_txt;
2009

    
2010
	// Check if inetd is running, if not start it.	If so, restart it gracefully.
2011
	$helpers = isvalidproc("inetd");
2012
	if(file_exists("/var/etc/inetd.conf")) {
2013
		if(!$helpers)
2014
			mwexec("/usr/sbin/inetd -wW -R 0 -a 127.0.0.1 /var/etc/inetd.conf");
2015
		else
2016
			sigkillbypid("/var/run/inetd.pid", "HUP");
2017
	}
2018

    
2019
	return $natrules;
2020
}
2021

    
2022
function filter_generate_user_rule_arr($rule) {
2023
	global $config;
2024
	update_filter_reload_status(sprintf(gettext("Creating filter rule %s ..."), $rule['descr']));
2025
	$ret = array();
2026
	$line = filter_generate_user_rule($rule);
2027
	$ret['rule'] = $line;
2028
	$ret['interface'] = $rule['interface'];
2029
	if($rule['descr'] != "" and $line != "")
2030
		$ret['descr'] = "label \"" . fix_rule_label("USER_RULE: {$rule['descr']}") . "\"";
2031
	else
2032
		$ret['descr'] = "label \"USER_RULE\"";
2033

    
2034
	return $ret;
2035
}
2036

    
2037
function filter_generate_port(& $rule, $target = "source", $isnat = false) {
2038

    
2039
	$src = "";
2040

    
2041
	$rule['protocol'] = strtolower($rule['protocol']);
2042
	if(in_array($rule['protocol'], array("tcp","udp","tcp/udp"))) {
2043
		if($rule[$target]['port']) {
2044
			$srcport = explode("-", $rule[$target]['port']);
2045
			$srcporta = alias_expand($srcport[0]);
2046
			if(!$srcporta)
2047
				log_error(sprintf(gettext("filter_generate_port: %s is not a valid {$target} port."), $srcport[0]));
2048
			else if((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
2049
				$src .= " port {$srcporta} ";
2050
			} else if(($srcport[0] == 1) && ($srcport[1] == 65535)) {
2051
			/* no need for a port statement here */
2052
			} else if ($isnat) {
2053
				$src .= " port {$srcport[0]}:{$srcport[1]}";
2054
			} else {
2055
				if(is_port($srcporta) && $srcport[1] == 65535) {
2056
					$src .= " port >= {$srcporta} ";
2057
				} else if($srcport[0] == 1) {
2058
					$src .= " port <= {$srcport[1]} ";
2059
				} else {
2060
					$srcport[0]--;
2061
					$srcport[1]++;
2062
					$src .= " port {$srcport[0]} >< {$srcport[1]} ";
2063
				}
2064
			}
2065
		}
2066
	}
2067

    
2068
	return $src;
2069
}
2070

    
2071
function filter_generate_address(& $rule, $target = "source", $isnat = false) {
2072
	global $FilterIflist, $config;
2073
	$src = "";
2074

    
2075
	if(isset($rule[$target]['any'])) {
2076
		$src = "any";
2077
	} else if($rule[$target]['network']) {
2078
		if(strstr($rule[$target]['network'], "opt")) {
2079
			$optmatch = "";
2080
			$matches = "";
2081
			if($rule['ipprotocol'] == "inet6") {
2082
				if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
2083
					$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ipv6'];
2084
					if(!is_ipaddrv6($opt_ip))
2085
						return "";
2086
					$src = $opt_ip . "/" .
2087
					$FilterIflist["opt{$optmatch[1]}"]['snv6'];
2088
				/* check for opt$NUMip here */
2089
				} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
2090
					$src = $FilterIflist["opt{$matches[1]}"]['ipv6'];
2091
					if(!is_ipaddrv6($src))
2092
						return "";
2093
				}
2094
				if(isset($rule[$target]['not']))
2095
					$src = " !{$src}";
2096
			} else {
2097
				if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
2098
					$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ip'];
2099
					if(!is_ipaddrv4($opt_ip))
2100
						return "";
2101
					$src = $opt_ip . "/" .
2102
					$FilterIflist["opt{$optmatch[1]}"]['sn'];
2103
				/* check for opt$NUMip here */
2104
				} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
2105
					$src = $FilterIflist["opt{$matches[1]}"]['ip'];
2106
					if(!is_ipaddrv4($src))
2107
						return "";
2108
				}
2109
				if(isset($rule[$target]['not']))
2110
					$src = " !{$src}";
2111
			}
2112
		} else {
2113
			if($rule['ipprotocol'] == "inet6") {
2114
				switch ($rule[$target]['network']) {
2115
					case 'wan':
2116
						$wansa = $FilterIflist['wan']['sav6'];
2117
						if (!is_ipaddrv6($wansa))
2118
							return "";
2119
						$wansn = $FilterIflist['wan']['snv6'];
2120
						$src = "{$wansa}/{$wansn}";
2121
						break;
2122
					case 'wanip':
2123
						$src = $FilterIflist["wan"]['ipv6'];
2124
						if (!is_ipaddrv6($src))
2125
							return "";
2126
						break;
2127
					case 'lanip':
2128
						$src = $FilterIflist["lan"]['ipv6'];
2129
						if (!is_ipaddrv6($src))
2130
							return "";
2131
						break;
2132
					case 'lan':
2133
						$lansa = $FilterIflist['lan']['sav6'];
2134
						if (!is_ipaddrv6($lansa))
2135
							return "";
2136
						$lansn = $FilterIflist['lan']['snv6'];
2137
						$src = "{$lansa}/{$lansn}";
2138
						break;
2139
					case '(self)':
2140
						$src = "(self)";
2141
						break;
2142
					case 'pptp':
2143
						$pptpsav6 = gen_subnetv6($FilterIflist['pptp']['sav6'], $FilterIflist['pptp']['snv6']);
2144
						$pptpsnv6 = $FilterIflist['pptp']['snv6'];
2145
						$src = "{$pptpsav6}/{$pptpsnv6}";
2146
						break;
2147
					case 'pppoe':
2148
						if (is_array($FilterIflist['pppoe'])) {
2149
							$pppoesav6 = gen_subnetv6($FilterIflist['pppoe'][0]['ipv6'], $FilterIflist['pppoe'][0]['snv6']);
2150
							$pppoesnv6 = $FilterIflist['pppoe'][0]['snv6'];
2151
							$src = "{$pppoesav6}/{$pppoesnv6}";
2152
						}
2153
					}
2154
				if(isset($rule[$target]['not']))
2155
					$src = " !{$src}";
2156
			} else {
2157
				switch ($rule[$target]['network']) {
2158
					case 'wan':
2159
						$wansa = $FilterIflist['wan']['sa'];
2160
						if (!is_ipaddrv4($wansa))
2161
							return "";
2162
						$wansn = $FilterIflist['wan']['sn'];
2163
						$src = "{$wansa}/{$wansn}";
2164
						break;
2165
					case 'wanip':
2166
						$src = $FilterIflist["wan"]['ip'];
2167
						break;
2168
					case 'lanip':
2169
						$src = $FilterIflist["lan"]['ip'];
2170
						break;
2171
					case 'lan':
2172
						$lansa = $FilterIflist['lan']['sa'];
2173
						if (!is_ipaddrv4($lansa))
2174
							return "";
2175
						$lansn = $FilterIflist['lan']['sn'];
2176
						$src = "{$lansa}/{$lansn}";
2177
						break;
2178
					case '(self)':
2179
						$src = "(self)";
2180
						break;
2181
					case 'pptp':
2182
						if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
2183
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
2184
						else
2185
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
2186
						if (empty($pptp_subnets))
2187
							return "";
2188
						$src = "{ " . implode(" ", $pptp_subnets) . " }";
2189
						break;
2190
					case 'pppoe':
2191
						/* XXX: This needs to be fixed somehow! */
2192
						if (is_array($FilterIflist['pppoe'])) {
2193
							$pppoesa = gen_subnet($FilterIflist['pppoe'][0]['ip'], $FilterIflist['pppoe'][0]['sn']);
2194
							$pppoesn = $FilterIflist['pppoe'][0]['sn'];
2195
							$src = "{$pppoesa}/{$pppoesn}";
2196
						}
2197
						break;
2198
				}
2199
				if(isset($rule[$target]['not']))
2200
					$src = " !{$src}";
2201
			}
2202
		}
2203
	} else if($rule[$target]['address']) {
2204
		$expsrc = alias_expand($rule[$target]['address']);
2205
		if(isset($rule[$target]['not']))
2206
			$not = "!";
2207
		else
2208
			$not = "";
2209
		$src = " {$not} {$expsrc}";
2210
	}
2211

    
2212
	$src .= filter_generate_port($rule, $target, $isnat);
2213

    
2214
	return $src;
2215
}
2216

    
2217
function filter_generate_user_rule($rule) {
2218
	global $config, $g, $FilterIflist, $GatewaysList;
2219
	global $layer7_rules_list, $dummynet_name_list;
2220

    
2221
	if(isset($config['system']['developerspew'])) {
2222
		$mt = microtime();
2223
		echo "filter_generate_user_rule() being called $mt\n";
2224
	}
2225
	/* don't include disabled rules */
2226
	if(isset($rule['disabled'])) {
2227
		return "# rule " . $rule['descr'] . " disabled \n";
2228
	}
2229
	update_filter_reload_status("Creating filter rules {$rule['descr']} ...");
2230
	$pptpdcfg = $config['pptpd'];
2231
	$int = "";
2232
	$aline = array();
2233

    
2234
	/* Check to see if the interface is in our list */
2235
	if(isset($rule['floating'])) {
2236
		if(isset($rule['interface']) && $rule['interface'] <> "") {
2237
			$interfaces = explode(",", $rule['interface']);
2238
			$ifliste = "";
2239
			foreach ($interfaces as $iface) {
2240
				if(array_key_exists($iface, $FilterIflist))
2241
					$ifliste .= " " . $FilterIflist[$iface]['if'] . " ";
2242
			}
2243
			if($ifliste <> "")
2244
				$aline['interface'] = " on { {$ifliste} } ";
2245
			else
2246
				$aline['interface'] = "";
2247
		} else
2248
			$aline['interface'] = "";
2249
	} else if(!array_key_exists($rule['interface'], $FilterIflist)) {
2250
			foreach($FilterIflist as $oc)
2251
				$items .= $oc['descr'] . " ";
2252
			return "# array key \"{$rule['interface']}\" does not exist for \"" . $rule['descr'] . "\" in array: {{$items}}";
2253
	} else if((array_key_exists($rule['interface'], $FilterIflist))
2254
		&& (is_array($FilterIflist[$rule['interface']]))
2255
		&& (is_array($FilterIflist[$rule['interface']][0]))) {
2256
		/* Currently this only case for this is the pppoe server. There should be an existing macro with this name. */
2257
		$aline['interface'] = " on \$" . $rule['interface'] . " ";
2258
	} else
2259
		$aline['interface'] = " on \$" . $FilterIflist[$rule['interface']]['descr'] . " ";
2260
	$ifcfg = $FilterIflist[$rule['interface']];
2261
	if($pptpdcfg['mode'] != "server") {
2262
		if(($rule['source']['network'] == "pptp") ||
2263
			($rule['destination']['network'] == "pptp"))
2264
				return "# source network or destination network == pptp on " . $rule['descr'];
2265
	}
2266

    
2267
	switch($rule['ipprotocol']) {
2268
	case "inet":
2269
		$aline['ipprotocol'] = "inet";
2270
		break;
2271
	case "inet6":
2272
		$aline['ipprotocol'] = "inet6";
2273
		break;
2274
	default:
2275
		$aline['ipprotocol'] = "";
2276
		break;
2277
	}
2278

    
2279
	/* check for unresolvable aliases */
2280
	if($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
2281
		$error_text = "Unresolvable source alias '{$rule['source']['address']}' for rule '{$rule['descr']}'";
2282
		file_notice("Filter_Reload", $error_text);
2283
		return "# {$error_text}";
2284
	}
2285
	if($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
2286
		$error_text = "Unresolvable destination alias '{$rule['destination']['address']}' for rule '{$rule['descr']}'";
2287
		file_notice("Filter_Reload", $error_text);
2288
		return "# {$error_text}";
2289
	}
2290
	update_filter_reload_status("Setting up pass/block rules");
2291
	$type = $rule['type'];
2292
	if($type != "pass" && $type != "block" && $type != "reject" && $type != "match") {
2293
		/* default (for older rules) is pass */
2294
		$type = "pass";
2295
	}
2296
	if($type == "reject") {
2297
		$aline['type'] = "block return ";
2298
	} else
2299
		$aline['type'] = $type . " ";
2300
	if(isset($rule['floating']) && $rule['floating'] == "yes") {
2301
		if($rule['direction'] != "any")
2302
			$aline['direction'] = " " . $rule['direction'] . " ";
2303
	} else {
2304
		/* ensure the direction is in */
2305
		$aline['direction'] = " in ";
2306
	}
2307
	if(isset($rule['log']))
2308
		$aline['log'] = "log ";
2309
	if(!isset($rule['floating']) || isset($rule['quick']))
2310
		$aline['quick'] = " quick ";
2311

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

    
2315
	/* do not process reply-to for gateway'd rules */
2316
	if($rule['gateway'] == "" && $aline['direction'] <> "" && (interface_has_gateway($rule['interface']) || interface_has_gatewayv6($rule['interface'])) && !isset($config['system']['disablereplyto']) && !isset($rule['disablereplyto']) && $type != "match") {
2317
		if ($rule['ipprotocol'] == "inet6") {
2318
			$rg = get_interface_gateway_v6($rule['interface']);
2319
			if (is_ipaddrv6($rg))
2320
				$aline['reply'] = "reply-to ( {$ifcfg['ifv6']} {$rg} ) ";
2321
			else if ($rule['interface'] <> "pptp")
2322
				log_error("Could not find IPv6 gateway for interface({$rule['interface']}).");
2323
		} else {
2324
			$rg = get_interface_gateway($rule['interface']);
2325
			if (is_ipaddrv4($rg))
2326
				$aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) ";
2327
			else if ($rule['interface'] <> "pptp")
2328
				log_error(sprintf(gettext("Could not find IPv4 gateway for interface (%s)."), $rule['interface']));
2329
		}
2330
	}
2331
	/* if user has selected a custom gateway, lets work with it */
2332
	else if($rule['gateway'] <> "" && $type == "pass") {
2333
		if (isset($GatewaysList[$rule['gateway']]))
2334
			/* Add the load balanced gateways */
2335
			$aline['route'] = " \$GW{$rule['gateway']} ";
2336
		else if (isset($config['system']['skip_rules_gw_down']))
2337
			return "# rule " . $rule['descr'] . " disabled because gateway " . $rule['gateway'] . " is down ";
2338
		else
2339
			log_error("The gateway: {$rule['gateway']} is invalid or unknown, not using it.");
2340
	}
2341

    
2342
	if (isset($rule['protocol']) && !empty($rule['protocol'])) {
2343
		if($rule['protocol'] == "tcp/udp")
2344
			$aline['prot'] = " proto { tcp udp } ";
2345
		elseif(($rule['protocol'] == "icmp") && ($rule['ipprotocol'] == "inet6"))
2346
			$aline['prot'] = " proto ipv6-icmp ";
2347
		elseif($rule['protocol'] == "icmp")
2348
			$aline['prot'] = " proto icmp ";
2349
		else
2350
			$aline['prot'] = " proto {$rule['protocol']} ";
2351
	} else {
2352
		if($rule['source']['port'] <> "" || $rule['destination']['port'] <> "")
2353
			$aline['prot'] = " proto tcp ";
2354
	}
2355
	update_filter_reload_status(sprintf(gettext("Creating rule %s"), $rule['descr']));
2356

    
2357
	/* source address */
2358
	$src = trim(filter_generate_address($rule, "source"));
2359
	if (empty($src) || ($src == "/")) {
2360
		return "# at the break!";
2361
	}
2362
	$aline['src'] = " from $src ";
2363

    
2364
	/* OS signatures */
2365
	if(($rule['protocol'] == "tcp") && ($rule['os'] <> ""))
2366
		$aline['os'] = " os \"{$rule['os']}\" ";
2367

    
2368
	/* destination address */
2369
	$dst = trim(filter_generate_address($rule, "destination"));
2370
	if (empty($dst) || ($dst == "/")) {
2371
		return "# returning at dst $dst == \"/\"";
2372
	}
2373
	$aline['dst'] = "to $dst ";
2374

    
2375
	//Layer7 support
2376
	$l7_present = false;
2377
	$l7_structures = array();
2378
	if(isset($rule['l7container']) && $rule['l7container'] != "none") {
2379
		$l7_present = true;
2380
		$l7rule =& $layer7_rules_list[$rule['l7container']];
2381
		$l7_structures = $l7rule->get_unique_structures();
2382
		$aline['divert'] = "divert " . $l7rule->GetRPort() . " ";
2383
	}
2384
	if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet"))
2385
		$aline['icmp-type'] = "icmp-type {$rule['icmptype']} ";
2386
	if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet6"))
2387
		$aline['icmp6-type'] = "icmp6-type {$rule['icmptype']} ";
2388
	if (!empty($rule['tag']))
2389
		$aline['tag'] = " tag " .$rule['tag']. " ";
2390
	if (!empty($rule['tagged']))
2391
		$aline['tagged'] = " tagged " .$rule['tagged'] . " ";
2392
	if (!empty($rule['dscp'])) {
2393
		switch (strtolower($rule['dscp'])) {
2394
			case 'va':  $aline['dscp'] = " dscp 44 "; break;
2395
			case 'cs1': $aline['dscp'] = " dscp 8 ";  break;
2396
			case 'cs2': $aline['dscp'] = " dscp 16 "; break;
2397
			case 'cs3': $aline['dscp'] = " dscp 24 "; break;
2398
			case 'cs4': $aline['dscp'] = " dscp 32 "; break;
2399
			case 'cs5': $aline['dscp'] = " dscp 40 "; break;
2400
			case 'cs6': $aline['dscp'] = " dscp 48 "; break;
2401
			case 'cs7': $aline['dscp'] = " dscp 56 "; break;
2402
			default:    $aline['dscp'] = " dscp " . $rule['dscp'] . " "; break;
2403
		}
2404
	}
2405
	if (!empty($rule['vlanprio']) && ($rule['vlanprio'] != "none"))
2406
		$aline['vlanprio'] = " ieee8021q-pcp " . $rule['vlanprio'] . " ";
2407
	if (!empty($rule['vlanprioset']) && ($rule['vlanprioset'] != "none"))
2408
		$aline['vlanprioset'] = " ieee8021q-setpcp " . $rule['vlanprioset'] . " ";
2409
	if ($type == "pass") {
2410
		if (isset($rule['allowopts']))
2411
			$aline['allowopts'] = " allow-opts ";
2412
	}
2413
	$aline['flags'] = "";
2414
	if ($rule['protocol'] == "tcp") {
2415
		if (isset($rule['tcpflags_any']))
2416
			$aline['flags'] = "flags any ";
2417
		else if (!empty($rule['tcpflags2'])) {
2418
			$aline['flags'] = "flags ";
2419
			if (!empty($rule['tcpflags1'])) {
2420
				$flags1 = explode(",", $rule['tcpflags1']);
2421
				foreach ($flags1 as $flag1) {
2422
					// CWR flag needs special treatment
2423
					if($flag1[0] == "c")
2424
						$aline['flags'] .= "W";
2425
					else
2426
						$aline['flags'] .= strtoupper($flag1[0]);
2427
				}
2428
			}
2429
			$aline['flags'] .= "/";
2430
			if (!empty($rule['tcpflags2'])) {
2431
				$flags2 = explode(",", $rule['tcpflags2']);
2432
				foreach ($flags2 as $flag2) {
2433
					// CWR flag needs special treatment
2434
					if($flag2[0] == "c")
2435
						$aline['flags'] .= "W";
2436
					else
2437
						$aline['flags'] .= strtoupper($flag2[0]);
2438
				}
2439
			}
2440
			$aline['flags'] .= " ";
2441
		} else {
2442
			$aline['flags'] = "flags S/SA ";
2443
		}
2444
	}
2445
	if ($type == "pass") {
2446
		/*
2447
		 *	# keep state
2448
		 *		works with TCP, UDP, and ICMP.
2449
		 *	# modulate state
2450
		 *		works only with TCP. pfSense will generate strong Initial Sequence Numbers (ISNs)
2451
		 *		for packets matching this rule.
2452
		 *	# synproxy state
2453
		 *		proxies incoming TCP connections to help protect servers from spoofed TCP SYN floods.
2454
		 *		This option includes the functionality of keep state and modulate state combined.
2455
		 *	# none
2456
		 *		do not use state mechanisms to keep track. this is only useful if your doing advanced
2457
		 *		queueing in certain situations. please check the faq.
2458
		 */
2459
		$noadvoptions = false;
2460
		if (isset($rule['statetype']) && $rule['statetype'] <> "") {
2461
			switch($rule['statetype']) {
2462
				case "none":
2463
					$noadvoptions = true;
2464
					$aline['flags'] .= " no state ";
2465
					break;
2466
				case "modulate state":
2467
				case "synproxy state":
2468
					if ($rule['protocol'] == "tcp")
2469
						$aline['flags'] .= "{$rule['statetype']} ";
2470
					break;
2471
				case "sloppy state":
2472
					$aline['flags'] .= "keep state ";
2473
					$rule['sloppy'] = true;
2474
					break;
2475
				default:
2476
					$aline['flags'] .= "{$rule['statetype']} ";
2477
					break;
2478
			}
2479
		} else
2480
			$aline['flags'] .= "keep state ";
2481

    
2482
		if ($noadvoptions == false && isset($rule['nopfsync']))
2483
			$rule['nopfsync'] = true;
2484

    
2485
		if ($noadvoptions == false || $l7_present)
2486
			if ((isset($rule['source-track']) and $rule['source-track'] <> "") or
2487
			    (isset($rule['max']) and $rule['max'] <> "") or
2488
			    (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") or
2489
			    (isset($rule['max-src-states']) and $rule['max-src-states'] <> "") or
2490
			    ((in_array($rule['protocol'], array("tcp","tcp/udp"))) and
2491
			     ((isset($rule['statetimeout']) and $rule['statetimeout'] <> "") or
2492
			      (isset($rule['max-src-conn']) and $rule['max-src-conn'] <> "") or
2493
			      (isset($rule['max-src-conn-rate']) and $rule['max-src-conn-rate'] <> "") or
2494
			      (isset($rule['max-src-conn-rates']) and $rule['max-src-conn-rates'] <> ""))) or
2495
			    isset($rule['sloppy']) or isset($rule['nopfsync']) or $l7_present) {
2496
					$aline['flags'] .= "( ";
2497
					if (isset($rule['sloppy']))
2498
						$aline['flags'] .= "sloppy ";
2499
					if (isset($rule['nopfsync']))
2500
						$aline['flags'] .= "no-sync ";
2501
					if (isset($rule['source-track']) and $rule['source-track'] <> "")
2502
						$aline['flags'] .= "source-track rule ";
2503
					if (isset($rule['max']) and $rule['max'] <> "")
2504
						$aline['flags'] .= "max " . $rule['max'] . " ";
2505
					if (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "")
2506
						$aline['flags'] .= "max-src-nodes " . $rule['max-src-nodes'] . " ";
2507
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2508
							and isset($rule['max-src-conn']) 
2509
							and $rule['max-src-conn'] <> "")
2510
						$aline['flags'] .= "max-src-conn " . $rule['max-src-conn'] . " ";
2511
					if (isset($rule['max-src-states']) and $rule['max-src-states'] <> "")
2512
						$aline['flags'] .= "max-src-states " . $rule['max-src-states'] . " ";
2513
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2514
							and isset($rule['statetimeout']) 
2515
							and $rule['statetimeout'] <> "")
2516
						$aline['flags'] .= "tcp.established " . $rule['statetimeout'] . " ";
2517
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2518
							and isset($rule['max-src-conn-rate'])
2519
							and $rule['max-src-conn-rate'] <> ""
2520
							and isset($rule['max-src-conn-rates'])
2521
							and $rule['max-src-conn-rates'] <> "") {
2522
						$aline['flags'] .= "max-src-conn-rate " . $rule['max-src-conn-rate'] . " ";
2523
						$aline['flags'] .= "/" . $rule['max-src-conn-rates'] . ", overload <virusprot> flush global ";
2524
					}
2525

    
2526
					if(!empty($aline['divert']))
2527
						$aline['flags'] .= "max-packets 8 ";
2528

    
2529
					$aline['flags'] .= " ) ";
2530
				}
2531
	}
2532
	if($rule['defaultqueue'] <> "") {
2533
		$aline['queue'] = " queue (".$rule['defaultqueue'];
2534
		if($rule['ackqueue'] <> "")
2535
			$aline['queue'] .= ",".$rule['ackqueue'];
2536
		$aline['queue'] .= ") ";
2537
	}
2538
	if($rule['dnpipe'] <> "") {
2539
		if (!empty($dummynet_name_list[$rule['dnpipe']])) {
2540
			if($dummynet_name_list[$rule['dnpipe']][0] == "?") {
2541
				$aline['dnpipe'] = " dnqueue( ";
2542
				$aline['dnpipe'] .= substr($dummynet_name_list[$rule['dnpipe']],1);
2543
				if($rule['pdnpipe'] <> "")
2544
					$aline['dnpipe'] .= ",".substr($dummynet_name_list[$rule['pdnpipe']], 1);
2545
			} else {
2546
				$aline['dnpipe'] = " dnpipe ( " . $dummynet_name_list[$rule['dnpipe']];
2547
				if($rule['pdnpipe'] <> "")
2548
					$aline['dnpipe'] .= "," . $dummynet_name_list[$rule['pdnpipe']];
2549
			}
2550
			$aline['dnpipe'] .= ") ";
2551
		}
2552
	}
2553

    
2554
	/* is a time based rule schedule attached? */
2555
	if(!empty($rule['sched']) && !empty($config['schedules'])) {
2556
		$aline['schedlabel'] = "";
2557
		foreach ($config['schedules']['schedule'] as $sched) {
2558
			if($sched['name'] == $rule['sched']) {
2559
				if(!filter_get_time_based_rule_status($sched)) {
2560
					if(!isset($config['system']['schedule_states']))
2561
						mwexec("/sbin/pfctl -y {$sched['schedlabel']}");
2562
					return "# schedule finished - {$rule['descr']}";
2563
				} else if($g['debug'])
2564
					log_error("[TDR DEBUG] status true -- rule type '$type'");
2565

    
2566
				$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
2567
				break;
2568
			}
2569
		}
2570
	}
2571

    
2572
	if (!empty($rule['tracker']))
2573
		$aline['tracker'] = "tracker {$rule['tracker']} ";
2574

    
2575
	$line = "";
2576
	/* exception(s) to a user rules can go here. */
2577
	/* rules with a gateway or pool should create another rule for routing to vpns */
2578
	if((($aline['route'] <> "") && (trim($aline['type']) == "pass") && strstr($dst, "any")) && (!isset($config['system']['disablenegate']))) {
2579
		/* negate VPN/PPTP/PPPoE/Static Route networks for load balancer/gateway rules */
2580
		$negate_networks = " to <negate_networks> " . filter_generate_port($rule, "destination");
2581
		$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] .
2582
			$aline['interface'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] .
2583
			$negate_networks . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] .
2584
			$aline['vlanprio'] . $aline['vlanprioset'] . $aline['dscp'] . $aline['tracker'] . $aline['allowopts'] . $aline['flags'] .
2585
			$aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'] .
2586
			" label \"NEGATE_ROUTE: Negate policy routing for destination\"\n";
2587

    
2588
	}
2589
	/* piece together the actual user rule */
2590
	$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
2591
		$aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
2592
		$aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] . $aline['tracker'] .
2593
		$aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
2594

    
2595
	unset($aline);
2596

    
2597
	return $line;
2598
}
2599

    
2600
function filter_rules_generate() {
2601
	global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
2602

    
2603
	$fix_rule_label = 'fix_rule_label';
2604
	$increment_tracker = 'filter_rule_tracker';
2605

    
2606
	update_filter_reload_status(gettext("Creating default rules"));
2607
	if(isset($config['system']['developerspew'])) {
2608
		$mt = microtime();
2609
		echo "filter_rules_generate() being called $mt\n";
2610
	}
2611

    
2612
	$pptpdcfg = $config['pptpd'];
2613

    
2614
	$ipfrules = "";
2615
	$ipfrules .= discover_pkg_rules("pfearly");
2616

    
2617
	/* relayd */
2618
	$ipfrules .= "anchor \"relayd/*\"\n";
2619
	/* OpenVPN user rules from radius */
2620
	$ipfrules .= "anchor \"openvpn/*\"\n";
2621
	/* IPSec user rules from radius */
2622
	$ipfrules .= "anchor \"ipsec/*\"\n";
2623
	# BEGIN OF firewall rules
2624
	/* default block logging? */
2625
	$log = array(); 
2626
	if(!isset($config['syslog']['nologdefaultblock']))
2627
		$log['block'] = "log";
2628
	if(isset($config['syslog']['nologdefaultpass']))
2629
		$log['pass'] = "log";
2630

    
2631
	$saved_tracker = $tracker;
2632

    
2633
	if(!isset($config['system']['ipv6allow'])) {
2634
		$ipfrules .= "# Block all IPv6\n";
2635
		$ipfrules .= "block in {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2636
		$ipfrules .= "block out {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2637
	}
2638

    
2639
	$saved_tracker += 100;
2640
	$tracker = $saved_tracker;
2641

    
2642
	$ipfrules .= <<<EOD
2643
#---------------------------------------------------------------------------
2644
# default deny rules
2645
#---------------------------------------------------------------------------
2646
block in {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2647
block out {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2648
block in {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2649
block out {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2650

    
2651
# IPv6 ICMP is not auxilary, it is required for operation
2652
# See man icmp6(4)
2653
# 1    unreach         Destination unreachable
2654
# 2    toobig          Packet too big
2655
# 128  echoreq         Echo service request
2656
# 129  echorep         Echo service reply
2657
# 133  routersol       Router solicitation
2658
# 134  routeradv       Router advertisement
2659
# 135  neighbrsol      Neighbor solicitation
2660
# 136  neighbradv      Neighbor advertisement
2661
pass {$log['pass']} quick inet6 proto ipv6-icmp from any to any icmp6-type {1,2,135,136} tracker {$increment_tracker($tracker)} keep state
2662

    
2663
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
2664
pass out {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2665
pass out {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2666
pass in {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2667
pass in {$log['pass']} quick inet6 proto ipv6-icmp from ff02::/16 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2668
pass in {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2669

    
2670
# We use the mighty pf, we cannot be fooled.
2671
block {$log['block']} quick inet proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2672
block {$log['block']} quick inet proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2673
block {$log['block']} quick inet6 proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2674
block {$log['block']} quick inet6 proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2675

    
2676
# Snort package
2677
block {$log['block']} quick from <snort2c> to any tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2678
block {$log['block']} quick from any to <snort2c> tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2679

    
2680
EOD;
2681

    
2682
	$saved_tracker += 100;
2683
	$tracker = $saved_tracker;
2684

    
2685
	$ipfrules .= filter_process_carp_rules($log);
2686

    
2687
	$saved_tracker += 100;
2688
	$tracker = $saved_tracker;
2689

    
2690
	$ipfrules .= "\n# SSH lockout\n";
2691
	if(is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
2692
		$ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port ";
2693
		$ipfrules .= $config['system']['ssh']['port'];
2694
		$ipfrules .= " tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
2695
	} else {
2696
		if($config['system']['ssh']['port'] <> "")
2697
			$sshport = $config['system']['ssh']['port'];
2698
		else
2699
			$sshport = 22;
2700
		if($sshport)
2701
			$ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port {$sshport} tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
2702
	}
2703

    
2704
	$saved_tracker += 50;
2705
	$tracker = $saved_tracker;
2706

    
2707
	$ipfrules .= "\n# webConfigurator lockout\n";
2708
	if(!$config['system']['webgui']['port']) {
2709
		if($config['system']['webgui']['protocol'] == "http")
2710
			$webConfiguratorlockoutport = "80";
2711
		else
2712
			$webConfiguratorlockoutport = "443";
2713
	} else {
2714
		$webConfiguratorlockoutport = $config['system']['webgui']['port'];
2715
	}
2716
	if($webConfiguratorlockoutport)
2717
		$ipfrules .= "block in {$log['block']} quick proto tcp from <webConfiguratorlockout> to (self) port {$webConfiguratorlockoutport} tracker {$increment_tracker($tracker)} label \"webConfiguratorlockout\"\n";
2718

    
2719
	$saved_tracker += 100;
2720
	$tracker = $saved_tracker;
2721

    
2722
	/*
2723
	 * Support for allow limiting of TCP connections by establishment rate
2724
	 * Useful for protecting against sudden outburts, etc.
2725
	 */
2726
	$ipfrules .= "block in {$log['block']} quick from <virusprot> to any tracker 1000000400 label \"virusprot overload table\"\n";
2727

    
2728
	$saved_tracker += 100;
2729
	$tracker = $saved_tracker;
2730

    
2731
	/* if captive portal is enabled, ensure that access to this port
2732
	 * is allowed on a locked down interface
2733
	 */
2734
	if(is_array($config['captiveportal'])) {
2735
		foreach ($config['captiveportal'] as $cpcfg) {
2736
			if(!isset($cpcfg['enable']))
2737
				continue;
2738
			$cpinterfaces = explode(",", $cpcfg['interface']);
2739
			$cpiflist = array();
2740
			$cpiplist = array();
2741
			foreach ($cpinterfaces as $cpifgrp) {
2742
				if(!isset($FilterIflist[$cpifgrp]))
2743
					continue;
2744
				$tmpif = get_real_interface($cpifgrp);
2745
				if(!empty($tmpif)) {
2746
					$cpiflist[] = "{$tmpif}";
2747
					$cpipm = get_interface_ip($cpifgrp);
2748
					if(is_ipaddr($cpipm)) {
2749
						$carpif = link_ip_to_carp_interface($cpipm);
2750
						if (!empty($carpif)) {
2751
							$cpiflist[] = $carpif;
2752
							$carpsif = explode(" ", $carpif);
2753
							foreach ($carpsif as $cpcarp) {
2754
								$carpip = find_interface_ip($cpcarp);
2755
								if (is_ipaddr($carpip))
2756
									$cpiplist[] = $carpip;
2757
							}
2758
						}
2759
						$cpiplist[] = $cpipm;
2760
					}
2761
				}
2762
			}
2763
			if (count($cpiplist) > 0 && count($cpiflist) > 0) {
2764
				$cpinterface = implode(" ", $cpiflist);
2765
				$cpaddresses = implode(" ", $cpiplist);
2766
				$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
2767
				$listenporthttp  = $cpcfg['listenporthttp']  ? $cpcfg['listenporthttp']  : $cpcfg['zoneid'];
2768
				$portalias = $listenporthttps;
2769
				$portalias .= " {$listenporthttp}";
2770
				$ipfrules .= "pass in {$log['pass']} quick on { {$cpinterface} } proto tcp from any to { {$cpaddresses} } port { {$portalias} } tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
2771
				$ipfrules .= "pass out {$log['pass']} quick on { {$cpinterface} } proto tcp from any to any flags any tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
2772
			}
2773
		}
2774
	}
2775

    
2776
	$bogontableinstalled = 0;
2777
	foreach ($FilterIflist as $on => $oc) {
2778
		/* XXX: Not static but give a step of 1000 for each interface to at least be able to match rules. */
2779
		$saved_tracker += 1000;
2780
		$tracker = $saved_tracker;
2781

    
2782
		/* block bogon networks */
2783
		/* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
2784
		/* file is automatically in cron every 3000 minutes */
2785
		if(!isset($config['syslog']['nologbogons']))
2786
			$bogonlog = "log";
2787
		else
2788
			$bogonlog = "";
2789

    
2790
		if(isset($config['interfaces'][$on]['blockbogons'])) {
2791
			$ipfrules .= <<<EOD
2792
# block bogon networks (IPv4)
2793
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
2794
block in $bogonlog quick on \${$oc['descr']} from <bogons> to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("block bogon IPv4 networks from {$oc['descr']}")}"
2795

    
2796
EOD;
2797

    
2798
			if(isset($config['system']['ipv6allow'])) {
2799
				$ipfrules .= <<<EOD
2800
# block bogon networks (IPv6)
2801
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
2802
block in $bogonlog quick on \${$oc['descr']} from <bogonsv6> to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("block bogon IPv6 networks from {$oc['descr']}")}"
2803

    
2804
EOD;
2805
			}
2806
		}
2807

    
2808

    
2809
		$saved_tracker += 10;
2810
		$tracker = $saved_tracker;
2811

    
2812
		if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
2813
			$ipfrules .= <<<EOD
2814
# allow our DHCPv6 client out to the {$oc['descr']}
2815
pass in {$log['pass']} quick on \${$oc['descr']} proto udp from fe80::/10 port = 546 to fe80::/10 port = 546 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcpv6 client in {$oc['descr']}")}"
2816
pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 547 to any port = 546 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcpv6 client in {$oc['descr']}")}"
2817
pass out {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 546 to any port = 547 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcpv6 client out {$oc['descr']}")}"
2818

    
2819
EOD;
2820
		}
2821

    
2822
		$saved_tracker += 10;
2823
		$tracker = $saved_tracker;
2824

    
2825
		$isbridged = false;
2826
		if(is_array($config['bridges']['bridged'])) {
2827
			foreach ($config['bridges']['bridged'] as $oc2) {
2828
				if(stristr($oc2['members'], $on)) {
2829
					$isbridged = true;
2830
					break;
2831
				}
2832
			}
2833
		}
2834

    
2835
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2836
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
2837

    
2838
		/* block private networks ? */
2839
		if(!isset($config['syslog']['nologprivatenets']))
2840
			$privnetlog = "log";
2841
		else
2842
			$privnetlog = "";
2843

    
2844
		$saved_tracker += 10;
2845
		$tracker = $saved_tracker;
2846

    
2847
		if(isset($config['interfaces'][$on]['blockpriv'])) {
2848
			if($isbridged == false) {
2849
				$ipfrules .= <<<EOD
2850
# block anything from private networks on interfaces with the option set
2851
block in $privnetlog quick on \${$oc['descr']} from 10.0.0.0/8 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 10/8")}"
2852
block in $privnetlog quick on \${$oc['descr']} from 127.0.0.0/8 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 127/8")}"
2853
block in $privnetlog quick on \${$oc['descr']} from 100.64.0.0/10 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 100.64/10")}"
2854
block in $privnetlog quick on \${$oc['descr']} from 172.16.0.0/12 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 172.16/12")}"
2855
block in $privnetlog quick on \${$oc['descr']} from 192.168.0.0/16 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block private networks from {$oc['descr']} block 192.168/16")}"
2856
block in $privnetlog quick on \${$oc['descr']} from fc00::/7 to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Block ULA networks from {$oc['descr']} block fc00::/7")}"
2857

    
2858
EOD;
2859
			}
2860
		}
2861

    
2862
		$saved_tracker += 10;
2863
		$tracker = $saved_tracker;
2864

    
2865
		switch ($oc['type']) {
2866
		case "pptp":
2867
				$ipfrules .= <<<EOD
2868
# allow PPTP client
2869
pass in {$log['pass']} on \${$oc['descr']} proto tcp from any to any port = 1723 flags S/SA modulate state tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
2870
pass in {$log['pass']} on \${$oc['descr']} proto gre from any to any keep state tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
2871

    
2872
EOD;
2873
			break;
2874
		case "dhcp":
2875
			$ipfrules .= <<<EOD
2876
# allow our DHCP client out to the {$oc['descr']}
2877
pass in {$log['pass']} on \${$oc['descr']} proto udp from any port = 67 to any port = 68 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
2878
pass out {$log['pass']} on \${$oc['descr']} proto udp from any port = 68 to any port = 67 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
2879
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2880

    
2881
EOD;
2882

    
2883
			break;
2884
		case "pppoe":
2885
		case "none":
2886
			/* XXX: Nothing to do in this case?! */
2887
			break;
2888
		default:
2889
			/* allow access to DHCP server on interfaces */
2890
			if(isset($config['dhcpd'][$on]['enable'])) {
2891
				$ipfrules .= <<<EOD
2892
# allow access to DHCP server on {$oc['descr']}
2893
pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to 255.255.255.255 port = 67 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
2894

    
2895
EOD;
2896
				if (is_ipaddrv4($oc['ip'])) {
2897
					$ipfrules .= <<<EOD
2898
pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to {$oc['ip']} port = 67 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
2899
pass out {$log['pass']} quick on \${$oc['descr']} proto udp from {$oc['ip']} port = 67 to any port = 68 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
2900

    
2901
EOD;
2902
				}
2903

    
2904
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2905
					$ipfrules .= <<<EOD
2906
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2907
pass in {$log['pass']} quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 519 tracker {$increment_tracker($tracker)} label "allow access to DHCP failover"
2908
pass in {$log['pass']} quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 520 tracker {$increment_tracker($tracker)} label "allow access to DHCP failover"
2909

    
2910
EOD;
2911
				}
2912

    
2913
			}
2914
			break;
2915
		}
2916

    
2917
		$saved_tracker += 10;
2918
		$tracker = $saved_tracker;
2919
		switch($oc['type6']) {
2920
		case "6rd":
2921
			$ipfrules .= <<<EOD
2922
# allow our proto 41 traffic from the 6RD border relay in
2923
pass in {$log['pass']} on \${$oc['descr']} proto 41 from {$config['interfaces'][$on]['gateway-6rd']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6rd on {$oc['descr']}")}"
2924
pass out {$log['pass']} on \${$oc['descr']} proto 41 from any to {$config['interfaces'][$on]['gateway-6rd']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6rd on {$oc['descr']}")}"
2925

    
2926
EOD;
2927
		/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
2928
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2929
			$ipfrules .= <<<EOD
2930
pass in {$log['pass']} on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6rd traffic in for 6rd on {$oc['descr']}")}"
2931
pass out {$log['pass']} on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6rd traffic out for 6rd on {$oc['descr']}")}"
2932

    
2933
EOD;
2934
		}
2935
			break;
2936
		case "6to4":
2937
			if (is_ipaddrv4($oc['ip'])) {
2938
			$ipfrules .= <<<EOD
2939
# allow our proto 41 traffic from the 6to4 border relay in
2940
pass in {$log['pass']} on \${$oc['descr']} proto 41 from any to {$oc['ip']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
2941
pass out {$log['pass']} on \${$oc['descr']} proto 41 from {$oc['ip']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
2942

    
2943
EOD;
2944
		}
2945
		/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
2946
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2947
			$ipfrules .= <<<EOD
2948
pass in {$log['pass']} on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
2949
pass out {$log['pass']} on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
2950

    
2951
EOD;
2952
		}
2953
			break;
2954
		default:
2955
			if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface']) 
2956
				|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
2957
				$ipfrules .= <<<EOD
2958
# allow access to DHCPv6 server on {$oc['descr']}
2959
# We need inet6 icmp for stateless autoconfig and dhcpv6
2960
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to fe80::/10 port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
2961
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
2962
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 547 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
2963
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from ff02::/16 to fe80::/10 port = 547 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
2964

    
2965
EOD;
2966
				if (is_ipaddrv6($oc['ipv6'])) {
2967
					$ipfrules .= <<<EOD
2968
pass in {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to {$oc['ipv6']} port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
2969
pass out {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from {$oc['ipv6']} port = 547 to fe80::/10 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
2970

    
2971
EOD;
2972
				}
2973
			}
2974
			break;
2975
		}
2976
	}
2977

    
2978
	$saved_tracker += 10;
2979
	$tracker = $saved_tracker;
2980

    
2981
	/*
2982
	 * NB: The loopback rules are needed here since the antispoof would take precedence then.
2983
	 *	If you ever add the 'quick' keyword to the antispoof rules above move the looback
2984
	 *	rules before them.
2985
	 */
2986
	$ipfrules .= <<<EOD
2987

    
2988
# loopback
2989
pass in {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
2990
pass out {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
2991
pass in {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
2992
pass out {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
2993
# let out anything from the firewall host itself and decrypted IPsec traffic
2994
pass out {$log['pass']} inet all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv4 from firewall host itself"
2995
pass out {$log['pass']} inet6 all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv6 from firewall host itself"
2996

    
2997
EOD;
2998

    
2999
	$saved_tracker += 100;
3000
	$tracker = $saved_tracker;
3001
	foreach ($FilterIflist as $ifdescr => $ifcfg) {
3002
		if(isset($ifcfg['virtual']))
3003
			continue;
3004

    
3005
		$gw = get_interface_gateway($ifdescr);
3006
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
3007
			$ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$ifcfg['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3008
			if (is_array($ifcfg['vips'])) {
3009
				foreach ($ifcfg['vips'] as $vip)
3010
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
3011
						$ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3012
					else
3013
						$ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !" . gen_subnet($vip['ip'], $vip['sn']) . "/{$vip['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3014
			}
3015
		}
3016

    
3017
		$gwv6 = get_interface_gateway_v6($ifdescr);
3018
		$stf = get_real_interface($ifdescr, "inet6");
3019
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
3020
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
3021
			$ipfrules .= "pass out {$log['pass']} route-to ( {$stf} {$gwv6} ) inet6 from {$ifcfg['ipv6']} to !{$ifcfg['ipv6']}/{$pdlen} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3022
			if (is_array($ifcfg['vips6'])) {
3023
				foreach ($ifcfg['vips6'] as $vip)
3024
					$ipfrules .= "pass out {$log['pass']} route-to ( {$stf} {$gwv6} ) inet6 from {$vip['ip']} to !{$vip['ip']}/{$pdlen} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3025
			}
3026
		}
3027
	}
3028

    
3029

    
3030
	$saved_tracker += 300;
3031
	$tracker = $saved_tracker;
3032
	/* add ipsec interfaces */
3033
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
3034
		$ipfrules .= "pass out {$log['pass']} on \$IPsec all tracker {$increment_tracker($tracker)} tracker {$increment_tracker($tracker)} keep state label \"IPsec internal host to host\"\n";
3035

    
3036
	$saved_tracker += 10;
3037
	$tracker = $saved_tracker;
3038
	if(is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
3039
		$alports = filter_get_antilockout_ports();
3040

    
3041
		if(count($config['interfaces']) > 1 && !empty($FilterIflist['lan']['if'])) {
3042
				/* if antilockout is enabled, LAN exists and has
3043
				 * an IP and subnet mask assigned
3044
				 */
3045
				$lanif = $FilterIflist['lan']['if'];
3046
				$ipfrules .= <<<EOD
3047
# make sure the user cannot lock himself out of the webConfigurator or SSH
3048
pass in {$log['pass']} quick on {$lanif} proto tcp from any to ({$lanif}) port { {$alports} } tracker {$increment_tracker($tracker)} keep state label "anti-lockout rule"
3049

    
3050
EOD;
3051
		} else if (count($config['interfaces']) == 1) {
3052
			/* single-interface deployment, add to WAN	*/
3053
			$wanif = $FilterIflist["wan"]['if'];
3054
			$ipfrules .= <<<EOD
3055
# make sure the user cannot lock himself out of the webConfigurator or SSH
3056
pass in {$log['pass']} quick on {$wanif} proto tcp from any to ({$wanif}) port { {$alports} } tracker {$increment_tracker($tracker)} keep state label "anti-lockout rule"
3057

    
3058
EOD;
3059
		}
3060
		unset($alports);
3061
	}
3062

    
3063
	$saved_tracker += 10;
3064
	$tracker = $saved_tracker;
3065
	/* PPTPd enabled? */
3066
	if($pptpdcfg['mode'] && ($pptpdcfg['mode'] != "off") && !isset($config['system']['disablevpnrules'])) {
3067
		if($pptpdcfg['mode'] == "server")
3068
			$pptpdtarget = get_interface_ip();
3069
		else
3070
			$pptpdtarget = $pptpdcfg['redir'];
3071
		if(is_ipaddr($pptpdtarget) and is_array($FilterIflist['wan'])) {
3072
			$ipfrules .= <<<EOD
3073
# PPTPd rules
3074
pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto tcp from any to $pptpdtarget port = 1723 tracker {$increment_tracker($tracker)} modulate state label "{$fix_rule_label("allow pptpd {$pptpdtarget}")}"
3075
pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto gre from any to any tracker {$increment_tracker($tracker)} keep state label "allow gre pptpd"
3076

    
3077
EOD;
3078

    
3079
		} else {
3080
			/*	  this shouldnt ever happen but instead of breaking the clients ruleset
3081
			 *	  log an error.
3082
			 */
3083
			log_error("ERROR!  PPTP enabled but could not resolve the \$pptpdtarget");
3084
		}
3085
	}
3086

    
3087
	$saved_tracker += 10;
3088
	$tracker = $saved_tracker;
3089
	if(isset($config['nat']['rule']) && is_array($config['nat']['rule'])) {
3090
		foreach ($config['nat']['rule'] as $rule) {
3091
			if((!isset($config['system']['disablenatreflection']) || $rule['natreflection'] == "enable")
3092
			   && $rule['natreflection'] != "disable") {
3093
				$ipfrules .= "# NAT Reflection rules\n";
3094
				$ipfrules .= <<<EOD
3095
pass in {$log['pass']} inet tagged PFREFLECT tracker {$increment_tracker($tracker)} keep state label "NAT REFLECT: Allow traffic to localhost"
3096

    
3097
EOD;
3098
				break;
3099
			}
3100
		}
3101
	}
3102

    
3103
	if (isset($config['filter']['rule'])) {
3104
		/* Pre-cache all our rules so we only have to generate them once */
3105
		$rule_arr1 = array();
3106
		$rule_arr2 = array();
3107
		$rule_arr3 = array();
3108
		$vpn_and_ppp_ifs = array("l2tp", "pptp", "pppoe", "enc0", "openvpn");
3109
		/*
3110
		 * NB: The order must be: Floating rules, then interface group and then regular ones.
3111
		 */
3112
		foreach ($config['filter']['rule'] as $rule) {
3113
			update_filter_reload_status("Pre-caching {$rule['descr']}...");
3114
			if (isset ($rule['disabled']))
3115
				continue;
3116

    
3117
			if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
3118
				if (isset($rule['floating'])) {
3119
					$rule['ipprotocol'] = "inet";
3120
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3121
					$rule['ipprotocol'] = "inet6";
3122
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3123
				} else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
3124
					$rule['ipprotocol'] = "inet";
3125
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3126
					$rule['ipprotocol'] = "inet6";
3127
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3128
				} else {
3129
					$rule['ipprotocol'] = "inet";
3130
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3131
					$rule['ipprotocol'] = "inet6";
3132
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3133
				}
3134
				$rule['ipprotocol'] = "inet46";
3135
			} else {
3136
				if (isset($rule['floating']))
3137
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3138
				else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs))
3139
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3140
				else
3141
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3142
			}
3143
			if ($rule['sched'])
3144
				$time_based_rules = true;
3145
		}
3146

    
3147
		$ipfrules .= "\n# User-defined rules follow\n";
3148
		$ipfrules .= "\nanchor \"userrules/*\"\n";
3149
		/* Generate user rule lines */
3150
		foreach($rule_arr1 as $rule) {
3151
			if (isset($rule['disabled']))
3152
				continue;
3153
			if (!$rule['rule'])
3154
				continue;
3155
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3156
		}
3157
		foreach($rule_arr2 as $rule) {
3158
			if (isset($rule['disabled']))
3159
				continue;
3160
			if (!$rule['rule'])
3161
				continue;
3162
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3163
		}
3164
		foreach($rule_arr3 as $rule) {
3165
			if (isset($rule['disabled']))
3166
				continue;
3167
			if (!$rule['rule'])
3168
				continue;
3169
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3170
		}
3171
		unset($rule_arr1, $rule_arr2, $rule_arr3);
3172
	}
3173

    
3174
	$saved_tracker += 100;
3175
	$tracker = $saved_tracker;
3176

    
3177
	/*  pass traffic between statically routed subnets and the subnet on the
3178
	 *  interface in question to avoid problems with complicated routing
3179
	 *  topologies
3180
	 */
3181
	if(isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
3182
		$ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
3183
		foreach (get_staticroutes() as $route) {
3184
			$friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
3185
			if(is_array($FilterIflist[$friendly])) {
3186
				$oc = $FilterIflist[$friendly];
3187
				$routeent = explode("/", $route['network']);
3188
				unset($sa);
3189
				if (is_ipaddrv4($oc['ip'])) {
3190
					$sa = $oc['sa'];
3191
					$sn = $oc['sn'];
3192
				}
3193
				if ($sa && is_ipaddrv4($routeent[0])) {
3194
					$ipfrules .= <<<EOD
3195
pass {$log['pass']} quick on \${$oc['descr']} proto tcp from {$sa}/{$sn} to {$route['network']} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3196
pass {$log['pass']} quick on \${$oc['descr']} from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3197
pass {$log['pass']} quick on \${$oc['descr']} proto tcp from {$route['network']} to {$sa}/{$sn} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3198
pass {$log['pass']} quick on \${$oc['descr']} from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3199

    
3200
EOD;
3201
				}
3202
				unset($sa);
3203
				if (is_ipaddrv6($oc['ipv6'])) {
3204
					$sa = $oc['sav6'];
3205
					$sn = $oc['snv6'];
3206
				}
3207
				if ($sa && is_ipaddrv6($routeent[0])) {
3208
					$ipfrules .= <<<EOD
3209
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto tcp from {$sa}/{$sn} to {$route['network']} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3210
pass {$log['pass']} quick on \${$oc['descr']} inet6 from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3211
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto tcp from {$route['network']} to {$sa}/{$sn} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3212
pass {$log['pass']} quick on \${$oc['descr']} inet6 from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3213

    
3214
EOD;
3215
				}
3216
			}
3217
		}
3218
	}
3219

    
3220
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3221
	$saved_tracker += 100000;
3222
	$tracker = $saved_tracker;
3223
	$ipfrules .= filter_generate_ipsec_rules($log);
3224

    
3225
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3226

    
3227
	$saved_tracker += 200;
3228
	$tracker = $saved_tracker;
3229
	update_filter_reload_status("Creating uPNP rules...");
3230
	if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
3231
		if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable']))
3232
			$ipfrules .= "anchor \"miniupnpd\"\n";
3233

    
3234
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3235
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3236
			foreach($upnp_interfaces as $upnp_if) {
3237
				if (is_array($FilterIflist[$upnp_if])) {
3238
					$oc = $FilterIflist[$upnp_if];
3239
					unset($sa);
3240
					if($oc['ip']) {
3241
						$sa = $oc['sa'];
3242
						$sn = $oc['sn'];
3243
					}
3244
					if($sa) {
3245
						$ipfrules .= <<<EOD
3246
pass in {$log['pass']} on \${$oc['descr']} proto tcp from {$sa}/{$sn} to 239.255.255.250/32 port 1900 tracker {$increment_tracker($tracker)} keep state label "pass multicast traffic to miniupnpd"
3247

    
3248
EOD;
3249
					}
3250
				}
3251
			}
3252
		}
3253
	}
3254

    
3255

    
3256
	return $ipfrules;
3257
}
3258

    
3259
function filter_rules_spoofcheck_generate($ifname, $ifcfg, $log) {
3260
	global $g, $config, $tracker;
3261
	if(isset($config['system']['developerspew'])) {
3262
		$mt = microtime();
3263
		echo "filter_rules_spoofcheck_generate() being called $mt\n";
3264
	}
3265
	$ipfrules = "antispoof {$log['block']} for \${$ifcfg['descr']} tracker {$tracker}\n";
3266
	$tracker++;
3267

    
3268
	return $ipfrules;
3269
}
3270

    
3271
/* COMPAT Function */
3272
function tdr_install_cron($should_install) {
3273
	log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
3274
	filter_tdr_install_cron($should_install);
3275
}
3276

    
3277
/****f* filter/filter_tdr_install_cron
3278
 * NAME
3279
 *   filter_tdr_install_cron
3280
 * INPUTS
3281
 *   $should_install true if the cron entry should be installed, false
3282
 *   if the entry should be removed if it is present
3283
 * RESULT
3284
 *   none
3285
 ******/
3286
function filter_tdr_install_cron($should_install) {
3287
	global $config, $g;
3288

    
3289
	if($g['booting']==true)
3290
		return;
3291

    
3292
	if (!is_array($config['cron']))
3293
		$config['cron'] = array();
3294
	if (!is_array($config['cron']['item']))
3295
		$config['cron']['item'] = array();
3296

    
3297
	$x=0;
3298
	$is_installed = false;
3299
	foreach($config['cron']['item'] as $item) {
3300
		if (strstr($item['command'], "filter_configure_sync")) {
3301
			$is_installed = true;
3302
			break;
3303
		}
3304
		$x++;
3305
	}
3306

    
3307
	switch($should_install) {
3308
		case true:
3309
			if (!$is_installed) {
3310
				$cron_item = array();
3311
				$cron_item['minute'] = "0,15,30,45";
3312
				$cron_item['hour'] = "*";
3313
				$cron_item['mday'] = "*";
3314
				$cron_item['month'] = "*";
3315
				$cron_item['wday'] = "*";
3316
				$cron_item['who'] = "root";
3317
				$cron_item['command'] = "/etc/rc.filter_configure_sync";
3318
				$config['cron']['item'][] = $cron_item;
3319
				write_config(gettext("Installed 15 minute filter reload for Time Based Rules"));
3320
				configure_cron();
3321
			}
3322
			break;
3323
		case false:
3324
			if ($is_installed == true) {
3325
				unset($config['cron']['item'][$x]);
3326
				write_config(gettext("Removed 15 minute filter reload for Time Based Rules"));
3327
				configure_cron();
3328
			}
3329
			break;
3330
	}
3331
}
3332

    
3333
/****f* filter/filter_get_time_based_rule_status
3334
 * NAME
3335
 *   filter_get_time_based_rule_status
3336
 * INPUTS
3337
 *   xml schedule block
3338
 * RESULT
3339
 *   true/false - true if the rule should be installed
3340
 ******/
3341
/*
3342
 <schedules>
3343
   <schedule>
3344
     <name>ScheduleMultipleTime</name>
3345
     <descr>main descr</descr>
3346
     <time>
3347
       <position>0,1,2</position>
3348
       <hour>0:0-24:0</hour>
3349
       <desc>time range 2</desc>
3350
     </time>
3351
     <time>
3352
       <position>4,5,6</position>
3353
       <hour>0:0-24:0</hour>
3354
       <desc>time range 1</desc>
3355
     </time>
3356
   </schedule>
3357
 </schedules>
3358
*/
3359
function filter_get_time_based_rule_status($schedule) {
3360

    
3361
	/* no schedule? rule should be installed */
3362
	if (empty($schedule))
3363
		return true;
3364
	/*
3365
	 * iterate through time blocks and determine
3366
	 * if the rule should be installed or not.
3367
	 */
3368
	foreach($schedule['timerange'] as $timeday) {
3369
		if (empty($timeday['month']))
3370
			$monthstatus = true;
3371
		else
3372
			$monthstatus = filter_tdr_month($timeday['month']);
3373
		if (empty($timeday['day']))
3374
			$daystatus = true;
3375
		else
3376
			$daystatus = filter_tdr_day($timeday['day']);
3377
		if (empty($timeday['hour']))
3378
			$hourstatus = true;
3379
		else
3380
			$hourstatus = filter_tdr_hour($timeday['hour']);
3381
		if (empty($timeday['position']))
3382
			$positionstatus = true;
3383
		else
3384
			$positionstatus = filter_tdr_position($timeday['position']);
3385

    
3386
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3387
			return true;
3388
	}
3389

    
3390
	return false;
3391
}
3392

    
3393
function filter_tdr_day($schedule) {
3394
	global $g;
3395

    
3396
	if($g['debug'])
3397
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3398

    
3399
	/*
3400
	 * Calculate day of month.
3401
	 * IE: 29th of may
3402
	 */
3403
	$date = date("d");
3404
	$defined_days = explode(",", $schedule);
3405
	foreach($defined_days as $dd) {
3406
		if ($date == $dd)
3407
			return true;
3408
	}
3409
	return false;
3410
}
3411
function filter_tdr_hour($schedule) {
3412
	global $g;
3413

    
3414
	/* $schedule should be a string such as 16:00-19:00 */
3415
	$tmp = explode("-", $schedule);
3416
	$starting_time = strtotime($tmp[0]);
3417
	$ending_time = strtotime($tmp[1]);
3418
	$now = strtotime("now");
3419
	if($g['debug'])
3420
		log_error("[TDR DEBUG] S: $starting_time E: $ending_time N: $now");
3421
	if($now >= $starting_time and $now < $ending_time)
3422
		return true;
3423
	return false;
3424
}
3425

    
3426
function filter_tdr_position($schedule) {
3427
	global $g;
3428

    
3429
	/*
3430
	 * Calculate position, ie: day of week.
3431
	 * Sunday = 7, Monday = 1, Tuesday = 2
3432
	 * Weds = 3, Thursday = 4, Friday = 5,
3433
	 * Saturday = 6
3434
	 * ...
3435
	 */
3436
	$weekday = date("w");
3437
	if($g['debug'])
3438
		log_error("[TDR DEBUG] filter_tdr_position($schedule) $weekday");
3439
	if($weekday == 0)
3440
		$weekday = 7;
3441
	$schedule_days = explode(",", $schedule);
3442
	foreach($schedule_days as $day) {
3443
		if($day == $weekday)
3444
			return true;
3445
	}
3446
	return false;
3447
}
3448

    
3449
function filter_tdr_month($schedule) {
3450
	global $g;
3451

    
3452
	/*
3453
	 * Calculate month
3454
	 */
3455
	$todays_month = date("n");
3456
	$months = explode(",", $schedule);
3457
	if($g['debug'])
3458
		log_error("[TDR DEBUG] filter_tdr_month($schedule)");
3459
	foreach($months as $month) {
3460
		if($month == $todays_month)
3461
			return true;
3462
	}
3463
	return false;
3464
}
3465

    
3466
function filter_setup_logging_interfaces() {
3467
	global $config, $FilterIflist;
3468

    
3469
	if(isset($config['system']['developerspew'])) {
3470
		$mt = microtime();
3471
		echo "filter_setup_logging_interfaces() being called $mt\n";
3472
	}
3473
	$rules = "";
3474
	if (isset($FilterIflist['lan']))
3475
		$rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
3476
	else if (isset($FilterIflist['wan']))
3477
		$rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
3478

    
3479
	return $rules;
3480
}
3481

    
3482
function filter_process_carp_rules($log) {
3483
	global $g, $config, $tracker;
3484

    
3485
	if(isset($config['system']['developerspew'])) {
3486
		$mt = microtime();
3487
		echo "filter_process_carp_rules() being called $mt\n";
3488
	}
3489

    
3490
	$increment_tracker = 'filter_rule_tracker';
3491
	$lines = "";
3492
	/* return if there are no carp configured items */
3493
	if (!empty($config['hasync']) or !empty($config['virtualip']['vip'])) {
3494
		$lines .= "block in {$log['block']} quick proto carp from (self) to any tracker {$increment_tracker($tracker)}\n";
3495
		$lines .= "pass {$log['pass']} quick proto carp tracker {$increment_tracker($tracker)}\n";
3496
	}
3497
	return $lines;
3498
}
3499

    
3500
/* Generate IPSEC Filter Items */
3501
function filter_generate_ipsec_rules($log = array()) {
3502
	global $config, $g, $FilterIflist, $tracker;
3503

    
3504
	if(isset($config['system']['developerspew'])) {
3505
		$mt = microtime();
3506
		echo "filter_generate_ipsec_rules() being called $mt\n";
3507
	}
3508

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

    
3512
	$increment_tracker = 'filter_rule_tracker';
3513

    
3514
	$ipfrules = "\n# VPN Rules\n";
3515
	/* Is IP Compression enabled? */
3516
	if(isset($config['ipsec']['ipcomp']))
3517
		exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=1");
3518
	else
3519
		exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=0");
3520

    
3521
	if(isset($config['ipsec']['enable']) &&
3522
		is_array($config['ipsec']['phase1'])) {
3523
		/* step through all phase1 entries */
3524
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
3525
			$tracker += 10;
3526

    
3527
			if(isset ($ph1ent['disabled']))
3528
				continue;
3529
			/* determine local and remote peer addresses */
3530
			if(!isset($ph1ent['mobile'])) {
3531
				if (!function_exists('ipsec_get_phase1_dst'))
3532
					require_once("ipsec.inc");
3533
				$rgip = ipsec_get_phase1_dst($ph1ent);
3534
				if(!$rgip) {
3535
					$ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n";
3536
					continue;
3537
				}
3538
			} else
3539
				$rgip = " any ";
3540
			/* Determine best description */
3541
			if($ph1ent['descr'])
3542
				$descr = $ph1ent['descr'];
3543
			else
3544
				$descr = $rgip;
3545
			/*
3546
			 * Step through all phase2 entries and determine
3547
			 * which protocols are in use with this peer
3548
			 */
3549
			$prot_used_esp = false;
3550
			$prot_used_ah  = false;
3551
			if(is_array($config['ipsec']['phase2'])) {
3552
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
3553
					/* only evaluate ph2's bound to our ph1 */
3554
					if($ph2ent['ikeid'] != $ph1ent['ikeid'])
3555
						continue;
3556
					if($ph2ent['protocol'] == 'esp')
3557
						$prot_used_esp = true;
3558
					if($ph2ent['protocol'] == 'ah')
3559
						$prot_used_ah = true;
3560
				}
3561
			}
3562

    
3563
			if (strstr($ph1ent['interface'], "_vip"))
3564
				list($parentinterface, $vhid) = explode("_vhid", $ph1ent['interface']);
3565
			else
3566
				$parentinterface = $ph1ent['interface'];
3567
			if (empty($FilterIflist[$parentinterface]['descr'])) {
3568
				$ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
3569
				continue;
3570
			}
3571

    
3572
			unset($gateway);
3573
			/* add endpoint routes to correct gateway on interface */
3574
			if((is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
3575
				$gateway = get_interface_gateway($parentinterface);
3576
				$interface = $FilterIflist[$parentinterface]['if'];
3577

    
3578
				$route_to = " route-to ( $interface $gateway ) ";
3579
				$reply_to = " reply-to ( $interface $gateway ) ";
3580

    
3581
			}
3582
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3583
				$gateway = get_interface_gateway_v6($parentinterface);
3584
				$interface = $FilterIflist[$parentinterface]['if'];
3585

    
3586
				$route_to = " route-to ( $interface $gateway ) ";
3587
				$reply_to = " reply-to ( $interface $gateway ) ";
3588
			}
3589

    
3590
			/* Just in case */
3591
			if((!is_ipaddr($gateway) || empty($interface))) {
3592
				$route_to = " ";
3593
				$reply_to = " ";
3594
			}
3595

    
3596
			/* Add rules to allow IKE to pass */
3597
			$shorttunneldescr = substr($descr, 0, 35);
3598
				$ipfrules .= <<<EOD
3599
pass out {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto udp from any to {$rgip} port = 500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound isakmp"
3600
pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto udp from {$rgip} to any port = 500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound isakmp"
3601

    
3602
EOD;
3603
			/* If NAT-T is enabled, add additional rules */
3604
			if($ph1ent['nat_traversal'] != "off" ) {
3605
				$ipfrules .= <<<EOD
3606
pass out {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto udp from any to {$rgip} port = 4500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound nat-t"
3607
pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto udp from {$rgip} to any port = 4500 tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound nat-t"
3608

    
3609
EOD;
3610
			}
3611
			/* Add rules to allow the protocols in use */
3612
			if($prot_used_esp == true) {
3613
				$ipfrules .= <<<EOD
3614
pass out {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto esp from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound esp proto"
3615
pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto esp from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound esp proto"
3616

    
3617
EOD;
3618
			}
3619
			if($prot_used_ah == true) {
3620
				$ipfrules .= <<<EOD
3621
pass out {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto ah from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound ah proto"
3622
pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto ah from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound ah proto"
3623

    
3624
EOD;
3625
			}
3626
		}
3627

    
3628
	}
3629
	return($ipfrules);
3630
}
3631

    
3632
function discover_pkg_rules($ruletype) {
3633
	global $config, $g, $aliases;
3634

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

    
3639
	$rules = "";
3640
	$files = glob("/usr/local/pkg/*.inc");
3641
	foreach($files as $pkg_inc) {
3642
		update_filter_reload_status(sprintf(gettext('Checking for %1$s PF hooks in package %2$s'), $ruletype, $pkg_inc));
3643
		$pkg = basename($pkg_inc, ".inc");
3644
		$pkg_generate_rules = "{$pkg}_generate_rules";
3645
		if (!function_exists($pkg_generate_rules))
3646
			require_once($pkg_inc);
3647
		if(function_exists($pkg_generate_rules)) {
3648
			update_filter_reload_status(sprintf(gettext('Processing early %1$s rules for package %2$s'), $ruletype, $pkg_inc));
3649
			$tmprules = $pkg_generate_rules("$ruletype");
3650
			file_put_contents("{$g['tmp_path']}/rules.test.packages", $aliases . $tmprules);
3651
			$status = mwexec("/sbin/pfctl -nf {$g['tmp_path']}/rules.test.packages");
3652
			if ($status <> 0) {
3653
				$errorrules = sprintf(gettext("There was an error while parsing the package filter rules for %s."), $pkg_inc) . "\n";
3654
				log_error($errorrules);
3655
				file_put_contents("{$g['tmp_path']}/rules.packages.{$pkg}", "#{$errorrules}\n{$tmprules}\n");
3656
				continue;
3657
			}
3658
			$rules .= $tmprules;
3659
		}
3660
	}
3661
	return $rules;
3662
}
3663

    
3664
function filter_get_antilockout_ports($wantarray = false) {
3665
	global $config;
3666

    
3667
	$lockoutports = array();
3668
	$guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
3669
	$guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
3670
	$lockoutports[] = $guiport;
3671

    
3672
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3673
		$lockoutports[] = "80";
3674

    
3675
	if (isset($config['system']['enablesshd']))
3676
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3677

    
3678
	if ($wantarray)
3679
		return $lockoutports;
3680
	else
3681
		return implode(" ", $lockoutports);
3682

    
3683
}
3684

    
3685
?>
(19-19/68)