1238104Sdes/* 2238104Sdes * util.c 3238104Sdes * 4238104Sdes * some general memory functions 5238104Sdes * 6238104Sdes * a Net::DNS like library for C 7238104Sdes * 8238104Sdes * (c) NLnet Labs, 2004-2006 9238104Sdes * 10238104Sdes * See the file LICENSE for the license 11238104Sdes */ 12238104Sdes 13238104Sdes#include <ldns/config.h> 14238104Sdes 15238104Sdes#include <ldns/rdata.h> 16238104Sdes#include <ldns/rr.h> 17238104Sdes#include <ldns/util.h> 18238104Sdes#include <strings.h> 19238104Sdes#include <stdlib.h> 20238104Sdes#include <stdio.h> 21238104Sdes#include <sys/time.h> 22238104Sdes#include <time.h> 23238104Sdes 24238104Sdes#ifdef HAVE_SSL 25238104Sdes#include <openssl/rand.h> 26238104Sdes#endif 27238104Sdes 28238104Sdesldns_lookup_table * 29238104Sdesldns_lookup_by_name(ldns_lookup_table *table, const char *name) 30238104Sdes{ 31238104Sdes while (table->name != NULL) { 32238104Sdes if (strcasecmp(name, table->name) == 0) 33238104Sdes return table; 34238104Sdes table++; 35238104Sdes } 36238104Sdes return NULL; 37238104Sdes} 38238104Sdes 39238104Sdesldns_lookup_table * 40238104Sdesldns_lookup_by_id(ldns_lookup_table *table, int id) 41238104Sdes{ 42238104Sdes while (table->name != NULL) { 43238104Sdes if (table->id == id) 44238104Sdes return table; 45238104Sdes table++; 46238104Sdes } 47238104Sdes return NULL; 48238104Sdes} 49238104Sdes 50238104Sdesint 51238104Sdesldns_get_bit(uint8_t bits[], size_t index) 52238104Sdes{ 53238104Sdes /* 54238104Sdes * The bits are counted from left to right, so bit #0 is the 55238104Sdes * left most bit. 56238104Sdes */ 57238104Sdes return (int) (bits[index / 8] & (1 << (7 - index % 8))); 58238104Sdes} 59238104Sdes 60238104Sdesint 61238104Sdesldns_get_bit_r(uint8_t bits[], size_t index) 62238104Sdes{ 63238104Sdes /* 64238104Sdes * The bits are counted from right to left, so bit #0 is the 65238104Sdes * right most bit. 66238104Sdes */ 67238104Sdes return (int) bits[index / 8] & (1 << (index % 8)); 68238104Sdes} 69238104Sdes 70238104Sdesvoid 71238104Sdesldns_set_bit(uint8_t *byte, int bit_nr, bool value) 72238104Sdes{ 73238104Sdes /* 74238104Sdes * The bits are counted from right to left, so bit #0 is the 75238104Sdes * right most bit. 76238104Sdes */ 77238104Sdes if (bit_nr >= 0 && bit_nr < 8) { 78238104Sdes if (value) { 79238104Sdes *byte = *byte | (0x01 << bit_nr); 80238104Sdes } else { 81238104Sdes *byte = *byte & ~(0x01 << bit_nr); 82238104Sdes } 83238104Sdes } 84238104Sdes} 85238104Sdes 86238104Sdesint 87238104Sdesldns_hexdigit_to_int(char ch) 88238104Sdes{ 89238104Sdes switch (ch) { 90238104Sdes case '0': return 0; 91238104Sdes case '1': return 1; 92238104Sdes case '2': return 2; 93238104Sdes case '3': return 3; 94238104Sdes case '4': return 4; 95238104Sdes case '5': return 5; 96238104Sdes case '6': return 6; 97238104Sdes case '7': return 7; 98238104Sdes case '8': return 8; 99238104Sdes case '9': return 9; 100238104Sdes case 'a': case 'A': return 10; 101238104Sdes case 'b': case 'B': return 11; 102238104Sdes case 'c': case 'C': return 12; 103238104Sdes case 'd': case 'D': return 13; 104238104Sdes case 'e': case 'E': return 14; 105238104Sdes case 'f': case 'F': return 15; 106238104Sdes default: 107238104Sdes return -1; 108238104Sdes } 109238104Sdes} 110238104Sdes 111238104Sdeschar 112238104Sdesldns_int_to_hexdigit(int i) 113238104Sdes{ 114238104Sdes switch (i) { 115238104Sdes case 0: return '0'; 116238104Sdes case 1: return '1'; 117238104Sdes case 2: return '2'; 118238104Sdes case 3: return '3'; 119238104Sdes case 4: return '4'; 120238104Sdes case 5: return '5'; 121238104Sdes case 6: return '6'; 122238104Sdes case 7: return '7'; 123238104Sdes case 8: return '8'; 124238104Sdes case 9: return '9'; 125238104Sdes case 10: return 'a'; 126238104Sdes case 11: return 'b'; 127238104Sdes case 12: return 'c'; 128238104Sdes case 13: return 'd'; 129238104Sdes case 14: return 'e'; 130238104Sdes case 15: return 'f'; 131238104Sdes default: 132238104Sdes abort(); 133238104Sdes } 134238104Sdes} 135238104Sdes 136238104Sdesint 137238104Sdesldns_hexstring_to_data(uint8_t *data, const char *str) 138238104Sdes{ 139238104Sdes size_t i; 140238104Sdes 141238104Sdes if (!str || !data) { 142238104Sdes return -1; 143238104Sdes } 144238104Sdes 145238104Sdes if (strlen(str) % 2 != 0) { 146238104Sdes return -2; 147238104Sdes } 148238104Sdes 149238104Sdes for (i = 0; i < strlen(str) / 2; i++) { 150238104Sdes data[i] = 151238104Sdes 16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) + 152238104Sdes (uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]); 153238104Sdes } 154238104Sdes 155238104Sdes return (int) i; 156238104Sdes} 157238104Sdes 158238104Sdesconst char * 159238104Sdesldns_version(void) 160238104Sdes{ 161238104Sdes return (char*)LDNS_VERSION; 162238104Sdes} 163238104Sdes 164238104Sdes/* Number of days per month (except for February in leap years). */ 165238104Sdesstatic const int mdays[] = { 166238104Sdes 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 167238104Sdes}; 168238104Sdes 169238104Sdes#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y))) 170238104Sdes#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y))) 171238104Sdes 172238104Sdesstatic int 173238104Sdesis_leap_year(int year) 174238104Sdes{ 175238104Sdes return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0 176238104Sdes || LDNS_MOD(year, 400) == 0); 177238104Sdes} 178238104Sdes 179238104Sdesstatic int 180238104Sdesleap_days(int y1, int y2) 181238104Sdes{ 182238104Sdes --y1; 183238104Sdes --y2; 184238104Sdes return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) - 185238104Sdes (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) + 186238104Sdes (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400)); 187238104Sdes} 188238104Sdes 189238104Sdes/* 190238104Sdes * Code adapted from Python 2.4.1 sources (Lib/calendar.py). 191238104Sdes */ 192238104Sdestime_t 193246854Sdesldns_mktime_from_utc(const struct tm *tm) 194238104Sdes{ 195238104Sdes int year = 1900 + tm->tm_year; 196238104Sdes time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year); 197238104Sdes time_t hours; 198238104Sdes time_t minutes; 199238104Sdes time_t seconds; 200238104Sdes int i; 201238104Sdes 202238104Sdes for (i = 0; i < tm->tm_mon; ++i) { 203238104Sdes days += mdays[i]; 204238104Sdes } 205238104Sdes if (tm->tm_mon > 1 && is_leap_year(year)) { 206238104Sdes ++days; 207238104Sdes } 208238104Sdes days += tm->tm_mday - 1; 209238104Sdes 210238104Sdes hours = days * 24 + tm->tm_hour; 211238104Sdes minutes = hours * 60 + tm->tm_min; 212238104Sdes seconds = minutes * 60 + tm->tm_sec; 213238104Sdes 214238104Sdes return seconds; 215238104Sdes} 216238104Sdes 217246854Sdestime_t 218246854Sdesmktime_from_utc(const struct tm *tm) 219246854Sdes{ 220246854Sdes return ldns_mktime_from_utc(tm); 221246854Sdes} 222246854Sdes 223238104Sdes#if SIZEOF_TIME_T <= 4 224238104Sdes 225238104Sdesstatic void 226238104Sdesldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result) 227238104Sdes{ 228238104Sdes int year = 1970; 229238104Sdes int new_year; 230238104Sdes 231238104Sdes while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) { 232238104Sdes new_year = year + (int) LDNS_DIV(days, 365); 233238104Sdes days -= (new_year - year) * 365; 234238104Sdes days -= leap_days(year, new_year); 235238104Sdes year = new_year; 236238104Sdes } 237238104Sdes result->tm_year = year; 238238104Sdes result->tm_yday = (int) days; 239238104Sdes} 240238104Sdes 241238104Sdes/* Number of days per month in a leap year. */ 242238104Sdesstatic const int leap_year_mdays[] = { 243238104Sdes 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 244238104Sdes}; 245238104Sdes 246238104Sdesstatic void 247238104Sdesldns_mon_and_mday_from_year_and_yday(struct tm *result) 248238104Sdes{ 249238104Sdes int idays = result->tm_yday; 250238104Sdes const int *mon_lengths = is_leap_year(result->tm_year) ? 251238104Sdes leap_year_mdays : mdays; 252238104Sdes 253238104Sdes result->tm_mon = 0; 254238104Sdes while (idays >= mon_lengths[result->tm_mon]) { 255238104Sdes idays -= mon_lengths[result->tm_mon++]; 256238104Sdes } 257238104Sdes result->tm_mday = idays + 1; 258238104Sdes} 259238104Sdes 260238104Sdesstatic void 261238104Sdesldns_wday_from_year_and_yday(struct tm *result) 262238104Sdes{ 263238104Sdes result->tm_wday = 4 /* 1-1-1970 was a thursday */ 264238104Sdes + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7) 265238104Sdes + leap_days(1970, result->tm_year) 266238104Sdes + result->tm_yday; 267238104Sdes result->tm_wday = LDNS_MOD(result->tm_wday, 7); 268238104Sdes if (result->tm_wday < 0) { 269238104Sdes result->tm_wday += 7; 270238104Sdes } 271238104Sdes} 272238104Sdes 273238104Sdesstatic struct tm * 274238104Sdesldns_gmtime64_r(int64_t clock, struct tm *result) 275238104Sdes{ 276238104Sdes result->tm_isdst = 0; 277238104Sdes result->tm_sec = (int) LDNS_MOD(clock, 60); 278238104Sdes clock = LDNS_DIV(clock, 60); 279238104Sdes result->tm_min = (int) LDNS_MOD(clock, 60); 280238104Sdes clock = LDNS_DIV(clock, 60); 281238104Sdes result->tm_hour = (int) LDNS_MOD(clock, 24); 282238104Sdes clock = LDNS_DIV(clock, 24); 283238104Sdes 284238104Sdes ldns_year_and_yday_from_days_since_epoch(clock, result); 285238104Sdes ldns_mon_and_mday_from_year_and_yday(result); 286238104Sdes ldns_wday_from_year_and_yday(result); 287238104Sdes result->tm_year -= 1900; 288238104Sdes 289238104Sdes return result; 290238104Sdes} 291238104Sdes 292238104Sdes#endif /* SIZEOF_TIME_T <= 4 */ 293238104Sdes 294238104Sdesstatic int64_t 295238104Sdesldns_serial_arithmitics_time(int32_t time, time_t now) 296238104Sdes{ 297238104Sdes int32_t offset = time - (int32_t) now; 298238104Sdes return (int64_t) now + offset; 299238104Sdes} 300238104Sdes 301238104Sdes 302238104Sdesstruct tm * 303238104Sdesldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result) 304238104Sdes{ 305238104Sdes#if SIZEOF_TIME_T <= 4 306238104Sdes int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); 307238104Sdes return ldns_gmtime64_r(secs_since_epoch, result); 308238104Sdes#else 309238104Sdes time_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); 310238104Sdes return gmtime_r(&secs_since_epoch, result); 311238104Sdes#endif 312238104Sdes} 313238104Sdes 314238104Sdes/** 315238104Sdes * Init the random source 316238104Sdes * applications should call this if they need entropy data within ldns 317238104Sdes * If openSSL is available, it is automatically seeded from /dev/urandom 318238104Sdes * or /dev/random 319238104Sdes * 320238104Sdes * If you need more entropy, or have no openssl available, this function 321238104Sdes * MUST be called at the start of the program 322238104Sdes * 323238104Sdes * If openssl *is* available, this function just adds more entropy 324238104Sdes **/ 325238104Sdesint 326238104Sdesldns_init_random(FILE *fd, unsigned int size) 327238104Sdes{ 328238104Sdes /* if fp is given, seed srandom with data from file 329238104Sdes otherwise use /dev/urandom */ 330238104Sdes FILE *rand_f; 331238104Sdes uint8_t *seed; 332238104Sdes size_t read = 0; 333238104Sdes unsigned int seed_i; 334238104Sdes struct timeval tv; 335238104Sdes 336238104Sdes /* we'll need at least sizeof(unsigned int) bytes for the 337238104Sdes standard prng seed */ 338238104Sdes if (size < (unsigned int) sizeof(seed_i)){ 339238104Sdes size = (unsigned int) sizeof(seed_i); 340238104Sdes } 341238104Sdes 342238104Sdes seed = LDNS_XMALLOC(uint8_t, size); 343238104Sdes if(!seed) { 344238104Sdes return 1; 345238104Sdes } 346238104Sdes 347238104Sdes if (!fd) { 348238104Sdes if ((rand_f = fopen("/dev/urandom", "r")) == NULL) { 349238104Sdes /* no readable /dev/urandom, try /dev/random */ 350238104Sdes if ((rand_f = fopen("/dev/random", "r")) == NULL) { 351238104Sdes /* no readable /dev/random either, and no entropy 352238104Sdes source given. we'll have to improvise */ 353238104Sdes for (read = 0; read < size; read++) { 354238104Sdes gettimeofday(&tv, NULL); 355238104Sdes seed[read] = (uint8_t) (tv.tv_usec % 256); 356238104Sdes } 357238104Sdes } else { 358238104Sdes read = fread(seed, 1, size, rand_f); 359238104Sdes } 360238104Sdes } else { 361238104Sdes read = fread(seed, 1, size, rand_f); 362238104Sdes } 363238104Sdes } else { 364238104Sdes rand_f = fd; 365238104Sdes read = fread(seed, 1, size, rand_f); 366238104Sdes } 367238104Sdes 368238104Sdes if (read < size) { 369238104Sdes LDNS_FREE(seed); 370246854Sdes if (!fd) fclose(rand_f); 371238104Sdes return 1; 372238104Sdes } else { 373238104Sdes#ifdef HAVE_SSL 374238104Sdes /* Seed the OpenSSL prng (most systems have it seeded 375238104Sdes automatically, in that case this call just adds entropy */ 376238104Sdes RAND_seed(seed, (int) size); 377238104Sdes#else 378238104Sdes /* Seed the standard prng, only uses the first 379238104Sdes * unsigned sizeof(unsiged int) bytes found in the entropy pool 380238104Sdes */ 381238104Sdes memcpy(&seed_i, seed, sizeof(seed_i)); 382238104Sdes srandom(seed_i); 383238104Sdes#endif 384238104Sdes LDNS_FREE(seed); 385238104Sdes } 386238104Sdes 387238104Sdes if (!fd) { 388238104Sdes if (rand_f) fclose(rand_f); 389238104Sdes } 390238104Sdes 391238104Sdes return 0; 392238104Sdes} 393238104Sdes 394238104Sdes/** 395238104Sdes * Get random number. 396238104Sdes * 397238104Sdes */ 398238104Sdesuint16_t 399238104Sdesldns_get_random(void) 400238104Sdes{ 401238104Sdes uint16_t rid = 0; 402238104Sdes#ifdef HAVE_SSL 403238104Sdes if (RAND_bytes((unsigned char*)&rid, 2) != 1) { 404238104Sdes rid = (uint16_t) random(); 405238104Sdes } 406238104Sdes#else 407238104Sdes rid = (uint16_t) random(); 408238104Sdes#endif 409238104Sdes return rid; 410238104Sdes} 411238104Sdes 412238104Sdes/* 413238104Sdes * BubbleBabble code taken from OpenSSH 414238104Sdes * Copyright (c) 2001 Carsten Raskgaard. All rights reserved. 415238104Sdes */ 416238104Sdeschar * 417238104Sdesldns_bubblebabble(uint8_t *data, size_t len) 418238104Sdes{ 419238104Sdes char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; 420238104Sdes char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 421238104Sdes 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; 422238104Sdes size_t i, j = 0, rounds, seed = 1; 423238104Sdes char *retval; 424238104Sdes 425238104Sdes rounds = (len / 2) + 1; 426238104Sdes retval = LDNS_XMALLOC(char, rounds * 6); 427238104Sdes if(!retval) return NULL; 428238104Sdes retval[j++] = 'x'; 429238104Sdes for (i = 0; i < rounds; i++) { 430238104Sdes size_t idx0, idx1, idx2, idx3, idx4; 431238104Sdes if ((i + 1 < rounds) || (len % 2 != 0)) { 432238104Sdes idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) + 433238104Sdes seed) % 6; 434238104Sdes idx1 = (((size_t)(data[2 * i])) >> 2) & 15; 435238104Sdes idx2 = ((((size_t)(data[2 * i])) & 3) + 436238104Sdes (seed / 6)) % 6; 437238104Sdes retval[j++] = vowels[idx0]; 438238104Sdes retval[j++] = consonants[idx1]; 439238104Sdes retval[j++] = vowels[idx2]; 440238104Sdes if ((i + 1) < rounds) { 441238104Sdes idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15; 442238104Sdes idx4 = (((size_t)(data[(2 * i) + 1]))) & 15; 443238104Sdes retval[j++] = consonants[idx3]; 444238104Sdes retval[j++] = '-'; 445238104Sdes retval[j++] = consonants[idx4]; 446238104Sdes seed = ((seed * 5) + 447238104Sdes ((((size_t)(data[2 * i])) * 7) + 448238104Sdes ((size_t)(data[(2 * i) + 1])))) % 36; 449238104Sdes } 450238104Sdes } else { 451238104Sdes idx0 = seed % 6; 452238104Sdes idx1 = 16; 453238104Sdes idx2 = seed / 6; 454238104Sdes retval[j++] = vowels[idx0]; 455238104Sdes retval[j++] = consonants[idx1]; 456238104Sdes retval[j++] = vowels[idx2]; 457238104Sdes } 458238104Sdes } 459238104Sdes retval[j++] = 'x'; 460238104Sdes retval[j++] = '\0'; 461238104Sdes return retval; 462238104Sdes} 463