Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ fb0a4e7a

1
<?php
2
/* $Id$ */
3
/*
4
	filter.inc
5
	Copyright (C) 2004-2006 Scott Ullrich
6
	Copyright (C) 2005		Bill Marquette
7
	Copyright (C) 2006		Peter Allgeyer
8
	Copyright (C) 2008-2010		Ermal Luci
9
	All rights reserved.
10

    
11
	originally part of m0n0wall (http://m0n0.ch/wall)
12
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
13
	All rights reserved.
14

    
15
	Redistribution and use in source and binary forms, with or without
16
	modification, are permitted provided that the following conditions are met:
17

    
18
	1. Redistributions of source code must retain the above copyright notice,
19
	   this list of conditions and the following disclaimer.
20

    
21
	2. Redistributions in binary form must reproduce the above copyright
22
	   notice, this list of conditions and the following disclaimer in the
23
	   documentation and/or other materials provided with the distribution.
24

    
25
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
	POSSIBILITY OF SUCH DAMAGE.
35

    
36
	pfSense_BUILDER_BINARIES:	/sbin/kldload	/usr/sbin/tcpdump	/sbin/pfctl	/bin/rm
37
	pfSense_BUILDER_BINARIES:	/usr/sbin/inetd
38
	pfSense_MODULE:	filter
39
*/
40

    
41
/* DISABLE_PHP_LINT_CHECKING */
42

    
43
/* holds the items that will be executed *AFTER* the filter is fully loaded */
44
$after_filter_configure_run = array();
45

    
46
/* For installing cron job of schedules */
47
$time_based_rules = false;
48

    
49
/* Used to hold the interface list that will be used on ruleset creation. */
50
$FilterIflist = array();
51

    
52
/* Create a global array to avoid errors on rulesets. */
53
$GatewaysList = array();
54

    
55
/* Used for the hostname dns resolver */
56
$filterdns = array(); 
57

    
58
/* Used for aliases and interface macros */
59
$aliases = "";
60

    
61
global $tracker;
62
$tracker = 1000000000;
63

    
64
function filter_rule_tracker($tracker) {
65
	global $tracker;
66

    
67
	return (++$tracker);
68

    
69
}
70

    
71
function fix_rule_label($descr) {
72
	$descr = str_replace('"', '', $descr);
73
	if (strlen($descr) > 63)
74
		return substr($descr, 0, 60) . "...";
75
	else
76
		return $descr;
77
}
78

    
79
function is_bogonsv6_used() {
80
	global $config, $g;
81
	# Only use bogonsv6 table if IPv6 Allow is on, and at least 1 enabled interface also has "blockbogons" enabled.
82
	$usebogonsv6 = false;
83
	if (isset($config['system']['ipv6allow'])) {
84
		foreach ($config['interfaces'] as $ifacedata) {
85
			if(isset($ifacedata['enable']) && isset($ifacedata['blockbogons'])) {
86
				$usebogonsv6 = true;
87
				break;
88
			}
89
		}
90
	}
91
	return $usebogonsv6;
92
}
93

    
94
function flowtable_configure() {
95
	global $config, $g;
96

    
97
	if (empty($config['system']['flowtable'])) {
98
		set_single_sysctl("net.inet.flowtable.enable", "0");
99
		return;
100
	}
101

    
102
	// Figure out how many flows we should reserve
103
	// sized 2x larger than the number of unique connection destinations.
104
	if($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates']))
105
		$maxstates = $config['system']['maximumstates'];
106
	else
107
		$maxstates = 150000;
108
	// nmbflows cpu count * ($maxstates * 2)
109
	$cpus = get_single_sysctl('kern.smp.cpus');
110
	$nmbflows = ($cpus*($maxstates*2));
111
	// Flowtable currently only works on 8.0
112
	if(get_freebsd_version() == "8") {
113
		set_sysctl(array(
114
			"net.inet.flowtable.nmbflows" => $nmbflows,
115
			"net.inet.ip.output_flowtable_size" => $maxstates,
116
			"net.inet.flowtable.enable" => "1")
117
		);
118
	}
119
}
120

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

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

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

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

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

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

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

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

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

    
188

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
354
	# If we are not using bogonsv6 then we can remove any bogonsv6 table from the running pf (if the table is not there, the kill is still fine).
355
	if (!is_bogonsv6_used())
356
		$_grbg = exec("/sbin/pfctl -t bogonsv6 -T kill 2>/dev/null");
357

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

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

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

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

    
399
		fclose($fda);
400
	}
401

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
685
	return $result;
686
}
687

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

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

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

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

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

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

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

    
757
	$rules .= "\n";
758

    
759
	return $rules;
760
}
761

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

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

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

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

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

    
822
	return $vpns;
823
}
824

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

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

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

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

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

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

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

    
1048
	$nat_if_list = array();
1049

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

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

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

    
1061
	return $nat_if_list;
1062
}
1063

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

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

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

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

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

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

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

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

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

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

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

    
1146
	return $natrules;
1147
}
1148

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1338
	return $natrules;
1339
}
1340

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1492
	return $rules;
1493
}
1494

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1674
		}
1675
	}
1676

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2039
	return $natrules;
2040
}
2041

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

    
2054
	return $ret;
2055
}
2056

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

    
2059
	$src = "";
2060

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

    
2088
	return $src;
2089
}
2090

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

    
2094
	$if_subnets = array($subnets);
2095

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

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

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

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

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

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

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

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

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

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

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

    
2277
	return $src;
2278
}
2279

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2658
	unset($aline);
2659

    
2660
	return $line;
2661
}
2662

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

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

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

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

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

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

    
2694
	$saved_tracker = $tracker;
2695

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

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

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

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

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

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

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

    
2743
EOD;
2744

    
2745
	$saved_tracker += 100;
2746
	$tracker = $saved_tracker;
2747

    
2748
	$ipfrules .= filter_process_carp_rules($log);
2749

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

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

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

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

    
2782
	$saved_tracker += 100;
2783
	$tracker = $saved_tracker;
2784

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

    
2791
	$saved_tracker += 100;
2792
	$tracker = $saved_tracker;
2793

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

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

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

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

    
2859
EOD;
2860

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

    
2867
EOD;
2868
			}
2869
		}
2870

    
2871

    
2872
		$saved_tracker += 10;
2873
		$tracker = $saved_tracker;
2874

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

    
2882
EOD;
2883
		}
2884

    
2885
		$saved_tracker += 10;
2886
		$tracker = $saved_tracker;
2887

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

    
2898
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2899
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
2900

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

    
2907
		$saved_tracker += 10;
2908
		$tracker = $saved_tracker;
2909

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

    
2921
EOD;
2922
			}
2923
		}
2924

    
2925
		$saved_tracker += 10;
2926
		$tracker = $saved_tracker;
2927

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

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

    
2944
EOD;
2945

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

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

    
2964
EOD;
2965
				}
2966

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

    
2973
EOD;
2974
				}
2975

    
2976
			}
2977
			break;
2978
		}
2979

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

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

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

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

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

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

    
3034
EOD;
3035
				}
3036
			}
3037
			break;
3038
		}
3039
	}
3040

    
3041
	$saved_tracker += 10;
3042
	$tracker = $saved_tracker;
3043

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

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

    
3060
EOD;
3061

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

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

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

    
3092

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

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

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

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

    
3121
EOD;
3122
		}
3123
		unset($alports);
3124
	}
3125

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

    
3140
EOD;
3141

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

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

    
3160
EOD;
3161
				break;
3162
			}
3163
		}
3164
	}
3165

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

    
3180
			if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
3181
				if (isset($rule['floating'])) {
3182
					$rule['ipprotocol'] = "inet";
3183
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3184
					$rule['ipprotocol'] = "inet6";
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['ipprotocol'] = "inet";
3188
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3189
					$rule['ipprotocol'] = "inet6";
3190
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3191
				} else {
3192
					$rule['ipprotocol'] = "inet";
3193
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3194
					$rule['ipprotocol'] = "inet6";
3195
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3196
				}
3197
				$rule['ipprotocol'] = "inet46";
3198
			} else {
3199
				if (isset($rule['floating']))
3200
					$rule_arr1[] = filter_generate_user_rule_arr($rule);
3201
				else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs))
3202
					$rule_arr2[] = filter_generate_user_rule_arr($rule);
3203
				else
3204
					$rule_arr3[] = filter_generate_user_rule_arr($rule);
3205
			}
3206
			if ($rule['sched'])
3207
				$time_based_rules = true;
3208
		}
3209

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

    
3237
	$saved_tracker += 100;
3238
	$tracker = $saved_tracker;
3239

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

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

    
3277
EOD;
3278
				}
3279
			}
3280
		}
3281
	}
3282

    
3283
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3284
	$saved_tracker += 100000;
3285
	$tracker = $saved_tracker;
3286
	$ipfrules .= filter_generate_ipsec_rules($log);
3287

    
3288
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3289

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

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

    
3311
EOD;
3312
					}
3313
				}
3314
			}
3315
		}
3316
	}
3317

    
3318

    
3319
	return $ipfrules;
3320
}
3321

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

    
3331
	return $ipfrules;
3332
}
3333

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

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

    
3352
	if($g['booting']==true)
3353
		return;
3354

    
3355
	if (!is_array($config['cron']))
3356
		$config['cron'] = array();
3357
	if (!is_array($config['cron']['item']))
3358
		$config['cron']['item'] = array();
3359

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

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

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

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

    
3449
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3450
			return true;
3451
	}
3452

    
3453
	return false;
3454
}
3455

    
3456
function filter_tdr_day($schedule) {
3457
	global $g;
3458

    
3459
	if($g['debug'])
3460
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3461

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

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

    
3489
function filter_tdr_position($schedule) {
3490
	global $g;
3491

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

    
3512
function filter_tdr_month($schedule) {
3513
	global $g;
3514

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

    
3529
function filter_setup_logging_interfaces() {
3530
	global $config, $FilterIflist;
3531

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

    
3542
	return $rules;
3543
}
3544

    
3545
function filter_process_carp_rules($log) {
3546
	global $g, $config, $tracker;
3547

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

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

    
3563
/* Generate IPsec Filter Items */
3564
function filter_generate_ipsec_rules($log = array()) {
3565
	global $config, $g, $FilterIflist, $tracker;
3566

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

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

    
3575
	$increment_tracker = 'filter_rule_tracker';
3576

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

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

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

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

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

    
3641
				$route_to = " route-to ( $interface $gateway ) ";
3642
				$reply_to = " reply-to ( $interface $gateway ) ";
3643

    
3644
			}
3645
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3646
				$gateway = get_interface_gateway_v6($parentinterface);
3647
				$interface = $FilterIflist[$parentinterface]['if'];
3648

    
3649
				$route_to = " route-to ( $interface $gateway ) ";
3650
				$reply_to = " reply-to ( $interface $gateway ) ";
3651
			}
3652

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

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

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

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

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

    
3687
EOD;
3688
			}
3689
		}
3690

    
3691
	}
3692
	return($ipfrules);
3693
}
3694

    
3695
function discover_pkg_rules($ruletype) {
3696
	global $config, $g, $aliases;
3697

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

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

    
3727
function filter_get_antilockout_ports($wantarray = false) {
3728
	global $config;
3729

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

    
3735
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3736
		$lockoutports[] = "80";
3737

    
3738
	if (isset($config['system']['enablesshd']))
3739
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3740

    
3741
	if ($wantarray)
3742
		return $lockoutports;
3743
	else
3744
		return implode(" ", $lockoutports);
3745

    
3746
}
3747

    
3748
?>
(19-19/68)