Project

General

Profile

Download (35.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	firewall_nat_edit.php
5
	part of m0n0wall (http://m0n0.ch/wall)
6

    
7
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
8
	All rights reserved.
9

    
10
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
11

    
12
	Redistribution and use in source and binary forms, with or without
13
	modification, are permitted provided that the following conditions are met:
14

    
15
	1. Redistributions of source code must retain the above copyright notice,
16
	   this list of conditions and the following disclaimer.
17

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

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

    
37
##|+PRIV
38
##|*IDENT=page-firewall-nat-portforward-edit
39
##|*NAME=Firewall: NAT: Port Forward: Edit page
40
##|*DESCR=Allow access to the 'Firewall: NAT: Port Forward: Edit' page.
41
##|*MATCH=firewall_nat_edit.php*
42
##|-PRIV
43

    
44
require("guiconfig.inc");
45
require_once("itemid.inc");
46
require_once("filter.inc");
47
require("shaper.inc");
48

    
49
$referer = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/firewall_nat.php');
50

    
51
$specialsrcdst = explode(" ", "any (self) pptp pppoe l2tp openvpn");
52
$ifdisp = get_configured_interface_with_descr();
53

    
54
foreach ($ifdisp as $kif => $kdescr) {
55
	$specialsrcdst[] = "{$kif}";
56
	$specialsrcdst[] = "{$kif}ip";
57
}
58

    
59
if (!is_array($config['nat']['rule'])) {
60
	$config['nat']['rule'] = array();
61
}
62

    
63
$a_nat = &$config['nat']['rule'];
64

    
65
if (is_numericint($_GET['id']))
66
	$id = $_GET['id'];
67

    
68
if (isset($_POST['id']) && is_numericint($_POST['id']))
69
	$id = $_POST['id'];
70

    
71
if (is_numericint($_GET['after']) || $_GET['after'] == "-1")
72
	$after = $_GET['after'];
73

    
74
if (isset($_POST['after']) && (is_numericint($_POST['after']) || $_POST['after'] == "-1"))
75
	$after = $_POST['after'];
76

    
77
if (isset($_GET['dup']) && is_numericint($_GET['dup'])) {
78
		$id = $_GET['dup'];
79
		$after = $_GET['dup'];
80
}
81

    
82
if (isset($id) && $a_nat[$id]) {
83
	if ( isset($a_nat[$id]['created']) && is_array($a_nat[$id]['created']) )
84
		$pconfig['created'] = $a_nat[$id]['created'];
85

    
86
	if ( isset($a_nat[$id]['updated']) && is_array($a_nat[$id]['updated']) )
87
		$pconfig['updated'] = $a_nat[$id]['updated'];
88

    
89
	$pconfig['disabled'] = isset($a_nat[$id]['disabled']);
90
	$pconfig['nordr'] = isset($a_nat[$id]['nordr']);
91

    
92
	address_to_pconfig($a_nat[$id]['source'], $pconfig['src'],
93
		$pconfig['srcmask'], $pconfig['srcnot'],
94
		$pconfig['srcbeginport'], $pconfig['srcendport']);
95

    
96
	address_to_pconfig($a_nat[$id]['destination'], $pconfig['dst'],
97
		$pconfig['dstmask'], $pconfig['dstnot'],
98
		$pconfig['dstbeginport'], $pconfig['dstendport']);
99

    
100
	$pconfig['proto'] = $a_nat[$id]['protocol'];
101
	$pconfig['localip'] = $a_nat[$id]['target'];
102
	$pconfig['localbeginport'] = $a_nat[$id]['local-port'];
103
	$pconfig['descr'] = $a_nat[$id]['descr'];
104
	$pconfig['interface'] = $a_nat[$id]['interface'];
105
	$pconfig['associated-rule-id'] = $a_nat[$id]['associated-rule-id'];
106
	$pconfig['nosync'] = isset($a_nat[$id]['nosync']);
107
	$pconfig['natreflection'] = $a_nat[$id]['natreflection'];
108

    
109
	if (!$pconfig['interface'])
110
		$pconfig['interface'] = "wan";
111
	} else {
112
		$pconfig['interface'] = "wan";
113
		$pconfig['src'] = "any";
114
		$pconfig['srcbeginport'] = "any";
115
		$pconfig['srcendport'] = "any";
116
	}
117

    
118
if (isset($_GET['dup']) && is_numericint($_GET['dup']))
119
	unset($id);
120

    
121
/*	run through $_POST items encoding HTML entties so that the user
122
 *	cannot think he is slick and perform a XSS attack on the unwilling
123
 */
124
unset($input_errors);
125

    
126
foreach ($_POST as $key => $value) {
127
	$temp = $value;
128
	$newpost = htmlentities($temp);
129
	if($newpost != $temp)
130
		$input_errors[] = sprintf(gettext("Invalid characters detected %s. Please remove invalid characters and save again."), $temp);
131
}
132

    
133
if ($_POST) {
134
	if(strtoupper($_POST['proto']) == "TCP" || strtoupper($_POST['proto']) == "UDP" || strtoupper($_POST['proto']) == "TCP/UDP") {
135
		if ($_POST['srcbeginport_cust'] && !$_POST['srcbeginport'])
136
			$_POST['srcbeginport'] = trim($_POST['srcbeginport_cust']);
137

    
138
		if ($_POST['srcendport_cust'] && !$_POST['srcendport'])
139
			$_POST['srcendport'] = trim($_POST['srcendport_cust']);
140

    
141
		if ($_POST['srcbeginport'] == "any") {
142
			$_POST['srcbeginport'] = 0;
143
			$_POST['srcendport'] = 0;
144
		} else {
145
			if (!$_POST['srcendport'])
146
				$_POST['srcendport'] = $_POST['srcbeginport'];
147
		}
148

    
149
		if ($_POST['srcendport'] == "any")
150
			$_POST['srcendport'] = $_POST['srcbeginport'];
151

    
152
		if ($_POST['dstbeginport_cust'] && !$_POST['dstbeginport'])
153
			$_POST['dstbeginport'] = trim($_POST['dstbeginport_cust']);
154

    
155
		if ($_POST['dstendport_cust'] && !$_POST['dstendport'])
156
			$_POST['dstendport'] = trim($_POST['dstendport_cust']);
157

    
158
		if ($_POST['dstbeginport'] == "any") {
159
			$_POST['dstbeginport'] = 0;
160
			$_POST['dstendport'] = 0;
161
		} else {
162
			if (!$_POST['dstendport'])
163
				$_POST['dstendport'] = $_POST['dstbeginport'];
164
		}
165

    
166
		if ($_POST['dstendport'] == "any")
167
			$_POST['dstendport'] = $_POST['dstbeginport'];
168

    
169
		if ($_POST['localbeginport_cust'] && !$_POST['localbeginport'])
170
			$_POST['localbeginport'] = trim($_POST['localbeginport_cust']);
171

    
172
		/* Make beginning port end port if not defined and endport is */
173
		if (!$_POST['srcbeginport'] && $_POST['srcendport'])
174
			$_POST['srcbeginport'] = $_POST['srcendport'];
175

    
176
		if (!$_POST['dstbeginport'] && $_POST['dstendport'])
177
			$_POST['dstbeginport'] = $_POST['dstendport'];
178
	} else {
179
		$_POST['srcbeginport'] = 0;
180
		$_POST['srcendport'] = 0;
181
		$_POST['dstbeginport'] = 0;
182
		$_POST['dstendport'] = 0;
183
	}
184

    
185
	if (is_specialnet($_POST['srctype'])) {
186
		$_POST['src'] = $_POST['srctype'];
187
		$_POST['srcmask'] = 0;
188
	} else if ($_POST['srctype'] == "single") {
189
		$_POST['srcmask'] = 32;
190
	}
191

    
192
	if (is_specialnet($_POST['dsttype'])) {
193
		$_POST['dst'] = $_POST['dsttype'];
194
		$_POST['dstmask'] = 0;
195
	} else if ($_POST['dsttype'] == "single") {
196
		$_POST['dstmask'] = 32;
197
	} else if (is_ipaddr($_POST['dsttype'])) {
198
		$_POST['dst'] = $_POST['dsttype'];
199
		$_POST['dstmask'] = 32;
200
		$_POST['dsttype'] = "single";
201
	}
202

    
203
	$pconfig = $_POST;
204

    
205
	/* input validation */
206
	if(strtoupper($_POST['proto']) == "TCP" or strtoupper($_POST['proto']) == "UDP" or strtoupper($_POST['proto']) == "TCP/UDP") {
207
		$reqdfields = explode(" ", "interface proto dstbeginport dstendport");
208
		$reqdfieldsn = array(gettext("Interface"),gettext("Protocol"),gettext("Destination port from"),gettext("Destination port to"));
209
	} else {
210
		$reqdfields = explode(" ", "interface proto");
211
		$reqdfieldsn = array(gettext("Interface"),gettext("Protocol"));
212
	}
213

    
214
	if ($_POST['srctype'] == "single" || $_POST['srctype'] == "network") {
215
		$reqdfields[] = "src";
216
		$reqdfieldsn[] = gettext("Source address");
217
	}
218

    
219
	if ($_POST['dsttype'] == "single" || $_POST['dsttype'] == "network") {
220
		$reqdfields[] = "dst";
221
		$reqdfieldsn[] = gettext("Destination address");
222
	}
223

    
224
	if (!isset($_POST['nordr'])) {
225
		$reqdfields[] = "localip";
226
		$reqdfieldsn[] = gettext("Redirect target IP");
227
	}
228

    
229
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
230

    
231
	if (!$_POST['srcbeginport']) {
232
		$_POST['srcbeginport'] = 0;
233
		$_POST['srcendport'] = 0;
234
	}
235

    
236
	if (!$_POST['dstbeginport']) {
237
		$_POST['dstbeginport'] = 0;
238
		$_POST['dstendport'] = 0;
239
	}
240

    
241
	if ($_POST['src'])
242
		$_POST['src'] = trim($_POST['src']);
243
	if ($_POST['dst'])
244
		$_POST['dst'] = trim($_POST['dst']);
245
	if ($_POST['localip'])
246
		$_POST['localip'] = trim($_POST['localip']);
247

    
248
	if (!isset($_POST['nordr']) && ($_POST['localip'] && !is_ipaddroralias($_POST['localip']))) {
249
		$input_errors[] = sprintf(gettext("\"%s\" is not a valid redirect target IP address or host alias."), $_POST['localip']);
250
	}
251

    
252
	if ($_POST['srcbeginport'] && !is_portoralias($_POST['srcbeginport']))
253
		$input_errors[] = sprintf(gettext("%s is not a valid start source port. It must be a port alias or integer between 1 and 65535."), $_POST['srcbeginport']);
254
	if ($_POST['srcendport'] && !is_portoralias($_POST['srcendport']))
255
		$input_errors[] = sprintf(gettext("%s is not a valid end source port. It must be a port alias or integer between 1 and 65535."), $_POST['srcendport']);
256
	if ($_POST['dstbeginport'] && !is_portoralias($_POST['dstbeginport']))
257
		$input_errors[] = sprintf(gettext("%s is not a valid start destination port. It must be a port alias or integer between 1 and 65535."), $_POST['dstbeginport']);
258
	if ($_POST['dstendport'] && !is_portoralias($_POST['dstendport']))
259
		$input_errors[] = sprintf(gettext("%s is not a valid end destination port. It must be a port alias or integer between 1 and 65535."), $_POST['dstendport']);
260

    
261
	if ((strtoupper($_POST['proto']) == "TCP" || strtoupper($_POST['proto']) == "UDP" || strtoupper($_POST['proto']) == "TCP/UDP") && (!isset($_POST['nordr']) && !is_portoralias($_POST['localbeginport']))) {
262
		$input_errors[] = sprintf(gettext("A valid redirect target port must be specified. It must be a port alias or integer between 1 and 65535."), $_POST['localbeginport']);
263
	}
264

    
265
	/* if user enters an alias and selects "network" then disallow. */
266
	if( ($_POST['srctype'] == "network" && is_alias($_POST['src']) )
267
	 || ($_POST['dsttype'] == "network" && is_alias($_POST['dst']) ) ) {
268
		$input_errors[] = gettext("You must specify single host or alias for alias entries.");
269
	}
270

    
271
	if (!is_specialnet($_POST['srctype'])) {
272
		if (($_POST['src'] && !is_ipaddroralias($_POST['src']))) {
273
			$input_errors[] = sprintf(gettext("%s is not a valid source IP address or alias."), $_POST['src']);
274
		}
275
		if (($_POST['srcmask'] && !is_numericint($_POST['srcmask']))) {
276
			$input_errors[] = gettext("A valid source bit count must be specified.");
277
		}
278
	}
279

    
280
	if (!is_specialnet($_POST['dsttype'])) {
281
		if (($_POST['dst'] && !is_ipaddroralias($_POST['dst']))) {
282
			$input_errors[] = sprintf(gettext("%s is not a valid destination IP address or alias."), $_POST['dst']);
283
		}
284
		if (($_POST['dstmask'] && !is_numericint($_POST['dstmask']))) {
285
			$input_errors[] = gettext("A valid destination bit count must be specified.");
286
		}
287
	}
288

    
289
	if ($_POST['srcbeginport'] > $_POST['srcendport']) {
290
		/* swap */
291
		$tmp = $_POST['srcendport'];
292
		$_POST['srcendport'] = $_POST['srcbeginport'];
293
		$_POST['srcbeginport'] = $tmp;
294
	}
295

    
296
	if ($_POST['dstbeginport'] > $_POST['dstendport']) {
297
		/* swap */
298
		$tmp = $_POST['dstendport'];
299
		$_POST['dstendport'] = $_POST['dstbeginport'];
300
		$_POST['dstbeginport'] = $tmp;
301
	}
302

    
303
	if (!$input_errors) {
304
		if (!isset($_POST['nordr']) && ($_POST['dstendport'] - $_POST['dstbeginport'] + $_POST['localbeginport']) > 65535)
305
			$input_errors[] = gettext("The target port range must be an integer between 1 and 65535.");
306
	}
307

    
308
	/* check for overlaps */
309
	foreach ($a_nat as $natent) {
310
		if (isset($id) && ($a_nat[$id]) && ($a_nat[$id] === $natent))
311
			continue;
312
		if ($natent['interface'] != $_POST['interface'])
313
			continue;
314
		if ($natent['destination']['address'] != $_POST['dst'])
315
			continue;
316
		if (($natent['proto'] != $_POST['proto']) && ($natent['proto'] != "tcp/udp") && ($_POST['proto'] != "tcp/udp"))
317
			continue;
318

    
319
		list($begp,$endp) = explode("-", $natent['destination']['port']);
320
		if (!$endp)
321
			$endp = $begp;
322

    
323
		if (!(	 (($_POST['beginport'] < $begp) && ($_POST['endport'] < $begp))
324
			  || (($_POST['beginport'] > $endp) && ($_POST['endport'] > $endp)))) {
325

    
326
			$input_errors[] = gettext("The destination port range overlaps with an existing entry.");
327
			break;
328
		}
329
	}
330

    
331
	if (!$input_errors) {
332
		$natent = array();
333

    
334
		$natent['disabled'] = isset($_POST['disabled']) ? true:false;
335
		$natent['nordr'] = isset($_POST['nordr']) ? true:false;
336

    
337
		if ($natent['nordr']) {
338
			$_POST['associated-rule-id'] = '';
339
			$_POST['filter-rule-association'] = '';
340
		}
341

    
342
		pconfig_to_address($natent['source'], $_POST['src'],
343
			$_POST['srcmask'], $_POST['srcnot'],
344
			$_POST['srcbeginport'], $_POST['srcendport']);
345

    
346
		pconfig_to_address($natent['destination'], $_POST['dst'],
347
			$_POST['dstmask'], $_POST['dstnot'],
348
			$_POST['dstbeginport'], $_POST['dstendport']);
349

    
350
		$natent['protocol'] = $_POST['proto'];
351

    
352
		if (!$natent['nordr']) {
353
			$natent['target'] = $_POST['localip'];
354
			$natent['local-port'] = $_POST['localbeginport'];
355
		}
356

    
357
		$natent['interface'] = $_POST['interface'];
358
		$natent['descr'] = $_POST['descr'];
359
		$natent['associated-rule-id'] = $_POST['associated-rule-id'];
360

    
361
		if($_POST['filter-rule-association'] == "pass")
362
			$natent['associated-rule-id'] = "pass";
363

    
364
		if($_POST['nosync'] == "yes")
365
			$natent['nosync'] = true;
366
		else
367
			unset($natent['nosync']);
368

    
369
		if ($_POST['natreflection'] == "enable" || $_POST['natreflection'] == "purenat" || $_POST['natreflection'] == "disable")
370
			$natent['natreflection'] = $_POST['natreflection'];
371
		else
372
			unset($natent['natreflection']);
373

    
374
		// If we used to have an associated filter rule, but no-longer should have one
375
		if (!empty($a_nat[$id]) && ( empty($natent['associated-rule-id']) || $natent['associated-rule-id'] != $a_nat[$id]['associated-rule-id'] ) ) {
376
			// Delete the previous rule
377
			delete_id($a_nat[$id]['associated-rule-id'], $config['filter']['rule']);
378
			mark_subsystem_dirty('filter');
379
		}
380

    
381
		$need_filter_rule = false;
382
		// Updating a rule with a filter rule associated
383
		if (!empty($natent['associated-rule-id']))
384
			$need_filter_rule = true;
385

    
386
		// Create a rule or if we want to create a new one
387
		if( $natent['associated-rule-id']=='new' ) {
388
			$need_filter_rule = true;
389
			unset( $natent['associated-rule-id'] );
390
			$_POST['filter-rule-association']='add-associated';
391
		}
392
		// If creating a new rule, where we want to add the filter rule, associated or not
393
		else if( isset($_POST['filter-rule-association']) &&
394
			($_POST['filter-rule-association']=='add-associated' ||
395
			$_POST['filter-rule-association']=='add-unassociated') )
396
			$need_filter_rule = true;
397

    
398
		if ($need_filter_rule == true) {
399
			/* auto-generate a matching firewall rule */
400
			$filterent = array();
401
			unset($filterentid);
402
			// If a rule already exists, load it
403
			if (!empty($natent['associated-rule-id'])) {
404
				$filterentid = get_id($natent['associated-rule-id'], $config['filter']['rule']);
405
				if ($filterentid === false)
406
					$filterent['associated-rule-id'] = $natent['associated-rule-id'];
407
				else
408
					$filterent =& $config['filter']['rule'][$filterentid];
409
			}
410

    
411
			pconfig_to_address($filterent['source'], $_POST['src'],
412
				$_POST['srcmask'], $_POST['srcnot'],
413
				$_POST['srcbeginport'], $_POST['srcendport']);
414

    
415
			// Update interface, protocol and destination
416
			$filterent['interface'] = $_POST['interface'];
417
			$filterent['protocol'] = $_POST['proto'];
418
			$filterent['destination']['address'] = $_POST['localip'];
419

    
420
			$dstpfrom = $_POST['localbeginport'];
421
			$dstpto = $dstpfrom + $_POST['dstendport'] - $_POST['dstbeginport'];
422

    
423
			if ($dstpfrom == $dstpto)
424
				$filterent['destination']['port'] = $dstpfrom;
425
			else
426
				$filterent['destination']['port'] = $dstpfrom . "-" . $dstpto;
427

    
428
			/*
429
			 * Our firewall filter description may be no longer than
430
			 * 63 characters, so don't let it be.
431
			 */
432
			$filterent['descr'] = substr("NAT " . $_POST['descr'], 0, 62);
433

    
434
			// If this is a new rule, create an ID and add the rule
435
			if( $_POST['filter-rule-association']=='add-associated' ) {
436
				$filterent['associated-rule-id'] = $natent['associated-rule-id'] = get_unique_id();
437
				$filterent['created'] = make_config_revision_entry(null, gettext("NAT Port Forward"));
438
				$config['filter']['rule'][] = $filterent;
439
			}
440

    
441
			mark_subsystem_dirty('filter');
442
		}
443

    
444
		if ( isset($a_nat[$id]['created']) && is_array($a_nat[$id]['created']) )
445
			$natent['created'] = $a_nat[$id]['created'];
446

    
447
		$natent['updated'] = make_config_revision_entry();
448

    
449
		// Allow extending of the firewall edit page and include custom input validation
450
		pfSense_handle_custom_code("/usr/local/pkg/firewall_nat/pre_write_config");
451

    
452
		// Update the NAT entry now
453
		if (isset($id) && $a_nat[$id])
454
			$a_nat[$id] = $natent;
455
		else {
456
			$natent['created'] = make_config_revision_entry();
457
			if (is_numeric($after))
458
				array_splice($a_nat, $after+1, 0, array($natent));
459
			else
460
				$a_nat[] = $natent;
461
		}
462

    
463
		if (write_config())
464
			mark_subsystem_dirty('natconf');
465

    
466
		header("Location: firewall_nat.php");
467
		exit;
468
	}
469
}
470

    
471
function build_srctype_list() {
472
	global $pconfig, $ifdisp;
473

    
474
	$list = array('any' => 'Any', 'single' => 'Single host or alias', 'network' => 'Network');
475

    
476
	$sel = is_specialnet($pconfig['src']);
477

    
478
	if(have_ruleint_access("pptp"))
479
		$list['pptp'] = 'PPTP clients';
480

    
481
	if(have_ruleint_access("pppoe"))
482
		$list['pppoe'] = 'PPPoE clients';
483

    
484
	if(have_ruleint_access("l2tp"))
485
		$list['l2tp'] = 'L2TP clients';
486

    
487
	foreach ($ifdisp as $ifent => $ifdesc) {
488
		if(have_ruleint_access($ifent)) {
489
			$list[$ifent] = $ifdesc . ' net';
490
			$list[$ifent . 'ip'] = $ifdesc . ' address';
491
		}
492
	}
493

    
494
	return($list);
495
}
496

    
497
function build_dsttype_list() {
498
	global $pconfig, $config, $ifdisp;
499

    
500
	$sel = is_specialnet($pconfig['dst']);
501
	$list = array('any' => 'Any', 'single' => 'Single host or alias', 'network' => 'Network', '(self)' => 'This Firewall (self)');
502

    
503
	if(have_ruleint_access("pptp"))
504
		$list['pptp'] = 'PPTP clients';
505

    
506
	if(have_ruleint_access("pppoe"))
507
		$list['pppoe'] = 'PPPoE clients';
508

    
509
	if(have_ruleint_access("l2tp"))
510
		$list['l2tp'] = 'L2TP clients';
511

    
512
	foreach ($ifdisp as $if => $ifdesc) {
513
		if(have_ruleint_access($if)) {
514
			$list[$if] = $ifdesc;
515
			$list[$if . 'ip'] = $ifdesc . ' address';
516
		}
517
	}
518

    
519
	if (is_array($config['virtualip']['vip'])) {
520
		foreach ($config['virtualip']['vip'] as $sn) {
521
			if (isset($sn['noexpand']))
522
				continue;
523

    
524
			if ($sn['mode'] == "proxyarp" && $sn['type'] == "network") {
525
				$start = ip2long32(gen_subnet($sn['subnet'], $sn['subnet_bits']));
526
				$end = ip2long32(gen_subnet_max($sn['subnet'], $sn['subnet_bits']));
527
				$len = $end - $start;
528

    
529
				for ($i = 0; $i <= $len; $i++) {
530
					$snip = long2ip32($start+$i);
531

    
532
					$list[$snip] = $snip . ' (' . $sn['descr'] . ')';
533
				}
534

    
535
				$list[$sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')';
536
			}
537
		}
538
	}
539

    
540
	return($list);
541
}
542

    
543
function dsttype_selected() {
544
	global $pconfig;
545

    
546
	$sel = is_specialnet($pconfig['dst']);
547

    
548
	if(!$sel) {
549
		if($pconfig['dstmask'] == 32)
550
			return('single');
551

    
552
		return('network');
553
	}
554

    
555
	return($pconfig['dst']);
556
}
557

    
558
function srctype_selected() {
559
	global $pconfig;
560

    
561
	$sel = is_specialnet($pconfig['src']);
562

    
563
	if(!$sel) {
564
		if($pconfig['srcmask'] == 32)
565
			return('single');
566

    
567
		return('network');
568
	}
569

    
570
	return($pconfig['src']);
571
}
572

    
573
$closehead = false;
574
$pgtitle = array(gettext("Firewall"),gettext("NAT"),gettext("Port Forward"),gettext("Edit"));
575
include("head.inc");
576

    
577
if ($input_errors)
578
	print_input_errors($input_errors);
579

    
580
require('classes/Form.class.php');
581

    
582
$form = new Form(new Form_Button(
583
	'Submit',
584
	gettext("Save")
585
));
586

    
587
$section = new Form_Section('Edit Redirect entry');
588

    
589
$section->addInput(new Form_Checkbox(
590
	'disabled',
591
	'Disabled',
592
	'Disable this rule',
593
	$pconfig['disabled']
594
));
595

    
596
$section->addInput(new Form_Checkbox(
597
	'nordr',
598
	'No RDR (NOT)',
599
	'Disable redirection for traffic matching this rule',
600
	$pconfig['nordr']
601
))->setHelp('This option is rarely needed, don\'t use this unless you know what you\'re doing.');
602

    
603
$iflist = get_configured_interface_with_descr(false, true);
604

    
605
foreach ($iflist as $if => $ifdesc)
606
	if(have_ruleint_access($if))
607
		$interfaces[$if] = $ifdesc;
608

    
609
if ($config['l2tp']['mode'] == "server")
610
	if(have_ruleint_access("l2tp"))
611
		$interfaces['l2tp'] = "L2TP VPN";
612

    
613
if ($config['pptpd']['mode'] == "server")
614
	if(have_ruleint_access("pptp"))
615
		$interfaces['pptp'] = "PPTP VPN";
616

    
617
if (is_pppoe_server_enabled() && have_ruleint_access("pppoe"))
618
	$interfaces['pppoe'] = "PPPoE Server";
619

    
620
/* add ipsec interfaces */
621
if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable']))
622
	if(have_ruleint_access("enc0"))
623
		$interfaces["enc0"] = "IPsec";
624

    
625
/* add openvpn/tun interfaces */
626
if	($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"])
627
	$interfaces["openvpn"] = "OpenVPN";
628

    
629
$section->addInput(new Form_Select(
630
	'interface',
631
	'Interface',
632
	$pconfig['interface'],
633
	$interfaces
634
))->setHelp('Choose which interface this rule applies to. In most cases "WAN" is specified.');
635

    
636
$protocols = "TCP UDP TCP/UDP ICMP ESP AH GRE IPV6 IGMP PIM OSPF";
637

    
638
$section->addInput(new Form_Select(
639
	'proto',
640
	'Protocol',
641
	$pconfig['proto'],
642
	array_combine(explode(" ", strtolower($protocols)), explode(" ", $protocols))
643
))->setHelp('Choose which protocol this rule should match. In most cases "TCP" is specified.');
644

    
645
$group = new Form_Group('Source');
646

    
647
$group->add(new Form_Select(
648
	'srctype',
649
	null,
650
	srctype_selected(),
651
	build_srctype_list()
652
))->setHelp('Type');
653

    
654
$group->add(new Form_IpAddress(
655
	'src',
656
	null,
657
	is_specialnet($pconfig['src']) ? '': $pconfig['src']
658
))->addMask('srcmask', $pconfig['srcmask'], 31)->setHelp('Address/mask');
659

    
660
$section->add($group);
661

    
662
$portlist = array("" => 'Other', 'any' => 'Any');
663

    
664
foreach ($wkports as $wkport => $wkportdesc)
665
	$portlist[$wkport] = $wkportdesc;
666

    
667
$group = new Form_Group('Source port range');
668
$group->addClass('srcportrange');
669

    
670
$group->add(new Form_Select(
671
	'srcbeginport',
672
	null,
673
	$pconfig['srcbeginport'],
674
	$portlist
675
))->setHelp('From port');
676

    
677
$group->add(new Form_Input(
678
	'srcbeginport_cust',
679
	null,
680
	'number',
681
	$pconfig['srcbeginport_cust'],
682
	['min' => '1', 'max' => '65536']
683
))->setHelp('Custom');
684

    
685
$group->add(new Form_Select(
686
	'srcendport',
687
	null,
688
	$pconfig['srcendport'],
689
	$portlist
690
))->setHelp('To port');
691

    
692
$group->add(new Form_Input(
693
	'srcendport_cust',
694
	null,
695
	'number',
696
	$pconfig['srcendport_cust'],
697
	['min' => '1', 'max' => '65536']
698
))->setHelp('Custom');
699

    
700
$group->setHelp('Specify the source port or port range for this rule. This is usually random and almost never ' .
701
				'equal to the destination port range (and should usually be \'any\'). You can leave the \'to\' field ' .
702
				'empty if you only want to filter a single port.');
703

    
704
$section->add($group);
705

    
706
$group = new Form_Group('Destination');
707

    
708
$group->add(new Form_Select(
709
	'dsttype',
710
	null,
711
	dsttype_selected(),
712
	build_dsttype_list()
713
))->setHelp('Type');
714

    
715
$group->add(new Form_IpAddress(
716
	'dst',
717
	null,
718
	is_specialnet($pconfig['dst']) ? '': $pconfig['dst']
719
))->addMask('dstmask', $pconfig['dstmask'], 31)->setHelp('Address/mask');
720

    
721
$section->add($group);
722

    
723
$group = new Form_Group('Destination port range');
724
$group->addClass('dstportrange');
725

    
726
$group->add(new Form_Select(
727
	'dstbeginport',
728
	null,
729
	$pconfig['dstbeginport'],
730
	$portlist
731
))->setHelp('From port');
732

    
733
$group->add(new Form_Input(
734
	'dstbeginport_cust',
735
	null,
736
	'number',
737
	$pconfig['dstbeginport_cust'],
738
	['min' => '1', 'max' => '65536']
739
))->setHelp('Custom');
740

    
741
$group->add(new Form_Select(
742
	'dstendport',
743
	null,
744
	$pconfig['dstendport'],
745
	$portlist
746
))->setHelp('To port');
747

    
748
$group->add(new Form_Input(
749
	'dstendport_cust',
750
	null,
751
	'number',
752
	$pconfig['dstendport_cust'],
753
	['min' => '1', 'max' => '65536']
754
))->setHelp('Custom');
755

    
756
$group->setHelp('Specify the port or port range for the destination of the packet for this mapping. ' .
757
				'You can leave the \'to\' field empty if you only want to map a single port ');
758

    
759
$section->add($group);
760

    
761
$section->addInput(new Form_Checkbox(
762
	'dstnot',
763
	null,
764
	'Not (Invert the sense of the match)',
765
	$pconfig['dstnot'],
766
	'yes'
767
));
768

    
769
$section->addInput(new Form_IpAddress(
770
	'localip',
771
	'Redirect target IP',
772
	$pconfig['localip']
773
))->setHelp('Enter the internal IP address of the server on which you want to map the ports.' . '<br />' .
774
			'e.g.: 192.168.1.12');
775

    
776
$group = new Form_Group('Redirect target port');
777
$group->addClass('lclportrange');
778

    
779
$group->add(new Form_Select(
780
	'localbeginport',
781
	null,
782
	$pconfig['localbeginport'],
783
	array('' => 'Other') + $wkports
784
))->setHelp('Port');
785

    
786
$group->setHelp('Specify the port on the machine with the IP address entered above. In case of a port range, specify the ' .
787
				'beginning port of the range (the end port will be calculated automatically).' . '<br />' .
788
				'this is usually identical to "From port" above');
789

    
790
$group->add(new Form_Input(
791
	'localbeginport_cust',
792
	null,
793
	'number',
794
	$pconfig['localbeginport_cust'],
795
	['min' => '1', 'max' => '65536']
796
))->setHelp('Custom');
797

    
798
$section->add($group);
799

    
800
$section->addInput(new Form_Input(
801
	'descr',
802
	'Description',
803
	'text',
804
	$pconfig['descr']
805
))->setHelp('You may enter a description here for your reference (not parsed).');
806

    
807

    
808
$section->addInput(new Form_Checkbox(
809
	'nosync',
810
	'No XMLRPC Sync',
811
	null,
812
	$pconfig['nosync']
813
))->setHelp('This prevents the rule on Master from automatically syncing to other CARP members. ' .
814
			'This does NOT prevent the rule from being overwritten on Slave.');
815

    
816
$section->addInput(new Form_Select(
817
	'natreflection',
818
	'NAT reflection',
819
	$pconfig['natreflection'],
820
	array(
821
		'default' => 'Use system default',
822
		'enable'  => 'Enable (NAT + Proxy)',
823
		'purenat' => 'Enable (Pure NAT)',
824
		'disable' => 'Disable'
825
	)
826
));
827

    
828
if (isset($id) && $a_nat[$id] && (!isset($_GET['dup']) || !is_numericint($_GET['dup']))) {
829
	$hlpstr = '';
830
	$rulelist = array('' => 'None', 'pass' => 'Pass');
831

    
832
	if (is_array($config['filter']['rule'])) {
833
		filter_rules_sort();
834
		foreach ($config['filter']['rule'] as $filter_id => $filter_rule) {
835
			if (isset($filter_rule['associated-rule-id'])) {
836
				$rulelist[$filter_rule['associated-rule-id']] = 'Rule ' . $filter_rule['descr'];
837

    
838
				if ($filter_rule['associated-rule-id']==$pconfig['associated-rule-id']) {
839
					$hlpstr = '<a href="firewall_rules_edit.php?id=' . $filter_id . '">' . gettext("View the filter rule") . '</a><br />';
840
				}
841
			}
842
		}
843
	}
844

    
845
	if (isset($pconfig['associated-rule-id']))
846
	$rulelist['new'] = 'Create new associated filter rule';
847

    
848
	$section->addInput(new Form_Select(
849
		'associated-rule-id',
850
		'Filter rule association',
851
		'add-associated',
852
		$rulelist
853
	))->setHelp($hlpstr);
854
} else {
855
	$section->addInput(new Form_Select(
856
		'associated-rule-id',
857
		'Filter rule association',
858
		'add-associated',
859
		array(
860
			'' => 'None',
861
			'add-associated'  => 'Add associated filter rule',
862
			'add-unassociated' => 'Add unassociated filter rule',
863
			'pass' => 'Pass'
864
		)
865
	))->setHelp('The "pass" selection does not work properly with Multi-WAN. It will only work on an interface containing the default gateway.');
866
}
867

    
868
$form->add($section);
869

    
870
$has_created_time = (isset($a_nat[$id]['created']) && is_array($a_nat[$id]['created']));
871
$has_updated_time = (isset($a_nat[$id]['updated']) && is_array($a_nat[$id]['updated']));
872

    
873
if ($has_created_time || $has_updated_time) {
874
	$section = new Form_Section('Rule Information');
875

    
876
	if($has_created_time) {
877
		$section->addInput(new Form_StaticText(
878
			'Created',
879
			date(gettext("n/j/y H:i:s"), $a_nat[$id]['created']['time']) . gettext("by") . $a_nat[$id]['created']['username']
880
		));
881
	}
882

    
883
	if($has_updated_time) {
884
		$section->addInput(new Form_StaticText(
885
			'Updated',
886
			date(gettext("n/j/y H:i:s"), $a_nat[$id]['updated']['time']) . gettext("by") . $a_nat[$id]['updated']['username']
887
		));
888
	}
889

    
890
	$form->add($section);
891
}
892

    
893
if (isset($id) && $a_nat[$id]) {
894
	$form->addGlobal(new Form_Input(
895
		'id',
896
		null,
897
		'hidden',
898
		$id
899
	));
900
}
901

    
902
$form->addGlobal(new Form_Input(
903
	'after',
904
	null,
905
	'hidden',
906
	$after
907
));
908

    
909
print($form);
910
?>
911

    
912
<script type="text/javascript">
913
//<![CDATA[
914
events.push(function(){
915
	var portsenabled = 1;
916
	var dstenabled = 1;
917
	var showsource = 0;
918
	var iface_old = '';
919

    
920
	// ---------- "Library" functions ---------------------------------------------------------------------------------
921
	// Hides the <div> in which the specified input element lives so that the input, its label and help text are hidden
922
	function hideInput(id, hide) {
923
		if(hide)
924
			$('#' + id).parent().parent('div').addClass('hidden');
925
		else
926
			$('#' + id).parent().parent('div').removeClass('hidden');
927
	}
928

    
929
	// Disables the specified input element
930
	function disableInput(id, disable) {
931
		$('#' + id).prop("disabled", disable);
932
	}
933

    
934
	// Hides all elements of the specified class. This will usually be a section
935
	function hideClass(s_class, hide) {
936
		if(hide)
937
			$('.' + s_class).hide();
938
		else
939
			$('.' + s_class).show();
940
	}
941

    
942
	// ---------- jQuery functions, lovingly converted from the original javascript------------------------------------------
943
	function ext_change() {
944

    
945
		if (($('#srcbeginport').find(":selected").index() == 0) && portsenabled) {
946
			disableInput('srcbeginport_cust', false);
947
		} else {
948
			$('#srcbeginport_cust').val('');
949
			disableInput('srcbeginport_cust', true);
950
		}
951

    
952
		if (($('#srcendport').find(":selected").index() == 0) && portsenabled) {
953
			disableInput('srcendport_cust', false);
954
		} else {
955
			$('#srcendport_cust').val('');
956
			disableInput('srcendport_cust', true);
957
		}
958

    
959
		if (($('#dstbeginport').find(":selected").index() == 0) && portsenabled && dstenabled) {
960
			disableInput('dstbeginport_cust', false);
961
		} else {
962
			$('#dstbeginport_cust').val('');
963
			disableInput('dstbeginport_cust', true);
964
		}
965

    
966
		if (($('#dstendport').find(":selected").index() == 0) && portsenabled && dstenabled) {
967
			disableInput('dstendport_cust', false);
968
		} else {
969
			$('#dstendport_cust').val('');
970
			disableInput('dstendport_cust', true);
971
		}
972

    
973
		if (($('#localbeginport').find(":selected").index() == 0) && portsenabled) {
974
			disableInput('localbeginport_cust', false);
975
		} else {
976
			$('#localbeginport_cust').val('');
977
			disableInput('localbeginport_cust', true);
978
		}
979

    
980
		if (!portsenabled) {
981
			disableInput('srcbeginport', true);
982
			disableInput('srcendport', true);
983
			disableInput('dstbeginport', true);
984
			disableInput('dstendport', true);
985
			disableInput('localbeginport_cust', true);
986
		} else {
987
			disableInput('srcbeginport', false);
988
			disableInput('srcendport', false);
989
			disableInput('localbeginport_cust', false);
990
			if( dstenabled ) {
991
				disableInput('dstbeginport', false);
992
				disableInput('dstendport', false);
993
			}
994
		}
995
	}
996

    
997
	function nordr_change() {
998
		if( $('#nordr').prop('checked') ) {
999
			hideInput('localip', true);
1000
			hideClass('lclportrange', true);
1001
			hideInput('associated-rule-id', true);
1002
		} else {
1003
			hideInput('localip', false);
1004
			hideClass('lclportrange', !portsenabled);
1005
			hideInput('associated-rule-id', false);
1006
		}
1007
	}
1008

    
1009
	var customarray	 = <?= json_encode(get_alias_list(array("port", "url_ports", "urltable_ports"))) ?>;
1010

    
1011
	function check_for_aliases() {
1012
		//	if External port range is an alias, then disallow
1013
		//	entry of Local port
1014
		//
1015
		for(i=0; i<customarray.length; i++) {
1016
			if($('#dstbeginport_cust').val() == customarray[i]) {
1017
				$('#dstendport_cust').val(customarray[i]);
1018
				$('#localbeginport_cust').val(customarray[i]);
1019
				disableInput('dstendport_cust', true);
1020
				disableInput('localbeginport', true);
1021
				disableInput('localbeginport_cust', true);
1022
				disableInput('dstendport_cust', false);
1023
				disableInput('localbeginport', false);
1024
				disableInput('localbeginport_cust', false);
1025
			}
1026
			if($('#dstbeginport').val() == customarray[i]) {
1027
				$('#dstendport_cust').val(customarray[i]);
1028
				$('#localbeginport_cust').val(customarray[i]);
1029
				disableInput('dstendport_cust', true);
1030
				disableInput('localbeginport', true);
1031
				disableInput('localbeginport_cust', true);
1032
				disableInput('dstendport_cust', false);
1033
				disableInput('localbeginport', false);
1034
				disableInput('localbeginport_cust', false);
1035
			}
1036
			if($('#dstendport_cust').val() == customarray[i]) {
1037
				$('#dstendport_cust').val(customarray[i]);
1038
				$('#localbeginport_cust').val(customarray[i]);
1039
				disableInput('dstendport_cust', true);
1040
				disableInput('localbeginport', true);
1041
				disableInput('localbeginport_cust', true);
1042
				disableInput('dstendport_cust', false);
1043
				disableInput('localbeginport', false);
1044
				disableInput('localbeginport_cust', false);
1045
			}
1046
			if($('#dstendport').val() == customarray[i]) {
1047
				$('#dstendport_cust').val(customarray[i]);
1048
				$('#localbeginport_cust').val(customarray[i]);
1049
				disableInput('dstendport_cust', true);
1050
				disableInput('localbeginport', true);
1051
				disableInput('localbeginport_cust', true);
1052
				disableInput('dstendport_cust', false);
1053
				ddisableInput('localbeginport', false);
1054
				disableInput('localbeginport_cust', false);
1055
			}
1056

    
1057
		}
1058
	}
1059

    
1060
	function proto_change() {
1061
		if ($('#proto').find(":selected").index() >= 0 && $('#proto').find(":selected").index() <= 2) {
1062
			portsenabled = 1;
1063
		} else {
1064
			portsenabled = 0;
1065
		}
1066

    
1067
		if (portsenabled) {
1068
			hideClass('srcportrange', showsource == 1);
1069
			hideClass('dstportrange', false);
1070
			hideClass('lclportrange', false);
1071
		} else {
1072
			hideClass('srcportrange', true);
1073
			hideClass('dstportrange', true);
1074
			hideClass('lclportrange', true);
1075
			$('#dstbeginport').prop("selectedIndex", 0).selectmenu('refresh');
1076
			$('#dstbeginport_cust').val('');
1077
			$('#dstendport').prop("selectedIndex", 0).selectmenu('refresh');
1078
			$('#dstendport_cust').val('');
1079
			$('#localbeginport').prop("selectedIndex", 0).selectmenu('refresh');
1080
			$('#localbeginport_cust').val('');
1081
		}
1082
	}
1083

    
1084
	function typesel_change() {
1085
		switch ($('#srctype').find(":selected").index()) {
1086
			case 1: // single
1087
				disableInput('src', false);
1088
				$('#srcmask').val('');
1089
				disableInput('srcmask', true);
1090
				break;
1091
			case 2: // network
1092
				disableInput('src', false);
1093
				disableInput('srcmask', false);
1094
				break;
1095
			default:
1096
				$('#src').val('');
1097
				disableInput('src', true);
1098
				$('#srcmask').val('');
1099
				disableInput('srcmask', true);
1100
				break;
1101
		}
1102

    
1103
		if(dstenabled) {
1104
			switch ($('#dsttype').find(":selected").index()) {
1105
				case 1: // single
1106
					disableInput('dst', false);
1107
					$('#dstmask').val('');
1108
					disableInput('dstmask', true);;
1109
					break;
1110
				case 2: // network /
1111
					disableInput('dst', false);
1112
					disableInput('dstmask', false);
1113
					break;
1114
				default:
1115
					$('#dst').val('');
1116
					disableInput('dst', true);
1117
					$('#dstmask').val('');
1118
					disableInput('dstmask', true);
1119
					break;
1120
			}
1121
		}
1122
	}
1123

    
1124
	function src_rep_change() {
1125
		$('#srcendport').prop("selectedIndex", $('#srcbeginport').find(":selected").index());
1126
	}
1127

    
1128
	function dst_rep_change() {
1129
		$('#dstendport').prop("selectedIndex", $('#dstbeginport').find(":selected").index());
1130
	}
1131

    
1132
	function dst_change( iface, old_iface, old_dst ) {
1133
		if ( ( old_dst == "" ) || ( old_iface.concat("ip") == old_dst ) ) {
1134
			$('#dsttype').val($('#dsttype').val() + "ip");
1135
		}
1136
	}
1137

    
1138
	// ---------- "onclick" functions ---------------------------------------------------------------------------------
1139
	$('#srcbeginport').on('change', function() {
1140
		src_rep_change();
1141
		ext_change();
1142
	});
1143

    
1144
	$('#srcendport').on('change', function() {
1145
		ext_change();
1146
	});
1147

    
1148
	$('#dstbeginport').on('change', function() {
1149
		dst_rep_change();
1150
		ext_change();
1151
	});
1152

    
1153
	$('#dstendport').on('change', function() {
1154
		ext_change();
1155
	});
1156

    
1157
	$('#localbeginport').on('change', function() {
1158
		ext_change();
1159
		check_for_aliases();
1160
	});
1161

    
1162
	$('#proto').on('change', function() {
1163
		proto_change();
1164
		check_for_aliases()
1165
	});
1166

    
1167
	$('#nordr').click(function () {
1168
		nordr_change();
1169
	});
1170

    
1171
	$('#interface').click(function () {
1172
		dst_change($('#interface').val(), iface_old, $('#dsttype').val());
1173
		iface_old = $('#interface').val();
1174
		typesel_change();
1175
	});
1176

    
1177
	$('#srctype').click(function () {
1178
		typesel_change();
1179
	});
1180

    
1181
	$('#dsttype').click(function () {
1182
		typesel_change();
1183
	});
1184

    
1185
	// ---------- On initial page load --------------------------------------------------------------------------------
1186

    
1187
	ext_change();
1188
	dst_change($('#interface').val(),'<?=htmlspecialchars($pconfig['interface'])?>','<?=htmlspecialchars($pconfig['dst'])?>');
1189
	iface_old = $('#interface').val();
1190
	typesel_change();
1191
	proto_change();
1192
	nordr_change();
1193

    
1194
});
1195
//]]>
1196
</script>
1197

    
1198
<?php include("foot.inc");
(55-55/237)