]>
git.ipfire.org Git - people/teissler/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" ;
29 ###--- HTML HEAD ---###
34 border-collapse: collapse;
43 /* section separators */
44 #zoneconf tr.divider-top {
45 border-top: 2px solid $Header ::bordercolour;
47 #zoneconf tr.divider-bottom {
48 border-bottom: 2px solid $Header ::bordercolour;
54 border-left: 0.5px solid $Header ::bordercolour;
58 /* grey header cells */
59 #zoneconf td.heading {
60 background-color: lightgrey;
63 #zoneconf td.heading.bold::first-line {
68 /* narrow left column with background color */
69 #zoneconf tr > td:first-child {
72 #zoneconf tr.nic-row > td:first-child {
73 background-color: darkgray;
75 #zoneconf tr.nic-row {
76 border-bottom: 0.5px solid $Header ::bordercolour;
79 /* alternating row background color */
81 background-color: $Header ::table2colour;
83 #zoneconf tr:nth-child(2n+3) {
84 background-color: $Header ::table1colour;
87 /* special cell colors */
89 background-color: $Header ::colourgreen;
93 background-color: $Header ::colourred;
97 background-color: $Header ::colourblue;
100 #zoneconf td.orange {
101 background-color: $Header ::colourorange;
104 #zoneconf td.topleft {
105 background-color: $Header ::pagecolour;
119 #submit-container.input {
124 <script src="/include/zoneconf.js"></script>
127 ###--- END HTML HEAD ---###
129 ### Read configuration ###
130 my %ethsettings = ();
131 my %vlansettings = ();
134 my $restart_notice = "" ;
136 & General
:: readhash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
137 & General
:: readhash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
139 & Header
:: getcgihash
( \
%cgiparams );
140 & Header
:: showhttpheaders
();
142 # Define all zones we will check for NIC assignment
143 my @zones = ( "red" , "green" , "orange" , "blue" );
145 # Get all physical NICs present
146 opendir ( my $dh , "/sys/class/net/" );
149 while ( my $nic = readdir ( $dh )) {
150 if (- e
"/sys/class/net/ $nic /device" ) { # Indicates that the NIC is physical
151 push ( @nics , [& Network
:: get_nic_property
( $nic , "address" ), $nic , 0 ]);
157 @nics = sort { $a ->[ 0 ] cmp $b ->[ 0 ]} @nics ; # Sort nics by their MAC address
159 # Name the physical NICs
160 # Even though they may not be really named like this, we will name them ethX or wlanX
167 if (- e
"/sys/class/net/ $nic /wireless" ) {
168 $_ ->[ 1 ] = "wlan $wlancount " ;
172 $_ ->[ 1 ] = "eth $ethcount " ;
179 # Check if a zone is in IP mode or in PPP, PPPoE, VDSL, ... mode
181 my $zone_type = shift ;
182 return ( $zone_type eq "STATIC" || $zone_type eq "DHCP" );
185 # Check if a zone is activated (device assigned)
186 sub is_zone_activated
{
188 return ( $ethsettings { "${zone}_DEV" } ne "" );
192 & Header
:: openpage
( $Lang :: tr
{ "zoneconf title" }, 1 , $extraHead );
193 & Header
:: openbigbox
( '100%' , 'center' );
195 ### Evaluate POST parameters ###
197 if ( $cgiparams { "ACTION" } eq $Lang :: tr
{ "save" }) {
198 my %VALIDATE_nic_check = ();
199 my $VALIDATE_error = "" ;
203 my $slave_string = "" ;
204 my $zone_mode = $cgiparams { "MODE $uc " };
205 my $VALIDATE_vlancount = 0 ;
206 my $VALIDATE_zoneslaves = 0 ;
208 $ethsettings { "${uc}_MACADDR" } = "" ;
209 $ethsettings { "${uc}_MODE" } = "" ;
210 $ethsettings { "${uc}_SLAVES" } = "" ;
211 $vlansettings { "${uc}_PARENT_DEV" } = "" ;
212 $vlansettings { "${uc}_VLAN_ID" } = "" ;
213 $vlansettings { "${uc}_MAC_ADDRESS" } = "" ;
215 # If RED is not in DHCP or static mode, we only set its MACADDR property
216 if ( $uc eq "RED" && ! $cgiparams { "PPPACCESS" } eq "" ) {
220 if ( $mac eq $cgiparams { "PPPACCESS" }) {
221 $ethsettings { "${uc}_MACADDR" } = $mac ;
223 # Check if this interface is already accessed by any other zone
224 # If this is the case, show an error message
225 if ( $VALIDATE_nic_check { "ACC $mac " }) {
226 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
229 $VALIDATE_nic_check { "RESTRICT $mac " } = 1 ;
234 # skip NIC/VLAN assignment and additional zone options for RED in PPP mode
240 my $nic_access = $cgiparams { "ACCESS $uc $mac " };
242 next unless ( $nic_access );
244 if ( $nic_access ne "NONE" ) {
245 if ( $VALIDATE_nic_check { "RESTRICT $mac " }) { # If this interface is already assigned to RED in PPP mode, throw an error
246 $VALIDATE_error = $Lang :: tr
{ "zoneconf val ppp assignment error" };
250 if ( $zone_mode ne "BRIDGE" && $VALIDATE_zoneslaves > 0 && $nic_access ne "" ) {
251 $VALIDATE_error = $Lang :: tr
{ "zoneconf val zoneslave amount error" };
255 $VALIDATE_nic_check { "ACC $mac " } = 1 ;
256 $VALIDATE_zoneslaves ++;
259 if ( $nic_access eq "NATIVE" ) {
260 if ( $VALIDATE_nic_check { "NATIVE $mac " }) {
261 $VALIDATE_error = $Lang :: tr
{ "zoneconf val native assignment error" };
265 $VALIDATE_nic_check { "NATIVE $mac " } = 1 ;
267 if ( $zone_mode eq "BRIDGE" ) {
268 $slave_string = "${slave_string}${mac} " ;
270 $ethsettings { "${uc}_MACADDR" } = $mac ;
272 } elsif ( $nic_access eq "VLAN" ) {
273 my $vlan_tag = $cgiparams { "TAG $uc $mac " };
275 if ( $VALIDATE_nic_check { "VLAN $mac $vlan_tag " }) {
276 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan tag assignment error" };
280 $VALIDATE_nic_check { "VLAN $mac $vlan_tag " } = 1 ;
282 if (! looks_like_number
( $vlan_tag )) {
285 if ( $vlan_tag < 1 || $vlan_tag > 4095 ) {
289 my $rnd_mac = & Network
:: random_mac
();
291 $vlansettings { "${uc}_PARENT_DEV" } = $mac ;
292 $vlansettings { "${uc}_VLAN_ID" } = $vlan_tag ;
293 $vlansettings { "${uc}_MAC_ADDRESS" } = $rnd_mac ;
295 if ( $zone_mode eq "BRIDGE" ) {
296 $slave_string = "${slave_string}${rnd_mac} " ;
299 $VALIDATE_vlancount ++; # We can't allow more than one VLAN per zone
303 if ( $VALIDATE_vlancount > 1 ) {
304 $VALIDATE_error = $Lang :: tr
{ "zoneconf val vlan amount assignment error" };
310 if ( $zone_mode eq "BRIDGE" ) {
311 $ethsettings { "${uc}_MODE" } = "bridge" ;
312 $ethsettings { "${uc}_SLAVES" } = $slave_string ;
313 } elsif ( $zone_mode eq "MACVTAP" ) {
314 $ethsettings { "${uc}_MODE" } = "macvtap" ;
318 # validation failed, show error message and exit
319 if ( $VALIDATE_error ) {
320 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "error" });
322 print " $VALIDATE_error <br><br><a href=' $ENV {'SCRIPT_NAME'}'> $Lang ::tr{'back'}</a> \n " ;
325 & Header
:: closebigbox
();
326 & Header
:: closepage
();
331 # new settings are valid, write configuration files
332 & General
:: writehash
( "${General::swroot}/ethernet/settings" , \
%ethsettings );
333 & General
:: writehash
( "${General::swroot}/ethernet/vlans" , \
%vlansettings );
335 $restart_notice = $Lang :: tr
{ 'zoneconf notice reboot' };
338 ### START OF TABLE ###
340 & Header
:: openbox
( '100%' , 'left' , $Lang :: tr
{ "zoneconf nic assignment" });
343 <form method='post' enctype='multipart/form-data'>
344 <table id="zoneconf">
345 <tr class="divider-bottom">
346 <td class="topleft"></td>
350 # Fill the table header with all activated zones
354 # If the zone is not activated, don't show it
355 next unless is_zone_activated
( $_ );
357 # If the red zone is in PPP mode, don't show a mode dropdown
359 my $red_type = $ethsettings { "RED_TYPE" };
361 unless ( is_zonetype_ip
( $red_type )) {
362 print " \t\t <td class='heading bold $_ '> $uc ( $red_type )</td> \n " ;
364 next ; # We're done here
368 my %mode_selected = ();
369 my $zone_mode = $ethsettings { "${uc}_MODE" };
371 if ( $zone_mode eq "" ) {
372 $mode_selected { "DEFAULT" } = "selected" ;
373 } elsif ( $zone_mode eq "bridge" ) {
374 $mode_selected { "BRIDGE" } = "selected" ;
375 } elsif ( $zone_mode eq "macvtap" ) {
376 $mode_selected { "MACVTAP" } = "selected" ;
380 <td class='heading bold $_ '> $uc <br>
381 <select name="MODE $uc ">
382 <option value="DEFAULT" $mode_selected {"DEFAULT"}> $Lang ::tr{"zoneconf nicmode default"}</option>
383 <option value="BRIDGE" $mode_selected {"BRIDGE"}> $Lang ::tr{"zoneconf nicmode bridge"}</option>
384 <option value="MACVTAP" $mode_selected {"MACVTAP"}> $Lang ::tr{"zoneconf nicmode macvtap"}</option>
393 # NIC assignment matrix
399 print " \t <tr class='nic-row'> \n " ;
400 print " \t\t <td class='heading bold'> $nic <br> $mac </td> \n " ;
402 # Iterate through all zones and check if the current NIC is assigned to it
407 # If the zone is not activated, don't show it
408 next unless is_zone_activated
( $_ );
411 # VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ...
412 unless ( is_zonetype_ip
( $ethsettings { "RED_TYPE" })) {
415 if ( $mac eq $ethsettings { "${uc}_MACADDR" }) {
416 $checked = "checked" ;
421 <td class=" $highlight ">
422 <input type="radio" name="PPPACCESS" value=" $mac " data-zone="RED" data-mac=" $mac " onchange="highlightAccess(this)" $checked >
426 next ; # We're done here
430 my %access_selected = ();
431 my $zone_mode = $ethsettings { "${uc}_MODE" };
432 my $zone_parent_dev = $vlansettings { "${uc}_PARENT_DEV" }; # ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN
433 my $field_disabled = "disabled" ; # Only enable the VLAN ID input field if the current access mode is VLAN
434 my $zone_vlan_id = "" ;
436 # 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
437 $zone_parent_dev = & Network
:: get_mac_by_name
( $zone_parent_dev );
439 # If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC
440 if ( $mac eq $zone_parent_dev ) {
441 $access_selected { "VLAN" } = "selected" ;
442 $field_disabled = "" ;
443 $zone_vlan_id = $vlansettings { "${uc}_VLAN_ID" };
444 } 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
445 my @slaves = split ( / / , $ethsettings { "${uc}_SLAVES" });
448 # Slaves can be set to a NICs name so we have to find out its MAC address
449 $_ = & Network
:: get_mac_by_name
( $_ );
452 $access_selected { "NATIVE" } = "selected" ;
456 } 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
457 $access_selected { "NATIVE" } = "selected" ;
460 $access_selected { "NONE" } = ( $access_selected { "NATIVE" } eq "" ) && ( $access_selected { "VLAN" } eq "" ) ?
"selected" : "" ;
461 my $vlan_disabled = ( $wlan ) ?
"disabled" : "" ;
463 # If the interface is assigned, hightlight table cell
464 if ( $access_selected { "NONE" } eq "" ) {
469 <td class=" $highlight ">
470 <select name="ACCESS $uc $mac " data-zone=" $uc " data-mac=" $mac " onchange="highlightAccess(this)">
471 <option value="NONE" $access_selected {"NONE"}>- $Lang ::tr{"zoneconf access none"} -</option>
472 <option value="NATIVE" $access_selected {"NATIVE"}> $Lang ::tr{"zoneconf access native"}</option>
473 <option value="VLAN" $access_selected {"VLAN"} $vlan_disabled > $Lang ::tr{"zoneconf access vlan"}</option>
475 <input type="number" class="vlanid" id="TAG- $uc - $mac " name="TAG $uc $mac " min="1" max="4095" value=" $zone_vlan_id " $field_disabled >
484 # footer and submit button
488 <div id="submit-container">
490 <input type="submit" name="ACTION" value=" $Lang ::tr{"save"}">
499 & Header
:: closebigbox
();
500 & Header
:: closepage
();