Exemple #1
0
ya_result
tsig_register(const u8 *name, const u8 *mac, u16 mac_size, u8 mac_algorithm)
{
    ya_result return_code = SUCCESS;

    tsig_node *node = tsig_avl_insert(&tsig_tree, name);

    if(node != NULL)
    {
        if(node->item.mac != NULL)
        {
            bool same = (node->item.mac_size == mac_size)                 &&
                        (node->item.mac_algorithm == mac_algorithm)       &&
                        (memcmp((u8*)node->item.mac, mac, mac_size) == 0);
            
            if(node->item.load_serial != tsig_serial)
            {
                node->item.load_serial = tsig_serial; // else every 256 updates will see a duplicate
                        
                if(same)
                {
                    // same key, different instances ... nothing to do
                    
                    return SUCCESS;
                }
                else
                {
                    // this is an old version of the key
                    
                    free((void*)node->item.mac);
                    node->item.mac = NULL;
                }
            }
            else
            {
                // it's a dup in the config file
                
                return TSIG_DUPLICATE_REGISTRATION; /* dup */
            }
        }
        
        yassert(node->item.mac == NULL);
        
        MALLOC_OR_DIE(u8*, node->item.mac, mac_size, TSIGMAC_TAG);
        MEMCOPY((u8*)node->item.mac, mac, mac_size);

        node->item.evp_md = tsig_get_EVP_MD(mac_algorithm);
        node->item.mac_algorithm_name = tsig_get_algorithm_name(mac_algorithm);
        node->item.name_len = dnsname_len(name);
        node->item.mac_algorithm_name_len = dnsname_len(node->item.mac_algorithm_name);
        node->item.mac_size = mac_size;
        node->item.mac_algorithm = mac_algorithm;
        node->item.load_serial = tsig_serial;

        tsig_tree_count++;
    }
    else
    {
ya_result
dynupdate_icmtlhook_enable(u8* origin, output_stream* os_remove, output_stream* os_add)
{
    zassert(icmtl_listener.next == NULL);

#ifndef NDEBUG
    log_debug("incremental: enabled %{dnsname} for updates", origin);
#endif

    icmtl_listener.os_remove.data = os_remove->data;
    icmtl_listener.os_remove.vtbl = os_remove->vtbl;
    icmtl_listener.os_add.data = os_add->data;
    icmtl_listener.os_add.vtbl = os_add->vtbl;
    icmtl_listener.origin = origin;
    icmtl_listener.origin_len = dnsname_len(origin);
    
    zdb_listener_chain((zdb_listener*) & icmtl_listener);

    return SUCCESS;
}
static void
icmtl_on_update_nsec3rrsig_callback(zdb_listener* base_listener, zdb_packed_ttlrdata* removed_rrsig_sll, zdb_packed_ttlrdata* added_rrsig_sll, nsec3_zone_item* item)
{
    u8 label[MAX_DOMAIN_LENGTH];

    icmtl_zdb_listener* listener = (icmtl_zdb_listener*)base_listener;

    u32 origin_len = dnsname_len(listener->origin);

    u32 label_len = nsec3_zone_item_get_label(item, label, sizeof (label));

#ifndef NDEBUG
    log_debug("incremental: del RRSIG: (NSEC3)");
#endif
    
    output_stream_write_rrsig_wire(&listener->os_remove, label, label_len, listener->origin, origin_len, removed_rrsig_sll);
    
#ifndef NDEBUG
    log_debug("incremental: add RRSIG: (NSEC3)");
#endif
    
    output_stream_write_rrsig_wire(&listener->os_add, label, label_len, listener->origin, origin_len, added_rrsig_sll);
}
Exemple #4
0
u8
tsig_get_algorithm(const u8 *name)
{
#if 1
    string_node *node = string_set_avl_find(&hmac_algorithms, (char*)name);

    return (node != NULL) ? node->value : HMAC_UNKNOWN;
#else
    /* Here is an example of an hard-coded one: I should complete it and bench ... */
    u32 len = dnsname_len(name);
    if(len >= 24)
    {
        if(memcmp(name, "hmac-", 5) == 0)
        {
            if(memcmp(&name[5], "md5.sig-alg.reg.int", 20) == 0)
            {
                return HMAC_MD5;
            }
            if(memcmp(&name[5], "sha", 3) == 0)
            {
                if(memcmp(&name[8], "1.sig-alg.reg.int", 18) == 0)
                {
                    return HMAC_SHA1;
                }
                if(memcmp(&name[8], "224.sig-alg.reg.int", 20) == 0)
                {
                    return HMAC_SHA224;
                }
                ...
            }
        }
    }

    return HMAC_UNKNOWN;
#endif
}
Exemple #5
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;
}
Exemple #6
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;
}
Exemple #7
0
static ya_result
journal_ix_get_ixfr_stream_at_serial(journal *jh, u32 serial_from, input_stream *out_input_stream, dns_resource_record *last_soa_rr)
{
    journal_ix *jix = (journal_ix*)jh;
    ya_result return_value = SUCCESS;
    
    journal_ix_readlock(jix);
    
    /*
     * check that serial_from in in the journal range
     * set the file descriptor to the position
     * create a stream that'll stop at the current end of the stream
     */
    
    if(serial_lt(serial_from, jix->first_serial) || serial_ge(serial_from, jix->last_serial) || ((jix->first_serial == 0) && (jix->last_serial == 0)))
    {
        /* out of known range */
        
        journal_ix_readunlock(jix);
        
        if(serial_from == jix->last_serial)
        {
            return SUCCESS;
        }
        else
        {        
            return ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
        }
    }
    
    /*
     * On success, dup() returns a new file descriptor that has the following in common with the original:
     * 
     *  _ Same open file (or pipe)
     *  _ Same file pointer (both file descriptors share one file pointer) <= THIS is a problem
     *  _ Same access mode (read, write, or read/write)
     * 
     * So this is wrong:
     * 
     * cloned_fd = dup(jix->fd);
     */    
    
    int cloned_fd;
    
    while((cloned_fd = open_ex(jix->journal_name, O_RDONLY)) < 0)
    {
        int err = errno;

        if(err == EINTR)
        {
            continue;
        }

        return_value = MAKE_ERRNO_ERROR(err);

#ifdef DEBUG
        log_debug("journal: ix: unable to clone the file descriptor: %r", return_value);
#endif
        journal_ix_readunlock(jix);

        return return_value;
    }
    
    /* 
     * given that I use a clone of the fd and
     * given that only appends are done in the file and
     * given that the limit of the file has already been processed (should be at this point)
     * 
     * THEN
     * 
     * there is no point keeping the lock for reading (on unix systems)
     */
    
    struct stat journal_stat;
    
    s64 last_page_offset = jix->last_page_offset;
    
    if(fstat(cloned_fd, &journal_stat) < 0)
    {
        return_value = ERRNO_ERROR;
        
        log_err("journal: ix: unable to get journal file status", return_value);
        
        close_ex(cloned_fd);

        return return_value;
    }
    
    s64 file_size = journal_stat.st_size;
    
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: the last page starts at position %lld", last_page_offset);
#endif

    journal_ix_readunlock(jix);
    jix = NULL;  
    
    input_stream fis;
    fd_input_stream_attach(&fis, cloned_fd);
    
    if(last_soa_rr != NULL)
    {
        /* seek and store the last SOA print*/
        
        last_soa_rr->tctr.qtype = 0; // clear type
        
        if(lseek(cloned_fd, last_page_offset, SEEK_SET) >= 0)
        {
            /* deleted SOA */
            if((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
            {
                if(last_soa_rr->tctr.qtype == TYPE_SOA)
                {
                    /* DEL records */
                    last_soa_rr->tctr.qtype = 0; // clear type
            
                    /* scan until added SOA found */
                    while((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
                    {
                        if(last_soa_rr->tctr.qtype == TYPE_SOA)
                        {
                            break;
                        }
                    }
                }
            }
            
            // if the SOA has not been found, it's an error (EOF has been reached is covered by this)
            
            
            if(ISOK(return_value))
            {
                if(last_soa_rr->tctr.qtype != TYPE_SOA)
                {
                    return_value = ZDB_JOURNAL_SOA_RECORD_EXPECTED;
                }
            }
        }
        else
        {
            return_value = ERRNO_ERROR;
        }
        
        if(FAIL(return_value))
        {
            input_stream_close(&fis);
            
            return return_value;
        }
    }
    
    /*
     * this format has no indexing so we scan for a page that STARTS with a DELETE of the SOA with serial = serial_from
     */
    
    if(lseek(cloned_fd, 0, SEEK_SET) != 0)  /* the resulting offset MUST be zero */
    {
        return_value = ERRNO_ERROR;
        
        if(ISOK(return_value))
        {
            return_value = ERROR;
        }
        
        input_stream_close(&fis);
            
        return return_value;
    }
    
    input_stream bis;
    dns_resource_record rr;
    dns_resource_record_init(&rr);
    buffer_input_stream_init(&fis, &bis, 512);
    
    s64 offset = 0;

    /* skip until the right serial is found */

    u32 soa_count = 0;

#ifdef DEBUG_JOURNAL
    u32 rr_count = 0;
#endif
    
    for(;;)
    {
        if( (return_value = dns_resource_record_read(&rr, &bis)) <= 0 ) // FAIL or nothing to 
        {
            return_value = ZDB_JOURNAL_ERROR_READING_JOURNAL; /* is the journal file broken ? */
            
            break;
        }

#ifdef DEBUG_JOURNAL
        rr_count++;
#endif
        
        u32 record_size = return_value;
        
        if(rr.tctr.qtype == TYPE_SOA)
        {
            // ((0+1)&1) != 0 => Y N Y N 
            
            if((++soa_count & 1) != 0) // 1 2 3 4
            {
                u8 *p = rr.rdata;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                u32 serial = ntohl(GET_U32_AT(*p));

                if(serial_ge(serial, serial_from))
                {
                    if(serial == serial_from)
                    {
                        /* setup the serial to be from 'offset' up to the current length of the stream */

                        return_value = SUCCESS;
                    }
                    else
                    {
                        /* the serial does not exist in the range */

                        return_value = ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
                    }

                    break;
                }
            }
        }
        
        offset += record_size;
    }
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: serial %08x (%d) is at offset %lld. %d records parsed", serial_from, serial_from, offset, rr_count);
#endif
    
    dns_resource_record_clear(&rr);
    
    /* 
     * detach the file descriptor from the file stream in the buffer stream
     * I do it like this because the streams are not needed anymore but the
     * file descriptor still is (if no error occurred)
     */
    
    fd_input_stream_detach(buffer_input_stream_get_filtered(&bis));
    input_stream_close(&bis);

    if(ISOK(return_value))
    {
        // offset is the start of the page we are looking for
        if(lseek(cloned_fd, offset, SEEK_SET) >= 0)
        {
            fd_input_stream_attach(&fis, cloned_fd);
            limited_input_stream_init(&fis, out_input_stream, file_size - offset);
        }
        else
        {
            return_value = ERRNO_ERROR;
            
            close_ex(cloned_fd);
        }
    }
    else
    {
        close_ex(cloned_fd);
    }
        
    return return_value;
}
Exemple #8
0
static ya_result
rr_check_qname(char **src, u8 *dst, const u8 *origin, u8 *label)
{
    char                                                             *start;
    char                                                            *needle;

    ya_result                                              return_code = OK;
    
    size_t							  start_len;
    size_t							 origin_len;
    bool				              append_origin = FALSE;

    zassert(*src != NULL);

    if(*src == NULL)
    {
        return ZRE_NO_VALUE_FOUND;
    }

    needle = *src;

    if(isspace(*needle))		    /* re-use */
    {
        SKIP_WHSPACE(needle);
        *src = needle;

        if(*label == '\0')		    /* label !empty: only the label will be used */
        {
            if(origin == NULL)
            {
                return NO_ORIGIN_FOUND;
            }

            dnsname_copy(label, origin);    /* label empty: the origin will be added (effectively only the origin will be used) */
        }

        return dnsname_copy(dst, label);    /** @note most of the time dst already have the same content as label */
    }

    /* parse/get (and cut) the first word (the whole string if there is no spaces) */
    start = needle;
    while(!isspace(*needle) && (*needle != '\0'))
    {
        needle++;
    }
    *needle = '\0';

    start_len = needle - start;	/* start_len > 0 because we know the first char was not a space ... */

    /* If it does not ends with '.' we need to append the origin */
    append_origin = (needle[-1] != '.');

    /* cut */
    needle++;
    SKIP_WHSPACE(needle);
    *src = needle;

    if(FAIL(return_code = cstr_to_dnsname_with_check(dst, start)))
    {
        return return_code;
    }

    if(append_origin)
    {
        u8* origin_dst = dst + (return_code - 1);

        if( (origin == NULL) || ((origin_len = dnsname_len(origin)) == 0) )
        {
            return NO_ORIGIN_FOUND;
        }

        if(start_len + origin_len > MAX_DOMAIN_TEXT_LENGTH)
        {
            return ZRE_INCORRECT_DOMAIN_LEN;
        }

        return_code = dnsname_copy(origin_dst, origin);
    }

    dnsname_copy(label, dst);
    
    

    return return_code;
}
Exemple #9
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;
}
Exemple #10
0
ya_result
xfr_input_stream_init(input_stream* filtering_stream, const u8 *origin, input_stream *xfr_source_stream, message_data *message, u32 current_serial, xfr_copy_flags flags)
{
    yassert(filtering_stream != NULL && origin != NULL && xfr_source_stream != NULL && message != NULL);
    
    input_stream *is = xfr_source_stream;
    
    packet_unpack_reader_data reader;
    u8 *buffer;
    u8 *record;
    u8 *ptr;
#if DNSCORE_HAS_TSIG_SUPPORT
    const tsig_item *tsig;
#endif
    ya_result record_len;
    ya_result return_value;
    u32 origin_len;
    u32 last_serial = 0;

    u16 tcplen;
    u16 qtype;
    u16 qclass;

    u16 old_mac_size;
    
    bool last_message_had_tsig;
    bool need_cleanup_tsig = FALSE;

#if DNSCORE_HAS_TSIG_SUPPORT
    u8 old_mac[64];
#endif
    
    /*
     * ensure the stream will be unusable if the initialisation fails
     */
    
    input_stream_set_void(filtering_stream);
    
    /*
     * Start by reading the first packet, and determine if it's an AXFR or an IXFR (for the name)
     * note: it's read and converted to the host endianness
     */
    
    if(!is_fd_input_stream(is))
    {
        // expected file input stream
        return INVALID_ARGUMENT_ERROR;
    }
    
    //buffer_input_stream_init(is, is, 4096);
    
    /* TCP length */

    if(FAIL(return_value = input_stream_read_nu16(is, &tcplen)))
    {
        return return_value;
    }
    
    if(return_value != 2)
    {
        return UNEXPECTED_EOF;
    }
    
    /* if the length is not enough, return the most appropriate error code */

    origin_len = dnsname_len(origin);

    if(tcplen < DNS_HEADER_LENGTH + origin_len + 4)
    {
        return_value = UNEXPECTED_EOF;
        
        if(tcplen >= DNS_HEADER_LENGTH)
        {
            if(ISOK(return_value = input_stream_read_fully(is, message->pool_buffer, DNS_HEADER_LENGTH)))
            {
                return_value = MAKE_DNSMSG_ERROR(MESSAGE_RCODE(message->pool_buffer));
            }
        }

        return return_value;
    }
    
    /* read the whole message */

    buffer = &message->buffer[0];
    record = &message->pool_buffer[0];
    
    assert(sizeof(message->pool_buffer) >= 255 + 10 + 65535);

    if(FAIL(return_value = input_stream_read_fully(is, buffer, tcplen)))
    {
        return return_value;
    }
    
#if DEBUG_XFR_INPUT_STREAM
    log_memdump(g_system_logger, MSG_DEBUG1, &message->buffer[0], tcplen, 32);
#endif
    
    message->received = return_value;
    
    /* check the message makes sense */

    const u64 *h64 = (u64*)buffer;
    u64 m64 = AXFR_MESSAGE_HEADER_MASK;
    u64 r64 = AXFR_MESSAGE_HEADER_RESULT;

    if(((*h64&m64) != r64) || (MESSAGE_NS(message->buffer) != 0))
    {
        u8 code = MESSAGE_RCODE(message->buffer);

        if(code != 0)
        {
            return_value = MAKE_DNSMSG_ERROR(code);
        }
        else
        {
            return_value = UNPROCESSABLE_MESSAGE;
        }

         return return_value;
    }

    //m64 = AXFR_NEXT_MESSAGE_HEADER_MASK;
    //r64 = AXFR_NEXT_MESSAGE_HEADER_RESULT;

    packet_reader_init(&reader, buffer, tcplen);
    reader.offset = DNS_HEADER_LENGTH;

    packet_reader_read_fqdn(&reader, record, RDATA_MAX_LENGTH + 1);

    if(!dnsname_equals(record, origin))
    {
        return INVALID_PROTOCOL;
    }

    if(FAIL(return_value = packet_reader_read_u16(&reader, &qtype)))
    {
        return return_value;
    }
    
    if(return_value != 2)
    {
        return UNEXPECTED_EOF;
    }

    /* 
     * check that we are allowed to process this particular kind of transfer
     * note : this does not determine what is REALLY begin transferred
     */
    
    switch(qtype)
    {
        case TYPE_AXFR:
        {
            if((flags & XFR_ALLOW_AXFR) == 0)
            {
                return INVALID_PROTOCOL;
            }
            break;
        }
        case TYPE_IXFR:
        {
            if((flags & XFR_ALLOW_IXFR) == 0)
            {
                return INVALID_PROTOCOL;
            }
            break;
        }
        default:
        {
            return INVALID_PROTOCOL;
        }
    }

    if(FAIL(return_value = packet_reader_read_u16(&reader, &qclass)))
    {
        return return_value;
    }

    if(qclass != CLASS_IN)
    {
        /** wrong answer */
        return INVALID_PROTOCOL;
    }
    
    /* check for TSIG and verify */

    u16 ancount = ntohs(MESSAGE_AN(buffer));
    
#if DNSCORE_HAS_TSIG_SUPPORT
    if((last_message_had_tsig = ((tsig = message->tsig.tsig) != NULL)))
    {
        /* verify the TSIG
         *
         * AR > 0
         * skip ALL the records until the last AR
         * it MUST be a TSIG
         * It's the first TSIG answering to our query
         * verify it
         *
         */
        
        message->tsig.tsig = NULL;

        old_mac_size = message->tsig.mac_size;
        memcpy(old_mac, message->tsig.mac, old_mac_size);

        if(FAIL(return_value = tsig_message_extract(message)))
        {
            log_debug("xfr_input_stream: error extracting the signature");

            return return_value;
        }

        if(return_value == 0)
        {
            log_debug("xfr_input_stream: no signature when one was requested");

            return TSIG_BADSIG; /* no signature, when one was requested, is a bad signature */
        }

        if(message->tsig.tsig != tsig)
        {
            /* This is not the one we started with */

            log_debug("xfr_input_stream: signature key does not match");

            return TSIG_BADSIG;
        }

        /// check that the tsig in the message matches the one that was sent

        if(FAIL(return_value = tsig_verify_tcp_first_message(message, old_mac, old_mac_size)))
        {
            return return_value;
        }

        reader.packet_size = message->received;
        
        need_cleanup_tsig = TRUE;
    }
#endif
    
    log_debug("xfr_input_stream: expecting %5d answer records", ancount);    

    /*
     * read the SOA (it MUST be an SOA)
     */

    if(FAIL(record_len = packet_reader_read_record(&reader, record, RDATA_MAX_LENGTH + 1)))
    {
        return record_len;
    }

    if(!dnsname_equals(record, origin))
    {
        return INVALID_PROTOCOL;
    }

    ptr = &record[origin_len];

    if(GET_U16_AT(*ptr) != TYPE_SOA)
    {
        return INVALID_PROTOCOL;
    }

    ptr += 8; /* type class ttl */
    
    u16 rdata_size = ntohs(GET_U16_AT(*ptr));
    
    if(rdata_size < 22)
    {
        return INVALID_PROTOCOL;
    }

    rdata_size -= 16;

    ptr += 2; /* rdata size */

    s32 len = dnsname_len(ptr);

    if(len >= rdata_size)
    {
        return INVALID_PROTOCOL;
    }
    rdata_size -= len;
    ptr += len;

    len = dnsname_len(ptr);
    if(len >= rdata_size)
    {
        return INVALID_PROTOCOL;
    }
    rdata_size -= len;

    if(rdata_size != 4)
    {
        return INVALID_PROTOCOL;
    }

    ptr += len;

    // if the serial of the SOA is the same one as we know, then there is no
    // need to download the zone
    
    last_serial = ntohl(GET_U32_AT(*ptr));
    
    if(last_serial == current_serial)
    {
        //args->out_loaded_serial = args->current_serial;
                        
        return ZONE_ALREADY_UP_TO_DATE;
    }

    xfr_input_stream_data *data;    
    ZALLOC_OR_DIE(xfr_input_stream_data*, data, xfr_input_stream_data, XFRISDTA_TAG);
    ZEROMEMORY(data, sizeof(xfr_input_stream_data));
    
    /*
     * We have got the first SOA
     * Next time we find this SOA (second next time for IXFR) the stream, it will be the end of the stream
     */

    /*
     * The stream can be AXFR or IXFR.
     * The only way to know this is to look at the records, maybe on many packets.
     * If there are two SOA (different serial numbers) for the start, then it's an IXFR, else it's an AXFR.
     * 
     * OPEN A PIPE STREAM "XFRs"
     *
     * Save the first SOA
     */

    MALLOC_OR_DIE(u8*, data->first_soa_record, record_len, XFRISSOA_TAG);
    MEMCOPY(data->first_soa_record, record, record_len);
    data->first_soa_record_size = record_len;         

    filtering_stream->vtbl = &xfr_input_stream_vtbl;
    filtering_stream->data = data;
    
    pipe_stream_init(&data->pipe_stream_output, &data->pipe_stream_input, 65536);
    MEMCOPY(&data->reader, &reader, sizeof(packet_unpack_reader_data));
    
    data->origin = origin;
    data->message = message;
    
    data->ancount = ancount - 1;
    data->record_index++;
    data->last_serial = last_serial;
    data->xfr_mode = TYPE_ANY;
    data->ixfr_mark = FALSE;
    data->last_message_had_tsig = last_message_had_tsig;
    data->source_stream = *is;
    data->need_cleanup_tsig = need_cleanup_tsig;
    
    /*
     * Then we read all records for all packets
     * If we find an SOA ...
     *      AXFR: it has to be the last serial and it is the end of the stream.
     *      IXFR: if it's not the last serial it has to go from step to step
     *            AND once we have reached the "last serial" once, the next hit is the end of the stream.
     */

    data->eos = FALSE;
    
    /*
     * In order to know what the type is, read the first packet.
     */
    
    return_value = xfr_input_stream_read_packet(data);
    
    if(FAIL(return_value))
    {
        xfr_input_stream_close(filtering_stream);
    }
    
    return return_value;
}
Exemple #11
0
static ya_result
xfr_input_stream_read_packet(xfr_input_stream_data *data)
{
    message_data *message = data->message;
    packet_unpack_reader_data *reader = &data->reader;
    u8 *record = &message->pool_buffer[0];
    u32 record_len;
    ya_result return_value = SUCCESS;
        
#if DEBUG_XFR_INPUT_STREAM
    log_debug("xfr_input_stream_read_packet(%p) ancount=%hd record_index=%u", data, data->ancount, data->record_index);
#endif
    
    while((data->ancount > 0) && (pipe_stream_write_available(&data->pipe_stream_output) > 2048 ))
    {
        --data->ancount;
        
        if(FAIL(record_len = packet_reader_read_record(reader, record, RDATA_MAX_LENGTH + 1)))
        {
            if(record_len != UNSUPPORTED_TYPE)
            {
                data->eos = TRUE;

                return_value = record_len;

                break;
            }

            log_err("xfr_input_stream: skipped unsupported record #%d %{recordwire}", data->record_index, record);

            data->record_index++;
            continue;
        }

#if DEBUG_XFR_INPUT_STREAM
        log_debug("xfr_input_stream: #%u %{recordwire}", data->record_index, record);
#endif
        
        u8 *ptr = record + dnsname_len(record);

        u16 rtype = GET_U16_AT(*ptr);

        switch(rtype)
        {
            case TYPE_SOA:
            {
                /* handle SOA case */

                if(!dnsname_equals(record, data->origin))
                {
                    data->eos = TRUE;

                    return_value = ERROR; // OWNER OF SOA RECORD SHOULD BE ORIGIN (protocol error)

                    return return_value;
                }

                ptr += 10;                  /* type class ttl rdata_size */
                ptr += dnsname_len(ptr);
                ptr += dnsname_len(ptr);
                u32 soa_serial = ntohl(GET_U32_AT(*ptr));

                if(data->xfr_mode == TYPE_ANY)
                {
                    if(data->record_index == 1)
                    {
                        /*
                         * This is an IXFR, the first record is not sent up
                         */

                        data->xfr_mode = TYPE_IXFR;
                    }
                    else
                    {
                        output_stream_write(&data->pipe_stream_output, data->first_soa_record, data->first_soa_record_size);
                        data->xfr_mode = TYPE_AXFR;
                    }
                }

                if(soa_serial == data->last_serial)
                {
                    // the SOA serial has the same value as the last record we expect
                    // if it's an AXFR or this is the second time it happens on an IXFR, then it's then end of the stream
                    
                    if(data->xfr_mode == TYPE_AXFR || ((data->xfr_mode == TYPE_IXFR) && data->ixfr_mark))
                    {
                        return_value = SUCCESS;

                        /*
                         * The last record of an AXFR must be written,
                         * the last record of an IXFR must not.
                         */

                        if(data->xfr_mode == TYPE_AXFR)
                        {
#if DEBUG_XFR_INPUT_STREAM
                            log_debug("xfr_input_stream: #%u %{recordwire} ; (AXFR END)", data->record_index, record);
#endif
                            
                            return_value = output_stream_write(&data->pipe_stream_output, record, record_len);
                        }
#if DEBUG_XFR_INPUT_STREAM
                        else
                        {
                            log_debug("xfr_input_stream: #%u %{recordwire} ; (IXFR END)", data->record_index, record);
                        }
#endif

                        // done
                        data->eos = TRUE;                       

                        return return_value; // reached the end
                    }

                    // IXFR needs to find the mark twice
                    
#if DEBUG_XFR_INPUT_STREAM
                    log_debug("xfr_input_stream: #%u %{recordwire} ; (IXFR LAST)", data->record_index, record);
#endif

                    data->ixfr_mark = TRUE;
                }
                
                break;
            }

            case TYPE_IXFR:
            case TYPE_AXFR:
            case TYPE_OPT:
            case TYPE_ANY:
                return INVALID_PROTOCOL;
            default:
                if(data->record_index == 1)
                {
                    // special case to detect an AXFR returned by an IXFR query
                    
                    if(data->xfr_mode == TYPE_ANY)
                    {
                        data->xfr_mode = TYPE_AXFR;
                        
                        if(FAIL(return_value = output_stream_write(&data->pipe_stream_output, data->first_soa_record, data->first_soa_record_size)))
                        {
                            return return_value;
                        }
                    }
                    else
                    {
                        return_value = ERROR;
                        return return_value;    // invalid status
                    }
                }
                break;
        }
        
#if DEBUG_XFR_INPUT_STREAM
        log_debug("xfr_input_stream: >%u %{recordwire}", data->record_index, record);
#endif

        if(FAIL(return_value = output_stream_write(&data->pipe_stream_output, record, record_len)))
        {
            data->eos = TRUE;

            break;
        }
        
        if(return_value != record_len)
        {
            return UNEXPECTED_EOF;
        }

        data->record_index++;
    }
    
    return return_value;
}
Exemple #12
0
ya_result
output_stream_write_dnsname(output_stream* os, const u8 *name)
{
    u32 len = dnsname_len(name);
    return output_stream_write(os, name, len);
}
Exemple #13
0
static void
message_viewer_wire_section_record(message_viewer *mv, u8 *record_wire, u8 view_mode_with)
{
    if(!(mv->view_mode_with & view_mode_with))
    {
        return;
    }


    /*
     * there is no padding support for formats on complex types (padding is ignored)
     * doing it would be relatively expensive for it's best doing it manually when needed (afaik: only here)
     */

    counter_output_stream_data                                     counters;
    output_stream                                                       cos;
    output_stream *os_                                             = mv->os;
    counter_output_stream_init(os_, &cos, &counters);

    output_stream                                                *os = &cos; /* final output stream */

    /*    ------------------------------------------------------------    */


    /* 1. get the needed parameters: FQDN, TYPE, CLASS, TTL, RDATA size */
    u8 *rname      = record_wire;
    u8 *rdata      = rname + dnsname_len(rname);
    u16 rtype      = GET_U16_AT(rdata[0]);
    u16 rclass     = GET_U16_AT(rdata[2]);
    u32 rttl       = ntohl(GET_U32_AT(rdata[4]));
    u16 rdata_size = ntohs(GET_U16_AT(rdata[8]));

    /** @todo 20150716 gve -- test that rdata_size matches the record size */

    /* move pointer to RDATA information in the record_wire */
    rdata         += 10;


    /* 2. write the retrieved info into the stream:
     *    FQDN                     TTL     CLASS   TYPE    RDATA
     *
     *    e.g.
     *    somedomain.eu.           86400   IN      NS      ns1.somedomain.eu.
     */

    /* A. write FQDN + alignment for next item */
    u64 next       = counters.write_count + 24;

    osformat(os, "%{dnsname}", rname);
    while(counters.write_count < next)
    {
        output_stream_write_u8(os, (u8)' ');
    }
    output_stream_write_u8(os, (u8)' ');

    /* B. write TTL + alignment for next item */
    osformat(os, "%7d", rttl);
    output_stream_write_u8(os, (u8)' ');


    /* C. write CLASS + alignment for next item */
    next = counters.write_count + 7;

    osformat(os, "%7{dnsclass}", &rclass);
    while(counters.write_count < next)
    {
        output_stream_write_u8(os, (u8) ' ');
    }
    output_stream_write_u8(os, (u8)' ');


    /* D. write TYPE + alignment for next item */
    next = counters.write_count + 7;

    osformat(os, "%7{dnstype} ", &rtype);
    while(counters.write_count < next)
    {
        output_stream_write_u8(os, (u8)' ');
    }
    output_stream_write_u8(os, (u8)' ');


    /* E. write RDATA */
    osprint_rdata(os, rtype, rdata, rdata_size);


    osprintln(os, "");
    flushout();
}
Exemple #14
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 */
}