Current File : //usr/local/jetapps/usr/share/rear/lib/network-functions.sh
#
# ReaR networking functions.
#
# MASKS, prefix2netmask, num2ip, and get_device_by_hwaddr
# are originally from an old fedora-14 dhclient-script
# that was there used for DHCP setup and is still used in ReaR
# for  DHCP setup in skel/default/etc/scripts/dhcp-setup-functions.sh
# cf. https://github.com/rear/rear/issues/1517

NETMASKS_BINARY=( 0
                  10000000000000000000000000000000
                  11000000000000000000000000000000
                  11100000000000000000000000000000
                  11110000000000000000000000000000
                  11111000000000000000000000000000
                  11111100000000000000000000000000
                  11111110000000000000000000000000
                  11111111000000000000000000000000
                  11111111100000000000000000000000
                  11111111110000000000000000000000
                  11111111111000000000000000000000
                  11111111111100000000000000000000
                  11111111111110000000000000000000
                  11111111111111000000000000000000
                  11111111111111100000000000000000
                  11111111111111110000000000000000
                  11111111111111111000000000000000
                  11111111111111111100000000000000
                  11111111111111111110000000000000
                  11111111111111111111000000000000
                  11111111111111111111100000000000
                  11111111111111111111110000000000
                  11111111111111111111111000000000
                  11111111111111111111111100000000
                  11111111111111111111111110000000
                  11111111111111111111111111000000
                  11111111111111111111111111100000
                  11111111111111111111111111110000
                  11111111111111111111111111111000
                  11111111111111111111111111111100
                  11111111111111111111111111111110
                  11111111111111111111111111111111
                  -1 )

NETMASKS_DECIMAL=( $( for mask in "${NETMASKS_BINARY[@]}" ; do echo "ibase=2 ; $mask" | bc -l ; done ) )
# NETMASKS_DECIMAL is the same as
# MASKS=( 0
#         2147483648       3221225472       3758096384       4026531840
#         4160749568       4227858432       4261412864       4278190080
#         4286578688       4290772992       4292870144       4293918720
#         4294443008       4294705152       4294836224       4294901760
#         4294934528       4294950912       4294959104       4294963200
#         4294965248       4294966272       4294966784       4294967040
#         4294967168       4294967232       4294967264       4294967280
#         4294967288       4294967292       4294967294       4294967295
#         -1 )
# and those numbers match the following IP addresses according to the output of
#   for mask in "${NETMASKS_DECIMAL[@]}" ; do num2ip $mask ; done
#         0.0.0.0
#         128.0.0.0        192.0.0.0        224.0.0.0        240.0.0.0
#         248.0.0.0        252.0.0.0        254.0.0.0        255.0.0.0
#         255.128.0.0      255.192.0.0      255.224.0.0      255.240.0.0
#         255.248.0.0      255.252.0.0      255.254.0.0      255.255.0.0
#         255.255.128.0    255.255.192.0    255.255.224.0    255.255.240.0
#         255.255.248.0    255.255.252.0    255.255.254.0    255.255.255.0
#         255.255.255.128  255.255.255.192  255.255.255.224  255.255.255.240
#         255.255.255.248  255.255.255.252  255.255.255.254  255.255.255.255
#         255.255.255.255

# Output the IP address that match a decimal number:
function num2ip () {
    local num=$1
    let octet1="(num >> 24) & 0xff"
    let octet2="(num >> 16) & 0xff"
    let octet3="(num >> 8) & 0xff"
    let octet4="num & 0xff"
    echo $octet1.$octet2.$octet3.$octet4
}

# Output the netmask in IP address format nnn.nnn.nnn.nnn for a prefix, for example:
#   prefix2netmask 1   results   128.0.0.0
#   prefix2netmask 2   results   192.0.0.0
#   prefix2netmask 8   results   255.0.0.0
#   prefix2netmask 16  results   255.255.0.0
#   prefix2netmask 24  results   255.255.255.0
function prefix2netmask () {
    local prefix=$1
    test $prefix -gt 32 && BugError "function prefix2netmask() called with prefix '$prefix' > 32"
    num2ip ${NETMASKS_DECIMAL[$prefix]}
}

# Output all network interfaces (here falsely called 'device' and even in singular)
# each one on a separated line (i.e. each one separated by '\n')
# that belong to a hardware address (MAC address), for example on commandline:
#   # hwaddr="64:00:6A:64:C0:06"
#   # ip -o link | grep -v 'link/ieee802.11' | grep -i "$hwaddr"
#   2: eth0:  ...  link/ether 64:00:6a:64:c0:06  ...
#   3: br0:   ...  link/ether 64:00:6a:64:c0:06  ...
#   # ip -o link | grep -v 'link/ieee802.11' | grep -i "$hwaddr" | awk -F ": " '{print $2}'
#   eth0
#   br0
function get_device_by_hwaddr () {
    local hwaddr="$1"
    ip -o link | grep -v 'link/ieee802.11' | grep -i "$hwaddr" | awk -F ": " '{print $2}'
}

# Return 0 if args is a valid IPV4 ip_address
function is_ip () {
    local test_ip=$1
    [ -z "$test_ip" ] && BugError "function is_ip() called without argument."

    # ip_pattern variable is used to store a regex which validate an IPV4 address: "[0 to 255].[0 to 255].[0 to 255].[0 to 255]".
    local ip_pattern="^(([0-9]{1,2}|1[0-9]{2}|2([0-4][0-9]|5[0-5]))\.){3}([0-9]{1,2}|1[0-9]{2}|2([0-4][0-9]|5[0-5]))$"

    # $ip_pattern MUST NOT be quoted. Using a variable to store regex is used here to assure
    # compatibility with pre-3.2 bash version (SLES10).
    if [[ "$test_ip" =~ $ip_pattern ]] ; then
        return 0
    else
        return 1
    fi
}

# function which get the ipv4 address from a fqdn
function get_ip_from_fqdn () {
    local fqdn=$1
    [ -z "$fqdn" ] && BugError "function get_ip_from_name() called without argument."

    # Get a list of potential IPs that resolve $fqdn
    ip=( $(getent ahostsv4 $fqdn) ) || Error "Could not resolve $fqdn to IP"
    # Check if $ip is a valid IP
    is_ip "$ip" || Error "Got '$ip' from resolving $fqdn which is not an IP"
    Log "$fqdn resolved to $ip"
    echo "$ip"
}

function linearize_interfaces_file () {
    # Transform each network_file (debian network interfaces files) into temporary one_line_interfaces file
    # for easier sed substitution.
    # ex:
    #auto eth1
    #iface eth1 inet static
    #   address 9.9.9.9
    #   netmask 255.255.255.0
    #
    # will become: auto eth1;iface eth1 inet static;address 9.9.9.9;netmask 255.255.255.0;
    interfaces_file=$1
    test -z $interfaces_file && Error "debian_linearize_interface function called without argument (file_to_migrate)"

    awk '
        /^#/ {print}
        !/^ *$/ && !/^  *$/ && !/^#/ { PRINT=1 ; gsub("^ *","") ; ITEM=ITEM $0";" }
        (/^     *$/ || /^ *$/ || /^#/ ) && PRINT==1 { print ITEM ; ITEM="" ; PRINT=0 }
        END { if( ITEM!="" ) print ITEM }
    ' < "$interfaces_file"
}

function rebuild_interfaces_file_from_linearized () {
    # recreate a Debian/ubuntu network interafces files from a linearized file (see linearize_interfaces_file).
    # It is the opposite version of linearize_interfaces_file function.

    linearized_interfaces_file=$1
    test -z $interfaces_file && Error "rebuild_interfaces_file_from_linearized function called without argument (file_to_migrate)"

    awk -F\; '
    {
        INDENT=0
        for(i=1;i<=NF;i++) {
            if ($i ~ /^iface/) {
                print $i
                INDENT=1
            }
            else {
                if (INDENT == 1) print "    "$i ; else print $i
            }
        }
    }
    ' < $linearized_interfaces_file
}

function is_persistent_ethernet_name () {
    # this function is borrowed from /usr/lib/dracut/modules.d/40network/net-lib.sh (from CentOS 7)
    local _netif="$1"
    local _name_assign_type="0"

    [ -f "/sys/class/net/$_netif/name_assign_type" ] \
        && _name_assign_type=$(cat "/sys/class/net/$_netif/name_assign_type")

    # NET_NAME_ENUM 1
    [ "$_name_assign_type" = "1" ] && return 1

    # NET_NAME_PREDICTABLE 2
    [ "$_name_assign_type" = "2" ] && return 0

    case "$_netif" in
        # udev persistent interface names
        eno[0-9]|eno[0-9][0-9]|eno[0-9][0-9][0-9]*)
            ;;
        ens[0-9]|ens[0-9][0-9]|ens[0-9][0-9][0-9]*)
            ;;
        enp[0-9]s[0-9]*|enp[0-9][0-9]s[0-9]*|enp[0-9][0-9][0-9]*s[0-9]*)
            ;;
        enP*p[0-9]s[0-9]*|enP*p[0-9][0-9]s[0-9]*|enP*p[0-9][0-9][0-9]*s[0-9]*)
            ;;
        # biosdevname
        em[0-9]|em[0-9][0-9]|em[0-9][0-9][0-9]*)
            ;;
        p[0-9]p[0-9]*|p[0-9][0-9]p[0-9]*|p[0-9][0-9][0-9]*p[0-9]*)
            ;;
        *)
            return 1
    esac
    return 0
}