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/sysctl /sbin/kldload /usr/sbin/tcpdump /sbin/pfctl /bin/rm
|
37
|
pfSense_BUILDER_BINARIES: /usr/sbin/inetd
|
38
|
pfSense_MODULE: filter
|
39
|
*/
|
40
|
|
41
|
/* DISABLE_PHP_LINT_CHECKING */
|
42
|
|
43
|
/* holds the items that will be executed *AFTER* the filter is fully loaded */
|
44
|
$after_filter_configure_run = array();
|
45
|
|
46
|
/* For installing cron job of schedules */
|
47
|
$time_based_rules = false;
|
48
|
|
49
|
/* Used to hold the interface list that will be used on ruleset creation. */
|
50
|
$FilterIflist = array();
|
51
|
|
52
|
/* Create a global array to avoid errors on rulesets. */
|
53
|
$GatewaysList = array();
|
54
|
|
55
|
/* Used for the hostname dns resolver */
|
56
|
$filterdns = array();
|
57
|
|
58
|
/* Used for aliases and interface macros */
|
59
|
$aliases = "";
|
60
|
|
61
|
global $tracker;
|
62
|
$tracker = 1000000000;
|
63
|
|
64
|
function filter_rule_tracker($tracker) {
|
65
|
global $tracker;
|
66
|
|
67
|
return (++$tracker);
|
68
|
|
69
|
}
|
70
|
|
71
|
function fix_rule_label($descr) {
|
72
|
$descr = str_replace('"', '', $descr);
|
73
|
if (strlen($descr) > 63)
|
74
|
return substr($descr, 0, 60) . "...";
|
75
|
else
|
76
|
return $descr;
|
77
|
}
|
78
|
|
79
|
function is_bogonsv6_used() {
|
80
|
global $config, $g;
|
81
|
# Only use bogonsv6 table if IPv6 Allow is on, and at least 1 enabled interface also has "blockbogons" enabled.
|
82
|
$usebogonsv6 = false;
|
83
|
if (isset($config['system']['ipv6allow'])) {
|
84
|
foreach ($config['interfaces'] as $ifacedata) {
|
85
|
if(isset($ifacedata['enable']) && isset($ifacedata['blockbogons'])) {
|
86
|
$usebogonsv6 = true;
|
87
|
break;
|
88
|
}
|
89
|
}
|
90
|
}
|
91
|
return $usebogonsv6;
|
92
|
}
|
93
|
|
94
|
function flowtable_configure() {
|
95
|
global $config, $g;
|
96
|
|
97
|
if (empty($config['system']['flowtable'])) {
|
98
|
mwexec("/sbin/sysctl net.inet.flowtable.enable=0", true);
|
99
|
return;
|
100
|
}
|
101
|
|
102
|
// Figure out how many flows we should reserve
|
103
|
// sized 2x larger than the number of unique connection destinations.
|
104
|
if($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates']))
|
105
|
$maxstates = $config['system']['maximumstates'];
|
106
|
else
|
107
|
$maxstates = 150000;
|
108
|
// nmbflows cpu count * ($maxstates * 2)
|
109
|
$cpus = trim(`/sbin/sysctl -n kern.smp.cpus`, " \n");
|
110
|
$nmbflows = ($cpus*($maxstates*2));
|
111
|
// Flowtable currently only works on 8.0
|
112
|
if(get_freebsd_version() == "8") {
|
113
|
mwexec("/sbin/sysctl net.inet.flowtable.nmbflows={$nmbflows}");
|
114
|
mwexec("/sbin/sysctl net.inet.ip.output_flowtable_size={$maxstates}");
|
115
|
mwexec("/sbin/sysctl net.inet.flowtable.enable=1");
|
116
|
}
|
117
|
}
|
118
|
|
119
|
function filter_pflog_start($kill_first = false) {
|
120
|
global $config, $g;
|
121
|
if ($g['platform'] == 'jail')
|
122
|
return;
|
123
|
if(isset($config['system']['developerspew'])) {
|
124
|
$mt = microtime();
|
125
|
echo "filter_pflog_start() being called $mt\n";
|
126
|
}
|
127
|
if (!file_exists("{$g['varrun_path']}/filterlog.pid") ||
|
128
|
!isvalidpid("{$g['varrun_path']}/filterlog.pid"))
|
129
|
mwexec("/usr/local/sbin/filterlog -i pflog0 -p {$g['varrun_path']}/filterlog.pid");
|
130
|
}
|
131
|
|
132
|
/* reload filter async */
|
133
|
function filter_configure() {
|
134
|
global $g;
|
135
|
|
136
|
if(isset($config['system']['developerspew'])) {
|
137
|
$mt = microtime();
|
138
|
echo "filter_configure() being called $mt\n";
|
139
|
}
|
140
|
|
141
|
/*
|
142
|
* NOTE: Check here for bootup status since this should not be triggered during bootup.
|
143
|
* The reason is that rc.bootup calls filter_configure_sync directly which does this too.
|
144
|
*/
|
145
|
if (!$g['booting'])
|
146
|
send_event("filter reload");
|
147
|
}
|
148
|
|
149
|
function filter_delete_states_for_down_gateways() {
|
150
|
global $config, $GatewaysList;
|
151
|
|
152
|
if (isset($config['system']['kill_states']))
|
153
|
return;
|
154
|
|
155
|
$any_gateway_down = false;
|
156
|
$a_gateways = return_gateways_status();
|
157
|
if (is_array($GatewaysList)) {
|
158
|
foreach ($GatewaysList as $gwname => $gateway) {
|
159
|
if (empty($gateway['monitor']))
|
160
|
continue;
|
161
|
if (!is_ipaddr($gateway['monitor']))
|
162
|
continue;
|
163
|
if (strstr($gateway['monitor'], "127.0.0."))
|
164
|
continue;
|
165
|
if (empty($a_gateways[$gateway['monitor']]))
|
166
|
continue;
|
167
|
$gwstatus =& $a_gateways[$gateway['monitor']];
|
168
|
if (strstr($gwstatus['status'], "down")) {
|
169
|
$any_gateway_down = true;
|
170
|
break;
|
171
|
}
|
172
|
}
|
173
|
}
|
174
|
if ($any_gateway_down == true)
|
175
|
mwexec("/sbin/pfctl -Fs");
|
176
|
}
|
177
|
|
178
|
/* reload filter sync */
|
179
|
function filter_configure_sync($delete_states_if_needed = true) {
|
180
|
global $config, $g, $after_filter_configure_run, $FilterIflist;
|
181
|
global $time_based_rules, $filterdns, $aliases, $dummynet_name_list;
|
182
|
|
183
|
/* Use filter lock to not allow concurrent filter reloads during this run. */
|
184
|
$filterlck = lock('filter', LOCK_EX);
|
185
|
|
186
|
|
187
|
filter_pflog_start();
|
188
|
update_filter_reload_status(gettext("Initializing"));
|
189
|
|
190
|
/* invalidate interface cache */
|
191
|
get_interface_arr(true);
|
192
|
|
193
|
if(isset($config['system']['developerspew'])) {
|
194
|
$mt = microtime();
|
195
|
echo "filter_configure_sync() being called $mt\n";
|
196
|
}
|
197
|
/* Get interface list to work with. */
|
198
|
filter_generate_optcfg_array();
|
199
|
if($g['booting'] == true)
|
200
|
echo gettext("Configuring firewall");
|
201
|
|
202
|
/* generate aliases */
|
203
|
if($g['booting'] == true)
|
204
|
echo ".";
|
205
|
update_filter_reload_status(gettext("Creating aliases"));
|
206
|
$aliases = filter_generate_aliases();
|
207
|
$gateways = filter_generate_gateways();
|
208
|
if($g['booting'] == true)
|
209
|
echo ".";
|
210
|
update_filter_reload_status(gettext("Generating Limiter rules"));
|
211
|
$dummynet_rules = filter_generate_dummynet_rules();
|
212
|
$dummynet_name_list = get_unique_dnqueue_list();
|
213
|
update_filter_reload_status(gettext("Generating NAT rules"));
|
214
|
/* generate nat rules */
|
215
|
$natrules = filter_nat_rules_generate();
|
216
|
if($g['booting'] == true)
|
217
|
echo ".";
|
218
|
update_filter_reload_status(gettext("Generating filter rules"));
|
219
|
/* generate pfctl rules */
|
220
|
$pfrules = filter_rules_generate();
|
221
|
/* generate altq, limiter */
|
222
|
if($g['booting'] == true)
|
223
|
echo ".";
|
224
|
update_filter_reload_status(gettext("Generating ALTQ queues"));
|
225
|
$altq_queues = filter_generate_altq_queues();
|
226
|
update_filter_reload_status(gettext("Generating Layer7 rules"));
|
227
|
generate_layer7_files();
|
228
|
if($g['booting'] == true)
|
229
|
echo ".";
|
230
|
update_filter_reload_status(gettext("Loading filter rules"));
|
231
|
/* enable pf if we need to, otherwise disable */
|
232
|
if(!isset ($config['system']['disablefilter'])) {
|
233
|
mwexec("/sbin/pfctl -e", true);
|
234
|
} else {
|
235
|
mwexec("/sbin/pfctl -d", true);
|
236
|
unlink_if_exists("{$g['tmp_path']}/filter_loading");
|
237
|
update_filter_reload_status(gettext("Filter is disabled. Not loading rules."));
|
238
|
if($g['booting'] == true)
|
239
|
echo gettext("done.") . "\n";
|
240
|
unlock($filterlck);
|
241
|
return;
|
242
|
}
|
243
|
|
244
|
$limitrules = "";
|
245
|
/* User defined maximum table entries in Advanced menu. */
|
246
|
if ($config['system']['maximumtableentries'] <> "" && is_numeric($config['system']['maximumtableentries']))
|
247
|
$limitrules .= "set limit table-entries {$config['system']['maximumtableentries']}\n";
|
248
|
|
249
|
if ($config['system']['optimization'] <> "") {
|
250
|
$limitrules .= "set optimization {$config['system']['optimization']}\n";
|
251
|
if($config['system']['optimization'] == "conservative") {
|
252
|
$limitrules .= "set timeout { udp.first 300, udp.single 150, udp.multiple 900 }\n";
|
253
|
}
|
254
|
} else
|
255
|
$limitrules .= "set optimization normal\n";
|
256
|
|
257
|
if (!empty($config['system']['adaptivestart']) && !empty($config['system']['adaptiveend']))
|
258
|
$limitrules .= "set timeout { adaptive.start {$config['system']['adaptivestart']}, adaptive.end {$config['system']['adaptiveend']} }\n";
|
259
|
else
|
260
|
$limitrules .= "set timeout { adaptive.start 0, adaptive.end 0 }\n";
|
261
|
|
262
|
if ($config['system']['maximumstates'] <> "" && is_numeric($config['system']['maximumstates'])) {
|
263
|
/* User defined maximum states in Advanced menu. */
|
264
|
$limitrules .= "set limit states {$config['system']['maximumstates']}\n";
|
265
|
$limitrules .= "set limit src-nodes {$config['system']['maximumstates']}\n";
|
266
|
} else {
|
267
|
$max_states = pfsense_default_state_size();
|
268
|
$limitrules .= "set limit states {$max_states}\n";
|
269
|
$limitrules .= "set limit src-nodes {$max_states}\n";
|
270
|
}
|
271
|
|
272
|
if (isset($config['system']['lb_use_sticky']) && is_numeric($config['system']['srctrack']) && ($config['system']['srctrack'] > 0))
|
273
|
$limitrules .= "set timeout src.track {$config['system']['srctrack']}\n";
|
274
|
|
275
|
// Configure flowtable support if enabled.
|
276
|
flowtable_configure();
|
277
|
|
278
|
$rules = "";
|
279
|
$rules = "{$limitrules}\n";
|
280
|
$rules .= "{$aliases} \n";
|
281
|
$rules .= "{$gateways} \n";
|
282
|
update_filter_reload_status(gettext("Setting up logging information"));
|
283
|
$rules .= filter_setup_logging_interfaces();
|
284
|
$rules .= "\n";
|
285
|
$rules .= "set skip on pfsync0\n";
|
286
|
$rules .= "\n";
|
287
|
update_filter_reload_status(gettext("Setting up SCRUB information"));
|
288
|
$rules .= filter_generate_scrubing();
|
289
|
$rules .= "\n";
|
290
|
$rules .= "{$altq_queues}\n";
|
291
|
$rules .= "{$natrules}\n";
|
292
|
$rules .= "{$pfrules}\n";
|
293
|
$rules .= discover_pkg_rules("filter");
|
294
|
|
295
|
unset($aliases, $gateways, $altq_queues, $natrules, $pfrules);
|
296
|
|
297
|
// Copy rules.debug to rules.debug.old
|
298
|
if(file_exists("{$g['tmp_path']}/rules.debug"))
|
299
|
@copy("{$g['tmp_path']}/rules.debug", "{$g['tmp_path']}/rules.debug.old");
|
300
|
|
301
|
if (!@file_put_contents("{$g['tmp_path']}/rules.debug", $rules, LOCK_EX)) {
|
302
|
log_error("WARNING: Could not write new rules!");
|
303
|
unlock($filterlck);
|
304
|
return;
|
305
|
}
|
306
|
|
307
|
@file_put_contents("{$g['tmp_path']}/rules.limits", $limitrules);
|
308
|
mwexec("/sbin/pfctl -Of {$g['tmp_path']}/rules.limits");
|
309
|
unset($rules, $limitrules);
|
310
|
|
311
|
if(isset($config['system']['developerspew'])) {
|
312
|
$mt = microtime();
|
313
|
echo "pfctl being called at $mt\n";
|
314
|
}
|
315
|
unset($rules_loading, $rules_error);
|
316
|
$_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug 2>&1", $rules_error, $rules_loading);
|
317
|
if(isset($config['system']['developerspew'])) {
|
318
|
$mt = microtime();
|
319
|
echo "pfctl done at $mt\n";
|
320
|
}
|
321
|
/*
|
322
|
* check for a error while loading the rules file. if an error has occurred
|
323
|
* then output the contents of the error to the caller
|
324
|
*/
|
325
|
if($rules_loading <> 0) {
|
326
|
$saved_line_error = $rules_error[0];
|
327
|
$line_error = explode(":", $rules_error[0]);
|
328
|
$line_number = $line_error[1];
|
329
|
$line_split = file("{$g['tmp_path']}/rules.debug");
|
330
|
if(is_array($line_split))
|
331
|
$line_error = sprintf(gettext('The line in question reads [%1$d]: %2$s'), $line_number, $line_split[$line_number-1]);
|
332
|
unset($line_split);
|
333
|
|
334
|
/* Brutal ugly hack but required -- PF is stuck, unwedge */
|
335
|
if (strstr("$rules_error[0]", "busy")) {
|
336
|
exec("/sbin/pfctl -d; /sbin/pfctl -e; /sbin/pfctl -f {$g['tmp_path']}/rules.debug");
|
337
|
$error_msg = gettext("PF was wedged/busy and has been reset.");
|
338
|
file_notice("pf_busy", $error_msg, "pf_busy", "");
|
339
|
} else {
|
340
|
$_grbg = exec("/sbin/pfctl -o basic -f {$g['tmp_path']}/rules.debug.old 2>&1");
|
341
|
}
|
342
|
unset($rules_loading, $rules_error);
|
343
|
|
344
|
if ($line_error and $line_number) {
|
345
|
file_notice("filter_load", sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error), "Filter Reload", "");
|
346
|
update_filter_reload_status(sprintf(gettext('There were error(s) loading the rules: %1$s - %2$s'), $saved_line_error, $line_error));
|
347
|
unlock($filterlck);
|
348
|
return;
|
349
|
}
|
350
|
}
|
351
|
|
352
|
# 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).
|
353
|
if (!is_bogonsv6_used())
|
354
|
$_grbg = exec("/sbin/pfctl -t bogonsv6 -T kill 2>/dev/null");
|
355
|
|
356
|
update_filter_reload_status(gettext("Starting up layer7 daemon"));
|
357
|
layer7_start_l7daemon();
|
358
|
|
359
|
if(!empty($filterdns)) {
|
360
|
@file_put_contents("{$g['varetc_path']}/filterdns.conf", implode("", $filterdns));
|
361
|
unset($filterdns);
|
362
|
if (isvalidpid("{$g['varrun_path']}/filterdns.pid"))
|
363
|
sigkillbypid("{$g['varrun_path']}/filterdns.pid", "HUP");
|
364
|
else {
|
365
|
/*
|
366
|
* FilterDNS has three debugging levels. The default choosen is 1.
|
367
|
* Availabe are level 2 and greater then 2.
|
368
|
*/
|
369
|
if (isset($config['system']['aliasesresolveinterval']) && is_numeric($config['system']['aliasesresolveinterval']))
|
370
|
$resolve_interval = $config['system']['aliasesresolveinterval'];
|
371
|
else
|
372
|
$resolve_interval = 300;
|
373
|
mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns.pid -i {$resolve_interval} -c {$g['varetc_path']}/filterdns.conf -d 1");
|
374
|
}
|
375
|
} else {
|
376
|
killbypid("{$g['varrun_path']}/filterdns.pid");
|
377
|
@unlink("{$g['varrun_path']}/filterdns.pid");
|
378
|
}
|
379
|
|
380
|
/* run items scheduled for after filter configure run */
|
381
|
$fda = fopen("{$g['tmp_path']}/commands.txt", "w");
|
382
|
if($fda) {
|
383
|
if($after_filter_configure_run) {
|
384
|
foreach($after_filter_configure_run as $afcr)
|
385
|
fwrite($fda, $afcr . "\n");
|
386
|
unset($after_filter_configure_run);
|
387
|
}
|
388
|
|
389
|
/*
|
390
|
* we need a way to let a user run a shell cmd after each
|
391
|
* filter_configure() call. run this xml command after
|
392
|
* each change.
|
393
|
*/
|
394
|
if($config['system']['afterfilterchangeshellcmd'] <> "")
|
395
|
fwrite($fda, $config['system']['afterfilterchangeshellcmd'] . "\n");
|
396
|
|
397
|
fclose($fda);
|
398
|
}
|
399
|
|
400
|
if(file_exists("{$g['tmp_path']}/commands.txt")) {
|
401
|
mwexec("sh {$g['tmp_path']}/commands.txt &");
|
402
|
unlink("{$g['tmp_path']}/commands.txt");
|
403
|
}
|
404
|
|
405
|
/* if time based rules are enabled then swap in the set */
|
406
|
if($time_based_rules == true)
|
407
|
filter_tdr_install_cron(true);
|
408
|
else
|
409
|
filter_tdr_install_cron(false);
|
410
|
|
411
|
if($g['booting'] == true)
|
412
|
echo ".";
|
413
|
|
414
|
if($delete_states_if_needed) {
|
415
|
update_filter_reload_status(gettext("Processing down interface states"));
|
416
|
filter_delete_states_for_down_gateways();
|
417
|
}
|
418
|
|
419
|
update_filter_reload_status(gettext("Running plugins"));
|
420
|
|
421
|
if(is_dir("/usr/local/pkg/pf/")) {
|
422
|
/* process packager manager custom rules */
|
423
|
update_filter_reload_status(gettext("Running plugins (pf)"));
|
424
|
run_plugins("/usr/local/pkg/pf/");
|
425
|
update_filter_reload_status(gettext("Plugins completed."));
|
426
|
}
|
427
|
|
428
|
update_filter_reload_status(gettext("Done"));
|
429
|
if($g['booting'] == true)
|
430
|
echo gettext("done.") . "\n";
|
431
|
|
432
|
unlock($filterlck);
|
433
|
return 0;
|
434
|
}
|
435
|
|
436
|
function filter_generate_scrubing() {
|
437
|
global $config, $FilterIflist;
|
438
|
$scrubrules = "";
|
439
|
|
440
|
if (isset($config['system']['maxmss_enable'])) {
|
441
|
$maxmss = 1400;
|
442
|
if (!empty($config['system']['maxmss']))
|
443
|
$maxmss = $config['system']['maxmss'];
|
444
|
|
445
|
$scrubrules .= "scrub from any to <vpn_networks> max-mss {$maxmss}\n";
|
446
|
}
|
447
|
/* disable scrub option */
|
448
|
foreach ($FilterIflist as $scrubif => $scrubcfg) {
|
449
|
if(isset($scrubcfg['virtual']) || empty($scrubcfg['descr']))
|
450
|
continue;
|
451
|
/* set up MSS clamping */
|
452
|
if($scrubcfg['mss'] <> "" && is_numeric($scrubcfg['mss']) && $scrubcfg['if'] != "pppoe" && $scrubcfg['if'] != "pptp" &&
|
453
|
$scrubif['if'] != "l2tp")
|
454
|
$mssclamp = "max-mss " . (intval($scrubcfg['mss'] - 40));
|
455
|
else
|
456
|
$mssclamp = "";
|
457
|
/* configure no-df for linux nfs and others */
|
458
|
if($config['system']['scrubnodf'])
|
459
|
$scrubnodf = "no-df";
|
460
|
else
|
461
|
$scrubnodf = "";
|
462
|
if($config['system']['scrubrnid'])
|
463
|
$scrubrnid = "random-id";
|
464
|
else
|
465
|
$scrubrnid = "";
|
466
|
if(!isset($config['system']['disablescrub']))
|
467
|
$scrubrules .= "scrub on \${$scrubcfg['descr']} all {$scrubnodf} {$scrubrnid} {$mssclamp} fragment reassemble\n"; // reassemble all directions
|
468
|
else if(!empty($mssclamp))
|
469
|
$scrubrules .= "scrub on \${$scrubcfg['descr']} {$mssclamp}\n";
|
470
|
}
|
471
|
return $scrubrules;
|
472
|
}
|
473
|
|
474
|
function filter_generate_nested_alias($name, $alias, &$aliasnesting, &$aliasaddrnesting) {
|
475
|
global $aliastable, $filterdns;
|
476
|
|
477
|
$addresses = explode(" ", $alias);
|
478
|
$finallist = "";
|
479
|
$builtlist = "";
|
480
|
$urltable_nesting = "";
|
481
|
$aliasnesting[$name] = $name;
|
482
|
foreach ($addresses as $address) {
|
483
|
if (empty($address))
|
484
|
continue;
|
485
|
$linelength = strlen($builtlist);
|
486
|
$tmpline = "";
|
487
|
if(is_alias($address)) {
|
488
|
if (alias_get_type($address) == 'urltable') {
|
489
|
// Feature#1603. For this type of alias we do not need to recursively call filter_generate_nested_alias. Just load IPs from the file.
|
490
|
$urltable_netsting = alias_expand_urltable($address);
|
491
|
if (!empty($urltable_nesting)) {
|
492
|
$urlfile_as_arr = file($urltable_nesting);
|
493
|
foreach($urlfile_as_arr as $line) {
|
494
|
$address= rtrim($line);
|
495
|
if ((strlen($tmpline) + $linelength) > 4036) {
|
496
|
$finallist .= "{$tmpline} \\\n";
|
497
|
$tmpline = "";
|
498
|
}
|
499
|
$tmpline .= " {$address}";
|
500
|
}
|
501
|
}
|
502
|
}
|
503
|
/* We already expanded this alias so there is no neccessity to do it again. */
|
504
|
else if(!isset($aliasnesting[$address]))
|
505
|
$tmpline = filter_generate_nested_alias($name, $aliastable[$address], $aliasnesting, $aliasaddrnesting);
|
506
|
} else if(!isset($aliasaddrnesting[$address])) {
|
507
|
if (!is_ipaddr($address) && !is_subnet($address) && !is_port($address) && is_hostname($address)) {
|
508
|
if (!isset($filterdns["{$address}{$name}"]))
|
509
|
$filterdns["{$address}{$name}"] = "pf {$address} {$name}\n";
|
510
|
continue;
|
511
|
}
|
512
|
$aliasaddrnesting[$address] = $address;
|
513
|
$tmpline = " {$address}";
|
514
|
}
|
515
|
if ((strlen($tmpline)+ $linelength) > 4036) {
|
516
|
$finallist .= "{$builtlist} \\\n";
|
517
|
$builtlist = "";
|
518
|
}
|
519
|
if (!empty($tmpline))
|
520
|
$builtlist .= " {$tmpline}";
|
521
|
}
|
522
|
$finallist .= $builtlist;
|
523
|
return $finallist;
|
524
|
}
|
525
|
|
526
|
function filter_expand_alias($alias_name)
|
527
|
{
|
528
|
global $config;
|
529
|
|
530
|
if(isset($config['aliases']['alias'])) {
|
531
|
foreach ($config['aliases']['alias'] as $aliased) {
|
532
|
if($aliased['name'] == $alias_name) {
|
533
|
$aliasnesting = array();
|
534
|
$aliasaddrnesting = array();
|
535
|
return filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
|
536
|
}
|
537
|
}
|
538
|
}
|
539
|
}
|
540
|
|
541
|
function filter_expand_alias_array($alias_name) {
|
542
|
$expansion = filter_expand_alias($alias_name);
|
543
|
return explode(" ", preg_replace('/\s+/', ' ', trim($expansion)));
|
544
|
}
|
545
|
|
546
|
function filter_generate_aliases() {
|
547
|
global $config, $FilterIflist, $after_filter_configure_run;
|
548
|
|
549
|
if(isset($config['system']['developerspew'])) {
|
550
|
$mt = microtime();
|
551
|
echo "filter_generate_aliases() being called $mt\n";
|
552
|
}
|
553
|
|
554
|
$alias = "#System aliases\n ";
|
555
|
$aliases = "loopback = \"{ lo0 }\"\n";
|
556
|
|
557
|
foreach ($FilterIflist as $if => $ifcfg) {
|
558
|
if (is_array($ifcfg[0])) {
|
559
|
if ($ifcfg[0]['if'] == 'pppoe') {
|
560
|
$aliases .= "{$ifcfg[0]['descr']} = \"{ {$ifcfg[0]['if']}";
|
561
|
$aliases .= " }\"\n";
|
562
|
}
|
563
|
} elseif (!empty($ifcfg['descr']) && !empty($ifcfg['if'])) {
|
564
|
if ($ifcfg['type6'] == '6rd')
|
565
|
$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
|
566
|
else if ($ifcfg['type6'] == '6to4')
|
567
|
$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']} {$if}_stf";
|
568
|
else {
|
569
|
$aliases .= "{$ifcfg['descr']} = \"{ {$ifcfg['if']}";
|
570
|
|
571
|
if ($ifcfg['type'] == 'pptp') {
|
572
|
foreach (get_parent_interface($ifcfg['if']) as $parent_if) {
|
573
|
if ($parent_if != $ifcfg['if']) {
|
574
|
$aliases .= " {$parent_if}";
|
575
|
}
|
576
|
}
|
577
|
}
|
578
|
}
|
579
|
$aliases .= " }\"\n";
|
580
|
}
|
581
|
}
|
582
|
|
583
|
$aliases .= "\n#SSH Lockout Table\n";
|
584
|
$aliases .= "table <sshlockout> persist\n";
|
585
|
$aliases .= "table <webConfiguratorlockout> persist\n";
|
586
|
|
587
|
$aliases .= "#Snort tables\n";
|
588
|
$aliases .= "table <snort2c>\n";
|
589
|
$aliases .= "table <virusprot>\n";
|
590
|
if (!file_exists("/etc/bogons"))
|
591
|
@file_put_contents("/etc/bogons", "");
|
592
|
if (!file_exists("/etc/bogonsv6"))
|
593
|
@file_put_contents("/etc/bogonsv6", "");
|
594
|
$aliases .= "table <bogons> persist file \"/etc/bogons\"\n";
|
595
|
if (is_bogonsv6_used())
|
596
|
$aliases .= "table <bogonsv6> persist file \"/etc/bogonsv6\"\n";
|
597
|
|
598
|
$vpns_list = filter_get_vpns_list();
|
599
|
if($vpns_list)
|
600
|
$aliases .= "table <vpn_networks> { $vpns_list }\n";
|
601
|
|
602
|
/* add a Negate_networks table */
|
603
|
$aliases .= "table <negate_networks> ";
|
604
|
if($vpns_list)
|
605
|
$aliases .= "{ $vpns_list }";
|
606
|
$aliases .= "\n";
|
607
|
|
608
|
$aliases .= "\n# User Aliases \n";
|
609
|
/* Setup pf groups */
|
610
|
if(isset($config['aliases']['alias'])) {
|
611
|
foreach ($config['aliases']['alias'] as $aliased) {
|
612
|
$extralias = "";
|
613
|
/*
|
614
|
* XXX: i am not sure what this does so i am commenting it out for now, because as it is
|
615
|
* its quite dangerous!
|
616
|
* $ip = find_interface_ip($aliased['address']);
|
617
|
* $extraalias = " " . link_ip_to_carp_interface($ip);
|
618
|
*/
|
619
|
$aliasnesting = array();
|
620
|
$aliasaddrnesting = array();
|
621
|
$addrlist = filter_generate_nested_alias($aliased['name'], $aliased['address'], $aliasnesting, $aliasaddrnesting);
|
622
|
switch ($aliased['type']) {
|
623
|
case "host":
|
624
|
case "network":
|
625
|
case "url":
|
626
|
$tableaddrs = "{$addrlist}{$extralias}";
|
627
|
if(empty($tableaddrs)) {
|
628
|
$aliases .= "table <{$aliased['name']}> persist\n";
|
629
|
if (empty($aliased['address']))
|
630
|
$after_filter_configure_run[] = "/sbin/pfctl -T flush -t " . escapeshellarg($aliased['name']);
|
631
|
} else
|
632
|
$aliases .= "table <{$aliased['name']}> { {$addrlist}{$extralias} } \n";
|
633
|
|
634
|
$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
|
635
|
break;
|
636
|
case "openvpn":
|
637
|
$openvpncfg = array();
|
638
|
if($config['openvpn']['user']) {
|
639
|
/* XXX: Check if we have a correct ip? */
|
640
|
foreach ($config['openvpn']['user'] as $openvpn)
|
641
|
$openvpncfg[$openvpn['name']] = $openvpn['ip'];
|
642
|
}
|
643
|
$vpn_lines = explode("\n", $addrlist);
|
644
|
foreach ($vpn_lines as $vpn_line) {
|
645
|
$vpn_address_split = explode(" ", $vpn_line);
|
646
|
foreach($vpn_address_split as $vpnsplit) {
|
647
|
if(isset($openvpncfg[$vpnsplit])) {
|
648
|
$newaddress .= " ";
|
649
|
$newaddress .= $openvpn[$vpnsplit];
|
650
|
break;
|
651
|
}
|
652
|
}
|
653
|
}
|
654
|
$aliases .= "table <{$aliased['name']}> { {$newaddress}{$extralias} } \n";
|
655
|
$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
|
656
|
break;
|
657
|
case "urltable":
|
658
|
$urlfn = alias_expand_urltable($aliased['name']);
|
659
|
if ($urlfn) {
|
660
|
$aliases .= "table <{$aliased['name']}> persist file \"{$urlfn}\"\n";
|
661
|
$aliases .= "{$aliased['name']} = \"<{$aliased['name']}>\"\n";
|
662
|
}
|
663
|
break;
|
664
|
case "urltable_ports":
|
665
|
// TODO: Change it when pf supports tables with ports
|
666
|
$urlfn = alias_expand_urltable($aliased['name']);
|
667
|
if ($urlfn)
|
668
|
$aliases .= "{$aliased['name']} = \"{ " . preg_replace("/\n/", " ", file_get_contents($urlfn)) . " }\"\n";
|
669
|
break;
|
670
|
case "port":
|
671
|
case "url_ports":
|
672
|
$aliases .= "{$aliased['name']} = \"{ {$addrlist} }\"\n";
|
673
|
break;
|
674
|
default:
|
675
|
$aliases .= "{$aliased['name']} = \"{ {$aliased['address']}{$extralias} }\"\n";
|
676
|
break;
|
677
|
}
|
678
|
}
|
679
|
}
|
680
|
$result = "{$alias} \n";
|
681
|
$result .= "{$aliases}";
|
682
|
|
683
|
return $result;
|
684
|
}
|
685
|
|
686
|
function filter_generate_gateways() {
|
687
|
global $config, $g, $GatewaysList;
|
688
|
|
689
|
$rules = "# Gateways\n";
|
690
|
|
691
|
update_filter_reload_status(gettext("Creating gateway group item..."));
|
692
|
|
693
|
/* Lookup Gateways to be used in filter rules once */
|
694
|
$GatewaysList = return_gateways_array();
|
695
|
$GatewayGroupsList = return_gateway_groups_array();
|
696
|
|
697
|
if (is_array($GatewaysList)) {
|
698
|
foreach ($GatewaysList as $gwname => $gateway) {
|
699
|
$int = $gateway['interface'];
|
700
|
$gwip = $gateway['gateway'];
|
701
|
$route = "";
|
702
|
if (!is_ipaddr($gwip))
|
703
|
$gwip = get_interface_gateway($gateway['friendlyiface']);
|
704
|
if (is_ipaddr($gwip) && !empty($int))
|
705
|
$route = "route-to ( {$int} {$gwip} )";
|
706
|
if (($route === "") && isset($config['system']['skip_rules_gw_down']))
|
707
|
unset($GatewaysList[$gwname]);
|
708
|
else
|
709
|
$rules .= "GW{$gwname} = \" {$route} \"\n";
|
710
|
}
|
711
|
}
|
712
|
|
713
|
if (is_array($GatewayGroupsList)) {
|
714
|
foreach ($GatewayGroupsList as $gateway => $members) {
|
715
|
$route = "";
|
716
|
/* hey, that's not a group member! */
|
717
|
unset($members['ipprotocol']);
|
718
|
if (count($members) > 0) {
|
719
|
$foundlb = 0;
|
720
|
$routeto = "";
|
721
|
foreach($members as $idx => $member) {
|
722
|
$int = $member['int'];
|
723
|
$gatewayip = $member['gwip'];
|
724
|
if (($int <> "") && is_ipaddr($gatewayip)) {
|
725
|
if ($g['debug'])
|
726
|
log_error(sprintf(gettext('Setting up route with %1$s on %2$s'), $gatewayip, $int));
|
727
|
if ($member['weight'] > 1) {
|
728
|
$routeto .= str_repeat("( {$int} {$gatewayip} ) ", $member['weight']);
|
729
|
} else
|
730
|
$routeto .= "( {$int} {$gatewayip} ) ";
|
731
|
$foundlb++;
|
732
|
} else
|
733
|
log_error(sprintf(gettext("An error occurred while trying to find the interface got %s . The rule has not been added."), $gatewayip));
|
734
|
}
|
735
|
$route = "";
|
736
|
if ($foundlb > 0) {
|
737
|
$route = " route-to { {$routeto} } ";
|
738
|
if($foundlb > 1) {
|
739
|
$route .= " round-robin ";
|
740
|
if (isset($config['system']['lb_use_sticky']))
|
741
|
$route .= " sticky-address ";
|
742
|
}
|
743
|
}
|
744
|
}
|
745
|
if (($route === "") && isset($config['system']['skip_rules_gw_down']))
|
746
|
unset($GatewayGroupsList[$gateway]);
|
747
|
else
|
748
|
$rules .= "GW{$gateway} = \" {$route} \"\n";
|
749
|
}
|
750
|
}
|
751
|
|
752
|
/* Create a global array to avoid errors on rulesets. */
|
753
|
$GatewaysList = $GatewaysList + $GatewayGroupsList;
|
754
|
|
755
|
$rules .= "\n";
|
756
|
|
757
|
return $rules;
|
758
|
}
|
759
|
|
760
|
/* returns space separated list of vpn subnets */
|
761
|
function filter_get_vpns_list() {
|
762
|
global $config;
|
763
|
|
764
|
$vpns = "";
|
765
|
$vpns_arr = array();
|
766
|
|
767
|
/* ipsec */
|
768
|
if (isset($config['ipsec']['enable'])) {
|
769
|
if (is_array($config['ipsec']['phase2'])) {
|
770
|
foreach ($config['ipsec']['phase2'] as $ph2ent) {
|
771
|
if ((!$ph2ent['mobile']) && ($ph2ent['mode'] != 'transport')) {
|
772
|
if (!function_exists('ipsec_idinfo_to_cidr'))
|
773
|
require_once("ipsec.inc");
|
774
|
if (!is_array($ph2ent['remoteid']))
|
775
|
continue;
|
776
|
$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
|
777
|
$vpns_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
|
778
|
if ($vpns_subnet == "0.0.0.0/0")
|
779
|
continue;
|
780
|
$vpns_arr[] = $vpns_subnet;
|
781
|
}
|
782
|
}
|
783
|
}
|
784
|
}
|
785
|
|
786
|
/* openvpn */
|
787
|
foreach (array('client', 'server') as $type) {
|
788
|
if(is_array($config['openvpn']["openvpn-$type"])) {
|
789
|
foreach ($config['openvpn']["openvpn-$type"] as $settings) {
|
790
|
if(is_array($settings)) {
|
791
|
if (!isset($settings['disable'])) {
|
792
|
$remote_networks = explode(',', $settings['remote_network']);
|
793
|
foreach ($remote_networks as $remote_network) {
|
794
|
if (is_subnet($remote_network) && ($remote_network <> "0.0.0.0/0"))
|
795
|
$vpns_arr[] = $remote_network;
|
796
|
}
|
797
|
if (is_subnet($settings['tunnel_network']) && $settings['tunnel_network'] <> "0.0.0.0/0")
|
798
|
$vpns_arr[] = $settings['tunnel_network'];
|
799
|
}
|
800
|
}
|
801
|
}
|
802
|
}
|
803
|
}
|
804
|
/* pppoe */
|
805
|
if (is_array($config['pppoes']['pppoe'])) {
|
806
|
foreach($config['pppoes']['pppoe'] as $pppoe) {
|
807
|
if ($pppoe['mode'] == "server") {
|
808
|
if(is_ipaddr($pppoe['remoteip'])) {
|
809
|
$pppoesub = gen_subnet($pppoe['remoteip'], $pppoe['pppoe_subnet']);
|
810
|
if (is_subnet($pppoesub))
|
811
|
$vpns_arr[] = $pppoesub;
|
812
|
}
|
813
|
}
|
814
|
}
|
815
|
}
|
816
|
|
817
|
if (!empty($vpns_arr))
|
818
|
$vpns = implode(" ", $vpns_arr);
|
819
|
|
820
|
return $vpns;
|
821
|
}
|
822
|
|
823
|
/* returns space separated list of directly connected networks
|
824
|
* optionally returns an array instead, including friendly interface and gateway (if applicable)
|
825
|
*/
|
826
|
function filter_get_direct_networks_list($returnsubnetsonly = true) {
|
827
|
global $config, $FilterIflist, $GatewaysList;
|
828
|
/* build list of directly connected interfaces and networks */
|
829
|
$networks = "";
|
830
|
$networks_arr = array();
|
831
|
if(empty($FilterIflist)) {
|
832
|
filter_generate_optcfg_array();
|
833
|
}
|
834
|
foreach ($FilterIflist as $ifent => $ifcfg) {
|
835
|
$subnet = "{$ifcfg['sa']}/{$ifcfg['sn']}";
|
836
|
if(is_subnet($subnet)) {
|
837
|
if($returnsubnetsonly) {
|
838
|
$networks_arr[] = $subnet;
|
839
|
} else {
|
840
|
$networks_arr[] = array(
|
841
|
'subnet' => $subnet,
|
842
|
'if' => $ifent,
|
843
|
'ip' => $ifcfg['ip']);
|
844
|
}
|
845
|
}
|
846
|
}
|
847
|
foreach(get_configured_ip_aliases_list(true) as $vip) {
|
848
|
$subnet = "{$vip['subnet']}/{$vip['subnet_bits']}";
|
849
|
if(is_subnet($subnet) && !(is_subnetv4($subnet) && $vip['subnet_bits'] == 32) && !(is_subnetv6($subnet) && $vip['subnet_bits'] == 128)) {
|
850
|
if(is_subnetv4($subnet))
|
851
|
$subnet = gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
|
852
|
else if(is_subnetv6($subnet))
|
853
|
$subnet = gen_subnetv6($vip['subnet'], $vip['subnet_bits']) . "/{$vip['subnet_bits']}";
|
854
|
if($returnsubnetsonly) {
|
855
|
$networks_arr[] = $subnet;
|
856
|
} else {
|
857
|
$networks_arr[] = array(
|
858
|
'subnet' => $subnet,
|
859
|
'if' => $vip['interface'],
|
860
|
'ip' => $vip['subnet']);
|
861
|
}
|
862
|
}
|
863
|
}
|
864
|
foreach(get_staticroutes() as $netent) {
|
865
|
if(is_subnet($netent['network'])) {
|
866
|
if($returnsubnetsonly) {
|
867
|
$networks_arr[] = $netent['network'];
|
868
|
} else if(isset($GatewaysList[$netent['gateway']])) {
|
869
|
$networks_arr[] = array(
|
870
|
'subnet' => $netent['network'],
|
871
|
'if' => $GatewaysList[$netent['gateway']]['friendlyiface'],
|
872
|
'gateway' => $GatewaysList[$netent['gateway']]['gateway']);
|
873
|
}
|
874
|
}
|
875
|
}
|
876
|
if($returnsubnetsonly) {
|
877
|
if(!empty($networks_arr)) {
|
878
|
$networks = implode(" ", $networks_arr);
|
879
|
}
|
880
|
return $networks;
|
881
|
} else {
|
882
|
return $networks_arr;
|
883
|
}
|
884
|
}
|
885
|
|
886
|
function filter_generate_optcfg_array() {
|
887
|
global $config, $FilterIflist;
|
888
|
if(isset($config['system']['developerspew'])) {
|
889
|
$mt = microtime();
|
890
|
echo "filter_generate_optcfg_array() being called $mt\n";
|
891
|
}
|
892
|
|
893
|
read_layer7_config();
|
894
|
/* if list */
|
895
|
$iflist = get_configured_interface_with_descr();
|
896
|
foreach ($iflist as $if => $ifdetail) {
|
897
|
$oc = $config['interfaces'][$if];
|
898
|
$oic = array();
|
899
|
$oic['if'] = get_real_interface($if);
|
900
|
if (!does_interface_exist($oic['if']))
|
901
|
continue;
|
902
|
$oic['ifv6'] = get_real_interface($if, "inet6");
|
903
|
$oic['ip'] = get_interface_ip($if);
|
904
|
$oic['ipv6'] = get_interface_ipv6($if);
|
905
|
if(!is_ipaddrv4($oc['ipaddr']) && !empty($oc['ipaddr']))
|
906
|
$oic['type'] = $oc['ipaddr'];
|
907
|
if(!is_ipaddrv6($oc['ipaddrv6']) && !empty($oc['ipaddrv6']))
|
908
|
$oic['type6'] = $oc['ipaddrv6'];
|
909
|
if (!empty($oc['track6-interface']))
|
910
|
$oic['track6-interface'] = $oc['track6-interface'];
|
911
|
$oic['sn'] = get_interface_subnet($if);
|
912
|
$oic['snv6'] = get_interface_subnetv6($if);
|
913
|
$oic['mtu'] = empty($oc['mtu']) ? 1500 : $oc['mtu'];
|
914
|
$oic['mss'] = empty($oc['mss']) ? '' : $oc['mss'];
|
915
|
$oic['descr'] = $ifdetail;
|
916
|
$oic['sa'] = gen_subnet($oic['ip'], $oic['sn']);
|
917
|
$oic['sav6'] = gen_subnetv6($oic['ipv6'], $oic['snv6']);
|
918
|
$oic['nonat'] = $oc['nonat'];
|
919
|
$oic['alias-address'] = $oc['alias-address'];
|
920
|
$oic['alias-subnet'] = $oc['alias-subnet'];
|
921
|
$oic['gateway'] = $oc['gateway'];
|
922
|
$oic['gatewayv6'] = $oc['gatewayv6'];
|
923
|
$oic['spoofcheck'] = "yes";
|
924
|
$oic['bridge'] = link_interface_to_bridge($if);
|
925
|
$vips = link_interface_to_vips($if);
|
926
|
if (!empty($vips)) {
|
927
|
foreach ($vips as $vipidx => $vip) {
|
928
|
if (is_ipaddrv4($vip['subnet'])) {
|
929
|
if (!is_array($oic['vips']))
|
930
|
$oic['vips'] = array();
|
931
|
$oic['vips'][$vipidx]['ip'] = $vip['subnet'];
|
932
|
if (empty($vip['subnet_bits']))
|
933
|
$oic['vips'][$vipidx]['sn'] = 32;
|
934
|
else
|
935
|
$oic['vips'][$vipidx]['sn'] = $vip['subnet_bits'];
|
936
|
} else if (is_ipaddrv6($vip['subnet'])) {
|
937
|
if (!is_array($oic['vips6']))
|
938
|
$oic['vips6'] = array();
|
939
|
$oic['vips6'][$vipidx]['ip'] = $vip['subnet'];
|
940
|
if (empty($vip['subnet_bits']))
|
941
|
$oic['vips6'][$vipidx]['sn'] = 128;
|
942
|
else
|
943
|
$oic['vips6'][$vipidx]['sn'] = $vip['subnet_bits'];
|
944
|
}
|
945
|
}
|
946
|
}
|
947
|
unset($vips);
|
948
|
$FilterIflist[$if] = $oic;
|
949
|
}
|
950
|
|
951
|
if($config['pptpd']['mode'] == "server" || $config['pptpd']['mode'] == "redir") {
|
952
|
$oic = array();
|
953
|
$oic['if'] = 'pptp';
|
954
|
$oic['descr'] = 'pptp';
|
955
|
$oic['ip'] = $config['pptpd']['localip'];
|
956
|
$oic['sa'] = $config['pptpd']['remoteip'];
|
957
|
$oic['mode'] = $config['pptpd']['mode'];
|
958
|
$oic['virtual'] = true;
|
959
|
if($config['pptpd']['pptp_subnet'] <> "")
|
960
|
$oic['sn'] = $config['pptpd']['pptp_subnet'];
|
961
|
else
|
962
|
$oic['sn'] = "32";
|
963
|
$FilterIflist['pptp'] = $oic;
|
964
|
}
|
965
|
if($config['l2tp']['mode'] == "server") {
|
966
|
$oic = array();
|
967
|
$oic['if'] = 'l2tp';
|
968
|
$oic['descr'] = 'L2TP';
|
969
|
$oic['ip'] = $config['l2tp']['localip'];
|
970
|
$oic['sa'] = $config['l2tp']['remoteip'];
|
971
|
if($config['l2tp']['l2tp_subnet'] <> "")
|
972
|
$oic['sn'] = $config['l2tp']['l2tp_subnet'];
|
973
|
else
|
974
|
$oic['sn'] = "32";
|
975
|
$oic['mode'] = $config['l2tp']['mode'];
|
976
|
$oic['virtual'] = true;
|
977
|
$FilterIflist['l2tp'] = $oic;
|
978
|
}
|
979
|
if (is_array($config['pppoes']['pppoe']) && (count($config['pppoes']['pppoe']) > 0)) {
|
980
|
$pppoeifs = array();
|
981
|
foreach($config['pppoes']['pppoe'] as $pppoe) {
|
982
|
if ($pppoe['mode'] == "server") {
|
983
|
$oic = array();
|
984
|
$oic['if'] = 'pppoe';
|
985
|
$oic['descr'] = 'pppoe';
|
986
|
$oic['ip'] = $pppoe['localip'];
|
987
|
$oic['sa'] = $pppoe['remoteip'];
|
988
|
$oic['mode'] = $pppoe['mode'];
|
989
|
$oic['virtual'] = true;
|
990
|
if($pppoe['pppoe_subnet'] <> "")
|
991
|
$oic['sn'] = $pppoe['pppoe_subnet'];
|
992
|
else
|
993
|
$oic['sn'] = "32";
|
994
|
$pppoeifs[] = $oic;
|
995
|
}
|
996
|
}
|
997
|
if (count($pppoeifs))
|
998
|
$FilterIflist['pppoe'] = $pppoeifs;
|
999
|
}
|
1000
|
/* add ipsec interfaces */
|
1001
|
if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
|
1002
|
$oic = array();
|
1003
|
$oic['if'] = 'enc0';
|
1004
|
$oic['descr'] = 'IPsec';
|
1005
|
$oic['type'] = "none";
|
1006
|
$oic['virtual'] = true;
|
1007
|
$FilterIflist['enc0'] = $oic;
|
1008
|
}
|
1009
|
/* add openvpn interfaces */
|
1010
|
if($config['openvpn']['openvpn-server'] || $config['openvpn']['openvpn-client']) {
|
1011
|
$oic = array();
|
1012
|
$oic['if'] = "openvpn";
|
1013
|
$oic['descr'] = 'OpenVPN';
|
1014
|
$oic['type'] = "none";
|
1015
|
$oic['virtual'] = true;
|
1016
|
$FilterIflist['openvpn'] = $oic;
|
1017
|
}
|
1018
|
/* add interface groups */
|
1019
|
if(is_array($config['ifgroups']['ifgroupentry'])) {
|
1020
|
foreach($config['ifgroups']['ifgroupentry'] as $ifgen) {
|
1021
|
$oc = array();
|
1022
|
$oc['if'] = $ifgen['ifname'];
|
1023
|
$oc['descr'] = $ifgen['ifname'];
|
1024
|
$oc['virtual'] = true;
|
1025
|
$FilterIflist[$ifgen['ifname']] = $oc;
|
1026
|
}
|
1027
|
}
|
1028
|
}
|
1029
|
|
1030
|
function filter_flush_nat_table() {
|
1031
|
global $config, $g;
|
1032
|
if(isset($config['system']['developerspew'])) {
|
1033
|
$mt = microtime();
|
1034
|
echo "filter_flush_nat_table() being called $mt\n";
|
1035
|
}
|
1036
|
return mwexec("/sbin/pfctl -F nat");
|
1037
|
}
|
1038
|
|
1039
|
function filter_flush_state_table() {
|
1040
|
return mwexec("/sbin/pfctl -F state");
|
1041
|
}
|
1042
|
|
1043
|
function filter_get_reflection_interfaces($natif = "") {
|
1044
|
global $FilterIflist;
|
1045
|
|
1046
|
$nat_if_list = array();
|
1047
|
|
1048
|
foreach ($FilterIflist as $ifent => $ifname) {
|
1049
|
if($ifname['if'] == $natif)
|
1050
|
continue;
|
1051
|
|
1052
|
/* Do not add reflection redirects for interfaces with gateways */
|
1053
|
if(interface_has_gateway($ifent))
|
1054
|
continue;
|
1055
|
|
1056
|
$nat_if_list[] = $ifname['if'];
|
1057
|
}
|
1058
|
|
1059
|
return $nat_if_list;
|
1060
|
}
|
1061
|
|
1062
|
function filter_generate_reflection_nat($rule, &$route_table, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = "") {
|
1063
|
global $config, $FilterIflist;
|
1064
|
|
1065
|
if(!isset($config['system']['enablenatreflectionhelper']))
|
1066
|
return "";
|
1067
|
|
1068
|
// Initialize natrules holder string
|
1069
|
$natrules = "";
|
1070
|
|
1071
|
update_filter_reload_status(sprintf(gettext("Creating reflection NAT rule for %s..."), $rule['descr']));
|
1072
|
|
1073
|
/* TODO: Add this option to port forwards page. */
|
1074
|
if(isset($rule['staticnatport'])) {
|
1075
|
$static_port = " static-port";
|
1076
|
} else {
|
1077
|
$static_port = " port 1024:65535";
|
1078
|
}
|
1079
|
|
1080
|
if(!empty($protocol)) {
|
1081
|
$protocol_text = " proto {$protocol}";
|
1082
|
} else {
|
1083
|
$protocol_text = "";
|
1084
|
}
|
1085
|
|
1086
|
if(empty($target_subnet) || !is_numeric($target_subnet))
|
1087
|
$target_subnet = 32;
|
1088
|
|
1089
|
if(!is_array($route_table)) {
|
1090
|
/* get a simulated IPv4-only route table based on the config */
|
1091
|
$route_table = filter_get_direct_networks_list(false);
|
1092
|
foreach($route_table as $rt_key => $rt_ent) {
|
1093
|
if(!is_subnetv4($rt_ent['subnet']))
|
1094
|
unset($route_table[$rt_key]);
|
1095
|
if(isset($route_table[$rt_key]) && isset($FilterIflist[$rt_ent['if']]['if']))
|
1096
|
$route_table[$rt_key]['if'] = $FilterIflist[$rt_ent['if']]['if'];
|
1097
|
}
|
1098
|
}
|
1099
|
|
1100
|
/* Check if the target is accessed through a static route */
|
1101
|
foreach($route_table as $route) {
|
1102
|
if(isset($route['gateway']) && is_ipaddr($route['gateway'])) {
|
1103
|
$subnet_split = explode("/", $route['subnet']);
|
1104
|
if(in_array($route['if'], $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
|
1105
|
$target_ip = $route['gateway'];
|
1106
|
$target_subnet = 32;
|
1107
|
break;
|
1108
|
}
|
1109
|
}
|
1110
|
}
|
1111
|
|
1112
|
/* Search for matching subnets in the routing table */
|
1113
|
foreach($route_table as $route) {
|
1114
|
$subnet = $route['subnet'];
|
1115
|
$subnet_split = explode("/", $subnet);
|
1116
|
$subnet_if = $route['if'];
|
1117
|
if(in_array($subnet_if, $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) {
|
1118
|
$ifsubnet_ip = "";
|
1119
|
/* Find interface IP to use for NAT */
|
1120
|
foreach ($route_table as $ifnetwork) {
|
1121
|
if(isset($ifnetwork['ip']) && is_ipaddr($ifnetwork['ip']) && $ifnetwork['if'] == $subnet_if && ip_in_subnet($ifnetwork['ip'], $subnet)) {
|
1122
|
$ifsubnet_ip = $ifnetwork['ip'];
|
1123
|
break;
|
1124
|
}
|
1125
|
}
|
1126
|
if(!empty($ifsubnet_ip)) {
|
1127
|
$subnets = array($subnet);
|
1128
|
/* Find static routes that also need to be referenced in the NAT rule */
|
1129
|
foreach($route_table as $rtentry) {
|
1130
|
if(isset($rtentry['gateway']) && is_ipaddr($rtentry['gateway']) && $rtentry['if'] == $subnet_if && ip_in_subnet($rtentry['gateway'], $subnet))
|
1131
|
$subnets[] = $rtentry['subnet'];
|
1132
|
}
|
1133
|
if(count($subnets) > 1)
|
1134
|
$subnet = "{ " . implode(" ", $subnets) . " }";
|
1135
|
$natrules .= "no nat on {$subnet_if}{$protocol_text} from {$subnet_if} to {$target}\n";
|
1136
|
$natrules .= "nat on {$subnet_if}{$protocol_text} from {$subnet} to {$target} -> {$ifsubnet_ip}{$static_port}\n";
|
1137
|
}
|
1138
|
}
|
1139
|
}
|
1140
|
|
1141
|
if(!empty($natrules))
|
1142
|
$natrules .= "\n";
|
1143
|
|
1144
|
return $natrules;
|
1145
|
}
|
1146
|
|
1147
|
function filter_generate_reflection_proxy($rule, $nordr, $rdr_ifs, $srcaddr, $dstaddr_port, &$starting_localhost_port, &$reflection_txt) {
|
1148
|
global $FilterIflist, $config;
|
1149
|
|
1150
|
// Initialize natrules holder string
|
1151
|
$natrules = "";
|
1152
|
$reflection_txt = array();
|
1153
|
|
1154
|
if(!empty($rdr_ifs)) {
|
1155
|
if($config['system']['reflectiontimeout'])
|
1156
|
$reflectiontimeout = $config['system']['reflectiontimeout'];
|
1157
|
else
|
1158
|
$reflectiontimeout = "2000";
|
1159
|
|
1160
|
update_filter_reload_status(sprintf(gettext("Creating reflection rule for %s..."), $rule['descr']));
|
1161
|
|
1162
|
$rdr_if_list = implode(" ", $rdr_ifs);
|
1163
|
if(count($rdr_ifs) > 1)
|
1164
|
$rdr_if_list = "{ {$rdr_if_list} }";
|
1165
|
|
1166
|
$natrules .= "\n# Reflection redirects\n";
|
1167
|
|
1168
|
$localport = $rule['local-port'];
|
1169
|
if(!empty($localport) && is_alias($localport)) {
|
1170
|
$localport = filter_expand_alias($localport);
|
1171
|
$localport = explode(" ", trim($localport));
|
1172
|
// The translation port for rdr, when specified, does not support more than one port or range.
|
1173
|
// Emulating for behavior consistent with the original port forward.
|
1174
|
$localport = $localport[0];
|
1175
|
}
|
1176
|
|
1177
|
if(is_alias($rule['destination']['port'])) {
|
1178
|
if(empty($localport) || $rule['destination']['port'] == $rule['local-port']) {
|
1179
|
$dstport = filter_expand_alias($rule['destination']['port']);
|
1180
|
$dstport = array_filter(explode(" ", trim($dstport)));
|
1181
|
$localport = "";
|
1182
|
} else if(!empty($localport)) {
|
1183
|
$dstport = array($localport);
|
1184
|
}
|
1185
|
} else {
|
1186
|
$dstport = array(str_replace("-", ":", $rule['destination']['port']));
|
1187
|
$dstport_split = explode(":", $dstport[0]);
|
1188
|
|
1189
|
if(!empty($localport) && $dstport_split[0] != $rule['local-port']) {
|
1190
|
if(!is_alias($rule['local-port']) && $dstport_split[1] && $dstport_split[0] != $dstport_split[1]) {
|
1191
|
$localendport = $localport + ($dstport_split[1] - $dstport_split[0]);
|
1192
|
$localport .= ":$localendport";
|
1193
|
}
|
1194
|
|
1195
|
$dstport = array($localport);
|
1196
|
} else
|
1197
|
$localport = "";
|
1198
|
}
|
1199
|
|
1200
|
$dstaddr = explode(" ", $dstaddr_port);
|
1201
|
if($dstaddr[2]) {
|
1202
|
$rflctintrange = array_pop($dstaddr);
|
1203
|
array_pop($dstaddr);
|
1204
|
} else
|
1205
|
return "";
|
1206
|
$dstaddr = implode(" ", $dstaddr);
|
1207
|
if(empty($dstaddr) || trim($dstaddr) == "0.0.0.0" || strtolower(trim($dstaddr)) == "port")
|
1208
|
return "";
|
1209
|
|
1210
|
if(isset($rule['destination']['any'])) {
|
1211
|
if(!$rule['interface'])
|
1212
|
$natif = "wan";
|
1213
|
else
|
1214
|
$natif = $rule['interface'];
|
1215
|
|
1216
|
if(!isset($FilterIflist[$natif]))
|
1217
|
return "";
|
1218
|
if(is_ipaddr($FilterIflist[$natif]['ip']))
|
1219
|
$dstaddr = $FilterIflist[$natif]['ip'];
|
1220
|
else
|
1221
|
return "";
|
1222
|
|
1223
|
if(!empty($FilterIflist[$natif]['sn']))
|
1224
|
$dstaddr = gen_subnet($dstaddr, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
|
1225
|
}
|
1226
|
|
1227
|
switch($rule['protocol']) {
|
1228
|
case "tcp/udp":
|
1229
|
$protocol = "{ tcp udp }";
|
1230
|
$reflect_protos = array('tcp', 'udp');
|
1231
|
break;
|
1232
|
case "tcp":
|
1233
|
case "udp":
|
1234
|
$protocol = $rule['protocol'];
|
1235
|
$reflect_protos = array($rule['protocol']);
|
1236
|
break;
|
1237
|
default:
|
1238
|
return "";
|
1239
|
break;
|
1240
|
}
|
1241
|
|
1242
|
if(!empty($nordr)) {
|
1243
|
$natrules .= "no rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange}\n";
|
1244
|
return $natrules;
|
1245
|
}
|
1246
|
|
1247
|
if (is_alias($rule['target']))
|
1248
|
$target = filter_expand_alias($rule['target']);
|
1249
|
else if(is_ipaddr($rule['target']))
|
1250
|
$target = $rule['target'];
|
1251
|
else if (is_ipaddr($FilterIflist[$rule['target']]['ip']))
|
1252
|
$target = $FilterIflist[$rule['target']]['ip'];
|
1253
|
else
|
1254
|
return "";
|
1255
|
$starting_localhost_port_tmp = $starting_localhost_port;
|
1256
|
$toomanyports = false;
|
1257
|
/* only install reflection rules for < 19991 items */
|
1258
|
foreach($dstport as $loc_pt) {
|
1259
|
if($starting_localhost_port < 19991) {
|
1260
|
$toadd_array = array();
|
1261
|
$inetdport = $starting_localhost_port;
|
1262
|
$rflctrange = $starting_localhost_port;
|
1263
|
|
1264
|
$loc_pt = explode(":", $loc_pt);
|
1265
|
if($loc_pt[1] && $loc_pt[1] > $loc_pt[0])
|
1266
|
$delta = $loc_pt[1] - $loc_pt[0];
|
1267
|
else
|
1268
|
$delta = 0;
|
1269
|
|
1270
|
if(($inetdport + $delta + 1) - $starting_localhost_port_tmp > 500) {
|
1271
|
log_error("Not installing NAT reflection rules for a port range > 500");
|
1272
|
$inetdport = $starting_localhost_port;
|
1273
|
$toadd_array = array();
|
1274
|
$toomanyports = true;
|
1275
|
break;
|
1276
|
} else if(($inetdport + $delta) > 19990) {
|
1277
|
log_error("Installing partial NAT reflection rules. Maximum 1,000 reached.");
|
1278
|
$delta = 19990 - $inetdport;
|
1279
|
$loc_pt[1] = $loc_pt[0] + $delta;
|
1280
|
if($delta == 0)
|
1281
|
unset($loc_pt[1]);
|
1282
|
$toomanyports = true;
|
1283
|
|
1284
|
if(!empty($localport)) {
|
1285
|
if(is_alias($rule['destination']['port'])) {
|
1286
|
$rflctintrange = alias_expand($rule['destination']['port']);
|
1287
|
} else {
|
1288
|
if($dstport_split[1])
|
1289
|
$dstport_split[1] = $dstport_split[0] + $inetdport + $delta - $starting_localhost_port;
|
1290
|
$rflctintrange = implode(":", $dstport_split);
|
1291
|
}
|
1292
|
}
|
1293
|
}
|
1294
|
|
1295
|
if(empty($localport))
|
1296
|
$rflctintrange = implode(":", $loc_pt);
|
1297
|
if($inetdport + $delta > $starting_localhost_port)
|
1298
|
$rflctrange .= ":" . ($inetdport + $delta);
|
1299
|
$starting_localhost_port = $inetdport + $delta + 1;
|
1300
|
$toadd_array = array_merge($toadd_array, range($loc_pt[0], $loc_pt[0] + $delta));
|
1301
|
|
1302
|
if(!empty($toadd_array)) {
|
1303
|
$rtarget = explode(" ", trim($target));
|
1304
|
foreach($toadd_array as $tda) {
|
1305
|
if (empty($tda))
|
1306
|
continue;
|
1307
|
foreach($reflect_protos as $reflect_proto) {
|
1308
|
if($reflect_proto == "udp") {
|
1309
|
$socktype = "dgram";
|
1310
|
$dash_u = "-u ";
|
1311
|
$wait = "wait\t";
|
1312
|
} else {
|
1313
|
$socktype = "stream";
|
1314
|
$dash_u = "";
|
1315
|
$wait = "nowait/0";
|
1316
|
}
|
1317
|
foreach ($rtarget as $targip) {
|
1318
|
if (empty($targip))
|
1319
|
continue;
|
1320
|
$reflection_txt[] = "{$inetdport}\t{$socktype}\t{$reflect_proto}\t{$wait}\tnobody\t/usr/bin/nc\tnc {$dash_u}-w {$reflectiontimeout} {$targip} {$tda}\n";
|
1321
|
}
|
1322
|
}
|
1323
|
$inetdport++;
|
1324
|
}
|
1325
|
$natrules .= "rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange} tag PFREFLECT -> 127.0.0.1 port {$rflctrange}\n";
|
1326
|
}
|
1327
|
}
|
1328
|
|
1329
|
if($toomanyports)
|
1330
|
break;
|
1331
|
}
|
1332
|
|
1333
|
$reflection_txt = array_unique($reflection_txt);
|
1334
|
}
|
1335
|
|
1336
|
return $natrules;
|
1337
|
}
|
1338
|
|
1339
|
function filter_nat_rules_automatic_tonathosts($with_descr = false) {
|
1340
|
global $config, $FilterIflist, $GatewaysList;
|
1341
|
|
1342
|
$tonathosts = array("127.0.0.0/8");
|
1343
|
$descriptions = array(gettext("localhost"), gettext("localhost"));
|
1344
|
|
1345
|
foreach (get_staticroutes() as $route) {
|
1346
|
$netip = explode("/", $route['network']);
|
1347
|
if (isset($GatewaysList[$route['gateway']])) {
|
1348
|
$gateway =& $GatewaysList[$route['gateway']];
|
1349
|
if(!interface_has_gateway($gateway['interface']) && is_private_ip($netip[0])) {
|
1350
|
$tonathosts[] = $route['network'];
|
1351
|
$descriptions[] = gettext("static route");
|
1352
|
}
|
1353
|
}
|
1354
|
}
|
1355
|
|
1356
|
/* create outbound nat entries for all local networks */
|
1357
|
foreach($FilterIflist as $ocname => $oc) {
|
1358
|
if(interface_has_gateway($ocname))
|
1359
|
continue;
|
1360
|
if(is_ipaddr($oc['alias-address'])) {
|
1361
|
$tonathosts[] = "{$oc['alias-address']}/{$oc['alias-subnet']}";
|
1362
|
$descriptions[] = $oc['descr'] . " " . gettext("DHCP alias address");
|
1363
|
}
|
1364
|
if($oc['sa']) {
|
1365
|
$tonathosts[] = "{$oc['sa']}/{$oc['sn']}";
|
1366
|
$descriptions[] = $oc['descr'];
|
1367
|
}
|
1368
|
}
|
1369
|
|
1370
|
/* PPTP subnet */
|
1371
|
if(($config['pptpd']['mode'] == "server" ) && is_private_ip($config['pptpd']['remoteip'])) {
|
1372
|
if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
|
1373
|
$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
|
1374
|
long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
|
1375
|
else
|
1376
|
$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'],
|
1377
|
long2ip32(ip2long($config['pptpd']['remoteip'])));
|
1378
|
|
1379
|
foreach ($pptp_subnets as $subnet) {
|
1380
|
$tonathosts[] = $subnet;
|
1381
|
$descriptions[] = gettext("PPTP server");
|
1382
|
}
|
1383
|
}
|
1384
|
|
1385
|
/* PPPoE subnet */
|
1386
|
if (is_array($FilterIflist['pppoe']))
|
1387
|
foreach ($FilterIflist['pppoe'] as $pppoe)
|
1388
|
if(is_private_ip($pppoe['ip'])) {
|
1389
|
$tonathosts[] = "{$pppoe['sa']}/{$pppoe['sn']}";
|
1390
|
$descriptions[] = gettext("PPPoE server");
|
1391
|
}
|
1392
|
|
1393
|
/* L2TP subnet */
|
1394
|
if(isset($FilterIflist['l2tp']) && $FilterIflist['l2tp']['mode'] == "server") {
|
1395
|
$l2tp_sa = $FilterIflist['l2tp']['sa'];
|
1396
|
$l2tp_sn = $FilterIflist['l2tp']['sn'];
|
1397
|
if(is_private_ip($l2tp_sa) && !empty($l2tp_sn)) {
|
1398
|
$tonathosts[] = "{$l2tp_sa}/{$l2tp_sn}";
|
1399
|
$descriptions[] = gettext("L2TP server");
|
1400
|
}
|
1401
|
}
|
1402
|
|
1403
|
/* add openvpn interfaces */
|
1404
|
if(is_array($config['openvpn']['openvpn-server']))
|
1405
|
foreach ($config['openvpn']['openvpn-server'] as $ovpnsrv)
|
1406
|
if (!empty($ovpnsrv['tunnel_network'])) {
|
1407
|
$tonathosts[] = $ovpnsrv['tunnel_network'];
|
1408
|
$descriptions[] = gettext("OpenVPN server");
|
1409
|
}
|
1410
|
|
1411
|
if(is_array($config['openvpn']['openvpn-client']))
|
1412
|
foreach ($config['openvpn']['openvpn-client'] as $ovpncli)
|
1413
|
if (!empty($ovpncli['tunnel_network'])) {
|
1414
|
$tonathosts[] = $ovpncli['tunnel_network'];
|
1415
|
$descriptions[] = gettext("OpenVPN client");
|
1416
|
}
|
1417
|
|
1418
|
/* IPsec mode_cfg subnet */
|
1419
|
if (isset($config['ipsec']['client']['enable']) &&
|
1420
|
!empty($config['ipsec']['client']['pool_address']) &&
|
1421
|
!empty($config['ipsec']['client']['pool_netbits'])) {
|
1422
|
$tonathosts[] = "{$config['ipsec']['client']['pool_address']}/{$config['ipsec']['client']['pool_netbits']}";
|
1423
|
$descriptions[] = gettext("IPsec client");
|
1424
|
}
|
1425
|
|
1426
|
if ($with_descr) {
|
1427
|
$combined = array();
|
1428
|
foreach ($tonathosts as $idx => $subnet) {
|
1429
|
$combined[] = array(
|
1430
|
"subnet" => $subnet,
|
1431
|
"descr" => $descriptions[$idx]);
|
1432
|
}
|
1433
|
|
1434
|
return $combined;
|
1435
|
} else
|
1436
|
return $tonathosts;
|
1437
|
}
|
1438
|
|
1439
|
function filter_nat_rules_outbound_automatic($src) {
|
1440
|
global $config, $FilterIflist;
|
1441
|
|
1442
|
$rules = array();
|
1443
|
foreach ($FilterIflist as $if => $ifcfg) {
|
1444
|
if (substr($ifcfg['if'], 0, 4) == "ovpn")
|
1445
|
continue;
|
1446
|
if (!interface_has_gateway($if))
|
1447
|
continue;
|
1448
|
|
1449
|
$natent = array();
|
1450
|
$natent['interface'] = $if;
|
1451
|
$natent['source']['network'] = $src;
|
1452
|
$natent['dstport'] = "500";
|
1453
|
$natent['target'] = $ifcfg['ip'];
|
1454
|
$natent['destination']['any'] = true;
|
1455
|
$natent['staticnatport'] = true;
|
1456
|
$natent['descr'] = gettext('Auto created rule for ISAKMP');
|
1457
|
$rules[] = $natent;
|
1458
|
|
1459
|
$natent = array();
|
1460
|
$natent['interface'] = $if;
|
1461
|
$natent['source']['network'] = $src;
|
1462
|
$natent['sourceport'] = "";
|
1463
|
$natent['target'] = $ifcfg['ip'];
|
1464
|
$natent['destination']['any'] = true;
|
1465
|
$natent['natport'] = "";
|
1466
|
$natent['descr'] = gettext('Auto created rule');
|
1467
|
if (isset($ifcfg['nonat']))
|
1468
|
$natent['nonat'] = true;
|
1469
|
$rules[] = $natent;
|
1470
|
}
|
1471
|
|
1472
|
return $rules;
|
1473
|
}
|
1474
|
|
1475
|
/* Generate a 'nat on' or 'no nat on' rule for given interface */
|
1476
|
function filter_nat_rules_generate_if($if, $src = "any", $srcport = "", $dst = "any", $dstport = "", $natip = "", $natport = "", $nonat = false, $staticnatport = false, $proto = "", $poolopts = "") {
|
1477
|
global $config, $FilterIflist;
|
1478
|
/* XXX: billm - any idea if this code is needed? */
|
1479
|
if($src == "/32" || $src{0} == "/")
|
1480
|
return "# src incorrectly specified\n";
|
1481
|
if($natip != "") {
|
1482
|
if (is_subnet($natip))
|
1483
|
$tgt = $natip;
|
1484
|
elseif (is_alias($natip))
|
1485
|
$tgt = "\${$natip}";
|
1486
|
else
|
1487
|
$tgt = "{$natip}/32";
|
1488
|
} else {
|
1489
|
$natip = get_interface_ip($if);
|
1490
|
if(is_ipaddr($natip))
|
1491
|
$tgt = "{$natip}/32";
|
1492
|
else
|
1493
|
$tgt = "(" . $FilterIflist[$if]['if'] . ")";
|
1494
|
}
|
1495
|
/* Add the protocol, if defined */
|
1496
|
if (!empty($proto) && $proto != "any") {
|
1497
|
if ($proto == "tcp/udp")
|
1498
|
$protocol = " proto { tcp udp }";
|
1499
|
else
|
1500
|
$protocol = " proto {$proto}";
|
1501
|
} else
|
1502
|
$protocol = "";
|
1503
|
/* Set tgt for IPv6 */
|
1504
|
if ($proto == "ipv6") {
|
1505
|
$natip = get_interface_ipv6($if);
|
1506
|
if(is_ipaddrv6($natip))
|
1507
|
$tgt = "{$natip}/128";
|
1508
|
}
|
1509
|
/* Add the hard set source port (useful for ISAKMP) */
|
1510
|
if($natport != "")
|
1511
|
$tgt .= " port {$natport}";
|
1512
|
/* sometimes this gets called with "" instead of a value */
|
1513
|
if($src == "")
|
1514
|
$src = "any";
|
1515
|
/* Match on this source port */
|
1516
|
if($srcport != "") {
|
1517
|
$srcportexpand = alias_expand($srcport);
|
1518
|
if(!$srcportexpand)
|
1519
|
$srcportexpand = $srcport;
|
1520
|
$src .= " port {$srcportexpand}";
|
1521
|
}
|
1522
|
/* sometimes this gets called with "" instead of a value */
|
1523
|
if($dst == "")
|
1524
|
$dst = "any";
|
1525
|
/* Match on this dest port */
|
1526
|
if($dstport != "") {
|
1527
|
$dstportexpand = alias_expand($dstport);
|
1528
|
if(!$dstportexpand)
|
1529
|
$dstportexpand = $dstport;
|
1530
|
$dst .= " port {$dstportexpand}";
|
1531
|
}
|
1532
|
/* outgoing static-port option, hamachi, Grandstream, VOIP, etc */
|
1533
|
$staticnatport_txt = "";
|
1534
|
if($staticnatport)
|
1535
|
$staticnatport_txt = "static-port";
|
1536
|
elseif(!$natport)
|
1537
|
$tgt .= " port 1024:65535"; // set source port range
|
1538
|
/* Allow for negating NAT entries */
|
1539
|
if($nonat) {
|
1540
|
$nat = "no nat";
|
1541
|
$target = "";
|
1542
|
$staticnatport_txt = "";
|
1543
|
$poolopts = "";
|
1544
|
} else {
|
1545
|
$nat = "nat";
|
1546
|
$target = "-> {$tgt}";
|
1547
|
}
|
1548
|
$if_friendly = $FilterIflist[$if]['descr'];
|
1549
|
/* Put all the pieces together */
|
1550
|
if($if_friendly)
|
1551
|
$natrule = "{$nat} on \${$if_friendly} {$protocol} from {$src} to {$dst} {$target} {$poolopts} {$staticnatport_txt}\n";
|
1552
|
else
|
1553
|
$natrule .= "# Could not convert {$if} to friendly name(alias)\n";
|
1554
|
return $natrule;
|
1555
|
}
|
1556
|
|
1557
|
function filter_nat_rules_generate() {
|
1558
|
global $config, $g, $after_filter_configure_run, $FilterIflist, $GatewaysList, $aliases;
|
1559
|
|
1560
|
$natrules = "no nat proto carp\n";
|
1561
|
$natrules .= "no rdr proto carp\n";
|
1562
|
$natrules .= "nat-anchor \"natearly/*\"\n";
|
1563
|
|
1564
|
$natrules .= "nat-anchor \"natrules/*\"\n\n";
|
1565
|
update_filter_reload_status(gettext("Creating 1:1 rules..."));
|
1566
|
|
1567
|
$reflection_txt = "";
|
1568
|
$route_table = "";
|
1569
|
|
1570
|
/* any 1:1 mappings? */
|
1571
|
if(is_array($config['nat']['onetoone'])) {
|
1572
|
foreach ($config['nat']['onetoone'] as $rule) {
|
1573
|
if (isset($rule['disabled']))
|
1574
|
continue;
|
1575
|
|
1576
|
$sn = "";
|
1577
|
$sn1 = "";
|
1578
|
$target = alias_expand($rule['external']);
|
1579
|
if (!$target) {
|
1580
|
$natrules .= "# Unresolvable alias {$rule['target']}\n";
|
1581
|
continue; /* unresolvable alias */
|
1582
|
}
|
1583
|
|
1584
|
if (!$rule['interface'])
|
1585
|
$natif = "wan";
|
1586
|
else
|
1587
|
$natif = $rule['interface'];
|
1588
|
if (!isset($FilterIflist[$natif]))
|
1589
|
continue;
|
1590
|
|
1591
|
$srcaddr = filter_generate_address($rule, 'source');
|
1592
|
$dstaddr = filter_generate_address($rule, 'destination');
|
1593
|
if(!$dstaddr)
|
1594
|
$dstaddr = $FilterIflist[$natif]['ip'];
|
1595
|
|
1596
|
$srcaddr = trim($srcaddr);
|
1597
|
$dstaddr = trim($dstaddr);
|
1598
|
|
1599
|
$tmp = explode('/', $srcaddr);
|
1600
|
$srcip = $tmp[0];
|
1601
|
if (!empty($tmp[1]) && is_numeric($tmp[1])) {
|
1602
|
$sn = $tmp[1];
|
1603
|
$sn1 = "/{$sn}";
|
1604
|
}
|
1605
|
|
1606
|
$natif = $FilterIflist[$natif]['if'];
|
1607
|
|
1608
|
/*
|
1609
|
* If reflection is enabled, turn on extra redirections
|
1610
|
* for this rule by adding other interfaces to an rdr rule.
|
1611
|
*/
|
1612
|
if ((isset($config['system']['enablebinatreflection']) || $rule['natreflection'] == "enable")
|
1613
|
&& $rule['natreflection'] != "disable")
|
1614
|
$nat_if_list = filter_get_reflection_interfaces($natif);
|
1615
|
else
|
1616
|
$nat_if_list = array();
|
1617
|
|
1618
|
$natrules .= "binat on {$natif} from {$srcaddr} to {$dstaddr} -> {$target}{$sn1}\n";
|
1619
|
if (!empty($nat_if_list)) {
|
1620
|
$binat_if_list = implode(" ", $nat_if_list);
|
1621
|
$binat_if_list = "{ {$binat_if_list} }";
|
1622
|
$reflection_txt .= "rdr on {$binat_if_list} from {$dstaddr} to {$target}{$sn1} -> {$srcaddr} bitmask\n";
|
1623
|
}
|
1624
|
|
1625
|
$nat_if_list = array_merge(array($natif), $nat_if_list);
|
1626
|
$reflection_txt .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, "", $srcaddr, $srcip, $sn);
|
1627
|
}
|
1628
|
}
|
1629
|
|
1630
|
/* Add binat rules for Network Prefix translation */
|
1631
|
if(is_array($config['nat']['npt'])) {
|
1632
|
foreach ($config['nat']['npt'] as $rule) {
|
1633
|
if (isset($rule['disabled']))
|
1634
|
continue;
|
1635
|
|
1636
|
if (!$rule['interface'])
|
1637
|
$natif = "wan";
|
1638
|
else
|
1639
|
$natif = $rule['interface'];
|
1640
|
if (!isset($FilterIflist[$natif]))
|
1641
|
continue;
|
1642
|
|
1643
|
$srcaddr = filter_generate_address($rule, 'source');
|
1644
|
$dstaddr = filter_generate_address($rule, 'destination');
|
1645
|
|
1646
|
$srcaddr = trim($srcaddr);
|
1647
|
$dstaddr = trim($dstaddr);
|
1648
|
|
1649
|
$natif = $FilterIflist[$natif]['descr'];
|
1650
|
|
1651
|
$natrules .= "binat on \${$natif} from {$srcaddr} to any -> {$dstaddr}\n";
|
1652
|
$natrules .= "binat on \${$natif} from any to {$dstaddr} -> {$srcaddr}\n";
|
1653
|
|
1654
|
}
|
1655
|
}
|
1656
|
|
1657
|
/* ipsec nat */
|
1658
|
if (is_array($config['ipsec']) && isset($config['ipsec']['enable'])) {
|
1659
|
if (is_array($config['ipsec']['phase2'])) {
|
1660
|
foreach ($config['ipsec']['phase2'] as $ph2ent) {
|
1661
|
if ($ph2ent['mode'] != 'transport' && !empty($ph2ent['natlocalid'])) {
|
1662
|
if (!function_exists('ipsec_idinfo_to_cidr'))
|
1663
|
require_once("ipsec.inc");
|
1664
|
if (!is_array($ph2ent['localid']))
|
1665
|
$ph2ent['localid'] = array();
|
1666
|
$ph2ent['localid']['mode'] = $ph2ent['mode'];
|
1667
|
$local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid']);
|
1668
|
if (empty($local_subnet) || $local_subnet == "0.0.0.0/0")
|
1669
|
continue;
|
1670
|
if (!is_subnet($local_subnet) && !is_ipaddr($local_subnet))
|
1671
|
continue;
|
1672
|
if (!is_array($ph2ent['natlocalid']))
|
1673
|
$ph2ent['natlocalid'] = array();
|
1674
|
$ph2ent['natlocalid']['mode'] = $ph2ent['mode'];
|
1675
|
$natlocal_subnet = ipsec_idinfo_to_cidr($ph2ent['natlocalid']);
|
1676
|
if (empty($natlocal_subnet) || $natlocal_subnet == "0.0.0.0/0")
|
1677
|
continue;
|
1678
|
if (!is_subnet($natlocal_subnet) && !is_ipaddr($natlocal_subnet))
|
1679
|
continue;
|
1680
|
if (!is_array($ph2ent['remoteid']))
|
1681
|
$ph2ent['remoteid'] = array();
|
1682
|
$ph2ent['remoteid']['mode'] = $ph2ent['mode'];
|
1683
|
$remote_subnet = ipsec_idinfo_to_cidr($ph2ent['remoteid']);
|
1684
|
if (empty($remote_subnet))
|
1685
|
continue;
|
1686
|
if (!is_subnet($remote_subnet) && !is_ipaddr($remote_subnet))
|
1687
|
continue;
|
1688
|
if ($remote_subnet == "0.0.0.0/0")
|
1689
|
$remote_subnet = "any";
|
1690
|
if (is_ipaddr($natlocal_subnet) && !is_ipaddr($local_subnet) )
|
1691
|
$nattype = "nat";
|
1692
|
else
|
1693
|
$nattype = "binat";
|
1694
|
$natrules .= "{$nattype} on enc0 from {$local_subnet} to {$remote_subnet} -> {$natlocal_subnet}\n";
|
1695
|
}
|
1696
|
}
|
1697
|
}
|
1698
|
}
|
1699
|
|
1700
|
if ($config['nat']['outbound']['mode'] == "disabled")
|
1701
|
$natrules .= "\n# Outbound NAT rules are disabled\n";
|
1702
|
|
1703
|
if ($config['nat']['outbound']['mode'] == "advanced" || $config['nat']['outbound']['mode'] == "hybrid") {
|
1704
|
$natrules .= "\n# Outbound NAT rules (manual)\n";
|
1705
|
/* advanced outbound rules */
|
1706
|
if(is_array($config['nat']['outbound']['rule'])) {
|
1707
|
foreach ($config['nat']['outbound']['rule'] as $obent) {
|
1708
|
if (isset($obent['disabled']))
|
1709
|
continue;
|
1710
|
update_filter_reload_status(sprintf(gettext("Creating advanced outbound rule %s"), $obent['descr']));
|
1711
|
$src = alias_expand($obent['source']['network']);
|
1712
|
if(!$src)
|
1713
|
$src = $obent['source']['network'];
|
1714
|
$dst = alias_expand($obent['destination']['address']);
|
1715
|
if(!$dst)
|
1716
|
$dst = $obent['destination']['address'];
|
1717
|
if(isset($obent['destination']['not']) && !isset($obent['destination']['any']))
|
1718
|
$dst = "!" . $dst;
|
1719
|
|
1720
|
if(!$obent['interface'] || !isset($FilterIflist[$obent['interface']]))
|
1721
|
continue;
|
1722
|
|
1723
|
$obtarget = ($obent['target'] == "other-subnet") ? $obent['targetip'] . '/' . $obent['targetip_subnet']: $obent['target'];
|
1724
|
$poolopts = (is_subnet($obtarget) || is_alias($obtarget)) ? $obent['poolopts'] : "";
|
1725
|
|
1726
|
$natrules .= filter_nat_rules_generate_if($obent['interface'],
|
1727
|
$src,
|
1728
|
$obent['sourceport'],
|
1729
|
$dst,
|
1730
|
$obent['dstport'],
|
1731
|
$obtarget,
|
1732
|
$obent['natport'],
|
1733
|
isset($obent['nonat']),
|
1734
|
isset($obent['staticnatport']),
|
1735
|
$obent['protocol'],
|
1736
|
$poolopts
|
1737
|
);
|
1738
|
}
|
1739
|
}
|
1740
|
}
|
1741
|
|
1742
|
/* outbound rules */
|
1743
|
if (!isset($config['nat']['outbound']['mode']) ||
|
1744
|
$config['nat']['outbound']['mode'] == "automatic" ||
|
1745
|
$config['nat']['outbound']['mode'] == "hybrid") {
|
1746
|
$natrules .= "\n# Outbound NAT rules (automatic)\n";
|
1747
|
/* standard outbound rules (one for each interface) */
|
1748
|
update_filter_reload_status(gettext("Creating outbound NAT rules"));
|
1749
|
$tonathosts_array = filter_nat_rules_automatic_tonathosts();
|
1750
|
$tonathosts = implode(" ", $tonathosts_array);
|
1751
|
$numberofnathosts = count($tonathosts_array);
|
1752
|
|
1753
|
$natrules .= "\n# Subnets to NAT \n";
|
1754
|
if ($numberofnathosts > 0) {
|
1755
|
update_filter_reload_status(gettext('Creating automatic outbound rules'));
|
1756
|
|
1757
|
if ($numberofnathosts > 4) {
|
1758
|
$natrules .= "table <tonatsubnets> { {$tonathosts} }\n";
|
1759
|
$macroortable = "<tonatsubnets>";
|
1760
|
} else {
|
1761
|
$natrules .= "tonatsubnets = \"{ {$tonathosts} }\"\n";
|
1762
|
$macroortable = "\$tonatsubnets";
|
1763
|
}
|
1764
|
|
1765
|
$a_outs = filter_nat_rules_outbound_automatic($macroortable);
|
1766
|
foreach ($a_outs as $a_out) {
|
1767
|
$natrules .= filter_nat_rules_generate_if($a_out['interface'],
|
1768
|
$a_out['source']['network'],
|
1769
|
$a_out['sourceport'],
|
1770
|
$a_out['destination']['address'],
|
1771
|
$a_out['dstport'],
|
1772
|
$a_out['target'],
|
1773
|
$a_out['natport'],
|
1774
|
isset($a_out['nonat']),
|
1775
|
isset($a_out['staticnatport']));
|
1776
|
}
|
1777
|
}
|
1778
|
unset($tonathosts, $tonathosts_array, $numberofnathosts);
|
1779
|
}
|
1780
|
|
1781
|
/* load balancer anchor */
|
1782
|
$natrules .= "\n# Load balancing anchor\n";
|
1783
|
$natrules .= "rdr-anchor \"relayd/*\"\n";
|
1784
|
|
1785
|
update_filter_reload_status(gettext("Setting up TFTP helper"));
|
1786
|
$natrules .= "# TFTP proxy\n";
|
1787
|
$natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
|
1788
|
|
1789
|
if (!empty($config['system']['tftpinterface'])) {
|
1790
|
$tftpifs = explode(",", $config['system']['tftpinterface']);
|
1791
|
foreach($tftpifs as $tftpif) {
|
1792
|
if ($FilterIflist[$tftpif])
|
1793
|
$natrules .= "rdr pass on {$FilterIflist[$tftpif]['if']} proto udp from any to any port tftp -> 127.0.0.1 port 6969\n";
|
1794
|
}
|
1795
|
}
|
1796
|
|
1797
|
/* DIAG: add ipv6 NAT, if requested */
|
1798
|
if(isset($config['diag']['ipv6nat']['enable']) &&
|
1799
|
is_ipaddr($config['diag']['ipv6nat']['ipaddr']) &&
|
1800
|
is_array($FilterIflist['wan'])) {
|
1801
|
/* XXX: FIX ME! IPV6 */
|
1802
|
$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto ipv6 from any to any -> {$config['diag']['ipv6nat']['ipaddr']}\n";
|
1803
|
}
|
1804
|
|
1805
|
if(file_exists("/var/etc/inetd.conf"))
|
1806
|
@unlink("/var/etc/inetd.conf");
|
1807
|
// Open inetd.conf write handle
|
1808
|
$inetd_fd = fopen("/var/etc/inetd.conf","w");
|
1809
|
/* add tftp protocol helper */
|
1810
|
fwrite($inetd_fd, "tftp-proxy\tdgram\tudp\twait\t\troot\t/usr/libexec/tftp-proxy\ttftp-proxy -v\n");
|
1811
|
|
1812
|
if(isset($config['nat']['rule'])) {
|
1813
|
/* start reflection redirects on port 19000 of localhost */
|
1814
|
$starting_localhost_port = 19000;
|
1815
|
$natrules .= "# NAT Inbound Redirects\n";
|
1816
|
foreach ($config['nat']['rule'] as $rule) {
|
1817
|
update_filter_reload_status(sprintf(gettext("Creating NAT rule %s"), $rule['descr']));
|
1818
|
|
1819
|
if(isset($rule['disabled']))
|
1820
|
continue;
|
1821
|
|
1822
|
/* if item is an alias, expand */
|
1823
|
$dstport = "";
|
1824
|
$dstport[0] = alias_expand($rule['destination']['port']);
|
1825
|
if(!$dstport[0])
|
1826
|
$dstport = explode("-", $rule['destination']['port']);
|
1827
|
|
1828
|
/* if item is an alias, expand */
|
1829
|
$localport = alias_expand($rule['local-port']);
|
1830
|
if(!$localport || $dstport[0] == $localport) {
|
1831
|
$localport = "";
|
1832
|
} else if(is_alias($rule['local-port'])) {
|
1833
|
$localport = filter_expand_alias($rule['local-port']);
|
1834
|
if($localport) {
|
1835
|
$localport = explode(" ", trim($localport));
|
1836
|
$localport = $localport[0];
|
1837
|
$localport = " port {$localport}";
|
1838
|
}
|
1839
|
} else if(is_alias($rule['destination']['port'])) {
|
1840
|
$localport = " port {$localport}";
|
1841
|
} else {
|
1842
|
if(($dstport[1]) && ($dstport[0] != $dstport[1])) {
|
1843
|
$localendport = $localport + ($dstport[1] - $dstport[0]);
|
1844
|
|
1845
|
$localport .= ":$localendport";
|
1846
|
}
|
1847
|
|
1848
|
$localport = " port {$localport}";
|
1849
|
}
|
1850
|
|
1851
|
switch(strtolower($rule['protocol'])) {
|
1852
|
case "tcp/udp":
|
1853
|
$protocol = "{ tcp udp }";
|
1854
|
break;
|
1855
|
case "tcp":
|
1856
|
case "udp":
|
1857
|
$protocol = strtolower($rule['protocol']);
|
1858
|
break;
|
1859
|
default:
|
1860
|
$protocol = strtolower($rule['protocol']);
|
1861
|
$localport = "";
|
1862
|
break;
|
1863
|
}
|
1864
|
|
1865
|
$target = alias_expand($rule['target']);
|
1866
|
if(!$target && !isset($rule['nordr'])) {
|
1867
|
$natrules .= "# Unresolvable alias {$rule['target']}\n";
|
1868
|
continue; /* unresolvable alias */
|
1869
|
}
|
1870
|
|
1871
|
if(is_alias($rule['target']))
|
1872
|
$target_ip = filter_expand_alias($rule['target']);
|
1873
|
else if(is_ipaddr($rule['target']))
|
1874
|
$target_ip = $rule['target'];
|
1875
|
else if(is_ipaddr($FilterIflist[$rule['target']]['ip']))
|
1876
|
$target_ip = $FilterIflist[$rule['target']]['ip'];
|
1877
|
else
|
1878
|
$target_ip = $rule['target'];
|
1879
|
$target_ip = trim($target_ip);
|
1880
|
|
1881
|
if($rule['associated-rule-id'] == "pass")
|
1882
|
$rdrpass = "pass ";
|
1883
|
else
|
1884
|
$rdrpass = "";
|
1885
|
|
1886
|
if (isset($rule['nordr'])) {
|
1887
|
$nordr = "no ";
|
1888
|
$rdrpass = "";
|
1889
|
} else
|
1890
|
$nordr = "";
|
1891
|
|
1892
|
if(!$rule['interface'])
|
1893
|
$natif = "wan";
|
1894
|
else
|
1895
|
$natif = $rule['interface'];
|
1896
|
|
1897
|
if (!isset($FilterIflist[$natif]))
|
1898
|
continue;
|
1899
|
|
1900
|
$srcaddr = filter_generate_address($rule, 'source', true);
|
1901
|
$dstaddr = filter_generate_address($rule, 'destination', true);
|
1902
|
$srcaddr = trim($srcaddr);
|
1903
|
$dstaddr = trim($dstaddr);
|
1904
|
|
1905
|
if(!$dstaddr)
|
1906
|
$dstaddr = $FilterIflist[$natif]['ip'];
|
1907
|
|
1908
|
$dstaddr_port = explode(" ", $dstaddr);
|
1909
|
if(empty($dstaddr_port[0]) || strtolower(trim($dstaddr_port[0])) == "port")
|
1910
|
continue; // Skip port forward if no destination address found
|
1911
|
$dstaddr_reflect = $dstaddr;
|
1912
|
if(isset($rule['destination']['any'])) {
|
1913
|
/* With reflection enabled, destination of 'any' has side effects
|
1914
|
* that most people would not expect, so change it on reflection rules. */
|
1915
|
$dstaddr_reflect = $FilterIflist[$natif]['ip'];
|
1916
|
if(!empty($FilterIflist[$natif]['sn']))
|
1917
|
$dstaddr_reflect = gen_subnet($dstaddr_reflect, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
|
1918
|
|
1919
|
if($dstaddr_port[2])
|
1920
|
$dstaddr_reflect .= " port " . $dstaddr_port[2];
|
1921
|
}
|
1922
|
|
1923
|
$natif = $FilterIflist[$natif]['if'];
|
1924
|
|
1925
|
$reflection_type = "none";
|
1926
|
if($rule['natreflection'] != "disable" && $dstaddr_port[0] != "0.0.0.0") {
|
1927
|
if($rule['natreflection'] == "enable")
|
1928
|
$reflection_type = "proxy";
|
1929
|
else if($rule['natreflection'] == "purenat")
|
1930
|
$reflection_type = "purenat";
|
1931
|
else if(!isset($config['system']['disablenatreflection'])) {
|
1932
|
if(isset($config['system']['enablenatreflectionpurenat']))
|
1933
|
$reflection_type = "purenat";
|
1934
|
else
|
1935
|
$reflection_type = "proxy";
|
1936
|
}
|
1937
|
}
|
1938
|
|
1939
|
if($reflection_type != "none")
|
1940
|
$nat_if_list = filter_get_reflection_interfaces($natif);
|
1941
|
else
|
1942
|
$nat_if_list = array();
|
1943
|
|
1944
|
if(empty($nat_if_list))
|
1945
|
$reflection_type = "none";
|
1946
|
|
1947
|
$localport_nat = $localport;
|
1948
|
if(empty($localport_nat) && $dstaddr_port[2])
|
1949
|
$localport_nat = " port " . $dstaddr_port[2];
|
1950
|
|
1951
|
if($srcaddr <> "" && $dstaddr <> "" && $natif) {
|
1952
|
$natrules .= "{$nordr}rdr {$rdrpass}on {$natif} proto {$protocol} from {$srcaddr} to {$dstaddr}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
|
1953
|
|
1954
|
/* Does this rule redirect back to a internal host? */
|
1955
|
if(isset($rule['destination']['any']) && !isset($rule['nordr']) && !isset($config['system']['enablenatreflectionhelper']) && !interface_has_gateway($rule['interface'])) {
|
1956
|
$rule_interface_ip = find_interface_ip($natif);
|
1957
|
$rule_interface_subnet = find_interface_subnet($natif);
|
1958
|
if(!empty($rule_interface_ip) && !empty($rule_interface_subnet)) {
|
1959
|
$rule_subnet = gen_subnet($rule_interface_ip, $rule_interface_subnet);
|
1960
|
$natrules .= "\n";
|
1961
|
$natrules .= "no nat on {$natif} proto tcp from ({$natif}) to {$rule_subnet}/{$rule_interface_subnet}\n";
|
1962
|
$natrules .= "nat on {$natif} proto tcp from {$rule_subnet}/{$rule_interface_subnet} to {$target} port {$dstport[0]} -> ({$natif})\n";
|
1963
|
}
|
1964
|
}
|
1965
|
|
1966
|
if ($reflection_type != "none") {
|
1967
|
if($reflection_type == "proxy" && !isset($rule['nordr'])) {
|
1968
|
$natrules .= filter_generate_reflection_proxy($rule, $nordr, $nat_if_list, $srcaddr, $dstaddr, $starting_localhost_port, $reflection_rules);
|
1969
|
$nat_if_list = array($natif);
|
1970
|
foreach ($reflection_rules as $txtline)
|
1971
|
fwrite($inetd_fd, $txtline);
|
1972
|
} else if($reflection_type == "purenat" || isset($rule['nordr'])) {
|
1973
|
$rdr_if_list = implode(" ", $nat_if_list);
|
1974
|
if(count($nat_if_list) > 1)
|
1975
|
$rdr_if_list = "{ {$rdr_if_list} }";
|
1976
|
$natrules .= "\n# Reflection redirect\n";
|
1977
|
$natrules .= "{$nordr}rdr {$rdrpass}on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr_reflect}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
|
1978
|
$nat_if_list = array_merge(array($natif), $nat_if_list);
|
1979
|
}
|
1980
|
}
|
1981
|
|
1982
|
if(empty($nat_if_list))
|
1983
|
$nat_if_list = array($natif);
|
1984
|
|
1985
|
$natrules .= "\n";
|
1986
|
if(!isset($rule['nordr']))
|
1987
|
$natrules .= filter_generate_reflection_nat($rule, $route_table, $nat_if_list, $protocol, "{$target}{$localport_nat}", $target_ip);
|
1988
|
}
|
1989
|
}
|
1990
|
}
|
1991
|
fclose($inetd_fd); // Close file handle
|
1992
|
|
1993
|
if (isset($config['pptpd']['mode']) && ($config['pptpd']['mode'] != "off")) {
|
1994
|
if ($config['pptpd']['mode'] == "redir") {
|
1995
|
$pptpdtarget = $config['pptpd']['redir'];
|
1996
|
$natrules .= "# PPTP\n";
|
1997
|
$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto gre from any to any -> {$pptpdtarget}\n";
|
1998
|
$natrules .= "rdr on \${$FilterIflist['wan']['descr']} proto tcp from any to any port 1723 -> {$pptpdtarget}\n";
|
1999
|
}
|
2000
|
}
|
2001
|
|
2002
|
$natrules .= discover_pkg_rules("nat");
|
2003
|
|
2004
|
$natrules .= "# UPnPd rdr anchor\n";
|
2005
|
$natrules .= "rdr-anchor \"miniupnpd\"\n";
|
2006
|
|
2007
|
if(!empty($reflection_txt))
|
2008
|
$natrules .= "\n# Reflection redirects and NAT for 1:1 mappings\n" . $reflection_txt;
|
2009
|
|
2010
|
// Check if inetd is running, if not start it. If so, restart it gracefully.
|
2011
|
$helpers = isvalidproc("inetd");
|
2012
|
if(file_exists("/var/etc/inetd.conf")) {
|
2013
|
if(!$helpers)
|
2014
|
mwexec("/usr/sbin/inetd -wW -R 0 -a 127.0.0.1 /var/etc/inetd.conf");
|
2015
|
else
|
2016
|
sigkillbypid("/var/run/inetd.pid", "HUP");
|
2017
|
}
|
2018
|
|
2019
|
return $natrules;
|
2020
|
}
|
2021
|
|
2022
|
function filter_generate_user_rule_arr($rule) {
|
2023
|
global $config;
|
2024
|
update_filter_reload_status(sprintf(gettext("Creating filter rule %s ..."), $rule['descr']));
|
2025
|
$ret = array();
|
2026
|
$line = filter_generate_user_rule($rule);
|
2027
|
$ret['rule'] = $line;
|
2028
|
$ret['interface'] = $rule['interface'];
|
2029
|
if($rule['descr'] != "" and $line != "")
|
2030
|
$ret['descr'] = "label \"" . fix_rule_label("USER_RULE: {$rule['descr']}") . "\"";
|
2031
|
else
|
2032
|
$ret['descr'] = "label \"USER_RULE\"";
|
2033
|
|
2034
|
return $ret;
|
2035
|
}
|
2036
|
|
2037
|
function filter_generate_port(& $rule, $target = "source", $isnat = false) {
|
2038
|
|
2039
|
$src = "";
|
2040
|
|
2041
|
$rule['protocol'] = strtolower($rule['protocol']);
|
2042
|
if(in_array($rule['protocol'], array("tcp","udp","tcp/udp"))) {
|
2043
|
if($rule[$target]['port']) {
|
2044
|
$srcport = explode("-", $rule[$target]['port']);
|
2045
|
$srcporta = alias_expand($srcport[0]);
|
2046
|
if(!$srcporta)
|
2047
|
log_error(sprintf(gettext("filter_generate_port: %s is not a valid {$target} port."), $srcport[0]));
|
2048
|
else if((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
|
2049
|
$src .= " port {$srcporta} ";
|
2050
|
} else if(($srcport[0] == 1) && ($srcport[1] == 65535)) {
|
2051
|
/* no need for a port statement here */
|
2052
|
} else if ($isnat) {
|
2053
|
$src .= " port {$srcport[0]}:{$srcport[1]}";
|
2054
|
} else {
|
2055
|
if(is_port($srcporta) && $srcport[1] == 65535) {
|
2056
|
$src .= " port >= {$srcporta} ";
|
2057
|
} else if($srcport[0] == 1) {
|
2058
|
$src .= " port <= {$srcport[1]} ";
|
2059
|
} else {
|
2060
|
$srcport[0]--;
|
2061
|
$srcport[1]++;
|
2062
|
$src .= " port {$srcport[0]} >< {$srcport[1]} ";
|
2063
|
}
|
2064
|
}
|
2065
|
}
|
2066
|
}
|
2067
|
|
2068
|
return $src;
|
2069
|
}
|
2070
|
|
2071
|
function filter_generate_address(& $rule, $target = "source", $isnat = false) {
|
2072
|
global $FilterIflist, $config;
|
2073
|
$src = "";
|
2074
|
|
2075
|
if(isset($rule[$target]['any'])) {
|
2076
|
$src = "any";
|
2077
|
} else if($rule[$target]['network']) {
|
2078
|
if(strstr($rule[$target]['network'], "opt")) {
|
2079
|
$optmatch = "";
|
2080
|
$matches = "";
|
2081
|
if($rule['ipprotocol'] == "inet6") {
|
2082
|
if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
|
2083
|
$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ipv6'];
|
2084
|
if(!is_ipaddrv6($opt_ip))
|
2085
|
return "";
|
2086
|
$src = $opt_ip . "/" .
|
2087
|
$FilterIflist["opt{$optmatch[1]}"]['snv6'];
|
2088
|
/* check for opt$NUMip here */
|
2089
|
} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
|
2090
|
$src = $FilterIflist["opt{$matches[1]}"]['ipv6'];
|
2091
|
if(!is_ipaddrv6($src))
|
2092
|
return "";
|
2093
|
}
|
2094
|
if(isset($rule[$target]['not']))
|
2095
|
$src = " !{$src}";
|
2096
|
} else {
|
2097
|
if(preg_match("/opt([0-9]*)$/", $rule[$target]['network'], $optmatch)) {
|
2098
|
$opt_ip = $FilterIflist["opt{$optmatch[1]}"]['ip'];
|
2099
|
if(!is_ipaddrv4($opt_ip))
|
2100
|
return "";
|
2101
|
$src = $opt_ip . "/" .
|
2102
|
$FilterIflist["opt{$optmatch[1]}"]['sn'];
|
2103
|
/* check for opt$NUMip here */
|
2104
|
} else if(preg_match("/opt([0-9]*)ip/", $rule[$target]['network'], $matches)) {
|
2105
|
$src = $FilterIflist["opt{$matches[1]}"]['ip'];
|
2106
|
if(!is_ipaddrv4($src))
|
2107
|
return "";
|
2108
|
}
|
2109
|
if(isset($rule[$target]['not']))
|
2110
|
$src = " !{$src}";
|
2111
|
}
|
2112
|
} else {
|
2113
|
if($rule['ipprotocol'] == "inet6") {
|
2114
|
switch ($rule[$target]['network']) {
|
2115
|
case 'wan':
|
2116
|
$wansa = $FilterIflist['wan']['sav6'];
|
2117
|
if (!is_ipaddrv6($wansa))
|
2118
|
return "";
|
2119
|
$wansn = $FilterIflist['wan']['snv6'];
|
2120
|
$src = "{$wansa}/{$wansn}";
|
2121
|
break;
|
2122
|
case 'wanip':
|
2123
|
$src = $FilterIflist["wan"]['ipv6'];
|
2124
|
if (!is_ipaddrv6($src))
|
2125
|
return "";
|
2126
|
break;
|
2127
|
case 'lanip':
|
2128
|
$src = $FilterIflist["lan"]['ipv6'];
|
2129
|
if (!is_ipaddrv6($src))
|
2130
|
return "";
|
2131
|
break;
|
2132
|
case 'lan':
|
2133
|
$lansa = $FilterIflist['lan']['sav6'];
|
2134
|
if (!is_ipaddrv6($lansa))
|
2135
|
return "";
|
2136
|
$lansn = $FilterIflist['lan']['snv6'];
|
2137
|
$src = "{$lansa}/{$lansn}";
|
2138
|
break;
|
2139
|
case 'pptp':
|
2140
|
$pptpsav6 = gen_subnetv6($FilterIflist['pptp']['sav6'], $FilterIflist['pptp']['snv6']);
|
2141
|
$pptpsnv6 = $FilterIflist['pptp']['snv6'];
|
2142
|
$src = "{$pptpsav6}/{$pptpsnv6}";
|
2143
|
break;
|
2144
|
case 'pppoe':
|
2145
|
if (is_array($FilterIflist['pppoe'])) {
|
2146
|
$pppoesav6 = gen_subnetv6($FilterIflist['pppoe'][0]['ipv6'], $FilterIflist['pppoe'][0]['snv6']);
|
2147
|
$pppoesnv6 = $FilterIflist['pppoe'][0]['snv6'];
|
2148
|
$src = "{$pppoesav6}/{$pppoesnv6}";
|
2149
|
}
|
2150
|
}
|
2151
|
if(isset($rule[$target]['not']))
|
2152
|
$src = " !{$src}";
|
2153
|
} else {
|
2154
|
switch ($rule[$target]['network']) {
|
2155
|
case 'wan':
|
2156
|
$wansa = $FilterIflist['wan']['sa'];
|
2157
|
if (!is_ipaddrv4($wansa))
|
2158
|
return "";
|
2159
|
$wansn = $FilterIflist['wan']['sn'];
|
2160
|
$src = "{$wansa}/{$wansn}";
|
2161
|
break;
|
2162
|
case 'wanip':
|
2163
|
$src = $FilterIflist["wan"]['ip'];
|
2164
|
break;
|
2165
|
case 'lanip':
|
2166
|
$src = $FilterIflist["lan"]['ip'];
|
2167
|
break;
|
2168
|
case 'lan':
|
2169
|
$lansa = $FilterIflist['lan']['sa'];
|
2170
|
if (!is_ipaddrv4($lansa))
|
2171
|
return "";
|
2172
|
$lansn = $FilterIflist['lan']['sn'];
|
2173
|
$src = "{$lansa}/{$lansn}";
|
2174
|
break;
|
2175
|
case 'pptp':
|
2176
|
if (isset($config['pptpd']['n_pptp_units']) && is_numeric($config['pptpd']['n_pptp_units']))
|
2177
|
$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])+($config['pptpd']['n_pptp_units']-1)));
|
2178
|
else
|
2179
|
$pptp_subnets = ip_range_to_subnet_array($config['pptpd']['remoteip'], long2ip32(ip2long($config['pptpd']['remoteip'])));
|
2180
|
if (empty($pptp_subnets))
|
2181
|
return "";
|
2182
|
$src = "{ " . implode(" ", $pptp_subnets) . " }";
|
2183
|
break;
|
2184
|
case 'pppoe':
|
2185
|
/* XXX: This needs to be fixed somehow! */
|
2186
|
if (is_array($FilterIflist['pppoe'])) {
|
2187
|
$pppoesa = gen_subnet($FilterIflist['pppoe'][0]['ip'], $FilterIflist['pppoe'][0]['sn']);
|
2188
|
$pppoesn = $FilterIflist['pppoe'][0]['sn'];
|
2189
|
$src = "{$pppoesa}/{$pppoesn}";
|
2190
|
}
|
2191
|
break;
|
2192
|
}
|
2193
|
if(isset($rule[$target]['not']))
|
2194
|
$src = " !{$src}";
|
2195
|
}
|
2196
|
}
|
2197
|
} else if($rule[$target]['address']) {
|
2198
|
$expsrc = alias_expand($rule[$target]['address']);
|
2199
|
if(isset($rule[$target]['not']))
|
2200
|
$not = "!";
|
2201
|
else
|
2202
|
$not = "";
|
2203
|
$src = " {$not} {$expsrc}";
|
2204
|
}
|
2205
|
|
2206
|
$src .= filter_generate_port($rule, $target, $isnat);
|
2207
|
|
2208
|
return $src;
|
2209
|
}
|
2210
|
|
2211
|
function filter_generate_user_rule($rule) {
|
2212
|
global $config, $g, $FilterIflist, $GatewaysList;
|
2213
|
global $layer7_rules_list, $dummynet_name_list;
|
2214
|
|
2215
|
if(isset($config['system']['developerspew'])) {
|
2216
|
$mt = microtime();
|
2217
|
echo "filter_generate_user_rule() being called $mt\n";
|
2218
|
}
|
2219
|
/* don't include disabled rules */
|
2220
|
if(isset($rule['disabled'])) {
|
2221
|
return "# rule " . $rule['descr'] . " disabled \n";
|
2222
|
}
|
2223
|
update_filter_reload_status("Creating filter rules {$rule['descr']} ...");
|
2224
|
$pptpdcfg = $config['pptpd'];
|
2225
|
$int = "";
|
2226
|
$aline = array();
|
2227
|
|
2228
|
/* Check to see if the interface is in our list */
|
2229
|
if(isset($rule['floating'])) {
|
2230
|
if(isset($rule['interface']) && $rule['interface'] <> "") {
|
2231
|
$interfaces = explode(",", $rule['interface']);
|
2232
|
$ifliste = "";
|
2233
|
foreach ($interfaces as $iface) {
|
2234
|
if(array_key_exists($iface, $FilterIflist))
|
2235
|
$ifliste .= " " . $FilterIflist[$iface]['if'] . " ";
|
2236
|
}
|
2237
|
if($ifliste <> "")
|
2238
|
$aline['interface'] = " on { {$ifliste} } ";
|
2239
|
else
|
2240
|
$aline['interface'] = "";
|
2241
|
} else
|
2242
|
$aline['interface'] = "";
|
2243
|
} else if(!array_key_exists($rule['interface'], $FilterIflist)) {
|
2244
|
foreach($FilterIflist as $oc)
|
2245
|
$items .= $oc['descr'] . " ";
|
2246
|
return "# array key \"{$rule['interface']}\" does not exist for \"" . $rule['descr'] . "\" in array: {{$items}}";
|
2247
|
} else if((array_key_exists($rule['interface'], $FilterIflist))
|
2248
|
&& (is_array($FilterIflist[$rule['interface']]))
|
2249
|
&& (is_array($FilterIflist[$rule['interface']][0]))) {
|
2250
|
/* Currently this only case for this is the pppoe server. There should be an existing macro with this name. */
|
2251
|
$aline['interface'] = " on \$" . $rule['interface'] . " ";
|
2252
|
} else
|
2253
|
$aline['interface'] = " on \$" . $FilterIflist[$rule['interface']]['descr'] . " ";
|
2254
|
$ifcfg = $FilterIflist[$rule['interface']];
|
2255
|
if($pptpdcfg['mode'] != "server") {
|
2256
|
if(($rule['source']['network'] == "pptp") ||
|
2257
|
($rule['destination']['network'] == "pptp"))
|
2258
|
return "# source network or destination network == pptp on " . $rule['descr'];
|
2259
|
}
|
2260
|
|
2261
|
switch($rule['ipprotocol']) {
|
2262
|
case "inet":
|
2263
|
$aline['ipprotocol'] = "inet";
|
2264
|
break;
|
2265
|
case "inet6":
|
2266
|
$aline['ipprotocol'] = "inet6";
|
2267
|
break;
|
2268
|
default:
|
2269
|
$aline['ipprotocol'] = "";
|
2270
|
break;
|
2271
|
}
|
2272
|
|
2273
|
/* check for unresolvable aliases */
|
2274
|
if($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
|
2275
|
$error_text = "Unresolvable source alias '{$rule['source']['address']}' for rule '{$rule['descr']}'";
|
2276
|
file_notice("Filter_Reload", $error_text);
|
2277
|
return "# {$error_text}";
|
2278
|
}
|
2279
|
if($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
|
2280
|
$error_text = "Unresolvable destination alias '{$rule['destination']['address']}' for rule '{$rule['descr']}'";
|
2281
|
file_notice("Filter_Reload", $error_text);
|
2282
|
return "# {$error_text}";
|
2283
|
}
|
2284
|
update_filter_reload_status("Setting up pass/block rules");
|
2285
|
$type = $rule['type'];
|
2286
|
if($type != "pass" && $type != "block" && $type != "reject" && $type != "match") {
|
2287
|
/* default (for older rules) is pass */
|
2288
|
$type = "pass";
|
2289
|
}
|
2290
|
if($type == "reject") {
|
2291
|
$aline['type'] = "block return ";
|
2292
|
} else
|
2293
|
$aline['type'] = $type . " ";
|
2294
|
if(isset($rule['floating']) && $rule['floating'] == "yes") {
|
2295
|
if($rule['direction'] != "any")
|
2296
|
$aline['direction'] = " " . $rule['direction'] . " ";
|
2297
|
} else {
|
2298
|
/* ensure the direction is in */
|
2299
|
$aline['direction'] = " in ";
|
2300
|
}
|
2301
|
if(isset($rule['log']))
|
2302
|
$aline['log'] = "log ";
|
2303
|
if(!isset($rule['floating']) || isset($rule['quick']))
|
2304
|
$aline['quick'] = " quick ";
|
2305
|
|
2306
|
/* set the gateway interface */
|
2307
|
update_filter_reload_status(sprintf(gettext("Setting up pass/block rules %s"), $rule['descr']));
|
2308
|
|
2309
|
/* do not process reply-to for gateway'd rules */
|
2310
|
if($rule['gateway'] == "" && $aline['direction'] <> "" && (interface_has_gateway($rule['interface']) || interface_has_gatewayv6($rule['interface'])) && !isset($config['system']['disablereplyto']) && !isset($rule['disablereplyto']) && $type != "match") {
|
2311
|
if ($rule['ipprotocol'] == "inet6") {
|
2312
|
$rg = get_interface_gateway_v6($rule['interface']);
|
2313
|
if (is_ipaddrv6($rg))
|
2314
|
$aline['reply'] = "reply-to ( {$ifcfg['ifv6']} {$rg} ) ";
|
2315
|
else if ($rule['interface'] <> "pptp")
|
2316
|
log_error("Could not find IPv6 gateway for interface({$rule['interface']}).");
|
2317
|
} else {
|
2318
|
$rg = get_interface_gateway($rule['interface']);
|
2319
|
if (is_ipaddrv4($rg))
|
2320
|
$aline['reply'] = "reply-to ( {$ifcfg['if']} {$rg} ) ";
|
2321
|
else if ($rule['interface'] <> "pptp")
|
2322
|
log_error(sprintf(gettext("Could not find IPv4 gateway for interface (%s)."), $rule['interface']));
|
2323
|
}
|
2324
|
}
|
2325
|
/* if user has selected a custom gateway, lets work with it */
|
2326
|
else if($rule['gateway'] <> "" && $type == "pass") {
|
2327
|
if (isset($GatewaysList[$rule['gateway']]))
|
2328
|
/* Add the load balanced gateways */
|
2329
|
$aline['route'] = " \$GW{$rule['gateway']} ";
|
2330
|
else if (isset($config['system']['skip_rules_gw_down']))
|
2331
|
return "# rule " . $rule['descr'] . " disabled because gateway " . $rule['gateway'] . " is down ";
|
2332
|
else
|
2333
|
log_error("The gateway: {$rule['gateway']} is invalid or unknown, not using it.");
|
2334
|
}
|
2335
|
|
2336
|
if (isset($rule['protocol']) && !empty($rule['protocol'])) {
|
2337
|
if($rule['protocol'] == "tcp/udp")
|
2338
|
$aline['prot'] = " proto { tcp udp } ";
|
2339
|
elseif(($rule['protocol'] == "icmp") && ($rule['ipprotocol'] == "inet6"))
|
2340
|
$aline['prot'] = " proto ipv6-icmp ";
|
2341
|
elseif($rule['protocol'] == "icmp")
|
2342
|
$aline['prot'] = " proto icmp ";
|
2343
|
else
|
2344
|
$aline['prot'] = " proto {$rule['protocol']} ";
|
2345
|
} else {
|
2346
|
if($rule['source']['port'] <> "" || $rule['destination']['port'] <> "")
|
2347
|
$aline['prot'] = " proto tcp ";
|
2348
|
}
|
2349
|
update_filter_reload_status(sprintf(gettext("Creating rule %s"), $rule['descr']));
|
2350
|
|
2351
|
/* source address */
|
2352
|
$src = trim(filter_generate_address($rule, "source"));
|
2353
|
if (empty($src) || ($src == "/")) {
|
2354
|
return "# at the break!";
|
2355
|
}
|
2356
|
$aline['src'] = " from $src ";
|
2357
|
|
2358
|
/* OS signatures */
|
2359
|
if(($rule['protocol'] == "tcp") && ($rule['os'] <> ""))
|
2360
|
$aline['os'] = " os \"{$rule['os']}\" ";
|
2361
|
|
2362
|
/* destination address */
|
2363
|
$dst = trim(filter_generate_address($rule, "destination"));
|
2364
|
if (empty($dst) || ($dst == "/")) {
|
2365
|
return "# returning at dst $dst == \"/\"";
|
2366
|
}
|
2367
|
$aline['dst'] = "to $dst ";
|
2368
|
|
2369
|
//Layer7 support
|
2370
|
$l7_present = false;
|
2371
|
$l7_structures = array();
|
2372
|
if(isset($rule['l7container']) && $rule['l7container'] != "none") {
|
2373
|
$l7_present = true;
|
2374
|
$l7rule =& $layer7_rules_list[$rule['l7container']];
|
2375
|
$l7_structures = $l7rule->get_unique_structures();
|
2376
|
$aline['divert'] = "divert " . $l7rule->GetRPort() . " ";
|
2377
|
}
|
2378
|
if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet"))
|
2379
|
$aline['icmp-type'] = "icmp-type {$rule['icmptype']} ";
|
2380
|
if (($rule['protocol'] == "icmp") && $rule['icmptype'] && ($rule['ipprotocol'] == "inet6"))
|
2381
|
$aline['icmp6-type'] = "icmp6-type {$rule['icmptype']} ";
|
2382
|
if (!empty($rule['tag']))
|
2383
|
$aline['tag'] = " tag " .$rule['tag']. " ";
|
2384
|
if (!empty($rule['tagged']))
|
2385
|
$aline['tagged'] = " tagged " .$rule['tagged'] . " ";
|
2386
|
if (!empty($rule['dscp'])) {
|
2387
|
switch (strtolower($rule['dscp'])) {
|
2388
|
case 'va': $aline['dscp'] = " dscp 44 "; break;
|
2389
|
case 'cs1': $aline['dscp'] = " dscp 8 "; break;
|
2390
|
case 'cs2': $aline['dscp'] = " dscp 16 "; break;
|
2391
|
case 'cs3': $aline['dscp'] = " dscp 24 "; break;
|
2392
|
case 'cs4': $aline['dscp'] = " dscp 32 "; break;
|
2393
|
case 'cs5': $aline['dscp'] = " dscp 40 "; break;
|
2394
|
case 'cs6': $aline['dscp'] = " dscp 48 "; break;
|
2395
|
case 'cs7': $aline['dscp'] = " dscp 56 "; break;
|
2396
|
default: $aline['dscp'] = " dscp " . $rule['dscp'] . " "; break;
|
2397
|
}
|
2398
|
}
|
2399
|
if (!empty($rule['vlanprio']) && ($rule['vlanprio'] != "none"))
|
2400
|
$aline['vlanprio'] = " ieee8021q-pcp " . $rule['vlanprio'] . " ";
|
2401
|
if (!empty($rule['vlanprioset']) && ($rule['vlanprioset'] != "none"))
|
2402
|
$aline['vlanprioset'] = " ieee8021q-setpcp " . $rule['vlanprioset'] . " ";
|
2403
|
if ($type == "pass") {
|
2404
|
if (isset($rule['allowopts']))
|
2405
|
$aline['allowopts'] = " allow-opts ";
|
2406
|
}
|
2407
|
$aline['flags'] = "";
|
2408
|
if ($rule['protocol'] == "tcp") {
|
2409
|
if (isset($rule['tcpflags_any']))
|
2410
|
$aline['flags'] = "flags any ";
|
2411
|
else if (!empty($rule['tcpflags2'])) {
|
2412
|
$aline['flags'] = "flags ";
|
2413
|
if (!empty($rule['tcpflags1'])) {
|
2414
|
$flags1 = explode(",", $rule['tcpflags1']);
|
2415
|
foreach ($flags1 as $flag1) {
|
2416
|
// CWR flag needs special treatment
|
2417
|
if($flag1[0] == "c")
|
2418
|
$aline['flags'] .= "W";
|
2419
|
else
|
2420
|
$aline['flags'] .= strtoupper($flag1[0]);
|
2421
|
}
|
2422
|
}
|
2423
|
$aline['flags'] .= "/";
|
2424
|
if (!empty($rule['tcpflags2'])) {
|
2425
|
$flags2 = explode(",", $rule['tcpflags2']);
|
2426
|
foreach ($flags2 as $flag2) {
|
2427
|
// CWR flag needs special treatment
|
2428
|
if($flag2[0] == "c")
|
2429
|
$aline['flags'] .= "W";
|
2430
|
else
|
2431
|
$aline['flags'] .= strtoupper($flag2[0]);
|
2432
|
}
|
2433
|
}
|
2434
|
$aline['flags'] .= " ";
|
2435
|
} else {
|
2436
|
$aline['flags'] = "flags S/SA ";
|
2437
|
}
|
2438
|
}
|
2439
|
if ($type == "pass") {
|
2440
|
/*
|
2441
|
* # keep state
|
2442
|
* works with TCP, UDP, and ICMP.
|
2443
|
* # modulate state
|
2444
|
* works only with TCP. pfSense will generate strong Initial Sequence Numbers (ISNs)
|
2445
|
* for packets matching this rule.
|
2446
|
* # synproxy state
|
2447
|
* proxies incoming TCP connections to help protect servers from spoofed TCP SYN floods.
|
2448
|
* This option includes the functionality of keep state and modulate state combined.
|
2449
|
* # none
|
2450
|
* do not use state mechanisms to keep track. this is only useful if your doing advanced
|
2451
|
* queueing in certain situations. please check the faq.
|
2452
|
*/
|
2453
|
$noadvoptions = false;
|
2454
|
if (isset($rule['statetype']) && $rule['statetype'] <> "") {
|
2455
|
switch($rule['statetype']) {
|
2456
|
case "none":
|
2457
|
$noadvoptions = true;
|
2458
|
$aline['flags'] .= " no state ";
|
2459
|
break;
|
2460
|
case "modulate state":
|
2461
|
case "synproxy state":
|
2462
|
if ($rule['protocol'] == "tcp")
|
2463
|
$aline['flags'] .= "{$rule['statetype']} ";
|
2464
|
break;
|
2465
|
case "sloppy state":
|
2466
|
$aline['flags'] .= "keep state ";
|
2467
|
$rule['sloppy'] = true;
|
2468
|
break;
|
2469
|
default:
|
2470
|
$aline['flags'] .= "{$rule['statetype']} ";
|
2471
|
break;
|
2472
|
}
|
2473
|
} else
|
2474
|
$aline['flags'] .= "keep state ";
|
2475
|
|
2476
|
if ($noadvoptions == false && isset($rule['nopfsync']))
|
2477
|
$rule['nopfsync'] = true;
|
2478
|
|
2479
|
if ($noadvoptions == false || $l7_present)
|
2480
|
if ((isset($rule['source-track']) and $rule['source-track'] <> "") or
|
2481
|
(isset($rule['max']) and $rule['max'] <> "") or
|
2482
|
(isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "") or
|
2483
|
(isset($rule['max-src-states']) and $rule['max-src-states'] <> "") or
|
2484
|
((in_array($rule['protocol'], array("tcp","tcp/udp"))) and
|
2485
|
((isset($rule['statetimeout']) and $rule['statetimeout'] <> "") or
|
2486
|
(isset($rule['max-src-conn']) and $rule['max-src-conn'] <> "") or
|
2487
|
(isset($rule['max-src-conn-rate']) and $rule['max-src-conn-rate'] <> "") or
|
2488
|
(isset($rule['max-src-conn-rates']) and $rule['max-src-conn-rates'] <> ""))) or
|
2489
|
isset($rule['sloppy']) or isset($rule['nopfsync']) or $l7_present) {
|
2490
|
$aline['flags'] .= "( ";
|
2491
|
if (isset($rule['sloppy']))
|
2492
|
$aline['flags'] .= "sloppy ";
|
2493
|
if (isset($rule['nopfsync']))
|
2494
|
$aline['flags'] .= "no-sync ";
|
2495
|
if (isset($rule['source-track']) and $rule['source-track'] <> "")
|
2496
|
$aline['flags'] .= "source-track rule ";
|
2497
|
if (isset($rule['max']) and $rule['max'] <> "")
|
2498
|
$aline['flags'] .= "max " . $rule['max'] . " ";
|
2499
|
if (isset($rule['max-src-nodes']) and $rule['max-src-nodes'] <> "")
|
2500
|
$aline['flags'] .= "max-src-nodes " . $rule['max-src-nodes'] . " ";
|
2501
|
if ((in_array($rule['protocol'], array("tcp","tcp/udp")))
|
2502
|
and isset($rule['max-src-conn'])
|
2503
|
and $rule['max-src-conn'] <> "")
|
2504
|
$aline['flags'] .= "max-src-conn " . $rule['max-src-conn'] . " ";
|
2505
|
if (isset($rule['max-src-states']) and $rule['max-src-states'] <> "")
|
2506
|
$aline['flags'] .= "max-src-states " . $rule['max-src-states'] . " ";
|
2507
|
if ((in_array($rule['protocol'], array("tcp","tcp/udp")))
|
2508
|
and isset($rule['statetimeout'])
|
2509
|
and $rule['statetimeout'] <> "")
|
2510
|
$aline['flags'] .= "tcp.established " . $rule['statetimeout'] . " ";
|
2511
|
if ((in_array($rule['protocol'], array("tcp","tcp/udp")))
|
2512
|
and isset($rule['max-src-conn-rate'])
|
2513
|
and $rule['max-src-conn-rate'] <> ""
|
2514
|
and isset($rule['max-src-conn-rates'])
|
2515
|
and $rule['max-src-conn-rates'] <> "") {
|
2516
|
$aline['flags'] .= "max-src-conn-rate " . $rule['max-src-conn-rate'] . " ";
|
2517
|
$aline['flags'] .= "/" . $rule['max-src-conn-rates'] . ", overload <virusprot> flush global ";
|
2518
|
}
|
2519
|
|
2520
|
if(!empty($aline['divert']))
|
2521
|
$aline['flags'] .= "max-packets 8 ";
|
2522
|
|
2523
|
$aline['flags'] .= " ) ";
|
2524
|
}
|
2525
|
}
|
2526
|
if($rule['defaultqueue'] <> "") {
|
2527
|
$aline['queue'] = " queue (".$rule['defaultqueue'];
|
2528
|
if($rule['ackqueue'] <> "")
|
2529
|
$aline['queue'] .= ",".$rule['ackqueue'];
|
2530
|
$aline['queue'] .= ") ";
|
2531
|
}
|
2532
|
if($rule['dnpipe'] <> "") {
|
2533
|
if (!empty($dummynet_name_list[$rule['dnpipe']])) {
|
2534
|
if($dummynet_name_list[$rule['dnpipe']][0] == "?") {
|
2535
|
$aline['dnpipe'] = " dnqueue( ";
|
2536
|
$aline['dnpipe'] .= substr($dummynet_name_list[$rule['dnpipe']],1);
|
2537
|
if($rule['pdnpipe'] <> "")
|
2538
|
$aline['dnpipe'] .= ",".substr($dummynet_name_list[$rule['pdnpipe']], 1);
|
2539
|
} else {
|
2540
|
$aline['dnpipe'] = " dnpipe ( " . $dummynet_name_list[$rule['dnpipe']];
|
2541
|
if($rule['pdnpipe'] <> "")
|
2542
|
$aline['dnpipe'] .= "," . $dummynet_name_list[$rule['pdnpipe']];
|
2543
|
}
|
2544
|
$aline['dnpipe'] .= ") ";
|
2545
|
}
|
2546
|
}
|
2547
|
|
2548
|
/* is a time based rule schedule attached? */
|
2549
|
if(!empty($rule['sched']) && !empty($config['schedules'])) {
|
2550
|
$aline['schedlabel'] = "";
|
2551
|
foreach ($config['schedules']['schedule'] as $sched) {
|
2552
|
if($sched['name'] == $rule['sched']) {
|
2553
|
if(!filter_get_time_based_rule_status($sched)) {
|
2554
|
if(!isset($config['system']['schedule_states']))
|
2555
|
mwexec("/sbin/pfctl -y {$sched['schedlabel']}");
|
2556
|
return "# schedule finished - {$rule['descr']}";
|
2557
|
} else if($g['debug'])
|
2558
|
log_error("[TDR DEBUG] status true -- rule type '$type'");
|
2559
|
|
2560
|
$aline['schedlabel'] = " schedule \"{$sched['schedlabel']}\" ";
|
2561
|
break;
|
2562
|
}
|
2563
|
}
|
2564
|
}
|
2565
|
|
2566
|
if (!empty($rule['tracker']))
|
2567
|
$aline['tracker'] = "tracker {$rule['tracker']} ";
|
2568
|
|
2569
|
$line = "";
|
2570
|
/* exception(s) to a user rules can go here. */
|
2571
|
/* rules with a gateway or pool should create another rule for routing to vpns */
|
2572
|
if((($aline['route'] <> "") && (trim($aline['type']) == "pass") && strstr($dst, "any")) && (!isset($config['system']['disablenegate']))) {
|
2573
|
/* negate VPN/PPTP/PPPoE/Static Route networks for load balancer/gateway rules */
|
2574
|
$negate_networks = " to <negate_networks> " . filter_generate_port($rule, "destination");
|
2575
|
$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] .
|
2576
|
$aline['interface'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] .
|
2577
|
$negate_networks . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] .
|
2578
|
$aline['vlanprio'] . $aline['vlanprioset'] . $aline['dscp'] . $aline['tracker'] . $aline['allowopts'] . $aline['flags'] .
|
2579
|
$aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'] .
|
2580
|
" label \"NEGATE_ROUTE: Negate policy routing for destination\"\n";
|
2581
|
|
2582
|
}
|
2583
|
/* piece together the actual user rule */
|
2584
|
$line .= $aline['type'] . $aline['direction'] . $aline['log'] . $aline['quick'] . $aline['interface'] .
|
2585
|
$aline['reply'] . $aline['route'] . $aline['ipprotocol'] . $aline['prot'] . $aline['src'] . $aline['os'] . $aline['dst'] .
|
2586
|
$aline['divert'] . $aline['icmp-type'] . $aline['icmp6-type'] . $aline['tag'] . $aline['tagged'] . $aline['dscp'] . $aline['tracker'] .
|
2587
|
$aline['vlanprio'] . $aline['vlanprioset'] . $aline['allowopts'] . $aline['flags'] . $aline['queue'] . $aline['dnpipe'] . $aline['schedlabel'];
|
2588
|
|
2589
|
unset($aline);
|
2590
|
|
2591
|
return $line;
|
2592
|
}
|
2593
|
|
2594
|
function filter_rules_generate() {
|
2595
|
global $config, $g, $FilterIflist, $time_based_rules, $GatewaysList, $tracker;
|
2596
|
|
2597
|
$fix_rule_label = 'fix_rule_label';
|
2598
|
$increment_tracker = 'filter_rule_tracker';
|
2599
|
|
2600
|
update_filter_reload_status(gettext("Creating default rules"));
|
2601
|
if(isset($config['system']['developerspew'])) {
|
2602
|
$mt = microtime();
|
2603
|
echo "filter_rules_generate() being called $mt\n";
|
2604
|
}
|
2605
|
|
2606
|
$pptpdcfg = $config['pptpd'];
|
2607
|
|
2608
|
$ipfrules = "";
|
2609
|
$ipfrules .= discover_pkg_rules("pfearly");
|
2610
|
|
2611
|
/* relayd */
|
2612
|
$ipfrules .= "anchor \"relayd/*\"\n";
|
2613
|
/* OpenVPN user rules from radius */
|
2614
|
$ipfrules .= "anchor \"openvpn/*\"\n";
|
2615
|
/* IPSec user rules from radius */
|
2616
|
$ipfrules .= "anchor \"ipsec/*\"\n";
|
2617
|
# BEGIN OF firewall rules
|
2618
|
/* default block logging? */
|
2619
|
if(!isset($config['syslog']['nologdefaultblock']))
|
2620
|
$log = "log";
|
2621
|
else
|
2622
|
$log = "";
|
2623
|
|
2624
|
$saved_tracker = $tracker;
|
2625
|
|
2626
|
if(!isset($config['system']['ipv6allow'])) {
|
2627
|
$ipfrules .= "# Block all IPv6\n";
|
2628
|
$ipfrules .= "block in {$log} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
|
2629
|
$ipfrules .= "block out {$log} quick inet6 all tracker {$increment_tracker($tracker)} label \"Block all IPv6\"\n";
|
2630
|
}
|
2631
|
|
2632
|
$saved_tracker += 100;
|
2633
|
$tracker = $saved_tracker;
|
2634
|
|
2635
|
$ipfrules .= <<<EOD
|
2636
|
#---------------------------------------------------------------------------
|
2637
|
# default deny rules
|
2638
|
#---------------------------------------------------------------------------
|
2639
|
block in {$log} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
|
2640
|
block out {$log} inet all tracker {$increment_tracker($tracker)} label "Default deny rule IPv4"
|
2641
|
block in {$log} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
|
2642
|
block out {$log} inet6 all tracker {$increment_tracker($tracker)} label "Default deny rule IPv6"
|
2643
|
|
2644
|
# IPv6 ICMP is not auxilary, it is required for operation
|
2645
|
# See man icmp6(4)
|
2646
|
# 1 unreach Destination unreachable
|
2647
|
# 2 toobig Packet too big
|
2648
|
# 128 echoreq Echo service request
|
2649
|
# 129 echorep Echo service reply
|
2650
|
# 133 routersol Router solicitation
|
2651
|
# 134 routeradv Router advertisement
|
2652
|
# 135 neighbrsol Neighbor solicitation
|
2653
|
# 136 neighbradv Neighbor advertisement
|
2654
|
pass {$log} quick inet6 proto ipv6-icmp from any to any icmp6-type {1,2,135,136} tracker {$increment_tracker($tracker)} keep state
|
2655
|
|
2656
|
# Allow only bare essential icmpv6 packets (NS, NA, and RA, echoreq, echorep)
|
2657
|
pass out {$log} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
|
2658
|
pass out {$log} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {129,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
|
2659
|
pass in {$log} quick inet6 proto ipv6-icmp from fe80::/10 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
|
2660
|
pass in {$log} quick inet6 proto ipv6-icmp from ff02::/16 to fe80::/10 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
|
2661
|
pass in {$log} quick inet6 proto ipv6-icmp from fe80::/10 to ff02::/16 icmp6-type {128,133,134,135,136} tracker {$increment_tracker($tracker)} keep state
|
2662
|
|
2663
|
# We use the mighty pf, we cannot be fooled.
|
2664
|
block {$log} quick inet proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
|
2665
|
block {$log} quick inet proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
|
2666
|
block {$log} quick inet6 proto { tcp, udp } from any port = 0 to any tracker {$increment_tracker($tracker)}
|
2667
|
block {$log} quick inet6 proto { tcp, udp } from any to any port = 0 tracker {$increment_tracker($tracker)}
|
2668
|
|
2669
|
# Snort package
|
2670
|
block {$log} quick from <snort2c> to any tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
|
2671
|
block {$log} quick from any to <snort2c> tracker {$increment_tracker($tracker)} label "Block snort2c hosts"
|
2672
|
|
2673
|
EOD;
|
2674
|
|
2675
|
$saved_tracker += 100;
|
2676
|
$tracker = $saved_tracker;
|
2677
|
|
2678
|
$ipfrules .= filter_process_carp_rules($log);
|
2679
|
|
2680
|
$saved_tracker += 100;
|
2681
|
$tracker = $saved_tracker;
|
2682
|
|
2683
|
$ipfrules .= "\n# SSH lockout\n";
|
2684
|
if(is_array($config['system']['ssh']) && !empty($config['system']['ssh']['port'])) {
|
2685
|
$ipfrules .= "block in log quick proto tcp from <sshlockout> to (self) port ";
|
2686
|
$ipfrules .= $config['system']['ssh']['port'];
|
2687
|
$ipfrules .= " tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
|
2688
|
} else {
|
2689
|
if($config['system']['ssh']['port'] <> "")
|
2690
|
$sshport = $config['system']['ssh']['port'];
|
2691
|
else
|
2692
|
$sshport = 22;
|
2693
|
if($sshport)
|
2694
|
$ipfrules .= "block in log quick proto tcp from <sshlockout> to (self) port {$sshport} tracker {$increment_tracker($tracker)} label \"sshlockout\"\n";
|
2695
|
}
|
2696
|
|
2697
|
$saved_tracker += 50;
|
2698
|
$tracker = $saved_tracker;
|
2699
|
|
2700
|
$ipfrules .= "\n# webConfigurator lockout\n";
|
2701
|
if(!$config['system']['webgui']['port']) {
|
2702
|
if($config['system']['webgui']['protocol'] == "http")
|
2703
|
$webConfiguratorlockoutport = "80";
|
2704
|
else
|
2705
|
$webConfiguratorlockoutport = "443";
|
2706
|
} else {
|
2707
|
$webConfiguratorlockoutport = $config['system']['webgui']['port'];
|
2708
|
}
|
2709
|
if($webConfiguratorlockoutport)
|
2710
|
$ipfrules .= "block in log quick proto tcp from <webConfiguratorlockout> to (self) port {$webConfiguratorlockoutport} tracker {$increment_tracker($tracker)} label \"webConfiguratorlockout\"\n";
|
2711
|
|
2712
|
$saved_tracker += 100;
|
2713
|
$tracker = $saved_tracker;
|
2714
|
|
2715
|
/*
|
2716
|
* Support for allow limiting of TCP connections by establishment rate
|
2717
|
* Useful for protecting against sudden outburts, etc.
|
2718
|
*/
|
2719
|
$ipfrules .= "block in {$log} quick from <virusprot> to any tracker 1000000400 label \"virusprot overload table\"\n";
|
2720
|
|
2721
|
$saved_tracker += 100;
|
2722
|
$tracker = $saved_tracker;
|
2723
|
|
2724
|
/* if captive portal is enabled, ensure that access to this port
|
2725
|
* is allowed on a locked down interface
|
2726
|
*/
|
2727
|
if(is_array($config['captiveportal'])) {
|
2728
|
foreach ($config['captiveportal'] as $cpcfg) {
|
2729
|
if(!isset($cpcfg['enable']))
|
2730
|
continue;
|
2731
|
$cpinterfaces = explode(",", $cpcfg['interface']);
|
2732
|
$cpiflist = array();
|
2733
|
$cpiplist = array();
|
2734
|
foreach ($cpinterfaces as $cpifgrp) {
|
2735
|
if(!isset($FilterIflist[$cpifgrp]))
|
2736
|
continue;
|
2737
|
$tmpif = get_real_interface($cpifgrp);
|
2738
|
if(!empty($tmpif)) {
|
2739
|
$cpiflist[] = "{$tmpif}";
|
2740
|
$cpipm = get_interface_ip($cpifgrp);
|
2741
|
if(is_ipaddr($cpipm)) {
|
2742
|
$carpif = link_ip_to_carp_interface($cpipm);
|
2743
|
if (!empty($carpif)) {
|
2744
|
$cpiflist[] = $carpif;
|
2745
|
$carpsif = explode(" ", $carpif);
|
2746
|
foreach ($carpsif as $cpcarp) {
|
2747
|
$carpip = find_interface_ip($cpcarp);
|
2748
|
if (is_ipaddr($carpip))
|
2749
|
$cpiplist[] = $carpip;
|
2750
|
}
|
2751
|
}
|
2752
|
$cpiplist[] = $cpipm;
|
2753
|
}
|
2754
|
}
|
2755
|
}
|
2756
|
if (count($cpiplist) > 0 && count($cpiflist) > 0) {
|
2757
|
$cpinterface = implode(" ", $cpiflist);
|
2758
|
$cpaddresses = implode(" ", $cpiplist);
|
2759
|
$listenporthttps = $cpcfg['listenporthttps'] ? $cpcfg['listenporthttps'] : ($cpcfg['zoneid'] + 1);
|
2760
|
$listenporthttp = $cpcfg['listenporthttp'] ? $cpcfg['listenporthttp'] : $cpcfg['zoneid'];
|
2761
|
$portalias = $listenporthttps;
|
2762
|
$portalias .= " {$listenporthttp}";
|
2763
|
$ipfrules .= "pass in {$log} quick on { {$cpinterface} } proto tcp from any to { {$cpaddresses} } port { {$portalias} } tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
|
2764
|
$ipfrules .= "pass out {$log} quick on { {$cpinterface} } proto tcp from any to any flags any tracker {$increment_tracker($tracker)} keep state(sloppy)\n";
|
2765
|
}
|
2766
|
}
|
2767
|
}
|
2768
|
|
2769
|
$bogontableinstalled = 0;
|
2770
|
foreach ($FilterIflist as $on => $oc) {
|
2771
|
/* XXX: Not static but give a step of 1000 for each interface to at least be able to match rules. */
|
2772
|
$saved_tracker += 1000;
|
2773
|
$tracker = $saved_tracker;
|
2774
|
|
2775
|
/* block bogon networks */
|
2776
|
/* http://www.cymru.com/Documents/bogon-bn-nonagg.txt */
|
2777
|
/* file is automatically in cron every 3000 minutes */
|
2778
|
if(!isset($config['syslog']['nologbogons']))
|
2779
|
$bogonlog = "log";
|
2780
|
else
|
2781
|
$bogonlog = "";
|
2782
|
|
2783
|
if(isset($config['interfaces'][$on]['blockbogons'])) {
|
2784
|
$ipfrules .= <<<EOD
|
2785
|
# block bogon networks (IPv4)
|
2786
|
# http://www.cymru.com/Documents/bogon-bn-nonagg.txt
|
2787
|
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']}")}"
|
2788
|
|
2789
|
EOD;
|
2790
|
|
2791
|
if(isset($config['system']['ipv6allow'])) {
|
2792
|
$ipfrules .= <<<EOD
|
2793
|
# block bogon networks (IPv6)
|
2794
|
# http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt
|
2795
|
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']}")}"
|
2796
|
|
2797
|
EOD;
|
2798
|
}
|
2799
|
}
|
2800
|
|
2801
|
|
2802
|
$saved_tracker += 10;
|
2803
|
$tracker = $saved_tracker;
|
2804
|
|
2805
|
if(isset($config['system']['ipv6allow']) && ($oc['type6'] == "slaac" || $oc['type6'] == "dhcp6")) {
|
2806
|
$ipfrules .= <<<EOD
|
2807
|
# allow our DHCPv6 client out to the {$oc['descr']}
|
2808
|
pass in {$log} 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']}")}"
|
2809
|
pass in {$log} 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']}")}"
|
2810
|
pass out {$log} 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']}")}"
|
2811
|
|
2812
|
EOD;
|
2813
|
}
|
2814
|
|
2815
|
$saved_tracker += 10;
|
2816
|
$tracker = $saved_tracker;
|
2817
|
|
2818
|
$isbridged = false;
|
2819
|
if(is_array($config['bridges']['bridged'])) {
|
2820
|
foreach ($config['bridges']['bridged'] as $oc2) {
|
2821
|
if(stristr($oc2['members'], $on)) {
|
2822
|
$isbridged = true;
|
2823
|
break;
|
2824
|
}
|
2825
|
}
|
2826
|
}
|
2827
|
|
2828
|
if($oc['ip'] && !($isbridged) && isset($oc['spoofcheck']))
|
2829
|
$ipfrules .= filter_rules_spoofcheck_generate($on, $oc, $log);
|
2830
|
|
2831
|
/* block private networks ? */
|
2832
|
if(!isset($config['syslog']['nologprivatenets']))
|
2833
|
$privnetlog = "log";
|
2834
|
else
|
2835
|
$privnetlog = "";
|
2836
|
|
2837
|
$saved_tracker += 10;
|
2838
|
$tracker = $saved_tracker;
|
2839
|
|
2840
|
if(isset($config['interfaces'][$on]['blockpriv'])) {
|
2841
|
if($isbridged == false) {
|
2842
|
$ipfrules .= <<<EOD
|
2843
|
# block anything from private networks on interfaces with the option set
|
2844
|
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")}"
|
2845
|
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")}"
|
2846
|
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")}"
|
2847
|
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")}"
|
2848
|
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")}"
|
2849
|
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")}"
|
2850
|
|
2851
|
EOD;
|
2852
|
}
|
2853
|
}
|
2854
|
|
2855
|
$saved_tracker += 10;
|
2856
|
$tracker = $saved_tracker;
|
2857
|
|
2858
|
switch ($oc['type']) {
|
2859
|
case "pptp":
|
2860
|
$ipfrules .= <<<EOD
|
2861
|
# allow PPTP client
|
2862
|
pass in {$log} 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']}")}"
|
2863
|
pass in {$log} 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']}")}"
|
2864
|
|
2865
|
EOD;
|
2866
|
break;
|
2867
|
case "dhcp":
|
2868
|
$ipfrules .= <<<EOD
|
2869
|
# allow our DHCP client out to the {$oc['descr']}
|
2870
|
pass in {$log} 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']}")}"
|
2871
|
pass out {$log} 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']}")}"
|
2872
|
# Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP.
|
2873
|
|
2874
|
EOD;
|
2875
|
|
2876
|
break;
|
2877
|
case "pppoe":
|
2878
|
case "none":
|
2879
|
/* XXX: Nothing to do in this case?! */
|
2880
|
break;
|
2881
|
default:
|
2882
|
/* allow access to DHCP server on interfaces */
|
2883
|
if(isset($config['dhcpd'][$on]['enable'])) {
|
2884
|
$ipfrules .= <<<EOD
|
2885
|
# allow access to DHCP server on {$oc['descr']}
|
2886
|
pass in {$log} 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"
|
2887
|
|
2888
|
EOD;
|
2889
|
if (is_ipaddrv4($oc['ip'])) {
|
2890
|
$ipfrules .= <<<EOD
|
2891
|
pass in {$log} 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"
|
2892
|
pass out {$log} 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"
|
2893
|
|
2894
|
EOD;
|
2895
|
}
|
2896
|
|
2897
|
if(is_ipaddrv4($oc['ip']) && $config['dhcpd'][$on]['failover_peerip'] <> "") {
|
2898
|
$ipfrules .= <<<EOD
|
2899
|
# allow access to DHCP failover on {$oc['descr']} from {$config['dhcpd'][$on]['failover_peerip']}
|
2900
|
pass in {$log} 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"
|
2901
|
pass in {$log} 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"
|
2902
|
|
2903
|
EOD;
|
2904
|
}
|
2905
|
|
2906
|
}
|
2907
|
break;
|
2908
|
}
|
2909
|
|
2910
|
$saved_tracker += 10;
|
2911
|
$tracker = $saved_tracker;
|
2912
|
switch($oc['type6']) {
|
2913
|
case "6rd":
|
2914
|
$ipfrules .= <<<EOD
|
2915
|
# allow our proto 41 traffic from the 6RD border relay in
|
2916
|
pass in {$log} 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']}")}"
|
2917
|
pass out {$log} 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']}")}"
|
2918
|
|
2919
|
EOD;
|
2920
|
/* XXX: Really need to allow 6rd traffic coming in for v6 this is against default behaviour! */
|
2921
|
if (0 && is_ipaddrv6($oc['ipv6'])) {
|
2922
|
$ipfrules .= <<<EOD
|
2923
|
pass in {$log} 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']}")}"
|
2924
|
pass out {$log} 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']}")}"
|
2925
|
|
2926
|
EOD;
|
2927
|
}
|
2928
|
break;
|
2929
|
case "6to4":
|
2930
|
if (is_ipaddrv4($oc['ip'])) {
|
2931
|
$ipfrules .= <<<EOD
|
2932
|
# allow our proto 41 traffic from the 6to4 border relay in
|
2933
|
pass in {$log} 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']}")}"
|
2934
|
pass out {$log} 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']}")}"
|
2935
|
|
2936
|
EOD;
|
2937
|
}
|
2938
|
/* XXX: Really need to allow 6to4 traffic coming in for v6 this is against default behaviour! */
|
2939
|
if (0 && is_ipaddrv6($oc['ipv6'])) {
|
2940
|
$ipfrules .= <<<EOD
|
2941
|
pass in {$log} 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']}")}"
|
2942
|
pass out {$log} 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']}")}"
|
2943
|
|
2944
|
EOD;
|
2945
|
}
|
2946
|
break;
|
2947
|
default:
|
2948
|
if ((is_array($config['dhcpdv6'][$on]) && isset($config['dhcpdv6'][$on]['enable'])) || isset($oc['track6-interface'])
|
2949
|
|| (is_array($config['dhcrelay6']) && !empty($config['dhcrelay6']['interface']) && in_array($on, explode(',', $config['dhcrelay6']['interface'])))) {
|
2950
|
$ipfrules .= <<<EOD
|
2951
|
# allow access to DHCPv6 server on {$oc['descr']}
|
2952
|
# We need inet6 icmp for stateless autoconfig and dhcpv6
|
2953
|
pass {$log} 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"
|
2954
|
pass {$log} 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"
|
2955
|
pass {$log} 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"
|
2956
|
pass {$log} 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"
|
2957
|
|
2958
|
EOD;
|
2959
|
if (is_ipaddrv6($oc['ipv6'])) {
|
2960
|
$ipfrules .= <<<EOD
|
2961
|
pass in {$log} 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"
|
2962
|
pass out {$log} 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"
|
2963
|
|
2964
|
EOD;
|
2965
|
}
|
2966
|
}
|
2967
|
break;
|
2968
|
}
|
2969
|
}
|
2970
|
|
2971
|
$saved_tracker += 10;
|
2972
|
$tracker = $saved_tracker;
|
2973
|
|
2974
|
/*
|
2975
|
* NB: The loopback rules are needed here since the antispoof would take precedence then.
|
2976
|
* If you ever add the 'quick' keyword to the antispoof rules above move the looback
|
2977
|
* rules before them.
|
2978
|
*/
|
2979
|
$ipfrules .= <<<EOD
|
2980
|
|
2981
|
# loopback
|
2982
|
pass in {$log} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
|
2983
|
pass out {$log} on \$loopback inet all tracker {$increment_tracker($tracker)} label "pass IPv4 loopback"
|
2984
|
pass in {$log} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
|
2985
|
pass out {$log} on \$loopback inet6 all tracker {$increment_tracker($tracker)} label "pass IPv6 loopback"
|
2986
|
# let out anything from the firewall host itself and decrypted IPsec traffic
|
2987
|
pass out {$log} inet all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv4 from firewall host itself"
|
2988
|
pass out {$log} inet6 all keep state allow-opts tracker {$increment_tracker($tracker)} label "let out anything IPv6 from firewall host itself"
|
2989
|
|
2990
|
EOD;
|
2991
|
|
2992
|
$saved_tracker += 100;
|
2993
|
$tracker = $saved_tracker;
|
2994
|
foreach ($FilterIflist as $ifdescr => $ifcfg) {
|
2995
|
if(isset($ifcfg['virtual']))
|
2996
|
continue;
|
2997
|
|
2998
|
$gw = get_interface_gateway($ifdescr);
|
2999
|
if (is_ipaddrv4($gw) && is_ipaddrv4($ifcfg['ip'])) {
|
3000
|
$ipfrules .= "pass out {$log} 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";
|
3001
|
if (is_array($ifcfg['vips'])) {
|
3002
|
foreach ($ifcfg['vips'] as $vip)
|
3003
|
if (ip_in_subnet($vip['ip'], "{$ifcfg['sa']}/{$ifcfg['sn']}"))
|
3004
|
$ipfrules .= "pass out {$log} 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";
|
3005
|
else
|
3006
|
$ipfrules .= "pass out {$log} 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";
|
3007
|
}
|
3008
|
}
|
3009
|
|
3010
|
$gwv6 = get_interface_gateway_v6($ifdescr);
|
3011
|
$stf = get_real_interface($ifdescr, "inet6");
|
3012
|
$pdlen = 64 - calculate_ipv6_delegation_length($ifdescr);
|
3013
|
if (is_ipaddrv6($gwv6) && is_ipaddrv6($ifcfg['ipv6'])) {
|
3014
|
$ipfrules .= "pass out {$log} 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";
|
3015
|
if (is_array($ifcfg['vips6'])) {
|
3016
|
foreach ($ifcfg['vips6'] as $vip)
|
3017
|
$ipfrules .= "pass out {$log} 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";
|
3018
|
}
|
3019
|
}
|
3020
|
}
|
3021
|
|
3022
|
|
3023
|
$saved_tracker += 300;
|
3024
|
$tracker = $saved_tracker;
|
3025
|
/* add ipsec interfaces */
|
3026
|
if(isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
|
3027
|
$ipfrules .= "pass out {$log} on \$IPsec all tracker {$increment_tracker($tracker)} tracker {$increment_tracker($tracker)} keep state label \"IPsec internal host to host\"\n";
|
3028
|
|
3029
|
$saved_tracker += 10;
|
3030
|
$tracker = $saved_tracker;
|
3031
|
if(is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
|
3032
|
$alports = filter_get_antilockout_ports();
|
3033
|
|
3034
|
if(count($config['interfaces']) > 1 && !empty($FilterIflist['lan']['if'])) {
|
3035
|
/* if antilockout is enabled, LAN exists and has
|
3036
|
* an IP and subnet mask assigned
|
3037
|
*/
|
3038
|
$lanif = $FilterIflist['lan']['if'];
|
3039
|
$ipfrules .= <<<EOD
|
3040
|
# make sure the user cannot lock himself out of the webConfigurator or SSH
|
3041
|
pass in {$log} quick on {$lanif} proto tcp from any to ({$lanif}) port { {$alports} } tracker {$increment_tracker($tracker)} keep state label "anti-lockout rule"
|
3042
|
|
3043
|
EOD;
|
3044
|
} else if (count($config['interfaces']) == 1) {
|
3045
|
/* single-interface deployment, add to WAN */
|
3046
|
$wanif = $FilterIflist["wan"]['if'];
|
3047
|
$ipfrules .= <<<EOD
|
3048
|
# make sure the user cannot lock himself out of the webConfigurator or SSH
|
3049
|
pass in {$log} quick on {$wanif} proto tcp from any to ({$wanif}) port { {$alports} } tracker {$increment_tracker($tracker)} keep state label "anti-lockout rule"
|
3050
|
|
3051
|
EOD;
|
3052
|
}
|
3053
|
unset($alports);
|
3054
|
}
|
3055
|
|
3056
|
$saved_tracker += 10;
|
3057
|
$tracker = $saved_tracker;
|
3058
|
/* PPTPd enabled? */
|
3059
|
if($pptpdcfg['mode'] && ($pptpdcfg['mode'] != "off") && !isset($config['system']['disablevpnrules'])) {
|
3060
|
if($pptpdcfg['mode'] == "server")
|
3061
|
$pptpdtarget = get_interface_ip();
|
3062
|
else
|
3063
|
$pptpdtarget = $pptpdcfg['redir'];
|
3064
|
if(is_ipaddr($pptpdtarget) and is_array($FilterIflist['wan'])) {
|
3065
|
$ipfrules .= <<<EOD
|
3066
|
# PPTPd rules
|
3067
|
pass in {$log} 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}")}"
|
3068
|
pass in {$log} on \${$FilterIflist['wan']['descr']} proto gre from any to any tracker {$increment_tracker($tracker)} keep state label "allow gre pptpd"
|
3069
|
|
3070
|
EOD;
|
3071
|
|
3072
|
} else {
|
3073
|
/* this shouldnt ever happen but instead of breaking the clients ruleset
|
3074
|
* log an error.
|
3075
|
*/
|
3076
|
log_error("ERROR! PPTP enabled but could not resolve the \$pptpdtarget");
|
3077
|
}
|
3078
|
}
|
3079
|
|
3080
|
$saved_tracker += 10;
|
3081
|
$tracker = $saved_tracker;
|
3082
|
if(isset($config['nat']['rule']) && is_array($config['nat']['rule'])) {
|
3083
|
foreach ($config['nat']['rule'] as $rule) {
|
3084
|
if((!isset($config['system']['disablenatreflection']) || $rule['natreflection'] == "enable")
|
3085
|
&& $rule['natreflection'] != "disable") {
|
3086
|
$ipfrules .= "# NAT Reflection rules\n";
|
3087
|
$ipfrules .= <<<EOD
|
3088
|
pass in {$log} inet tagged PFREFLECT tracker {$increment_tracker($tracker)} keep state label "NAT REFLECT: Allow traffic to localhost"
|
3089
|
|
3090
|
EOD;
|
3091
|
break;
|
3092
|
}
|
3093
|
}
|
3094
|
}
|
3095
|
|
3096
|
if (isset($config['filter']['rule'])) {
|
3097
|
/* Pre-cache all our rules so we only have to generate them once */
|
3098
|
$rule_arr1 = array();
|
3099
|
$rule_arr2 = array();
|
3100
|
$rule_arr3 = array();
|
3101
|
$vpn_and_ppp_ifs = array("l2tp", "pptp", "pppoe", "enc0", "openvpn");
|
3102
|
/*
|
3103
|
* NB: The order must be: Floating rules, then interface group and then regular ones.
|
3104
|
*/
|
3105
|
foreach ($config['filter']['rule'] as $rule) {
|
3106
|
update_filter_reload_status("Pre-caching {$rule['descr']}...");
|
3107
|
if (isset ($rule['disabled']))
|
3108
|
continue;
|
3109
|
|
3110
|
if (!empty($rule['ipprotocol']) && $rule['ipprotocol'] == "inet46") {
|
3111
|
if (isset($rule['floating'])) {
|
3112
|
$rule['ipprotocol'] = "inet";
|
3113
|
$rule_arr1[] = filter_generate_user_rule_arr($rule);
|
3114
|
$rule['ipprotocol'] = "inet6";
|
3115
|
$rule_arr1[] = filter_generate_user_rule_arr($rule);
|
3116
|
} else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs)) {
|
3117
|
$rule['ipprotocol'] = "inet";
|
3118
|
$rule_arr2[] = filter_generate_user_rule_arr($rule);
|
3119
|
$rule['ipprotocol'] = "inet6";
|
3120
|
$rule_arr2[] = filter_generate_user_rule_arr($rule);
|
3121
|
} else {
|
3122
|
$rule['ipprotocol'] = "inet";
|
3123
|
$rule_arr3[] = filter_generate_user_rule_arr($rule);
|
3124
|
$rule['ipprotocol'] = "inet6";
|
3125
|
$rule_arr3[] = filter_generate_user_rule_arr($rule);
|
3126
|
}
|
3127
|
$rule['ipprotocol'] = "inet46";
|
3128
|
} else {
|
3129
|
if (isset($rule['floating']))
|
3130
|
$rule_arr1[] = filter_generate_user_rule_arr($rule);
|
3131
|
else if (is_interface_group($rule['interface']) || in_array($rule['interface'], $vpn_and_ppp_ifs))
|
3132
|
$rule_arr2[] = filter_generate_user_rule_arr($rule);
|
3133
|
else
|
3134
|
$rule_arr3[] = filter_generate_user_rule_arr($rule);
|
3135
|
}
|
3136
|
if ($rule['sched'])
|
3137
|
$time_based_rules = true;
|
3138
|
}
|
3139
|
|
3140
|
$ipfrules .= "\n# User-defined rules follow\n";
|
3141
|
$ipfrules .= "\nanchor \"userrules/*\"\n";
|
3142
|
/* Generate user rule lines */
|
3143
|
foreach($rule_arr1 as $rule) {
|
3144
|
if (isset($rule['disabled']))
|
3145
|
continue;
|
3146
|
if (!$rule['rule'])
|
3147
|
continue;
|
3148
|
$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
|
3149
|
}
|
3150
|
foreach($rule_arr2 as $rule) {
|
3151
|
if (isset($rule['disabled']))
|
3152
|
continue;
|
3153
|
if (!$rule['rule'])
|
3154
|
continue;
|
3155
|
$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
|
3156
|
}
|
3157
|
foreach($rule_arr3 as $rule) {
|
3158
|
if (isset($rule['disabled']))
|
3159
|
continue;
|
3160
|
if (!$rule['rule'])
|
3161
|
continue;
|
3162
|
$ipfrules .= "{$rule['rule']} {$rule['descr']}\n";
|
3163
|
}
|
3164
|
unset($rule_arr1, $rule_arr2, $rule_arr3);
|
3165
|
}
|
3166
|
|
3167
|
$saved_tracker += 100;
|
3168
|
$tracker = $saved_tracker;
|
3169
|
|
3170
|
/* pass traffic between statically routed subnets and the subnet on the
|
3171
|
* interface in question to avoid problems with complicated routing
|
3172
|
* topologies
|
3173
|
*/
|
3174
|
if(isset($config['filter']['bypassstaticroutes']) && is_array($config['staticroutes']['route']) && count($config['staticroutes']['route'])) {
|
3175
|
$ipfrules .= "# Add rules to bypass firewall rules for static routes\n";
|
3176
|
foreach (get_staticroutes() as $route) {
|
3177
|
$friendly = $GatewaysList[$route['gateway']]['friendlyiface'];
|
3178
|
if(is_array($FilterIflist[$friendly])) {
|
3179
|
$oc = $FilterIflist[$friendly];
|
3180
|
$routeent = explode("/", $route['network']);
|
3181
|
unset($sa);
|
3182
|
if (is_ipaddrv4($oc['ip'])) {
|
3183
|
$sa = $oc['sa'];
|
3184
|
$sn = $oc['sn'];
|
3185
|
}
|
3186
|
if ($sa && is_ipaddrv4($routeent[0])) {
|
3187
|
$ipfrules .= <<<EOD
|
3188
|
pass {$log} 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"
|
3189
|
pass {$log} quick on \${$oc['descr']} from {$sa}/{$sn} to {$route['network']} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
|
3190
|
pass {$log} 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"
|
3191
|
pass {$log} quick on \${$oc['descr']} from {$route['network']} to {$sa}/{$sn} tracker {$increment_tracker($tracker)} keep state(sloppy) label "pass traffic between statically routed subnets"
|
3192
|
|
3193
|
EOD;
|
3194
|
}
|
3195
|
unset($sa);
|
3196
|
if (is_ipaddrv6($oc['ipv6'])) {
|
3197
|
$sa = $oc['sav6'];
|
3198
|
$sn = $oc['snv6'];
|
3199
|
}
|
3200
|
if ($sa && is_ipaddrv6($routeent[0])) {
|
3201
|
$ipfrules .= <<<EOD
|
3202
|
pass {$log} 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"
|
3203
|
pass {$log} 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"
|
3204
|
pass {$log} 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"
|
3205
|
pass {$log} 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"
|
3206
|
|
3207
|
EOD;
|
3208
|
}
|
3209
|
}
|
3210
|
}
|
3211
|
}
|
3212
|
|
3213
|
update_filter_reload_status(gettext("Creating IPsec rules..."));
|
3214
|
$saved_tracker += 100000;
|
3215
|
$tracker = $saved_tracker;
|
3216
|
$ipfrules .= filter_generate_ipsec_rules($log);
|
3217
|
|
3218
|
$ipfrules .= "\nanchor \"tftp-proxy/*\"\n";
|
3219
|
|
3220
|
$saved_tracker += 200;
|
3221
|
$tracker = $saved_tracker;
|
3222
|
update_filter_reload_status("Creating uPNP rules...");
|
3223
|
if (is_array($config['installedpackages']['miniupnpd']) && is_array($config['installedpackages']['miniupnpd']['config'][0])) {
|
3224
|
if (isset($config['installedpackages']['miniupnpd']['config'][0]['enable']))
|
3225
|
$ipfrules .= "anchor \"miniupnpd\"\n";
|
3226
|
|
3227
|
if (is_array($config['installedpackages']['miniupnpd'][0]['config'])) {
|
3228
|
$upnp_interfaces = explode(",", $config['installedpackages']['miniupnpd'][0]['config']['iface_array']);
|
3229
|
foreach($upnp_interfaces as $upnp_if) {
|
3230
|
if (is_array($FilterIflist[$upnp_if])) {
|
3231
|
$oc = $FilterIflist[$upnp_if];
|
3232
|
unset($sa);
|
3233
|
if($oc['ip']) {
|
3234
|
$sa = $oc['sa'];
|
3235
|
$sn = $oc['sn'];
|
3236
|
}
|
3237
|
if($sa) {
|
3238
|
$ipfrules .= <<<EOD
|
3239
|
pass in {$log} 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"
|
3240
|
|
3241
|
EOD;
|
3242
|
}
|
3243
|
}
|
3244
|
}
|
3245
|
}
|
3246
|
}
|
3247
|
|
3248
|
|
3249
|
return $ipfrules;
|
3250
|
}
|
3251
|
|
3252
|
function filter_rules_spoofcheck_generate($ifname, $ifcfg, $log) {
|
3253
|
global $g, $config, $tracker;
|
3254
|
if(isset($config['system']['developerspew'])) {
|
3255
|
$mt = microtime();
|
3256
|
echo "filter_rules_spoofcheck_generate() being called $mt\n";
|
3257
|
}
|
3258
|
$ipfrules = "antispoof {$log} for \${$ifcfg['descr']} tracker {$tracker}\n";
|
3259
|
$tracker++;
|
3260
|
|
3261
|
return $ipfrules;
|
3262
|
}
|
3263
|
|
3264
|
/* COMPAT Function */
|
3265
|
function tdr_install_cron($should_install) {
|
3266
|
log_error(gettext("Please use filter_tdr_install_cron() function tdr_install_cron will be deprecated!"));
|
3267
|
filter_tdr_install_cron($should_install);
|
3268
|
}
|
3269
|
|
3270
|
/****f* filter/filter_tdr_install_cron
|
3271
|
* NAME
|
3272
|
* filter_tdr_install_cron
|
3273
|
* INPUTS
|
3274
|
* $should_install true if the cron entry should be installed, false
|
3275
|
* if the entry should be removed if it is present
|
3276
|
* RESULT
|
3277
|
* none
|
3278
|
******/
|
3279
|
function filter_tdr_install_cron($should_install) {
|
3280
|
global $config, $g;
|
3281
|
|
3282
|
if($g['booting']==true)
|
3283
|
return;
|
3284
|
|
3285
|
if (!is_array($config['cron']))
|
3286
|
$config['cron'] = array();
|
3287
|
if (!is_array($config['cron']['item']))
|
3288
|
$config['cron']['item'] = array();
|
3289
|
|
3290
|
$x=0;
|
3291
|
$is_installed = false;
|
3292
|
foreach($config['cron']['item'] as $item) {
|
3293
|
if (strstr($item['command'], "filter_configure_sync")) {
|
3294
|
$is_installed = true;
|
3295
|
break;
|
3296
|
}
|
3297
|
$x++;
|
3298
|
}
|
3299
|
|
3300
|
switch($should_install) {
|
3301
|
case true:
|
3302
|
if (!$is_installed) {
|
3303
|
$cron_item = array();
|
3304
|
$cron_item['minute'] = "0,15,30,45";
|
3305
|
$cron_item['hour'] = "*";
|
3306
|
$cron_item['mday'] = "*";
|
3307
|
$cron_item['month'] = "*";
|
3308
|
$cron_item['wday'] = "*";
|
3309
|
$cron_item['who'] = "root";
|
3310
|
$cron_item['command'] = "/etc/rc.filter_configure_sync";
|
3311
|
$config['cron']['item'][] = $cron_item;
|
3312
|
write_config(gettext("Installed 15 minute filter reload for Time Based Rules"));
|
3313
|
configure_cron();
|
3314
|
}
|
3315
|
break;
|
3316
|
case false:
|
3317
|
if ($is_installed == true) {
|
3318
|
unset($config['cron']['item'][$x]);
|
3319
|
write_config(gettext("Removed 15 minute filter reload for Time Based Rules"));
|
3320
|
configure_cron();
|
3321
|
}
|
3322
|
break;
|
3323
|
}
|
3324
|
}
|
3325
|
|
3326
|
/****f* filter/filter_get_time_based_rule_status
|
3327
|
* NAME
|
3328
|
* filter_get_time_based_rule_status
|
3329
|
* INPUTS
|
3330
|
* xml schedule block
|
3331
|
* RESULT
|
3332
|
* true/false - true if the rule should be installed
|
3333
|
******/
|
3334
|
/*
|
3335
|
<schedules>
|
3336
|
<schedule>
|
3337
|
<name>ScheduleMultipleTime</name>
|
3338
|
<descr>main descr</descr>
|
3339
|
<time>
|
3340
|
<position>0,1,2</position>
|
3341
|
<hour>0:0-24:0</hour>
|
3342
|
<desc>time range 2</desc>
|
3343
|
</time>
|
3344
|
<time>
|
3345
|
<position>4,5,6</position>
|
3346
|
<hour>0:0-24:0</hour>
|
3347
|
<desc>time range 1</desc>
|
3348
|
</time>
|
3349
|
</schedule>
|
3350
|
</schedules>
|
3351
|
*/
|
3352
|
function filter_get_time_based_rule_status($schedule) {
|
3353
|
|
3354
|
/* no schedule? rule should be installed */
|
3355
|
if (empty($schedule))
|
3356
|
return true;
|
3357
|
/*
|
3358
|
* iterate through time blocks and determine
|
3359
|
* if the rule should be installed or not.
|
3360
|
*/
|
3361
|
foreach($schedule['timerange'] as $timeday) {
|
3362
|
if (empty($timeday['month']))
|
3363
|
$monthstatus = true;
|
3364
|
else
|
3365
|
$monthstatus = filter_tdr_month($timeday['month']);
|
3366
|
if (empty($timeday['day']))
|
3367
|
$daystatus = true;
|
3368
|
else
|
3369
|
$daystatus = filter_tdr_day($timeday['day']);
|
3370
|
if (empty($timeday['hour']))
|
3371
|
$hourstatus = true;
|
3372
|
else
|
3373
|
$hourstatus = filter_tdr_hour($timeday['hour']);
|
3374
|
if (empty($timeday['position']))
|
3375
|
$positionstatus = true;
|
3376
|
else
|
3377
|
$positionstatus = filter_tdr_position($timeday['position']);
|
3378
|
|
3379
|
if ($monthstatus == true && $daystatus == true && $positionstatus == true && $hourstatus == true)
|
3380
|
return true;
|
3381
|
}
|
3382
|
|
3383
|
return false;
|
3384
|
}
|
3385
|
|
3386
|
function filter_tdr_day($schedule) {
|
3387
|
global $g;
|
3388
|
|
3389
|
if($g['debug'])
|
3390
|
log_error("[TDR DEBUG] filter_tdr_day($schedule)");
|
3391
|
|
3392
|
/*
|
3393
|
* Calculate day of month.
|
3394
|
* IE: 29th of may
|
3395
|
*/
|
3396
|
$date = date("d");
|
3397
|
$defined_days = explode(",", $schedule);
|
3398
|
foreach($defined_days as $dd) {
|
3399
|
if ($date == $dd)
|
3400
|
return true;
|
3401
|
}
|
3402
|
return false;
|
3403
|
}
|
3404
|
function filter_tdr_hour($schedule) {
|
3405
|
global $g;
|
3406
|
|
3407
|
/* $schedule should be a string such as 16:00-19:00 */
|
3408
|
$tmp = explode("-", $schedule);
|
3409
|
$starting_time = strtotime($tmp[0]);
|
3410
|
$ending_time = strtotime($tmp[1]);
|
3411
|
$now = strtotime("now");
|
3412
|
if($g['debug'])
|
3413
|
log_error("[TDR DEBUG] S: $starting_time E: $ending_time N: $now");
|
3414
|
if($now >= $starting_time and $now <= $ending_time)
|
3415
|
return true;
|
3416
|
return false;
|
3417
|
}
|
3418
|
|
3419
|
function filter_tdr_position($schedule) {
|
3420
|
global $g;
|
3421
|
|
3422
|
/*
|
3423
|
* Calculate position, ie: day of week.
|
3424
|
* Sunday = 7, Monday = 1, Tuesday = 2
|
3425
|
* Weds = 3, Thursday = 4, Friday = 5,
|
3426
|
* Saturday = 6
|
3427
|
* ...
|
3428
|
*/
|
3429
|
$weekday = date("w");
|
3430
|
if($g['debug'])
|
3431
|
log_error("[TDR DEBUG] filter_tdr_position($schedule) $weekday");
|
3432
|
if($weekday == 0)
|
3433
|
$weekday = 7;
|
3434
|
$schedule_days = explode(",", $schedule);
|
3435
|
foreach($schedule_days as $day) {
|
3436
|
if($day == $weekday)
|
3437
|
return true;
|
3438
|
}
|
3439
|
return false;
|
3440
|
}
|
3441
|
|
3442
|
function filter_tdr_month($schedule) {
|
3443
|
global $g;
|
3444
|
|
3445
|
/*
|
3446
|
* Calculate month
|
3447
|
*/
|
3448
|
$todays_month = date("n");
|
3449
|
$months = explode(",", $schedule);
|
3450
|
if($g['debug'])
|
3451
|
log_error("[TDR DEBUG] filter_tdr_month($schedule)");
|
3452
|
foreach($months as $month) {
|
3453
|
if($month == $todays_month)
|
3454
|
return true;
|
3455
|
}
|
3456
|
return false;
|
3457
|
}
|
3458
|
|
3459
|
function filter_setup_logging_interfaces() {
|
3460
|
global $config, $FilterIflist;
|
3461
|
|
3462
|
if(isset($config['system']['developerspew'])) {
|
3463
|
$mt = microtime();
|
3464
|
echo "filter_setup_logging_interfaces() being called $mt\n";
|
3465
|
}
|
3466
|
$rules = "";
|
3467
|
if (isset($FilterIflist['lan']))
|
3468
|
$rules .= "set loginterface {$FilterIflist['lan']['if']}\n";
|
3469
|
else if (isset($FilterIflist['wan']))
|
3470
|
$rules .= "set loginterface {$FilterIflist['wan']['if']}\n";
|
3471
|
|
3472
|
return $rules;
|
3473
|
}
|
3474
|
|
3475
|
function filter_process_carp_rules($log) {
|
3476
|
global $g, $config, $tracker;
|
3477
|
|
3478
|
if(isset($config['system']['developerspew'])) {
|
3479
|
$mt = microtime();
|
3480
|
echo "filter_process_carp_rules($log) being called $mt\n";
|
3481
|
}
|
3482
|
|
3483
|
$increment_tracker = 'filter_rule_tracker';
|
3484
|
$lines = "";
|
3485
|
/* return if there are no carp configured items */
|
3486
|
if (!empty($config['hasync']) or !empty($config['virtualip']['vip'])) {
|
3487
|
$lines .= "block in {$log} quick proto carp from (self) to any tracker {$increment_tracker($tracker)}\n";
|
3488
|
$lines .= "pass {$log} quick proto carp tracker {$increment_tracker($tracker)}\n";
|
3489
|
}
|
3490
|
return $lines;
|
3491
|
}
|
3492
|
|
3493
|
/* Generate IPSEC Filter Items */
|
3494
|
function filter_generate_ipsec_rules($log = "") {
|
3495
|
global $config, $g, $FilterIflist, $tracker;
|
3496
|
|
3497
|
if(isset($config['system']['developerspew'])) {
|
3498
|
$mt = microtime();
|
3499
|
echo "filter_generate_ipsec_rules() being called $mt\n";
|
3500
|
}
|
3501
|
|
3502
|
if (isset($config['system']['disablevpnrules']))
|
3503
|
return "\n# VPN Rules not added disabled in System->Advanced.\n";
|
3504
|
|
3505
|
$increment_tracker = 'filter_rule_tracker';
|
3506
|
|
3507
|
$ipfrules = "\n# VPN Rules\n";
|
3508
|
/* Is IP Compression enabled? */
|
3509
|
if(isset($config['ipsec']['ipcomp']))
|
3510
|
exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=1");
|
3511
|
else
|
3512
|
exec("/sbin/sysctl net.inet.ipcomp.ipcomp_enable=0");
|
3513
|
|
3514
|
if(isset($config['ipsec']['enable']) &&
|
3515
|
is_array($config['ipsec']['phase1'])) {
|
3516
|
/* step through all phase1 entries */
|
3517
|
foreach ($config['ipsec']['phase1'] as $ph1ent) {
|
3518
|
$tracker += 10;
|
3519
|
|
3520
|
if(isset ($ph1ent['disabled']))
|
3521
|
continue;
|
3522
|
/* determine local and remote peer addresses */
|
3523
|
if(!isset($ph1ent['mobile'])) {
|
3524
|
if (!function_exists('ipsec_get_phase1_dst'))
|
3525
|
require_once("ipsec.inc");
|
3526
|
$rgip = ipsec_get_phase1_dst($ph1ent);
|
3527
|
if(!$rgip) {
|
3528
|
$ipfrules .= "# ERROR! Unable to determine remote IPsec peer address for {$ph1ent['remote-gateway']}\n";
|
3529
|
continue;
|
3530
|
}
|
3531
|
} else
|
3532
|
$rgip = " any ";
|
3533
|
/* Determine best description */
|
3534
|
if($ph1ent['descr'])
|
3535
|
$descr = $ph1ent['descr'];
|
3536
|
else
|
3537
|
$descr = $rgip;
|
3538
|
/*
|
3539
|
* Step through all phase2 entries and determine
|
3540
|
* which protocols are in use with this peer
|
3541
|
*/
|
3542
|
$prot_used_esp = false;
|
3543
|
$prot_used_ah = false;
|
3544
|
if(is_array($config['ipsec']['phase2'])) {
|
3545
|
foreach ($config['ipsec']['phase2'] as $ph2ent) {
|
3546
|
/* only evaluate ph2's bound to our ph1 */
|
3547
|
if($ph2ent['ikeid'] != $ph1ent['ikeid'])
|
3548
|
continue;
|
3549
|
if($ph2ent['protocol'] == 'esp')
|
3550
|
$prot_used_esp = true;
|
3551
|
if($ph2ent['protocol'] == 'ah')
|
3552
|
$prot_used_ah = true;
|
3553
|
}
|
3554
|
}
|
3555
|
|
3556
|
if (strstr($ph1ent['interface'], "_vip"))
|
3557
|
list($parentinterface, $vhid) = explode("_vhid", $ph1ent['interface']);
|
3558
|
else
|
3559
|
$parentinterface = $ph1ent['interface'];
|
3560
|
if (empty($FilterIflist[$parentinterface]['descr'])) {
|
3561
|
$ipfrules .= "# Could not locate interface for IPsec: {$descr}\n";
|
3562
|
continue;
|
3563
|
}
|
3564
|
|
3565
|
unset($gateway);
|
3566
|
/* add endpoint routes to correct gateway on interface */
|
3567
|
if((is_ipaddrv4($rgip)) && (interface_has_gateway($parentinterface))) {
|
3568
|
$gateway = get_interface_gateway($parentinterface);
|
3569
|
$interface = $FilterIflist[$parentinterface]['if'];
|
3570
|
|
3571
|
$route_to = " route-to ( $interface $gateway ) ";
|
3572
|
$reply_to = " reply-to ( $interface $gateway ) ";
|
3573
|
|
3574
|
}
|
3575
|
if((is_ipaddrv6($rgip)) && (interface_has_gatewayv6($parentinterface))) {
|
3576
|
$gateway = get_interface_gateway_v6($parentinterface);
|
3577
|
$interface = $FilterIflist[$parentinterface]['if'];
|
3578
|
|
3579
|
$route_to = " route-to ( $interface $gateway ) ";
|
3580
|
$reply_to = " reply-to ( $interface $gateway ) ";
|
3581
|
}
|
3582
|
|
3583
|
/* Just in case */
|
3584
|
if((!is_ipaddr($gateway) || empty($interface))) {
|
3585
|
$route_to = " ";
|
3586
|
$reply_to = " ";
|
3587
|
}
|
3588
|
|
3589
|
/* Add rules to allow IKE to pass */
|
3590
|
$shorttunneldescr = substr($descr, 0, 35);
|
3591
|
$ipfrules .= <<<EOD
|
3592
|
pass out {$log} 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"
|
3593
|
pass in {$log} 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"
|
3594
|
|
3595
|
EOD;
|
3596
|
/* If NAT-T is enabled, add additional rules */
|
3597
|
if($ph1ent['nat_traversal'] != "off" ) {
|
3598
|
$ipfrules .= <<<EOD
|
3599
|
pass out {$log} 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"
|
3600
|
pass in {$log} 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"
|
3601
|
|
3602
|
EOD;
|
3603
|
}
|
3604
|
/* Add rules to allow the protocols in use */
|
3605
|
if($prot_used_esp == true) {
|
3606
|
$ipfrules .= <<<EOD
|
3607
|
pass out {$log} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto esp from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound esp proto"
|
3608
|
pass in {$log} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto esp from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound esp proto"
|
3609
|
|
3610
|
EOD;
|
3611
|
}
|
3612
|
if($prot_used_ah == true) {
|
3613
|
$ipfrules .= <<<EOD
|
3614
|
pass out {$log} on \${$FilterIflist[$parentinterface]['descr']} $route_to proto ah from any to {$rgip} tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - outbound ah proto"
|
3615
|
pass in {$log} on \${$FilterIflist[$parentinterface]['descr']} $reply_to proto ah from {$rgip} to any tracker {$increment_tracker($tracker)} keep state label "IPsec: {$shorttunneldescr} - inbound ah proto"
|
3616
|
|
3617
|
EOD;
|
3618
|
}
|
3619
|
}
|
3620
|
|
3621
|
}
|
3622
|
return($ipfrules);
|
3623
|
}
|
3624
|
|
3625
|
function discover_pkg_rules($ruletype) {
|
3626
|
global $config, $g, $aliases;
|
3627
|
|
3628
|
/* Bail if there is no pkg directory, or if the package files might be out of sync. */
|
3629
|
if(!is_dir("/usr/local/pkg") || file_exists('/conf/needs_package_sync'))
|
3630
|
return "";
|
3631
|
|
3632
|
$rules = "";
|
3633
|
$files = glob("/usr/local/pkg/*.inc");
|
3634
|
foreach($files as $pkg_inc) {
|
3635
|
update_filter_reload_status(sprintf(gettext('Checking for %1$s PF hooks in package %2$s'), $ruletype, $pkg_inc));
|
3636
|
$pkg = basename($pkg_inc, ".inc");
|
3637
|
$pkg_generate_rules = "{$pkg}_generate_rules";
|
3638
|
if (!function_exists($pkg_generate_rules))
|
3639
|
require_once($pkg_inc);
|
3640
|
if(function_exists($pkg_generate_rules)) {
|
3641
|
update_filter_reload_status(sprintf(gettext('Processing early %1$s rules for package %2$s'), $ruletype, $pkg_inc));
|
3642
|
$tmprules = $pkg_generate_rules("$ruletype");
|
3643
|
file_put_contents("{$g['tmp_path']}/rules.test.packages", $aliases . $tmprules);
|
3644
|
$status = mwexec("/sbin/pfctl -nf {$g['tmp_path']}/rules.test.packages");
|
3645
|
if ($status <> 0) {
|
3646
|
$errorrules = sprintf(gettext("There was an error while parsing the package filter rules for %s."), $pkg_inc) . "\n";
|
3647
|
log_error($errorrules);
|
3648
|
file_put_contents("{$g['tmp_path']}/rules.packages.{$pkg}", "#{$errorrules}\n{$tmprules}\n");
|
3649
|
continue;
|
3650
|
}
|
3651
|
$rules .= $tmprules;
|
3652
|
}
|
3653
|
}
|
3654
|
return $rules;
|
3655
|
}
|
3656
|
|
3657
|
function filter_get_antilockout_ports($wantarray = false) {
|
3658
|
global $config;
|
3659
|
|
3660
|
$lockoutports = array();
|
3661
|
$guiport = ($config['system']['webgui']['protocol'] == "https") ? "443" : "80";
|
3662
|
$guiport = empty($config['system']['webgui']['port']) ? $guiport : $config['system']['webgui']['port'];
|
3663
|
$lockoutports[] = $guiport;
|
3664
|
|
3665
|
if (($config['system']['webgui']['protocol'] == "https") && !isset($config['system']['webgui']['disablehttpredirect']) && ($guiport != "80"))
|
3666
|
$lockoutports[] = "80";
|
3667
|
|
3668
|
if (isset($config['system']['enablesshd']))
|
3669
|
$lockoutports[] = empty($config['system']['ssh']['port']) ? "22" : $config['system']['ssh']['port'];
|
3670
|
|
3671
|
if ($wantarray)
|
3672
|
return $lockoutports;
|
3673
|
else
|
3674
|
return implode(" ", $lockoutports);
|
3675
|
|
3676
|
}
|
3677
|
|
3678
|
?>
|