Home | History | Annotate | Line # | Download | only in dist
xfrd-disk.c revision 1.1.1.6
      1      1.1  christos /*
      2      1.1  christos  * xfrd-disk.c - XFR (transfer) Daemon TCP system source file. Read/Write state to disk.
      3      1.1  christos  *
      4      1.1  christos  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
      5      1.1  christos  *
      6      1.1  christos  * See LICENSE for the license.
      7      1.1  christos  *
      8      1.1  christos  */
      9      1.1  christos 
     10      1.1  christos #include "config.h"
     11      1.1  christos #include <stdio.h>
     12      1.1  christos #include <stdlib.h>
     13      1.1  christos #include <ctype.h>
     14      1.1  christos #include <errno.h>
     15      1.1  christos #include <sys/stat.h>
     16      1.1  christos #include <sys/types.h>
     17      1.1  christos #include <unistd.h>
     18      1.1  christos #include "xfrd-disk.h"
     19      1.1  christos #include "xfrd.h"
     20      1.1  christos #include "buffer.h"
     21      1.1  christos #include "nsd.h"
     22      1.1  christos #include "options.h"
     23      1.1  christos 
     24      1.1  christos /* quick tokenizer, reads words separated by whitespace.
     25      1.1  christos    No quoted strings. Comments are skipped (#... eol). */
     26      1.1  christos static char*
     27      1.1  christos xfrd_read_token(FILE* in)
     28      1.1  christos {
     29      1.1  christos 	static char buf[4000];
     30      1.1  christos 	buf[sizeof(buf)-1]=0;
     31      1.1  christos 	while(1) {
     32      1.1  christos 		if(fscanf(in, " %3990s", buf) != 1)
     33      1.1  christos 			return 0;
     34      1.1  christos 
     35      1.1  christos 		if(buf[0] != '#')
     36      1.1  christos 			return buf;
     37      1.1  christos 
     38      1.1  christos 		if(!fgets(buf, sizeof(buf), in))
     39      1.1  christos 			return 0;
     40      1.1  christos 	}
     41      1.1  christos }
     42      1.1  christos 
     43      1.1  christos static int
     44      1.1  christos xfrd_read_i16(FILE *in, uint16_t* v)
     45      1.1  christos {
     46      1.1  christos 	char* p = xfrd_read_token(in);
     47      1.1  christos 	if(!p)
     48      1.1  christos 		return 0;
     49      1.1  christos 
     50      1.1  christos 	*v=atoi(p);
     51      1.1  christos 	return 1;
     52      1.1  christos }
     53      1.1  christos 
     54      1.1  christos static int
     55      1.1  christos xfrd_read_i32(FILE *in, uint32_t* v)
     56      1.1  christos {
     57      1.1  christos 	char* p = xfrd_read_token(in);
     58      1.1  christos 	if(!p)
     59      1.1  christos 		return 0;
     60      1.1  christos 
     61      1.1  christos 	*v=atoi(p);
     62      1.1  christos 	return 1;
     63      1.1  christos }
     64      1.1  christos 
     65      1.1  christos static int
     66      1.1  christos xfrd_read_time_t(FILE *in, time_t* v)
     67      1.1  christos {
     68      1.1  christos 	char* p = xfrd_read_token(in);
     69      1.1  christos 	if(!p)
     70      1.1  christos 		return 0;
     71      1.1  christos 
     72      1.1  christos 	*v=atol(p);
     73      1.1  christos 	return 1;
     74      1.1  christos }
     75      1.1  christos 
     76      1.1  christos static int
     77      1.1  christos xfrd_read_check_str(FILE* in, const char* str)
     78      1.1  christos {
     79      1.1  christos 	char *p = xfrd_read_token(in);
     80      1.1  christos 	if(!p)
     81      1.1  christos 		return 0;
     82      1.1  christos 
     83      1.1  christos 	if(strcmp(p, str) != 0)
     84      1.1  christos 		return 0;
     85      1.1  christos 
     86      1.1  christos 	return 1;
     87      1.1  christos }
     88      1.1  christos 
     89      1.1  christos static int
     90      1.1  christos xfrd_read_state_soa(FILE* in, const char* id_acquired,
     91  1.1.1.2  christos 	const char* id, xfrd_soa_type* soa, time_t* soatime)
     92      1.1  christos {
     93      1.1  christos 	char *p;
     94      1.1  christos 
     95      1.1  christos 	if(!xfrd_read_check_str(in, id_acquired) ||
     96      1.1  christos 	   !xfrd_read_time_t(in, soatime)) {
     97      1.1  christos 		return 0;
     98      1.1  christos 	}
     99      1.1  christos 
    100      1.1  christos 	if(*soatime == 0)
    101      1.1  christos 		return 1;
    102      1.1  christos 
    103      1.1  christos 	if(!xfrd_read_check_str(in, id) ||
    104      1.1  christos 	   !xfrd_read_i16(in, &soa->type) ||
    105      1.1  christos 	   !xfrd_read_i16(in, &soa->klass) ||
    106      1.1  christos 	   !xfrd_read_i32(in, &soa->ttl) ||
    107      1.1  christos 	   !xfrd_read_i16(in, &soa->rdata_count))
    108      1.1  christos 	{
    109      1.1  christos 		return 0;
    110      1.1  christos 	}
    111      1.1  christos 
    112      1.1  christos 	soa->type = htons(soa->type);
    113      1.1  christos 	soa->klass = htons(soa->klass);
    114      1.1  christos 	soa->ttl = htonl(soa->ttl);
    115      1.1  christos 	soa->rdata_count = htons(soa->rdata_count);
    116      1.1  christos 
    117      1.1  christos 	if(!(p=xfrd_read_token(in)) ||
    118      1.1  christos 	   !(soa->prim_ns[0] = dname_parse_wire(soa->prim_ns+1, p)))
    119      1.1  christos 		return 0;
    120      1.1  christos 
    121      1.1  christos 	if(!(p=xfrd_read_token(in)) ||
    122      1.1  christos 	   !(soa->email[0] = dname_parse_wire(soa->email+1, p)))
    123      1.1  christos 		return 0;
    124      1.1  christos 
    125      1.1  christos 	if(!xfrd_read_i32(in, &soa->serial) ||
    126      1.1  christos 	   !xfrd_read_i32(in, &soa->refresh) ||
    127      1.1  christos 	   !xfrd_read_i32(in, &soa->retry) ||
    128      1.1  christos 	   !xfrd_read_i32(in, &soa->expire) ||
    129      1.1  christos 	   !xfrd_read_i32(in, &soa->minimum))
    130      1.1  christos 	{
    131      1.1  christos 		return 0;
    132      1.1  christos 	}
    133      1.1  christos 
    134      1.1  christos 	soa->serial = htonl(soa->serial);
    135      1.1  christos 	soa->refresh = htonl(soa->refresh);
    136      1.1  christos 	soa->retry = htonl(soa->retry);
    137      1.1  christos 	soa->expire = htonl(soa->expire);
    138      1.1  christos 	soa->minimum = htonl(soa->minimum);
    139      1.1  christos 	return 1;
    140      1.1  christos }
    141      1.1  christos 
    142      1.1  christos void
    143      1.1  christos xfrd_read_state(struct xfrd_state* xfrd)
    144      1.1  christos {
    145      1.1  christos 	const char* statefile = xfrd->nsd->options->xfrdfile;
    146      1.1  christos 	FILE *in;
    147      1.1  christos 	uint32_t filetime = 0;
    148      1.1  christos 	uint32_t numzones, i;
    149      1.1  christos 	region_type *tempregion;
    150      1.1  christos 	time_t soa_refresh;
    151      1.1  christos 
    152      1.1  christos 	tempregion = region_create(xalloc, free);
    153      1.1  christos 	if(!tempregion)
    154      1.1  christos 		return;
    155      1.1  christos 
    156      1.1  christos 	in = fopen(statefile, "r");
    157      1.1  christos 	if(!in) {
    158      1.1  christos 		if(errno != ENOENT) {
    159      1.1  christos 			log_msg(LOG_ERR, "xfrd: Could not open file %s for reading: %s",
    160      1.1  christos 				statefile, strerror(errno));
    161      1.1  christos 		} else {
    162      1.1  christos 			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: no file %s. refreshing all zones.",
    163      1.1  christos 				statefile));
    164      1.1  christos 		}
    165      1.1  christos 		region_destroy(tempregion);
    166      1.1  christos 		return;
    167      1.1  christos 	}
    168      1.1  christos 	if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) {
    169      1.1  christos 		/* older file version; reset everything */
    170      1.1  christos 		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: file %s is old version. refreshing all zones.",
    171      1.1  christos 			statefile));
    172      1.1  christos 		fclose(in);
    173      1.1  christos 		region_destroy(tempregion);
    174      1.1  christos 		return;
    175      1.1  christos 	}
    176      1.1  christos 	if(!xfrd_read_check_str(in, "filetime:") ||
    177      1.1  christos 	   !xfrd_read_i32(in, &filetime) ||
    178      1.1  christos 	   (time_t)filetime > xfrd_time()+15 ||
    179      1.1  christos 	   !xfrd_read_check_str(in, "numzones:") ||
    180      1.1  christos 	   !xfrd_read_i32(in, &numzones))
    181      1.1  christos 	{
    182      1.1  christos 		log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)",
    183      1.1  christos 			statefile, (int)filetime, (long long)xfrd_time());
    184      1.1  christos 		fclose(in);
    185      1.1  christos 		region_destroy(tempregion);
    186      1.1  christos 		return;
    187      1.1  christos 	}
    188      1.1  christos 
    189      1.1  christos 	for(i=0; i<numzones; i++) {
    190      1.1  christos 		char *p;
    191  1.1.1.2  christos 		xfrd_zone_type* zone;
    192      1.1  christos 		const dname_type* dname;
    193      1.1  christos 		uint32_t state, masnum, nextmas, round_num, timeout, backoff;
    194  1.1.1.2  christos 		xfrd_soa_type soa_nsd_read, soa_disk_read, soa_notified_read;
    195      1.1  christos 		time_t soa_nsd_acquired_read,
    196      1.1  christos 			soa_disk_acquired_read, soa_notified_acquired_read;
    197  1.1.1.2  christos 		xfrd_soa_type incoming_soa;
    198      1.1  christos 		time_t incoming_acquired;
    199      1.1  christos 
    200      1.1  christos 		if(nsd.signal_hint_shutdown) {
    201      1.1  christos 			fclose(in);
    202      1.1  christos 			region_destroy(tempregion);
    203      1.1  christos 			return;
    204      1.1  christos 		}
    205      1.1  christos 
    206      1.1  christos 		memset(&soa_nsd_read, 0, sizeof(soa_nsd_read));
    207      1.1  christos 		memset(&soa_disk_read, 0, sizeof(soa_disk_read));
    208      1.1  christos 		memset(&soa_notified_read, 0, sizeof(soa_notified_read));
    209      1.1  christos 
    210      1.1  christos 		if(!xfrd_read_check_str(in, "zone:") ||
    211      1.1  christos 		   !xfrd_read_check_str(in, "name:")  ||
    212      1.1  christos 		   !(p=xfrd_read_token(in)) ||
    213      1.1  christos 		   !(dname = dname_parse(tempregion, p)) ||
    214      1.1  christos 		   !xfrd_read_check_str(in, "state:") ||
    215      1.1  christos 		   !xfrd_read_i32(in, &state) || (state>2) ||
    216      1.1  christos 		   !xfrd_read_check_str(in, "master:") ||
    217      1.1  christos 		   !xfrd_read_i32(in, &masnum) ||
    218      1.1  christos 		   !xfrd_read_check_str(in, "next_master:") ||
    219      1.1  christos 		   !xfrd_read_i32(in, &nextmas) ||
    220      1.1  christos 		   !xfrd_read_check_str(in, "round_num:") ||
    221      1.1  christos 		   !xfrd_read_i32(in, &round_num) ||
    222      1.1  christos 		   !xfrd_read_check_str(in, "next_timeout:") ||
    223      1.1  christos 		   !xfrd_read_i32(in, &timeout) ||
    224      1.1  christos 		   !xfrd_read_check_str(in, "backoff:") ||
    225      1.1  christos 		   !xfrd_read_i32(in, &backoff) ||
    226      1.1  christos 		   !xfrd_read_state_soa(in, "soa_nsd_acquired:", "soa_nsd:",
    227      1.1  christos 			&soa_nsd_read, &soa_nsd_acquired_read) ||
    228      1.1  christos 		   !xfrd_read_state_soa(in, "soa_disk_acquired:", "soa_disk:",
    229      1.1  christos 			&soa_disk_read, &soa_disk_acquired_read) ||
    230      1.1  christos 		   !xfrd_read_state_soa(in, "soa_notify_acquired:", "soa_notify:",
    231      1.1  christos 			&soa_notified_read, &soa_notified_acquired_read))
    232      1.1  christos 		{
    233      1.1  christos 			log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)",
    234      1.1  christos 				statefile, (int)filetime, (long long)xfrd_time());
    235      1.1  christos 			fclose(in);
    236      1.1  christos 			region_destroy(tempregion);
    237      1.1  christos 			return;
    238      1.1  christos 		}
    239      1.1  christos 
    240  1.1.1.2  christos 		zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, dname);
    241      1.1  christos 		if(!zone) {
    242      1.1  christos 			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: state file has info for not configured zone %s", p));
    243      1.1  christos 			continue;
    244      1.1  christos 		}
    245      1.1  christos 
    246      1.1  christos 		if(soa_nsd_acquired_read>xfrd_time()+15 ||
    247      1.1  christos 			soa_disk_acquired_read>xfrd_time()+15 ||
    248      1.1  christos 			soa_notified_acquired_read>xfrd_time()+15)
    249      1.1  christos 		{
    250      1.1  christos 			log_msg(LOG_ERR, "xfrd: statefile %s contains"
    251      1.1  christos 				" times in the future for zone %s. Ignoring.",
    252      1.1  christos 				statefile, zone->apex_str);
    253      1.1  christos 			continue;
    254      1.1  christos 		}
    255      1.1  christos 		zone->state = state;
    256      1.1  christos 		zone->master_num = masnum;
    257      1.1  christos 		zone->next_master = nextmas;
    258      1.1  christos 		zone->round_num = round_num;
    259      1.1  christos 		zone->timeout.tv_sec = timeout;
    260      1.1  christos 		zone->timeout.tv_usec = 0;
    261      1.1  christos 		zone->fresh_xfr_timeout = backoff*XFRD_TRANSFER_TIMEOUT_START;
    262      1.1  christos 
    263      1.1  christos 		/* read the zone OK, now set the master properly */
    264      1.1  christos 		zone->master = acl_find_num(zone->zone_options->pattern->
    265      1.1  christos 			request_xfr, zone->master_num);
    266      1.1  christos 		if(!zone->master) {
    267      1.1  christos 			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: masters changed for zone %s",
    268      1.1  christos 				zone->apex_str));
    269      1.1  christos 			zone->master = zone->zone_options->pattern->request_xfr;
    270      1.1  christos 			zone->master_num = 0;
    271      1.1  christos 			zone->round_num = 0;
    272      1.1  christos 		}
    273      1.1  christos 
    274      1.1  christos 		/*
    275      1.1  christos 		 * There is no timeout,
    276      1.1  christos 		 * or there is a notification,
    277      1.1  christos 		 * or there is a soa && current time is past refresh point
    278      1.1  christos 		 */
    279      1.1  christos 		soa_refresh = ntohl(soa_disk_read.refresh);
    280      1.1  christos 		if (soa_refresh > (time_t)zone->zone_options->pattern->max_refresh_time)
    281      1.1  christos 			soa_refresh = zone->zone_options->pattern->max_refresh_time;
    282      1.1  christos 		else if (soa_refresh < (time_t)zone->zone_options->pattern->min_refresh_time)
    283      1.1  christos 			soa_refresh = zone->zone_options->pattern->min_refresh_time;
    284      1.1  christos 		if(timeout == 0 || soa_notified_acquired_read != 0 ||
    285      1.1  christos 			(soa_disk_acquired_read != 0 &&
    286      1.1  christos 			(uint32_t)xfrd_time() - soa_disk_acquired_read
    287      1.1  christos 				> (uint32_t)soa_refresh))
    288      1.1  christos 		{
    289      1.1  christos 			zone->state = xfrd_zone_refreshing;
    290      1.1  christos 			xfrd_set_refresh_now(zone);
    291      1.1  christos 		}
    292  1.1.1.4  christos 		if(timeout != 0 && filetime + timeout < (uint32_t)xfrd_time()) {
    293  1.1.1.4  christos 			/* timeout is in the past, refresh the zone */
    294  1.1.1.4  christos 			timeout = 0;
    295  1.1.1.4  christos 			if(zone->state == xfrd_zone_ok)
    296  1.1.1.4  christos 				zone->state = xfrd_zone_refreshing;
    297  1.1.1.4  christos 			xfrd_set_refresh_now(zone);
    298  1.1.1.4  christos 		}
    299      1.1  christos 
    300      1.1  christos 		/* There is a soa && current time is past expiry point */
    301      1.1  christos 		if(soa_disk_acquired_read!=0 &&
    302      1.1  christos 			(uint32_t)xfrd_time() - soa_disk_acquired_read
    303      1.1  christos 				> ntohl(soa_disk_read.expire))
    304      1.1  christos 		{
    305      1.1  christos 			zone->state = xfrd_zone_expired;
    306      1.1  christos 			xfrd_set_refresh_now(zone);
    307      1.1  christos 		}
    308      1.1  christos 
    309      1.1  christos 		/* there is a zone read and it matches what we had before */
    310      1.1  christos 		if(zone->soa_nsd_acquired && zone->state != xfrd_zone_expired
    311      1.1  christos 			&& zone->soa_nsd.serial == soa_nsd_read.serial) {
    312      1.1  christos 			xfrd_deactivate_zone(zone);
    313      1.1  christos 			zone->state = state;
    314  1.1.1.5  christos 			xfrd_set_timer(zone,
    315  1.1.1.5  christos 				within_refresh_bounds(zone, timeout));
    316      1.1  christos 		}
    317      1.1  christos 		if((zone->soa_nsd_acquired == 0 && soa_nsd_acquired_read == 0 &&
    318      1.1  christos 			soa_disk_acquired_read == 0) ||
    319      1.1  christos 			(zone->state != xfrd_zone_ok && timeout != 0)) {
    320      1.1  christos 			/* but don't check now, because that would mean a
    321      1.1  christos 			 * storm of attempts on some master servers */
    322      1.1  christos 			xfrd_deactivate_zone(zone);
    323      1.1  christos 			zone->state = state;
    324  1.1.1.5  christos 			xfrd_set_timer(zone,
    325  1.1.1.5  christos 				within_retry_bounds(zone, timeout));
    326      1.1  christos 		}
    327      1.1  christos 
    328      1.1  christos 		/* handle as an incoming SOA. */
    329      1.1  christos 		incoming_soa = zone->soa_nsd;
    330      1.1  christos 		incoming_acquired = zone->soa_nsd_acquired;
    331      1.1  christos 		zone->soa_nsd = soa_nsd_read;
    332      1.1  christos 		zone->soa_nsd_acquired = soa_nsd_acquired_read;
    333  1.1.1.6  christos 		/* use soa and soa_acquired from starting NSD, not what is stored in
    334  1.1.1.6  christos 		 * the state file, because the actual zone contents trumps the contents
    335  1.1.1.6  christos 		 * of this cache */
    336  1.1.1.6  christos 		zone->soa_disk = incoming_soa;
    337  1.1.1.6  christos 		zone->soa_disk_acquired = incoming_acquired;
    338  1.1.1.6  christos 		zone->soa_notified = soa_notified_read;
    339      1.1  christos 		zone->soa_notified_acquired = soa_notified_acquired_read;
    340      1.1  christos 		if (zone->state == xfrd_zone_expired)
    341      1.1  christos 		{
    342      1.1  christos 			xfrd_send_expire_notification(zone);
    343      1.1  christos 		}
    344      1.1  christos 		if(incoming_acquired != 0)
    345      1.1  christos 			xfrd_handle_incoming_soa(zone, &incoming_soa, incoming_acquired);
    346      1.1  christos 	}
    347      1.1  christos 
    348      1.1  christos 	if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) {
    349      1.1  christos 		log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)",
    350      1.1  christos 			statefile, (int)filetime, (long long)xfrd_time());
    351      1.1  christos 		region_destroy(tempregion);
    352      1.1  christos 		fclose(in);
    353      1.1  christos 		return;
    354      1.1  christos 	}
    355      1.1  christos 
    356      1.1  christos 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: read %d zones from state file", (int)numzones));
    357      1.1  christos 	fclose(in);
    358      1.1  christos 	region_destroy(tempregion);
    359      1.1  christos }
    360      1.1  christos 
    361      1.1  christos /* prints neato days hours and minutes. */
    362      1.1  christos static void
    363      1.1  christos neato_timeout(FILE* out, const char* str, time_t secs)
    364      1.1  christos {
    365      1.1  christos 	fprintf(out, "%s", str);
    366      1.1  christos 	if(secs <= 0) {
    367      1.1  christos 		fprintf(out, " %llds", (long long)secs);
    368      1.1  christos 		return;
    369      1.1  christos 	}
    370      1.1  christos 	if(secs >= 3600*24) {
    371      1.1  christos 		fprintf(out, " %lldd", (long long)(secs/(3600*24)));
    372      1.1  christos 		secs = secs % (3600*24);
    373      1.1  christos 	}
    374      1.1  christos 	if(secs >= 3600) {
    375      1.1  christos 		fprintf(out, " %lldh", (long long)(secs/3600));
    376      1.1  christos 		secs = secs%3600;
    377      1.1  christos 	}
    378      1.1  christos 	if(secs >= 60) {
    379      1.1  christos 		fprintf(out, " %lldm", (long long)(secs/60));
    380      1.1  christos 		secs = secs%60;
    381      1.1  christos 	}
    382      1.1  christos 	if(secs > 0) {
    383      1.1  christos 		fprintf(out, " %llds", (long long)secs);
    384      1.1  christos 	}
    385      1.1  christos }
    386      1.1  christos 
    387      1.1  christos static void xfrd_write_dname(FILE* out, uint8_t* dname)
    388      1.1  christos {
    389      1.1  christos 	uint8_t* d= dname+1;
    390      1.1  christos 	uint8_t len = *d++;
    391      1.1  christos 	uint8_t i;
    392      1.1  christos 
    393      1.1  christos 	if(dname[0]<=1) {
    394      1.1  christos 		fprintf(out, ".");
    395      1.1  christos 		return;
    396      1.1  christos 	}
    397      1.1  christos 
    398      1.1  christos 	while(len)
    399      1.1  christos 	{
    400      1.1  christos 		assert(d - (dname+1) <= dname[0]);
    401      1.1  christos 		for(i=0; i<len; i++)
    402      1.1  christos 		{
    403      1.1  christos 			uint8_t ch = *d++;
    404      1.1  christos 			if (isalnum((unsigned char)ch) || ch == '-' || ch == '_') {
    405      1.1  christos 				fprintf(out, "%c", ch);
    406      1.1  christos 			} else if (ch == '.' || ch == '\\') {
    407      1.1  christos 				fprintf(out, "\\%c", ch);
    408      1.1  christos 			} else {
    409      1.1  christos 				fprintf(out, "\\%03u", (unsigned int)ch);
    410      1.1  christos 			}
    411      1.1  christos 		}
    412      1.1  christos 		fprintf(out, ".");
    413      1.1  christos 		len = *d++;
    414      1.1  christos 	}
    415      1.1  christos }
    416      1.1  christos 
    417      1.1  christos static void
    418      1.1  christos xfrd_write_state_soa(FILE* out, const char* id,
    419  1.1.1.2  christos 	xfrd_soa_type* soa, time_t soatime, const dname_type* ATTR_UNUSED(apex))
    420      1.1  christos {
    421      1.1  christos 	fprintf(out, "\t%s_acquired: %d", id, (int)soatime);
    422      1.1  christos 	if(!soatime) {
    423      1.1  christos 		fprintf(out, "\n");
    424      1.1  christos 		return;
    425      1.1  christos 	}
    426      1.1  christos 	neato_timeout(out, "\t# was", xfrd_time()-soatime);
    427      1.1  christos 	fprintf(out, " ago\n");
    428      1.1  christos 
    429      1.1  christos 	fprintf(out, "\t%s: %u %u %u %u", id,
    430      1.1  christos 		(unsigned)ntohs(soa->type), (unsigned)ntohs(soa->klass),
    431      1.1  christos 		(unsigned)ntohl(soa->ttl), (unsigned)ntohs(soa->rdata_count));
    432      1.1  christos 	fprintf(out, " ");
    433      1.1  christos 	xfrd_write_dname(out, soa->prim_ns);
    434      1.1  christos 	fprintf(out, " ");
    435      1.1  christos 	xfrd_write_dname(out, soa->email);
    436      1.1  christos 	fprintf(out, " %u", (unsigned)ntohl(soa->serial));
    437      1.1  christos 	fprintf(out, " %u", (unsigned)ntohl(soa->refresh));
    438      1.1  christos 	fprintf(out, " %u", (unsigned)ntohl(soa->retry));
    439      1.1  christos 	fprintf(out, " %u", (unsigned)ntohl(soa->expire));
    440      1.1  christos 	fprintf(out, " %u\n", (unsigned)ntohl(soa->minimum));
    441      1.1  christos 	fprintf(out, "\t#");
    442      1.1  christos 	neato_timeout(out, " refresh =", ntohl(soa->refresh));
    443      1.1  christos 	neato_timeout(out, " retry =", ntohl(soa->retry));
    444      1.1  christos 	neato_timeout(out, " expire =", ntohl(soa->expire));
    445      1.1  christos 	neato_timeout(out, " minimum =", ntohl(soa->minimum));
    446      1.1  christos 	fprintf(out, "\n");
    447      1.1  christos }
    448      1.1  christos 
    449      1.1  christos void
    450      1.1  christos xfrd_write_state(struct xfrd_state* xfrd)
    451      1.1  christos {
    452  1.1.1.2  christos 	rbnode_type* p;
    453      1.1  christos 	const char* statefile = xfrd->nsd->options->xfrdfile;
    454      1.1  christos 	FILE *out;
    455      1.1  christos 	time_t now = xfrd_time();
    456      1.1  christos 
    457      1.1  christos 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: write file %s", statefile));
    458      1.1  christos 	out = fopen(statefile, "w");
    459      1.1  christos 	if(!out) {
    460      1.1  christos 		log_msg(LOG_ERR, "xfrd: Could not open file %s for writing: %s",
    461      1.1  christos 				statefile, strerror(errno));
    462      1.1  christos 		return;
    463      1.1  christos 	}
    464      1.1  christos 
    465      1.1  christos 	fprintf(out, "%s\n", XFRD_FILE_MAGIC);
    466      1.1  christos 	fprintf(out, "# This file is written on exit by nsd xfr daemon.\n");
    467      1.1  christos 	fprintf(out, "# This file contains slave zone information:\n");
    468      1.1  christos 	fprintf(out, "# 	* timeouts (when was zone data acquired)\n");
    469      1.1  christos 	fprintf(out, "# 	* state (OK, refreshing, expired)\n");
    470      1.1  christos 	fprintf(out, "# 	* which master transfer to attempt next\n");
    471      1.1  christos 	fprintf(out, "# The file is read on start (but not on reload) by nsd xfr daemon.\n");
    472      1.1  christos 	fprintf(out, "# You can edit; but do not change statement order\n");
    473      1.1  christos 	fprintf(out, "# and no fancy stuff (like quoted \"strings\").\n");
    474      1.1  christos 	fprintf(out, "#\n");
    475      1.1  christos 	fprintf(out, "# If you remove a zone entry, it will be refreshed.\n");
    476      1.1  christos 	fprintf(out, "# This can be useful for an expired zone; it revives\n");
    477      1.1  christos 	fprintf(out, "# the zone temporarily, from refresh-expiry time.\n");
    478      1.1  christos 	fprintf(out, "# If you delete the file all slave zones are updated.\n");
    479      1.1  christos 	fprintf(out, "#\n");
    480      1.1  christos 	fprintf(out, "# Note: if you edit this file while nsd is running,\n");
    481      1.1  christos 	fprintf(out, "#       it will be overwritten on exit by nsd.\n");
    482      1.1  christos 	fprintf(out, "\n");
    483      1.1  christos 	fprintf(out, "filetime: %lld\t# %s\n", (long long)now, ctime(&now));
    484      1.1  christos 	fprintf(out, "# The number of zone entries in this file\n");
    485      1.1  christos 	fprintf(out, "numzones: %d\n", (int)xfrd->zones->count);
    486      1.1  christos 	fprintf(out, "\n");
    487      1.1  christos 	for(p = rbtree_first(xfrd->zones); p && p!=RBTREE_NULL; p=rbtree_next(p))
    488      1.1  christos 	{
    489  1.1.1.2  christos 		xfrd_zone_type* zone = (xfrd_zone_type*)p;
    490      1.1  christos 		fprintf(out, "zone: \tname: %s\n", zone->apex_str);
    491      1.1  christos 		fprintf(out, "\tstate: %d", (int)zone->state);
    492      1.1  christos 		fprintf(out, " # %s", zone->state==xfrd_zone_ok?"OK":(
    493      1.1  christos 			zone->state==xfrd_zone_refreshing?"refreshing":"expired"));
    494      1.1  christos 		fprintf(out, "\n");
    495      1.1  christos 		fprintf(out, "\tmaster: %d\n", zone->master_num);
    496      1.1  christos 		fprintf(out, "\tnext_master: %d\n", zone->next_master);
    497      1.1  christos 		fprintf(out, "\tround_num: %d\n", zone->round_num);
    498      1.1  christos 		fprintf(out, "\tnext_timeout: %d",
    499      1.1  christos 			(zone->zone_handler_flags&EV_TIMEOUT)?(int)zone->timeout.tv_sec:0);
    500      1.1  christos 		if((zone->zone_handler_flags&EV_TIMEOUT)) {
    501      1.1  christos 			neato_timeout(out, "\t# =", zone->timeout.tv_sec);
    502      1.1  christos 		}
    503      1.1  christos 		fprintf(out, "\n");
    504      1.1  christos 		fprintf(out, "\tbackoff: %d\n", zone->fresh_xfr_timeout/XFRD_TRANSFER_TIMEOUT_START);
    505      1.1  christos 		xfrd_write_state_soa(out, "soa_nsd", &zone->soa_nsd,
    506      1.1  christos 			zone->soa_nsd_acquired, zone->apex);
    507      1.1  christos 		xfrd_write_state_soa(out, "soa_disk", &zone->soa_disk,
    508      1.1  christos 			zone->soa_disk_acquired, zone->apex);
    509      1.1  christos 		xfrd_write_state_soa(out, "soa_notify", &zone->soa_notified,
    510      1.1  christos 			zone->soa_notified_acquired, zone->apex);
    511      1.1  christos 		fprintf(out, "\n");
    512      1.1  christos 	}
    513      1.1  christos 
    514      1.1  christos 	fprintf(out, "%s\n", XFRD_FILE_MAGIC);
    515      1.1  christos 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: written %d zones to state file",
    516      1.1  christos 		(int)xfrd->zones->count));
    517      1.1  christos 	fclose(out);
    518      1.1  christos }
    519      1.1  christos 
    520      1.1  christos /* return tempdirname */
    521      1.1  christos static void
    522      1.1  christos tempdirname(char* buf, size_t sz, struct nsd* nsd)
    523      1.1  christos {
    524      1.1  christos 	snprintf(buf, sz, "%snsd-xfr-%d",
    525      1.1  christos 		nsd->options->xfrdir, (int)nsd->pid);
    526      1.1  christos }
    527      1.1  christos 
    528      1.1  christos void
    529      1.1  christos xfrd_make_tempdir(struct nsd* nsd)
    530      1.1  christos {
    531      1.1  christos 	char tnm[1024];
    532      1.1  christos 	tempdirname(tnm, sizeof(tnm), nsd);
    533      1.1  christos 	/* create parent directories if needed (0750 permissions) */
    534      1.1  christos 	if(!create_dirs(tnm)) {
    535      1.1  christos 		log_msg(LOG_ERR, "parentdirs of %s failed", tnm);
    536      1.1  christos 	}
    537      1.1  christos 	/* restrictive permissions here, because this may be in /tmp */
    538      1.1  christos 	if(mkdir(tnm, 0700)==-1) {
    539      1.1  christos 		if(errno != EEXIST) {
    540      1.1  christos 			log_msg(LOG_ERR, "mkdir %s failed: %s",
    541      1.1  christos 				tnm, strerror(errno));
    542      1.1  christos 		}
    543      1.1  christos 	}
    544      1.1  christos }
    545      1.1  christos 
    546      1.1  christos void
    547      1.1  christos xfrd_del_tempdir(struct nsd* nsd)
    548      1.1  christos {
    549      1.1  christos 	char tnm[1024];
    550      1.1  christos 	tempdirname(tnm, sizeof(tnm), nsd);
    551      1.1  christos 	/* ignore parent directories, they are likely /var/tmp, /tmp or
    552      1.1  christos 	 * /var/cache/nsd and do not have to be deleted */
    553      1.1  christos 	if(rmdir(tnm)==-1 && errno != ENOENT) {
    554      1.1  christos 		log_msg(LOG_WARNING, "rmdir %s failed: %s", tnm,
    555      1.1  christos 			strerror(errno));
    556      1.1  christos 	}
    557      1.1  christos }
    558      1.1  christos 
    559      1.1  christos /* return name of xfrfile in tempdir */
    560      1.1  christos static void
    561      1.1  christos tempxfrname(char* buf, size_t sz, struct nsd* nsd, uint64_t number)
    562      1.1  christos {
    563      1.1  christos 	char tnm[1024];
    564      1.1  christos 	tempdirname(tnm, sizeof(tnm), nsd);
    565      1.1  christos 	snprintf(buf, sz, "%s/xfr.%lld", tnm, (long long)number);
    566      1.1  christos }
    567      1.1  christos 
    568      1.1  christos FILE*
    569      1.1  christos xfrd_open_xfrfile(struct nsd* nsd, uint64_t number, char* mode)
    570      1.1  christos {
    571  1.1.1.3  christos 	char fname[1200];
    572      1.1  christos 	FILE* xfr;
    573      1.1  christos 	tempxfrname(fname, sizeof(fname), nsd, number);
    574      1.1  christos 	xfr = fopen(fname, mode);
    575      1.1  christos 	if(!xfr && errno == ENOENT) {
    576      1.1  christos 		/* directory may not exist */
    577      1.1  christos 		xfrd_make_tempdir(nsd);
    578      1.1  christos 		xfr = fopen(fname, mode);
    579      1.1  christos 	}
    580      1.1  christos 	if(!xfr) {
    581      1.1  christos 		log_msg(LOG_ERR, "open %s for %s failed: %s", fname, mode,
    582      1.1  christos 			strerror(errno));
    583      1.1  christos 		return NULL;
    584      1.1  christos 	}
    585      1.1  christos 	return xfr;
    586      1.1  christos }
    587      1.1  christos 
    588      1.1  christos void
    589      1.1  christos xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number)
    590      1.1  christos {
    591  1.1.1.3  christos 	char fname[1200];
    592      1.1  christos 	tempxfrname(fname, sizeof(fname), nsd, number);
    593      1.1  christos 	if(unlink(fname) == -1) {
    594      1.1  christos 		log_msg(LOG_WARNING, "could not unlink %s: %s", fname,
    595      1.1  christos 			strerror(errno));
    596      1.1  christos 	}
    597      1.1  christos }
    598      1.1  christos 
    599      1.1  christos uint64_t
    600      1.1  christos xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number )
    601      1.1  christos {
    602  1.1.1.3  christos 	char fname[1200];
    603      1.1  christos 	struct stat tempxfr_stat;
    604      1.1  christos 	tempxfrname(fname, sizeof(fname), nsd, number);
    605      1.1  christos 	if( stat( fname, &tempxfr_stat ) < 0 ) {
    606      1.1  christos 	    log_msg(LOG_WARNING, "could not get file size %s: %s", fname,
    607      1.1  christos 		    strerror(errno));
    608      1.1  christos 	    return 0;
    609      1.1  christos 	}
    610      1.1  christos 	return (uint64_t)tempxfr_stat.st_size;
    611      1.1  christos }
    612