]>
git.ipfire.org Git - ipfire-2.x.git/blob - html/cgi-bin/zoneconf.cgi
2 ###############################################################################
4 # VLAN Management for IPFire #
5 # Copyright (C) 2019 Florian Bührle <fbuehrle@ipfire.org> #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
23 use Scalar
:: Util
qw(looks_like_number) ;
25 require '/var/ipfire/general-functions.pl' ;
26 require "${General::swroot}/lang.pl" ;
27 require "${General::swroot}/header.pl" ;
33 border-collapse: collapse;
53 border: 0.5px solid black;
57 background-color: #F0F0F0;
61 background-color: grey;
67 background-color: $Header ::colourgreen;
71 background-color: $Header ::colourred;
75 background-color: $Header ::colourblue;
79 background-color: $Header ::colourorange;
83 background-color: white;
84 border-top-style: none;
85 border-left-style: none;
89 background-color: #cccccc;
103 #submit-container.input {
114 my %ethsettings = ();
115 my %vlansettings = ();
118 my $restart_notice = "" ;
120 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
121 & General
:: readhash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
123 & Header
:: getcgihash
( \
%cgiparams );
124 & Header
:: showhttpheaders
();
126 # Define all zones we will check for NIC assignment
127 my @zones = ( "green" , "red" , "orange" , "blue" );
129 # Get all physical NICs present
130 opendir ( my $dh , "/sys/class/net/" );
133 while ( my $nic = readdir ( $dh )) {
134 if (- e
"/sys/class/net/ $nic /device" ) { # Indicates that the NIC is physical
135 push ( @nics , [& Network
:: get_nic_property
( $nic , "address" ), $nic , 0 ]);
141 @nics = sort { $a ->[ 0 ] cmp $b ->[ 0 ]} @nics ; # Sort nics by their MAC address
143 # Name the physical NICs
144 # Even though they may not be really named like this, we will name them ethX or wlanX
151 if (- e
"/sys/class/net/ $nic /wireless" ) {
152 $_ ->[ 1 ] = "wlan $wlancount " ;
156 $_ ->[ 1 ] = "eth $ethcount " ;
161 & Header
:: openpage
( $Lang :: tr
{ "zoneconf title" }, 1 , $css );
162 & Header
:: openbigbox
( '100%' , 'center' );
164 ### Evaluate POST parameters ###
166 if ( $cgiparams { "ACTION" } eq $Lang :: tr
{ "save" }) {
167 my %VALIDATE_nic_check = ();
168 my $VALIDATE_error = "" ;
172 my $slave_string = "" ;
173 my $zone_mode = $cgiparams { "MODE $uc " };
174 my $VALIDATE_vlancount = 0 ;
175 my $VALIDATE_zoneslaves = 0 ;
177 $ethsettings { "${uc}_MACADDR" } = "" ;
178 $ethsettings { "${uc}_MODE" } = "" ;
179 $ethsettings { "${uc}_SLAVES" } = "" ;
180 $vlansettings { "${uc}_PARENT_DEV" } = "" ;
181 $vlansettings { "${uc}_VLAN_ID" } = "" ;
182 $vlansettings { "${uc}_MAC_ADDRESS" } = "" ;
184 # If RED is not in DHCP or static mode, we only set its MACADDR property
185 if ( $uc eq "RED" && ! $cgiparams { "PPPACCESS" } eq "" ) {
189 if ( $mac eq $cgiparams { "PPPACCESS" }) {
190 $ethsettings { "${uc}_MACADDR" } = $mac ;
192 # Check if this interface is already accessed by any other zone
193 # If this is the case, show an error message
194 if ( $VALIDATE_nic_check { "ACC $mac " }) {
195 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
198 $VALIDATE_nic_check { "RESTRICT $mac " } = 1 ;
208 my $nic_access = $cgiparams { "ACCESS $uc $mac " };
210 if ( $nic_access ne "NONE" ) {
211 if ( $VALIDATE_nic_check { "RESTRICT $mac " }) { # If this interface is already assigned to RED in PPP mode, throw an error
212 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
216 if ( $zone_mode ne "BRIDGE" && $VALIDATE_zoneslaves > 0 && $nic_access ne "" ) {
217 $VALIDATE_error = $Lang :: tr
{ "zoneconf val zoneslave amount error" };
221 $VALIDATE_nic_check { "ACC $mac " } = 1 ;
222 $VALIDATE_zoneslaves ++;
225 if ( $nic_access eq "NATIVE" ) {
226 if ( $VALIDATE_nic_check { "NATIVE $mac " }) {
227 $VALIDATE_error = $Lang :: tr
{ "zoneconf val native assignment error" };
231 $VALIDATE_nic_check { "NATIVE $mac " } = 1 ;
233 if ( $zone_mode eq "BRIDGE" ) {
234 $slave_string = "${slave_string}${mac} " ;
236 $ethsettings { "${uc}_MACADDR" } = $mac ;
238 } elsif ( $nic_access eq "VLAN" ) {
239 my $vlan_tag = $cgiparams { "TAG $uc $mac " };
241 if ( $VALIDATE_nic_check { "VLAN $mac $vlan_tag " }) {
242 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan tag assignment error" };
246 $VALIDATE_nic_check { "VLAN $mac $vlan_tag " } = 1 ;
248 if (! looks_like_number
( $vlan_tag )) {
251 if ( $vlan_tag < 1 || $vlan_tag > 4095 ) {
255 my $rnd_mac = & Network
:: random_mac
();
257 $vlansettings { "${uc}_PARENT_DEV" } = $mac ;
258 $vlansettings { "${uc}_VLAN_ID" } = $vlan_tag ;
259 $vlansettings { "${uc}_MAC_ADDRESS" } = $rnd_mac ;
261 if ( $zone_mode eq "BRIDGE" ) {
262 $slave_string = "${slave_string}${rnd_mac} " ;
265 $VALIDATE_vlancount ++; # We can't allow more than one VLAN per zone
269 if ( $VALIDATE_vlancount > 1 ) {
270 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan amount assignment error" };
276 if ( $zone_mode eq "BRIDGE" ) {
277 $ethsettings { "${uc}_MODE" } = "bridge" ;
278 $ethsettings { "${uc}_SLAVES" } = $slave_string ;
279 } elsif ( $zone_mode eq "MACVTAP" ) {
280 $ethsettings { "${uc}_MODE" } = "macvtap" ;
284 if ( $VALIDATE_error ) {
285 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "error" });
287 print " $VALIDATE_error <br><a href='/cgi-bin/zoneconf.cgi'><button> $Lang ::tr{'ok'}</button></a>" ;
290 & Header
:: closebigbox
();
291 & Header
:: closepage
();
296 & General
:: writehash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
297 & General
:: writehash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
299 $restart_notice = $Lang :: tr
{ 'zoneconf notice reboot' };
302 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "zoneconf nic assignment" });
304 ### START OF TABLE ###
307 <form method='post' enctype='multipart/form-data'>
310 <td class="h narrow topleft" /td>
314 # Fill the table header with all activated zones
317 my $dev_name = $ethsettings { "${uc}_DEV" };
319 if ( $dev_name eq "" ) { # If the zone is not activated, don't show it
323 # If the zone is in PPP mode, don't show a mode dropdown
325 my $red_type = $ethsettings { "RED_TYPE" };
326 my $red_restricted = ( $uc eq "RED" && ! ( $red_type eq "STATIC" || $red_type eq "DHCP" ));
328 if ( $red_restricted ) {
329 print "<td class='h textcenter $_ '> $uc ( $red_type )</td>" ;
331 next ; # We're done here
335 my %mode_selected = ();
336 my $zone_mode = $ethsettings { "${uc}_MODE" };
338 if ( $zone_mode eq "" ) {
339 $mode_selected { "DEFAULT" } = "selected" ;
340 } elsif ( $zone_mode eq "bridge" ) {
341 $mode_selected { "BRIDGE" } = "selected" ;
342 } elsif ( $zone_mode eq "macvtap" ) {
343 $mode_selected { "MACVTAP" } = "selected" ;
347 <td class='h textcenter $_ '> $uc </br>
348 <select name="MODE $uc ">
349 <option value="DEFAULT" $mode_selected {"DEFAULT"}> $Lang ::tr{"zoneconf nicmode default"}</option>
350 <option value="BRIDGE" $mode_selected {"BRIDGE"}> $Lang ::tr{"zoneconf nicmode bridge"}</option>
351 <option value="MACVTAP" $mode_selected {"MACVTAP"}> $Lang ::tr{"zoneconf nicmode macvtap"}</option>
360 my $slightlygrey = "" ;
367 print "<tr><td class='h narrow textcenter'> $nic <br> $mac </td>" ;
369 # Iterate through all zones and check if the current NIC is assigned to it
372 my $dev_name = $ethsettings { "${uc}_DEV" };
374 if ( $dev_name eq "" ) { # Again, skip the zone if it is not activated
379 my $red_type = $ethsettings { "RED_TYPE" };
380 my $red_restricted = ( $uc eq "RED" && ! ( $red_type eq "STATIC" || $red_type eq "DHCP" ));
382 # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ...
383 if ( $red_restricted ) {
386 if ( $mac eq $ethsettings { "${uc}_MACADDR" }) {
387 $checked = "checked" ;
390 print "<td class='textcenter $slightlygrey '><input type='radio' id='PPPACCESS $mac ' name='PPPACCESS' value=' $mac ' $checked ></td>" ;
391 next ; # We're done here
395 my %access_selected = ();
396 my $zone_mode = $ethsettings { "${uc}_MODE" };
397 my $zone_parent_dev = $vlansettings { "${uc}_PARENT_DEV" }; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN
398 my $field_disabled = "disabled" ; # Only enable the VLAN ID input field if the current access mode is VLAN
399 my $zone_vlan_id = "" ;
401 # If ZONE_PARENT_DEV is set to a NICs name (e.g. green0 or eth0) instead of a MAC address, we have to find out this NICs MAC address
402 $zone_parent_dev = & Network
:: get_mac_by_name
( $zone_parent_dev );
404 # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC
405 if ( $mac eq $zone_parent_dev ) {
406 $access_selected { "VLAN" } = "selected" ;
407 $field_disabled = "" ;
408 $zone_vlan_id = $vlansettings { "${uc}_VLAN_ID" };
409 } elsif ( $zone_mode eq "bridge" ) { # If the current zone is in bridge mode, all corresponding NICs (Native as well as VLAN) are set via the ZONE_SLAVES option
410 my @slaves = split ( / / , $ethsettings { "${uc}_SLAVES" });
413 # Slaves can be set to a NICs name so we have to find out its MAC address
414 $_ = & Network
:: get_mac_by_name
( $_ );
417 $access_selected { "NATIVE" } = "selected" ;
421 } elsif ( $mac eq $ethsettings { "${uc}_MACADDR" }) { # Native access via ZONE_MACADDR is only set if the zone does not access a NIC via a VLAN and the zone is not in bridge mode
422 $access_selected { "NATIVE" } = "selected" ;
425 $access_selected { "NONE" } = ( $access_selected { "NATIVE" } eq "" ) && ( $access_selected { "VLAN" } eq "" ) ?
"selected" : "" ;
426 my $vlan_disabled = ( $wlan ) ?
"disabled" : "" ;
429 <td class="textcenter $slightlygrey ">
430 <select name="ACCESS $uc $mac " onchange="document.getElementById('TAG $uc $mac ').disabled = (this.value === 'VLAN' ? false : true)">
431 <option value="NONE" $access_selected {"NONE"}>- $Lang ::tr{"zoneconf access none"} -</option>
432 <option value="NATIVE" $access_selected {"NATIVE"}> $Lang ::tr{"zoneconf access native"}</option>
433 <option value="VLAN" $access_selected {"VLAN"} $vlan_disabled > $Lang ::tr{"zoneconf access vlan"}</option>
435 <input type="number" id="TAG $uc $mac " name="TAG $uc $mac " min="1" max="4095" value=" $zone_vlan_id " $field_disabled >
446 $slightlygrey = "slightlygrey" ;
453 <div id="submit-container">
455 <input type="submit" name="ACTION" value=" $Lang ::tr{"save"}">
464 & Header
:: closebigbox
();
465 & Header
:: closepage
();