to two RRs. Thanks Emilio Caballero
* Fix #131: Drill sig chasing breaks with gcc-11 and
strict-aliasing. Thanks Stanislav Levin
+ * Fix #130: Unless $TLL is defined, ttl defaults to the last
+ explicitly stated value. Thanks Benno
1.7.1 2019-07-26
* bugfix: Manage verification paths for OpenSSL >= 1.1.0
LDNS_FREE(node);
}
+ldns_status _ldns_rr_new_frm_fp_l_internal(ldns_rr **newrr, FILE *fp,
+ uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev,
+ int *line_nr, bool *explicit_ttl);
+
ldns_status
ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* origin,
- uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
+ uint32_t default_ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
{
ldns_rr* cur_rr;
size_t i;
#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
ldns_zone* zone = NULL;
#else
- uint32_t my_ttl = ttl;
+ ldns_rr *prev_rr = NULL;
+ uint32_t my_ttl = default_ttl;
+ /* RFC 1035 Section 5.1, says 'Omitted class and TTL values are default
+ * to the last explicitly stated values.'
+ */
+ bool ttl_from_TTL = false;
+ bool explicit_ttl = false;
#endif
ldns_rbtree_init(&todo_nsec3_ents, ldns_dname_compare_v);
#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
- status = ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr);
+ status = ldns_zone_new_frm_fp_l(&zone, fp, origin, default_ttl, c, line_nr);
if (status != LDNS_STATUS_OK)
goto error;
#endif
status = LDNS_STATUS_OK;
#else
while (!feof(fp)) {
+ /* If ttl came from $TTL line, then it should be the default.
+ * (RFC 2308 Section 4)
+ * Otherwise it "defaults to the last explicitly stated value"
+ * (RFC 1035 Section 5.1)
+ */
+ if (ttl_from_TTL)
+ my_ttl = default_ttl;
status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
- &my_prev, line_nr);
-
+ &my_prev, line_nr, &explicit_ttl);
#endif
switch (status) {
case LDNS_STATUS_OK:
+#ifndef FASTER_DNSSEC_ZONE_NEW_FRM_FP
+ if (explicit_ttl) {
+ if (!ttl_from_TTL) {
+ /* No $TTL, so ttl "defaults to the
+ * last explicitly stated value"
+ * (RFC 1035 Section 5.1)
+ */
+ my_ttl = ldns_rr_ttl(cur_rr);
+ }
+ /* When ttl is implicit, try to adhere to the rules as
+ * much as posssible. (also for compatibility with bind)
+ * This was changed when fixing an issue with ZONEMD
+ * which hashes the TTL too.
+ */
+ } else if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SIG
+ || ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_RRSIG) {
+ if (ldns_rr_rd_count(cur_rr) >= 4
+ && ldns_rdf_get_type(ldns_rr_rdf(cur_rr, 3)) == LDNS_RDF_TYPE_INT32)
+
+ /* SIG without explicit ttl get ttl
+ * from the original_ttl field
+ * (RFC 2535 Section 7.2)
+ *
+ * Similarly for RRSIG, but stated less
+ * specifically in the spec.
+ * (RFC 4034 Section 3)
+ */
+ ldns_rr_set_ttl(cur_rr,
+ ldns_rdf2native_int32(
+ ldns_rr_rdf(rr, 3)));
+
+ } else if (prev_rr
+ && ldns_rr_get_type(prev_rr) == ldns_rr_get_type(cur_rr)
+ && ldns_dname_compare( ldns_rr_owner(prev_rr)
+ , ldns_rr_owner(cur_rr)) == 0)
+
+ /* "TTLs of all RRs in an RRSet must be the same"
+ * (RFC 2881 Section 5.2)
+ */
+ ldns_rr_set_ttl(cur_rr, ldns_rr_ttl(prev_rr));
+ prev_rr = cur_rr;
+#endif
status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
if (status ==
LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
break;
+ case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/
+#ifndef FASTER_DNSSEC_ZONE_NEW_FRM_FP
+ default_ttl = my_ttl;
+ ttl_from_TTL = true;
+#endif
+ status = LDNS_STATUS_OK;
+ break;
+
case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */
- case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/
case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/
status = LDNS_STATUS_OK;
break;
*/
static ldns_status
ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
- uint32_t default_ttl, const ldns_rdf *origin,
- ldns_rdf **prev, bool question)
+ uint32_t default_ttl, const ldns_rdf *origin,
+ ldns_rdf **prev, bool question,
+ bool *explicit_ttl)
{
ldns_rr *new;
const ldns_rr_descriptor *desc;
} else {
ttl_val = default_ttl;
}
+ if (explicit_ttl)
+ *explicit_ttl = false;
+
/* we not ASSUMING the TTL is missing and that
* the rest of the RR is still there. That is
* CLASS TYPE RDATA
strlcpy(type, ttl, type_sz);
}
} else {
+ if (explicit_ttl)
+ *explicit_ttl = true;
+
if (-1 == ldns_bget_token(
rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN)) {
}
ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata));
- if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) {
+ if (strncmp(owner, "@", 1) == 0) {
if (origin) {
ldns_rr_set_owner(new, ldns_rdf_clone(origin));
} else if (prev && *prev) {
default_ttl,
origin,
prev,
- false);
+ false,
+ NULL);
}
ldns_status
0,
origin,
prev,
- true);
+ true,
+ NULL);
}
/* Strip whitespace from the start and the end of <line>. */
}
ldns_status
-ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev, int *line_nr)
+_ldns_rr_new_frm_fp_l_internal(ldns_rr **newrr, FILE *fp,
+ uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev,
+ int *line_nr, bool *explicit_ttl)
{
char *line = NULL;
size_t limit = 0;
return LDNS_STATUS_SYNTAX_EMPTY;
} else {
if (origin && *origin) {
- s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, *origin, prev);
+ s = ldns_rr_new_frm_str_internal(&rr, (const char*)line,
+ ttl, *origin, prev, false, explicit_ttl);
} else {
- s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, NULL, prev);
+ s = ldns_rr_new_frm_str_internal(&rr, (const char*)line,
+ ttl, NULL, prev, false, explicit_ttl);
}
}
LDNS_FREE(line);
return s;
}
+ldns_status
+ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl,
+ ldns_rdf **origin, ldns_rdf **prev, int *line_nr)
+{
+ return _ldns_rr_new_frm_fp_l_internal(newrr, fp, default_ttl, origin,
+ prev, line_nr, NULL);
+}
+
void
ldns_rr_set_owner(ldns_rr *rr, ldns_rdf *owner)
{
return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
}
+ldns_status _ldns_rr_new_frm_fp_l_internal(ldns_rr **newrr, FILE *fp,
+ uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev,
+ int *line_nr, bool *explicit_ttl);
+
/* XXX: class is never used */
ldns_status
-ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t ttl,
- ldns_rr_class ATTR_UNUSED(c), int *line_nr)
+ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin,
+ uint32_t default_ttl, ldns_rr_class ATTR_UNUSED(c), int *line_nr)
{
ldns_zone *newzone;
- ldns_rr *rr;
+ ldns_rr *rr, *prev_rr = NULL;
uint32_t my_ttl;
ldns_rdf *my_origin;
ldns_rdf *my_prev;
bool soa_seen = false; /* 2 soa are an error */
ldns_status s;
ldns_status ret;
+ /* RFC 1035 Section 5.1, says 'Omitted class and TTL values are default
+ * to the last explicitly stated values.'
+ */
+ bool ttl_from_TTL = false;
+ bool explicit_ttl = false;
/* most cases of error are memory problems */
ret = LDNS_STATUS_MEM_ERR;
my_origin = NULL;
my_prev = NULL;
- my_ttl = ttl;
+ my_ttl = default_ttl;
if (origin) {
my_origin = ldns_rdf_clone(origin);
if (!newzone) goto error;
while(!feof(fp)) {
- s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr);
+ /* If ttl came from $TTL line, then it should be the default.
+ * (RFC 2308 Section 4)
+ * Otherwise it "defaults to the last explicitly stated value"
+ * (RFC 1035 Section 5.1)
+ */
+ if (ttl_from_TTL)
+ my_ttl = default_ttl;
+ s = _ldns_rr_new_frm_fp_l_internal(&rr, fp, &my_ttl, &my_origin,
+ &my_prev, line_nr, &explicit_ttl);
switch (s) {
case LDNS_STATUS_OK:
+ if (explicit_ttl) {
+ if (!ttl_from_TTL) {
+ /* No $TTL, so ttl "defaults to the
+ * last explicitly stated value"
+ * (RFC 1035 Section 5.1)
+ */
+ my_ttl = ldns_rr_ttl(rr);
+ }
+ /* When ttl is implicit, try to adhere to the rules as
+ * much as posssible. (also for compatibility with bind)
+ * This was changed when fixing an issue with ZONEMD
+ * which hashes the TTL too.
+ */
+ } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SIG
+ || ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
+ if (ldns_rr_rd_count(rr) >= 4
+ && ldns_rdf_get_type(ldns_rr_rdf(rr, 3)) == LDNS_RDF_TYPE_INT32)
+
+ /* SIG without explicit ttl get ttl
+ * from the original_ttl field
+ * (RFC 2535 Section 7.2)
+ *
+ * Similarly for RRSIG, but stated less
+ * specifically in the spec.
+ * (RFC 4034 Section 3)
+ */
+ ldns_rr_set_ttl(rr,
+ ldns_rdf2native_int32(
+ ldns_rr_rdf(rr, 3)));
+
+ } else if (prev_rr
+ && ldns_rr_get_type(prev_rr) == ldns_rr_get_type(rr)
+ && ldns_dname_compare( ldns_rr_owner(prev_rr)
+ , ldns_rr_owner(rr)) == 0)
+
+ /* "TTLs of all RRs in an RRSet must be the same"
+ * (RFC 2881 Section 5.2)
+ */
+ ldns_rr_set_ttl(rr, ldns_rr_ttl(prev_rr));
+
+ prev_rr = rr;
if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
if (soa_seen) {
/* second SOA
/* empty line was seen */
case LDNS_STATUS_SYNTAX_TTL:
/* the function set the ttl */
+ default_ttl = my_ttl;
+ ttl_from_TTL = true;
break;
case LDNS_STATUS_SYNTAX_ORIGIN:
/* the function set the origin */