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
		write_config("New interface assigned");
201

    
202
		filter_configure();
203

    
204
		$action_msg = gettext("Interface has been added.");
205
		$class = "success";
206
	}
207

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

    
215
		$changes_applied = true;
216
		$retval = 0;
217
		$retval |= filter_configure();
218
	}
219

    
220
} else if (isset($_POST['Submit'])) {
221

    
222
	unset($input_errors);
223

    
224
	/* input validation */
225

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

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

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

    
251
			foreach ($portifmap[$portname] as $ifn) {
252
				$errstr .= " " . convert_friendly_interface_to_friendly_descr(strtolower($ifn)) . " (" . $ifn . ")";
253
			}
254

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

    
262
				$members = explode(",", strtoupper($bridge['members']));
263
				foreach ($members as $member) {
264
					if ($member == $ifnames[0]) {
265
						$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);
266
						break;
267
					}
268
				}
269
			}
270
		}
271
	}
272

    
273
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
274
		if (does_interface_exist($vlan['if']) == false) {
275
			$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']);
276
		}
277
	}
278

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

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

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

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

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

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

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

    
346
		enable_rrd_graphing();
347
	}
348
} else {
349
	unset($delbtn);
350
	if (!empty($_POST['del']) && is_string(key($_POST['del']))) {
351
		$delbtn = key($_POST['del']);
352
	}
353

    
354
	if (isset($delbtn)) {
355
		$id = $delbtn;
356

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

    
373
			if (is_array(config_get_path("dhcpd/{$id}"))) {
374
				config_del_path("dhcpd/{$id}");
375
				services_dhcpd_configure('inet');
376
			}
377

    
378
			if (is_array(config_get_path("dhcpdv6/{$id}"))) {
379
				config_del_path("dhcpdv6/{$id}");
380
				services_dhcpd_configure('inet6');
381
			}
382

    
383
			config_init_path('filter/rule');
384

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

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

    
399
			write_config(gettext('Interface assignment deleted'));
400

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

    
410
			link_interface_to_vlans($realid, "update");
411

    
412
			filter_configure();
413

    
414
			$action_msg = gettext("Interface has been deleted.");
415
			$class = "success";
416
		}
417
	}
418
}
419

    
420
/* Create a list of unused ports */
421
$unused_portlist = array();
422
$portArray = array_keys($portlist);
423

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

    
430
include("head.inc");
431

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

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

    
459
pfSense_handle_custom_code("/usr/local/pkg/interfaces_assign/pre_input_errors");
460

    
461
if ($input_errors) {
462
	print_input_errors($input_errors);
463
}
464

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

    
478
/*Generate the port select box only once.
479
Not indenting the HTML to produce smaller code
480
and faster page load times */
481

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

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

    
558
	<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>
559
</form>
560
<br />
561

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

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