#!/bin/bash

INTERFACE=wg0
METRIC=31
TIMEOUT=180
INTERVAL=2

readarray -t ROUTES < <(echo "$WG_ROUTES" | tr , '\n')

netenclose () {
    local o1 o2 o3 o4 p1 p2 p3 p4 m1 m2 ip1 ip2 min
    IFS=./ read o1 o2 o3 o4 m1 <<< "$1"
    IFS=./ read p1 p2 p3 p4 m2 <<< "$2"

    ((min = m1 > m2 ? m2 : m1))
    ip1=$(((o1 << 24) + (o2 << 16) + (o3 << 8) + o4))
    ip2=$(((p1 << 24) + (p2 << 16) + (p3 << 8) + p4))

    if (( (ip1 >> (32 - min)) == (ip2 >> (32 - min)) )); then
        if ((m1 > m2)); then
            echo "$2"
        else
            echo "$1"
        fi
    else
        echo "0.0.0.0/0"
    fi
}


while true
do
  current_time=`date +%s`
  readarray -t peers < <(wg show wg0 dump)
  for peer in "${peers[@]}"
  do
   args=($(echo $peer))
   public_key=${args[0]}
   private_key=${args[1]}
   endpoint=${args[2]}
   route_list=${args[3]}
   handshake=${args[4]}
   bytes_recv=${args[5]}
   bytes_sent=${args[6]}
   keep_alive=${args[7]}

   # If it's a remote peer, the private key should be '(none)'
   # Otherwise, it's us
   if [ "$private_key" != "(none)" ]; then
    continue
   fi
    
   # The following checks ensure this peer is reachable and set the 'up'
   # flag accordingly
   if [ "$endpoint" == "(none)" ]; then
    up=false
   elif [ "$handshake" == "0" ]; then
    up=false
   elif [ "$bytes_recv" == "0" ]; then
    # A peer we have never received data from is not available
    up=false
   else
    delta="$((current_time - handshake))"
    if [ $delta -gt $TIMEOUT ]; then
     up=false
    else
     up=true
    fi
   fi

   readarray -t routes < <(echo "$route_list" | tr , '\n')
   for route in "${routes[@]}"
   do
    in_network=false
    for ROUTE in "${ROUTES[@]}"
    do
      parent_route=`netenclose $route $ROUTE`
      if [ "$parent_route" == "$ROUTE" ]; then
        in_network=true
        break
      fi
    done
    
    # Only manipulate routes that are in the global WG_ROUTES variable
    if [ $in_network == false ]; then
      continue
    fi
    
    if [ "$up" == "true" ]; then
      ip route add $route dev $INTERFACE metric $METRIC 2> /dev/null && echo "Added route $route from peer $public_key ($endpoint)"
    else
      ip route delete $route dev $INTERFACE 2> /dev/null && echo "Removed route $route from peer $public_key"
    fi
   done

  done
  sleep $INTERVAL
done