#!/bin/sh
set -eu

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
CONFIG_PATH="/etc/banger-network.conf"

if ! command -v ip >/dev/null 2>&1; then
  exit 0
fi

guest_ip=""
gateway_ip=""
netmask=""
iface_hint=""
dns1=""
dns2=""

load_file_config() {
  if [ ! -r "$CONFIG_PATH" ]; then
    return 1
  fi

  # shellcheck disable=SC1090
  . "$CONFIG_PATH"
  guest_ip="${GUEST_IP:-}"
  gateway_ip="${GATEWAY_IP:-}"
  netmask="${NETMASK:-}"
  iface_hint="${INTERFACE:-}"
  dns1="${DNS1:-}"
  dns2="${DNS2:-}"
  [ -n "$guest_ip" ]
}

load_cmdline_config() {
  cmdline="$(cat /proc/cmdline 2>/dev/null || true)"
  ip_arg=""
  for arg in $cmdline; do
    case "$arg" in
      ip=*)
        ip_arg="${arg#ip=}"
        break
        ;;
    esac
  done

  if [ -z "$ip_arg" ]; then
    return 1
  fi

  guest_ip="$(field 1)"
  gateway_ip="$(field 3)"
  netmask="$(field 4)"
  iface_hint="$(field 6)"
  dns1="$(field 8)"
  dns2="$(field 9)"
  [ -n "$guest_ip" ]
}

field() {
  printf '%s' "$ip_arg" | cut -d: -f"$1"
}

mask_to_prefix() {
  case "$1" in
    [0-9]|[1-2][0-9]|3[0-2])
      printf '%s\n' "$1"
      return 0
      ;;
  esac

  prefix=0
  old_ifs=$IFS
  IFS=.
  set -- $1
  IFS=$old_ifs
  if [ "$#" -ne 4 ]; then
    return 1
  fi

  for octet in "$@"; do
    case "$octet" in
      255) prefix=$((prefix + 8)) ;;
      254) prefix=$((prefix + 7)) ;;
      252) prefix=$((prefix + 6)) ;;
      248) prefix=$((prefix + 5)) ;;
      240) prefix=$((prefix + 4)) ;;
      224) prefix=$((prefix + 3)) ;;
      192) prefix=$((prefix + 2)) ;;
      128) prefix=$((prefix + 1)) ;;
      0) ;;
      *) return 1 ;;
    esac
  done

  printf '%s\n' "$prefix"
}

find_iface() {
  hint="$1"
  if [ -n "$hint" ] && [ -d "/sys/class/net/$hint" ]; then
    printf '%s\n' "$hint"
    return 0
  fi

  for path in /sys/class/net/*; do
    [ -e "$path" ] || continue
    iface="${path##*/}"
    if [ "$iface" = "lo" ]; then
      continue
    fi
    printf '%s\n' "$iface"
    return 0
  done

  return 1
}

if ! load_file_config; then
  load_cmdline_config || exit 0
fi

if [ -z "$guest_ip" ]; then
  exit 0
fi

iface=""
attempt=0
while [ "$attempt" -lt 50 ]; do
  iface="$(find_iface "$iface_hint" || true)"
  if [ -n "$iface" ]; then
    break
  fi
  attempt=$((attempt + 1))
  sleep 0.2
done

if [ -z "$iface" ]; then
  exit 0
fi

prefix="$(mask_to_prefix "$netmask" || printf '24\n')"

ip link set "$iface" up
ip addr replace "$guest_ip/$prefix" dev "$iface"

if [ -n "$gateway_ip" ]; then
  ip route replace default via "$gateway_ip" dev "$iface"
fi

if [ -n "$dns1" ] || [ -n "$dns2" ]; then
  tmp_resolv="/tmp/.banger-resolv.conf.$$"
  : > "$tmp_resolv"
  if [ -n "$dns1" ]; then
    printf 'nameserver %s\n' "$dns1" >> "$tmp_resolv"
  fi
  if [ -n "$dns2" ]; then
    printf 'nameserver %s\n' "$dns2" >> "$tmp_resolv"
  fi
  if [ -s "$tmp_resolv" ]; then
    cat "$tmp_resolv" > /etc/resolv.conf
  fi
  rm -f "$tmp_resolv"
fi
