/* 
 * Library of useful functions for check_danssec
 * 
 * License: GPL
 * Copyright (c) 2009 Marius Rieder <marius.rieder@durchmesser.ch>
 * 
 * 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 <signal.h>

#include "utils.h"

extern const char *progname;
extern const char *version;
extern const int timeout_interval;
extern const int verbose;
extern int checkState;
extern const char *checkText;

/*
 * Plugin output functions.
 */
void ok(const char *fmt, ...) {
    va_list ap;
    printf("OK: %s - ", progname);
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    printf("\n");
    checkState = STATE_OK;
}

void warning(const char *fmt, ...) {
    va_list ap;
    printf("WARNING: %s - ", progname);
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    printf("\n");
    checkState  = STATE_WARNING;
}

void critical(const char *fmt, ...) {
    va_list ap;
    printf("CRITICAL: %s - ", progname);
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    printf("\n");
    checkState = STATE_CRITICAL;
}

void unknown(const char *fmt, ...) {
    va_list ap;
    printf("UNKNOWN: %s - ", progname);
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    printf("\n");
    checkState = STATE_UNKNOWN;
}

/*
 * createResolver - Create a ldns resolver. Use dns_server or resolf.conf
 */
ldns_resolver* createResolver(const char *dns_server){
    ldns_resolver   *res = NULL;
    ldns_status     status;
    ldns_rdf        *serv_rdf;
    
    if (dns_server) {
        // Use the given DNS server
        res = ldns_resolver_new();
        if (!res) {
            warning("Could not create a resolver structure.");
            return NULL;
        }
        
        /* add the nameserver */
        serv_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, dns_server);
        if (!serv_rdf) {
            serv_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, dns_server);
        }
        
        if (!serv_rdf) {
            warning("Use IP for dnsserver.");
            ldns_resolver_free(res);
	    ldns_rdf_deep_free(serv_rdf);
            return NULL;
        } else {
            if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) {
                warning("Could not push nameserver");
                ldns_resolver_free(res);
		ldns_rdf_deep_free(serv_rdf);
                return NULL;
            } else {
                ldns_rdf_deep_free(serv_rdf);
            }
        }
    } else {
        // Use a DNS server from resolv.conf
        status = ldns_resolver_new_frm_file(&res, NULL);
        if (status != LDNS_STATUS_OK) {
            warning("Could not create a resolver structure: %s", 
                    ldns_get_errorstr_by_id(status));
            ldns_resolver_free(res);
            return NULL;
        }
    }
    ldns_resolver_set_dnssec(res,1);
    ldns_resolver_set_dnssec_cd(res, 1);
    
    return res;
}

/*
 * timeout_alarm_handler - Don't let a check hang forever
 */
void timeout_alarm_handler(int sig) {
    if (sig == SIGALRM) {
        critical("check timed out after %d seconds\n", timeout_interval);
        exit(STATE_CRITICAL);
    }
}

/*
 * print_version - print version information
 */
void print_version(void) {
    char *ldnsVersion;
    
    printf("%s, version %s\n", progname, version);
    
    ldnsVersion = ldns_version();
    if (strcmp(LDNS_VERSION, ldnsVersion) == 0)
        printf(" * ldns, version %s\n", ldnsVersion);
    else
        printf(" * ldns, version %s (compiled with %s)\n", ldnsVersion, LDNS_VERSION);
}

/*
 * Args parser functions
 */
int getTime(const char *optarg) {
    int time = 0;
    int len = strlen(optarg);
    switch (optarg[(len-1)]) {
        case 'd':
            time = atoi(optarg) * 86400;
            break;
        case 'h':
            time = atoi(optarg) * 3600;
            break;
        case 'm':
            time = atoi(optarg) * 60;
            break;
        default:
            time = atoi(optarg);
      }
      return time;
}

void setHostname(const char *optarg, char **dns_server) {
    int len = strlen(optarg)+1;
    *dns_server = malloc(len);
    strncpy(*dns_server, optarg, len);
}

void setDomainname(const char *optarg, char **domain_name) {
    int len = strlen(optarg)+1;
    *domain_name = malloc(len);
    strncpy(*domain_name, optarg, len);
}

void loadKeyfile(const char *optarg, ldns_rr_list **trusted_keys) {
    
    int     col = 0;
    int     line = 0;
    FILE    *key_file;
    char    c;
    char    linebuffer[LDNS_MAX_PACKETLEN];
    
    ldns_status     status;
    ldns_rr         *rr;
    
    // Try open trusted key file
    key_file = fopen(optarg, "r");
    if (!key_file) {
        if (verbose >= 1)
            fprintf(stderr,"Error opening trusted-key file %s: %s\n", optarg,
                                                           strerror(errno));
        return;
    }
    
    // Create empty list
    *trusted_keys = ldns_rr_list_new();
    
    // Read File
    do {
        c = getc(key_file);
        if (c == '\n' || c == EOF) {
            linebuffer[col] = '\0';
            line++;
            if (linebuffer[0] == ';' || col == 0) {
                col = 0;
                continue;
            }
            col = 0;
             
            status = ldns_rr_new_frm_str(&rr, linebuffer, 0, NULL, NULL);
            if (status != LDNS_STATUS_OK) {
                if (verbose >= 1)
                    fprintf(stderr, "Error parsing RR in %s:%d: %s\n",
                        optarg, line, ldns_get_errorstr_by_id(status));
                if (verbose >= 2)
                    fprintf(stderr, "%s\n", linebuffer);
                ldns_rr_free(rr);
            } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY || 
                       ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) {
                ldns_rr_list_push_rr(*trusted_keys, rr);
            } else {
                ldns_rr_free(rr);
			}
        } else {
            linebuffer[col++] = c;
        }
        
    } while (c != EOF);
    
    fclose(key_file);
}

void loadAnchorfile(const char *optarg, ldns_rr_list **trusted_keys) {
    
    int     col = 0;
    int     line = 0;
    int     grouped = 0;
    int     tk_section = 0;
    FILE    *key_file;
    char    c;
    char    linebuffer[LDNS_MAX_PACKETLEN];
    
    ldns_rdf        *rd;
    ldns_rr         *rr;
    
    // Try open trusted key file
    key_file = fopen(optarg, "r");
    if (!key_file) {
        if (verbose >= 1)
            fprintf(stderr,"Error opening trusted-key file %s: %s\n", optarg,
                                                           strerror(errno));
        return;
    }
    
    // Create empty list
    *trusted_keys = ldns_rr_list_new();
    
    // Read File
    do {
        c = getc(key_file);
        if ((c == '\n' && grouped == 0) || c == EOF) {
            linebuffer[col] = '\0';
            line++;
            
            if(strstr(linebuffer, "trusted-keys")) {
                col = 0;
                tk_section = 1;
                continue;
            }
            
            if (linebuffer[0] == ';' || col == 0 || tk_section == 0) {
                col = 0;
                continue;
            }
            col = 0;
           
            rr = ldns_rr_new();
            ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
            ldns_rr_set_type(rr, LDNS_RR_TYPE_DNSKEY);
            ldns_rr_set_ttl(rr, 3600);
            
            char *cur = linebuffer;
            char *t = strtok(cur, " ");
            cur += strlen(t)+1;
            
            
            ldns_str2rdf_dname(&rd, t);
            ldns_rr_set_owner(rr, rd);
            
            t = strtok(cur, " ");
            cur += strlen(t)+1;
          
            ldns_str2rdf_int16(&rd, t);
            ldns_rr_push_rdf(rr, rd);
            
            t = strtok(cur, " ");
            cur += strlen(t)+1;
            
            ldns_str2rdf_int8(&rd, t);
            ldns_rr_push_rdf(rr, rd);
            
            t = strtok(cur, " ");
            cur += strlen(t)+1;
            
            ldns_str2rdf_alg(&rd, t);
            ldns_rr_push_rdf(rr, rd);
            
            t = strtok(cur, " ");
            
            if (t[strlen(t)-1] == ';')
                t[strlen(t)-1] = '\0';
            
            ldns_str2rdf_b64(&rd, t);
            ldns_rr_push_rdf(rr, rd);
            
            ldns_rr_list_push_rr(*trusted_keys,rr);
            
        } else {
            if (c == '}') {
                tk_section = 0;
            } else if (c == '"') {
                grouped = (grouped+1)%2;
            } else {
                linebuffer[col++] = c;
            }
        }
        
    } while (c != EOF);

    fclose(key_file);
}

// vim: ts=4 expandtab filetype=c
