Example #1
0
static void
rr_canonize_nsec3param(zdb_packed_ttlrdata* rr, ptr_vector* v)
{
    while(rr != NULL)
    {
        zdb_canonized_packed_ttlrdata* c_rr;

        u32 c_rr_size = sizeof (zdb_canonized_packed_ttlrdata) - 1 + ZDB_PACKEDRECORD_PTR_RDATASIZE(rr);
        MALLOC_OR_DIE(zdb_canonized_packed_ttlrdata*, c_rr, c_rr_size, RR_CANONIZE_NOP_TAG);

        ZDB_PACKEDRECORD_PTR_RDATASIZE(c_rr) = ZDB_PACKEDRECORD_PTR_RDATASIZE(rr);
        c_rr->rdata_canonized_size = htons(ZDB_PACKEDRECORD_PTR_RDATASIZE(rr));
        MEMCOPY(&c_rr->rdata_start[0], ZDB_PACKEDRECORD_PTR_RDATAPTR(rr), ZDB_PACKEDRECORD_PTR_RDATASIZE(rr));
        c_rr->rdata_start[1] = 0; /* The signed NSEC3PARAM has its flags to 0 */
        ptr_vector_append(v, c_rr);

        rr = rr->next;
    }
}
Example #2
0
static void
rr_canonize_nop(zdb_packed_ttlrdata* rr, ptr_vector* v)
{
    while(rr != NULL)
    {
        zdb_canonized_packed_ttlrdata* c_rr;

        u32 c_rr_size = sizeof (zdb_canonized_packed_ttlrdata) - 1 + ZDB_PACKEDRECORD_PTR_RDATASIZE(rr);
        MALLOC_OR_DIE(zdb_canonized_packed_ttlrdata*, c_rr, c_rr_size, RR_CANONIZE_NOP_TAG);

        ZDB_PACKEDRECORD_PTR_RDATASIZE(c_rr) = ZDB_PACKEDRECORD_PTR_RDATASIZE(rr);
        c_rr->rdata_canonized_size = htons(ZDB_PACKEDRECORD_PTR_RDATASIZE(rr));
        /** @todo CHECK: If we don't lo-case anymore maybe I could grab some
         *        more cycles here.  Not for the A-records on a 64bits arch,
         *        but for any case where the rdata is (much) bigger than 8 bytes
         */
        MEMCOPY(&c_rr->rdata_start[0], ZDB_PACKEDRECORD_PTR_RDATAPTR(rr), ZDB_PACKEDRECORD_PTR_RDATASIZE(rr));
        ptr_vector_append(v, c_rr);

        rr = rr->next;
    }
}
Example #3
0
bool
nsec_update_label_record(zdb_rr_label *label, nsec_node *node, nsec_node *next_node, u8 *name, u32 ttl)
{
    type_bit_maps_context tbmctx;
    u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */
    u32 tbm_size = type_bit_maps_initialize(&tbmctx, label, TRUE, TRUE);

    type_bit_maps_write(tmp_bitmap, &tbmctx);

    /*
     * Get the NSEC record
     */

    zdb_packed_ttlrdata *nsec_record;

    if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL)
    {
        /*
         * has record -> compare the type and the nsec next
         * if something does not match remove the record and its signature (no record)
         *
         */

        log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) updating record.", name, node->inverse_relative_name, next_node->inverse_relative_name);

        /*
         * If there is more than one record, clean-up
         */


        if(nsec_record->next == NULL)
        {
            u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
            u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record);

            u16 dname_len = dnsname_len(rdata);

            if(dname_len < size)
            {
                u8* type_bitmap = &rdata[dname_len];

                /*
                 * check the type bitmap
                 */

                if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0)
                {
                    /*
                     * check the nsec next
                     */

                    if(dnsname_equals(rdata, name))
                    {
                        /* All good */

                        return FALSE;
                    }
                }
            }    
        }

        if(zdb_listener_notify_enabled())
        {
            zdb_packed_ttlrdata *nsec_rec = nsec_record;

            do
            {
                zdb_ttlrdata unpacked_ttlrdata;

                unpacked_ttlrdata.ttl = nsec_rec->ttl;
                unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec);
                unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec);

                zdb_listener_notify_remove_record(name, TYPE_NSEC, &unpacked_ttlrdata);

                nsec_rec = nsec_rec->next;
            }
            while(nsec_rec != NULL);
        }

        zdb_record_delete(&label->resource_record_set, TYPE_NSEC);

        rrsig_delete(name, label, TYPE_NSEC);

        nsec_record = NULL;
    }

    /*
     * no record -> create one and schedule a signature
     */

    if(nsec_record == NULL)
    {
        zdb_packed_ttlrdata *nsec_record;
        u8 next_name[256];

        log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) building new record.", name, node->inverse_relative_name, next_node->inverse_relative_name);

        u16 dname_len = nsec_inverse_name(next_name, next_node->inverse_relative_name);
        u16 rdata_size = dname_len + tbm_size;

        ZDB_RECORD_ZALLOC_EMPTY(nsec_record, ttl, rdata_size);

        u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

        memcpy(rdata, next_name, dname_len);
        rdata += dname_len;

        memcpy(rdata, tmp_bitmap, tbm_size);

        zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record);
        
        if(zdb_listener_notify_enabled())
        {        
            dnsname_vector name_path;

            zdb_ttlrdata unpacked_ttlrdata;
            
            unpacked_ttlrdata.ttl = ttl;
            unpacked_ttlrdata.rdata_size = rdata_size;
            unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

            dnsname_to_dnsname_vector(name, &name_path);

            zdb_listener_notify_add_record(name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata);
        }

        /*
         * Schedule a signature
         */
    }

    label->flags |= ZDB_RR_LABEL_NSEC;

    return TRUE;
}
Example #4
0
ya_result
nsec_update_zone(zdb_zone *zone)
{
    nsec_node *nsec_tree = NULL;
    soa_rdata soa;

    u8 name[MAX_DOMAIN_LENGTH];
    u8 inverse_name[MAX_DOMAIN_LENGTH];
    u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */

    ya_result return_code;

    if(FAIL(return_code = zdb_zone_getsoa(zone, &soa)))
    {
        return return_code;
    }

    zdb_zone_label_iterator label_iterator;
    zdb_zone_label_iterator_init(zone, &label_iterator);

    while(zdb_zone_label_iterator_hasnext(&label_iterator))
    {
        zdb_zone_label_iterator_nextname(&label_iterator, name);
        zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);

        if(zdb_rr_label_is_glue(label) || (label->resource_record_set == NULL))
        {
            continue;
        }

        nsec_inverse_name(inverse_name, name);

        nsec_node *node = nsec_avl_insert(&nsec_tree, inverse_name);
        node->label = label;
        label->nsec.nsec.node = node;
    }

    /*
     * Now that we have the NSEC chain
     */

    nsec_node *first_node;
    nsec_node *node;

    type_bit_maps_context tbmctx;

    nsec_avl_iterator nsec_iter;
    nsec_avl_iterator_init(&nsec_tree, &nsec_iter);

    if(nsec_avl_iterator_hasnext(&nsec_iter))
    {
        first_node = nsec_avl_iterator_next_node(&nsec_iter);

        node = first_node;

        do
        {
            nsec_node *next_node;

            nsec_update_zone_count++;

            if(nsec_avl_iterator_hasnext(&nsec_iter))
            {
                next_node = nsec_avl_iterator_next_node(&nsec_iter);
            }
            else
            {
                next_node = first_node;
            }

            /*
             * Compute the type bitmap
             */

            zdb_rr_label *label = node->label;

            u32 tbm_size = type_bit_maps_initialize(&tbmctx, label, TRUE, TRUE);
            type_bit_maps_write(tmp_bitmap, &tbmctx);

            nsec_inverse_name(name, next_node->inverse_relative_name);

            /*
             * Get the NSEC record
             */

            zdb_packed_ttlrdata *nsec_record;

            if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL)
            {
                /*
                 * has record -> compare the type and the nsec next
                 * if something does not match remove the record and its signature (no record)
                 *
                 */

                if(nsec_record->next == NULL)
                {
                    u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
                    u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record);

                    u16 dname_len = dnsname_len(rdata);

                    if(dname_len < size)
                    {
                        u8* type_bitmap = &rdata[dname_len];

                        /*
                         * check the type bitmap
                         */

                        if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0)
                        {
                            /*
                             * check the nsec next
                             */

                            if(dnsname_equals(rdata, name))
                            {
                                /* All good */
                                
                                label->flags |= ZDB_RR_LABEL_NSEC;

                                node = next_node;
                                continue;
                            }
                        }
                    }
                }
                
                if(zdb_listener_notify_enabled())
                {
                    zdb_packed_ttlrdata *nsec_rec = nsec_record;

                    do
                    {
                        zdb_ttlrdata unpacked_ttlrdata;

                        unpacked_ttlrdata.ttl = nsec_rec->ttl;
                        unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec);
                        unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec);

                        zdb_listener_notify_remove_record(name, TYPE_NSEC, &unpacked_ttlrdata);

                        nsec_rec = nsec_rec->next;
                    }
                    while(nsec_rec != NULL);
                }

                zdb_record_delete(&label->resource_record_set, TYPE_NSEC);

                rrsig_delete(name, label, TYPE_NSEC);

                nsec_record = NULL;
            }

            /*
             * no record -> create one and schedule a signature
             */

            if(nsec_record == NULL)
            {
                zdb_packed_ttlrdata *nsec_record;

                u16 dname_len = nsec_inverse_name(name, next_node->inverse_relative_name);
                u16 rdata_size = dname_len + tbm_size;

                ZDB_RECORD_ZALLOC_EMPTY(nsec_record, soa.minimum, rdata_size);

                u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

                memcpy(rdata, name, dname_len);
                rdata += dname_len;

                memcpy(rdata, tmp_bitmap, tbm_size);
                
                zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record);

                /*
                 * Schedule a signature
                 */
            }

            label->flags |= ZDB_RR_LABEL_NSEC;

            node = next_node;
        }
        while(node != first_node);
    }

    zone->nsec.nsec = nsec_tree;

    return SUCCESS;
}
Example #5
0
ya_result
nsec3_icmtl_replay_execute(nsec3_icmtl_replay *replay)
{
    bool nsec3param_added = FALSE;
    
    if(!treeset_avl_isempty(&replay->nsec3param_add))
    {
        treeset_avl_iterator n3p_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3param_add, &n3p_avl_iter);

        while(treeset_avl_iterator_hasnext(&n3p_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&n3p_avl_iter);
            zdb_ttlrdata* nsec3param = (zdb_ttlrdata*)node->data;
            
            nsec3_zone* n3 = nsec3_zone_get_from_rdata(replay->zone, nsec3param->rdata_size, nsec3param->rdata_pointer);
            
            if(n3 == NULL)
            {
                /*
                 * add the record
                 */
                
                zdb_packed_ttlrdata *packed_ttlrdata;
                ZDB_RECORD_ZALLOC(packed_ttlrdata, 0, nsec3param->rdata_size ,nsec3param->rdata_pointer);
                zdb_record_insert(&replay->zone->apex->resource_record_set, TYPE_NSEC3PARAM, packed_ttlrdata);
                
                nsec3_zone_add_from_rdata(replay->zone, nsec3param->rdata_size, nsec3param->rdata_pointer);
                //nsec3_load_chain_init(nsec3param->rdata_pointer, nsec3param->rdata_size);
                
                nsec3param_added = TRUE;
            }
            
            zdb_ttlrdata_delete(nsec3param);
            
            node->key = NULL;
            node->data = NULL;
        }
        
        treeset_avl_destroy(&replay->nsec3param_add);
    }
    
    if(!treeset_avl_isempty(&replay->nsec3_del))
    {
        /* stuff to delete */

        treeset_avl_iterator ts_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3_del, &ts_avl_iter);

        while(treeset_avl_iterator_hasnext(&ts_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter);
            u8 *fqdn = (u8*)node->key;
            zdb_ttlrdata *ttlrdata = (zdb_ttlrdata*)node->data;

#ifndef NDEBUG
            log_debug("journal: NSEC3: post/del %{dnsname}", fqdn);
#endif
            treeset_node *add_node;

            if((add_node = treeset_avl_find(&replay->nsec3_add, fqdn)) != NULL)
            {
                /* replace */

#ifndef NDEBUG
                log_debug("journal: NSEC3: upd %{dnsname}", fqdn);

                rdata_desc type_len_rdata = {TYPE_NSEC3, ttlrdata->rdata_size, ttlrdata->rdata_pointer };
                log_debug("journal: NSEC3: - %{typerdatadesc}", &type_len_rdata);
#endif

                zdb_ttlrdata *add_ttlrdata = (zdb_ttlrdata *)add_node->data;

#ifndef NDEBUG
                rdata_desc add_type_len_rdata = {TYPE_NSEC3, add_ttlrdata->rdata_size, add_ttlrdata->rdata_pointer };
                log_debug("journal: NSEC3: + %{typerdatadesc}", &add_type_len_rdata);
#endif

                /*
                 * The node may need an update of the type bitmap
                 * After all changes (del/upd/add) all the added records should be matched again (check)
                 *
                 * nsec3_zone_item_get_by_name();
                 * nsec3_zone_item_update_bitmap(item, rdata, rdata_len)
                 */

                nsec3_zone_item *add_item = nsec3_zone_item_find_by_record(replay->zone, fqdn, ttlrdata->rdata_size, ttlrdata->rdata_pointer);
                
                if(add_item != NULL)
                {
                    nsec3_zone_item_update_bitmap(add_item, add_ttlrdata->rdata_pointer, add_ttlrdata->rdata_size);

                    u8* add_key = add_node->key;
                    treeset_avl_delete(&replay->nsec3_add, fqdn);
                    zdb_ttlrdata_delete(add_ttlrdata);
                    free(add_key);
                }
                else
                {
                    log_err("journal: NSEC3: %{dnsname} has not been found in the NSEC3 database (del/add)", fqdn);
                    
                    return ERROR;
                }
            }
            else
            {
#ifndef NDEBUG
                log_debug("journal: NSEC3: del %{dnsname}", fqdn);

                rdata_desc type_len_rdata = {TYPE_NSEC3, ttlrdata->rdata_size, ttlrdata->rdata_pointer };
                log_debug("journal: NSEC3: - %{typerdatadesc}", &type_len_rdata);
#endif

                /* delete */

                nsec3_zone_item *add_item = nsec3_zone_item_find_by_record(replay->zone, fqdn, ttlrdata->rdata_size, ttlrdata->rdata_pointer);

                if(add_item != NULL)
                {
                    nsec3_remove_nsec3_by_name(replay->zone, fqdn, ttlrdata->rdata_pointer);
                }
                else
                {
                    log_err("journal: NSEC3: %{dnsname} has not been found in the NSEC3 database (del)", fqdn);
                }

                /*
                 * The node has to be deleted
                 */
            }

            zdb_ttlrdata_delete(ttlrdata);
            free(fqdn);
            
            node->key = NULL;
            node->data = NULL;
        }

        treeset_avl_destroy(&replay->nsec3_del);
    }
    if(!treeset_avl_isempty(&replay->nsec3_add))
    {
        /* stuff to add */

        treeset_avl_iterator ts_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3_add, &ts_avl_iter);

        while(treeset_avl_iterator_hasnext(&ts_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter);
            u8 *fqdn = (u8*)node->key;

#ifndef NDEBUG
            log_debug("journal: NSEC3: post/add %{dnsname}", fqdn);
#endif

            zdb_ttlrdata *ttlrdata = (zdb_ttlrdata*)node->data;

#ifndef NDEBUG
            log_debug("journal: NSEC3: add %{dnsname}", fqdn);

            rdata_desc type_len_rdata = {TYPE_NSEC3, ttlrdata->rdata_size, ttlrdata->rdata_pointer };
            log_debug("journal: NSEC3: + %{typerdatadesc}", &type_len_rdata);
#endif

            /*
             * The node must be added.  It should not exist already.
             * After all changes (del/upd/add) all the added records should be matched again (check)
             */

            nsec3_zone_item *add_item = nsec3_zone_item_find_by_record(replay->zone, fqdn, ttlrdata->rdata_size, ttlrdata->rdata_pointer);
            
            if(add_item != NULL)
            {
                log_err("journal: NSEC3: already exists");
                
                nsec3_zone *n3 = replay->zone->nsec.nsec3;
                
                if(n3 != NULL )
                {
                    zdb_packed_ttlrdata *nsec3;
                    zdb_packed_ttlrdata *nsec3_rrsig;
                    u8 owner[256];
                    
                    nsec3_zone_item_to_zdb_packed_ttlrdata(n3,
                                                    add_item,
                                                    replay->zone->origin,
                                                    owner,
                                                    600,
                                                    &nsec3,
                                                    &nsec3_rrsig);
                    
#ifndef NDEBUG
                    rdata_desc type_len_rdata = {TYPE_NSEC3, nsec3->rdata_size, nsec3->rdata_start };
                    log_debug("journal: NSEC3: ? %{typerdatadesc}", &type_len_rdata);
#endif
                    
                    free(nsec3);
                    
                    nsec3_remove_nsec3_by_digest(replay->zone, add_item->digest, ttlrdata->rdata_pointer);
                }
            }
            
            nsec3_add_nsec3_by_name(replay->zone, fqdn, ttlrdata->rdata_pointer, ttlrdata->rdata_size);

            zdb_ttlrdata_delete(ttlrdata);
            free(fqdn);
            
            node->key = NULL;
            node->data = NULL;
        }

        treeset_avl_destroy(&replay->nsec3_add);
    }
    if(!treeset_avl_isempty(&replay->nsec3rrsig_del))
    {
        /* stuff to add */

        treeset_avl_iterator ts_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3rrsig_del, &ts_avl_iter);

        while(treeset_avl_iterator_hasnext(&ts_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter);
            u8 *fqdn = (u8*)node->key;
            
#ifndef NDEBUG
            log_debug("journal: NSEC3: post/add %{dnsname}", fqdn);
#endif

            zdb_ttlrdata *nsec3_rrsig = (zdb_ttlrdata*)node->data;

#ifndef NDEBUG
            log_debug("journal: NSEC3: add %{dnsname}", fqdn);

            rdata_desc type_len_rdata = {TYPE_RRSIG, ZDB_RECORD_PTR_RDATASIZE(nsec3_rrsig), ZDB_RECORD_PTR_RDATAPTR(nsec3_rrsig) };
            log_debug("journal: NSEC3: + %{typerdatadesc}", &type_len_rdata);
#endif

            /*
             * The node must be added.  It should not exist already.
             * After all changes (del/upd/add) all the added records should be matched again (check)
             */
            nsec3_zone_item *item = nsec3_zone_item_find_by_name_ext(replay->zone, fqdn, NULL);

            if(item != NULL)
            {
                nsec3_zone_item_rrsig_del(item, nsec3_rrsig);
            }

            zdb_ttlrdata_delete(nsec3_rrsig);
            free(fqdn);
            
            node->key = NULL;
            node->data = NULL;
        }

        treeset_avl_destroy(&replay->nsec3rrsig_del);
    }
    if(!treeset_avl_isempty(&replay->nsec3rrsig_add))
    {
        /* stuff to add */

        treeset_avl_iterator ts_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3rrsig_add, &ts_avl_iter);

        while(treeset_avl_iterator_hasnext(&ts_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter);
            u8 *fqdn = (u8*)node->key;

#ifndef NDEBUG
            log_debug("journal: NSEC3: post/add %{dnsname}", fqdn);
#endif

            zdb_packed_ttlrdata *nsec3_rrsig = (zdb_packed_ttlrdata*)node->data;

#ifndef NDEBUG
            log_debug("journal: NSEC3: add %{dnsname}", fqdn);

            rdata_desc type_len_rdata = {TYPE_RRSIG, ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec3_rrsig), ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec3_rrsig) };
            log_debug("journal: NSEC3: + %{typerdatadesc}", &type_len_rdata);
#endif

            /*
             * The node must be added.  It should not exist already.
             * After all changes (del/upd/add) all the added records should be matched again (check)
             */
            nsec3_zone_item *item = nsec3_zone_item_find_by_name_ext(replay->zone, fqdn, NULL);

            if(item != NULL)
            {
                nsec3_zone_item_rrsig_add(item, nsec3_rrsig);
            }
            else
            {
                ZDB_RECORD_ZFREE(nsec3_rrsig);
            }

            free(fqdn);
            
            node->key = NULL;
            node->data = NULL;
        }

        treeset_avl_destroy(&replay->nsec3rrsig_add);
    }
    if(!treeset_avl_isempty(&replay->nsec3_labels))
    {
        /* labels to update */

        treeset_avl_iterator ts_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3_labels, &ts_avl_iter);

        while(treeset_avl_iterator_hasnext(&ts_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter);
            u8 *fqdn = (u8*)node->key;
            zdb_rr_label *rr_label = (zdb_rr_label*)node->data;

#ifndef NDEBUG
            log_debug("journal: NSEC3: lbl %{dnsname} (%{dnslabel})", fqdn, rr_label->name);
#endif
            
            /*
             * The fqdn/label should be updated for self & star match.
             */

            if(rr_label->nsec.nsec3 == NULL)
            {
                nsec3_label_link(replay->zone, rr_label, fqdn);
            }
            
            free(fqdn);
            
            node->key = NULL;
            node->data = NULL;
        }

        treeset_avl_destroy(&replay->nsec3_labels);
    }
    
    /**/
    
    if(nsec3param_added)
    {
        /*
         * ALL the labels of the zone have to be linked again.
         */
        
        zdb_zone_label_iterator label_iterator;
        
        u8 fqdn[MAX_DOMAIN_LENGTH];
        
        
        zdb_zone_label_iterator_init(replay->zone, &label_iterator);

        while(zdb_zone_label_iterator_hasnext(&label_iterator))
        {
            
            zdb_zone_label_iterator_nextname(&label_iterator, fqdn);

            zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
         
            nsec3_label_link(replay->zone, label, fqdn);
        }
    }
    
    if(!treeset_avl_isempty(&replay->nsec3param_del))
    {
        treeset_avl_iterator n3p_avl_iter;
        treeset_avl_iterator_init(&replay->nsec3param_del, &n3p_avl_iter);

        while(treeset_avl_iterator_hasnext(&n3p_avl_iter))
        {
            treeset_node *node = treeset_avl_iterator_next_node(&n3p_avl_iter);
            zdb_ttlrdata* nsec3param = (zdb_ttlrdata*)node->data;
            
            nsec3_zone* n3 = nsec3_zone_get_from_rdata(replay->zone, nsec3param->rdata_size, nsec3param->rdata_pointer);
            
            if(n3 == NULL)
            {
                nsec3_zone_destroy(replay->zone, n3);
                
                zdb_record_delete_exact(&replay->zone->apex->resource_record_set, TYPE_NSEC3PARAM, nsec3param);
            }
            
            zdb_ttlrdata_delete(nsec3param);
            
            node->key = NULL;
            node->data = NULL;
        }
        
        treeset_avl_destroy(&replay->nsec3param_del);
    }    
    
    return SUCCESS;
}
Example #6
0
ya_result
nsec_update_zone(zdb_zone *zone, bool read_only) // read_only a.k.a slave
{
    nsec_node *nsec_tree = NULL;
    nsec_node *first_node;
    nsec_node *node;
    u8 *prev_name;
    u8 *name;
    soa_rdata soa;
    u32 missing_nsec_records = 0;
    u32 sibling_count = 0;
    u32 nsec_under_delegation = 0;
    ya_result return_code;
    u8 name_buffer[2][MAX_DOMAIN_LENGTH];
    u8 inverse_name[MAX_DOMAIN_LENGTH];
    u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */

    yassert(zdb_zone_islocked_weak(zone));
    
    if(FAIL(return_code = zdb_zone_getsoa(zone, &soa))) // zone is locked (weak)
    {
        return return_code;
    }
    
#ifdef DEBUG
    memset(name_buffer, 0xde, sizeof(name_buffer));
#endif
    
    name = name_buffer[0];
    prev_name = name_buffer[1];
    
    zdb_zone_label_iterator label_iterator;
    zdb_zone_label_iterator_init(&label_iterator, zone);

    while(zdb_zone_label_iterator_hasnext(&label_iterator))
    {
        zdb_zone_label_iterator_nextname(&label_iterator, name);
        zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);

        if(zdb_rr_label_is_glue(label) || (label->resource_record_set == NULL))
        {
            // we are under a delegation or on an empty (non-terminal) 
            // there should not be an NSEC record here
            
            zdb_packed_ttlrdata *nsec_record;

            if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked
            {
                nsec_under_delegation++;
                
                log_err("nsec: %{dnsname}: unexpected NSEC record under a delegation", name);
            }
            
            continue;
        }

        nsec_inverse_name(inverse_name, name);

        nsec_node *node = nsec_avl_insert(&nsec_tree, inverse_name);
        node->label = label;
        label->nsec.nsec.node = node;
    }

    /*
     * Now that we have the NSEC chain
     */

    type_bit_maps_context tbmctx;
    
    nsec_avl_iterator nsec_iter;
    nsec_avl_iterator_init(&nsec_tree, &nsec_iter);

    if(nsec_avl_iterator_hasnext(&nsec_iter))
    {
        first_node = nsec_avl_iterator_next_node(&nsec_iter);

        node = first_node;

        do
        {
            nsec_node *next_node;

            nsec_update_zone_count++;

            if(nsec_avl_iterator_hasnext(&nsec_iter))
            {
                next_node = nsec_avl_iterator_next_node(&nsec_iter);
            }
            else
            {
                next_node = first_node;
            }

            /*
             * Compute the type bitmap
             */

            zdb_rr_label *label = node->label;
            
            if(label == NULL)
            {
                node = next_node;
                continue;
            }

            u32 tbm_size = type_bit_maps_initialise_from_label(&tbmctx, label, TRUE, TRUE);
            type_bit_maps_write(&tbmctx, tmp_bitmap);
            
            u8 *tmp_name = prev_name;
            prev_name = name;
            name = tmp_name;

            nsec_inverse_name(name, next_node->inverse_relative_name);

            /*
             * Get the NSEC record
             */

            zdb_packed_ttlrdata *nsec_record;

            if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked
            {
                /*
                 * has record -> compare the type and the nsec next
                 * if something does not match remove the record and its signature (no record)
                 *
                 */

                if(nsec_record->next == NULL) // should only be one record => delete all if not the case (the rrsig is lost anyway)
                {
                    const u8 *rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
                    const u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record);
                    const u16 dname_len = dnsname_len(rdata);

                    if(dname_len < size)
                    {
                        const u8 *type_bitmap = &rdata[dname_len];

                        /*
                         * check the type bitmap
                         */

                        if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0)
                        {
                            /*
                             * check the nsec next
                             */

                            if(dnsname_equals(rdata, name))
                            {
                                /* All good */
                                
                                label->flags |= ZDB_RR_LABEL_NSEC;

                                node = next_node;
                                continue;
                            }
                            else // else the "next fqdn" do not match (this is irrecoverable for a slave)
                            {
                                rdata_desc nsec_desc = {TYPE_NSEC, size, rdata};
                                log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} next field do not match expected value (%{dnsname})", zone->origin, prev_name, &nsec_desc, name);
                            }
                        }
                        else // else the type bitmap do not match (this is wrong)
                        {
                            rdata_desc nsec_desc = {TYPE_NSEC, size, rdata};
                            log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} types map do not match expected value", zone->origin, prev_name, &nsec_desc);
                        }
                    }
                    else // else the "next fqdn" do not match (early test, this is irrecoverable for a slave)
                    {
                        rdata_desc nsec_desc = {TYPE_NSEC, size, rdata};
                        log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} next field do not match expected value (%{dnsname})", zone->origin, prev_name, &nsec_desc, name);
                    }
                }
                else
                {
                    sibling_count++;
                    
                    log_warn("nsec: %{dnsname}: %{dnsname}: multiple NSEC records where only one is expected", zone->origin, prev_name);
                }
                
                // wrong NSEC RRSET
                
                zdb_packed_ttlrdata *nsec_rec = nsec_record;

                do
                {
                    zdb_ttlrdata unpacked_ttlrdata;

                    unpacked_ttlrdata.ttl = nsec_rec->ttl;
                    unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec);
                    unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec);

                    rdata_desc nsec_desc = {TYPE_NSEC, unpacked_ttlrdata.rdata_size, unpacked_ttlrdata.rdata_pointer};

                    if(!read_only)
                    {
                        log_warn("nsec: %{dnsname}: del: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
#if ZDB_CHANGE_FEEDBACK_SUPPORT
                        zdb_listener_notify_remove_record(zone, name, TYPE_NSEC, &unpacked_ttlrdata);
#endif
                    }
                    else
                    {
                        log_err("nsec: %{dnsname}: got: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
                    }

                    nsec_rec = nsec_rec->next;
                }
                while(nsec_rec != NULL);
                
                if(!read_only)
                {
                    zdb_record_delete(&label->resource_record_set, TYPE_NSEC);
                    rrsig_delete(zone, name, label, TYPE_NSEC);
                    nsec_record = NULL;
                }
            }

            /*
             * no record -> create one and schedule a signature (MASTER ONLY)
             */

            if(nsec_record == NULL)
            {
                missing_nsec_records++;
                
                zdb_packed_ttlrdata *nsec_record;

                u16 dname_len = nsec_inverse_name(name, next_node->inverse_relative_name);
                u16 rdata_size = dname_len + tbm_size;

                ZDB_RECORD_ZALLOC_EMPTY(nsec_record, soa.minimum, rdata_size);
                u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
                memcpy(rdata, name, dname_len);
                rdata += dname_len;
                memcpy(rdata, tmp_bitmap, tbm_size);
                
                rdata_desc nsec_desc = {TYPE_NSEC, ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record), ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record)};
                
                if(!read_only)
                {                    
                    zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record);

#ifdef DEBUG
                    log_debug("nsec: %{dnsname}: add: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
#endif
#if ZDB_CHANGE_FEEDBACK_SUPPORT
                    if(zdb_listener_notify_enabled())
                    {        
                        dnsname_vector name_path;

                        zdb_ttlrdata unpacked_ttlrdata;

                        unpacked_ttlrdata.ttl = nsec_record->ttl;
                        unpacked_ttlrdata.rdata_size = rdata_size;
                        unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

                        dnsname_to_dnsname_vector(name, &name_path);
                        zdb_listener_notify_add_record(zone, name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata);
                    }
#endif
                    
                    /*
                     * Schedule a signature
                     */
                }
                else
                {
                    log_warn("nsec: %{dnsname}: need: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
                    ZDB_RECORD_ZFREE(nsec_record);
                }
            }

            label->flags |= ZDB_RR_LABEL_NSEC;

            node = next_node;
        }
        while(node != first_node);
    }

    zone->nsec.nsec = nsec_tree;
    
    if(read_only)
    {
        if(missing_nsec_records + sibling_count + nsec_under_delegation)
        {
            log_err("nsec: missing records: %u, nsec with siblings: %u, nsec under delegation: %u", missing_nsec_records, sibling_count, nsec_under_delegation);
            
            //return DNSSEC_ERROR_NSEC_INVALIDZONESTATE;
        }
    }
    else
    {
        if(missing_nsec_records + sibling_count + nsec_under_delegation)
        {
            log_warn("nsec: missing records: %u, nsec with siblings: %u, nsec under delegation: %u", missing_nsec_records, sibling_count, nsec_under_delegation);
        }
    }
    
    return SUCCESS;
}
Example #7
0
ya_result
zdb_icmtl_replay_commit(zdb_zone *zone, input_stream *is, u32 *current_serialp)
{
    ya_result ret;
    /*
     * 0: DELETE, 1: ADD
     * The mode is switched every time an SOA is found.
     */

    yassert(zdb_zone_islocked(zone));
    
#if ZDB_HAS_NSEC3_SUPPORT
    bool has_nsec3 = zdb_zone_is_nsec3(zone);
#endif
#if ZDB_HAS_NSEC_SUPPORT
    bool has_nsec = zdb_zone_is_nsec(zone);
#endif
    
#if ZDB_HAS_NSEC3_SUPPORT && ZDB_HAS_NSEC_SUPPORT
    if(has_nsec3 && has_nsec)
    {
        log_err("journal: %{dnsname}: zone has both NSEC and NSEC3 status, which is not supported by YADIFA", zone->origin);
        return ERROR;
    }
#endif
    
    u8 mode = 1; // the first SOA will switch the mode to delete
    s32 changes = 0;
    
    zdb_ttlrdata ttlrdata;
    dns_resource_record rr;
    dns_resource_record_init(&rr);
    const u8 *fqdn = rr.name;
    dnslabel_vector labels;

    ttlrdata.next = NULL;
    


    /*
     * The plan for NSEC3 :
     * Store the fqdn + type class ttl rdata in collections
     * => the delete collection
     * => the add collection
     * Then there is the NSEC3 covered labels: keep a reference to them for later
     *
     * When a pass of SOA-/SOA+ has finished:
     * _ replace the NSEC3 in both collections (reading from delete)
     * _ delete NSEC3 to delete
     * _ add NSEC3 to add
     *
     * _ and finally update the NSEC3 for the labels kept above
     */

#if ZDB_HAS_NSEC3_SUPPORT
    chain_replay nsec3replay;
    nsec3_chain_replay_init(&nsec3replay, zone);
#endif
    
#if ZDB_HAS_NSEC_SUPPORT
    chain_replay nsecreplay;
    nsec_chain_replay_init(&nsecreplay, zone);
#endif
    
#if ZDB_HAS_NSEC3_SUPPORT
    ptr_set downed_fqdn = PTR_SET_DNSNAME_EMPTY;
#endif

    /* 
     * At this point : the next record, if it exists AND is not an SOA , has to be deleted
     * 
     */
    
    bool did_remove_soa = FALSE;

    // something has to be committed

    for(;;)
    {
        /*
         * read the full record
         * 
         * == 0 : no record (EOF)
         *  < 0 : failed
         */

        if((ret = dns_resource_record_read(&rr, is)) <= 0)
        {
            if(ISOK(ret))
            {
                log_info("journal: %{dnsname}: reached the end of the journal page", zone->origin);
            }
            else
            {
                log_err("journal: %{dnsname}: broken journal: %r", zone->origin, ret);
                logger_flush(); // broken journal (bad, keep me)
            }

            break;
        }
        
        ttlrdata.ttl = ntohl(rr.tctr.ttl);
        ttlrdata.rdata_pointer = rr.rdata;
        ttlrdata.rdata_size = rr.rdata_size;

        /*
         * Stop at the SOA
         */

        if(rr.tctr.qtype == TYPE_SOA)
        {
            mode ^= 1;

            if(mode == 0)
            {
                /* ADD */

#if ZDB_HAS_NSEC3_SUPPORT
                // NSEC3
                {
                    ret = nsec3replay.vtbl->execute(&nsec3replay);

                    if(FAIL(ret))
                    {
                        dns_resource_record_clear(&rr);
                        // DO NOT: input_stream_close(is);

                        nsec3replay.vtbl->finalise(&nsec3replay);
                        
#if ZDB_HAS_NSEC_SUPPORT
                        nsecreplay.vtbl->finalise(&nsecreplay);
#endif // ZDB_HAS_NSEC_SUPPORT
                        return ret;
                    }
                }
#endif
                
#if ZDB_HAS_NSEC_SUPPORT
                // NSEC
                ret = nsecreplay.vtbl->execute(&nsecreplay);
#endif //ZDB_HAS_NSEC_SUPPORT
            }
        }

        if(!did_remove_soa)
        {
            log_info("journal: %{dnsname}: removing obsolete SOA", zone->origin);

            if(FAIL(ret = zdb_record_delete(&zone->apex->resource_record_set, TYPE_SOA)))
            {
                /**
                * complain
                */

                log_err("journal: %{dnsname}: removing current SOA gave an error: %r", zone->origin, ret);

                /* That's VERY bad ... */

                changes = ret;

                break;
            }

            did_remove_soa = TRUE;
        }

        s32 top = dnsname_to_dnslabel_vector(fqdn, labels);

        if(mode == 0)
        {
            /*
             * "TO DEL" record
             */

#if ICMTL_DUMP_JOURNAL_RECORDS
            rdata_desc type_len_rdata = {rr.tctr.qtype, rr.rdata_size, rr.rdata };
            log_debug("journal: del %{dnsname} %{typerdatadesc}", fqdn, &type_len_rdata);
            logger_flush();
#endif
            bool added_in_chain = FALSE;

#if ZDB_HAS_NSEC3_SUPPORT
            
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if((added_in_chain = (nsec3replay.vtbl->record_del(&nsec3replay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)))
            {
                // add everything up until a non-empty terminal is found (the apex will thus be automatically avoided)
                // if the record is a delegation, add everything down too
                /*
                if((top > zone->origin_vector.size) &&
                        (rr.tctr.qtype != TYPE_NSEC3) &&
                        (   (rr.tctr.qtype != TYPE_RRSIG) ||
                            ((rr.tctr.qtype == TYPE_RRSIG) && (GET_U16_AT_P(ZDB_RECORD_PTR_RDATAPTR(&ttlrdata)) != TYPE_NSEC3))
                        )
                    )
                {
                    
                }
                */
                ++changes;
            }
            else
            {
                if(top > zone->origin_vector.size)
                {
                    const u8 *above_fqdn = fqdn;
                    for(int i = 1; i < top - zone->origin_vector.size; ++i)
                    {
                        zdb_rr_label *above = zdb_rr_label_find_exact(zone->apex, &labels[i], top - zone->origin_vector.size - 1 - i);
                        if(above != NULL)
                        {
                            if(btree_notempty(above->resource_record_set))
                            {
                                break;
                            }
                        }

                        above_fqdn += above_fqdn[0] + 1;
                        nsec3replay.vtbl->record_del(&nsec3replay, above_fqdn, TYPE_NONE, NULL);
                    }

                    zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, labels, (top - zone->origin_vector.size) - 1);
                    if(rr_label != NULL)
                    {
                        zdb_rr_label_forall_children_of_fqdn(rr_label, fqdn, zdb_icmtl_replay_commit_label_forall_nsec3_del_cb, &nsec3replay);
                    }
                }
            }
#endif
#if ZDB_HAS_NSEC_SUPPORT
            
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if(!added_in_chain && (added_in_chain = nsecreplay.vtbl->record_del(&nsecreplay, fqdn, rr.tctr.qtype, &ttlrdata) != 0))
            {
                ++changes;
            }
            //else
#endif
            if(!added_in_chain)
            switch(rr.tctr.qtype)
            {
                case TYPE_SOA:
                {
                    rdata_desc rdata = {TYPE_SOA, ttlrdata.rdata_size, ttlrdata.rdata_pointer};
                    log_info("journal: %{dnsname}: SOA: del %{dnsname} %{typerdatadesc}", zone->origin, fqdn, &rdata);

                    s32 m1 = (top - zone->origin_vector.size) - 1;

                    if(m1 == -1)
                    {
                        if(FAIL(ret = zdb_record_delete_exact(&zone->apex->resource_record_set, TYPE_SOA, &ttlrdata))) /* FB done, APEX : no delegation, source is the journal */
                        {
                            if(!did_remove_soa)
                            {
                                log_err("journal: %{dnsname}: SOA: %r", zone->origin, ret);
                            }
                        }
                    }
                    else
                    {
                        if(FAIL(ret = zdb_rr_label_delete_record_exact(zone, labels, (top - zone->origin_vector.size) - 1, rr.tctr.qtype, &ttlrdata))) // source is journal
                        {
                            if(!did_remove_soa)
                            {
                                log_err("journal: %{dnsname}: SOA: (2) %r", zone->origin, ret);
                            }
                        }
                    }
                    break;
                }

                default:
                {
#if ZDB_HAS_NSEC3_SUPPORT
                    // NSEC3
                    if(rr.tctr.qtype != TYPE_NSEC3)
                    {
                        if((rr.tctr.qtype != TYPE_RRSIG) && (rrsig_get_type_covered_from_rdata(rr.rdata, rr.rdata_size) != TYPE_NSEC3))
                        {
                            if(ptr_set_avl_find(&downed_fqdn, fqdn) == NULL)
                            {
                                ptr_set_avl_insert(&downed_fqdn, dnsname_dup(fqdn));
                            }
                        }
                    }
                    else
                    {
                        if(!NSEC3_RDATA_IS_OPTOUT(rr.rdata))
                        {
                            zone->_flags &= ~ZDB_ZONE_HAS_OPTOUT_COVERAGE;
                        }
                    }
#endif
                    if(FAIL(ret = zdb_rr_label_delete_record_exact(zone, labels, (top - zone->origin_vector.size) - 1, rr.tctr.qtype, &ttlrdata))) // source is journal
                    {
                        // signatures can be removed automatically by maintenance
                        
                        if((rr.tctr.qtype != TYPE_RRSIG) && (ret != ZDB_ERROR_KEY_NOTFOUND))
                        {
                            log_err("journal: %{dnsname}: del %{dnsrr}", zone->origin, &rr);
                            log_err("journal: %{dnsname}: %{dnstype}: %r", zone->origin, &rr.tctr.qtype, ret);
                        }
                        else
                        {
                            log_debug("journal: %{dnsname}: del %{dnsrr}", zone->origin, &rr);
                            log_debug("journal: %{dnsname}: %{dnstype}: %r", zone->origin, &rr.tctr.qtype, ret);
                        }
                    }
                }
            }
        }
        else
        {
            /*
             * "TO ADD" record
             */
            
            bool added_in_chain = FALSE;
            
#if ZDB_HAS_NSEC3_SUPPORT

            // returns the number of changes taken into account (0 or 1)
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if((added_in_chain = (nsec3replay.vtbl->record_add(&nsec3replay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)))
            {
                ++changes;
            }
            else
            {
                if( (top > zone->origin_vector.size) &&
                    (rr.tctr.qtype != TYPE_NSEC3) &&
                    (   (rr.tctr.qtype != TYPE_RRSIG) ||
                        ((rr.tctr.qtype == TYPE_RRSIG) && (GET_U16_AT_P(ZDB_RECORD_PTR_RDATAPTR(&ttlrdata)) != TYPE_NSEC3))
                        )
                    )
                {
                    const u8 *above_fqdn = fqdn;
                    for(int i = 1; i < top - zone->origin_vector.size; ++i)
                    {
                        zdb_rr_label *above = zdb_rr_label_find_exact(zone->apex, &labels[i], top - zone->origin_vector.size - 1 - i);
                        if(above != NULL)
                        {
                            if(btree_notempty(above->resource_record_set))
                            {
                                break;
                            }
                        }

                        above_fqdn += above_fqdn[0] + 1;
                        nsec3replay.vtbl->record_add(&nsec3replay, above_fqdn, TYPE_NONE, NULL);
                    }

                    zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, labels, (top - zone->origin_vector.size) - 1);
                    if(rr_label != NULL)
                    {
                        zdb_rr_label_forall_children_of_fqdn(rr_label, fqdn, zdb_icmtl_replay_commit_label_forall_nsec3_add_cb, &nsec3replay);
                    }
                }
            }
#endif
#if ZDB_HAS_NSEC_SUPPORT
            
            // returns the number of changes taken into account (0 or 1)
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if(!added_in_chain && (added_in_chain = (nsecreplay.vtbl->record_add(&nsecreplay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)))
            {
                ++changes;
            }
            //else
#endif
            if(!added_in_chain)
            switch(rr.tctr.qtype)
            {
#if ZDB_HAS_NSEC3_SUPPORT
                case TYPE_NSEC3CHAINSTATE:
                {
                    // create chain if missing ...
                    
                    nsec3_zone_add_from_rdata(zone, rr.rdata_size, rr.rdata);
                    
                    // add the record
                    
                    zdb_packed_ttlrdata *packed_ttlrdata;

                    ZDB_RECORD_ZALLOC_EMPTY(packed_ttlrdata, ttlrdata.ttl, rr.rdata_size);
                    packed_ttlrdata->next = NULL;
                    MEMCOPY(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), rr.rdata, rr.rdata_size);
                    zdb_zone_record_add(zone, labels, top, rr.tctr.qtype, packed_ttlrdata); // class is implicit, flow verified
                    
                    break;
                }
#endif // ZDB_HAS_NSEC3_SUPPORT
#
                default:
                {
                    zdb_packed_ttlrdata *packed_ttlrdata;

                    ZDB_RECORD_ZALLOC_EMPTY(packed_ttlrdata, ttlrdata.ttl, rr.rdata_size);
                    packed_ttlrdata->next = NULL;
                    MEMCOPY(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), rr.rdata, rr.rdata_size);

#if ICMTL_DUMP_JOURNAL_RECORDS
                    rdata_desc type_len_rdata = {rr.tctr.qtype, rr.rdata_size, ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata) };
                    log_debug("journal: add %{dnsname} %{typerdatadesc}", fqdn, &type_len_rdata);
                    logger_flush();
#endif
                    if(rr.tctr.qtype == TYPE_SOA)
                    {
                        rr_soa_get_serial(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), ZDB_PACKEDRECORD_PTR_RDATASIZE(packed_ttlrdata), current_serialp);
                        rdata_desc rdata = {TYPE_SOA, ZDB_PACKEDRECORD_PTR_RDATASIZE(packed_ttlrdata), ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata)};
                        log_info("journal: %{dnsname}: SOA: add %{dnsname} %{typerdatadesc}", zone->origin, fqdn, &rdata);
                    }
                    
                    zdb_zone_record_add(zone, labels, top, rr.tctr.qtype, packed_ttlrdata); // class is implicit, flow verified
                }
            }            
        } // end if ADD

        changes++;
    }

    /*
     * Yes, I know.  If 2^32 changes (add batch + del batch) occurs then it will be seen as an error ...
     */

    if(ISOK(changes))
    {
#if ZDB_HAS_NSEC3_SUPPORT && ZDB_HAS_NSEC_SUPPORT
        
        if(has_nsec3 && has_nsec)
        {
            log_warn("journal: %{dnsname}: both NSEC3 and NSEC operations happened, which is not supported by YADIFA. Keeping the original one.", zone->origin);
            
            has_nsec3 = zdb_zone_is_nsec3(zone);
            has_nsec = zdb_zone_is_nsec(zone);
        }        
#endif
        
#if ZDB_HAS_NSEC3_SUPPORT
        nsec3replay.vtbl->execute(&nsec3replay);
#endif

#if ZDB_HAS_NSEC_SUPPORT
        nsecreplay.vtbl->execute(&nsecreplay);
#endif
    }
    
#if ZDB_HAS_NSEC3_SUPPORT
    // has_nsec3 = zdb_zone_is_nsec3(zone);
    nsec3replay.vtbl->finalise(&nsec3replay);
#endif
#if ZDB_HAS_NSEC_SUPPORT
    // has_nsec = zdb_zone_is_nsec(zone);
    nsecreplay.vtbl->finalise(&nsecreplay);
#endif
    
    dns_resource_record_clear(&rr);


    
    return changes;
}
Example #8
0
ya_result
zdb_zone_update_ixfr(zdb* db, input_stream* is)
{
    u8 rname[MAX_DOMAIN_LENGTH];
    u16 rtype;
    u16 rclass;
    u32 rttl;
    u16 rdata_size;
    u8* rdata;

    zdb_packed_ttlrdata* soa_ttlrdata;
    zdb_packed_ttlrdata* tmp_ttlrdata;
    zdb_packed_ttlrdata* ttlrdata;

    dnsname_vector name;
    dnsname_vector entry_name;

    ya_result err;

    /* Get the first SOA */

    if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size)))
    {
        return err;
    }

    if(rtype != TYPE_SOA)
    {
        return ZDB_ERROR_GENERAL;
    }

    DEBUG_RESET_dnsname(name);
    dnsname_to_dnsname_vector(rname, &name);

    ZDB_RECORD_ZALLOC_EMPTY(soa_ttlrdata, rttl, rdata_size);
    if(FAIL(err = input_stream_read_fully(is, ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_ttlrdata), rdata_size)))
    {
        return err;
    }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
    if(err != 0)
    {
        format("zdb_zone_update_ixfr H: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
        print_rdata(rtype, ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_ttlrdata), rdata_size);
        println("");
    }
#endif
#endif

    u32 serial_first;

    if(FAIL(err = rr_soa_get_serial(soa_ttlrdata->rdata_start, soa_ttlrdata->rdata_size, &serial_first)))
    {
        return err;
    }

    zdb_zone_label* zone_label = zdb_zone_label_find(db, &name, rclass);

    if((zone_label == NULL) || (zone_label->zone == NULL))
    {
        /* Not loaded */

        return ZDB_ERROR_GENERAL;
    }

    zdb_zone* zone = zone_label->zone;

    u32 serial_current;

    if(FAIL(err = zdb_zone_getserial(zone, &serial_current)))
    {
        return err;
    }

#if ZDB_NSEC3_SUPPORT != 0
    nsec3_load_context nsec3_context;
    nsec3_load_init(&nsec3_context, zone);
#endif

    MALLOC_OR_DIE(zdb_packed_ttlrdata*, tmp_ttlrdata, sizeof (zdb_ttlrdata) + RDATA_MAX_LENGTH, ZDB_RDATABUF_TAG);

    /* We do not need tmp_ttlrdata and rdata at the same time, let's spare memory */

    rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(tmp_ttlrdata);

    /* Read the next SOA (sub or end) */

    if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size)))
    {
        return err;
    }

    if(rtype != TYPE_SOA)
    {
        return ZDB_ERROR_GENERAL;
    }

    for(;;)
    {
        if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size)))
        {
            break;
        }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
        if(err != 0)
        {
            format("zdb_zone_update_ixfr F: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
            print_rdata(rtype, rdata, rdata_size);
            println("");
        }
#endif
#endif

        /* The SOA serial is supposed to match our current one or the first one
         *
         * If it's the first one, then the task is done
         *
         * If it's the current one, we are moving forward
         *
         * If it's something else, there is an error
         *
         */

        u32 serial_from;

        if(FAIL(err = rr_soa_get_serial(rdata, rdata_size, &serial_from)))
        {
            break;
        }

        /* Check the serial */

        if(serial_from != serial_current)
        {
            if(serial_from == serial_first)
            {
                /* IXFR done */

                err = SUCCESS;

                break;
            }

            /* Serial sequence is not right */

            err = ZDB_ERROR_GENERAL;

            break;
        }

        tmp_ttlrdata->ttl = rttl;
        tmp_ttlrdata->rdata_size = rdata_size;
        zdb_zone_record_delete(zone, NULL, -1, TYPE_SOA, tmp_ttlrdata);

        for(;;)
        {
            /* Load the next record without the data (sub) */

            if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size)))
            {
                break;
            }

            /* If we got an SOA, it's the one that starts the "add" sequence */

            if(rtype == TYPE_SOA)
            {
                break;
            }

            /* Load the data */

            if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size)))
            {
                break;
            }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
            if(err != 0)
            {
                format("zdb_zone_update_ixfr R: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
                print_rdata(rtype, rdata, rdata_size);
                println("");
            }
#endif
#endif
            tmp_ttlrdata->ttl = rttl;
            tmp_ttlrdata->rdata_size = rdata_size;

            /* The vector is not always required, but it's so much easier to
             * read putting it here
             */

            DEBUG_RESET_dnsname(entry_name);
            dnsname_to_dnsname_vector(rname, &entry_name);

#if ZDB_NSEC3_SUPPORT != 0

            if(rtype == TYPE_NSEC3PARAM)
            {
                /* Remove it from the zone */

                zdb_zone_record_delete(zone, name.labels, (entry_name.size - name.size) - 1, rtype, tmp_ttlrdata);

                /* Destroy the whole NSEC3 collection associated to the NSEC3PARAM  */

                nsec3_remove_nsec3param_by_record(zone, tmp_ttlrdata);

                continue;
            }

            if(rtype == TYPE_NSEC3)
            {
                /* Remove the NSEC3 label (and its signature)
                 *
                 * The previous record will have its signature changed, no doubt.
                 * But I cannot edit the previous one about this.
                 * Since we are in an IXFR, the previous NSEC3 is supposed to be
                 * removed too, until one of the previous is also added in the
                 * next section (soa add)
                 *
                 * zdb_zone_record_delete is not the right call, it's
                 *
                 * nsec3_...
                 *
                 */

                nsec3_remove_nsec3(zone, tmp_ttlrdata);

                continue;
            }

            if(rtype == TYPE_RRSIG)
            {
                if((GET_U16_AT(*rdata)) == TYPE_NSEC3) /** @note : NATIVETYPE */
                {
                    /* Remove the RRSIG from the NSEC3 label
                     *
                     * zdb_zone_record_delete is not the right call, it's
                     *
                     * nsec3_...
                     *
                     */

                    nsec3_remove_rrsig(zone, tmp_ttlrdata);

                    continue;
                }
            }

#endif

            /* Remove from the zone */

            zdb_zone_record_delete(zone, name.labels, (entry_name.size - name.size) - 1, rtype, tmp_ttlrdata);

        } /* Remove records */

        /* The current header is the "ADD" SOA */

        if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size)))
        {
            break;
        }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
        if(err != 0)
        {
            format("zdb_zone_update_ixfr T: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
            print_rdata(rtype, rdata, rdata_size);
            println("");
        }
#endif
#endif

        /* The SOA serial is supposed to be bigger than the previous one */

        u32 serial_to;

        if(FAIL(err = rr_soa_get_serial(rdata, rdata_size, &serial_to)))
        {
            break;
        }

        /*
         * After the "add" sequence is done, serial_current will be serial_to
         */

        do
        {
            /* Load the record without the data (add) */

            if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size)))
            {
                break;
            }

#if ZDB_NSEC3_SUPPORT != 0

            if(rtype == TYPE_NSEC3PARAM)
            {
                /* Load the data */

                if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size)))
                {
                    break;
                }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
                if(err != 0)
                {
                    format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
                    print_rdata(rtype, rdata, rdata_size);
                    println("");
                }
#endif
#endif
                /* Add it to the nsec3 context */

                nsec3_load_add_nsec3param(&nsec3_context, rdata, rdata_size);

                /* Add it to the zone */

                DEBUG_RESET_dnsname(entry_name);
                dnsname_to_dnsname_vector(rname, &entry_name);

                ZDB_RECORD_ZALLOC(ttlrdata, rttl, rdata_size, rdata);
                zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata);
            }
            else if(rtype == TYPE_NSEC3)
            {
                /* Load the data */

                if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size)))
                {
                    break;
                }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
                if(err != 0)
                {
                    format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
                    print_rdata(rtype, rdata, rdata_size);
                    println("");
                }
#endif
#endif
                /* Add it to the nsec3 context */

                if(FAIL(err = nsec3_load_add_nsec3(&nsec3_context, rname, rttl, rdata, rdata_size)))
                {
                    break;
                }
            }
            else if(rtype == TYPE_RRSIG)
            {
                /* Load the data */

                if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size)))
                {
                    break;
                }

#if DUMP_ICMTL_UPDATE != 0
                if(err != 0)
                {
                    format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
                    print_rdata(rtype, rdata, rdata_size);
                    println("");
                }
#endif

                if((GET_U16_AT(*rdata)) == TYPE_NSEC3) /** @note : NATIVETYPE */
                {
                    /* Add it to the nsec3 context */

                    if(FAIL(err = nsec3_load_add_rrsig(&nsec3_context, rname, rttl, rdata, rdata_size)))
                    {
                        break;
                    }
                }
                else
                {
                    /* Add it to the zone */

                    DEBUG_RESET_dnsname(entry_name);
                    dnsname_to_dnsname_vector(rname, &entry_name);

                    ZDB_RECORD_ZALLOC(ttlrdata, rttl, rdata_size, rdata);
                    zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata);
                }
            }
            else
            {
#endif
                /* Add it to the zone */

                ZDB_RECORD_ZALLOC_EMPTY(ttlrdata, rttl, rdata_size);

                if(FAIL(err = input_stream_read_fully(is, ZDB_PACKEDRECORD_PTR_RDATAPTR(ttlrdata), rdata_size)))
                {
                    break;
                }

#ifndef NDEBUG
#if DUMP_ICMTL_UPDATE != 0
                if(err != 0)
                {
                    format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype);
                    print_rdata(rtype, ttlrdata->rdata_start, rdata_size);
                    println(termout, "");
                }
#endif
#endif
                DEBUG_RESET_dnsname(entry_name);
                dnsname_to_dnsname_vector(rname, &entry_name);

                zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); /* class is implicit */

#if ZDB_NSEC3_SUPPORT != 0
            }
#endif
        }
        while(rtype != TYPE_SOA);

        /*
         * The record is either the first of another SOA pair (sub, add)
         * Either the final one.
         */

        /* Update the current serial */

        serial_current = serial_to;

        break;
    }

    free(tmp_ttlrdata);

    if(ISOK(err))
    {
        /*
         * soa_ttlrdata is the new SOA
         */

        zdb_zone_record_add(zone, NULL, -1, TYPE_SOA, soa_ttlrdata);

#if ZDB_NSEC3_SUPPORT != 0
        /**
         * Check if there is both NSEC & NSEC3.  Reject if yes.
         *       compile NSEC if any
         *	 compile NSEC3 if any
         *
         * @todo: I'm only doing NSEC3 here. Do NSEC as well
         */
        
        err = nsec3_load_compile(&nsec3_context);
        
        if((nsec3_context.nsec3_rejected > 0)||(nsec3_context.nsec3_discarded > 0))
        {
            err = DNSSEC_ERROR_NSEC3_INVALIDZONESTATE;
        }

        if(ISOK(err))
        {
            nsec3_load_destroy(&nsec3_context);
#endif
            zone_label->zone = zone;

            return err;
#if ZDB_NSEC3_SUPPORT != 0
        }
#endif
    }

#if ZDB_NSEC3_SUPPORT != 0
    nsec3_load_destroy(&nsec3_context);
#endif

    /**
     * @note : do NOT use these to unload a zone.
     *         zdb_zone_label_delete(db, &name, zone->zclass);
     *         zdb_zone_destroy(zone);
     */

    zdb_zone_unload(db, &name, zdb_zone_getclass(zone));

    return err;
}
Example #9
0
static bool
write_label(zdb_resourcerecord* rr, u32* countp, packet_writer* pc)
{
    u32 count = 0;
    bool fully_written = TRUE;

    while(rr != NULL)
    {
        /* Store the name */
        const u8* name = rr->name;

        u16 rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(rr->ttl_rdata);

        u32 offset_backup = pc->packet_offset;

        /* copy the name */

#if ANSWER_DO_COMPRESSION == 0
        packet_writer_add_fqdn_uncompressed(pc, name);
#else
        packet_writer_add_fqdn(pc, name);
#endif
        /* copy the TYPE + CLASS + RDATA SIZE */

        packet_writer_add_u16(pc, (rr->rtype)); /** @note: NATIVETYPE */
        packet_writer_add_u16(pc, (rr->zclass)); /** @note: NATIVECLASS */
        
        packet_writer_add_u32(pc, htonl(rr->ttl));

        /* Here we do compression (or not) */

#if ANSWER_DO_COMPRESSION == 0
        /* Store the RDATA len (16 bits) */

        u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(rr->ttl_rdata);

        packet_writer_add_u16(pc, htons(rdata_size));

        /* copy the RDATA */

        packet_writer_add_bytes(pc, rdata, rdata_size);

#else
        u32 offset = pc->packet_offset;
        u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(rr->ttl_rdata);
        pc->packet_offset += 2;

        switch(rr->rtype)
        {
            case TYPE_MX:

                packet_writer_add_bytes(pc, rdata, 2);
                rdata += 2;

                /* Fallthrough */

            case TYPE_NS:
            case TYPE_CNAME:
            case TYPE_DNAME:
            case TYPE_PTR:
            case TYPE_MB:
            case TYPE_MD:
            case TYPE_MF:
            case TYPE_MG:
            case TYPE_MR:
                /* ONE NAME record */
            {
                packet_writer_add_fqdn(pc, rdata);

                packet_writer_set_u16(pc, htons(pc->packet_offset - offset - 2), offset);

                break;
            }
            case TYPE_SOA:
            {
                u32 len1 = dnsname_len(rdata);
                packet_writer_add_fqdn(pc, rdata);
                rdata += len1;

                u32 len2 = dnsname_len(rdata);
                packet_writer_add_fqdn(pc, rdata);
                rdata += len2;

                packet_writer_add_bytes(pc, rdata, 20);

                packet_writer_set_u16(pc, htons(pc->packet_offset - offset - 2), offset);

                break;
            }
            default:
            {
                packet_writer_set_u16(pc, htons(rdata_size), offset);
                packet_writer_add_bytes(pc, rdata, rdata_size);
                break;
            }
        } /* switch(type) */
#endif

        /*
         * If we are beyond the limit, we restore the offset and stop here.
         */

        if(pc->packet_offset > pc->packet_limit)
        {
            pc->packet_offset = offset_backup;

            fully_written = FALSE;
            break;
        }

        count++;

        rr = rr->next;
    }

    *countp = count; /* stores the count */

    return fully_written; /* returns the offset of the next writable byte */
}