Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ 687d11a6

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_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
		}
1370
	}
1371

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

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

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

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

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

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

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

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

    
1436
		return $combined;
1437
	} else
1438
		return $tonathosts;
1439
}
1440

    
1441
function filter_nat_rules_outbound_automatic($src) {
1442
	global $config, $FilterIflist;
1443

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

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

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

    
1474
	return $rules;
1475
}
1476

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

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

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

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

    
1569
	$reflection_txt = "";
1570
	$route_table = "";
1571

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

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

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

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

    
1598
			$srcaddr = trim($srcaddr);
1599
			$dstaddr = trim($dstaddr);
1600

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

    
1608
			$natif = $FilterIflist[$natif]['if'];
1609

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

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

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

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

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

    
1645
			$srcaddr = filter_generate_address($rule, 'source');
1646
			$dstaddr = filter_generate_address($rule, 'destination');
1647

    
1648
			$srcaddr = trim($srcaddr);
1649
			$dstaddr = trim($dstaddr);
1650

    
1651
			$natif = $FilterIflist[$natif]['descr'];
1652

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

    
1656
		}
1657
	}
1658

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1821
			if(isset($rule['disabled']))
1822
				continue;
1823

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

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

    
1847
					$localport .= ":$localendport";
1848
				}
1849

    
1850
				$localport = " port {$localport}";
1851
			}
1852

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

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

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

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

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

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

    
1899
			if (!isset($FilterIflist[$natif]))
1900
				continue;
1901

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

    
1907
			if(!$dstaddr)
1908
				$dstaddr = $FilterIflist[$natif]['ip'];
1909

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

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

    
1925
			$natif = $FilterIflist[$natif]['if'];
1926

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

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

    
1946
			if(empty($nat_if_list))
1947
				$reflection_type = "none";
1948

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

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

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

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

    
1984
				if(empty($nat_if_list))
1985
					$nat_if_list = array($natif);
1986

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

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

    
2004
	$natrules .= discover_pkg_rules("nat");
2005

    
2006
	$natrules .= "# UPnPd rdr anchor\n";
2007
	$natrules .= "rdr-anchor \"miniupnpd\"\n";
2008

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

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

    
2021
	return $natrules;
2022
}
2023

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

    
2036
	return $ret;
2037
}
2038

    
2039
function filter_generate_port(& $rule, $target = "source", $isnat = false) {
2040

    
2041
	$src = "";
2042

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

    
2070
	return $src;
2071
}
2072

    
2073
function filter_address_add_vips_subnets(&$subnets, $if, $not) {
2074
	global $FilterIflist;
2075

    
2076
	if (!isset($FilterIflist[$if]['vips']) || !is_array($FilterIflist[$if]['vips']))
2077
		return;
2078

    
2079
	$if_subnets = array($subnets);
2080

    
2081
	if ($not == true)
2082
		$subnets = "!{$subnets}";
2083

    
2084
	foreach ($FilterIflist[$if]['vips'] as $vip) {
2085
		foreach ($if_subnets as $subnet)
2086
			if (ip_in_subnet($vip['ip'], $subnet))
2087
				continue 2;
2088

    
2089
		if (is_ipaddrv4($vip['ip'])) {
2090
			if (!is_subnetv4($if_subnets[0]))
2091
				continue;
2092

    
2093
			$network = gen_subnet($vip['ip'], $vip['sn']);
2094
		} else if (is_ipaddrv6($vip['ip'])) {
2095
			if (!is_subnetv6($if_subnets[0]))
2096
				continue;
2097

    
2098
			$network = gen_subnetv6($vip['ip'], $vip['sn']);
2099
		} else
2100
			continue;
2101

    
2102
		$subnets .= ' ' . ($not == true ? '!' : '') . $network . '/' . $vip['sn'];
2103
		$if_subnets[] = $network . '/' . $vip['sn'];
2104
	}
2105
	unset($if_subnets);
2106

    
2107
	if (strpos($subnets, ' ') !== false)
2108
		$subnets = "{ {$subnets} }";
2109
}
2110

    
2111
function filter_generate_address(& $rule, $target = "source", $isnat = false) {
2112
	global $FilterIflist, $config;
2113
	$src = "";
2114

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

    
2260
	$src .= filter_generate_port($rule, $target, $isnat);
2261

    
2262
	return $src;
2263
}
2264

    
2265
function filter_generate_user_rule($rule) {
2266
	global $config, $g, $FilterIflist, $GatewaysList;
2267
	global $layer7_rules_list, $dummynet_name_list;
2268

    
2269
	if(isset($config['system']['developerspew'])) {
2270
		$mt = microtime();
2271
		echo "filter_generate_user_rule() being called $mt\n";
2272
	}
2273
	/* don't include disabled rules */
2274
	if(isset($rule['disabled'])) {
2275
		return "# rule " . $rule['descr'] . " disabled \n";
2276
	}
2277
	update_filter_reload_status("Creating filter rules {$rule['descr']} ...");
2278
	$pptpdcfg = $config['pptpd'];
2279
	$int = "";
2280
	$aline = array();
2281

    
2282
	/* Check to see if the interface is in our list */
2283
	if(isset($rule['floating'])) {
2284
		if(isset($rule['interface']) && $rule['interface'] <> "") {
2285
			$interfaces = explode(",", $rule['interface']);
2286
			$ifliste = "";
2287
			foreach ($interfaces as $iface) {
2288
				if(array_key_exists($iface, $FilterIflist))
2289
					$ifliste .= " " . $FilterIflist[$iface]['if'] . " ";
2290
			}
2291
			if($ifliste <> "")
2292
				$aline['interface'] = " on { {$ifliste} } ";
2293
			else
2294
				$aline['interface'] = "";
2295
		} else
2296
			$aline['interface'] = "";
2297
	} else if(!array_key_exists($rule['interface'], $FilterIflist)) {
2298
			foreach($FilterIflist as $oc)
2299
				$items .= $oc['descr'] . " ";
2300
			return "# array key \"{$rule['interface']}\" does not exist for \"" . $rule['descr'] . "\" in array: {{$items}}";
2301
	} else if((array_key_exists($rule['interface'], $FilterIflist))
2302
		&& (is_array($FilterIflist[$rule['interface']]))
2303
		&& (is_array($FilterIflist[$rule['interface']][0]))) {
2304
		/* Currently this only case for this is the pppoe server. There should be an existing macro with this name. */
2305
		$aline['interface'] = " on \$" . $rule['interface'] . " ";
2306
	} else
2307
		$aline['interface'] = " on \$" . $FilterIflist[$rule['interface']]['descr'] . " ";
2308
	$ifcfg = $FilterIflist[$rule['interface']];
2309
	if($pptpdcfg['mode'] != "server") {
2310
		if(($rule['source']['network'] == "pptp") ||
2311
			($rule['destination']['network'] == "pptp"))
2312
				return "# source network or destination network == pptp on " . $rule['descr'];
2313
	}
2314

    
2315
	switch($rule['ipprotocol']) {
2316
	case "inet":
2317
		$aline['ipprotocol'] = "inet";
2318
		break;
2319
	case "inet6":
2320
		$aline['ipprotocol'] = "inet6";
2321
		break;
2322
	default:
2323
		$aline['ipprotocol'] = "";
2324
		break;
2325
	}
2326

    
2327
	/* check for unresolvable aliases */
2328
	if($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
2329
		$error_text = "Unresolvable source alias '{$rule['source']['address']}' for rule '{$rule['descr']}'";
2330
		file_notice("Filter_Reload", $error_text);
2331
		return "# {$error_text}";
2332
	}
2333
	if($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
2334
		$error_text = "Unresolvable destination alias '{$rule['destination']['address']}' for rule '{$rule['descr']}'";
2335
		file_notice("Filter_Reload", $error_text);
2336
		return "# {$error_text}";
2337
	}
2338
	update_filter_reload_status("Setting up pass/block rules");
2339
	$type = $rule['type'];
2340
	if($type != "pass" && $type != "block" && $type != "reject" && $type != "match") {
2341
		/* default (for older rules) is pass */
2342
		$type = "pass";
2343
	}
2344
	if($type == "reject") {
2345
		$aline['type'] = "block return ";
2346
	} else
2347
		$aline['type'] = $type . " ";
2348
	if(isset($rule['floating']) && $rule['floating'] == "yes") {
2349
		if($rule['direction'] != "any")
2350
			$aline['direction'] = " " . $rule['direction'] . " ";
2351
	} else {
2352
		/* ensure the direction is in */
2353
		$aline['direction'] = " in ";
2354
	}
2355
	if(isset($rule['log']))
2356
		$aline['log'] = "log ";
2357
	if(!isset($rule['floating']) || isset($rule['quick']))
2358
		$aline['quick'] = " quick ";
2359

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

    
2363
	/* do not process reply-to for gateway'd rules */
2364
	if($rule['gateway'] == "" && $aline['direction'] <> "" && (interface_has_gateway($rule['interface']) || interface_has_gatewayv6($rule['interface'])) && !isset($config['system']['disablereplyto']) && !isset($rule['disablereplyto']) && $type != "match") {
2365
		if ($rule['ipprotocol'] == "inet6") {
2366
			$rg = get_interface_gateway_v6($rule['interface']);
2367
			if (is_ipaddrv6($rg))
2368
				$aline['reply'] = "reply-to ( {$ifcfg['ifv6']} {$rg} ) ";
2369
			else if ($rule['interface'] <> "pptp")
2370
				log_error("Could not find IPv6 gateway for interface({$rule['interface']}).");
2371
		} else {
2372
			$rg = get_interface_gateway($rule['interface']);
2373
			if (is_ipaddrv4($rg))
2374
				$aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) ";
2375
			else if ($rule['interface'] <> "pptp")
2376
				log_error(sprintf(gettext("Could not find IPv4 gateway for interface (%s)."), $rule['interface']));
2377
		}
2378
	}
2379
	/* if user has selected a custom gateway, lets work with it */
2380
	else if($rule['gateway'] <> "" && $type == "pass") {
2381
		if (isset($GatewaysList[$rule['gateway']]))
2382
			/* Add the load balanced gateways */
2383
			$aline['route'] = " \$GW{$rule['gateway']} ";
2384
		else if (isset($config['system']['skip_rules_gw_down']))
2385
			return "# rule " . $rule['descr'] . " disabled because gateway " . $rule['gateway'] . " is down ";
2386
		else
2387
			log_error("The gateway: {$rule['gateway']} is invalid or unknown, not using it.");
2388
	}
2389

    
2390
	if (isset($rule['protocol']) && !empty($rule['protocol'])) {
2391
		if($rule['protocol'] == "tcp/udp")
2392
			$aline['prot'] = " proto { tcp udp } ";
2393
		elseif(($rule['protocol'] == "icmp") && ($rule['ipprotocol'] == "inet6"))
2394
			$aline['prot'] = " proto ipv6-icmp ";
2395
		elseif($rule['protocol'] == "icmp")
2396
			$aline['prot'] = " proto icmp ";
2397
		else
2398
			$aline['prot'] = " proto {$rule['protocol']} ";
2399
	} else {
2400
		if($rule['source']['port'] <> "" || $rule['destination']['port'] <> "")
2401
			$aline['prot'] = " proto tcp ";
2402
	}
2403
	update_filter_reload_status(sprintf(gettext("Creating rule %s"), $rule['descr']));
2404

    
2405
	/* source address */
2406
	$src = trim(filter_generate_address($rule, "source"));
2407
	if (empty($src) || ($src == "/")) {
2408
		return "# at the break!";
2409
	}
2410
	$aline['src'] = " from $src ";
2411

    
2412
	/* OS signatures */
2413
	if(($rule['protocol'] == "tcp") && ($rule['os'] <> ""))
2414
		$aline['os'] = " os \"{$rule['os']}\" ";
2415

    
2416
	/* destination address */
2417
	$dst = trim(filter_generate_address($rule, "destination"));
2418
	if (empty($dst) || ($dst == "/")) {
2419
		return "# returning at dst $dst == \"/\"";
2420
	}
2421
	$aline['dst'] = "to $dst ";
2422

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

    
2530
		if ($noadvoptions == false && isset($rule['nopfsync']))
2531
			$rule['nopfsync'] = true;
2532

    
2533
		if ($noadvoptions == false || $l7_present)
2534
			if ((isset($rule['source-track']) and $rule['source-track'] <> "") or
2535
			    (isset($rule['max']) and $rule['max'] <> "") or
2536
			    (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") or
2537
			    (isset($rule['max-src-states']) and $rule['max-src-states'] <> "") or
2538
			    ((in_array($rule['protocol'], array("tcp","tcp/udp"))) and
2539
			     ((isset($rule['statetimeout']) and $rule['statetimeout'] <> "") or
2540
			      (isset($rule['max-src-conn']) and $rule['max-src-conn'] <> "") or
2541
			      (isset($rule['max-src-conn-rate']) and $rule['max-src-conn-rate'] <> "") or
2542
			      (isset($rule['max-src-conn-rates']) and $rule['max-src-conn-rates'] <> ""))) or
2543
			    isset($rule['sloppy']) or isset($rule['nopfsync']) or $l7_present) {
2544
					$aline['flags'] .= "( ";
2545
					if (isset($rule['sloppy']))
2546
						$aline['flags'] .= "sloppy ";
2547
					if (isset($rule['nopfsync']))
2548
						$aline['flags'] .= "no-sync ";
2549
					if (isset($rule['source-track']) and $rule['source-track'] <> "")
2550
						$aline['flags'] .= "source-track rule ";
2551
					if (isset($rule['max']) and $rule['max'] <> "")
2552
						$aline['flags'] .= "max " . $rule['max'] . " ";
2553
					if (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "")
2554
						$aline['flags'] .= "max-src-nodes " . $rule['max-src-nodes'] . " ";
2555
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2556
							and isset($rule['max-src-conn']) 
2557
							and $rule['max-src-conn'] <> "")
2558
						$aline['flags'] .= "max-src-conn " . $rule['max-src-conn'] . " ";
2559
					if (isset($rule['max-src-states']) and $rule['max-src-states'] <> "")
2560
						$aline['flags'] .= "max-src-states " . $rule['max-src-states'] . " ";
2561
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2562
							and isset($rule['statetimeout']) 
2563
							and $rule['statetimeout'] <> "")
2564
						$aline['flags'] .= "tcp.established " . $rule['statetimeout'] . " ";
2565
					if ((in_array($rule['protocol'], array("tcp","tcp/udp"))) 
2566
							and isset($rule['max-src-conn-rate'])
2567
							and $rule['max-src-conn-rate'] <> ""
2568
							and isset($rule['max-src-conn-rates'])
2569
							and $rule['max-src-conn-rates'] <> "") {
2570
						$aline['flags'] .= "max-src-conn-rate " . $rule['max-src-conn-rate'] . " ";
2571
						$aline['flags'] .= "/" . $rule['max-src-conn-rates'] . ", overload <virusprot> flush global ";
2572
					}
2573

    
2574
					if(!empty($aline['divert']))
2575
						$aline['flags'] .= "max-packets 8 ";
2576

    
2577
					$aline['flags'] .= " ) ";
2578
				}
2579
	}
2580
	if($rule['defaultqueue'] <> "") {
2581
		$aline['queue'] = " queue (".$rule['defaultqueue'];
2582
		if($rule['ackqueue'] <> "")
2583
			$aline['queue'] .= ",".$rule['ackqueue'];
2584
		$aline['queue'] .= ") ";
2585
	}
2586
	if($rule['dnpipe'] <> "") {
2587
		if (!empty($dummynet_name_list[$rule['dnpipe']])) {
2588
			if($dummynet_name_list[$rule['dnpipe']][0] == "?") {
2589
				$aline['dnpipe'] = " dnqueue( ";
2590
				$aline['dnpipe'] .= substr($dummynet_name_list[$rule['dnpipe']],1);
2591
				if($rule['pdnpipe'] <> "")
2592
					$aline['dnpipe'] .= ",".substr($dummynet_name_list[$rule['pdnpipe']], 1);
2593
			} else {
2594
				$aline['dnpipe'] = " dnpipe ( " . $dummynet_name_list[$rule['dnpipe']];
2595
				if($rule['pdnpipe'] <> "")
2596
					$aline['dnpipe'] .= "," . $dummynet_name_list[$rule['pdnpipe']];
2597
			}
2598
			$aline['dnpipe'] .= ") ";
2599
		}
2600
	}
2601

    
2602
	/* is a time based rule schedule attached? */
2603
	if(!empty($rule['sched']) && !empty($config['schedules'])) {
2604
		$aline['schedlabel'] = "";
2605
		foreach ($config['schedules']['schedule'] as $sched) {
2606
			if($sched['name'] == $rule['sched']) {
2607
				if(!filter_get_time_based_rule_status($sched)) {
2608
					if(!isset($config['system']['schedule_states']))
2609
						mwexec("/sbin/pfctl -y {$sched['schedlabel']}");
2610
					return "# schedule finished - {$rule['descr']}";
2611
				} else if($g['debug'])
2612
					log_error("[TDR DEBUG] status true -- rule type '$type'");
2613

    
2614
				$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
2615
				break;
2616
			}
2617
		}
2618
	}
2619

    
2620
	if (!empty($rule['tracker']))
2621
		$aline['tracker'] = "tracker {$rule['tracker']} ";
2622

    
2623
	$line = "";
2624
	/* exception(s) to a user rules can go here. */
2625
	/* rules with a gateway or pool should create another rule for routing to vpns */
2626
	if((($aline['route'] <> "") && (trim($aline['type']) == "pass") && strstr($dst, "any")) && (!isset($config['system']['disablenegate']))) {
2627
		/* negate VPN/PPTP/PPPoE/Static Route networks for load balancer/gateway rules */
2628
		$negate_networks = " to <negate_networks> " . filter_generate_port($rule, "destination");
2629
		$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] .
2630
			$aline['interface'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] .
2631
			$negate_networks . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] .
2632
			$aline['vlanprio'] . $aline['vlanprioset'] . $aline['dscp'] . $aline['tracker'] . $aline['allowopts'] . $aline['flags'] .
2633
			$aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'] .
2634
			" label \"NEGATE_ROUTE: Negate policy routing for destination\"\n";
2635

    
2636
	}
2637
	/* piece together the actual user rule */
2638
	$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
2639
		$aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
2640
		$aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] . $aline['tracker'] .
2641
		$aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
2642

    
2643
	unset($aline);
2644

    
2645
	return $line;
2646
}
2647

    
2648
function filter_rules_generate() {
2649
	global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
2650

    
2651
	$fix_rule_label = 'fix_rule_label';
2652
	$increment_tracker = 'filter_rule_tracker';
2653

    
2654
	update_filter_reload_status(gettext("Creating default rules"));
2655
	if(isset($config['system']['developerspew'])) {
2656
		$mt = microtime();
2657
		echo "filter_rules_generate() being called $mt\n";
2658
	}
2659

    
2660
	$pptpdcfg = $config['pptpd'];
2661

    
2662
	$ipfrules = "";
2663
	$ipfrules .= discover_pkg_rules("pfearly");
2664

    
2665
	/* relayd */
2666
	$ipfrules .= "anchor \"relayd/*\"\n";
2667
	/* OpenVPN user rules from radius */
2668
	$ipfrules .= "anchor \"openvpn/*\"\n";
2669
	/* IPSec user rules from radius */
2670
	$ipfrules .= "anchor \"ipsec/*\"\n";
2671
	# BEGIN OF firewall rules
2672
	/* default block logging? */
2673
	$log = array(); 
2674
	if(!isset($config['syslog']['nologdefaultblock']))
2675
		$log['block'] = "log";
2676
	if(isset($config['syslog']['nologdefaultpass']))
2677
		$log['pass'] = "log";
2678

    
2679
	$saved_tracker = $tracker;
2680

    
2681
	if(!isset($config['system']['ipv6allow'])) {
2682
		$ipfrules .= "# Block all IPv6\n";
2683
		$ipfrules .= "block in {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2684
		$ipfrules .= "block out {$log['block']} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
2685
	}
2686

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

    
2690
	$ipfrules .= <<<EOD
2691
#---------------------------------------------------------------------------
2692
# default deny rules
2693
#---------------------------------------------------------------------------
2694
block in {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2695
block out {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2696
block in {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2697
block out {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2698

    
2699
# IPv6 ICMP is not auxilary, it is required for operation
2700
# See man icmp6(4)
2701
# 1    unreach         Destination unreachable
2702
# 2    toobig          Packet too big
2703
# 128  echoreq         Echo service request
2704
# 129  echorep         Echo service reply
2705
# 133  routersol       Router solicitation
2706
# 134  routeradv       Router advertisement
2707
# 135  neighbrsol      Neighbor solicitation
2708
# 136  neighbradv      Neighbor advertisement
2709
pass {$log['pass']} quick inet6 proto ipv6-icmp from any to any icmp6-type {1,2,135,136} tracker {$increment_tracker($tracker)} keep state
2710

    
2711
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
2712
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
2713
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
2714
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
2715
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
2716
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
2717

    
2718
# We use the mighty pf, we cannot be fooled.
2719
block {$log['block']} quick inet proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2720
block {$log['block']} quick inet proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2721
block {$log['block']} quick inet6 proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
2722
block {$log['block']} quick inet6 proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
2723

    
2724
# Snort package
2725
block {$log['block']} quick from <snort2c> to any tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2726
block {$log['block']} quick from any to <snort2c> tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
2727

    
2728
EOD;
2729

    
2730
	$saved_tracker += 100;
2731
	$tracker = $saved_tracker;
2732

    
2733
	$ipfrules .= filter_process_carp_rules($log);
2734

    
2735
	$saved_tracker += 100;
2736
	$tracker = $saved_tracker;
2737

    
2738
	$ipfrules .= "\n# SSH lockout\n";
2739
	if(is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
2740
		$ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port ";
2741
		$ipfrules .= $config['system']['ssh']['port'];
2742
		$ipfrules .= " tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
2743
	} else {
2744
		if($config['system']['ssh']['port'] <> "")
2745
			$sshport = $config['system']['ssh']['port'];
2746
		else
2747
			$sshport = 22;
2748
		if($sshport)
2749
			$ipfrules .= "block in {$log['block']} quick proto tcp from <sshlockout> to (self) port {$sshport} tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
2750
	}
2751

    
2752
	$saved_tracker += 50;
2753
	$tracker = $saved_tracker;
2754

    
2755
	$ipfrules .= "\n# webConfigurator lockout\n";
2756
	if(!$config['system']['webgui']['port']) {
2757
		if($config['system']['webgui']['protocol'] == "http")
2758
			$webConfiguratorlockoutport = "80";
2759
		else
2760
			$webConfiguratorlockoutport = "443";
2761
	} else {
2762
		$webConfiguratorlockoutport = $config['system']['webgui']['port'];
2763
	}
2764
	if($webConfiguratorlockoutport)
2765
		$ipfrules .= "block in {$log['block']} quick proto tcp from <webConfiguratorlockout> to (self) port {$webConfiguratorlockoutport} tracker {$increment_tracker($tracker)} label \"webConfiguratorlockout\"\n";
2766

    
2767
	$saved_tracker += 100;
2768
	$tracker = $saved_tracker;
2769

    
2770
	/*
2771
	 * Support for allow limiting of TCP connections by establishment rate
2772
	 * Useful for protecting against sudden outburts, etc.
2773
	 */
2774
	$ipfrules .= "block in {$log['block']} quick from <virusprot> to any tracker 1000000400 label \"virusprot overload table\"\n";
2775

    
2776
	$saved_tracker += 100;
2777
	$tracker = $saved_tracker;
2778

    
2779
	/* if captive portal is enabled, ensure that access to this port
2780
	 * is allowed on a locked down interface
2781
	 */
2782
	if(is_array($config['captiveportal'])) {
2783
		foreach ($config['captiveportal'] as $cpcfg) {
2784
			if(!isset($cpcfg['enable']))
2785
				continue;
2786
			$cpinterfaces = explode(",", $cpcfg['interface']);
2787
			$cpiflist = array();
2788
			$cpiplist = array();
2789
			foreach ($cpinterfaces as $cpifgrp) {
2790
				if(!isset($FilterIflist[$cpifgrp]))
2791
					continue;
2792
				$tmpif = get_real_interface($cpifgrp);
2793
				if(!empty($tmpif)) {
2794
					$cpiflist[] = "{$tmpif}";
2795
					$cpipm = get_interface_ip($cpifgrp);
2796
					if(is_ipaddr($cpipm)) {
2797
						$carpif = link_ip_to_carp_interface($cpipm);
2798
						if (!empty($carpif)) {
2799
							$cpiflist[] = $carpif;
2800
							$carpsif = explode(" ", $carpif);
2801
							foreach ($carpsif as $cpcarp) {
2802
								$carpip = find_interface_ip($cpcarp);
2803
								if (is_ipaddr($carpip))
2804
									$cpiplist[] = $carpip;
2805
							}
2806
						}
2807
						$cpiplist[] = $cpipm;
2808
					}
2809
				}
2810
			}
2811
			if (count($cpiplist) > 0 && count($cpiflist) > 0) {
2812
				$cpinterface = implode(" ", $cpiflist);
2813
				$cpaddresses = implode(" ", $cpiplist);
2814
				$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
2815
				$listenporthttp  = $cpcfg['listenporthttp']  ? $cpcfg['listenporthttp']  : $cpcfg['zoneid'];
2816
				$portalias = $listenporthttps;
2817
				$portalias .= " {$listenporthttp}";
2818
				$ipfrules .= "pass in {$log['pass']} quick on { {$cpinterface} } proto tcp from any to { {$cpaddresses} } port { {$portalias} } tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
2819
				$ipfrules .= "pass out {$log['pass']} quick on { {$cpinterface} } proto tcp from any to any flags any tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
2820
			}
2821
		}
2822
	}
2823

    
2824
	$bogontableinstalled = 0;
2825
	foreach ($FilterIflist as $on => $oc) {
2826
		/* XXX: Not static but give a step of 1000 for each interface to at least be able to match rules. */
2827
		$saved_tracker += 1000;
2828
		$tracker = $saved_tracker;
2829

    
2830
		/* block bogon networks */
2831
		/* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
2832
		/* file is automatically in cron every 3000 minutes */
2833
		if(!isset($config['syslog']['nologbogons']))
2834
			$bogonlog = "log";
2835
		else
2836
			$bogonlog = "";
2837

    
2838
		if(isset($config['interfaces'][$on]['blockbogons'])) {
2839
			$ipfrules .= <<<EOD
2840
# block bogon networks (IPv4)
2841
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
2842
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']}")}"
2843

    
2844
EOD;
2845

    
2846
			if(isset($config['system']['ipv6allow'])) {
2847
				$ipfrules .= <<<EOD
2848
# block bogon networks (IPv6)
2849
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
2850
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']}")}"
2851

    
2852
EOD;
2853
			}
2854
		}
2855

    
2856

    
2857
		$saved_tracker += 10;
2858
		$tracker = $saved_tracker;
2859

    
2860
		if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
2861
			$ipfrules .= <<<EOD
2862
# allow our DHCPv6 client out to the {$oc['descr']}
2863
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']}")}"
2864
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']}")}"
2865
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']}")}"
2866

    
2867
EOD;
2868
		}
2869

    
2870
		$saved_tracker += 10;
2871
		$tracker = $saved_tracker;
2872

    
2873
		$isbridged = false;
2874
		if(is_array($config['bridges']['bridged'])) {
2875
			foreach ($config['bridges']['bridged'] as $oc2) {
2876
				if(stristr($oc2['members'], $on)) {
2877
					$isbridged = true;
2878
					break;
2879
				}
2880
			}
2881
		}
2882

    
2883
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2884
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
2885

    
2886
		/* block private networks ? */
2887
		if(!isset($config['syslog']['nologprivatenets']))
2888
			$privnetlog = "log";
2889
		else
2890
			$privnetlog = "";
2891

    
2892
		$saved_tracker += 10;
2893
		$tracker = $saved_tracker;
2894

    
2895
		if(isset($config['interfaces'][$on]['blockpriv'])) {
2896
			if($isbridged == false) {
2897
				$ipfrules .= <<<EOD
2898
# block anything from private networks on interfaces with the option set
2899
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")}"
2900
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")}"
2901
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")}"
2902
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")}"
2903
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")}"
2904
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")}"
2905

    
2906
EOD;
2907
			}
2908
		}
2909

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

    
2913
		switch ($oc['type']) {
2914
		case "pptp":
2915
				$ipfrules .= <<<EOD
2916
# allow PPTP client
2917
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']}")}"
2918
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']}")}"
2919

    
2920
EOD;
2921
			break;
2922
		case "dhcp":
2923
			$ipfrules .= <<<EOD
2924
# allow our DHCP client out to the {$oc['descr']}
2925
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']}")}"
2926
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']}")}"
2927
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
2928

    
2929
EOD;
2930

    
2931
			break;
2932
		case "pppoe":
2933
		case "none":
2934
			/* XXX: Nothing to do in this case?! */
2935
			break;
2936
		default:
2937
			/* allow access to DHCP server on interfaces */
2938
			if(isset($config['dhcpd'][$on]['enable'])) {
2939
				$ipfrules .= <<<EOD
2940
# allow access to DHCP server on {$oc['descr']}
2941
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"
2942

    
2943
EOD;
2944
				if (is_ipaddrv4($oc['ip'])) {
2945
					$ipfrules .= <<<EOD
2946
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"
2947
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"
2948

    
2949
EOD;
2950
				}
2951

    
2952
				if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
2953
					$ipfrules .= <<<EOD
2954
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
2955
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"
2956
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"
2957

    
2958
EOD;
2959
				}
2960

    
2961
			}
2962
			break;
2963
		}
2964

    
2965
		$saved_tracker += 10;
2966
		$tracker = $saved_tracker;
2967
		switch($oc['type6']) {
2968
		case "6rd":
2969
			$ipfrules .= <<<EOD
2970
# allow our proto 41 traffic from the 6RD border relay in
2971
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']}")}"
2972
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']}")}"
2973

    
2974
EOD;
2975
		/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
2976
		if (0 && is_ipaddrv6($oc['ipv6'])) {
2977
			$ipfrules .= <<<EOD
2978
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']}")}"
2979
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']}")}"
2980

    
2981
EOD;
2982
		}
2983
			break;
2984
		case "6to4":
2985
			if (is_ipaddrv4($oc['ip'])) {
2986
			$ipfrules .= <<<EOD
2987
# allow our proto 41 traffic from the 6to4 border relay in
2988
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']}")}"
2989
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']}")}"
2990

    
2991
EOD;
2992
		}
2993
		/* XXX: Really need to allow 6to4 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 6in4 traffic in for 6to4 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 6in4 traffic out for 6to4 on {$oc['descr']}")}"
2998

    
2999
EOD;
3000
		}
3001
			break;
3002
		default:
3003
			if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface']) 
3004
				|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
3005
				$ipfrules .= <<<EOD
3006
# allow access to DHCPv6 server on {$oc['descr']}
3007
# We need inet6 icmp for stateless autoconfig and dhcpv6
3008
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"
3009
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"
3010
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"
3011
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"
3012

    
3013
EOD;
3014
				if (is_ipaddrv6($oc['ipv6'])) {
3015
					$ipfrules .= <<<EOD
3016
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"
3017
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"
3018

    
3019
EOD;
3020
				}
3021
			}
3022
			break;
3023
		}
3024
	}
3025

    
3026
	$saved_tracker += 10;
3027
	$tracker = $saved_tracker;
3028

    
3029
	/*
3030
	 * NB: The loopback rules are needed here since the antispoof would take precedence then.
3031
	 *	If you ever add the 'quick' keyword to the antispoof rules above move the looback
3032
	 *	rules before them.
3033
	 */
3034
	$ipfrules .= <<<EOD
3035

    
3036
# loopback
3037
pass in {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
3038
pass out {$log['pass']} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
3039
pass in {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
3040
pass out {$log['pass']} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
3041
# let out anything from the firewall host itself and decrypted IPsec traffic
3042
pass out {$log['pass']} inet all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv4 from firewall host itself"
3043
pass out {$log['pass']} inet6 all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv6 from firewall host itself"
3044

    
3045
EOD;
3046

    
3047
	$saved_tracker += 100;
3048
	$tracker = $saved_tracker;
3049
	foreach ($FilterIflist as $ifdescr => $ifcfg) {
3050
		if(isset($ifcfg['virtual']))
3051
			continue;
3052

    
3053
		$gw = get_interface_gateway($ifdescr);
3054
		if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
3055
			$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";
3056
			if (is_array($ifcfg['vips'])) {
3057
				foreach ($ifcfg['vips'] as $vip)
3058
					if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
3059
						$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";
3060
					else
3061
						$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";
3062
			}
3063
		}
3064

    
3065
		$gwv6 = get_interface_gateway_v6($ifdescr);
3066
		$stf = get_real_interface($ifdescr, "inet6");
3067
		$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
3068
		if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
3069
			$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";
3070
			if (is_array($ifcfg['vips6'])) {
3071
				foreach ($ifcfg['vips6'] as $vip)
3072
					$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";
3073
			}
3074
		}
3075
	}
3076

    
3077

    
3078
	$saved_tracker += 300;
3079
	$tracker = $saved_tracker;
3080
	/* add ipsec interfaces */
3081
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
3082
		$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";
3083

    
3084
	$saved_tracker += 10;
3085
	$tracker = $saved_tracker;
3086
	if(is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
3087
		$alports = filter_get_antilockout_ports();
3088

    
3089
		if(count($config['interfaces']) > 1 && !empty($FilterIflist['lan']['if'])) {
3090
				/* if antilockout is enabled, LAN exists and has
3091
				 * an IP and subnet mask assigned
3092
				 */
3093
				$lanif = $FilterIflist['lan']['if'];
3094
				$ipfrules .= <<<EOD
3095
# make sure the user cannot lock himself out of the webConfigurator or SSH
3096
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"
3097

    
3098
EOD;
3099
		} else if (count($config['interfaces']) == 1) {
3100
			/* single-interface deployment, add to WAN	*/
3101
			$wanif = $FilterIflist["wan"]['if'];
3102
			$ipfrules .= <<<EOD
3103
# make sure the user cannot lock himself out of the webConfigurator or SSH
3104
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"
3105

    
3106
EOD;
3107
		}
3108
		unset($alports);
3109
	}
3110

    
3111
	$saved_tracker += 10;
3112
	$tracker = $saved_tracker;
3113
	/* PPTPd enabled? */
3114
	if($pptpdcfg['mode'] && ($pptpdcfg['mode'] != "off") && !isset($config['system']['disablevpnrules'])) {
3115
		if($pptpdcfg['mode'] == "server")
3116
			$pptpdtarget = get_interface_ip();
3117
		else
3118
			$pptpdtarget = $pptpdcfg['redir'];
3119
		if(is_ipaddr($pptpdtarget) and is_array($FilterIflist['wan'])) {
3120
			$ipfrules .= <<<EOD
3121
# PPTPd rules
3122
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}")}"
3123
pass in {$log['pass']} on \${$FilterIflist['wan']['descr']} proto gre from any to any tracker {$increment_tracker($tracker)} keep state label "allow gre pptpd"
3124

    
3125
EOD;
3126

    
3127
		} else {
3128
			/*	  this shouldnt ever happen but instead of breaking the clients ruleset
3129
			 *	  log an error.
3130
			 */
3131
			log_error("ERROR!  PPTP enabled but could not resolve the \$pptpdtarget");
3132
		}
3133
	}
3134

    
3135
	$saved_tracker += 10;
3136
	$tracker = $saved_tracker;
3137
	if(isset($config['nat']['rule']) && is_array($config['nat']['rule'])) {
3138
		foreach ($config['nat']['rule'] as $rule) {
3139
			if((!isset($config['system']['disablenatreflection']) || $rule['natreflection'] == "enable")
3140
			   && $rule['natreflection'] != "disable") {
3141
				$ipfrules .= "# NAT Reflection rules\n";
3142
				$ipfrules .= <<<EOD
3143
pass in {$log['pass']} inet tagged PFREFLECT tracker {$increment_tracker($tracker)} keep state label "NAT REFLECT: Allow traffic to localhost"
3144

    
3145
EOD;
3146
				break;
3147
			}
3148
		}
3149
	}
3150

    
3151
	if (isset($config['filter']['rule'])) {
3152
		/* Pre-cache all our rules so we only have to generate them once */
3153
		$rule_arr1 = array();
3154
		$rule_arr2 = array();
3155
		$rule_arr3 = array();
3156
		$vpn_and_ppp_ifs = array("l2tp", "pptp", "pppoe", "enc0", "openvpn");
3157
		/*
3158
		 * NB: The order must be: Floating rules, then interface group and then regular ones.
3159
		 */
3160
		foreach ($config['filter']['rule'] as $rule) {
3161
			update_filter_reload_status("Pre-caching {$rule['descr']}...");
3162
			if (isset ($rule['disabled']))
3163
				continue;
3164

    
3165
			if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
3166
				if (isset($rule['floating'])) {
3167
					$rule['ipprotocol'] = "inet";
3168
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3169
					$rule['ipprotocol'] = "inet6";
3170
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3171
				} else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
3172
					$rule['ipprotocol'] = "inet";
3173
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3174
					$rule['ipprotocol'] = "inet6";
3175
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3176
				} else {
3177
					$rule['ipprotocol'] = "inet";
3178
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3179
					$rule['ipprotocol'] = "inet6";
3180
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3181
				}
3182
				$rule['ipprotocol'] = "inet46";
3183
			} else {
3184
				if (isset($rule['floating']))
3185
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3186
				else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs))
3187
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3188
				else
3189
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3190
			}
3191
			if ($rule['sched'])
3192
				$time_based_rules = true;
3193
		}
3194

    
3195
		$ipfrules .= "\n# User-defined rules follow\n";
3196
		$ipfrules .= "\nanchor \"userrules/*\"\n";
3197
		/* Generate user rule lines */
3198
		foreach($rule_arr1 as $rule) {
3199
			if (isset($rule['disabled']))
3200
				continue;
3201
			if (!$rule['rule'])
3202
				continue;
3203
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3204
		}
3205
		foreach($rule_arr2 as $rule) {
3206
			if (isset($rule['disabled']))
3207
				continue;
3208
			if (!$rule['rule'])
3209
				continue;
3210
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3211
		}
3212
		foreach($rule_arr3 as $rule) {
3213
			if (isset($rule['disabled']))
3214
				continue;
3215
			if (!$rule['rule'])
3216
				continue;
3217
			$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
3218
		}
3219
		unset($rule_arr1, $rule_arr2, $rule_arr3);
3220
	}
3221

    
3222
	$saved_tracker += 100;
3223
	$tracker = $saved_tracker;
3224

    
3225
	/*  pass traffic between statically routed subnets and the subnet on the
3226
	 *  interface in question to avoid problems with complicated routing
3227
	 *  topologies
3228
	 */
3229
	if(isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
3230
		$ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
3231
		foreach (get_staticroutes() as $route) {
3232
			$friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
3233
			if(is_array($FilterIflist[$friendly])) {
3234
				$oc = $FilterIflist[$friendly];
3235
				$routeent = explode("/", $route['network']);
3236
				unset($sa);
3237
				if (is_ipaddrv4($oc['ip'])) {
3238
					$sa = $oc['sa'];
3239
					$sn = $oc['sn'];
3240
				}
3241
				if ($sa && is_ipaddrv4($routeent[0])) {
3242
					$ipfrules .= <<<EOD
3243
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"
3244
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"
3245
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"
3246
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"
3247

    
3248
EOD;
3249
				}
3250
				unset($sa);
3251
				if (is_ipaddrv6($oc['ipv6'])) {
3252
					$sa = $oc['sav6'];
3253
					$sn = $oc['snv6'];
3254
				}
3255
				if ($sa && is_ipaddrv6($routeent[0])) {
3256
					$ipfrules .= <<<EOD
3257
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"
3258
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"
3259
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"
3260
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"
3261

    
3262
EOD;
3263
				}
3264
			}
3265
		}
3266
	}
3267

    
3268
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3269
	$saved_tracker += 100000;
3270
	$tracker = $saved_tracker;
3271
	$ipfrules .= filter_generate_ipsec_rules($log);
3272

    
3273
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3274

    
3275
	$saved_tracker += 200;
3276
	$tracker = $saved_tracker;
3277
	update_filter_reload_status("Creating uPNP rules...");
3278
	if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
3279
		if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable']))
3280
			$ipfrules .= "anchor \"miniupnpd\"\n";
3281

    
3282
		if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
3283
			$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
3284
			foreach($upnp_interfaces as $upnp_if) {
3285
				if (is_array($FilterIflist[$upnp_if])) {
3286
					$oc = $FilterIflist[$upnp_if];
3287
					unset($sa);
3288
					if($oc['ip']) {
3289
						$sa = $oc['sa'];
3290
						$sn = $oc['sn'];
3291
					}
3292
					if($sa) {
3293
						$ipfrules .= <<<EOD
3294
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"
3295

    
3296
EOD;
3297
					}
3298
				}
3299
			}
3300
		}
3301
	}
3302

    
3303

    
3304
	return $ipfrules;
3305
}
3306

    
3307
function filter_rules_spoofcheck_generate($ifname, $ifcfg, $log) {
3308
	global $g, $config, $tracker;
3309
	if(isset($config['system']['developerspew'])) {
3310
		$mt = microtime();
3311
		echo "filter_rules_spoofcheck_generate() being called $mt\n";
3312
	}
3313
	$ipfrules = "antispoof {$log['block']} for \${$ifcfg['descr']} tracker {$tracker}\n";
3314
	$tracker++;
3315

    
3316
	return $ipfrules;
3317
}
3318

    
3319
/* COMPAT Function */
3320
function tdr_install_cron($should_install) {
3321
	log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
3322
	filter_tdr_install_cron($should_install);
3323
}
3324

    
3325
/****f* filter/filter_tdr_install_cron
3326
 * NAME
3327
 *   filter_tdr_install_cron
3328
 * INPUTS
3329
 *   $should_install true if the cron entry should be installed, false
3330
 *   if the entry should be removed if it is present
3331
 * RESULT
3332
 *   none
3333
 ******/
3334
function filter_tdr_install_cron($should_install) {
3335
	global $config, $g;
3336

    
3337
	if($g['booting']==true)
3338
		return;
3339

    
3340
	if (!is_array($config['cron']))
3341
		$config['cron'] = array();
3342
	if (!is_array($config['cron']['item']))
3343
		$config['cron']['item'] = array();
3344

    
3345
	$x=0;
3346
	$is_installed = false;
3347
	foreach($config['cron']['item'] as $item) {
3348
		if (strstr($item['command'], "filter_configure_sync")) {
3349
			$is_installed = true;
3350
			break;
3351
		}
3352
		$x++;
3353
	}
3354

    
3355
	switch($should_install) {
3356
		case true:
3357
			if (!$is_installed) {
3358
				$cron_item = array();
3359
				$cron_item['minute'] = "0,15,30,45";
3360
				$cron_item['hour'] = "*";
3361
				$cron_item['mday'] = "*";
3362
				$cron_item['month'] = "*";
3363
				$cron_item['wday'] = "*";
3364
				$cron_item['who'] = "root";
3365
				$cron_item['command'] = "/etc/rc.filter_configure_sync";
3366
				$config['cron']['item'][] = $cron_item;
3367
				write_config(gettext("Installed 15 minute filter reload for Time Based Rules"));
3368
				configure_cron();
3369
			}
3370
			break;
3371
		case false:
3372
			if ($is_installed == true) {
3373
				unset($config['cron']['item'][$x]);
3374
				write_config(gettext("Removed 15 minute filter reload for Time Based Rules"));
3375
				configure_cron();
3376
			}
3377
			break;
3378
	}
3379
}
3380

    
3381
/****f* filter/filter_get_time_based_rule_status
3382
 * NAME
3383
 *   filter_get_time_based_rule_status
3384
 * INPUTS
3385
 *   xml schedule block
3386
 * RESULT
3387
 *   true/false - true if the rule should be installed
3388
 ******/
3389
/*
3390
 <schedules>
3391
   <schedule>
3392
     <name>ScheduleMultipleTime</name>
3393
     <descr>main descr</descr>
3394
     <time>
3395
       <position>0,1,2</position>
3396
       <hour>0:0-24:0</hour>
3397
       <desc>time range 2</desc>
3398
     </time>
3399
     <time>
3400
       <position>4,5,6</position>
3401
       <hour>0:0-24:0</hour>
3402
       <desc>time range 1</desc>
3403
     </time>
3404
   </schedule>
3405
 </schedules>
3406
*/
3407
function filter_get_time_based_rule_status($schedule) {
3408

    
3409
	/* no schedule? rule should be installed */
3410
	if (empty($schedule))
3411
		return true;
3412
	/*
3413
	 * iterate through time blocks and determine
3414
	 * if the rule should be installed or not.
3415
	 */
3416
	foreach($schedule['timerange'] as $timeday) {
3417
		if (empty($timeday['month']))
3418
			$monthstatus = true;
3419
		else
3420
			$monthstatus = filter_tdr_month($timeday['month']);
3421
		if (empty($timeday['day']))
3422
			$daystatus = true;
3423
		else
3424
			$daystatus = filter_tdr_day($timeday['day']);
3425
		if (empty($timeday['hour']))
3426
			$hourstatus = true;
3427
		else
3428
			$hourstatus = filter_tdr_hour($timeday['hour']);
3429
		if (empty($timeday['position']))
3430
			$positionstatus = true;
3431
		else
3432
			$positionstatus = filter_tdr_position($timeday['position']);
3433

    
3434
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3435
			return true;
3436
	}
3437

    
3438
	return false;
3439
}
3440

    
3441
function filter_tdr_day($schedule) {
3442
	global $g;
3443

    
3444
	if($g['debug'])
3445
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3446

    
3447
	/*
3448
	 * Calculate day of month.
3449
	 * IE: 29th of may
3450
	 */
3451
	$date = date("d");
3452
	$defined_days = explode(",", $schedule);
3453
	foreach($defined_days as $dd) {
3454
		if ($date == $dd)
3455
			return true;
3456
	}
3457
	return false;
3458
}
3459
function filter_tdr_hour($schedule) {
3460
	global $g;
3461

    
3462
	/* $schedule should be a string such as 16:00-19:00 */
3463
	$tmp = explode("-", $schedule);
3464
	$starting_time = strtotime($tmp[0]);
3465
	$ending_time = strtotime($tmp[1]);
3466
	$now = strtotime("now");
3467
	if($g['debug'])
3468
		log_error("[TDR DEBUG] S: $starting_time E: $ending_time N: $now");
3469
	if($now >= $starting_time and $now < $ending_time)
3470
		return true;
3471
	return false;
3472
}
3473

    
3474
function filter_tdr_position($schedule) {
3475
	global $g;
3476

    
3477
	/*
3478
	 * Calculate position, ie: day of week.
3479
	 * Sunday = 7, Monday = 1, Tuesday = 2
3480
	 * Weds = 3, Thursday = 4, Friday = 5,
3481
	 * Saturday = 6
3482
	 * ...
3483
	 */
3484
	$weekday = date("w");
3485
	if($g['debug'])
3486
		log_error("[TDR DEBUG] filter_tdr_position($schedule) $weekday");
3487
	if($weekday == 0)
3488
		$weekday = 7;
3489
	$schedule_days = explode(",", $schedule);
3490
	foreach($schedule_days as $day) {
3491
		if($day == $weekday)
3492
			return true;
3493
	}
3494
	return false;
3495
}
3496

    
3497
function filter_tdr_month($schedule) {
3498
	global $g;
3499

    
3500
	/*
3501
	 * Calculate month
3502
	 */
3503
	$todays_month = date("n");
3504
	$months = explode(",", $schedule);
3505
	if($g['debug'])
3506
		log_error("[TDR DEBUG] filter_tdr_month($schedule)");
3507
	foreach($months as $month) {
3508
		if($month == $todays_month)
3509
			return true;
3510
	}
3511
	return false;
3512
}
3513

    
3514
function filter_setup_logging_interfaces() {
3515
	global $config, $FilterIflist;
3516

    
3517
	if(isset($config['system']['developerspew'])) {
3518
		$mt = microtime();
3519
		echo "filter_setup_logging_interfaces() being called $mt\n";
3520
	}
3521
	$rules = "";
3522
	if (isset($FilterIflist['lan']))
3523
		$rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
3524
	else if (isset($FilterIflist['wan']))
3525
		$rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
3526

    
3527
	return $rules;
3528
}
3529

    
3530
function filter_process_carp_rules($log) {
3531
	global $g, $config, $tracker;
3532

    
3533
	if(isset($config['system']['developerspew'])) {
3534
		$mt = microtime();
3535
		echo "filter_process_carp_rules() being called $mt\n";
3536
	}
3537

    
3538
	$increment_tracker = 'filter_rule_tracker';
3539
	$lines = "";
3540
	/* return if there are no carp configured items */
3541
	if (!empty($config['hasync']) or !empty($config['virtualip']['vip'])) {
3542
		$lines .= "block in {$log['block']} quick proto carp from (self) to any tracker {$increment_tracker($tracker)}\n";
3543
		$lines .= "pass {$log['pass']} quick proto carp tracker {$increment_tracker($tracker)}\n";
3544
	}
3545
	return $lines;
3546
}
3547

    
3548
/* Generate IPSEC Filter Items */
3549
function filter_generate_ipsec_rules($log = array()) {
3550
	global $config, $g, $FilterIflist, $tracker;
3551

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

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

    
3560
	$increment_tracker = 'filter_rule_tracker';
3561

    
3562
	$ipfrules = "\n# VPN Rules\n";
3563
	/* Is IP Compression enabled? */
3564
	if(isset($config['ipsec']['ipcomp']))
3565
		set_single_sysctl("net.inet.ipcomp.ipcomp_enable" , "1");
3566
	else
3567
		set_single_sysctl("net.inet.ipcomp.ipcomp_enable" , "0");
3568

    
3569
	if(isset($config['ipsec']['enable']) &&
3570
		is_array($config['ipsec']['phase1'])) {
3571
		/* step through all phase1 entries */
3572
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
3573
			$tracker += 10;
3574

    
3575
			if(isset ($ph1ent['disabled']))
3576
				continue;
3577
			/* determine local and remote peer addresses */
3578
			if(!isset($ph1ent['mobile'])) {
3579
				if (!function_exists('ipsec_get_phase1_dst'))
3580
					require_once("ipsec.inc");
3581
				$rgip = ipsec_get_phase1_dst($ph1ent);
3582
				if(!$rgip) {
3583
					$ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n";
3584
					continue;
3585
				}
3586
			} else
3587
				$rgip = " any ";
3588
			/* Determine best description */
3589
			if($ph1ent['descr'])
3590
				$descr = $ph1ent['descr'];
3591
			else
3592
				$descr = $rgip;
3593
			/*
3594
			 * Step through all phase2 entries and determine
3595
			 * which protocols are in use with this peer
3596
			 */
3597
			$prot_used_esp = false;
3598
			$prot_used_ah  = false;
3599
			if(is_array($config['ipsec']['phase2'])) {
3600
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
3601
					/* only evaluate ph2's bound to our ph1 */
3602
					if($ph2ent['ikeid'] != $ph1ent['ikeid'])
3603
						continue;
3604
					if($ph2ent['protocol'] == 'esp')
3605
						$prot_used_esp = true;
3606
					if($ph2ent['protocol'] == 'ah')
3607
						$prot_used_ah = true;
3608
				}
3609
			}
3610

    
3611
			if (strstr($ph1ent['interface'], "_vip"))
3612
				list($parentinterface, $vhid) = explode("_vhid", $ph1ent['interface']);
3613
			else
3614
				$parentinterface = $ph1ent['interface'];
3615
			if (empty($FilterIflist[$parentinterface]['descr'])) {
3616
				$ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
3617
				continue;
3618
			}
3619

    
3620
			unset($gateway);
3621
			/* add endpoint routes to correct gateway on interface */
3622
			if((is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
3623
				$gateway = get_interface_gateway($parentinterface);
3624
				$interface = $FilterIflist[$parentinterface]['if'];
3625

    
3626
				$route_to = " route-to ( $interface $gateway ) ";
3627
				$reply_to = " reply-to ( $interface $gateway ) ";
3628

    
3629
			}
3630
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3631
				$gateway = get_interface_gateway_v6($parentinterface);
3632
				$interface = $FilterIflist[$parentinterface]['if'];
3633

    
3634
				$route_to = " route-to ( $interface $gateway ) ";
3635
				$reply_to = " reply-to ( $interface $gateway ) ";
3636
			}
3637

    
3638
			/* Just in case */
3639
			if((!is_ipaddr($gateway) || empty($interface))) {
3640
				$route_to = " ";
3641
				$reply_to = " ";
3642
			}
3643

    
3644
			/* Add rules to allow IKE to pass */
3645
			$shorttunneldescr = substr($descr, 0, 35);
3646
				$ipfrules .= <<<EOD
3647
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"
3648
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"
3649

    
3650
EOD;
3651
			/* If NAT-T is enabled, add additional rules */
3652
			if($ph1ent['nat_traversal'] != "off" ) {
3653
				$ipfrules .= <<<EOD
3654
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"
3655
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"
3656

    
3657
EOD;
3658
			}
3659
			/* Add rules to allow the protocols in use */
3660
			if($prot_used_esp == true) {
3661
				$ipfrules .= <<<EOD
3662
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"
3663
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"
3664

    
3665
EOD;
3666
			}
3667
			if($prot_used_ah == true) {
3668
				$ipfrules .= <<<EOD
3669
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"
3670
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"
3671

    
3672
EOD;
3673
			}
3674
		}
3675

    
3676
	}
3677
	return($ipfrules);
3678
}
3679

    
3680
function discover_pkg_rules($ruletype) {
3681
	global $config, $g, $aliases;
3682

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

    
3687
	$rules = "";
3688
	$files = glob("/usr/local/pkg/*.inc");
3689
	foreach($files as $pkg_inc) {
3690
		update_filter_reload_status(sprintf(gettext('Checking for %1$s PF hooks in package %2$s'), $ruletype, $pkg_inc));
3691
		$pkg = basename($pkg_inc, ".inc");
3692
		$pkg_generate_rules = "{$pkg}_generate_rules";
3693
		if (!function_exists($pkg_generate_rules))
3694
			require_once($pkg_inc);
3695
		if(function_exists($pkg_generate_rules)) {
3696
			update_filter_reload_status(sprintf(gettext('Processing early %1$s rules for package %2$s'), $ruletype, $pkg_inc));
3697
			$tmprules = $pkg_generate_rules("$ruletype");
3698
			file_put_contents("{$g['tmp_path']}/rules.test.packages", $aliases . $tmprules);
3699
			$status = mwexec("/sbin/pfctl -nf {$g['tmp_path']}/rules.test.packages");
3700
			if ($status <> 0) {
3701
				$errorrules = sprintf(gettext("There was an error while parsing the package filter rules for %s."), $pkg_inc) . "\n";
3702
				log_error($errorrules);
3703
				file_put_contents("{$g['tmp_path']}/rules.packages.{$pkg}", "#{$errorrules}\n{$tmprules}\n");
3704
				continue;
3705
			}
3706
			$rules .= $tmprules;
3707
		}
3708
	}
3709
	return $rules;
3710
}
3711

    
3712
function filter_get_antilockout_ports($wantarray = false) {
3713
	global $config;
3714

    
3715
	$lockoutports = array();
3716
	$guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
3717
	$guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
3718
	$lockoutports[] = $guiport;
3719

    
3720
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3721
		$lockoutports[] = "80";
3722

    
3723
	if (isset($config['system']['enablesshd']))
3724
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3725

    
3726
	if ($wantarray)
3727
		return $lockoutports;
3728
	else
3729
		return implode(" ", $lockoutports);
3730

    
3731
}
3732

    
3733
?>
(19-19/68)