Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ eb71461c

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/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
		set_single_sysctl("net.inet.flowtable.enable", "0");
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 = get_single_sysctl('kern.smp.cpus');
110
	$nmbflows = ($cpus*($maxstates*2));
111
	// Flowtable currently only works on 8.0
112
	if(get_freebsd_version() == "8") {
113
		set_sysctl(array(
114
			"net.inet.flowtable.nmbflows" => $nmbflows,
115
			"net.inet.ip.output_flowtable_size" => $maxstates,
116
			"net.inet.flowtable.enable" => "1")
117
		);
118
	}
119
}
120

    
121
function filter_pflog_start($kill_first = false) {
122
	global $config, $g;
123
	if ($g['platform'] == 'jail')
124
		return;
125
	if(isset($config['system']['developerspew'])) {
126
		$mt = microtime();
127
		echo "filter_pflog_start() being called $mt\n";
128
	}
129
	if (!file_exists("{$g['varrun_path']}/filterlog.pid") ||
130
	    !isvalidpid("{$g['varrun_path']}/filterlog.pid"))
131
		mwexec("/usr/local/sbin/filterlog -i pflog0 -p {$g['varrun_path']}/filterlog.pid");
132
}
133

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

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

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

    
151
function filter_delete_states_for_down_gateways() {
152
	global $config, $GatewaysList;
153

    
154
	if (isset($config['system']['kill_states']))
155
		return;
156

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

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

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

    
188

    
189
	filter_pflog_start();
190
	update_filter_reload_status(gettext("Initializing"));
191

    
192
	/* invalidate interface cache */
193
	get_interface_arr(true);
194

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

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

    
246
	$limitrules = "";
247
	/* User defined maximum table entries in Advanced menu. */
248
	if ($config['system']['maximumtableentries'] <> "" && is_numeric($config['system']['maximumtableentries']))
249
		$limitrules .= "set limit table-entries {$config['system']['maximumtableentries']}\n";
250

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
399
		fclose($fda);
400
	}
401

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

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

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

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

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

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

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

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

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

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

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

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

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

    
528
function filter_expand_alias($alias_name)
529
{
530
	global $config;
531

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

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

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

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

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

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

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

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

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

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

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

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

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

    
685
	return $result;
686
}
687

    
688
function filter_generate_gateways() {
689
	global $config, $g, $GatewaysList;
690

    
691
	$rules = "# Gateways\n";
692

    
693
	update_filter_reload_status(gettext("Creating gateway group item..."));
694

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

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

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

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

    
757
	$rules .= "\n";
758

    
759
	return $rules;
760
}
761

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

    
766
	$vpns = "";
767
	$vpns_arr = array();
768

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

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

    
819
	if (!empty($vpns_arr))
820
		$vpns = implode(" ", $vpns_arr);
821

    
822
	return $vpns;
823
}
824

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

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

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

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

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

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

    
1045
function filter_get_reflection_interfaces($natif = "") {
1046
	global $FilterIflist;
1047

    
1048
	$nat_if_list = array();
1049

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

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

    
1058
		$nat_if_list[] = $ifname['if'];
1059
	}
1060

    
1061
	return $nat_if_list;
1062
}
1063

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

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

    
1070
	// Initialize natrules holder string
1071
	$natrules = "";
1072

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

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

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

    
1088
	if(empty($target_subnet) || !is_numeric($target_subnet))
1089
		$target_subnet = 32;
1090

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

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

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

    
1143
	if(!empty($natrules))
1144
		$natrules .= "\n";
1145

    
1146
	return $natrules;
1147
}
1148

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

    
1152
	// Initialize natrules holder string
1153
	$natrules = "";
1154
	$reflection_txt = array();
1155

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

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

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

    
1168
		$natrules .= "\n# Reflection redirects\n";
1169

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

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

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

    
1197
				$dstport = array($localport);
1198
			} else
1199
				$localport = "";
1200
		}
1201

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

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

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

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

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

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

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

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

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

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

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

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

    
1331
			if($toomanyports)
1332
				break;
1333
		}
1334

    
1335
		$reflection_txt = array_unique($reflection_txt);
1336
	}
1337

    
1338
	return $natrules;
1339
}
1340

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

    
1344
	$tonathosts = array("127.0.0.0/8");
1345
	$descriptions = array(gettext("localhost"));
1346

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

    
1358
	/* create outbound nat entries for all local networks */
1359
	foreach($FilterIflist as $ocname => $oc) {
1360
		if(interface_has_gateway($ocname))
1361
			continue;
1362
		if(is_ipaddr($oc['alias-address'])) {
1363
			$tonathosts[] = "{$oc['alias-address']}/{$oc['alias-subnet']}";
1364
			$descriptions[] = $oc['descr'] . " " . gettext("DHCP alias address");
1365
		}
1366
		if($oc['sa']) {
1367
			$tonathosts[] = "{$oc['sa']}/{$oc['sn']}";
1368
			$descriptions[] = $oc['descr'];
1369
			if (isset($oc['vips']) && is_array($oc['vips'])) {
1370
				$if_subnets = array("{$oc['sa']}/{$oc['sn']}");
1371
				foreach ($oc['vips'] as $vip) {
1372
					if (!is_ipaddrv4($vip['ip']))
1373
						continue;
1374

    
1375
					foreach ($if_subnets as $subnet)
1376
						if (ip_in_subnet($vip['ip'], $subnet))
1377
							continue 2;
1378

    
1379
					$network = gen_subnet($vip['ip'], $vip['sn']);
1380
					array_unshift($tonathosts, $network . '/' . $vip['sn']);
1381
					array_unshift($descriptions, "Virtual IP ({$oc['descr']})");
1382
					$if_subnets[] = $network . '/' . $vip['sn'];
1383
					unset($network);
1384
				}
1385
				unset($if_subnets);
1386
			}
1387
		}
1388
	}
1389

    
1390
	/* PPTP subnet */
1391
	if(($config['pptpd']['mode'] == "server" ) && is_private_ip($config['pptpd']['remoteip'])) {
1392
		if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
1393
			$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
1394
				long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
1395
		else
1396
			$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
1397
				long2ip32(ip2long($config['pptpd']['remoteip'])));
1398

    
1399
		foreach ($pptp_subnets as $subnet) {
1400
			$tonathosts[] = $subnet;
1401
			$descriptions[] = gettext("PPTP server");
1402
		}
1403
	}
1404

    
1405
	/* PPPoE subnet */
1406
	if (is_array($FilterIflist['pppoe']))
1407
		foreach ($FilterIflist['pppoe'] as $pppoe)
1408
			if(is_private_ip($pppoe['ip'])) {
1409
				$tonathosts[] = "{$pppoe['sa']}/{$pppoe['sn']}";
1410
				$descriptions[] = gettext("PPPoE server");
1411
			}
1412

    
1413
	/* L2TP subnet */
1414
	if(isset($FilterIflist['l2tp']) && $FilterIflist['l2tp']['mode'] == "server") {
1415
		$l2tp_sa = $FilterIflist['l2tp']['sa'];
1416
		$l2tp_sn = $FilterIflist['l2tp']['sn'];
1417
		if(is_private_ip($l2tp_sa) && !empty($l2tp_sn)) {
1418
			$tonathosts[] = "{$l2tp_sa}/{$l2tp_sn}";
1419
			$descriptions[] = gettext("L2TP server");
1420
		}
1421
	}
1422

    
1423
	/* add openvpn interfaces */
1424
	if(is_array($config['openvpn']['openvpn-server']))
1425
		foreach ($config['openvpn']['openvpn-server'] as $ovpnsrv)
1426
			if (!isset($ovpnsrv['disable']) && !empty($ovpnsrv['tunnel_network'])) {
1427
				$tonathosts[] = $ovpnsrv['tunnel_network'];
1428
				$descriptions[] = gettext("OpenVPN server");
1429
			}
1430

    
1431
	if(is_array($config['openvpn']['openvpn-client']))
1432
		foreach ($config['openvpn']['openvpn-client'] as $ovpncli)
1433
			if (!isset($ovpncli['disable']) && !empty($ovpncli['tunnel_network'])) {
1434
				$tonathosts[] = $ovpncli['tunnel_network'];
1435
				$descriptions[] = gettext("OpenVPN client");
1436
			}
1437

    
1438
	/* IPsec mode_cfg subnet */
1439
	if (isset($config['ipsec']['client']['enable']) &&
1440
	    !empty($config['ipsec']['client']['pool_address']) &&
1441
	    !empty($config['ipsec']['client']['pool_netbits'])) {
1442
		$tonathosts[] = "{$config['ipsec']['client']['pool_address']}/{$config['ipsec']['client']['pool_netbits']}";
1443
		$descriptions[] = gettext("IPsec client");
1444
	}
1445

    
1446
	if ($with_descr) {
1447
		$combined = array();
1448
		foreach ($tonathosts as $idx => $subnet) {
1449
			$combined[] = array(
1450
				"subnet" => $subnet,
1451
				"descr" => $descriptions[$idx]);
1452
		}
1453

    
1454
		return $combined;
1455
	} else
1456
		return $tonathosts;
1457
}
1458

    
1459
function filter_nat_rules_outbound_automatic($src) {
1460
	global $config, $FilterIflist;
1461

    
1462
	$rules = array();
1463
	foreach ($FilterIflist as $if => $ifcfg) {
1464
		if (substr($ifcfg['if'], 0, 4) == "ovpn")
1465
			continue;
1466
		if (!interface_has_gateway($if))
1467
			continue;
1468

    
1469
		$natent = array();
1470
		$natent['interface'] = $if;
1471
		$natent['source']['network'] = $src;
1472
		$natent['dstport'] = "500";
1473
		$natent['target'] = $ifcfg['ip'];
1474
		$natent['destination']['any'] = true;
1475
		$natent['staticnatport'] = true;
1476
		$natent['descr'] = gettext('Auto created rule for ISAKMP');
1477
		$rules[] = $natent;
1478

    
1479
		$natent = array();
1480
		$natent['interface'] = $if;
1481
		$natent['source']['network'] = $src;
1482
		$natent['sourceport'] = "";
1483
		$natent['target'] = $ifcfg['ip'];
1484
		$natent['destination']['any'] = true;
1485
		$natent['natport'] = "";
1486
		$natent['descr'] = gettext('Auto created rule');
1487
		if (isset($ifcfg['nonat']))
1488
			$natent['nonat'] = true;
1489
		$rules[] = $natent;
1490
	}
1491

    
1492
	return $rules;
1493
}
1494

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

    
1577
function filter_nat_rules_generate() {
1578
	global $config, $g, $after_filter_configure_run, $FilterIflist, $GatewaysList, $aliases;
1579

    
1580
	$natrules = "no nat proto carp\n";
1581
	$natrules .= "no rdr proto carp\n";
1582
	$natrules .= "nat-anchor \"natearly/*\"\n";
1583

    
1584
	$natrules .= "nat-anchor \"natrules/*\"\n\n";
1585
	update_filter_reload_status(gettext("Creating 1:1 rules..."));
1586

    
1587
	$reflection_txt = "";
1588
	$route_table = "";
1589

    
1590
	/* any 1:1 mappings? */
1591
	if(is_array($config['nat']['onetoone'])) {
1592
		foreach ($config['nat']['onetoone'] as $rule) {
1593
			if (isset($rule['disabled']))
1594
				continue;
1595

    
1596
			$sn = "";
1597
			$sn1 = "";
1598
			$target = alias_expand($rule['external']);
1599
			if (!$target) {
1600
				$natrules .= "# Unresolvable alias {$rule['target']}\n";
1601
				continue;               /* unresolvable alias */
1602
			}
1603

    
1604
			if (!$rule['interface'])
1605
				$natif = "wan";
1606
			else
1607
				$natif = $rule['interface'];
1608
			if (!isset($FilterIflist[$natif]))
1609
				continue;
1610

    
1611
			$srcaddr = filter_generate_address($rule, 'source');
1612
			$dstaddr = filter_generate_address($rule, 'destination');
1613
			if(!$dstaddr)
1614
				$dstaddr = $FilterIflist[$natif]['ip'];
1615

    
1616
			$srcaddr = trim($srcaddr);
1617
			$dstaddr = trim($dstaddr);
1618

    
1619
			$tmp = explode('/', $srcaddr);
1620
			$srcip = $tmp[0];
1621
			if (!empty($tmp[1]) && is_numeric($tmp[1])) {
1622
				$sn = $tmp[1];
1623
				$sn1 = "/{$sn}";
1624
			}
1625

    
1626
			$natif = $FilterIflist[$natif]['if'];
1627

    
1628
			/*
1629
			 * If reflection is enabled, turn on extra redirections
1630
			 * for this rule by adding other interfaces to an rdr rule.
1631
			 */
1632
			if ((isset($config['system']['enablebinatreflection']) || $rule['natreflection'] == "enable")
1633
			   && $rule['natreflection'] != "disable")
1634
				$nat_if_list = filter_get_reflection_interfaces($natif);
1635
			else
1636
				$nat_if_list = array();
1637

    
1638
			$natrules .= "binat on {$natif} from {$srcaddr} to {$dstaddr} -> {$target}{$sn1}\n";
1639
			if (!empty($nat_if_list)) {
1640
				$binat_if_list = implode(" ", $nat_if_list);
1641
				$binat_if_list = "{ {$binat_if_list} }";
1642
				$reflection_txt .= "rdr on {$binat_if_list} from {$dstaddr} to {$target}{$sn1} -> {$srcaddr} bitmask\n";
1643
			}
1644

    
1645
			$nat_if_list = array_merge(array($natif), $nat_if_list);
1646
			$reflection_txt .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, "", $srcaddr, $srcip, $sn);
1647
		}
1648
	}
1649

    
1650
	/* Add binat rules for Network Prefix translation */
1651
	if(is_array($config['nat']['npt'])) {
1652
		foreach ($config['nat']['npt'] as $rule) {
1653
			if (isset($rule['disabled']))
1654
				continue;
1655

    
1656
			if (!$rule['interface'])
1657
				$natif = "wan";
1658
			else
1659
				$natif = $rule['interface'];
1660
			if (!isset($FilterIflist[$natif]))
1661
				continue;
1662

    
1663
			$srcaddr = filter_generate_address($rule, 'source');
1664
			$dstaddr = filter_generate_address($rule, 'destination');
1665

    
1666
			$srcaddr = trim($srcaddr);
1667
			$dstaddr = trim($dstaddr);
1668

    
1669
			$natif = $FilterIflist[$natif]['descr'];
1670

    
1671
			$natrules .= "binat on \${$natif} from {$srcaddr} to any -> {$dstaddr}\n";
1672
			$natrules .= "binat on \${$natif} from any to {$dstaddr} -> {$srcaddr}\n";
1673

    
1674
		}
1675
	}
1676

    
1677
	/* ipsec nat */
1678
	if (is_array($config['ipsec']) && isset($config['ipsec']['enable'])) {
1679
		if (is_array($config['ipsec']['phase2'])) {
1680
			foreach ($config['ipsec']['phase2'] as $ph2ent) {
1681
				if ($ph2ent['mode'] != 'transport' && !empty($ph2ent['natlocalid'])) {
1682
					if (!function_exists('ipsec_idinfo_to_cidr'))
1683
						require_once("ipsec.inc");
1684
					if (!is_array($ph2ent['localid']))
1685
						$ph2ent['localid'] = array();
1686
					$ph2ent['localid']['mode'] = $ph2ent['mode'];
1687
					$local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid']);
1688
					if (empty($local_subnet) || $local_subnet == "0.0.0.0/0")
1689
						continue;
1690
					if (!is_subnet($local_subnet) && !is_ipaddr($local_subnet))
1691
						continue;
1692
					if (!is_array($ph2ent['natlocalid']))
1693
						$ph2ent['natlocalid'] = array();
1694
					$ph2ent['natlocalid']['mode'] = $ph2ent['mode'];
1695
					$natlocal_subnet = ipsec_idinfo_to_cidr($ph2ent['natlocalid']);
1696
					if (empty($natlocal_subnet) || $natlocal_subnet == "0.0.0.0/0")
1697
						continue;
1698
					if (!is_subnet($natlocal_subnet) && !is_ipaddr($natlocal_subnet))
1699
						continue;
1700
					if (!is_array($ph2ent['remoteid']))
1701
						$ph2ent['remoteid'] = array();
1702
					$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
1703
					$remote_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
1704
					if (empty($remote_subnet))
1705
						continue;
1706
					if (!is_subnet($remote_subnet) && !is_ipaddr($remote_subnet))
1707
						continue;
1708
					if ($remote_subnet == "0.0.0.0/0")
1709
						$remote_subnet = "any";
1710
					if (is_ipaddr($natlocal_subnet) && !is_ipaddr($local_subnet) )
1711
						$nattype = "nat";
1712
					else
1713
						$nattype = "binat";
1714
					$natrules .= "{$nattype} on enc0 from {$local_subnet} to {$remote_subnet} -> {$natlocal_subnet}\n";
1715
				}
1716
			}
1717
		}
1718
	}
1719

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

    
1723
	if ($config['nat']['outbound']['mode'] == "advanced" || $config['nat']['outbound']['mode'] == "hybrid") {
1724
		$natrules .= "\n# Outbound NAT rules (manual)\n";
1725
		/* advanced outbound rules */
1726
		if(is_array($config['nat']['outbound']['rule'])) {
1727
			foreach ($config['nat']['outbound']['rule'] as $obent) {
1728
				if (isset($obent['disabled']))
1729
					continue;
1730
				update_filter_reload_status(sprintf(gettext("Creating advanced outbound rule %s"), $obent['descr']));
1731
				$src = alias_expand($obent['source']['network']);
1732
				if(!$src)
1733
					$src = $obent['source']['network'];
1734
				$dst = alias_expand($obent['destination']['address']);
1735
				if(!$dst)
1736
					$dst = $obent['destination']['address'];
1737
				if(isset($obent['destination']['not']) && !isset($obent['destination']['any']))
1738
					$dst = "!" . $dst;
1739

    
1740
				if(!$obent['interface'] || !isset($FilterIflist[$obent['interface']]))
1741
					continue;
1742

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

    
1746
				$natrules .= filter_nat_rules_generate_if($obent['interface'],
1747
					$src,
1748
					$obent['sourceport'],
1749
					$dst,
1750
					$obent['dstport'],
1751
					$obtarget,
1752
					$obent['natport'],
1753
					isset($obent['nonat']),
1754
					isset($obent['staticnatport']),
1755
					$obent['protocol'],
1756
					$poolopts
1757
				);
1758
			}
1759
		}
1760
	}
1761

    
1762
	/* outbound rules */
1763
	if (!isset($config['nat']['outbound']['mode']) ||
1764
	    $config['nat']['outbound']['mode'] == "automatic" ||
1765
	    $config['nat']['outbound']['mode'] == "hybrid") {
1766
		$natrules .= "\n# Outbound NAT rules (automatic)\n";
1767
		/* standard outbound rules (one for each interface) */
1768
		update_filter_reload_status(gettext("Creating outbound NAT rules"));
1769
		$tonathosts_array = filter_nat_rules_automatic_tonathosts();
1770
		$tonathosts = implode(" ", $tonathosts_array);
1771
		$numberofnathosts = count($tonathosts_array);
1772

    
1773
		$natrules .= "\n# Subnets to NAT \n";
1774
		if ($numberofnathosts > 0) {
1775
			update_filter_reload_status(gettext('Creating automatic outbound rules'));
1776

    
1777
			if ($numberofnathosts > 4) {
1778
				$natrules .= "table <tonatsubnets> { {$tonathosts} }\n";
1779
				$macroortable = "<tonatsubnets>";
1780
			} else {
1781
				$natrules .= "tonatsubnets	= \"{ {$tonathosts} }\"\n";
1782
				$macroortable = "\$tonatsubnets";
1783
			}
1784

    
1785
			$a_outs = filter_nat_rules_outbound_automatic($macroortable);
1786
			foreach ($a_outs as $a_out) {
1787
				$natrules .= filter_nat_rules_generate_if($a_out['interface'],
1788
					$a_out['source']['network'],
1789
					$a_out['sourceport'],
1790
					$a_out['destination']['address'],
1791
					$a_out['dstport'],
1792
					$a_out['target'],
1793
					$a_out['natport'],
1794
					isset($a_out['nonat']),
1795
					isset($a_out['staticnatport']));
1796
			}
1797
		}
1798
		unset($tonathosts, $tonathosts_array, $numberofnathosts);
1799
	}
1800

    
1801
	/* load balancer anchor */
1802
	$natrules .= "\n# Load balancing anchor\n";
1803
	$natrules .= "rdr-anchor \"relayd/*\"\n";
1804

    
1805
	update_filter_reload_status(gettext("Setting up TFTP helper"));
1806
	$natrules .= "# TFTP proxy\n";
1807
	$natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
1808

    
1809
	if (!empty($config['system']['tftpinterface'])) {
1810
		$tftpifs = explode(",", $config['system']['tftpinterface']);
1811
		foreach($tftpifs as $tftpif) {
1812
			if ($FilterIflist[$tftpif])
1813
				$natrules .= "rdr pass on {$FilterIflist[$tftpif]['if']} proto udp from any to any port tftp -> 127.0.0.1 port 6969\n";
1814
		}
1815
	}
1816

    
1817
	/* DIAG: add ipv6 NAT, if requested */
1818
	if(isset($config['diag']['ipv6nat']['enable']) &&
1819
		is_ipaddr($config['diag']['ipv6nat']['ipaddr']) &&
1820
		is_array($FilterIflist['wan'])) {
1821
		/* XXX: FIX ME!	 IPV6 */
1822
		$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto ipv6 from any to any -> {$config['diag']['ipv6nat']['ipaddr']}\n";
1823
	}
1824

    
1825
	if(file_exists("/var/etc/inetd.conf"))
1826
		@unlink("/var/etc/inetd.conf");
1827
	// Open inetd.conf write handle
1828
	$inetd_fd = fopen("/var/etc/inetd.conf","w");
1829
	/* add tftp protocol helper */
1830
	fwrite($inetd_fd, "tftp-proxy\tdgram\tudp\twait\t\troot\t/usr/libexec/tftp-proxy\ttftp-proxy -v\n");
1831

    
1832
	if(isset($config['nat']['rule'])) {
1833
		/* start reflection redirects on port 19000 of localhost */
1834
		$starting_localhost_port = 19000;
1835
		$natrules .= "# NAT Inbound Redirects\n";
1836
		foreach ($config['nat']['rule'] as $rule) {
1837
			update_filter_reload_status(sprintf(gettext("Creating NAT rule %s"), $rule['descr']));
1838

    
1839
			if(isset($rule['disabled']))
1840
				continue;
1841

    
1842
			/* if item is an alias, expand */
1843
			$dstport = "";
1844
			$dstport[0] = alias_expand($rule['destination']['port']);
1845
			if(!$dstport[0])
1846
				$dstport = explode("-", $rule['destination']['port']);
1847

    
1848
			/* if item is an alias, expand */
1849
			$localport = alias_expand($rule['local-port']);
1850
			if(!$localport || $dstport[0] == $localport) {
1851
				$localport = "";
1852
			} else if(is_alias($rule['local-port'])) {
1853
				$localport = filter_expand_alias($rule['local-port']);
1854
				if($localport) {
1855
					$localport = explode(" ", trim($localport));
1856
					$localport = $localport[0];
1857
					$localport = " port {$localport}";
1858
				}
1859
			} else if(is_alias($rule['destination']['port'])) {
1860
				$localport = " port {$localport}";
1861
			} else {
1862
				if(($dstport[1]) && ($dstport[0] != $dstport[1])) {
1863
					$localendport = $localport + ($dstport[1] - $dstport[0]);
1864

    
1865
					$localport .= ":$localendport";
1866
				}
1867

    
1868
				$localport = " port {$localport}";
1869
			}
1870

    
1871
			switch(strtolower($rule['protocol'])) {
1872
			case "tcp/udp":
1873
				$protocol = "{ tcp udp }";
1874
				break;
1875
			case "tcp":
1876
			case "udp":
1877
				$protocol = strtolower($rule['protocol']);
1878
				break;
1879
			default:
1880
				$protocol = strtolower($rule['protocol']);
1881
				$localport = "";
1882
				break;
1883
			}
1884

    
1885
			$target = alias_expand($rule['target']);
1886
			if(!$target && !isset($rule['nordr'])) {
1887
				$natrules .= "# Unresolvable alias {$rule['target']}\n";
1888
				continue;		/* unresolvable alias */
1889
			}
1890

    
1891
			if(is_alias($rule['target']))
1892
				$target_ip = filter_expand_alias($rule['target']);
1893
			else if(is_ipaddr($rule['target']))
1894
				$target_ip = $rule['target'];
1895
			else if(is_ipaddr($FilterIflist[$rule['target']]['ip']))
1896
				$target_ip = $FilterIflist[$rule['target']]['ip'];
1897
			else
1898
				$target_ip = $rule['target'];
1899
			$target_ip = trim($target_ip);
1900

    
1901
			if($rule['associated-rule-id'] == "pass")
1902
				$rdrpass = "pass ";
1903
			else
1904
				$rdrpass = "";
1905

    
1906
			if (isset($rule['nordr'])) {
1907
				$nordr = "no ";
1908
				$rdrpass = "";
1909
			} else
1910
				$nordr = "";
1911

    
1912
			if(!$rule['interface'])
1913
				$natif = "wan";
1914
			else
1915
				$natif = $rule['interface'];
1916

    
1917
			if (!isset($FilterIflist[$natif]))
1918
				continue;
1919

    
1920
			$srcaddr = filter_generate_address($rule, 'source', true);
1921
			$dstaddr = filter_generate_address($rule, 'destination', true);
1922
			$srcaddr = trim($srcaddr);
1923
			$dstaddr = trim($dstaddr);
1924

    
1925
			if(!$dstaddr)
1926
				$dstaddr = $FilterIflist[$natif]['ip'];
1927

    
1928
			$dstaddr_port = explode(" ", $dstaddr);
1929
			if(empty($dstaddr_port[0]) || strtolower(trim($dstaddr_port[0])) == "port")
1930
				continue; // Skip port forward if no destination address found
1931
			$dstaddr_reflect = $dstaddr;
1932
			if(isset($rule['destination']['any'])) {
1933
				/* With reflection enabled, destination of 'any' has side effects
1934
				 * that most people would not expect, so change it on reflection rules. */
1935
				$dstaddr_reflect = $FilterIflist[$natif]['ip'];
1936
				if(!empty($FilterIflist[$natif]['sn']))
1937
					$dstaddr_reflect = gen_subnet($dstaddr_reflect, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
1938

    
1939
				if($dstaddr_port[2])
1940
					$dstaddr_reflect .= " port " . $dstaddr_port[2];
1941
			}
1942

    
1943
			$natif = $FilterIflist[$natif]['if'];
1944

    
1945
			$reflection_type = "none";
1946
			if($rule['natreflection'] != "disable" && $dstaddr_port[0] != "0.0.0.0") {
1947
				if($rule['natreflection'] == "enable")
1948
					$reflection_type = "proxy";
1949
				else if($rule['natreflection'] == "purenat")
1950
					$reflection_type = "purenat";
1951
				else if(!isset($config['system']['disablenatreflection'])) {
1952
					if(isset($config['system']['enablenatreflectionpurenat']))
1953
						$reflection_type = "purenat";
1954
					else
1955
						$reflection_type = "proxy";
1956
				}
1957
			}
1958

    
1959
			if($reflection_type != "none")
1960
				$nat_if_list = filter_get_reflection_interfaces($natif);
1961
			else
1962
				$nat_if_list = array();
1963

    
1964
			if(empty($nat_if_list))
1965
				$reflection_type = "none";
1966

    
1967
			$localport_nat = $localport;
1968
			if(empty($localport_nat) && $dstaddr_port[2])
1969
				$localport_nat = " port " . $dstaddr_port[2];
1970

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

    
1974
				/* Does this rule redirect back to a internal host? */
1975
				if(isset($rule['destination']['any']) && !isset($rule['nordr']) && !isset($config['system']['enablenatreflectionhelper']) && !interface_has_gateway($rule['interface'])) {
1976
					$rule_interface_ip = find_interface_ip($natif);
1977
					$rule_interface_subnet = find_interface_subnet($natif);
1978
					if(!empty($rule_interface_ip) && !empty($rule_interface_subnet)) {
1979
						$rule_subnet = gen_subnet($rule_interface_ip, $rule_interface_subnet);
1980
						$natrules .= "\n";
1981
						$natrules .= "no nat on {$natif} proto tcp from ({$natif}) to {$rule_subnet}/{$rule_interface_subnet}\n";
1982
						$natrules .= "nat on {$natif} proto tcp from {$rule_subnet}/{$rule_interface_subnet} to {$target} port {$dstport[0]} -> ({$natif})\n";
1983
					}
1984
				}
1985

    
1986
				if ($reflection_type != "none") {
1987
					if($reflection_type == "proxy" && !isset($rule['nordr'])) {
1988
						$natrules .= filter_generate_reflection_proxy($rule, $nordr, $nat_if_list, $srcaddr, $dstaddr, $starting_localhost_port, $reflection_rules);
1989
						$nat_if_list = array($natif);
1990
						foreach ($reflection_rules as $txtline)
1991
							fwrite($inetd_fd, $txtline);
1992
					} else if($reflection_type == "purenat" || isset($rule['nordr'])) {
1993
						$rdr_if_list = implode(" ", $nat_if_list);
1994
						if(count($nat_if_list) > 1)
1995
							$rdr_if_list = "{ {$rdr_if_list} }";
1996
						$natrules .= "\n# Reflection redirect\n";
1997
						$natrules .= "{$nordr}rdr {$rdrpass}on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr_reflect}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
1998
						$nat_if_list = array_merge(array($natif), $nat_if_list);
1999
					}
2000
				}
2001

    
2002
				if(empty($nat_if_list))
2003
					$nat_if_list = array($natif);
2004

    
2005
				$natrules .= "\n";
2006
				if(!isset($rule['nordr']))
2007
					$natrules .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, $protocol, "{$target}{$localport_nat}", $target_ip);
2008
			}
2009
		}
2010
	}
2011
	fclose($inetd_fd);		// Close file handle
2012

    
2013
	if (isset($config['pptpd']['mode']) && ($config['pptpd']['mode'] != "off")) {
2014
		if ($config['pptpd']['mode'] == "redir") {
2015
			$pptpdtarget = $config['pptpd']['redir'];
2016
			$natrules .= "# PPTP\n";
2017
			$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto gre from any to any -> {$pptpdtarget}\n";
2018
			$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto tcp from any to any port 1723 -> {$pptpdtarget}\n";
2019
		}
2020
	}
2021

    
2022
	$natrules .= discover_pkg_rules("nat");
2023

    
2024
	$natrules .= "# UPnPd rdr anchor\n";
2025
	$natrules .= "rdr-anchor \"miniupnpd\"\n";
2026

    
2027
	if(!empty($reflection_txt))
2028
		$natrules .= "\n# Reflection redirects and NAT for 1:1 mappings\n" . $reflection_txt;
2029

    
2030
	// Check if inetd is running, if not start it.	If so, restart it gracefully.
2031
	$helpers = isvalidproc("inetd");
2032
	if(file_exists("/var/etc/inetd.conf")) {
2033
		if(!$helpers)
2034
			mwexec("/usr/sbin/inetd -wW -R 0 -a 127.0.0.1 /var/etc/inetd.conf");
2035
		else
2036
			sigkillbypid("/var/run/inetd.pid", "HUP");
2037
	}
2038

    
2039
	return $natrules;
2040
}
2041

    
2042
function filter_generate_user_rule_arr($rule) {
2043
	global $config;
2044
	update_filter_reload_status(sprintf(gettext("Creating filter rule %s ..."), $rule['descr']));
2045
	$ret = array();
2046
	$line = filter_generate_user_rule($rule);
2047
	$ret['rule'] = $line;
2048
	$ret['interface'] = $rule['interface'];
2049
	if($rule['descr'] != "" and $line != "")
2050
		$ret['descr'] = "label \"" . fix_rule_label("USER_RULE: {$rule['descr']}") . "\"";
2051
	else
2052
		$ret['descr'] = "label \"USER_RULE\"";
2053

    
2054
	return $ret;
2055
}
2056

    
2057
function filter_generate_port(& $rule, $target = "source", $isnat = false) {
2058

    
2059
	$src = "";
2060

    
2061
	$rule['protocol'] = strtolower($rule['protocol']);
2062
	if(in_array($rule['protocol'], array("tcp","udp","tcp/udp"))) {
2063
		if($rule[$target]['port']) {
2064
			$srcport = explode("-", $rule[$target]['port']);
2065
			$srcporta = alias_expand($srcport[0]);
2066
			if(!$srcporta)
2067
				log_error(sprintf(gettext("filter_generate_port: %s is not a valid {$target} port."), $srcport[0]));
2068
			else if((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
2069
				$src .= " port {$srcporta} ";
2070
			} else if(($srcport[0] == 1) && ($srcport[1] == 65535)) {
2071
			/* no need for a port statement here */
2072
			} else if ($isnat) {
2073
				$src .= " port {$srcport[0]}:{$srcport[1]}";
2074
			} else {
2075
				if(is_port($srcporta) && $srcport[1] == 65535) {
2076
					$src .= " port >= {$srcporta} ";
2077
				} else if($srcport[0] == 1) {
2078
					$src .= " port <= {$srcport[1]} ";
2079
				} else {
2080
					$srcport[0]--;
2081
					$srcport[1]++;
2082
					$src .= " port {$srcport[0]} >< {$srcport[1]} ";
2083
				}
2084
			}
2085
		}
2086
	}
2087

    
2088
	return $src;
2089
}
2090

    
2091
function filter_address_add_vips_subnets(&$subnets, $if, $not) {
2092
	global $FilterIflist;
2093

    
2094
	$if_subnets = array($subnets);
2095

    
2096
	if ($not == true)
2097
		$subnets = "!{$subnets}";
2098

    
2099
	if (!isset($FilterIflist[$if]['vips']) || !is_array($FilterIflist[$if]['vips']))
2100
		return;
2101

    
2102
	foreach ($FilterIflist[$if]['vips'] as $vip) {
2103
		foreach ($if_subnets as $subnet)
2104
			if (ip_in_subnet($vip['ip'], $subnet))
2105
				continue 2;
2106

    
2107
		if (is_ipaddrv4($vip['ip'])) {
2108
			if (!is_subnetv4($if_subnets[0]))
2109
				continue;
2110

    
2111
			$network = gen_subnet($vip['ip'], $vip['sn']);
2112
		} else if (is_ipaddrv6($vip['ip'])) {
2113
			if (!is_subnetv6($if_subnets[0]))
2114
				continue;
2115

    
2116
			$network = gen_subnetv6($vip['ip'], $vip['sn']);
2117
		} else
2118
			continue;
2119

    
2120
		$subnets .= ' ' . ($not == true ? '!' : '') . $network . '/' . $vip['sn'];
2121
		$if_subnets[] = $network . '/' . $vip['sn'];
2122
	}
2123
	unset($if_subnets);
2124

    
2125
	if (strpos($subnets, ' ') !== false)
2126
		$subnets = "{ {$subnets} }";
2127
}
2128

    
2129
function filter_generate_address(& $rule, $target = "source", $isnat = false) {
2130
	global $FilterIflist, $config;
2131
	$src = "";
2132

    
2133
	if(isset($rule[$target]['any'])) {
2134
		$src = "any";
2135
	} else if($rule[$target]['network']) {
2136
		if(strstr($rule[$target]['network'], "opt")) {
2137
			$optmatch = "";
2138
			$matches = "";
2139
			if($rule['ipprotocol'] == "inet6") {
2140
				if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
2141
					$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ipv6'];
2142
					if(!is_ipaddrv6($opt_ip))
2143
						return "";
2144
					$src = $opt_ip . "/" . $FilterIflist["opt{$optmatch[1]}"]['snv6'];
2145
				/* check for opt$NUMip here */
2146
				} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
2147
					$src = $FilterIflist["opt{$matches[1]}"]['ipv6'];
2148
					if(!is_ipaddrv6($src))
2149
						return "";
2150
					if(isset($rule[$target]['not']))
2151
						$src = " !{$src}";
2152
				}
2153
			} else {
2154
				if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
2155
					$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ip'];
2156
					if(!is_ipaddrv4($opt_ip))
2157
						return "";
2158
					$src = $opt_ip . "/" . $FilterIflist["opt{$optmatch[1]}"]['sn'];
2159
				/* check for opt$NUMip here */
2160
				} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
2161
					$src = $FilterIflist["opt{$matches[1]}"]['ip'];
2162
					if(!is_ipaddrv4($src))
2163
						return "";
2164
					if(isset($rule[$target]['not']))
2165
						$src = " !{$src}";
2166
				}
2167
			}
2168
		} else {
2169
			if($rule['ipprotocol'] == "inet6") {
2170
				switch ($rule[$target]['network']) {
2171
					case 'wan':
2172
						$wansa = $FilterIflist['wan']['sav6'];
2173
						if (!is_ipaddrv6($wansa))
2174
							return "";
2175
						$wansn = $FilterIflist['wan']['snv6'];
2176
						$src = "{$wansa}/{$wansn}";
2177
						break;
2178
					case 'wanip':
2179
						$src = $FilterIflist["wan"]['ipv6'];
2180
						if (!is_ipaddrv6($src))
2181
							return "";
2182
						break;
2183
					case 'lanip':
2184
						$src = $FilterIflist["lan"]['ipv6'];
2185
						if (!is_ipaddrv6($src))
2186
							return "";
2187
						break;
2188
					case 'lan':
2189
						$lansa = $FilterIflist['lan']['sav6'];
2190
						if (!is_ipaddrv6($lansa))
2191
							return "";
2192
						$lansn = $FilterIflist['lan']['snv6'];
2193
						$src = "{$lansa}/{$lansn}";
2194
						break;
2195
					case '(self)':
2196
						$src = "(self)";
2197
						break;
2198
					case 'pptp':
2199
						$pptpsav6 = gen_subnetv6($FilterIflist['pptp']['sav6'], $FilterIflist['pptp']['snv6']);
2200
						$pptpsnv6 = $FilterIflist['pptp']['snv6'];
2201
						$src = "{$pptpsav6}/{$pptpsnv6}";
2202
						break;
2203
					case 'pppoe':
2204
						if (is_array($FilterIflist['pppoe'])) {
2205
							$pppoesav6 = gen_subnetv6($FilterIflist['pppoe'][0]['ipv6'], $FilterIflist['pppoe'][0]['snv6']);
2206
							$pppoesnv6 = $FilterIflist['pppoe'][0]['snv6'];
2207
							$src = "{$pppoesav6}/{$pppoesnv6}";
2208
						}
2209
					}
2210
				if(isset($rule[$target]['not']) && !is_subnet($src))
2211
					$src = " !{$src}";
2212
			} else {
2213
				switch ($rule[$target]['network']) {
2214
					case 'wan':
2215
						$wansa = $FilterIflist['wan']['sa'];
2216
						if (!is_ipaddrv4($wansa))
2217
							return "";
2218
						$wansn = $FilterIflist['wan']['sn'];
2219
						$src = "{$wansa}/{$wansn}";
2220
						break;
2221
					case 'wanip':
2222
						$src = $FilterIflist["wan"]['ip'];
2223
						break;
2224
					case 'lanip':
2225
						$src = $FilterIflist["lan"]['ip'];
2226
						break;
2227
					case 'lan':
2228
						$lansa = $FilterIflist['lan']['sa'];
2229
						if (!is_ipaddrv4($lansa))
2230
							return "";
2231
						$lansn = $FilterIflist['lan']['sn'];
2232
						$src = "{$lansa}/{$lansn}";
2233
						break;
2234
					case '(self)':
2235
						$src = "(self)";
2236
						break;
2237
					case 'pptp':
2238
						if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
2239
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
2240
						else
2241
							$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
2242
						if (empty($pptp_subnets))
2243
							return "";
2244
						if(isset($rule[$target]['not']))
2245
							array_walk($pptp_subnets, function (&$value, $key) {
2246
								$value="!{$value}";
2247
							});
2248
						$src = "{ " . implode(" ", $pptp_subnets) . " }";
2249
						break;
2250
					case 'pppoe':
2251
						/* XXX: This needs to be fixed somehow! */
2252
						if (is_array($FilterIflist['pppoe'])) {
2253
							$pppoesa = gen_subnet($FilterIflist['pppoe'][0]['ip'], $FilterIflist['pppoe'][0]['sn']);
2254
							$pppoesn = $FilterIflist['pppoe'][0]['sn'];
2255
							$src = "{$pppoesa}/{$pppoesn}";
2256
						}
2257
						break;
2258
				}
2259
				if(isset($rule[$target]['not']) && !is_subnet($src) &&
2260
				    (strpos($src, '{') === false))
2261
					$src = " !{$src}";
2262
			}
2263
		}
2264
		if (is_subnet($src))
2265
			filter_address_add_vips_subnets($src, $rule[$target]['network'], isset($rule[$target]['not']));
2266
	} else if($rule[$target]['address']) {
2267
		$expsrc = alias_expand($rule[$target]['address']);
2268
		if(isset($rule[$target]['not']))
2269
			$not = "!";
2270
		else
2271
			$not = "";
2272
		$src = " {$not} {$expsrc}";
2273
	}
2274

    
2275
	$src .= filter_generate_port($rule, $target, $isnat);
2276

    
2277
	return $src;
2278
}
2279

    
2280
function filter_generate_user_rule($rule) {
2281
	global $config, $g, $FilterIflist, $GatewaysList;
2282
	global $layer7_rules_list, $dummynet_name_list;
2283

    
2284
	if(isset($config['system']['developerspew'])) {
2285
		$mt = microtime();
2286
		echo "filter_generate_user_rule() being called $mt\n";
2287
	}
2288
	/* don't include disabled rules */
2289
	if(isset($rule['disabled'])) {
2290
		return "# rule " . $rule['descr'] . " disabled \n";
2291
	}
2292
	update_filter_reload_status("Creating filter rules {$rule['descr']} ...");
2293
	$pptpdcfg = $config['pptpd'];
2294
	$int = "";
2295
	$aline = array();
2296

    
2297
	/* Check to see if the interface is in our list */
2298
	if(isset($rule['floating'])) {
2299
		if(isset($rule['interface']) && $rule['interface'] <> "") {
2300
			$interfaces = explode(",", $rule['interface']);
2301
			$ifliste = "";
2302
			foreach ($interfaces as $iface) {
2303
				if(array_key_exists($iface, $FilterIflist))
2304
					$ifliste .= " " . $FilterIflist[$iface]['if'] . " ";
2305
			}
2306
			if($ifliste <> "")
2307
				$aline['interface'] = " on { {$ifliste} } ";
2308
			else
2309
				$aline['interface'] = "";
2310
		} else
2311
			$aline['interface'] = "";
2312
	} else if(!array_key_exists($rule['interface'], $FilterIflist)) {
2313
			foreach($FilterIflist as $oc)
2314
				$items .= $oc['descr'] . " ";
2315
			return "# array key \"{$rule['interface']}\" does not exist for \"" . $rule['descr'] . "\" in array: {{$items}}";
2316
	} else if((array_key_exists($rule['interface'], $FilterIflist))
2317
		&& (is_array($FilterIflist[$rule['interface']]))
2318
		&& (is_array($FilterIflist[$rule['interface']][0]))) {
2319
		/* Currently this only case for this is the pppoe server. There should be an existing macro with this name. */
2320
		$aline['interface'] = " on \$" . $rule['interface'] . " ";
2321
	} else
2322
		$aline['interface'] = " on \$" . $FilterIflist[$rule['interface']]['descr'] . " ";
2323
	$ifcfg = $FilterIflist[$rule['interface']];
2324
	if($pptpdcfg['mode'] != "server") {
2325
		if(($rule['source']['network'] == "pptp") ||
2326
			($rule['destination']['network'] == "pptp"))
2327
				return "# source network or destination network == pptp on " . $rule['descr'];
2328
	}
2329

    
2330
	switch($rule['ipprotocol']) {
2331
	case "inet":
2332
		$aline['ipprotocol'] = "inet";
2333
		break;
2334
	case "inet6":
2335
		$aline['ipprotocol'] = "inet6";
2336
		break;
2337
	default:
2338
		$aline['ipprotocol'] = "";
2339
		break;
2340
	}
2341

    
2342
	/* check for unresolvable aliases */
2343
	if($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
2344
		$error_text = "Unresolvable source alias '{$rule['source']['address']}' for rule '{$rule['descr']}'";
2345
		file_notice("Filter_Reload", $error_text);
2346
		return "# {$error_text}";
2347
	}
2348
	if($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
2349
		$error_text = "Unresolvable destination alias '{$rule['destination']['address']}' for rule '{$rule['descr']}'";
2350
		file_notice("Filter_Reload", $error_text);
2351
		return "# {$error_text}";
2352
	}
2353
	update_filter_reload_status("Setting up pass/block rules");
2354
	$type = $rule['type'];
2355
	if($type != "pass" && $type != "block" && $type != "reject" && $type != "match") {
2356
		/* default (for older rules) is pass */
2357
		$type = "pass";
2358
	}
2359
	if($type == "reject") {
2360
		$aline['type'] = "block return ";
2361
	} else
2362
		$aline['type'] = $type . " ";
2363
	if(isset($rule['floating']) && $rule['floating'] == "yes") {
2364
		if($rule['direction'] != "any")
2365
			$aline['direction'] = " " . $rule['direction'] . " ";
2366
	} else {
2367
		/* ensure the direction is in */
2368
		$aline['direction'] = " in ";
2369
	}
2370
	if(isset($rule['log']))
2371
		$aline['log'] = "log ";
2372
	if(!isset($rule['floating']) || isset($rule['quick']))
2373
		$aline['quick'] = " quick ";
2374

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

    
2378
	/* do not process reply-to for gateway'd rules */
2379
	if($rule['gateway'] == "" && $aline['direction'] <> "" && (interface_has_gateway($rule['interface']) || interface_has_gatewayv6($rule['interface'])) && !isset($config['system']['disablereplyto']) && !isset($rule['disablereplyto']) && $type != "match") {
2380
		if ($rule['ipprotocol'] == "inet6") {
2381
			$rg = get_interface_gateway_v6($rule['interface']);
2382
			if (is_ipaddrv6($rg))
2383
				$aline['reply'] = "reply-to ( {$ifcfg['ifv6']} {$rg} ) ";
2384
			else if ($rule['interface'] <> "pptp")
2385
				log_error("Could not find IPv6 gateway for interface({$rule['interface']}).");
2386
		} else {
2387
			$rg = get_interface_gateway($rule['interface']);
2388
			if (is_ipaddrv4($rg))
2389
				$aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) ";
2390
			else if ($rule['interface'] <> "pptp")
2391
				log_error(sprintf(gettext("Could not find IPv4 gateway for interface (%s)."), $rule['interface']));
2392
		}
2393
	}
2394
	/* if user has selected a custom gateway, lets work with it */
2395
	else if($rule['gateway'] <> "" && $type == "pass") {
2396
		if (isset($GatewaysList[$rule['gateway']]))
2397
			/* Add the load balanced gateways */
2398
			$aline['route'] = " \$GW{$rule['gateway']} ";
2399
		else if (isset($config['system']['skip_rules_gw_down']))
2400
			return "# rule " . $rule['descr'] . " disabled because gateway " . $rule['gateway'] . " is down ";
2401
		else
2402
			log_error("The gateway: {$rule['gateway']} is invalid or unknown, not using it.");
2403
	}
2404

    
2405
	if (isset($rule['protocol']) && !empty($rule['protocol'])) {
2406
		if($rule['protocol'] == "tcp/udp")
2407
			$aline['prot'] = " proto { tcp udp } ";
2408
		elseif(($rule['protocol'] == "icmp") && ($rule['ipprotocol'] == "inet6"))
2409
			$aline['prot'] = " proto ipv6-icmp ";
2410
		elseif($rule['protocol'] == "icmp")
2411
			$aline['prot'] = " proto icmp ";
2412
		else
2413
			$aline['prot'] = " proto {$rule['protocol']} ";
2414
	} else {
2415
		if($rule['source']['port'] <> "" || $rule['destination']['port'] <> "")
2416
			$aline['prot'] = " proto tcp ";
2417
	}
2418
	update_filter_reload_status(sprintf(gettext("Creating rule %s"), $rule['descr']));
2419

    
2420
	/* source address */
2421
	$src = trim(filter_generate_address($rule, "source"));
2422
	if (empty($src) || ($src == "/")) {
2423
		return "# at the break!";
2424
	}
2425
	$aline['src'] = " from $src ";
2426

    
2427
	/* OS signatures */
2428
	if(($rule['protocol'] == "tcp") && ($rule['os'] <> ""))
2429
		$aline['os'] = " os \"{$rule['os']}\" ";
2430

    
2431
	/* destination address */
2432
	$dst = trim(filter_generate_address($rule, "destination"));
2433
	if (empty($dst) || ($dst == "/")) {
2434
		return "# returning at dst $dst == \"/\"";
2435
	}
2436
	$aline['dst'] = "to $dst ";
2437

    
2438
	//Layer7 support
2439
	$l7_present = false;
2440
	$l7_structures = array();
2441
	if(isset($rule['l7container']) && $rule['l7container'] != "none") {
2442
		$l7_present = true;
2443
		$l7rule =& $layer7_rules_list[$rule['l7container']];
2444
		$l7_structures = $l7rule->get_unique_structures();
2445
		$aline['divert'] = "divert-to " . $l7rule->GetRPort() . " ";
2446
	}
2447
	if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet"))
2448
		$aline['icmp-type'] = "icmp-type {$rule['icmptype']} ";
2449
	if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet6"))
2450
		$aline['icmp6-type'] = "icmp6-type {$rule['icmptype']} ";
2451
	if (!empty($rule['tag']))
2452
		$aline['tag'] = " tag " .$rule['tag']. " ";
2453
	if (!empty($rule['tagged']))
2454
		$aline['tagged'] = " tagged " .$rule['tagged'] . " ";
2455
	if (!empty($rule['dscp'])) {
2456
		switch (strtolower($rule['dscp'])) {
2457
			case 'va':  $aline['dscp'] = " dscp 44 "; break;
2458
			case 'cs1': $aline['dscp'] = " dscp 8 ";  break;
2459
			case 'cs2': $aline['dscp'] = " dscp 16 "; break;
2460
			case 'cs3': $aline['dscp'] = " dscp 24 "; break;
2461
			case 'cs4': $aline['dscp'] = " dscp 32 "; break;
2462
			case 'cs5': $aline['dscp'] = " dscp 40 "; break;
2463
			case 'cs6': $aline['dscp'] = " dscp 48 "; break;
2464
			case 'cs7': $aline['dscp'] = " dscp 56 "; break;
2465
			default:    $aline['dscp'] = " dscp " . $rule['dscp'] . " "; break;
2466
		}
2467
	}
2468
	if (!empty($rule['vlanprio']) && ($rule['vlanprio'] != "none"))
2469
		$aline['vlanprio'] = " ieee8021q-pcp " . $rule['vlanprio'] . " ";
2470
	if (!empty($rule['vlanprioset']) && ($rule['vlanprioset'] != "none"))
2471
		$aline['vlanprioset'] = " ieee8021q-setpcp " . $rule['vlanprioset'] . " ";
2472
	if ($type == "pass") {
2473
		if (isset($rule['allowopts']))
2474
			$aline['allowopts'] = " allow-opts ";
2475
	}
2476
	$aline['flags'] = "";
2477
	if ($rule['protocol'] == "tcp") {
2478
		if (isset($rule['tcpflags_any']))
2479
			$aline['flags'] = "flags any ";
2480
		else if (!empty($rule['tcpflags2'])) {
2481
			$aline['flags'] = "flags ";
2482
			if (!empty($rule['tcpflags1'])) {
2483
				$flags1 = explode(",", $rule['tcpflags1']);
2484
				foreach ($flags1 as $flag1) {
2485
					// CWR flag needs special treatment
2486
					if($flag1[0] == "c")
2487
						$aline['flags'] .= "W";
2488
					else
2489
						$aline['flags'] .= strtoupper($flag1[0]);
2490
				}
2491
			}
2492
			$aline['flags'] .= "/";
2493
			if (!empty($rule['tcpflags2'])) {
2494
				$flags2 = explode(",", $rule['tcpflags2']);
2495
				foreach ($flags2 as $flag2) {
2496
					// CWR flag needs special treatment
2497
					if($flag2[0] == "c")
2498
						$aline['flags'] .= "W";
2499
					else
2500
						$aline['flags'] .= strtoupper($flag2[0]);
2501
				}
2502
			}
2503
			$aline['flags'] .= " ";
2504
		} else {
2505
			$aline['flags'] = "flags S/SA ";
2506
		}
2507
	}
2508
	if ($type == "pass") {
2509
		/*
2510
		 *	# keep state
2511
		 *		works with TCP, UDP, and ICMP.
2512
		 *	# modulate state
2513
		 *		works only with TCP. pfSense will generate strong Initial Sequence Numbers (ISNs)
2514
		 *		for packets matching this rule.
2515
		 *	# synproxy state
2516
		 *		proxies incoming TCP connections to help protect servers from spoofed TCP SYN floods.
2517
		 *		This option includes the functionality of keep state and modulate state combined.
2518
		 *	# none
2519
		 *		do not use state mechanisms to keep track. this is only useful if your doing advanced
2520
		 *		queueing in certain situations. please check the faq.
2521
		 */
2522
		$noadvoptions = false;
2523
		if (isset($rule['statetype']) && $rule['statetype'] <> "") {
2524
			switch($rule['statetype']) {
2525
				case "none":
2526
					$noadvoptions = true;
2527
					$aline['flags'] .= " no state ";
2528
					break;
2529
				case "modulate state":
2530
				case "synproxy state":
2531
					if ($rule['protocol'] == "tcp")
2532
						$aline['flags'] .= "{$rule['statetype']} ";
2533
					break;
2534
				case "sloppy state":
2535
					$aline['flags'] .= "keep state ";
2536
					$rule['sloppy'] = true;
2537
					break;
2538
				default:
2539
					$aline['flags'] .= "{$rule['statetype']} ";
2540
					break;
2541
			}
2542
		} else
2543
			$aline['flags'] .= "keep state ";
2544

    
2545
		if ($noadvoptions == false && isset($rule['nopfsync']))
2546
			$rule['nopfsync'] = true;
2547

    
2548
		if ($noadvoptions == false || $l7_present)
2549
			if ((isset($rule['source-track']) and $rule['source-track'] <> "") or
2550
			    (isset($rule['max']) and $rule['max'] <> "") or
2551
			    (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") or
2552
			    (isset($rule['max-src-states']) and $rule['max-src-states'] <> "") or
2553
			    ((in_array($rule['protocol'], array("tcp","tcp/udp"))) and
2554
			     ((isset($rule['statetimeout']) and $rule['statetimeout'] <> "") or
2555
			      (isset($rule['max-src-conn']) and $rule['max-src-conn'] <> "") or
2556
			      (isset($rule['max-src-conn-rate']) and $rule['max-src-conn-rate'] <> "") or
2557
			      (isset($rule['max-src-conn-rates']) and $rule['max-src-conn-rates'] <> ""))) or
2558
			    isset($rule['sloppy']) or isset($rule['nopfsync']) or $l7_present) {
2559
					$aline['flags'] .= "( ";
2560
					if (isset($rule['sloppy']))
2561
						$aline['flags'] .= "sloppy ";
2562
					if (isset($rule['nopfsync']))
2563
						$aline['flags'] .= "no-sync ";
2564
					if (isset($rule['source-track']) and $rule['source-track'] <> "")
2565
						$aline['flags'] .= "source-track rule ";
2566
					if (isset($rule['max']) and $rule['max'] <> "")
2567
						$aline['flags'] .= "max " . $rule['max'] . " ";
2568
					if (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "")
2569
						$aline['flags'] .= "max-src-nodes " . $rule['max-src-nodes'] . " ";
2570
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2571
							and isset($rule['max-src-conn']) 
2572
							and $rule['max-src-conn'] <> "")
2573
						$aline['flags'] .= "max-src-conn " . $rule['max-src-conn'] . " ";
2574
					if (isset($rule['max-src-states']) and $rule['max-src-states'] <> "")
2575
						$aline['flags'] .= "max-src-states " . $rule['max-src-states'] . " ";
2576
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2577
							and isset($rule['statetimeout']) 
2578
							and $rule['statetimeout'] <> "")
2579
						$aline['flags'] .= "tcp.established " . $rule['statetimeout'] . " ";
2580
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2581
							and isset($rule['max-src-conn-rate'])
2582
							and $rule['max-src-conn-rate'] <> ""
2583
							and isset($rule['max-src-conn-rates'])
2584
							and $rule['max-src-conn-rates'] <> "") {
2585
						$aline['flags'] .= "max-src-conn-rate " . $rule['max-src-conn-rate'] . " ";
2586
						$aline['flags'] .= "/" . $rule['max-src-conn-rates'] . ", overload <virusprot> flush global ";
2587
					}
2588

    
2589
					if(!empty($aline['divert']))
2590
						$aline['flags'] .= "max-packets 8 ";
2591

    
2592
					$aline['flags'] .= " ) ";
2593
				}
2594
	}
2595
	if($rule['defaultqueue'] <> "") {
2596
		$aline['queue'] = " queue (".$rule['defaultqueue'];
2597
		if($rule['ackqueue'] <> "")
2598
			$aline['queue'] .= ",".$rule['ackqueue'];
2599
		$aline['queue'] .= ") ";
2600
	}
2601
	if($rule['dnpipe'] <> "") {
2602
		if (!empty($dummynet_name_list[$rule['dnpipe']])) {
2603
			if($dummynet_name_list[$rule['dnpipe']][0] == "?") {
2604
				$aline['dnpipe'] = " dnqueue( ";
2605
				$aline['dnpipe'] .= substr($dummynet_name_list[$rule['dnpipe']],1);
2606
				if($rule['pdnpipe'] <> "")
2607
					$aline['dnpipe'] .= ",".substr($dummynet_name_list[$rule['pdnpipe']], 1);
2608
			} else {
2609
				$aline['dnpipe'] = " dnpipe ( " . $dummynet_name_list[$rule['dnpipe']];
2610
				if($rule['pdnpipe'] <> "")
2611
					$aline['dnpipe'] .= "," . $dummynet_name_list[$rule['pdnpipe']];
2612
			}
2613
			$aline['dnpipe'] .= ") ";
2614
		}
2615
	}
2616

    
2617
	/* is a time based rule schedule attached? */
2618
	if(!empty($rule['sched']) && !empty($config['schedules'])) {
2619
		$aline['schedlabel'] = "";
2620
		foreach ($config['schedules']['schedule'] as $sched) {
2621
			if($sched['name'] == $rule['sched']) {
2622
				if(!filter_get_time_based_rule_status($sched)) {
2623
					if(!isset($config['system']['schedule_states']))
2624
						mwexec("/sbin/pfctl -y {$sched['schedlabel']}");
2625
					return "# schedule finished - {$rule['descr']}";
2626
				} else if($g['debug'])
2627
					log_error("[TDR DEBUG] status true -- rule type '$type'");
2628

    
2629
				$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
2630
				break;
2631
			}
2632
		}
2633
	}
2634

    
2635
	if (!empty($rule['tracker']))
2636
		$aline['tracker'] = "tracker {$rule['tracker']} ";
2637

    
2638
	$line = "";
2639
	/* exception(s) to a user rules can go here. */
2640
	/* rules with a gateway or pool should create another rule for routing to vpns */
2641
	if((($aline['route'] <> "") && (trim($aline['type']) == "pass") && strstr($dst, "any")) && (!isset($config['system']['disablenegate']))) {
2642
		/* negate VPN/PPTP/PPPoE/Static Route networks for load balancer/gateway rules */
2643
		$negate_networks = " to <negate_networks> " . filter_generate_port($rule, "destination");
2644
		$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] .
2645
			$aline['interface'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] .
2646
			$negate_networks . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] .
2647
			$aline['vlanprio'] . $aline['vlanprioset'] . $aline['dscp'] . $aline['tracker'] . $aline['allowopts'] . $aline['flags'] .
2648
			$aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'] .
2649
			" label \"NEGATE_ROUTE: Negate policy routing for destination\"\n";
2650

    
2651
	}
2652
	/* piece together the actual user rule */
2653
	$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
2654
		$aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
2655
		$aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] . $aline['tracker'] .
2656
		$aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
2657

    
2658
	unset($aline);
2659

    
2660
	return $line;
2661
}
2662

    
2663
function filter_rules_generate() {
2664
	global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
2665

    
2666
	$fix_rule_label = 'fix_rule_label';
2667
	$increment_tracker = 'filter_rule_tracker';
2668

    
2669
	update_filter_reload_status(gettext("Creating default rules"));
2670
	if(isset($config['system']['developerspew'])) {
2671
		$mt = microtime();
2672
		echo "filter_rules_generate() being called $mt\n";
2673
	}
2674

    
2675
	$pptpdcfg = $config['pptpd'];
2676

    
2677
	$ipfrules = "";
2678
	$ipfrules .= discover_pkg_rules("pfearly");
2679

    
2680
	/* relayd */
2681
	$ipfrules .= "anchor \"relayd/*\"\n";
2682
	/* OpenVPN user rules from radius */
2683
	$ipfrules .= "anchor \"openvpn/*\"\n";
2684
	/* IPsec user rules from radius */
2685
	$ipfrules .= "anchor \"ipsec/*\"\n";
2686
	# BEGIN OF firewall rules
2687
	/* default block logging? */
2688
	$log = array(); 
2689
	if(!isset($config['syslog']['nologdefaultblock']))
2690
		$log['block'] = "log";
2691
	if(isset($config['syslog']['nologdefaultpass']))
2692
		$log['pass'] = "log";
2693

    
2694
	$saved_tracker = $tracker;
2695

    
2696
	if(!isset($config['system']['ipv6allow'])) {
2697
		$ipfrules .= "# Block all IPv6\n";
2698
		$ipfrules .= "block in {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2699
		$ipfrules .= "block out {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2700
	}
2701

    
2702
	$saved_tracker += 100;
2703
	$tracker = $saved_tracker;
2704

    
2705
	$ipfrules .= <<<EOD
2706
# block IPv4 link-local. Per RFC 3927, link local "MUST NOT" be forwarded by a routing device,
2707
# and clients "MUST NOT" send such packets to a router. FreeBSD won't route 169.254./16, but
2708
# route-to can override that, causing problems such as in redmine #2073
2709
block in {$log['block']} quick from 169.254.0.0/16 to any
2710
block in {$log['block']} quick from any to 169.254.0.0/16 
2711
#---------------------------------------------------------------------------
2712
# default deny rules
2713
#---------------------------------------------------------------------------
2714
block in {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2715
block out {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2716
block in {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2717
block out {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2718

    
2719
# IPv6 ICMP is not auxilary, it is required for operation
2720
# See man icmp6(4)
2721
# 1    unreach         Destination unreachable
2722
# 2    toobig          Packet too big
2723
# 128  echoreq         Echo service request
2724
# 129  echorep         Echo service reply
2725
# 133  routersol       Router solicitation
2726
# 134  routeradv       Router advertisement
2727
# 135  neighbrsol      Neighbor solicitation
2728
# 136  neighbradv      Neighbor advertisement
2729
pass {$log['pass']} quick inet6 proto ipv6-icmp from any to any icmp6-type {1,2,135,136} tracker {$increment_tracker($tracker)} keep state
2730

    
2731
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
2732
pass out {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2733
pass out {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2734
pass in {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2735
pass in {$log['pass']} quick inet6 proto ipv6-icmp from ff02::/16 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2736
pass in {$log['pass']} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
2737

    
2738
# We use the mighty pf, we cannot be fooled.
2739
block {$log['block']} quick inet proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2740
block {$log['block']} quick inet proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2741
block {$log['block']} quick inet6 proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2742
block {$log['block']} quick inet6 proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2743

    
2744
# Snort package
2745
block {$log['block']} quick from <snort2c> to any tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2746
block {$log['block']} quick from any to <snort2c> tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2747

    
2748
EOD;
2749

    
2750
	$saved_tracker += 100;
2751
	$tracker = $saved_tracker;
2752

    
2753
	$ipfrules .= filter_process_carp_rules($log);
2754

    
2755
	$saved_tracker += 100;
2756
	$tracker = $saved_tracker;
2757

    
2758
	$ipfrules .= "\n# SSH lockout\n";
2759
	if(is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
2760
		$ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port ";
2761
		$ipfrules .= $config['system']['ssh']['port'];
2762
		$ipfrules .= " tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
2763
	} else {
2764
		if($config['system']['ssh']['port'] <> "")
2765
			$sshport = $config['system']['ssh']['port'];
2766
		else
2767
			$sshport = 22;
2768
		if($sshport)
2769
			$ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port {$sshport} tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
2770
	}
2771

    
2772
	$saved_tracker += 50;
2773
	$tracker = $saved_tracker;
2774

    
2775
	$ipfrules .= "\n# webConfigurator lockout\n";
2776
	if(!$config['system']['webgui']['port']) {
2777
		if($config['system']['webgui']['protocol'] == "http")
2778
			$webConfiguratorlockoutport = "80";
2779
		else
2780
			$webConfiguratorlockoutport = "443";
2781
	} else {
2782
		$webConfiguratorlockoutport = $config['system']['webgui']['port'];
2783
	}
2784
	if($webConfiguratorlockoutport)
2785
		$ipfrules .= "block in {$log['block']} quick proto tcp from <webConfiguratorlockout> to (self) port {$webConfiguratorlockoutport} tracker {$increment_tracker($tracker)} label \"webConfiguratorlockout\"\n";
2786

    
2787
	$saved_tracker += 100;
2788
	$tracker = $saved_tracker;
2789

    
2790
	/*
2791
	 * Support for allow limiting of TCP connections by establishment rate
2792
	 * Useful for protecting against sudden outburts, etc.
2793
	 */
2794
	$ipfrules .= "block in {$log['block']} quick from <virusprot> to any tracker 1000000400 label \"virusprot overload table\"\n";
2795

    
2796
	$saved_tracker += 100;
2797
	$tracker = $saved_tracker;
2798

    
2799
	/* if captive portal is enabled, ensure that access to this port
2800
	 * is allowed on a locked down interface
2801
	 */
2802
	if(is_array($config['captiveportal'])) {
2803
		foreach ($config['captiveportal'] as $cpcfg) {
2804
			if(!isset($cpcfg['enable']))
2805
				continue;
2806
			$cpinterfaces = explode(",", $cpcfg['interface']);
2807
			$cpiflist = array();
2808
			$cpiplist = array();
2809
			foreach ($cpinterfaces as $cpifgrp) {
2810
				if(!isset($FilterIflist[$cpifgrp]))
2811
					continue;
2812
				$tmpif = get_real_interface($cpifgrp);
2813
				if(!empty($tmpif)) {
2814
					$cpiflist[] = "{$tmpif}";
2815
					$cpipm = get_interface_ip($cpifgrp);
2816
					if(is_ipaddr($cpipm)) {
2817
						$carpif = link_ip_to_carp_interface($cpipm);
2818
						if (!empty($carpif)) {
2819
							$cpiflist[] = $carpif;
2820
							$carpsif = explode(" ", $carpif);
2821
							foreach ($carpsif as $cpcarp) {
2822
								$carpip = find_interface_ip($cpcarp);
2823
								if (is_ipaddr($carpip))
2824
									$cpiplist[] = $carpip;
2825
							}
2826
						}
2827
						$cpiplist[] = $cpipm;
2828
					}
2829
				}
2830
			}
2831
			if (count($cpiplist) > 0 && count($cpiflist) > 0) {
2832
				$cpinterface = implode(" ", $cpiflist);
2833
				$cpaddresses = implode(" ", $cpiplist);
2834
				$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
2835
				$listenporthttp  = $cpcfg['listenporthttp']  ? $cpcfg['listenporthttp']  : $cpcfg['zoneid'];
2836
				$portalias = $listenporthttps;
2837
				$portalias .= " {$listenporthttp}";
2838
				$ipfrules .= "pass in {$log['pass']} quick on { {$cpinterface} } proto tcp from any to { {$cpaddresses} } port { {$portalias} } tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
2839
				$ipfrules .= "pass out {$log['pass']} quick on { {$cpinterface} } proto tcp from any to any flags any tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
2840
			}
2841
		}
2842
	}
2843

    
2844
	$bogontableinstalled = 0;
2845
	foreach ($FilterIflist as $on => $oc) {
2846
		/* XXX: Not static but give a step of 1000 for each interface to at least be able to match rules. */
2847
		$saved_tracker += 1000;
2848
		$tracker = $saved_tracker;
2849

    
2850
		/* block bogon networks */
2851
		/* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
2852
		/* file is automatically in cron every 3000 minutes */
2853
		if(!isset($config['syslog']['nologbogons']))
2854
			$bogonlog = "log";
2855
		else
2856
			$bogonlog = "";
2857

    
2858
		if(isset($config['interfaces'][$on]['blockbogons'])) {
2859
			$ipfrules .= <<<EOD
2860
# block bogon networks (IPv4)
2861
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
2862
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']}")}"
2863

    
2864
EOD;
2865

    
2866
			if(isset($config['system']['ipv6allow'])) {
2867
				$ipfrules .= <<<EOD
2868
# block bogon networks (IPv6)
2869
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
2870
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']}")}"
2871

    
2872
EOD;
2873
			}
2874
		}
2875

    
2876

    
2877
		$saved_tracker += 10;
2878
		$tracker = $saved_tracker;
2879

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

    
2887
EOD;
2888
		}
2889

    
2890
		$saved_tracker += 10;
2891
		$tracker = $saved_tracker;
2892

    
2893
		$isbridged = false;
2894
		if(is_array($config['bridges']['bridged'])) {
2895
			foreach ($config['bridges']['bridged'] as $oc2) {
2896
				if(stristr($oc2['members'], $on)) {
2897
					$isbridged = true;
2898
					break;
2899
				}
2900
			}
2901
		}
2902

    
2903
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2904
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
2905

    
2906
		/* block private networks ? */
2907
		if(!isset($config['syslog']['nologprivatenets']))
2908
			$privnetlog = "log";
2909
		else
2910
			$privnetlog = "";
2911

    
2912
		$saved_tracker += 10;
2913
		$tracker = $saved_tracker;
2914

    
2915
		if(isset($config['interfaces'][$on]['blockpriv'])) {
2916
			if($isbridged == false) {
2917
				$ipfrules .= <<<EOD
2918
# block anything from private networks on interfaces with the option set
2919
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")}"
2920
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")}"
2921
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")}"
2922
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")}"
2923
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")}"
2924
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")}"
2925

    
2926
EOD;
2927
			}
2928
		}
2929

    
2930
		$saved_tracker += 10;
2931
		$tracker = $saved_tracker;
2932

    
2933
		switch ($oc['type']) {
2934
		case "pptp":
2935
				$ipfrules .= <<<EOD
2936
# allow PPTP client
2937
pass in {$log['pass']} on \${$oc['descr']} proto tcp from any to any port = 1723 flags S/SA modulate state tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
2938
pass in {$log['pass']} on \${$oc['descr']} proto gre from any to any keep state tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow PPTP client on {$oc['descr']}")}"
2939

    
2940
EOD;
2941
			break;
2942
		case "dhcp":
2943
			$ipfrules .= <<<EOD
2944
# allow our DHCP client out to the {$oc['descr']}
2945
pass in {$log['pass']} on \${$oc['descr']} proto udp from any port = 67 to any port = 68 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
2946
pass out {$log['pass']} on \${$oc['descr']} proto udp from any port = 68 to any port = 67 tracker {$increment_tracker($tracker)} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}"
2947
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2948

    
2949
EOD;
2950

    
2951
			break;
2952
		case "pppoe":
2953
		case "none":
2954
			/* XXX: Nothing to do in this case?! */
2955
			break;
2956
		default:
2957
			/* allow access to DHCP server on interfaces */
2958
			if(isset($config['dhcpd'][$on]['enable'])) {
2959
				$ipfrules .= <<<EOD
2960
# allow access to DHCP server on {$oc['descr']}
2961
pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to 255.255.255.255 port = 67 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
2962

    
2963
EOD;
2964
				if (is_ipaddrv4($oc['ip'])) {
2965
					$ipfrules .= <<<EOD
2966
pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to {$oc['ip']} port = 67 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
2967
pass out {$log['pass']} quick on \${$oc['descr']} proto udp from {$oc['ip']} port = 67 to any port = 68 tracker {$increment_tracker($tracker)} label "allow access to DHCP server"
2968

    
2969
EOD;
2970
				}
2971

    
2972
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2973
					$ipfrules .= <<<EOD
2974
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2975
pass in {$log['pass']} quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 519 tracker {$increment_tracker($tracker)} label "allow access to DHCP failover"
2976
pass in {$log['pass']} quick on \${$oc['descr']} proto { tcp udp } from {$config['dhcpd'][$on]['failover_peerip']} to {$oc['ip']} port = 520 tracker {$increment_tracker($tracker)} label "allow access to DHCP failover"
2977

    
2978
EOD;
2979
				}
2980

    
2981
			}
2982
			break;
2983
		}
2984

    
2985
		$saved_tracker += 10;
2986
		$tracker = $saved_tracker;
2987
		switch($oc['type6']) {
2988
		case "6rd":
2989
			$ipfrules .= <<<EOD
2990
# allow our proto 41 traffic from the 6RD border relay in
2991
pass in {$log['pass']} on \${$oc['descr']} proto 41 from {$config['interfaces'][$on]['gateway-6rd']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6rd on {$oc['descr']}")}"
2992
pass out {$log['pass']} on \${$oc['descr']} proto 41 from any to {$config['interfaces'][$on]['gateway-6rd']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6rd on {$oc['descr']}")}"
2993

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

    
3001
EOD;
3002
		}
3003
			break;
3004
		case "6to4":
3005
			if (is_ipaddrv4($oc['ip'])) {
3006
			$ipfrules .= <<<EOD
3007
# allow our proto 41 traffic from the 6to4 border relay in
3008
pass in {$log['pass']} on \${$oc['descr']} proto 41 from any to {$oc['ip']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
3009
pass out {$log['pass']} on \${$oc['descr']} proto 41 from {$oc['ip']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
3010

    
3011
EOD;
3012
		}
3013
		/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
3014
		if (0 && is_ipaddrv6($oc['ipv6'])) {
3015
			$ipfrules .= <<<EOD
3016
pass in {$log['pass']} on \${$oc['descr']} inet6 from any to {$oc['ipv6']}/{$oc['snv6']} tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic in for 6to4 on {$oc['descr']}")}"
3017
pass out {$log['pass']} on \${$oc['descr']} inet6 from {$oc['ipv6']}/{$oc['snv6']} to any tracker {$increment_tracker($tracker)} label "{$fix_rule_label("Allow 6in4 traffic out for 6to4 on {$oc['descr']}")}"
3018

    
3019
EOD;
3020
		}
3021
			break;
3022
		default:
3023
			if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface']) 
3024
				|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
3025
				$ipfrules .= <<<EOD
3026
# allow access to DHCPv6 server on {$oc['descr']}
3027
# We need inet6 icmp for stateless autoconfig and dhcpv6
3028
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to fe80::/10 port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
3029
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
3030
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to ff02::/16 port = 547 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
3031
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from ff02::/16 to fe80::/10 port = 547 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
3032

    
3033
EOD;
3034
				if (is_ipaddrv6($oc['ipv6'])) {
3035
					$ipfrules .= <<<EOD
3036
pass in {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from fe80::/10 to {$oc['ipv6']} port = 546 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
3037
pass out {$log['pass']} quick on \${$oc['descr']} inet6 proto udp from {$oc['ipv6']} port = 547 to fe80::/10 tracker {$increment_tracker($tracker)} label "allow access to DHCPv6 server"
3038

    
3039
EOD;
3040
				}
3041
			}
3042
			break;
3043
		}
3044
	}
3045

    
3046
	$saved_tracker += 10;
3047
	$tracker = $saved_tracker;
3048

    
3049
	/*
3050
	 * NB: The loopback rules are needed here since the antispoof would take precedence then.
3051
	 *	If you ever add the 'quick' keyword to the antispoof rules above move the looback
3052
	 *	rules before them.
3053
	 */
3054
	$ipfrules .= <<<EOD
3055

    
3056
# loopback
3057
pass in {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
3058
pass out {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
3059
pass in {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
3060
pass out {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
3061
# let out anything from the firewall host itself and decrypted IPsec traffic
3062
pass out {$log['pass']} inet all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv4 from firewall host itself"
3063
pass out {$log['pass']} inet6 all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv6 from firewall host itself"
3064

    
3065
EOD;
3066

    
3067
	$saved_tracker += 100;
3068
	$tracker = $saved_tracker;
3069
	foreach ($FilterIflist as $ifdescr => $ifcfg) {
3070
		if(isset($ifcfg['virtual']))
3071
			continue;
3072

    
3073
		$gw = get_interface_gateway($ifdescr);
3074
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
3075
			$ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$ifcfg['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3076
			if (is_array($ifcfg['vips'])) {
3077
				foreach ($ifcfg['vips'] as $vip)
3078
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
3079
						$ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !{$ifcfg['sa']}/{$ifcfg['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3080
					else
3081
						$ipfrules .= "pass out {$log['pass']} route-to ( {$ifcfg['if']} {$gw} ) from {$vip['ip']} to !" . gen_subnet($vip['ip'], $vip['sn']) . "/{$vip['sn']} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3082
			}
3083
		}
3084

    
3085
		$gwv6 = get_interface_gateway_v6($ifdescr);
3086
		$stf = get_real_interface($ifdescr, "inet6");
3087
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
3088
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
3089
			$ipfrules .= "pass out {$log['pass']} route-to ( {$stf} {$gwv6} ) inet6 from {$ifcfg['ipv6']} to !{$ifcfg['ipv6']}/{$pdlen} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3090
			if (is_array($ifcfg['vips6'])) {
3091
				foreach ($ifcfg['vips6'] as $vip)
3092
					$ipfrules .= "pass out {$log['pass']} route-to ( {$stf} {$gwv6} ) inet6 from {$vip['ip']} to !{$vip['ip']}/{$pdlen} tracker {$increment_tracker($tracker)} keep state allow-opts label \"let out anything from firewall host itself\"\n";
3093
			}
3094
		}
3095
	}
3096

    
3097

    
3098
	$saved_tracker += 300;
3099
	$tracker = $saved_tracker;
3100
	/* add ipsec interfaces */
3101
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
3102
		$ipfrules .= "pass out {$log['pass']} on \$IPsec all tracker {$increment_tracker($tracker)} tracker {$increment_tracker($tracker)} keep state label \"IPsec internal host to host\"\n";
3103

    
3104
	$saved_tracker += 10;
3105
	$tracker = $saved_tracker;
3106
	if(is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
3107
		$alports = filter_get_antilockout_ports();
3108

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

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

    
3126
EOD;
3127
		}
3128
		unset($alports);
3129
	}
3130

    
3131
	$saved_tracker += 10;
3132
	$tracker = $saved_tracker;
3133
	/* PPTPd enabled? */
3134
	if($pptpdcfg['mode'] && ($pptpdcfg['mode'] != "off") && !isset($config['system']['disablevpnrules'])) {
3135
		if($pptpdcfg['mode'] == "server")
3136
			$pptpdtarget = get_interface_ip();
3137
		else
3138
			$pptpdtarget = $pptpdcfg['redir'];
3139
		if(is_ipaddr($pptpdtarget) and is_array($FilterIflist['wan'])) {
3140
			$ipfrules .= <<<EOD
3141
# PPTPd rules
3142
pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto tcp from any to $pptpdtarget port = 1723 tracker {$increment_tracker($tracker)} modulate state label "{$fix_rule_label("allow pptpd {$pptpdtarget}")}"
3143
pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto gre from any to any tracker {$increment_tracker($tracker)} keep state label "allow gre pptpd"
3144

    
3145
EOD;
3146

    
3147
		} else {
3148
			/*	  this shouldnt ever happen but instead of breaking the clients ruleset
3149
			 *	  log an error.
3150
			 */
3151
			log_error("ERROR!  PPTP enabled but could not resolve the \$pptpdtarget");
3152
		}
3153
	}
3154

    
3155
	$saved_tracker += 10;
3156
	$tracker = $saved_tracker;
3157
	if(isset($config['nat']['rule']) && is_array($config['nat']['rule'])) {
3158
		foreach ($config['nat']['rule'] as $rule) {
3159
			if((!isset($config['system']['disablenatreflection']) || $rule['natreflection'] == "enable")
3160
			   && $rule['natreflection'] != "disable") {
3161
				$ipfrules .= "# NAT Reflection rules\n";
3162
				$ipfrules .= <<<EOD
3163
pass in {$log['pass']} inet tagged PFREFLECT tracker {$increment_tracker($tracker)} keep state label "NAT REFLECT: Allow traffic to localhost"
3164

    
3165
EOD;
3166
				break;
3167
			}
3168
		}
3169
	}
3170

    
3171
	if (isset($config['filter']['rule'])) {
3172
		/* Pre-cache all our rules so we only have to generate them once */
3173
		$rule_arr1 = array();
3174
		$rule_arr2 = array();
3175
		$rule_arr3 = array();
3176
		$vpn_and_ppp_ifs = array("l2tp", "pptp", "pppoe", "enc0", "openvpn");
3177
		/*
3178
		 * NB: The order must be: Floating rules, then interface group and then regular ones.
3179
		 */
3180
		foreach ($config['filter']['rule'] as $rule) {
3181
			update_filter_reload_status("Pre-caching {$rule['descr']}...");
3182
			if (isset ($rule['disabled']))
3183
				continue;
3184

    
3185
			if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
3186
				if (isset($rule['floating'])) {
3187
					$rule['ipprotocol'] = "inet";
3188
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3189
					$rule['ipprotocol'] = "inet6";
3190
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3191
				} else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
3192
					$rule['ipprotocol'] = "inet";
3193
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3194
					$rule['ipprotocol'] = "inet6";
3195
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3196
				} else {
3197
					$rule['ipprotocol'] = "inet";
3198
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3199
					$rule['ipprotocol'] = "inet6";
3200
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3201
				}
3202
				$rule['ipprotocol'] = "inet46";
3203
			} else {
3204
				if (isset($rule['floating']))
3205
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3206
				else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs))
3207
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3208
				else
3209
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3210
			}
3211
			if ($rule['sched'])
3212
				$time_based_rules = true;
3213
		}
3214

    
3215
		$ipfrules .= "\n# User-defined rules follow\n";
3216
		$ipfrules .= "\nanchor \"userrules/*\"\n";
3217
		/* Generate user rule lines */
3218
		foreach($rule_arr1 as $rule) {
3219
			if (isset($rule['disabled']))
3220
				continue;
3221
			if (!$rule['rule'])
3222
				continue;
3223
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3224
		}
3225
		foreach($rule_arr2 as $rule) {
3226
			if (isset($rule['disabled']))
3227
				continue;
3228
			if (!$rule['rule'])
3229
				continue;
3230
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3231
		}
3232
		foreach($rule_arr3 as $rule) {
3233
			if (isset($rule['disabled']))
3234
				continue;
3235
			if (!$rule['rule'])
3236
				continue;
3237
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3238
		}
3239
		unset($rule_arr1, $rule_arr2, $rule_arr3);
3240
	}
3241

    
3242
	$saved_tracker += 100;
3243
	$tracker = $saved_tracker;
3244

    
3245
	/*  pass traffic between statically routed subnets and the subnet on the
3246
	 *  interface in question to avoid problems with complicated routing
3247
	 *  topologies
3248
	 */
3249
	if(isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
3250
		$ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
3251
		foreach (get_staticroutes() as $route) {
3252
			$friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
3253
			if(is_array($FilterIflist[$friendly])) {
3254
				$oc = $FilterIflist[$friendly];
3255
				$routeent = explode("/", $route['network']);
3256
				unset($sa);
3257
				if (is_ipaddrv4($oc['ip'])) {
3258
					$sa = $oc['sa'];
3259
					$sn = $oc['sn'];
3260
				}
3261
				if ($sa && is_ipaddrv4($routeent[0])) {
3262
					$ipfrules .= <<<EOD
3263
pass {$log['pass']} quick on \${$oc['descr']} proto tcp from {$sa}/{$sn} to {$route['network']} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3264
pass {$log['pass']} quick on \${$oc['descr']} from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3265
pass {$log['pass']} quick on \${$oc['descr']} proto tcp from {$route['network']} to {$sa}/{$sn} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3266
pass {$log['pass']} quick on \${$oc['descr']} from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3267

    
3268
EOD;
3269
				}
3270
				unset($sa);
3271
				if (is_ipaddrv6($oc['ipv6'])) {
3272
					$sa = $oc['sav6'];
3273
					$sn = $oc['snv6'];
3274
				}
3275
				if ($sa && is_ipaddrv6($routeent[0])) {
3276
					$ipfrules .= <<<EOD
3277
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto tcp from {$sa}/{$sn} to {$route['network']} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3278
pass {$log['pass']} quick on \${$oc['descr']} inet6 from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3279
pass {$log['pass']} quick on \${$oc['descr']} inet6 proto tcp from {$route['network']} to {$sa}/{$sn} flags any tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3280
pass {$log['pass']} quick on \${$oc['descr']} inet6 from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
3281

    
3282
EOD;
3283
				}
3284
			}
3285
		}
3286
	}
3287

    
3288
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3289
	$saved_tracker += 100000;
3290
	$tracker = $saved_tracker;
3291
	$ipfrules .= filter_generate_ipsec_rules($log);
3292

    
3293
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3294

    
3295
	$saved_tracker += 200;
3296
	$tracker = $saved_tracker;
3297
	update_filter_reload_status("Creating uPNP rules...");
3298
	if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
3299
		if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable']))
3300
			$ipfrules .= "anchor \"miniupnpd\"\n";
3301

    
3302
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3303
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3304
			foreach($upnp_interfaces as $upnp_if) {
3305
				if (is_array($FilterIflist[$upnp_if])) {
3306
					$oc = $FilterIflist[$upnp_if];
3307
					unset($sa);
3308
					if($oc['ip']) {
3309
						$sa = $oc['sa'];
3310
						$sn = $oc['sn'];
3311
					}
3312
					if($sa) {
3313
						$ipfrules .= <<<EOD
3314
pass in {$log['pass']} on \${$oc['descr']} proto tcp from {$sa}/{$sn} to 239.255.255.250/32 port 1900 tracker {$increment_tracker($tracker)} keep state label "pass multicast traffic to miniupnpd"
3315

    
3316
EOD;
3317
					}
3318
				}
3319
			}
3320
		}
3321
	}
3322

    
3323

    
3324
	return $ipfrules;
3325
}
3326

    
3327
function filter_rules_spoofcheck_generate($ifname, $ifcfg, $log) {
3328
	global $g, $config, $tracker;
3329
	if(isset($config['system']['developerspew'])) {
3330
		$mt = microtime();
3331
		echo "filter_rules_spoofcheck_generate() being called $mt\n";
3332
	}
3333
	$ipfrules = "antispoof {$log['block']} for \${$ifcfg['descr']} tracker {$tracker}\n";
3334
	$tracker++;
3335

    
3336
	return $ipfrules;
3337
}
3338

    
3339
/* COMPAT Function */
3340
function tdr_install_cron($should_install) {
3341
	log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
3342
	filter_tdr_install_cron($should_install);
3343
}
3344

    
3345
/****f* filter/filter_tdr_install_cron
3346
 * NAME
3347
 *   filter_tdr_install_cron
3348
 * INPUTS
3349
 *   $should_install true if the cron entry should be installed, false
3350
 *   if the entry should be removed if it is present
3351
 * RESULT
3352
 *   none
3353
 ******/
3354
function filter_tdr_install_cron($should_install) {
3355
	global $config, $g;
3356

    
3357
	if($g['booting']==true)
3358
		return;
3359

    
3360
	if (!is_array($config['cron']))
3361
		$config['cron'] = array();
3362
	if (!is_array($config['cron']['item']))
3363
		$config['cron']['item'] = array();
3364

    
3365
	$x=0;
3366
	$is_installed = false;
3367
	foreach($config['cron']['item'] as $item) {
3368
		if (strstr($item['command'], "filter_configure_sync")) {
3369
			$is_installed = true;
3370
			break;
3371
		}
3372
		$x++;
3373
	}
3374

    
3375
	switch($should_install) {
3376
		case true:
3377
			if (!$is_installed) {
3378
				$cron_item = array();
3379
				$cron_item['minute'] = "0,15,30,45";
3380
				$cron_item['hour'] = "*";
3381
				$cron_item['mday'] = "*";
3382
				$cron_item['month'] = "*";
3383
				$cron_item['wday'] = "*";
3384
				$cron_item['who'] = "root";
3385
				$cron_item['command'] = "/etc/rc.filter_configure_sync";
3386
				$config['cron']['item'][] = $cron_item;
3387
				write_config(gettext("Installed 15 minute filter reload for Time Based Rules"));
3388
				configure_cron();
3389
			}
3390
			break;
3391
		case false:
3392
			if ($is_installed == true) {
3393
				unset($config['cron']['item'][$x]);
3394
				write_config(gettext("Removed 15 minute filter reload for Time Based Rules"));
3395
				configure_cron();
3396
			}
3397
			break;
3398
	}
3399
}
3400

    
3401
/****f* filter/filter_get_time_based_rule_status
3402
 * NAME
3403
 *   filter_get_time_based_rule_status
3404
 * INPUTS
3405
 *   xml schedule block
3406
 * RESULT
3407
 *   true/false - true if the rule should be installed
3408
 ******/
3409
/*
3410
 <schedules>
3411
   <schedule>
3412
     <name>ScheduleMultipleTime</name>
3413
     <descr>main descr</descr>
3414
     <time>
3415
       <position>0,1,2</position>
3416
       <hour>0:0-24:0</hour>
3417
       <desc>time range 2</desc>
3418
     </time>
3419
     <time>
3420
       <position>4,5,6</position>
3421
       <hour>0:0-24:0</hour>
3422
       <desc>time range 1</desc>
3423
     </time>
3424
   </schedule>
3425
 </schedules>
3426
*/
3427
function filter_get_time_based_rule_status($schedule) {
3428

    
3429
	/* no schedule? rule should be installed */
3430
	if (empty($schedule))
3431
		return true;
3432
	/*
3433
	 * iterate through time blocks and determine
3434
	 * if the rule should be installed or not.
3435
	 */
3436
	foreach($schedule['timerange'] as $timeday) {
3437
		if (empty($timeday['month']))
3438
			$monthstatus = true;
3439
		else
3440
			$monthstatus = filter_tdr_month($timeday['month']);
3441
		if (empty($timeday['day']))
3442
			$daystatus = true;
3443
		else
3444
			$daystatus = filter_tdr_day($timeday['day']);
3445
		if (empty($timeday['hour']))
3446
			$hourstatus = true;
3447
		else
3448
			$hourstatus = filter_tdr_hour($timeday['hour']);
3449
		if (empty($timeday['position']))
3450
			$positionstatus = true;
3451
		else
3452
			$positionstatus = filter_tdr_position($timeday['position']);
3453

    
3454
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3455
			return true;
3456
	}
3457

    
3458
	return false;
3459
}
3460

    
3461
function filter_tdr_day($schedule) {
3462
	global $g;
3463

    
3464
	if($g['debug'])
3465
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3466

    
3467
	/*
3468
	 * Calculate day of month.
3469
	 * IE: 29th of may
3470
	 */
3471
	$date = date("d");
3472
	$defined_days = explode(",", $schedule);
3473
	foreach($defined_days as $dd) {
3474
		if ($date == $dd)
3475
			return true;
3476
	}
3477
	return false;
3478
}
3479
function filter_tdr_hour($schedule) {
3480
	global $g;
3481

    
3482
	/* $schedule should be a string such as 16:00-19:00 */
3483
	$tmp = explode("-", $schedule);
3484
	$starting_time = strtotime($tmp[0]);
3485
	$ending_time = strtotime($tmp[1]);
3486
	$now = strtotime("now");
3487
	if($g['debug'])
3488
		log_error("[TDR DEBUG] S: $starting_time E: $ending_time N: $now");
3489
	if($now >= $starting_time and $now < $ending_time)
3490
		return true;
3491
	return false;
3492
}
3493

    
3494
function filter_tdr_position($schedule) {
3495
	global $g;
3496

    
3497
	/*
3498
	 * Calculate position, ie: day of week.
3499
	 * Sunday = 7, Monday = 1, Tuesday = 2
3500
	 * Weds = 3, Thursday = 4, Friday = 5,
3501
	 * Saturday = 6
3502
	 * ...
3503
	 */
3504
	$weekday = date("w");
3505
	if($g['debug'])
3506
		log_error("[TDR DEBUG] filter_tdr_position($schedule) $weekday");
3507
	if($weekday == 0)
3508
		$weekday = 7;
3509
	$schedule_days = explode(",", $schedule);
3510
	foreach($schedule_days as $day) {
3511
		if($day == $weekday)
3512
			return true;
3513
	}
3514
	return false;
3515
}
3516

    
3517
function filter_tdr_month($schedule) {
3518
	global $g;
3519

    
3520
	/*
3521
	 * Calculate month
3522
	 */
3523
	$todays_month = date("n");
3524
	$months = explode(",", $schedule);
3525
	if($g['debug'])
3526
		log_error("[TDR DEBUG] filter_tdr_month($schedule)");
3527
	foreach($months as $month) {
3528
		if($month == $todays_month)
3529
			return true;
3530
	}
3531
	return false;
3532
}
3533

    
3534
function filter_setup_logging_interfaces() {
3535
	global $config, $FilterIflist;
3536

    
3537
	if(isset($config['system']['developerspew'])) {
3538
		$mt = microtime();
3539
		echo "filter_setup_logging_interfaces() being called $mt\n";
3540
	}
3541
	$rules = "";
3542
	if (isset($FilterIflist['lan']))
3543
		$rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
3544
	else if (isset($FilterIflist['wan']))
3545
		$rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
3546

    
3547
	return $rules;
3548
}
3549

    
3550
function filter_process_carp_rules($log) {
3551
	global $g, $config, $tracker;
3552

    
3553
	if(isset($config['system']['developerspew'])) {
3554
		$mt = microtime();
3555
		echo "filter_process_carp_rules() being called $mt\n";
3556
	}
3557

    
3558
	$increment_tracker = 'filter_rule_tracker';
3559
	$lines = "";
3560
	/* return if there are no carp configured items */
3561
	if (!empty($config['hasync']) or !empty($config['virtualip']['vip'])) {
3562
		$lines .= "block in {$log['block']} quick proto carp from (self) to any tracker {$increment_tracker($tracker)}\n";
3563
		$lines .= "pass {$log['pass']} quick proto carp tracker {$increment_tracker($tracker)}\n";
3564
	}
3565
	return $lines;
3566
}
3567

    
3568
/* Generate IPsec Filter Items */
3569
function filter_generate_ipsec_rules($log = array()) {
3570
	global $config, $g, $FilterIflist, $tracker;
3571

    
3572
	if(isset($config['system']['developerspew'])) {
3573
		$mt = microtime();
3574
		echo "filter_generate_ipsec_rules() being called $mt\n";
3575
	}
3576

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

    
3580
	$increment_tracker = 'filter_rule_tracker';
3581

    
3582
	$ipfrules = "\n# VPN Rules\n";
3583
	/* Is IP Compression enabled? */
3584
	if(isset($config['ipsec']['ipcomp']))
3585
		set_single_sysctl("net.inet.ipcomp.ipcomp_enable" , "1");
3586
	else
3587
		set_single_sysctl("net.inet.ipcomp.ipcomp_enable" , "0");
3588

    
3589
	if(isset($config['ipsec']['enable']) &&
3590
		is_array($config['ipsec']['phase1'])) {
3591
		/* step through all phase1 entries */
3592
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
3593
			$tracker += 10;
3594

    
3595
			if(isset ($ph1ent['disabled']))
3596
				continue;
3597
			/* determine local and remote peer addresses */
3598
			if(!isset($ph1ent['mobile'])) {
3599
				if (!function_exists('ipsec_get_phase1_dst'))
3600
					require_once("ipsec.inc");
3601
				$rgip = ipsec_get_phase1_dst($ph1ent);
3602
				if(!$rgip) {
3603
					$ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n";
3604
					continue;
3605
				}
3606
			} else
3607
				$rgip = " any ";
3608
			/* Determine best description */
3609
			if($ph1ent['descr'])
3610
				$descr = $ph1ent['descr'];
3611
			else
3612
				$descr = $rgip;
3613
			/*
3614
			 * Step through all phase2 entries and determine
3615
			 * which protocols are in use with this peer
3616
			 */
3617
			$prot_used_esp = false;
3618
			$prot_used_ah  = false;
3619
			if(is_array($config['ipsec']['phase2'])) {
3620
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
3621
					/* only evaluate ph2's bound to our ph1 */
3622
					if($ph2ent['ikeid'] != $ph1ent['ikeid'])
3623
						continue;
3624
					if($ph2ent['protocol'] == 'esp')
3625
						$prot_used_esp = true;
3626
					if($ph2ent['protocol'] == 'ah')
3627
						$prot_used_ah = true;
3628
				}
3629
			}
3630

    
3631
			if (strstr($ph1ent['interface'], "_vip"))
3632
				list($parentinterface, $vhid) = explode("_vhid", $ph1ent['interface']);
3633
			else
3634
				$parentinterface = $ph1ent['interface'];
3635
			if (empty($FilterIflist[$parentinterface]['descr'])) {
3636
				$ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
3637
				continue;
3638
			}
3639

    
3640
			unset($gateway);
3641
			/* add endpoint routes to correct gateway on interface */
3642
			if((is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
3643
				$gateway = get_interface_gateway($parentinterface);
3644
				$interface = $FilterIflist[$parentinterface]['if'];
3645

    
3646
				$route_to = " route-to ( $interface $gateway ) ";
3647
				$reply_to = " reply-to ( $interface $gateway ) ";
3648

    
3649
			}
3650
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3651
				$gateway = get_interface_gateway_v6($parentinterface);
3652
				$interface = $FilterIflist[$parentinterface]['if'];
3653

    
3654
				$route_to = " route-to ( $interface $gateway ) ";
3655
				$reply_to = " reply-to ( $interface $gateway ) ";
3656
			}
3657

    
3658
			/* Just in case */
3659
			if((!is_ipaddr($gateway) || empty($interface))) {
3660
				$route_to = " ";
3661
				$reply_to = " ";
3662
			}
3663

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

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

    
3677
EOD;
3678
			}
3679
			/* Add rules to allow the protocols in use */
3680
			if($prot_used_esp == true) {
3681
				$ipfrules .= <<<EOD
3682
pass out {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto esp from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound esp proto"
3683
pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto esp from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound esp proto"
3684

    
3685
EOD;
3686
			}
3687
			if($prot_used_ah == true) {
3688
				$ipfrules .= <<<EOD
3689
pass out {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto ah from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound ah proto"
3690
pass in {$log['pass']} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto ah from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound ah proto"
3691

    
3692
EOD;
3693
			}
3694
		}
3695

    
3696
	}
3697
	return($ipfrules);
3698
}
3699

    
3700
function discover_pkg_rules($ruletype) {
3701
	global $config, $g, $aliases;
3702

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

    
3707
	$rules = "";
3708
	$files = glob("/usr/local/pkg/*.inc");
3709
	foreach($files as $pkg_inc) {
3710
		update_filter_reload_status(sprintf(gettext('Checking for %1$s PF hooks in package %2$s'), $ruletype, $pkg_inc));
3711
		$pkg = basename($pkg_inc, ".inc");
3712
		$pkg_generate_rules = "{$pkg}_generate_rules";
3713
		if (!function_exists($pkg_generate_rules))
3714
			require_once($pkg_inc);
3715
		if(function_exists($pkg_generate_rules)) {
3716
			update_filter_reload_status(sprintf(gettext('Processing early %1$s rules for package %2$s'), $ruletype, $pkg_inc));
3717
			$tmprules = $pkg_generate_rules("$ruletype");
3718
			file_put_contents("{$g['tmp_path']}/rules.test.packages", $aliases . $tmprules);
3719
			$status = mwexec("/sbin/pfctl -nf {$g['tmp_path']}/rules.test.packages");
3720
			if ($status <> 0) {
3721
				$errorrules = sprintf(gettext("There was an error while parsing the package filter rules for %s."), $pkg_inc) . "\n";
3722
				log_error($errorrules);
3723
				file_put_contents("{$g['tmp_path']}/rules.packages.{$pkg}", "#{$errorrules}\n{$tmprules}\n");
3724
				continue;
3725
			}
3726
			$rules .= $tmprules;
3727
		}
3728
	}
3729
	return $rules;
3730
}
3731

    
3732
function filter_get_antilockout_ports($wantarray = false) {
3733
	global $config;
3734

    
3735
	$lockoutports = array();
3736
	$guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
3737
	$guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
3738
	$lockoutports[] = $guiport;
3739

    
3740
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3741
		$lockoutports[] = "80";
3742

    
3743
	if (isset($config['system']['enablesshd']))
3744
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3745

    
3746
	if ($wantarray)
3747
		return $lockoutports;
3748
	else
3749
		return implode(" ", $lockoutports);
3750

    
3751
}
3752

    
3753
?>
(19-19/68)