#!/bin/bash
# Copyright 2016 The Kubernetes Authors 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.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License 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.

set -o errexit
set -o nounset
set -o pipefail
set -o errtrace

IP_CIDR=$(ip addr show eth0 | grep -w inet | awk '{ print $2; }')
IP=$(echo $IP_CIDR | sed 's,/.*,,')

function dind::setup-bridge {
  # create dind0 bridge and attach it to the veth interface eth0
  brctl addbr dind0
  brctl addif dind0 eth0
  ip link set dind0 up
  
  # move ip to the bridge and restore routing via the old gateway
  NETWORK_SIZE=$(echo $IP_CIDR | sed 's,.*/,,')
  DEFAULT_ROUTE=$(ip route | grep default | sed 's/eth0/dind0/')
  DEFAULT_GW=$(echo $DEFAULT_ROUTE|awk '{print $3;}')
  
  ip addr del $IP_CIDR dev eth0
  ip addr add $IP_CIDR dev dind0
  ip route add $DEFAULT_ROUTE
  
  # compute a network for the containers to live in
  # by adding CNI_BRIDGE_NETWORK_OFFSET to the current IP and cutting off
  # non-network bits according to CNI_BRIDGE_NETWORK_SIZE
  CNI_BRIDGE_NETWORK_SIZE=${CNI_BRIDGE_NETWORK_SIZE:-24}
  NETWORK=$(ip route | grep dind0 | grep -v default | sed 's,/.*,,')
  
  WILDCARD=$(ipcalc $IP_CIDR | grep Wildcard | awk '{print $2;}')
  IFS=. read -r i1 i2 i3 i4 <<< ${IP}
  IFS=. read -r n1 n2 n3 n4 <<< ${NETWORK}
  IFS=. read -r o1 o2 o3 o4 <<< ${CNI_BRIDGE_NETWORK_OFFSET}
  IFS=. read -r w1 w2 w3 w4 <<< ${WILDCARD}
  
  IP_PLUS_OFFSET=$(printf "%d.%d.%d.%d\n" \
                          "$(( n1 + ((i1 - n1 + o1) & w1) ))" \
                          "$(( n2 + ((i2 - n2 + o2) & w2) ))" \
                          "$(( n3 + ((i3 - n3 + o3) & w3) ))" \
                          "$(( n4 + ((i4 - n4 + o4) & w4) ))")
  
  HOST_MIN=$(ipcalc $IP_PLUS_OFFSET/$CNI_BRIDGE_NETWORK_SIZE | grep HostMin | awk '{print $2;}')
  HOST_MAX=$(ipcalc $IP_PLUS_OFFSET/$CNI_BRIDGE_NETWORK_SIZE | grep HostMax | awk '{print $2;}')
  echo "Using ${HOST_MIN} .. ${HOST_MAX} for docker containers"
  
  cat >/etc/cni/net.d/cni.conf <<EOF
{
    "name": "dindnet",
    "type": "bridge",
    "bridge": "dind0",
    "ipam": {
        "type": "host-local",
        "subnet": "${NETWORK}/${NETWORK_SIZE}",
        "rangeStart": "${HOST_MIN}",
        "rangeEnd": "${HOST_MAX}",
        "gateway": "${DEFAULT_GW}",
        "routes": [
            { "dst": "0.0.0.0/0" }
        ]
    }
}
EOF
}

if [[ "${CNI_BRIDGE_NETWORK_OFFSET:-}" ]]; then
   dind::setup-bridge
fi

# make docker's kube-dns friendly
old_ns="$(awk '/^nameserver/ {print $2; exit}' /etc/resolv.conf)"
if [[ ${old_ns} ]]; then
  # sed -i doesn't work here because of docker's handling of /etc/resolv.conf
  sed "s/^nameserver.*/nameserver ${IP}/" /etc/resolv.conf >/etc/resolv.conf.updated
  cat /etc/resolv.conf.updated >/etc/resolv.conf
  # rm /tmp/resolv.conf.updated
  while true; do
    socat udp4-recvfrom:53,reuseaddr,fork,bind=${IP} UDP:${old_ns}:53 || true
    echo "WARNING: restarting socat" >&2
  done
else
  echo "WARNING: couldn't get nameserver" >&2
  exit 1  
fi
