]>
git.ipfire.org Git - people/pmueller/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;
107 #submit-container.input {
118 my %ethsettings = ();
119 my %vlansettings = ();
122 my $restart_notice = "" ;
124 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
125 & General
:: readhash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
127 & Header
:: getcgihash
( \
%cgiparams );
128 & Header
:: showhttpheaders
();
130 # Define all zones we will check for NIC assignment
131 my @zones = ( "green" , "red" , "orange" , "blue" );
133 # Get all physical NICs present
134 opendir ( my $dh , "/sys/class/net/" );
137 while ( my $nic = readdir ( $dh )) {
138 if (- e
"/sys/class/net/ $nic /device" ) { # Indicates that the NIC is physical
139 push ( @nics , [& Network
:: get_nic_property
( $nic , "address" ), $nic , 0 ]);
145 @nics = sort { $a ->[ 0 ] cmp $b ->[ 0 ]} @nics ; # Sort nics by their MAC address
147 # Name the physical NICs
148 # Even though they may not be really named like this, we will name them ethX or wlanX
155 if (- e
"/sys/class/net/ $nic /wireless" ) {
156 $_ ->[ 1 ] = "wlan $wlancount " ;
160 $_ ->[ 1 ] = "eth $ethcount " ;
165 & Header
:: openpage
( $Lang :: tr
{ "zoneconf title" }, 1 , $css );
166 & Header
:: openbigbox
( '100%' , 'center' );
168 ### Evaluate POST parameters ###
170 if ( $cgiparams { "ACTION" } eq $Lang :: tr
{ "save" }) {
171 my %VALIDATE_nic_check = ();
172 my $VALIDATE_error = "" ;
176 my $slave_string = "" ;
177 my $zone_mode = $cgiparams { "MODE $uc " };
178 my $VALIDATE_vlancount = 0 ;
179 my $VALIDATE_zoneslaves = 0 ;
181 $ethsettings { "${uc}_MACADDR" } = "" ;
182 $ethsettings { "${uc}_MODE" } = "" ;
183 $ethsettings { "${uc}_SLAVES" } = "" ;
184 $vlansettings { "${uc}_PARENT_DEV" } = "" ;
185 $vlansettings { "${uc}_VLAN_ID" } = "" ;
186 $vlansettings { "${uc}_MAC_ADDRESS" } = "" ;
188 # If RED is not in DHCP or static mode, we only set its MACADDR property
189 if ( $uc eq "RED" && ! $cgiparams { "PPPACCESS" } eq "" ) {
193 if ( $mac eq $cgiparams { "PPPACCESS" }) {
194 $ethsettings { "${uc}_MACADDR" } = $mac ;
196 # Check if this interface is already accessed by any other zone
197 # If this is the case, show an error message
198 if ( $VALIDATE_nic_check { "ACC $mac " }) {
199 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
202 $VALIDATE_nic_check { "RESTRICT $mac " } = 1 ;
212 my $nic_access = $cgiparams { "ACCESS $uc $mac " };
214 if ( $nic_access ne "NONE" ) {
215 if ( $VALIDATE_nic_check { "RESTRICT $mac " }) { # If this interface is already assigned to RED in PPP mode, throw an error
216 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
220 if ( $zone_mode ne "BRIDGE" && $VALIDATE_zoneslaves > 0 && $nic_access ne "" ) {
221 $VALIDATE_error = $Lang :: tr
{ "zoneconf val zoneslave amount error" };
225 $VALIDATE_nic_check { "ACC $mac " } = 1 ;
226 $VALIDATE_zoneslaves ++;
229 if ( $nic_access eq "NATIVE" ) {
230 if ( $VALIDATE_nic_check { "NATIVE $mac " }) {
231 $VALIDATE_error = $Lang :: tr
{ "zoneconf val native assignment error" };
235 $VALIDATE_nic_check { "NATIVE $mac " } = 1 ;
237 if ( $zone_mode eq "BRIDGE" ) {
238 $slave_string = "${slave_string}${mac} " ;
240 $ethsettings { "${uc}_MACADDR" } = $mac ;
242 } elsif ( $nic_access eq "VLAN" ) {
243 my $vlan_tag = $cgiparams { "TAG $uc $mac " };
245 if ( $VALIDATE_nic_check { "VLAN $mac $vlan_tag " }) {
246 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan tag assignment error" };
250 $VALIDATE_nic_check { "VLAN $mac $vlan_tag " } = 1 ;
252 if (! looks_like_number
( $vlan_tag )) {
255 if ( $vlan_tag < 1 || $vlan_tag > 4095 ) {
259 my $rnd_mac = & Network
:: random_mac
();
261 $vlansettings { "${uc}_PARENT_DEV" } = $mac ;
262 $vlansettings { "${uc}_VLAN_ID" } = $vlan_tag ;
263 $vlansettings { "${uc}_MAC_ADDRESS" } = $rnd_mac ;
265 if ( $zone_mode eq "BRIDGE" ) {
266 $slave_string = "${slave_string}${rnd_mac} " ;
269 $VALIDATE_vlancount ++; # We can't allow more than one VLAN per zone
273 if ( $VALIDATE_vlancount > 1 ) {
274 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan amount assignment error" };
280 if ( $zone_mode eq "BRIDGE" ) {
281 $ethsettings { "${uc}_MODE" } = "bridge" ;
282 $ethsettings { "${uc}_SLAVES" } = $slave_string ;
283 } elsif ( $zone_mode eq "MACVTAP" ) {
284 $ethsettings { "${uc}_MODE" } = "macvtap" ;
288 if ( $VALIDATE_error ) {
289 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "error" });
291 print " $VALIDATE_error <br><a href='/cgi-bin/zoneconf.cgi'><button> $Lang ::tr{'ok'}</button></a>" ;
294 & Header
:: closebigbox
();
295 & Header
:: closepage
();
300 & General
:: writehash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
301 & General
:: writehash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
303 $restart_notice = $Lang :: tr
{ 'zoneconf notice reboot' };
306 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "zoneconf nic assignment" });
308 ### START OF TABLE ###
311 <form method='post' enctype='multipart/form-data'>
314 <td class="h narrow topleft" /td>
318 # Fill the table header with all activated zones
321 my $dev_name = $ethsettings { "${uc}_DEV" };
323 if ( $dev_name eq "" ) { # If the zone is not activated, don't show it
327 # If the zone is in PPP mode, don't show a mode dropdown
329 my $red_type = $ethsettings { "RED_TYPE" };
330 my $red_restricted = ( $uc eq "RED" && ! ( $red_type eq "STATIC" || $red_type eq "DHCP" ));
332 if ( $red_restricted ) {
333 print "<td class='h textcenter $_ '> $uc ( $red_type )</td>" ;
335 next ; # We're done here
339 my %mode_selected = ();
340 my $zone_mode = $ethsettings { "${uc}_MODE" };
342 if ( $zone_mode eq "" ) {
343 $mode_selected { "DEFAULT" } = "selected" ;
344 } elsif ( $zone_mode eq "bridge" ) {
345 $mode_selected { "BRIDGE" } = "selected" ;
346 } elsif ( $zone_mode eq "macvtap" ) {
347 $mode_selected { "MACVTAP" } = "selected" ;
351 <td class='h textcenter $_ '> $uc </br>
352 <select name="MODE $uc ">
353 <option value="DEFAULT" $mode_selected {"DEFAULT"}> $Lang ::tr{"zoneconf nicmode default"}</option>
354 <option value="BRIDGE" $mode_selected {"BRIDGE"}> $Lang ::tr{"zoneconf nicmode bridge"}</option>
355 <option value="MACVTAP" $mode_selected {"MACVTAP"}> $Lang ::tr{"zoneconf nicmode macvtap"}</option>
364 my $slightlygrey = "" ;
371 print "<tr><td class='h narrow textcenter'> $nic <br> $mac </td>" ;
373 # Iterate through all zones and check if the current NIC is assigned to it
376 my $dev_name = $ethsettings { "${uc}_DEV" };
378 if ( $dev_name eq "" ) { # Again, skip the zone if it is not activated
383 my $red_type = $ethsettings { "RED_TYPE" };
384 my $red_restricted = ( $uc eq "RED" && ! ( $red_type eq "STATIC" || $red_type eq "DHCP" ));
386 # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ...
387 if ( $red_restricted ) {
390 if ( $mac eq $ethsettings { "${uc}_MACADDR" }) {
391 $checked = "checked" ;
394 print "<td class='textcenter $slightlygrey '><input type='radio' id='PPPACCESS $mac ' name='PPPACCESS' value=' $mac ' $checked ></td>" ;
395 next ; # We're done here
399 my %access_selected = ();
400 my $zone_mode = $ethsettings { "${uc}_MODE" };
401 my $zone_parent_dev = $vlansettings { "${uc}_PARENT_DEV" }; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN
402 my $field_disabled = "disabled" ; # Only enable the VLAN ID input field if the current access mode is VLAN
403 my $zone_vlan_id = "" ;
405 # 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
406 $zone_parent_dev = & Network
:: get_mac_by_name
( $zone_parent_dev );
408 # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC
409 if ( $mac eq $zone_parent_dev ) {
410 $access_selected { "VLAN" } = "selected" ;
411 $field_disabled = "" ;
412 $zone_vlan_id = $vlansettings { "${uc}_VLAN_ID" };
413 } 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
414 my @slaves = split ( / / , $ethsettings { "${uc}_SLAVES" });
417 # Slaves can be set to a NICs name so we have to find out its MAC address
418 $_ = & Network
:: get_mac_by_name
( $_ );
421 $access_selected { "NATIVE" } = "selected" ;
425 } 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
426 $access_selected { "NATIVE" } = "selected" ;
429 $access_selected { "NONE" } = ( $access_selected { "NATIVE" } eq "" ) && ( $access_selected { "VLAN" } eq "" ) ?
"selected" : "" ;
430 my $vlan_disabled = ( $wlan ) ?
"disabled" : "" ;
433 <td class="textcenter $slightlygrey ">
434 <select name="ACCESS $uc $mac " onchange="document.getElementById('TAG $uc $mac ').disabled = (this.value === 'VLAN' ? false : true)">
435 <option value="NONE" $access_selected {"NONE"}>- $Lang ::tr{"zoneconf access none"} -</option>
436 <option value="NATIVE" $access_selected {"NATIVE"}> $Lang ::tr{"zoneconf access native"}</option>
437 <option value="VLAN" $access_selected {"VLAN"} $vlan_disabled > $Lang ::tr{"zoneconf access vlan"}</option>
439 <input type="number" class="vlanid" id="TAG $uc $mac " name="TAG $uc $mac " min="1" max="4095" value=" $zone_vlan_id " $field_disabled >
450 $slightlygrey = "slightlygrey" ;
457 <div id="submit-container">
459 <input type="submit" name="ACTION" value=" $Lang ::tr{"save"}">
468 & Header
:: closebigbox
();
469 & Header
:: closepage
();