Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ 34bb5eb0

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 'pptp':
2140
						$pptpsav6 = gen_subnetv6($FilterIflist['pptp']['sav6'], $FilterIflist['pptp']['snv6']);
2141
						$pptpsnv6 = $FilterIflist['pptp']['snv6'];
2142
						$src = "{$pptpsav6}/{$pptpsnv6}";
2143
						break;
2144
					case 'pppoe':
2145
						if (is_array($FilterIflist['pppoe'])) {
2146
							$pppoesav6 = gen_subnetv6($FilterIflist['pppoe'][0]['ipv6'], $FilterIflist['pppoe'][0]['snv6']);
2147
							$pppoesnv6 = $FilterIflist['pppoe'][0]['snv6'];
2148
							$src = "{$pppoesav6}/{$pppoesnv6}";
2149
						}
2150
					}
2151
				if(isset($rule[$target]['not']))
2152
					$src = " !{$src}";
2153
			} else {
2154
				switch ($rule[$target]['network']) {
2155
					case 'wan':
2156
						$wansa = $FilterIflist['wan']['sa'];
2157
						if (!is_ipaddrv4($wansa))
2158
							return "";
2159
						$wansn = $FilterIflist['wan']['sn'];
2160
						$src = "{$wansa}/{$wansn}";
2161
						break;
2162
					case 'wanip':
2163
						$src = $FilterIflist["wan"]['ip'];
2164
						break;
2165
					case 'lanip':
2166
						$src = $FilterIflist["lan"]['ip'];
2167
						break;
2168
					case 'lan':
2169
						$lansa = $FilterIflist['lan']['sa'];
2170
						if (!is_ipaddrv4($lansa))
2171
							return "";
2172
						$lansn = $FilterIflist['lan']['sn'];
2173
						$src = "{$lansa}/{$lansn}";
2174
						break;
2175
					case 'pptp':
2176
						if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
2177
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
2178
						else
2179
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
2180
						if (empty($pptp_subnets))
2181
							return "";
2182
						$src = "{ " . implode(" ", $pptp_subnets) . " }";
2183
						break;
2184
					case 'pppoe':
2185
						/* XXX: This needs to be fixed somehow! */
2186
						if (is_array($FilterIflist['pppoe'])) {
2187
							$pppoesa = gen_subnet($FilterIflist['pppoe'][0]['ip'], $FilterIflist['pppoe'][0]['sn']);
2188
							$pppoesn = $FilterIflist['pppoe'][0]['sn'];
2189
							$src = "{$pppoesa}/{$pppoesn}";
2190
						}
2191
						break;
2192
				}
2193
				if(isset($rule[$target]['not']))
2194
					$src = " !{$src}";
2195
			}
2196
		}
2197
	} else if($rule[$target]['address']) {
2198
		$expsrc = alias_expand($rule[$target]['address']);
2199
		if(isset($rule[$target]['not']))
2200
			$not = "!";
2201
		else
2202
			$not = "";
2203
		$src = " {$not} {$expsrc}";
2204
	}
2205

    
2206
	$src .= filter_generate_port($rule, $target, $isnat);
2207

    
2208
	return $src;
2209
}
2210

    
2211
function filter_generate_user_rule($rule) {
2212
	global $config, $g, $FilterIflist, $GatewaysList;
2213
	global $layer7_rules_list, $dummynet_name_list;
2214

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

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

    
2261
	switch($rule['ipprotocol']) {
2262
	case "inet":
2263
		$aline['ipprotocol'] = "inet";
2264
		break;
2265
	case "inet6":
2266
		$aline['ipprotocol'] = "inet6";
2267
		break;
2268
	default:
2269
		$aline['ipprotocol'] = "";
2270
		break;
2271
	}
2272

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

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

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

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

    
2351
	/* source address */
2352
	$src = trim(filter_generate_address($rule, "source"));
2353
	if (empty($src) || ($src == "/")) {
2354
		return "# at the break!";
2355
	}
2356
	$aline['src'] = " from $src ";
2357

    
2358
	/* OS signatures */
2359
	if(($rule['protocol'] == "tcp") && ($rule['os'] <> ""))
2360
		$aline['os'] = " os \"{$rule['os']}\" ";
2361

    
2362
	/* destination address */
2363
	$dst = trim(filter_generate_address($rule, "destination"));
2364
	if (empty($dst) || ($dst == "/")) {
2365
		return "# returning at dst $dst == \"/\"";
2366
	}
2367
	$aline['dst'] = "to $dst ";
2368

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

    
2476
		if ($noadvoptions == false && isset($rule['nopfsync']))
2477
			$rule['nopfsync'] = true;
2478

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

    
2520
					if(!empty($aline['divert']))
2521
						$aline['flags'] .= "max-packets 8 ";
2522

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

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

    
2560
				$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
2561
				break;
2562
			}
2563
		}
2564
	}
2565

    
2566
	if (!empty($rule['tracker']))
2567
		$aline['tracker'] = "tracker {$rule['tracker']} ";
2568

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

    
2582
	}
2583
	/* piece together the actual user rule */
2584
	$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
2585
		$aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
2586
		$aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] . $aline['tracker'] .
2587
		$aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
2588

    
2589
	unset($aline);
2590

    
2591
	return $line;
2592
}
2593

    
2594
function filter_rules_generate() {
2595
	global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
2596

    
2597
	$fix_rule_label = 'fix_rule_label';
2598
	$increment_tracker = 'filter_rule_tracker';
2599

    
2600
	update_filter_reload_status(gettext("Creating default rules"));
2601
	if(isset($config['system']['developerspew'])) {
2602
		$mt = microtime();
2603
		echo "filter_rules_generate() being called $mt\n";
2604
	}
2605

    
2606
	$pptpdcfg = $config['pptpd'];
2607

    
2608
	$ipfrules = "";
2609
	$ipfrules .= discover_pkg_rules("pfearly");
2610

    
2611
	/* relayd */
2612
	$ipfrules .= "anchor \"relayd/*\"\n";
2613
	/* OpenVPN user rules from radius */
2614
	$ipfrules .= "anchor \"openvpn/*\"\n";
2615
	/* IPSec user rules from radius */
2616
	$ipfrules .= "anchor \"ipsec/*\"\n";
2617
	# BEGIN OF firewall rules
2618
	/* default block logging? */
2619
	if(!isset($config['syslog']['nologdefaultblock']))
2620
		$log = "log";
2621
	else
2622
		$log = "";
2623

    
2624
	$saved_tracker = $tracker;
2625

    
2626
	if(!isset($config['system']['ipv6allow'])) {
2627
		$ipfrules .= "# Block all IPv6\n";
2628
		$ipfrules .= "block in {$log} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2629
		$ipfrules .= "block out {$log} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2630
	}
2631

    
2632
	$saved_tracker += 100;
2633
	$tracker = $saved_tracker;
2634

    
2635
	$ipfrules .= <<<EOD
2636
#---------------------------------------------------------------------------
2637
# default deny rules
2638
#---------------------------------------------------------------------------
2639
block in {$log} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2640
block out {$log} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2641
block in {$log} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2642
block out {$log} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2643

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

    
2656
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
2657
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
2658
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
2659
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
2660
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
2661
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
2662

    
2663
# We use the mighty pf, we cannot be fooled.
2664
block {$log} quick inet proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2665
block {$log} quick inet proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2666
block {$log} quick inet6 proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2667
block {$log} quick inet6 proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2668

    
2669
# Snort package
2670
block {$log} quick from <snort2c> to any tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2671
block {$log} quick from any to <snort2c> tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2672

    
2673
EOD;
2674

    
2675
	$saved_tracker += 100;
2676
	$tracker = $saved_tracker;
2677

    
2678
	$ipfrules .= filter_process_carp_rules($log);
2679

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

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

    
2697
	$saved_tracker += 50;
2698
	$tracker = $saved_tracker;
2699

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

    
2712
	$saved_tracker += 100;
2713
	$tracker = $saved_tracker;
2714

    
2715
	/*
2716
	 * Support for allow limiting of TCP connections by establishment rate
2717
	 * Useful for protecting against sudden outburts, etc.
2718
	 */
2719
	$ipfrules .= "block in {$log} quick from <virusprot> to any tracker 1000000400 label \"virusprot overload table\"\n";
2720

    
2721
	$saved_tracker += 100;
2722
	$tracker = $saved_tracker;
2723

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

    
2769
	$bogontableinstalled = 0;
2770
	foreach ($FilterIflist as $on => $oc) {
2771
		/* XXX: Not static but give a step of 1000 for each interface to at least be able to match rules. */
2772
		$saved_tracker += 1000;
2773
		$tracker = $saved_tracker;
2774

    
2775
		/* block bogon networks */
2776
		/* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
2777
		/* file is automatically in cron every 3000 minutes */
2778
		if(!isset($config['syslog']['nologbogons']))
2779
			$bogonlog = "log";
2780
		else
2781
			$bogonlog = "";
2782

    
2783
		if(isset($config['interfaces'][$on]['blockbogons'])) {
2784
			$ipfrules .= <<<EOD
2785
# block bogon networks (IPv4)
2786
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
2787
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']}")}"
2788

    
2789
EOD;
2790

    
2791
			if(isset($config['system']['ipv6allow'])) {
2792
				$ipfrules .= <<<EOD
2793
# block bogon networks (IPv6)
2794
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
2795
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']}")}"
2796

    
2797
EOD;
2798
			}
2799
		}
2800

    
2801

    
2802
		$saved_tracker += 10;
2803
		$tracker = $saved_tracker;
2804

    
2805
		if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
2806
			$ipfrules .= <<<EOD
2807
# allow our DHCPv6 client out to the {$oc['descr']}
2808
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']}")}"
2809
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']}")}"
2810
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']}")}"
2811

    
2812
EOD;
2813
		}
2814

    
2815
		$saved_tracker += 10;
2816
		$tracker = $saved_tracker;
2817

    
2818
		$isbridged = false;
2819
		if(is_array($config['bridges']['bridged'])) {
2820
			foreach ($config['bridges']['bridged'] as $oc2) {
2821
				if(stristr($oc2['members'], $on)) {
2822
					$isbridged = true;
2823
					break;
2824
				}
2825
			}
2826
		}
2827

    
2828
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2829
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
2830

    
2831
		/* block private networks ? */
2832
		if(!isset($config['syslog']['nologprivatenets']))
2833
			$privnetlog = "log";
2834
		else
2835
			$privnetlog = "";
2836

    
2837
		$saved_tracker += 10;
2838
		$tracker = $saved_tracker;
2839

    
2840
		if(isset($config['interfaces'][$on]['blockpriv'])) {
2841
			if($isbridged == false) {
2842
				$ipfrules .= <<<EOD
2843
# block anything from private networks on interfaces with the option set
2844
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")}"
2845
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")}"
2846
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")}"
2847
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")}"
2848
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")}"
2849
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")}"
2850

    
2851
EOD;
2852
			}
2853
		}
2854

    
2855
		$saved_tracker += 10;
2856
		$tracker = $saved_tracker;
2857

    
2858
		switch ($oc['type']) {
2859
		case "pptp":
2860
				$ipfrules .= <<<EOD
2861
# allow PPTP client
2862
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']}")}"
2863
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']}")}"
2864

    
2865
EOD;
2866
			break;
2867
		case "dhcp":
2868
			$ipfrules .= <<<EOD
2869
# allow our DHCP client out to the {$oc['descr']}
2870
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']}")}"
2871
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']}")}"
2872
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2873

    
2874
EOD;
2875

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

    
2888
EOD;
2889
				if (is_ipaddrv4($oc['ip'])) {
2890
					$ipfrules .= <<<EOD
2891
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"
2892
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"
2893

    
2894
EOD;
2895
				}
2896

    
2897
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2898
					$ipfrules .= <<<EOD
2899
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2900
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"
2901
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"
2902

    
2903
EOD;
2904
				}
2905

    
2906
			}
2907
			break;
2908
		}
2909

    
2910
		$saved_tracker += 10;
2911
		$tracker = $saved_tracker;
2912
		switch($oc['type6']) {
2913
		case "6rd":
2914
			$ipfrules .= <<<EOD
2915
# allow our proto 41 traffic from the 6RD border relay in
2916
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']}")}"
2917
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']}")}"
2918

    
2919
EOD;
2920
		/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
2921
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2922
			$ipfrules .= <<<EOD
2923
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']}")}"
2924
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']}")}"
2925

    
2926
EOD;
2927
		}
2928
			break;
2929
		case "6to4":
2930
			if (is_ipaddrv4($oc['ip'])) {
2931
			$ipfrules .= <<<EOD
2932
# allow our proto 41 traffic from the 6to4 border relay in
2933
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']}")}"
2934
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']}")}"
2935

    
2936
EOD;
2937
		}
2938
		/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
2939
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2940
			$ipfrules .= <<<EOD
2941
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']}")}"
2942
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']}")}"
2943

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

    
2958
EOD;
2959
				if (is_ipaddrv6($oc['ipv6'])) {
2960
					$ipfrules .= <<<EOD
2961
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"
2962
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"
2963

    
2964
EOD;
2965
				}
2966
			}
2967
			break;
2968
		}
2969
	}
2970

    
2971
	$saved_tracker += 10;
2972
	$tracker = $saved_tracker;
2973

    
2974
	/*
2975
	 * NB: The loopback rules are needed here since the antispoof would take precedence then.
2976
	 *	If you ever add the 'quick' keyword to the antispoof rules above move the looback
2977
	 *	rules before them.
2978
	 */
2979
	$ipfrules .= <<<EOD
2980

    
2981
# loopback
2982
pass in {$log} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
2983
pass out {$log} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
2984
pass in {$log} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
2985
pass out {$log} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
2986
# let out anything from the firewall host itself and decrypted IPsec traffic
2987
pass out {$log} inet all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv4 from firewall host itself"
2988
pass out {$log} inet6 all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv6 from firewall host itself"
2989

    
2990
EOD;
2991

    
2992
	$saved_tracker += 100;
2993
	$tracker = $saved_tracker;
2994
	foreach ($FilterIflist as $ifdescr => $ifcfg) {
2995
		if(isset($ifcfg['virtual']))
2996
			continue;
2997

    
2998
		$gw = get_interface_gateway($ifdescr);
2999
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
3000
			$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";
3001
			if (is_array($ifcfg['vips'])) {
3002
				foreach ($ifcfg['vips'] as $vip)
3003
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
3004
						$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";
3005
					else
3006
						$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";
3007
			}
3008
		}
3009

    
3010
		$gwv6 = get_interface_gateway_v6($ifdescr);
3011
		$stf = get_real_interface($ifdescr, "inet6");
3012
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
3013
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
3014
			$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";
3015
			if (is_array($ifcfg['vips6'])) {
3016
				foreach ($ifcfg['vips6'] as $vip)
3017
					$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";
3018
			}
3019
		}
3020
	}
3021

    
3022

    
3023
	$saved_tracker += 300;
3024
	$tracker = $saved_tracker;
3025
	/* add ipsec interfaces */
3026
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
3027
		$ipfrules .= "pass out {$log} on \$IPsec all tracker {$increment_tracker($tracker)} tracker {$increment_tracker($tracker)} keep state label \"IPsec internal host to host\"\n";
3028

    
3029
	$saved_tracker += 10;
3030
	$tracker = $saved_tracker;
3031
	if(is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
3032
		$alports = filter_get_antilockout_ports();
3033

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

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

    
3051
EOD;
3052
		}
3053
		unset($alports);
3054
	}
3055

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

    
3070
EOD;
3071

    
3072
		} else {
3073
			/*	  this shouldnt ever happen but instead of breaking the clients ruleset
3074
			 *	  log an error.
3075
			 */
3076
			log_error("ERROR!  PPTP enabled but could not resolve the \$pptpdtarget");
3077
		}
3078
	}
3079

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

    
3090
EOD;
3091
				break;
3092
			}
3093
		}
3094
	}
3095

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

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

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

    
3167
	$saved_tracker += 100;
3168
	$tracker = $saved_tracker;
3169

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

    
3193
EOD;
3194
				}
3195
				unset($sa);
3196
				if (is_ipaddrv6($oc['ipv6'])) {
3197
					$sa = $oc['sav6'];
3198
					$sn = $oc['snv6'];
3199
				}
3200
				if ($sa && is_ipaddrv6($routeent[0])) {
3201
					$ipfrules .= <<<EOD
3202
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"
3203
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"
3204
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"
3205
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"
3206

    
3207
EOD;
3208
				}
3209
			}
3210
		}
3211
	}
3212

    
3213
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3214
	$saved_tracker += 100000;
3215
	$tracker = $saved_tracker;
3216
	$ipfrules .= filter_generate_ipsec_rules($log);
3217

    
3218
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3219

    
3220
	$saved_tracker += 200;
3221
	$tracker = $saved_tracker;
3222
	update_filter_reload_status("Creating uPNP rules...");
3223
	if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
3224
		if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable']))
3225
			$ipfrules .= "anchor \"miniupnpd\"\n";
3226

    
3227
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3228
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3229
			foreach($upnp_interfaces as $upnp_if) {
3230
				if (is_array($FilterIflist[$upnp_if])) {
3231
					$oc = $FilterIflist[$upnp_if];
3232
					unset($sa);
3233
					if($oc['ip']) {
3234
						$sa = $oc['sa'];
3235
						$sn = $oc['sn'];
3236
					}
3237
					if($sa) {
3238
						$ipfrules .= <<<EOD
3239
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"
3240

    
3241
EOD;
3242
					}
3243
				}
3244
			}
3245
		}
3246
	}
3247

    
3248

    
3249
	return $ipfrules;
3250
}
3251

    
3252
function filter_rules_spoofcheck_generate($ifname, $ifcfg, $log) {
3253
	global $g, $config, $tracker;
3254
	if(isset($config['system']['developerspew'])) {
3255
		$mt = microtime();
3256
		echo "filter_rules_spoofcheck_generate() being called $mt\n";
3257
	}
3258
	$ipfrules = "antispoof {$log} for \${$ifcfg['descr']} tracker {$tracker}\n";
3259
	$tracker++;
3260

    
3261
	return $ipfrules;
3262
}
3263

    
3264
/* COMPAT Function */
3265
function tdr_install_cron($should_install) {
3266
	log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
3267
	filter_tdr_install_cron($should_install);
3268
}
3269

    
3270
/****f* filter/filter_tdr_install_cron
3271
 * NAME
3272
 *   filter_tdr_install_cron
3273
 * INPUTS
3274
 *   $should_install true if the cron entry should be installed, false
3275
 *   if the entry should be removed if it is present
3276
 * RESULT
3277
 *   none
3278
 ******/
3279
function filter_tdr_install_cron($should_install) {
3280
	global $config, $g;
3281

    
3282
	if($g['booting']==true)
3283
		return;
3284

    
3285
	if (!is_array($config['cron']))
3286
		$config['cron'] = array();
3287
	if (!is_array($config['cron']['item']))
3288
		$config['cron']['item'] = array();
3289

    
3290
	$x=0;
3291
	$is_installed = false;
3292
	foreach($config['cron']['item'] as $item) {
3293
		if (strstr($item['command'], "filter_configure_sync")) {
3294
			$is_installed = true;
3295
			break;
3296
		}
3297
		$x++;
3298
	}
3299

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

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

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

    
3379
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3380
			return true;
3381
	}
3382

    
3383
	return false;
3384
}
3385

    
3386
function filter_tdr_day($schedule) {
3387
	global $g;
3388

    
3389
	if($g['debug'])
3390
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3391

    
3392
	/*
3393
	 * Calculate day of month.
3394
	 * IE: 29th of may
3395
	 */
3396
	$date = date("d");
3397
	$defined_days = explode(",", $schedule);
3398
	foreach($defined_days as $dd) {
3399
		if ($date == $dd)
3400
			return true;
3401
	}
3402
	return false;
3403
}
3404
function filter_tdr_hour($schedule) {
3405
	global $g;
3406

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

    
3419
function filter_tdr_position($schedule) {
3420
	global $g;
3421

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

    
3442
function filter_tdr_month($schedule) {
3443
	global $g;
3444

    
3445
	/*
3446
	 * Calculate month
3447
	 */
3448
	$todays_month = date("n");
3449
	$months = explode(",", $schedule);
3450
	if($g['debug'])
3451
		log_error("[TDR DEBUG] filter_tdr_month($schedule)");
3452
	foreach($months as $month) {
3453
		if($month == $todays_month)
3454
			return true;
3455
	}
3456
	return false;
3457
}
3458

    
3459
function filter_setup_logging_interfaces() {
3460
	global $config, $FilterIflist;
3461

    
3462
	if(isset($config['system']['developerspew'])) {
3463
		$mt = microtime();
3464
		echo "filter_setup_logging_interfaces() being called $mt\n";
3465
	}
3466
	$rules = "";
3467
	if (isset($FilterIflist['lan']))
3468
		$rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
3469
	else if (isset($FilterIflist['wan']))
3470
		$rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
3471

    
3472
	return $rules;
3473
}
3474

    
3475
function filter_process_carp_rules($log) {
3476
	global $g, $config, $tracker;
3477

    
3478
	if(isset($config['system']['developerspew'])) {
3479
		$mt = microtime();
3480
		echo "filter_process_carp_rules($log) being called $mt\n";
3481
	}
3482

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

    
3493
/* Generate IPSEC Filter Items */
3494
function filter_generate_ipsec_rules($log = "") {
3495
	global $config, $g, $FilterIflist, $tracker;
3496

    
3497
	if(isset($config['system']['developerspew'])) {
3498
		$mt = microtime();
3499
		echo "filter_generate_ipsec_rules() being called $mt\n";
3500
	}
3501

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

    
3505
	$increment_tracker = 'filter_rule_tracker';
3506

    
3507
	$ipfrules = "\n# VPN Rules\n";
3508
	/* Is IP Compression enabled? */
3509
	if(isset($config['ipsec']['ipcomp']))
3510
		exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=1");
3511
	else
3512
		exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=0");
3513

    
3514
	if(isset($config['ipsec']['enable']) &&
3515
		is_array($config['ipsec']['phase1'])) {
3516
		/* step through all phase1 entries */
3517
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
3518
			$tracker += 10;
3519

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

    
3556
			if (strstr($ph1ent['interface'], "_vip"))
3557
				list($parentinterface, $vhid) = explode("_vhid", $ph1ent['interface']);
3558
			else
3559
				$parentinterface = $ph1ent['interface'];
3560
			if (empty($FilterIflist[$parentinterface]['descr'])) {
3561
				$ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
3562
				continue;
3563
			}
3564

    
3565
			unset($gateway);
3566
			/* add endpoint routes to correct gateway on interface */
3567
			if((is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
3568
				$gateway = get_interface_gateway($parentinterface);
3569
				$interface = $FilterIflist[$parentinterface]['if'];
3570

    
3571
				$route_to = " route-to ( $interface $gateway ) ";
3572
				$reply_to = " reply-to ( $interface $gateway ) ";
3573

    
3574
			}
3575
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3576
				$gateway = get_interface_gateway_v6($parentinterface);
3577
				$interface = $FilterIflist[$parentinterface]['if'];
3578

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

    
3583
			/* Just in case */
3584
			if((!is_ipaddr($gateway) || empty($interface))) {
3585
				$route_to = " ";
3586
				$reply_to = " ";
3587
			}
3588

    
3589
			/* Add rules to allow IKE to pass */
3590
			$shorttunneldescr = substr($descr, 0, 35);
3591
				$ipfrules .= <<<EOD
3592
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"
3593
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"
3594

    
3595
EOD;
3596
			/* If NAT-T is enabled, add additional rules */
3597
			if($ph1ent['nat_traversal'] != "off" ) {
3598
				$ipfrules .= <<<EOD
3599
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"
3600
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"
3601

    
3602
EOD;
3603
			}
3604
			/* Add rules to allow the protocols in use */
3605
			if($prot_used_esp == true) {
3606
				$ipfrules .= <<<EOD
3607
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"
3608
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"
3609

    
3610
EOD;
3611
			}
3612
			if($prot_used_ah == true) {
3613
				$ipfrules .= <<<EOD
3614
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"
3615
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"
3616

    
3617
EOD;
3618
			}
3619
		}
3620

    
3621
	}
3622
	return($ipfrules);
3623
}
3624

    
3625
function discover_pkg_rules($ruletype) {
3626
	global $config, $g, $aliases;
3627

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

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

    
3657
function filter_get_antilockout_ports($wantarray = false) {
3658
	global $config;
3659

    
3660
	$lockoutports = array();
3661
	$guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
3662
	$guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
3663
	$lockoutports[] = $guiport;
3664

    
3665
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3666
		$lockoutports[] = "80";
3667

    
3668
	if (isset($config['system']['enablesshd']))
3669
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3670

    
3671
	if ($wantarray)
3672
		return $lockoutports;
3673
	else
3674
		return implode(" ", $lockoutports);
3675

    
3676
}
3677

    
3678
?>
(19-19/67)