#!/usr/bin/env bash
#
# Syd: rock-solid application kernel
# dev/syd-net.bash: Create a virtual network for the given syd container.
#
# Copyright (c) 2024 Ali Polatel <alip@chesswob.org>
#
# SPDX-License-Identifier: GPL-3.0

# Default values
BRIDGE_ADDRESS='10.10.10.1/24'
BRIDGE_NAME='syd-br0'
CONTAINER_ADDRESS='10.10.10.2/24'
PID=''
VETH_NAME_PREFIX='syd'

# Function to print error message and exit
die() {
    echo >&2 "$*"
    exit 1
}

# Function to generate a unique veth name
veth_name() {
    local uuid=$(cat /proc/sys/kernel/random/uuid | cut -d '-' -f1)
    echo "${VETH_NAME_PREFIX}-${uuid}-0"
}

# Parse options
while getopts "B:b:C:p:v:" opt; do
    case $opt in
        B) BRIDGE_ADDRESS=$OPTARG ;;
        b) BRIDGE_NAME=$OPTARG ;;
        C) CONTAINER_ADDRESS=$OPTARG ;;
        p) PID=$OPTARG ;;
        v) VETH_NAME_PREFIX=$OPTARG ;;
        *) die "${0##*/} [-bBcpv]" ;;
    esac
done

# Check for required PID argument
[ -z "$PID" ] && die 'Missing required -p argument for PID'
kill -0 "$PID" || die 'Invalid PID'

# From this point report commands and make errors are fatal.
set -ex

# Create the bridge device if it does not exist
if ! ip link show "$BRIDGE_NAME" &>/dev/null; then
    ip link add name "$BRIDGE_NAME" type bridge
    ip addr add "$BRIDGE_ADDRESS" dev "$BRIDGE_NAME"
    ip link set dev "$BRIDGE_NAME" up
fi

# Create the veth pair with a unique name
VETH_HOST=$(veth_name)
VETH_CONTAINER=${VETH_HOST%0}1

ip link add "$VETH_HOST" type veth peer name "$VETH_CONTAINER"
ip link set "$VETH_HOST" up
ip link set "$VETH_CONTAINER" up

# Attach one side of the veth to the bridge
ip link set "$VETH_HOST" master "$BRIDGE_NAME"

# Move the other side of the veth to the container's network namespace
ip link set "$VETH_CONTAINER" netns "$PID"

# Setup NAT using iptables
FILTER_NAME=$BRIDGE_NAME
iptables -t nat -N "$FILTER_NAME" || true
iptables -t nat -F "$FILTER_NAME"

iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j "$FILTER_NAME"
iptables -t nat -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j "$FILTER_NAME"
iptables -t nat -A POSTROUTING -s "${BRIDGE_ADDRESS}" ! -o "$BRIDGE_NAME" -j MASQUERADE
iptables -t nat -A "$FILTER_NAME" -i "$BRIDGE_NAME" -j RETURN

# Setup the container's network interface (inside the syd container)
nsenter --net=/proc/"$PID"/ns/net ip addr add "$CONTAINER_ADDRESS" dev "$VETH_CONTAINER"
nsenter --net=/proc/"$PID"/ns/net ip link set "$VETH_CONTAINER" up
nsenter --net=/proc/"$PID"/ns/net ip route add default via "${BRIDGE_ADDRESS%/*}"

echo "Network setup complete for syd container with PID $PID"
