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