Project

General

Profile

Download (33 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * firewall_rules.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * originally based on m0n0wall (http://m0n0.ch/wall)
10
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
11
 * All rights reserved.
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 * http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25

    
26
##|+PRIV
27
##|*IDENT=page-firewall-rules
28
##|*NAME=Firewall: Rules
29
##|*DESCR=Allow access to the 'Firewall: Rules' page.
30
##|*MATCH=firewall_rules.php*
31
##|-PRIV
32

    
33
require_once("guiconfig.inc");
34
require_once("functions.inc");
35
require_once("filter.inc");
36
require_once("ipsec.inc");
37
require_once("shaper.inc");
38

    
39
$XmoveTitle = gettext("Move checked rules above this one. Shift+Click to move checked rules below.");
40
$ShXmoveTitle = gettext("Move checked rules below this one. Release shift to move checked rules above.");
41

    
42
$shortcut_section = "firewall";
43

    
44
function get_pf_rules($rules, $tracker) {
45

    
46
	if ($rules == NULL || !is_array($rules))
47
		return (NULL);
48

    
49
	$arr = array();
50
	foreach ($rules as $rule) {
51
		if ($rule['tracker'] === $tracker) {
52
			$arr[] = $rule;
53
		}
54
	}
55

    
56
	if (count($arr) == 0)
57
		return (NULL);
58

    
59
	return ($arr);
60
}
61

    
62
function print_states($tracker) {
63
	global $rulescnt;
64

    
65
	$rulesid = "";
66
	$bytes = 0;
67
	$states = 0;
68
	$packets = 0;
69
	$evaluations = 0;
70
	$stcreations = 0;
71
	$rules = get_pf_rules($rulescnt, $tracker);
72
	if (is_array($rules)) {
73
		foreach ($rules as $rule) {
74
			$bytes += $rule['bytes'];
75
			$states += $rule['states'];
76
			$packets += $rule['packets'];
77
			$evaluations += $rule['evaluations'];
78
			$stcreations += $rule['state creations'];
79
			if (strlen($rulesid) > 0) {
80
				$rulesid .= ",";
81
			}
82
			$rulesid .= "{$rule['id']}";
83
		}
84
	}
85

    
86
	printf("<a href=\"diag_dump_states.php?ruleid=%s\" data-toggle=\"popover\" data-trigger=\"hover focus\" title=\"%s\" ",
87
	    $rulesid, gettext("States details"));
88
	printf("data-content=\"evaluations: %s<br>packets: %s<br>bytes: %s<br>states: %s<br>state creations: %s\" data-html=\"true\">",
89
	    format_number($evaluations), format_number($packets), format_bytes($bytes),
90
	    format_number($states), format_number($stcreations));
91
	printf("%s/%s</a><br>", format_number($states), format_bytes($bytes));
92
}
93

    
94
function delete_nat_association($id) {
95
	global $config;
96

    
97
	if (!$id || !is_array($config['nat']['rule'])) {
98
		return;
99
	}
100

    
101
	$a_nat = &$config['nat']['rule'];
102

    
103
	foreach ($a_nat as &$natent) {
104
		if ($natent['associated-rule-id'] == $id) {
105
			$natent['associated-rule-id'] = '';
106
		}
107
	}
108
}
109

    
110
if (!is_array($config['filter']['rule'])) {
111
	$config['filter']['rule'] = array();
112
}
113

    
114
filter_rules_sort();
115
$a_filter = &$config['filter']['rule'];
116

    
117
$if = $_GET['if'];
118

    
119
if ($_POST['if']) {
120
	$if = $_POST['if'];
121
}
122

    
123
$ifdescs = get_configured_interface_with_descr();
124

    
125
/* add group interfaces */
126
if (is_array($config['ifgroups']['ifgroupentry'])) {
127
	foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
128
		if (have_ruleint_access($ifgen['ifname'])) {
129
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
130
		}
131
	}
132
}
133

    
134
foreach ($ifdescs as $ifent => $ifdesc) {
135
	if (have_ruleint_access($ifent)) {
136
		$iflist[$ifent] = $ifdesc;
137
	}
138
}
139

    
140
if ($config['l2tp']['mode'] == "server") {
141
	if (have_ruleint_access("l2tp")) {
142
		$iflist['l2tp'] = gettext("L2TP VPN");
143
	}
144
}
145

    
146
if (is_array($config['pppoes']['pppoe'])) {
147
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
148
		if (($pppoes['mode'] == 'server') && have_ruleint_access("pppoe")) {
149
			$iflist['pppoe'] = gettext("PPPoE Server");
150
		}
151
	}
152
}
153

    
154
/* add ipsec interfaces */
155
if (ipsec_enabled() && have_ruleint_access("enc0")) {
156
	$iflist["enc0"] = gettext("IPsec");
157
}
158

    
159
/* add openvpn/tun interfaces */
160
if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
161
	$iflist["openvpn"] = gettext("OpenVPN");
162
}
163

    
164
if (!$if || !isset($iflist[$if])) {
165
	if ($if != "any" && $if != "FloatingRules" && isset($iflist['wan'])) {
166
		$if = "wan";
167
	} else {
168
		$if = "FloatingRules";
169
	}
170
}
171

    
172
if ($_POST) {
173
	$pconfig = $_POST;
174

    
175
	if ($_POST['apply']) {
176
		$retval = 0;
177
		$retval |= filter_configure();
178

    
179
		clear_subsystem_dirty('filter');
180
	}
181
}
182

    
183
if ($_GET['act'] == "del") {
184
	if ($a_filter[$_GET['id']]) {
185
		if (!empty($a_filter[$_GET['id']]['associated-rule-id'])) {
186
			delete_nat_association($a_filter[$_GET['id']]['associated-rule-id']);
187
		}
188
		unset($a_filter[$_GET['id']]);
189

    
190
		// Update the separators
191
		$a_separators = &$config['filter']['separator'][strtolower($if)];
192
		$ridx = ifridx($if, $_GET['id']);	// get rule index within interface
193
		$mvnrows = -1;
194
		move_separators($a_separators, $ridx, $mvnrows);
195

    
196
		if (write_config()) {
197
			mark_subsystem_dirty('filter');
198
		}
199

    
200
		header("Location: firewall_rules.php?if=" . htmlspecialchars($if));
201
		exit;
202
	}
203
}
204

    
205
// Handle save msg if defined
206
if ($_REQUEST['savemsg']) {
207
	$savemsg = htmlentities($_REQUEST['savemsg']);
208
}
209

    
210
if (isset($_POST['del_x'])) {
211
	/* delete selected rules */
212
	$deleted = false;
213

    
214
	if (is_array($_POST['rule']) && count($_POST['rule'])) {
215
		$a_separators = &$config['filter']['separator'][strtolower($if)];
216
		$num_deleted = 0;
217

    
218
		foreach ($_POST['rule'] as $rulei) {
219
			delete_nat_association($a_filter[$rulei]['associated-rule-id']);
220
			unset($a_filter[$rulei]);
221
			$deleted = true;
222

    
223
			// Update the separators
224
			// As rules are deleted, $ridx has to be decremented or separator position will break
225
			$ridx = ifridx($if, $rulei) - $num_deleted;	// get rule index within interface
226
			$mvnrows = -1;
227
			move_separators($a_separators, $ridx, $mvnrows);
228
			$num_deleted++;
229
		}
230

    
231
		if ($deleted) {
232
			if (write_config()) {
233
				mark_subsystem_dirty('filter');
234
			}
235
		}
236

    
237
		header("Location: firewall_rules.php?if=" . htmlspecialchars($if));
238
		exit;
239
	}
240
} else if ($_GET['act'] == "toggle") {
241
	if ($a_filter[$_GET['id']]) {
242
		if (isset($a_filter[$_GET['id']]['disabled'])) {
243
			unset($a_filter[$_GET['id']]['disabled']);
244
		} else {
245
			$a_filter[$_GET['id']]['disabled'] = true;
246
		}
247
		if (write_config()) {
248
			mark_subsystem_dirty('filter');
249
		}
250

    
251
		header("Location: firewall_rules.php?if=" . htmlspecialchars($if));
252
		exit;
253
	}
254
} else if ($_POST['order-store']) {
255

    
256
	/* update rule order, POST[rule] is an array of ordered IDs */
257
	if (is_array($_POST['rule']) && !empty($_POST['rule'])) {
258
		$a_filter_new = array();
259

    
260
		// Include the rules of other interfaces listed in config before this (the selected) interface.
261
		foreach ($a_filter as $filteri_before => $filterent) {
262
			if (($filterent['interface'] == $if && !isset($filterent['floating'])) || (isset($filterent['floating']) && "FloatingRules" == $if)) {
263
				break;
264
			} else {
265
				$a_filter_new[] = $filterent;
266
			}
267
		}
268

    
269
		// Include the rules of this (the selected) interface.
270
		// If a rule is not in POST[rule], it has been deleted by the user
271
		foreach ($_POST['rule'] as $id) {
272
			$a_filter_new[] = $a_filter[$id];
273
		}
274

    
275
		// Include the rules of other interfaces listed in config after this (the selected) interface.
276
		foreach ($a_filter as $filteri_after => $filterent) {
277
			if ($filteri_before > $filteri_after) {
278
				continue;
279
			}
280
			if (($filterent['interface'] == $if && !isset($filterent['floating'])) || (isset($filterent['floating']) && "FloatingRules" == $if)) {
281
				continue;
282
			} else {
283
				$a_filter_new[] = $filterent;
284
			}
285
		}
286

    
287
		$a_filter = $a_filter_new;
288

    
289
		$config['filter']['separator'][strtolower($if)] = "";
290

    
291
		if ($_POST['separator']) {
292
			$idx = 0;
293
			foreach ($_POST['separator'] as $separator) {
294
				$config['filter']['separator'][strtolower($separator['if'])]['sep' . $idx++] = $separator;
295
			}
296
		}
297

    
298
		if (write_config()) {
299
			mark_subsystem_dirty('filter');
300
		}
301

    
302
		header("Location: firewall_rules.php?if=" . htmlspecialchars($if));
303
		exit;
304
	}
305
}
306

    
307
$tab_array = array(array(gettext("Floating"), ("FloatingRules" == $if), "firewall_rules.php?if=FloatingRules"));
308

    
309
foreach ($iflist as $ifent => $ifname) {
310
	$tab_array[] = array($ifname, ($ifent == $if), "firewall_rules.php?if={$ifent}");
311
}
312

    
313
foreach ($tab_array as $dtab) {
314
	if ($dtab[1]) {
315
		$bctab = $dtab[0];
316
		break;
317
	}
318
}
319

    
320
$pgtitle = array(gettext("Firewall"), gettext("Rules"), $bctab);
321
$pglinks = array("", "firewall_rules.php", "@self");
322
$shortcut_section = "firewall";
323

    
324
include("head.inc");
325
$nrules = 0;
326

    
327
if ($savemsg) {
328
	print_info_box($savemsg, 'success');
329
}
330

    
331
if ($_POST['apply']) {
332
	print_apply_result_box($retval);
333
}
334

    
335
if (is_subsystem_dirty('filter')) {
336
	print_apply_box(gettext("The firewall rule configuration has been changed.") . "<br />" . gettext("The changes must be applied for them to take effect."));
337
}
338

    
339
display_top_tabs($tab_array);
340

    
341
$showantilockout = false;
342
$showprivate = false;
343
$showblockbogons = false;
344

    
345
if (!isset($config['system']['webgui']['noantilockout']) &&
346
    (((count($config['interfaces']) > 1) && ($if == 'lan')) ||
347
    ((count($config['interfaces']) == 1) && ($if == 'wan')))) {
348
	$showantilockout = true;
349
}
350

    
351
if (isset($config['interfaces'][$if]['blockpriv'])) {
352
	$showprivate = true;
353
}
354

    
355
if (isset($config['interfaces'][$if]['blockbogons'])) {
356
	$showblockbogons = true;
357
}
358

    
359
/* Load the counter data of each pf rule. */
360
$rulescnt = pfSense_get_pf_rules();
361

    
362
// Update this if you add or remove columns!
363
$columns_in_table = 13;
364

    
365
?>
366
<!-- Allow table to scroll when dragging outside of the display window -->
367
<style>
368
.table-responsive {
369
    clear: both;
370
    overflow-x: visible;
371
    margin-bottom: 0px;
372
}
373
</style>
374

    
375
<form method="post">
376
	<div class="panel panel-default">
377
		<div class="panel-heading"><h2 class="panel-title"><?=gettext("Rules (Drag to Change Order)")?></h2></div>
378
		<div id="mainarea" class="table-responsive panel-body">
379
			<table id="ruletable" class="table table-hover table-striped table-condensed" style="overflow-x: 'visible'">
380
				<thead>
381
					<tr>
382
						<th><!-- checkbox --></th>
383
						<th><!-- status icons --></th>
384
						<th><?=gettext("States")?></th>
385
						<th><?=gettext("Protocol")?></th>
386
						<th><?=gettext("Source")?></th>
387
						<th><?=gettext("Port")?></th>
388
						<th><?=gettext("Destination")?></th>
389
						<th><?=gettext("Port")?></th>
390
						<th><?=gettext("Gateway")?></th>
391
						<th><?=gettext("Queue")?></th>
392
						<th><?=gettext("Schedule")?></th>
393
						<th><?=gettext("Description")?></th>
394
						<th><?=gettext("Actions")?></th>
395
					</tr>
396
				</thead>
397

    
398
<?php if ($showblockbogons || $showantilockout || $showprivate) :
399
?>
400
				<tbody>
401
<?php
402
		// Show the anti-lockout rule if it's enabled, and we are on LAN with an if count > 1, or WAN with an if count of 1.
403
		if ($showantilockout):
404
			$alports = implode('<br />', filter_get_antilockout_ports(true));
405
?>
406
					<tr id="antilockout">
407
						<td></td>
408
						<td title="<?=gettext("traffic is passed")?>"><i class="fa fa-check text-success"></i></td>
409
						<td><?php print_states(intval(ANTILOCKOUT_TRACKER)); ?></td>
410
						<td>*</td>
411
						<td>*</td>
412
						<td>*</td>
413
						<td><?=$iflist[$if];?> Address</td>
414
						<td><?=$alports?></td>
415
						<td>*</td>
416
						<td>*</td>
417
						<td></td>
418
						<td><?=gettext("Anti-Lockout Rule");?></td>
419
						<td>
420
							<a href="system_advanced_admin.php" title="<?=gettext("Settings");?>"><i class="fa fa-cog"></i></a>
421
						</td>
422
					</tr>
423
<?php 	endif;?>
424
<?php 	if ($showprivate): ?>
425
					<tr id="private">
426
						<td></td>
427
						<td title="<?=gettext("traffic is blocked")?>"><i class="fa fa-times text-danger"></i></td>
428
						<td><?php print_states(intval(RFC1918_TRACKER)); ?></td>
429
						<td>*</td>
430
						<td><?=gettext("RFC 1918 networks");?></td>
431
						<td>*</td>
432
						<td>*</td>
433
						<td>*</td>
434
						<td>*</td>
435
						<td>*</td>
436
						<td></td>
437
						<td><?=gettext("Block private networks");?></td>
438
						<td>
439
							<a href="interfaces.php?if=<?=htmlspecialchars($if)?>" title="<?=gettext("Settings");?>"><i class="fa fa-cog"></i></a>
440
						</td>
441
					</tr>
442
<?php 	endif;?>
443
<?php 	if ($showblockbogons): ?>
444
					<tr id="bogons">
445
						<td></td>
446
						<td title="<?=gettext("traffic is blocked")?>"><i class="fa fa-times text-danger"></i></td>
447
						<td><?php print_states(intval(BOGONS_TRACKER)); ?></td>
448
						<td>*</td>
449
						<td><?=sprintf(gettext("Reserved%sNot assigned by IANA"), "<br />");?></td>
450
						<td>*</td>
451
						<td>*</td>
452
						<td>*</td>
453
						<td>*</td>
454
						<td>*</td>
455
						<td></td>
456
						<td><?=gettext("Block bogon networks");?></td>
457
						<td>
458
							<a href="interfaces.php?if=<?=htmlspecialchars($if)?>" title="<?=gettext("Settings");?>"><i class="fa fa-cog"></i></a>
459
						</td>
460
					</tr>
461
<?php 	endif;?>
462
			</tbody>
463
<?php endif;?>
464
			<tbody class="user-entries">
465
<?php
466
$nrules = 0;
467
$separators = $config['filter']['separator'][strtolower($if)];
468

    
469
// Get a list of separator rows and use it to call the display separator function only for rows which there are separator(s).
470
// More efficient than looping through the list of separators on every row.
471
$seprows = separator_rows($separators);
472

    
473
foreach ($a_filter as $filteri => $filterent):
474

    
475
	if (($filterent['interface'] == $if && !isset($filterent['floating'])) || (isset($filterent['floating']) && "FloatingRules" == $if)) {
476

    
477
		// Display separator(s) for section beginning at rule n
478
		if ($seprows[$nrules]) {
479
			display_separator($separators, $nrules, $columns_in_table);
480
		}
481
?>
482
					<tr id="fr<?=$nrules;?>" onClick="fr_toggle(<?=$nrules;?>)" ondblclick="document.location='firewall_rules_edit.php?id=<?=$filteri;?>';" <?=(isset($filterent['disabled']) ? ' class="disabled"' : '')?>>
483
						<td>
484
							<input type="checkbox" id="frc<?=$nrules;?>" onClick="fr_toggle(<?=$nrules;?>)" name="rule[]" value="<?=$filteri;?>"/>
485
						</td>
486

    
487
	<?php
488
		if ($filterent['type'] == "block") {
489
			$iconfn = "times text-danger";
490
			$title_text = gettext("traffic is blocked");
491
		} else if ($filterent['type'] == "reject") {
492
			$iconfn = "hand-stop-o text-warning";
493
			$title_text = gettext("traffic is rejected");
494
		} else if ($filterent['type'] == "match") {
495
			$iconfn = "filter";
496
			$title_text = gettext("traffic is matched");
497
		} else {
498
			$iconfn = "check text-success";
499
			$title_text = gettext("traffic is passed");
500
		}
501
	?>
502
						<td title="<?=$title_text?>">
503
							<a href="?if=<?=htmlspecialchars($if);?>&amp;act=toggle&amp;id=<?=$filteri;?>">
504
								<i class="fa fa-<?=$iconfn?>" title="<?=gettext("click to toggle enabled/disabled status");?>"></i>
505
							</a>
506
	<?php
507
		if ($filterent['quick'] == 'yes') {
508
			print '<i class="fa fa-forward text-success" title="'. gettext("&quot;Quick&quot; rule. Applied immediately on match.") .'" style="cursor: pointer;"></i>';
509
		}
510

    
511
		$isadvset = firewall_check_for_advanced_options($filterent);
512
		if ($isadvset) {
513
			print '<i class="fa fa-cog" title="'. gettext("advanced setting") .': '. $isadvset .'"></i>';
514
		}
515

    
516
		if (isset($filterent['log'])) {
517
			print '<i class="fa fa-tasks" title="'. gettext("traffic is logged") .'" style="cursor: pointer;"></i>';
518
		}
519
	?>
520
						</td>
521
	<?php
522
		$alias = rule_columns_with_alias(
523
			$filterent['source']['address'],
524
			pprint_port($filterent['source']['port']),
525
			$filterent['destination']['address'],
526
			pprint_port($filterent['destination']['port'])
527
		);
528

    
529
		//build Schedule popup box
530
		$a_schedules = &$config['schedules']['schedule'];
531
		$schedule_span_begin = "";
532
		$schedule_span_end = "";
533
		$sched_caption_escaped = "";
534
		$sched_content = "";
535
		$schedstatus = false;
536
		$dayArray = array (gettext('Mon'), gettext('Tues'), gettext('Wed'), gettext('Thur'), gettext('Fri'), gettext('Sat'), gettext('Sun'));
537
		$monthArray = array (gettext('January'), gettext('February'), gettext('March'), gettext('April'), gettext('May'), gettext('June'), gettext('July'), gettext('August'), gettext('September'), gettext('October'), gettext('November'), gettext('December'));
538
		if ($config['schedules']['schedule'] != "" && is_array($config['schedules']['schedule'])) {
539
			$idx = 0;
540
			foreach ($a_schedules as $schedule) {
541
				if ($schedule['name'] == $filterent['sched']) {
542
					$schedstatus = filter_get_time_based_rule_status($schedule);
543

    
544
					foreach ($schedule['timerange'] as $timerange) {
545
						$tempFriendlyTime = "";
546
						$tempID = "";
547
						$firstprint = false;
548
						if ($timerange) {
549
							$dayFriendly = "";
550
							$tempFriendlyTime = "";
551

    
552
							//get hours
553
							$temptimerange = $timerange['hour'];
554
							$temptimeseparator = strrpos($temptimerange, "-");
555

    
556
							$starttime = substr ($temptimerange, 0, $temptimeseparator);
557
							$stoptime = substr ($temptimerange, $temptimeseparator+1);
558

    
559
							if ($timerange['month']) {
560
								$tempmontharray = explode(",", $timerange['month']);
561
								$tempdayarray = explode(",", $timerange['day']);
562
								$arraycounter = 0;
563
								$firstDayFound = false;
564
								$firstPrint = false;
565
								foreach ($tempmontharray as $monthtmp) {
566
									$month = $tempmontharray[$arraycounter];
567
									$day = $tempdayarray[$arraycounter];
568

    
569
									if (!$firstDayFound) {
570
										$firstDay = $day;
571
										$firstmonth = $month;
572
										$firstDayFound = true;
573
									}
574

    
575
									$currentDay = $day;
576
									$nextDay = $tempdayarray[$arraycounter+1];
577
									$currentDay++;
578
									if (($currentDay != $nextDay) || ($tempmontharray[$arraycounter] != $tempmontharray[$arraycounter+1])) {
579
										if ($firstPrint) {
580
											$dayFriendly .= ", ";
581
										}
582
										$currentDay--;
583
										if ($currentDay != $firstDay) {
584
											$dayFriendly .= $monthArray[$firstmonth-1] . " " . $firstDay . " - " . $currentDay ;
585
										} else {
586
											$dayFriendly .=	 $monthArray[$month-1] . " " . $day;
587
										}
588
										$firstDayFound = false;
589
										$firstPrint = true;
590
									}
591
									$arraycounter++;
592
								}
593
							} else {
594
								$tempdayFriendly = $timerange['position'];
595
								$firstDayFound = false;
596
								$tempFriendlyDayArray = explode(",", $tempdayFriendly);
597
								$currentDay = "";
598
								$firstDay = "";
599
								$nextDay = "";
600
								$counter = 0;
601
								foreach ($tempFriendlyDayArray as $day) {
602
									if ($day != "") {
603
										if (!$firstDayFound) {
604
											$firstDay = $tempFriendlyDayArray[$counter];
605
											$firstDayFound = true;
606
										}
607
										$currentDay =$tempFriendlyDayArray[$counter];
608
										//get next day
609
										$nextDay = $tempFriendlyDayArray[$counter+1];
610
										$currentDay++;
611
										if ($currentDay != $nextDay) {
612
											if ($firstprint) {
613
												$dayFriendly .= ", ";
614
											}
615
											$currentDay--;
616
											if ($currentDay != $firstDay) {
617
												$dayFriendly .= $dayArray[$firstDay-1] . " - " . $dayArray[$currentDay-1];
618
											} else {
619
												$dayFriendly .= $dayArray[$firstDay-1];
620
											}
621
											$firstDayFound = false;
622
											$firstprint = true;
623
										}
624
										$counter++;
625
									}
626
								}
627
							}
628
							$timeFriendly = $starttime . " - " . $stoptime;
629
							$description = $timerange['rangedescr'];
630
							$sched_content .= $dayFriendly . "; " . $timeFriendly . "<br />";
631
						}
632
					}
633
					#FIXME
634
					$sched_caption_escaped = str_replace("'", "\'", $schedule['descr']);
635
					$schedule_span_begin = '<a href="/firewall_schedule_edit.php?id=' . $idx . '" data-toggle="popover" data-trigger="hover focus" title="' . $schedule['name'] . '" data-content="' .
636
						$sched_caption_escaped . '" data-html="true">';
637
					$schedule_span_end = "</a>";
638
				}
639
				$idx++;
640
			}
641
		}
642
		$printicon = false;
643
		$alttext = "";
644
		$image = "";
645
		if (!isset($filterent['disabled'])) {
646
			if ($schedstatus) {
647
				if ($filterent['type'] == "block" || $filterent['type'] == "reject") {
648
					$image = "times-circle";
649
					$dispcolor = "text-danger";
650
					$alttext = gettext("Traffic matching this rule is currently being denied");
651
				} else {
652
					$image = "play-circle";
653
					$dispcolor = "text-success";
654
					$alttext = gettext("Traffic matching this rule is currently being allowed");
655
				}
656
				$printicon = true;
657
			} else if ($filterent['sched']) {
658
				if ($filterent['type'] == "block" || $filterent['type'] == "reject") {
659
					$image = "times-circle";
660
				} else {
661
					$image = "play-circle";
662
				}
663
				$alttext = gettext("This rule is not currently active because its period has expired");
664
				$dispcolor = "text-warning";
665
				$printicon = true;
666
			}
667
		}
668
	?>
669
				<td><?php print_states(intval($filterent['tracker'])); ?></td>
670
				<td>
671
	<?php
672
		if (isset($filterent['ipprotocol'])) {
673
			switch ($filterent['ipprotocol']) {
674
				case "inet":
675
					echo "IPv4 ";
676
					break;
677
				case "inet6":
678
					echo "IPv6 ";
679
					break;
680
				case "inet46":
681
					echo "IPv4+6 ";
682
					break;
683
			}
684
		} else {
685
			echo "IPv4 ";
686
		}
687

    
688
		if (isset($filterent['protocol'])) {
689
			echo strtoupper($filterent['protocol']);
690

    
691
			if (strtoupper($filterent['protocol']) == "ICMP" && !empty($filterent['icmptype'])) {
692
				// replace each comma-separated icmptype item by its (localised) full description
693
				$t = 	implode(', ',
694
						array_map(
695
						        function($type) {
696
								global $icmptypes;
697
								return $icmptypes[$type]['descrip'];
698
							},
699
							explode(',', $filterent['icmptype'])
700
						)
701
					);
702
				echo sprintf('<br /><div style="cursor:help;padding:1px;line-height:1.1em;max-height:2.5em;max-width:180px;overflow-y:auto;overflow-x:hidden" title="%s:%s%s"><small><u>%s</u></small></div>', gettext('ICMP subtypes'), chr(13), $t, str_replace(',', '</u>, <u>',$filterent['icmptype']));
703
			}
704
		} else {
705
			echo " *";
706
		}
707
	?>
708
						</td>
709
						<td>
710
							<?php if (isset($alias['src'])): ?>
711
								<a href="/firewall_aliases_edit.php?id=<?=$alias['src']?>" data-toggle="popover" data-trigger="hover focus" title="<?=gettext('Alias details')?>" data-content="<?=alias_info_popup($alias['src'])?>" data-html="true">
712
									<?=str_replace('_', ' ', htmlspecialchars(pprint_address($filterent['source'])))?>
713
								</a>
714
							<?php else: ?>
715
								<?=htmlspecialchars(pprint_address($filterent['source']))?>
716
							<?php endif; ?>
717
						</td>
718
						<td>
719
							<?php if (isset($alias['srcport'])): ?>
720
								<a href="/firewall_aliases_edit.php?id=<?=$alias['srcport']?>" data-toggle="popover" data-trigger="hover focus" title="<?=gettext('Alias details')?>" data-content="<?=alias_info_popup($alias['srcport'])?>" data-html="true">
721
									<?=str_replace('_', ' ', htmlspecialchars(pprint_port($filterent['source']['port'])))?>
722
								</a>
723
							<?php else: ?>
724
								<?=htmlspecialchars(pprint_port($filterent['source']['port']))?>
725
							<?php endif; ?>
726
						</td>
727
						<td>
728
							<?php if (isset($alias['dst'])): ?>
729
								<a href="/firewall_aliases_edit.php?id=<?=$alias['dst']?>" data-toggle="popover" data-trigger="hover focus" title="<?=gettext('Alias details')?>" data-content="<?=alias_info_popup($alias['dst'])?>" data-html="true">
730
									<?=str_replace('_', ' ', htmlspecialchars(pprint_address($filterent['destination'])))?>
731
								</a>
732
							<?php else: ?>
733
								<?=htmlspecialchars(pprint_address($filterent['destination']))?>
734
							<?php endif; ?>
735
						</td>
736
						<td>
737
							<?php if (isset($alias['dstport'])): ?>
738
								<a href="/firewall_aliases_edit.php?id=<?=$alias['dstport']?>" data-toggle="popover" data-trigger="hover focus" title="<?=gettext('Alias details')?>" data-content="<?=alias_info_popup($alias['dstport'])?>" data-html="true">
739
									<?=str_replace('_', ' ', htmlspecialchars(pprint_port($filterent['destination']['port'])))?>
740
								</a>
741
							<?php else: ?>
742
								<?=htmlspecialchars(pprint_port($filterent['destination']['port']))?>
743
							<?php endif; ?>
744
						</td>
745
						<td>
746
							<?php if (isset($config['interfaces'][$filterent['gateway']]['descr'])):?>
747
								<?=str_replace('_', ' ', htmlspecialchars($config['interfaces'][$filterent['gateway']]['descr']))?>
748
							<?php else: ?>
749
								<?=htmlspecialchars(pprint_port($filterent['gateway']))?>
750
							<?php endif; ?>
751
						</td>
752
						<td>
753
							<?php
754
								if (isset($filterent['ackqueue']) && isset($filterent['defaultqueue'])) {
755
									$desc = str_replace('_', ' ', $filterent['ackqueue']);
756
									echo "<a href=\"firewall_shaper_queues.php?queue={$filterent['ackqueue']}&amp;action=show\">{$desc}</a>";
757
									$desc = str_replace('_', ' ', $filterent['defaultqueue']);
758
									echo "/<a href=\"firewall_shaper_queues.php?queue={$filterent['defaultqueue']}&amp;action=show\">{$desc}</a>";
759
								} else if (isset($filterent['defaultqueue'])) {
760
									$desc = str_replace('_', ' ', $filterent['defaultqueue']);
761
									echo "<a href=\"firewall_shaper_queues.php?queue={$filterent['defaultqueue']}&amp;action=show\">{$desc}</a>";
762
								} else {
763
									echo gettext("none");
764
								}
765
							?>
766
						</td>
767
						<td>
768
							<?php if ($printicon) { ?>
769
								<i class="fa fa-<?=$image?> <?=$dispcolor?>" title="<?=$alttext;?>"></i>
770
							<?php } ?>
771
							<?=$schedule_span_begin;?><?=str_replace('_', ' ', htmlspecialchars($filterent['sched']));?>&nbsp;<?=$schedule_span_end;?>
772
						</td>
773
						<td>
774
							<?=htmlspecialchars($filterent['descr']);?>
775
						</td>
776
						<td class="action-icons">
777
						<!-- <?=(isset($filterent['disabled']) ? 'enable' : 'disable')?> -->
778
							<a	class="fa fa-anchor icon-pointer" id="Xmove_<?=$filteri?>" title="<?=$XmoveTitle?>"></a>
779
							<a href="firewall_rules_edit.php?id=<?=$filteri;?>" class="fa fa-pencil" title="<?=gettext('Edit')?>"></a>
780
							<a href="firewall_rules_edit.php?dup=<?=$filteri;?>" class="fa fa-clone" title="<?=gettext('Copy')?>"></a>
781
<?php if (isset($filterent['disabled'])) {
782
?>
783
							<a href="?act=toggle&amp;if=<?=htmlspecialchars($if);?>&amp;id=<?=$filteri;?>" class="fa fa-check-square-o" title="<?=gettext('Enable')?>"></a>
784
<?php } else {
785
?>
786
							<a href="?act=toggle&amp;if=<?=htmlspecialchars($if);?>&amp;id=<?=$filteri;?>" class="fa fa-ban" title="<?=gettext('Disable')?>"></a>
787
<?php }
788
?>
789
							<a href="?act=del&amp;if=<?=htmlspecialchars($if);?>&amp;id=<?=$filteri;?>" class="fa fa-trash" title="<?=gettext('Delete this rule')?>"></a>
790
						</td>
791
					</tr>
792
<?php
793
		$nrules++;
794
	}
795
endforeach;
796

    
797
// There can be separator(s) after the last rule listed.
798
if ($seprows[$nrules]) {
799
	display_separator($separators, $nrules, $columns_in_table);
800
}
801
?>
802
				</tbody>
803
			</table>
804
		</div>
805
	</div>
806

    
807
<?php if ($nrules == 0): ?>
808
	<div class="alert alert-warning" role="alert">
809
		<p>
810
		<?php if ($_REQUEST['if'] == "FloatingRules"): ?>
811
			<?=gettext("No floating rules are currently defined.");?>
812
		<?php else: ?>
813
			<?=gettext("No rules are currently defined for this interface");?><br />
814
			<?=gettext("All incoming connections on this interface will be blocked until pass rules are added.");?>
815
		<?php endif;?>
816
			<?=gettext("Click the button to add a new rule.");?>
817
		</p>
818
	</div>
819
<?php endif;?>
820

    
821
	<nav class="action-buttons">
822
		<a href="firewall_rules_edit.php?if=<?=htmlspecialchars($if);?>&amp;after=-1" role="button" class="btn btn-sm btn-success" title="<?=gettext('Add rule to the top of the list')?>">
823
			<i class="fa fa-level-up icon-embed-btn"></i>
824
			<?=gettext("Add");?>
825
		</a>
826
		<a href="firewall_rules_edit.php?if=<?=htmlspecialchars($if);?>" role="button" class="btn btn-sm btn-success" title="<?=gettext('Add rule to the end of the list')?>">
827
			<i class="fa fa-level-down icon-embed-btn"></i>
828
			<?=gettext("Add");?>
829
		</a>
830
		<button name="del_x" type="submit" class="btn btn-danger btn-sm" value="<?=gettext("Delete selected rules"); ?>" title="<?=gettext('Delete selected rules')?>">
831
			<i class="fa fa-trash icon-embed-btn"></i>
832
			<?=gettext("Delete"); ?>
833
		</button>
834
		<button type="submit" id="order-store" name="order-store" class="btn btn-sm btn-primary" value="store changes" disabled title="<?=gettext('Save rule order')?>">
835
			<i class="fa fa-save icon-embed-btn"></i>
836
			<?=gettext("Save")?>
837
		</button>
838
		<button type="submit" id="addsep" name="addsep" class="btn btn-sm btn-warning" title="<?=gettext('Add separator')?>">
839
			<i class="fa fa-plus icon-embed-btn"></i>
840
			<?=gettext("Separator")?>
841
		</button>
842
	</nav>
843
</form>
844

    
845
<div class="infoblock">
846
	<div class="alert alert-info clearfix" role="alert"><div class="pull-left">
847
		<dl class="dl-horizontal responsive">
848
		<!-- Legend -->
849
			<dt><?=gettext('Legend')?></dt>				<dd></dd>
850
			<dt><i class="fa fa-check text-success"></i></dt>		<dd><?=gettext("Pass");?></dd>
851
			<dt><i class="fa fa-filter"></i></dt>	<dd><?=gettext("Match");?></dd>
852
			<dt><i class="fa fa-times text-danger"></i></dt>	<dd><?=gettext("Block");?></dd>
853
			<dt><i class="fa fa-hand-stop-o text-warning"></i></dt>		<dd><?=gettext("Reject");?></dd>
854
			<dt><i class="fa fa-tasks"></i></dt>	<dd> <?=gettext("Log");?></dd>
855
			<dt><i class="fa fa-cog"></i></dt>		<dd> <?=gettext("Advanced filter");?></dd>
856
			<dt><i class="fa fa-forward text-success"></i></dt><dd> <?=gettext("&quot;Quick&quot; rule. Applied immediately on match.")?></dd>
857
		</dl>
858

    
859
<?php
860
	if ("FloatingRules" != $if) {
861
		print(gettext("Rules are evaluated on a first-match basis (i.e. " .
862
			"the action of the first rule to match a packet will be executed). ") . '<br />' .
863
			gettext("This means that if block rules are used, it is important to pay attention " .
864
			"to the rule order. Everything that isn't explicitly passed is blocked " .
865
			"by default. "));
866
	} else {
867
		print(gettext("Floating rules are evaluated on a first-match basis (i.e. " .
868
			"the action of the first rule to match a packet will be executed) only " .
869
			"if the 'quick' option is checked on a rule. Otherwise they will only match if no " .
870
			"other rules match. Pay close attention to the rule order and options " .
871
			"chosen. If no rule here matches, the per-interface or default rules are used. "));
872
	}
873

    
874
	printf(gettext('%1$sClick the anchor icon %2$s to move checked rules before the clicked row. Hold down ' .
875
			'the shift key and click to move the rules after the clicked row.'), '<br /><br />', '<i class="fa fa-anchor"></i>')
876
?>
877
	</div>
878
	</div>
879
</div>
880

    
881
<script type="text/javascript">
882
//<![CDATA[
883

    
884
//Need to create some variables here so that jquery/pfSenseHelpers.js can read them
885
iface = "<?=strtolower($if)?>";
886
cncltxt = '<?=gettext("Cancel")?>';
887
svtxt = '<?=gettext("Save")?>';
888
svbtnplaceholder = '<?=gettext("Enter a description, Save, then drag to final location.")?>';
889
configsection = "filter";
890

    
891
events.push(function() {
892

    
893
	// "Move to here" (anchor) action
894
	$('[id^=Xmove_]').click(function (event) {
895

    
896
		// Prevent click from toggling row
897
		event.stopImmediatePropagation();
898

    
899
		// Save the target rule position
900
		var anchor_row = $(this).parents("tr:first");
901

    
902
		if (event.shiftKey) {
903
			$($('#ruletable > tbody  > tr').get().reverse()).each(function() {
904
				ruleid = this.id.slice(2);
905

    
906
				if (ruleid && !isNaN(ruleid)) {
907
					if ($('#frc' + ruleid).prop('checked')) {
908
						// Move the selected rows, un-select them and add highlight class
909
						$(this).insertAfter(anchor_row);
910
						fr_toggle(ruleid, "fr");
911
						$('#fr' + ruleid).addClass("highlight");
912
					}
913
				}
914
			});
915
		} else {
916
			$('#ruletable > tbody  > tr').each(function() {
917
				ruleid = this.id.slice(2);
918

    
919
				if (ruleid && !isNaN(ruleid)) {
920
					if ($('#frc' + ruleid).prop('checked')) {
921
						// Move the selected rows, un-select them and add highlight class
922
						$(this).insertBefore(anchor_row);
923
						fr_toggle(ruleid, "fr");
924
						$('#fr' + ruleid).addClass("highlight");
925
					}
926
				}
927
			});
928
		}
929

    
930
		// Temporarily set background color so user can more easily see the moved rules, then fade
931
		$('.highlight').effect("highlight", {color: "#739b4b;"}, 4000);
932
		$('#ruletable tr').removeClass("highlight");
933
		$('#order-store').removeAttr('disabled');
934
		reindex_rules($(anchor_row).parent('tbody'));
935
		dirty = true;
936
	}).mouseover(function(e) {
937
		var ruleselected = false;
938

    
939
		$(this).css("cursor", "default");
940

    
941
		// Are any rules currently selected?
942
		$('[id^=frc]').each(function () {
943
			if ($(this).prop("checked")) {
944
				ruleselected = true;
945
			}
946
		});
947

    
948
		// If so, change the icon to show the insetion point
949
		if (ruleselected) {
950
			if (e.shiftKey) {
951
				$(this).removeClass().addClass("fa fa-lg fa-arrow-down text-danger");
952
			} else {
953
				$(this).removeClass().addClass("fa fa-lg fa-arrow-up text-danger");
954
			}
955
		}
956
	}).mouseout(function(e) {
957
		$(this).removeClass().addClass("fa fa-anchor");
958
	});
959

    
960
	// Make rules sortable. Hiding the table before applying sortable, then showing it again is
961
	// a work-around for very slow sorting on FireFox
962
	$('table tbody.user-entries').hide();
963

    
964
	$('table tbody.user-entries').sortable({
965
		cursor: 'grabbing',
966
		scroll: true,
967
		overflow: 'scroll',
968
		scrollSensitivity: 100,
969
		update: function(event, ui) {
970
			$('#order-store').removeAttr('disabled');
971
			reindex_rules(ui.item.parent('tbody'));
972
			dirty = true;
973
		}
974
	});
975

    
976
	$('table tbody.user-entries').show();
977

    
978
	// Check all of the rule checkboxes so that their values are posted
979
	$('#order-store').click(function () {
980
		$('[id^=frc]').prop('checked', true);
981

    
982
		// Save the separator bar configuration
983
		save_separators();
984

    
985
		// Suppress the "Do you really want to leave the page" message
986
		saving = true;
987
	});
988

    
989
	// Provide a warning message if the user tries to change page before saving
990
	$(window).bind('beforeunload', function(){
991
		if ((!saving && dirty) || newSeperator) {
992
			return ("<?=gettext('One or more rules have been moved but have not yet been saved')?>");
993
		} else {
994
			return undefined;
995
		}
996
	});
997

    
998
	$(document).on('keyup keydown', function(e){
999
		if (e.shiftKey) {
1000
			$('[id^=Xmove_]').attr("title", "<?=$ShXmoveTitle?>");
1001
		} else {
1002
			$('[id^=Xmove_]').attr("title", "<?=$XmoveTitle?>");
1003
		}
1004
	});
1005
});
1006
//]]>
1007
</script>
1008

    
1009
<?php include("foot.inc");?>
(45-45/223)