/*****************************************************************************
*
* Nagios check_dnssec_trust_anchor plugin
*
* License: GPL
* Copyright (c) 2009 Marius Rieder <marius.rieder@durchmesser.ch>
*
* Description:
*
* This file contains the check_dnssec_trust_anchor plugin
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <ldns/ldns.h>

#include "utils.h"

const char *progname = "check_dnssec_trust_anchor";
const char *version = PACKAGE_VERSION;
const char *copyright = "2009";
const char *email = "marius.rieder@durchmesser.ch";

int process_arguments(int, char **);
void print_help(void);
void print_usage(void);

/* Global Vars */
char *dns_server;
ldns_rr_list *trusted_keys = NULL;
int verbose = 0;
int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
int checkState;

int main(int argc, char **argv) {

    /* C vars */
    int         i;
    char        *invalid = NULL;

    /* LDNS vars */
    ldns_resolver   *res;
    ldns_rdf        *rd_owner;
    ldns_rr         *rr;
    ldns_rr_list    *rrl_keys;

    /* Set signal handling and alarm */
    if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
        unknown("Cannot catch SIGALRM");
        return checkState;
    }

    /* process commandline arguments */
    i = process_arguments(argc, argv);
    if (i != AP_OK) {
        checkState = STATE_OK;
        free(dns_server);
        ldns_rr_list_deep_free(trusted_keys);
        if (i == AP_WARN)
            unknown("Could not parse arguments");
        return checkState;
    }

    /* start plugin timeout */
    alarm(timeout_interval);

    /* create a new resolver with dns_server or server from /etc/resolv.conf */
    res = createResolver(dns_server);
    if (!res)
        return checkState;

    /* Test all trust anchors */
    for(i = 0; i < ldns_rr_list_rr_count(trusted_keys); i++) {
        rr = ldns_rr_list_rr(trusted_keys, i);
        rd_owner = ldns_rr_owner(rr);

        if (verbose >= 1)
            printf("Test: %s\n", ldns_rdf2str(rd_owner));

        rrl_keys = ldns_validate_domain_dnskey(res, rd_owner, trusted_keys);

        if (verbose >= 2) {
            printf("--[ Valid Domain Key ]----------------------------------------\n");
            ldns_rr_list_print(stdout, rrl_keys);
            printf("------------------------------------------------------------\n");
        }

        if (!rrl_keys) {
            if (verbose >= 1)
                printf("  Invalid.\n");
            if (invalid) {
                char *c = invalid;
                sprintf(invalid, "%s, %s", c, ldns_rdf2str(rd_owner));
            } else {
                invalid = ldns_rdf2str(rd_owner);
            }
        }

        ldns_rr_list_deep_free(rrl_keys);
    }

    ldns_rr_list_deep_free(trusted_keys);
    ldns_resolver_deep_free(res);

    if (invalid)
        critical("Invalid KEYs in trusted-keys for '%s'", invalid);
    else
        ok("All keys from trusted-keys valid");
    free(invalid);
    return checkState;
}

/*
 * Process and check command line args
 */
int process_arguments(int argc, char **argv) {

    int c;
    int opt_index = 0;

    static struct option long_opts[] = {
        // Default args
        {"help", no_argument, 0, 'h'},
        {"version", no_argument, 0, 'V'},
        {"verbose", no_argument, 0, 'v'},
        {"timeout", required_argument, 0, 't'},
        {"hostname", required_argument, 0, 'H'},
        // Plugin specific args
        {"domain", required_argument, 0, 'D'},
        {"trusted-keys", required_argument, 0, 'k'},
        {0, 0, 0, 0}
    };

    if (argc < 2) {
        print_help();
        exit (STATE_OK);
    }

    while (1) {
        c = getopt_long(argc, argv, "hVvt:H:k:w:c:", long_opts, &opt_index);
        if (c == -1 || c == EOF)
            break;

        switch (c) {
            // Default args
            case 'h': // -h --help
                print_help();
                return AP_EXIT;
            case 'V': // -V --version
                print_version();
                return AP_EXIT;
            case 'v': // -v --verbose
                verbose += 1;
                break;
            case 't': // -t --timeout
                timeout_interval = atoi(optarg);
                break;
            case 'H': // -H --hostname
                setHostname(optarg, &dns_server);
                break;
            // Plugin specific args
            case 'k': // -k --trusted-keys
                loadAnchorfile(optarg, &trusted_keys);
                break;
            default: // unknown args
                print_usage();
                return AP_WARN;
        }
    }

    //validate_arguments
    if(ldns_rr_list_rr_count(trusted_keys) == 0) {
        print_usage();
        return AP_WARN;
    }

    return AP_OK;
}

void print_help(void) {
  printf ("%s %s\n", progname, version);
  printf ("Copyright (c) 2009 Marius Rieder <marius.rieder@durchmesser.ch>\n\n");

  printf ("This plugin uses the ldns library to check if trust anchors from a file.\n");
  printf (" are still valid and in use.\n\n");

  print_usage ();

  printf ("Options:\n");
  printf (" -h, --help\n");
  printf ("    Print detailed help screen.\n");
  printf (" -V, --version\n");
  printf ("    Print version information.\n");
  printf (" -v, --verbose\n");
  printf ("    Increase verbosity.\n");
  printf (" -t, --timeout=INTEGER\n");
  printf ("    Seconds before connection times out. (default: %d)\n",
    DEFAULT_SOCKET_TIMEOUT );
  printf (" -H, --hostname=HOST\n");
  printf ("    The name or address of your DNS server you want to use for the lookup.\n");
  printf (" -k, --trusted-keys=FILE\n");
  printf ("    File to read trust-anchors from.\n\n");

  printf ("Send email to marius.rieder@durchmesser.ch if you have questions\n");
  printf ("regarding use of this software.\n\n");
}

void print_usage(void) {
  printf ("Usage: %s [-H host] -k file [-t timeout]\n",
          progname);
}

// vim: ts=4 expandtab filetype=c
