162ac0c33Sjakob /*
262ac0c33Sjakob * difffile.c - DIFF file handling source code. Read and write diff files.
362ac0c33Sjakob *
4d3fecca9Ssthen * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob *
662ac0c33Sjakob * See LICENSE for the license.
762ac0c33Sjakob *
862ac0c33Sjakob */
962ac0c33Sjakob
102c1ae072Ssthen #include "config.h"
1162ac0c33Sjakob #include <assert.h>
1262ac0c33Sjakob #include <string.h>
1362ac0c33Sjakob #include <unistd.h>
1462ac0c33Sjakob #include <stdlib.h>
1562ac0c33Sjakob #include <errno.h>
1662ac0c33Sjakob #include "difffile.h"
17d3fecca9Ssthen #include "xfrd-disk.h"
1862ac0c33Sjakob #include "util.h"
1962ac0c33Sjakob #include "packet.h"
2062ac0c33Sjakob #include "rdata.h"
21d3fecca9Ssthen #include "udb.h"
220c2b6c02Sjakob #include "nsec3.h"
23d3fecca9Ssthen #include "nsd.h"
24d3fecca9Ssthen #include "rrl.h"
254564029fSflorian #include "ixfr.h"
264564029fSflorian #include "zonec.h"
27*bf87c3c0Sflorian #include "xfrd-catalog-zones.h"
28d3fecca9Ssthen
29d3fecca9Ssthen static int
write_64(FILE * out,uint64_t val)30d3fecca9Ssthen write_64(FILE *out, uint64_t val)
31d3fecca9Ssthen {
32d3fecca9Ssthen return write_data(out, &val, sizeof(val));
33d3fecca9Ssthen }
3462ac0c33Sjakob
3562ac0c33Sjakob static int
write_32(FILE * out,uint32_t val)3662ac0c33Sjakob write_32(FILE *out, uint32_t val)
3762ac0c33Sjakob {
3862ac0c33Sjakob val = htonl(val);
3962ac0c33Sjakob return write_data(out, &val, sizeof(val));
4062ac0c33Sjakob }
4162ac0c33Sjakob
4262ac0c33Sjakob static int
write_8(FILE * out,uint8_t val)4362ac0c33Sjakob write_8(FILE *out, uint8_t val)
4462ac0c33Sjakob {
4562ac0c33Sjakob return write_data(out, &val, sizeof(val));
4662ac0c33Sjakob }
4762ac0c33Sjakob
4862ac0c33Sjakob static int
write_str(FILE * out,const char * str)4962ac0c33Sjakob write_str(FILE *out, const char* str)
5062ac0c33Sjakob {
5162ac0c33Sjakob uint32_t len = strlen(str);
5262ac0c33Sjakob if(!write_32(out, len))
5362ac0c33Sjakob return 0;
5462ac0c33Sjakob return write_data(out, str, len);
5562ac0c33Sjakob }
5662ac0c33Sjakob
5762ac0c33Sjakob void
diff_write_packet(const char * zone,const char * pat,uint32_t old_serial,uint32_t new_serial,uint32_t seq_nr,uint8_t * data,size_t len,struct nsd * nsd,uint64_t filenumber)58d3fecca9Ssthen diff_write_packet(const char* zone, const char* pat, uint32_t old_serial,
59d3fecca9Ssthen uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len,
60d3fecca9Ssthen struct nsd* nsd, uint64_t filenumber)
6162ac0c33Sjakob {
62d3fecca9Ssthen FILE* df = xfrd_open_xfrfile(nsd, filenumber, seq_nr?"a":"w");
6362ac0c33Sjakob if(!df) {
64d3fecca9Ssthen log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
65d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
6662ac0c33Sjakob return;
6762ac0c33Sjakob }
6862ac0c33Sjakob
69d3fecca9Ssthen /* if first part, first write the header */
70d3fecca9Ssthen if(seq_nr == 0) {
71d3fecca9Ssthen struct timeval tv;
72d3fecca9Ssthen if (gettimeofday(&tv, NULL) != 0) {
73d3fecca9Ssthen log_msg(LOG_ERR, "could not get timestamp for %s: %s",
74d3fecca9Ssthen zone, strerror(errno));
75d3fecca9Ssthen }
76d3fecca9Ssthen if(!write_32(df, DIFF_PART_XFRF) ||
77d3fecca9Ssthen !write_8(df, 0) /* notcommitted(yet) */ ||
78d3fecca9Ssthen !write_32(df, 0) /* numberofparts when done */ ||
79d3fecca9Ssthen !write_64(df, (uint64_t) tv.tv_sec) ||
8062ac0c33Sjakob !write_32(df, (uint32_t) tv.tv_usec) ||
81d3fecca9Ssthen !write_32(df, old_serial) ||
8262ac0c33Sjakob !write_32(df, new_serial) ||
83d3fecca9Ssthen !write_64(df, (uint64_t) tv.tv_sec) ||
84d3fecca9Ssthen !write_32(df, (uint32_t) tv.tv_usec) ||
85d3fecca9Ssthen !write_str(df, zone) ||
86d3fecca9Ssthen !write_str(df, pat)) {
87d3fecca9Ssthen log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
88d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
89d3fecca9Ssthen fclose(df);
90d3fecca9Ssthen return;
91d3fecca9Ssthen }
92d3fecca9Ssthen }
93d3fecca9Ssthen
94d3fecca9Ssthen if(!write_32(df, DIFF_PART_XXFR) ||
95d3fecca9Ssthen !write_32(df, len) ||
9662ac0c33Sjakob !write_data(df, data, len) ||
97d3fecca9Ssthen !write_32(df, len))
9862ac0c33Sjakob {
99d3fecca9Ssthen log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
100d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
10162ac0c33Sjakob }
10262ac0c33Sjakob fclose(df);
10362ac0c33Sjakob }
10462ac0c33Sjakob
10562ac0c33Sjakob void
diff_write_commit(const char * zone,uint32_t old_serial,uint32_t new_serial,uint32_t num_parts,uint8_t commit,const char * log_str,struct nsd * nsd,uint64_t filenumber)106d3fecca9Ssthen diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial,
107d3fecca9Ssthen uint32_t num_parts, uint8_t commit, const char* log_str,
108d3fecca9Ssthen struct nsd* nsd, uint64_t filenumber)
10962ac0c33Sjakob {
11062ac0c33Sjakob struct timeval tv;
11162ac0c33Sjakob FILE* df;
11262ac0c33Sjakob
11362ac0c33Sjakob if (gettimeofday(&tv, NULL) != 0) {
11462ac0c33Sjakob log_msg(LOG_ERR, "could not set timestamp for %s: %s",
115d3fecca9Ssthen zone, strerror(errno));
11662ac0c33Sjakob }
11762ac0c33Sjakob
118d3fecca9Ssthen /* overwrite the first part of the file with 'committed = 1',
119d3fecca9Ssthen * as well as the end_time and number of parts.
120d3fecca9Ssthen * also write old_serial and new_serial, so that a bad file mixup
121d3fecca9Ssthen * will result in unusable serial numbers. */
122d3fecca9Ssthen
123d3fecca9Ssthen df = xfrd_open_xfrfile(nsd, filenumber, "r+");
12462ac0c33Sjakob if(!df) {
125d3fecca9Ssthen log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
126d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
127d3fecca9Ssthen return;
128d3fecca9Ssthen }
129d3fecca9Ssthen if(!write_32(df, DIFF_PART_XFRF) ||
130d3fecca9Ssthen !write_8(df, commit) /* committed */ ||
131d3fecca9Ssthen !write_32(df, num_parts) ||
132d3fecca9Ssthen !write_64(df, (uint64_t) tv.tv_sec) ||
133d3fecca9Ssthen !write_32(df, (uint32_t) tv.tv_usec) ||
134d3fecca9Ssthen !write_32(df, old_serial) ||
135d3fecca9Ssthen !write_32(df, new_serial))
136d3fecca9Ssthen {
137d3fecca9Ssthen log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
138d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
139d3fecca9Ssthen fclose(df);
14062ac0c33Sjakob return;
14162ac0c33Sjakob }
14262ac0c33Sjakob
143d3fecca9Ssthen /* append the log_str to the end of the file */
144d3fecca9Ssthen if(fseek(df, 0, SEEK_END) == -1) {
145d3fecca9Ssthen log_msg(LOG_ERR, "could not fseek transfer %s file %lld: %s",
146d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
147d3fecca9Ssthen fclose(df);
148d3fecca9Ssthen return;
149d3fecca9Ssthen }
150d3fecca9Ssthen if(!write_str(df, log_str)) {
151d3fecca9Ssthen log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
152d3fecca9Ssthen zone, (long long)filenumber, strerror(errno));
153d3fecca9Ssthen fclose(df);
154d3fecca9Ssthen return;
15562ac0c33Sjakob
15662ac0c33Sjakob }
15762ac0c33Sjakob fflush(df);
15862ac0c33Sjakob fclose(df);
15962ac0c33Sjakob }
16062ac0c33Sjakob
1613f21e8ccSflorian void
diff_update_commit(const char * zone,uint8_t commit,struct nsd * nsd,uint64_t filenumber)1623f21e8ccSflorian diff_update_commit(
1633f21e8ccSflorian const char* zone, uint8_t commit, struct nsd* nsd, uint64_t filenumber)
1643f21e8ccSflorian {
1653f21e8ccSflorian FILE *df;
1663f21e8ccSflorian
1673f21e8ccSflorian assert(zone != NULL);
1683f21e8ccSflorian assert(nsd != NULL);
1693f21e8ccSflorian assert(commit == DIFF_NOT_COMMITTED ||
1703f21e8ccSflorian commit == DIFF_COMMITTED ||
1713f21e8ccSflorian commit == DIFF_CORRUPT ||
1723f21e8ccSflorian commit == DIFF_INCONSISTENT ||
1733f21e8ccSflorian commit == DIFF_VERIFIED);
1743f21e8ccSflorian
1753f21e8ccSflorian df = xfrd_open_xfrfile(nsd, filenumber, "r+");
1763f21e8ccSflorian if(!df) {
1773f21e8ccSflorian log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
1783f21e8ccSflorian zone, (long long)filenumber, strerror(errno));
1793f21e8ccSflorian return;
1803f21e8ccSflorian }
1813f21e8ccSflorian if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, commit)) {
1823f21e8ccSflorian log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
1833f21e8ccSflorian zone, (long long)filenumber, strerror(errno));
1843f21e8ccSflorian fclose(df);
1853f21e8ccSflorian return;
1863f21e8ccSflorian }
1873f21e8ccSflorian fflush(df);
1883f21e8ccSflorian fclose(df);
1893f21e8ccSflorian }
1903f21e8ccSflorian
19162ac0c33Sjakob int
diff_read_64(FILE * in,uint64_t * result)192d3fecca9Ssthen diff_read_64(FILE *in, uint64_t* result)
19362ac0c33Sjakob {
19462ac0c33Sjakob if (fread(result, sizeof(*result), 1, in) == 1) {
19562ac0c33Sjakob return 1;
19662ac0c33Sjakob } else {
19762ac0c33Sjakob return 0;
19862ac0c33Sjakob }
19962ac0c33Sjakob }
20062ac0c33Sjakob
20162ac0c33Sjakob int
diff_read_32(FILE * in,uint32_t * result)202d3fecca9Ssthen diff_read_32(FILE *in, uint32_t* result)
20362ac0c33Sjakob {
20462ac0c33Sjakob if (fread(result, sizeof(*result), 1, in) == 1) {
205d3fecca9Ssthen *result = ntohl(*result);
20662ac0c33Sjakob return 1;
20762ac0c33Sjakob } else {
20862ac0c33Sjakob return 0;
20962ac0c33Sjakob }
21062ac0c33Sjakob }
21162ac0c33Sjakob
21262ac0c33Sjakob int
diff_read_8(FILE * in,uint8_t * result)21362ac0c33Sjakob diff_read_8(FILE *in, uint8_t* result)
21462ac0c33Sjakob {
21562ac0c33Sjakob if (fread(result, sizeof(*result), 1, in) == 1) {
21662ac0c33Sjakob return 1;
21762ac0c33Sjakob } else {
21862ac0c33Sjakob return 0;
21962ac0c33Sjakob }
22062ac0c33Sjakob }
22162ac0c33Sjakob
22262ac0c33Sjakob int
diff_read_str(FILE * in,char * buf,size_t len)22362ac0c33Sjakob diff_read_str(FILE* in, char* buf, size_t len)
22462ac0c33Sjakob {
22562ac0c33Sjakob uint32_t disklen;
22662ac0c33Sjakob if(!diff_read_32(in, &disklen))
22762ac0c33Sjakob return 0;
22862ac0c33Sjakob if(disklen >= len)
22962ac0c33Sjakob return 0;
23062ac0c33Sjakob if(fread(buf, disklen, 1, in) != 1)
23162ac0c33Sjakob return 0;
23262ac0c33Sjakob buf[disklen] = 0;
23362ac0c33Sjakob return 1;
23462ac0c33Sjakob }
23562ac0c33Sjakob
23662ac0c33Sjakob static void
add_rdata_to_recyclebin(namedb_type * db,rr_type * rr)23762ac0c33Sjakob add_rdata_to_recyclebin(namedb_type* db, rr_type* rr)
23862ac0c33Sjakob {
23962ac0c33Sjakob /* add rdatas to recycle bin. */
24062ac0c33Sjakob size_t i;
24162ac0c33Sjakob for(i=0; i<rr->rdata_count; i++)
24262ac0c33Sjakob {
24362ac0c33Sjakob if(!rdata_atom_is_domain(rr->type, i))
24462ac0c33Sjakob region_recycle(db->region, rr->rdatas[i].data,
24562ac0c33Sjakob rdata_atom_size(rr->rdatas[i])
24662ac0c33Sjakob + sizeof(uint16_t));
24762ac0c33Sjakob }
24862ac0c33Sjakob region_recycle(db->region, rr->rdatas,
24962ac0c33Sjakob sizeof(rdata_atom_type)*rr->rdata_count);
25062ac0c33Sjakob }
25162ac0c33Sjakob
25262ac0c33Sjakob /* this routine determines if below a domain there exist names with
25362ac0c33Sjakob * data (is_existing) or no names below the domain have data.
25462ac0c33Sjakob */
25562ac0c33Sjakob static int
has_data_below(domain_type * top)25662ac0c33Sjakob has_data_below(domain_type* top)
25762ac0c33Sjakob {
25862ac0c33Sjakob domain_type* d = top;
25962ac0c33Sjakob assert(d != NULL);
26062ac0c33Sjakob /* in the canonical ordering subdomains are after this name */
26162ac0c33Sjakob d = domain_next(d);
262d3fecca9Ssthen while(d != NULL && domain_is_subdomain(d, top)) {
26362ac0c33Sjakob if(d->is_existing)
26462ac0c33Sjakob return 1;
26562ac0c33Sjakob d = domain_next(d);
26662ac0c33Sjakob }
26762ac0c33Sjakob return 0;
26862ac0c33Sjakob }
26962ac0c33Sjakob
27015ed76cbSbrad /** check if domain with 0 rrsets has become empty (nonexist) */
27103739794Sbrad static domain_type*
rrset_zero_nonexist_check(domain_type * domain,domain_type * ce)27203739794Sbrad rrset_zero_nonexist_check(domain_type* domain, domain_type* ce)
27315ed76cbSbrad {
27415ed76cbSbrad /* is the node now an empty node (completely deleted) */
27515ed76cbSbrad if(domain->rrsets == 0) {
27615ed76cbSbrad /* if there is no data below it, it becomes non existing.
27715ed76cbSbrad also empty nonterminals above it become nonexisting */
27815ed76cbSbrad /* check for data below this node. */
27915ed76cbSbrad if(!has_data_below(domain)) {
28015ed76cbSbrad /* nonexist this domain and all parent empty nonterminals */
28115ed76cbSbrad domain_type* p = domain;
28215ed76cbSbrad while(p != NULL && p->rrsets == 0) {
28303739794Sbrad if(p == ce || has_data_below(p))
28403739794Sbrad return p;
28515ed76cbSbrad p->is_existing = 0;
28603739794Sbrad /* fixup wildcard child of parent */
28703739794Sbrad if(p->parent &&
28803739794Sbrad p->parent->wildcard_child_closest_match == p)
28903739794Sbrad p->parent->wildcard_child_closest_match = domain_previous_existing_child(p);
29015ed76cbSbrad p = p->parent;
29115ed76cbSbrad }
29215ed76cbSbrad }
29315ed76cbSbrad }
29403739794Sbrad return NULL;
29515ed76cbSbrad }
29615ed76cbSbrad
297d3fecca9Ssthen /** remove rrset. Adjusts zone params. Does not remove domain */
298d3fecca9Ssthen static void
rrset_delete(namedb_type * db,domain_type * domain,rrset_type * rrset)29962ac0c33Sjakob rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
30062ac0c33Sjakob {
30162ac0c33Sjakob int i;
30262ac0c33Sjakob /* find previous */
30362ac0c33Sjakob rrset_type** pp = &domain->rrsets;
30462ac0c33Sjakob while(*pp && *pp != rrset) {
30562ac0c33Sjakob pp = &( (*pp)->next );
30662ac0c33Sjakob }
30762ac0c33Sjakob if(!*pp) {
30862ac0c33Sjakob /* rrset does not exist for domain */
309d3fecca9Ssthen return;
31062ac0c33Sjakob }
31162ac0c33Sjakob *pp = rrset->next;
31262ac0c33Sjakob
31362ac0c33Sjakob DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s",
314d3fecca9Ssthen domain_to_string(domain),
31562ac0c33Sjakob rrtype_to_string(rrset_rrtype(rrset))));
31662ac0c33Sjakob
31762ac0c33Sjakob /* is this a SOA rrset ? */
31862ac0c33Sjakob if(rrset->zone->soa_rrset == rrset) {
31962ac0c33Sjakob rrset->zone->soa_rrset = 0;
32062ac0c33Sjakob }
32162ac0c33Sjakob if(rrset->zone->ns_rrset == rrset) {
32262ac0c33Sjakob rrset->zone->ns_rrset = 0;
32362ac0c33Sjakob }
32462ac0c33Sjakob if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) {
32562ac0c33Sjakob for (i = 0; i < rrset->rr_count; ++i) {
3260c2b6c02Sjakob if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY) {
32762ac0c33Sjakob rrset->zone->is_secure = 0;
32862ac0c33Sjakob break;
32962ac0c33Sjakob }
33062ac0c33Sjakob }
33162ac0c33Sjakob }
33262ac0c33Sjakob /* recycle the memory space of the rrset */
33362ac0c33Sjakob for (i = 0; i < rrset->rr_count; ++i)
33462ac0c33Sjakob add_rdata_to_recyclebin(db, &rrset->rrs[i]);
33562ac0c33Sjakob region_recycle(db->region, rrset->rrs,
33662ac0c33Sjakob sizeof(rr_type) * rrset->rr_count);
337044f85deSsthen rrset->rr_count = 0;
33862ac0c33Sjakob region_recycle(db->region, rrset, sizeof(rrset_type));
33962ac0c33Sjakob }
34062ac0c33Sjakob
34162ac0c33Sjakob static int
rdatas_equal(rdata_atom_type * a,rdata_atom_type * b,int num,uint16_t type,int * rdnum,char ** reason)342d3fecca9Ssthen rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type,
343d3fecca9Ssthen int* rdnum, char** reason)
34462ac0c33Sjakob {
345cbbc2d6cSbrad int k, start, end;
346cbbc2d6cSbrad start = 0;
347cbbc2d6cSbrad end = num;
34815ed76cbSbrad /**
34915ed76cbSbrad * SOA RDATA comparisons in XFR are more lenient,
35015ed76cbSbrad * only serial rdata is checked.
35115ed76cbSbrad **/
352cbbc2d6cSbrad if (type == TYPE_SOA) {
353cbbc2d6cSbrad start = 2;
35415ed76cbSbrad end = 3;
355cbbc2d6cSbrad }
356cbbc2d6cSbrad for(k = start; k < end; k++)
35762ac0c33Sjakob {
35862ac0c33Sjakob if(rdata_atom_is_domain(type, k)) {
35962ac0c33Sjakob if(dname_compare(domain_dname(a[k].domain),
360d3fecca9Ssthen domain_dname(b[k].domain))!=0) {
361d3fecca9Ssthen *rdnum = k;
362d3fecca9Ssthen *reason = "dname data";
36362ac0c33Sjakob return 0;
364d3fecca9Ssthen }
365d3fecca9Ssthen } else if(rdata_atom_is_literal_domain(type, k)) {
366d3fecca9Ssthen /* literal dname, but compare case insensitive */
367d3fecca9Ssthen if(a[k].data[0] != b[k].data[0]) {
368d3fecca9Ssthen *rdnum = k;
369d3fecca9Ssthen *reason = "literal dname len";
370d3fecca9Ssthen return 0; /* uncompressed len must be equal*/
371d3fecca9Ssthen }
372d3fecca9Ssthen if(!dname_equal_nocase((uint8_t*)(a[k].data+1),
373d3fecca9Ssthen (uint8_t*)(b[k].data+1), a[k].data[0])) {
374d3fecca9Ssthen *rdnum = k;
375d3fecca9Ssthen *reason = "literal dname data";
376d3fecca9Ssthen return 0;
377d3fecca9Ssthen }
37862ac0c33Sjakob } else {
37962ac0c33Sjakob /* check length */
380d3fecca9Ssthen if(a[k].data[0] != b[k].data[0]) {
381d3fecca9Ssthen *rdnum = k;
382d3fecca9Ssthen *reason = "rdata len";
38362ac0c33Sjakob return 0;
384d3fecca9Ssthen }
38562ac0c33Sjakob /* check data */
386d3fecca9Ssthen if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) {
387d3fecca9Ssthen *rdnum = k;
388d3fecca9Ssthen *reason = "rdata data";
38962ac0c33Sjakob return 0;
39062ac0c33Sjakob }
39162ac0c33Sjakob }
392d3fecca9Ssthen }
39362ac0c33Sjakob return 1;
39462ac0c33Sjakob }
39562ac0c33Sjakob
396d3fecca9Ssthen static void
debug_find_rr_num(rrset_type * rrset,uint16_t type,uint16_t klass,rdata_atom_type * rdatas,ssize_t rdata_num)397d3fecca9Ssthen debug_find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
39862ac0c33Sjakob rdata_atom_type *rdatas, ssize_t rdata_num)
39962ac0c33Sjakob {
400d3fecca9Ssthen int i, rd;
401d3fecca9Ssthen char* reason = "";
402d3fecca9Ssthen
403d3fecca9Ssthen for(i=0; i < rrset->rr_count; ++i) {
404d3fecca9Ssthen if (rrset->rrs[i].type != type) {
405d3fecca9Ssthen log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match "
406d3fecca9Ssthen "RR num %d type %s",
407c1e73312Sflorian dname_to_string(domain_dname(rrset->rrs[i].owner),0),
408d3fecca9Ssthen rrtype_to_string(type), i,
409d3fecca9Ssthen rrtype_to_string(rrset->rrs[i].type));
410d3fecca9Ssthen }
411d3fecca9Ssthen if (rrset->rrs[i].klass != klass) {
412d3fecca9Ssthen log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d "
413d3fecca9Ssthen "does not match RR num %d class %d",
414c1e73312Sflorian dname_to_string(domain_dname(rrset->rrs[i].owner),0),
415d3fecca9Ssthen rrtype_to_string(type),
416d3fecca9Ssthen klass, i,
417d3fecca9Ssthen rrset->rrs[i].klass);
418d3fecca9Ssthen }
419d3fecca9Ssthen if (rrset->rrs[i].rdata_count != rdata_num) {
420d3fecca9Ssthen log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u "
421d3fecca9Ssthen "does not match RR num %d rdlen %d",
422c1e73312Sflorian dname_to_string(domain_dname(rrset->rrs[i].owner),0),
423d3fecca9Ssthen rrtype_to_string(type),
424d3fecca9Ssthen (unsigned) rdata_num, i,
425d3fecca9Ssthen (unsigned) rrset->rrs[i].rdata_count);
426d3fecca9Ssthen }
427d3fecca9Ssthen if (!rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
428d3fecca9Ssthen &rd, &reason)) {
429d3fecca9Ssthen log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element "
430d3fecca9Ssthen "%d differs from RR num %d rdata (%s)",
431c1e73312Sflorian dname_to_string(domain_dname(rrset->rrs[i].owner),0),
432d3fecca9Ssthen rrtype_to_string(type),
433d3fecca9Ssthen rd, i, reason);
434d3fecca9Ssthen }
435d3fecca9Ssthen }
436d3fecca9Ssthen }
437d3fecca9Ssthen
438d3fecca9Ssthen static int
find_rr_num(rrset_type * rrset,uint16_t type,uint16_t klass,rdata_atom_type * rdatas,ssize_t rdata_num,int add)439d3fecca9Ssthen find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
440d3fecca9Ssthen rdata_atom_type *rdatas, ssize_t rdata_num, int add)
441d3fecca9Ssthen {
442d3fecca9Ssthen int i, rd;
443d3fecca9Ssthen char* reason;
44462ac0c33Sjakob
44562ac0c33Sjakob for(i=0; i < rrset->rr_count; ++i) {
44662ac0c33Sjakob if(rrset->rrs[i].type == type &&
44762ac0c33Sjakob rrset->rrs[i].klass == klass &&
44862ac0c33Sjakob rrset->rrs[i].rdata_count == rdata_num &&
449d3fecca9Ssthen rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
450d3fecca9Ssthen &rd, &reason))
45162ac0c33Sjakob {
45262ac0c33Sjakob return i;
45362ac0c33Sjakob }
45462ac0c33Sjakob }
455d3fecca9Ssthen /* this is odd. Log why rr cannot be found. */
456d3fecca9Ssthen if (!add) {
457d3fecca9Ssthen debug_find_rr_num(rrset, type, klass, rdatas, rdata_num);
458d3fecca9Ssthen }
45962ac0c33Sjakob return -1;
46062ac0c33Sjakob }
46162ac0c33Sjakob
462d3fecca9Ssthen #ifdef NSEC3
463d3fecca9Ssthen /* see if nsec3 deletion triggers need action */
464d3fecca9Ssthen static void
nsec3_delete_rr_trigger(namedb_type * db,rr_type * rr,zone_type * zone)465b71395eaSflorian nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone)
466d3fecca9Ssthen {
467d3fecca9Ssthen /* the RR has not actually been deleted yet, so we can inspect it */
468d3fecca9Ssthen if(!zone->nsec3_param)
469d3fecca9Ssthen return;
470d3fecca9Ssthen /* see if the domain was an NSEC3-domain in the chain, but no longer */
471d3fecca9Ssthen if(rr->type == TYPE_NSEC3 && rr->owner->nsec3 &&
472d3fecca9Ssthen rr->owner->nsec3->nsec3_node.key &&
473d3fecca9Ssthen nsec3_rr_uses_params(rr, zone) &&
474d3fecca9Ssthen nsec3_in_chain_count(rr->owner, zone) <= 1) {
475d3fecca9Ssthen domain_type* prev = nsec3_chain_find_prev(zone, rr->owner);
476d3fecca9Ssthen /* remove from prehash because no longer an NSEC3 domain */
477d3fecca9Ssthen if(domain_is_prehash(db->domains, rr->owner))
478d3fecca9Ssthen prehash_del(db->domains, rr->owner);
479d3fecca9Ssthen /* fixup the last in the zone */
480d3fecca9Ssthen if(rr->owner == zone->nsec3_last)
481d3fecca9Ssthen zone->nsec3_last = prev;
482d3fecca9Ssthen /* unlink from the nsec3tree */
483d3fecca9Ssthen zone_del_domain_in_hash_tree(zone->nsec3tree,
484d3fecca9Ssthen &rr->owner->nsec3->nsec3_node);
485d3fecca9Ssthen /* add previous NSEC3 to the prehash list */
486d3fecca9Ssthen if(prev && prev != rr->owner)
487d3fecca9Ssthen prehash_add(db->domains, prev);
488d3fecca9Ssthen else nsec3_clear_precompile(db, zone);
489d3fecca9Ssthen /* this domain becomes ordinary data domain: done later */
490d3fecca9Ssthen }
491d3fecca9Ssthen /* see if the rr was NSEC3PARAM that we were using */
492d3fecca9Ssthen else if(rr->type == TYPE_NSEC3PARAM && rr == zone->nsec3_param) {
493d3fecca9Ssthen /* clear trees, wipe hashes, wipe precompile */
494d3fecca9Ssthen nsec3_clear_precompile(db, zone);
49515ed76cbSbrad /* pick up new nsec3param (from udb, or avoid deleted rr) */
496b71395eaSflorian nsec3_find_zone_param(db, zone, rr, 0);
497d3fecca9Ssthen /* if no more NSEC3, done */
498d3fecca9Ssthen if(!zone->nsec3_param)
499d3fecca9Ssthen return;
500d3fecca9Ssthen nsec3_precompile_newparam(db, zone);
501d3fecca9Ssthen }
502d3fecca9Ssthen }
503d3fecca9Ssthen
504d3fecca9Ssthen /* see if nsec3 prehash can be removed with new rrset content */
505d3fecca9Ssthen static void
nsec3_rrsets_changed_remove_prehash(domain_type * domain,zone_type * zone)506d3fecca9Ssthen nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
507d3fecca9Ssthen {
508d3fecca9Ssthen /* deletion of rrset already done, we can check if conditions apply */
509d3fecca9Ssthen /* see if the domain is no longer precompiled */
510d3fecca9Ssthen /* it has a hash_node, but no longer fulfills conditions */
511d3fecca9Ssthen if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 &&
512ee5153b7Sflorian domain->nsec3->hash_wc &&
513ee5153b7Sflorian domain->nsec3->hash_wc->hash.node.key &&
514d3fecca9Ssthen !nsec3_condition_hash(domain, zone)) {
515d3fecca9Ssthen /* remove precompile */
516d3fecca9Ssthen domain->nsec3->nsec3_cover = NULL;
517d3fecca9Ssthen domain->nsec3->nsec3_wcard_child_cover = NULL;
518d3fecca9Ssthen domain->nsec3->nsec3_is_exact = 0;
519d3fecca9Ssthen /* remove it from the hash tree */
520d3fecca9Ssthen zone_del_domain_in_hash_tree(zone->hashtree,
521ee5153b7Sflorian &domain->nsec3->hash_wc->hash.node);
522d3fecca9Ssthen zone_del_domain_in_hash_tree(zone->wchashtree,
523ee5153b7Sflorian &domain->nsec3->hash_wc->wc.node);
524d3fecca9Ssthen }
525d3fecca9Ssthen if(domain != zone->apex && domain->nsec3 &&
526ee5153b7Sflorian domain->nsec3->ds_parent_hash &&
527ee5153b7Sflorian domain->nsec3->ds_parent_hash->node.key &&
528cdb6bbddSbrad (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) &&
529d3fecca9Ssthen !nsec3_condition_dshash(domain, zone)) {
530d3fecca9Ssthen /* remove precompile */
531d3fecca9Ssthen domain->nsec3->nsec3_ds_parent_cover = NULL;
532d3fecca9Ssthen domain->nsec3->nsec3_ds_parent_is_exact = 0;
533d3fecca9Ssthen /* remove it from the hash tree */
534d3fecca9Ssthen zone_del_domain_in_hash_tree(zone->dshashtree,
535ee5153b7Sflorian &domain->nsec3->ds_parent_hash->node);
536d3fecca9Ssthen }
537d3fecca9Ssthen }
538d3fecca9Ssthen
539d3fecca9Ssthen /* see if domain needs to get precompiled info */
540d3fecca9Ssthen static void
nsec3_rrsets_changed_add_prehash(namedb_type * db,domain_type * domain,zone_type * zone)541d3fecca9Ssthen nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain,
542d3fecca9Ssthen zone_type* zone)
543d3fecca9Ssthen {
544d3fecca9Ssthen if(!zone->nsec3_param)
545d3fecca9Ssthen return;
546ee5153b7Sflorian if((!domain->nsec3 || !domain->nsec3->hash_wc
547ee5153b7Sflorian || !domain->nsec3->hash_wc->hash.node.key)
548d3fecca9Ssthen && nsec3_condition_hash(domain, zone)) {
549d3fecca9Ssthen region_type* tmpregion = region_create(xalloc, free);
550d3fecca9Ssthen nsec3_precompile_domain(db, domain, zone, tmpregion);
551d3fecca9Ssthen region_destroy(tmpregion);
552d3fecca9Ssthen }
553ee5153b7Sflorian if((!domain->nsec3 || !domain->nsec3->ds_parent_hash
554ee5153b7Sflorian || !domain->nsec3->ds_parent_hash->node.key)
555d3fecca9Ssthen && nsec3_condition_dshash(domain, zone)) {
556d3fecca9Ssthen nsec3_precompile_domain_ds(db, domain, zone);
557d3fecca9Ssthen }
558d3fecca9Ssthen }
559d3fecca9Ssthen
560d3fecca9Ssthen /* see if nsec3 rrset-deletion triggers need action */
561d3fecca9Ssthen static void
nsec3_delete_rrset_trigger(namedb_type * db,domain_type * domain,zone_type * zone,uint16_t type)562d3fecca9Ssthen nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain,
563d3fecca9Ssthen zone_type* zone, uint16_t type)
564d3fecca9Ssthen {
565d3fecca9Ssthen if(!zone->nsec3_param)
566d3fecca9Ssthen return;
567d3fecca9Ssthen nsec3_rrsets_changed_remove_prehash(domain, zone);
568d3fecca9Ssthen /* for type nsec3, or a delegation, the domain may have become a
569d3fecca9Ssthen * 'normal' domain with its remaining data now */
570d3fecca9Ssthen if(type == TYPE_NSEC3 || type == TYPE_NS || type == TYPE_DS)
571d3fecca9Ssthen nsec3_rrsets_changed_add_prehash(db, domain, zone);
572d3fecca9Ssthen /* for type DNAME or a delegation, obscured data may be revealed */
573d3fecca9Ssthen if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
574d3fecca9Ssthen /* walk over subdomains and check them each */
575d3fecca9Ssthen domain_type *d;
576d3fecca9Ssthen for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
577d3fecca9Ssthen d=domain_next(d)) {
578d3fecca9Ssthen nsec3_rrsets_changed_add_prehash(db, d, zone);
579d3fecca9Ssthen }
580d3fecca9Ssthen }
581d3fecca9Ssthen }
582d3fecca9Ssthen
583d3fecca9Ssthen /* see if nsec3 addition triggers need action */
584d3fecca9Ssthen static void
nsec3_add_rr_trigger(namedb_type * db,rr_type * rr,zone_type * zone)585b71395eaSflorian nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone)
586d3fecca9Ssthen {
587d3fecca9Ssthen /* the RR has been added in full, also to UDB (and thus NSEC3PARAM
588d3fecca9Ssthen * in the udb has been adjusted) */
589d3fecca9Ssthen if(zone->nsec3_param && rr->type == TYPE_NSEC3 &&
590d3fecca9Ssthen (!rr->owner->nsec3 || !rr->owner->nsec3->nsec3_node.key)
591d3fecca9Ssthen && nsec3_rr_uses_params(rr, zone)) {
592063644e9Sflorian if(!zone->nsec3_last) {
593063644e9Sflorian /* all nsec3s have previously been deleted, but
594063644e9Sflorian * we have nsec3 parameters, set it up again from
595063644e9Sflorian * being cleared. */
596063644e9Sflorian nsec3_precompile_newparam(db, zone);
597063644e9Sflorian }
598d3fecca9Ssthen /* added NSEC3 into the chain */
599d3fecca9Ssthen nsec3_precompile_nsec3rr(db, rr->owner, zone);
600d3fecca9Ssthen /* the domain has become an NSEC3-domain, if it was precompiled
601d3fecca9Ssthen * previously, remove that, neatly done in routine above */
602d3fecca9Ssthen nsec3_rrsets_changed_remove_prehash(rr->owner, zone);
603d3fecca9Ssthen /* set this NSEC3 to prehash */
604d3fecca9Ssthen prehash_add(db->domains, rr->owner);
605d3fecca9Ssthen } else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) {
606d3fecca9Ssthen /* see if this means NSEC3 chain can be used */
607b71395eaSflorian nsec3_find_zone_param(db, zone, NULL, 0);
608d3fecca9Ssthen if(!zone->nsec3_param)
609d3fecca9Ssthen return;
610d3fecca9Ssthen nsec3_zone_trees_create(db->region, zone);
611d3fecca9Ssthen nsec3_precompile_newparam(db, zone);
612d3fecca9Ssthen }
613d3fecca9Ssthen }
614d3fecca9Ssthen
615d3fecca9Ssthen /* see if nsec3 rrset-addition triggers need action */
616d3fecca9Ssthen static void
nsec3_add_rrset_trigger(namedb_type * db,domain_type * domain,zone_type * zone,uint16_t type)617d3fecca9Ssthen nsec3_add_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone,
618d3fecca9Ssthen uint16_t type)
619d3fecca9Ssthen {
620d3fecca9Ssthen /* the rrset has been added so we can inspect it */
621d3fecca9Ssthen if(!zone->nsec3_param)
622d3fecca9Ssthen return;
623d3fecca9Ssthen /* because the rrset is added we can check conditions easily.
624d3fecca9Ssthen * check if domain needs to become precompiled now */
625d3fecca9Ssthen nsec3_rrsets_changed_add_prehash(db, domain, zone);
626d3fecca9Ssthen /* if a delegation, it changes from normal name to unhashed referral */
627d3fecca9Ssthen if(type == TYPE_NS || type == TYPE_DS) {
628d3fecca9Ssthen nsec3_rrsets_changed_remove_prehash(domain, zone);
629d3fecca9Ssthen }
630d3fecca9Ssthen /* if delegation or DNAME added, then some RRs may get obscured */
631d3fecca9Ssthen if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
632d3fecca9Ssthen /* walk over subdomains and check them each */
633d3fecca9Ssthen domain_type *d;
634d3fecca9Ssthen for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
635d3fecca9Ssthen d=domain_next(d)) {
636d3fecca9Ssthen nsec3_rrsets_changed_remove_prehash(d, zone);
637d3fecca9Ssthen }
638d3fecca9Ssthen }
639d3fecca9Ssthen }
640d3fecca9Ssthen #endif /* NSEC3 */
641d3fecca9Ssthen
642d3fecca9Ssthen /* fixup usage lower for domain names in the rdata */
643d3fecca9Ssthen static void
rr_lower_usage(namedb_type * db,rr_type * rr)644d3fecca9Ssthen rr_lower_usage(namedb_type* db, rr_type* rr)
645d3fecca9Ssthen {
646d3fecca9Ssthen unsigned i;
647d3fecca9Ssthen for(i=0; i<rr->rdata_count; i++) {
648d3fecca9Ssthen if(rdata_atom_is_domain(rr->type, i)) {
649d3fecca9Ssthen assert(rdata_atom_domain(rr->rdatas[i])->usage > 0);
650d3fecca9Ssthen rdata_atom_domain(rr->rdatas[i])->usage --;
651d3fecca9Ssthen if(rdata_atom_domain(rr->rdatas[i])->usage == 0)
652d3fecca9Ssthen domain_table_deldomain(db,
653d3fecca9Ssthen rdata_atom_domain(rr->rdatas[i]));
654d3fecca9Ssthen }
655d3fecca9Ssthen }
656d3fecca9Ssthen }
657d3fecca9Ssthen
658d3fecca9Ssthen static void
rrset_lower_usage(namedb_type * db,rrset_type * rrset)659d3fecca9Ssthen rrset_lower_usage(namedb_type* db, rrset_type* rrset)
660d3fecca9Ssthen {
661d3fecca9Ssthen unsigned i;
662d3fecca9Ssthen for(i=0; i<rrset->rr_count; i++)
663d3fecca9Ssthen rr_lower_usage(db, &rrset->rrs[i]);
664d3fecca9Ssthen }
665d3fecca9Ssthen
666d3fecca9Ssthen int
delete_RR(namedb_type * db,const dname_type * dname,uint16_t type,uint16_t klass,buffer_type * packet,size_t rdatalen,zone_type * zone,region_type * temp_region,int * softfail)66762ac0c33Sjakob delete_RR(namedb_type* db, const dname_type* dname,
66862ac0c33Sjakob uint16_t type, uint16_t klass,
66962ac0c33Sjakob buffer_type* packet, size_t rdatalen, zone_type *zone,
670b71395eaSflorian region_type* temp_region, int* softfail)
67162ac0c33Sjakob {
67262ac0c33Sjakob domain_type *domain;
67362ac0c33Sjakob rrset_type *rrset;
67462ac0c33Sjakob domain = domain_table_find(db->domains, dname);
67562ac0c33Sjakob if(!domain) {
67662ac0c33Sjakob log_msg(LOG_WARNING, "diff: domain %s does not exist",
67762ac0c33Sjakob dname_to_string(dname,0));
67862ac0c33Sjakob buffer_skip(packet, rdatalen);
679cdb6bbddSbrad *softfail = 1;
68062ac0c33Sjakob return 1; /* not fatal error */
68162ac0c33Sjakob }
68262ac0c33Sjakob rrset = domain_find_rrset(domain, zone, type);
68362ac0c33Sjakob if(!rrset) {
68462ac0c33Sjakob log_msg(LOG_WARNING, "diff: rrset %s does not exist",
68562ac0c33Sjakob dname_to_string(dname,0));
68662ac0c33Sjakob buffer_skip(packet, rdatalen);
687cdb6bbddSbrad *softfail = 1;
68862ac0c33Sjakob return 1; /* not fatal error */
68962ac0c33Sjakob } else {
69062ac0c33Sjakob /* find the RR in the rrset */
69162ac0c33Sjakob domain_table_type *temptable;
69262ac0c33Sjakob rdata_atom_type *rdatas;
69362ac0c33Sjakob ssize_t rdata_num;
69462ac0c33Sjakob int rrnum;
69562ac0c33Sjakob temptable = domain_table_create(temp_region);
69662ac0c33Sjakob /* This will ensure that the dnames in rdata are
69762ac0c33Sjakob * normalized, conform RFC 4035, section 6.2
69862ac0c33Sjakob */
69962ac0c33Sjakob rdata_num = rdata_wireformat_to_rdata_atoms(
70062ac0c33Sjakob temp_region, temptable, type, rdatalen, packet, &rdatas);
70162ac0c33Sjakob if(rdata_num == -1) {
70262ac0c33Sjakob log_msg(LOG_ERR, "diff: bad rdata for %s",
70362ac0c33Sjakob dname_to_string(dname,0));
70462ac0c33Sjakob return 0;
70562ac0c33Sjakob }
706d3fecca9Ssthen rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0);
707cdb6bbddSbrad if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex
708cdb6bbddSbrad && rrset->rr_count != 0)
709cdb6bbddSbrad rrnum = 0; /* replace existing SOA if no match */
71062ac0c33Sjakob if(rrnum == -1) {
7112c1ae072Ssthen log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist",
7122c1ae072Ssthen dname_to_string(dname,0), rrtype_to_string(type));
713cdb6bbddSbrad *softfail = 1;
71462ac0c33Sjakob return 1; /* not fatal error */
71562ac0c33Sjakob }
7160c2b6c02Sjakob #ifdef NSEC3
717d3fecca9Ssthen /* process triggers for RR deletions */
718b71395eaSflorian nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone);
719d3fecca9Ssthen #endif
720d3fecca9Ssthen /* lower usage (possibly deleting other domains, and thus
721d3fecca9Ssthen * invalidating the current RR's domain pointers) */
722d3fecca9Ssthen rr_lower_usage(db, &rrset->rrs[rrnum]);
72362ac0c33Sjakob if(rrset->rr_count == 1) {
72462ac0c33Sjakob /* delete entire rrset */
725d3fecca9Ssthen rrset_delete(db, domain, rrset);
72615ed76cbSbrad /* check if domain is now nonexisting (or parents) */
72703739794Sbrad rrset_zero_nonexist_check(domain, NULL);
728d3fecca9Ssthen #ifdef NSEC3
729d3fecca9Ssthen /* cleanup nsec3 */
730d3fecca9Ssthen nsec3_delete_rrset_trigger(db, domain, zone, type);
731d3fecca9Ssthen #endif
732d3fecca9Ssthen /* see if the domain can be deleted (and inspect parents) */
733d3fecca9Ssthen domain_table_deldomain(db, domain);
73462ac0c33Sjakob } else {
73562ac0c33Sjakob /* swap out the bad RR and decrease the count */
73662ac0c33Sjakob rr_type* rrs_orig = rrset->rrs;
73762ac0c33Sjakob add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]);
73862ac0c33Sjakob if(rrnum < rrset->rr_count-1)
73962ac0c33Sjakob rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1];
74062ac0c33Sjakob memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type));
74162ac0c33Sjakob /* realloc the rrs array one smaller */
7428d8f1862Ssthen rrset->rrs = region_alloc_array_init(db->region, rrs_orig,
7438d8f1862Ssthen (rrset->rr_count-1), sizeof(rr_type));
74462ac0c33Sjakob if(!rrset->rrs) {
74562ac0c33Sjakob log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
74662ac0c33Sjakob exit(1);
74762ac0c33Sjakob }
74862ac0c33Sjakob region_recycle(db->region, rrs_orig,
74962ac0c33Sjakob sizeof(rr_type) * rrset->rr_count);
750d3fecca9Ssthen #ifdef NSEC3
751d3fecca9Ssthen if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
752d3fecca9Ssthen /* fixup nsec3_param pointer to same RR */
753d3fecca9Ssthen assert(zone->nsec3_param >= rrs_orig &&
754d3fecca9Ssthen zone->nsec3_param <=
755d3fecca9Ssthen rrs_orig+rrset->rr_count);
756d3fecca9Ssthen /* last moved to rrnum, others at same index*/
757d3fecca9Ssthen if(zone->nsec3_param == &rrs_orig[
758d3fecca9Ssthen rrset->rr_count-1])
759d3fecca9Ssthen zone->nsec3_param = &rrset->rrs[rrnum];
760d3fecca9Ssthen else
761d3fecca9Ssthen zone->nsec3_param =
762d3fecca9Ssthen (void*)zone->nsec3_param
763d3fecca9Ssthen -(void*)rrs_orig +
764d3fecca9Ssthen (void*)rrset->rrs;
765d3fecca9Ssthen }
766d3fecca9Ssthen #endif /* NSEC3 */
76762ac0c33Sjakob rrset->rr_count --;
768d3fecca9Ssthen #ifdef NSEC3
769d3fecca9Ssthen /* for type nsec3, the domain may have become a
770d3fecca9Ssthen * 'normal' domain with its remaining data now */
771d3fecca9Ssthen if(type == TYPE_NSEC3)
772d3fecca9Ssthen nsec3_rrsets_changed_add_prehash(db, domain,
773d3fecca9Ssthen zone);
774d3fecca9Ssthen #endif /* NSEC3 */
77562ac0c33Sjakob }
77662ac0c33Sjakob }
77762ac0c33Sjakob return 1;
77862ac0c33Sjakob }
77962ac0c33Sjakob
780d3fecca9Ssthen int
add_RR(namedb_type * db,const dname_type * dname,uint16_t type,uint16_t klass,uint32_t ttl,buffer_type * packet,size_t rdatalen,zone_type * zone,int * softfail)78162ac0c33Sjakob add_RR(namedb_type* db, const dname_type* dname,
78262ac0c33Sjakob uint16_t type, uint16_t klass, uint32_t ttl,
783b71395eaSflorian buffer_type* packet, size_t rdatalen, zone_type *zone,
784cdb6bbddSbrad int* softfail)
78562ac0c33Sjakob {
78662ac0c33Sjakob domain_type* domain;
78762ac0c33Sjakob rrset_type* rrset;
78862ac0c33Sjakob rdata_atom_type *rdatas;
78962ac0c33Sjakob rr_type *rrs_old;
79062ac0c33Sjakob ssize_t rdata_num;
79162ac0c33Sjakob int rrnum;
792db7d0d02Sflorian #ifdef NSEC3
793d3fecca9Ssthen int rrset_added = 0;
794db7d0d02Sflorian #endif
79562ac0c33Sjakob domain = domain_table_find(db->domains, dname);
79662ac0c33Sjakob if(!domain) {
79762ac0c33Sjakob /* create the domain */
79862ac0c33Sjakob domain = domain_table_insert(db->domains, dname);
79962ac0c33Sjakob }
80062ac0c33Sjakob rrset = domain_find_rrset(domain, zone, type);
80162ac0c33Sjakob if(!rrset) {
80262ac0c33Sjakob /* create the rrset */
80362ac0c33Sjakob rrset = region_alloc(db->region, sizeof(rrset_type));
80462ac0c33Sjakob if(!rrset) {
80562ac0c33Sjakob log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
80662ac0c33Sjakob exit(1);
80762ac0c33Sjakob }
80862ac0c33Sjakob rrset->zone = zone;
80962ac0c33Sjakob rrset->rrs = 0;
81062ac0c33Sjakob rrset->rr_count = 0;
81162ac0c33Sjakob domain_add_rrset(domain, rrset);
812db7d0d02Sflorian #ifdef NSEC3
813d3fecca9Ssthen rrset_added = 1;
814db7d0d02Sflorian #endif
81562ac0c33Sjakob }
81662ac0c33Sjakob
81762ac0c33Sjakob /* dnames in rdata are normalized, conform RFC 4035,
81862ac0c33Sjakob * Section 6.2
81962ac0c33Sjakob */
82062ac0c33Sjakob rdata_num = rdata_wireformat_to_rdata_atoms(
82162ac0c33Sjakob db->region, db->domains, type, rdatalen, packet, &rdatas);
82262ac0c33Sjakob if(rdata_num == -1) {
82362ac0c33Sjakob log_msg(LOG_ERR, "diff: bad rdata for %s",
82462ac0c33Sjakob dname_to_string(dname,0));
82562ac0c33Sjakob return 0;
82662ac0c33Sjakob }
827d3fecca9Ssthen rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 1);
82862ac0c33Sjakob if(rrnum != -1) {
8292c1ae072Ssthen DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists",
8302c1ae072Ssthen dname_to_string(dname,0), rrtype_to_string(type)));
83162ac0c33Sjakob /* ignore already existing RR: lenient accepting of messages */
832cdb6bbddSbrad *softfail = 1;
83362ac0c33Sjakob return 1;
83462ac0c33Sjakob }
8358d8f1862Ssthen if(rrset->rr_count == 65535) {
8368d8f1862Ssthen log_msg(LOG_ERR, "diff: too many RRs at %s",
8378d8f1862Ssthen dname_to_string(dname,0));
8388d8f1862Ssthen return 0;
8398d8f1862Ssthen }
84062ac0c33Sjakob
84162ac0c33Sjakob /* re-alloc the rrs and add the new */
84262ac0c33Sjakob rrs_old = rrset->rrs;
8438d8f1862Ssthen rrset->rrs = region_alloc_array(db->region,
8448d8f1862Ssthen (rrset->rr_count+1), sizeof(rr_type));
84562ac0c33Sjakob if(!rrset->rrs) {
84662ac0c33Sjakob log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
84762ac0c33Sjakob exit(1);
84862ac0c33Sjakob }
84962ac0c33Sjakob if(rrs_old)
85062ac0c33Sjakob memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type));
85162ac0c33Sjakob region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count);
85262ac0c33Sjakob rrset->rr_count ++;
85362ac0c33Sjakob
85462ac0c33Sjakob rrset->rrs[rrset->rr_count - 1].owner = domain;
85562ac0c33Sjakob rrset->rrs[rrset->rr_count - 1].rdatas = rdatas;
85662ac0c33Sjakob rrset->rrs[rrset->rr_count - 1].ttl = ttl;
85762ac0c33Sjakob rrset->rrs[rrset->rr_count - 1].type = type;
85862ac0c33Sjakob rrset->rrs[rrset->rr_count - 1].klass = klass;
85962ac0c33Sjakob rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num;
86062ac0c33Sjakob
86162ac0c33Sjakob /* see if it is a SOA */
86262ac0c33Sjakob if(domain == zone->apex) {
863d3fecca9Ssthen apex_rrset_checks(db, rrset, domain);
8640c2b6c02Sjakob #ifdef NSEC3
865d3fecca9Ssthen if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
866d3fecca9Ssthen /* the pointer just changed, fix it up to point
867d3fecca9Ssthen * to the same record */
868d3fecca9Ssthen assert(zone->nsec3_param >= rrs_old &&
869d3fecca9Ssthen zone->nsec3_param < rrs_old+rrset->rr_count);
870d3fecca9Ssthen /* in this order to make sure no overflow/underflow*/
871d3fecca9Ssthen zone->nsec3_param = (void*)zone->nsec3_param -
872d3fecca9Ssthen (void*)rrs_old + (void*)rrset->rrs;
8730c2b6c02Sjakob }
8740c2b6c02Sjakob #endif /* NSEC3 */
875d3fecca9Ssthen }
8760c2b6c02Sjakob
877d3fecca9Ssthen #ifdef NSEC3
878d3fecca9Ssthen if(rrset_added) {
879d3fecca9Ssthen domain_type* p = domain->parent;
880d3fecca9Ssthen nsec3_add_rrset_trigger(db, domain, zone, type);
881d3fecca9Ssthen /* go up and process (possibly created) empty nonterminals,
882d3fecca9Ssthen * until we hit the apex or root */
883d3fecca9Ssthen while(p && p->rrsets == NULL && !p->is_apex) {
884d3fecca9Ssthen nsec3_rrsets_changed_add_prehash(db, p, zone);
885d3fecca9Ssthen p = p->parent;
886d3fecca9Ssthen }
887d3fecca9Ssthen }
888b71395eaSflorian nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone);
889d3fecca9Ssthen #endif /* NSEC3 */
89062ac0c33Sjakob return 1;
89162ac0c33Sjakob }
89262ac0c33Sjakob
89362ac0c33Sjakob static zone_type*
find_or_create_zone(namedb_type * db,const dname_type * zone_name,struct nsd_options * opt,const char * zstr,const char * patname)894d3fecca9Ssthen find_or_create_zone(namedb_type* db, const dname_type* zone_name,
895fe5fe5f6Sflorian struct nsd_options* opt, const char* zstr, const char* patname)
89662ac0c33Sjakob {
89762ac0c33Sjakob zone_type* zone;
898fe5fe5f6Sflorian struct zone_options* zopt;
899d3fecca9Ssthen zone = namedb_find_zone(db, zone_name);
90062ac0c33Sjakob if(zone) {
90162ac0c33Sjakob return zone;
90262ac0c33Sjakob }
903d3fecca9Ssthen zopt = zone_options_find(opt, zone_name);
904d3fecca9Ssthen if(!zopt) {
905d3fecca9Ssthen /* if _implicit_ then insert as _part_of_config */
906d3fecca9Ssthen if(strncmp(patname, PATTERN_IMPLICIT_MARKER,
907d3fecca9Ssthen strlen(PATTERN_IMPLICIT_MARKER)) == 0) {
908d3fecca9Ssthen zopt = zone_options_create(opt->region);
909d3fecca9Ssthen if(!zopt) return 0;
910d3fecca9Ssthen zopt->part_of_config = 1;
911d3fecca9Ssthen zopt->name = region_strdup(opt->region, zstr);
912d3fecca9Ssthen zopt->pattern = pattern_options_find(opt, patname);
913d3fecca9Ssthen if(!zopt->name || !zopt->pattern) return 0;
914d3fecca9Ssthen if(!nsd_options_insert_zone(opt, zopt)) {
915d3fecca9Ssthen log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
916d3fecca9Ssthen "pattern %s", zstr, patname);
91762ac0c33Sjakob }
918d3fecca9Ssthen } else {
919d3fecca9Ssthen /* create zone : presumably already added to zonelist
920d3fecca9Ssthen * by xfrd, who wrote the AXFR or IXFR to disk, so we only
921d3fecca9Ssthen * need to add it to our config.
922d3fecca9Ssthen * This process does not need linesize and offset zonelist */
923*bf87c3c0Sflorian zopt = zone_list_zone_insert(opt, zstr, patname);
924d3fecca9Ssthen if(!zopt)
92538a044fdSsthen return 0;
92638a044fdSsthen }
92762ac0c33Sjakob }
928d3fecca9Ssthen zone = namedb_zone_create(db, zone_name, zopt);
92962ac0c33Sjakob return zone;
93062ac0c33Sjakob }
93162ac0c33Sjakob
932d3fecca9Ssthen void
delete_zone_rrs(namedb_type * db,zone_type * zone)93362ac0c33Sjakob delete_zone_rrs(namedb_type* db, zone_type* zone)
93462ac0c33Sjakob {
93562ac0c33Sjakob rrset_type *rrset;
936d3fecca9Ssthen domain_type *domain = zone->apex, *next;
93715ed76cbSbrad int nonexist_check = 0;
93862ac0c33Sjakob /* go through entire tree below the zone apex (incl subzones) */
939d3fecca9Ssthen while(domain && domain_is_subdomain(domain, zone->apex))
94062ac0c33Sjakob {
94162ac0c33Sjakob DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s",
942d3fecca9Ssthen domain_to_string(domain)));
94362ac0c33Sjakob /* delete all rrsets of the zone */
94462ac0c33Sjakob while((rrset = domain_find_any_rrset(domain, zone))) {
945d3fecca9Ssthen /* lower usage can delete other domains */
946d3fecca9Ssthen rrset_lower_usage(db, rrset);
947d3fecca9Ssthen /* rrset del does not delete our domain(yet) */
948d3fecca9Ssthen rrset_delete(db, domain, rrset);
94915ed76cbSbrad /* no rrset_zero_nonexist_check, do that later */
95015ed76cbSbrad if(domain->rrsets == 0)
95115ed76cbSbrad nonexist_check = 1;
95262ac0c33Sjakob }
953d3fecca9Ssthen /* the delete upcoming could delete parents, but nothing next
954d3fecca9Ssthen * or after the domain so store next ptr */
955044f85deSsthen next = domain_next(domain);
956d3fecca9Ssthen /* see if the domain can be deleted (and inspect parents) */
957d3fecca9Ssthen domain_table_deldomain(db, domain);
958044f85deSsthen domain = next;
95962ac0c33Sjakob }
96062ac0c33Sjakob
96103739794Sbrad /* check if data deletions have created nonexisting domain entries,
96215ed76cbSbrad * but after deleting domains so the checks are faster */
96315ed76cbSbrad if(nonexist_check) {
96403739794Sbrad domain_type* ce = NULL; /* for speeding up has_data_below */
96515ed76cbSbrad DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check"));
96615ed76cbSbrad domain = zone->apex;
96715ed76cbSbrad while(domain && domain_is_subdomain(domain, zone->apex))
96815ed76cbSbrad {
96915ed76cbSbrad /* the interesting domains should be existing==1
97015ed76cbSbrad * and rrsets==0, speeding up out processing of
97115ed76cbSbrad * sub-zones, since we only spuriously check empty
97215ed76cbSbrad * nonterminals */
97315ed76cbSbrad if(domain->is_existing)
97403739794Sbrad ce = rrset_zero_nonexist_check(domain, ce);
97515ed76cbSbrad domain = domain_next(domain);
97615ed76cbSbrad }
97715ed76cbSbrad }
97815ed76cbSbrad
97962ac0c33Sjakob DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes",
98062ac0c33Sjakob (unsigned long) region_get_recycle_size(db->region)));
98162ac0c33Sjakob #ifndef NDEBUG
98215ed76cbSbrad if(nsd_debug_level >= 2)
98362ac0c33Sjakob region_log_stats(db->region);
98462ac0c33Sjakob #endif
98562ac0c33Sjakob
98662ac0c33Sjakob assert(zone->soa_rrset == 0);
987d3fecca9Ssthen /* keep zone->soa_nx_rrset alloced: it is reused */
98862ac0c33Sjakob assert(zone->ns_rrset == 0);
98962ac0c33Sjakob assert(zone->is_secure == 0);
990044f85deSsthen }
991044f85deSsthen
9920c2b6c02Sjakob /* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */
99362ac0c33Sjakob static int
apply_ixfr(nsd_type * nsd,FILE * in,uint32_t serialno,uint32_t seq_nr,uint32_t seq_total,int * is_axfr,int * delete_mode,int * rr_count,struct zone * zone,int * bytes,int * softfail,struct ixfr_store * ixfr_store)994b71395eaSflorian apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno,
995b71395eaSflorian uint32_t seq_nr, uint32_t seq_total,
99662ac0c33Sjakob int* is_axfr, int* delete_mode, int* rr_count,
997b71395eaSflorian struct zone* zone, int* bytes,
9984564029fSflorian int* softfail, struct ixfr_store* ixfr_store)
99962ac0c33Sjakob {
1000d3fecca9Ssthen uint32_t msglen, checklen, pkttype;
1001b71395eaSflorian int qcount, ancount;
100262ac0c33Sjakob buffer_type* packet;
100362ac0c33Sjakob region_type* region;
100462ac0c33Sjakob
1005d3fecca9Ssthen /* note that errors could not really happen due to format of the
1006d3fecca9Ssthen * packet since xfrd has checked all dnames and RRs before commit,
1007d3fecca9Ssthen * this is why the errors are fatal (exit process), it must be
1008d3fecca9Ssthen * something internal or a bad disk or something. */
1009d3fecca9Ssthen
101062ac0c33Sjakob /* read ixfr packet RRs and apply to in memory db */
1011d3fecca9Ssthen if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_XXFR) {
101262ac0c33Sjakob log_msg(LOG_ERR, "could not read type or wrong type");
101362ac0c33Sjakob return 0;
101462ac0c33Sjakob }
101562ac0c33Sjakob
1016d3fecca9Ssthen if(!diff_read_32(in, &msglen)) {
101762ac0c33Sjakob log_msg(LOG_ERR, "could not read len");
101862ac0c33Sjakob return 0;
101962ac0c33Sjakob }
102062ac0c33Sjakob
1021d3fecca9Ssthen if(msglen < QHEADERSZ) {
102262ac0c33Sjakob log_msg(LOG_ERR, "msg too short");
102362ac0c33Sjakob return 0;
102462ac0c33Sjakob }
102562ac0c33Sjakob
102662ac0c33Sjakob region = region_create(xalloc, free);
102762ac0c33Sjakob if(!region) {
102862ac0c33Sjakob log_msg(LOG_ERR, "out of memory");
102962ac0c33Sjakob return 0;
103062ac0c33Sjakob }
103162ac0c33Sjakob packet = buffer_create(region, QIOBUFSZ);
103262ac0c33Sjakob if(msglen > QIOBUFSZ) {
103362ac0c33Sjakob log_msg(LOG_ERR, "msg too long");
103462ac0c33Sjakob region_destroy(region);
103562ac0c33Sjakob return 0;
103662ac0c33Sjakob }
103762ac0c33Sjakob buffer_clear(packet);
103862ac0c33Sjakob if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
103962ac0c33Sjakob log_msg(LOG_ERR, "short fread: %s", strerror(errno));
104062ac0c33Sjakob region_destroy(region);
104162ac0c33Sjakob return 0;
104262ac0c33Sjakob }
104362ac0c33Sjakob buffer_set_limit(packet, msglen);
104462ac0c33Sjakob
1045d3fecca9Ssthen /* see if check on data fails: checks that we are not reading
1046d3fecca9Ssthen * random garbage */
1047d3fecca9Ssthen if(!diff_read_32(in, &checklen) || checklen != msglen) {
1048d3fecca9Ssthen log_msg(LOG_ERR, "transfer part has incorrect checkvalue");
1049d3fecca9Ssthen return 0;
1050d3fecca9Ssthen }
1051d3fecca9Ssthen *bytes += msglen;
1052d3fecca9Ssthen
105362ac0c33Sjakob /* only answer section is really used, question, additional and
105462ac0c33Sjakob authority section RRs are skipped */
105562ac0c33Sjakob qcount = QDCOUNT(packet);
105662ac0c33Sjakob ancount = ANCOUNT(packet);
105762ac0c33Sjakob buffer_skip(packet, QHEADERSZ);
1058308d2509Sflorian /* qcount should be 0 or 1 really, ancount limited by 64k packet */
1059308d2509Sflorian if(qcount > 64 || ancount > 65530) {
1060308d2509Sflorian log_msg(LOG_ERR, "RR count impossibly high");
1061308d2509Sflorian region_destroy(region);
1062308d2509Sflorian return 0;
1063308d2509Sflorian }
106462ac0c33Sjakob
106562ac0c33Sjakob /* skip queries */
1066b71395eaSflorian for(int i=0; i < qcount; ++i) {
106762ac0c33Sjakob if(!packet_skip_rr(packet, 1)) {
106862ac0c33Sjakob log_msg(LOG_ERR, "bad RR in question section");
106962ac0c33Sjakob region_destroy(region);
107062ac0c33Sjakob return 0;
107162ac0c33Sjakob }
1072b71395eaSflorian }
107362ac0c33Sjakob
107462ac0c33Sjakob DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "diff: started packet for zone %s",
1075b71395eaSflorian domain_to_string(zone->apex)));
107662ac0c33Sjakob
1077b71395eaSflorian for(int i=0; i < ancount; ++i, ++(*rr_count)) {
1078b71395eaSflorian const dname_type *owner;
1079b71395eaSflorian uint16_t type, klass, rrlen;
108062ac0c33Sjakob uint32_t ttl;
108162ac0c33Sjakob
1082b71395eaSflorian owner = dname_make_from_packet(region, packet, 1, 1);
1083b71395eaSflorian if(!owner) {
108462ac0c33Sjakob log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count);
108562ac0c33Sjakob region_destroy(region);
108662ac0c33Sjakob return 0;
108762ac0c33Sjakob }
108862ac0c33Sjakob if(!buffer_available(packet, 10)) {
108962ac0c33Sjakob log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count);
109062ac0c33Sjakob region_destroy(region);
109162ac0c33Sjakob return 0;
109262ac0c33Sjakob }
109362ac0c33Sjakob type = buffer_read_u16(packet);
109462ac0c33Sjakob klass = buffer_read_u16(packet);
109562ac0c33Sjakob ttl = buffer_read_u32(packet);
109662ac0c33Sjakob rrlen = buffer_read_u16(packet);
109762ac0c33Sjakob if(!buffer_available(packet, rrlen)) {
109862ac0c33Sjakob log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d",
109962ac0c33Sjakob *rr_count, rrlen, (int)buffer_remaining(packet));
110062ac0c33Sjakob region_destroy(region);
110162ac0c33Sjakob return 0;
110262ac0c33Sjakob }
110362ac0c33Sjakob
1104b71395eaSflorian DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d",
1105b71395eaSflorian domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode));
1106b71395eaSflorian
1107b71395eaSflorian if (type == TYPE_SOA) {
1108b71395eaSflorian size_t position;
1109b71395eaSflorian uint32_t serial;
1110b71395eaSflorian position = buffer_position(packet);
111162ac0c33Sjakob if (!packet_skip_dname(packet) ||
111262ac0c33Sjakob !packet_skip_dname(packet) ||
111362ac0c33Sjakob buffer_remaining(packet) < sizeof(uint32_t) * 5)
111462ac0c33Sjakob {
111562ac0c33Sjakob log_msg(LOG_ERR, "bad xfr SOA RR formerr.");
111662ac0c33Sjakob region_destroy(region);
111762ac0c33Sjakob return 0;
111862ac0c33Sjakob }
1119b71395eaSflorian
1120b71395eaSflorian serial = buffer_read_u32(packet);
1121b71395eaSflorian buffer_set_position(packet, position);
1122b71395eaSflorian
1123b71395eaSflorian /* first RR: check if SOA and correct zone & serialno */
1124b71395eaSflorian if (*rr_count == 0) {
1125b71395eaSflorian assert(!*is_axfr);
1126b71395eaSflorian assert(!*delete_mode);
1127b71395eaSflorian if (klass != CLASS_IN) {
1128b71395eaSflorian log_msg(LOG_ERR, "first RR not SOA IN");
1129b71395eaSflorian region_destroy(region);
1130b71395eaSflorian return 0;
113162ac0c33Sjakob }
1132b71395eaSflorian if(dname_compare(domain_dname(zone->apex), owner) != 0) {
1133b71395eaSflorian log_msg(LOG_ERR, "SOA dname not equal to zone %s",
1134b71395eaSflorian domain_to_string(zone->apex));
1135b71395eaSflorian region_destroy(region);
1136b71395eaSflorian return 0;
1137b71395eaSflorian }
1138b71395eaSflorian if(serial != serialno) {
1139b71395eaSflorian log_msg(LOG_ERR, "SOA serial %u different from commit %u",
1140b71395eaSflorian (unsigned)serial, (unsigned)serialno);
1141b71395eaSflorian region_destroy(region);
1142b71395eaSflorian return 0;
1143b71395eaSflorian }
1144b71395eaSflorian buffer_skip(packet, rrlen);
1145b71395eaSflorian
1146b71395eaSflorian if(ixfr_store)
1147b71395eaSflorian ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen);
1148b71395eaSflorian
1149b71395eaSflorian continue;
1150b71395eaSflorian } else if (*rr_count == 1) {
1151b71395eaSflorian assert(!*is_axfr);
1152b71395eaSflorian assert(!*delete_mode);
1153b71395eaSflorian /* if the serial no of the SOA equals the serialno, then AXFR */
1154b71395eaSflorian if (serial == serialno)
1155b71395eaSflorian goto axfr;
1156b71395eaSflorian *delete_mode = 1;
11570c2b6c02Sjakob /* must have stuff in memory for a successful IXFR,
11580c2b6c02Sjakob * the serial number of the SOA has been checked
11590c2b6c02Sjakob * previously (by check_for_bad_serial) if it exists */
1160b71395eaSflorian if(!domain_find_rrset(zone->apex, zone, TYPE_SOA)) {
1161cdb6bbddSbrad log_msg(LOG_ERR, "%s SOA serial %u is not "
1162b71395eaSflorian "in memory, skip IXFR", domain_to_string(zone->apex), serialno);
11630c2b6c02Sjakob region_destroy(region);
11640c2b6c02Sjakob /* break out and stop the IXFR, ignore it */
11650c2b6c02Sjakob return 2;
11660c2b6c02Sjakob }
1167b71395eaSflorian
1168b71395eaSflorian if(ixfr_store)
1169b71395eaSflorian ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen);
1170b71395eaSflorian } else if (!*is_axfr) {
1171b71395eaSflorian /* do not delete final SOA RR for IXFR */
1172b71395eaSflorian if (i == ancount - 1 && seq_nr == seq_total - 1) {
1173b71395eaSflorian if (ixfr_store) {
1174b71395eaSflorian ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen);
117562ac0c33Sjakob }
1176b71395eaSflorian *delete_mode = 0;
1177b71395eaSflorian buffer_skip(packet, rrlen);
1178b71395eaSflorian continue;
1179b71395eaSflorian } else
1180b71395eaSflorian *delete_mode = !*delete_mode;
1181b71395eaSflorian
1182b71395eaSflorian if (ixfr_store && *delete_mode) {
1183b71395eaSflorian ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen);
1184b71395eaSflorian ixfr_store_finish(ixfr_store, nsd, NULL);
1185b71395eaSflorian ixfr_store_start(zone, ixfr_store);
1186b71395eaSflorian ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen);
1187b71395eaSflorian }
118862ac0c33Sjakob /* switch from delete-part to add-part and back again,
118962ac0c33Sjakob just before soa - so it gets deleted and added too */
119062ac0c33Sjakob DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d",
1191b71395eaSflorian domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode));
119262ac0c33Sjakob }
1193b71395eaSflorian } else {
1194b71395eaSflorian if (*rr_count == 0) {
1195b71395eaSflorian log_msg(LOG_ERR, "first RR not SOA IN");
1196b71395eaSflorian region_destroy(region);
1197b71395eaSflorian return 0;
1198b71395eaSflorian /* second RR: if not SOA: this is an AXFR; delete all zone contents */
1199b71395eaSflorian } else if (*rr_count == 1) {
1200b71395eaSflorian axfr:
1201b71395eaSflorian *is_axfr = 1;
1202b71395eaSflorian #ifdef NSEC3
1203b71395eaSflorian nsec3_clear_precompile(nsd->db, zone);
1204b71395eaSflorian zone->nsec3_param = NULL;
1205b71395eaSflorian #endif
1206b71395eaSflorian delete_zone_rrs(nsd->db, zone);
1207b71395eaSflorian if(ixfr_store) {
1208b71395eaSflorian ixfr_store_cancel(ixfr_store);
1209b71395eaSflorian ixfr_store_delixfrs(zone);
1210b71395eaSflorian }
1211b71395eaSflorian DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d",
1212b71395eaSflorian domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode));
1213b71395eaSflorian }
1214b71395eaSflorian }
1215b71395eaSflorian
121662ac0c33Sjakob if(type == TYPE_TSIG || type == TYPE_OPT) {
121762ac0c33Sjakob /* ignore pseudo RRs */
121862ac0c33Sjakob buffer_skip(packet, rrlen);
121962ac0c33Sjakob continue;
122062ac0c33Sjakob }
122162ac0c33Sjakob
122262ac0c33Sjakob DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s",
122362ac0c33Sjakob *delete_mode?"del":"add",
1224b71395eaSflorian dname_to_string(owner, 0), rrtype_to_string(type)));
122562ac0c33Sjakob if(*delete_mode) {
1226b71395eaSflorian assert(!*is_axfr);
122762ac0c33Sjakob /* delete this rr */
12284564029fSflorian if(ixfr_store)
1229b71395eaSflorian ixfr_store_delrr(ixfr_store, owner, type,
12304564029fSflorian klass, ttl, packet, rrlen, region);
1231b71395eaSflorian if(!delete_RR(nsd->db, owner, type, klass, packet,
1232b71395eaSflorian rrlen, zone, region, softfail)) {
123362ac0c33Sjakob region_destroy(region);
123462ac0c33Sjakob return 0;
123562ac0c33Sjakob }
1236b71395eaSflorian } else {
123762ac0c33Sjakob /* add this rr */
12384564029fSflorian if(ixfr_store)
1239b71395eaSflorian ixfr_store_addrr(ixfr_store, owner, type,
12404564029fSflorian klass, ttl, packet, rrlen, region);
1241b71395eaSflorian if(!add_RR(nsd->db, owner, type, klass, ttl, packet,
1242b71395eaSflorian rrlen, zone, softfail)) {
124362ac0c33Sjakob region_destroy(region);
124462ac0c33Sjakob return 0;
124562ac0c33Sjakob }
124662ac0c33Sjakob }
124762ac0c33Sjakob }
124862ac0c33Sjakob region_destroy(region);
124962ac0c33Sjakob return 1;
125062ac0c33Sjakob }
125162ac0c33Sjakob
125262ac0c33Sjakob static int
check_for_bad_serial(namedb_type * db,const char * zone_str,uint32_t old_serial)125362ac0c33Sjakob check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial)
125462ac0c33Sjakob {
125562ac0c33Sjakob /* see if serial OK with in-memory serial */
125662ac0c33Sjakob domain_type* domain;
125762ac0c33Sjakob region_type* region = region_create(xalloc, free);
125862ac0c33Sjakob const dname_type* zone_name = dname_parse(region, zone_str);
125962ac0c33Sjakob zone_type* zone = 0;
126062ac0c33Sjakob domain = domain_table_find(db->domains, zone_name);
126162ac0c33Sjakob if(domain)
1262cbbc2d6cSbrad zone = domain_find_zone(db, domain);
126362ac0c33Sjakob if(zone && zone->apex == domain && zone->soa_rrset && old_serial)
126462ac0c33Sjakob {
126562ac0c33Sjakob uint32_t memserial;
126662ac0c33Sjakob memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]),
126762ac0c33Sjakob sizeof(uint32_t));
126862ac0c33Sjakob if(old_serial != ntohl(memserial)) {
126962ac0c33Sjakob region_destroy(region);
127062ac0c33Sjakob return 1;
127162ac0c33Sjakob }
127262ac0c33Sjakob }
127362ac0c33Sjakob region_destroy(region);
127462ac0c33Sjakob return 0;
127562ac0c33Sjakob }
127662ac0c33Sjakob
1277*bf87c3c0Sflorian int
apply_ixfr_for_zone(nsd_type * nsd,zone_type * zone,FILE * in,struct nsd_options * ATTR_UNUSED (opt),udb_base * taskudb,udb_ptr * last_task,uint32_t xfrfilenr)1278b71395eaSflorian apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in,
1279b71395eaSflorian struct nsd_options* ATTR_UNUSED(opt), udb_base* taskudb, udb_ptr* last_task,
1280d3fecca9Ssthen uint32_t xfrfilenr)
128162ac0c33Sjakob {
128262ac0c33Sjakob char zone_buf[3072];
128362ac0c33Sjakob char log_buf[5120];
1284d3fecca9Ssthen char patname_buf[2048];
1285d3fecca9Ssthen
1286d3fecca9Ssthen uint32_t old_serial, new_serial, num_parts, type;
1287d3fecca9Ssthen uint64_t time_end_0, time_start_0;
1288d3fecca9Ssthen uint32_t time_end_1, time_start_1;
128962ac0c33Sjakob uint8_t committed;
129062ac0c33Sjakob uint32_t i;
1291d3fecca9Ssthen int num_bytes = 0;
12923f21e8ccSflorian (void)last_task;
1293b71395eaSflorian assert(zone);
129462ac0c33Sjakob
129562ac0c33Sjakob /* read zone name and serial */
1296d3fecca9Ssthen if(!diff_read_32(in, &type)) {
1297d3fecca9Ssthen log_msg(LOG_ERR, "diff file too short");
1298d3fecca9Ssthen return 0;
1299d3fecca9Ssthen }
1300d3fecca9Ssthen if(type != DIFF_PART_XFRF) {
1301d3fecca9Ssthen log_msg(LOG_ERR, "xfr file has wrong format");
1302d3fecca9Ssthen return 0;
1303d3fecca9Ssthen
1304d3fecca9Ssthen }
1305d3fecca9Ssthen /* committed and num_parts are first because they need to be
1306d3fecca9Ssthen * updated once the rest is written. The log buf is not certain
1307d3fecca9Ssthen * until its done, so at end of file. The patname is in case a
1308d3fecca9Ssthen * new zone is created, we know what the options-pattern is */
1309d3fecca9Ssthen if(!diff_read_8(in, &committed) ||
1310d3fecca9Ssthen !diff_read_32(in, &num_parts) ||
1311d3fecca9Ssthen !diff_read_64(in, &time_end_0) ||
1312d3fecca9Ssthen !diff_read_32(in, &time_end_1) ||
131362ac0c33Sjakob !diff_read_32(in, &old_serial) ||
131462ac0c33Sjakob !diff_read_32(in, &new_serial) ||
1315d3fecca9Ssthen !diff_read_64(in, &time_start_0) ||
1316d3fecca9Ssthen !diff_read_32(in, &time_start_1) ||
1317d3fecca9Ssthen !diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
1318d3fecca9Ssthen !diff_read_str(in, patname_buf, sizeof(patname_buf))) {
131962ac0c33Sjakob log_msg(LOG_ERR, "diff file bad commit part");
132062ac0c33Sjakob return 0;
132162ac0c33Sjakob }
132262ac0c33Sjakob
132362ac0c33Sjakob /* has been read in completely */
1324b71395eaSflorian if(strcmp(zone_buf, domain_to_string(zone->apex)) != 0) {
1325d3fecca9Ssthen log_msg(LOG_ERR, "file %s does not match task %s",
1326b71395eaSflorian zone_buf, domain_to_string(zone->apex));
1327d3fecca9Ssthen return 0;
132862ac0c33Sjakob }
13293f21e8ccSflorian switch(committed) {
13303f21e8ccSflorian case DIFF_NOT_COMMITTED:
1331d3fecca9Ssthen log_msg(LOG_ERR, "diff file %s was not committed", zone_buf);
1332d3fecca9Ssthen return 0;
13333f21e8ccSflorian case DIFF_CORRUPT:
13343f21e8ccSflorian log_msg(LOG_ERR, "diff file %s was corrupt", zone_buf);
13353f21e8ccSflorian return 0;
13363f21e8ccSflorian case DIFF_INCONSISTENT:
13373f21e8ccSflorian log_msg(LOG_ERR, "diff file %s was inconsistent", zone_buf);
13383f21e8ccSflorian return 0;
13393f21e8ccSflorian case DIFF_VERIFIED:
13403f21e8ccSflorian log_msg(LOG_INFO, "diff file %s already verified", zone_buf);
13413f21e8ccSflorian break;
13423f21e8ccSflorian default:
13433f21e8ccSflorian break;
1344d3fecca9Ssthen }
1345d3fecca9Ssthen if(num_parts == 0) {
1346d3fecca9Ssthen log_msg(LOG_ERR, "diff file %s was not completed", zone_buf);
1347d3fecca9Ssthen return 0;
1348d3fecca9Ssthen }
1349d3fecca9Ssthen if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) {
135062ac0c33Sjakob DEBUG(DEBUG_XFRD,1, (LOG_ERR,
135162ac0c33Sjakob "skipping diff file commit with bad serial"));
1352*bf87c3c0Sflorian return -2; /* Success in "main" process, failure in "xfrd" */
135362ac0c33Sjakob }
135462ac0c33Sjakob
1355b71395eaSflorian if(!zone->is_skipped)
135662ac0c33Sjakob {
1357cdb6bbddSbrad int is_axfr=0, delete_mode=0, rr_count=0, softfail=0;
13584564029fSflorian struct ixfr_store* ixfr_store = NULL, ixfr_store_mem;
135962ac0c33Sjakob
1360d3fecca9Ssthen DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf));
1361b71395eaSflorian if(zone_is_ixfr_enabled(zone))
1362b71395eaSflorian ixfr_store = ixfr_store_start(zone, &ixfr_store_mem);
1363d3fecca9Ssthen /* read and apply all of the parts */
136462ac0c33Sjakob for(i=0; i<num_parts; i++) {
13650c2b6c02Sjakob int ret;
136662ac0c33Sjakob DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i));
1367b71395eaSflorian ret = apply_ixfr(nsd, in, new_serial,
1368d3fecca9Ssthen i, num_parts, &is_axfr, &delete_mode,
1369b71395eaSflorian &rr_count, zone,
1370b71395eaSflorian &num_bytes, &softfail, ixfr_store);
13710c2b6c02Sjakob if(ret == 0) {
1372d3fecca9Ssthen log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf);
13733f21e8ccSflorian diff_update_commit(
13743f21e8ccSflorian zone_buf, DIFF_CORRUPT, nsd, xfrfilenr);
1375d3fecca9Ssthen /* the udb is still dirty, it is bad */
1376*bf87c3c0Sflorian return -1; /* Fatal! */
13770c2b6c02Sjakob } else if(ret == 2) {
13780c2b6c02Sjakob break;
137962ac0c33Sjakob }
138062ac0c33Sjakob }
1381d3fecca9Ssthen /* read the final log_str: but do not fail on it */
1382d3fecca9Ssthen if(!diff_read_str(in, log_buf, sizeof(log_buf))) {
1383d3fecca9Ssthen log_msg(LOG_ERR, "could not read log for transfer %s",
1384d3fecca9Ssthen zone_buf);
1385d3fecca9Ssthen snprintf(log_buf, sizeof(log_buf), "error reading log");
1386d3fecca9Ssthen }
13870c2b6c02Sjakob #ifdef NSEC3
1388b71395eaSflorian prehash_zone(nsd->db, zone);
13890c2b6c02Sjakob #endif /* NSEC3 */
1390b71395eaSflorian zone->is_changed = 1;
1391b71395eaSflorian zone->is_updated = 1;
1392b71395eaSflorian zone->is_checked = (committed == DIFF_VERIFIED);
1393b71395eaSflorian zone->mtime.tv_sec = time_end_0;
1394b71395eaSflorian zone->mtime.tv_nsec = time_end_1*1000;
1395b71395eaSflorian if(zone->logstr)
1396b71395eaSflorian region_recycle(nsd->db->region, zone->logstr,
1397b71395eaSflorian strlen(zone->logstr)+1);
1398b71395eaSflorian zone->logstr = region_strdup(nsd->db->region, log_buf);
1399b71395eaSflorian if(zone->filename)
1400b71395eaSflorian region_recycle(nsd->db->region, zone->filename,
1401b71395eaSflorian strlen(zone->filename)+1);
1402b71395eaSflorian zone->filename = NULL;
1403cdb6bbddSbrad if(softfail && taskudb && !is_axfr) {
1404cdb6bbddSbrad log_msg(LOG_ERR, "Failed to apply IXFR cleanly "
1405cdb6bbddSbrad "(deletes nonexistent RRs, adds existing RRs). "
1406*bf87c3c0Sflorian "Zone %s contents is different from primary, "
1407cdb6bbddSbrad "starting AXFR. Transfer %s", zone_buf, log_buf);
1408cdb6bbddSbrad /* add/del failures in IXFR, get an AXFR */
14093f21e8ccSflorian diff_update_commit(
14103f21e8ccSflorian zone_buf, DIFF_INCONSISTENT, nsd, xfrfilenr);
1411*bf87c3c0Sflorian return -1; /* Fatal! */
1412cdb6bbddSbrad }
14134564029fSflorian if(ixfr_store)
14144564029fSflorian ixfr_store_finish(ixfr_store, nsd, log_buf);
14150c2b6c02Sjakob
1416d3fecca9Ssthen if(1 <= verbosity) {
1417d3fecca9Ssthen double elapsed = (double)(time_end_0 - time_start_0)+
1418d3fecca9Ssthen (double)((double)time_end_1
1419d3fecca9Ssthen -(double)time_start_1) / 1000000.0;
14208d8f1862Ssthen VERBOSITY(1, (LOG_INFO, "zone %s %s of %d bytes in %g seconds",
1421d3fecca9Ssthen zone_buf, log_buf, num_bytes, elapsed));
142262ac0c33Sjakob }
142362ac0c33Sjakob }
142462ac0c33Sjakob else {
1425de04d855Ssthen DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", zone_buf));
142662ac0c33Sjakob }
142762ac0c33Sjakob return 1;
142862ac0c33Sjakob }
142962ac0c33Sjakob
udb_task_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)1430b71395eaSflorian static void udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void *arg)
1431b71395eaSflorian {
1432b71395eaSflorian struct task_list_d* p = (struct task_list_d*)d;
1433b71395eaSflorian assert(s >= p->size);
1434b71395eaSflorian (void)s;
1435b71395eaSflorian (*cb)(base, &p->next, arg);
1436b71395eaSflorian }
1437b71395eaSflorian
udb_walkfunc(void * base,void * warg,uint8_t t,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)1438b71395eaSflorian void udb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s,
1439b71395eaSflorian udb_walk_relptr_cb* cb, void *arg)
1440b71395eaSflorian {
1441b71395eaSflorian (void)warg;
1442b71395eaSflorian switch(t) {
1443b71395eaSflorian case udb_chunk_type_task:
1444b71395eaSflorian udb_task_walk_chunk(base, d, s, cb, arg);
1445b71395eaSflorian break;
1446b71395eaSflorian default:
1447b71395eaSflorian /* no rel ptrs */
1448b71395eaSflorian break;
1449b71395eaSflorian }
1450b71395eaSflorian }
1451b71395eaSflorian
task_file_create(const char * file)1452d3fecca9Ssthen struct udb_base* task_file_create(const char* file)
1453d3fecca9Ssthen {
1454b71395eaSflorian return udb_base_create_new(file, &udb_walkfunc, NULL);
1455d3fecca9Ssthen }
1456d3fecca9Ssthen
145762ac0c33Sjakob static int
task_create_new_elem(struct udb_base * udb,udb_ptr * last,udb_ptr * e,size_t sz,const dname_type * zname)1458d3fecca9Ssthen task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e,
1459d3fecca9Ssthen size_t sz, const dname_type* zname)
146062ac0c33Sjakob {
1461d3fecca9Ssthen if(!udb_ptr_alloc_space(e, udb, udb_chunk_type_task, sz)) {
146262ac0c33Sjakob return 0;
146362ac0c33Sjakob }
1464d3fecca9Ssthen if(udb_ptr_is_null(last)) {
1465d3fecca9Ssthen udb_base_set_userdata(udb, e->data);
146662ac0c33Sjakob } else {
1467d3fecca9Ssthen udb_rptr_set_ptr(&TASKLIST(last)->next, udb, e);
146862ac0c33Sjakob }
1469d3fecca9Ssthen udb_ptr_set_ptr(last, udb, e);
1470d3fecca9Ssthen
1471d3fecca9Ssthen /* fill in tasklist item */
1472d3fecca9Ssthen udb_rel_ptr_init(&TASKLIST(e)->next);
1473d3fecca9Ssthen TASKLIST(e)->size = sz;
1474d3fecca9Ssthen TASKLIST(e)->oldserial = 0;
1475d3fecca9Ssthen TASKLIST(e)->newserial = 0;
1476d3fecca9Ssthen TASKLIST(e)->yesno = 0;
1477d3fecca9Ssthen
1478d3fecca9Ssthen if(zname) {
1479d3fecca9Ssthen memmove(TASKLIST(e)->zname, zname, dname_total_size(zname));
1480d3fecca9Ssthen }
148162ac0c33Sjakob return 1;
148262ac0c33Sjakob }
148362ac0c33Sjakob
task_new_soainfo(struct udb_base * udb,udb_ptr * last,struct zone * z,enum soainfo_hint hint)1484cdb6bbddSbrad void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z,
14853f21e8ccSflorian enum soainfo_hint hint)
148662ac0c33Sjakob {
1487d3fecca9Ssthen /* calculate size */
1488d3fecca9Ssthen udb_ptr e;
1489d3fecca9Ssthen size_t sz;
1490d3fecca9Ssthen const dname_type* apex, *ns, *em;
1491d3fecca9Ssthen if(!z || !z->apex || !domain_dname(z->apex))
1492d3fecca9Ssthen return; /* safety check */
149362ac0c33Sjakob
1494d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "nsd: add soa info for zone %s",
1495d3fecca9Ssthen domain_to_string(z->apex)));
1496d3fecca9Ssthen apex = domain_dname(z->apex);
1497d3fecca9Ssthen sz = sizeof(struct task_list_d) + dname_total_size(apex);
14983f21e8ccSflorian if(z->soa_rrset && hint == soainfo_ok) {
1499d3fecca9Ssthen ns = domain_dname(rdata_atom_domain(
1500d3fecca9Ssthen z->soa_rrset->rrs[0].rdatas[0]));
1501d3fecca9Ssthen em = domain_dname(rdata_atom_domain(
1502d3fecca9Ssthen z->soa_rrset->rrs[0].rdatas[1]));
1503d3fecca9Ssthen sz += sizeof(uint32_t)*6 + sizeof(uint8_t)*2
1504d3fecca9Ssthen + ns->name_size + em->name_size;
150562ac0c33Sjakob } else {
1506d3fecca9Ssthen ns = 0;
1507d3fecca9Ssthen em = 0;
150862ac0c33Sjakob }
150962ac0c33Sjakob
1510d3fecca9Ssthen /* create new task_list item */
1511d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sz, apex)) {
1512d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add SOAINFO");
1513d3fecca9Ssthen return;
1514d3fecca9Ssthen }
1515d3fecca9Ssthen TASKLIST(&e)->task_type = task_soa_info;
15163f21e8ccSflorian TASKLIST(&e)->yesno = (uint64_t)hint;
1517d3fecca9Ssthen
15183f21e8ccSflorian if(z->soa_rrset && hint == soainfo_ok) {
1519d3fecca9Ssthen uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl);
1520d3fecca9Ssthen uint8_t* p = (uint8_t*)TASKLIST(&e)->zname;
1521d3fecca9Ssthen p += dname_total_size(apex);
1522d3fecca9Ssthen memmove(p, &ttl, sizeof(uint32_t));
1523d3fecca9Ssthen p += sizeof(uint32_t);
1524d3fecca9Ssthen memmove(p, &ns->name_size, sizeof(uint8_t));
1525d3fecca9Ssthen p += sizeof(uint8_t);
1526d3fecca9Ssthen memmove(p, dname_name(ns), ns->name_size);
1527d3fecca9Ssthen p += ns->name_size;
1528d3fecca9Ssthen memmove(p, &em->name_size, sizeof(uint8_t));
1529d3fecca9Ssthen p += sizeof(uint8_t);
1530d3fecca9Ssthen memmove(p, dname_name(em), em->name_size);
1531d3fecca9Ssthen p += em->name_size;
1532d3fecca9Ssthen memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[2]),
1533d3fecca9Ssthen sizeof(uint32_t));
1534d3fecca9Ssthen p += sizeof(uint32_t);
1535d3fecca9Ssthen memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[3]),
1536d3fecca9Ssthen sizeof(uint32_t));
1537d3fecca9Ssthen p += sizeof(uint32_t);
1538d3fecca9Ssthen memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[4]),
1539d3fecca9Ssthen sizeof(uint32_t));
1540d3fecca9Ssthen p += sizeof(uint32_t);
1541d3fecca9Ssthen memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[5]),
1542d3fecca9Ssthen sizeof(uint32_t));
1543d3fecca9Ssthen p += sizeof(uint32_t);
1544d3fecca9Ssthen memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[6]),
1545d3fecca9Ssthen sizeof(uint32_t));
1546d3fecca9Ssthen }
1547d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1548d3fecca9Ssthen }
1549d3fecca9Ssthen
task_process_sync(struct udb_base * taskudb)1550d3fecca9Ssthen void task_process_sync(struct udb_base* taskudb)
1551d3fecca9Ssthen {
1552d3fecca9Ssthen /* need to sync before other process uses the mmap? */
1553d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "task procsync %s size %d",
1554d3fecca9Ssthen taskudb->fname, (int)taskudb->base_size));
1555d3fecca9Ssthen (void)taskudb;
1556d3fecca9Ssthen }
1557d3fecca9Ssthen
task_remap(struct udb_base * taskudb)1558d3fecca9Ssthen void task_remap(struct udb_base* taskudb)
1559d3fecca9Ssthen {
1560d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "task remap %s size %d",
1561d3fecca9Ssthen taskudb->fname, (int)taskudb->glob_data->fsize));
1562d3fecca9Ssthen udb_base_remap_process(taskudb);
1563d3fecca9Ssthen }
1564d3fecca9Ssthen
task_clear(struct udb_base * taskudb)1565d3fecca9Ssthen void task_clear(struct udb_base* taskudb)
1566d3fecca9Ssthen {
1567d3fecca9Ssthen udb_ptr t, n;
1568d3fecca9Ssthen udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb));
1569d3fecca9Ssthen udb_base_set_userdata(taskudb, 0);
1570d3fecca9Ssthen udb_ptr_init(&n, taskudb);
1571d3fecca9Ssthen while(!udb_ptr_is_null(&t)) {
1572d3fecca9Ssthen udb_ptr_set_rptr(&n, taskudb, &TASKLIST(&t)->next);
1573d3fecca9Ssthen udb_rptr_zero(&TASKLIST(&t)->next, taskudb);
1574d3fecca9Ssthen udb_ptr_free_space(&t, taskudb, TASKLIST(&t)->size);
1575d3fecca9Ssthen udb_ptr_set_ptr(&t, taskudb, &n);
1576d3fecca9Ssthen }
1577d3fecca9Ssthen udb_ptr_unlink(&t, taskudb);
1578d3fecca9Ssthen udb_ptr_unlink(&n, taskudb);
1579d3fecca9Ssthen }
1580d3fecca9Ssthen
task_new_expire(struct udb_base * udb,udb_ptr * last,const struct dname * z,int expired)1581d3fecca9Ssthen void task_new_expire(struct udb_base* udb, udb_ptr* last,
1582d3fecca9Ssthen const struct dname* z, int expired)
1583d3fecca9Ssthen {
1584d3fecca9Ssthen udb_ptr e;
1585d3fecca9Ssthen if(!z) return;
1586d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add expire info for zone %s",
1587d3fecca9Ssthen dname_to_string(z,NULL)));
1588d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
1589d3fecca9Ssthen dname_total_size(z), z)) {
1590d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add expire");
1591d3fecca9Ssthen return;
1592d3fecca9Ssthen }
1593d3fecca9Ssthen TASKLIST(&e)->task_type = task_expire;
1594d3fecca9Ssthen TASKLIST(&e)->yesno = expired;
1595d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1596d3fecca9Ssthen }
1597d3fecca9Ssthen
task_new_check_zonefiles(udb_base * udb,udb_ptr * last,const dname_type * zone)1598d3fecca9Ssthen void task_new_check_zonefiles(udb_base* udb, udb_ptr* last,
1599d3fecca9Ssthen const dname_type* zone)
1600d3fecca9Ssthen {
1601d3fecca9Ssthen udb_ptr e;
1602*bf87c3c0Sflorian xfrd_check_catalog_consumer_zonefiles(zone);
1603d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles"));
1604d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
1605d3fecca9Ssthen (zone?dname_total_size(zone):0), zone)) {
1606d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add check_zones");
1607d3fecca9Ssthen return;
1608d3fecca9Ssthen }
1609d3fecca9Ssthen TASKLIST(&e)->task_type = task_check_zonefiles;
1610d3fecca9Ssthen TASKLIST(&e)->yesno = (zone!=NULL);
1611d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1612d3fecca9Ssthen }
1613d3fecca9Ssthen
task_new_write_zonefiles(udb_base * udb,udb_ptr * last,const dname_type * zone)1614d3fecca9Ssthen void task_new_write_zonefiles(udb_base* udb, udb_ptr* last,
1615d3fecca9Ssthen const dname_type* zone)
1616d3fecca9Ssthen {
1617d3fecca9Ssthen udb_ptr e;
1618d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task writezonefiles"));
1619d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
1620d3fecca9Ssthen (zone?dname_total_size(zone):0), zone)) {
1621d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add writezones");
1622d3fecca9Ssthen return;
1623d3fecca9Ssthen }
1624d3fecca9Ssthen TASKLIST(&e)->task_type = task_write_zonefiles;
1625d3fecca9Ssthen TASKLIST(&e)->yesno = (zone!=NULL);
1626d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1627d3fecca9Ssthen }
1628d3fecca9Ssthen
task_new_set_verbosity(udb_base * udb,udb_ptr * last,int v)1629d3fecca9Ssthen void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v)
1630d3fecca9Ssthen {
1631d3fecca9Ssthen udb_ptr e;
1632d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task set_verbosity"));
1633d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
1634d3fecca9Ssthen NULL)) {
1635d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add set_v");
1636d3fecca9Ssthen return;
1637d3fecca9Ssthen }
1638d3fecca9Ssthen TASKLIST(&e)->task_type = task_set_verbosity;
1639d3fecca9Ssthen TASKLIST(&e)->yesno = v;
1640d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1641d3fecca9Ssthen }
1642d3fecca9Ssthen
1643d3fecca9Ssthen void
task_new_add_zone(udb_base * udb,udb_ptr * last,const char * zone,const char * pattern,unsigned zonestatid)1644d3fecca9Ssthen task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone,
1645c1404d4fSbrad const char* pattern, unsigned zonestatid)
1646d3fecca9Ssthen {
1647d3fecca9Ssthen size_t zlen = strlen(zone);
1648d3fecca9Ssthen size_t plen = strlen(pattern);
1649d3fecca9Ssthen void *p;
1650d3fecca9Ssthen udb_ptr e;
1651d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addzone %s %s", zone, pattern));
1652d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
1653d3fecca9Ssthen zlen + 1 + plen + 1, NULL)) {
1654d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add addz");
1655d3fecca9Ssthen return;
1656d3fecca9Ssthen }
1657d3fecca9Ssthen TASKLIST(&e)->task_type = task_add_zone;
1658c1404d4fSbrad TASKLIST(&e)->yesno = zonestatid;
1659d3fecca9Ssthen p = TASKLIST(&e)->zname;
1660d3fecca9Ssthen memcpy(p, zone, zlen+1);
1661308d2509Sflorian memmove((char*)p+zlen+1, pattern, plen+1);
1662d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1663d3fecca9Ssthen }
1664d3fecca9Ssthen
1665d3fecca9Ssthen void
task_new_del_zone(udb_base * udb,udb_ptr * last,const dname_type * dname)1666d3fecca9Ssthen task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname)
1667d3fecca9Ssthen {
1668d3fecca9Ssthen udb_ptr e;
1669d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delzone %s", dname_to_string(dname, 0)));
1670d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1671d3fecca9Ssthen +dname_total_size(dname), dname)) {
1672d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add delz");
1673d3fecca9Ssthen return;
1674d3fecca9Ssthen }
1675d3fecca9Ssthen TASKLIST(&e)->task_type = task_del_zone;
1676d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1677d3fecca9Ssthen }
1678d3fecca9Ssthen
task_new_add_key(udb_base * udb,udb_ptr * last,struct key_options * key)1679fe5fe5f6Sflorian void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key)
1680d3fecca9Ssthen {
1681d3fecca9Ssthen char* p;
1682d3fecca9Ssthen udb_ptr e;
1683d3fecca9Ssthen assert(key->name && key->algorithm && key->secret);
1684d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addkey"));
1685d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1686d3fecca9Ssthen +strlen(key->name)+1+strlen(key->algorithm)+1+
1687d3fecca9Ssthen strlen(key->secret)+1, NULL)) {
1688d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add addk");
1689d3fecca9Ssthen return;
1690d3fecca9Ssthen }
1691d3fecca9Ssthen TASKLIST(&e)->task_type = task_add_key;
1692d3fecca9Ssthen p = (char*)TASKLIST(&e)->zname;
1693d3fecca9Ssthen memmove(p, key->name, strlen(key->name)+1);
1694d3fecca9Ssthen p+=strlen(key->name)+1;
1695d3fecca9Ssthen memmove(p, key->algorithm, strlen(key->algorithm)+1);
1696d3fecca9Ssthen p+=strlen(key->algorithm)+1;
1697d3fecca9Ssthen memmove(p, key->secret, strlen(key->secret)+1);
1698d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1699d3fecca9Ssthen }
1700d3fecca9Ssthen
task_new_del_key(udb_base * udb,udb_ptr * last,const char * name)1701d3fecca9Ssthen void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name)
1702d3fecca9Ssthen {
1703d3fecca9Ssthen char* p;
1704d3fecca9Ssthen udb_ptr e;
1705d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delkey"));
1706d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1707d3fecca9Ssthen +strlen(name)+1, NULL)) {
1708d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add delk");
1709d3fecca9Ssthen return;
1710d3fecca9Ssthen }
1711d3fecca9Ssthen TASKLIST(&e)->task_type = task_del_key;
1712d3fecca9Ssthen p = (char*)TASKLIST(&e)->zname;
1713d3fecca9Ssthen memmove(p, name, strlen(name)+1);
1714d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1715d3fecca9Ssthen }
1716d3fecca9Ssthen
task_new_add_cookie_secret(udb_base * udb,udb_ptr * last,const char * secret)1717063644e9Sflorian void task_new_add_cookie_secret(udb_base* udb, udb_ptr* last,
1718063644e9Sflorian const char* secret) {
1719063644e9Sflorian udb_ptr e;
1720063644e9Sflorian char* p;
1721063644e9Sflorian size_t const secret_size = strlen(secret) + 1;
1722063644e9Sflorian
1723063644e9Sflorian DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task add_cookie_secret"));
1724063644e9Sflorian
1725063644e9Sflorian if(!task_create_new_elem(udb, last, &e,
1726063644e9Sflorian sizeof(struct task_list_d) + secret_size, NULL)) {
1727063644e9Sflorian log_msg(LOG_ERR, "tasklist: out of space, cannot add add_cookie_secret");
1728063644e9Sflorian return;
1729063644e9Sflorian }
1730063644e9Sflorian TASKLIST(&e)->task_type = task_add_cookie_secret;
1731063644e9Sflorian p = (char*)TASKLIST(&e)->zname;
1732063644e9Sflorian memmove(p, secret, secret_size);
1733063644e9Sflorian udb_ptr_unlink(&e, udb);
1734063644e9Sflorian }
1735063644e9Sflorian
task_new_drop_cookie_secret(udb_base * udb,udb_ptr * last)1736063644e9Sflorian void task_new_drop_cookie_secret(udb_base* udb, udb_ptr* last) {
1737063644e9Sflorian udb_ptr e;
1738063644e9Sflorian DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task drop_cookie_secret"));
1739063644e9Sflorian if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) {
1740063644e9Sflorian log_msg(LOG_ERR, "tasklist: out of space, cannot add drop_cookie_secret");
1741063644e9Sflorian return;
1742063644e9Sflorian }
1743063644e9Sflorian TASKLIST(&e)->task_type = task_drop_cookie_secret;
1744063644e9Sflorian udb_ptr_unlink(&e, udb);
1745063644e9Sflorian }
1746063644e9Sflorian
task_new_activate_cookie_secret(udb_base * udb,udb_ptr * last)1747063644e9Sflorian void task_new_activate_cookie_secret(udb_base* udb, udb_ptr* last) {
1748063644e9Sflorian udb_ptr e;
1749063644e9Sflorian DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task activate_cookie_secret"));
1750063644e9Sflorian if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) {
1751063644e9Sflorian log_msg(LOG_ERR, "tasklist: out of space, cannot add activate_cookie_secret");
1752063644e9Sflorian return;
1753063644e9Sflorian }
1754063644e9Sflorian TASKLIST(&e)->task_type = task_activate_cookie_secret;
1755063644e9Sflorian udb_ptr_unlink(&e, udb);
1756063644e9Sflorian }
1757063644e9Sflorian
task_new_add_pattern(udb_base * udb,udb_ptr * last,struct pattern_options * p)1758fe5fe5f6Sflorian void task_new_add_pattern(udb_base* udb, udb_ptr* last,
1759fe5fe5f6Sflorian struct pattern_options* p)
1760d3fecca9Ssthen {
1761d3fecca9Ssthen region_type* temp;
1762d3fecca9Ssthen buffer_type* buffer;
1763d3fecca9Ssthen udb_ptr e;
1764d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addpattern %s", p->pname));
1765d3fecca9Ssthen temp = region_create(xalloc, free);
1766d3fecca9Ssthen buffer = buffer_create(temp, 4096);
1767d3fecca9Ssthen pattern_options_marshal(buffer, p);
1768d3fecca9Ssthen buffer_flip(buffer);
1769d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1770d3fecca9Ssthen + buffer_limit(buffer), NULL)) {
1771d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add addp");
1772d3fecca9Ssthen region_destroy(temp);
1773d3fecca9Ssthen return;
1774d3fecca9Ssthen }
1775d3fecca9Ssthen TASKLIST(&e)->task_type = task_add_pattern;
1776d3fecca9Ssthen TASKLIST(&e)->yesno = buffer_limit(buffer);
1777d3fecca9Ssthen memmove(TASKLIST(&e)->zname, buffer_begin(buffer),
1778d3fecca9Ssthen buffer_limit(buffer));
1779d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1780d3fecca9Ssthen region_destroy(temp);
1781d3fecca9Ssthen }
1782d3fecca9Ssthen
task_new_del_pattern(udb_base * udb,udb_ptr * last,const char * name)1783d3fecca9Ssthen void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name)
1784d3fecca9Ssthen {
1785d3fecca9Ssthen char* p;
1786d3fecca9Ssthen udb_ptr e;
1787d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delpattern %s", name));
1788d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1789d3fecca9Ssthen +strlen(name)+1, NULL)) {
1790d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add delp");
1791d3fecca9Ssthen return;
1792d3fecca9Ssthen }
1793d3fecca9Ssthen TASKLIST(&e)->task_type = task_del_pattern;
1794d3fecca9Ssthen p = (char*)TASKLIST(&e)->zname;
1795d3fecca9Ssthen memmove(p, name, strlen(name)+1);
1796d3fecca9Ssthen udb_ptr_unlink(&e, udb);
1797d3fecca9Ssthen }
1798d3fecca9Ssthen
task_new_opt_change(udb_base * udb,udb_ptr * last,struct nsd_options * opt)1799fe5fe5f6Sflorian void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt)
1800d3fecca9Ssthen {
1801d3fecca9Ssthen udb_ptr e;
1802d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task opt_change"));
1803d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
1804d3fecca9Ssthen NULL)) {
1805d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add o_c");
1806d3fecca9Ssthen return;
1807d3fecca9Ssthen }
1808d3fecca9Ssthen TASKLIST(&e)->task_type = task_opt_change;
1809d3fecca9Ssthen #ifdef RATELIMIT
1810d3fecca9Ssthen TASKLIST(&e)->oldserial = opt->rrl_ratelimit;
1811d3fecca9Ssthen TASKLIST(&e)->newserial = opt->rrl_whitelist_ratelimit;
1812d3fecca9Ssthen TASKLIST(&e)->yesno = (uint64_t) opt->rrl_slip;
1813d3fecca9Ssthen #else
1814d3fecca9Ssthen (void)opt;
1815d3fecca9Ssthen #endif
1816d3fecca9Ssthen udb_ptr_unlink(&e, udb);
181762ac0c33Sjakob }
181862ac0c33Sjakob
task_new_zonestat_inc(udb_base * udb,udb_ptr * last,unsigned sz)1819c1404d4fSbrad void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz)
1820c1404d4fSbrad {
1821c1404d4fSbrad udb_ptr e;
1822c1404d4fSbrad DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task zonestat_inc"));
1823c1404d4fSbrad if(sz == 0)
1824c1404d4fSbrad return; /* no need to decrease to 0 */
1825c1404d4fSbrad if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
1826c1404d4fSbrad NULL)) {
1827c1404d4fSbrad log_msg(LOG_ERR, "tasklist: out of space, cannot add z_i");
1828c1404d4fSbrad return;
1829c1404d4fSbrad }
1830c1404d4fSbrad TASKLIST(&e)->task_type = task_zonestat_inc;
1831c1404d4fSbrad TASKLIST(&e)->oldserial = (uint32_t)sz;
1832c1404d4fSbrad udb_ptr_unlink(&e, udb);
1833c1404d4fSbrad }
1834c1404d4fSbrad
183562ac0c33Sjakob int
task_new_apply_xfr(udb_base * udb,udb_ptr * last,const dname_type * dname,uint32_t old_serial,uint32_t new_serial,uint64_t filenumber)1836d3fecca9Ssthen task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname,
1837d3fecca9Ssthen uint32_t old_serial, uint32_t new_serial, uint64_t filenumber)
183862ac0c33Sjakob {
1839d3fecca9Ssthen udb_ptr e;
1840d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task apply_xfr"));
1841d3fecca9Ssthen if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1842d3fecca9Ssthen +dname_total_size(dname), dname)) {
1843d3fecca9Ssthen log_msg(LOG_ERR, "tasklist: out of space, cannot add applyxfr");
1844d3fecca9Ssthen return 0;
1845d3fecca9Ssthen }
1846d3fecca9Ssthen TASKLIST(&e)->oldserial = old_serial;
1847d3fecca9Ssthen TASKLIST(&e)->newserial = new_serial;
1848d3fecca9Ssthen TASKLIST(&e)->yesno = filenumber;
1849d3fecca9Ssthen TASKLIST(&e)->task_type = task_apply_xfr;
1850d3fecca9Ssthen udb_ptr_unlink(&e, udb);
185162ac0c33Sjakob return 1;
185262ac0c33Sjakob }
185362ac0c33Sjakob
1854d3fecca9Ssthen void
task_process_expire(namedb_type * db,struct task_list_d * task)1855d3fecca9Ssthen task_process_expire(namedb_type* db, struct task_list_d* task)
185662ac0c33Sjakob {
1857d3fecca9Ssthen uint8_t ok;
1858d3fecca9Ssthen zone_type* z = namedb_find_zone(db, task->zname);
1859d3fecca9Ssthen assert(task->task_type == task_expire);
1860d3fecca9Ssthen if(!z) {
1861d3fecca9Ssthen DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "zone %s %s but not in zonetree",
1862d3fecca9Ssthen dname_to_string(task->zname, NULL),
1863d3fecca9Ssthen task->yesno?"expired":"unexpired"));
1864d3fecca9Ssthen return;
1865d3fecca9Ssthen }
1866d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: expire task zone %s %s",
1867d3fecca9Ssthen dname_to_string(task->zname,0),
1868d3fecca9Ssthen task->yesno?"expired":"unexpired"));
1869d3fecca9Ssthen /* find zone, set expire flag */
1870d3fecca9Ssthen ok = !task->yesno;
1871d3fecca9Ssthen /* only update zone->is_ok if needed to minimize copy-on-write
1872d3fecca9Ssthen * of memory pages shared after fork() */
1873d3fecca9Ssthen if(ok && !z->is_ok)
1874d3fecca9Ssthen z->is_ok = 1;
1875d3fecca9Ssthen else if(!ok && z->is_ok)
1876d3fecca9Ssthen z->is_ok = 0;
187762ac0c33Sjakob }
187862ac0c33Sjakob
1879d3fecca9Ssthen static void
task_process_set_verbosity(struct task_list_d * task)1880d3fecca9Ssthen task_process_set_verbosity(struct task_list_d* task)
188162ac0c33Sjakob {
1882d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "verbosity task %d", (int)task->yesno));
1883d3fecca9Ssthen verbosity = task->yesno;
188462ac0c33Sjakob }
188562ac0c33Sjakob
1886d3fecca9Ssthen static void
task_process_checkzones(struct nsd * nsd,udb_base * taskudb,udb_ptr * last_task,struct task_list_d * task)1887b71395eaSflorian task_process_checkzones(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task,
1888d3fecca9Ssthen struct task_list_d* task)
1889d3fecca9Ssthen {
1890d3fecca9Ssthen /* on SIGHUP check if zone-text-files changed and if so,
1891d3fecca9Ssthen * reread. When from xfrd-reload, no need to fstat the files */
1892d3fecca9Ssthen if(task->yesno) {
1893fe5fe5f6Sflorian struct zone_options* zo = zone_options_find(nsd->options,
1894d3fecca9Ssthen task->zname);
1895d3fecca9Ssthen if(zo)
1896b71395eaSflorian namedb_check_zonefile(nsd, taskudb, last_task, zo);
189762ac0c33Sjakob } else {
1898d3fecca9Ssthen /* check all zones */
1899b71395eaSflorian namedb_check_zonefiles(nsd, nsd->options, taskudb, last_task);
190062ac0c33Sjakob }
190162ac0c33Sjakob }
190262ac0c33Sjakob
1903d3fecca9Ssthen static void
task_process_writezones(struct nsd * nsd,struct task_list_d * task)1904d3fecca9Ssthen task_process_writezones(struct nsd* nsd, struct task_list_d* task)
1905d3fecca9Ssthen {
1906d3fecca9Ssthen if(task->yesno) {
1907fe5fe5f6Sflorian struct zone_options* zo = zone_options_find(nsd->options,
1908d3fecca9Ssthen task->zname);
1909d3fecca9Ssthen if(zo)
1910cdb6bbddSbrad namedb_write_zonefile(nsd, zo);
1911d3fecca9Ssthen } else {
1912cdb6bbddSbrad namedb_write_zonefiles(nsd, nsd->options);
1913d3fecca9Ssthen }
191462ac0c33Sjakob }
191562ac0c33Sjakob
1916d3fecca9Ssthen static void
task_process_add_zone(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,struct task_list_d * task)1917d3fecca9Ssthen task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task,
1918d3fecca9Ssthen struct task_list_d* task)
191962ac0c33Sjakob {
1920d3fecca9Ssthen zone_type* z;
1921d3fecca9Ssthen const dname_type* zdname;
1922d3fecca9Ssthen const char* zname = (const char*)task->zname;
1923d3fecca9Ssthen const char* pname = zname + strlen(zname)+1;
1924d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "addzone task %s %s", zname, pname));
1925d3fecca9Ssthen zdname = dname_parse(nsd->db->region, zname);
1926d3fecca9Ssthen if(!zdname) {
1927d3fecca9Ssthen log_msg(LOG_ERR, "can not parse zone name %s", zname);
1928d3fecca9Ssthen return;
192962ac0c33Sjakob }
1930d3fecca9Ssthen /* create zone */
1931d3fecca9Ssthen z = find_or_create_zone(nsd->db, zdname, nsd->options, zname, pname);
1932d3fecca9Ssthen if(!z) {
1933d3fecca9Ssthen region_recycle(nsd->db->region, (void*)zdname,
1934d3fecca9Ssthen dname_total_size(zdname));
1935d3fecca9Ssthen log_msg(LOG_ERR, "can not add zone %s %s", zname, pname);
1936d3fecca9Ssthen return;
193762ac0c33Sjakob }
1938c1404d4fSbrad z->zonestatid = (unsigned)task->yesno;
1939d3fecca9Ssthen /* if zone is empty, attempt to read the zonefile from disk (if any) */
1940d3fecca9Ssthen if(!z->soa_rrset && z->opts->pattern->zonefile) {
1941cdb6bbddSbrad namedb_read_zonefile(nsd, z, udb, last_task);
1942d3fecca9Ssthen }
194362ac0c33Sjakob }
194462ac0c33Sjakob
1945d3fecca9Ssthen static void
task_process_del_zone(struct nsd * nsd,struct task_list_d * task)1946d3fecca9Ssthen task_process_del_zone(struct nsd* nsd, struct task_list_d* task)
194762ac0c33Sjakob {
1948d3fecca9Ssthen zone_type* zone;
1949fe5fe5f6Sflorian struct zone_options* zopt;
1950d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "delzone task %s", dname_to_string(
1951d3fecca9Ssthen task->zname, NULL)));
1952d3fecca9Ssthen zone = namedb_find_zone(nsd->db, task->zname);
1953d3fecca9Ssthen if(!zone)
1954d3fecca9Ssthen return;
1955d3fecca9Ssthen
1956d3fecca9Ssthen #ifdef NSEC3
19574b6a9f59Sflorian nsec3_clear_precompile(nsd->db, zone);
19584b6a9f59Sflorian zone->nsec3_param = NULL;
1959d3fecca9Ssthen #endif
1960d3fecca9Ssthen delete_zone_rrs(nsd->db, zone);
1961d3fecca9Ssthen
1962d3fecca9Ssthen /* remove from zonetree, apex, soa */
1963d3fecca9Ssthen zopt = zone->opts;
1964d3fecca9Ssthen namedb_zone_delete(nsd->db, zone);
1965d3fecca9Ssthen /* remove from options (zone_list already edited by xfrd) */
1966d3fecca9Ssthen zone_options_delete(nsd->options, zopt);
1967d3fecca9Ssthen }
1968d3fecca9Ssthen
1969d3fecca9Ssthen static void
task_process_add_key(struct nsd * nsd,struct task_list_d * task)1970d3fecca9Ssthen task_process_add_key(struct nsd* nsd, struct task_list_d* task)
1971d3fecca9Ssthen {
1972fe5fe5f6Sflorian struct key_options key;
1973d3fecca9Ssthen key.name = (char*)task->zname;
1974d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "addkey task %s", key.name));
1975d3fecca9Ssthen key.algorithm = key.name + strlen(key.name)+1;
1976d3fecca9Ssthen key.secret = key.algorithm + strlen(key.algorithm)+1;
1977d3fecca9Ssthen key_options_add_modify(nsd->options, &key);
1978d3fecca9Ssthen memset(key.secret, 0xdd, strlen(key.secret)); /* wipe secret */
1979d3fecca9Ssthen }
1980d3fecca9Ssthen
1981d3fecca9Ssthen static void
task_process_del_key(struct nsd * nsd,struct task_list_d * task)1982d3fecca9Ssthen task_process_del_key(struct nsd* nsd, struct task_list_d* task)
1983d3fecca9Ssthen {
1984d3fecca9Ssthen char* name = (char*)task->zname;
1985d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "delkey task %s", name));
1986d3fecca9Ssthen /* this is reload and nothing is using the TSIG key right now */
1987d3fecca9Ssthen key_options_remove(nsd->options, name);
1988d3fecca9Ssthen }
1989d3fecca9Ssthen
1990d3fecca9Ssthen static void
task_process_add_cookie_secret(struct nsd * nsd,struct task_list_d * task)1991063644e9Sflorian task_process_add_cookie_secret(struct nsd* nsd, struct task_list_d* task) {
1992063644e9Sflorian uint8_t secret_tmp[NSD_COOKIE_SECRET_SIZE];
1993063644e9Sflorian ssize_t decoded_len;
1994063644e9Sflorian char* secret = (char*)task->zname;
1995063644e9Sflorian
1996063644e9Sflorian DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add_cookie_secret task %s", secret));
1997063644e9Sflorian
1998063644e9Sflorian if( strlen(secret) != 32 ) {
1999063644e9Sflorian log_msg(LOG_ERR, "invalid cookie secret: %s", secret);
2000063644e9Sflorian explicit_bzero(secret, strlen(secret));
2001063644e9Sflorian return;
2002063644e9Sflorian }
2003063644e9Sflorian
2004063644e9Sflorian decoded_len = hex_pton(secret, secret_tmp, NSD_COOKIE_SECRET_SIZE);
2005063644e9Sflorian if( decoded_len != 16 ) {
2006063644e9Sflorian explicit_bzero(secret_tmp, NSD_COOKIE_SECRET_SIZE);
2007063644e9Sflorian log_msg(LOG_ERR, "unable to parse cookie secret: %s", secret);
2008063644e9Sflorian explicit_bzero(secret, strlen(secret));
2009063644e9Sflorian return;
2010063644e9Sflorian }
2011063644e9Sflorian explicit_bzero(secret, strlen(secret));
2012063644e9Sflorian add_cookie_secret(nsd, secret_tmp);
2013063644e9Sflorian explicit_bzero(secret_tmp, NSD_COOKIE_SECRET_SIZE);
2014063644e9Sflorian }
2015063644e9Sflorian
2016063644e9Sflorian static void
task_process_drop_cookie_secret(struct nsd * nsd,struct task_list_d * task)2017063644e9Sflorian task_process_drop_cookie_secret(struct nsd* nsd, struct task_list_d* task)
2018063644e9Sflorian {
2019063644e9Sflorian (void)task;
2020063644e9Sflorian DEBUG(DEBUG_IPC, 1, (LOG_INFO, "drop_cookie_secret task"));
2021063644e9Sflorian if( nsd->cookie_count <= 1 ) {
2022063644e9Sflorian log_msg(LOG_ERR, "can not drop the only active cookie secret");
2023063644e9Sflorian return;
2024063644e9Sflorian }
2025063644e9Sflorian drop_cookie_secret(nsd);
2026063644e9Sflorian }
2027063644e9Sflorian
2028063644e9Sflorian static void
task_process_activate_cookie_secret(struct nsd * nsd,struct task_list_d * task)2029063644e9Sflorian task_process_activate_cookie_secret(struct nsd* nsd, struct task_list_d* task)
2030063644e9Sflorian {
2031063644e9Sflorian (void)task;
2032063644e9Sflorian DEBUG(DEBUG_IPC, 1, (LOG_INFO, "activate_cookie_secret task"));
2033063644e9Sflorian if( nsd->cookie_count <= 1 ) {
2034063644e9Sflorian log_msg(LOG_ERR, "can not activate the only active cookie secret");
2035063644e9Sflorian return;
2036063644e9Sflorian }
2037063644e9Sflorian activate_cookie_secret(nsd);
2038063644e9Sflorian }
2039063644e9Sflorian
2040063644e9Sflorian static void
task_process_add_pattern(struct nsd * nsd,struct task_list_d * task)2041d3fecca9Ssthen task_process_add_pattern(struct nsd* nsd, struct task_list_d* task)
2042d3fecca9Ssthen {
2043d3fecca9Ssthen region_type* temp = region_create(xalloc, free);
2044d3fecca9Ssthen buffer_type buffer;
2045fe5fe5f6Sflorian struct pattern_options *pat;
2046d3fecca9Ssthen buffer_create_from(&buffer, task->zname, task->yesno);
2047d3fecca9Ssthen pat = pattern_options_unmarshal(temp, &buffer);
2048d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "addpattern task %s", pat->pname));
2049d3fecca9Ssthen pattern_options_add_modify(nsd->options, pat);
2050d3fecca9Ssthen region_destroy(temp);
2051d3fecca9Ssthen }
2052d3fecca9Ssthen
2053d3fecca9Ssthen static void
task_process_del_pattern(struct nsd * nsd,struct task_list_d * task)2054d3fecca9Ssthen task_process_del_pattern(struct nsd* nsd, struct task_list_d* task)
2055d3fecca9Ssthen {
2056d3fecca9Ssthen char* name = (char*)task->zname;
2057d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "delpattern task %s", name));
2058d3fecca9Ssthen pattern_options_remove(nsd->options, name);
2059d3fecca9Ssthen }
2060d3fecca9Ssthen
2061d3fecca9Ssthen static void
task_process_opt_change(struct nsd * nsd,struct task_list_d * task)2062d3fecca9Ssthen task_process_opt_change(struct nsd* nsd, struct task_list_d* task)
2063d3fecca9Ssthen {
2064d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "optchange task"));
2065d3fecca9Ssthen #ifdef RATELIMIT
2066d3fecca9Ssthen nsd->options->rrl_ratelimit = task->oldserial;
2067d3fecca9Ssthen nsd->options->rrl_whitelist_ratelimit = task->newserial;
2068d3fecca9Ssthen nsd->options->rrl_slip = task->yesno;
2069d3fecca9Ssthen rrl_set_limit(nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit,
2070d3fecca9Ssthen nsd->options->rrl_slip);
2071d3fecca9Ssthen #else
2072d3fecca9Ssthen (void)nsd; (void)task;
2073d3fecca9Ssthen #endif
2074d3fecca9Ssthen }
2075d3fecca9Ssthen
2076c1404d4fSbrad #ifdef USE_ZONE_STATS
2077c1404d4fSbrad static void
task_process_zonestat_inc(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,struct task_list_d * task)2078c1404d4fSbrad task_process_zonestat_inc(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
2079c1404d4fSbrad struct task_list_d* task)
2080c1404d4fSbrad {
2081c1404d4fSbrad DEBUG(DEBUG_IPC,1, (LOG_INFO, "zonestat_inc task %u", (unsigned)task->oldserial));
2082c1404d4fSbrad nsd->zonestatdesired = (unsigned)task->oldserial;
2083c1404d4fSbrad /* send echo to xfrd to increment on its end */
2084c1404d4fSbrad task_new_zonestat_inc(udb, last_task, nsd->zonestatdesired);
2085c1404d4fSbrad }
2086c1404d4fSbrad #endif
2087c1404d4fSbrad
2088d3fecca9Ssthen static void
task_process_apply_xfr(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,udb_ptr * task)2089d3fecca9Ssthen task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
2090d3fecca9Ssthen udb_ptr* task)
2091d3fecca9Ssthen {
2092d3fecca9Ssthen /* we have to use an udb_ptr task here, because the apply_xfr procedure
2093d3fecca9Ssthen * appends soa_info which may remap and change the pointer. */
2094d3fecca9Ssthen zone_type* zone;
209562ac0c33Sjakob FILE* df;
2096d3fecca9Ssthen DEBUG(DEBUG_IPC,1, (LOG_INFO, "applyxfr task %s", dname_to_string(
2097d3fecca9Ssthen TASKLIST(task)->zname, NULL)));
2098d3fecca9Ssthen zone = namedb_find_zone(nsd->db, TASKLIST(task)->zname);
2099d3fecca9Ssthen if(!zone) {
2100d3fecca9Ssthen /* assume the zone has been deleted and a zone transfer was
2101d3fecca9Ssthen * still waiting to be processed */
2102d3fecca9Ssthen return;
2103d3fecca9Ssthen }
21043f21e8ccSflorian
2105d3fecca9Ssthen /* apply the XFR */
2106d3fecca9Ssthen /* oldserial, newserial, yesno is filenumber */
2107d3fecca9Ssthen df = xfrd_open_xfrfile(nsd, TASKLIST(task)->yesno, "r");
210862ac0c33Sjakob if(!df) {
2109d3fecca9Ssthen /* could not open file to update */
21103f21e8ccSflorian /* soainfo_gone will be communicated from server_reload, unless
21113f21e8ccSflorian preceding updates have been applied */
21123f21e8ccSflorian zone->is_skipped = 1;
211362ac0c33Sjakob return;
211462ac0c33Sjakob }
2115d3fecca9Ssthen /* read and apply zone transfer */
2116*bf87c3c0Sflorian switch(apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb, last_task,
2117*bf87c3c0Sflorian TASKLIST(task)->yesno)) {
2118*bf87c3c0Sflorian case 1: /* Success */
2119*bf87c3c0Sflorian break;
2120*bf87c3c0Sflorian
2121*bf87c3c0Sflorian case 0: /* Failure */
21223f21e8ccSflorian /* soainfo_gone will be communicated from server_reload, unless
21233f21e8ccSflorian preceding updates have been applied */
21243f21e8ccSflorian zone->is_skipped = 1;
2125*bf87c3c0Sflorian break;
212662ac0c33Sjakob
2127*bf87c3c0Sflorian case -1:/* Fatal */
2128*bf87c3c0Sflorian exit(1);
2129*bf87c3c0Sflorian break;
2130*bf87c3c0Sflorian
2131*bf87c3c0Sflorian default:break;
2132*bf87c3c0Sflorian }
2133d3fecca9Ssthen fclose(df);
2134d3fecca9Ssthen }
2135d3fecca9Ssthen
2136d3fecca9Ssthen
task_process_in_reload(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,udb_ptr * task)2137d3fecca9Ssthen void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
2138d3fecca9Ssthen udb_ptr* task)
213962ac0c33Sjakob {
2140d3fecca9Ssthen switch(TASKLIST(task)->task_type) {
2141d3fecca9Ssthen case task_expire:
2142d3fecca9Ssthen task_process_expire(nsd->db, TASKLIST(task));
2143d3fecca9Ssthen break;
2144d3fecca9Ssthen case task_check_zonefiles:
2145d3fecca9Ssthen task_process_checkzones(nsd, udb, last_task, TASKLIST(task));
2146d3fecca9Ssthen break;
2147d3fecca9Ssthen case task_write_zonefiles:
2148d3fecca9Ssthen task_process_writezones(nsd, TASKLIST(task));
2149d3fecca9Ssthen break;
2150d3fecca9Ssthen case task_set_verbosity:
2151d3fecca9Ssthen task_process_set_verbosity(TASKLIST(task));
2152d3fecca9Ssthen break;
2153d3fecca9Ssthen case task_add_zone:
2154d3fecca9Ssthen task_process_add_zone(nsd, udb, last_task, TASKLIST(task));
2155d3fecca9Ssthen break;
2156d3fecca9Ssthen case task_del_zone:
2157d3fecca9Ssthen task_process_del_zone(nsd, TASKLIST(task));
2158d3fecca9Ssthen break;
2159d3fecca9Ssthen case task_add_key:
2160d3fecca9Ssthen task_process_add_key(nsd, TASKLIST(task));
2161d3fecca9Ssthen break;
2162d3fecca9Ssthen case task_del_key:
2163d3fecca9Ssthen task_process_del_key(nsd, TASKLIST(task));
2164d3fecca9Ssthen break;
2165d3fecca9Ssthen case task_add_pattern:
2166d3fecca9Ssthen task_process_add_pattern(nsd, TASKLIST(task));
2167d3fecca9Ssthen break;
2168d3fecca9Ssthen case task_del_pattern:
2169d3fecca9Ssthen task_process_del_pattern(nsd, TASKLIST(task));
2170d3fecca9Ssthen break;
2171d3fecca9Ssthen case task_opt_change:
2172d3fecca9Ssthen task_process_opt_change(nsd, TASKLIST(task));
2173d3fecca9Ssthen break;
2174c1404d4fSbrad #ifdef USE_ZONE_STATS
2175c1404d4fSbrad case task_zonestat_inc:
2176c1404d4fSbrad task_process_zonestat_inc(nsd, udb, last_task, TASKLIST(task));
2177c1404d4fSbrad break;
2178c1404d4fSbrad #endif
2179d3fecca9Ssthen case task_apply_xfr:
2180d3fecca9Ssthen task_process_apply_xfr(nsd, udb, last_task, task);
2181d3fecca9Ssthen break;
2182063644e9Sflorian case task_add_cookie_secret:
2183063644e9Sflorian task_process_add_cookie_secret(nsd, TASKLIST(task));
2184063644e9Sflorian break;
2185063644e9Sflorian case task_drop_cookie_secret:
2186063644e9Sflorian task_process_drop_cookie_secret(nsd, TASKLIST(task));
2187063644e9Sflorian break;
2188063644e9Sflorian case task_activate_cookie_secret:
2189063644e9Sflorian task_process_activate_cookie_secret(nsd, TASKLIST(task));
2190063644e9Sflorian break;
2191d3fecca9Ssthen default:
2192d3fecca9Ssthen log_msg(LOG_WARNING, "unhandled task in reload type %d",
2193d3fecca9Ssthen (int)TASKLIST(task)->task_type);
2194d3fecca9Ssthen break;
219562ac0c33Sjakob }
2196d3fecca9Ssthen udb_ptr_free_space(task, udb, TASKLIST(task)->size);
219762ac0c33Sjakob }
2198