Example #1
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 #2
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 #3
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;
}