#!/bin/bash

# test suite for hddemux

# requires:
#  - nginx
#  - knot-resolver
#  - kdig (from knot-dnsutils)
#  - curl
#  - certtool (from gnutls-bin)

# environment variables:
#  - WORKDIR: a place for all generated files.
#             if unset, it will be auto-generated.
#             it will be created as needed.
#             if the directory doesn't currently exist, it will be cleaned up at exit.
#             if it already exists, it will not be cleaned up.
#  -  TESTIP: the IP address to use for testing.
#             the user needs to be able to open listening sockets, and to connect to them
#             by default, 127.7.8.9

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

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

hddemux=$(which hddemux) || hddemux=./hddemux

[ -x "$hddemux" ]

if [ -z "$WORKDIR" ]; then
    d="$(mktemp -d)"
    remove="$d"
else
    d="$WORKDIR"
fi
ip="${TESTIP:-127.7.8.9}"

printf "hddemux test\n------------\n  binary: %s\n workdir: %s\n IP addr: %s\n" "$hddemux" "$d" "$ip"

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

cleanup () {
    section "cleaning up"
    /usr/sbin/nginx -c "$d/nginx.conf" -p "$d" -s stop 2> "$d/nginx-stop.err" || true
    kill %2 || true
    kill %1 || true
    if [ "$remove" ]; then
        printf "cleaning up working directory %s\n" "$remove"
        rm -rf "$remove"
    fi
}

trap cleanup EXIT


section "simple failing run"
# hddemux with no arguments and no listening file descriptors should fail:
if "$hddemux"; then
    false
fi


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 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 "make knot-resolver configuration on $ip:8853"
cat > "$d/kresd.conf" <<EOF
modules = { 'hints > iterate' }
net.tls("$d/ee-cert.pem", "$d/ee-key.pem")
hints["monkeys.example"] = "127.15.23.5"
EOF
systemd-socket-activate -l "$ip:8853" --fdname=tls /usr/sbin/kresd -c "$d/kresd.conf" "$d" 2> "$d/kresd.err" &

section "make hddeumx configuration on $ip:2000"
systemd-socket-activate -l "$ip:2000" -E=HTTP_TARGET="$ip:8853" -E DNS_TARGET="$ip:8853" "$hddemux" 2> "$d/hddemux.err" &

section "set up nginx on $ip:4433"
cat >"$d/nginx.conf" <<EOF
error_log stderr;
worker_processes 1;
pid nginx.pid;

events {
 worker_connections 10;
}
http {
 default_type text/plain;
 ssl_protocols TLSv1.2;
 ssl_prefer_server_ciphers on;
 server {
  listen $ip:4433 ssl;
  server_name test.example;
  ssl_certificate ee-cert.pem;
  ssl_certificate_key ee-key.pem;
  access_log access.log;
  location / {
   root data;
   index index.txt;
  }
 }
}
EOF
mkdir -p "$d/data"
echo "Hello, world!" > "$d/data/index.txt"
/usr/sbin/nginx -c "$d/nginx.conf" -p "$d" 2> "$d/nginx.err"

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

section "test with curl"
x=$(curl --silent --show-error --cacert "$d/ca-cert.pem" --resolve "test.example:2000:$ip" --resolve "test.example:4433:$ip" https://test.example:4433/)
[ "$x" = "Hello, world!" ]
echo "successful HTTPS request to $ip on port 2000"
