interface_information.sh 5.98 KB
##
# \file

# To each interface a set of caller functions exist, that take an instance
# of an object and then in turn call the implementation for the class of
# this object. If there is none within the class it looks into its
# parent class and so forth.
#
# This is somewhat similar to late binding in real OOP languages, but
# by far not so elaborated. This is not a real object oriented language
# and will surely never ever provide all features these have.
#
# That said it has proven very usefull for me to orgnize code and prevent
# code duplication.
#
# \author	Georg Hopp
#
# \copyright
# Copyright © 2014 Georg Hopp
#
# 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/>.
#

##
# retrieve interfaces. I prefer using ip if it is
# available, else I fallback to ifconfig... don't know
# how to retrieve this information on other systems.
# This also exports the environment variables.
#
gather_interface_info() {
	[ -z "${NINTERFACES}" ] || return

	local NO=1

	if [ ${IP} ]
	then
		gather_if_info_ip
	else
		if [ ${IFCONFIG} ]
		then
			gather_if_info_ifconfig
		else
			${LOGGER} -p local0.warn 'Found no way to retrieve interface information.'
		fi
	fi

	export NINTERFACES

	while [ ${NO} -le ${NINTERFACES:=0} ]
	do
		export IF${NO}_NAME IF${NO}_MAC IF${NO}_STATE IF${NO}_IPV4 IF${NO}_IPV6
		NO=$((NO+1))
	done
}

##
# get the interface information from the ip tool
#
gather_if_info_ip() {
	eval $(${IP} -o link | ${AWK} '{
		sub(/:/,"",$1);
		ifno=$1;
		sub(/:/,"",$2);
		name=$2;
		classes=classes "net_iface_" name " ";
		for (i=3; i<NF; i++) {
			if ($i == "state") {
				i++; state=$i
			}
			if ($i ~ /link/) {
				i++; mac=$i;
				classes=classes mac " "
			}
		}
		print "IF" no "_NAME=" name ";IF" no "_STATE=" state ";IF" no "_MAC=" mac ";";
		if ("UP" == state) classes=classes mac " ";
		if_numbers=if_numbers " " ifno;
		no+=1
	}
	BEGIN {
		classes="";
		no=1;
		if_numbers=""
	}
	END {
		print "set_class " classes ";";
		print "NINTERFACES=" FNR ";"
		sub(/^ */,"",if_numbers);
		sub(/ *$/,"",if_numbers);
		print "IF_NUMBERS=\"" if_numbers "\";";
	}')

	eval $(${IP} -o addr | ${AWK} -v if_numbers="${IF_NUMBERS}" '{
        sub(/:/,"",$1);
        if_no=$1;
		no=r_if_numbers[if_no];
        if ($3 == "inet") {
            split($4,addr,/[\/]/);
			ipv4=ipv4 addr[1] " ";
			network(no, addr[1], addr[2]);
            classes=classes addr[1] " "
        }
        if ($3 == "inet6") {
            split($4,addr,/[\/]/);
			ipv6=ipv6 addr[1] " ";
            classes=classes addr[1] " "
        }
    }
	$1 != current_if {
		print "IF" no "_IPV4=\"" ipv4 "\";";
		print "IF" no "_IPV6=\"" ipv6 " \";";
        print "IF" no "_NETWORK=\"" networks "\";";
        print "IF" no "_MASK=\"" netmasks "\";";
		current_if=$1;
		ipv6=ipv4="";
		networks=netmasks="";
	}
    BEGIN {
        classes="";
		sub(/^ */,"",if_numbers);
		sub(/ *$/,"",if_numbers);
		split(if_numbers,tmp_array,/ /);
		for(no in tmp_array) {
			if_no=tmp_array[no];
			r_if_numbers[if_no]=no;
		}
		current_if=$1;
    }
    END {
        print "set_class " classes ";"
    }
    function network(no, addr, cidr) {
        mask="";
        net="";
        full_octets=cidr/8;
        part_octets=cidr%8;
        split(addr,parts,/\./);
        for(i=1; i<5; i++) {
            if(i-1 < full_octets) {
                mask=mask "255";
                net=net parts[i];
            } else {
                if (i-1 == full_octets) {
                    mpart=256-lshift(1, 8-part_octets);
                    mask=mask mpart;
					net=net and(parts[i],mpart);
                } else {
                    mask=mask "0";
                    net=net "0";
                }
            }
            if (i < 4) {
                mask=mask ".";
                net=net ".";
            }
        }
		classes=classes net " ";
		networks=networks net " ";
		netmasks=netmasks mask " ";
	}')
}

##
# get interface data via the ifconfig tool
# FIXME This is outdated. It does not set classes at all.
#
gather_if_info_ifconfig() {
	eval $(${IFCONFIG} -a | ${AWK} --non-decimal-data '
	/^[^ \t]/ {
		if ("UP" == state) classes=classes mac " ";
		if ("" != name) {
			print "IF" no "_NAME=" name ";IF" no "_STATE=" state ";IF" no "_MAC=" mac ";" \
				"IF" no "_IPV4=\"" ipv4 "\";" \
				"IF" no "_IPV6=\"" ipv6 "\";" \
				"IF" no "_NETWORK=\"" networks "\";" \
				"IF" no "_MASK=\"" netmasks "\";";
			no++;
		}
		ipv4=ipv6=mac="";
		networks=netmasks="";
		sub(/:/,"",$1);
		name=$1;
		state="DOWN";
	}
	/ether/  { mac=$2 }
	/inet /  {
		ipv4=ipv4 $2 " ";
		if("0x" == substr($4,0,2)) {
			mask=netmask sprintf("%d.%d.%d.%d ",
				"0x" substr($4,2,2),
				"0x" substr($4,4,2),
				"0x" substr($4,6,2),
				"0x" substr($4,8,2));
		} else {
			mask=mask $4 " ";
		}
        split($2,parts,/\./);
        split(mask,mparts,/\./);
		for(i=1; i<5; i++) {
			net=net and(parts[i],mparts[i]);
			if(i < 4) net=net ".";
		}
		classes=classes $2 " ";
		classes=classes net " ";
		networks=networks net " ";
		netmasks=netmasks mask " ";
	}
	/inet6/  {
		sub(/%.*/,"",$2);
		ipv6=ipv6 $2 " ";
		classes=classes $2 " "
	}
	(/status/ && /active/) || /^lo[0-9]/ { state="UP" }
	BEGIN {
		classes="";
		state="DOWN";
		no=1;
		mac="";
	}
	END {
		if ("UP" == state) classes=classes mac " ";
		print "IF" no "_NAME=" name ";IF" no "_STATE=" state ";IF" no "_MAC=" mac ";" \
			"IF" no "_IPV4=\"${IF" no "_IPV4}" ipv4 " \";" \
			"IF" no "_IPV6=\"${IF" no "_IPV6}" ipv6 " \";";
		print "set_class " classes ";";
		print "NINTERFACES=" no
	}')
}

# vim: set ts=4 sw=4: