]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - config/cfgroot/network-functions.pl
Merge remote-tracking branch 'origin/next'
[people/pmueller/ipfire-2.x.git] / config / cfgroot / network-functions.pl
index 66f1ed554ab12041c31cc0b3163f9e1c8a75710f..b7a840559ccd5ec52a4cf918065538690a2c32ed 100644 (file)
@@ -25,8 +25,17 @@ package Network;
 
 require "/var/ipfire/general-functions.pl";
 
+use experimental 'smartmatch';
 use Socket;
 
+# System ethernet configuration
+our %ethernet_settings = ();
+&General::readhash("${General::swroot}/ethernet/settings", \%ethernet_settings);
+
+# List of all possible network zones that can be configured
+our @known_network_zones = ("red", "green", "orange", "blue");
+
+# IPv4 netmask CIDR to dotted decimal notation conversion table
 my %PREFIX2NETMASK = (
        32 => "255.255.255.255",
        31 => "255.255.255.254",
@@ -108,10 +117,14 @@ sub network_equal {
        my $network1 = shift;
        my $network2 = shift;
 
-       my $bin1 = &network2bin($network1);
-       my $bin2 = &network2bin($network2);
+       my @bin1 = &network2bin($network1);
+       my @bin2 = &network2bin($network2);
+
+       if (!defined $bin1 || !defined $bin2) {
+               return undef;
+       }
 
-       if ($bin1 eq $bin2) {
+       if ($bin1[0] == $bin2[0] && $bin1[1] == $bin2[1]) {
                return 1;
        }
 
@@ -133,6 +146,10 @@ sub network2bin($) {
        my $address_bin = &ip2bin($address);
        my $netmask_bin = &ip2bin($netmask);
 
+       if (!defined $address_bin || !defined $netmask_bin) {
+               return undef;
+       }
+
        my $network_start = $address_bin & $netmask_bin;
 
        return ($network_start, $netmask_bin);
@@ -183,7 +200,7 @@ sub check_ip_address_and_netmask($$) {
        my ($address, $netmask) = split(/\//, $network, 2);
 
        # Check if the IP address is fine.
-       # 
+       #
        my $result = &check_ip_address($address);
        unless ($result) {
                return $result;
@@ -287,7 +304,7 @@ sub ip_address_in_network($$) {
        # Find end address
        my $broadcast_bin = $network_bin ^ (~$netmask_bin % 2 ** 32);
 
-       return (($address_bin ge $network_bin) && ($address_bin le $broadcast_bin));
+       return (($address_bin >= $network_bin) && ($address_bin <= $broadcast_bin));
 }
 
 sub setup_upstream_proxy() {
@@ -315,13 +332,35 @@ sub setup_upstream_proxy() {
        }
 }
 
+sub list_wireless_interfaces() {
+       my %interfaces = ();
+
+       opendir(INTERFACES, "/sys/class/net");
+
+       my $intf;
+       while ($intf = readdir(INTERFACES)) {
+               # Is this a wireless interface?
+               opendir(PHY80211, "/sys/class/net/$intf/phy80211") or next;
+               closedir(PHY80211);
+
+               # Read the MAC address
+               my $address = &get_nic_property($intf, "address");
+
+               $interfaces{$address} = "$address ($intf)";
+       }
+
+       closedir(INTERFACES);
+
+       return %interfaces;
+}
+
 my %wireless_status = ();
 
 sub _get_wireless_status($) {
        my $intf = shift;
 
        if (!$wireless_status{$intf}) {
-               $wireless_status{$intf} = `iwconfig $intf`;
+               $wireless_status{$intf} = &General::system_output("iwconfig", "$intf");
        }
 
        return $wireless_status{$intf};
@@ -374,19 +413,174 @@ sub wifi_get_signal_level($) {
 
        return $signal_level;
 }
+
+sub get_hardware_address($) {
+       my $ip_address = shift;
+       my $ret;
+
+       open(FILE, "/proc/net/arp") or die("Could not read ARP table");
+
+       while (<FILE>) {
+               my ($ip_addr, $hwtype, $flags, $hwaddr, $mask, $device) = split(/\s+/, $_);
+               if ($ip_addr eq $ip_address) {
+                       $ret = $hwaddr;
+                       last;
+               }
+       }
+
+       close(FILE);
+
+       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 $property for $nicname");
+       $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})$/;
+}
+
+# Compares two MAC addresses and returns true if they are equal
+sub is_mac_equal {
+       my $mac_1 = uc shift; # convert to upper case
+       my $mac_2 = uc shift;
+
+       if(valid_mac($mac_1) && valid_mac($mac_2) && ($mac_1 eq $mac_2)) {
+               return 1;
+       }
+
+       return 0;
+}
+
+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;
+}
+
+sub get_intf_by_address($) {
+       my $address = shift;
+
+       opendir(INTERFACES, "/sys/class/net");
+
+       while (my $intf = readdir(INTERFACES)) {
+               next if ($intf eq "." or $intf eq "..");
+
+               my $intf_address = &get_nic_property($intf, "address");
+
+               # Skip interfaces without addresses
+               next if ($intf_address eq "");
+
+               # Return a match
+               return $intf if ($intf_address eq $address);
+       }
+
+       closedir(INTERFACES);
+
+       return undef;
+}
+
+#
+## Function to get a list of all available network zones.
+#
+sub get_available_network_zones () {
+       # Obtain the configuration type from the netsettings hash.
+       my $config_type = $ethernet_settings{'CONFIG_TYPE'};
+
+       # Hash which contains the conversation from the config mode
+       # to the existing network interface names. They are stored like
+       # an array.
+       #
+       # Mode "0" red is a modem and green
+       # Mode "1" red is a netdev and green
+       # Mode "2" red, green and orange
+       # Mode "3" red, green and blue
+       # Mode "4" red, green, blue, orange
+       my %config_type_to_interfaces = (
+               "0" => [ "red", "green" ],
+               "1" => [ "red", "green" ],
+               "2" => [ "red", "green", "orange" ],
+               "3" => [ "red", "green", "blue" ],
+               "4" => [ "red", "green", "blue", "orange" ]
+       );
+
+       # Obtain and dereference the corresponding network interaces based on the read
+       # network config type.
+       my @network_zones = @{ $config_type_to_interfaces{$config_type} };
+
+       # Return them.
+       return @network_zones;
+}
+
+#
+## Function to check if a network zone is available in the current configuration
+#
+sub is_zone_available() {
+       my $zone = lc shift;
+       
+       # Make sure the zone is valid
+       die("Unknown network zone '$zone'") unless ($zone ~~ @known_network_zones);
+       
+       # Get available zones and return result
+       my @available_zones = get_available_network_zones();
+       return ($zone ~~ @available_zones);
+}
+
+#
+## Function to determine if the RED zone is in standard IP (or modem, PPP, VDSL, ...) mode
+#
+sub is_red_mode_ip() {
+       # Obtain the settings from the netsettings hash
+       my $config_type = $ethernet_settings{'CONFIG_TYPE'};
+       my $red_type = $ethernet_settings{'RED_TYPE'};
+
+       # RED must be a network device (configuration 1-4) with dynamic or static IP
+       return (($config_type ~~ [1..4]) && ($red_type ~~ ["DHCP", "STATIC"]));
+}
+
 1;
 
 # Remove the next line to enable the testsuite
 __END__
 
-sub assert($) {
+sub assert($$) {
+       my $tst = shift;
        my $ret = shift;
 
        if ($ret) {
                return;
        }
 
-       print "ASSERTION ERROR";
+       print "ASSERTION ERROR - $tst\n";
        exit(1);
 }
 
@@ -394,10 +588,10 @@ sub testsuite() {
        my $result;
 
        my $address1 = &ip2bin("8.8.8.8");
-       assert($address1 == 134744072);
+       assert('ip2bin("8.8.8.8")', $address1 == 134744072);
 
        my $address2 = &bin2ip($address1);
-       assert($address2 eq "8.8.8.8");
+       assert("bin2ip($address1)", $address2 eq "8.8.8.8");
 
        # Check if valid IP addresses are correctly recognised.
        foreach my $address ("1.2.3.4", "192.168.180.1", "127.0.0.1") {
@@ -416,34 +610,37 @@ sub testsuite() {
        }
 
        $result = &check_ip_address_and_netmask("192.168.180.0/255.255.255.0");
-       assert($result);
+       assert('check_ip_address_and_netmask("192.168.180.0/255.255.255.0")', $result);
 
        $result = &convert_netmask2prefix("255.255.254.0");
-       assert($result == 23);
+       assert('convert_netmask2prefix("255.255.254.0")', $result == 23);
 
        $result = &convert_prefix2netmask(8);
-       assert($result eq "255.0.0.0");
+       assert('convert_prefix2netmask(8)', $result eq "255.0.0.0");
 
        $result = &find_next_ip_address("1.2.3.4", 2);
-       assert($result eq "1.2.3.6");
+       assert('find_next_ip_address("1.2.3.4", 2)', $result eq "1.2.3.6");
 
        $result = &network_equal("192.168.0.0/24", "192.168.0.0/255.255.255.0");
-       assert($result);
+       assert('network_equal("192.168.0.0/24", "192.168.0.0/255.255.255.0")', $result);
 
        $result = &network_equal("192.168.0.0/24", "192.168.0.0/25");
-       assert(!$result);
+       assert('network_equal("192.168.0.0/24", "192.168.0.0/25")', !$result);
 
        $result = &network_equal("192.168.0.0/24", "192.168.0.128/25");
-       assert(!$result);
+       assert('network_equal("192.168.0.0/24", "192.168.0.128/25")', !$result);
 
        $result = &network_equal("192.168.0.1/24", "192.168.0.XXX/24");
-       assert($result);
+       assert('network_equal("192.168.0.1/24", "192.168.0.XXX/24")', !$result);
 
        $result = &ip_address_in_network("10.0.1.4", "10.0.0.0/8");
-       assert($result);
+       assert('ip_address_in_network("10.0.1.4", "10.0.0.0/8"', $result);
 
        $result = &ip_address_in_network("192.168.30.11", "192.168.30.0/255.255.255.0");
-       assert($result);
+       assert('ip_address_in_network("192.168.30.11", "192.168.30.0/255.255.255.0")', $result);
+
+       $result = &ip_address_in_network("192.168.30.11", "0.0.0.0/8");
+       assert('ip_address_in_network("192.168.30.11", "0.0.0.0/8")', !$result);
 
        print "Testsuite completed successfully!\n";