14564029fSflorian /*
24564029fSflorian * ixfrcreate.c -- generating IXFR differences from zone files.
34564029fSflorian *
44564029fSflorian * Copyright (c) 2021, NLnet Labs. All rights reserved.
54564029fSflorian *
64564029fSflorian * See LICENSE for the license.
74564029fSflorian *
84564029fSflorian */
94564029fSflorian
104564029fSflorian #include "config.h"
114564029fSflorian #include <stdio.h>
124564029fSflorian #include <errno.h>
134564029fSflorian #include <unistd.h>
144564029fSflorian #include "ixfrcreate.h"
154564029fSflorian #include "namedb.h"
164564029fSflorian #include "ixfr.h"
174564029fSflorian #include "options.h"
184564029fSflorian
194564029fSflorian /* spool a uint16_t to file */
spool_u16(FILE * out,uint16_t val)204564029fSflorian static int spool_u16(FILE* out, uint16_t val)
214564029fSflorian {
224564029fSflorian if(!fwrite(&val, sizeof(val), 1, out)) {
234564029fSflorian return 0;
244564029fSflorian }
254564029fSflorian return 1;
264564029fSflorian }
274564029fSflorian
284564029fSflorian /* spool a uint32_t to file */
spool_u32(FILE * out,uint32_t val)294564029fSflorian static int spool_u32(FILE* out, uint32_t val)
304564029fSflorian {
314564029fSflorian if(!fwrite(&val, sizeof(val), 1, out)) {
324564029fSflorian return 0;
334564029fSflorian }
344564029fSflorian return 1;
354564029fSflorian }
364564029fSflorian
374564029fSflorian /* spool dname to file */
spool_dname(FILE * out,dname_type * dname)384564029fSflorian static int spool_dname(FILE* out, dname_type* dname)
394564029fSflorian {
404564029fSflorian uint16_t namelen = dname->name_size;
414564029fSflorian if(!fwrite(&namelen, sizeof(namelen), 1, out)) {
424564029fSflorian return 0;
434564029fSflorian }
444564029fSflorian if(!fwrite(dname_name(dname), namelen, 1, out)) {
454564029fSflorian return 0;
464564029fSflorian }
474564029fSflorian return 1;
484564029fSflorian }
494564029fSflorian
504564029fSflorian /* calculate the rdatalen of an RR */
rr_rdatalen_uncompressed(rr_type * rr)514564029fSflorian static size_t rr_rdatalen_uncompressed(rr_type* rr)
524564029fSflorian {
534564029fSflorian int i;
544564029fSflorian size_t rdlen_uncompressed = 0;
554564029fSflorian for(i=0; i<rr->rdata_count; i++) {
564564029fSflorian if(rdata_atom_is_domain(rr->type, i)) {
574564029fSflorian rdlen_uncompressed += domain_dname(rr->rdatas[i].domain)
584564029fSflorian ->name_size;
594564029fSflorian } else {
604564029fSflorian rdlen_uncompressed += rr->rdatas[i].data[0];
614564029fSflorian }
624564029fSflorian }
634564029fSflorian return rdlen_uncompressed;
644564029fSflorian }
654564029fSflorian
664564029fSflorian /* spool the data for one rr into the file */
spool_rr_data(FILE * out,rr_type * rr)674564029fSflorian static int spool_rr_data(FILE* out, rr_type* rr)
684564029fSflorian {
694564029fSflorian int i;
704564029fSflorian uint16_t rdlen;
714564029fSflorian if(!spool_u32(out, rr->ttl))
724564029fSflorian return 0;
734564029fSflorian rdlen = rr_rdatalen_uncompressed(rr);
744564029fSflorian if(!spool_u16(out, rdlen))
754564029fSflorian return 0;
764564029fSflorian for(i=0; i<rr->rdata_count; i++) {
774564029fSflorian if(rdata_atom_is_domain(rr->type, i)) {
784564029fSflorian if(!fwrite(dname_name(domain_dname(
794564029fSflorian rr->rdatas[i].domain)), domain_dname(
804564029fSflorian rr->rdatas[i].domain)->name_size, 1, out))
814564029fSflorian return 0;
824564029fSflorian } else {
834564029fSflorian if(!fwrite(&rr->rdatas[i].data[1],
844564029fSflorian rr->rdatas[i].data[0], 1, out))
854564029fSflorian return 0;
864564029fSflorian }
874564029fSflorian }
884564029fSflorian return 1;
894564029fSflorian }
904564029fSflorian
914564029fSflorian /* spool one rrset to file */
spool_rrset(FILE * out,rrset_type * rrset)924564029fSflorian static int spool_rrset(FILE* out, rrset_type* rrset)
934564029fSflorian {
944564029fSflorian int i;
954564029fSflorian if(rrset->rr_count == 0)
964564029fSflorian return 1;
974564029fSflorian if(!spool_u16(out, rrset->rrs[0].type))
984564029fSflorian return 0;
994564029fSflorian if(!spool_u16(out, rrset->rrs[0].klass))
1004564029fSflorian return 0;
1014564029fSflorian if(!spool_u16(out, rrset->rr_count))
1024564029fSflorian return 0;
1034564029fSflorian for(i=0; i<rrset->rr_count; i++) {
1044564029fSflorian if(!spool_rr_data(out, &rrset->rrs[i]))
1054564029fSflorian return 0;
1064564029fSflorian }
1074564029fSflorian return 1;
1084564029fSflorian }
1094564029fSflorian
1104564029fSflorian /* spool rrsets to file */
spool_rrsets(FILE * out,rrset_type * rrsets,struct zone * zone)1114564029fSflorian static int spool_rrsets(FILE* out, rrset_type* rrsets, struct zone* zone)
1124564029fSflorian {
1134564029fSflorian rrset_type* s;
1144564029fSflorian for(s=rrsets; s; s=s->next) {
1154564029fSflorian if(s->zone != zone)
1164564029fSflorian continue;
1174564029fSflorian if(!spool_rrset(out, s)) {
1184564029fSflorian return 0;
1194564029fSflorian }
1204564029fSflorian }
1214564029fSflorian return 1;
1224564029fSflorian }
1234564029fSflorian
1244564029fSflorian /* count number of rrsets for a domain */
domain_count_rrsets(domain_type * domain,zone_type * zone)1254564029fSflorian static size_t domain_count_rrsets(domain_type* domain, zone_type* zone)
1264564029fSflorian {
1274564029fSflorian rrset_type* s;
1284564029fSflorian size_t count = 0;
1294564029fSflorian for(s=domain->rrsets; s; s=s->next) {
1304564029fSflorian if(s->zone == zone)
1314564029fSflorian count++;
1324564029fSflorian }
1334564029fSflorian return count;
1344564029fSflorian }
1354564029fSflorian
1364564029fSflorian /* spool the domain names to file, each one in turn. end with enddelimiter */
spool_domains(FILE * out,struct zone * zone)1374564029fSflorian static int spool_domains(FILE* out, struct zone* zone)
1384564029fSflorian {
1394564029fSflorian domain_type* domain;
1404564029fSflorian for(domain = zone->apex; domain && domain_is_subdomain(domain,
1414564029fSflorian zone->apex); domain = domain_next(domain)) {
1424564029fSflorian uint32_t count = domain_count_rrsets(domain, zone);
1434564029fSflorian if(count == 0)
1444564029fSflorian continue;
1454564029fSflorian /* write the name */
1464564029fSflorian if(!spool_dname(out, domain_dname(domain)))
1474564029fSflorian return 0;
1484564029fSflorian if(!spool_u32(out, count))
1494564029fSflorian return 0;
1504564029fSflorian /* write the rrsets */
1514564029fSflorian if(!spool_rrsets(out, domain->rrsets, zone))
1524564029fSflorian return 0;
1534564029fSflorian }
1544564029fSflorian /* the end delimiter is a 0 length. domain names are not zero length */
1554564029fSflorian if(!spool_u16(out, 0))
1564564029fSflorian return 0;
1574564029fSflorian return 1;
1584564029fSflorian }
1594564029fSflorian
1604564029fSflorian /* spool the namedb zone to the file. print error on failure. */
spool_zone_to_file(struct zone * zone,char * file_name,uint32_t serial)1614564029fSflorian static int spool_zone_to_file(struct zone* zone, char* file_name,
1624564029fSflorian uint32_t serial)
1634564029fSflorian {
1644564029fSflorian FILE* out;
1654564029fSflorian out = fopen(file_name, "w");
1664564029fSflorian if(!out) {
1674564029fSflorian log_msg(LOG_ERR, "could not open %s for writing: %s",
1684564029fSflorian file_name, strerror(errno));
1694564029fSflorian return 0;
1704564029fSflorian }
1714564029fSflorian if(!spool_dname(out, domain_dname(zone->apex))) {
1724564029fSflorian log_msg(LOG_ERR, "could not write %s: %s",
1734564029fSflorian file_name, strerror(errno));
1743f21e8ccSflorian fclose(out);
1754564029fSflorian return 0;
1764564029fSflorian }
1774564029fSflorian if(!spool_u32(out, serial)) {
1784564029fSflorian log_msg(LOG_ERR, "could not write %s: %s",
1794564029fSflorian file_name, strerror(errno));
1803f21e8ccSflorian fclose(out);
1814564029fSflorian return 0;
1824564029fSflorian }
1834564029fSflorian if(!spool_domains(out, zone)) {
1844564029fSflorian log_msg(LOG_ERR, "could not write %s: %s",
1854564029fSflorian file_name, strerror(errno));
1863f21e8ccSflorian fclose(out);
1874564029fSflorian return 0;
1884564029fSflorian }
1894564029fSflorian fclose(out);
1904564029fSflorian return 1;
1914564029fSflorian }
1924564029fSflorian
1934564029fSflorian /* create ixfr spool file name */
create_ixfr_spool_name(struct ixfr_create * ixfrcr,const char * zfile)1944564029fSflorian static int create_ixfr_spool_name(struct ixfr_create* ixfrcr,
1954564029fSflorian const char* zfile)
1964564029fSflorian {
1974564029fSflorian char buf[1024];
1984564029fSflorian snprintf(buf, sizeof(buf), "%s.spoolzone.%u", zfile,
1994564029fSflorian (unsigned)getpid());
2004564029fSflorian ixfrcr->file_name = strdup(buf);
2014564029fSflorian if(!ixfrcr->file_name)
2024564029fSflorian return 0;
2034564029fSflorian return 1;
2044564029fSflorian }
2054564029fSflorian
2064564029fSflorian /* start ixfr creation */
ixfr_create_start(struct zone * zone,const char * zfile,uint64_t ixfr_size,int errorcmdline)2074564029fSflorian struct ixfr_create* ixfr_create_start(struct zone* zone, const char* zfile,
2084564029fSflorian uint64_t ixfr_size, int errorcmdline)
2094564029fSflorian {
2104564029fSflorian struct ixfr_create* ixfrcr = (struct ixfr_create*)calloc(1,
2114564029fSflorian sizeof(*ixfrcr));
2124564029fSflorian if(!ixfrcr) {
2134564029fSflorian log_msg(LOG_ERR, "malloc failure");
2144564029fSflorian return NULL;
2154564029fSflorian }
2164564029fSflorian ixfrcr->zone_name_len = domain_dname(zone->apex)->name_size;
2174564029fSflorian ixfrcr->zone_name = (uint8_t*)malloc(ixfrcr->zone_name_len);
2184564029fSflorian if(!ixfrcr->zone_name) {
2194564029fSflorian free(ixfrcr);
2204564029fSflorian log_msg(LOG_ERR, "malloc failure");
2214564029fSflorian return NULL;
2224564029fSflorian }
2234564029fSflorian memmove(ixfrcr->zone_name, dname_name(domain_dname(zone->apex)),
2244564029fSflorian ixfrcr->zone_name_len);
2254564029fSflorian
2264564029fSflorian if(!create_ixfr_spool_name(ixfrcr, zfile)) {
2274564029fSflorian ixfr_create_free(ixfrcr);
2284564029fSflorian log_msg(LOG_ERR, "malloc failure");
2294564029fSflorian return NULL;
2304564029fSflorian }
2314564029fSflorian ixfrcr->old_serial = zone_get_current_serial(zone);
2324564029fSflorian if(!spool_zone_to_file(zone, ixfrcr->file_name, ixfrcr->old_serial)) {
2334564029fSflorian ixfr_create_free(ixfrcr);
2344564029fSflorian return NULL;
2354564029fSflorian }
2364564029fSflorian if(zone->opts && zone->opts->pattern)
2374564029fSflorian ixfrcr->max_size = (size_t)zone->opts->pattern->ixfr_size;
2384564029fSflorian else ixfrcr->max_size = (size_t)ixfr_size;
2394564029fSflorian ixfrcr->errorcmdline = errorcmdline;
2404564029fSflorian return ixfrcr;
2414564029fSflorian }
2424564029fSflorian
2434564029fSflorian /* free ixfr create */
ixfr_create_free(struct ixfr_create * ixfrcr)2444564029fSflorian void ixfr_create_free(struct ixfr_create* ixfrcr)
2454564029fSflorian {
2464564029fSflorian if(!ixfrcr)
2474564029fSflorian return;
2484564029fSflorian free(ixfrcr->file_name);
2494564029fSflorian free(ixfrcr->zone_name);
2504564029fSflorian free(ixfrcr);
2514564029fSflorian }
2524564029fSflorian
2534564029fSflorian /* read uint16_t from spool */
read_spool_u16(FILE * spool,uint16_t * val)2544564029fSflorian static int read_spool_u16(FILE* spool, uint16_t* val)
2554564029fSflorian {
2563f21e8ccSflorian if(fread(val, sizeof(*val), 1, spool) < 1)
2574564029fSflorian return 0;
2584564029fSflorian return 1;
2594564029fSflorian }
2604564029fSflorian
2614564029fSflorian /* read uint32_t from spool */
read_spool_u32(FILE * spool,uint32_t * val)2624564029fSflorian static int read_spool_u32(FILE* spool, uint32_t* val)
2634564029fSflorian {
2643f21e8ccSflorian if(fread(val, sizeof(*val), 1, spool) < 1)
2654564029fSflorian return 0;
2664564029fSflorian return 1;
2674564029fSflorian }
2684564029fSflorian
2694564029fSflorian /* read dname from spool */
read_spool_dname(FILE * spool,uint8_t * buf,size_t buflen,size_t * dname_len)2704564029fSflorian static int read_spool_dname(FILE* spool, uint8_t* buf, size_t buflen,
2714564029fSflorian size_t* dname_len)
2724564029fSflorian {
2734564029fSflorian uint16_t len;
2743f21e8ccSflorian if(fread(&len, sizeof(len), 1, spool) < 1)
2754564029fSflorian return 0;
2764564029fSflorian if(len > buflen) {
2774564029fSflorian log_msg(LOG_ERR, "dname too long");
2784564029fSflorian return 0;
2794564029fSflorian }
2804564029fSflorian if(len > 0) {
2813f21e8ccSflorian if(fread(buf, len, 1, spool) < 1)
2824564029fSflorian return 0;
2834564029fSflorian }
2844564029fSflorian *dname_len = len;
2854564029fSflorian return 1;
2864564029fSflorian }
2874564029fSflorian
2884564029fSflorian /* read and check the spool file header */
read_spool_header(FILE * spool,struct ixfr_create * ixfrcr)2894564029fSflorian static int read_spool_header(FILE* spool, struct ixfr_create* ixfrcr)
2904564029fSflorian {
2914564029fSflorian uint8_t dname[MAXDOMAINLEN+1];
2924564029fSflorian size_t dname_len;
2934564029fSflorian uint32_t serial;
2944564029fSflorian /* read apex */
2954564029fSflorian if(!read_spool_dname(spool, dname, sizeof(dname), &dname_len)) {
2964564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
2974564029fSflorian ixfrcr->file_name, strerror(errno));
2984564029fSflorian return 0;
2994564029fSflorian }
3004564029fSflorian /* read serial */
3014564029fSflorian if(!read_spool_u32(spool, &serial)) {
3024564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
3034564029fSflorian ixfrcr->file_name, strerror(errno));
3044564029fSflorian return 0;
3054564029fSflorian }
3064564029fSflorian
3074564029fSflorian /* check */
3084564029fSflorian if(ixfrcr->zone_name_len != dname_len ||
3094564029fSflorian memcmp(ixfrcr->zone_name, dname, ixfrcr->zone_name_len) != 0) {
3104564029fSflorian log_msg(LOG_ERR, "error file %s does not contain the correct zone apex",
3114564029fSflorian ixfrcr->file_name);
3124564029fSflorian return 0;
3134564029fSflorian }
3144564029fSflorian if(ixfrcr->old_serial != serial) {
3154564029fSflorian log_msg(LOG_ERR, "error file %s does not contain the correct zone serial",
3164564029fSflorian ixfrcr->file_name);
3174564029fSflorian return 0;
3184564029fSflorian }
3194564029fSflorian return 1;
3204564029fSflorian }
3214564029fSflorian
3224564029fSflorian /* store the old soa record when we encounter it on the spool */
process_store_oldsoa(struct ixfr_store * store,uint8_t * dname,size_t dname_len,uint16_t tp,uint16_t kl,uint32_t ttl,uint8_t * buf,uint16_t rdlen)3234564029fSflorian static int process_store_oldsoa(struct ixfr_store* store, uint8_t* dname,
3244564029fSflorian size_t dname_len, uint16_t tp, uint16_t kl, uint32_t ttl, uint8_t* buf,
3254564029fSflorian uint16_t rdlen)
3264564029fSflorian {
3274564029fSflorian if(store->data->oldsoa) {
3284564029fSflorian log_msg(LOG_ERR, "error spool contains multiple SOA records");
3294564029fSflorian return 0;
3304564029fSflorian }
3314564029fSflorian if(!ixfr_store_oldsoa_uncompressed(store, dname, dname_len, tp, kl,
3324564029fSflorian ttl, buf, rdlen)) {
3334564029fSflorian log_msg(LOG_ERR, "out of memory");
3344564029fSflorian return 0;
3354564029fSflorian }
3364564029fSflorian return 1;
3374564029fSflorian }
3384564029fSflorian
3394564029fSflorian /* see if rdata matches, true if equal */
rdata_match(struct rr * rr,uint8_t * rdata,uint16_t rdlen)3404564029fSflorian static int rdata_match(struct rr* rr, uint8_t* rdata, uint16_t rdlen)
3414564029fSflorian {
3424564029fSflorian size_t rdpos = 0;
3434564029fSflorian int i;
3444564029fSflorian for(i=0; i<rr->rdata_count; i++) {
3454564029fSflorian if(rdata_atom_is_domain(rr->type, i)) {
3464564029fSflorian if(rdpos + domain_dname(rr->rdatas[i].domain)->name_size
3474564029fSflorian > rdlen)
3484564029fSflorian return 0;
3494564029fSflorian if(memcmp(rdata+rdpos,
3504564029fSflorian dname_name(domain_dname(rr->rdatas[i].domain)),
3514564029fSflorian domain_dname(rr->rdatas[i].domain)->name_size)
3524564029fSflorian != 0)
3534564029fSflorian return 0;
3544564029fSflorian rdpos += domain_dname(rr->rdatas[i].domain)->name_size;
3554564029fSflorian } else {
3564564029fSflorian if(rdpos + rr->rdatas[i].data[0] > rdlen)
3574564029fSflorian return 0;
3584564029fSflorian if(memcmp(rdata+rdpos, &rr->rdatas[i].data[1],
3594564029fSflorian rr->rdatas[i].data[0]) != 0)
3604564029fSflorian return 0;
3614564029fSflorian rdpos += rr->rdatas[i].data[0];
3624564029fSflorian }
3634564029fSflorian }
3644564029fSflorian if(rdpos != rdlen)
3654564029fSflorian return 0;
3664564029fSflorian return 1;
3674564029fSflorian }
3684564029fSflorian
3694564029fSflorian /* find an rdata in an rrset, true if found and sets index found */
rrset_find_rdata(struct rrset * rrset,uint32_t ttl,uint8_t * rdata,uint16_t rdlen,uint16_t * index)3704564029fSflorian static int rrset_find_rdata(struct rrset* rrset, uint32_t ttl, uint8_t* rdata,
3714564029fSflorian uint16_t rdlen, uint16_t* index)
3724564029fSflorian {
3734564029fSflorian int i;
3744564029fSflorian for(i=0; i<rrset->rr_count; i++) {
3754564029fSflorian if(rrset->rrs[i].ttl != ttl)
3764564029fSflorian continue;
3774564029fSflorian if(rdata_match(&rrset->rrs[i], rdata, rdlen)) {
3784564029fSflorian *index = i;
3794564029fSflorian return 1;
3804564029fSflorian }
3814564029fSflorian }
3824564029fSflorian return 0;
3834564029fSflorian }
3844564029fSflorian
3854564029fSflorian /* sort comparison for uint16 elements */
sort_uint16(const void * x,const void * y)3864564029fSflorian static int sort_uint16(const void* x, const void* y)
3874564029fSflorian {
3884564029fSflorian const uint16_t* ax = (const uint16_t*)x;
3894564029fSflorian const uint16_t* ay = (const uint16_t*)y;
3904564029fSflorian if(*ax < *ay)
3914564029fSflorian return -1;
3924564029fSflorian if(*ax > *ay)
3934564029fSflorian return 1;
3944564029fSflorian return 0;
3954564029fSflorian }
3964564029fSflorian
3974564029fSflorian /* spool read an rrset, it is a deleted RRset */
process_diff_rrset(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct domain * domain,uint16_t tp,uint16_t kl,uint16_t rrcount,struct rrset * rrset)3984564029fSflorian static int process_diff_rrset(FILE* spool, struct ixfr_create* ixfrcr,
3994564029fSflorian struct ixfr_store* store, struct domain* domain,
4004564029fSflorian uint16_t tp, uint16_t kl, uint16_t rrcount, struct rrset* rrset)
4014564029fSflorian {
4024564029fSflorian /* read RRs from file and see if they are added, deleted or in both */
4034564029fSflorian uint8_t buf[MAX_RDLENGTH];
4044564029fSflorian uint16_t marked[65536];
4054564029fSflorian size_t marked_num = 0, atmarked;
4064564029fSflorian int i;
4074564029fSflorian for(i=0; i<rrcount; i++) {
4084564029fSflorian uint16_t rdlen, index;
4094564029fSflorian uint32_t ttl;
4104564029fSflorian if(!read_spool_u32(spool, &ttl) ||
4114564029fSflorian !read_spool_u16(spool, &rdlen)) {
4124564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
4134564029fSflorian ixfrcr->file_name, strerror(errno));
4144564029fSflorian return 0;
4154564029fSflorian }
4164564029fSflorian /* because rdlen is uint16_t always smaller than sizeof(buf)*/
4173f21e8ccSflorian #pragma GCC diagnostic push
4183f21e8ccSflorian #pragma GCC diagnostic ignored "-Wtype-limits"
4193f21e8ccSflorian assert(rdlen <= sizeof(buf));
4203f21e8ccSflorian #pragma GCC diagnostic pop
4213f21e8ccSflorian if(fread(buf, rdlen, 1, spool) < 1) {
4224564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
4234564029fSflorian ixfrcr->file_name, strerror(errno));
4244564029fSflorian return 0;
4254564029fSflorian }
4264564029fSflorian if(tp == TYPE_SOA) {
4274564029fSflorian if(!process_store_oldsoa(store,
4284564029fSflorian (void*)dname_name(domain_dname(domain)),
4294564029fSflorian domain_dname(domain)->name_size, tp, kl, ttl,
4304564029fSflorian buf, rdlen))
4314564029fSflorian return 0;
4324564029fSflorian }
4334564029fSflorian /* see if the rr is in the RRset */
4344564029fSflorian if(rrset_find_rdata(rrset, ttl, buf, rdlen, &index)) {
4354564029fSflorian /* it is in both, mark it */
4364564029fSflorian marked[marked_num++] = index;
4374564029fSflorian } else {
4384564029fSflorian /* not in new rrset, but only on spool, it is
4394564029fSflorian * a deleted RR */
4404564029fSflorian if(!ixfr_store_delrr_uncompressed(store,
4414564029fSflorian (void*)dname_name(domain_dname(domain)),
4424564029fSflorian domain_dname(domain)->name_size,
4434564029fSflorian tp, kl, ttl, buf, rdlen)) {
4444564029fSflorian log_msg(LOG_ERR, "out of memory");
4454564029fSflorian return 0;
4464564029fSflorian }
4474564029fSflorian }
4484564029fSflorian }
4494564029fSflorian /* now that we are done, see if RRs in the rrset are not marked,
4504564029fSflorian * and thus are new rrs that are added */
4514564029fSflorian qsort(marked, marked_num, sizeof(marked[0]), &sort_uint16);
4524564029fSflorian atmarked = 0;
4534564029fSflorian for(i=0; i<rrset->rr_count; i++) {
4544564029fSflorian if(atmarked < marked_num && marked[atmarked] == i) {
4554564029fSflorian /* the item is in the marked list, skip it */
4564564029fSflorian atmarked++;
4574564029fSflorian continue;
4584564029fSflorian }
4594564029fSflorian /* not in the marked list, the RR is added */
4604564029fSflorian if(!ixfr_store_addrr_rdatas(store, domain_dname(domain),
4614564029fSflorian rrset->rrs[i].type, rrset->rrs[i].klass,
4624564029fSflorian rrset->rrs[i].ttl, rrset->rrs[i].rdatas,
4634564029fSflorian rrset->rrs[i].rdata_count)) {
4644564029fSflorian log_msg(LOG_ERR, "out of memory");
4654564029fSflorian return 0;
4664564029fSflorian }
4674564029fSflorian }
4684564029fSflorian return 1;
4694564029fSflorian }
4704564029fSflorian
4714564029fSflorian /* spool read an rrset, it is a deleted RRset */
process_spool_delrrset(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,uint8_t * dname,size_t dname_len,uint16_t tp,uint16_t kl,uint16_t rrcount)4724564029fSflorian static int process_spool_delrrset(FILE* spool, struct ixfr_create* ixfrcr,
4734564029fSflorian struct ixfr_store* store, uint8_t* dname, size_t dname_len,
4744564029fSflorian uint16_t tp, uint16_t kl, uint16_t rrcount)
4754564029fSflorian {
4764564029fSflorian /* read the RRs from file and add to del list. */
4774564029fSflorian uint8_t buf[MAX_RDLENGTH];
4784564029fSflorian int i;
4794564029fSflorian for(i=0; i<rrcount; i++) {
4804564029fSflorian uint16_t rdlen;
4814564029fSflorian uint32_t ttl;
4824564029fSflorian if(!read_spool_u32(spool, &ttl) ||
4834564029fSflorian !read_spool_u16(spool, &rdlen)) {
4844564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
4854564029fSflorian ixfrcr->file_name, strerror(errno));
4864564029fSflorian return 0;
4874564029fSflorian }
4884564029fSflorian /* because rdlen is uint16_t always smaller than sizeof(buf)*/
4893f21e8ccSflorian #pragma GCC diagnostic push
4903f21e8ccSflorian #pragma GCC diagnostic ignored "-Wtype-limits"
4913f21e8ccSflorian assert(rdlen <= sizeof(buf));
4923f21e8ccSflorian #pragma GCC diagnostic pop
4933f21e8ccSflorian if(fread(buf, rdlen, 1, spool) < 1) {
4944564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
4954564029fSflorian ixfrcr->file_name, strerror(errno));
4964564029fSflorian return 0;
4974564029fSflorian }
4984564029fSflorian if(tp == TYPE_SOA) {
4994564029fSflorian if(!process_store_oldsoa(store, dname, dname_len,
5004564029fSflorian tp, kl, ttl, buf, rdlen))
5014564029fSflorian return 0;
5024564029fSflorian }
5034564029fSflorian if(!ixfr_store_delrr_uncompressed(store, dname, dname_len, tp,
5044564029fSflorian kl, ttl, buf, rdlen)) {
5054564029fSflorian log_msg(LOG_ERR, "out of memory");
5064564029fSflorian return 0;
5074564029fSflorian }
5084564029fSflorian }
5094564029fSflorian return 1;
5104564029fSflorian }
5114564029fSflorian
5124564029fSflorian /* add the rrset to the added list */
process_add_rrset(struct ixfr_store * ixfr_store,struct domain * domain,struct rrset * rrset)5134564029fSflorian static int process_add_rrset(struct ixfr_store* ixfr_store,
5144564029fSflorian struct domain* domain, struct rrset* rrset)
5154564029fSflorian {
5164564029fSflorian int i;
5174564029fSflorian for(i=0; i<rrset->rr_count; i++) {
5184564029fSflorian if(!ixfr_store_addrr_rdatas(ixfr_store, domain_dname(domain),
5194564029fSflorian rrset->rrs[i].type, rrset->rrs[i].klass,
5204564029fSflorian rrset->rrs[i].ttl, rrset->rrs[i].rdatas,
5214564029fSflorian rrset->rrs[i].rdata_count)) {
5224564029fSflorian log_msg(LOG_ERR, "out of memory");
5234564029fSflorian return 0;
5244564029fSflorian }
5254564029fSflorian }
5264564029fSflorian return 1;
5274564029fSflorian }
5284564029fSflorian
5294564029fSflorian /* add the RR types that are not in the marktypes list from the new zone */
process_marktypes(struct ixfr_store * store,struct zone * zone,struct domain * domain,uint16_t * marktypes,size_t marktypes_used)5304564029fSflorian static int process_marktypes(struct ixfr_store* store, struct zone* zone,
5314564029fSflorian struct domain* domain, uint16_t* marktypes, size_t marktypes_used)
5324564029fSflorian {
5334564029fSflorian /* walk through the rrsets in the zone, if it is not in the
5344564029fSflorian * marktypes list, then it is new and an added RRset */
5354564029fSflorian rrset_type* s;
5364564029fSflorian qsort(marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16);
5374564029fSflorian for(s=domain->rrsets; s; s=s->next) {
5384564029fSflorian uint16_t tp;
5394564029fSflorian if(s->zone != zone)
5404564029fSflorian continue;
5414564029fSflorian tp = rrset_rrtype(s);
5423efee2e1Sflorian if(bsearch(&tp, marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16)) {
5434564029fSflorian /* the item is in the marked list, skip it */
5444564029fSflorian continue;
5454564029fSflorian }
5464564029fSflorian if(!process_add_rrset(store, domain, s))
5474564029fSflorian return 0;
5484564029fSflorian }
5494564029fSflorian return 1;
5504564029fSflorian }
5514564029fSflorian
5524564029fSflorian /* check the difference between the domain and RRs from spool */
process_diff_domain(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone,struct domain * domain)5534564029fSflorian static int process_diff_domain(FILE* spool, struct ixfr_create* ixfrcr,
5544564029fSflorian struct ixfr_store* store, struct zone* zone, struct domain* domain)
5554564029fSflorian {
5564564029fSflorian /* Read the RR types from spool. Mark off the ones seen,
5574564029fSflorian * later, the notseen ones from the new zone are added RRsets.
5584564029fSflorian * For the ones not in the new zone, they are deleted RRsets.
5594564029fSflorian * If they exist in old and new, check for RR differences. */
5604564029fSflorian uint32_t spool_type_count, i;
5614564029fSflorian uint16_t marktypes[65536];
5624564029fSflorian size_t marktypes_used = 0;
5634564029fSflorian if(!read_spool_u32(spool, &spool_type_count)) {
5644564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
5654564029fSflorian ixfrcr->file_name, strerror(errno));
5664564029fSflorian return 0;
5674564029fSflorian }
5683f21e8ccSflorian if(spool_type_count > sizeof(marktypes)) {
5693f21e8ccSflorian log_msg(LOG_ERR, "error reading file %s: spool type count "
5703f21e8ccSflorian "too large", ixfrcr->file_name);
5713f21e8ccSflorian return 0;
5723f21e8ccSflorian }
5734564029fSflorian for(i=0; i<spool_type_count; i++) {
5744564029fSflorian uint16_t tp, kl, rrcount;
5754564029fSflorian struct rrset* rrset;
5764564029fSflorian if(!read_spool_u16(spool, &tp) ||
5774564029fSflorian !read_spool_u16(spool, &kl) ||
5784564029fSflorian !read_spool_u16(spool, &rrcount)) {
5794564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
5804564029fSflorian ixfrcr->file_name, strerror(errno));
5814564029fSflorian return 0;
5824564029fSflorian }
5833f21e8ccSflorian /* The rrcount is within limits of sizeof(marktypes), because
5843f21e8ccSflorian * the uint16_t < 65536 */
5854564029fSflorian rrset = domain_find_rrset(domain, zone, tp);
5864564029fSflorian if(!rrset) {
5874564029fSflorian /* rrset in spool but not in new zone, deleted RRset */
5884564029fSflorian if(!process_spool_delrrset(spool, ixfrcr, store,
5894564029fSflorian (void*)dname_name(domain_dname(domain)),
5904564029fSflorian domain_dname(domain)->name_size, tp, kl,
5914564029fSflorian rrcount))
5924564029fSflorian return 0;
5934564029fSflorian } else {
5944564029fSflorian /* add to the marked types, this one is present in
5954564029fSflorian * spool */
5964564029fSflorian marktypes[marktypes_used++] = tp;
5974564029fSflorian /* rrset in old and in new zone, diff the RRset */
5984564029fSflorian if(!process_diff_rrset(spool, ixfrcr, store, domain,
5994564029fSflorian tp, kl, rrcount, rrset))
6004564029fSflorian return 0;
6014564029fSflorian }
6024564029fSflorian }
6034564029fSflorian /* process markoff to see if new zone has RRsets not in spool,
6044564029fSflorian * those are added RRsets. */
6054564029fSflorian if(!process_marktypes(store, zone, domain, marktypes, marktypes_used))
6064564029fSflorian return 0;
6074564029fSflorian return 1;
6084564029fSflorian }
6094564029fSflorian
6104564029fSflorian /* add the RRs for the domain in new zone */
process_domain_add_RRs(struct ixfr_store * store,struct zone * zone,struct domain * domain)6114564029fSflorian static int process_domain_add_RRs(struct ixfr_store* store, struct zone* zone,
6124564029fSflorian struct domain* domain)
6134564029fSflorian {
6144564029fSflorian rrset_type* s;
6154564029fSflorian for(s=domain->rrsets; s; s=s->next) {
6164564029fSflorian if(s->zone != zone)
6174564029fSflorian continue;
6184564029fSflorian if(!process_add_rrset(store, domain, s))
6194564029fSflorian return 0;
6204564029fSflorian }
6214564029fSflorian return 1;
6224564029fSflorian }
6234564029fSflorian
6244564029fSflorian /* del the RRs for the domain from the spool */
process_domain_del_RRs(struct ixfr_create * ixfrcr,struct ixfr_store * store,FILE * spool,uint8_t * dname,size_t dname_len)6254564029fSflorian static int process_domain_del_RRs(struct ixfr_create* ixfrcr,
6264564029fSflorian struct ixfr_store* store, FILE* spool, uint8_t* dname,
6274564029fSflorian size_t dname_len)
6284564029fSflorian {
6294564029fSflorian uint32_t spool_type_count, i;
6304564029fSflorian if(!read_spool_u32(spool, &spool_type_count)) {
6314564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
6324564029fSflorian ixfrcr->file_name, strerror(errno));
6334564029fSflorian return 0;
6344564029fSflorian }
6353f21e8ccSflorian if(spool_type_count > 65536) {
6363f21e8ccSflorian log_msg(LOG_ERR, "error reading file %s: del RR spool type "
6373f21e8ccSflorian "count too large", ixfrcr->file_name);
6383f21e8ccSflorian return 0;
6393f21e8ccSflorian }
6404564029fSflorian for(i=0; i<spool_type_count; i++) {
6414564029fSflorian uint16_t tp, kl, rrcount;
6424564029fSflorian if(!read_spool_u16(spool, &tp) ||
6434564029fSflorian !read_spool_u16(spool, &kl) ||
6444564029fSflorian !read_spool_u16(spool, &rrcount)) {
6454564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
6464564029fSflorian ixfrcr->file_name, strerror(errno));
6474564029fSflorian return 0;
6484564029fSflorian }
6493f21e8ccSflorian /* The rrcount is within reasonable limits, because
6503f21e8ccSflorian * the uint16_t < 65536 */
6514564029fSflorian if(!process_spool_delrrset(spool, ixfrcr, store, dname,
6524564029fSflorian dname_len, tp, kl, rrcount))
6534564029fSflorian return 0;
6544564029fSflorian }
6554564029fSflorian return 1;
6564564029fSflorian }
6574564029fSflorian
6584564029fSflorian /* init the spool dname iterator */
spool_dname_iter_init(struct spool_dname_iterator * iter,FILE * spool,char * file_name)6594564029fSflorian static void spool_dname_iter_init(struct spool_dname_iterator* iter,
6604564029fSflorian FILE* spool, char* file_name)
6614564029fSflorian {
6624564029fSflorian memset(iter, 0, sizeof(*iter));
6634564029fSflorian iter->spool = spool;
6644564029fSflorian iter->file_name = file_name;
6654564029fSflorian }
6664564029fSflorian
6674564029fSflorian /* read the dname element into the buffer for the spool dname iterator */
spool_dname_iter_read(struct spool_dname_iterator * iter)6684564029fSflorian static int spool_dname_iter_read(struct spool_dname_iterator* iter)
6694564029fSflorian {
6704564029fSflorian if(!read_spool_dname(iter->spool, iter->dname, sizeof(iter->dname),
6714564029fSflorian &iter->dname_len)) {
6724564029fSflorian log_msg(LOG_ERR, "error reading file %s: %s",
6734564029fSflorian iter->file_name, strerror(errno));
6744564029fSflorian return 0;
6754564029fSflorian }
6764564029fSflorian return 1;
6774564029fSflorian }
6784564029fSflorian
6794564029fSflorian /* get the next name to operate on, that is not processed yet, 0 on failure
6804564029fSflorian * returns okay on endoffile, check with eof for that.
6814564029fSflorian * when done with an element, set iter->is_processed on the element. */
spool_dname_iter_next(struct spool_dname_iterator * iter)6824564029fSflorian static int spool_dname_iter_next(struct spool_dname_iterator* iter)
6834564029fSflorian {
6844564029fSflorian if(iter->eof)
6854564029fSflorian return 1;
6864564029fSflorian if(!iter->read_first) {
6874564029fSflorian /* read the first one */
6884564029fSflorian if(!spool_dname_iter_read(iter))
6894564029fSflorian return 0;
6904564029fSflorian if(iter->dname_len == 0)
6914564029fSflorian iter->eof = 1;
6924564029fSflorian iter->read_first = 1;
6934564029fSflorian iter->is_processed = 0;
6944564029fSflorian }
6954564029fSflorian if(!iter->is_processed) {
6964564029fSflorian /* the current one needs processing */
6974564029fSflorian return 1;
6984564029fSflorian }
6994564029fSflorian /* read the next one */
7004564029fSflorian if(!spool_dname_iter_read(iter))
7014564029fSflorian return 0;
7024564029fSflorian if(iter->dname_len == 0)
7034564029fSflorian iter->eof = 1;
7044564029fSflorian iter->is_processed = 0;
7054564029fSflorian return 1;
7064564029fSflorian }
7074564029fSflorian
7084564029fSflorian /* check if the ixfr is too large */
ixfr_create_too_large(struct ixfr_create * ixfrcr,struct ixfr_store * store)7094564029fSflorian static int ixfr_create_too_large(struct ixfr_create* ixfrcr,
7104564029fSflorian struct ixfr_store* store)
7114564029fSflorian {
7124564029fSflorian if(store->cancelled)
7134564029fSflorian return 1;
7144564029fSflorian if(ixfrcr->max_size != 0 &&
7154564029fSflorian ixfr_data_size(store->data) > ixfrcr->max_size) {
7164564029fSflorian if(ixfrcr->errorcmdline) {
7174564029fSflorian log_msg(LOG_ERR, "the ixfr for %s exceeds size %u, it is not created",
7184564029fSflorian wiredname2str(ixfrcr->zone_name),
7194564029fSflorian (unsigned)ixfrcr->max_size);
7204564029fSflorian } else {
7214564029fSflorian VERBOSITY(2, (LOG_INFO, "the ixfr for %s exceeds size %u, it is not created",
7224564029fSflorian wiredname2str(ixfrcr->zone_name),
7234564029fSflorian (unsigned)ixfrcr->max_size));
7244564029fSflorian }
7254564029fSflorian ixfr_store_cancel(store);
7264564029fSflorian return 1;
7274564029fSflorian }
7284564029fSflorian return 0;
7294564029fSflorian }
7304564029fSflorian
7314564029fSflorian /* process the spool input before the domain */
process_spool_before_domain(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct domain * domain,struct spool_dname_iterator * iter,struct region * tmp_region)7324564029fSflorian static int process_spool_before_domain(FILE* spool, struct ixfr_create* ixfrcr,
7334564029fSflorian struct ixfr_store* store, struct domain* domain,
7344564029fSflorian struct spool_dname_iterator* iter, struct region* tmp_region)
7354564029fSflorian {
7364564029fSflorian const dname_type* dname;
7374564029fSflorian if(ixfr_create_too_large(ixfrcr, store))
7384564029fSflorian return 0;
7394564029fSflorian /* read the domains and rrsets before the domain and those are from
7404564029fSflorian * the old zone. If the domain is equal, return to have that processed
7414564029fSflorian * if we bypass, that means the domain does not exist, do that */
7424564029fSflorian while(!iter->eof) {
7434564029fSflorian if(!spool_dname_iter_next(iter))
7444564029fSflorian return 0;
7454564029fSflorian if(iter->eof)
7464564029fSflorian break;
7474564029fSflorian /* see if we are at, before or after the domain */
7484564029fSflorian dname = dname_make(tmp_region, iter->dname, 1);
7494564029fSflorian if(!dname) {
7504564029fSflorian log_msg(LOG_ERR, "error in dname in %s",
7514564029fSflorian iter->file_name);
7524564029fSflorian return 0;
7534564029fSflorian }
7544564029fSflorian if(dname_compare(dname, domain_dname(domain)) < 0) {
7554564029fSflorian /* the dname is smaller than the one from the zone.
7564564029fSflorian * it must be deleted, process it */
7574564029fSflorian if(!process_domain_del_RRs(ixfrcr, store, spool,
7584564029fSflorian iter->dname, iter->dname_len))
7594564029fSflorian return 0;
7604564029fSflorian iter->is_processed = 1;
7614564029fSflorian } else {
7624564029fSflorian /* we are at or after the domain we are looking for,
7634564029fSflorian * done here */
7644564029fSflorian return 1;
7654564029fSflorian }
7664564029fSflorian if(ixfr_create_too_large(ixfrcr, store))
7674564029fSflorian return 0;
7684564029fSflorian }
7694564029fSflorian /* no more domains on spool, done here */
7704564029fSflorian return 1;
7714564029fSflorian }
7724564029fSflorian
7734564029fSflorian /* process the spool input for the domain */
process_spool_for_domain(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone,struct domain * domain,struct spool_dname_iterator * iter,struct region * tmp_region)7744564029fSflorian static int process_spool_for_domain(FILE* spool, struct ixfr_create* ixfrcr,
7754564029fSflorian struct ixfr_store* store, struct zone* zone, struct domain* domain,
7764564029fSflorian struct spool_dname_iterator* iter, struct region* tmp_region)
7774564029fSflorian {
7784564029fSflorian /* process all the spool that is not the domain, that is before the
7794564029fSflorian * domain in the new zone */
7804564029fSflorian if(!process_spool_before_domain(spool, ixfrcr, store, domain, iter,
7814564029fSflorian tmp_region))
7824564029fSflorian return 0;
7834564029fSflorian
7844564029fSflorian if(ixfr_create_too_large(ixfrcr, store))
7854564029fSflorian return 0;
7864564029fSflorian /* are we at the correct domain now? */
7874564029fSflorian if(iter->eof || iter->dname_len != domain_dname(domain)->name_size ||
7884564029fSflorian memcmp(iter->dname, dname_name(domain_dname(domain)),
7894564029fSflorian iter->dname_len) != 0) {
7904564029fSflorian /* the domain from the new zone is not present in the old zone,
7914564029fSflorian * the content is in the added RRs set */
7924564029fSflorian if(!process_domain_add_RRs(store, zone, domain))
7934564029fSflorian return 0;
7944564029fSflorian return 1;
7954564029fSflorian }
7964564029fSflorian
7974564029fSflorian /* process the domain */
7984564029fSflorian /* the domain exists both in the old and new zone,
7994564029fSflorian * check for RR differences */
8004564029fSflorian if(!process_diff_domain(spool, ixfrcr, store, zone, domain))
8014564029fSflorian return 0;
8024564029fSflorian iter->is_processed = 1;
8034564029fSflorian
8044564029fSflorian return 1;
8054564029fSflorian }
8064564029fSflorian
8074564029fSflorian /* process remaining spool items */
process_spool_remaining(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct spool_dname_iterator * iter)8084564029fSflorian static int process_spool_remaining(FILE* spool, struct ixfr_create* ixfrcr,
8094564029fSflorian struct ixfr_store* store, struct spool_dname_iterator* iter)
8104564029fSflorian {
8114564029fSflorian /* the remaining domain names in the spool file, that is after
8124564029fSflorian * the last domain in the new zone. */
8134564029fSflorian if(ixfr_create_too_large(ixfrcr, store))
8144564029fSflorian return 0;
8154564029fSflorian while(!iter->eof) {
8164564029fSflorian if(!spool_dname_iter_next(iter))
8174564029fSflorian return 0;
8184564029fSflorian if(iter->eof)
8194564029fSflorian break;
8204564029fSflorian /* the domain only exists in the spool, the old zone,
8214564029fSflorian * and not in the new zone. That would be domains
8224564029fSflorian * after the new zone domains, or there are no new
8234564029fSflorian * zone domains */
8244564029fSflorian if(!process_domain_del_RRs(ixfrcr, store, spool, iter->dname,
8254564029fSflorian iter->dname_len))
8264564029fSflorian return 0;
8274564029fSflorian iter->is_processed = 1;
8284564029fSflorian if(ixfr_create_too_large(ixfrcr, store))
8294564029fSflorian return 0;
8304564029fSflorian }
8314564029fSflorian return 1;
8324564029fSflorian }
8334564029fSflorian
8344564029fSflorian /* walk through the zone and find the differences */
ixfr_create_walk_zone(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone)8354564029fSflorian static int ixfr_create_walk_zone(FILE* spool, struct ixfr_create* ixfrcr,
8364564029fSflorian struct ixfr_store* store, struct zone* zone)
8374564029fSflorian {
8384564029fSflorian struct domain* domain;
8394564029fSflorian struct spool_dname_iterator iter;
8404564029fSflorian struct region* tmp_region;
8414564029fSflorian spool_dname_iter_init(&iter, spool, ixfrcr->file_name);
8424564029fSflorian tmp_region = region_create(xalloc, free);
8434564029fSflorian for(domain = zone->apex; domain && domain_is_subdomain(domain,
8444564029fSflorian zone->apex); domain = domain_next(domain)) {
8454564029fSflorian uint32_t count = domain_count_rrsets(domain, zone);
8464564029fSflorian if(count == 0)
8474564029fSflorian continue;
8484564029fSflorian
8494564029fSflorian /* the domain is a domain in the new zone */
8504564029fSflorian if(!process_spool_for_domain(spool, ixfrcr, store, zone,
8514564029fSflorian domain, &iter, tmp_region)) {
8524564029fSflorian region_destroy(tmp_region);
8534564029fSflorian return 0;
8544564029fSflorian }
8554564029fSflorian region_free_all(tmp_region);
8564564029fSflorian if(ixfr_create_too_large(ixfrcr, store))
8574564029fSflorian return 0;
8584564029fSflorian }
8594564029fSflorian if(!process_spool_remaining(spool, ixfrcr, store, &iter)) {
8604564029fSflorian region_destroy(tmp_region);
8614564029fSflorian return 0;
8624564029fSflorian }
8634564029fSflorian region_destroy(tmp_region);
8644564029fSflorian return 1;
8654564029fSflorian }
8664564029fSflorian
8674564029fSflorian /* see if the ixfr has already been created by reading the file header
8684564029fSflorian * of the to-be-created file, if that file already exists */
ixfr_create_already_done_serial(struct zone * zone,const char * zfile,int checknew,uint32_t old_serial,uint32_t new_serial)8694564029fSflorian static int ixfr_create_already_done_serial(struct zone* zone,
8704564029fSflorian const char* zfile, int checknew, uint32_t old_serial,
8714564029fSflorian uint32_t new_serial)
8724564029fSflorian {
8734564029fSflorian uint32_t file_oldserial = 0, file_newserial = 0;
8744564029fSflorian size_t data_size = 0;
8754564029fSflorian if(!ixfr_read_file_header(zone->opts->name, zfile, 1, &file_oldserial,
8764564029fSflorian &file_newserial, &data_size, 0)) {
8774564029fSflorian /* could not read, so it was not done */
8784564029fSflorian return 0;
8794564029fSflorian }
8804564029fSflorian if(file_oldserial == old_serial &&
8814564029fSflorian (!checknew || file_newserial == new_serial)) {
8824564029fSflorian log_msg(LOG_INFO, "IXFR already exists in file %s.ixfr, nothing to do",
8834564029fSflorian zfile);
8844564029fSflorian return 1;
8854564029fSflorian }
8864564029fSflorian return 0;
8874564029fSflorian }
8884564029fSflorian
8894564029fSflorian /* See the data size of the ixfr by reading the file header of the ixfr file */
ixfr_read_header_data_size(const char * zname,const char * zfile,int file_num,size_t * data_size)8904564029fSflorian static int ixfr_read_header_data_size(const char* zname,
8914564029fSflorian const char* zfile, int file_num, size_t* data_size)
8924564029fSflorian {
8934564029fSflorian uint32_t file_oldserial = 0, file_newserial = 0;
8944564029fSflorian if(!ixfr_read_file_header(zname, zfile, file_num, &file_oldserial,
8954564029fSflorian &file_newserial, data_size, 0)) {
8964564029fSflorian /* could not read */
8974564029fSflorian return 0;
8984564029fSflorian }
8994564029fSflorian return 1;
9004564029fSflorian }
9014564029fSflorian
9024564029fSflorian /* see if the ixfr has already been created by reading the file header
9034564029fSflorian * of the to-be-created file, if that file already exists */
ixfr_create_already_done(struct ixfr_create * ixfrcr,struct zone * zone,const char * zfile,int checknew)9044564029fSflorian static int ixfr_create_already_done(struct ixfr_create* ixfrcr,
9054564029fSflorian struct zone* zone, const char* zfile, int checknew)
9064564029fSflorian {
9074564029fSflorian return ixfr_create_already_done_serial(zone, zfile, checknew,
9084564029fSflorian ixfrcr->old_serial, ixfrcr->new_serial);
9094564029fSflorian }
9104564029fSflorian
9114564029fSflorian /* store the new soa record for the ixfr */
ixfr_create_store_newsoa(struct ixfr_store * store,struct zone * zone)9124564029fSflorian static int ixfr_create_store_newsoa(struct ixfr_store* store,
9134564029fSflorian struct zone* zone)
9144564029fSflorian {
9154564029fSflorian if(!zone || !zone->soa_rrset) {
9164564029fSflorian log_msg(LOG_ERR, "error no SOA rrset");
9174564029fSflorian return 0;
9184564029fSflorian }
9194564029fSflorian if(zone->soa_rrset->rr_count == 0) {
9204564029fSflorian log_msg(LOG_ERR, "error empty SOA rrset");
9214564029fSflorian return 0;
9224564029fSflorian }
9234564029fSflorian if(!ixfr_store_add_newsoa_rdatas(store, domain_dname(zone->apex),
9244564029fSflorian zone->soa_rrset->rrs[0].type, zone->soa_rrset->rrs[0].klass,
9254564029fSflorian zone->soa_rrset->rrs[0].ttl, zone->soa_rrset->rrs[0].rdatas,
9264564029fSflorian zone->soa_rrset->rrs[0].rdata_count)) {
9274564029fSflorian log_msg(LOG_ERR, "out of memory");
9284564029fSflorian return 0;
9294564029fSflorian }
9304564029fSflorian return 1;
9314564029fSflorian }
9324564029fSflorian
9334564029fSflorian /* initialise ixfr_create perform, open spool, read header, get serial */
ixfr_perform_init(struct ixfr_create * ixfrcr,struct zone * zone,struct ixfr_store * store_mem,struct ixfr_store ** store,FILE ** spool)9344564029fSflorian static int ixfr_perform_init(struct ixfr_create* ixfrcr, struct zone* zone,
9354564029fSflorian struct ixfr_store* store_mem, struct ixfr_store** store, FILE** spool)
9364564029fSflorian {
9374564029fSflorian *spool = fopen(ixfrcr->file_name, "r");
9384564029fSflorian if(!*spool) {
9394564029fSflorian log_msg(LOG_ERR, "could not open %s for reading: %s",
9404564029fSflorian ixfrcr->file_name, strerror(errno));
9414564029fSflorian return 0;
9424564029fSflorian }
9434564029fSflorian if(!read_spool_header(*spool, ixfrcr)) {
9444564029fSflorian fclose(*spool);
9454564029fSflorian return 0;
9464564029fSflorian }
9474564029fSflorian ixfrcr->new_serial = zone_get_current_serial(zone);
948*b71395eaSflorian *store = ixfr_store_start(zone, store_mem);
9494564029fSflorian if(!ixfr_create_store_newsoa(*store, zone)) {
9504564029fSflorian fclose(*spool);
9514564029fSflorian ixfr_store_free(*store);
9524564029fSflorian return 0;
9534564029fSflorian }
9544564029fSflorian return 1;
9554564029fSflorian }
9564564029fSflorian
9574564029fSflorian /* rename the other ixfr files */
ixfr_create_rename_and_delete_files(const char * zname,const char * zoptsname,const char * zfile,uint32_t ixfr_number,size_t ixfr_size,size_t cur_data_size)9584564029fSflorian static int ixfr_create_rename_and_delete_files(const char* zname,
9594564029fSflorian const char* zoptsname, const char* zfile, uint32_t ixfr_number,
9604564029fSflorian size_t ixfr_size, size_t cur_data_size)
9614564029fSflorian {
9624564029fSflorian size_t size_in_use = cur_data_size;
9634564029fSflorian int dest_nr_files = (int)ixfr_number, maxsizehit = 0;
9644564029fSflorian int num = 1;
9654564029fSflorian while(ixfr_file_exists(zfile, num)) {
9664564029fSflorian size_t fsize = 0;
9674564029fSflorian if(!maxsizehit) {
9684564029fSflorian if(!ixfr_read_header_data_size(zoptsname, zfile, num,
9694564029fSflorian &fsize) || size_in_use + fsize > ixfr_size) {
9704564029fSflorian /* no more than this because of storage size */
9714564029fSflorian dest_nr_files = num;
9724564029fSflorian maxsizehit = 1;
9734564029fSflorian }
9744564029fSflorian size_in_use += fsize;
9754564029fSflorian }
9764564029fSflorian num++;
9774564029fSflorian }
9784564029fSflorian num--;
9794564029fSflorian /* num is now the number of ixfr files that exist */
9804564029fSflorian while(num > 0) {
9814564029fSflorian if(num+1 > dest_nr_files) {
9824564029fSflorian (void)ixfr_unlink_it(zname, zfile, num, 0);
9834564029fSflorian } else {
9844564029fSflorian if(!ixfr_rename_it(zname, zfile, num, 0, num+1, 0))
9854564029fSflorian return 0;
9864564029fSflorian }
9874564029fSflorian num--;
9884564029fSflorian }
9894564029fSflorian return 1;
9904564029fSflorian }
9914564029fSflorian
9924564029fSflorian /* finish up ixfr create processing */
ixfr_create_finishup(struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone,int append_mem,struct nsd * nsd,const char * zfile,uint32_t ixfr_number)9934564029fSflorian static void ixfr_create_finishup(struct ixfr_create* ixfrcr,
9944564029fSflorian struct ixfr_store* store, struct zone* zone, int append_mem,
9954564029fSflorian struct nsd* nsd, const char* zfile, uint32_t ixfr_number)
9964564029fSflorian {
9974564029fSflorian char log_buf[1024], nowstr[128];
9984564029fSflorian /* create the log message */
9994564029fSflorian time_t now = time(NULL);
10004564029fSflorian if(store->cancelled || ixfr_create_too_large(ixfrcr, store)) {
10014564029fSflorian /* remove unneeded files.
10024564029fSflorian * since this ixfr cannot be created the others are useless. */
10034564029fSflorian ixfr_delete_superfluous_files(zone, zfile, 0);
10044564029fSflorian return;
10054564029fSflorian }
10064564029fSflorian snprintf(nowstr, sizeof(nowstr), "%s", ctime(&now));
10074564029fSflorian if(strchr(nowstr, '\n'))
10084564029fSflorian *strchr(nowstr, '\n') = 0;
10094564029fSflorian snprintf(log_buf, sizeof(log_buf),
10104564029fSflorian "IXFR created by NSD %s for %s %u to %u of %u bytes at time %s",
10114564029fSflorian PACKAGE_VERSION, wiredname2str(ixfrcr->zone_name),
10124564029fSflorian (unsigned)ixfrcr->old_serial, (unsigned)ixfrcr->new_serial,
10134564029fSflorian (unsigned)ixfr_data_size(store->data), nowstr);
10144564029fSflorian store->data->log_str = strdup(log_buf);
10154564029fSflorian if(!store->data->log_str) {
10164564029fSflorian log_msg(LOG_ERR, "out of memory");
10174564029fSflorian ixfr_store_free(store);
10184564029fSflorian return;
10194564029fSflorian }
10204564029fSflorian if(!ixfr_create_rename_and_delete_files(
10214564029fSflorian wiredname2str(ixfrcr->zone_name), zone->opts->name, zfile,
10224564029fSflorian ixfr_number, ixfrcr->max_size, ixfr_data_size(store->data))) {
10234564029fSflorian log_msg(LOG_ERR, "could not rename other ixfr files");
10244564029fSflorian ixfr_store_free(store);
10254564029fSflorian return;
10264564029fSflorian }
10274564029fSflorian if(!ixfr_write_file(zone, store->data, zfile, 1)) {
10284564029fSflorian log_msg(LOG_ERR, "could not write to file");
10294564029fSflorian ixfr_store_free(store);
10304564029fSflorian return;
10314564029fSflorian }
10324564029fSflorian if(append_mem) {
10334564029fSflorian ixfr_store_finish(store, nsd, log_buf);
10344564029fSflorian }
10354564029fSflorian }
10364564029fSflorian
ixfr_readup_exist(struct zone * zone,struct nsd * nsd,const char * zfile)10374564029fSflorian void ixfr_readup_exist(struct zone* zone, struct nsd* nsd,
10384564029fSflorian const char* zfile)
10394564029fSflorian {
10404564029fSflorian /* the .ixfr file already exists with the correct serial numbers
10414564029fSflorian * on the disk. Read up the ixfr files from the drive and put them
10424564029fSflorian * in memory. To match the zone that has just been read.
10434564029fSflorian * We can skip ixfr creation, and read up the files from the drive.
10444564029fSflorian * If the files on the drive are consistent, we end up with exactly
10454564029fSflorian * those ixfrs and that zone in memory.
10464564029fSflorian * Presumably, the user has used nsd-checkzone to create an IXFR
10474564029fSflorian * file and has put a new zone file, so we read up the data that
10484564029fSflorian * we should have now.
10494564029fSflorian * This also takes into account the config on number and size. */
10504564029fSflorian ixfr_read_from_file(nsd, zone, zfile);
10514564029fSflorian }
10524564029fSflorian
ixfr_create_perform(struct ixfr_create * ixfrcr,struct zone * zone,int append_mem,struct nsd * nsd,const char * zfile,uint32_t ixfr_number)10534564029fSflorian int ixfr_create_perform(struct ixfr_create* ixfrcr, struct zone* zone,
10544564029fSflorian int append_mem, struct nsd* nsd, const char* zfile,
10554564029fSflorian uint32_t ixfr_number)
10564564029fSflorian {
10574564029fSflorian struct ixfr_store store_mem, *store;
10584564029fSflorian FILE* spool;
10594564029fSflorian if(!ixfr_perform_init(ixfrcr, zone, &store_mem, &store, &spool)) {
10604564029fSflorian (void)unlink(ixfrcr->file_name);
10614564029fSflorian return 0;
10624564029fSflorian }
10634564029fSflorian if(ixfrcr->new_serial == ixfrcr->old_serial ||
10644564029fSflorian compare_serial(ixfrcr->new_serial, ixfrcr->old_serial)<0) {
10654564029fSflorian log_msg(LOG_ERR, "zone %s ixfr could not be created because the serial is the same or moves backwards, from %u to %u",
10664564029fSflorian wiredname2str(ixfrcr->zone_name),
10674564029fSflorian (unsigned)ixfrcr->old_serial,
10684564029fSflorian (unsigned)ixfrcr->new_serial);
10694564029fSflorian ixfr_store_cancel(store);
10704564029fSflorian fclose(spool);
10714564029fSflorian ixfr_store_free(store);
10724564029fSflorian (void)unlink(ixfrcr->file_name);
10734564029fSflorian ixfr_delete_superfluous_files(zone, zfile, 0);
10744564029fSflorian if(append_mem)
10754564029fSflorian ixfr_store_delixfrs(zone);
10764564029fSflorian return 0;
10774564029fSflorian }
10784564029fSflorian if(ixfr_create_already_done(ixfrcr, zone, zfile, 1)) {
10794564029fSflorian ixfr_store_cancel(store);
10804564029fSflorian fclose(spool);
10814564029fSflorian ixfr_store_free(store);
10824564029fSflorian (void)unlink(ixfrcr->file_name);
10834564029fSflorian if(append_mem) {
10844564029fSflorian ixfr_readup_exist(zone, nsd, zfile);
10854564029fSflorian }
10864564029fSflorian return 0;
10874564029fSflorian }
10884564029fSflorian
10894564029fSflorian if(!ixfr_create_walk_zone(spool, ixfrcr, store, zone)) {
10904564029fSflorian fclose(spool);
10914564029fSflorian ixfr_store_free(store);
10924564029fSflorian (void)unlink(ixfrcr->file_name);
10934564029fSflorian ixfr_delete_superfluous_files(zone, zfile, 0);
10944564029fSflorian return 0;
10954564029fSflorian }
10964564029fSflorian if(store->data && !store->data->oldsoa) {
10974564029fSflorian log_msg(LOG_ERR, "error spool file did not contain a SOA record");
10984564029fSflorian fclose(spool);
10994564029fSflorian ixfr_store_free(store);
11004564029fSflorian (void)unlink(ixfrcr->file_name);
11014564029fSflorian return 0;
11024564029fSflorian }
11034564029fSflorian if(!store->cancelled)
11044564029fSflorian ixfr_store_finish_data(store);
11054564029fSflorian fclose(spool);
11064564029fSflorian (void)unlink(ixfrcr->file_name);
11074564029fSflorian
11084564029fSflorian ixfr_create_finishup(ixfrcr, store, zone, append_mem, nsd, zfile,
11094564029fSflorian ixfr_number);
11104564029fSflorian return 1;
11114564029fSflorian }
11124564029fSflorian
ixfr_create_cancel(struct ixfr_create * ixfrcr)11134564029fSflorian void ixfr_create_cancel(struct ixfr_create* ixfrcr)
11144564029fSflorian {
11154564029fSflorian if(!ixfrcr)
11164564029fSflorian return;
11174564029fSflorian (void)unlink(ixfrcr->file_name);
11184564029fSflorian ixfr_create_free(ixfrcr);
11194564029fSflorian }
11204564029fSflorian
ixfr_create_from_difference(struct zone * zone,const char * zfile,int * ixfr_create_already_done_flag)11214564029fSflorian int ixfr_create_from_difference(struct zone* zone, const char* zfile,
11224564029fSflorian int* ixfr_create_already_done_flag)
11234564029fSflorian {
11244564029fSflorian uint32_t old_serial;
11254564029fSflorian *ixfr_create_already_done_flag = 0;
11264564029fSflorian /* only if the zone is ixfr enabled */
11274564029fSflorian if(!zone_is_ixfr_enabled(zone))
11284564029fSflorian return 0;
11294564029fSflorian /* only if ixfr create is enabled */
11304564029fSflorian if(!zone->opts->pattern->create_ixfr)
11314564029fSflorian return 0;
11324564029fSflorian /* only if there is a zone in memory to compare with */
11333f21e8ccSflorian if(!zone->soa_rrset || !zone->apex)
11344564029fSflorian return 0;
11354564029fSflorian
11364564029fSflorian old_serial = zone_get_current_serial(zone);
11374564029fSflorian if(ixfr_create_already_done_serial(zone, zfile, 0, old_serial, 0)) {
11384564029fSflorian *ixfr_create_already_done_flag = 1;
11394564029fSflorian return 0;
11404564029fSflorian }
11414564029fSflorian
11424564029fSflorian return 1;
11434564029fSflorian }
1144