Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ 3c4fc30b

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 (!isset($FilterIflist[$if]['vips']) || !is_array($FilterIflist[$if]['vips']))
2095
		return;
2096

    
2097
	$if_subnets = array($subnets);
2098

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

    
2278
	$src .= filter_generate_port($rule, $target, $isnat);
2279

    
2280
	return $src;
2281
}
2282

    
2283
function filter_generate_user_rule($rule) {
2284
	global $config, $g, $FilterIflist, $GatewaysList;
2285
	global $layer7_rules_list, $dummynet_name_list;
2286

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

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

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

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

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

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

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

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

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

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

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

    
2548
		if ($noadvoptions == false && isset($rule['nopfsync']))
2549
			$rule['nopfsync'] = true;
2550

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

    
2592
					if(!empty($aline['divert']))
2593
						$aline['flags'] .= "max-packets 8 ";
2594

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

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

    
2632
				$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
2633
				break;
2634
			}
2635
		}
2636
	}
2637

    
2638
	if (!empty($rule['tracker']))
2639
		$aline['tracker'] = "tracker {$rule['tracker']} ";
2640

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

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

    
2661
	unset($aline);
2662

    
2663
	return $line;
2664
}
2665

    
2666
function filter_rules_generate() {
2667
	global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
2668

    
2669
	$fix_rule_label = 'fix_rule_label';
2670
	$increment_tracker = 'filter_rule_tracker';
2671

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

    
2678
	$pptpdcfg = $config['pptpd'];
2679

    
2680
	$ipfrules = "";
2681
	$ipfrules .= discover_pkg_rules("pfearly");
2682

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

    
2697
	$saved_tracker = $tracker;
2698

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

    
2705
	$saved_tracker += 100;
2706
	$tracker = $saved_tracker;
2707

    
2708
	$ipfrules .= <<<EOD
2709
#---------------------------------------------------------------------------
2710
# default deny rules
2711
#---------------------------------------------------------------------------
2712
block in {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2713
block out {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2714
block in {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2715
block out {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2716

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

    
2729
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
2730
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
2731
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
2732
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
2733
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
2734
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
2735

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

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

    
2746
EOD;
2747

    
2748
	$saved_tracker += 100;
2749
	$tracker = $saved_tracker;
2750

    
2751
	$ipfrules .= filter_process_carp_rules($log);
2752

    
2753
	$saved_tracker += 100;
2754
	$tracker = $saved_tracker;
2755

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

    
2770
	$saved_tracker += 50;
2771
	$tracker = $saved_tracker;
2772

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

    
2785
	$saved_tracker += 100;
2786
	$tracker = $saved_tracker;
2787

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

    
2794
	$saved_tracker += 100;
2795
	$tracker = $saved_tracker;
2796

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

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

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

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

    
2862
EOD;
2863

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

    
2870
EOD;
2871
			}
2872
		}
2873

    
2874

    
2875
		$saved_tracker += 10;
2876
		$tracker = $saved_tracker;
2877

    
2878
		if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
2879
			$ipfrules .= <<<EOD
2880
# allow our DHCPv6 client out to the {$oc['descr']}
2881
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']}")}"
2882
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']}")}"
2883
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']}")}"
2884

    
2885
EOD;
2886
		}
2887

    
2888
		$saved_tracker += 10;
2889
		$tracker = $saved_tracker;
2890

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

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

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

    
2910
		$saved_tracker += 10;
2911
		$tracker = $saved_tracker;
2912

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

    
2924
EOD;
2925
			}
2926
		}
2927

    
2928
		$saved_tracker += 10;
2929
		$tracker = $saved_tracker;
2930

    
2931
		switch ($oc['type']) {
2932
		case "pptp":
2933
				$ipfrules .= <<<EOD
2934
# allow PPTP client
2935
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']}")}"
2936
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']}")}"
2937

    
2938
EOD;
2939
			break;
2940
		case "dhcp":
2941
			$ipfrules .= <<<EOD
2942
# allow our DHCP client out to the {$oc['descr']}
2943
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']}")}"
2944
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']}")}"
2945
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2946

    
2947
EOD;
2948

    
2949
			break;
2950
		case "pppoe":
2951
		case "none":
2952
			/* XXX: Nothing to do in this case?! */
2953
			break;
2954
		default:
2955
			/* allow access to DHCP server on interfaces */
2956
			if(isset($config['dhcpd'][$on]['enable'])) {
2957
				$ipfrules .= <<<EOD
2958
# allow access to DHCP server on {$oc['descr']}
2959
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"
2960

    
2961
EOD;
2962
				if (is_ipaddrv4($oc['ip'])) {
2963
					$ipfrules .= <<<EOD
2964
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"
2965
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"
2966

    
2967
EOD;
2968
				}
2969

    
2970
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2971
					$ipfrules .= <<<EOD
2972
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2973
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"
2974
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"
2975

    
2976
EOD;
2977
				}
2978

    
2979
			}
2980
			break;
2981
		}
2982

    
2983
		$saved_tracker += 10;
2984
		$tracker = $saved_tracker;
2985
		switch($oc['type6']) {
2986
		case "6rd":
2987
			$ipfrules .= <<<EOD
2988
# allow our proto 41 traffic from the 6RD border relay in
2989
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']}")}"
2990
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']}")}"
2991

    
2992
EOD;
2993
		/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
2994
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2995
			$ipfrules .= <<<EOD
2996
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']}")}"
2997
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']}")}"
2998

    
2999
EOD;
3000
		}
3001
			break;
3002
		case "6to4":
3003
			if (is_ipaddrv4($oc['ip'])) {
3004
			$ipfrules .= <<<EOD
3005
# allow our proto 41 traffic from the 6to4 border relay in
3006
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']}")}"
3007
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']}")}"
3008

    
3009
EOD;
3010
		}
3011
		/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
3012
		if (0 && is_ipaddrv6($oc['ipv6'])) {
3013
			$ipfrules .= <<<EOD
3014
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']}")}"
3015
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']}")}"
3016

    
3017
EOD;
3018
		}
3019
			break;
3020
		default:
3021
			if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface']) 
3022
				|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
3023
				$ipfrules .= <<<EOD
3024
# allow access to DHCPv6 server on {$oc['descr']}
3025
# We need inet6 icmp for stateless autoconfig and dhcpv6
3026
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"
3027
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"
3028
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"
3029
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"
3030

    
3031
EOD;
3032
				if (is_ipaddrv6($oc['ipv6'])) {
3033
					$ipfrules .= <<<EOD
3034
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"
3035
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"
3036

    
3037
EOD;
3038
				}
3039
			}
3040
			break;
3041
		}
3042
	}
3043

    
3044
	$saved_tracker += 10;
3045
	$tracker = $saved_tracker;
3046

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

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

    
3063
EOD;
3064

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

    
3071
		$gw = get_interface_gateway($ifdescr);
3072
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
3073
			$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";
3074
			if (is_array($ifcfg['vips'])) {
3075
				foreach ($ifcfg['vips'] as $vip)
3076
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
3077
						$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";
3078
					else
3079
						$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";
3080
			}
3081
		}
3082

    
3083
		$gwv6 = get_interface_gateway_v6($ifdescr);
3084
		$stf = get_real_interface($ifdescr, "inet6");
3085
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
3086
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
3087
			$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";
3088
			if (is_array($ifcfg['vips6'])) {
3089
				foreach ($ifcfg['vips6'] as $vip)
3090
					$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";
3091
			}
3092
		}
3093
	}
3094

    
3095

    
3096
	$saved_tracker += 300;
3097
	$tracker = $saved_tracker;
3098
	/* add ipsec interfaces */
3099
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
3100
		$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";
3101

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

    
3107
		if(count($config['interfaces']) > 1 && !empty($FilterIflist['lan']['if'])) {
3108
				/* if antilockout is enabled, LAN exists and has
3109
				 * an IP and subnet mask assigned
3110
				 */
3111
				$lanif = $FilterIflist['lan']['if'];
3112
				$ipfrules .= <<<EOD
3113
# make sure the user cannot lock himself out of the webConfigurator or SSH
3114
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"
3115

    
3116
EOD;
3117
		} else if (count($config['interfaces']) == 1) {
3118
			/* single-interface deployment, add to WAN	*/
3119
			$wanif = $FilterIflist["wan"]['if'];
3120
			$ipfrules .= <<<EOD
3121
# make sure the user cannot lock himself out of the webConfigurator or SSH
3122
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"
3123

    
3124
EOD;
3125
		}
3126
		unset($alports);
3127
	}
3128

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

    
3143
EOD;
3144

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

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

    
3163
EOD;
3164
				break;
3165
			}
3166
		}
3167
	}
3168

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

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

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

    
3240
	$saved_tracker += 100;
3241
	$tracker = $saved_tracker;
3242

    
3243
	/*  pass traffic between statically routed subnets and the subnet on the
3244
	 *  interface in question to avoid problems with complicated routing
3245
	 *  topologies
3246
	 */
3247
	if(isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
3248
		$ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
3249
		foreach (get_staticroutes() as $route) {
3250
			$friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
3251
			if(is_array($FilterIflist[$friendly])) {
3252
				$oc = $FilterIflist[$friendly];
3253
				$routeent = explode("/", $route['network']);
3254
				unset($sa);
3255
				if (is_ipaddrv4($oc['ip'])) {
3256
					$sa = $oc['sa'];
3257
					$sn = $oc['sn'];
3258
				}
3259
				if ($sa && is_ipaddrv4($routeent[0])) {
3260
					$ipfrules .= <<<EOD
3261
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"
3262
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"
3263
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"
3264
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"
3265

    
3266
EOD;
3267
				}
3268
				unset($sa);
3269
				if (is_ipaddrv6($oc['ipv6'])) {
3270
					$sa = $oc['sav6'];
3271
					$sn = $oc['snv6'];
3272
				}
3273
				if ($sa && is_ipaddrv6($routeent[0])) {
3274
					$ipfrules .= <<<EOD
3275
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"
3276
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"
3277
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"
3278
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"
3279

    
3280
EOD;
3281
				}
3282
			}
3283
		}
3284
	}
3285

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

    
3291
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3292

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

    
3300
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3301
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3302
			foreach($upnp_interfaces as $upnp_if) {
3303
				if (is_array($FilterIflist[$upnp_if])) {
3304
					$oc = $FilterIflist[$upnp_if];
3305
					unset($sa);
3306
					if($oc['ip']) {
3307
						$sa = $oc['sa'];
3308
						$sn = $oc['sn'];
3309
					}
3310
					if($sa) {
3311
						$ipfrules .= <<<EOD
3312
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"
3313

    
3314
EOD;
3315
					}
3316
				}
3317
			}
3318
		}
3319
	}
3320

    
3321

    
3322
	return $ipfrules;
3323
}
3324

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

    
3334
	return $ipfrules;
3335
}
3336

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

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

    
3355
	if($g['booting']==true)
3356
		return;
3357

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

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

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

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

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

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

    
3456
	return false;
3457
}
3458

    
3459
function filter_tdr_day($schedule) {
3460
	global $g;
3461

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

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

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

    
3492
function filter_tdr_position($schedule) {
3493
	global $g;
3494

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

    
3515
function filter_tdr_month($schedule) {
3516
	global $g;
3517

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

    
3532
function filter_setup_logging_interfaces() {
3533
	global $config, $FilterIflist;
3534

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

    
3545
	return $rules;
3546
}
3547

    
3548
function filter_process_carp_rules($log) {
3549
	global $g, $config, $tracker;
3550

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

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

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

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

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

    
3578
	$increment_tracker = 'filter_rule_tracker';
3579

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

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

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

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

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

    
3644
				$route_to = " route-to ( $interface $gateway ) ";
3645
				$reply_to = " reply-to ( $interface $gateway ) ";
3646

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

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

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

    
3662
			/* Add rules to allow IKE to pass */
3663
			$shorttunneldescr = substr($descr, 0, 35);
3664
				$ipfrules .= <<<EOD
3665
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"
3666
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"
3667

    
3668
EOD;
3669
			/* If NAT-T is enabled, add additional rules */
3670
			if($ph1ent['nat_traversal'] != "off" ) {
3671
				$ipfrules .= <<<EOD
3672
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"
3673
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"
3674

    
3675
EOD;
3676
			}
3677
			/* Add rules to allow the protocols in use */
3678
			if($prot_used_esp == true) {
3679
				$ipfrules .= <<<EOD
3680
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"
3681
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"
3682

    
3683
EOD;
3684
			}
3685
			if($prot_used_ah == true) {
3686
				$ipfrules .= <<<EOD
3687
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"
3688
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"
3689

    
3690
EOD;
3691
			}
3692
		}
3693

    
3694
	}
3695
	return($ipfrules);
3696
}
3697

    
3698
function discover_pkg_rules($ruletype) {
3699
	global $config, $g, $aliases;
3700

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

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

    
3730
function filter_get_antilockout_ports($wantarray = false) {
3731
	global $config;
3732

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

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

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

    
3744
	if ($wantarray)
3745
		return $lockoutports;
3746
	else
3747
		return implode(" ", $lockoutports);
3748

    
3749
}
3750

    
3751
?>
(19-19/68)