#!/bin/sh /etc/rc.common

USE_PROCD=1

START=30
STOP=51

stubby="/usr/sbin/stubby"
stubby_init="/etc/init.d/stubby"
stubby_config_dir="/var/etc/stubby"
stubby_config="$stubby_config_dir/stubby.yml"
stubby_pid_file="/var/run/stubby.pid"
stubby_manual_config="/etc/stubby/stubby.yml"
stubby_default_appdata_dir="/var/lib/stubby"

boot()
{
    stubby_boot=1
    rc_procd start_service
}

generate_config()
{
    local round_robin
    local tls_authentication
    local tls_query_padding_blocksize
    local edns_client_subnet_private
    local idle_timeout
    local appdata_dir
    local trust_anchors_backoff_time
    local tls_connection_retries
    local tls_backoff_time
    local timeout
    local dnssec_return_status
    local dnssec_trust_anchors
    local listen_addresses_section=0
    local dns_transport_list_section=0
    local upstream_recursive_servers_section=0
    local command_line_arguments
    local log_level
    local tls_cipher_list
    local tls_ciphersuites
    local tls_min_version
    local tls_max_version

    # Generate configuration. See: https://github.com/getdnsapi/stubby/blob/develop/stubby.yml.example
    echo "# Autogenerated configuration from uci data"
    echo "resolution_type: GETDNS_RESOLUTION_STUB"

    config_get round_robin "global" round_robin_upstreams "1"
    echo "round_robin_upstreams: $round_robin"

    config_get appdata_dir "global" appdata_dir "$stubby_default_appdata_dir"
    echo "appdata_dir: \"$appdata_dir\""

    config_get trust_anchors_backoff_time "global" trust_anchors_backoff_time "2500"
    echo "trust_anchors_backoff_time: $trust_anchors_backoff_time"

    config_get tls_connection_retries "global" tls_connection_retries ""
    if [ -n "$tls_connection_retries" ]; then
        echo "tls_connection_retries: $tls_connection_retries"
    fi

    config_get tls_backoff_time "global" tls_backoff_time ""
    if [ -n "$tls_backoff_time" ]; then
        echo "tls_backoff_time: $tls_backoff_time"
    fi

    config_get timeout "global" timeout ""
    if [ -n "$timeout" ]; then
        echo "timeout: $timeout"
    fi

    config_get_bool tls_authentication "global" tls_authentication "1"
    if [ "$tls_authentication" = "1" ]; then
        echo "tls_authentication: GETDNS_AUTHENTICATION_REQUIRED"
    else
        echo "tls_authentication: GETDNS_AUTHENTICATION_NONE"
    fi

    config_get_bool dnssec_return_status "global" dnssec_return_status "0"
    if [ "$dnssec_return_status" = "1" ]; then
        echo "dnssec_return_status: GETDNS_EXTENSION_TRUE"
    fi

    config_get dnssec_trust_anchors "global" dnssec_trust_anchors ""
    if [ -n "$dnssec_trust_anchors" ]; then
        echo "dnssec_trust_anchors: \"$dnssec_trust_anchors\""
    fi

    config_get tls_query_padding_blocksize "global" tls_query_padding_blocksize "128"
    echo "tls_query_padding_blocksize: $tls_query_padding_blocksize"

    config_get_bool edns_client_subnet_private "global" edns_client_subnet_private "1"
    echo "edns_client_subnet_private: $edns_client_subnet_private"

    config_get idle_timeout "global" idle_timeout "10000"
    echo "idle_timeout: $idle_timeout"

    config_get tls_cipher_list "global" tls_cipher_list ""
    if [ -n "$tls_cipher_list" ]; then
        echo "tls_cipher_list: \"$tls_cipher_list\""
    fi

    config_get tls_ciphersuites "global" tls_ciphersuites ""
    if [ -n "$tls_ciphersuites" ]; then
        echo "tls_ciphersuites: \"$tls_ciphersuites\""
    fi

    config_get tls_min_version "global" tls_min_version ""
    if [ -n "$tls_min_version" ]; then
        echo "tls_min_version: GETDNS_TLS${tls_min_version/\./_}"
    fi

    config_get tls_max_version "global" tls_max_version ""
    if [ -n "$tls_max_version" ]; then
        echo "tls_max_version: GETDNS_TLS${tls_max_version/\./_}"
    fi

    handle_listen_address_value()
    {
        local value="$1"

        if [ "$listen_addresses_section" = 0 ]; then
            echo "listen_addresses:"
            listen_addresses_section=1
        fi
        echo "  - $value"
    }
    config_list_foreach "global" listen_address handle_listen_address_value

    handle_dns_transport_list_value()
    {
        local value="$1"

        if [ "$dns_transport_list_section" = 0 ]; then
            echo "dns_transport_list:"
            dns_transport_list_section=1
        fi
        echo "  - $value"
    }
    config_list_foreach "global" dns_transport handle_dns_transport_list_value

    handle_resolver()
    {
        local config=$1
        local address
        local tls_auth_name
        local tls_port
        local tls_pubkey_pinset_section=0
        local tls_cipher_list
        local tls_ciphersuites
        local tls_min_version
        local tls_max_version

        if [ "$upstream_recursive_servers_section" = 0 ]; then
            echo "upstream_recursive_servers:"
            upstream_recursive_servers_section=1
        fi
        config_get address "$config" address
        echo "  - address_data: \"$address\""

        config_get tls_auth_name "$config" tls_auth_name
        echo "    tls_auth_name: \"$tls_auth_name\""

        config_get tls_port "$config" tls_port ""
        if [ -n "$tls_port" ]; then
            echo "    tls_port: $tls_port"
        fi

        config_get tls_cipher_list "$config" tls_cipher_list ""
        if [ -n "$tls_cipher_list" ]; then
            echo "    tls_cipher_list: \"$tls_cipher_list\""
        fi

        config_get tls_ciphersuites "$config" tls_ciphersuites ""
        if [ -n "$tls_ciphersuites" ]; then
            echo "    tls_ciphersuites: \"$tls_ciphersuites\""
        fi

        config_get tls_min_version "$config" tls_min_version ""
        if [ -n "$tls_min_version" ]; then
            echo "    tls_min_version: GETDNS_TLS${tls_min_version/\./_}"
        fi

        config_get tls_max_version "$config" tls_max_version ""
        if [ -n "$tls_max_version" ]; then
            echo "    tls_max_version: GETDNS_TLS${tls_max_version/\./_}"
        fi

        handle_resolver_spki()
        {
            local val="$1"
            local digest="${val%%/*}"
            local value="${val#*/}"

            if [ "$tls_pubkey_pinset_section" = 0 ]; then
                echo "    tls_pubkey_pinset:"
                tls_pubkey_pinset_section=1
            fi
            echo "      - digest: \"$digest\""
            echo "        value: $value"
        }
        config_list_foreach "$config" spki handle_resolver_spki
    }

    config_foreach handle_resolver resolver
} > "$config_file_tmp"

start_service() {
    local config_file_tmp
    local manual
    local log_level
    local command_line_arguments
    local appdata_dir

    mkdir -p "$stubby_config_dir"

    config_load "stubby"

    config_get_bool manual "global" manual "0"

    if [ "$manual" = "1" ]; then
        cp "$stubby_manual_config" "$stubby_config"
    else
        config_file_tmp="$stubby_config.$$"
        generate_config
        mv "$config_file_tmp" "$stubby_config"
    fi
    chown stubby:stubby "$stubby_config"
    chmod 0400 "$stubby_config"

    config_get appdata_dir "global" appdata_dir "$stubby_default_appdata_dir"
    if [ -n "$appdata_dir" ]; then
        if mkdir -p "$appdata_dir"; then
            chown stubby:stubby "$appdata_dir"
            chmod 0700 "$appdata_dir"
        fi
    fi

    config_get command_line_arguments "global" command_line_arguments ""

    config_get log_level "global" log_level ""

    if [ "$("$stubby_init" enabled; printf "%u" $?)" -eq 0 ]; then
        if [ -n "$stubby_boot" ]; then
            local trigger
            trigger="$(uci_get stubby global trigger)"
            if [ "$trigger" != "timed" ]; then
                return 0
            fi
        fi
        procd_open_instance "stubby"
        procd_set_param command "$stubby" -C "$stubby_config"
        if [ -n "$log_level" ]; then
            procd_append_param command -v "$log_level"
        fi
        if [ -n "$command_line_arguments" ]; then
            procd_append_param command "$command_line_arguments"
        fi
        procd_set_param respawn
        procd_set_param file "$stubby_config"
        procd_set_param stdout 1
        procd_set_param stderr 1
        procd_set_param pidfile "$stubby_pid_file"
        procd_set_param user stubby
        procd_close_instance
    fi
}

service_triggers()
{
    local trigger
    local delay

    trigger="$(uci_get stubby global trigger)"
    delay="$(uci_get stubby global triggerdelay "2")"

    PROCD_RELOAD_DELAY=$((${delay:-2} * 1000))

    for trigger_item in $trigger
    do
        procd_add_interface_trigger "interface.*" "$trigger_item" "$stubby_init" restart
    done

    procd_add_reload_trigger "stubby"
}
