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