mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-08-13 01:26:58 +00:00
FS-3110 --comment-only phase 1 to replace udns with ldns in mod_enum may need to rerun bootstrap
This commit is contained in:
713
libs/ldns/examples/ldns-verify-zone.c
Normal file
713
libs/ldns/examples/ldns-verify-zone.c
Normal file
@@ -0,0 +1,713 @@
|
||||
/*
|
||||
* read a zone file from disk and prints it, one RR per line
|
||||
*
|
||||
* (c) NLnetLabs 2008
|
||||
*
|
||||
* See the file LICENSE for the license
|
||||
*
|
||||
* Missing from the checks: empty non-terminals
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#include <openssl/err.h>
|
||||
|
||||
int verbosity = 3;
|
||||
|
||||
/* returns 1 if the list is empty, or if there are only ns rrs in the
|
||||
* list, 0 otherwise */
|
||||
static int
|
||||
only_ns_in_rrsets(ldns_dnssec_rrsets *rrsets) {
|
||||
ldns_dnssec_rrsets *cur_rrset = rrsets;
|
||||
|
||||
while (cur_rrset) {
|
||||
if (cur_rrset->type != LDNS_RR_TYPE_NS) {
|
||||
return 0;
|
||||
}
|
||||
cur_rrset = cur_rrset->next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
zone_is_nsec3_optout(ldns_rbtree_t *zone_nodes)
|
||||
{
|
||||
/* simply find the first NSEC3 RR and check its flags */
|
||||
/* TODO: maybe create a general function that uses the active
|
||||
* NSEC3PARAM RR? */
|
||||
ldns_rbnode_t *cur_node;
|
||||
ldns_dnssec_name *cur_name;
|
||||
cur_node = ldns_rbtree_first(zone_nodes);
|
||||
while (cur_node != LDNS_RBTREE_NULL) {
|
||||
cur_name = (ldns_dnssec_name *) cur_node->data;
|
||||
if (cur_name && cur_name->nsec &&
|
||||
ldns_rr_get_type(cur_name->nsec) == LDNS_RR_TYPE_NSEC3) {
|
||||
if (ldns_nsec3_optout(cur_name->nsec)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cur_node = ldns_rbtree_next(cur_node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
ldns_rr_list_contains_name(const ldns_rr_list *rr_list,
|
||||
const ldns_rdf *name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
|
||||
if (ldns_dname_compare(name,
|
||||
ldns_rr_owner(ldns_rr_list_rr(rr_list, i))) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
print_type(ldns_rr_type type)
|
||||
{
|
||||
const ldns_rr_descriptor *descriptor;
|
||||
|
||||
descriptor = ldns_rr_descript(type);
|
||||
if (descriptor && descriptor->_name) {
|
||||
fprintf(stdout, "%s", descriptor->_name);
|
||||
} else {
|
||||
fprintf(stdout, "TYPE%u",
|
||||
type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static ldns_dnssec_zone *
|
||||
create_dnssec_zone(ldns_zone *orig_zone)
|
||||
{
|
||||
size_t i;
|
||||
ldns_dnssec_zone *dnssec_zone;
|
||||
ldns_rr *cur_rr;
|
||||
ldns_status status;
|
||||
|
||||
/* when reading NSEC3s, there is a chance that we encounter nsecs
|
||||
for empty nonterminals, whose nonterminals we cannot derive yet
|
||||
because the needed information is to be read later. in that case
|
||||
we keep a list of those nsec3's and retry to add them later */
|
||||
ldns_rr_list *failed_nsec3s = ldns_rr_list_new();
|
||||
|
||||
dnssec_zone = ldns_dnssec_zone_new();
|
||||
if (ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(orig_zone)) !=
|
||||
LDNS_STATUS_OK) {
|
||||
if (verbosity > 0) {
|
||||
fprintf(stderr,
|
||||
"Error adding SOA to dnssec zone, skipping record\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(orig_zone)); i++) {
|
||||
cur_rr = ldns_rr_list_rr(ldns_zone_rrs(orig_zone), i);
|
||||
status = ldns_dnssec_zone_add_rr(dnssec_zone, cur_rr);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
if (status == LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
|
||||
ldns_rr_list_push_rr(failed_nsec3s, cur_rr);
|
||||
} else {
|
||||
if (verbosity > 0) {
|
||||
fprintf(stderr, "Error adding RR to dnssec zone");
|
||||
fprintf(stderr, ", skipping record:\n");
|
||||
ldns_rr_print(stderr, cur_rr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ldns_rr_list_rr_count(failed_nsec3s) > 0) {
|
||||
(void) ldns_dnssec_zone_add_empty_nonterminals(dnssec_zone);
|
||||
for (i = 0; i < ldns_rr_list_rr_count(failed_nsec3s); i++) {
|
||||
cur_rr = ldns_rr_list_rr(failed_nsec3s, i);
|
||||
status = ldns_dnssec_zone_add_rr(dnssec_zone, cur_rr);
|
||||
}
|
||||
}
|
||||
|
||||
ldns_rr_list_free(failed_nsec3s);
|
||||
return dnssec_zone;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_dnssec_rrset(ldns_rdf *zone_name,
|
||||
ldns_rdf *name,
|
||||
ldns_dnssec_rrsets *rrset,
|
||||
ldns_rr_list *keys,
|
||||
ldns_rr_list *glue_rrs)
|
||||
{
|
||||
ldns_rr_list *rrset_rrs;
|
||||
ldns_dnssec_rrs *cur_rr, *cur_sig;
|
||||
ldns_status status;
|
||||
ldns_rr_list *good_keys;
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
|
||||
if (!rrset->rrs) return LDNS_STATUS_OK;
|
||||
|
||||
rrset_rrs = ldns_rr_list_new();
|
||||
cur_rr = rrset->rrs;
|
||||
while(cur_rr && cur_rr->rr) {
|
||||
ldns_rr_list_push_rr(rrset_rrs, cur_rr->rr);
|
||||
cur_rr = cur_rr->next;
|
||||
}
|
||||
cur_sig = rrset->signatures;
|
||||
if (cur_sig) {
|
||||
while (cur_sig) {
|
||||
good_keys = ldns_rr_list_new();
|
||||
status = ldns_verify_rrsig_keylist(rrset_rrs,
|
||||
cur_sig->rr,
|
||||
keys,
|
||||
good_keys);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
if (verbosity > 0) {
|
||||
printf("Error: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
printf(" for ");
|
||||
ldns_rdf_print(stdout,
|
||||
ldns_rr_owner(rrset->rrs->rr));
|
||||
printf("\t");
|
||||
print_type(rrset->type);
|
||||
printf("\n");
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
if (status == LDNS_STATUS_SSL_ERR) {
|
||||
ERR_load_crypto_strings();
|
||||
ERR_print_errors_fp(stdout);
|
||||
}
|
||||
if (verbosity >= 4) {
|
||||
printf("RRSet:\n");
|
||||
ldns_dnssec_rrs_print(stdout, rrset->rrs);
|
||||
printf("Signature:\n");
|
||||
ldns_rr_print(stdout, cur_sig->rr);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
ldns_rr_list_free(good_keys);
|
||||
|
||||
cur_sig = cur_sig->next;
|
||||
}
|
||||
} else {
|
||||
/* delegations are unsigned */
|
||||
if (rrset->type != LDNS_RR_TYPE_NS ||
|
||||
ldns_dname_compare(name, zone_name) == 0) {
|
||||
if (verbosity > 0) {
|
||||
printf("Error: no signatures for ");
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(rrset->rrs->rr));
|
||||
printf("\t");
|
||||
print_type(rrset->type);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
ldns_rr_list_free(rrset_rrs);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_single_rr(ldns_rr *rr,
|
||||
ldns_dnssec_rrs *signature_rrs,
|
||||
ldns_rr_list *keys)
|
||||
{
|
||||
ldns_rr_list *rrset_rrs;
|
||||
ldns_rr_list *good_keys;
|
||||
ldns_dnssec_rrs *cur_sig;
|
||||
ldns_status status;
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
|
||||
rrset_rrs = ldns_rr_list_new();
|
||||
ldns_rr_list_push_rr(rrset_rrs, rr);
|
||||
|
||||
cur_sig = signature_rrs;
|
||||
while (cur_sig) {
|
||||
good_keys = ldns_rr_list_new();
|
||||
status = ldns_verify_rrsig_keylist(rrset_rrs,
|
||||
cur_sig->rr,
|
||||
keys,
|
||||
good_keys);
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
if (verbosity >= 1) {
|
||||
printf("Error: %s ", ldns_get_errorstr_by_id(status));
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
printf("for ");
|
||||
ldns_rdf_print(stdout, ldns_rr_owner(rr));
|
||||
printf("\t");
|
||||
print_type(ldns_rr_get_type(rr));
|
||||
printf("\n");
|
||||
if (status == LDNS_STATUS_SSL_ERR) {
|
||||
ERR_load_crypto_strings();
|
||||
ERR_print_errors_fp(stdout);
|
||||
}
|
||||
if (verbosity >= 4) {
|
||||
printf("RRSet:\n");
|
||||
ldns_rr_list_print(stdout, rrset_rrs);
|
||||
printf("Signature:\n");
|
||||
ldns_rr_print(stdout, cur_sig->rr);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
result = status;
|
||||
}
|
||||
ldns_rr_list_free(good_keys);
|
||||
cur_sig = cur_sig->next;
|
||||
}
|
||||
|
||||
ldns_rr_list_free(rrset_rrs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_next_hashed_name(ldns_rbtree_t *zone_nodes,
|
||||
ldns_dnssec_name *name)
|
||||
{
|
||||
ldns_rbnode_t *next_node;
|
||||
ldns_dnssec_name *next_name;
|
||||
ldns_dnssec_name *cur_next_name = NULL;
|
||||
ldns_dnssec_name *cur_first_name = NULL;
|
||||
int cmp;
|
||||
char *next_owner_str;
|
||||
ldns_rdf *next_owner_dname;
|
||||
|
||||
if (!name->hashed_name) {
|
||||
name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(name->nsec,
|
||||
name->name);
|
||||
}
|
||||
next_node = ldns_rbtree_first(zone_nodes);
|
||||
while (next_node != LDNS_RBTREE_NULL) {
|
||||
next_name = (ldns_dnssec_name *)next_node->data;
|
||||
/* skip over names that have no NSEC3 records (whether it
|
||||
* actually should or should not should have been checked
|
||||
* already */
|
||||
if (!next_name->nsec) {
|
||||
next_node = ldns_rbtree_next(next_node);
|
||||
continue;
|
||||
}
|
||||
if (!next_name->hashed_name) {
|
||||
next_name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(
|
||||
name->nsec, next_name->name);
|
||||
}
|
||||
/* we keep track of what 'so far' is the next hashed name;
|
||||
* it must of course be 'larger' than the current name
|
||||
* if we find one that is larger, but smaller than what we
|
||||
* previously thought was the next one, that one is the next
|
||||
*/
|
||||
cmp = ldns_dname_compare(name->hashed_name,
|
||||
next_name->hashed_name);
|
||||
if (cmp < 0) {
|
||||
if (!cur_next_name) {
|
||||
cur_next_name = next_name;
|
||||
} else {
|
||||
cmp = ldns_dname_compare(next_name->hashed_name,
|
||||
cur_next_name->hashed_name);
|
||||
if (cmp < 0) {
|
||||
cur_next_name = next_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* in case the hashed name of the nsec we are checking is the
|
||||
* last one, we need the first hashed name of the zone */
|
||||
if (!cur_first_name) {
|
||||
cur_first_name = next_name;
|
||||
} else {
|
||||
cmp = ldns_dname_compare(next_name->hashed_name,
|
||||
cur_first_name->hashed_name);
|
||||
if (cmp < 0) {
|
||||
cur_first_name = next_name;
|
||||
}
|
||||
}
|
||||
next_node = ldns_rbtree_next(next_node);
|
||||
}
|
||||
if (!cur_next_name) {
|
||||
cur_next_name = cur_first_name;
|
||||
}
|
||||
|
||||
next_owner_str = ldns_rdf2str(ldns_nsec3_next_owner(name->nsec));
|
||||
next_owner_dname = ldns_dname_new_frm_str(next_owner_str);
|
||||
cmp = ldns_dname_compare(next_owner_dname,
|
||||
cur_next_name->hashed_name);
|
||||
ldns_rdf_deep_free(next_owner_dname);
|
||||
LDNS_FREE(next_owner_str);
|
||||
if (cmp != 0) {
|
||||
printf("Error: The NSEC3 record for ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf(" points to the wrong next hashed owner name\n");
|
||||
printf("(should point to ");
|
||||
ldns_rdf_print(stdout, cur_next_name->name);
|
||||
printf("(whose hashed name is ");
|
||||
ldns_rdf_print(stdout, cur_next_name->hashed_name);
|
||||
printf(")\n");
|
||||
return LDNS_STATUS_ERR;
|
||||
} else {
|
||||
return LDNS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static ldns_rbnode_t *
|
||||
next_nonglue_node(ldns_rbnode_t *node, ldns_rr_list *glue_rrs)
|
||||
{
|
||||
ldns_rbnode_t *cur_node = ldns_rbtree_next(node);
|
||||
ldns_dnssec_name *cur_name;
|
||||
while (cur_node != LDNS_RBTREE_NULL) {
|
||||
cur_name = (ldns_dnssec_name *) cur_node->data;
|
||||
if (cur_name && cur_name->name) {
|
||||
if (!ldns_rr_list_contains_name(glue_rrs, cur_name->name)) {
|
||||
return cur_node;
|
||||
}
|
||||
}
|
||||
cur_node = ldns_rbtree_next(cur_node);
|
||||
}
|
||||
return LDNS_RBTREE_NULL;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_nsec(ldns_rbtree_t *zone_nodes,
|
||||
ldns_rbnode_t *cur_node,
|
||||
ldns_rr_list *keys,
|
||||
ldns_rr_list *glue_rrs
|
||||
)
|
||||
{
|
||||
ldns_rbnode_t *next_node;
|
||||
ldns_dnssec_name *name, *next_name;
|
||||
ldns_status status, result;
|
||||
result = LDNS_STATUS_OK;
|
||||
|
||||
name = (ldns_dnssec_name *) cur_node->data;
|
||||
if (name->nsec) {
|
||||
if (name->nsec_signatures) {
|
||||
status = verify_single_rr(name->nsec,
|
||||
name->nsec_signatures,
|
||||
keys);
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
} else {
|
||||
if (verbosity >= 1) {
|
||||
printf("Error: the NSEC(3) record of ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf(" has no signatures\n");
|
||||
}
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
}
|
||||
/* check whether the NSEC record points to the right name */
|
||||
switch (ldns_rr_get_type(name->nsec)) {
|
||||
case LDNS_RR_TYPE_NSEC:
|
||||
/* simply try next name */
|
||||
next_node = next_nonglue_node(cur_node, glue_rrs);
|
||||
if (next_node == LDNS_RBTREE_NULL) {
|
||||
next_node = ldns_rbtree_first(zone_nodes);
|
||||
}
|
||||
next_name = (ldns_dnssec_name *)next_node->data;
|
||||
if (ldns_dname_compare(next_name->name,
|
||||
ldns_rr_rdf(name->nsec, 0))
|
||||
!= 0) {
|
||||
printf("Error: the NSEC record for ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf(" points to the wrong next owner name\n");
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LDNS_RR_TYPE_NSEC3:
|
||||
/* find the hashed next name in the tree */
|
||||
/* this is expensive, do we need to add support
|
||||
* for this in the structs? (ie. pointer to next
|
||||
* hashed name?)
|
||||
*/
|
||||
status = verify_next_hashed_name(zone_nodes, name);
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* todo; do this once and cache result? */
|
||||
if (zone_is_nsec3_optout(zone_nodes) &&
|
||||
only_ns_in_rrsets(name->rrsets)) {
|
||||
/* ok, no problem, but we need to remember to check
|
||||
* whether the chain does not actually point to this
|
||||
* name later */
|
||||
} else {
|
||||
if (verbosity >= 1) {
|
||||
printf("Error: there is no NSEC(3) for ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf("\n");
|
||||
}
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
ldns_dnssec_name_has_only_a(ldns_dnssec_name *cur_name)
|
||||
{
|
||||
ldns_dnssec_rrsets *cur_rrset;
|
||||
cur_rrset = cur_name->rrsets;
|
||||
while (cur_rrset) {
|
||||
if (cur_rrset->type != LDNS_RR_TYPE_A &&
|
||||
cur_rrset->type != LDNS_RR_TYPE_AAAA) {
|
||||
return 0;
|
||||
} else {
|
||||
cur_rrset = cur_rrset->next;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_dnssec_name(ldns_rdf *zone_name,
|
||||
ldns_dnssec_zone *zone,
|
||||
ldns_rbtree_t *zone_nodes,
|
||||
ldns_rbnode_t *cur_node,
|
||||
ldns_rr_list *keys,
|
||||
ldns_rr_list *glue_rrs)
|
||||
{
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
ldns_status status;
|
||||
ldns_dnssec_rrsets *cur_rrset;
|
||||
ldns_dnssec_name *name;
|
||||
/* for NSEC chain checks */
|
||||
|
||||
name = (ldns_dnssec_name *) cur_node->data;
|
||||
if (verbosity >= 3) {
|
||||
printf("Checking: ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (ldns_rr_list_contains_name(glue_rrs, name->name) &&
|
||||
ldns_dnssec_name_has_only_a(name)
|
||||
) {
|
||||
/* glue */
|
||||
cur_rrset = name->rrsets;
|
||||
while (cur_rrset) {
|
||||
if (cur_rrset->signatures) {
|
||||
if (verbosity >= 1) {
|
||||
printf("Error: ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf("\t");
|
||||
print_type(cur_rrset->type);
|
||||
printf(" has signature(s), but is glue\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
cur_rrset = cur_rrset->next;
|
||||
}
|
||||
if (name->nsec) {
|
||||
if (verbosity >= 1) {
|
||||
printf("Error: ");
|
||||
ldns_rdf_print(stdout, name->name);
|
||||
printf("\thas an NSEC(3), but is glue\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
} else {
|
||||
/* not glue, do real verify */
|
||||
cur_rrset = name->rrsets;
|
||||
while(cur_rrset) {
|
||||
if (cur_rrset->type != LDNS_RR_TYPE_A ||
|
||||
!ldns_dnssec_zone_find_rrset(zone, name->name, LDNS_RR_TYPE_NS)) {
|
||||
status = verify_dnssec_rrset(zone_name, name->name, cur_rrset, keys, glue_rrs);
|
||||
if (status != LDNS_STATUS_OK && result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
}
|
||||
cur_rrset = cur_rrset->next;
|
||||
}
|
||||
|
||||
status = verify_nsec(zone_nodes, cur_node, keys, glue_rrs);
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ldns_status
|
||||
verify_dnssec_zone(ldns_dnssec_zone *dnssec_zone,
|
||||
ldns_rdf *zone_name,
|
||||
ldns_rr_list *glue_rrs)
|
||||
{
|
||||
ldns_rr_list *keys;
|
||||
ldns_rbnode_t *cur_node;
|
||||
ldns_dnssec_rrsets *cur_key_rrset;
|
||||
ldns_dnssec_rrs *cur_key;
|
||||
ldns_dnssec_name *cur_name;
|
||||
ldns_status status;
|
||||
ldns_status result = LDNS_STATUS_OK;
|
||||
|
||||
keys = ldns_rr_list_new();
|
||||
cur_key_rrset = ldns_dnssec_zone_find_rrset(dnssec_zone,
|
||||
zone_name,
|
||||
LDNS_RR_TYPE_DNSKEY);
|
||||
if (!cur_key_rrset || !cur_key_rrset->rrs) {
|
||||
if (verbosity >= 1) {
|
||||
printf("No DNSKEY records at zone apex\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
} else {
|
||||
cur_key = cur_key_rrset->rrs;
|
||||
while (cur_key) {
|
||||
if (verbosity >= 4) {
|
||||
printf("DNSKEY: ");
|
||||
ldns_rr_print(stdout, cur_key->rr);
|
||||
}
|
||||
ldns_rr_list_push_rr(keys, cur_key->rr);
|
||||
cur_key = cur_key->next;
|
||||
}
|
||||
|
||||
cur_node = ldns_rbtree_first(dnssec_zone->names);
|
||||
if (cur_node == LDNS_RBTREE_NULL) {
|
||||
if (verbosity >= 1) {
|
||||
printf("Empty zone?\n");
|
||||
}
|
||||
result = LDNS_STATUS_ERR;
|
||||
}
|
||||
while (cur_node != LDNS_RBTREE_NULL) {
|
||||
cur_name = (ldns_dnssec_name *) cur_node->data;
|
||||
status = verify_dnssec_name(zone_name,
|
||||
dnssec_zone,
|
||||
dnssec_zone->names,
|
||||
cur_node,
|
||||
keys,
|
||||
glue_rrs);
|
||||
if (status != LDNS_STATUS_OK && result == LDNS_STATUS_OK) {
|
||||
result = status;
|
||||
}
|
||||
cur_node = ldns_rbtree_next(cur_node);
|
||||
}
|
||||
}
|
||||
|
||||
ldns_rr_list_free(keys);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *filename;
|
||||
FILE *fp;
|
||||
ldns_zone *z;
|
||||
int line_nr = 0;
|
||||
int c;
|
||||
ldns_status s;
|
||||
ldns_dnssec_zone *dnssec_zone;
|
||||
ldns_status result = LDNS_STATUS_ERR;
|
||||
ldns_rr_list *glue_rrs;
|
||||
|
||||
while ((c = getopt(argc, argv, "hvV:")) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
printf("Usage: %s [OPTIONS] <zonefile>\n", argv[0]);
|
||||
printf("\tReads the zonefile and checks for DNSSEC errors.\n");
|
||||
printf("\nIt checks whether NSEC(3)s are present,");
|
||||
printf(" and verifies all signatures\n");
|
||||
printf("It also checks the NSEC(3) chain, but it will error on opted-out delegations\n");
|
||||
printf("\nOPTIONS:\n");
|
||||
printf("\t-h show this text\n");
|
||||
printf("\t-v shows the version and exits\n");
|
||||
printf("\t-V [0-5]\tset verbosity level (default 3)\n");
|
||||
printf("\nif no file is given standard input is read\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'v':
|
||||
printf("read zone version %s (ldns version %s)\n",
|
||||
LDNS_VERSION, ldns_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'V':
|
||||
verbosity = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0) {
|
||||
fp = stdin;
|
||||
} else {
|
||||
filename = argv[0];
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr,
|
||||
"Unable to open %s: %s\n",
|
||||
filename,
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
s = ldns_zone_new_frm_fp_l(&z, fp, NULL, 0, LDNS_RR_CLASS_IN, &line_nr);
|
||||
|
||||
if (s == LDNS_STATUS_OK) {
|
||||
if (!ldns_zone_soa(z)) {
|
||||
fprintf(stderr, "; Error: no SOA in the zone\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glue_rrs = ldns_zone_glue_rr_list(z);
|
||||
dnssec_zone = create_dnssec_zone(z);
|
||||
|
||||
if (verbosity >= 5) {
|
||||
ldns_dnssec_zone_print(stdout, dnssec_zone);
|
||||
}
|
||||
|
||||
result = verify_dnssec_zone(dnssec_zone,
|
||||
ldns_rr_owner(ldns_zone_soa(z)),
|
||||
glue_rrs);
|
||||
|
||||
|
||||
if (result == LDNS_STATUS_OK) {
|
||||
if (verbosity >= 1) {
|
||||
printf("Zone is verified and complete\n");
|
||||
}
|
||||
} else {
|
||||
if (verbosity >= 1) {
|
||||
printf("There were errors in the zone\n");
|
||||
}
|
||||
}
|
||||
|
||||
ldns_zone_free(z);
|
||||
ldns_dnssec_zone_deep_free(dnssec_zone);
|
||||
} else {
|
||||
fprintf(stderr, "%s at %d\n",
|
||||
ldns_get_errorstr_by_id(s),
|
||||
line_nr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
exit(result);
|
||||
}
|
||||
#else
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
fprintf(stderr, "ldns-verifyzone needs OpenSSL support, which has not been compiled in\n");
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
Reference in New Issue
Block a user