#!/bin/bash

# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
# 2018-08-30
# License: GPLv3+

# error on exit
set -e
# for handling jobspecs:
set -m

if [ -z "$AUTOPKGTEST_ARTIFACTS" ]; then
    d="$(mktemp -d)"
    remove="$d"
else
    d="$AUTOPKGTEST_ARTIFACTS"
fi
ip="${TESTIP:-127.$(( $RANDOM % 256 )).$(( $RANDOM % 256 )).$(( $RANDOM % 256 ))}"
kresd="${KRESD:-/usr/sbin/kresd}"
kdig="${KDIG:-$(command -v kdig)}"

declare -a kresd_args=(--addr="$ip@8053" --tls="$ip@8853" --noninteractive --config="$d/kresd.conf" --verbose --verbose --verbose)
if [ -n "$MODULE_DIR" ]; then
    kresd_args+=(-m "$MODULE_DIR")
fi

printf "%s + %s roundtrip tests\n------------\n    workdir: %s\n    IP addr: %s\n kresd args: %s\n" "$kresd" "$kdig" "$d" "$ip" "${kresd_args[*]}"

section() {
    printf "\n%s\n" "$1"
    sed 's/./-/g' <<<"$1"
}

cleanup () {
    section "cleaning up"
    find "$d" -ls
    tail -n +1 -v "$d"/*.err
    ctrl_socket=/run/knot-resolver/control/1
    if [ -S "$ctrl_socket" ]; then
        echo 'quit()' | socat STDIO "UNIX-CONNECT:$ctrl_socket"
        wait %1
    else
        pkill -KILL kresd ; true
    fi

    if [ "$remove" ]; then
        printf "\ncleaning up working directory %s\n" "$remove"
        rm -rf "$remove"
    fi
}
trap cleanup EXIT

section "make Certificate Authority key and certificate"
cat > "$d/ca.template" <<EOF
cn = "testing certificate authority (NOT FOR PRODUCTION)"
expiration_days = 12
ca
path_len = 1
nc_permit_dns = example
cert_signing_key
EOF
certtool --stdout-info --generate-privkey --outfile "$d/ca-key.pem"
certtool --stdout-info --generate-self-signed --template "$d/ca.template" --load-privkey "$d/ca-key.pem" --outfile "$d/ca-cert.pem"

section "make Bogus Certificate Authority key and certificate"
certtool --stdout-info --generate-privkey --outfile "$d/bogus-key.pem"
certtool --stdout-info --generate-self-signed --template "$d/ca.template" --load-privkey "$d/bogus-key.pem" --outfile "$d/bogus-cert.pem"

section "make End Entity key and certificate"
cat > "$d/ee.template" <<EOF
cn = "test.example"
dns_name = test.example
expiration_days = 10
signing_key
tls_www_server
EOF
certtool --stdout-info --generate-privkey --outfile "$d/ee-key.pem"
certtool --stdout-info --pubkey-info --load-privkey "$d/ee-key.pem" --outfile "$d/ee-pubkey.pem"
certtool --stdout-info --generate-certificate --load-ca-privkey "$d/ca-key.pem" --load-ca-certificate "$d/ca-cert.pem" --template "$d/ee.template" --load-pubkey "$d/ee-pubkey.pem" --outfile "$d/ee-cert.pem"

section "set up kresd daemon on $ip on ports 8053 (UDP, TCP) and 8853 (TLS)"
cat > "$d/kresd.conf" <<EOF
verbose(true)
modules = { 'hints > iterate' }
net.tls("$d/ee-cert.pem", "$d/ee-key.pem")
hints["monkeys.example"] = "127.15.23.5"

local path = '/run/knot-resolver/control/1'
local ok, err = pcall(net.listen, path, nil, { kind = 'control' })
if not ok then
    warn('bind to '..path..' failed '..err)
end
EOF
"$kresd" "${kresd_args[@]}" "$d" 2> "$d/kresd.err" &

sleep 1

section "test UDP with kdig"
x=$("$kdig" +short +time=2 +retry=0 @"$ip:8053" monkeys.example)
[ "$x" = "127.15.23.5" ]
echo "successful UDP request to $ip on port 8053"

section "test TCP with kdig"
x=$("$kdig" +short +tcp @"$ip:8053" monkeys.example)
[ "$x" = "127.15.23.5" ]
echo "successful TCP request to $ip on port 8053"

section "test opportunistic DNS-over-TLS with kdig"
x=$("$kdig" +short +tls @"$ip:8853" monkeys.example)
[ "$x" = "127.15.23.5" ]
echo "successful opportunistic DNS-over-TLS request to $ip on port 8853"

section "test strict DNS-over-TLS with kdig"
x=$("$kdig" +short +tls +tls-ca="$d/ca-cert.pem" +tls-hostname=test.example @"$ip:8853" monkeys.example)
[ "$x" = "127.15.23.5" ]
echo "successful strict DNS-over-TLS request to $ip on port 8853"

section "test invalid name with strict DNS-over-TLS with kdig"
# Kdig returns non-zero code if error since version 2.7.5
x=$("$kdig" +tls +tls-ca="$d/ca-cert.pem" +tls-hostname=notright.example @"$ip:8853" monkeys.example 2>"$d/badname.err" || true)
if [ "$x" ]; then
    printf >&2 "got: %s\nShould not have succeeded since name did not match!" "$x"
    false
fi
echo "successful strict DNS-over-TLS request failure when name mismatch to $ip on port 8853"

section "test bad authority with strict DNS-over-TLS with kdig"
# Kdig returns non-zero code if error since version 2.7.5
x=$("$kdig" +tls-ca="$d/bogus-cert.pem" +tls-hostname=test.example @"$ip:8853" monkeys.example 2>"$d/badca.err" || true)
if [ "$x" ]; then
    printf >&2 "got: %s\nShould not have succeeded since authority was wrong!" "$x"
    false
fi
echo "successful strict DNS-over-TLS request failure to $ip on port 8853"
