return 0;
}
-/* returns true if the current dnssec_rrset from the given list of rrsets
- * is glue */
-static int
-is_glue(ldns_dnssec_rrsets *cur_rrsets, ldns_dnssec_rrsets *orig_rrsets)
-{
- /* only glue if a or aaaa with names that have an NS rrset and are not the
- apex (do not have a soa rrset) */
- return (cur_rrsets->type == LDNS_RR_TYPE_A ||
- cur_rrsets->type == LDNS_RR_TYPE_AAAA) &&
- (ldns_dnssec_rrsets_contains_type(orig_rrsets,
- LDNS_RR_TYPE_NS) &&
- !ldns_dnssec_rrsets_contains_type(orig_rrsets,
- LDNS_RR_TYPE_SOA));
-}
-
ldns_rr *
ldns_dnssec_create_nsec(ldns_dnssec_name *from,
ldns_dnssec_name *to,
ldns_rr_type types[65536];
size_t type_count = 0;
ldns_dnssec_rrsets *cur_rrsets;
+ int on_delegation_point;
if (!from || !to || (nsec_type != LDNS_RR_TYPE_NSEC &&
nsec_type != LDNS_RR_TYPE_NSEC3)) {
ldns_rr_set_owner(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(from)));
ldns_rr_push_rdf(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(to)));
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_SOA);
+
cur_rrsets = from->rrsets;
while (cur_rrsets) {
- if (is_glue(cur_rrsets, from->rrsets)) {
- cur_rrsets = cur_rrsets->next;
- continue;
- }
- if (cur_rrsets->type != LDNS_RR_TYPE_RRSIG &&
- cur_rrsets->type != LDNS_RR_TYPE_NSEC) {
+ /* Do not include obscured rrsets on the delegation point
+ * in the type bitmap */
+ if ( ( on_delegation_point && (
+ cur_rrsets->type == LDNS_RR_TYPE_NS
+ || cur_rrsets->type == LDNS_RR_TYPE_DS))
+ || (!on_delegation_point &&
+ cur_rrsets->type != LDNS_RR_TYPE_RRSIG
+ && cur_rrsets->type != LDNS_RR_TYPE_NSEC)) {
+
types[type_count] = cur_rrsets->type;
type_count++;
}
size_t type_count = 0;
ldns_dnssec_rrsets *cur_rrsets;
ldns_status status;
+ int on_delegation_point;
flags = flags;
salt_length,
salt);
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_SOA);
cur_rrsets = from->rrsets;
while (cur_rrsets) {
- if (is_glue(cur_rrsets, from->rrsets)) {
- cur_rrsets = cur_rrsets->next;
- continue;
- }
- if (cur_rrsets->type != LDNS_RR_TYPE_RRSIG) {
+ /* Do not include obscured rrsets on the delegation point
+ * in the type bitmap. Potentionally not skipping insecure
+ * delegation should have been done earlier, in
+ *
+ */
+ if ( ( on_delegation_point && (
+ cur_rrsets->type == LDNS_RR_TYPE_NS
+ || cur_rrsets->type == LDNS_RR_TYPE_DS))
+ || (!on_delegation_point &&
+ cur_rrsets->type != LDNS_RR_TYPE_RRSIG)) {
+
types[type_count] = cur_rrsets->type;
type_count++;
}
}
#endif /* HAVE_SSL */
-static int
-ldns_dnssec_name_has_only_a(ldns_dnssec_name *cur_name)
+/**
+ * Pushes all rrs from the rrsets of type A and AAAA on gluelist.
+ */
+static ldns_status
+ldns_dnssec_addresses_on_glue_list(
+ ldns_dnssec_rrsets *cur_rrset,
+ ldns_rr_list *glue_list)
{
- ldns_dnssec_rrsets *cur_rrset;
- cur_rrset = cur_name->rrsets;
+ ldns_dnssec_rrs *cur_rrs;
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;
+ if (cur_rrset->type == LDNS_RR_TYPE_A
+ || cur_rrset->type == LDNS_RR_TYPE_AAAA) {
+ for (cur_rrs = cur_rrset->rrs;
+ cur_rrs;
+ cur_rrs = cur_rrs->next) {
+ if (cur_rrs->rr) {
+ if (!ldns_rr_list_push_rr(glue_list,
+ cur_rrs->rr)) {
+ return LDNS_STATUS_MEM_ERR;
+ /* ldns_rr_list_push_rr()
+ * returns false when unable
+ * to increase the capacity
+ * of the ldsn_rr_list
+ */
+ }
+ }
+ }
}
+ cur_rrset = cur_rrset->next;
}
- return 1;
+ return LDNS_STATUS_OK;
}
-/*
- * Regardless of its name, this function does not mark the glue rrsets as glue,
- * but only names that have ONLY glue rrsets.
+/**
+ * Marks the names in the zone that are occluded. Those names will be skipped
+ * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
+ * function. But watch out! Names that are partially obscured (like glue with
+ * the same name as the delegation) will not be marked and should specifically
+ * be taken into account seperatly.
*
- * TODO
- * Names with glue on the delegation are NOT marked! They are handled seperatly
- * and specially within the is_glue() function in dnssec.c to exclude them
- * from the NSEC and NSEC3 bitmaps; and in ldns_dnssec_zone_create_rrsigs_flg()
- * in dnssec_sign.c to make sure those rrsets are not signed.
- *
- * Also, names that have other obscured rrsets besides A and AAAA types will NOT
- * be marked. This is probably a mistake.
+ * When glue_list is given (not NULL), in the process of marking the names, all
+ * glue resource records will be pushed to that list. Even glue in partially
+ * obscured names.
+ *
+ * \param[in] zone the zone in which to mark the names
+ * \param[in] glue_list the list to which to push the glue rrs
+ * \return LDNS_STATUS_OK on success, an error code otherwise
*/
ldns_status
-ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone)
+ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone,
+ ldns_rr_list *glue_list)
{
- ldns_rbnode_t *cur_node;
- ldns_dnssec_name *cur_name;
- ldns_rdf *cur_owner, *cur_parent;
+ ldns_rbnode_t *node;
+ ldns_dnssec_name *name;
+ ldns_rdf *owner;
+ ldns_rdf *cut = NULL; /* keeps track of zone cuts */
+ /* When the cut is caused by a delegation, below_delegation will be 1.
+ * When caused by a DNAME, below_delegation will be 0.
+ */
+ int below_delegation = -1; /* init suppresses comiler warning */
+ ldns_status s;
- cur_node = ldns_rbtree_first(zone->names);
- while (cur_node != LDNS_RBTREE_NULL) {
- cur_name = (ldns_dnssec_name *) cur_node->data;
- cur_node = ldns_rbtree_next(cur_node);
- if (ldns_dnssec_name_has_only_a(cur_name)) {
- /* assume glue XXX check for zone cut */
- cur_owner = ldns_rdf_clone(ldns_rr_owner(
- cur_name->rrsets->rrs->rr));
- while (ldns_dname_label_count(cur_owner) >
- ldns_dname_label_count(zone->soa->name)) {
- if (ldns_dnssec_zone_find_rrset(zone,
- cur_owner,
- LDNS_RR_TYPE_NS)) {
- /*
- fprintf(stderr, "[XX] Marking as glue: ");
- ldns_rdf_print(stderr, cur_name->name);
- fprintf(stderr, "\n");
- */
- cur_name->is_glue = true;
+ if (!zone || !zone->names) {
+ return LDNS_STATUS_NULL;
+ }
+ for (node = ldns_rbtree_first(zone->names);
+ node != LDNS_RBTREE_NULL;
+ node = ldns_rbtree_next(node)) {
+ name = (ldns_dnssec_name *) node->data;
+ owner = ldns_dnssec_name_name(name);
+
+ if (cut) {
+ /* The previous node was a zone cut, or a subdomain
+ * below a zone cut. Is this node (still) a subdomain
+ * below the cut? Then the name is occluded. Unless
+ * the name contains a SOA, after which we are
+ * authoritative again.
+ *
+ * FIXME! If there are labels in between the SOA and
+ * the cut, going from the authoritative space (below
+ * the SOA) up into occluded space again, will not be
+ * detected with the contruct below!
+ */
+ if (ldns_dname_is_subdomain(owner, cut) &&
+ !ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_SOA)) {
+
+ if (below_delegation && glue_list) {
+ s = ldns_dnssec_addresses_on_glue_list(
+ name->rrsets, glue_list);
+ if (s != LDNS_STATUS_OK) {
+ return s;
+ }
}
- cur_parent = ldns_dname_left_chop(cur_owner);
- ldns_rdf_deep_free(cur_owner);
- cur_owner = cur_parent;
+ name->is_glue = true; /* Mark occluded name! */
+ continue;
+ } else {
+ cut = NULL;
}
- ldns_rdf_deep_free(cur_owner);
+ }
+
+ /* The node is not below a zone cut. Is it a zone cut itself?
+ * Everything below a SOA is authoritative of course; Except
+ * when the name also contains a DNAME :).
+ */
+ if (ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_SOA)) {
+ cut = owner;
+ below_delegation = 1;
+ if (glue_list) { /* record glue on the zone cut */
+ s = ldns_dnssec_addresses_on_glue_list(
+ name->rrsets, glue_list);
+ if (s != LDNS_STATUS_OK) {
+ return s;
+ }
+ }
+ } else if (ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_DNAME)) {
+ cut = owner;
+ below_delegation = 0;
}
}
return LDNS_STATUS_OK;
}
+/**
+ * Marks the names in the zone that are occluded. Those names will be skipped
+ * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
+ * function. But watch out! Names that are partially obscured (like glue with
+ * the same name as the delegation) will not be marked and should specifically
+ * be taken into account seperatly.
+ *
+ * \param[in] zone the zone in which to mark the names
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status
+ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone)
+{
+ return ldns_dnssec_zone_mark_and_get_glue(zone, NULL);
+}
+
ldns_rbnode_t *
ldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node)
{
size_t i;
+ int on_delegation_point = 0; /* handle partially obscured names */
+
ldns_rr_list *pubkey_list = ldns_rr_list_new();
zone = zone;
new_rrs = new_rrs;
cur_name = (ldns_dnssec_name *) cur_node->data;
if (!cur_name->is_glue) {
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ cur_name->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ cur_name->rrsets, LDNS_RR_TYPE_SOA);
cur_rrset = cur_name->rrsets;
while (cur_rrset) {
/* reset keys to use */
}
/* only sign non-delegation RRsets */
- /* (glue should have been marked earlier) */
- if ((ldns_rr_list_type(rr_list) != LDNS_RR_TYPE_NS ||
- ldns_dname_compare(ldns_rr_list_owner(rr_list),
- zone->soa->name) == 0) &&
- /* OK, there is also the possibility that the record
- * is glue, but at the same owner name as other records that
- * are not NS nor A/AAAA. Bleh, our current data structure
- * doesn't really support that... */
- !((ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_A ||
- ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_AAAA) &&
- !ldns_dname_compare(ldns_rr_list_owner(rr_list), zone->soa->name) == 0 &&
- ldns_dnssec_zone_find_rrset(zone, ldns_rr_list_owner(rr_list), LDNS_RR_TYPE_NS)
- )) {
-
+ /* (glue should have been marked earlier,
+ * except on the delegation points itself) */
+ if (!on_delegation_point ||
+ ldns_rr_list_type(rr_list)
+ == LDNS_RR_TYPE_DS ||
+ ldns_rr_list_type(rr_list)
+ == LDNS_RR_TYPE_NSEC ||
+ ldns_rr_list_type(rr_list)
+ == LDNS_RR_TYPE_NSEC3) {
siglist = ldns_sign_public(rr_list, key_list);
for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
if (cur_rrset->signatures) {
}
#endif /* HAVE_SSL */
+
return false;
}
-/* returns 1 if the list is empty, or if there are only ns or glue rrs in the
- * list, 0 otherwise */
-static int
-only_ns_and_glues_in_rrsets(ldns_dnssec_name *name,
- ldns_rr_list *glue_rrs
-)
-{
- ldns_dnssec_rrsets *cur_rrset = name->rrsets;
-
- while (cur_rrset) {
- if (cur_rrset->type != LDNS_RR_TYPE_NS &&
- !ldns_rr_list_contains_name(glue_rrs, name->name)
- ) {
- return 0;
- }
- cur_rrset = cur_rrset->next;
- }
- return 1;
-}
-
static void
print_type(ldns_rr_type type)
{
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 *keys)
{
ldns_rr_list *rrset_rrs;
ldns_dnssec_rrs *cur_rr, *cur_sig;
}
}
-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_rr_list *keys)
{
ldns_rbnode_t *next_node;
ldns_dnssec_name *name, *next_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);
+ next_node = ldns_rbtree_next(cur_node);
if (next_node == LDNS_RBTREE_NULL) {
next_node = ldns_rbtree_first(zone_nodes);
}
+ next_node = ldns_dnssec_name_node_next_nonglue(next_node);
next_name = (ldns_dnssec_name *)next_node->data;
if (ldns_dname_compare(next_name->name,
ldns_rr_rdf(name->nsec, 0))
printf("Error: the NSEC record for ");
ldns_rdf_print(stdout, name->name);
printf(" points to the wrong next owner name\n");
+ printf(" : ");
+ ldns_rdf_print(stdout, ldns_rr_rdf(name->nsec, 0));
+ printf(" i.s.o. ");
+ ldns_rdf_print(stdout, next_name->name);
+ printf(".\n");
if (result == LDNS_STATUS_OK) {
result = LDNS_STATUS_ERR;
}
} else {
/* todo; do this once and cache result? */
if (zone_is_nsec3_optout(zone_nodes) &&
- only_ns_and_glues_in_rrsets(name, glue_rrs)) {
+ ( ldns_dnssec_name_is_glue(name)
+ || (
+ ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_DS)
+ )
+ )) {
/* ok, no problem, but we need to remember to check
* whether the chain does not actually point to this
* name later */
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_rr_list *keys)
{
ldns_status result = LDNS_STATUS_OK;
ldns_status status;
ldns_dnssec_rrsets *cur_rrset;
ldns_dnssec_name *name;
+ int on_delegation_point;
/* for NSEC chain checks */
name = (ldns_dnssec_name *) cur_node->data;
printf("\n");
}
- if (ldns_dnssec_name_has_only_a(name) &&
- ldns_rr_list_contains_name(glue_rrs, name->name)
- ) {
+ if (ldns_dnssec_name_is_glue(name)) {
/* glue */
cur_rrset = name->rrsets;
while (cur_rrset) {
}
} else {
/* not glue, do real verify */
+
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_SOA);
+
cur_rrset = name->rrsets;
while(cur_rrset) {
- if ((cur_rrset->type != LDNS_RR_TYPE_A && cur_rrset->type != LDNS_RR_TYPE_AAAA) ||
- !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);
+
+ /* Do not check obscured rrsets
+ * on the delegation point
+ */
+ if ( ( on_delegation_point && (
+ cur_rrset->type == LDNS_RR_TYPE_NS
+ || cur_rrset->type == LDNS_RR_TYPE_DS))
+ || (!on_delegation_point &&
+ cur_rrset->type != LDNS_RR_TYPE_RRSIG
+ && cur_rrset->type != LDNS_RR_TYPE_NSEC)) {
+
+ status = verify_dnssec_rrset(zone_name, name->name, cur_rrset, keys);
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);
+ status = verify_nsec(zone_nodes, cur_node, keys);
if (result == LDNS_STATUS_OK) {
result = status;
}
static ldns_status
verify_dnssec_zone(ldns_dnssec_zone *dnssec_zone,
- ldns_rdf *zone_name,
- ldns_rr_list *glue_rrs)
-{
+ ldns_rdf *zone_name) {
ldns_rr_list *keys;
ldns_rbnode_t *cur_node;
ldns_dnssec_rrsets *cur_key_rrset;
dnssec_zone,
dnssec_zone->names,
cur_node,
- keys,
- glue_rrs);
+ keys);
if (status != LDNS_STATUS_OK && result == LDNS_STATUS_OK) {
result = status;
}
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) {
exit(1);
}
- glue_rrs = ldns_zone_glue_rr_list(z);
dnssec_zone = create_dnssec_zone(z);
+ result = ldns_dnssec_zone_mark_glue(dnssec_zone);
+ if (result != LDNS_STATUS_OK) {
+ if (verbosity >= 1) {
+ printf("There were errors identifying the glue in the zone\n");
+ }
+ }
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);
+ ldns_rr_owner(ldns_zone_soa(z)));
if (result == LDNS_STATUS_OK) {
size_t size,
ldns_rr_type nsec_type);
+/**
+ * returns whether a rrset of the given type is found in the rrsets.
+ *
+ * \param[in] *rsets the rrsets to be tested
+ * \param[in] type the type to test for
+ * \return int 1 if the type was found, 0 otherwise.
+ */
+int
+ldns_dnssec_rrsets_contains_type (ldns_dnssec_rrsets *rrsets, ldns_rr_type type);
+
/**
* Creates NSEC
*/
#endif /* HAVE_SSL */
/**
- * Marks the names in the zone that contain only glue, by setting the
- * is_glue attribute of the ldns_dnssec_name structure to true.
- * Names with glue on the delegation point and occluded names with other
- * rrsets than only A and AAAA are not marked!
+ * Marks the names in the zone that are occluded. Those names will be skipped
+ * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
+ * function. But watch out! Names that are partially obscured (like glue with
+ * the same name as the delegation) will not be marked and should specifically
+ * be taken into account seperatly.
+ *
+ * When glue_list is given (not NULL), in the process of marking the names, all
+ * glue resource records will be pushed to that list. Even glue in partially
+ * obscured names.
+ *
+ * \param[in] zone the zone in which to mark the names
+ * \param[in] glue_list the list to which to push the glue rrs
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status
+ldns_dnssec_zone_mark_and_get_glue(
+ ldns_dnssec_zone *zone, ldns_rr_list *glue_list);
+
+/**
+ * Marks the names in the zone that are occluded. Those names will be skipped
+ * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
+ * function. But watch out! Names that are partially obscured (like glue with
+ * the same name as the delegation) will not be marked and should specifically
+ * be taken into account seperatly.
*
* \param[in] zone the zone in which to mark the names
* \return LDNS_STATUS_OK on succesful completion
ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone);
/**
- * Finds the first dnssec_name node in the rbtree that has not been marked
- * as glue, starting at the given node
+ * Finds the first dnssec_name node in the rbtree that is not occluded.
+ * It *does* return names that are partially obscured.
*
* \param[in] node the first node to check
* \return the first node that has not been marked as glue, or NULL
ldns_dnssec_zone_find_nsec3_original
ldns_dnssec_zone_find_rrset
ldns_dnssec_zone_free
+ldns_dnssec_zone_mark_and_get_glue
ldns_dnssec_zone_mark_glue
ldns_dnssec_zone_names_print
ldns_dnssec_zone_new