/*************************************************************************** masterfile.cpp - master file i/o ------------------- begin : Wed Dec 25 2002 copyright : (C) 2002 by Meilof email : meilof@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include "zones.h" #include "primary.h" #include "masterfile.h" #include "configuration.h" #include "posadisrc.h" struct mfdata { PrimaryZone *zn; domainname *root; const char *file; FILE *out; }; void errorcallback(void *user_dat, const char *file, int linenum, const char *message) { pos_log(context_zonedata, log_error, "%s:%d: %s", file, linenum, message); } char data_filename[PATH_MAX]; char *build_filename(domainname &dom, uint32_t serial) { char str_serial[16]; stl_string domstr = dom.tostring(); sprintf(str_serial, "%d", serial); if (strlen(datadir) + strlen(str_serial) + strlen(domstr.c_str()) >= sizeof(data_filename)) { pos_log(context_zonedata, log_error, "%s: Data file name too long", dom.tocstr()); return NULL; } strcpy(data_filename, datadir); strcat(data_filename, domstr.c_str()); strcat(data_filename, str_serial); return data_filename; } void rrcallback(void *user_dat, DnsRR *rr) { mfdata *dat = (mfdata *)user_dat; ZoneDomain *zonedom; RrSet *set; uint32_t old; char *fname; /* let's add the rr */ int *checksum = &dat->zn->checksum; for (int t = 0; t < rr->RDLENGTH; t++) *checksum += rr->RDATA[t]; if (rr->TYPE == DNS_TYPE_SOA) { old = dat->zn->serial; dat->zn->serial = rr_getlong(rr->RDATA, DNS_TYPE_SOA, 2); if (old != dat->zn->serial) { /* open outfile */ domainname dom = dat->zn->getfqdn(); if (datadir[0]) { /* at first, try to delete previous serial */ fname = build_filename(dom, old); if (fname) unlink(fname); fname = build_filename(dom, dat->zn->serial); if (!file_exists(fname) && !(dat->out = try_fopen(fname, "wb"))) { pos_log(context_zonedata, log_error, "%s: Could not create data file %s", dat->file, fname); } } } } if (dat->out) { /* output data */ fwrite(uint16_buff(rr->NAME.len() + rr->RDLENGTH + 10), 1, 2, dat->out); fwrite(rr->NAME.c_str(), 1, rr->NAME.len(), dat->out); fwrite(uint16_buff(rr->TYPE), 1, 2, dat->out); fwrite(uint16_buff(rr->CLASS), 1, 2, dat->out); fwrite(uint32_buff(rr->TTL), 1, 4, dat->out); fwrite(uint16_buff(rr->RDLENGTH), 1, 2, dat->out); fwrite(rr->RDATA, 1, rr->RDLENGTH, dat->out); } zonedom = create_domainname(dat->zn->rootdomain, *dat->root, rr->NAME); if (zonedom) { if (rr->TYPE == DNS_TYPE_CNAME) { if (zonedom->rrsets.count != 0) { pos_log(context_zonedata, log_error, "%s: Error: both CNAME and non-CNAME records at %s", dat->file, rr->NAME.tocstr()); } } else if (zonedom->get_rrset(DNS_TYPE_CNAME) != NULL) { pos_log(context_zonedata, log_error, "%s: Error: both CNAME and non-CNAME records at %s", dat->file, rr->NAME.tocstr()); } set = zonedom->create_rrset(rr->TYPE); set->add_rr(rr->TTL, rr->RDLENGTH, rr->RDATA); } else { pos_log(context_zonedata, log_error, "%s: Could not create zone node %s", dat->file, rr->NAME.tocstr()); } } void commentcallback(void *user_dat, const char *comment) { mfdata *dat = (mfdata *)user_dat; const char *ptr; char command[32]; try { if (strncmpi(comment, "set ", 4) == 0) { ptr = strchr(comment + 4, ' '); if (!ptr) set_setting((setting_fn)zone_set, dat->zn, (char*)comment + 4, ""); else if (ptr - comment - 4 < 32) { memcpy(command, comment + 4, ptr - comment); command[ptr-comment-4] = 0; if (strcmpi(command, "file") != 0) { set_setting((setting_fn)zone_set, dat->zn, command, ptr + 1); } } } } catch (PException p) { pos_log(context_zonedata, log_error, "%s: Error in comment line \"%s\" (ignored)", dat->file, comment); } } void load_master_file(PrimaryZone *zn, domainname zon, const char *file) { bool was_loaded = zn->zone_is_loaded; int check = zn->checksum; uint32_t ser = zn->serial; mfdata dat = { zn, &zon, file, NULL }; zn->checksum = 0; read_master_file(file, zon, &dat, errorcallback, rrcallback, NULL, commentcallback, POSLIB_MF_AUTOPROBE); if (dat.out) fclose(dat.out); pos_log(context_server, log_info, "primary %s[%s]: master file loaded, serial %d", zn->getfqdn().tocstr(), file, zn->serial); if (was_loaded && zn->zone_is_loaded && zn->checksum != check && ser == zn->serial) { pos_log(context_server, log_error, "primary %s[%s]: changes were made in the zone, but serial not increased", zn->getfqdn().tocstr(), file); } } /* loading of initial cache file */ void cache_errorcallback(void *user_dat, const char *file, int linenum, const char *message) { pos_log(context_zonedata, log_error, "cache:%s:%d %s", file, linenum, message); } void cache_rrcallback(void *user_dat, DnsRR *rr) { ZoneDomain *zonedom; RrSet *set; // uint32_t old; // char *fname; domainname root; /* let's add the rr */ zonedom = create_domainname(cache_root_domain, root, rr->NAME); if (zonedom) { set = zonedom->create_rrset(rr->TYPE); set->add_rr(rr->TTL, rr->RDLENGTH, rr->RDATA); } else { pos_log(context_zonedata, log_error, "cache: Could not create zone node %s", rr->NAME.tocstr()); } } void load_initial_cache(const char *file) { domainname root = ""; read_master_file(file, root, NULL, cache_errorcallback, cache_rrcallback, NULL, NULL, POSLIB_MF_NOSOA); pos_log(context_server, log_info, "cachefile %s loaded", file); }