]>
git.ipfire.org Git - people/mfischer/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;
43 border: 0.5px solid black;
47 /* dark grey header cells */
48 #zoneconf td.heading {
49 background-color: grey;
52 #zoneconf td.heading::first-line {
57 /* narrow left column */
58 #zoneconf tr > td:first-child {
62 /* alternating row background color */
63 #zoneconf tr:nth-child(2n+3) {
64 background-color: #F0F0F0;
68 background-color: $Header ::colourgreen;
72 background-color: $Header ::colourred;
76 background-color: $Header ::colourblue;
80 background-color: $Header ::colourorange;
83 #zoneconf td.topleft {
84 background-color: $Header ::pagecolour;
85 border-top-style: none;
86 border-left-style: none;
100 #submit-container.input {
105 <script src="/include/zoneconf.js"></script>
109 my %ethsettings = ();
110 my %vlansettings = ();
113 my $restart_notice = "" ;
115 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
116 & General
:: readhash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
118 & Header
:: getcgihash
( \
%cgiparams );
119 & Header
:: showhttpheaders
();
121 # Define all zones we will check for NIC assignment
122 my @zones = ( "green" , "red" , "orange" , "blue" );
124 # Get all physical NICs present
125 opendir ( my $dh , "/sys/class/net/" );
128 while ( my $nic = readdir ( $dh )) {
129 if (- e
"/sys/class/net/ $nic /device" ) { # Indicates that the NIC is physical
130 push ( @nics , [& Network
:: get_nic_property
( $nic , "address" ), $nic , 0 ]);
136 @nics = sort { $a ->[ 0 ] cmp $b ->[ 0 ]} @nics ; # Sort nics by their MAC address
138 # Name the physical NICs
139 # Even though they may not be really named like this, we will name them ethX or wlanX
146 if (- e
"/sys/class/net/ $nic /wireless" ) {
147 $_ ->[ 1 ] = "wlan $wlancount " ;
151 $_ ->[ 1 ] = "eth $ethcount " ;
156 & Header
:: openpage
( $Lang :: tr
{ "zoneconf title" }, 1 , $extraHead );
157 & Header
:: openbigbox
( '100%' , 'center' );
159 ### Evaluate POST parameters ###
161 if ( $cgiparams { "ACTION" } eq $Lang :: tr
{ "save" }) {
162 my %VALIDATE_nic_check = ();
163 my $VALIDATE_error = "" ;
167 my $slave_string = "" ;
168 my $zone_mode = $cgiparams { "MODE $uc " };
169 my $VALIDATE_vlancount = 0 ;
170 my $VALIDATE_zoneslaves = 0 ;
172 $ethsettings { "${uc}_MACADDR" } = "" ;
173 $ethsettings { "${uc}_MODE" } = "" ;
174 $ethsettings { "${uc}_SLAVES" } = "" ;
175 $vlansettings { "${uc}_PARENT_DEV" } = "" ;
176 $vlansettings { "${uc}_VLAN_ID" } = "" ;
177 $vlansettings { "${uc}_MAC_ADDRESS" } = "" ;
179 # If RED is not in DHCP or static mode, we only set its MACADDR property
180 if ( $uc eq "RED" && ! $cgiparams { "PPPACCESS" } eq "" ) {
184 if ( $mac eq $cgiparams { "PPPACCESS" }) {
185 $ethsettings { "${uc}_MACADDR" } = $mac ;
187 # Check if this interface is already accessed by any other zone
188 # If this is the case, show an error message
189 if ( $VALIDATE_nic_check { "ACC $mac " }) {
190 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
193 $VALIDATE_nic_check { "RESTRICT $mac " } = 1 ;
203 my $nic_access = $cgiparams { "ACCESS $uc $mac " };
205 next unless ( $nic_access );
207 if ( $nic_access ne "NONE" ) {
208 if ( $VALIDATE_nic_check { "RESTRICT $mac " }) { # If this interface is already assigned to RED in PPP mode, throw an error
209 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
213 if ( $zone_mode ne "BRIDGE" && $VALIDATE_zoneslaves > 0 && $nic_access ne "" ) {
214 $VALIDATE_error = $Lang :: tr
{ "zoneconf val zoneslave amount error" };
218 $VALIDATE_nic_check { "ACC $mac " } = 1 ;
219 $VALIDATE_zoneslaves ++;
222 if ( $nic_access eq "NATIVE" ) {
223 if ( $VALIDATE_nic_check { "NATIVE $mac " }) {
224 $VALIDATE_error = $Lang :: tr
{ "zoneconf val native assignment error" };
228 $VALIDATE_nic_check { "NATIVE $mac " } = 1 ;
230 if ( $zone_mode eq "BRIDGE" ) {
231 $slave_string = "${slave_string}${mac} " ;
233 $ethsettings { "${uc}_MACADDR" } = $mac ;
235 } elsif ( $nic_access eq "VLAN" ) {
236 my $vlan_tag = $cgiparams { "TAG $uc $mac " };
238 if ( $VALIDATE_nic_check { "VLAN $mac $vlan_tag " }) {
239 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan tag assignment error" };
243 $VALIDATE_nic_check { "VLAN $mac $vlan_tag " } = 1 ;
245 if (! looks_like_number
( $vlan_tag )) {
248 if ( $vlan_tag < 1 || $vlan_tag > 4095 ) {
252 my $rnd_mac = & Network
:: random_mac
();
254 $vlansettings { "${uc}_PARENT_DEV" } = $mac ;
255 $vlansettings { "${uc}_VLAN_ID" } = $vlan_tag ;
256 $vlansettings { "${uc}_MAC_ADDRESS" } = $rnd_mac ;
258 if ( $zone_mode eq "BRIDGE" ) {
259 $slave_string = "${slave_string}${rnd_mac} " ;
262 $VALIDATE_vlancount ++; # We can't allow more than one VLAN per zone
266 if ( $VALIDATE_vlancount > 1 ) {
267 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan amount assignment error" };
273 if ( $zone_mode eq "BRIDGE" ) {
274 $ethsettings { "${uc}_MODE" } = "bridge" ;
275 $ethsettings { "${uc}_SLAVES" } = $slave_string ;
276 } elsif ( $zone_mode eq "MACVTAP" ) {
277 $ethsettings { "${uc}_MODE" } = "macvtap" ;
281 if ( $VALIDATE_error ) {
282 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "error" });
284 print " $VALIDATE_error <br><br><a href=' $ENV {'SCRIPT_NAME'}'> $Lang ::tr{'back'}</a> \n " ;
287 & Header
:: closebigbox
();
288 & Header
:: closepage
();
293 & General
:: writehash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
294 & General
:: writehash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
296 $restart_notice = $Lang :: tr
{ 'zoneconf notice reboot' };
299 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "zoneconf nic assignment" });
301 ### START OF TABLE ###
304 <form method='post' enctype='multipart/form-data'>
305 <table id="zoneconf">
307 <td class="topleft"></td>
311 # Fill the table header with all activated zones
314 my $dev_name = $ethsettings { "${uc}_DEV" };
316 if ( $dev_name eq "" ) { # If the zone is not activated, don't show it
320 # If the zone is in PPP mode, don't show a mode dropdown
322 my $red_type = $ethsettings { "RED_TYPE" };
323 my $red_restricted = ( $uc eq "RED" && ! ( $red_type eq "STATIC" || $red_type eq "DHCP" ));
325 if ( $red_restricted ) {
326 print " \t\t <td class='heading $_ '> $uc ( $red_type )</td> \n " ;
328 next ; # We're done here
332 my %mode_selected = ();
333 my $zone_mode = $ethsettings { "${uc}_MODE" };
335 if ( $zone_mode eq "" ) {
336 $mode_selected { "DEFAULT" } = "selected" ;
337 } elsif ( $zone_mode eq "bridge" ) {
338 $mode_selected { "BRIDGE" } = "selected" ;
339 } elsif ( $zone_mode eq "macvtap" ) {
340 $mode_selected { "MACVTAP" } = "selected" ;
344 <td class='heading $_ '> $uc <br>
345 <select name="MODE $uc ">
346 <option value="DEFAULT" $mode_selected {"DEFAULT"}> $Lang ::tr{"zoneconf nicmode default"}</option>
347 <option value="BRIDGE" $mode_selected {"BRIDGE"}> $Lang ::tr{"zoneconf nicmode bridge"}</option>
348 <option value="MACVTAP" $mode_selected {"MACVTAP"}> $Lang ::tr{"zoneconf nicmode macvtap"}</option>
363 print " \t\t <td class='heading'> $nic <br> $mac </td> \n " ;
365 # Iterate through all zones and check if the current NIC is assigned to it
368 my $dev_name = $ethsettings { "${uc}_DEV" };
371 if ( $dev_name eq "" ) { # Again, skip the zone if it is not activated
376 my $red_type = $ethsettings { "RED_TYPE" };
377 my $red_restricted = ( $uc eq "RED" && ! ( $red_type eq "STATIC" || $red_type eq "DHCP" ));
379 # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ...
380 if ( $red_restricted ) {
383 if ( $mac eq $ethsettings { "${uc}_MACADDR" }) {
384 $checked = "checked" ;
389 <td class=" $highlight ">
390 <input type="radio" name="PPPACCESS" value=" $mac " data-zone="RED" data-mac=" $mac " onchange="highlightAccess(this)" $checked >
394 next ; # We're done here
398 my %access_selected = ();
399 my $zone_mode = $ethsettings { "${uc}_MODE" };
400 my $zone_parent_dev = $vlansettings { "${uc}_PARENT_DEV" }; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN
401 my $field_disabled = "disabled" ; # Only enable the VLAN ID input field if the current access mode is VLAN
402 my $zone_vlan_id = "" ;
404 # 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
405 $zone_parent_dev = & Network
:: get_mac_by_name
( $zone_parent_dev );
407 # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC
408 if ( $mac eq $zone_parent_dev ) {
409 $access_selected { "VLAN" } = "selected" ;
410 $field_disabled = "" ;
411 $zone_vlan_id = $vlansettings { "${uc}_VLAN_ID" };
412 } 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
413 my @slaves = split ( / / , $ethsettings { "${uc}_SLAVES" });
416 # Slaves can be set to a NICs name so we have to find out its MAC address
417 $_ = & Network
:: get_mac_by_name
( $_ );
420 $access_selected { "NATIVE" } = "selected" ;
424 } 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
425 $access_selected { "NATIVE" } = "selected" ;
428 $access_selected { "NONE" } = ( $access_selected { "NATIVE" } eq "" ) && ( $access_selected { "VLAN" } eq "" ) ?
"selected" : "" ;
429 my $vlan_disabled = ( $wlan ) ?
"disabled" : "" ;
431 # If the interface is assigned, hightlight table cell
432 if ( $access_selected { "NONE" } eq "" ) {
437 <td class=" $highlight ">
438 <select name="ACCESS $uc $mac " data-zone=" $uc " data-mac=" $mac " onchange="highlightAccess(this)">
439 <option value="NONE" $access_selected {"NONE"}>- $Lang ::tr{"zoneconf access none"} -</option>
440 <option value="NATIVE" $access_selected {"NATIVE"}> $Lang ::tr{"zoneconf access native"}</option>
441 <option value="VLAN" $access_selected {"VLAN"} $vlan_disabled > $Lang ::tr{"zoneconf access vlan"}</option>
443 <input type="number" class="vlanid" id="TAG- $uc - $mac " name="TAG $uc $mac " min="1" max="4095" value=" $zone_vlan_id " $field_disabled >
455 <div id="submit-container">
457 <input type="submit" name="ACTION" value=" $Lang ::tr{"save"}">
466 & Header
:: closebigbox
();
467 & Header
:: closepage
();