Projet

Général

Profil

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

univnautes / etc / inc / filter.inc @ 340ce958

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

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

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

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

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

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

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

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

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

    
66
	return (++$tracker);
67

    
68
}
69

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

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

    
93
function filter_pflog_start($kill_first = false) {
94
	global $config, $g;
95
	if ($g['platform'] == 'jail')
96
		return;
97
	if(isset($config['system']['developerspew'])) {
98
		$mt = microtime();
99
		echo "filter_pflog_start() being called $mt\n";
100
	}
101
	if (!file_exists("{$g['varrun_path']}/filterlog.pid") ||
102
	    !isvalidpid("{$g['varrun_path']}/filterlog.pid"))
103
		mwexec("/usr/local/sbin/filterlog -i pflog0 -p {$g['varrun_path']}/filterlog.pid");
104
}
105

    
106
/* reload filter async */
107
function filter_configure() {
108
	global $g;
109

    
110
	if(isset($config['system']['developerspew'])) {
111
		$mt = microtime();
112
		echo "filter_configure() being called $mt\n";
113
	}
114

    
115
	/*
116
	 * NOTE: Check here for bootup status since this should not be triggered during bootup.
117
	 *	 The reason is that rc.bootup calls filter_configure_sync directly which does this too.
118
	 */
119
	if (!$g['booting'])
120
		send_event("filter reload");
121
}
122

    
123
function filter_delete_states_for_down_gateways() {
124
	global $config, $GatewaysList;
125

    
126
	if (isset($config['system']['kill_states']))
127
		return;
128

    
129
	$any_gateway_down = false;
130
	$a_gateways = return_gateways_status();
131
	if (is_array($GatewaysList)) {
132
		foreach ($GatewaysList as $gwname => $gateway) {
133
			if (empty($gateway['monitor']))
134
				continue;
135
			if (!is_ipaddr($gateway['monitor']))
136
				continue;
137
			if (strstr($gateway['monitor'], "127.0.0."))
138
				continue;
139
			if (empty($a_gateways[$gateway['monitor']]))
140
				continue;
141
			$gwstatus =& $a_gateways[$gateway['monitor']];
142
			if (strstr($gwstatus['status'], "down")) {
143
				$any_gateway_down = true;
144
				break;
145
			}
146
		}
147
	}
148
	if ($any_gateway_down == true)
149
		mwexec("/sbin/pfctl -Fs");
150
}
151

    
152
/* reload filter sync */
153
function filter_configure_sync($delete_states_if_needed = true) {
154
	global $config, $g, $after_filter_configure_run, $FilterIflist;
155
	global $time_based_rules, $filterdns, $aliases, $dummynet_name_list;
156

    
157
	/* Use filter lock to not allow concurrent filter reloads during this run. */
158
	$filterlck = lock('filter', LOCK_EX);
159

    
160

    
161
	filter_pflog_start();
162
	update_filter_reload_status(gettext("Initializing"));
163

    
164
	/* invalidate interface cache */
165
	get_interface_arr(true);
166

    
167
	if(isset($config['system']['developerspew'])) {
168
		$mt = microtime();
169
		echo "filter_configure_sync() being called $mt\n";
170
	}
171
	/* Get interface list to work with. */
172
	filter_generate_optcfg_array();
173
	if($g['booting'] == true)
174
		echo gettext("Configuring firewall");
175

    
176
	/* generate aliases */
177
	if($g['booting'] == true)
178
		echo ".";
179
	update_filter_reload_status(gettext("Creating aliases"));
180
	$aliases = filter_generate_aliases();
181
	$gateways = filter_generate_gateways();
182
	if($g['booting'] == true)
183
		echo ".";
184
	update_filter_reload_status(gettext("Generating Limiter rules"));
185
	$dummynet_rules = filter_generate_dummynet_rules();
186
	$dummynet_name_list = get_unique_dnqueue_list();
187
	update_filter_reload_status(gettext("Generating NAT rules"));
188
	/* generate nat rules */
189
	$natrules = filter_nat_rules_generate();
190
	if($g['booting'] == true)
191
		echo ".";
192
	update_filter_reload_status(gettext("Generating filter rules"));
193
	/* generate pfctl rules */
194
	$pfrules = filter_rules_generate();
195
	/* generate altq, limiter */
196
	if($g['booting'] == true)
197
		echo ".";
198
	update_filter_reload_status(gettext("Generating ALTQ queues"));
199
	$altq_queues = filter_generate_altq_queues();
200
	update_filter_reload_status(gettext("Generating Layer7 rules"));
201
	generate_layer7_files();
202
	if($g['booting'] == true)
203
		echo ".";
204
	update_filter_reload_status(gettext("Loading filter rules"));
205
	/* enable pf if we need to, otherwise disable */
206
	if(!isset ($config['system']['disablefilter'])) {
207
		mwexec("/sbin/pfctl -e", true);
208
	} else {
209
		mwexec("/sbin/pfctl -d", true);
210
		unlink_if_exists("{$g['tmp_path']}/filter_loading");
211
		update_filter_reload_status(gettext("Filter is disabled.  Not loading rules."));
212
		if($g['booting'] == true)
213
			echo gettext("done.") . "\n";
214
		unlock($filterlck);
215
		return;
216
	}
217

    
218
	$limitrules = "";
219
	/* User defined maximum table entries in Advanced menu. */
220
	if ($config['system']['maximumtableentries'] <> "" && is_numeric($config['system']['maximumtableentries']))
221
		$limitrules .= "set limit table-entries {$config['system']['maximumtableentries']}\n";
222

    
223
	if ($config['system']['optimization'] <> "") {
224
		$limitrules .= "set optimization {$config['system']['optimization']}\n";
225
		if($config['system']['optimization'] == "conservative") {
226
			$limitrules .= "set timeout { udp.first 300, udp.single 150, udp.multiple 900 }\n";
227
		}
228
	} else
229
		$limitrules .= "set optimization normal\n";
230

    
231
	if (!empty($config['system']['adaptivestart']) && !empty($config['system']['adaptiveend']))
232
		$limitrules .= "set timeout { adaptive.start {$config['system']['adaptivestart']}, adaptive.end {$config['system']['adaptiveend']} }\n";
233
	else
234
		$limitrules .= "set timeout { adaptive.start 0, adaptive.end 0 }\n";
235

    
236
	if ($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates'])) {
237
		/* User defined maximum states in Advanced menu. */
238
		$limitrules .= "set limit states {$config['system']['maximumstates']}\n";
239
		$limitrules .= "set limit src-nodes {$config['system']['maximumstates']}\n";
240
	} else {
241
		$max_states = pfsense_default_state_size();
242
		$limitrules .= "set limit states {$max_states}\n";
243
		$limitrules .= "set limit src-nodes {$max_states}\n";
244
	}
245

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

    
249
	$rules = "";
250
	$rules = "{$limitrules}\n";
251
	$rules .= "{$aliases} \n";
252
	$rules .= "{$gateways} \n";
253
	update_filter_reload_status(gettext("Setting up logging information"));
254
	$rules .= filter_setup_logging_interfaces();
255
	$rules .= "\n";
256
	$rules .= "set skip on pfsync0\n";
257
	$rules .= "\n";
258
	update_filter_reload_status(gettext("Setting up SCRUB information"));
259
	$rules .= filter_generate_scrubing();
260
	$rules .= "\n";
261
	$rules .= "{$altq_queues}\n";
262
	$rules .= "{$natrules}\n";
263
	$rules .= "{$pfrules}\n";
264
	$rules .= discover_pkg_rules("filter");
265

    
266
	unset($aliases, $gateways, $altq_queues, $natrules, $pfrules);
267

    
268
	// Copy rules.debug to rules.debug.old
269
	if(file_exists("{$g['tmp_path']}/rules.debug"))
270
		@copy("{$g['tmp_path']}/rules.debug", "{$g['tmp_path']}/rules.debug.old");
271

    
272
	if (!@file_put_contents("{$g['tmp_path']}/rules.debug", $rules, LOCK_EX)) {
273
		log_error("WARNING: Could not write new rules!");
274
		unlock($filterlck);
275
		return;
276
	}
277

    
278
	@file_put_contents("{$g['tmp_path']}/rules.limits", $limitrules);
279
	mwexec("/sbin/pfctl -Of {$g['tmp_path']}/rules.limits");
280
	unset($rules, $limitrules);
281

    
282
	if(isset($config['system']['developerspew'])) {
283
		$mt = microtime();
284
		echo "pfctl being called at $mt\n";
285
	}
286
	unset($rules_loading, $rules_error);
287
	$_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug 2>&1", $rules_error, $rules_loading);
288
	if(isset($config['system']['developerspew'])) {
289
		$mt = microtime();
290
		echo "pfctl done at $mt\n";
291
	}
292
	/*
293
	 * check for a error while loading the rules file.	if an error has occurred
294
	 * then output the contents of the error to the caller
295
	 */
296
	if($rules_loading <> 0) {
297
		$saved_line_error = $rules_error[0];
298
		$line_error = explode(":", $rules_error[0]);
299
		$line_number = $line_error[1];
300
		$line_split = file("{$g['tmp_path']}/rules.debug");
301
		if(is_array($line_split))
302
			$line_error = sprintf(gettext('The line in question reads [%1$d]: %2$s'), $line_number, $line_split[$line_number-1]);
303
		unset($line_split);
304

    
305
		/* Brutal ugly hack but required -- PF is stuck, unwedge */
306
		if (strstr("$rules_error[0]", "busy")) {
307
			exec("/sbin/pfctl -d; /sbin/pfctl -e; /sbin/pfctl -f {$g['tmp_path']}/rules.debug");
308
			$error_msg = gettext("PF was wedged/busy and has been reset.");
309
			file_notice("pf_busy", $error_msg, "pf_busy", "");
310
		} else {
311
			$_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug.old 2>&1");
312
		}
313
		unset($rules_loading, $rules_error);
314

    
315
		if ($line_error and $line_number) {
316
			file_notice("filter_load", sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error), "Filter Reload", "");
317
			update_filter_reload_status(sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error));
318
			unlock($filterlck);
319
			return;
320
		}
321
	}
322

    
323
	# 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).
324
	if (!is_bogonsv6_used())
325
		$_grbg = exec("/sbin/pfctl -t bogonsv6 -T kill 2>/dev/null");
326

    
327
	update_filter_reload_status(gettext("Starting up layer7 daemon"));
328
	layer7_start_l7daemon();
329

    
330
	if(!empty($filterdns)) {
331
		@file_put_contents("{$g['varetc_path']}/filterdns.conf", implode("", $filterdns));
332
		unset($filterdns);
333
		if (isvalidpid("{$g['varrun_path']}/filterdns.pid"))
334
			sigkillbypid("{$g['varrun_path']}/filterdns.pid", "HUP");
335
		else {
336
			/*
337
			 * FilterDNS has three debugging levels. The default choosen is 1.
338
			 * Availabe are level 2 and greater then 2.
339
			 */
340
			if (isset($config['system']['aliasesresolveinterval']) && is_numeric($config['system']['aliasesresolveinterval']))
341
				$resolve_interval = $config['system']['aliasesresolveinterval'];
342
			else
343
				$resolve_interval = 300;
344
			mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns.pid -i {$resolve_interval} -c {$g['varetc_path']}/filterdns.conf -d 1");
345
		}
346
	} else {
347
		killbypid("{$g['varrun_path']}/filterdns.pid");
348
		@unlink("{$g['varrun_path']}/filterdns.pid");
349
	}
350

    
351
	/* run items scheduled for after filter configure run */
352
	$fda = fopen("{$g['tmp_path']}/commands.txt", "w");
353
	if($fda) {
354
		if($after_filter_configure_run) {
355
			foreach($after_filter_configure_run as $afcr)
356
				fwrite($fda, $afcr . "\n");
357
			unset($after_filter_configure_run);
358
		}
359

    
360
		/*
361
		 *      we need a way to let a user run a shell cmd after each
362
		 *      filter_configure() call.  run this xml command after
363
		 *      each change.
364
		 */
365
		if($config['system']['afterfilterchangeshellcmd'] <> "")
366
			fwrite($fda, $config['system']['afterfilterchangeshellcmd'] . "\n");
367

    
368
		fclose($fda);
369
	}
370

    
371
	if(file_exists("{$g['tmp_path']}/commands.txt")) {
372
		mwexec("sh {$g['tmp_path']}/commands.txt &");
373
		unlink("{$g['tmp_path']}/commands.txt");
374
	}
375

    
376
	/* if time based rules are enabled then swap in the set */
377
	if($time_based_rules == true)
378
		filter_tdr_install_cron(true);
379
	else
380
		filter_tdr_install_cron(false);
381

    
382
	if($g['booting'] == true)
383
		echo ".";
384

    
385
	if($delete_states_if_needed) {
386
		update_filter_reload_status(gettext("Processing down interface states"));
387
		filter_delete_states_for_down_gateways();
388
	}
389

    
390
	update_filter_reload_status(gettext("Running plugins"));
391

    
392
	if(is_dir("/usr/local/pkg/pf/")) {
393
		/* process packager manager custom rules */
394
		update_filter_reload_status(gettext("Running plugins (pf)"));
395
		run_plugins("/usr/local/pkg/pf/");
396
		update_filter_reload_status(gettext("Plugins completed."));
397
	}
398

    
399
	update_filter_reload_status(gettext("Done"));
400
	if($g['booting'] == true)
401
		echo gettext("done.") . "\n";
402

    
403
	unlock($filterlck);
404
	return 0;
405
}
406

    
407
function filter_generate_scrubing() {
408
	global $config, $FilterIflist;
409
	$scrubrules = "";
410

    
411
	if (isset($config['system']['maxmss_enable'])) {
412
		$maxmss = 1400;
413
		if (!empty($config['system']['maxmss']))
414
			$maxmss = $config['system']['maxmss'];
415

    
416
		$scrubrules .= "scrub from any to <vpn_networks> max-mss {$maxmss}\n";
417
	}
418
	/* disable scrub option */
419
	foreach ($FilterIflist as $scrubif => $scrubcfg) {
420
		if(isset($scrubcfg['virtual']) || empty($scrubcfg['descr']))
421
			continue;
422
		/* set up MSS clamping */
423
		if($scrubcfg['mss'] <> "" && is_numeric($scrubcfg['mss']) && $scrubcfg['if'] != "pppoe" && $scrubcfg['if'] != "pptp" &&
424
			$scrubif['if'] != "l2tp")
425
			$mssclamp = "max-mss " . (intval($scrubcfg['mss'] - 40));
426
		else
427
			$mssclamp = "";
428
		/* configure no-df for linux nfs and others */
429
		if($config['system']['scrubnodf'])
430
			$scrubnodf = "no-df";
431
		else
432
			$scrubnodf = "";
433
		if($config['system']['scrubrnid'])
434
			$scrubrnid = "random-id";
435
		else
436
			$scrubrnid = "";
437
		if(!isset($config['system']['disablescrub']))
438
			$scrubrules .= "scrub on \${$scrubcfg['descr']} all {$scrubnodf} {$scrubrnid} {$mssclamp} fragment reassemble\n"; // reassemble all directions
439
		else if(!empty($mssclamp))
440
			$scrubrules .= "scrub on \${$scrubcfg['descr']} {$mssclamp}\n";
441
	}
442
	return $scrubrules;
443
}
444

    
445
function filter_generate_nested_alias($name, $alias, &$aliasnesting, &$aliasaddrnesting) {
446
	global $aliastable, $filterdns;
447

    
448
	$addresses = explode(" ", $alias);
449
	$use_filterdns = false;
450
	$finallist = "";
451
	$builtlist = "";
452
	$urltable_nesting = "";
453
	$aliasnesting[$name] = $name;
454
	foreach ($addresses as $address) {
455
		if (empty($address))
456
			continue;
457
		$linelength = strlen($builtlist);
458
		$tmpline = "";
459
		if(is_alias($address)) {
460
			if (alias_get_type($address) == 'urltable') {
461
				// Feature#1603. For this type of alias we do not need to recursively call filter_generate_nested_alias. Just load IPs from the file.
462
				$urltable_netsting = alias_expand_urltable($address);
463
				if (!empty($urltable_nesting)) {
464
					$urlfile_as_arr = file($urltable_nesting);
465
					foreach($urlfile_as_arr as $line) {
466
						$address= rtrim($line);
467
						if ((strlen($tmpline) + $linelength) > 4036) {
468
							$finallist .= "{$tmpline} \\\n";
469
							$tmpline = "";
470
						}
471
						$tmpline .= " {$address}";
472
					}
473
				}
474
			}
475
			/* We already expanded this alias so there is no neccessity to do it again. */
476
			else if(!isset($aliasnesting[$address]))
477
				$tmpline = filter_generate_nested_alias($name, $aliastable[$address], $aliasnesting, $aliasaddrnesting);
478
		} else if(!isset($aliasaddrnesting[$address])) {
479
			if (!is_ipaddr($address) && !is_subnet($address) && !is_port($address) && !is_portrange($address) && is_hostname($address)) {
480
				if (!isset($filterdns["{$address}{$name}"])) {
481
					$use_filterdns = true;
482
					$filterdns["{$address}{$name}"] = "pf {$address} {$name}\n";
483
				}
484
				continue;
485
			}
486
			$aliasaddrnesting[$address] = $address;
487
			$tmpline = " {$address}";
488
		}
489
		if ((strlen($tmpline)+ $linelength) > 4036) {
490
			$finallist .= "{$builtlist} \\\n";
491
			$builtlist = "";
492
		}
493
		if (!empty($tmpline))
494
			$builtlist .= " {$tmpline}";
495
	}
496
	$finallist .= $builtlist;
497

    
498
	if ($use_filterdns === true && !empty($finallist)) {
499
		foreach (explode(" ", $finallist) as $address) {
500
			if (empty($address))
501
				continue;
502
			if ((is_ipaddr($address) || is_subnet($address)) && !isset($filterdns["{$address}{$name}"]))
503
				$filterdns["{$address}{$name}"] = "pf {$address} {$name}\n";
504
		}
505
		$finallist = '';
506
	}
507

    
508
	return $finallist;
509
}
510

    
511
function filter_expand_alias($alias_name)
512
{
513
	global $config;
514

    
515
	if(isset($config['aliases']['alias'])) {
516
		foreach ($config['aliases']['alias'] as $aliased) {
517
			if($aliased['name'] == $alias_name) {
518
				$aliasnesting = array();
519
				$aliasaddrnesting = array();
520
				return filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
521
			}
522
		}
523
	}
524
}
525

    
526
function filter_expand_alias_array($alias_name) {
527
	$expansion = filter_expand_alias($alias_name);
528
	return explode(" ", preg_replace('/\s+/', ' ', trim($expansion)));
529
}
530

    
531
function filter_generate_aliases() {
532
	global $config, $FilterIflist, $after_filter_configure_run;
533

    
534
	if(isset($config['system']['developerspew'])) {
535
		$mt = microtime();
536
		echo "filter_generate_aliases() being called $mt\n";
537
	}
538

    
539
	$alias = "#System aliases\n ";
540
	$aliases = "loopback = \"{ lo0 }\"\n";
541

    
542
	foreach ($FilterIflist as $if => $ifcfg) {
543
		if (is_array($ifcfg[0])) {
544
			if ($ifcfg[0]['if'] == 'pppoe') {
545
				$aliases .= "{$ifcfg[0]['descr']} = \"{ {$ifcfg[0]['if']}";
546
				$aliases .= " }\"\n";
547
			}
548
		} elseif (!empty($ifcfg['descr']) && !empty($ifcfg['if'])) {
549
			if ($ifcfg['type6'] == '6rd')
550
				$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
551
			else if ($ifcfg['type6'] == '6to4')
552
				$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
553
			else {
554
				$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']}";
555

    
556
				if ($ifcfg['type'] == 'pptp') {
557
					foreach (get_parent_interface($ifcfg['if']) as $parent_if) {
558
						if ($parent_if != $ifcfg['if']) {
559
							$aliases .= " {$parent_if}";
560
						}
561
					}
562
				}
563
			}
564
			$aliases .= " }\"\n";
565
		}
566
	}
567

    
568
	$aliases .= "\n#SSH Lockout Table\n";
569
	$aliases .= "table <sshlockout> persist\n";
570
	$aliases .= "table <webConfiguratorlockout> persist\n";
571

    
572
	$aliases .= "#Snort tables\n";
573
	$aliases .= "table <snort2c>\n";
574
	$aliases .= "table <virusprot>\n";
575
	if (!file_exists("/etc/bogons"))
576
		@file_put_contents("/etc/bogons", "");
577
	if (!file_exists("/etc/bogonsv6"))
578
		@file_put_contents("/etc/bogonsv6", "");
579
	$aliases .= "table <bogons> persist file \"/etc/bogons\"\n";
580
	if (is_bogonsv6_used())
581
		$aliases .= "table <bogonsv6> persist file \"/etc/bogonsv6\"\n";
582

    
583
	$vpns_list = filter_get_vpns_list();
584
	if($vpns_list)
585
		$aliases .= "table <vpn_networks> { $vpns_list }\n";
586

    
587
	/* add a Negate_networks table */
588
	$aliases .= "table <negate_networks> ";
589
	if($vpns_list)
590
		$aliases .= "{ $vpns_list }";
591
	$aliases .= "\n";
592

    
593
	$aliases .= "\n# User Aliases \n";
594
	/* Setup pf groups */
595
	if(isset($config['aliases']['alias'])) {
596
		foreach ($config['aliases']['alias'] as $aliased) {
597
			$extralias = "";
598
			/*
599
			 * XXX: i am not sure what this does so i am commenting it out for now, because as it is
600
			 * its quite dangerous!
601
			 * $ip = find_interface_ip($aliased['address']);
602
			 * $extraalias = " " . link_ip_to_carp_interface($ip);
603
			 */
604
			$aliasnesting = array();
605
			$aliasaddrnesting = array();
606
			$addrlist = filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
607
			switch ($aliased['type']) {
608
			case "host":
609
			case "network":
610
			case "url":
611
				$tableaddrs = "{$addrlist}{$extralias}";
612
				if(empty($tableaddrs)) {
613
					$aliases .= "table <{$aliased['name']}> persist\n";
614
					if (empty($aliased['address']))
615
						$after_filter_configure_run[] = "/sbin/pfctl -T flush -t " . escapeshellarg($aliased['name']);
616
				} else
617
					$aliases .= "table <{$aliased['name']}> { {$addrlist}{$extralias} } \n";
618

    
619
				$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
620
				break;
621
			case "openvpn":
622
				$openvpncfg = array();
623
				if($config['openvpn']['user']) {
624
					/* XXX: Check if we have a correct ip? */
625
					foreach ($config['openvpn']['user'] as $openvpn)
626
						$openvpncfg[$openvpn['name']] = $openvpn['ip'];
627
				}
628
				$vpn_lines = explode("\n", $addrlist);
629
				foreach ($vpn_lines as $vpn_line) {
630
					$vpn_address_split = explode(" ", $vpn_line);
631
					foreach($vpn_address_split as $vpnsplit) {
632
						if(isset($openvpncfg[$vpnsplit])) {
633
							$newaddress .= " ";
634
							$newaddress .= $openvpn[$vpnsplit];
635
							break;
636
						}
637
					}
638
				}
639
				$aliases .= "table <{$aliased['name']}> { {$newaddress}{$extralias} } \n";
640
				$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
641
				break;
642
			case "urltable":
643
				$urlfn = alias_expand_urltable($aliased['name']);
644
				if ($urlfn) {
645
					$aliases .= "table <{$aliased['name']}> persist file \"{$urlfn}\"\n";
646
					$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
647
				}
648
				break;
649
			case "urltable_ports":
650
				// TODO: Change it when pf supports tables with ports
651
				$urlfn = alias_expand_urltable($aliased['name']);
652
				if ($urlfn)
653
					$aliases .= "{$aliased['name']} = \"{ " . preg_replace("/\n/", " ", file_get_contents($urlfn)) . " }\"\n";
654
				break;
655
			case "port":
656
			case "url_ports":
657
				$aliases .= "{$aliased['name']} = \"{ {$addrlist} }\"\n";
658
				break;
659
			default:
660
				$aliases .= "{$aliased['name']} = \"{ {$aliased['address']}{$extralias} }\"\n";
661
				break;
662
			}
663
		}
664
	}
665
	$result = "{$alias} \n";
666
	$result .= "{$aliases}";
667

    
668
	return $result;
669
}
670

    
671
function filter_generate_gateways() {
672
	global $config, $g, $GatewaysList;
673

    
674
	$rules = "# Gateways\n";
675

    
676
	update_filter_reload_status(gettext("Creating gateway group item..."));
677

    
678
	/* Lookup Gateways to be used in filter rules once */
679
	$GatewaysList = return_gateways_array();
680
	$GatewayGroupsList = return_gateway_groups_array();
681

    
682
	if (is_array($GatewaysList)) {
683
		foreach ($GatewaysList as $gwname => $gateway) {
684
			$int = $gateway['interface'];
685
			$gwip = $gateway['gateway'];
686
			$route = "";
687
			if (!is_ipaddr($gwip))
688
				$gwip = get_interface_gateway($gateway['friendlyiface']);
689
			if (is_ipaddr($gwip) && !empty($int))
690
				$route = "route-to ( {$int} {$gwip} )";
691
			if (($route === "") && isset($config['system']['skip_rules_gw_down']))
692
				unset($GatewaysList[$gwname]);
693
			else
694
				$rules .= "GW{$gwname} = \" {$route} \"\n";
695
		}
696
	}
697

    
698
	if (is_array($GatewayGroupsList)) {
699
		foreach ($GatewayGroupsList as $gateway => $members) {
700
			$route = "";
701
			/* hey, that's not a group member! */
702
			unset($members['ipprotocol']);
703
			if (count($members) > 0) {
704
				$foundlb = 0;
705
				$routeto = "";
706
				foreach($members as $idx => $member) {
707
					$int = $member['int'];
708
					$gatewayip = $member['gwip'];
709
					if (($int <> "") && is_ipaddr($gatewayip)) {
710
						if ($g['debug'])
711
							log_error(sprintf(gettext('Setting up route with %1$s on %2$s'), $gatewayip, $int));
712
						if ($member['weight'] > 1) {
713
							$routeto .= str_repeat("( {$int} {$gatewayip} ) ", $member['weight']);
714
						} else
715
							$routeto .= "( {$int} {$gatewayip} ) ";
716
						$foundlb++;
717
					} else
718
						log_error(sprintf(gettext("An error occurred while trying to find the interface got %s .  The rule has not been added."), $gatewayip));
719
				}
720
				$route = "";
721
				if ($foundlb > 0) {
722
					$route = " route-to { {$routeto} } ";
723
					if($foundlb > 1) {
724
						$route .= " round-robin ";
725
						if (isset($config['system']['lb_use_sticky']))
726
							$route .= " sticky-address ";
727
					}
728
				}
729
			}
730
			if (($route === "") && isset($config['system']['skip_rules_gw_down']))
731
				unset($GatewayGroupsList[$gateway]);
732
			else
733
				$rules .= "GW{$gateway} = \" {$route} \"\n";
734
		}
735
	}
736

    
737
	/* Create a global array to avoid errors on rulesets. */
738
	$GatewaysList = $GatewaysList + $GatewayGroupsList;
739

    
740
	$rules .= "\n";
741

    
742
	return $rules;
743
}
744

    
745
/* returns space separated list of vpn subnets */
746
function filter_get_vpns_list() {
747
	global $config;
748

    
749
	$vpns = "";
750
	$vpns_arr = array();
751

    
752
	/* ipsec */
753
	if (isset($config['ipsec']['enable'])) {
754
		if (is_array($config['ipsec']['phase2'])) {
755
			foreach ($config['ipsec']['phase2'] as $ph2ent) {
756
				if ((!$ph2ent['mobile']) && ($ph2ent['mode'] != 'transport')) {
757
					if (!function_exists('ipsec_idinfo_to_cidr'))
758
						require_once("ipsec.inc");
759
					if (!is_array($ph2ent['remoteid']))
760
						continue;
761
					$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
762
					$vpns_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
763
					if ($vpns_subnet == "0.0.0.0/0")
764
						continue;
765
					$vpns_arr[] = $vpns_subnet;
766
				}
767
			}
768
		}
769
	}
770

    
771
	/* openvpn */
772
	foreach (array('client', 'server') as $type) {
773
		if(is_array($config['openvpn']["openvpn-$type"])) {
774
			foreach ($config['openvpn']["openvpn-$type"] as $settings) {
775
				if(is_array($settings)) {
776
					if (!isset($settings['disable'])) {
777
						$remote_networks = explode(',', $settings['remote_network']);
778
						foreach ($remote_networks as $remote_network) {
779
							if (is_subnet($remote_network) && ($remote_network <> "0.0.0.0/0"))
780
								$vpns_arr[] = $remote_network;
781
						}
782
						if (is_subnet($settings['tunnel_network']) && $settings['tunnel_network'] <> "0.0.0.0/0")
783
							$vpns_arr[] = $settings['tunnel_network'];
784
					}
785
				}
786
			}
787
		}
788
	}
789
	/* pppoe */
790
	if (is_array($config['pppoes']['pppoe'])) {
791
		foreach($config['pppoes']['pppoe'] as $pppoe) {
792
			if ($pppoe['mode'] == "server") {
793
				if(is_ipaddr($pppoe['remoteip'])) {
794
					$pppoesub = gen_subnet($pppoe['remoteip'], $pppoe['pppoe_subnet']);
795
					if (is_subnet($pppoesub))
796
						$vpns_arr[] = $pppoesub;
797
				}
798
			}
799
		}
800
	}
801

    
802
	if (!empty($vpns_arr))
803
		$vpns = implode(" ", $vpns_arr);
804

    
805
	return $vpns;
806
}
807

    
808
/* returns space separated list of directly connected networks
809
 * optionally returns an array instead, including friendly interface and gateway (if applicable)
810
 */
811
function filter_get_direct_networks_list($returnsubnetsonly = true) {
812
	global $config, $FilterIflist, $GatewaysList;
813
	/* build list of directly connected interfaces and networks */
814
	$networks = "";
815
	$networks_arr = array();
816
	if(empty($FilterIflist)) {
817
		filter_generate_optcfg_array();
818
	}
819
	foreach ($FilterIflist as $ifent => $ifcfg) {
820
		$subnet = "{$ifcfg['sa']}/{$ifcfg['sn']}";
821
		if(is_subnet($subnet)) {
822
			if($returnsubnetsonly) {
823
				$networks_arr[] = $subnet;
824
			} else {
825
				$networks_arr[] = array(
826
					'subnet' => $subnet,
827
					'if' => $ifent,
828
					'ip' => $ifcfg['ip']);
829
			}
830
		}
831
	}
832
	foreach(get_configured_ip_aliases_list(true) as $vip) {
833
		$subnet = "{$vip['subnet']}/{$vip['subnet_bits']}";
834
		if(is_subnet($subnet) && !(is_subnetv4($subnet) && $vip['subnet_bits'] == 32) && !(is_subnetv6($subnet) && $vip['subnet_bits'] == 128)) {
835
			if(is_subnetv4($subnet))
836
				$subnet = gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
837
			else if(is_subnetv6($subnet))
838
				$subnet = gen_subnetv6($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
839
			if($returnsubnetsonly) {
840
				$networks_arr[] = $subnet;
841
			} else {
842
				$networks_arr[] = array(
843
					'subnet' => $subnet,
844
					'if' => $vip['interface'],
845
					'ip' => $vip['subnet']);
846
			}
847
		}
848
	}
849
	foreach(get_staticroutes() as $netent) {
850
		if(is_subnet($netent['network'])) {
851
			if($returnsubnetsonly) {
852
				$networks_arr[] = $netent['network'];
853
			} else if(isset($GatewaysList[$netent['gateway']])) {
854
				$networks_arr[] = array(
855
					'subnet' => $netent['network'],
856
					'if' => $GatewaysList[$netent['gateway']]['friendlyiface'],
857
					'gateway' => $GatewaysList[$netent['gateway']]['gateway']);
858
			}
859
		}
860
	}
861
	if($returnsubnetsonly) {
862
		if(!empty($networks_arr)) {
863
			$networks = implode(" ", $networks_arr);
864
		}
865
		return $networks;
866
	} else {
867
		return $networks_arr;
868
	}
869
}
870

    
871
function filter_generate_optcfg_array() {
872
	global $config, $FilterIflist;
873
	if(isset($config['system']['developerspew'])) {
874
		$mt = microtime();
875
		echo "filter_generate_optcfg_array() being called $mt\n";
876
	}
877

    
878
	read_layer7_config();
879
	/* if list */
880
	$iflist = get_configured_interface_with_descr();
881
	foreach ($iflist as $if => $ifdetail) {
882
		$oc = $config['interfaces'][$if];
883
		$oic = array();
884
		$oic['if'] = get_real_interface($if);
885
		if (!does_interface_exist($oic['if']))
886
			continue;
887
		$oic['ifv6'] = get_real_interface($if, "inet6");
888
		$oic['ip'] = get_interface_ip($if);
889
		$oic['ipv6'] = get_interface_ipv6($if);
890
		if(!is_ipaddrv4($oc['ipaddr']) && !empty($oc['ipaddr']))
891
			$oic['type'] = $oc['ipaddr'];
892
		if(!is_ipaddrv6($oc['ipaddrv6']) && !empty($oc['ipaddrv6']))
893
			$oic['type6'] = $oc['ipaddrv6'];
894
		if (!empty($oc['track6-interface']))
895
			$oic['track6-interface'] = $oc['track6-interface'];
896
		$oic['sn'] = get_interface_subnet($if);
897
		$oic['snv6'] = get_interface_subnetv6($if);
898
		$oic['mtu'] = empty($oc['mtu']) ? 1500 : $oc['mtu'];
899
		$oic['mss'] = empty($oc['mss']) ? '' : $oc['mss'];
900
		$oic['descr'] = $ifdetail;
901
		$oic['sa'] = gen_subnet($oic['ip'], $oic['sn']);
902
		$oic['sav6'] = gen_subnetv6($oic['ipv6'], $oic['snv6']);
903
		$oic['nonat'] = $oc['nonat'];
904
		$oic['alias-address'] = $oc['alias-address'];
905
		$oic['alias-subnet'] = $oc['alias-subnet'];
906
		$oic['gateway'] = $oc['gateway'];
907
		$oic['gatewayv6'] = $oc['gatewayv6'];
908
		$oic['spoofcheck'] = "yes";
909
		$oic['bridge'] = link_interface_to_bridge($if);
910
		$vips = link_interface_to_vips($if);
911
		if (!empty($vips)) {
912
			foreach ($vips as $vipidx => $vip) {
913
				if (is_ipaddrv4($vip['subnet'])) {
914
					if (!is_array($oic['vips']))
915
						$oic['vips'] = array();
916
					$oic['vips'][$vipidx]['ip'] = $vip['subnet'];
917
					if (empty($vip['subnet_bits']))
918
						$oic['vips'][$vipidx]['sn'] = 32;
919
					else
920
						$oic['vips'][$vipidx]['sn'] = $vip['subnet_bits'];
921
				} else if (is_ipaddrv6($vip['subnet'])) {
922
					if (!is_array($oic['vips6']))
923
						$oic['vips6'] = array();
924
					$oic['vips6'][$vipidx]['ip'] = $vip['subnet'];
925
					if (empty($vip['subnet_bits']))
926
						$oic['vips6'][$vipidx]['sn'] = 128;
927
					else
928
						$oic['vips6'][$vipidx]['sn'] = $vip['subnet_bits'];
929
				}
930
			}
931
		}
932
		unset($vips);
933
		$FilterIflist[$if] = $oic;
934
	}
935

    
936
	if($config['pptpd']['mode'] == "server" || $config['pptpd']['mode'] == "redir") {
937
		$oic = array();
938
		$oic['if'] = 'pptp';
939
		$oic['descr'] = 'pptp';
940
		$oic['ip'] = $config['pptpd']['localip'];
941
		$oic['sa'] = $config['pptpd']['remoteip'];
942
		$oic['mode'] = $config['pptpd']['mode'];
943
		$oic['virtual'] = true;
944
		if($config['pptpd']['pptp_subnet'] <> "")
945
			$oic['sn'] = $config['pptpd']['pptp_subnet'];
946
		else
947
			$oic['sn'] = "32";
948
		$FilterIflist['pptp'] = $oic;
949
	}
950
	if($config['l2tp']['mode'] == "server") {
951
		$oic = array();
952
		$oic['if'] = 'l2tp';
953
		$oic['descr'] = 'L2TP';
954
		$oic['ip'] = $config['l2tp']['localip'];
955
		$oic['sa'] = $config['l2tp']['remoteip'];
956
		if($config['l2tp']['l2tp_subnet'] <> "")
957
			$oic['sn'] = $config['l2tp']['l2tp_subnet'];
958
		else
959
			$oic['sn'] = "32";
960
		$oic['mode'] = $config['l2tp']['mode'];
961
		$oic['virtual'] = true;
962
		$FilterIflist['l2tp'] = $oic;
963
	}
964
	if (is_array($config['pppoes']['pppoe']) && (count($config['pppoes']['pppoe']) > 0)) {
965
		$pppoeifs = array();
966
		foreach($config['pppoes']['pppoe'] as $pppoe) {
967
			if ($pppoe['mode'] == "server") {
968
				$oic = array();
969
				$oic['if'] = 'pppoe';
970
				$oic['descr'] = 'pppoe';
971
				$oic['ip'] = $pppoe['localip'];
972
				$oic['sa'] = $pppoe['remoteip'];
973
				$oic['mode'] = $pppoe['mode'];
974
				$oic['virtual'] = true;
975
				if($pppoe['pppoe_subnet'] <> "")
976
					$oic['sn'] = $pppoe['pppoe_subnet'];
977
				else
978
					$oic['sn'] = "32";
979
				$pppoeifs[] = $oic;
980
			}
981
		}
982
		if (count($pppoeifs))
983
			$FilterIflist['pppoe'] = $pppoeifs;
984
	}
985
	/* add ipsec interfaces */
986
	if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
987
		$oic = array();
988
		$oic['if'] = 'enc0';
989
		$oic['descr'] = 'IPsec';
990
		$oic['type'] = "none";
991
		$oic['virtual'] = true;
992
		$FilterIflist['enc0'] = $oic;
993
	}
994
	/* add openvpn interfaces */
995
	if($config['openvpn']['openvpn-server'] || $config['openvpn']['openvpn-client']) {
996
		$oic = array();
997
		$oic['if'] = "openvpn";
998
		$oic['descr'] = 'OpenVPN';
999
		$oic['type'] = "none";
1000
		$oic['virtual'] = true;
1001
		$FilterIflist['openvpn'] = $oic;
1002
	}
1003
	/* add interface groups */
1004
	if(is_array($config['ifgroups']['ifgroupentry'])) {
1005
		foreach($config['ifgroups']['ifgroupentry'] as $ifgen) {
1006
			$oc = array();
1007
			$oc['if'] = $ifgen['ifname'];
1008
			$oc['descr'] = $ifgen['ifname'];
1009
			$oc['virtual'] = true;
1010
			$FilterIflist[$ifgen['ifname']] = $oc;
1011
		}
1012
	}
1013
}
1014

    
1015
function filter_flush_nat_table() {
1016
	global $config, $g;
1017
	if(isset($config['system']['developerspew'])) {
1018
		$mt = microtime();
1019
		echo "filter_flush_nat_table() being called $mt\n";
1020
	}
1021
	return mwexec("/sbin/pfctl -F nat");
1022
}
1023

    
1024
function filter_flush_state_table() {
1025
	return mwexec("/sbin/pfctl -F state");
1026
}
1027

    
1028
function filter_get_reflection_interfaces($natif = "") {
1029
	global $FilterIflist;
1030

    
1031
	$nat_if_list = array();
1032

    
1033
	foreach ($FilterIflist as $ifent => $ifname) {
1034
		if($ifname['if'] == $natif)
1035
			continue;
1036

    
1037
		/* Do not add reflection redirects for interfaces with gateways */
1038
		if(interface_has_gateway($ifent))
1039
			continue;
1040

    
1041
		$nat_if_list[] = $ifname['if'];
1042
	}
1043

    
1044
	return $nat_if_list;
1045
}
1046

    
1047
function filter_generate_reflection_nat($rule, &$route_table, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = "") {
1048
	global $config, $FilterIflist;
1049

    
1050
	if(!isset($config['system']['enablenatreflectionhelper']))
1051
		return "";
1052

    
1053
	// Initialize natrules holder string
1054
	$natrules = "";
1055

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

    
1058
	/* TODO: Add this option to port forwards page. */
1059
	if(isset($rule['staticnatport'])) {
1060
		$static_port = " static-port";
1061
	} else {
1062
		$static_port = " port 1024:65535";
1063
	}
1064

    
1065
	if(!empty($protocol)) {
1066
		$protocol_text = " proto {$protocol}";
1067
	} else {
1068
		$protocol_text = "";
1069
	}
1070

    
1071
	if(empty($target_subnet) || !is_numeric($target_subnet))
1072
		$target_subnet = 32;
1073

    
1074
	if(!is_array($route_table)) {
1075
		/* get a simulated IPv4-only route table based on the config */
1076
		$route_table = filter_get_direct_networks_list(false);
1077
		foreach($route_table as $rt_key => $rt_ent) {
1078
			if(!is_subnetv4($rt_ent['subnet']))
1079
				unset($route_table[$rt_key]);
1080
			if(isset($route_table[$rt_key]) && isset($FilterIflist[$rt_ent['if']]['if']))
1081
				$route_table[$rt_key]['if'] = $FilterIflist[$rt_ent['if']]['if'];
1082
		}
1083
	}
1084

    
1085
	/* Check if the target is accessed through a static route */
1086
	foreach($route_table as $route) {
1087
		if(isset($route['gateway']) && is_ipaddr($route['gateway'])) {
1088
			$subnet_split = explode("/", $route['subnet']);
1089
			if(in_array($route['if'], $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
1090
				$target_ip = $route['gateway'];
1091
				$target_subnet = 32;
1092
				break;
1093
			}
1094
		}
1095
	}
1096

    
1097
	/* Search for matching subnets in the routing table */
1098
	foreach($route_table as $route) {
1099
		$subnet = $route['subnet'];
1100
		$subnet_split = explode("/", $subnet);
1101
		$subnet_if = $route['if'];
1102
		if(in_array($subnet_if, $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
1103
			$ifsubnet_ip = "";
1104
			/* Find interface IP to use for NAT */
1105
			foreach ($route_table as $ifnetwork) {
1106
				if(isset($ifnetwork['ip']) && is_ipaddr($ifnetwork['ip']) && $ifnetwork['if'] == $subnet_if && ip_in_subnet($ifnetwork['ip'], $subnet)) {
1107
					$ifsubnet_ip = $ifnetwork['ip'];
1108
					break;
1109
				}
1110
			}
1111
			if(!empty($ifsubnet_ip)) {
1112
				$subnets = array($subnet);
1113
				/* Find static routes that also need to be referenced in the NAT rule */
1114
				foreach($route_table as $rtentry) {
1115
					if(isset($rtentry['gateway']) && is_ipaddr($rtentry['gateway']) && $rtentry['if'] == $subnet_if && ip_in_subnet($rtentry['gateway'], $subnet))
1116
						$subnets[] = $rtentry['subnet'];
1117
				}
1118
				if(count($subnets) > 1)
1119
					$subnet = "{ " . implode(" ", $subnets) . " }";
1120
				$natrules .= "no nat on {$subnet_if}{$protocol_text} from {$subnet_if} to {$target}\n";
1121
				$natrules .= "nat on {$subnet_if}{$protocol_text} from {$subnet} to {$target} -> {$ifsubnet_ip}{$static_port}\n";
1122
			}
1123
		}
1124
	}
1125

    
1126
	if(!empty($natrules))
1127
		$natrules .= "\n";
1128

    
1129
	return $natrules;
1130
}
1131

    
1132
function filter_generate_reflection_proxy($rule, $nordr, $rdr_ifs, $srcaddr, $dstaddr_port, &$starting_localhost_port, &$reflection_txt) {
1133
	global $FilterIflist, $config;
1134

    
1135
	// Initialize natrules holder string
1136
	$natrules = "";
1137
	$reflection_txt = array();
1138

    
1139
	if(!empty($rdr_ifs)) {
1140
		if($config['system']['reflectiontimeout'])
1141
			$reflectiontimeout = $config['system']['reflectiontimeout'];
1142
		else
1143
			$reflectiontimeout = "2000";
1144

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

    
1147
		$rdr_if_list = implode(" ", $rdr_ifs);
1148
		if(count($rdr_ifs) > 1)
1149
			$rdr_if_list = "{ {$rdr_if_list} }";
1150

    
1151
		$natrules .= "\n# Reflection redirects\n";
1152

    
1153
		$localport = $rule['local-port'];
1154
		if(!empty($localport) && is_alias($localport)) {
1155
			$localport = filter_expand_alias($localport);
1156
			$localport = explode(" ", trim($localport));
1157
			// The translation port for rdr, when specified, does not support more than one port or range.
1158
			// Emulating for behavior consistent with the original port forward.
1159
			$localport = $localport[0];
1160
		}
1161

    
1162
		if(is_alias($rule['destination']['port'])) {
1163
			if(empty($localport) || $rule['destination']['port'] == $rule['local-port']) {
1164
				$dstport = filter_expand_alias($rule['destination']['port']);
1165
				$dstport = array_filter(explode(" ", trim($dstport)));
1166
				$localport = "";
1167
			} else if(!empty($localport)) {
1168
				$dstport = array($localport);
1169
			}
1170
		} else {
1171
			$dstport = array(str_replace("-", ":", $rule['destination']['port']));
1172
			$dstport_split = explode(":", $dstport[0]);
1173

    
1174
			if(!empty($localport) && $dstport_split[0] != $rule['local-port']) {
1175
				if(!is_alias($rule['local-port']) && $dstport_split[1] && $dstport_split[0] != $dstport_split[1]) {
1176
					$localendport = $localport + ($dstport_split[1] - $dstport_split[0]);
1177
					$localport .= ":$localendport";
1178
				}
1179

    
1180
				$dstport = array($localport);
1181
			} else
1182
				$localport = "";
1183
		}
1184

    
1185
		$dstaddr = explode(" ", $dstaddr_port);
1186
		if($dstaddr[2]) {
1187
			$rflctintrange = array_pop($dstaddr);
1188
			array_pop($dstaddr);
1189
		} else
1190
			return "";
1191
		$dstaddr = implode(" ", $dstaddr);
1192
		if(empty($dstaddr) || trim($dstaddr) == "0.0.0.0" || strtolower(trim($dstaddr)) == "port")
1193
			return "";
1194

    
1195
		if(isset($rule['destination']['any'])) {
1196
			if(!$rule['interface'])
1197
				$natif = "wan";
1198
			else
1199
				$natif = $rule['interface'];
1200

    
1201
			if(!isset($FilterIflist[$natif]))
1202
				return "";
1203
			if(is_ipaddr($FilterIflist[$natif]['ip']))
1204
				$dstaddr = $FilterIflist[$natif]['ip'];
1205
			else
1206
				return "";
1207

    
1208
			if(!empty($FilterIflist[$natif]['sn']))
1209
				$dstaddr = gen_subnet($dstaddr, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
1210
		}
1211

    
1212
		switch($rule['protocol']) {
1213
		case "tcp/udp":
1214
			$protocol = "{ tcp udp }";
1215
			$reflect_protos = array('tcp', 'udp');
1216
			break;
1217
		case "tcp":
1218
		case "udp":
1219
			$protocol = $rule['protocol'];
1220
			$reflect_protos = array($rule['protocol']);
1221
			break;
1222
		default:
1223
			return "";
1224
			break;
1225
		}
1226

    
1227
		if(!empty($nordr)) {
1228
			$natrules .= "no rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange}\n";
1229
			return $natrules;
1230
		}
1231

    
1232
		if (is_alias($rule['target']))
1233
			$target = filter_expand_alias($rule['target']);
1234
		else if(is_ipaddr($rule['target']))
1235
			$target = $rule['target'];
1236
		else if (is_ipaddr($FilterIflist[$rule['target']]['ip']))
1237
			$target = $FilterIflist[$rule['target']]['ip'];
1238
		else
1239
			return "";
1240
		$starting_localhost_port_tmp = $starting_localhost_port;
1241
		$toomanyports = false;
1242
		/* only install reflection rules for < 19991 items */
1243
		foreach($dstport as $loc_pt) {
1244
			if($starting_localhost_port < 19991) {
1245
				$toadd_array = array();
1246
				$inetdport = $starting_localhost_port;
1247
				$rflctrange = $starting_localhost_port;
1248

    
1249
				$loc_pt = explode(":", $loc_pt);
1250
				if($loc_pt[1] && $loc_pt[1] > $loc_pt[0])
1251
					$delta = $loc_pt[1] - $loc_pt[0];
1252
				else
1253
					$delta = 0;
1254

    
1255
				if(($inetdport + $delta + 1) - $starting_localhost_port_tmp > 500) {
1256
					log_error("Not installing NAT reflection rules for a port range > 500");
1257
					$inetdport = $starting_localhost_port;
1258
					$toadd_array = array();
1259
					$toomanyports = true;
1260
					break;
1261
				} else if(($inetdport + $delta) > 19990) {
1262
					log_error("Installing partial NAT reflection rules. Maximum 1,000 reached.");
1263
					$delta = 19990 - $inetdport;
1264
					$loc_pt[1] = $loc_pt[0] + $delta;
1265
					if($delta == 0)
1266
						unset($loc_pt[1]);
1267
					$toomanyports = true;
1268

    
1269
					if(!empty($localport)) {
1270
						if(is_alias($rule['destination']['port'])) {
1271
							$rflctintrange = alias_expand($rule['destination']['port']);
1272
						} else {
1273
							if($dstport_split[1])
1274
								$dstport_split[1] = $dstport_split[0] + $inetdport + $delta - $starting_localhost_port;
1275
							$rflctintrange = implode(":", $dstport_split);
1276
						}
1277
					}
1278
				}
1279

    
1280
				if(empty($localport))
1281
					$rflctintrange = implode(":", $loc_pt);
1282
				if($inetdport + $delta > $starting_localhost_port)
1283
					$rflctrange .= ":" . ($inetdport + $delta);
1284
				$starting_localhost_port = $inetdport + $delta + 1;
1285
				$toadd_array = array_merge($toadd_array, range($loc_pt[0], $loc_pt[0] + $delta));
1286

    
1287
				if(!empty($toadd_array)) {
1288
					$rtarget = explode(" ", trim($target));
1289
					foreach($toadd_array as $tda) {
1290
						if (empty($tda))
1291
							continue;
1292
						foreach($reflect_protos as $reflect_proto) {
1293
							if($reflect_proto == "udp") {
1294
								$socktype = "dgram";
1295
								$dash_u = "-u ";
1296
								$wait = "wait\t";
1297
							} else {
1298
								$socktype = "stream";
1299
								$dash_u = "";
1300
								$wait = "nowait/0";
1301
							}
1302
							foreach ($rtarget as $targip) {
1303
								if (empty($targip))
1304
									continue;
1305
								$reflection_txt[] = "{$inetdport}\t{$socktype}\t{$reflect_proto}\t{$wait}\tnobody\t/usr/bin/nc\tnc {$dash_u}-w {$reflectiontimeout} {$targip} {$tda}\n";
1306
							}
1307
						}
1308
						$inetdport++;
1309
					}
1310
					$natrules .= "rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange} tag PFREFLECT -> 127.0.0.1 port {$rflctrange}\n";
1311
				}
1312
			}
1313

    
1314
			if($toomanyports)
1315
				break;
1316
		}
1317

    
1318
		$reflection_txt = array_unique($reflection_txt);
1319
	}
1320

    
1321
	return $natrules;
1322
}
1323

    
1324
function filter_nat_rules_automatic_tonathosts($with_descr = false) {
1325
	global $config, $FilterIflist, $GatewaysList;
1326

    
1327
	$tonathosts = array("127.0.0.0/8");
1328
	$descriptions = array(gettext("localhost"));
1329

    
1330
	foreach (get_staticroutes() as $route) {
1331
		$netip = explode("/", $route['network']);
1332
		if (isset($GatewaysList[$route['gateway']])) {
1333
			$gateway =& $GatewaysList[$route['gateway']];
1334
			if(!interface_has_gateway($gateway['interface']) && is_private_ip($netip[0])) {
1335
				$tonathosts[] = $route['network'];
1336
				$descriptions[] = gettext("static route");
1337
			}
1338
		}
1339
	}
1340

    
1341
	/* create outbound nat entries for all local networks */
1342
	foreach($FilterIflist as $ocname => $oc) {
1343
		if(interface_has_gateway($ocname))
1344
			continue;
1345
		if(is_ipaddr($oc['alias-address'])) {
1346
			$tonathosts[] = "{$oc['alias-address']}/{$oc['alias-subnet']}";
1347
			$descriptions[] = $oc['descr'] . " " . gettext("DHCP alias address");
1348
		}
1349
		if($oc['sa']) {
1350
			$tonathosts[] = "{$oc['sa']}/{$oc['sn']}";
1351
			$descriptions[] = $oc['descr'];
1352
			if (isset($oc['vips']) && is_array($oc['vips'])) {
1353
				$if_subnets = array("{$oc['sa']}/{$oc['sn']}");
1354
				foreach ($oc['vips'] as $vip) {
1355
					if (!is_ipaddrv4($vip['ip']))
1356
						continue;
1357

    
1358
					foreach ($if_subnets as $subnet)
1359
						if (ip_in_subnet($vip['ip'], $subnet))
1360
							continue 2;
1361

    
1362
					$network = gen_subnet($vip['ip'], $vip['sn']);
1363
					array_unshift($tonathosts, $network . '/' . $vip['sn']);
1364
					array_unshift($descriptions, "Virtual IP ({$oc['descr']})");
1365
					$if_subnets[] = $network . '/' . $vip['sn'];
1366
					unset($network);
1367
				}
1368
				unset($if_subnets);
1369
			}
1370
		}
1371
	}
1372

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1475
	return $rules;
1476
}
1477

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1657
		}
1658
	}
1659

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2022
	return $natrules;
2023
}
2024

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

    
2037
	return $ret;
2038
}
2039

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

    
2042
	$src = "";
2043

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

    
2071
	return $src;
2072
}
2073

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

    
2077
	$if_subnets = array($subnets);
2078

    
2079
	if ($not == true)
2080
		$subnets = "!{$subnets}";
2081

    
2082
	if (!isset($FilterIflist[$if]['vips']) || !is_array($FilterIflist[$if]['vips']))
2083
		return;
2084

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

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

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

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

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

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

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

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

    
2258
	$src .= filter_generate_port($rule, $target, $isnat);
2259

    
2260
	return $src;
2261
}
2262

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2641
	unset($aline);
2642

    
2643
	return $line;
2644
}
2645

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

    
2649
	$fix_rule_label = 'fix_rule_label';
2650
	$increment_tracker = 'filter_rule_tracker';
2651

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

    
2658
	$pptpdcfg = $config['pptpd'];
2659

    
2660
	$ipfrules = "";
2661
	$ipfrules .= discover_pkg_rules("pfearly");
2662

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

    
2677
	$saved_tracker = $tracker;
2678

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

    
2685
	$saved_tracker += 100;
2686
	$tracker = $saved_tracker;
2687

    
2688
	$ipfrules .= <<<EOD
2689
# block IPv4 link-local. Per RFC 3927, link local "MUST NOT" be forwarded by a routing device,
2690
# and clients "MUST NOT" send such packets to a router. FreeBSD won't route 169.254./16, but
2691
# route-to can override that, causing problems such as in redmine #2073
2692
block in {$log['block']} quick from 169.254.0.0/16 to any
2693
block in {$log['block']} quick from any to 169.254.0.0/16 
2694
#---------------------------------------------------------------------------
2695
# default deny rules
2696
#---------------------------------------------------------------------------
2697
block in {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2698
block out {$log['block']} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
2699
block in {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2700
block out {$log['block']} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
2701

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

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

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

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

    
2731
EOD;
2732

    
2733
	$saved_tracker += 100;
2734
	$tracker = $saved_tracker;
2735

    
2736
	$ipfrules .= filter_process_carp_rules($log);
2737

    
2738
	$saved_tracker += 100;
2739
	$tracker = $saved_tracker;
2740

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

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

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

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

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

    
2779
	$saved_tracker += 100;
2780
	$tracker = $saved_tracker;
2781

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

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

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

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

    
2847
EOD;
2848

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

    
2855
EOD;
2856
			}
2857
		}
2858

    
2859

    
2860
		$saved_tracker += 10;
2861
		$tracker = $saved_tracker;
2862

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

    
2870
EOD;
2871
		}
2872

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

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

    
2886
		if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
2887
			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
2888

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

    
2895
		$saved_tracker += 10;
2896
		$tracker = $saved_tracker;
2897

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

    
2909
EOD;
2910
			}
2911
		}
2912

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

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

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

    
2932
EOD;
2933

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

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

    
2952
EOD;
2953
				}
2954

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

    
2961
EOD;
2962
				}
2963

    
2964
			}
2965
			break;
2966
		}
2967

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

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

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

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

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

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

    
3022
EOD;
3023
				}
3024
			}
3025
			break;
3026
		}
3027
	}
3028

    
3029
	$saved_tracker += 10;
3030
	$tracker = $saved_tracker;
3031

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

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

    
3048
EOD;
3049

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

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

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

    
3080

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

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

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

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

    
3109
EOD;
3110
		}
3111
		unset($alports);
3112
	}
3113

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

    
3128
EOD;
3129

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

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

    
3148
EOD;
3149
				break;
3150
			}
3151
		}
3152
	}
3153

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

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

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

    
3225
	$saved_tracker += 100;
3226
	$tracker = $saved_tracker;
3227

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

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

    
3265
EOD;
3266
				}
3267
			}
3268
		}
3269
	}
3270

    
3271
	update_filter_reload_status(gettext("Creating IPsec rules..."));
3272
	$saved_tracker += 100000;
3273
	$tracker = $saved_tracker;
3274
	$ipfrules .= filter_generate_ipsec_rules($log);
3275

    
3276
	$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
3277

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

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

    
3299
EOD;
3300
					}
3301
				}
3302
			}
3303
		}
3304
	}
3305

    
3306

    
3307
	return $ipfrules;
3308
}
3309

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

    
3319
	return $ipfrules;
3320
}
3321

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

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

    
3340
	if($g['booting']==true)
3341
		return;
3342

    
3343
	if (!is_array($config['cron']))
3344
		$config['cron'] = array();
3345
	if (!is_array($config['cron']['item']))
3346
		$config['cron']['item'] = array();
3347

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

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

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

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

    
3437
		if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
3438
			return true;
3439
	}
3440

    
3441
	return false;
3442
}
3443

    
3444
function filter_tdr_day($schedule) {
3445
	global $g;
3446

    
3447
	if($g['debug'])
3448
		log_error("[TDR DEBUG] filter_tdr_day($schedule)");
3449

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

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

    
3477
function filter_tdr_position($schedule) {
3478
	global $g;
3479

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

    
3500
function filter_tdr_month($schedule) {
3501
	global $g;
3502

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

    
3517
function filter_setup_logging_interfaces() {
3518
	global $config, $FilterIflist;
3519

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

    
3530
	return $rules;
3531
}
3532

    
3533
function filter_process_carp_rules($log) {
3534
	global $g, $config, $tracker;
3535

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

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

    
3551
/* Generate IPsec Filter Items */
3552
function filter_generate_ipsec_rules($log = array()) {
3553
	global $config, $g, $FilterIflist, $tracker;
3554

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

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

    
3563
	$increment_tracker = 'filter_rule_tracker';
3564

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

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

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

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

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

    
3629
				$route_to = " route-to ( $interface $gateway ) ";
3630
				$reply_to = " reply-to ( $interface $gateway ) ";
3631

    
3632
			}
3633
			if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
3634
				$gateway = get_interface_gateway_v6($parentinterface);
3635
				$interface = $FilterIflist[$parentinterface]['if'];
3636

    
3637
				$route_to = " route-to ( $interface $gateway ) ";
3638
				$reply_to = " reply-to ( $interface $gateway ) ";
3639
			}
3640

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

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

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

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

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

    
3675
EOD;
3676
			}
3677
		}
3678

    
3679
	}
3680
	return($ipfrules);
3681
}
3682

    
3683
function discover_pkg_rules($ruletype) {
3684
	global $config, $g, $aliases;
3685

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

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

    
3715
function filter_get_antilockout_ports($wantarray = false) {
3716
	global $config;
3717

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

    
3723
	if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
3724
		$lockoutports[] = "80";
3725

    
3726
	if (isset($config['system']['enablesshd']))
3727
		$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
3728

    
3729
	if ($wantarray)
3730
		return $lockoutports;
3731
	else
3732
		return implode(" ", $lockoutports);
3733

    
3734
}
3735

    
3736
?>
(19-19/68)