Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ 0d0c01ca

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
	if(!isset($config['syslog']['nologdefaultblock']))
2626
		$log = "log";
2627
	else
2628
		$log = "";
2629

    
2630
	$saved_tracker = $tracker;
2631

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

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

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

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

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

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

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

    
2679
EOD;
2680

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

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

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

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

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

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

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

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

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

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

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

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

    
2789
		if(isset($config['interfaces'][$on]['blockbogons'])) {
2790
			$ipfrules .= <<<EOD
2791
# block bogon networks (IPv4)
2792
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
2793
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']}")}"
2794

    
2795
EOD;
2796

    
2797
			if(isset($config['system']['ipv6allow'])) {
2798
				$ipfrules .= <<<EOD
2799
# block bogon networks (IPv6)
2800
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
2801
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']}")}"
2802

    
2803
EOD;
2804
			}
2805
		}
2806

    
2807

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

    
2811
		if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
2812
			$ipfrules .= <<<EOD
2813
# allow our DHCPv6 client out to the {$oc['descr']}
2814
pass in {$log} 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']}")}"
2815
pass in {$log} 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']}")}"
2816
pass out {$log} 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']}")}"
2817

    
2818
EOD;
2819
		}
2820

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

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

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

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

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

    
2846
		if(isset($config['interfaces'][$on]['blockpriv'])) {
2847
			if($isbridged == false) {
2848
				$ipfrules .= <<<EOD
2849
# block anything from private networks on interfaces with the option set
2850
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")}"
2851
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")}"
2852
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")}"
2853
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")}"
2854
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")}"
2855
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")}"
2856

    
2857
EOD;
2858
			}
2859
		}
2860

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

    
2864
		switch ($oc['type']) {
2865
		case "pptp":
2866
				$ipfrules .= <<<EOD
2867
# allow PPTP client
2868
pass in {$log} 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']}")}"
2869
pass in {$log} 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']}")}"
2870

    
2871
EOD;
2872
			break;
2873
		case "dhcp":
2874
			$ipfrules .= <<<EOD
2875
# allow our DHCP client out to the {$oc['descr']}
2876
pass in {$log} 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']}")}"
2877
pass out {$log} 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']}")}"
2878
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2879

    
2880
EOD;
2881

    
2882
			break;
2883
		case "pppoe":
2884
		case "none":
2885
			/* XXX: Nothing to do in this case?! */
2886
			break;
2887
		default:
2888
			/* allow access to DHCP server on interfaces */
2889
			if(isset($config['dhcpd'][$on]['enable'])) {
2890
				$ipfrules .= <<<EOD
2891
# allow access to DHCP server on {$oc['descr']}
2892
pass in {$log} 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"
2893

    
2894
EOD;
2895
				if (is_ipaddrv4($oc['ip'])) {
2896
					$ipfrules .= <<<EOD
2897
pass in {$log} 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"
2898
pass out {$log} 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"
2899

    
2900
EOD;
2901
				}
2902

    
2903
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2904
					$ipfrules .= <<<EOD
2905
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2906
pass in {$log} 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"
2907
pass in {$log} 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"
2908

    
2909
EOD;
2910
				}
2911

    
2912
			}
2913
			break;
2914
		}
2915

    
2916
		$saved_tracker += 10;
2917
		$tracker = $saved_tracker;
2918
		switch($oc['type6']) {
2919
		case "6rd":
2920
			$ipfrules .= <<<EOD
2921
# allow our proto 41 traffic from the 6RD border relay in
2922
pass in {$log} 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']}")}"
2923
pass out {$log} 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']}")}"
2924

    
2925
EOD;
2926
		/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
2927
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2928
			$ipfrules .= <<<EOD
2929
pass in {$log} 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']}")}"
2930
pass out {$log} 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']}")}"
2931

    
2932
EOD;
2933
		}
2934
			break;
2935
		case "6to4":
2936
			if (is_ipaddrv4($oc['ip'])) {
2937
			$ipfrules .= <<<EOD
2938
# allow our proto 41 traffic from the 6to4 border relay in
2939
pass in {$log} 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']}")}"
2940
pass out {$log} 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']}")}"
2941

    
2942
EOD;
2943
		}
2944
		/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
2945
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2946
			$ipfrules .= <<<EOD
2947
pass in {$log} 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']}")}"
2948
pass out {$log} 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']}")}"
2949

    
2950
EOD;
2951
		}
2952
			break;
2953
		default:
2954
			if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface']) 
2955
				|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
2956
				$ipfrules .= <<<EOD
2957
# allow access to DHCPv6 server on {$oc['descr']}
2958
# We need inet6 icmp for stateless autoconfig and dhcpv6
2959
pass {$log} 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"
2960
pass {$log} 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"
2961
pass {$log} 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"
2962
pass {$log} 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"
2963

    
2964
EOD;
2965
				if (is_ipaddrv6($oc['ipv6'])) {
2966
					$ipfrules .= <<<EOD
2967
pass in {$log} 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"
2968
pass out {$log} 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"
2969

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

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

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

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

    
2996
EOD;
2997

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

    
3004
		$gw = get_interface_gateway($ifdescr);
3005
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
3006
			$ipfrules .= "pass out {$log} 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";
3007
			if (is_array($ifcfg['vips'])) {
3008
				foreach ($ifcfg['vips'] as $vip)
3009
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
3010
						$ipfrules .= "pass out {$log} 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";
3011
					else
3012
						$ipfrules .= "pass out {$log} 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";
3013
			}
3014
		}
3015

    
3016
		$gwv6 = get_interface_gateway_v6($ifdescr);
3017
		$stf = get_real_interface($ifdescr, "inet6");
3018
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
3019
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
3020
			$ipfrules .= "pass out {$log} 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";
3021
			if (is_array($ifcfg['vips6'])) {
3022
				foreach ($ifcfg['vips6'] as $vip)
3023
					$ipfrules .= "pass out {$log} 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";
3024
			}
3025
		}
3026
	}
3027

    
3028

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

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

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

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

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

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

    
3076
EOD;
3077

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

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

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

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

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

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

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

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

    
3199
EOD;
3200
				}
3201
				unset($sa);
3202
				if (is_ipaddrv6($oc['ipv6'])) {
3203
					$sa = $oc['sav6'];
3204
					$sn = $oc['snv6'];
3205
				}
3206
				if ($sa && is_ipaddrv6($routeent[0])) {
3207
					$ipfrules .= <<<EOD
3208
pass {$log} 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"
3209
pass {$log} 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"
3210
pass {$log} 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"
3211
pass {$log} 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"
3212

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

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

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

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

    
3233
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3234
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3235
			foreach($upnp_interfaces as $upnp_if) {
3236
				if (is_array($FilterIflist[$upnp_if])) {
3237
					$oc = $FilterIflist[$upnp_if];
3238
					unset($sa);
3239
					if($oc['ip']) {
3240
						$sa = $oc['sa'];
3241
						$sn = $oc['sn'];
3242
					}
3243
					if($sa) {
3244
						$ipfrules .= <<<EOD
3245
pass in {$log} 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"
3246

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

    
3254

    
3255
	return $ipfrules;
3256
}
3257

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

    
3267
	return $ipfrules;
3268
}
3269

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

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

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

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

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

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

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

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

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

    
3389
	return false;
3390
}
3391

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

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

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

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

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

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

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

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

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

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

    
3478
	return $rules;
3479
}
3480

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

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

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

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

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

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

    
3511
	$increment_tracker = 'filter_rule_tracker';
3512

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

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

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

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

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

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

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

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

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

    
3595
			/* Add rules to allow IKE to pass */
3596
			$shorttunneldescr = substr($descr, 0, 35);
3597
				$ipfrules .= <<<EOD
3598
pass out {$log} 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"
3599
pass in {$log} 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"
3600

    
3601
EOD;
3602
			/* If NAT-T is enabled, add additional rules */
3603
			if($ph1ent['nat_traversal'] != "off" ) {
3604
				$ipfrules .= <<<EOD
3605
pass out {$log} 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"
3606
pass in {$log} 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"
3607

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

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

    
3623
EOD;
3624
			}
3625
		}
3626

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

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

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

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

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

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

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

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

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

    
3682
}
3683

    
3684
?>
(19-19/67)