Example #1
0
uint32_t
zonefile_get_serial(struct zonefile *z)
{
	ldns_rdf *rdf = ldns_rr_rdf(z->rr_soa, 2);
	assert(rdf != NULL);
	return (ldns_rdf2native_int32(rdf));
}
Example #2
0
struct zversion_t* zversion_read(struct zone_entry_t* entry, uint32_t serial)
{
	const char* fn = zinfo_ixfr_name(entry, serial);
	struct zversion_t* v;
	FILE* in = fopen(fn, "ra");
	ldns_status status;
	ldns_rr* rr = 0;
	uint32_t dttl = 3600;
	ldns_rdf* origin = 0, *prev = 0;
	int line_nr = 1;
	if(!in) {
		perror(fn);
		return NULL;
	}
	v = (struct zversion_t*)calloc(1, sizeof(*v));
	if(!v) {
		fclose(in);
		printf("out of memory\n");
		return NULL;
	}
	v->serial = serial;
	v->ixfr = ldns_rr_list_new();
	while(!feof(in)) {
		status = ldns_rr_new_frm_fp_l(&rr, in, &dttl, &origin, 
			&prev, &line_nr);
		if(status == LDNS_STATUS_SYNTAX_TTL || 
			status == LDNS_STATUS_SYNTAX_ORIGIN ||
			status == LDNS_STATUS_SYNTAX_EMPTY)
			continue;
		if(status != LDNS_STATUS_OK) {
			printf("error %s:%d: %s\n", fn, line_nr, 
				ldns_get_errorstr_by_id(status));
			fclose(in);
			ldns_rdf_deep_free(origin);
			ldns_rdf_deep_free(prev);
			ldns_rr_list_deep_free(v->ixfr);
			free(v);
			return NULL;
		}
		ldns_rr_list_push_rr(v->ixfr, rr);
	}
	ldns_rdf_deep_free(origin);
	ldns_rdf_deep_free(prev);
	fclose(in);
	if(ldns_rr_list_rr_count(v->ixfr) < 1 || 
		ldns_rr_get_type(ldns_rr_list_rr(v->ixfr, 0)) 
			!= LDNS_RR_TYPE_SOA) {
		printf("invalid IXFR format in %s\n", fn);
		ldns_rr_list_deep_free(v->ixfr);
		free(v);
		return NULL;
	}
	v->next_serial = ldns_rdf2native_int32(ldns_rr_rdf(
		ldns_rr_list_rr(v->ixfr, 0), 2));
	return v;
}
Example #3
0
/** get authority section SOA serial value */
static uint32_t get_serial(ldns_pkt* p)
{
	ldns_rr *rr = ldns_rr_list_rr(ldns_pkt_authority(p), 0);
	ldns_rdf *rdf;
	uint32_t val;
	if(!rr) return 0;
	rdf = ldns_rr_rdf(rr, 2);
	if(!rdf) return 0;
	val = ldns_rdf2native_int32(rdf);
	verbose(3, "found serial %u in msg. ", (int)val);
	return val;
}
Example #4
0
void
ldns_rr_soa_increment_func_data(ldns_rr *soa, 
		ldns_soa_serial_increment_func_t f, void *data)
{
	ldns_rdf *prev_soa_serial_rdf;
	if ( !soa || !f || ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA 
			|| !ldns_rr_rdf(soa, 2)) {
		return;
	}
	prev_soa_serial_rdf = ldns_rr_set_rdf(
		  soa
		, ldns_native2rdf_int32(
			  LDNS_RDF_TYPE_INT32
			, (*f)( ldns_rdf2native_int32(
					ldns_rr_rdf(soa, 2))
			      , data
			)
		)
		, 2
	);
	LDNS_FREE(prev_soa_serial_rdf);
}
Example #5
0
ldns_status
ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone,
						 ldns_rr_list *new_rrs,
						 uint8_t algorithm,
						 uint8_t flags,
						 uint16_t iterations,
						 uint8_t salt_length,
						 uint8_t *salt)
{
	ldns_rbnode_t *first_name_node;
	ldns_rbnode_t *current_name_node;
	ldns_dnssec_name *current_name;
	ldns_status result = LDNS_STATUS_OK;
	ldns_rr *nsec_rr;
	ldns_rr_list *nsec3_list;
	uint32_t nsec_ttl;
	ldns_dnssec_rrsets *soa;
	
	if (!zone || !new_rrs || !zone->names) {
		return LDNS_STATUS_ERR;
	}
	
	/* the TTL of NSEC rrs should be set to the minimum TTL of
	 * the zone SOA (RFC4035 Section 2.3)
	 */
	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
	
	/* did the caller actually set it? if not,
	 * fall back to default ttl
	 */
	if (soa && soa->rrs && soa->rrs->rr) {
		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(
		                                     soa->rrs->rr, 6));
	} else {
		nsec_ttl = LDNS_DEFAULT_TTL;
	}

	nsec3_list = ldns_rr_list_new();

	first_name_node = ldns_dnssec_name_node_next_nonglue(
					  ldns_rbtree_first(zone->names));
	
	current_name_node = first_name_node;

	while (current_name_node &&
	       current_name_node != LDNS_RBTREE_NULL) {
		current_name = (ldns_dnssec_name *) current_name_node->data;
		nsec_rr = ldns_dnssec_create_nsec3(current_name,
		                                   NULL,
		                                   zone->soa->name,
		                                   algorithm,
		                                   flags,
		                                   iterations,
		                                   salt_length,
		                                   salt);
		/* by default, our nsec based generator adds rrsigs
		 * remove the bitmap for empty nonterminals */
		if (!current_name->rrsets) {
			ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr));
		}
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		ldns_dnssec_name_add_rr(current_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
		ldns_rr_list_push_rr(nsec3_list, nsec_rr);
		current_name_node = ldns_dnssec_name_node_next_nonglue(
		                   ldns_rbtree_next(current_name_node));
	}

	ldns_rr_list_sort_nsec3(nsec3_list);
	ldns_dnssec_chain_nsec3_list(nsec3_list);
	if (result != LDNS_STATUS_OK) {
		return result;
	}
	
	ldns_rr_list_free(nsec3_list);
	return result;
}
Example #6
0
ldns_status
ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone,
                              ldns_rr_list *new_rrs)
{

	ldns_rbnode_t *first_node, *cur_node, *next_node;
	ldns_dnssec_name *cur_name, *next_name;
	ldns_rr *nsec_rr;
	uint32_t nsec_ttl;
	ldns_dnssec_rrsets *soa;
	
	/* the TTL of NSEC rrs should be set to the minimum TTL of
	 * the zone SOA (RFC4035 Section 2.3)
	 */
	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
	
	/* did the caller actually set it? if not,
	 * fall back to default ttl
	 */
	if (soa && soa->rrs && soa->rrs->rr) {
		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(
		                                     soa->rrs->rr, 6));
	} else {
		nsec_ttl = LDNS_DEFAULT_TTL;
	}
	
	first_node = ldns_dnssec_name_node_next_nonglue(
			       ldns_rbtree_first(zone->names));
	cur_node = first_node;
	if (cur_node) {
		next_node = ldns_dnssec_name_node_next_nonglue(
			           ldns_rbtree_next(cur_node));
	} else {
		next_node = NULL;
	}

	while (cur_node && next_node) {
		cur_name = (ldns_dnssec_name *)cur_node->data;
		next_name = (ldns_dnssec_name *)next_node->data;
		nsec_rr = ldns_dnssec_create_nsec(cur_name,
		                                  next_name,
		                                  LDNS_RR_TYPE_NSEC);
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		ldns_dnssec_name_add_rr(cur_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
		cur_node = next_node;
		if (cur_node) {
			next_node = ldns_dnssec_name_node_next_nonglue(
                               ldns_rbtree_next(cur_node));
		}
	}

	if (cur_node && !next_node) {
		cur_name = (ldns_dnssec_name *)cur_node->data;
		next_name = (ldns_dnssec_name *)first_node->data;
		nsec_rr = ldns_dnssec_create_nsec(cur_name,
		                                  next_name,
		                                  LDNS_RR_TYPE_NSEC);
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		ldns_dnssec_name_add_rr(cur_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
	} else {
		printf("error\n");
	}

	return LDNS_STATUS_OK;
}
/**
 * Read ixfr journal from file.
 *
 *
 */
ods_status
backup_read_ixfr(FILE* in, void* zone)
{
    zone_type* z = (zone_type*) zone;
    ods_status result = ODS_STATUS_OK;
    ldns_rr* rr = NULL;
    ldns_rdf* prev = NULL;
    ldns_rdf* orig = NULL;
    ldns_rdf* dname = NULL;
    ldns_status status = LDNS_STATUS_OK;
    char line[SE_ADFILE_MAXLINE];
    uint32_t serial = 0;
    unsigned l = 0;
    unsigned first_soa = 1; /* expect soa first */
    unsigned del_mode = 0;

    ods_log_assert(in);
    ods_log_assert(z);

    /* $ORIGIN <zone name> */
    dname = adapi_get_origin(z);
    if (!dname) {
        ods_log_error("[%s] error getting default value for $ORIGIN",
                      backup_str);
        return ODS_STATUS_ERR;
    }
    orig = ldns_rdf_clone(dname);
    if (!orig) {
        ods_log_error("[%s] error setting default value for $ORIGIN",
                      backup_str);
        return ODS_STATUS_ERR;
    }
    /* read RRs */
    while ((rr = backup_read_rr(in, z, line, &orig, &prev, &status, &l))
            != NULL) {
        /* check status */
        if (status != LDNS_STATUS_OK) {
            ods_log_error("[%s] error reading RR #%i (%s): %s",
                          backup_str, l, ldns_get_errorstr_by_id(status), line);
            result = ODS_STATUS_ERR;
            goto backup_ixfr_done;
        }
        if (first_soa == 2) {
            ods_log_error("[%s] bad ixfr journal: trailing RRs after final "
                          "SOA", backup_str);
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_ERR;
            goto backup_ixfr_done;
        }
        if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
            serial = ldns_rdf2native_int32(
                         ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
            if (first_soa) {
                ods_log_debug("[%s] ixfr first SOA: %s", backup_str,
                              ldns_rr2str(rr));
                /* first SOA */
                ldns_rr_free(rr);
                rr = NULL;
                if (z->db->outserial != serial) {
                    ods_log_error("[%s] bad ixfr journal: first SOA wrong "
                                  "serial (was %u, expected %u)", backup_str,
                                  serial, z->db->outserial);
                    result = ODS_STATUS_ERR;
                    goto backup_ixfr_done;
                }
                first_soa = 0;
                continue;
            }
            ods_log_assert(!first_soa);
            if (!del_mode) {
                if (z->db->outserial == serial) {
                    /* final SOA */
                    ods_log_debug("[%s] ixfr final SOA: %s", backup_str,
                                  ldns_rr2str(rr));
                    ldns_rr_free(rr);
                    rr = NULL;
                    result = ODS_STATUS_OK;
                    first_soa = 2;
                    continue;
                } else {
                    ods_log_debug("[%s] new part SOA: %s", backup_str,
                                  ldns_rr2str(rr));
                    lock_basic_lock(&z->ixfr->ixfr_lock);
                    ixfr_purge(z->ixfr);
                    lock_basic_unlock(&z->ixfr->ixfr_lock);
                }
            } else {
                ods_log_debug("[%s] second part SOA: %s", backup_str,
                              ldns_rr2str(rr));
            }
            del_mode = !del_mode;
        }
        /* ixfr add or del rr */
        if (first_soa) {
            ods_log_error("[%s] bad ixfr journal: first RR not SOA",
                          backup_str);
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_ERR;
            goto backup_ixfr_done;
        }
        ods_log_assert(!first_soa);
        lock_basic_lock(&z->ixfr->ixfr_lock);
        if (del_mode) {
            ods_log_debug("[%s] -IXFR: %s", backup_str, ldns_rr2str(rr));
            ixfr_del_rr(z->ixfr, rr);
        } else {
            ods_log_debug("[%s] +IXFR: %s", backup_str, ldns_rr2str(rr));
            ixfr_add_rr(z->ixfr, rr);
        }
        lock_basic_unlock(&z->ixfr->ixfr_lock);
    }
    if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) {
        ods_log_error("[%s] error reading RR #%i (%s): %s",
                      backup_str, l, ldns_get_errorstr_by_id(status), line);
        result = ODS_STATUS_ERR;
    }

backup_ixfr_done:
    if (orig) {
        ldns_rdf_deep_free(orig);
        orig = NULL;
    }
    if (prev) {
        ldns_rdf_deep_free(prev);
        prev = NULL;
    }
    return result;
}
Example #8
0
/**
 * Read zone file.
 *
 */
static ods_status
adfile_read_file(FILE* fd, zone_type* zone)
{
    ods_status result = ODS_STATUS_OK;
    ldns_rr* rr = NULL;
    ldns_rdf* prev = NULL;
    ldns_rdf* orig = NULL;
    ldns_rdf* dname = NULL;
    uint32_t ttl = 0;
    uint32_t new_serial = 0;
    ldns_status status = LDNS_STATUS_OK;
    char line[SE_ADFILE_MAXLINE];
    unsigned int line_update_interval = 100000;
    unsigned int line_update = line_update_interval;
    unsigned int l = 0;

    ods_log_assert(fd);
    ods_log_assert(zone);

    /* $ORIGIN <zone name> */
    dname = adapi_get_origin(zone);
    if (!dname) {
        ods_log_error("[%s] error getting default value for $ORIGIN",
            adapter_str);
        return ODS_STATUS_ERR;
    }
    orig = ldns_rdf_clone(dname);
    if (!orig) {
        ods_log_error("[%s] error setting default value for $ORIGIN",
            adapter_str);
        return ODS_STATUS_ERR;
    }
    /* $TTL <default ttl> */
    ttl = adapi_get_ttl(zone);
    /* read RRs */
    while ((rr = adfile_read_rr(fd, zone, line, &orig, &prev, &ttl,
        &status, &l)) != NULL) {
        /* check status */
        if (status != LDNS_STATUS_OK) {
            ods_log_error("[%s] error reading RR at line %i (%s): %s",
                adapter_str, l, ldns_get_errorstr_by_id(status), line);
            result = ODS_STATUS_ERR;
            break;
        }
        /* debug update */
        if (l > line_update) {
            ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line);
            line_update += line_update_interval;
        }
        /* SOA? */
        if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
            new_serial =
              ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
        }
        /* add to the database */
        result = adapi_add_rr(zone, rr, 0);
        if (result == ODS_STATUS_UNCHANGED) {
            ods_log_debug("[%s] skipping RR at line %i (duplicate): %s",
                adapter_str, l, line);
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_OK;
            continue;
        } else if (result != ODS_STATUS_OK) {
            ods_log_error("[%s] error adding RR at line %i: %s",
                adapter_str, l, line);
            ldns_rr_free(rr);
            rr = NULL;
            break;
        }
    }
    /* and done */
    if (orig) {
        ldns_rdf_deep_free(orig);
        orig = NULL;
    }
    if (prev) {
        ldns_rdf_deep_free(prev);
        prev = NULL;
    }
    if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) {
        ods_log_error("[%s] error reading RR at line %i (%s): %s",
            adapter_str, l, ldns_get_errorstr_by_id(status), line);
        result = ODS_STATUS_ERR;
    }
    /* input zone ok, set inbound serial and apply differences */
    if (result == ODS_STATUS_OK) {
        result = namedb_examine(zone->db);
        if (result != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to read file: zonefile contains errors",
                adapter_str);
            return result;
        }
        adapi_set_serial(zone, new_serial);
    }
    return result;
}
Example #9
0
/**
 * Process SOA.
 *
 */
static ods_status
adapi_process_soa(zone_type* zone, ldns_rr* rr, int add, int backup)
{
    uint32_t tmp = 0;
    ldns_rdf* soa_rdata = NULL;
    ods_status status = ODS_STATUS_OK;

    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->signconf);

    if (backup) {
        /* no need to do processing */
        return ODS_STATUS_OK;
    }
    if (zone->signconf->soa_ttl) {
        tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
        ods_log_verbose("[%s] zone %s set soa ttl to %u",
            adapi_str, zone->name, tmp);
        ldns_rr_set_ttl(rr, tmp);
    }
    if (zone->signconf->soa_min) {
        tmp = (uint32_t) duration2time(zone->signconf->soa_min);
        ods_log_verbose("[%s] zone %s set soa minimum to %u",
            adapi_str, zone->name, tmp);
        soa_rdata = ldns_rr_set_rdf(rr,
            ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
            SE_SOA_RDATA_MINIMUM);
        if (soa_rdata) {
            ldns_rdf_deep_free(soa_rdata);
            soa_rdata = NULL;
        } else {
            ods_log_error("[%s] unable to %s soa to zone %s: failed to replace "
                "soa minimum rdata", adapi_str, add?"add":"delete",
                zone->name);
            return ODS_STATUS_ASSERT_ERR;
        }
    }
    if (!add) {
        /* we are done */
        return ODS_STATUS_OK;
    }
    tmp = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
    status = namedb_update_serial(zone->db, zone->name,
        zone->signconf->soa_serial, tmp);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
            "soa serial rdata (%s)", adapi_str, zone->name,
            ods_status2str(status));
        if (status == ODS_STATUS_CONFLICT_ERR) {
            ods_log_error("[%s] If this is the result of a key rollover, "
                "please increment the serial in the unsigned zone %s",
                adapi_str, zone->name);
        }
        return status;
    }
    ods_log_verbose("[%s] zone %s set soa serial to %u", adapi_str,
        zone->name, zone->db->intserial);
    soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
        zone->db->intserial), SE_SOA_RDATA_SERIAL);
    if (soa_rdata) {
        ldns_rdf_deep_free(soa_rdata);
        soa_rdata = NULL;
    } else {
        ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
            "soa serial rdata", adapi_str, zone->name);
        return ODS_STATUS_ERR;
    }
    zone->db->serial_updated = 1;
    return ODS_STATUS_OK;
}
Example #10
0
static ldns_status
ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone,
		ldns_rr_list *new_rrs,
		uint8_t algorithm,
		uint8_t flags,
		uint16_t iterations,
		uint8_t salt_length,
		uint8_t *salt,
		ldns_rbtree_t **map)
{
	ldns_rbnode_t *first_name_node;
	ldns_rbnode_t *current_name_node;
	ldns_dnssec_name *current_name;
	ldns_status result = LDNS_STATUS_OK;
	ldns_rr *nsec_rr;
	ldns_rr_list *nsec3_list;
	uint32_t nsec_ttl;
	ldns_dnssec_rrsets *soa;
	ldns_rbnode_t *hashmap_node;

	if (!zone || !new_rrs || !zone->names) {
		return LDNS_STATUS_ERR;
	}

	/* the TTL of NSEC rrs should be set to the minimum TTL of
	 * the zone SOA (RFC4035 Section 2.3)
	 */
	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);

	/* did the caller actually set it? if not,
	 * fall back to default ttl
	 */
	if (soa && soa->rrs && soa->rrs->rr
			&& ldns_rr_rdf(soa->rrs->rr, 6) != NULL) {
		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6));
	} else {
		nsec_ttl = LDNS_DEFAULT_TTL;
	}

	if (zone->hashed_names) {
		ldns_traverse_postorder(zone->hashed_names,
				ldns_hashed_names_node_free, NULL);
		LDNS_FREE(zone->hashed_names);
	}
	zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
	if (zone->hashed_names && map) {
		*map = zone->hashed_names;
	}

	first_name_node = ldns_dnssec_name_node_next_nonglue(
					  ldns_rbtree_first(zone->names));

	current_name_node = first_name_node;

	while (current_name_node && current_name_node != LDNS_RBTREE_NULL &&
			result == LDNS_STATUS_OK) {

		current_name = (ldns_dnssec_name *) current_name_node->data;
		nsec_rr = ldns_dnssec_create_nsec3(current_name,
		                                   NULL,
		                                   zone->soa->name,
		                                   algorithm,
		                                   flags,
		                                   iterations,
		                                   salt_length,
		                                   salt);
		/* by default, our nsec based generator adds rrsigs
		 * remove the bitmap for empty nonterminals */
		if (!current_name->rrsets) {
			ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr));
		}
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		result = ldns_dnssec_name_add_rr(current_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
		if (ldns_rr_owner(nsec_rr)) {
			hashmap_node = LDNS_MALLOC(ldns_rbnode_t);
			if (hashmap_node == NULL) {
				return LDNS_STATUS_MEM_ERR;
			}
			current_name->hashed_name = 
				ldns_dname_label(ldns_rr_owner(nsec_rr), 0);

			if (current_name->hashed_name == NULL) {
				LDNS_FREE(hashmap_node);
				return LDNS_STATUS_MEM_ERR;
			}
			hashmap_node->key  = current_name->hashed_name;
			hashmap_node->data = current_name;

			if (! ldns_rbtree_insert(zone->hashed_names
						, hashmap_node)) {
				LDNS_FREE(hashmap_node);
			}
		}
		current_name_node = ldns_dnssec_name_node_next_nonglue(
		                   ldns_rbtree_next(current_name_node));
	}
	if (result != LDNS_STATUS_OK) {
		return result;
	}

	/* Make sorted list of nsec3s (via zone->hashed_names)
	 */
	nsec3_list = ldns_rr_list_new();
	if (nsec3_list == NULL) {
		return LDNS_STATUS_MEM_ERR;
	}
	for ( hashmap_node  = ldns_rbtree_first(zone->hashed_names)
	    ; hashmap_node != LDNS_RBTREE_NULL
	    ; hashmap_node  = ldns_rbtree_next(hashmap_node)
	    ) {
		current_name = (ldns_dnssec_name *) hashmap_node->data;
		nsec_rr = ((ldns_dnssec_name *) hashmap_node->data)->nsec;
		if (nsec_rr) {
			ldns_rr_list_push_rr(nsec3_list, nsec_rr);
		}
	}
	result = ldns_dnssec_chain_nsec3_list(nsec3_list);
	ldns_rr_list_free(nsec3_list);

	return result;
}
Example #11
0
/**
 * Read IXFR from file.
 *
 */
static ods_status
addns_read_file(FILE* fd, zone_type* zone)
{
    ldns_rr* rr = NULL;
    uint32_t new_serial = 0;
    uint32_t old_serial = 0;
    uint32_t tmp_serial = 0;
    ldns_rdf* prev = NULL;
    ldns_rdf* orig = NULL;
    ldns_rdf* dname = NULL;
    uint32_t ttl = 0;
    size_t rr_count = 0;
    ods_status result = ODS_STATUS_OK;
    ldns_status status = LDNS_STATUS_OK;
    char line[SE_ADFILE_MAXLINE];
    unsigned is_axfr = 0;
    unsigned del_mode = 0;
    unsigned soa_seen = 0;
    unsigned line_update_interval = 100000;
    unsigned line_update = line_update_interval;
    unsigned l = 0;

    ods_log_assert(fd);
    ods_log_assert(zone);

    /* $ORIGIN <zone name> */
    dname = adapi_get_origin(zone);
    if (!dname) {
        ods_log_error("[%s] error getting default value for $ORIGIN",
                      adapter_str);
        return ODS_STATUS_ERR;
    }
    orig = ldns_rdf_clone(dname);
    if (!orig) {
        ods_log_error("[%s] error setting default value for $ORIGIN",
                      adapter_str);
        return ODS_STATUS_ERR;
    }
    /* $TTL <default ttl> */
    ttl = adapi_get_ttl(zone);
    /* read RRs */
    while ((rr = addns_read_rr(fd, line, &orig, &prev, &ttl, &status, &l))
            != NULL) {
        /* check status */
        if (status != LDNS_STATUS_OK) {
            ods_log_error("[%s] error reading RR at line %i (%s): %s",
                          adapter_str, l, ldns_get_errorstr_by_id(status), line);
            result = ODS_STATUS_ERR;
            break;
        }
        /* debug update */
        if (l > line_update) {
            ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line);
            line_update += line_update_interval;
        }
        /* first RR: check if SOA and correct zone & serialno */
        if (rr_count == 0) {
            rr_count++;
            if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) {
                ods_log_error("[%s] bad xfr, first rr is not soa",
                              adapter_str);
                ldns_rr_free(rr);
                rr = NULL;
                result = ODS_STATUS_ERR;
                break;
            }
            soa_seen++;
            if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) {
                ods_log_error("[%s] bad xfr, soa dname not equal to zone "
                              "dname %s", adapter_str, zone->name);
                ldns_rr_free(rr);
                rr = NULL;
                result = ODS_STATUS_ERR;
                break;
            }
            tmp_serial =
                ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
            old_serial = adapi_get_serial(zone);
            if (!util_serial_gt(tmp_serial, old_serial)) {
                ods_log_info("[%s] zone %s is already up to date, have "
                             "serial %u, got serial %u", adapter_str, zone->name,
                             old_serial, tmp_serial);
                new_serial = tmp_serial;
                ldns_rr_free(rr);
                rr = NULL;
                result = ODS_STATUS_UNCHANGED;
                break;
            }
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_OK;
            continue;
        }
        /* second RR: if not soa, this is an AXFR */
        if (rr_count == 1) {
            if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) {
                ods_log_verbose("[%s] detected axfr serial=%u for zone %s",
                                adapter_str, tmp_serial, zone->name);
                new_serial = tmp_serial;
                is_axfr = 1;
                del_mode = 0;
            } else {
                ods_log_verbose("[%s] detected ixfr serial=%u for zone %s",
                                adapter_str, tmp_serial, zone->name);
                new_serial = tmp_serial;
                tmp_serial =
                    ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
                ldns_rr_free(rr);
                rr = NULL;
                rr_count++;
                if (tmp_serial < new_serial) {
                    del_mode = 1;
                    result = ODS_STATUS_OK;
                    continue;
                } else {
                    ods_log_error("[%s] bad xfr for zone %s, bad soa serial",
                                  adapter_str, zone->name);
                    result = ODS_STATUS_ERR;
                    break;
                }
            }
        }
        /* soa means swap */
        rr_count++;
        if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
            if (!is_axfr) {
                tmp_serial =
                    ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
                if (tmp_serial <= new_serial) {
                    if (tmp_serial == new_serial) {
                        soa_seen++;
                    }
                    del_mode = !del_mode;
                    ldns_rr_free(rr);
                    rr = NULL;
                    result = ODS_STATUS_OK;
                    continue;
                } else {
                    ods_log_assert(tmp_serial > new_serial);
                    ods_log_error("[%s] bad xfr for zone %s, bad soa serial",
                                  adapter_str, zone->name);
                    ldns_rr_free(rr);
                    rr = NULL;
                    result = ODS_STATUS_ERR;
                    break;
                }
            } else {
                /* for axfr */
                soa_seen++;
            }
        }
        /* [add to/remove from] the zone */
        if (!is_axfr && del_mode) {
            ods_log_debug("[%s] delete RR #%i at line %i: %s",
                          adapter_str, rr_count, l, line);
            result = adapi_del_rr(zone, rr, 0);
            ldns_rr_free(rr);
            rr = NULL;
        } else {
            ods_log_debug("[%s] add RR #%i at line %i: %s",
                          adapter_str, rr_count, l, line);
            result = adapi_add_rr(zone, rr, 0);
        }
        if (result == ODS_STATUS_UNCHANGED) {
            ods_log_debug("[%s] skipping RR at line %i (%s): %s",
                          adapter_str, l, del_mode?"not found":"duplicate", line);
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_OK;
            continue;
        } else if (result != ODS_STATUS_OK) {
            ods_log_error("[%s] error %s RR at line %i: %s",
                          adapter_str, del_mode?"deleting":"adding", l, line);
            ldns_rr_free(rr);
            rr = NULL;
            break;
        }
    }
    /* and done */
    if (orig) {
        ldns_rdf_deep_free(orig);
        orig = NULL;
    }
    if (prev) {
        ldns_rdf_deep_free(prev);
        prev = NULL;
    }
    if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) {
        ods_log_error("[%s] error reading RR at line %i (%s): %s",
                      adapter_str, l, ldns_get_errorstr_by_id(status), line);
        result = ODS_STATUS_ERR;
    }
    /* check the number of SOAs seen */
    if (result == ODS_STATUS_OK) {
        if ((is_axfr && soa_seen != 2) || (!is_axfr && soa_seen != 3)) {
            ods_log_error("[%s] bad %s, wrong number of SOAs (%u)",
                          adapter_str, is_axfr?"axfr":"ixfr", soa_seen);
            result = ODS_STATUS_ERR;
        }
    }
    /* input zone ok, set inbound serial and apply differences */
    if (result == ODS_STATUS_OK || result == ODS_STATUS_UNCHANGED) {
        adapi_set_serial(zone, new_serial);
        if (is_axfr) {
            adapi_trans_full(zone);
        } else {
            adapi_trans_diff(zone);
        }
        if (result == ODS_STATUS_UNCHANGED) {
            result = ODS_STATUS_OK;
        }
    }
    return result;
}