Revision d2eee7c8
Added by Steve Beaver over 4 years ago
src/usr/local/pfSense/include/www/firewall_nat_out.inc | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
* firewall_nat_out.inc |
|
4 |
* |
|
5 |
* part of pfSense (https://www.pfsense.org) |
|
6 |
* Copyright (c) 2014-2021 Rubicon Communications, LLC (Netgate) |
|
7 |
* All rights reserved. |
|
8 |
* |
|
9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
10 |
* you may not use this file except in compliance with the License. |
|
11 |
* You may obtain a copy of the License at |
|
12 |
* |
|
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
14 |
* |
|
15 |
* Unless required by applicable law or agreed to in writing, software |
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 |
* See the License for the specific language governing permissions and |
|
19 |
* limitations under the License. |
|
20 |
*/ |
|
21 |
|
|
22 |
// Functions to support firewall_nat_out.php and firewall_nat_out_edit.php |
|
23 |
|
|
24 |
require_once("config.gui.inc"); |
|
25 |
require_once("interfaces.inc"); |
|
26 |
require_once("util.inc"); |
|
27 |
require_once("pfsense-utils.inc"); |
|
28 |
require_once("ipsec.inc"); |
|
29 |
require_once("filter.inc"); |
|
30 |
|
|
31 |
// Save Outbound mode |
|
32 |
function saveNAToutMode($post, $json = false) { |
|
33 |
global $config; |
|
34 |
|
|
35 |
if (!isset($config['nat']['outbound']['mode'])) { |
|
36 |
$config['nat']['outbound']['mode'] = "automatic"; |
|
37 |
} |
|
38 |
|
|
39 |
$mode = $config['nat']['outbound']['mode']; |
|
40 |
|
|
41 |
/* mutually exclusive settings - if user wants advanced NAT, we don't generate automatic rules */ |
|
42 |
if ($post['mode'] == "advanced" && ($mode == "automatic" || $mode == "hybrid")) { |
|
43 |
/* |
|
44 |
* user has enabled advanced outbound NAT and doesn't have rules |
|
45 |
* lets automatically create entries |
|
46 |
* for all of the interfaces to make life easier on the pip-o-chap |
|
47 |
*/ |
|
48 |
if (empty($FilterIflist)) { |
|
49 |
filter_generate_optcfg_array(); |
|
50 |
} |
|
51 |
|
|
52 |
if (empty($GatewaysList)) { |
|
53 |
filter_generate_gateways(); |
|
54 |
} |
|
55 |
|
|
56 |
$tonathosts = filter_nat_rules_automatic_tonathosts(true); |
|
57 |
$automatic_rules = filter_nat_rules_outbound_automatic(""); |
|
58 |
|
|
59 |
foreach ($tonathosts as $tonathost) { |
|
60 |
foreach ($automatic_rules as $natent) { |
|
61 |
$natent['source']['network'] = $tonathost['subnet']; |
|
62 |
$natent['descr'] .= sprintf(gettext(' - %1$s to %2$s'), |
|
63 |
$tonathost['descr'], |
|
64 |
convert_real_interface_to_friendly_descr($natent['interface'])); |
|
65 |
$natent['created'] = make_config_revision_entry(null, gettext("Manual Outbound NAT Switch")); |
|
66 |
|
|
67 |
/* Try to detect already auto created rules and avoid duplicating them */ |
|
68 |
$found = false; |
|
69 |
foreach ($a_out as $rule) { |
|
70 |
if ($rule['interface'] == $natent['interface'] && |
|
71 |
$rule['source']['network'] == $natent['source']['network'] && |
|
72 |
$rule['dstport'] == $natent['dstport'] && |
|
73 |
$rule['target'] == $natent['target'] && |
|
74 |
$rule['descr'] == $natent['descr']) { |
|
75 |
$found = true; |
|
76 |
break; |
|
77 |
} |
|
78 |
} |
|
79 |
|
|
80 |
if ($found === false) { |
|
81 |
$a_out[] = $natent; |
|
82 |
} |
|
83 |
} |
|
84 |
} |
|
85 |
$default_rules_msg = gettext("Default rules for each interface have been created."); |
|
86 |
unset($FilterIflist, $GatewaysList); |
|
87 |
} |
|
88 |
|
|
89 |
$config['nat']['outbound']['mode'] = $post['mode']; |
|
90 |
|
|
91 |
if (write_config(gettext("Firewall: NAT: Outbound - saved outbound NAT settings."))) { |
|
92 |
mark_subsystem_dirty('natconf'); |
|
93 |
} |
|
94 |
|
|
95 |
if (!$json) { |
|
96 |
header("Location: firewall_nat_out.php"); |
|
97 |
exit; |
|
98 |
} |
|
99 |
} |
|
100 |
// Save Outbound rule |
|
101 |
function saveoutNATrule($post, $id, $json = false) { |
|
102 |
global $config; |
|
103 |
|
|
104 |
init_config_arr(array('nat', 'outbound', 'rule')); |
|
105 |
$a_out = &$config['nat']['outbound']['rule']; |
|
106 |
|
|
107 |
if ($post['destination_type'] == "any") { |
|
108 |
$post['destination'] = "any"; |
|
109 |
$post['destination_subnet'] = 24; |
|
110 |
} |
|
111 |
|
|
112 |
if ($post['source_type'] == "any") { |
|
113 |
$post['source'] = "any"; |
|
114 |
$post['source_subnet'] = 24; |
|
115 |
} elseif ($post['source_type'] == "(self)") { |
|
116 |
$post['source'] = "(self)"; |
|
117 |
$post['source_subnet'] = 24; |
|
118 |
} |
|
119 |
|
|
120 |
unset($input_errors); |
|
121 |
$pconfig = $post; |
|
122 |
|
|
123 |
/* run through $post items encoding HTML entitles so that the user |
|
124 |
* cannot think he is slick and perform a XSS attack on the unwilling |
|
125 |
*/ |
|
126 |
foreach ($post as $key => $value) { |
|
127 |
if ($key == 'descr') { |
|
128 |
continue; |
|
129 |
} |
|
130 |
|
|
131 |
$temp = str_replace(">", "", $value); |
|
132 |
$newpost = htmlentities($temp); |
|
133 |
if ($newpost <> $temp) { |
|
134 |
$input_errors[] = sprintf(gettext("Invalid characters detected (%s). Please remove invalid characters and save again."), $temp); |
|
135 |
} |
|
136 |
} |
|
137 |
|
|
138 |
/* input validation */ |
|
139 |
$reqdfields = explode(" ", "interface protocol source source_subnet destination destination_subnet"); |
|
140 |
$reqdfieldsn = array(gettext("Interface"), gettext("Protocol"), gettext("Source"), gettext("Source bit count"), gettext("Destination"), gettext("Destination bit count")); |
|
141 |
|
|
142 |
do_input_validation($post, $reqdfields, $reqdfieldsn, $input_errors); |
|
143 |
|
|
144 |
$protocol_uses_ports = in_array($post['protocol'], explode(" ", "any tcp udp tcp/udp")); |
|
145 |
|
|
146 |
if ($post['source']) { |
|
147 |
$post['source'] = trim($post['source']); |
|
148 |
} |
|
149 |
if ($post['destination']) { |
|
150 |
$post['destination'] = trim($post['destination']); |
|
151 |
} |
|
152 |
if ($post['targetip']) { |
|
153 |
$post['targetip'] = trim($post['targetip']); |
|
154 |
} |
|
155 |
if ($post['sourceport']) { |
|
156 |
$post['sourceport'] = trim($post['sourceport']); |
|
157 |
} |
|
158 |
if ($post['dstport']) { |
|
159 |
$post['dstport'] = trim($post['dstport']); |
|
160 |
} |
|
161 |
if ($post['natport']) { |
|
162 |
$post['natport'] = trim($post['natport']); |
|
163 |
} |
|
164 |
|
|
165 |
if (strlen($post['target']) > 0) { |
|
166 |
// Strip the target code 1-char code from the front before validating and saving. |
|
167 |
$post['target'] = substr($post['target'], 1); |
|
168 |
} |
|
169 |
|
|
170 |
if ($protocol_uses_ports && $post['sourceport'] <> "" && !is_port_or_range_or_alias($post['sourceport'])) { |
|
171 |
$input_errors[] = gettext("A valid port or port alias must be supplied for the source port entry."); |
|
172 |
} |
|
173 |
|
|
174 |
if ($protocol_uses_ports && $post['dstport'] <> "" && !is_port_or_range_or_alias($post['dstport'])) { |
|
175 |
$input_errors[] = gettext("A valid port or port alias must be supplied for the destination port entry."); |
|
176 |
} |
|
177 |
|
|
178 |
if ($protocol_uses_ports && $post['natport'] <> "" && !is_port_or_range_or_alias($post['natport']) && !isset($post['nonat'])) { |
|
179 |
$input_errors[] = gettext("A valid port must be supplied for the NAT port entry."); |
|
180 |
} |
|
181 |
|
|
182 |
if (($post['source_type'] != "any") && ($post['source_type'] != "(self)")) { |
|
183 |
if ($post['source'] && !is_ipaddroralias($post['source']) && $post['source'] != "any") { |
|
184 |
$input_errors[] = gettext("A valid source must be specified."); |
|
185 |
} |
|
186 |
} |
|
187 |
|
|
188 |
if ($post['source_subnet'] && !is_numericint($post['source_subnet'])) { |
|
189 |
$input_errors[] = gettext("A valid source bit count must be specified."); |
|
190 |
} |
|
191 |
|
|
192 |
if ($post['destination_type'] != "any") { |
|
193 |
if ($post['destination'] && !is_ipaddroralias($post['destination'])) { |
|
194 |
$input_errors[] = gettext("A valid destination must be specified."); |
|
195 |
} |
|
196 |
} |
|
197 |
|
|
198 |
if ($post['destination_subnet'] && !is_numericint($post['destination_subnet'])) { |
|
199 |
$input_errors[] = gettext("A valid destination bit count must be specified."); |
|
200 |
} |
|
201 |
|
|
202 |
if ($post['destination_type'] == "any") { |
|
203 |
if ($post['destination_not']) { |
|
204 |
$input_errors[] = gettext("Negating destination address of \"any\" is invalid."); |
|
205 |
} |
|
206 |
} |
|
207 |
|
|
208 |
if ($post['target'] && !is_ipaddr($post['target']) && !is_subnet($post['target']) && !is_alias($post['target']) && !isset($post['nonat']) && !($post['target'] == "other-subnet")) { |
|
209 |
$input_errors[] = gettext("A valid target IP address must be specified."); |
|
210 |
} |
|
211 |
|
|
212 |
if ($post['target'] == "other-subnet") { |
|
213 |
if (!is_ipaddr($post['targetip'])) { |
|
214 |
$input_errors[] = gettext("A valid target IP must be specified when using the 'Other Subnet' type."); |
|
215 |
} |
|
216 |
|
|
217 |
if (!is_numericint($post['targetip_subnet'])) { |
|
218 |
$input_errors[] = gettext("A valid target bit count must be specified when using the 'Other Subnet' type."); |
|
219 |
} |
|
220 |
} |
|
221 |
|
|
222 |
/* Verify Pool Options */ |
|
223 |
$poolopts = ""; |
|
224 |
$source_hash_key = ""; |
|
225 |
if ($post['poolopts']) { |
|
226 |
if (is_subnet($post['target']) || ($post['target'] == "other-subnet")) { |
|
227 |
$poolopts = $post['poolopts']; |
|
228 |
} elseif (is_alias($post['target'])) { |
|
229 |
if (substr($post['poolopts'], 0, 11) == "round-robin") { |
|
230 |
$poolopts = $post['poolopts']; |
|
231 |
} else { |
|
232 |
$input_errors[] = gettext("Only Round Robin pool options may be chosen when selecting an alias."); |
|
233 |
} |
|
234 |
} |
|
235 |
/* If specified, verify valid source-hash key or generate a valid key using md5 */ |
|
236 |
if ($post['source_hash_key']) { |
|
237 |
if (substr($post['source_hash_key'],0,2) == "0x") { |
|
238 |
if (ctype_xdigit(substr($post['source_hash_key'],2)) && strlen($post['source_hash_key']) == 34) { |
|
239 |
$source_hash_key = $post['source_hash_key']; |
|
240 |
} else { |
|
241 |
$input_errors[] = gettext("Incorrect format for source-hash key, \"0x\" must be followed by exactly 32 hexadecimal characters."); |
|
242 |
} |
|
243 |
} else { |
|
244 |
$source_hash_key = "0x".md5($post['source_hash_key']); |
|
245 |
} |
|
246 |
} |
|
247 |
} |
|
248 |
|
|
249 |
/* if user has selected any as source, set it here */ |
|
250 |
if ($post['source_type'] == "any") { |
|
251 |
$osn = "any"; |
|
252 |
} else if ($post['source_type'] == "(self)") { |
|
253 |
$osn = "(self)"; |
|
254 |
} else if (is_alias($post['source'])) { |
|
255 |
$osn = $post['source']; |
|
256 |
} else { |
|
257 |
$osn = gen_subnet($post['source'], $post['source_subnet']) . "/" . $post['source_subnet']; |
|
258 |
} |
|
259 |
|
|
260 |
/* check for existing entries */ |
|
261 |
if ($post['destination_type'] == "any") { |
|
262 |
$ext = "any"; |
|
263 |
} else if (is_alias($post['destination'])) { |
|
264 |
$ext = $post['destination']; |
|
265 |
} else { |
|
266 |
$ext = gen_subnet($post['destination'], $post['destination_subnet']) . "/" . $post['destination_subnet']; |
|
267 |
} |
|
268 |
|
|
269 |
foreach ($a_out as $natent) { |
|
270 |
if (isset($id) && ($a_out[$id]) && ($a_out[$id] === $natent)) { |
|
271 |
continue; |
|
272 |
} |
|
273 |
|
|
274 |
if (!$natent['interface']) { |
|
275 |
$natent['interface'] = "wan"; |
|
276 |
} |
|
277 |
} |
|
278 |
|
|
279 |
if (!$input_errors) { |
|
280 |
$natent = array(); |
|
281 |
$natent['source']['network'] = $osn; |
|
282 |
$natent['sourceport'] = ($protocol_uses_ports) ? $post['sourceport'] : ""; |
|
283 |
$natent['descr'] = $post['descr']; |
|
284 |
$natent['target'] = (!isset($post['nonat'])) ? $post['target'] : ""; |
|
285 |
$natent['targetip'] = (!isset($post['nonat'])) ? $post['targetip'] : ""; |
|
286 |
$natent['targetip_subnet'] = (!isset($post['nonat'])) ? $post['targetip_subnet'] : ""; |
|
287 |
$natent['interface'] = $post['interface']; |
|
288 |
$natent['poolopts'] = $poolopts; |
|
289 |
$natent['source_hash_key'] = $source_hash_key; |
|
290 |
|
|
291 |
/* static-port */ |
|
292 |
if (isset($post['staticnatport']) && $protocol_uses_ports && !isset($post['nonat'])) { |
|
293 |
$natent['staticnatport'] = true; |
|
294 |
} else { |
|
295 |
unset($natent['staticnatport']); |
|
296 |
} |
|
297 |
|
|
298 |
if (isset($post['disabled'])) { |
|
299 |
$natent['disabled'] = true; |
|
300 |
} else { |
|
301 |
unset($natent['disabled']); |
|
302 |
} |
|
303 |
|
|
304 |
/* if user has selected not nat, set it here */ |
|
305 |
if (isset($post['nonat'])) { |
|
306 |
$natent['nonat'] = true; |
|
307 |
} else { |
|
308 |
unset($natent['nonat']); |
|
309 |
} |
|
310 |
|
|
311 |
if ($post['ipprotocol'] && $post['ipprotocol'] != "inet46") { |
|
312 |
$natent['ipprotocol'] = $post['ipprotocol']; |
|
313 |
} else { |
|
314 |
unset($natent['ipprotocol']); |
|
315 |
} |
|
316 |
|
|
317 |
if ($post['protocol'] && $post['protocol'] != "any") { |
|
318 |
$natent['protocol'] = $post['protocol']; |
|
319 |
} else { |
|
320 |
unset($natent['protocol']); |
|
321 |
} |
|
322 |
|
|
323 |
if ($ext == "any") { |
|
324 |
$natent['destination']['any'] = true; |
|
325 |
} else { |
|
326 |
$natent['destination']['address'] = $ext; |
|
327 |
} |
|
328 |
if ($post['natport'] != "" && $protocol_uses_ports && !isset($post['nonat'])) { |
|
329 |
$natent['natport'] = $post['natport']; |
|
330 |
} else { |
|
331 |
unset($natent['natport']); |
|
332 |
} |
|
333 |
if ($post['dstport'] != "" && $protocol_uses_ports) { |
|
334 |
$natent['dstport'] = $post['dstport']; |
|
335 |
} else { |
|
336 |
unset($natent['dstport']); |
|
337 |
} |
|
338 |
|
|
339 |
if ($post['nosync'] == "yes") { |
|
340 |
$natent['nosync'] = true; |
|
341 |
} else { |
|
342 |
unset($natent['nosync']); |
|
343 |
} |
|
344 |
|
|
345 |
if (isset($post['destination_not']) && $ext != "any") { |
|
346 |
$natent['destination']['not'] = true; |
|
347 |
} |
|
348 |
|
|
349 |
if (isset($a_out[$id]['created']) && is_array($a_out[$id]['created'])) { |
|
350 |
$natent['created'] = $a_out[$id]['created']; |
|
351 |
} |
|
352 |
|
|
353 |
$natent['updated'] = make_config_revision_entry(); |
|
354 |
|
|
355 |
// Allow extending of the firewall edit page and include custom input validation |
|
356 |
pfSense_handle_custom_code("/usr/local/pkg/firewall_aon/pre_write_config"); |
|
357 |
|
|
358 |
if (isset($id) && $a_out[$id]) { |
|
359 |
$a_out[$id] = $natent; |
|
360 |
} else { |
|
361 |
$natent['created'] = make_config_revision_entry(); |
|
362 |
if (is_numeric($after)) { |
|
363 |
array_splice($a_out, $after+1, 0, array($natent)); |
|
364 |
} else { |
|
365 |
$a_out[] = $natent; |
|
366 |
} |
|
367 |
} |
|
368 |
|
|
369 |
if (write_config(gettext("Firewall: NAT: Outbound - saved/edited outbound NAT mapping.")) && !$json) { |
|
370 |
mark_subsystem_dirty('natconf'); |
|
371 |
} |
|
372 |
|
|
373 |
$rv = array(); |
|
374 |
$rv['input_errors'] = $input_errors; |
|
375 |
$rv['pconfig'] = $pconfig; |
|
376 |
} |
|
377 |
|
|
378 |
return $json ? json_encode($rv) : $rv; |
|
379 |
} |
|
380 |
|
|
381 |
// Retrieve the specified Outbound rule |
|
382 |
function getoutNATrule($id, $json = false) { |
|
383 |
global $config; |
|
384 |
|
|
385 |
init_config_arr(array('nat', 'outbound', 'rule')); |
|
386 |
$a_out = &$config['nat']['outbound']['rule']; |
|
387 |
|
|
388 |
$pconfig = array(); |
|
389 |
|
|
390 |
if (isset($id) && $a_out[$id]) { |
|
391 |
if (isset($a_out[$id]['created']) && is_array($a_out[$id]['created'])) { |
|
392 |
$pconfig['created'] = $a_out[$id]['created']; |
|
393 |
} |
|
394 |
|
|
395 |
if (isset($a_out[$id]['updated']) && is_array($a_out[$id]['updated'])) { |
|
396 |
$pconfig['updated'] = $a_out[$id]['updated']; |
|
397 |
} |
|
398 |
|
|
399 |
$pconfig['ipprotocol'] = $a_out[$id]['ipprotocol']; |
|
400 |
$pconfig['protocol'] = $a_out[$id]['protocol']; |
|
401 |
list($pconfig['source'], $pconfig['source_subnet']) = explode('/', $a_out[$id]['source']['network']); |
|
402 |
if (!is_numeric($pconfig['source_subnet'])) { |
|
403 |
$pconfig['source_subnet'] = 32; |
|
404 |
} |
|
405 |
$pconfig['sourceport'] = $a_out[$id]['sourceport']; |
|
406 |
address_to_pconfig($a_out[$id]['destination'], $pconfig['destination'], |
|
407 |
$pconfig['destination_subnet'], $pconfig['destination_not'], |
|
408 |
$none, $none); |
|
409 |
|
|
410 |
$pconfig['dstport'] = $a_out[$id]['dstport']; |
|
411 |
$pconfig['natport'] = $a_out[$id]['natport']; |
|
412 |
$pconfig['target'] = $a_out[$id]['target']; |
|
413 |
if (strlen($pconfig['target']) > 0) { |
|
414 |
// Deduce the target type and add to the front of the target string. |
|
415 |
if (is_subnet($pconfig['target'])) { |
|
416 |
$target_type = "S"; |
|
417 |
} elseif (is_ipaddr($pconfig['target'])) { |
|
418 |
$target_type = "I"; |
|
419 |
} elseif (is_alias($pconfig['target'])) { |
|
420 |
$target_type = "H"; |
|
421 |
} else { |
|
422 |
$target_type = "O"; |
|
423 |
} |
|
424 |
$pconfig['target'] = $target_type . $pconfig['target']; |
|
425 |
} |
|
426 |
|
|
427 |
$pconfig['targetip'] = $a_out[$id]['targetip']; |
|
428 |
$pconfig['targetip_subnet'] = $a_out[$id]['targetip_subnet']; |
|
429 |
$pconfig['poolopts'] = $a_out[$id]['poolopts']; |
|
430 |
$pconfig['source_hash_key'] = $a_out[$id]['source_hash_key']; |
|
431 |
$pconfig['interface'] = $a_out[$id]['interface']; |
|
432 |
|
|
433 |
if (!$pconfig['interface']) { |
|
434 |
$pconfig['interface'] = "wan"; |
|
435 |
} |
|
436 |
|
|
437 |
$pconfig['descr'] = $a_out[$id]['descr']; |
|
438 |
$pconfig['nonat'] = $a_out[$id]['nonat']; |
|
439 |
$pconfig['disabled'] = isset($a_out[$id]['disabled']); |
|
440 |
$pconfig['staticnatport'] = isset($a_out[$id]['staticnatport']); |
|
441 |
$pconfig['nosync'] = isset($a_out[$id]['nosync']); |
|
442 |
} else { |
|
443 |
$pconfig['source_subnet'] = 24; |
|
444 |
$pconfig['destination'] = "any"; |
|
445 |
$pconfig['destination_subnet'] = 24; |
|
446 |
$pconfig['interface'] = "wan"; |
|
447 |
} |
|
448 |
|
|
449 |
return $json ? json_encode($pconfig):$pconfig; |
|
450 |
} |
|
451 |
|
|
452 |
// Toggle enabled/disabled status of an Outbound rule |
|
453 |
function toggleoutNATrule($post, $json = false) { |
|
454 |
global $config; |
|
455 |
|
|
456 |
init_config_arr(array('nat', 'outbound', 'rule')); |
|
457 |
$a_out = &$config['nat']['outbound']['rule']; |
|
458 |
|
|
459 |
if (isset($a_out[$post['id']]['disabled'])) { |
|
460 |
unset($a_out[$post['id']]['disabled']); |
|
461 |
$wc_msg = gettext('Firewall: NAT: Outbound - enabled a NAT Outbound rule.'); |
|
462 |
} else { |
|
463 |
$a_out[$post['id']]['disabled'] = true; |
|
464 |
$wc_msg = gettext('Firewall: NAT: Outbound - disabled a NAT Outbound rule.'); |
|
465 |
} |
|
466 |
|
|
467 |
if (write_config($wc_msg) && !$json) { |
|
468 |
mark_subsystem_dirty('natconf'); |
|
469 |
} |
|
470 |
|
|
471 |
if (!$json) { |
|
472 |
header("Location: firewall_nat_out.php"); |
|
473 |
exit; |
|
474 |
} |
|
475 |
} |
|
476 |
|
|
477 |
// Delete multiple Outbound rules |
|
478 |
function deleteMultipleoutNATrules($post, $json = false) { |
|
479 |
global $config; |
|
480 |
|
|
481 |
init_config_arr(array('nat', 'outbound', 'rule')); |
|
482 |
$a_out = &$config['nat']['outbound']['rule']; |
|
483 |
|
|
484 |
foreach ($post['rule'] as $rulei) { |
|
485 |
unset($a_out[$rulei]); |
|
486 |
} |
|
487 |
|
|
488 |
if (write_config(gettext("Firewall: NAT: Outbound - deleted selected outbound mappings.")) && !$json) { |
|
489 |
mark_subsystem_dirty('natconf'); |
|
490 |
} |
|
491 |
|
|
492 |
if (!$json) { |
|
493 |
header("Location: firewall_nat_out.php"); |
|
494 |
exit; |
|
495 |
} |
|
496 |
} |
|
497 |
|
|
498 |
// Delete outbound rule |
|
499 |
function deleteoutNATrule($post, $json = false) { |
|
500 |
global $config; |
|
501 |
|
|
502 |
init_config_arr(array('nat', 'outbound', 'rule')); |
|
503 |
$a_out = &$config['nat']['outbound']['rule']; |
|
504 |
|
|
505 |
unset($a_out[$post['id']]); |
|
506 |
if (write_config(gettext("Firewall: NAT: Outbound - deleted NPt mapping.")) && !$json) { |
|
507 |
mark_subsystem_dirty('natconf'); |
|
508 |
} |
|
509 |
|
|
510 |
if(!$json) { |
|
511 |
header("Location: firewall_nat_out.php"); |
|
512 |
exit; |
|
513 |
} |
|
514 |
} |
|
515 |
|
|
516 |
// Re-order the NPtNAT rules per the array of iindicies passed in $post |
|
517 |
function reorderoutNATrules($post, $json = false) { |
|
518 |
global $config; |
|
519 |
|
|
520 |
if (is_array($post['rule']) && !empty($post['rule'])) { |
|
521 |
init_config_arr(array('nat', 'outbound', 'rule')); |
|
522 |
$a_out = &$config['nat']['outbound']['rule']; |
|
523 |
$a_out_new = array(); |
|
524 |
|
|
525 |
// if a rule is not in POST[rule], it has been deleted by the user |
|
526 |
foreach ($post['rule'] as $id) { |
|
527 |
$a_out_new[] = $a_out[$id]; |
|
528 |
} |
|
529 |
|
|
530 |
$a_out = $a_out_new; |
|
531 |
|
|
532 |
if (write_config(gettext("Firewall: NAT: Outbound - reordered outbound mappings.")) && !$json) { |
|
533 |
mark_subsystem_dirty('natconf'); |
|
534 |
} |
|
535 |
|
|
536 |
if (!$json) { |
|
537 |
header("Location: firewall_nat_out.php"); |
|
538 |
exit; |
|
539 |
} |
|
540 |
} |
|
541 |
} |
|
542 |
|
|
543 |
function applyoutNATrules() { |
|
544 |
$retval = 0; |
|
545 |
$retval |= filter_configure(); |
|
546 |
|
|
547 |
if ($retval == 0) { |
|
548 |
clear_subsystem_dirty('natconf'); |
|
549 |
clear_subsystem_dirty('filter'); |
|
550 |
} |
|
551 |
|
|
552 |
return $retval; |
|
553 |
} |
|
554 |
|
|
555 |
function build_target_list() { |
|
556 |
global $config; |
|
557 |
|
|
558 |
init_config_arr(array('aliases', 'alias')); |
|
559 |
$a_aliases = &$config['aliases']['alias']; |
|
560 |
|
|
561 |
$list = array(); |
|
562 |
// Target list entries are made to start with the following characters: |
|
563 |
// "" (blank) - the interface address of the selected interface |
|
564 |
// S - a subnet |
|
565 |
// I - an ordinary IP address |
|
566 |
// H - a host alias |
|
567 |
// O - other subnet |
|
568 |
// The prefix letter makes it easy for the JavaScript to distinguish |
|
569 |
// the type of entry based on the first letter of the value. |
|
570 |
// The prefix letter is removed before saving in the config, |
|
571 |
// and added back when reading from the config. |
|
572 |
|
|
573 |
$list[""] = gettext('Interface Address'); |
|
574 |
|
|
575 |
//Temporary array so we can sort IPs |
|
576 |
$templist = array(); |
|
577 |
if (is_array($config['virtualip']['vip'])) { |
|
578 |
foreach ($config['virtualip']['vip'] as $sn) { |
|
579 |
if (($sn['mode'] == "proxyarp" || $sn['mode'] == "other") && $sn['type'] == "network") { |
|
580 |
$templist['S' . $sn['subnet'] . '/' . $sn['subnet_bits']] = gettext('Subnet: ') . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')'; |
|
581 |
if (isset($sn['noexpand'])) { |
|
582 |
continue; |
|
583 |
} |
|
584 |
$start = ip2long32(gen_subnet($sn['subnet'], $sn['subnet_bits'])); |
|
585 |
$end = ip2long32(gen_subnet_max($sn['subnet'], $sn['subnet_bits'])); |
|
586 |
$len = $end - $start; |
|
587 |
for ($i = 0; $i <= $len; $i++) { |
|
588 |
$snip = long2ip32($start+$i); |
|
589 |
|
|
590 |
$templist['I' . $snip] = $snip . ' (' . $sn['descr'] . ')'; |
|
591 |
} |
|
592 |
} else { |
|
593 |
$templist['I' . $sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')'; |
|
594 |
} |
|
595 |
} |
|
596 |
} |
|
597 |
asort($templist); |
|
598 |
//Append sorted IP array onto main array |
|
599 |
$list = array_merge($list, $templist); |
|
600 |
unset($templist); |
|
601 |
|
|
602 |
foreach ($a_aliases as $alias) { |
|
603 |
if ($alias['type'] != "host") { |
|
604 |
continue; |
|
605 |
} |
|
606 |
|
|
607 |
$list['H' . $alias['name']] = gettext('Host Alias: ') . $alias['name'] . ' (' . $alias['descr'] . ')'; |
|
608 |
} |
|
609 |
|
|
610 |
$list['Oother-subnet'] = gettext('Other Subnet (Enter Below)'); |
|
611 |
|
|
612 |
return($list); |
|
613 |
} |
|
614 |
?> |
src/usr/local/www/firewall_nat_out.php | ||
---|---|---|
36 | 36 |
require_once("functions.inc"); |
37 | 37 |
require_once("filter.inc"); |
38 | 38 |
require_once("shaper.inc"); |
39 |
require_once("firewall_nat_out.inc"); |
|
39 | 40 |
|
40 | 41 |
global $FilterIflist; |
41 | 42 |
global $GatewaysList; |
... | ... | |
46 | 47 |
// update rule order, POST[rule] is an array of ordered IDs |
47 | 48 |
// All rule are 'checked' before posting |
48 | 49 |
if (isset($_REQUEST['order-store'])) { |
49 |
if (is_array($_REQUEST['rule']) && !empty($_REQUEST['rule'])) { |
|
50 |
|
|
51 |
$a_out_new = array(); |
|
52 |
|
|
53 |
// if a rule is not in POST[rule], it has been deleted by the user |
|
54 |
foreach ($_REQUEST['rule'] as $id) { |
|
55 |
$a_out_new[] = $a_out[$id]; |
|
56 |
} |
|
57 |
|
|
58 |
$a_out = $a_out_new; |
|
59 |
|
|
60 |
if (write_config(gettext("Firewall: NAT: Outbound - reordered outbound NAT mappings."))) { |
|
61 |
mark_subsystem_dirty('natconf'); |
|
62 |
} |
|
63 |
|
|
64 |
header("Location: firewall_nat_out.php"); |
|
65 |
exit; |
|
66 |
|
|
67 |
} |
|
50 |
reorderoutNATrules($_POST); |
|
68 | 51 |
} |
69 | 52 |
|
70 | 53 |
if (!isset($config['nat']['outbound']['mode'])) { |
... | ... | |
74 | 57 |
$mode = $config['nat']['outbound']['mode']; |
75 | 58 |
|
76 | 59 |
if ($_POST['apply']) { |
77 |
$retval = 0; |
|
78 |
$retval |= filter_configure(); |
|
79 |
|
|
80 |
if ($retval == 0) { |
|
81 |
clear_subsystem_dirty('natconf'); |
|
82 |
clear_subsystem_dirty('filter'); |
|
83 |
} |
|
84 |
} |
|
85 |
|
|
86 |
if ($_POST['save']) { |
|
87 |
/* mutually exclusive settings - if user wants advanced NAT, we don't generate automatic rules */ |
|
88 |
if ($_POST['mode'] == "advanced" && ($mode == "automatic" || $mode == "hybrid")) { |
|
89 |
/* |
|
90 |
* user has enabled advanced outbound NAT and doesn't have rules |
|
91 |
* lets automatically create entries |
|
92 |
* for all of the interfaces to make life easier on the pip-o-chap |
|
93 |
*/ |
|
94 |
if (empty($FilterIflist)) { |
|
95 |
filter_generate_optcfg_array(); |
|
96 |
} |
|
97 |
|
|
98 |
if (empty($GatewaysList)) { |
|
99 |
filter_generate_gateways(); |
|
100 |
} |
|
101 |
|
|
102 |
$tonathosts = filter_nat_rules_automatic_tonathosts(true); |
|
103 |
$automatic_rules = filter_nat_rules_outbound_automatic(""); |
|
104 |
|
|
105 |
foreach ($tonathosts as $tonathost) { |
|
106 |
foreach ($automatic_rules as $natent) { |
|
107 |
$natent['source']['network'] = $tonathost['subnet']; |
|
108 |
$natent['descr'] .= sprintf(gettext(' - %1$s to %2$s'), |
|
109 |
$tonathost['descr'], |
|
110 |
convert_real_interface_to_friendly_descr($natent['interface'])); |
|
111 |
$natent['created'] = make_config_revision_entry(null, gettext("Manual Outbound NAT Switch")); |
|
112 |
|
|
113 |
/* Try to detect already auto created rules and avoid duplicating them */ |
|
114 |
$found = false; |
|
115 |
foreach ($a_out as $rule) { |
|
116 |
if ($rule['interface'] == $natent['interface'] && |
|
117 |
$rule['source']['network'] == $natent['source']['network'] && |
|
118 |
$rule['dstport'] == $natent['dstport'] && |
|
119 |
$rule['target'] == $natent['target'] && |
|
120 |
$rule['descr'] == $natent['descr']) { |
|
121 |
$found = true; |
|
122 |
break; |
|
123 |
} |
|
124 |
} |
|
125 |
|
|
126 |
if ($found === false) { |
|
127 |
$a_out[] = $natent; |
|
128 |
} |
|
129 |
} |
|
130 |
} |
|
131 |
$default_rules_msg = gettext("Default rules for each interface have been created."); |
|
132 |
unset($FilterIflist, $GatewaysList); |
|
133 |
} |
|
134 |
|
|
135 |
$config['nat']['outbound']['mode'] = $_POST['mode']; |
|
136 |
|
|
137 |
if (write_config(gettext("Firewall: NAT: Outbound - saved outbound NAT settings."))) { |
|
138 |
mark_subsystem_dirty('natconf'); |
|
139 |
} |
|
140 |
|
|
141 |
header("Location: firewall_nat_out.php"); |
|
142 |
exit; |
|
143 |
} |
|
144 |
|
|
145 |
// Delete a single rule/map |
|
146 |
if ($_POST['act'] == "del") { |
|
147 |
|
|
148 |
if ($a_out[$_POST['id']]) { |
|
149 |
unset($a_out[$_POST['id']]); |
|
150 |
if (write_config(gettext("Firewall: NAT: Outbound - deleted outbound NAT mapping."))) { |
|
151 |
mark_subsystem_dirty('natconf'); |
|
152 |
} |
|
153 |
|
|
154 |
header("Location: firewall_nat_out.php"); |
|
155 |
exit; |
|
156 |
} |
|
157 |
} |
|
158 |
|
|
159 |
// Delete multiple maps Only checked rules will be in the |
|
160 |
// POST |
|
161 |
if (isset($_POST['del_x'])) { |
|
60 |
$retval = applyoutNATrules(); |
|
61 |
} else if ($_POST['save']) { |
|
62 |
saveNAToutMode($_POST); |
|
63 |
} else if ($_POST['act'] == "del") { |
|
64 |
deleteoutNATrule($_POST); |
|
65 |
} else if (isset($_POST['del_x'])) { |
|
162 | 66 |
/* delete selected rules */ |
163 |
print('Deleting rows<br />'); |
|
164 |
|
|
165 |
if (is_array($_POST['rule']) && count($_POST['rule'])) { |
|
166 |
foreach ($_POST['rule'] as $rulei) { |
|
167 |
print('Deleting ' . $rulei . '<br />'); |
|
168 |
unset($a_out[$rulei]); |
|
169 |
} |
|
170 |
|
|
171 |
if (write_config(gettext("Firewall: NAT: Outbound - deleted selected outbound NAT mappings."))) { |
|
172 |
mark_subsystem_dirty('natconf'); |
|
173 |
} |
|
174 |
|
|
175 |
header("Location: firewall_nat_out.php"); |
|
176 |
exit; |
|
177 |
} |
|
178 |
|
|
67 |
deleteMultipleoutNATrules($_POST); |
|
179 | 68 |
} else if ($_POST['act'] == "toggle") { |
180 |
if ($a_out[$_POST['id']]) { |
|
181 |
if (isset($a_out[$_POST['id']]['disabled'])) { |
|
182 |
unset($a_out[$_POST['id']]['disabled']); |
|
183 |
$wc_msg = gettext('Firewall: NAT: Outbound - enabled outbound NAT rule.'); |
|
184 |
} else { |
|
185 |
$a_out[$_POST['id']]['disabled'] = true; |
|
186 |
$wc_msg = gettext('Firewall: NAT: Outbound - disabled outbound NAT rule.'); |
|
187 |
} |
|
188 |
if (write_config($wc_msg)) { |
|
189 |
mark_subsystem_dirty('natconf'); |
|
190 |
} |
|
191 |
|
|
192 |
header("Location: firewall_nat_out.php"); |
|
193 |
exit; |
|
194 |
} |
|
69 |
toggleoutNATrule($_POST); |
|
195 | 70 |
} |
196 | 71 |
|
197 | 72 |
$pgtitle = array(gettext("Firewall"), gettext("NAT"), gettext("Outbound")); |
src/usr/local/www/firewall_nat_out_edit.php | ||
---|---|---|
36 | 36 |
require_once("ipsec.inc"); |
37 | 37 |
require_once("filter.inc"); |
38 | 38 |
require_once("shaper.inc"); |
39 |
require_once("firewall_nat_out.inc"); |
|
39 | 40 |
|
40 | 41 |
init_config_arr(array('nat', 'outbound', 'rule')); |
41 | 42 |
$a_out = &$config['nat']['outbound']['rule']; |
42 | 43 |
|
43 |
init_config_arr(array('aliases', 'alias')); |
|
44 |
$a_aliases = &$config['aliases']['alias']; |
|
45 |
|
|
46 | 44 |
if (isset($_REQUEST['id']) && is_numericint($_REQUEST['id'])) { |
47 | 45 |
$id = $_REQUEST['id']; |
48 | 46 |
} |
... | ... | |
56 | 54 |
$after = $_REQUEST['dup']; |
57 | 55 |
} |
58 | 56 |
|
59 |
if (isset($id) && $a_out[$id]) { |
|
60 |
if (isset($a_out[$id]['created']) && is_array($a_out[$id]['created'])) { |
|
61 |
$pconfig['created'] = $a_out[$id]['created']; |
|
62 |
} |
|
63 |
|
|
64 |
if (isset($a_out[$id]['updated']) && is_array($a_out[$id]['updated'])) { |
|
65 |
$pconfig['updated'] = $a_out[$id]['updated']; |
|
66 |
} |
|
67 |
|
|
68 |
$pconfig['ipprotocol'] = $a_out[$id]['ipprotocol']; |
|
69 |
$pconfig['protocol'] = $a_out[$id]['protocol']; |
|
70 |
list($pconfig['source'], $pconfig['source_subnet']) = explode('/', $a_out[$id]['source']['network']); |
|
71 |
if (!is_numeric($pconfig['source_subnet'])) { |
|
72 |
$pconfig['source_subnet'] = 32; |
|
73 |
} |
|
74 |
$pconfig['sourceport'] = $a_out[$id]['sourceport']; |
|
75 |
address_to_pconfig($a_out[$id]['destination'], $pconfig['destination'], |
|
76 |
$pconfig['destination_subnet'], $pconfig['destination_not'], |
|
77 |
$none, $none); |
|
78 |
|
|
79 |
$pconfig['dstport'] = $a_out[$id]['dstport']; |
|
80 |
$pconfig['natport'] = $a_out[$id]['natport']; |
|
81 |
$pconfig['target'] = $a_out[$id]['target']; |
|
82 |
if (strlen($pconfig['target']) > 0) { |
|
83 |
// Deduce the target type and add to the front of the target string. |
|
84 |
if (is_subnet($pconfig['target'])) { |
|
85 |
$target_type = "S"; |
|
86 |
} elseif (is_ipaddr($pconfig['target'])) { |
|
87 |
$target_type = "I"; |
|
88 |
} elseif (is_alias($pconfig['target'])) { |
|
89 |
$target_type = "H"; |
|
90 |
} else { |
|
91 |
$target_type = "O"; |
|
92 |
} |
|
93 |
$pconfig['target'] = $target_type . $pconfig['target']; |
|
94 |
} |
|
95 |
|
|
96 |
$pconfig['targetip'] = $a_out[$id]['targetip']; |
|
97 |
$pconfig['targetip_subnet'] = $a_out[$id]['targetip_subnet']; |
|
98 |
$pconfig['poolopts'] = $a_out[$id]['poolopts']; |
|
99 |
$pconfig['source_hash_key'] = $a_out[$id]['source_hash_key']; |
|
100 |
$pconfig['interface'] = $a_out[$id]['interface']; |
|
101 |
|
|
102 |
if (!$pconfig['interface']) { |
|
103 |
$pconfig['interface'] = "wan"; |
|
104 |
} |
|
105 |
|
|
106 |
$pconfig['descr'] = $a_out[$id]['descr']; |
|
107 |
$pconfig['nonat'] = $a_out[$id]['nonat']; |
|
108 |
$pconfig['disabled'] = isset($a_out[$id]['disabled']); |
|
109 |
$pconfig['staticnatport'] = isset($a_out[$id]['staticnatport']); |
|
110 |
$pconfig['nosync'] = isset($a_out[$id]['nosync']); |
|
111 |
} else { |
|
112 |
$pconfig['source_subnet'] = 24; |
|
113 |
$pconfig['destination'] = "any"; |
|
114 |
$pconfig['destination_subnet'] = 24; |
|
115 |
$pconfig['interface'] = "wan"; |
|
116 |
} |
|
117 |
|
|
118 | 57 |
if (isset($_REQUEST['dup']) && is_numericint($_REQUEST['dup'])) { |
119 | 58 |
unset($id); |
120 | 59 |
} |
121 | 60 |
|
122 | 61 |
if ($_POST['save']) { |
123 |
if ($_POST['destination_type'] == "any") { |
|
124 |
$_POST['destination'] = "any"; |
|
125 |
$_POST['destination_subnet'] = 24; |
|
126 |
} |
|
127 |
|
|
128 |
if ($_POST['source_type'] == "any") { |
|
129 |
$_POST['source'] = "any"; |
|
130 |
$_POST['source_subnet'] = 24; |
|
131 |
} elseif ($_POST['source_type'] == "(self)") { |
|
132 |
$_POST['source'] = "(self)"; |
|
133 |
$_POST['source_subnet'] = 24; |
|
134 |
} |
|
135 |
|
|
136 |
unset($input_errors); |
|
137 |
$pconfig = $_POST; |
|
138 |
/* run through $_POST items encoding HTML entitles so that the user |
|
139 |
* cannot think he is slick and perform a XSS attack on the unwilling |
|
140 |
*/ |
|
141 |
foreach ($_POST as $key => $value) { |
|
142 |
if ($key == 'descr') { |
|
143 |
continue; |
|
144 |
} |
|
145 |
|
|
146 |
$temp = str_replace(">", "", $value); |
|
147 |
$newpost = htmlentities($temp); |
|
148 |
if ($newpost <> $temp) { |
|
149 |
$input_errors[] = sprintf(gettext("Invalid characters detected (%s). Please remove invalid characters and save again."), $temp); |
|
150 |
} |
|
151 |
} |
|
152 |
|
|
153 |
/* input validation */ |
|
154 |
$reqdfields = explode(" ", "interface protocol source source_subnet destination destination_subnet"); |
|
155 |
$reqdfieldsn = array(gettext("Interface"), gettext("Protocol"), gettext("Source"), gettext("Source bit count"), gettext("Destination"), gettext("Destination bit count")); |
|
156 |
|
|
157 |
do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); |
|
158 |
|
|
159 |
$protocol_uses_ports = in_array($_POST['protocol'], explode(" ", "any tcp udp tcp/udp")); |
|
160 |
|
|
161 |
if ($_POST['source']) { |
|
162 |
$_POST['source'] = trim($_POST['source']); |
|
163 |
} |
|
164 |
if ($_POST['destination']) { |
|
165 |
$_POST['destination'] = trim($_POST['destination']); |
|
166 |
} |
|
167 |
if ($_POST['targetip']) { |
|
168 |
$_POST['targetip'] = trim($_POST['targetip']); |
|
169 |
} |
|
170 |
if ($_POST['sourceport']) { |
|
171 |
$_POST['sourceport'] = trim($_POST['sourceport']); |
|
172 |
} |
|
173 |
if ($_POST['dstport']) { |
|
174 |
$_POST['dstport'] = trim($_POST['dstport']); |
|
175 |
} |
|
176 |
if ($_POST['natport']) { |
|
177 |
$_POST['natport'] = trim($_POST['natport']); |
|
178 |
} |
|
179 |
|
|
180 |
if (strlen($_POST['target']) > 0) { |
|
181 |
// Strip the target code 1-char code from the front before validating and saving. |
|
182 |
$_POST['target'] = substr($_POST['target'], 1); |
|
183 |
} |
|
184 |
|
|
185 |
if ($protocol_uses_ports && $_POST['sourceport'] <> "" && !is_port_or_range_or_alias($_POST['sourceport'])) { |
|
186 |
$input_errors[] = gettext("A valid port or port alias must be supplied for the source port entry."); |
|
187 |
} |
|
188 |
|
|
189 |
if ($protocol_uses_ports && $_POST['dstport'] <> "" && !is_port_or_range_or_alias($_POST['dstport'])) { |
|
190 |
$input_errors[] = gettext("A valid port or port alias must be supplied for the destination port entry."); |
|
191 |
} |
|
192 |
|
|
193 |
if ($protocol_uses_ports && $_POST['natport'] <> "" && !is_port_or_range_or_alias($_POST['natport']) && !isset($_POST['nonat'])) { |
|
194 |
$input_errors[] = gettext("A valid port must be supplied for the NAT port entry."); |
|
195 |
} |
|
196 |
|
|
197 |
if (($_POST['source_type'] != "any") && ($_POST['source_type'] != "(self)")) { |
|
198 |
if ($_POST['source'] && !is_ipaddroralias($_POST['source']) && $_POST['source'] != "any") { |
|
199 |
$input_errors[] = gettext("A valid source must be specified."); |
|
200 |
} |
|
201 |
} |
|
202 |
|
|
203 |
if ($_POST['source_subnet'] && !is_numericint($_POST['source_subnet'])) { |
|
204 |
$input_errors[] = gettext("A valid source bit count must be specified."); |
|
205 |
} |
|
62 |
$rv = saveoutNATrule($_POST, $id); |
|
206 | 63 |
|
207 |
if ($_POST['destination_type'] != "any") { |
|
208 |
if ($_POST['destination'] && !is_ipaddroralias($_POST['destination'])) { |
|
209 |
$input_errors[] = gettext("A valid destination must be specified."); |
|
210 |
} |
|
211 |
} |
|
212 |
|
|
213 |
if ($_POST['destination_subnet'] && !is_numericint($_POST['destination_subnet'])) { |
|
214 |
$input_errors[] = gettext("A valid destination bit count must be specified."); |
|
215 |
} |
|
216 |
|
|
217 |
if ($_POST['destination_type'] == "any") { |
|
218 |
if ($_POST['destination_not']) { |
|
219 |
$input_errors[] = gettext("Negating destination address of \"any\" is invalid."); |
|
220 |
} |
|
221 |
} |
|
222 |
|
|
223 |
if ($_POST['target'] && !is_ipaddr($_POST['target']) && !is_subnet($_POST['target']) && !is_alias($_POST['target']) && !isset($_POST['nonat']) && !($_POST['target'] == "other-subnet")) { |
|
224 |
$input_errors[] = gettext("A valid target IP address must be specified."); |
|
225 |
} |
|
226 |
|
|
227 |
if ($_POST['target'] == "other-subnet") { |
|
228 |
if (!is_ipaddr($_POST['targetip'])) { |
|
229 |
$input_errors[] = gettext("A valid target IP must be specified when using the 'Other Subnet' type."); |
|
230 |
} |
|
231 |
|
|
232 |
if (!is_numericint($_POST['targetip_subnet'])) { |
|
233 |
$input_errors[] = gettext("A valid target bit count must be specified when using the 'Other Subnet' type."); |
|
234 |
} |
|
235 |
} |
|
236 |
|
|
237 |
/* Verify Pool Options */ |
|
238 |
$poolopts = ""; |
|
239 |
$source_hash_key = ""; |
|
240 |
if ($_POST['poolopts']) { |
|
241 |
if (is_subnet($_POST['target']) || ($_POST['target'] == "other-subnet")) { |
|
242 |
$poolopts = $_POST['poolopts']; |
|
243 |
} elseif (is_alias($_POST['target'])) { |
|
244 |
if (substr($_POST['poolopts'], 0, 11) == "round-robin") { |
|
245 |
$poolopts = $_POST['poolopts']; |
|
246 |
} else { |
|
247 |
$input_errors[] = gettext("Only Round Robin pool options may be chosen when selecting an alias."); |
|
248 |
} |
|
249 |
} |
|
250 |
/* If specified, verify valid source-hash key or generate a valid key using md5 */ |
|
251 |
if ($_POST['source_hash_key']) { |
|
252 |
if (substr($_POST['source_hash_key'],0,2) == "0x") { |
|
253 |
if (ctype_xdigit(substr($_POST['source_hash_key'],2)) && strlen($_POST['source_hash_key']) == 34) { |
|
254 |
$source_hash_key = $_POST['source_hash_key']; |
|
255 |
} else { |
|
256 |
$input_errors[] = gettext("Incorrect format for source-hash key, \"0x\" must be followed by exactly 32 hexadecimal characters."); |
|
257 |
} |
|
258 |
} else { |
|
259 |
$source_hash_key = "0x".md5($_POST['source_hash_key']); |
|
260 |
} |
|
261 |
} |
|
262 |
} |
|
263 |
|
|
264 |
/* if user has selected any as source, set it here */ |
|
265 |
if ($_POST['source_type'] == "any") { |
|
266 |
$osn = "any"; |
|
267 |
} else if ($_POST['source_type'] == "(self)") { |
|
268 |
$osn = "(self)"; |
|
269 |
} else if (is_alias($_POST['source'])) { |
|
270 |
$osn = $_POST['source']; |
|
271 |
} else { |
|
272 |
$osn = gen_subnet($_POST['source'], $_POST['source_subnet']) . "/" . $_POST['source_subnet']; |
|
273 |
} |
|
274 |
|
|
275 |
/* check for existing entries */ |
|
276 |
if ($_POST['destination_type'] == "any") { |
|
277 |
$ext = "any"; |
|
278 |
} else if (is_alias($_POST['destination'])) { |
|
279 |
$ext = $_POST['destination']; |
|
280 |
} else { |
|
281 |
$ext = gen_subnet($_POST['destination'], $_POST['destination_subnet']) . "/" . $_POST['destination_subnet']; |
|
282 |
} |
|
283 |
|
|
284 |
foreach ($a_out as $natent) { |
|
285 |
if (isset($id) && ($a_out[$id]) && ($a_out[$id] === $natent)) { |
|
286 |
continue; |
|
287 |
} |
|
288 |
|
|
289 |
if (!$natent['interface']) { |
|
290 |
$natent['interface'] = "wan"; |
|
291 |
} |
|
292 |
} |
|
64 |
$input_errors = $rv['input_errors']; |
|
65 |
$pconfig = $rv['pconfig']; |
|
293 | 66 |
|
294 | 67 |
if (!$input_errors) { |
295 |
$natent = array(); |
|
296 |
$natent['source']['network'] = $osn; |
|
297 |
$natent['sourceport'] = ($protocol_uses_ports) ? $_POST['sourceport'] : ""; |
|
298 |
$natent['descr'] = $_POST['descr']; |
|
299 |
$natent['target'] = (!isset($_POST['nonat'])) ? $_POST['target'] : ""; |
|
300 |
$natent['targetip'] = (!isset($_POST['nonat'])) ? $_POST['targetip'] : ""; |
|
301 |
$natent['targetip_subnet'] = (!isset($_POST['nonat'])) ? $_POST['targetip_subnet'] : ""; |
|
302 |
$natent['interface'] = $_POST['interface']; |
|
303 |
$natent['poolopts'] = $poolopts; |
|
304 |
$natent['source_hash_key'] = $source_hash_key; |
|
305 |
|
|
306 |
/* static-port */ |
|
307 |
if (isset($_POST['staticnatport']) && $protocol_uses_ports && !isset($_POST['nonat'])) { |
|
308 |
$natent['staticnatport'] = true; |
|
309 |
} else { |
|
310 |
unset($natent['staticnatport']); |
|
311 |
} |
|
312 |
|
|
313 |
if (isset($_POST['disabled'])) { |
|
314 |
$natent['disabled'] = true; |
|
315 |
} else { |
|
316 |
unset($natent['disabled']); |
|
317 |
} |
|
318 |
|
|
319 |
/* if user has selected not nat, set it here */ |
|
320 |
if (isset($_POST['nonat'])) { |
|
321 |
$natent['nonat'] = true; |
|
322 |
} else { |
|
323 |
unset($natent['nonat']); |
|
324 |
} |
|
325 |
|
|
326 |
if ($_POST['ipprotocol'] && $_POST['ipprotocol'] != "inet46") { |
|
327 |
$natent['ipprotocol'] = $_POST['ipprotocol']; |
|
328 |
} else { |
|
329 |
unset($natent['ipprotocol']); |
|
330 |
} |
|
331 |
|
|
332 |
if ($_POST['protocol'] && $_POST['protocol'] != "any") { |
|
333 |
$natent['protocol'] = $_POST['protocol']; |
|
334 |
} else { |
|
335 |
unset($natent['protocol']); |
|
336 |
} |
|
337 |
|
|
338 |
if ($ext == "any") { |
|
339 |
$natent['destination']['any'] = true; |
|
340 |
} else { |
|
341 |
$natent['destination']['address'] = $ext; |
|
342 |
} |
|
343 |
if ($_POST['natport'] != "" && $protocol_uses_ports && !isset($_POST['nonat'])) { |
|
344 |
$natent['natport'] = $_POST['natport']; |
|
345 |
} else { |
|
346 |
unset($natent['natport']); |
|
347 |
} |
|
348 |
if ($_POST['dstport'] != "" && $protocol_uses_ports) { |
|
349 |
$natent['dstport'] = $_POST['dstport']; |
|
350 |
} else { |
|
351 |
unset($natent['dstport']); |
|
352 |
} |
|
353 |
|
|
354 |
if ($_POST['nosync'] == "yes") { |
|
355 |
$natent['nosync'] = true; |
|
356 |
} else { |
|
357 |
unset($natent['nosync']); |
|
358 |
} |
|
359 |
|
|
360 |
if (isset($_POST['destination_not']) && $ext != "any") { |
|
361 |
$natent['destination']['not'] = true; |
|
362 |
} |
|
363 |
|
|
364 |
if (isset($a_out[$id]['created']) && is_array($a_out[$id]['created'])) { |
|
365 |
$natent['created'] = $a_out[$id]['created']; |
|
366 |
} |
|
367 |
|
|
368 |
$natent['updated'] = make_config_revision_entry(); |
|
369 |
|
|
370 |
// Allow extending of the firewall edit page and include custom input validation |
|
371 |
pfSense_handle_custom_code("/usr/local/pkg/firewall_aon/pre_write_config"); |
|
372 |
|
|
373 |
if (isset($id) && $a_out[$id]) { |
|
374 |
$a_out[$id] = $natent; |
|
375 |
} else { |
|
376 |
$natent['created'] = make_config_revision_entry(); |
|
377 |
if (is_numeric($after)) { |
|
378 |
array_splice($a_out, $after+1, 0, array($natent)); |
|
379 |
} else { |
|
380 |
$a_out[] = $natent; |
|
381 |
} |
|
382 |
} |
|
383 |
|
|
384 |
if (write_config(gettext("Firewall: NAT: Outbound - saved/edited outbound NAT mapping."))) { |
|
385 |
mark_subsystem_dirty('natconf'); |
|
386 |
} |
|
387 | 68 |
header("Location: firewall_nat_out.php"); |
388 | 69 |
exit; |
389 | 70 |
} |
71 |
} else { |
|
72 |
$pconfig = getoutNATrule($id); |
|
390 | 73 |
} |
391 | 74 |
|
392 | 75 |
$pgtitle = array(gettext("Firewall"), gettext("NAT"), gettext("Outbound"), gettext("Edit")); |
393 | 76 |
$pglinks = array("", "firewall_nat.php", "firewall_nat_out.php", "@self"); |
394 | 77 |
include("head.inc"); |
395 | 78 |
|
396 |
function build_target_list() { |
|
397 |
global $config, $sn, $a_aliases; |
|
398 |
$list = array(); |
|
399 |
// Target list entries are made to start with the following characters: |
|
400 |
// "" (blank) - the interface address of the selected interface |
|
401 |
// S - a subnet |
|
402 |
// I - an ordinary IP address |
|
403 |
// H - a host alias |
|
404 |
// O - other subnet |
|
405 |
// The prefix letter makes it easy for the JavaScript to distinguish |
|
406 |
// the type of entry based on the first letter of the value. |
|
407 |
// The prefix letter is removed before saving in the config, |
|
408 |
// and added back when reading from the config. |
|
409 |
|
|
410 |
$list[""] = gettext('Interface Address'); |
|
411 |
|
|
412 |
//Temporary array so we can sort IPs |
|
413 |
$templist = array(); |
|
414 |
if (is_array($config['virtualip']['vip'])) { |
|
415 |
foreach ($config['virtualip']['vip'] as $sn) { |
|
416 |
if (($sn['mode'] == "proxyarp" || $sn['mode'] == "other") && $sn['type'] == "network") { |
|
417 |
$templist['S' . $sn['subnet'] . '/' . $sn['subnet_bits']] = gettext('Subnet: ') . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')'; |
|
418 |
if (isset($sn['noexpand'])) { |
|
419 |
continue; |
|
420 |
} |
|
421 |
$start = ip2long32(gen_subnet($sn['subnet'], $sn['subnet_bits'])); |
|
422 |
$end = ip2long32(gen_subnet_max($sn['subnet'], $sn['subnet_bits'])); |
|
423 |
$len = $end - $start; |
|
424 |
for ($i = 0; $i <= $len; $i++) { |
|
425 |
$snip = long2ip32($start+$i); |
|
426 |
|
|
427 |
$templist['I' . $snip] = $snip . ' (' . $sn['descr'] . ')'; |
|
428 |
} |
|
429 |
} else { |
|
430 |
$templist['I' . $sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')'; |
|
431 |
} |
|
432 |
} |
|
433 |
} |
|
434 |
asort($templist); |
|
435 |
//Append sorted IP array onto main array |
|
436 |
$list = array_merge($list, $templist); |
|
437 |
unset($templist); |
|
438 |
|
|
439 |
foreach ($a_aliases as $alias) { |
|
440 |
if ($alias['type'] != "host") { |
|
441 |
continue; |
|
442 |
} |
|
443 |
|
|
444 |
$list['H' . $alias['name']] = gettext('Host Alias: ') . $alias['name'] . ' (' . $alias['descr'] . ')'; |
|
445 |
} |
|
446 |
|
|
447 |
$list['Oother-subnet'] = gettext('Other Subnet (Enter Below)'); |
|
448 |
|
|
449 |
return($list); |
|
450 |
} |
|
451 |
|
|
452 | 79 |
if ($input_errors) { |
453 | 80 |
print_input_errors($input_errors); |
454 | 81 |
} |
Also available in: Unified diff
Refactor firewall_nat_out for MVC