[2/2] webif: Add a GUI for configuring VLAN interfaces

Message ID 1557313868-10327-2-git-send-email-michael.tremer@ipfire.org
State Dropped
Headers
Series [1/2] udev: Accept MAC addresses for PARENT_DEV |

Commit Message

Michael Tremer May 8, 2019, 9:11 p.m. UTC
  From: Florian Bührle <florian.buehrle@ipfire.org>

This patch adds a new CGI file which allows users to edit the
VLAN configuration as well as configuring zones as bridges.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
---
 config/cfgroot/network-functions.pl |  42 ++++
 config/menu/30-network.menu         |   5 +
 doc/language_issues.de              |  13 ++
 doc/language_issues.en              |   1 +
 doc/language_issues.es              |   1 +
 doc/language_issues.fr              |   1 +
 doc/language_issues.it              |   1 +
 doc/language_issues.nl              |   1 +
 doc/language_issues.pl              |   1 +
 doc/language_issues.ru              |   1 +
 doc/language_issues.tr              |   1 +
 doc/language_missings               |  98 ++++++++
 html/cgi-bin/zoneconf.cgi           | 444 ++++++++++++++++++++++++++++++++++++
 langs/de/cgi-bin/de.pl              |  14 ++
 langs/en/cgi-bin/en.pl              |  14 ++
 15 files changed, 638 insertions(+)
 create mode 100644 html/cgi-bin/zoneconf.cgi
  

Patch

diff --git a/config/cfgroot/network-functions.pl b/config/cfgroot/network-functions.pl
index 2902aabb..8649d05 100644
--- a/config/cfgroot/network-functions.pl
+++ b/config/cfgroot/network-functions.pl
@@ -402,6 +402,48 @@  sub get_hardware_address($) {
 	return $ret;
 }
 
+sub get_nic_property {
+	my $nicname = shift;
+	my $property = shift;
+	my $result;
+
+	open(FILE, "/sys/class/net/$nicname/$property") or die("Could not read property");
+	$result = <FILE>;
+	close(FILE);
+
+	chomp($result);
+
+	return $result;
+}
+
+sub valid_mac($) {
+	my $mac = shift;
+
+	return $mac =~ /^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$/;
+}
+
+sub random_mac {
+	my $address = "02";
+
+	for my $i (0 .. 4) {
+		$address = sprintf("$address:%02x", int(rand(255)));
+	}
+
+	return $address;
+}
+
+sub get_mac_by_name($) {
+	my $mac = shift;
+
+	if ((!&valid_mac($mac)) && ($mac ne "")) {
+		if (-e "/sys/class/net/$mac/") {
+			$mac = get_nic_property($mac, "address");
+		}
+	}
+
+	return $mac;
+}
+
 1;
 
 # Remove the next line to enable the testsuite
diff --git a/config/menu/30-network.menu b/config/menu/30-network.menu
index 9b27de8..6294117 100644
--- a/config/menu/30-network.menu
+++ b/config/menu/30-network.menu
@@ -3,6 +3,11 @@ 
 			        'title' => "$Lang::tr{'net config'}",
 			        'enabled' => 0,
 			        };
+	$subnetwork->{'11.zoneconf'} = {'caption' => "$Lang::tr{'zoneconf title'}",
+			        'uri' => '/cgi-bin/zoneconf.cgi',
+			        'title' => "$Lang::tr{'zoneconf title'}",
+			        'enabled' => 1,
+			        };
     $subnetwork->{'20.proxy'} = {'caption' => "$Lang::tr{'web proxy'}",
 			        'uri' => '/cgi-bin/proxy.cgi',
 			        'title' => "$Lang::tr{'web proxy'}",
diff --git a/doc/language_issues.de b/doc/language_issues.de
index 5f7bf7b5..b250a35 100644
--- a/doc/language_issues.de
+++ b/doc/language_issues.de
@@ -237,6 +237,7 @@  WARNING: translation string unused: err rs 1
 WARNING: translation string unused: err rs 6 decrypt
 WARNING: translation string unused: err rs 7 untartst
 WARNING: translation string unused: err rs 8 untar
+WARNING: translation string unused: error
 WARNING: translation string unused: error config
 WARNING: translation string unused: error external access
 WARNING: translation string unused: esp encryption
@@ -734,6 +735,18 @@  WARNING: translation string unused: xtaccess all error
 WARNING: translation string unused: xtaccess bad transfert
 WARNING: translation string unused: year-graph
 WARNING: translation string unused: yearly firewallhits
+WARNING: translation string unused: zoneconf access native
+WARNING: translation string unused: zoneconf access none
+WARNING: translation string unused: zoneconf access vlan
+WARNING: translation string unused: zoneconf nic assignment
+WARNING: translation string unused: zoneconf nicmode bridge
+WARNING: translation string unused: zoneconf nicmode default
+WARNING: translation string unused: zoneconf nicmode macvtap
+WARNING: translation string unused: zoneconf val native assignment error
+WARNING: translation string unused: zoneconf val ppp assignment error
+WARNING: translation string unused: zoneconf val vlan amount assignment error
+WARNING: translation string unused: zoneconf val vlan tag assignment error
+WARNING: translation string unused: zoneconf warning incorrect configuration
 WARNING: untranslated string: Scan for Songs = unknown string
 WARNING: untranslated string: addons = Addons
 WARNING: untranslated string: bytes = unknown string
diff --git a/doc/language_issues.en b/doc/language_issues.en
index 498bf40..f245519 100644
--- a/doc/language_issues.en
+++ b/doc/language_issues.en
@@ -2199,3 +2199,4 @@  WARNING: untranslated string: yes = Yes
 WARNING: untranslated string: you can only define one roadwarrior connection when using pre-shared key authentication = You can only define one Roadwarrior connection when using pre-shared key authentication.<br />Either you already have a Roadwarrior connection with pre-shared key authentication, or you're trying to add one now.
 WARNING: untranslated string: your department = Your department
 WARNING: untranslated string: your e-mail = Your e-mail address
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.es b/doc/language_issues.es
index f3b695f..41833da 100644
--- a/doc/language_issues.es
+++ b/doc/language_issues.es
@@ -1371,3 +1371,4 @@  WARNING: untranslated string: wlanap management frame protection = Management Fr
 WARNING: untranslated string: wlanap neighbor scan = Neighborhood scan
 WARNING: untranslated string: wlanap neighbor scan warning = Warning! Disabling may violate regulatory rules!
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.fr b/doc/language_issues.fr
index af1f15a..46780db 100644
--- a/doc/language_issues.fr
+++ b/doc/language_issues.fr
@@ -885,3 +885,4 @@  WARNING: untranslated string: wlanap broadcast ssid = Broadcast SSID
 WARNING: untranslated string: wlanap client isolation = Client Isolation
 WARNING: untranslated string: wlanap management frame protection = Management Frame Protection (802.11w)
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.it b/doc/language_issues.it
index 5da8a8d..9d3e0e8 100644
--- a/doc/language_issues.it
+++ b/doc/language_issues.it
@@ -1038,3 +1038,4 @@  WARNING: untranslated string: wlanap management frame protection = Management Fr
 WARNING: untranslated string: wlanap neighbor scan = Neighborhood scan
 WARNING: untranslated string: wlanap neighbor scan warning = Warning! Disabling may violate regulatory rules!
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.nl b/doc/language_issues.nl
index 6be2cb6..69cefe1 100644
--- a/doc/language_issues.nl
+++ b/doc/language_issues.nl
@@ -1084,3 +1084,4 @@  WARNING: untranslated string: wlanap management frame protection = Management Fr
 WARNING: untranslated string: wlanap neighbor scan = Neighborhood scan
 WARNING: untranslated string: wlanap neighbor scan warning = Warning! Disabling may violate regulatory rules!
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.pl b/doc/language_issues.pl
index f3b695f..41833da 100644
--- a/doc/language_issues.pl
+++ b/doc/language_issues.pl
@@ -1371,3 +1371,4 @@  WARNING: untranslated string: wlanap management frame protection = Management Fr
 WARNING: untranslated string: wlanap neighbor scan = Neighborhood scan
 WARNING: untranslated string: wlanap neighbor scan warning = Warning! Disabling may violate regulatory rules!
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.ru b/doc/language_issues.ru
index 53a655c..b769c75 100644
--- a/doc/language_issues.ru
+++ b/doc/language_issues.ru
@@ -1366,3 +1366,4 @@  WARNING: untranslated string: wlanap management frame protection = Management Fr
 WARNING: untranslated string: wlanap neighbor scan = Neighborhood scan
 WARNING: untranslated string: wlanap neighbor scan warning = Warning! Disabling may violate regulatory rules!
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_issues.tr b/doc/language_issues.tr
index 88baad7..6a6893a 100644
--- a/doc/language_issues.tr
+++ b/doc/language_issues.tr
@@ -901,3 +901,4 @@  WARNING: untranslated string: wlanap management frame protection = Management Fr
 WARNING: untranslated string: wlanap neighbor scan = Neighborhood scan
 WARNING: untranslated string: wlanap neighbor scan warning = Warning! Disabling may violate regulatory rules!
 WARNING: untranslated string: wlanap ssid = SSID
+WARNING: untranslated string: zoneconf title = Zone Configuration
diff --git a/doc/language_missings b/doc/language_missings
index 354dbb3..0f3c2a7 100644
--- a/doc/language_missings
+++ b/doc/language_missings
@@ -273,6 +273,7 @@ 
 < encryption
 < entropy
 < entropy graphs
+< error
 < fifteen minutes
 < fireinfo ipfire version
 < fireinfo is disabled
@@ -846,6 +847,19 @@ 
 < wlan client wpa mode ccmp ccmp
 < wlan client wpa mode ccmp tkip
 < wlan client wpa mode tkip tkip
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
 ############################################################################
 # Checking cgi-bin translations for language: fr                           #
 ############################################################################
@@ -865,6 +879,7 @@ 
 < dnsforward dnssec disabled
 < dns forwarding dnssec disabled notice
 < emerging pro rules
+< error
 < generate ptr
 < ids apply
 < ids apply ruleset changes
@@ -912,6 +927,19 @@ 
 < wlanap client isolation
 < wlanap management frame protection
 < wlanap ssid
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
 ############################################################################
 # Checking cgi-bin translations for language: it                           #
 ############################################################################
@@ -1027,6 +1055,7 @@ 
 < email tls
 < email usemail
 < emerging pro rules
+< error
 < fifteen minutes
 < firewall graph country
 < firewall graph ip
@@ -1189,6 +1218,19 @@ 
 < wlan client password
 < wlan client tls cipher
 < wlan client tls version
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
 ############################################################################
 # Checking cgi-bin translations for language: nl                           #
 ############################################################################
@@ -1322,6 +1364,7 @@ 
 < email tls
 < email usemail
 < emerging pro rules
+< error
 < fifteen minutes
 < firewall graph country
 < firewall graph ip
@@ -1524,6 +1567,19 @@ 
 < wlan client password
 < wlan client tls cipher
 < wlan client tls version
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
 ############################################################################
 # Checking cgi-bin translations for language: pl                           #
 ############################################################################
@@ -1740,6 +1796,7 @@ 
 < encryption
 < entropy
 < entropy graphs
+< error
 < extrahd because there is already a device mounted
 < extrahd cant umount
 < extrahd install or load driver
@@ -2299,6 +2356,19 @@ 
 < wlan client wpa mode ccmp ccmp
 < wlan client wpa mode ccmp tkip
 < wlan client wpa mode tkip tkip
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
 ############################################################################
 # Checking cgi-bin translations for language: ru                           #
 ############################################################################
@@ -2519,6 +2589,7 @@ 
 < encryption
 < entropy
 < entropy graphs
+< error
 < extrahd because there is already a device mounted
 < extrahd cant umount
 < extrahd install or load driver
@@ -3081,6 +3152,19 @@ 
 < wlan client wpa mode ccmp tkip
 < wlan client wpa mode tkip tkip
 < year-graph
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
 ############################################################################
 # Checking cgi-bin translations for language: tr                           #
 ############################################################################
@@ -3103,6 +3187,7 @@ 
 < dnsforward forward_servers
 < dns forwarding dnssec disabled notice
 < emerging pro rules
+< error
 < fwdfw all subnets
 < generate ptr
 < ids apply
@@ -3163,3 +3248,16 @@ 
 < wlanap neighbor scan
 < wlanap neighbor scan warning
 < wlanap ssid
+< zoneconf access native
+< zoneconf access none
+< zoneconf access vlan
+< zoneconf nic assignment
+< zoneconf nicmode bridge
+< zoneconf nicmode default
+< zoneconf nicmode macvtap
+< zoneconf title
+< zoneconf val native assignment error
+< zoneconf val ppp assignment error
+< zoneconf val vlan amount assignment error
+< zoneconf val vlan tag assignment error
+< zoneconf warning incorrect configuration
diff --git a/html/cgi-bin/zoneconf.cgi b/html/cgi-bin/zoneconf.cgi
new file mode 100644
index 0000000..69a988b
--- /dev/null
+++ b/html/cgi-bin/zoneconf.cgi
@@ -0,0 +1,444 @@ 
+#!/usr/bin/perl
+###############################################################################
+#                                                                             #
+# VLAN Management for IPFire                                                  #
+# Copyright (C) 2019 Florian Bührle <fbuehrle@ipfire.org>                     #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+use strict;
+use Scalar::Util qw(looks_like_number);
+
+require '/var/ipfire/general-functions.pl';
+require "${General::swroot}/lang.pl";
+require "${General::swroot}/header.pl";
+
+my $css = <<END
+<style>
+	table {
+		width: 100%;
+	}
+
+	tr {
+		height: 4em;
+	}
+
+	td:first-child {
+		width: 1px;
+	}
+
+	td {
+		padding: 5px;
+		padding-left: 10px;
+		padding-right: 10px;
+		border: 0.5px solid black;
+	}
+
+	table {
+		border-collapse: collapse;
+	}
+
+	td.h {
+		background-color: grey;
+		color: white;
+		font-weight: 800;
+	}
+
+	td.green {
+		background-color: $Header::colourgreen;
+	}
+
+	td.red {
+		background-color: $Header::colourred;
+	}
+
+	td.blue {
+		background-color: $Header::colourblue;
+	}
+
+	td.orange {
+		background-color: $Header::colourorange;
+	}
+
+	td.topleft {
+		background-color: white;
+		border-top-style: none;
+		border-left-style: none;
+	}
+
+	td.disabled {
+		background-color: #cccccc;
+	}
+
+	td.textcenter {
+		text-align: center;
+	}
+
+	#submit-container {
+		display: flex;
+		width: 100%;
+		justify-content: space-between;
+		padding-top: 20px;
+		text-align: left;
+	}
+
+	#submit-container.input {
+		margin-left: auto;
+	}
+
+	button {
+		margin-top: 1em;
+	}
+
+</style>
+END
+;
+
+my %ethsettings = ();
+my %vlansettings = ();
+my %cgiparams = ();
+
+&General::readhash("${General::swroot}/ethernet/settings",\%ethsettings);
+&General::readhash("${General::swroot}/ethernet/vlans",\%vlansettings);
+
+&Header::getcgihash(\%cgiparams);
+&Header::showhttpheaders();
+
+# Define all zones we will check for NIC assignment
+my @zones = ("green", "red", "orange", "blue");
+
+# Get all physical NICs present
+opendir(my $dh, "/sys/class/net/");
+my @nics = ();
+
+while (my $nic = readdir($dh)) {
+	if (-e "/sys/class/net/$nic/device") { # Indicates that the NIC is physical
+		push(@nics, [&Network::get_nic_property($nic, "address"), $nic, 0]);
+	}
+}
+
+closedir($dh);
+
+@nics = sort {$a->[0] cmp $b->[0]} @nics; # Sort nics by their MAC address
+
+# Name the physical NICs
+# Even though they may not be really named like this, we will name them ethX or wlanX
+my $ethcount = 0;
+my $wlancount = 0;
+
+foreach (@nics) {
+	my $nic = $_->[1];
+
+	if (-e "/sys/class/net/$nic/wireless") {
+		$_->[1] = "wlan$wlancount";
+		$_->[2] = 1;
+		$wlancount++;
+	} else {
+		$_->[1] = "eth$ethcount";
+		$ethcount++;
+	}
+}
+
+&Header::openpage($Lang::tr{"zoneconf title"}, 1, $css);
+&Header::openbigbox('100%', 'center');
+
+### Evaluate POST parameters ###
+
+if ($cgiparams{"ACTION"} eq $Lang::tr{"save"}) {
+	my %VALIDATE_nic_check = ();
+	my $VALIDATE_error = "";
+
+	foreach (@zones) {
+		my $uc = uc $_;
+		my $slave_string = "";
+		my $zone_mode = $cgiparams{"MODE $uc"};
+		my $VALIDATE_vlancount = 0;
+
+		$ethsettings{"${uc}_MACADDR"} = "";
+		$ethsettings{"${uc}_MODE"} = "";
+		$ethsettings{"${uc}_SLAVES"} = "";
+		$vlansettings{"${uc}_PARENT_DEV"} = "";
+		$vlansettings{"${uc}_VLAN_ID"} = "";
+		$vlansettings{"${uc}_MAC_ADDRESS"} = "";
+
+		# If RED is not in DHCP or static mode, we only set its MACADDR property
+		if ($uc eq "RED" && ! $cgiparams{"PPPACCESS"} eq "") {
+			foreach (@nics) {
+				my $mac = $_->[0];
+
+				if ($mac eq $cgiparams{"PPPACCESS"}) {
+					$ethsettings{"${uc}_MACADDR"} = $mac;
+
+					# Check if this interface is already accessed by any other zone
+					# If this is the case, show an error message
+					if ($VALIDATE_nic_check{"ACC $mac"}) {
+						$VALIDATE_error = $Lang::tr{"zoneconf val ppp assignment error"};
+					}
+
+					$VALIDATE_nic_check{"RESTRICT $mac"} = 1;
+					last;
+				}
+			}
+
+			next;
+		}
+
+		foreach (@nics) {
+			my $mac = $_->[0];
+			my $nic_access = $cgiparams{"ACCESS $uc $mac"};
+
+			if (! ($nic_access eq "NONE")) {
+				if ($VALIDATE_nic_check{"RESTRICT $mac"}) { # If this interface is already assigned to RED in PPP mode, throw an error
+					$VALIDATE_error = $Lang::tr{"zoneconf val ppp assignment error"};
+					next;
+				}
+
+				$VALIDATE_nic_check{"ACC $mac"} = 1;
+			}
+
+			if ($nic_access eq "NATIVE") {
+				if ($VALIDATE_nic_check{"NATIVE $mac"}) {
+					$VALIDATE_error = $Lang::tr{"zoneconf val native assignment error"};
+					next;
+				}
+
+				$VALIDATE_nic_check{"NATIVE $mac"} = 1;
+
+				if ($zone_mode eq "BRIDGE") {
+					$slave_string = "${slave_string}${mac} ";
+				} else {
+					$ethsettings{"${uc}_MACADDR"} = $mac;
+				}
+			} elsif ($nic_access eq "VLAN") {
+				my $vlan_tag = $cgiparams{"TAG $uc $mac"};
+
+				if ($VALIDATE_nic_check{"VLAN $mac $vlan_tag"}) {
+					$VALIDATE_error = $Lang::tr{"zoneconf val vlan tag assignment error"};
+					next;
+				}
+
+				$VALIDATE_nic_check{"VLAN $mac $vlan_tag"} = 1;
+
+				if (! looks_like_number($vlan_tag)) {
+					next;
+				}
+				if ($vlan_tag < 1 || $vlan_tag > 4095) {
+					next;
+				}
+
+				my $rnd_mac = &Network::random_mac();
+
+				$vlansettings{"${uc}_PARENT_DEV"} = $mac;
+				$vlansettings{"${uc}_VLAN_ID"} = $vlan_tag;
+				$vlansettings{"${uc}_MAC_ADDRESS"} = $rnd_mac;
+
+				if ($zone_mode eq "BRIDGE") {
+					$slave_string = "${slave_string}${rnd_mac} ";
+				}
+
+				$VALIDATE_vlancount++; # We can't allow more than one VLAN per zone
+			}
+		}
+
+		if ($VALIDATE_vlancount > 1) {
+			$VALIDATE_error = $Lang::tr{"zoneconf val vlan amount assignment error"};
+			next;
+		}
+
+		chop($slave_string);
+
+		if ($zone_mode eq "BRIDGE") {
+			$ethsettings{"${uc}_MODE"} = "bridge";
+			$ethsettings{"${uc}_SLAVES"} = $slave_string;
+		} elsif ($zone_mode eq "MACVTAP") {
+			$ethsettings{"${uc}_MODE"} = "macvtap";
+		}
+	}
+
+	if ($VALIDATE_error) {
+		&Header::openbox('100%', 'left', $Lang::tr{"error"});
+
+		print "$VALIDATE_error<br><a href='/cgi-bin/zoneconf.cgi'><button>$Lang::tr{'ok'}</button></a>";
+
+		&Header::closebox();
+		&Header::closebigbox();
+		&Header::closepage();
+
+		exit 0;
+	}
+
+	&General::writehash("${General::swroot}/ethernet/settings",\%ethsettings);
+	&General::writehash("${General::swroot}/ethernet/vlans",\%vlansettings);
+}
+
+&Header::openbox('100%', 'left', $Lang::tr{"zoneconf nic assignment"});
+
+### START OF TABLE ###
+
+print <<END
+	<form method='post' enctype='multipart/form-data'>
+		<table>
+			<tr>
+			<td class="h topleft" /td>
+END
+;
+
+# Fill the table header with all physical NICs
+foreach (@nics) {
+	my $mac = $_->[0];
+	my $nic = $_->[1];
+
+	print "<td class='h textcenter'>$nic<br>$mac</td>";
+}
+
+print "</tr>";
+
+foreach (@zones) {
+	print "<tr>";
+	my $uc = uc $_;
+
+	my $dev_name = $ethsettings{"${uc}_DEV"};
+
+	if ($dev_name eq "") { # If the zone is not activated, color it light grey
+		print "<td class='h disabled'>$uc</td>";
+
+		foreach (@nics) {
+			print "<td class='disabled'/>";
+		}
+
+		print "</tr>";
+		next;
+	}
+
+	if ($uc eq "RED") {
+		my $red_type = $ethsettings{"RED_TYPE"};
+		my $red_restricted = ($uc eq "RED" && ! ($red_type eq "STATIC" || $red_type eq "DHCP"));
+
+		# VLANs/Bridging is not possible if the RED interface is set to PPP, PPPoE, VDSL, ...
+		if ($red_restricted) {
+			print "<td class='h $_'>$uc<br>($red_type)</td>";
+
+			foreach (@nics) {
+				my $mac = $_->[0];
+				my $checked = "";
+
+				if ($mac eq $ethsettings{"${uc}_MACADDR"}) {
+					$checked = "checked";
+				}
+
+				print "<td class='textcenter'><input type='radio' id='PPPACCESS $mac' name='PPPACCESS' value='$mac' $checked></td>";
+			}
+
+			print "</tr>";
+			next; # We're done here
+		}
+	}
+
+	my %mode_selected = ();
+	my $zone_mode = $ethsettings{"${uc}_MODE"};
+
+	if ($zone_mode eq "") {
+		$mode_selected{"DEFAULT"} = "selected";
+	} elsif ($zone_mode eq "bridge") {
+		$mode_selected{"BRIDGE"} = "selected";
+	} elsif ($zone_mode eq "macvtap") {
+		$mode_selected{"MACVTAP"} = "selected";
+	}
+
+	print <<END
+		<td class='h $_'>$uc<br>
+			<select name="MODE $uc">
+				<option value="DEFAULT" $mode_selected{"DEFAULT"}>$Lang::tr{"zoneconf nicmode default"}</option>
+				<option value="BRIDGE" $mode_selected{"BRIDGE"}>$Lang::tr{"zoneconf nicmode bridge"}</option>
+				<option value="MACVTAP" $mode_selected{"MACVTAP"}>$Lang::tr{"zoneconf nicmode macvtap"}</option>
+			</select>
+		</td>
+END
+;
+
+	# ZONE_PARENT_DEV is set if this zone accesses any interface via a VLAN
+	my $zone_parent_dev = $vlansettings{"${uc}_PARENT_DEV"};
+
+	# 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
+	$zone_parent_dev = &Network::get_mac_by_name($zone_parent_dev);
+
+	foreach (@nics) { # Check for all nics if they are assigned to the current zone
+		my %access_selected = ();
+		my $mac = $_->[0];
+		my $wlan = $_->[2];
+		my $field_disabled = "disabled"; # Only enable the VLAN ID input field if the current access mode is VLAN
+		my $zone_vlan_id = "";
+
+		# If the current NIC is accessed by the current zone via a VLAN, the ZONE_PARENT_DEV option corresponds to the current NIC
+		if ($mac eq $zone_parent_dev) {
+			$access_selected{"VLAN"} = "selected";
+			$field_disabled = "";
+			$zone_vlan_id = $vlansettings{"${uc}_VLAN_ID"};
+		}
+
+		# If the current zone is in bridge mode, all corresponding NICs (Native as well as VLAN) are set via the ZONE_SLAVES option
+		if ($zone_mode eq "bridge") {
+			my @slaves = split(/ /, $ethsettings{"${uc}_SLAVES"});
+
+			foreach (@slaves) {
+				# Slaves can be set to a NICs name so we have to find out its MAC address
+				$_ = &Network::get_mac_by_name($_);
+
+				if ($_ eq $mac) {
+					$access_selected{"NATIVE"} = "selected";
+					last;
+				}
+			}
+		} else { # 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
+			if ($mac eq $ethsettings{"${uc}_MACADDR"}) {
+				$access_selected{"NATIVE"} = "selected";
+			}
+		}
+
+		$access_selected{"NONE"} = ($access_selected{"NATIVE"} eq "") && ($access_selected{"VLAN"} eq "") ? "selected" : "";
+		my $vlan_disabled = ($wlan) ? "disabled" : "";
+
+		print <<END
+			<td class="textcenter">
+				<select name="ACCESS $uc $mac" onchange="document.getElementById('TAG $uc $mac').disabled = (this.value === 'VLAN' ? false : true)">
+					<option value="NATIVE" $access_selected{"NATIVE"}>$Lang::tr{"zoneconf access native"}</option>
+					<option value="VLAN" $access_selected{"VLAN"} $vlan_disabled>$Lang::tr{"zoneconf access vlan"}</option>
+					<option value="NONE" $access_selected{"NONE"}>$Lang::tr{"zoneconf access none"}</option>
+				</select>
+				<input type="number" id="TAG $uc $mac" name="TAG $uc $mac" min="1" max="4095" value="$zone_vlan_id" $field_disabled>
+			</td>
+END
+;
+
+	}
+	print "</tr>";
+}
+
+print <<END
+	</table>
+		<div id="submit-container">
+			<font color="red">$Lang::tr{"zoneconf warning incorrect configuration"}</font>
+			<input type="submit" name="ACTION" value="$Lang::tr{"save"}">
+		</div>
+	</form>
+END
+;
+
+### END OF TABLE ###
+
+&Header::closebox();
+&Header::closebigbox();
+&Header::closepage();
diff --git a/langs/de/cgi-bin/de.pl b/langs/de/cgi-bin/de.pl
index 0fc1ecf..dec4a9f 100644
--- a/langs/de/cgi-bin/de.pl
+++ b/langs/de/cgi-bin/de.pl
@@ -961,6 +961,7 @@ 
 'err rs 6 decrypt' => 'Fehler beim Entschlüsseln des Archivs',
 'err rs 7 untartst' => 'Ungültiges entschlüsseltes Archiv',
 'err rs 8 untar' => 'Fehler beim un-tar-en des Archivs',
+'error' => 'Fehler',
 'error config' => 'Kann /var/ipfire/ovpn/config/ZERINA.ovpn nicht öffnen!',
 'error external access' => 'Kann /var/ipfire/xtaccess/config nicht öffnen (external acccess could not be granted)!',
 'error messages' => 'Fehlermeldungen',
@@ -2879,6 +2880,19 @@ 
 'you can only define one roadwarrior connection when using pre-shared key authentication' => 'Sie können nur eine Roadwarrior-Verbindung definieren, wenn die Pre-shared-Schlüsselauthentifizierung verwendet wird.<br/>Entweder haben Sie bereits eine Roadwarrior-Verbindung mit Pre-shared-Schlüsselauthentifizierung, oder Sie versuchen gerade, eine hinzuzufügen.',
 'your department' => 'Ihre Abteilung',
 'your e-mail' => 'Ihre E-Mail-Adresse',
+'zoneconf access native' => 'Nativ',
+'zoneconf access none' => 'Keine',
+'zoneconf access vlan' => 'VLAN',
+'zoneconf nic assignment' => 'Netzwerkkarten-Zuordnung',
+'zoneconf nicmode bridge' => 'Brücke',
+'zoneconf nicmode default' => 'Normal',
+'zoneconf nicmode macvtap' => 'Macvtap',
+'zoneconf title' => 'Zonen einrichten',
+'zoneconf val native assignment error' => 'Eine Netzwerkkarte kann nicht von mehreren Zonen nativ verwendet werden.',
+'zoneconf val ppp assignment error' => 'Die Netzwerkkarte, die von RED im PPP-Modus verwendet wird, kann keiner anderen Zone zugeordnet werden.',
+'zoneconf val vlan amount assignment error' => 'Pro Zone kann nur ein VLAN verwendet werden.',
+'zoneconf val vlan tag assignment error' => 'Pro Netzwerkkarte kann derselbe VLAN-Tag nur einmal verwendet werden.',
+'zoneconf warning incorrect configuration' => 'Achtung: Fehlerhafte Einstellungen können dazu führen, dass diese Webseite nicht mehr erreichbar ist!',
 );
 
 #EOF
diff --git a/langs/en/cgi-bin/en.pl b/langs/en/cgi-bin/en.pl
index d14a860..005a352 100644
--- a/langs/en/cgi-bin/en.pl
+++ b/langs/en/cgi-bin/en.pl
@@ -991,6 +991,7 @@ 
 'err rs 6 decrypt' => 'Error decrypting archive',
 'err rs 7 untartst' => 'Invalid decrypted archive',
 'err rs 8 untar' => 'Error untarring archive',
+'error' => 'Error',
 'error config' => 'Could not open /var/ipfire/ovpn/config/ZERINA.ovpn !',
 'error external access' => 'Could not open /var/ipfire/xtaccess/config (external acccess could not be granted)!',
 'error messages' => 'Error messages',
@@ -2928,6 +2929,19 @@ 
 'you can only define one roadwarrior connection when using pre-shared key authentication' => 'You can only define one Roadwarrior connection when using pre-shared key authentication.<br />Either you already have a Roadwarrior connection with pre-shared key authentication, or you\'re trying to add one now.',
 'your department' => 'Your department',
 'your e-mail' => 'Your e-mail address',
+'zoneconf access native' => 'Native',
+'zoneconf access none' => 'None',
+'zoneconf access vlan' => 'VLAN',
+'zoneconf nic assignment' => 'NIC Assignment',
+'zoneconf nicmode bridge' => 'Bridge',
+'zoneconf nicmode default' => 'Default',
+'zoneconf nicmode macvtap' => 'Macvtap',
+'zoneconf title' => 'Zone Configuration',
+'zoneconf val native assignment error' => 'A NIC can\'t be accessed natively by more than one zone.',
+'zoneconf val ppp assignment error' => 'The NIC used for RED in PPP mode can\'t be accessed by any other zone.',
+'zoneconf val vlan amount assignment error' => 'A zone can\'t have more than one VLAN assigned.',
+'zoneconf val vlan tag assignment error' => 'You can\'t use the same VLAN tag more than once per NIC.',
+'zoneconf warning incorrect configuration' => 'Warning: Incorrect configuration may render this web interface unreachable!',
 );
 
 #EOF