Project

General

Profile

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

    
29
##|+PRIV
30
##|*IDENT=page-interfaces-assignnetworkports
31
##|*NAME=Interfaces: Interface Assignments
32
##|*DESCR=Allow access to the 'Interfaces: Interface Assignments' page.
33
##|*MATCH=interfaces_assign.php*
34
##|-PRIV
35

    
36
//$timealla = microtime(true);
37

    
38
$pgtitle = array(gettext("Interfaces"), gettext("Interface Assignments"));
39
$shortcut_section = "interfaces";
40

    
41
require_once("guiconfig.inc");
42
require_once("functions.inc");
43
require_once("filter.inc");
44
require_once("shaper.inc");
45
require_once("ipsec.inc");
46
require_once("vpn.inc");
47
require_once("openvpn.inc");
48
require_once("captiveportal.inc");
49
require_once("rrd.inc");
50
require_once("interfaces_fast.inc");
51

    
52
global $friendlyifnames;
53

    
54
/*moved most gettext calls to here, we really don't want to be repeatedly calling gettext() within loops if it can be avoided.*/
55
$gettextArray = array('add'=>gettext('Add'),'addif'=>gettext('Add interface'),'delete'=>gettext('Delete'),'deleteif'=>gettext('Delete interface'),'edit'=>gettext('Edit'),'on'=>gettext('on'));
56

    
57
/*
58
	In this file, "port" refers to the physical port name,
59
	while "interface" refers to LAN, WAN, or OPTn.
60
*/
61

    
62
/* get list without VLAN interfaces */
63
$portlist = get_interface_list();
64

    
65
/*another *_fast function from interfaces_fast.inc. These functions are basically the same as the
66
ones they're named after, except they (usually) take an array and (always) return an array. This means that they only
67
need to be called once per script run, the returned array contains all the data necessary for repeated use */
68
$friendlyifnames = convert_real_interface_to_friendly_interface_name_fast();
69

    
70
/* add wireless clone interfaces */
71
foreach (config_get_path('wireless/clone', []) as $clone) {
72
	$portlist[$clone['cloneif']] = $clone;
73
	$portlist[$clone['cloneif']]['iswlclone'] = true;
74
}
75

    
76
/* add VLAN interfaces */
77
//$timea = microtime(true);
78
foreach (config_get_path('vlans/vlan', []) as $vlan) {
79
	$portlist[$vlan['vlanif']] = $vlan;
80
	$portlist[$vlan['vlanif']]['isvlan'] = true;
81
}
82

    
83
/* add Bridge interfaces */
84
foreach (config_get_path('bridges/bridged', []) as $bridge) {
85
	$portlist[$bridge['bridgeif']] = $bridge;
86
	$portlist[$bridge['bridgeif']]['isbridge'] = true;
87
}
88

    
89
/* add GIF interfaces */
90
foreach (config_get_path('gifs/gif', []) as $gif) {
91
	$portlist[$gif['gifif']] = $gif;
92
	$portlist[$gif['gifif']]['isgif'] = true;
93
}
94

    
95
/* add GRE interfaces */
96
foreach (config_get_path('gres/gre', []) as $gre) {
97
	$portlist[$gre['greif']] = $gre;
98
	$portlist[$gre['greif']]['isgre'] = true;
99
}
100

    
101
/* add LAGG interfaces */
102
foreach (config_get_path('laggs/lagg', []) as $lagg) {
103
	$portlist[$lagg['laggif']] = $lagg;
104
	$portlist[$lagg['laggif']]['islagg'] = true;
105
	/* LAGG members cannot be assigned */
106
	$lagifs = explode(',', $lagg['members']);
107
	foreach ($lagifs as $lagif) {
108
		if (isset($portlist[$lagif])) {
109
			unset($portlist[$lagif]);
110
		}
111
	}
112
}
113

    
114
/* add QinQ interfaces */
115
foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
116
	$portlist["{$qinq['vlanif']}"]['descr'] = "VLAN {$qinq['tag']} on {$qinq['if']}";
117
	$portlist["{$qinq['vlanif']}"]['isqinq'] = true;
118
	/* QinQ members */
119
	$qinqifs = explode(' ', $qinq['members']);
120
	foreach ($qinqifs as $qinqif) {
121
		$portlist["{$qinq['vlanif']}.{$qinqif}"]['descr'] = "QinQ {$qinqif} on VLAN {$qinq['tag']} on {$qinq['if']}";
122
		$portlist["{$qinq['vlanif']}.{$qinqif}"]['isqinq'] = true;
123
	}
124
}
125

    
126
/* add PPP interfaces */
127
foreach (config_get_path('ppps/ppp', []) as $ppp) {
128
	$portname = $ppp['if'];
129
	$portlist[$portname] = $ppp;
130
	$portlist[$portname]['isppp'] = true;
131
	$ports_base = basename($ppp['ports']);
132
	if (isset($ppp['descr'])) {
133
		$portlist[$portname]['descr'] = strtoupper($ppp['if']). "({$ports_base}) - {$ppp['descr']}";
134
	} else if (isset($ppp['username'])) {
135
		$portlist[$portname]['descr'] = strtoupper($ppp['if']). "({$ports_base}) - {$ppp['username']}";
136
	} else {
137
		$portlist[$portname]['descr'] = strtoupper($ppp['if']). "({$ports_base})";
138
	}
139
}
140

    
141
$ovpn_descrs = array();
142
foreach (['server', 'client'] as $openvpn_mode) {
143
	foreach (config_get_path("openvpn/openvpn-{$openvpn_mode}", []) as $openvpn_settings) {
144
		$portname = openvpn_name($openvpn_mode, $openvpn_settings);
145
		$portlist[$portname] = $openvpn_settings;
146
		$ovpn_descrs[$openvpn_settings['vpnid']] = $openvpn_settings['description'];
147
	}
148
}
149

    
150
global $ipsec_descrs;
151
$ipsec_descrs = interface_ipsec_vti_list_all();
152
foreach ($ipsec_descrs as $ifname => $ifdescr) {
153
	$portlist[$ifname] = array('descr' => $ifdescr);
154
}
155

    
156

    
157
$ifdescrs = interface_assign_description_fast($portlist,$friendlyifnames);
158
if (isset($_REQUEST['add']) && isset($_REQUEST['if_add'])) {
159
	/* Be sure this port is not being used */
160
	$portused = false;
161
	foreach (config_get_path('interfaces', []) as $ifdata) {
162
		if ($ifdata['if'] == $_REQUEST['if_add']) {
163
			$portused = true;
164
			break;
165
		}
166
	}
167

    
168
	if ($portused === false) {
169
		/* find next free optional interface number */
170
		if (!config_get_path('interfaces/lan')) {
171
			$newifname = "lan";
172
			$descr = "LAN";
173
		} else {
174
			$interface_count = count(config_get_path('interfaces', []));
175
			for ($i = 1; $i <= $interface_count; $i++) {
176
				if (!config_get_path("interfaces/opt{$i}")) {
177
					break;
178
				}
179
			}
180
			$newifname = 'opt' . $i;
181
			$descr = "OPT" . $i;
182
		}
183

    
184
		config_set_path("interfaces/{$newifname}", [
185
			'descr' => $descr,
186
			'if' => $_POST['if_add']
187
		]);
188
		if (preg_match(g_get('wireless_regex'), $_POST['if_add'])) {
189
			config_set_path("interfaces/{$newifname}/wireless", []);
190
			$new_if_config = config_get_path("interfaces/{$newifname}");
191
			interface_sync_wireless_clones($new_if_config, false);
192
			config_set_path("interfaces/{$newifname}", $new_if_config);
193
		}
194

    
195

    
196
		$if_config = config_get_path('interfaces');
197
		uksort($if_config, "compare_interface_friendly_names");
198
		config_set_path('interfaces', $if_config);
199

    
200
		/* XXX: Do not remove this. */
201
		unlink_if_exists("{$g['tmp_path']}/config.cache");
202

    
203
		write_config("New interface assigned");
204

    
205
		filter_configure();
206

    
207
		$action_msg = gettext("Interface has been added.");
208
		$class = "success";
209
	}
210

    
211
} else if (isset($_POST['apply'])) {
212
	if (file_exists("/var/run/interface_mismatch_reboot_needed")) {
213
		system_reboot();
214
		$rebootingnow = true;
215
	} else {
216
		write_config("Interfaces assignment settings changed");
217

    
218
		$changes_applied = true;
219
		$retval = 0;
220
		$retval |= filter_configure();
221
	}
222

    
223
} else if (isset($_POST['Submit'])) {
224

    
225
	unset($input_errors);
226

    
227
	/* input validation */
228

    
229
	/* Build a list of the port names so we can see how the interfaces map */
230
	$portifmap = array();
231
	foreach ($portlist as $portname => $portinfo) {
232
		$portifmap[$portname] = array();
233
	}
234

    
235
	/* Go through the list of ports selected by the user,
236
	build a list of port-to-interface mappings in portifmap */
237
	foreach ($_POST as $ifname => $ifport) {
238
		if (($ifname == 'lan') || ($ifname == 'wan') || (substr($ifname, 0, 3) == 'opt')) {
239
			if (array_key_exists($ifport, $portlist)) {
240
				$portifmap[$ifport][] = strtoupper($ifname);
241
			} else {
242
				$input_errors[] = sprintf(gettext('Cannot set port %1$s because the submitted interface does not exist.'), $ifname);
243
			}
244
		}
245
	}
246

    
247
	/* Deliver error message for any port with more than one assignment */
248
	foreach ($portifmap as $portname => $ifnames) {
249
		if (count($ifnames) > 1) {
250
			$errstr = sprintf(gettext('Port %1$s '.
251
				' was assigned to %2$s' .
252
				' interfaces:'), $portname, count($ifnames));
253

    
254
			foreach ($portifmap[$portname] as $ifn) {
255
				$errstr .= " " . convert_friendly_interface_to_friendly_descr(strtolower($ifn)) . " (" . $ifn . ")";
256
			}
257

    
258
			$input_errors[] = $errstr;
259
		} else if (count($ifnames) == 1 && preg_match('/^bridge[0-9]/', $portname)) {
260
			foreach (config_get_path('bridges/bridged', []) as $bridge) {
261
				if ($bridge['bridgeif'] != $portname) {
262
					continue;
263
				}
264

    
265
				$members = explode(",", strtoupper($bridge['members']));
266
				foreach ($members as $member) {
267
					if ($member == $ifnames[0]) {
268
						$input_errors[] = sprintf(gettext('Cannot set port %1$s to interface %2$s because this interface is a member of %3$s.'), $portname, $member, $portname);
269
						break;
270
					}
271
				}
272
			}
273
		}
274
	}
275

    
276
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
277
		if (does_interface_exist($vlan['if']) == false) {
278
			$input_errors[] = sprintf(gettext('Vlan parent interface %1$s does not exist anymore so vlan id %2$s cannot be created please fix the issue before continuing.'), $vlan['if'], $vlan['tag']);
279
		}
280
	}
281

    
282
	if (!$input_errors) {
283
		/* No errors detected, so update the config */
284
		$filter_reload = false;
285
		foreach ($_POST as $ifname => $ifport) {
286

    
287
			if (($ifname == 'lan') || ($ifname == 'wan') || (substr($ifname, 0, 3) == 'opt')) {
288

    
289
				if (!is_array($ifport)) {
290
					$reloadif = false;
291
					if (!empty(config_get_path("interfaces/{$ifname}/if")) && config_get_path("interfaces/{$ifname}/if") <> $ifport) {
292
						interface_bring_down($ifname);
293
						/* Mark this to be reconfigured in any case. */
294
						$reloadif = true;
295
						$filter_reload = true;
296
						$gateway_monitor_reload = true;
297
					}
298
					$this_if_config = config_get_path("interfaces/{$ifname}");
299
					$this_if_config['if'] = $ifport;
300
					if (isset($portlist[$ifport]['isppp'])) {
301
						$this_if_config['ipaddr'] = $portlist[$ifport]['type'];
302
					}
303

    
304
					if ((substr($ifport, 0, 3) == 'gre') ||
305
					    (substr($ifport, 0, 5) == 'gif')) {
306
						unset($this_if_config['ipaddr']);
307
						unset($this_if_config['subnet']);
308
						unset($this_if_config['ipaddrv6']);
309
						unset($this_if_config['subnetv6']);
310
					}
311

    
312
					/* check for wireless interfaces, set or clear ['wireless'] */
313
					if (preg_match(g_get('wireless_regex'), $ifport)) {
314
						if (!is_array($this_if_config['wireless'])) {
315
							$this_if_config['wireless'] = array();
316
						}
317
					} else {
318
						unset($this_if_config['wireless']);
319
					}
320

    
321
					/* make sure there is a descr for all interfaces */
322
					if (!isset($this_if_config['descr'])) {
323
						$this_if_config['descr'] = strtoupper($ifname);
324
					}
325
					config_set_path("interfaces/{$ifname}", $this_if_config);
326

    
327
					if ($reloadif == true) {
328
						if (preg_match(g_get('wireless_regex'), $ifport)) {
329
							interface_sync_wireless_clones($this_if_config, false);
330
							config_set_path("interfaces/{$ifname}", $this_if_config);
331
						}
332
						/* Reload all for the interface. */
333
						interface_configure($ifname, true);
334
						$filter_reload = true;
335
					}
336
				}
337
			}
338
		}
339
		/* regenerated ruleset after re-assigning the interface,
340
		 * see https://redmine.pfsense.org/issues/12949 */
341
		if ($filter_reload) {
342
			filter_configure();
343
		}
344
		if ($gateway_monitor_reload) {
345
			setup_gateways_monitor();
346
		}
347
		write_config("Interfaces assignment settings changed");
348

    
349
		enable_rrd_graphing();
350
	}
351
} else {
352
	unset($delbtn);
353
	if (!empty($_POST['del'])) {
354
		$delbtn = key($_POST['del']);
355
	}
356

    
357
	if (isset($delbtn)) {
358
		$id = $delbtn;
359

    
360
		if (link_interface_to_group($id)) {
361
			$input_errors[] = gettext("The interface is part of a group. Please remove it from the group to continue");
362
		} else if (link_interface_to_bridge($id)) {
363
			$input_errors[] = gettext("The interface is part of a bridge. Please remove it from the bridge to continue");
364
		} else if (!empty(link_interface_to_tunnelif($id, 'gre'))) {
365
			$input_errors[] = gettext("The interface is part of a gre tunnel. Please delete the tunnel to continue");
366
		} else if (!empty(link_interface_to_tunnelif($id, 'gif'))) {
367
			$input_errors[] = gettext("The interface is part of a gif tunnel. Please delete the tunnel to continue");
368
		} else if (interface_has_queue($id)) {
369
			$input_errors[] = gettext("The interface has a traffic shaper queue configured.\nPlease remove all queues on the interface to continue.");
370
		} else {
371
			config_del_path("interfaces/{$id}/enable");
372
			$realid = get_real_interface($id);
373
			interface_bring_down($id);
374
			config_del_path("interfaces/{$id}");	/* delete the specified OPTn or LAN*/
375

    
376
			if (is_array(config_get_path("dhcpd/{$id}"))) {
377
				config_del_path("dhcpd/{$id}");
378
				services_dhcpd_configure('inet');
379
			}
380

    
381
			if (is_array(config_get_path("dhcpdv6/{$id}"))) {
382
				config_del_path("dhcpdv6/{$id}");
383
				services_dhcpd_configure('inet6');
384
			}
385

    
386
			config_init_path('filter/rule');
387

    
388
			foreach (config_get_path('filter/rule', []) as $x => $rule) {
389
				if ($rule['interface'] == $id) {
390
					config_del_path("filter/rule/{$x}");
391
				}
392
			}
393

    
394
			config_init_path('nat/rule');
395
		
396
			foreach (config_get_path('nat/rule', []) as $x => $rule) {
397
				if ($rule['interface'] == $id) {
398
					config_del_path("nat/rule/{$x}/interface");
399
				}
400
			}
401

    
402
			write_config(gettext('Interface assignment deleted'));
403

    
404
			/* If we are in firewall/routing mode (not single interface)
405
			 * then ensure that we are not running DHCP on the wan which
406
			 * will make a lot of ISPs unhappy.
407
			 */
408
			if (config_path_enabled('interfaces', 'lan')
409
				&& config_path_enabled('dhcpd', 'wan')) {
410
					config_del_path('dhcpd/wan');
411
			}
412

    
413
			link_interface_to_vlans($realid, "update");
414

    
415
			filter_configure();
416

    
417
			$action_msg = gettext("Interface has been deleted.");
418
			$class = "success";
419
		}
420
	}
421
}
422

    
423
/* Create a list of unused ports */
424
$unused_portlist = array();
425
$portArray = array_keys($portlist);
426

    
427
$ifaceArray = array_column(config_get_path('interfaces'),'if');
428
$unused = array_diff($portArray,$ifaceArray);
429
$unused = array_flip($unused);
430
$unused_portlist = array_intersect_key($portlist,$unused);//*/
431
unset($unused,$portArray,$ifaceArray);
432

    
433
include("head.inc");
434

    
435
if (file_exists("/var/run/interface_mismatch_reboot_needed")) {
436
	if ($_POST) {
437
		if ($rebootingnow) {
438
			$action_msg = gettext("The system is now rebooting. Please wait.");
439
			$class = "success";
440
		} else {
441
			$applymsg = gettext("Reboot is needed. Please apply the settings in order to reboot.");
442
			$class = "warning";
443
		}
444
	} else {
445
		$action_msg = gettext("Interface mismatch detected. Please resolve the mismatch, save and then click 'Apply Changes'. The firewall will reboot afterwards.");
446
		$class = "warning";
447
	}
448
}
449

    
450
if (file_exists("/tmp/reload_interfaces")) {
451
	echo "<p>\n";
452
	print_apply_box(gettext("The interface configuration has been changed.") . "<br />" . gettext("The changes must be applied for them to take effect."));
453
	echo "<br /></p>\n";
454
} elseif ($applymsg) {
455
	print_apply_box($applymsg);
456
} elseif ($action_msg) {
457
	print_info_box($action_msg, $class);
458
} elseif ($changes_applied) {
459
	print_apply_result_box($retval);
460
}
461

    
462
pfSense_handle_custom_code("/usr/local/pkg/interfaces_assign/pre_input_errors");
463

    
464
if ($input_errors) {
465
	print_input_errors($input_errors);
466
}
467

    
468
$tab_array = array();
469
$tab_array[] = array(gettext("Interface Assignments"), true, "interfaces_assign.php");
470
$tab_array[] = array(gettext("Interface Groups"), false, "interfaces_groups.php");
471
$tab_array[] = array(gettext("Wireless"), false, "interfaces_wireless.php");
472
$tab_array[] = array(gettext("VLANs"), false, "interfaces_vlan.php");
473
$tab_array[] = array(gettext("QinQs"), false, "interfaces_qinq.php");
474
$tab_array[] = array(gettext("PPPs"), false, "interfaces_ppps.php");
475
$tab_array[] = array(gettext("GREs"), false, "interfaces_gre.php");
476
$tab_array[] = array(gettext("GIFs"), false, "interfaces_gif.php");
477
$tab_array[] = array(gettext("Bridges"), false, "interfaces_bridge.php");
478
$tab_array[] = array(gettext("LAGGs"), false, "interfaces_lagg.php");
479
display_top_tabs($tab_array);
480

    
481
/*Generate the port select box only once.
482
Not indenting the HTML to produce smaller code
483
and faster page load times */
484

    
485
$portselect='';
486
foreach ($portlist as $portname => $portinfo) {
487
	$portselect.='<option value="'.$portname.'"';
488
	$portselect.=">".$ifdescrs[$portname]."</option>\n";
489
}
490

    
491
?>
492
<form action="interfaces_assign.php" method="post">
493
	<div class="table-responsive">
494
	<table class="table table-striped table-hover">
495
	<thead>
496
		<tr>
497
			<th><?=gettext("Interface")?></th>
498
			<th><?=gettext("Network port")?></th>
499
			<th>&nbsp;</th>
500
		</tr>
501
	</thead>
502
	<tbody>
503
<?php
504
	$i=0;
505
	foreach (config_get_path('interfaces', []) as $ifname => $iface):
506
		if ($iface['descr']) {
507
			$ifdescr = $iface['descr'];
508
		} else {
509
			$ifdescr = strtoupper($ifname);
510
		}
511
?>
512
		<tr>
513
			<td><a href="/interfaces.php?if=<?=$ifname?>"><?=$ifdescr?></a></td>
514
			<td>
515
				<select name="<?=$ifname?>" id="<?=$ifname?>" class="form-control">
516
<?php
517
/*port select menu generation loop replaced with pre-prepared select menu to reduce page generation time */
518
echo str_replace('value="'.$iface['if'].'">','value="'.$iface['if'].'" selected>',$portselect);
519
?>
520
				</select>
521
			</td>
522
			<td>
523
<?php if ($ifname != 'wan'):?>
524
				<button type="submit" name="del[<?=$ifname?>]" class="btn btn-danger btn-sm" title="<?=$gettextArray['deleteif']?>">
525
					<i class="fa-solid fa-trash-can icon-embed-btn"></i>
526
					<?=$gettextArray["delete"]?>
527
				</button>
528
<?php endif;?>
529
			</td>
530
		</tr>
531
<?php $i++;
532
endforeach;
533
	if (count(config_get_path('interfaces', [])) < count($portlist)):
534
?>
535
		<tr>
536
			<th>
537
				<?=gettext("Available network ports:")?>
538
			</th>
539
			<td>
540
				<select name="if_add" id="if_add" class="form-control">
541
<?php
542
/* HTML not indented to save on transmission/render time */
543
foreach ($unused_portlist as $portname => $portinfo):?>
544
<option value="<?=$portname?>" <?=($portname == $iface['if']) ? ' selected': ''?>><?=$ifdescrs[$portname]?></option>
545
<?php endforeach;
546
?>
547
				</select>
548
			</td>
549
			<td>
550
				<button type="submit" name="add" title="<?=gettext("Add selected interface")?>" value="add interface" class="btn btn-success btn-sm" >
551
					<i class="fa-solid fa-plus icon-embed-btn"></i>
552
					<?=$gettextArray["add"]?>
553
				</button>
554
			</td>
555
		</tr>
556
<?php endif;?>
557
		</tbody>
558
	</table>
559
	</div>
560

    
561
	<button name="Submit" type="submit" class="btn btn-primary" value="<?=gettext('Save')?>"><i class="fa-solid fa-save icon-embed-btn"></i><?=gettext('Save')?></button>
562
</form>
563
<br />
564

    
565
<?php
566
print_info_box(gettext("Interfaces that are configured as members of a lagg(4) interface will not be shown.") .
567
    '<br/><br/>' .
568
    gettext("Wireless interfaces must be created on the Wireless tab before they can be assigned."), 'info', false);
569
?>
570

    
571
<?php include("foot.inc")?>
(74-74/232)