xref: /openbsd-src/usr.sbin/nsd/util.c (revision bf87c3c07c3ad89262e2b8cae09f17e70aa9e1ee)
162ac0c33Sjakob /*
262ac0c33Sjakob  * util.c -- set of various support routines.
362ac0c33Sjakob  *
4dd5b221eSsthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
10d11a62c8Ssthen #include "config.h"
1162ac0c33Sjakob 
1262ac0c33Sjakob #include <assert.h>
1362ac0c33Sjakob #include <ctype.h>
1462ac0c33Sjakob #include <errno.h>
1562ac0c33Sjakob #include <stdarg.h>
1662ac0c33Sjakob #include <stdio.h>
1762ac0c33Sjakob #include <stdlib.h>
1862ac0c33Sjakob #include <string.h>
19308d2509Sflorian #ifdef HAVE_SCHED_H
20308d2509Sflorian #include <sched.h>
21308d2509Sflorian #endif /* HAVE_SCHED_H */
22308d2509Sflorian #ifdef HAVE_SYS_CPUSET_H
23308d2509Sflorian #include <sys/cpuset.h>
24308d2509Sflorian #endif /* HAVE_SYS_CPUSET_H */
2562ac0c33Sjakob #ifdef HAVE_SYSLOG_H
2662ac0c33Sjakob #include <syslog.h>
2762ac0c33Sjakob #endif /* HAVE_SYSLOG_H */
2862ac0c33Sjakob #include <unistd.h>
29308d2509Sflorian #ifdef HAVE_SYS_RANDOM_H
30308d2509Sflorian #include <sys/random.h>
31308d2509Sflorian #endif
3262ac0c33Sjakob 
3362ac0c33Sjakob #include "util.h"
3462ac0c33Sjakob #include "region-allocator.h"
3562ac0c33Sjakob #include "dname.h"
3662ac0c33Sjakob #include "namedb.h"
3762ac0c33Sjakob #include "rdata.h"
3875343be4Ssthen #include "zonec.h"
39063644e9Sflorian #include "nsd.h"
4062ac0c33Sjakob 
414ab91c82Sjakob #ifdef USE_MMAP_ALLOC
424ab91c82Sjakob #include <sys/mman.h>
434ab91c82Sjakob 
444ab91c82Sjakob #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
454ab91c82Sjakob #define	MAP_ANONYMOUS	MAP_ANON
464ab91c82Sjakob #elif defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
474ab91c82Sjakob #define	MAP_ANON	MAP_ANONYMOUS
484ab91c82Sjakob #endif
494ab91c82Sjakob 
504ab91c82Sjakob #endif /* USE_MMAP_ALLOC */
514ab91c82Sjakob 
5262ac0c33Sjakob #ifndef NDEBUG
5362ac0c33Sjakob unsigned nsd_debug_facilities = 0xffff;
5462ac0c33Sjakob int nsd_debug_level = 0;
5562ac0c33Sjakob #endif
5662ac0c33Sjakob 
5775343be4Ssthen #define MSB_32 0x80000000
5875343be4Ssthen 
5962ac0c33Sjakob int verbosity = 0;
6062ac0c33Sjakob 
6162ac0c33Sjakob static const char *global_ident = NULL;
6262ac0c33Sjakob static log_function_type *current_log_function = log_file;
6362ac0c33Sjakob static FILE *current_log_file = NULL;
64533110e2Sbrad int log_time_asc = 1;
6562ac0c33Sjakob 
66*bf87c3c0Sflorian #ifdef USE_LOG_PROCESS_ROLE
67*bf87c3c0Sflorian void
log_set_process_role(const char * process_role)68*bf87c3c0Sflorian log_set_process_role(const char *process_role)
69*bf87c3c0Sflorian {
70*bf87c3c0Sflorian 	global_ident = process_role;
71*bf87c3c0Sflorian }
72*bf87c3c0Sflorian #endif
73*bf87c3c0Sflorian 
7462ac0c33Sjakob void
log_init(const char * ident)7562ac0c33Sjakob log_init(const char *ident)
7662ac0c33Sjakob {
7762ac0c33Sjakob 	global_ident = ident;
7862ac0c33Sjakob 	current_log_file = stderr;
7962ac0c33Sjakob }
8062ac0c33Sjakob 
8162ac0c33Sjakob void
log_open(int option,int facility,const char * filename)8262ac0c33Sjakob log_open(int option, int facility, const char *filename)
8362ac0c33Sjakob {
8462ac0c33Sjakob #ifdef HAVE_SYSLOG_H
8562ac0c33Sjakob 	openlog(global_ident, option, facility);
8662ac0c33Sjakob #endif /* HAVE_SYSLOG_H */
8762ac0c33Sjakob 	if (filename) {
8862ac0c33Sjakob 		FILE *file = fopen(filename, "a");
8962ac0c33Sjakob 		if (!file) {
9062ac0c33Sjakob 			log_msg(LOG_ERR, "Cannot open %s for appending (%s), "
9162ac0c33Sjakob 					 "logging to stderr",
9262ac0c33Sjakob 				filename, strerror(errno));
9362ac0c33Sjakob 		} else {
9462ac0c33Sjakob 			current_log_file = file;
9562ac0c33Sjakob 		}
9662ac0c33Sjakob 	}
9762ac0c33Sjakob }
9862ac0c33Sjakob 
9962ac0c33Sjakob void
log_reopen(const char * filename,uint8_t verbose)10062ac0c33Sjakob log_reopen(const char *filename, uint8_t verbose)
10162ac0c33Sjakob {
10262ac0c33Sjakob 	if (filename) {
1039c620270Ssthen 		FILE *file;
1049c620270Ssthen 		if(strcmp(filename, "/dev/stdout")==0 || strcmp(filename, "/dev/stderr")==0)
1059c620270Ssthen 			return;
1069c620270Ssthen 		file = fopen(filename, "a");
10762ac0c33Sjakob 		if (!file) {
10862ac0c33Sjakob 			if (verbose)
10962ac0c33Sjakob 				VERBOSITY(2, (LOG_WARNING,
11062ac0c33Sjakob                                 	"Cannot reopen %s for appending (%s), "
11162ac0c33Sjakob 					"keeping old logfile",
11262ac0c33Sjakob 					filename, strerror(errno)));
11362ac0c33Sjakob 		} else {
11462ac0c33Sjakob 			if (current_log_file && current_log_file != stderr)
11562ac0c33Sjakob 				fclose(current_log_file);
11662ac0c33Sjakob 			current_log_file = file;
11762ac0c33Sjakob 		}
11862ac0c33Sjakob 	}
11962ac0c33Sjakob }
12062ac0c33Sjakob 
12162ac0c33Sjakob void
log_finalize(void)12262ac0c33Sjakob log_finalize(void)
12362ac0c33Sjakob {
12462ac0c33Sjakob #ifdef HAVE_SYSLOG_H
12562ac0c33Sjakob 	closelog();
12662ac0c33Sjakob #endif /* HAVE_SYSLOG_H */
12762ac0c33Sjakob 	if (current_log_file && current_log_file != stderr) {
12862ac0c33Sjakob 		fclose(current_log_file);
12962ac0c33Sjakob 	}
13062ac0c33Sjakob 	current_log_file = NULL;
13162ac0c33Sjakob }
13262ac0c33Sjakob 
13362ac0c33Sjakob static lookup_table_type log_priority_table[] = {
13462ac0c33Sjakob 	{ LOG_ERR, "error" },
13562ac0c33Sjakob 	{ LOG_WARNING, "warning" },
13662ac0c33Sjakob 	{ LOG_NOTICE, "notice" },
13762ac0c33Sjakob 	{ LOG_INFO, "info" },
13862ac0c33Sjakob 	{ 0, NULL }
13962ac0c33Sjakob };
14062ac0c33Sjakob 
14162ac0c33Sjakob void
log_file(int priority,const char * message)14262ac0c33Sjakob log_file(int priority, const char *message)
14362ac0c33Sjakob {
14462ac0c33Sjakob 	size_t length;
14562ac0c33Sjakob 	lookup_table_type *priority_info;
14662ac0c33Sjakob 	const char *priority_text = "unknown";
14762ac0c33Sjakob 
14862ac0c33Sjakob 	assert(global_ident);
14962ac0c33Sjakob 	assert(current_log_file);
15062ac0c33Sjakob 
15162ac0c33Sjakob 	priority_info = lookup_by_id(log_priority_table, priority);
15262ac0c33Sjakob 	if (priority_info) {
15362ac0c33Sjakob 		priority_text = priority_info->name;
15462ac0c33Sjakob 	}
15562ac0c33Sjakob 
15662ac0c33Sjakob 	/* Bug #104, add time_t timestamp */
157533110e2Sbrad #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R)
158533110e2Sbrad 	if(log_time_asc) {
159533110e2Sbrad 		struct timeval tv;
160533110e2Sbrad 		char tmbuf[32];
161533110e2Sbrad 		tmbuf[0]=0;
162533110e2Sbrad 		tv.tv_usec = 0;
163533110e2Sbrad 		if(gettimeofday(&tv, NULL) == 0) {
164533110e2Sbrad 			struct tm tm;
165533110e2Sbrad 			time_t now = (time_t)tv.tv_sec;
166533110e2Sbrad 			strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S",
167533110e2Sbrad 				localtime_r(&now, &tm));
168533110e2Sbrad 		}
169533110e2Sbrad 		fprintf(current_log_file, "[%s.%3.3d] %s[%d]: %s: %s",
170533110e2Sbrad 			tmbuf, (int)tv.tv_usec/1000,
171533110e2Sbrad 			global_ident, (int) getpid(), priority_text, message);
172533110e2Sbrad  	} else
173533110e2Sbrad #endif /* have time functions */
17462ac0c33Sjakob 		fprintf(current_log_file, "[%d] %s[%d]: %s: %s",
17562ac0c33Sjakob 		(int)time(NULL), global_ident, (int) getpid(), priority_text, message);
17662ac0c33Sjakob 	length = strlen(message);
17762ac0c33Sjakob 	if (length == 0 || message[length - 1] != '\n') {
17862ac0c33Sjakob 		fprintf(current_log_file, "\n");
17962ac0c33Sjakob 	}
18062ac0c33Sjakob 	fflush(current_log_file);
18162ac0c33Sjakob }
18262ac0c33Sjakob 
18362ac0c33Sjakob void
log_syslog(int priority,const char * message)18462ac0c33Sjakob log_syslog(int priority, const char *message)
18562ac0c33Sjakob {
18662ac0c33Sjakob #ifdef HAVE_SYSLOG_H
18762ac0c33Sjakob 	syslog(priority, "%s", message);
18862ac0c33Sjakob #endif /* !HAVE_SYSLOG_H */
18962ac0c33Sjakob 	log_file(priority, message);
19062ac0c33Sjakob }
19162ac0c33Sjakob 
19262ac0c33Sjakob void
log_only_syslog(int priority,const char * message)193ac5517e4Sflorian log_only_syslog(int priority, const char *message)
194ac5517e4Sflorian {
195ac5517e4Sflorian #ifdef HAVE_SYSLOG_H
196ac5517e4Sflorian 	syslog(priority, "%s", message);
197ac5517e4Sflorian #else /* !HAVE_SYSLOG_H */
198ac5517e4Sflorian 	/* no syslog, use stderr */
199ac5517e4Sflorian 	log_file(priority, message);
200ac5517e4Sflorian #endif
201ac5517e4Sflorian }
202ac5517e4Sflorian 
203ac5517e4Sflorian void
log_set_log_function(log_function_type * log_function)20462ac0c33Sjakob log_set_log_function(log_function_type *log_function)
20562ac0c33Sjakob {
20662ac0c33Sjakob 	current_log_function = log_function;
20762ac0c33Sjakob }
20862ac0c33Sjakob 
20962ac0c33Sjakob void
log_msg(int priority,const char * format,...)21062ac0c33Sjakob log_msg(int priority, const char *format, ...)
21162ac0c33Sjakob {
21262ac0c33Sjakob 	va_list args;
21362ac0c33Sjakob 	va_start(args, format);
21462ac0c33Sjakob 	log_vmsg(priority, format, args);
21562ac0c33Sjakob 	va_end(args);
21662ac0c33Sjakob }
21762ac0c33Sjakob 
21862ac0c33Sjakob void
log_vmsg(int priority,const char * format,va_list args)21962ac0c33Sjakob log_vmsg(int priority, const char *format, va_list args)
22062ac0c33Sjakob {
22162ac0c33Sjakob 	char message[MAXSYSLOGMSGLEN];
22262ac0c33Sjakob 	vsnprintf(message, sizeof(message), format, args);
22362ac0c33Sjakob 	current_log_function(priority, message);
22462ac0c33Sjakob }
22562ac0c33Sjakob 
22662ac0c33Sjakob void
set_bit(uint8_t bits[],size_t index)22762ac0c33Sjakob set_bit(uint8_t bits[], size_t index)
22862ac0c33Sjakob {
22962ac0c33Sjakob 	/*
23062ac0c33Sjakob 	 * The bits are counted from left to right, so bit #0 is the
23162ac0c33Sjakob 	 * left most bit.
23262ac0c33Sjakob 	 */
23362ac0c33Sjakob 	bits[index / 8] |= (1 << (7 - index % 8));
23462ac0c33Sjakob }
23562ac0c33Sjakob 
23662ac0c33Sjakob void
clear_bit(uint8_t bits[],size_t index)23762ac0c33Sjakob clear_bit(uint8_t bits[], size_t index)
23862ac0c33Sjakob {
23962ac0c33Sjakob 	/*
24062ac0c33Sjakob 	 * The bits are counted from left to right, so bit #0 is the
24162ac0c33Sjakob 	 * left most bit.
24262ac0c33Sjakob 	 */
24362ac0c33Sjakob 	bits[index / 8] &= ~(1 << (7 - index % 8));
24462ac0c33Sjakob }
24562ac0c33Sjakob 
24662ac0c33Sjakob int
get_bit(uint8_t bits[],size_t index)24762ac0c33Sjakob get_bit(uint8_t bits[], size_t index)
24862ac0c33Sjakob {
24962ac0c33Sjakob 	/*
25062ac0c33Sjakob 	 * The bits are counted from left to right, so bit #0 is the
25162ac0c33Sjakob 	 * left most bit.
25262ac0c33Sjakob 	 */
25362ac0c33Sjakob 	return bits[index / 8] & (1 << (7 - index % 8));
25462ac0c33Sjakob }
25562ac0c33Sjakob 
25662ac0c33Sjakob lookup_table_type *
lookup_by_name(lookup_table_type * table,const char * name)25762ac0c33Sjakob lookup_by_name(lookup_table_type *table, const char *name)
25862ac0c33Sjakob {
25962ac0c33Sjakob 	while (table->name != NULL) {
26062ac0c33Sjakob 		if (strcasecmp(name, table->name) == 0)
26162ac0c33Sjakob 			return table;
26262ac0c33Sjakob 		table++;
26362ac0c33Sjakob 	}
26462ac0c33Sjakob 	return NULL;
26562ac0c33Sjakob }
26662ac0c33Sjakob 
26762ac0c33Sjakob lookup_table_type *
lookup_by_id(lookup_table_type * table,int id)26862ac0c33Sjakob lookup_by_id(lookup_table_type *table, int id)
26962ac0c33Sjakob {
27062ac0c33Sjakob 	while (table->name != NULL) {
27162ac0c33Sjakob 		if (table->id == id)
27262ac0c33Sjakob 			return table;
27362ac0c33Sjakob 		table++;
27462ac0c33Sjakob 	}
27562ac0c33Sjakob 	return NULL;
27662ac0c33Sjakob }
27762ac0c33Sjakob 
2783b24e79eSsthen char *
xstrdup(const char * src)2793b24e79eSsthen xstrdup(const char *src)
2803b24e79eSsthen {
2813b24e79eSsthen 	char *result = strdup(src);
2823b24e79eSsthen 
2833b24e79eSsthen 	if(!result) {
2843b24e79eSsthen 		log_msg(LOG_ERR, "strdup failed: %s", strerror(errno));
2853b24e79eSsthen 		exit(1);
2863b24e79eSsthen 	}
2873b24e79eSsthen 
2883b24e79eSsthen 	return result;
2893b24e79eSsthen }
2903b24e79eSsthen 
29162ac0c33Sjakob void *
xalloc(size_t size)29262ac0c33Sjakob xalloc(size_t size)
29362ac0c33Sjakob {
29462ac0c33Sjakob 	void *result = malloc(size);
29562ac0c33Sjakob 
29662ac0c33Sjakob 	if (!result) {
29762ac0c33Sjakob 		log_msg(LOG_ERR, "malloc failed: %s", strerror(errno));
29862ac0c33Sjakob 		exit(1);
29962ac0c33Sjakob 	}
30062ac0c33Sjakob 	return result;
30162ac0c33Sjakob }
30262ac0c33Sjakob 
30362ac0c33Sjakob void *
xmallocarray(size_t num,size_t size)3048d8f1862Ssthen xmallocarray(size_t num, size_t size)
3058d8f1862Ssthen {
3068d8f1862Ssthen         void *result = reallocarray(NULL, num, size);
3078d8f1862Ssthen 
3088d8f1862Ssthen         if (!result) {
3098d8f1862Ssthen                 log_msg(LOG_ERR, "reallocarray failed: %s", strerror(errno));
3108d8f1862Ssthen                 exit(1);
3118d8f1862Ssthen         }
3128d8f1862Ssthen         return result;
3138d8f1862Ssthen }
3148d8f1862Ssthen 
3158d8f1862Ssthen void *
xalloc_zero(size_t size)31662ac0c33Sjakob xalloc_zero(size_t size)
31762ac0c33Sjakob {
318a302926fSbrad 	void *result = calloc(1, size);
319a302926fSbrad 	if (!result) {
320a302926fSbrad 		log_msg(LOG_ERR, "calloc failed: %s", strerror(errno));
321a302926fSbrad 		exit(1);
322a302926fSbrad 	}
32362ac0c33Sjakob 	return result;
32462ac0c33Sjakob }
32562ac0c33Sjakob 
32662ac0c33Sjakob void *
xalloc_array_zero(size_t num,size_t size)3278d8f1862Ssthen xalloc_array_zero(size_t num, size_t size)
3288d8f1862Ssthen {
3298d8f1862Ssthen 	void *result = calloc(num, size);
3308d8f1862Ssthen 	if (!result) {
3318d8f1862Ssthen 		log_msg(LOG_ERR, "calloc failed: %s", strerror(errno));
3328d8f1862Ssthen 		exit(1);
3338d8f1862Ssthen 	}
3348d8f1862Ssthen 	return result;
3358d8f1862Ssthen }
3368d8f1862Ssthen 
3378d8f1862Ssthen void *
xrealloc(void * ptr,size_t size)33862ac0c33Sjakob xrealloc(void *ptr, size_t size)
33962ac0c33Sjakob {
34062ac0c33Sjakob 	ptr = realloc(ptr, size);
34162ac0c33Sjakob 	if (!ptr) {
34262ac0c33Sjakob 		log_msg(LOG_ERR, "realloc failed: %s", strerror(errno));
34362ac0c33Sjakob 		exit(1);
34462ac0c33Sjakob 	}
34562ac0c33Sjakob 	return ptr;
34662ac0c33Sjakob }
34762ac0c33Sjakob 
3484ab91c82Sjakob #ifdef USE_MMAP_ALLOC
3494ab91c82Sjakob 
3504ab91c82Sjakob void *
mmap_alloc(size_t size)3514ab91c82Sjakob mmap_alloc(size_t size)
3524ab91c82Sjakob {
3534ab91c82Sjakob 	void *base;
3544ab91c82Sjakob 
3554ab91c82Sjakob 	size += MMAP_ALLOC_HEADER_SIZE;
356c3fd4e2aSjakob #ifdef HAVE_MMAP
3574ab91c82Sjakob 	base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
3584ab91c82Sjakob 	if (base == MAP_FAILED) {
3594ab91c82Sjakob 		log_msg(LOG_ERR, "mmap failed: %s", strerror(errno));
3604ab91c82Sjakob 		exit(1);
3614ab91c82Sjakob 	}
362c3fd4e2aSjakob #else /* !HAVE_MMAP */
363c3fd4e2aSjakob 	log_msg(LOG_ERR, "mmap failed: don't have mmap");
364c3fd4e2aSjakob 	exit(1);
365c3fd4e2aSjakob #endif /* HAVE_MMAP */
3664ab91c82Sjakob 
3674ab91c82Sjakob 	*((size_t*) base) = size;
3684ab91c82Sjakob 	return (void*)((uintptr_t)base + MMAP_ALLOC_HEADER_SIZE);
3694ab91c82Sjakob }
3704ab91c82Sjakob 
3714ab91c82Sjakob 
3724ab91c82Sjakob void
mmap_free(void * ptr)3734ab91c82Sjakob mmap_free(void *ptr)
3744ab91c82Sjakob {
3754ab91c82Sjakob 	void *base;
3764ab91c82Sjakob 	size_t size;
3774ab91c82Sjakob 
3784ab91c82Sjakob 	if (!ptr) return;
3794ab91c82Sjakob 
3804ab91c82Sjakob 	base = (void*)((uintptr_t)ptr - MMAP_ALLOC_HEADER_SIZE);
3814ab91c82Sjakob 	size = *((size_t*) base);
3824ab91c82Sjakob 
383c3fd4e2aSjakob #ifdef HAVE_MUNMAP
3844ab91c82Sjakob 	if (munmap(base, size) == -1) {
3854ab91c82Sjakob 		log_msg(LOG_ERR, "munmap failed: %s", strerror(errno));
3864ab91c82Sjakob 		exit(1);
3874ab91c82Sjakob 	}
388c3fd4e2aSjakob #else /* !HAVE_MUNMAP */
389c3fd4e2aSjakob 	log_msg(LOG_ERR, "munmap failed: don't have munmap");
390c3fd4e2aSjakob 	exit(1);
391c3fd4e2aSjakob #endif /* HAVE_MUNMAP */
3924ab91c82Sjakob }
3934ab91c82Sjakob 
3944ab91c82Sjakob #endif /* USE_MMAP_ALLOC */
3954ab91c82Sjakob 
39662ac0c33Sjakob int
write_data(FILE * file,const void * data,size_t size)39762ac0c33Sjakob write_data(FILE *file, const void *data, size_t size)
39862ac0c33Sjakob {
39962ac0c33Sjakob 	size_t result;
40062ac0c33Sjakob 
40162ac0c33Sjakob 	if (size == 0)
40262ac0c33Sjakob 		return 1;
40362ac0c33Sjakob 
40462ac0c33Sjakob 	result = fwrite(data, 1, size, file);
40562ac0c33Sjakob 
40662ac0c33Sjakob 	if (result == 0) {
40762ac0c33Sjakob 		log_msg(LOG_ERR, "write failed: %s", strerror(errno));
40862ac0c33Sjakob 		return 0;
40962ac0c33Sjakob 	} else if (result < size) {
41062ac0c33Sjakob 		log_msg(LOG_ERR, "short write (disk full?)");
41162ac0c33Sjakob 		return 0;
41262ac0c33Sjakob 	} else {
41362ac0c33Sjakob 		return 1;
41462ac0c33Sjakob 	}
41562ac0c33Sjakob }
41662ac0c33Sjakob 
4174ab91c82Sjakob int
write_socket(int s,const void * buf,size_t size)4184ab91c82Sjakob write_socket(int s, const void *buf, size_t size)
41962ac0c33Sjakob {
42062ac0c33Sjakob 	const char* data = (const char*)buf;
42162ac0c33Sjakob 	size_t total_count = 0;
42262ac0c33Sjakob 
42362ac0c33Sjakob 	while (total_count < size) {
42462ac0c33Sjakob 		ssize_t count
42562ac0c33Sjakob 			= write(s, data + total_count, size - total_count);
42662ac0c33Sjakob 		if (count == -1) {
42762ac0c33Sjakob 			if (errno != EAGAIN && errno != EINTR) {
42862ac0c33Sjakob 				return 0;
42962ac0c33Sjakob 			} else {
43062ac0c33Sjakob 				continue;
43162ac0c33Sjakob 			}
43262ac0c33Sjakob 		}
43362ac0c33Sjakob 		total_count += count;
43462ac0c33Sjakob 	}
43562ac0c33Sjakob 	return 1;
43662ac0c33Sjakob }
43762ac0c33Sjakob 
get_time(struct timespec * t)438275a8d89Sflorian void get_time(struct timespec* t)
439275a8d89Sflorian {
440275a8d89Sflorian 	struct timeval tv;
441275a8d89Sflorian #ifdef HAVE_CLOCK_GETTIME
442275a8d89Sflorian 	/* first try nanosecond precision */
443275a8d89Sflorian 	if(clock_gettime(CLOCK_REALTIME, t)>=0) {
444275a8d89Sflorian 		return; /* success */
445275a8d89Sflorian 	}
446275a8d89Sflorian 	log_msg(LOG_ERR, "clock_gettime: %s", strerror(errno));
447275a8d89Sflorian #endif
448275a8d89Sflorian 	/* try millisecond precision */
449275a8d89Sflorian 	if(gettimeofday(&tv, NULL)>=0) {
450275a8d89Sflorian 		t->tv_sec = tv.tv_sec;
451275a8d89Sflorian 		t->tv_nsec = tv.tv_usec*1000;
452275a8d89Sflorian 		return; /* success */
453275a8d89Sflorian 	}
454275a8d89Sflorian 	log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno));
455275a8d89Sflorian 	/* whole seconds precision */
456275a8d89Sflorian 	t->tv_sec = time(0);
457275a8d89Sflorian 	t->tv_nsec = 0;
458275a8d89Sflorian }
459275a8d89Sflorian 
46062ac0c33Sjakob int
timespec_compare(const struct timespec * left,const struct timespec * right)46162ac0c33Sjakob timespec_compare(const struct timespec *left,
46262ac0c33Sjakob 		 const struct timespec *right)
46362ac0c33Sjakob {
46462ac0c33Sjakob 	/* Compare seconds.  */
46562ac0c33Sjakob 	if (left->tv_sec < right->tv_sec) {
46662ac0c33Sjakob 		return -1;
46762ac0c33Sjakob 	} else if (left->tv_sec > right->tv_sec) {
46862ac0c33Sjakob 		return 1;
46962ac0c33Sjakob 	} else {
47062ac0c33Sjakob 		/* Seconds are equal, compare nanoseconds.  */
47162ac0c33Sjakob 		if (left->tv_nsec < right->tv_nsec) {
47262ac0c33Sjakob 			return -1;
47362ac0c33Sjakob 		} else if (left->tv_nsec > right->tv_nsec) {
47462ac0c33Sjakob 			return 1;
47562ac0c33Sjakob 		} else {
47662ac0c33Sjakob 			return 0;
47762ac0c33Sjakob 		}
47862ac0c33Sjakob 	}
47962ac0c33Sjakob }
48062ac0c33Sjakob 
48162ac0c33Sjakob 
48262ac0c33Sjakob /* One second is 1e9 nanoseconds.  */
48362ac0c33Sjakob #define NANOSECONDS_PER_SECOND   1000000000L
48462ac0c33Sjakob 
48562ac0c33Sjakob void
timespec_add(struct timespec * left,const struct timespec * right)48662ac0c33Sjakob timespec_add(struct timespec *left,
48762ac0c33Sjakob 	     const struct timespec *right)
48862ac0c33Sjakob {
48962ac0c33Sjakob 	left->tv_sec += right->tv_sec;
49062ac0c33Sjakob 	left->tv_nsec += right->tv_nsec;
49162ac0c33Sjakob 	if (left->tv_nsec >= NANOSECONDS_PER_SECOND) {
49262ac0c33Sjakob 		/* Carry.  */
49362ac0c33Sjakob 		++left->tv_sec;
49462ac0c33Sjakob 		left->tv_nsec -= NANOSECONDS_PER_SECOND;
49562ac0c33Sjakob 	}
49662ac0c33Sjakob }
49762ac0c33Sjakob 
49862ac0c33Sjakob void
timespec_subtract(struct timespec * left,const struct timespec * right)49962ac0c33Sjakob timespec_subtract(struct timespec *left,
50062ac0c33Sjakob 		  const struct timespec *right)
50162ac0c33Sjakob {
50262ac0c33Sjakob 	left->tv_sec -= right->tv_sec;
50362ac0c33Sjakob 	left->tv_nsec -= right->tv_nsec;
50462ac0c33Sjakob 	if (left->tv_nsec < 0L) {
50562ac0c33Sjakob 		/* Borrow.  */
50662ac0c33Sjakob 		--left->tv_sec;
50762ac0c33Sjakob 		left->tv_nsec += NANOSECONDS_PER_SECOND;
50862ac0c33Sjakob 	}
50962ac0c33Sjakob }
51062ac0c33Sjakob 
51162ac0c33Sjakob uint32_t
strtoserial(const char * nptr,const char ** endptr)51262ac0c33Sjakob strtoserial(const char* nptr, const char** endptr)
51362ac0c33Sjakob {
51462ac0c33Sjakob 	uint32_t i = 0;
51562ac0c33Sjakob 	uint32_t serial = 0;
51662ac0c33Sjakob 
51762ac0c33Sjakob 	for(*endptr = nptr; **endptr; (*endptr)++) {
51862ac0c33Sjakob 		switch (**endptr) {
51962ac0c33Sjakob 		case ' ':
52062ac0c33Sjakob 		case '\t':
52162ac0c33Sjakob 			break;
52262ac0c33Sjakob 		case '0':
52362ac0c33Sjakob 		case '1':
52462ac0c33Sjakob 		case '2':
52562ac0c33Sjakob 		case '3':
52662ac0c33Sjakob 		case '4':
52762ac0c33Sjakob 		case '5':
52862ac0c33Sjakob 		case '6':
52962ac0c33Sjakob 		case '7':
53062ac0c33Sjakob 		case '8':
53162ac0c33Sjakob 		case '9':
532fe5fe5f6Sflorian 			if((i*10)/10 != i)
533fe5fe5f6Sflorian 				/* number too large, return i
534fe5fe5f6Sflorian 				 * with *endptr != 0 as a failure*/
535fe5fe5f6Sflorian 				return i;
53662ac0c33Sjakob 			i *= 10;
53762ac0c33Sjakob 			i += (**endptr - '0');
53862ac0c33Sjakob 			break;
53962ac0c33Sjakob 		default:
540bc6311d7Sflorian 			return 0;
54162ac0c33Sjakob 		}
54262ac0c33Sjakob 	}
54362ac0c33Sjakob 	serial += i;
54462ac0c33Sjakob 	return serial;
54562ac0c33Sjakob }
54662ac0c33Sjakob 
54762ac0c33Sjakob uint32_t
strtottl(const char * nptr,const char ** endptr)54862ac0c33Sjakob strtottl(const char *nptr, const char **endptr)
54962ac0c33Sjakob {
55062ac0c33Sjakob 	uint32_t i = 0;
55162ac0c33Sjakob 	uint32_t seconds = 0;
55262ac0c33Sjakob 
55362ac0c33Sjakob 	for(*endptr = nptr; **endptr; (*endptr)++) {
55462ac0c33Sjakob 		switch (**endptr) {
55562ac0c33Sjakob 		case ' ':
55662ac0c33Sjakob 		case '\t':
55762ac0c33Sjakob 			break;
55862ac0c33Sjakob 		case 's':
55962ac0c33Sjakob 		case 'S':
56062ac0c33Sjakob 			seconds += i;
56162ac0c33Sjakob 			i = 0;
56262ac0c33Sjakob 			break;
56362ac0c33Sjakob 		case 'm':
56462ac0c33Sjakob 		case 'M':
56562ac0c33Sjakob 			seconds += i * 60;
56662ac0c33Sjakob 			i = 0;
56762ac0c33Sjakob 			break;
56862ac0c33Sjakob 		case 'h':
56962ac0c33Sjakob 		case 'H':
57062ac0c33Sjakob 			seconds += i * 60 * 60;
57162ac0c33Sjakob 			i = 0;
57262ac0c33Sjakob 			break;
57362ac0c33Sjakob 		case 'd':
57462ac0c33Sjakob 		case 'D':
57562ac0c33Sjakob 			seconds += i * 60 * 60 * 24;
57662ac0c33Sjakob 			i = 0;
57762ac0c33Sjakob 			break;
57862ac0c33Sjakob 		case 'w':
57962ac0c33Sjakob 		case 'W':
58062ac0c33Sjakob 			seconds += i * 60 * 60 * 24 * 7;
58162ac0c33Sjakob 			i = 0;
58262ac0c33Sjakob 			break;
58362ac0c33Sjakob 		case '0':
58462ac0c33Sjakob 		case '1':
58562ac0c33Sjakob 		case '2':
58662ac0c33Sjakob 		case '3':
58762ac0c33Sjakob 		case '4':
58862ac0c33Sjakob 		case '5':
58962ac0c33Sjakob 		case '6':
59062ac0c33Sjakob 		case '7':
59162ac0c33Sjakob 		case '8':
59262ac0c33Sjakob 		case '9':
59362ac0c33Sjakob 			i *= 10;
59462ac0c33Sjakob 			i += (**endptr - '0');
59562ac0c33Sjakob 			break;
59662ac0c33Sjakob 		default:
59762ac0c33Sjakob 			seconds += i;
59875343be4Ssthen 			/**
59975343be4Ssthen 			 * According to RFC2308, Section 8, the MSB
60075343be4Ssthen 			 * (sign bit) should be set to zero.
60175343be4Ssthen 			 * If we encounter a value larger than 2^31 -1,
60275343be4Ssthen 			 * we fall back to the default TTL.
60375343be4Ssthen 			 */
60475343be4Ssthen 			if ((seconds & MSB_32)) {
60575343be4Ssthen 				seconds = DEFAULT_TTL;
60675343be4Ssthen 			}
60762ac0c33Sjakob 			return seconds;
60862ac0c33Sjakob 		}
60962ac0c33Sjakob 	}
61062ac0c33Sjakob 	seconds += i;
61175343be4Ssthen 	if ((seconds & MSB_32)) {
61275343be4Ssthen 		seconds = DEFAULT_TTL;
61375343be4Ssthen 	}
61462ac0c33Sjakob 	return seconds;
61562ac0c33Sjakob }
61662ac0c33Sjakob 
61762ac0c33Sjakob 
61862ac0c33Sjakob ssize_t
hex_ntop(uint8_t const * src,size_t srclength,char * target,size_t targsize)61962ac0c33Sjakob hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize)
62062ac0c33Sjakob {
62162ac0c33Sjakob 	static char hexdigits[] = {
62262ac0c33Sjakob 		'0', '1', '2', '3', '4', '5', '6', '7',
62362ac0c33Sjakob 		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
62462ac0c33Sjakob 	};
62562ac0c33Sjakob 	size_t i;
62662ac0c33Sjakob 
62762ac0c33Sjakob 	if (targsize < srclength * 2 + 1) {
62862ac0c33Sjakob 		return -1;
62962ac0c33Sjakob 	}
63062ac0c33Sjakob 
63162ac0c33Sjakob 	for (i = 0; i < srclength; ++i) {
63262ac0c33Sjakob 		*target++ = hexdigits[src[i] >> 4U];
63362ac0c33Sjakob 		*target++ = hexdigits[src[i] & 0xfU];
63462ac0c33Sjakob 	}
63562ac0c33Sjakob 	*target = '\0';
63662ac0c33Sjakob 	return 2 * srclength;
63762ac0c33Sjakob }
63862ac0c33Sjakob 
63962ac0c33Sjakob ssize_t
hex_pton(const char * src,uint8_t * target,size_t targsize)64062ac0c33Sjakob hex_pton(const char* src, uint8_t* target, size_t targsize)
64162ac0c33Sjakob {
64262ac0c33Sjakob 	uint8_t *t = target;
64362ac0c33Sjakob 	if(strlen(src) % 2 != 0 || strlen(src)/2 > targsize) {
64462ac0c33Sjakob 		return -1;
64562ac0c33Sjakob 	}
64662ac0c33Sjakob 	while(*src) {
647c1404d4fSbrad 		if(!isxdigit((unsigned char)src[0]) ||
648c1404d4fSbrad 			!isxdigit((unsigned char)src[1]))
64962ac0c33Sjakob 			return -1;
65062ac0c33Sjakob 		*t++ = hexdigit_to_int(src[0]) * 16 +
65162ac0c33Sjakob 			hexdigit_to_int(src[1]) ;
65262ac0c33Sjakob 		src += 2;
65362ac0c33Sjakob 	}
65462ac0c33Sjakob 	return t-target;
65562ac0c33Sjakob }
65662ac0c33Sjakob 
65762ac0c33Sjakob int
b32_ntop(uint8_t const * src,size_t srclength,char * target,size_t targsize)65862ac0c33Sjakob b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize)
65962ac0c33Sjakob {
66062ac0c33Sjakob 	static char b32[]="0123456789abcdefghijklmnopqrstuv";
66162ac0c33Sjakob 	char buf[9];
66262ac0c33Sjakob 	ssize_t len=0;
66362ac0c33Sjakob 
66462ac0c33Sjakob 	while(srclength > 0)
66562ac0c33Sjakob 	{
66662ac0c33Sjakob 		int t;
66762ac0c33Sjakob 		memset(buf,'\0',sizeof buf);
66862ac0c33Sjakob 
66962ac0c33Sjakob 		/* xxxxx000 00000000 00000000 00000000 00000000 */
67062ac0c33Sjakob 		buf[0]=b32[src[0] >> 3];
67162ac0c33Sjakob 
67262ac0c33Sjakob 		/* 00000xxx xx000000 00000000 00000000 00000000 */
67362ac0c33Sjakob 		t=(src[0]&7) << 2;
67462ac0c33Sjakob 		if(srclength > 1)
67562ac0c33Sjakob 			t+=src[1] >> 6;
67662ac0c33Sjakob 		buf[1]=b32[t];
67762ac0c33Sjakob 		if(srclength == 1)
67862ac0c33Sjakob 			break;
67962ac0c33Sjakob 
68062ac0c33Sjakob 		/* 00000000 00xxxxx0 00000000 00000000 00000000 */
68162ac0c33Sjakob 		buf[2]=b32[(src[1] >> 1)&0x1f];
68262ac0c33Sjakob 
68362ac0c33Sjakob 		/* 00000000 0000000x xxxx0000 00000000 00000000 */
68462ac0c33Sjakob 		t=(src[1]&1) << 4;
68562ac0c33Sjakob 		if(srclength > 2)
68662ac0c33Sjakob 			t+=src[2] >> 4;
68762ac0c33Sjakob 		buf[3]=b32[t];
68862ac0c33Sjakob 		if(srclength == 2)
68962ac0c33Sjakob 			break;
69062ac0c33Sjakob 
69162ac0c33Sjakob 		/* 00000000 00000000 0000xxxx x0000000 00000000 */
69262ac0c33Sjakob 		t=(src[2]&0xf) << 1;
69362ac0c33Sjakob 		if(srclength > 3)
69462ac0c33Sjakob 			t+=src[3] >> 7;
69562ac0c33Sjakob 		buf[4]=b32[t];
69662ac0c33Sjakob 		if(srclength == 3)
69762ac0c33Sjakob 			break;
69862ac0c33Sjakob 
69962ac0c33Sjakob 		/* 00000000 00000000 00000000 0xxxxx00 00000000 */
70062ac0c33Sjakob 		buf[5]=b32[(src[3] >> 2)&0x1f];
70162ac0c33Sjakob 
70262ac0c33Sjakob 		/* 00000000 00000000 00000000 000000xx xxx00000 */
70362ac0c33Sjakob 		t=(src[3]&3) << 3;
70462ac0c33Sjakob 		if(srclength > 4)
70562ac0c33Sjakob 			t+=src[4] >> 5;
70662ac0c33Sjakob 		buf[6]=b32[t];
70762ac0c33Sjakob 		if(srclength == 4)
70862ac0c33Sjakob 			break;
70962ac0c33Sjakob 
71062ac0c33Sjakob 		/* 00000000 00000000 00000000 00000000 000xxxxx */
71162ac0c33Sjakob 		buf[7]=b32[src[4]&0x1f];
71262ac0c33Sjakob 
71362ac0c33Sjakob 		if(targsize < 8)
71462ac0c33Sjakob 			return -1;
71562ac0c33Sjakob 
71662ac0c33Sjakob 		src += 5;
71762ac0c33Sjakob 		srclength -= 5;
71862ac0c33Sjakob 
71962ac0c33Sjakob 		memcpy(target,buf,8);
72062ac0c33Sjakob 		target += 8;
72162ac0c33Sjakob 		targsize -= 8;
72262ac0c33Sjakob 		len += 8;
72362ac0c33Sjakob 	}
72462ac0c33Sjakob 	if(srclength)
72562ac0c33Sjakob 	{
72697f343bdSmillert 		size_t tlen = strlcpy(target, buf, targsize);
72797f343bdSmillert 		if (tlen >= targsize)
72862ac0c33Sjakob 			return -1;
72997f343bdSmillert 		len += tlen;
73062ac0c33Sjakob 	}
73162ac0c33Sjakob 	else if(targsize < 1)
73262ac0c33Sjakob 		return -1;
73362ac0c33Sjakob 	else
73462ac0c33Sjakob 		*target='\0';
73562ac0c33Sjakob 	return len;
73662ac0c33Sjakob }
73762ac0c33Sjakob 
73862ac0c33Sjakob int
b32_pton(const char * src,uint8_t * target,size_t tsize)73962ac0c33Sjakob b32_pton(const char *src, uint8_t *target, size_t tsize)
74062ac0c33Sjakob {
74162ac0c33Sjakob 	char ch;
74262ac0c33Sjakob 	size_t p=0;
74362ac0c33Sjakob 
74462ac0c33Sjakob 	memset(target,'\0',tsize);
74562ac0c33Sjakob 	while((ch = *src++)) {
74662ac0c33Sjakob 		uint8_t d;
74762ac0c33Sjakob 		size_t b;
74862ac0c33Sjakob 		size_t n;
74962ac0c33Sjakob 
75062ac0c33Sjakob 		if(p+5 >= tsize*8)
75162ac0c33Sjakob 		       return -1;
75262ac0c33Sjakob 
75382cafdebSmillert 		if(isspace((unsigned char)ch))
75462ac0c33Sjakob 			continue;
75562ac0c33Sjakob 
75662ac0c33Sjakob 		if(ch >= '0' && ch <= '9')
75762ac0c33Sjakob 			d=ch-'0';
75862ac0c33Sjakob 		else if(ch >= 'A' && ch <= 'V')
75962ac0c33Sjakob 			d=ch-'A'+10;
76062ac0c33Sjakob 		else if(ch >= 'a' && ch <= 'v')
76162ac0c33Sjakob 			d=ch-'a'+10;
76262ac0c33Sjakob 		else
76362ac0c33Sjakob 			return -1;
76462ac0c33Sjakob 
76562ac0c33Sjakob 		b=7-p%8;
76662ac0c33Sjakob 		n=p/8;
76762ac0c33Sjakob 
76862ac0c33Sjakob 		if(b >= 4)
76962ac0c33Sjakob 			target[n]|=d << (b-4);
77062ac0c33Sjakob 		else {
77162ac0c33Sjakob 			target[n]|=d >> (4-b);
77262ac0c33Sjakob 			target[n+1]|=d << (b+4);
77362ac0c33Sjakob 		}
77462ac0c33Sjakob 		p+=5;
77562ac0c33Sjakob 	}
77662ac0c33Sjakob 	return (p+7)/8;
77762ac0c33Sjakob }
77862ac0c33Sjakob 
77962ac0c33Sjakob void
strip_string(char * str)78062ac0c33Sjakob strip_string(char *str)
78162ac0c33Sjakob {
78262ac0c33Sjakob 	char *start = str;
78362ac0c33Sjakob 	char *end = str + strlen(str) - 1;
78462ac0c33Sjakob 
78582cafdebSmillert 	while (isspace((unsigned char)*start))
78662ac0c33Sjakob 		++start;
78762ac0c33Sjakob 	if (start > end) {
78862ac0c33Sjakob 		/* Completely blank. */
78962ac0c33Sjakob 		str[0] = '\0';
79062ac0c33Sjakob 	} else {
79182cafdebSmillert 		while (isspace((unsigned char)*end))
79262ac0c33Sjakob 			--end;
79362ac0c33Sjakob 		*++end = '\0';
79462ac0c33Sjakob 
79562ac0c33Sjakob 		if (str != start)
79662ac0c33Sjakob 			memmove(str, start, end - start + 1);
79762ac0c33Sjakob 	}
79862ac0c33Sjakob }
79962ac0c33Sjakob 
80062ac0c33Sjakob int
hexdigit_to_int(char ch)80162ac0c33Sjakob hexdigit_to_int(char ch)
80262ac0c33Sjakob {
80362ac0c33Sjakob 	switch (ch) {
80462ac0c33Sjakob 	case '0': return 0;
80562ac0c33Sjakob 	case '1': return 1;
80662ac0c33Sjakob 	case '2': return 2;
80762ac0c33Sjakob 	case '3': return 3;
80862ac0c33Sjakob 	case '4': return 4;
80962ac0c33Sjakob 	case '5': return 5;
81062ac0c33Sjakob 	case '6': return 6;
81162ac0c33Sjakob 	case '7': return 7;
81262ac0c33Sjakob 	case '8': return 8;
81362ac0c33Sjakob 	case '9': return 9;
81462ac0c33Sjakob 	case 'a': case 'A': return 10;
81562ac0c33Sjakob 	case 'b': case 'B': return 11;
81662ac0c33Sjakob 	case 'c': case 'C': return 12;
81762ac0c33Sjakob 	case 'd': case 'D': return 13;
81862ac0c33Sjakob 	case 'e': case 'E': return 14;
81962ac0c33Sjakob 	case 'f': case 'F': return 15;
82062ac0c33Sjakob 	default:
82162ac0c33Sjakob 		abort();
82262ac0c33Sjakob 	}
82362ac0c33Sjakob }
82462ac0c33Sjakob 
82562ac0c33Sjakob /* Number of days per month (except for February in leap years). */
82662ac0c33Sjakob static const int mdays[] = {
82762ac0c33Sjakob     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
82862ac0c33Sjakob };
82962ac0c33Sjakob 
83062ac0c33Sjakob static int
is_leap_year(int year)83162ac0c33Sjakob is_leap_year(int year)
83262ac0c33Sjakob {
83362ac0c33Sjakob     return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
83462ac0c33Sjakob }
83562ac0c33Sjakob 
83662ac0c33Sjakob static int
leap_days(int y1,int y2)83762ac0c33Sjakob leap_days(int y1, int y2)
83862ac0c33Sjakob {
83962ac0c33Sjakob     --y1;
84062ac0c33Sjakob     --y2;
84162ac0c33Sjakob     return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
84262ac0c33Sjakob }
84362ac0c33Sjakob 
84462ac0c33Sjakob /*
84562ac0c33Sjakob  * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
84662ac0c33Sjakob  */
84762ac0c33Sjakob time_t
mktime_from_utc(const struct tm * tm)84862ac0c33Sjakob mktime_from_utc(const struct tm *tm)
84962ac0c33Sjakob {
85062ac0c33Sjakob     int year = 1900 + tm->tm_year;
85162ac0c33Sjakob     time_t days = 365 * (year - 1970) + leap_days(1970, year);
85262ac0c33Sjakob     time_t hours;
85362ac0c33Sjakob     time_t minutes;
85462ac0c33Sjakob     time_t seconds;
85562ac0c33Sjakob     int i;
85662ac0c33Sjakob 
85762ac0c33Sjakob     for (i = 0; i < tm->tm_mon; ++i) {
85862ac0c33Sjakob         days += mdays[i];
85962ac0c33Sjakob     }
86062ac0c33Sjakob     if (tm->tm_mon > 1 && is_leap_year(year)) {
86162ac0c33Sjakob         ++days;
86262ac0c33Sjakob     }
86362ac0c33Sjakob     days += tm->tm_mday - 1;
86462ac0c33Sjakob 
86562ac0c33Sjakob     hours = days * 24 + tm->tm_hour;
86662ac0c33Sjakob     minutes = hours * 60 + tm->tm_min;
86762ac0c33Sjakob     seconds = minutes * 60 + tm->tm_sec;
86862ac0c33Sjakob 
86962ac0c33Sjakob     return seconds;
87062ac0c33Sjakob }
87162ac0c33Sjakob 
87262ac0c33Sjakob /* code to calculate CRC. Lifted from BSD 4.4 crc.c in cksum(1). BSD license.
87362ac0c33Sjakob    http://www.tsfr.org/~orc/Code/bsd/bsd-current/cksum/crc.c.
87462ac0c33Sjakob    or http://gobsd.com/code/freebsd/usr.bin/cksum/crc.c
87562ac0c33Sjakob    The polynomial is 0x04c11db7L. */
876308d2509Sflorian static uint32_t crctab[] = {
87762ac0c33Sjakob 	0x0,
87862ac0c33Sjakob 	0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
87962ac0c33Sjakob 	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
88062ac0c33Sjakob 	0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
88162ac0c33Sjakob 	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
88262ac0c33Sjakob 	0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
88362ac0c33Sjakob 	0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
88462ac0c33Sjakob 	0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
88562ac0c33Sjakob 	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
88662ac0c33Sjakob 	0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
88762ac0c33Sjakob 	0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
88862ac0c33Sjakob 	0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
88962ac0c33Sjakob 	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
89062ac0c33Sjakob 	0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
89162ac0c33Sjakob 	0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
89262ac0c33Sjakob 	0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
89362ac0c33Sjakob 	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
89462ac0c33Sjakob 	0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
89562ac0c33Sjakob 	0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
89662ac0c33Sjakob 	0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
89762ac0c33Sjakob 	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
89862ac0c33Sjakob 	0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
89962ac0c33Sjakob 	0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
90062ac0c33Sjakob 	0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
90162ac0c33Sjakob 	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
90262ac0c33Sjakob 	0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
90362ac0c33Sjakob 	0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
90462ac0c33Sjakob 	0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
90562ac0c33Sjakob 	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
90662ac0c33Sjakob 	0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
90762ac0c33Sjakob 	0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
90862ac0c33Sjakob 	0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
90962ac0c33Sjakob 	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
91062ac0c33Sjakob 	0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
91162ac0c33Sjakob 	0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
91262ac0c33Sjakob 	0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
91362ac0c33Sjakob 	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
91462ac0c33Sjakob 	0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
91562ac0c33Sjakob 	0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
91662ac0c33Sjakob 	0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
91762ac0c33Sjakob 	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
91862ac0c33Sjakob 	0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
91962ac0c33Sjakob 	0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
92062ac0c33Sjakob 	0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
92162ac0c33Sjakob 	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
92262ac0c33Sjakob 	0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
92362ac0c33Sjakob 	0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
92462ac0c33Sjakob 	0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
92562ac0c33Sjakob 	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
92662ac0c33Sjakob 	0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
92762ac0c33Sjakob 	0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
92862ac0c33Sjakob 	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
92962ac0c33Sjakob };
93062ac0c33Sjakob 
93162ac0c33Sjakob #define	COMPUTE(var, ch)	(var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
93262ac0c33Sjakob 
9334ab91c82Sjakob uint32_t
compute_crc(uint32_t crc,uint8_t * data,size_t len)9344ab91c82Sjakob compute_crc(uint32_t crc, uint8_t* data, size_t len)
93562ac0c33Sjakob {
93662ac0c33Sjakob 	size_t i;
93762ac0c33Sjakob 	for(i=0; i<len; ++i)
93862ac0c33Sjakob 		COMPUTE(crc, data[i]);
93962ac0c33Sjakob 	return crc;
94062ac0c33Sjakob }
94162ac0c33Sjakob 
9424ab91c82Sjakob int
write_data_crc(FILE * file,const void * data,size_t size,uint32_t * crc)9434ab91c82Sjakob write_data_crc(FILE *file, const void *data, size_t size, uint32_t* crc)
94462ac0c33Sjakob {
94562ac0c33Sjakob 	int ret = write_data(file, data, size);
94662ac0c33Sjakob 	*crc = compute_crc(*crc, (uint8_t*)data, size);
94762ac0c33Sjakob 	return ret;
94862ac0c33Sjakob }
94962ac0c33Sjakob 
95062ac0c33Sjakob #define SERIAL_BITS      32
9514ab91c82Sjakob int
compare_serial(uint32_t a,uint32_t b)9524ab91c82Sjakob compare_serial(uint32_t a, uint32_t b)
95362ac0c33Sjakob {
95462ac0c33Sjakob         const uint32_t cutoff = ((uint32_t) 1 << (SERIAL_BITS - 1));
95562ac0c33Sjakob 
95662ac0c33Sjakob         if (a == b) {
95762ac0c33Sjakob                 return 0;
95862ac0c33Sjakob         } else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) {
95962ac0c33Sjakob                 return -1;
96062ac0c33Sjakob         } else {
96162ac0c33Sjakob                 return 1;
96262ac0c33Sjakob         }
96362ac0c33Sjakob }
96462ac0c33Sjakob 
9654ab91c82Sjakob uint16_t
qid_generate(void)9664ab91c82Sjakob qid_generate(void)
9674ab91c82Sjakob {
968308d2509Sflorian #ifdef HAVE_GETRANDOM
969308d2509Sflorian 	uint16_t r;
970308d2509Sflorian 	if(getrandom(&r, sizeof(r), 0) == -1) {
971308d2509Sflorian 		log_msg(LOG_ERR, "getrandom failed: %s", strerror(errno));
972308d2509Sflorian 		exit(1);
973308d2509Sflorian 	}
974308d2509Sflorian 	return r;
975308d2509Sflorian #elif defined(HAVE_ARC4RANDOM)
976533110e2Sbrad     /* arc4random_uniform not needed because range is a power of 2 */
9774ab91c82Sjakob     return (uint16_t) arc4random();
978f72b2965Sjakob #else
979f72b2965Sjakob     return (uint16_t) random();
980f72b2965Sjakob #endif
9814ab91c82Sjakob }
9824ab91c82Sjakob 
983dd5b221eSsthen int
random_generate(int max)984dd5b221eSsthen random_generate(int max)
985dd5b221eSsthen {
986308d2509Sflorian #ifdef HAVE_GETRANDOM
987308d2509Sflorian 	int r;
988308d2509Sflorian 	if(getrandom(&r, sizeof(r), 0) == -1) {
989308d2509Sflorian 		log_msg(LOG_ERR, "getrandom failed: %s", strerror(errno));
990308d2509Sflorian 		exit(1);
991308d2509Sflorian 	}
992308d2509Sflorian 	return (int)(((unsigned)r)%max);
993308d2509Sflorian #elif defined(HAVE_ARC4RANDOM_UNIFORM)
994dd5b221eSsthen     return (int) arc4random_uniform(max);
995308d2509Sflorian #elif defined(HAVE_ARC4RANDOM)
996dd5b221eSsthen     return (int) (arc4random() % max);
997dd5b221eSsthen #else
998dd5b221eSsthen     return (int) ((unsigned)random() % max);
999dd5b221eSsthen #endif
1000dd5b221eSsthen }
1001dd5b221eSsthen 
100262ac0c33Sjakob void
cleanup_region(void * data)100362ac0c33Sjakob cleanup_region(void *data)
100462ac0c33Sjakob {
100562ac0c33Sjakob 	region_type *region = (region_type *) data;
100662ac0c33Sjakob 	region_destroy(region);
100762ac0c33Sjakob }
100862ac0c33Sjakob 
100962ac0c33Sjakob struct state_pretty_rr*
create_pretty_rr(struct region * region)101062ac0c33Sjakob create_pretty_rr(struct region* region)
101162ac0c33Sjakob {
101262ac0c33Sjakob 	struct state_pretty_rr* state = (struct state_pretty_rr*)
101362ac0c33Sjakob 		region_alloc(region, sizeof(struct state_pretty_rr));
101462ac0c33Sjakob 	state->previous_owner_region = region_create(xalloc, free);
101562ac0c33Sjakob 	state->previous_owner = NULL;
101662ac0c33Sjakob 	state->previous_owner_origin = NULL;
101762ac0c33Sjakob         region_add_cleanup(region, cleanup_region,
101862ac0c33Sjakob 		state->previous_owner_region);
101962ac0c33Sjakob 	return state;
102062ac0c33Sjakob }
102162ac0c33Sjakob 
102262ac0c33Sjakob static void
set_previous_owner(struct state_pretty_rr * state,const dname_type * dname)102362ac0c33Sjakob set_previous_owner(struct state_pretty_rr *state, const dname_type *dname)
102462ac0c33Sjakob {
102562ac0c33Sjakob 	region_free_all(state->previous_owner_region);
102662ac0c33Sjakob 	state->previous_owner = dname_copy(state->previous_owner_region, dname);
102762ac0c33Sjakob 	state->previous_owner_origin = dname_origin(
102862ac0c33Sjakob 		state->previous_owner_region, state->previous_owner);
102962ac0c33Sjakob }
103062ac0c33Sjakob 
103162ac0c33Sjakob int
print_rr(FILE * out,struct state_pretty_rr * state,rr_type * record,region_type * rr_region,buffer_type * output)103262ac0c33Sjakob print_rr(FILE *out,
103362ac0c33Sjakob          struct state_pretty_rr *state,
1034533110e2Sbrad          rr_type *record,
1035533110e2Sbrad 	 region_type* rr_region,
1036533110e2Sbrad 	 buffer_type* output)
103762ac0c33Sjakob {
103862ac0c33Sjakob         rrtype_descriptor_type *descriptor
103962ac0c33Sjakob                 = rrtype_descriptor_by_type(record->type);
104062ac0c33Sjakob         int result;
104162ac0c33Sjakob         const dname_type *owner = domain_dname(record->owner);
1042533110e2Sbrad 	buffer_clear(output);
1043dd5b221eSsthen         if (state) {
1044dd5b221eSsthen 		if (!state->previous_owner
1045dd5b221eSsthen 			|| dname_compare(state->previous_owner, owner) != 0) {
1046533110e2Sbrad 			const dname_type *owner_origin
1047533110e2Sbrad 				= dname_origin(rr_region, owner);
104862ac0c33Sjakob 			int origin_changed = (!state->previous_owner_origin
1049dd5b221eSsthen 				|| dname_compare(state->previous_owner_origin,
105062ac0c33Sjakob 				   owner_origin) != 0);
105162ac0c33Sjakob 			if (origin_changed) {
1052dd5b221eSsthen 				buffer_printf(output, "$ORIGIN %s\n",
105362ac0c33Sjakob 					dname_to_string(owner_origin, NULL));
105462ac0c33Sjakob 			}
105562ac0c33Sjakob 
105662ac0c33Sjakob 			set_previous_owner(state, owner);
1057dd5b221eSsthen 			buffer_printf(output, "%s",
105862ac0c33Sjakob 				dname_to_string(owner,
105962ac0c33Sjakob 					state->previous_owner_origin));
1060533110e2Sbrad 			region_free_all(rr_region);
106162ac0c33Sjakob 		}
1062dd5b221eSsthen 	} else {
1063dd5b221eSsthen 		buffer_printf(output, "%s", dname_to_string(owner, NULL));
1064dd5b221eSsthen 	}
106562ac0c33Sjakob 
1066dd5b221eSsthen 	buffer_printf(output, "\t%lu\t%s\t%s",
106762ac0c33Sjakob 		(unsigned long) record->ttl,
106862ac0c33Sjakob 		rrclass_to_string(record->klass),
106962ac0c33Sjakob 		rrtype_to_string(record->type));
107062ac0c33Sjakob 
107162ac0c33Sjakob 	result = print_rdata(output, descriptor, record);
107262ac0c33Sjakob 	if (!result) {
107362ac0c33Sjakob 		/*
107462ac0c33Sjakob 		 * Some RDATA failed to print, so print the record's
107562ac0c33Sjakob 		 * RDATA in unknown format.
107662ac0c33Sjakob 		 */
107762ac0c33Sjakob 		result = rdata_atoms_to_unknown_string(output,
1078dd5b221eSsthen 			descriptor, record->rdata_count, record->rdatas);
107962ac0c33Sjakob 	}
108062ac0c33Sjakob 
108162ac0c33Sjakob 	if (result) {
108262ac0c33Sjakob 		buffer_printf(output, "\n");
108362ac0c33Sjakob 		buffer_flip(output);
1084dd5b221eSsthen 		result = write_data(out, buffer_current(output),
1085dd5b221eSsthen 		buffer_remaining(output));
108662ac0c33Sjakob 	}
108762ac0c33Sjakob 	return result;
108862ac0c33Sjakob }
108962ac0c33Sjakob 
109062ac0c33Sjakob const char*
rcode2str(int rc)109162ac0c33Sjakob rcode2str(int rc)
109262ac0c33Sjakob {
1093dd5b221eSsthen 	switch(rc) {
109462ac0c33Sjakob 		case RCODE_OK:
109562ac0c33Sjakob 			return "NO ERROR";
109662ac0c33Sjakob 		case RCODE_FORMAT:
109762ac0c33Sjakob 			return "FORMAT ERROR";
109862ac0c33Sjakob 		case RCODE_SERVFAIL:
109962ac0c33Sjakob 			return "SERVFAIL";
110062ac0c33Sjakob 		case RCODE_NXDOMAIN:
110162ac0c33Sjakob 			return "NAME ERROR";
110262ac0c33Sjakob 		case RCODE_IMPL:
110362ac0c33Sjakob 			return "NOT IMPL";
110462ac0c33Sjakob 		case RCODE_REFUSE:
110562ac0c33Sjakob 			return "REFUSED";
110662ac0c33Sjakob 		case RCODE_YXDOMAIN:
110762ac0c33Sjakob 			return "YXDOMAIN";
110862ac0c33Sjakob 		case RCODE_YXRRSET:
110962ac0c33Sjakob 			return "YXRRSET";
111062ac0c33Sjakob 		case RCODE_NXRRSET:
111162ac0c33Sjakob 			return "NXRRSET";
111262ac0c33Sjakob 		case RCODE_NOTAUTH:
111362ac0c33Sjakob 			return "SERVER NOT AUTHORITATIVE FOR ZONE";
111462ac0c33Sjakob 		case RCODE_NOTZONE:
1115e3d8a0a5Ssthen 			/* Name not contained in zone */
111662ac0c33Sjakob 			return "NOTZONE";
111762ac0c33Sjakob 		default:
111862ac0c33Sjakob 			return "UNKNOWN ERROR";
111962ac0c33Sjakob 	}
112062ac0c33Sjakob 	return NULL; /* ENOREACH */
112162ac0c33Sjakob }
112262ac0c33Sjakob 
112362ac0c33Sjakob void
addr2str(struct sockaddr_storage * addr,char * str,size_t len)1124dd5b221eSsthen addr2str(
1125dd5b221eSsthen #ifdef INET6
1126dd5b221eSsthen 	struct sockaddr_storage *addr
1127dd5b221eSsthen #else
1128dd5b221eSsthen 	struct sockaddr_in *addr
1129dd5b221eSsthen #endif
1130dd5b221eSsthen 	, char* str, size_t len)
113162ac0c33Sjakob {
1132dd5b221eSsthen #ifdef INET6
1133dd5b221eSsthen 	if (addr->ss_family == AF_INET6) {
1134dd5b221eSsthen 		if (!inet_ntop(AF_INET6,
1135dd5b221eSsthen 			&((struct sockaddr_in6 *)addr)->sin6_addr, str, len))
1136dd5b221eSsthen 			strlcpy(str, "[unknown ip6, inet_ntop failed]", len);
113762ac0c33Sjakob 		return;
113862ac0c33Sjakob 	}
113962ac0c33Sjakob #endif
1140dd5b221eSsthen 	if (!inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr,
1141dd5b221eSsthen 		str, len))
1142dd5b221eSsthen 		strlcpy(str, "[unknown ip4, inet_ntop failed]", len);
114362ac0c33Sjakob }
11444b6a9f59Sflorian 
11454b6a9f59Sflorian void
addrport2str(struct sockaddr_storage * addr,char * str,size_t len)1146eab1363eSsthen addrport2str(
1147eab1363eSsthen #ifdef INET6
1148eab1363eSsthen 	struct sockaddr_storage *addr
1149eab1363eSsthen #else
1150eab1363eSsthen 	struct sockaddr_in *addr
1151eab1363eSsthen #endif
1152eab1363eSsthen 	, char* str, size_t len)
1153eab1363eSsthen {
1154eab1363eSsthen 	char ip[256];
1155eab1363eSsthen #ifdef INET6
1156eab1363eSsthen 	if (addr->ss_family == AF_INET6) {
1157eab1363eSsthen 		if (!inet_ntop(AF_INET6,
1158eab1363eSsthen 			&((struct sockaddr_in6 *)addr)->sin6_addr, ip, sizeof(ip)))
1159eab1363eSsthen 			strlcpy(ip, "[unknown ip6, inet_ntop failed]", sizeof(ip));
1160eab1363eSsthen 		/* append port number */
1161eab1363eSsthen 		snprintf(str, len, "%s@%u", ip,
1162eab1363eSsthen 			(unsigned)ntohs(((struct sockaddr_in6 *)addr)->sin6_port));
1163eab1363eSsthen 		return;
1164eab1363eSsthen 	} else
1165eab1363eSsthen #endif
1166eab1363eSsthen 	if (!inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr,
1167eab1363eSsthen 		ip, sizeof(ip)))
1168eab1363eSsthen 		strlcpy(ip, "[unknown ip4, inet_ntop failed]", sizeof(ip));
1169eab1363eSsthen 	/* append port number */
1170eab1363eSsthen 	snprintf(str, len, "%s@%u", ip,
1171eab1363eSsthen 		(unsigned)ntohs(((struct sockaddr_in *)addr)->sin_port));
1172eab1363eSsthen }
1173eab1363eSsthen 
1174eab1363eSsthen void
append_trailing_slash(const char ** dirname,region_type * region)11754b6a9f59Sflorian append_trailing_slash(const char** dirname, region_type* region)
11764b6a9f59Sflorian {
11774b6a9f59Sflorian 	int l = strlen(*dirname);
11784b6a9f59Sflorian 	if (l>0 && (*dirname)[l-1] != '/' && l < 0xffffff) {
11794b6a9f59Sflorian 		char *dirname_slash = region_alloc(region, l+2);
11804b6a9f59Sflorian 		memcpy(dirname_slash, *dirname, l+1);
11814b6a9f59Sflorian 		strlcat(dirname_slash, "/", l+2);
11824b6a9f59Sflorian 		/* old dirname is leaked, this is only used for chroot, once */
11834b6a9f59Sflorian 		*dirname = dirname_slash;
11844b6a9f59Sflorian 	}
11854b6a9f59Sflorian }
11864b6a9f59Sflorian 
11874b6a9f59Sflorian int
file_inside_chroot(const char * fname,const char * chr)11884b6a9f59Sflorian file_inside_chroot(const char* fname, const char* chr)
11894b6a9f59Sflorian {
11904b6a9f59Sflorian 	/* true if filename starts with chroot or is not absolute */
11914b6a9f59Sflorian 	return ((fname && fname[0] && strncmp(fname, chr, strlen(chr)) == 0) ||
11924b6a9f59Sflorian 		(fname && fname[0] != '/'));
11934b6a9f59Sflorian }
11944b6a9f59Sflorian 
11954b6a9f59Sflorian /*
11964b6a9f59Sflorian  * Something went wrong, give error messages and exit.
11974b6a9f59Sflorian  */
11984b6a9f59Sflorian void
error(const char * format,...)11994b6a9f59Sflorian error(const char *format, ...)
12004b6a9f59Sflorian {
12014b6a9f59Sflorian 	va_list args;
12024b6a9f59Sflorian 	va_start(args, format);
12034b6a9f59Sflorian 	log_vmsg(LOG_ERR, format, args);
12044b6a9f59Sflorian 	va_end(args);
12054b6a9f59Sflorian 	exit(1);
12064b6a9f59Sflorian }
12074b6a9f59Sflorian 
1208308d2509Sflorian #ifdef HAVE_CPUSET_T
1209308d2509Sflorian #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
1210308d2509Sflorian /* exists on Linux and FreeBSD */
number_of_cpus(void)1211308d2509Sflorian int number_of_cpus(void)
1212308d2509Sflorian {
1213308d2509Sflorian 	return (int)sysconf(_SC_NPROCESSORS_CONF);
1214308d2509Sflorian }
1215308d2509Sflorian #else
number_of_cpus(void)1216308d2509Sflorian int number_of_cpus(void)
1217308d2509Sflorian {
1218308d2509Sflorian 	return -1;
1219308d2509Sflorian }
1220308d2509Sflorian #endif
1221308d2509Sflorian #ifdef __gnu_hurd__
1222308d2509Sflorian /* HURD has no sched_setaffinity implementation, but links an always fail,
1223308d2509Sflorian  * with a linker error, we print an error when it is used */
set_cpu_affinity(cpuset_t * ATTR_UNUSED (set))1224308d2509Sflorian int set_cpu_affinity(cpuset_t *ATTR_UNUSED(set))
1225308d2509Sflorian {
1226308d2509Sflorian 	log_err("sched_setaffinity: not available on this system");
1227308d2509Sflorian 	return -1;
1228308d2509Sflorian }
1229308d2509Sflorian #elif defined(HAVE_SCHED_SETAFFINITY)
1230308d2509Sflorian /* Linux */
set_cpu_affinity(cpuset_t * set)1231308d2509Sflorian int set_cpu_affinity(cpuset_t *set)
1232308d2509Sflorian {
1233308d2509Sflorian 	assert(set != NULL);
1234308d2509Sflorian 	return sched_setaffinity(getpid(), sizeof(*set), set);
1235308d2509Sflorian }
1236308d2509Sflorian #else
1237308d2509Sflorian /* FreeBSD */
set_cpu_affinity(cpuset_t * set)1238308d2509Sflorian int set_cpu_affinity(cpuset_t *set)
1239308d2509Sflorian {
1240308d2509Sflorian 	assert(set != NULL);
1241308d2509Sflorian 	return cpuset_setaffinity(
1242308d2509Sflorian 		CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(*set), set);
1243308d2509Sflorian }
1244308d2509Sflorian #endif
1245308d2509Sflorian #endif /* HAVE_CPUSET_T */
1246063644e9Sflorian 
add_cookie_secret(struct nsd * nsd,uint8_t * secret)1247063644e9Sflorian void add_cookie_secret(struct nsd* nsd, uint8_t* secret)
1248063644e9Sflorian {
1249063644e9Sflorian 	/* New cookie secret becomes the staging secret (position 1)
1250063644e9Sflorian 	 * unless there is no active cookie yet, then it becomes the active
1251063644e9Sflorian 	 * secret.  If the NSD_COOKIE_HISTORY_SIZE > 2 then all staging cookies
1252063644e9Sflorian 	 * are moved one position down.
1253063644e9Sflorian 	 */
1254063644e9Sflorian 	if(nsd->cookie_count == 0) {
1255063644e9Sflorian 		memcpy( nsd->cookie_secrets->cookie_secret
1256063644e9Sflorian 		       , secret, NSD_COOKIE_SECRET_SIZE);
1257063644e9Sflorian 		nsd->cookie_count = 1;
1258063644e9Sflorian 		explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE);
1259063644e9Sflorian 		return;
1260063644e9Sflorian 	}
1261063644e9Sflorian #if NSD_COOKIE_HISTORY_SIZE > 2
1262063644e9Sflorian 	memmove( &nsd->cookie_secrets[2], &nsd->cookie_secrets[1]
1263063644e9Sflorian 	       , sizeof(struct cookie_secret) * (NSD_COOKIE_HISTORY_SIZE - 2));
1264063644e9Sflorian #endif
1265063644e9Sflorian 	memcpy( nsd->cookie_secrets[1].cookie_secret
1266063644e9Sflorian 	      , secret, NSD_COOKIE_SECRET_SIZE);
1267063644e9Sflorian 	nsd->cookie_count = nsd->cookie_count     < NSD_COOKIE_HISTORY_SIZE
1268063644e9Sflorian 	                  ? nsd->cookie_count + 1 : NSD_COOKIE_HISTORY_SIZE;
1269063644e9Sflorian 	explicit_bzero(secret, NSD_COOKIE_SECRET_SIZE);
1270063644e9Sflorian }
1271063644e9Sflorian 
activate_cookie_secret(struct nsd * nsd)1272063644e9Sflorian void activate_cookie_secret(struct nsd* nsd)
1273063644e9Sflorian {
1274063644e9Sflorian 	uint8_t active_secret[NSD_COOKIE_SECRET_SIZE];
1275063644e9Sflorian 	/* The staging secret becomes the active secret.
1276063644e9Sflorian 	 * The active secret becomes a staging secret.
1277063644e9Sflorian 	 * If the NSD_COOKIE_HISTORY_SIZE > 2 then all staging secrets are moved
1278063644e9Sflorian 	 * one position up and the previously active secret becomes the last
1279063644e9Sflorian 	 * staging secret.
1280063644e9Sflorian 	 */
1281063644e9Sflorian 	if(nsd->cookie_count < 2)
1282063644e9Sflorian 		return;
1283063644e9Sflorian 	memcpy( active_secret, nsd->cookie_secrets[0].cookie_secret
1284063644e9Sflorian 	      , NSD_COOKIE_SECRET_SIZE);
1285063644e9Sflorian 	memmove( &nsd->cookie_secrets[0], &nsd->cookie_secrets[1]
1286063644e9Sflorian 	       , sizeof(struct cookie_secret) * (NSD_COOKIE_HISTORY_SIZE - 1));
1287063644e9Sflorian 	memcpy( nsd->cookie_secrets[nsd->cookie_count - 1].cookie_secret
1288063644e9Sflorian 	      , active_secret, NSD_COOKIE_SECRET_SIZE);
1289063644e9Sflorian 	explicit_bzero(active_secret, NSD_COOKIE_SECRET_SIZE);
1290063644e9Sflorian }
1291063644e9Sflorian 
drop_cookie_secret(struct nsd * nsd)1292063644e9Sflorian void drop_cookie_secret(struct nsd* nsd)
1293063644e9Sflorian {
1294063644e9Sflorian 	/* Drops a staging cookie secret. If there are more than one, it will
1295063644e9Sflorian 	 * drop the last staging secret. */
1296063644e9Sflorian 	if(nsd->cookie_count < 2)
1297063644e9Sflorian 		return;
1298063644e9Sflorian 	explicit_bzero( nsd->cookie_secrets[nsd->cookie_count - 1].cookie_secret
1299063644e9Sflorian 	              , NSD_COOKIE_SECRET_SIZE);
1300063644e9Sflorian 	nsd->cookie_count -= 1;
1301063644e9Sflorian }
1302