/*! * \brief Connect two nodes by adding a NSEC RR into the first node. * * Callback function, signature chain_iterate_cb. * * \param a First node. * \param b Second node (immediate follower of a). * \param data Pointer to nsec_chain_iterate_data_t holding parameters * including changeset. * * \return Error code, KNOT_EOK if successful. */ static int connect_nsec_nodes(zone_node_t *a, zone_node_t *b, nsec_chain_iterate_data_t *data) { assert(a); assert(b); assert(data); if (b->rrset_count == 0 || b->flags & NODE_FLAGS_NONAUTH) { return NSEC_NODE_SKIP; } int ret = 0; /*! * If the node has no other RRSets than NSEC (and possibly RRSIGs), * just remove the NSEC and its RRSIG, they are redundant */ if (node_rrtype_exists(b, KNOT_RRTYPE_NSEC) && knot_nsec_empty_nsec_and_rrsigs_in_node(b)) { ret = knot_nsec_changeset_remove(b, data->changeset); if (ret != KNOT_EOK) { return ret; } // Skip the 'b' node return NSEC_NODE_SKIP; } // create new NSEC knot_rrset_t *new_nsec = create_nsec_rrset(a, b, data->ttl); if (!new_nsec) { dbg_dnssec_detail("Failed to create new NSEC.\n"); return KNOT_ENOMEM; } knot_rrset_t old_nsec = node_rrset(a, KNOT_RRTYPE_NSEC); if (!knot_rrset_empty(&old_nsec)) { if (knot_rrset_equal(new_nsec, &old_nsec, KNOT_RRSET_COMPARE_WHOLE)) { // current NSEC is valid, do nothing dbg_dnssec_detail("NSECs equal.\n"); knot_rrset_free(&new_nsec, NULL); return KNOT_EOK; } dbg_dnssec_detail("NSECs not equal, replacing.\n"); // Mark the node so that we do not sign this NSEC a->flags |= NODE_FLAGS_REMOVED_NSEC; ret = knot_nsec_changeset_remove(a, data->changeset); if (ret != KNOT_EOK) { knot_rrset_free(&new_nsec, NULL); return ret; } } dbg_dnssec_detail("Adding new NSEC to changeset.\n"); // Add new NSEC to the changeset (no matter if old was removed) return knot_changeset_add_rrset(data->changeset, new_nsec, KNOT_CHANGESET_ADD); }
static int adjust_pointers(zone_node_t **tnode, void *data) { assert(data != NULL); assert(tnode != NULL); zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; zone_node_t *node = *tnode; // remember first node if (args->first_node == NULL) { args->first_node = node; } // clear Removed NSEC flag so that no relicts remain node->flags &= ~NODE_FLAGS_REMOVED_NSEC; // check if this node is not a wildcard child of its parent if (knot_dname_is_wildcard(node->owner)) { assert(node->parent != NULL); node->parent->flags |= NODE_FLAGS_WILDCARD_CHILD; } // set flags (delegation point, non-authoritative) if (node->parent && ((node->parent->flags & NODE_FLAGS_DELEG) || node->parent->flags & NODE_FLAGS_NONAUTH)) { node->flags |= NODE_FLAGS_NONAUTH; } else if (node_rrtype_exists(node, KNOT_RRTYPE_NS) && node != args->zone->apex) { node->flags |= NODE_FLAGS_DELEG; } else { // Default. node->flags = NODE_FLAGS_AUTH; } // set pointer to previous node node->prev = args->previous_node; // update remembered previous pointer only if authoritative if (!(node->flags & NODE_FLAGS_NONAUTH) && node->rrset_count > 0) { args->previous_node = node; } return KNOT_EOK; }
/*! * \brief Create NSEC RR set. * * \param from Node that should contain the new RRSet * \param to Node that should be pointed to from 'from' * \param ttl Record TTL (SOA's minimum TTL). * * \return NSEC RR set, NULL on error. */ static knot_rrset_t *create_nsec_rrset(const zone_node_t *from, const zone_node_t *to, uint32_t ttl) { assert(from); assert(to); knot_rrset_t *rrset = knot_rrset_new(from->owner, KNOT_RRTYPE_NSEC, KNOT_CLASS_IN, NULL); if (!rrset) { return NULL; } // Create bitmap bitmap_t rr_types = { 0 }; bitmap_add_node_rrsets(&rr_types, from); bitmap_add_type(&rr_types, KNOT_RRTYPE_NSEC); bitmap_add_type(&rr_types, KNOT_RRTYPE_RRSIG); if (node_rrtype_exists(from, KNOT_RRTYPE_SOA)) { bitmap_add_type(&rr_types, KNOT_RRTYPE_DNSKEY); } // Create RDATA assert(to->owner); size_t next_owner_size = knot_dname_size(to->owner); size_t rdata_size = next_owner_size + bitmap_size(&rr_types); uint8_t rdata[rdata_size]; // Fill RDATA memcpy(rdata, to->owner, next_owner_size); bitmap_write(&rr_types, rdata + next_owner_size); int ret = knot_rrset_add_rdata(rrset, rdata, rdata_size, ttl, NULL); if (ret != KNOT_EOK) { knot_rrset_free(&rrset, NULL); return NULL; } return rrset; }
static int axfr_answer_packet(knot_pkt_t *pkt, struct xfr_proc *proc) { assert(pkt != NULL); assert(proc != NULL); /* Update counters. */ proc->npkts += 1; proc->nbytes += pkt->size; /* Init zone creator. */ zcreator_t zc = {.z = proc->contents, .master = false, .ret = KNOT_EOK }; const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); for (uint16_t i = 0; i < answer->count; ++i) { const knot_rrset_t *rr = &answer->rr[i]; if (rr->type == KNOT_RRTYPE_SOA && node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) { return KNOT_NS_PROC_DONE; } else { int ret = zcreator_step(&zc, rr); if (ret != KNOT_EOK) { return KNOT_NS_PROC_FAIL; } } } return KNOT_NS_PROC_MORE; } int axfr_answer_process(knot_pkt_t *pkt, struct answer_data *adata) { if (pkt == NULL || adata == NULL) { return KNOT_NS_PROC_FAIL; } /* Check RCODE. */ uint8_t rcode = knot_wire_get_rcode(pkt->wire); if (rcode != KNOT_RCODE_NOERROR) { lookup_table_t *lut = lookup_by_id(knot_rcode_names, rcode); if (lut != NULL) { AXFRIN_LOG(LOG_ERR, "server responded with %s", lut->name); } return KNOT_NS_PROC_FAIL; } /* Initialize processing with first packet. */ if (adata->ext == NULL) { NS_NEED_TSIG_SIGNED(&adata->param->tsig_ctx, 0); AXFRIN_LOG(LOG_INFO, "starting"); int ret = axfr_answer_init(adata); if (ret != KNOT_EOK) { AXFRIN_LOG(LOG_ERR, "failed (%s)", knot_strerror(ret)); return KNOT_NS_PROC_FAIL; } } else { NS_NEED_TSIG_SIGNED(&adata->param->tsig_ctx, 100); } /* Process answer packet. */ int ret = axfr_answer_packet(pkt, (struct xfr_proc *)adata->ext); if (ret == KNOT_NS_PROC_DONE) { NS_NEED_TSIG_SIGNED(&adata->param->tsig_ctx, 0); /* This was the last packet, finalize zone and publish it. */ int fret = axfr_answer_finalize(adata); if (fret != KNOT_EOK) { ret = KNOT_NS_PROC_FAIL; } } return ret; }