Home | History | Annotate | Line # | Download | only in dist
xfrd-disk.c revision 1.1.1.3.2.1
      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.3.2.1    martin 		if(timeout != 0 && filetime + timeout < (uint32_t)xfrd_time()) {
    293  1.1.1.3.2.1    martin 			/* timeout is in the past, refresh the zone */
    294  1.1.1.3.2.1    martin 			timeout = 0;
    295  1.1.1.3.2.1    martin 			if(zone->state == xfrd_zone_ok)
    296  1.1.1.3.2.1    martin 				zone->state = xfrd_zone_refreshing;
    297  1.1.1.3.2.1    martin 			xfrd_set_refresh_now(zone);
    298  1.1.1.3.2.1    martin 		}
    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.3.2.1    martin 			xfrd_set_timer(zone,
    315  1.1.1.3.2.1    martin 				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.3.2.1    martin 			xfrd_set_timer(zone,
    325  1.1.1.3.2.1    martin 				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.3.2.1    martin 		/* use soa and soa_acquired from starting NSD, not what is stored in
    334  1.1.1.3.2.1    martin 		 * the state file, because the actual zone contents trumps the contents
    335  1.1.1.3.2.1    martin 		 * of this cache */
    336  1.1.1.3.2.1    martin 		zone->soa_disk = incoming_soa;
    337  1.1.1.3.2.1    martin 		zone->soa_disk_acquired = incoming_acquired;
    338  1.1.1.3.2.1    martin 		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