# -*-Shell-script-*-

# Original source from:
# Copyright (C) 2012 Amazon.com, Inc. or its affiliates.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at
#
#    http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
# OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the
# License.

# This file is not a stand-alone shell script; it provides functions
# to ec2 network scripts that source it.

# Changes and GCP-related additions:
# Copyright (C) 2018 velostrata.com
# All Rights Reserved.
#

# Set up a default search path.
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
export PATH

# metadata query requires an interface and hardware address
if [ -z "${INTERFACE}" ]; then
  exit
fi
HWADDR=$(cat /sys/class/net/${INTERFACE}/address 2>/dev/null)
if [ -z "${HWADDR}" ] && [ "${ACTION}" != "remove" ]; then
  exit
fi
export HWADDR

# generate a routing table number
RTABLE=${INTERFACE#eth}
let RTABLE+=10000

config_file="/etc/sysconfig/network-scripts/ifcfg-${INTERFACE}"

# utility methods for metadata extraction
MY_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source ${MY_DIR}/alias-ip-utils

# make no changes to unmanaged interfaces
if [ -s ${config_file} ]; then
  unmanaged=$(LANG=C grep -l "^[[:space:]]*EC2SYNC=no\([[:space:]#]\|$\)" $config_file)
  if [ "${config_file}" == "${unmanaged}" ]; then
    exit
  fi
fi

function arr_value_exists() {
  local value array
  value=$1
  shift

  array=()
  array+=($*)
  for e in ${array[*]}; do
    if [[ "${e}" == "${value}" ]] ; then
      return 0
    fi
  done

  return 1
}

function match_rule() {
  local ip rules
  ip=$1
  shift

  rules=()
  rules+=($*)
  for rule in ${rules[*]}; do
    split=(${rule//:/ })
    if [[ "${split[1]}" == "${ip}" ]] ; then
      echo ${rule}
      return
    fi
  done
}

get_cidr() {
	if is_gcp && gcp_should_apply_ip_ranges ; then
		get_gcp_cidr 0
	fi
}

get_ipv4s() {
	if is_gcp && gcp_should_apply_ip_ranges ; then
		get_gcp_ipv4s
	fi
}

get_secondary_ipv4s() {
  if is_gcp && gcp_should_apply_ip_ranges ; then
		get_gcp_ipv4s
	fi
}

remove_aliases() {
  /sbin/ip addr flush dev ${INTERFACE} secondary
}

rewrite_aliases() {
  wait_for_meta
  aliases=$(get_secondary_ipv4s)
  if [ ${#aliases[*]} -eq 0 ]; then
    remove_aliases
    return
  fi
  # The network prefix can be provided in the environment by
  # e.g. DHCP, but if it's not available then we need it to
  # correctly configure secondary addresses.
  #if [ -z "${PREFIX}" ]; then
  #  cidr=$(get_cidr)
  #  PREFIX=$(echo ${cidr}|cut -d/ -f2)
  #fi
  #[ -n "${PREFIX##*[!0-9]*}" ] || return
  # Retrieve a list of secondary IP addresses on the interface.
  # Treat this as the stale list. For each IP address obtained
  # from metadata, cross it off the stale list if present, or
  # add it to the interface otherwise. Then, remove any address
  # remaining in the stale list.
  secondaries=()
  for secondary in $(/sbin/ip addr list dev ${INTERFACE} secondary \
                     |grep "inet .* secondary ${INTERFACE}" \
                     |awk '{print $2}'|cut -d/ -f1); do
    secondaries+=(${secondary})
  done
  for alias in ${aliases}; do
    if arr_value_exists ${alias} ${secondaries[*]} ; then
      secondaries=(${secondaries[@]/${alias}})
    else
      /sbin/ip addr add ${alias} brd + dev ${INTERFACE}
    fi
  done
  for secondary in "${secondaries[*]}"; do
    /sbin/ip addr del ${secondary} dev ${INTERFACE}
  done
}

remove_rules() {
  for rule in $(/sbin/ip rule list \
                |grep "from .* lookup ${RTABLE}" \
                |awk -F: '{print $1}'); do
    /sbin/ip rule delete pref "${rule}"
  done
}

rewrite_rules() {
  wait_for_meta
  ips_cidr=($(get_ipv4s))
  ips=()
  for ip in ${ips_cidr[@]}; do
  ips+=($(echo $ip | cut -d '/' -f 1))
  done
  if [ ${#ips[*]} -eq 0 ]; then
    remove_rules
    return
  fi
  # Retrieve a list of IP rules for the route table that belongs
  # to this interface. Treat this as the stale list. For each IP
  # address obtained from metadata, cross the corresponding rule
  # off the stale list if present. Otherwise, add a rule sending
  # outbound traffic from that IP to the interface route table.
  # Then, remove all other rules found in the stale list.
  rules=()
  for rule in $(/sbin/ip rule list \
                |grep "from .* lookup ${RTABLE}" \
                |awk '{print $1$3}'); do
    rules+=(${rule})
  done
  for ip in ${ips[@]}; do
    match=$(match_rule ${ip} ${rules[*]})
    if [ ! -z "${match}" ] ; then
      rules=(${rules[@]/${match}})
    else
      /sbin/ip rule add from ${ip} lookup ${RTABLE}
    fi
  done
  for entry in ${rules[*]}; do
    split=(${rule//:/ })
    /sbin/ip rule delete pref ${split[0]}
  done
}
