summaryrefslogtreecommitdiff
path: root/services/authzone.c
diff options
context:
space:
mode:
Diffstat (limited to 'services/authzone.c')
-rw-r--r--services/authzone.c150
1 files changed, 107 insertions, 43 deletions
diff --git a/services/authzone.c b/services/authzone.c
index 60ccc8698748..ebcdc7e43643 100644
--- a/services/authzone.c
+++ b/services/authzone.c
@@ -171,7 +171,7 @@ get_rrset_ttl(struct ub_packed_rrset_key* k)
/** Copy rrset into region from domain-datanode and packet rrset */
static struct ub_packed_rrset_key*
auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node,
- struct auth_rrset* rrset, struct regional* region, time_t adjust)
+ struct auth_rrset* rrset, struct regional* region)
{
struct ub_packed_rrset_key key;
memset(&key, 0, sizeof(key));
@@ -182,7 +182,7 @@ auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node,
key.rk.type = htons(rrset->type);
key.rk.rrset_class = htons(z->dclass);
key.entry.hash = rrset_key_hash(&key.rk);
- return packed_rrset_copy_region(&key, region, adjust);
+ return packed_rrset_copy_region(&key, region, 0);
}
/** fix up msg->rep TTL and prefetch ttl */
@@ -236,7 +236,7 @@ msg_add_rrset_an(struct auth_zone* z, struct regional* region,
return 0;
/* copy it */
if(!(msg->rep->rrsets[msg->rep->rrset_count] =
- auth_packed_rrset_copy_region(z, node, rrset, region, 0)))
+ auth_packed_rrset_copy_region(z, node, rrset, region)))
return 0;
msg->rep->rrset_count++;
msg->rep->an_numrrsets++;
@@ -260,7 +260,7 @@ msg_add_rrset_ns(struct auth_zone* z, struct regional* region,
return 0;
/* copy it */
if(!(msg->rep->rrsets[msg->rep->rrset_count] =
- auth_packed_rrset_copy_region(z, node, rrset, region, 0)))
+ auth_packed_rrset_copy_region(z, node, rrset, region)))
return 0;
msg->rep->rrset_count++;
msg->rep->ns_numrrsets++;
@@ -283,7 +283,7 @@ msg_add_rrset_ar(struct auth_zone* z, struct regional* region,
return 0;
/* copy it */
if(!(msg->rep->rrsets[msg->rep->rrset_count] =
- auth_packed_rrset_copy_region(z, node, rrset, region, 0)))
+ auth_packed_rrset_copy_region(z, node, rrset, region)))
return 0;
msg->rep->rrset_count++;
msg->rep->ar_numrrsets++;
@@ -1369,6 +1369,10 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
uncompressed_len = pkt_dname_len(&pktbuf);
if(!uncompressed_len)
return 0; /* parse error in dname */
+ compressed_len = sldns_buffer_position(
+ &pktbuf) - oldpos;
+ if(compressed_len > rdlen)
+ return 0; /* dname exceeds rdata */
if(!sldns_buffer_available(buf,
uncompressed_len))
/* dname too long for buffer */
@@ -1376,14 +1380,15 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
dname_pkt_copy(&pktbuf,
sldns_buffer_current(buf), rd);
sldns_buffer_skip(buf, (ssize_t)uncompressed_len);
- compressed_len = sldns_buffer_position(
- &pktbuf) - oldpos;
rd += compressed_len;
rdlen -= compressed_len;
count--;
len = 0;
break;
case LDNS_RDF_TYPE_STR:
+ /* Check rdlen for resilience, because it is
+ * checked above, that rdlen > 0 */
+ if(rdlen < 1) return 0; /* malformed */
len = rd[0] + 1;
break;
default:
@@ -1391,6 +1396,8 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
break;
}
if(len) {
+ if(len > rdlen)
+ return 0; /* malformed */
if(!sldns_buffer_available(buf, len))
return 0; /* too long for buffer */
sldns_buffer_write(buf, rd, len);
@@ -1998,12 +2005,21 @@ auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)
struct auth_data* apex;
struct auth_rrset* soa;
struct packed_rrset_data* d;
+ size_t primlen, mboxlen;
apex = az_find_name(z, z->name, z->namelen);
if(!apex) return 0;
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
if(!soa || soa->data->count==0)
return 0; /* no RRset or no RRs in rrset */
if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */
+ if((primlen = dname_valid(soa->data->rr_data[0]+2,
+ soa->data->rr_len[0]-2)) == 0)
+ return 0; /* primary dname malformed */
+ if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen,
+ soa->data->rr_len[0]-2-primlen)) == 0)
+ return 0; /* mailbox dname malformed */
+ if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0])
+ return 0; /* rdata malformed */
d = soa->data;
*serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20));
return 1;
@@ -2016,12 +2032,21 @@ xfr_find_soa(struct auth_zone* z, struct auth_xfer* xfr)
struct auth_data* apex;
struct auth_rrset* soa;
struct packed_rrset_data* d;
+ size_t primlen, mboxlen;
apex = az_find_name(z, z->name, z->namelen);
if(!apex) return 0;
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
if(!soa || soa->data->count==0)
return 0; /* no RRset or no RRs in rrset */
if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */
+ if((primlen = dname_valid(soa->data->rr_data[0]+2,
+ soa->data->rr_len[0]-2)) == 0)
+ return 0; /* primary dname malformed */
+ if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen,
+ soa->data->rr_len[0]-2-primlen)) == 0)
+ return 0; /* mailbox dname malformed */
+ if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0])
+ return 0; /* rdata malformed */
/* SOA record ends with serial, refresh, retry, expiry, minimum,
* as 4 byte fields */
d = soa->data;
@@ -3990,6 +4015,22 @@ auth_master_copy(struct auth_master* o)
return m;
}
+/** append the master to the copied list. */
+static int
+auth_master_copy_and_append(struct auth_master* p, struct auth_master** list,
+ struct auth_master** last)
+{
+ struct auth_master* m = auth_master_copy(p);
+ if(!m) {
+ return 0;
+ }
+ m->next = NULL;
+ if(*last) (*last)->next = m;
+ if(!*list) *list = m;
+ *last = m;
+ return 1;
+}
+
/** copy the master addresses from the task_probe lookups to the allow_notify
* list of masters */
static void
@@ -3998,17 +4039,27 @@ probe_copy_masters_for_allow_notify(struct auth_xfer* xfr)
struct auth_master* list = NULL, *last = NULL;
struct auth_master* p;
/* build up new list with copies */
+ /* The list in task probe has been looked up before the list in
+ * task transfer. */
+ for(p = xfr->task_probe->masters; p; p=p->next) {
+ if(!auth_master_copy_and_append(p, &list, &last)) {
+ auth_free_masters(list);
+ /* failed because of malloc failure, use old list */
+ return;
+ }
+ }
+ /* The list in task transfer also contains the http entries. */
for(p = xfr->task_transfer->masters; p; p=p->next) {
- struct auth_master* m = auth_master_copy(p);
- if(!m) {
+ /* Copy the http entries from this lookup. The allow_notify
+ * entries are not looked up from this list. The other
+ * ones are already in from the probe lookups. */
+ if(!p->http)
+ continue;
+ if(!auth_master_copy_and_append(p, &list, &last)) {
auth_free_masters(list);
/* failed because of malloc failure, use old list */
return;
}
- m->next = NULL;
- if(last) last->next = m;
- if(!list) list = m;
- last = m;
}
/* success, replace list */
auth_free_masters(xfr->allow_notify_list);
@@ -4556,6 +4607,23 @@ http_parse_ttl(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
return 0;
}
+/** remove newlines from collated line */
+static void
+chunkline_newline_removal(sldns_buffer* buf)
+{
+ size_t i, end=sldns_buffer_limit(buf);
+ for(i=0; i<end; i++) {
+ char c = (char)sldns_buffer_read_u8_at(buf, i);
+ if(c == '\n' && i==end-1) {
+ sldns_buffer_write_u8_at(buf, i, 0);
+ sldns_buffer_set_limit(buf, end-1);
+ return;
+ }
+ if(c == '\n')
+ sldns_buffer_write_u8_at(buf, i, (uint8_t)' ');
+ }
+}
+
/** find noncomment RR line in chunks, collates lines if ( ) format */
static int
chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos,
@@ -4563,6 +4631,7 @@ chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos,
{
int ret;
while(chunkline_get_line_collated(chunk, chunk_pos, buf)) {
+ chunkline_newline_removal(buf);
if(chunkline_is_comment_line_or_empty(buf)) {
/* a comment, go to next line */
continue;
@@ -4638,23 +4707,6 @@ chunklist_sum(struct auth_chunk* list)
return s;
}
-/** remove newlines from collated line */
-static void
-chunkline_newline_removal(sldns_buffer* buf)
-{
- size_t i, end=sldns_buffer_limit(buf);
- for(i=0; i<end; i++) {
- char c = (char)sldns_buffer_read_u8_at(buf, i);
- if(c == '\n' && i==end-1) {
- sldns_buffer_write_u8_at(buf, i, 0);
- sldns_buffer_set_limit(buf, end-1);
- return;
- }
- if(c == '\n')
- sldns_buffer_write_u8_at(buf, i, (uint8_t)' ');
- }
-}
-
/** for http download, parse and add RR to zone */
static int
http_parse_add_rr(struct auth_xfer* xfr, struct auth_zone* z,
@@ -6668,6 +6720,18 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
return 1;
}
+/** return true if there are probe (SOA UDP query) targets in the master list*/
+static int
+have_probe_targets(struct auth_master* list)
+{
+ struct auth_master* p;
+ for(p=list; p; p = p->next) {
+ if(!p->allow_notify && p->host)
+ return 1;
+ }
+ return 0;
+}
+
/** move to sending the probe packets, next if fails. task_probe */
static void
xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
@@ -6707,6 +6771,16 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname);
}
xfr_probe_disown(xfr);
+ if(!have_probe_targets(xfr->task_probe->masters)) {
+ /* If there are no masters to probe, go to transfer. */
+ if(xfr->task_transfer->worker == NULL) {
+ xfr_start_transfer(xfr, env, NULL);
+ return;
+ }
+ /* The transfer is already in progress. */
+ lock_basic_unlock(&xfr->lock);
+ return;
+ }
if(xfr->task_nextprobe->worker == NULL)
xfr_set_timeout(xfr, env, 0, 0);
lock_basic_unlock(&xfr->lock);
@@ -6863,18 +6937,6 @@ auth_xfer_timer(void* arg)
}
}
-/** return true if there are probe (SOA UDP query) targets in the master list*/
-static int
-have_probe_targets(struct auth_master* list)
-{
- struct auth_master* p;
- for(p=list; p; p = p->next) {
- if(!p->allow_notify && p->host)
- return 1;
- }
- return 0;
-}
-
/** start task_probe if possible, if no masters for probe start task_transfer
* returns true if task has been started, and false if the task is already
* in progress. */
@@ -6886,7 +6948,9 @@ xfr_start_probe(struct auth_xfer* xfr, struct module_env* env,
* progress (due to notify)) */
if(xfr->task_probe->worker == NULL) {
if(!have_probe_targets(xfr->task_probe->masters) &&
- !(xfr->task_probe->only_lookup &&
+ xfr->task_probe->masters != NULL)
+ xfr->task_probe->only_lookup = 1;
+ if(!(xfr->task_probe->only_lookup &&
xfr->task_probe->masters != NULL)) {
/* useless to pick up task_probe, no masters to
* probe. Instead attempt to pick up task transfer */