mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-02-14 08:13:12 -05:00
auth zone work, ixfr apply procedure.
git-svn-id: file:///svn/unbound/trunk@4461 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
b9f4ff6e9f
commit
a1e63e8118
1 changed files with 489 additions and 21 deletions
|
|
@ -635,6 +635,40 @@ domain_remove_rrset(struct auth_data* node, uint16_t rr_type)
|
|||
}
|
||||
}
|
||||
|
||||
/** find an rr index in the rrset. returns true if found */
|
||||
static int
|
||||
az_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
|
||||
size_t* index)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<d->count; i++) {
|
||||
if(d->rr_len[i] != len)
|
||||
continue;
|
||||
if(memcmp(d->rr_data[i], rdata, len) == 0) {
|
||||
*index = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** find an rrsig index in the rrset. returns true if found */
|
||||
static int
|
||||
az_rrset_find_rrsig(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
|
||||
size_t* index)
|
||||
{
|
||||
size_t i;
|
||||
for(i=d->count; i<d->count + d->rrsig_count; i++) {
|
||||
if(d->rr_len[i] != len)
|
||||
continue;
|
||||
if(memcmp(d->rr_data[i], rdata, len) == 0) {
|
||||
*index = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** see if rdata is duplicate */
|
||||
static int
|
||||
rdata_duplicate(struct packed_rrset_data* d, uint8_t* rdata, size_t len)
|
||||
|
|
@ -662,6 +696,68 @@ rrsig_rdata_get_type_covered(uint8_t* rdata, size_t rdatalen)
|
|||
return sldns_read_uint16(rdata+2);
|
||||
}
|
||||
|
||||
/** remove RR from existing RRset. Also sig, if it is a signature.
|
||||
* reallocates the packed rrset for a new one, false on alloc failure */
|
||||
static int
|
||||
rrset_remove_rr(struct auth_rrset* rrset, size_t index)
|
||||
{
|
||||
struct packed_rrset_data* d, *old = rrset->data;
|
||||
size_t i;
|
||||
if(index >= old->count + old->rrsig_count)
|
||||
return 0; /* index out of bounds */
|
||||
d = (struct packed_rrset_data*)calloc(1, packed_rrset_sizeof(old) - (
|
||||
sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t) +
|
||||
old->rr_len[index]));
|
||||
if(!d) {
|
||||
log_err("malloc failure");
|
||||
return 0;
|
||||
}
|
||||
d->ttl = old->ttl;
|
||||
d->count = old->count;
|
||||
d->rrsig_count = old->rrsig_count;
|
||||
if(index < d->count) d->count--;
|
||||
else d->rrsig_count--;
|
||||
d->trust = old->trust;
|
||||
d->security = old->security;
|
||||
|
||||
/* set rr_len, needed for ptr_fixup */
|
||||
d->rr_len = (size_t*)((uint8_t*)d +
|
||||
sizeof(struct packed_rrset_data));
|
||||
if(index > 0)
|
||||
memmove(d->rr_len, old->rr_len, (index)*sizeof(size_t));
|
||||
if(index+1 < old->count+old->rrsig_count)
|
||||
memmove(&d->rr_len[index], &old->rr_len[index+1],
|
||||
(old->count+old->rrsig_count - (index+1))*sizeof(size_t));
|
||||
packed_rrset_ptr_fixup(d);
|
||||
|
||||
/* move over ttls */
|
||||
if(index > 0)
|
||||
memmove(d->rr_ttl, old->rr_ttl, (index)*sizeof(time_t));
|
||||
if(index+1 < old->count+old->rrsig_count)
|
||||
memmove(&d->rr_ttl[index], &old->rr_ttl[index+1],
|
||||
(old->count+old->rrsig_count - (index+1))*sizeof(time_t));
|
||||
|
||||
/* move over rr_data */
|
||||
for(i=0; i<d->count+d->rrsig_count; i++) {
|
||||
int oldi;
|
||||
if(i < index) oldi = i;
|
||||
else oldi = i+1;
|
||||
memmove(d->rr_data[i], old->rr_data[oldi], d->rr_len[i]);
|
||||
}
|
||||
|
||||
/* recalc ttl (lowest of remaining RR ttls) */
|
||||
if(d->count + d->rrsig_count > 0)
|
||||
d->ttl = d->rr_ttl[0];
|
||||
for(i=0; i<d->count+d->rrsig_count; i++) {
|
||||
if(d->rr_ttl[i] < d->ttl)
|
||||
d->ttl = d->rr_ttl[i];
|
||||
}
|
||||
|
||||
free(rrset->data);
|
||||
rrset->data = d;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** add RR to existing RRset. If insert_sig is true, add to rrsigs.
|
||||
* This reallocates the packed rrset for a new one */
|
||||
static int
|
||||
|
|
@ -938,11 +1034,38 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** copy the rrsigs from the rrset to the rrsig rrset, because the rrset
|
||||
* is going to be deleted. reallocates the RRSIG rrset data. */
|
||||
static int
|
||||
rrsigs_copy_from_rrset_to_rrsigset(struct auth_rrset* rrset,
|
||||
struct auth_rrset* rrsigset)
|
||||
{
|
||||
size_t i;
|
||||
if(rrset->data->rrsig_count == 0)
|
||||
return 1;
|
||||
|
||||
/* move them over one by one, because there might be duplicates,
|
||||
* duplicates are ignored */
|
||||
for(i=rrset->data->count;
|
||||
i<rrset->data->count+rrset->data->rrsig_count; i++) {
|
||||
uint8_t* rdata = rrset->data->rr_data[i];
|
||||
size_t rdatalen = rrset->data->rr_len[i];
|
||||
time_t rr_ttl = rrset->data->rr_ttl[i];
|
||||
|
||||
if(rdata_duplicate(rrsigset->data, rdata, rdatalen)) {
|
||||
continue;
|
||||
}
|
||||
if(!rrset_add_rr(rrsigset, rr_ttl, rdata, rdatalen, 0))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Add rr to node, ignores duplicate RRs,
|
||||
* rdata points to buffer with rdatalen octets, starts with 2bytelength. */
|
||||
static int
|
||||
az_domain_add_rr(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl,
|
||||
uint8_t* rdata, size_t rdatalen)
|
||||
uint8_t* rdata, size_t rdatalen, int* duplicate)
|
||||
{
|
||||
struct auth_rrset* rrset;
|
||||
/* packed rrsets have their rrsigs along with them, sort them out */
|
||||
|
|
@ -951,14 +1074,18 @@ az_domain_add_rr(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl,
|
|||
if((rrset=az_domain_rrset(node, ctype))!= NULL) {
|
||||
/* a node of the correct type exists, add the RRSIG
|
||||
* to the rrset of the covered data type */
|
||||
if(rdata_duplicate(rrset->data, rdata, rdatalen))
|
||||
if(rdata_duplicate(rrset->data, rdata, rdatalen)) {
|
||||
if(duplicate) *duplicate = 1;
|
||||
return 1;
|
||||
}
|
||||
if(!rrset_add_rr(rrset, rr_ttl, rdata, rdatalen, 1))
|
||||
return 0;
|
||||
} else if((rrset=az_domain_rrset(node, rr_type))!= NULL) {
|
||||
/* add RRSIG to rrset of type RRSIG */
|
||||
if(rdata_duplicate(rrset->data, rdata, rdatalen))
|
||||
if(rdata_duplicate(rrset->data, rdata, rdatalen)) {
|
||||
if(duplicate) *duplicate = 1;
|
||||
return 1;
|
||||
}
|
||||
if(!rrset_add_rr(rrset, rr_ttl, rdata, rdatalen, 0))
|
||||
return 0;
|
||||
} else {
|
||||
|
|
@ -971,8 +1098,10 @@ az_domain_add_rr(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl,
|
|||
/* normal RR type */
|
||||
if((rrset=az_domain_rrset(node, rr_type))!= NULL) {
|
||||
/* add data to existing node with data type */
|
||||
if(rdata_duplicate(rrset->data, rdata, rdatalen))
|
||||
if(rdata_duplicate(rrset->data, rdata, rdatalen)) {
|
||||
if(duplicate) *duplicate = 1;
|
||||
return 1;
|
||||
}
|
||||
if(!rrset_add_rr(rrset, rr_ttl, rdata, rdatalen, 0))
|
||||
return 0;
|
||||
} else {
|
||||
|
|
@ -999,7 +1128,7 @@ az_domain_add_rr(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl,
|
|||
/** insert RR into zone, ignore duplicates */
|
||||
static int
|
||||
az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
|
||||
size_t dname_len)
|
||||
size_t dname_len, int* duplicate)
|
||||
{
|
||||
struct auth_data* node;
|
||||
uint8_t* dname = rr;
|
||||
|
|
@ -1019,13 +1148,273 @@ az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
|
|||
log_err("cannot create domain");
|
||||
return 0;
|
||||
}
|
||||
if(!az_domain_add_rr(node, rr_type, rr_ttl, rdata, rdatalen)) {
|
||||
if(!az_domain_add_rr(node, rr_type, rr_ttl, rdata, rdatalen,
|
||||
duplicate)) {
|
||||
log_err("cannot add RR to domain");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Remove rr from node, ignores nonexisting RRs,
|
||||
* rdata points to buffer with rdatalen octets, starts with 2bytelength. */
|
||||
static int
|
||||
az_domain_remove_rr(struct auth_data* node, uint16_t rr_type,
|
||||
uint8_t* rdata, size_t rdatalen, int* nonexist)
|
||||
{
|
||||
struct auth_rrset* rrset;
|
||||
size_t index = 0;
|
||||
|
||||
/* find the plain RR of the given type */
|
||||
if((rrset=az_domain_rrset(node, rr_type))!= NULL) {
|
||||
if(az_rrset_find_rr(rrset->data, rdata, rdatalen, &index)) {
|
||||
if(rrset->data->count == 1 &&
|
||||
rrset->data->rrsig_count == 0) {
|
||||
/* last RR, delete the rrset */
|
||||
domain_remove_rrset(node, rr_type);
|
||||
} else if(rrset->data->count == 1 &&
|
||||
rrset->data->rrsig_count != 0) {
|
||||
/* move RRSIGs to the RRSIG rrset, or
|
||||
* this one becomes that RRset */
|
||||
struct auth_rrset* rrsigset = az_domain_rrset(
|
||||
node, LDNS_RR_TYPE_RRSIG);
|
||||
if(rrsigset) {
|
||||
/* move left over rrsigs to the
|
||||
* existing rrset of type RRSIG */
|
||||
rrsigs_copy_from_rrset_to_rrsigset(
|
||||
rrset, rrsigset);
|
||||
/* and then delete the rrset */
|
||||
domain_remove_rrset(node, rr_type);
|
||||
} else {
|
||||
/* no rrset of type RRSIG, this
|
||||
* set is now of that type,
|
||||
* just remove the rr */
|
||||
if(!rrset_remove_rr(rrset, index))
|
||||
return 0;
|
||||
rrset->type = LDNS_RR_TYPE_RRSIG;
|
||||
rrset->data->count = rrset->data->rrsig_count;
|
||||
rrset->data->rrsig_count = 0;
|
||||
}
|
||||
} else {
|
||||
/* remove the RR from the rrset */
|
||||
if(!rrset_remove_rr(rrset, index))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* rr not found in rrset */
|
||||
}
|
||||
|
||||
/* is it a type RRSIG, look under the covered type */
|
||||
if(rr_type == LDNS_RR_TYPE_RRSIG) {
|
||||
uint16_t ctype = rrsig_rdata_get_type_covered(rdata, rdatalen);
|
||||
if((rrset=az_domain_rrset(node, ctype))!= NULL) {
|
||||
if(az_rrset_find_rrsig(rrset->data, rdata, rdatalen,
|
||||
&index)) {
|
||||
/* rrsig should have d->count > 0, be
|
||||
* over some rr of that type */
|
||||
/* remove the rrsig from the rrsigs list of the
|
||||
* rrset */
|
||||
if(!rrset_remove_rr(rrset, index))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* also RRSIG not found */
|
||||
}
|
||||
|
||||
/* nothing found to delete */
|
||||
if(nonexist) *nonexist = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** remove RR from zone, ignore if it does not exist, false on alloc failure*/
|
||||
static int
|
||||
az_remove_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
|
||||
size_t dname_len, int* nonexist)
|
||||
{
|
||||
struct auth_data* node;
|
||||
uint8_t* dname = rr;
|
||||
uint16_t rr_type = sldns_wirerr_get_type(rr, rr_len, dname_len);
|
||||
uint16_t rr_class = sldns_wirerr_get_class(rr, rr_len, dname_len);
|
||||
size_t rdatalen = ((size_t)sldns_wirerr_get_rdatalen(rr, rr_len,
|
||||
dname_len))+2;
|
||||
/* rdata points to rdata prefixed with uint16 rdatalength */
|
||||
uint8_t* rdata = sldns_wirerr_get_rdatawl(rr, rr_len, dname_len);
|
||||
|
||||
if(rr_class != z->dclass) {
|
||||
log_err("wrong class for RR");
|
||||
/* really also a nonexisting entry, because no records
|
||||
* of that class in the zone, but return an error because
|
||||
* getting records of the wrong class is a failure of the
|
||||
* zone transfer */
|
||||
return 0;
|
||||
}
|
||||
node = az_find_name(z, dname, dname_len);
|
||||
if(!node) {
|
||||
/* node with that name does not exist */
|
||||
/* nonexisting entry, because no such name */
|
||||
*nonexist = 1;
|
||||
return 1;
|
||||
}
|
||||
if(!az_domain_remove_rr(node, rr_type, rdata, rdatalen, nonexist)) {
|
||||
/* alloc failure or so */
|
||||
return 0;
|
||||
}
|
||||
/* remove the node, if necessary */
|
||||
/* an rrsets==NULL entry is not kept around for empty nonterminals,
|
||||
* and also parent nodes are not kept around, so we just delete it */
|
||||
if(node->rrsets == NULL) {
|
||||
rbtree_delete(&z->data, node);
|
||||
auth_data_delete(node);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** decompress an RR into the buffer where it'll be an uncompressed RR
|
||||
* with uncompressed dname and uncompressed rdata (dnames) */
|
||||
static int
|
||||
decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
|
||||
size_t pktlen, uint8_t* dname, uint16_t rr_type, uint16_t rr_class,
|
||||
uint32_t rr_ttl, uint8_t* rr_data, uint16_t rr_rdlen)
|
||||
{
|
||||
sldns_buffer pktbuf;
|
||||
size_t dname_len = 0;
|
||||
size_t rdlenpos;
|
||||
size_t rdlen;
|
||||
uint8_t* rd;
|
||||
const sldns_rr_descriptor* desc;
|
||||
sldns_buffer_init_frm_data(&pktbuf, pkt, pktlen);
|
||||
sldns_buffer_clear(buf);
|
||||
|
||||
/* decompress dname */
|
||||
sldns_buffer_set_position(&pktbuf,
|
||||
dname - sldns_buffer_current(&pktbuf));
|
||||
dname_len = pkt_dname_len(&pktbuf);
|
||||
if(dname_len == 0) return 0; /* parse fail on dname */
|
||||
if(!sldns_buffer_available(buf, dname_len)) return 0;
|
||||
dname_pkt_copy(&pktbuf, sldns_buffer_current(buf), dname);
|
||||
sldns_buffer_skip(buf, dname_len);
|
||||
|
||||
/* type, class, ttl and rdatalength fields */
|
||||
if(!sldns_buffer_available(buf, 10)) return 0;
|
||||
sldns_buffer_write_u16(buf, rr_type);
|
||||
sldns_buffer_write_u16(buf, rr_class);
|
||||
sldns_buffer_write_u32(buf, rr_ttl);
|
||||
rdlenpos = sldns_buffer_position(buf);
|
||||
sldns_buffer_write_u16(buf, 0); /* rd length position */
|
||||
|
||||
/* decompress rdata */
|
||||
desc = sldns_rr_descript(rr_type);
|
||||
rd = rr_data;
|
||||
rdlen = rr_rdlen;
|
||||
if(rdlen > 0 && desc && desc->_dname_count > 0) {
|
||||
int count = (int)desc->_dname_count;
|
||||
int rdf = 0;
|
||||
size_t len; /* how much rdata to plain copy */
|
||||
size_t uncompressed_len, compressed_len;
|
||||
size_t oldpos;
|
||||
/* decompress dnames. */
|
||||
while(rdlen > 0 && count) {
|
||||
switch(desc->_wireformat[rdf]) {
|
||||
case LDNS_RDF_TYPE_DNAME:
|
||||
sldns_buffer_set_position(&pktbuf,
|
||||
rd - sldns_buffer_current(&pktbuf));
|
||||
oldpos = sldns_buffer_position(&pktbuf);
|
||||
/* moves pktbuf to right after the
|
||||
* compressed dname, and returns uncompressed
|
||||
* dname length */
|
||||
uncompressed_len = pkt_dname_len(&pktbuf);
|
||||
if(!uncompressed_len)
|
||||
return 0; /* parse error in dname */
|
||||
if(!sldns_buffer_available(buf,
|
||||
uncompressed_len))
|
||||
/* dname too long for buffer */
|
||||
return 0;
|
||||
dname_pkt_copy(&pktbuf,
|
||||
sldns_buffer_current(buf), rd);
|
||||
sldns_buffer_skip(buf, uncompressed_len);
|
||||
compressed_len = sldns_buffer_position(
|
||||
&pktbuf) - oldpos;
|
||||
rd += compressed_len;
|
||||
rdlen -= compressed_len;
|
||||
count--;
|
||||
len = 0;
|
||||
break;
|
||||
case LDNS_RDF_TYPE_STR:
|
||||
len = rd[0] + 1;
|
||||
break;
|
||||
default:
|
||||
len = get_rdf_size(desc->_wireformat[rdf]);
|
||||
break;
|
||||
}
|
||||
if(len) {
|
||||
if(!sldns_buffer_available(buf, len))
|
||||
return 0; /* too long for buffer */
|
||||
sldns_buffer_write(buf, rd, len);
|
||||
rd += len;
|
||||
rdlen -= len;
|
||||
}
|
||||
rdf++;
|
||||
}
|
||||
}
|
||||
/* copy remaining data */
|
||||
if(rdlen > 0) {
|
||||
if(!sldns_buffer_available(buf, rdlen)) return 0;
|
||||
sldns_buffer_write(buf, rd, rdlen);
|
||||
}
|
||||
sldns_buffer_flip(buf);
|
||||
|
||||
/* fixup rdlength */
|
||||
sldns_buffer_write_u16_at(buf, rdlenpos,
|
||||
sldns_buffer_position(buf)-rdlenpos-2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** insert RR into zone, from packet, decompress RR,
|
||||
* if duplicate is nonNULL set the flag but otherwise ignore duplicates */
|
||||
static int
|
||||
az_insert_rr_decompress(struct auth_zone* z, uint8_t* pkt, size_t pktlen,
|
||||
struct sldns_buffer* scratch_buffer, uint8_t* dname, uint16_t rr_type,
|
||||
uint16_t rr_class, uint32_t rr_ttl, uint8_t* rr_data,
|
||||
uint16_t rr_rdlen, int* duplicate)
|
||||
{
|
||||
uint8_t* rr;
|
||||
size_t rr_len;
|
||||
size_t dname_len;
|
||||
if(!decompress_rr_into_buffer(scratch_buffer, pkt, pktlen, dname,
|
||||
rr_type, rr_class, rr_ttl, rr_data, rr_rdlen)) {
|
||||
log_err("could not decompress RR");
|
||||
return 0;
|
||||
}
|
||||
rr = sldns_buffer_begin(scratch_buffer);
|
||||
rr_len = sldns_buffer_limit(scratch_buffer);
|
||||
dname_len = dname_valid(rr, rr_len);
|
||||
return az_insert_rr(z, rr, rr_len, dname_len, duplicate);
|
||||
}
|
||||
|
||||
/** remove RR from zone, from packet, decompress RR,
|
||||
* if nonexist is nonNULL set the flag but otherwise ignore nonexisting entries*/
|
||||
static int
|
||||
az_remove_rr_decompress(struct auth_zone* z, uint8_t* pkt, size_t pktlen,
|
||||
struct sldns_buffer* scratch_buffer, uint8_t* dname, uint16_t rr_type,
|
||||
uint16_t rr_class, uint32_t rr_ttl, uint8_t* rr_data,
|
||||
uint16_t rr_rdlen, int* nonexist)
|
||||
{
|
||||
uint8_t* rr;
|
||||
size_t rr_len;
|
||||
size_t dname_len;
|
||||
if(!decompress_rr_into_buffer(scratch_buffer, pkt, pktlen, dname,
|
||||
rr_type, rr_class, rr_ttl, rr_data, rr_rdlen)) {
|
||||
log_err("could not decompress RR");
|
||||
return 0;
|
||||
}
|
||||
rr = sldns_buffer_begin(scratch_buffer);
|
||||
rr_len = sldns_buffer_limit(scratch_buffer);
|
||||
dname_len = dname_valid(rr, rr_len);
|
||||
return az_remove_rr(z, rr, rr_len, dname_len, nonexist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse zonefile
|
||||
* @param z: zone to read in.
|
||||
|
|
@ -1099,7 +1488,7 @@ az_parse_file(struct auth_zone* z, FILE* in, uint8_t* rr, size_t rrbuflen,
|
|||
continue;
|
||||
}
|
||||
/* insert wirerr in rrbuf */
|
||||
if(!az_insert_rr(z, rr, rr_len, dname_len)) {
|
||||
if(!az_insert_rr(z, rr, rr_len, dname_len, NULL)) {
|
||||
char buf[17];
|
||||
sldns_wire2str_type_buf(sldns_wirerr_get_type(rr,
|
||||
rr_len, dname_len), buf, sizeof(buf));
|
||||
|
|
@ -3294,7 +3683,7 @@ static int
|
|||
chunk_rrlist_get_current(struct auth_chunk* rr_chunk, int rr_num,
|
||||
size_t rr_pos, uint8_t** rr_dname, uint16_t* rr_type,
|
||||
uint16_t* rr_class, uint32_t* rr_ttl, uint16_t* rr_rdlen,
|
||||
uint8_t** rr_rdata, uint8_t** rr_pkt, size_t* rr_nextpos)
|
||||
uint8_t** rr_rdata, size_t* rr_nextpos)
|
||||
{
|
||||
sldns_buffer pkt;
|
||||
/* integrity checks on position */
|
||||
|
|
@ -3315,7 +3704,6 @@ chunk_rrlist_get_current(struct auth_chunk* rr_chunk, int rr_num,
|
|||
*rr_rdlen = sldns_buffer_read_u16(&pkt);
|
||||
if(sldns_buffer_remaining(&pkt) < (*rr_rdlen)) return 0;
|
||||
*rr_rdata = sldns_buffer_current(&pkt);
|
||||
*rr_pkt = sldns_buffer_begin(&pkt);
|
||||
sldns_buffer_skip(&pkt, (ssize_t)(*rr_rdlen));
|
||||
*rr_nextpos = sldns_buffer_position(&pkt);
|
||||
return 1;
|
||||
|
|
@ -3323,12 +3711,13 @@ chunk_rrlist_get_current(struct auth_chunk* rr_chunk, int rr_num,
|
|||
|
||||
/** apply IXFR to zone in memory. z is locked. false on failure(mallocfail) */
|
||||
static int
|
||||
apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z)
|
||||
apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
struct sldns_buffer* scratch_buffer)
|
||||
{
|
||||
struct auth_chunk* rr_chunk;
|
||||
int rr_num;
|
||||
size_t rr_pos;
|
||||
uint8_t* rr_dname, *rr_rdata, *rr_pkt;
|
||||
uint8_t* rr_dname, *rr_rdata;
|
||||
uint16_t rr_type, rr_class, rr_rdlen;
|
||||
uint32_t rr_ttl;
|
||||
size_t rr_nextpos;
|
||||
|
|
@ -3343,7 +3732,7 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z)
|
|||
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
|
||||
if(!chunk_rrlist_get_current(rr_chunk, rr_num, rr_pos,
|
||||
&rr_dname, &rr_type, &rr_class, &rr_ttl, &rr_rdlen,
|
||||
&rr_rdata, &rr_pkt, &rr_nextpos)) {
|
||||
&rr_rdata, &rr_nextpos)) {
|
||||
/* failed to parse RR */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3382,7 +3771,8 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z)
|
|||
* SOA 3 followed by add
|
||||
* SOA 3 end */
|
||||
/* ended by SOA record */
|
||||
return 1;
|
||||
xfr->serial = transfer_serial;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* twiddle add/del mode */
|
||||
|
|
@ -3398,11 +3788,32 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z)
|
|||
* that we serve something fairly nice during the refetch */
|
||||
if(delmode) {
|
||||
/* delete this RR */
|
||||
(void)z;
|
||||
/* TODO */
|
||||
int nonexist = 0;
|
||||
if(!az_remove_rr_decompress(z, rr_chunk->data,
|
||||
rr_chunk->len, scratch_buffer, rr_dname,
|
||||
rr_type, rr_class, rr_ttl, rr_rdata, rr_rdlen,
|
||||
&nonexist)) {
|
||||
/* failed, malloc error or so */
|
||||
return 0;
|
||||
}
|
||||
if(nonexist) {
|
||||
/* it was removal of a nonexisting RR */
|
||||
softfail = 1;
|
||||
}
|
||||
} else {
|
||||
int duplicate = 0;
|
||||
/* add this RR */
|
||||
/* TODO */
|
||||
if(!az_insert_rr_decompress(z, rr_chunk->data,
|
||||
rr_chunk->len, scratch_buffer, rr_dname,
|
||||
rr_type, rr_class, rr_ttl, rr_rdata, rr_rdlen,
|
||||
&duplicate)) {
|
||||
/* failed, malloc error or so */
|
||||
return 0;
|
||||
}
|
||||
if(duplicate) {
|
||||
/* it was a duplicate */
|
||||
softfail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rr_counter++;
|
||||
|
|
@ -3414,10 +3825,59 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z)
|
|||
|
||||
/** apply AXFR to zone in memory. z is locked. false on failure(mallocfail) */
|
||||
static int
|
||||
apply_axfr(struct auth_xfer* xfr, struct auth_zone* z)
|
||||
apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
struct sldns_buffer* scratch_buffer)
|
||||
{
|
||||
/* TODO */
|
||||
(void)xfr; (void)z;
|
||||
struct auth_chunk* rr_chunk;
|
||||
int rr_num;
|
||||
size_t rr_pos;
|
||||
uint8_t* rr_dname, *rr_rdata;
|
||||
uint16_t rr_type, rr_class, rr_rdlen;
|
||||
uint32_t rr_ttl;
|
||||
uint32_t serial = 0;
|
||||
size_t rr_nextpos;
|
||||
size_t rr_counter = 0;
|
||||
|
||||
/* clear the data tree */
|
||||
traverse_postorder(&z->data, auth_data_del, NULL);
|
||||
rbtree_init(&z->data, &auth_data_cmp);
|
||||
xfr->have_zone = 0;
|
||||
xfr->serial = 0;
|
||||
|
||||
/* insert all RRs in to the zone */
|
||||
/* insert the SOA only once, skip the last one */
|
||||
/* start RR iterator over chunklist of packets */
|
||||
chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos);
|
||||
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
|
||||
if(!chunk_rrlist_get_current(rr_chunk, rr_num, rr_pos,
|
||||
&rr_dname, &rr_type, &rr_class, &rr_ttl, &rr_rdlen,
|
||||
&rr_rdata, &rr_nextpos)) {
|
||||
/* failed to parse RR */
|
||||
return 0;
|
||||
}
|
||||
if(rr_type == LDNS_RR_TYPE_SOA) {
|
||||
if(rr_counter != 0) {
|
||||
/* end of the axfr */
|
||||
break;
|
||||
}
|
||||
if(rr_rdlen < 22) return 0; /* bad SOA rdlen */
|
||||
serial = sldns_read_uint32(rr_rdata+rr_rdlen-20);
|
||||
}
|
||||
|
||||
/* add this RR */
|
||||
if(!az_insert_rr_decompress(z, rr_chunk->data, rr_chunk->len,
|
||||
scratch_buffer, rr_dname, rr_type, rr_class, rr_ttl,
|
||||
rr_rdata, rr_rdlen, NULL)) {
|
||||
/* failed, malloc error or so */
|
||||
return 0;
|
||||
}
|
||||
|
||||
rr_counter++;
|
||||
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos);
|
||||
}
|
||||
|
||||
xfr->serial = serial;
|
||||
xfr->have_zone = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -3494,7 +3954,7 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
|||
/* apply data */
|
||||
if(xfr->task_transfer->on_ixfr &&
|
||||
!xfr->task_transfer->on_ixfr_is_axfr) {
|
||||
if(!apply_ixfr(xfr, z)) {
|
||||
if(!apply_ixfr(xfr, z, env->scratch_buffer)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
verbose(VERB_ALGO, "xfr from %s: could not store IXFR"
|
||||
" data", xfr->task_transfer->master->host);
|
||||
|
|
@ -3502,13 +3962,21 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
|||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(!apply_axfr(xfr, z)) {
|
||||
if(!apply_axfr(xfr, z, env->scratch_buffer)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
verbose(VERB_ALGO, "xfr from %s: could not store AXFR"
|
||||
" data", xfr->task_transfer->master->host);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!xfr_find_soa(z, xfr)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
verbose(VERB_ALGO, "xfr from %s: no SOA in zone after update"
|
||||
" (or malformed RR)", xfr->task_transfer->master->host);
|
||||
return 0;
|
||||
}
|
||||
xfr->zone_expired = 0;
|
||||
z->zone_expired = 0;
|
||||
|
||||
/* unlock */
|
||||
lock_rw_unlock(&z->lock);
|
||||
|
|
|
|||
Loading…
Reference in a new issue