util.c revision 246854
1/* 2 * util.c 3 * 4 * some general memory functions 5 * 6 * a Net::DNS like library for C 7 * 8 * (c) NLnet Labs, 2004-2006 9 * 10 * See the file LICENSE for the license 11 */ 12 13#include <ldns/config.h> 14 15#include <ldns/rdata.h> 16#include <ldns/rr.h> 17#include <ldns/util.h> 18#include <strings.h> 19#include <stdlib.h> 20#include <stdio.h> 21#include <sys/time.h> 22#include <time.h> 23 24#ifdef HAVE_SSL 25#include <openssl/rand.h> 26#endif 27 28/* put this here tmp. for debugging */ 29static void 30xprintf_rdf(ldns_rdf *rd) 31{ 32 /* assume printable string */ 33 fprintf(stderr, "size\t:%u\n", (unsigned int)ldns_rdf_size(rd)); 34 fprintf(stderr, "type\t:%u\n", (unsigned int)ldns_rdf_get_type(rd)); 35 fprintf(stderr, "data\t:[%.*s]\n", (int)ldns_rdf_size(rd), 36 (char*)ldns_rdf_data(rd)); 37} 38 39static void 40xprintf_rr(ldns_rr *rr) 41{ 42 /* assume printable string */ 43 uint16_t count, i; 44 45 count = ldns_rr_rd_count(rr); 46 47 for(i = 0; i < count; i++) { 48 fprintf(stderr, "print rd %u\n", (unsigned int) i); 49 xprintf_rdf(rr->_rdata_fields[i]); 50 } 51} 52 53static void 54xprintf_hex(uint8_t *data, size_t len) 55{ 56 size_t i; 57 for (i = 0; i < len; i++) { 58 if (i > 0 && i % 20 == 0) { 59 printf("\t; %u - %u\n", (unsigned int) i - 19, (unsigned int) i); 60 } 61 printf("%02x ", (unsigned int) data[i]); 62 } 63 printf("\n"); 64} 65 66ldns_lookup_table * 67ldns_lookup_by_name(ldns_lookup_table *table, const char *name) 68{ 69 while (table->name != NULL) { 70 if (strcasecmp(name, table->name) == 0) 71 return table; 72 table++; 73 } 74 return NULL; 75} 76 77ldns_lookup_table * 78ldns_lookup_by_id(ldns_lookup_table *table, int id) 79{ 80 while (table->name != NULL) { 81 if (table->id == id) 82 return table; 83 table++; 84 } 85 return NULL; 86} 87 88int 89ldns_get_bit(uint8_t bits[], size_t index) 90{ 91 /* 92 * The bits are counted from left to right, so bit #0 is the 93 * left most bit. 94 */ 95 return (int) (bits[index / 8] & (1 << (7 - index % 8))); 96} 97 98int 99ldns_get_bit_r(uint8_t bits[], size_t index) 100{ 101 /* 102 * The bits are counted from right to left, so bit #0 is the 103 * right most bit. 104 */ 105 return (int) bits[index / 8] & (1 << (index % 8)); 106} 107 108void 109ldns_set_bit(uint8_t *byte, int bit_nr, bool value) 110{ 111 /* 112 * The bits are counted from right to left, so bit #0 is the 113 * right most bit. 114 */ 115 if (bit_nr >= 0 && bit_nr < 8) { 116 if (value) { 117 *byte = *byte | (0x01 << bit_nr); 118 } else { 119 *byte = *byte & ~(0x01 << bit_nr); 120 } 121 } 122} 123 124int 125ldns_hexdigit_to_int(char ch) 126{ 127 switch (ch) { 128 case '0': return 0; 129 case '1': return 1; 130 case '2': return 2; 131 case '3': return 3; 132 case '4': return 4; 133 case '5': return 5; 134 case '6': return 6; 135 case '7': return 7; 136 case '8': return 8; 137 case '9': return 9; 138 case 'a': case 'A': return 10; 139 case 'b': case 'B': return 11; 140 case 'c': case 'C': return 12; 141 case 'd': case 'D': return 13; 142 case 'e': case 'E': return 14; 143 case 'f': case 'F': return 15; 144 default: 145 return -1; 146 } 147} 148 149char 150ldns_int_to_hexdigit(int i) 151{ 152 switch (i) { 153 case 0: return '0'; 154 case 1: return '1'; 155 case 2: return '2'; 156 case 3: return '3'; 157 case 4: return '4'; 158 case 5: return '5'; 159 case 6: return '6'; 160 case 7: return '7'; 161 case 8: return '8'; 162 case 9: return '9'; 163 case 10: return 'a'; 164 case 11: return 'b'; 165 case 12: return 'c'; 166 case 13: return 'd'; 167 case 14: return 'e'; 168 case 15: return 'f'; 169 default: 170 abort(); 171 } 172} 173 174int 175ldns_hexstring_to_data(uint8_t *data, const char *str) 176{ 177 size_t i; 178 179 if (!str || !data) { 180 return -1; 181 } 182 183 if (strlen(str) % 2 != 0) { 184 return -2; 185 } 186 187 for (i = 0; i < strlen(str) / 2; i++) { 188 data[i] = 189 16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) + 190 (uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]); 191 } 192 193 return (int) i; 194} 195 196const char * 197ldns_version(void) 198{ 199 return (char*)LDNS_VERSION; 200} 201 202/* Number of days per month (except for February in leap years). */ 203static const int mdays[] = { 204 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 205}; 206 207#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y))) 208#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y))) 209 210static int 211is_leap_year(int year) 212{ 213 return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0 214 || LDNS_MOD(year, 400) == 0); 215} 216 217static int 218leap_days(int y1, int y2) 219{ 220 --y1; 221 --y2; 222 return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) - 223 (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) + 224 (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400)); 225} 226 227/* 228 * Code adapted from Python 2.4.1 sources (Lib/calendar.py). 229 */ 230time_t 231ldns_mktime_from_utc(const struct tm *tm) 232{ 233 int year = 1900 + tm->tm_year; 234 time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year); 235 time_t hours; 236 time_t minutes; 237 time_t seconds; 238 int i; 239 240 for (i = 0; i < tm->tm_mon; ++i) { 241 days += mdays[i]; 242 } 243 if (tm->tm_mon > 1 && is_leap_year(year)) { 244 ++days; 245 } 246 days += tm->tm_mday - 1; 247 248 hours = days * 24 + tm->tm_hour; 249 minutes = hours * 60 + tm->tm_min; 250 seconds = minutes * 60 + tm->tm_sec; 251 252 return seconds; 253} 254 255time_t 256mktime_from_utc(const struct tm *tm) 257{ 258 return ldns_mktime_from_utc(tm); 259} 260 261#if SIZEOF_TIME_T <= 4 262 263static void 264ldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result) 265{ 266 int year = 1970; 267 int new_year; 268 269 while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) { 270 new_year = year + (int) LDNS_DIV(days, 365); 271 days -= (new_year - year) * 365; 272 days -= leap_days(year, new_year); 273 year = new_year; 274 } 275 result->tm_year = year; 276 result->tm_yday = (int) days; 277} 278 279/* Number of days per month in a leap year. */ 280static const int leap_year_mdays[] = { 281 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 282}; 283 284static void 285ldns_mon_and_mday_from_year_and_yday(struct tm *result) 286{ 287 int idays = result->tm_yday; 288 const int *mon_lengths = is_leap_year(result->tm_year) ? 289 leap_year_mdays : mdays; 290 291 result->tm_mon = 0; 292 while (idays >= mon_lengths[result->tm_mon]) { 293 idays -= mon_lengths[result->tm_mon++]; 294 } 295 result->tm_mday = idays + 1; 296} 297 298static void 299ldns_wday_from_year_and_yday(struct tm *result) 300{ 301 result->tm_wday = 4 /* 1-1-1970 was a thursday */ 302 + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7) 303 + leap_days(1970, result->tm_year) 304 + result->tm_yday; 305 result->tm_wday = LDNS_MOD(result->tm_wday, 7); 306 if (result->tm_wday < 0) { 307 result->tm_wday += 7; 308 } 309} 310 311static struct tm * 312ldns_gmtime64_r(int64_t clock, struct tm *result) 313{ 314 result->tm_isdst = 0; 315 result->tm_sec = (int) LDNS_MOD(clock, 60); 316 clock = LDNS_DIV(clock, 60); 317 result->tm_min = (int) LDNS_MOD(clock, 60); 318 clock = LDNS_DIV(clock, 60); 319 result->tm_hour = (int) LDNS_MOD(clock, 24); 320 clock = LDNS_DIV(clock, 24); 321 322 ldns_year_and_yday_from_days_since_epoch(clock, result); 323 ldns_mon_and_mday_from_year_and_yday(result); 324 ldns_wday_from_year_and_yday(result); 325 result->tm_year -= 1900; 326 327 return result; 328} 329 330#endif /* SIZEOF_TIME_T <= 4 */ 331 332static int64_t 333ldns_serial_arithmitics_time(int32_t time, time_t now) 334{ 335 int32_t offset = time - (int32_t) now; 336 return (int64_t) now + offset; 337} 338 339 340struct tm * 341ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result) 342{ 343#if SIZEOF_TIME_T <= 4 344 int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); 345 return ldns_gmtime64_r(secs_since_epoch, result); 346#else 347 time_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); 348 return gmtime_r(&secs_since_epoch, result); 349#endif 350} 351 352/** 353 * Init the random source 354 * applications should call this if they need entropy data within ldns 355 * If openSSL is available, it is automatically seeded from /dev/urandom 356 * or /dev/random 357 * 358 * If you need more entropy, or have no openssl available, this function 359 * MUST be called at the start of the program 360 * 361 * If openssl *is* available, this function just adds more entropy 362 **/ 363int 364ldns_init_random(FILE *fd, unsigned int size) 365{ 366 /* if fp is given, seed srandom with data from file 367 otherwise use /dev/urandom */ 368 FILE *rand_f; 369 uint8_t *seed; 370 size_t read = 0; 371 unsigned int seed_i; 372 struct timeval tv; 373 374 /* we'll need at least sizeof(unsigned int) bytes for the 375 standard prng seed */ 376 if (size < (unsigned int) sizeof(seed_i)){ 377 size = (unsigned int) sizeof(seed_i); 378 } 379 380 seed = LDNS_XMALLOC(uint8_t, size); 381 if(!seed) { 382 return 1; 383 } 384 385 if (!fd) { 386 if ((rand_f = fopen("/dev/urandom", "r")) == NULL) { 387 /* no readable /dev/urandom, try /dev/random */ 388 if ((rand_f = fopen("/dev/random", "r")) == NULL) { 389 /* no readable /dev/random either, and no entropy 390 source given. we'll have to improvise */ 391 for (read = 0; read < size; read++) { 392 gettimeofday(&tv, NULL); 393 seed[read] = (uint8_t) (tv.tv_usec % 256); 394 } 395 } else { 396 read = fread(seed, 1, size, rand_f); 397 } 398 } else { 399 read = fread(seed, 1, size, rand_f); 400 } 401 } else { 402 rand_f = fd; 403 read = fread(seed, 1, size, rand_f); 404 } 405 406 if (read < size) { 407 LDNS_FREE(seed); 408 if (!fd) fclose(rand_f); 409 return 1; 410 } else { 411#ifdef HAVE_SSL 412 /* Seed the OpenSSL prng (most systems have it seeded 413 automatically, in that case this call just adds entropy */ 414 RAND_seed(seed, (int) size); 415#else 416 /* Seed the standard prng, only uses the first 417 * unsigned sizeof(unsiged int) bytes found in the entropy pool 418 */ 419 memcpy(&seed_i, seed, sizeof(seed_i)); 420 srandom(seed_i); 421#endif 422 LDNS_FREE(seed); 423 } 424 425 if (!fd) { 426 if (rand_f) fclose(rand_f); 427 } 428 429 return 0; 430} 431 432/** 433 * Get random number. 434 * 435 */ 436uint16_t 437ldns_get_random(void) 438{ 439 uint16_t rid = 0; 440#ifdef HAVE_SSL 441 if (RAND_bytes((unsigned char*)&rid, 2) != 1) { 442 rid = (uint16_t) random(); 443 } 444#else 445 rid = (uint16_t) random(); 446#endif 447 return rid; 448} 449 450/* 451 * BubbleBabble code taken from OpenSSH 452 * Copyright (c) 2001 Carsten Raskgaard. All rights reserved. 453 */ 454char * 455ldns_bubblebabble(uint8_t *data, size_t len) 456{ 457 char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; 458 char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 459 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; 460 size_t i, j = 0, rounds, seed = 1; 461 char *retval; 462 463 rounds = (len / 2) + 1; 464 retval = LDNS_XMALLOC(char, rounds * 6); 465 if(!retval) return NULL; 466 retval[j++] = 'x'; 467 for (i = 0; i < rounds; i++) { 468 size_t idx0, idx1, idx2, idx3, idx4; 469 if ((i + 1 < rounds) || (len % 2 != 0)) { 470 idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) + 471 seed) % 6; 472 idx1 = (((size_t)(data[2 * i])) >> 2) & 15; 473 idx2 = ((((size_t)(data[2 * i])) & 3) + 474 (seed / 6)) % 6; 475 retval[j++] = vowels[idx0]; 476 retval[j++] = consonants[idx1]; 477 retval[j++] = vowels[idx2]; 478 if ((i + 1) < rounds) { 479 idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15; 480 idx4 = (((size_t)(data[(2 * i) + 1]))) & 15; 481 retval[j++] = consonants[idx3]; 482 retval[j++] = '-'; 483 retval[j++] = consonants[idx4]; 484 seed = ((seed * 5) + 485 ((((size_t)(data[2 * i])) * 7) + 486 ((size_t)(data[(2 * i) + 1])))) % 36; 487 } 488 } else { 489 idx0 = seed % 6; 490 idx1 = 16; 491 idx2 = seed / 6; 492 retval[j++] = vowels[idx0]; 493 retval[j++] = consonants[idx1]; 494 retval[j++] = vowels[idx2]; 495 } 496 } 497 retval[j++] = 'x'; 498 retval[j++] = '\0'; 499 return retval; 500} 501