Files

246 lines
5.6 KiB
C
Raw Permalink Normal View History

/* zinfo.c - zone information */
#include "config.h"
#include "zinfo.h"
#include "zones.h"
static int cmp_version(const void* a, const void* b)
{
struct zversion_t* x = (struct zversion_t*)a;
struct zversion_t* y = (struct zversion_t*)b;
if(x->serial < y->serial)
return -1;
if(x->serial > y->serial)
return -1;
return 0;
}
static int cmp_domain(const void* a, const void* b)
{
struct zdomain_t* x = (struct zdomain_t*)a;
struct zdomain_t* y = (struct zdomain_t*)b;
return ldns_rdf_compare(x->name, y->name);
}
struct zinfo_t* zinfo_create(void)
{
struct zinfo_t* zinfo = (struct zinfo_t*)calloc(1, sizeof(*zinfo));
zinfo->is_present = 0;
ldns_rbtree_init(&zinfo->vs, cmp_version);
ldns_rbtree_init(&zinfo->zone, cmp_domain);
return zinfo;
}
static void del_vs(ldns_rbnode_t* node, void* arg)
{
(void)arg;
zversion_delete((struct zversion_t*)node);
}
static void del_domain(ldns_rbnode_t* node, void* arg)
{
(void)arg;
zdomain_delete((struct zdomain_t*)node);
}
void zinfo_delete(struct zinfo_t* zinfo)
{
if(!zinfo) return;
free(zinfo->dir);
ldns_rr_list_deep_free(zinfo->last_soa);
ldns_traverse_postorder(&zinfo->vs, del_vs, NULL);
ldns_traverse_postorder(&zinfo->zone, del_domain, NULL);
free(zinfo);
}
/** Get a pointer to a static buffer with filename */
const char* zinfo_index_name(struct zone_entry_t* entry)
{
static char buf[1024];
snprintf(buf, sizeof(buf), "%s/zone.%s.index",
entry->zinfo->dir, entry->zstr);
return buf;
}
/** Get a pointer to a static buffer with filename */
const char* zinfo_ixfr_name(struct zone_entry_t* entry, uint32_t soa)
{
static char buf[1024];
snprintf(buf, sizeof(buf), "%s/zone.%s.ixfr.%u",
entry->zinfo->dir, entry->zstr, soa);
return buf;
}
/** Get a pointer to a static buffer with filename */
const char* zinfo_full_name(struct zone_entry_t* entry, uint32_t soa)
{
static char buf[1024];
snprintf(buf, sizeof(buf), "%s/zone.%s.full.%u",
entry->zinfo->dir, entry->zstr, soa);
return buf;
}
/** see if file exists */
static int file_exists(const char* path)
{
struct stat buf;
if(stat(path, &buf) < 0) {
if(errno == ENOENT)
return 0;
printf("stat(%s): %s\n", path, strerror(errno));
return 0;
}
return 1;
}
int zinfo_read(struct zone_entry_t* entry)
{
const char* iname = zinfo_index_name(entry);
FILE* index = fopen(iname, "ra");
uint32_t serial = 0;
uint32_t last_full = 0;
int have_last_full;
if(!index) {
if(errno == ENOENT) {
printf("zone %s is empty\n", entry->zstr);
return 1;
}
perror(iname);
return 0;
}
if(fscanf(index, " %u", &serial) != 1) {
fclose(index);
printf("error reading %s\n", iname);
return 0;
}
fclose(index);
/* read versions */
while(file_exists(zinfo_ixfr_name(entry, serial))) {
struct zversion_t* v = zversion_read(entry, serial);
if(!v) return 0;
if(file_exists(zinfo_full_name(entry, serial))) {
have_last_full = 1;
last_full = serial;
}
serial = v->next_serial;
}
if(file_exists(zinfo_full_name(entry, serial))) {
have_last_full = 1;
last_full = serial;
}
/* read full zone */
if(!have_last_full) {
printf("No full zone file available for zone %s\n",
entry->zstr);
return 0;
}
entry->zinfo->last_serial = serial;
entry->zinfo->is_present = 1;
if(!zfull_read(entry, last_full))
return 0;
return 1;
}
int zinfo_get_zone_diff(struct zone_entry_t* entry, uint32_t serial_from,
uint32_t serial_to, ldns_rr_list** rr_remove, ldns_rr_list** rr_add,
ldns_rr** soa_from, ldns_rr** soa_to)
{
/* DIFFs stored in memory and served from memory without copy */
/* TODO */
}
void zinfo_get_zone_full(struct zone_entry_t* entry, uint32_t serial,
ldns_zone** z)
{
/* full zone kept in memory, served from memory after a fork
* (and close of other sockets after fork) */
/* TODO */
}
void zversion_delete(struct zversion_t* v)
{
if(!v) return;
ldns_rr_list_deep_free(v->ixfr);
free(v);
}
struct zversion_t* zversion_read(struct zone_entry_t* entry, uint32_t serial)
{
const char* fn = zinfo_ixfr_name(entry, serial);
struct zversion_t* v;
FILE* in = fopen(fn, "ra");
ldns_status status;
ldns_rr* rr = 0;
uint32_t dttl = 3600;
ldns_rdf* origin = 0, *prev = 0;
int line_nr = 1;
if(!in) {
perror(fn);
return NULL;
}
v = (struct zversion_t*)calloc(1, sizeof(*v));
if(!v) {
fclose(in);
printf("out of memory\n");
return NULL;
}
v->serial = serial;
v->ixfr = ldns_rr_list_new();
while(!feof(in)) {
status = ldns_rr_new_frm_fp_l(&rr, in, &dttl, &origin,
&prev, &line_nr);
if(status == LDNS_STATUS_SYNTAX_TTL ||
status == LDNS_STATUS_SYNTAX_ORIGIN ||
status == LDNS_STATUS_SYNTAX_EMPTY)
continue;
if(status != LDNS_STATUS_OK) {
printf("error %s:%d: %s\n", fn, line_nr,
ldns_get_errorstr_by_id(status));
fclose(in);
ldns_rdf_deep_free(origin);
ldns_rdf_deep_free(prev);
ldns_rr_list_deep_free(v->ixfr);
free(v);
return NULL;
}
ldns_rr_list_push_rr(v->ixfr, rr);
}
ldns_rdf_deep_free(origin);
ldns_rdf_deep_free(prev);
fclose(in);
if(ldns_rr_list_rr_count(v->ixfr) < 1 ||
ldns_rr_get_type(ldns_rr_list_rr(v->ixfr, 0))
!= LDNS_RR_TYPE_SOA) {
printf("invalid IXFR format in %s\n", fn);
ldns_rr_list_deep_free(v->ixfr);
free(v);
return NULL;
}
v->next_serial = ldns_rdf2native_int32(ldns_rr_rdf(
ldns_rr_list_rr(v->ixfr, 0), 2));
return v;
}
static void del_rrset(ldns_rbnode_t* node, void* arg)
{
(void)arg;
zrrset_delete((struct zrrset_t*)node);
}
void zdomain_delete(struct zdomain_t* d)
{
if(!d) return;
ldns_traverse_postorder(&d->rrsets, del_rrset, NULL);
ldns_rdf_deep_free(d->name);
free(d);
}
int zfull_read(struct zone_entry_t* entry, uint32_t serial)
{
}
void zrrset_delete(struct zrrset_t* r)
{
if(!r) return;
ldns_rr_list_deep_free(r->list);
free(r);
}