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