xref: /freebsd/contrib/ldns/util.c (revision 2787e39aaaaffd1fb07657ffaa2e3561858b3c73)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * util.c
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * some general memory functions
57b5038d7SDag-Erling Smørgrav  *
67b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2004-2006
97b5038d7SDag-Erling Smørgrav  *
107b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
117b5038d7SDag-Erling Smørgrav  */
127b5038d7SDag-Erling Smørgrav 
137b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
147b5038d7SDag-Erling Smørgrav 
157b5038d7SDag-Erling Smørgrav #include <ldns/rdata.h>
167b5038d7SDag-Erling Smørgrav #include <ldns/rr.h>
177b5038d7SDag-Erling Smørgrav #include <ldns/util.h>
187b5038d7SDag-Erling Smørgrav #include <strings.h>
197b5038d7SDag-Erling Smørgrav #include <stdlib.h>
207b5038d7SDag-Erling Smørgrav #include <stdio.h>
217b5038d7SDag-Erling Smørgrav #include <sys/time.h>
227b5038d7SDag-Erling Smørgrav #include <time.h>
237b5038d7SDag-Erling Smørgrav 
247b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
257b5038d7SDag-Erling Smørgrav #include <openssl/rand.h>
267b5038d7SDag-Erling Smørgrav #endif
277b5038d7SDag-Erling Smørgrav 
287b5038d7SDag-Erling Smørgrav /* put this here tmp. for debugging */
297b5038d7SDag-Erling Smørgrav static void
307b5038d7SDag-Erling Smørgrav xprintf_rdf(ldns_rdf *rd)
317b5038d7SDag-Erling Smørgrav {
327b5038d7SDag-Erling Smørgrav 	/* assume printable string */
337b5038d7SDag-Erling Smørgrav 	fprintf(stderr, "size\t:%u\n", (unsigned int)ldns_rdf_size(rd));
347b5038d7SDag-Erling Smørgrav 	fprintf(stderr, "type\t:%u\n", (unsigned int)ldns_rdf_get_type(rd));
357b5038d7SDag-Erling Smørgrav 	fprintf(stderr, "data\t:[%.*s]\n", (int)ldns_rdf_size(rd),
367b5038d7SDag-Erling Smørgrav 			(char*)ldns_rdf_data(rd));
377b5038d7SDag-Erling Smørgrav }
387b5038d7SDag-Erling Smørgrav 
397b5038d7SDag-Erling Smørgrav static void
407b5038d7SDag-Erling Smørgrav xprintf_rr(ldns_rr *rr)
417b5038d7SDag-Erling Smørgrav {
427b5038d7SDag-Erling Smørgrav 	/* assume printable string */
437b5038d7SDag-Erling Smørgrav 	uint16_t count, i;
447b5038d7SDag-Erling Smørgrav 
457b5038d7SDag-Erling Smørgrav 	count = ldns_rr_rd_count(rr);
467b5038d7SDag-Erling Smørgrav 
477b5038d7SDag-Erling Smørgrav 	for(i = 0; i < count; i++) {
487b5038d7SDag-Erling Smørgrav 		fprintf(stderr, "print rd %u\n", (unsigned int) i);
497b5038d7SDag-Erling Smørgrav 		xprintf_rdf(rr->_rdata_fields[i]);
507b5038d7SDag-Erling Smørgrav 	}
517b5038d7SDag-Erling Smørgrav }
527b5038d7SDag-Erling Smørgrav 
537b5038d7SDag-Erling Smørgrav static void
547b5038d7SDag-Erling Smørgrav xprintf_hex(uint8_t *data, size_t len)
557b5038d7SDag-Erling Smørgrav {
567b5038d7SDag-Erling Smørgrav 	size_t i;
577b5038d7SDag-Erling Smørgrav 	for (i = 0; i < len; i++) {
587b5038d7SDag-Erling Smørgrav 		if (i > 0 && i % 20 == 0) {
597b5038d7SDag-Erling Smørgrav 			printf("\t; %u - %u\n", (unsigned int) i - 19, (unsigned int) i);
607b5038d7SDag-Erling Smørgrav 		}
617b5038d7SDag-Erling Smørgrav 		printf("%02x ", (unsigned int) data[i]);
627b5038d7SDag-Erling Smørgrav 	}
637b5038d7SDag-Erling Smørgrav 	printf("\n");
647b5038d7SDag-Erling Smørgrav }
657b5038d7SDag-Erling Smørgrav 
667b5038d7SDag-Erling Smørgrav ldns_lookup_table *
677b5038d7SDag-Erling Smørgrav ldns_lookup_by_name(ldns_lookup_table *table, const char *name)
687b5038d7SDag-Erling Smørgrav {
697b5038d7SDag-Erling Smørgrav 	while (table->name != NULL) {
707b5038d7SDag-Erling Smørgrav 		if (strcasecmp(name, table->name) == 0)
717b5038d7SDag-Erling Smørgrav 			return table;
727b5038d7SDag-Erling Smørgrav 		table++;
737b5038d7SDag-Erling Smørgrav 	}
747b5038d7SDag-Erling Smørgrav 	return NULL;
757b5038d7SDag-Erling Smørgrav }
767b5038d7SDag-Erling Smørgrav 
777b5038d7SDag-Erling Smørgrav ldns_lookup_table *
787b5038d7SDag-Erling Smørgrav ldns_lookup_by_id(ldns_lookup_table *table, int id)
797b5038d7SDag-Erling Smørgrav {
807b5038d7SDag-Erling Smørgrav 	while (table->name != NULL) {
817b5038d7SDag-Erling Smørgrav 		if (table->id == id)
827b5038d7SDag-Erling Smørgrav 			return table;
837b5038d7SDag-Erling Smørgrav 		table++;
847b5038d7SDag-Erling Smørgrav 	}
857b5038d7SDag-Erling Smørgrav 	return NULL;
867b5038d7SDag-Erling Smørgrav }
877b5038d7SDag-Erling Smørgrav 
887b5038d7SDag-Erling Smørgrav int
897b5038d7SDag-Erling Smørgrav ldns_get_bit(uint8_t bits[], size_t index)
907b5038d7SDag-Erling Smørgrav {
917b5038d7SDag-Erling Smørgrav 	/*
927b5038d7SDag-Erling Smørgrav 	 * The bits are counted from left to right, so bit #0 is the
937b5038d7SDag-Erling Smørgrav 	 * left most bit.
947b5038d7SDag-Erling Smørgrav 	 */
957b5038d7SDag-Erling Smørgrav 	return (int) (bits[index / 8] & (1 << (7 - index % 8)));
967b5038d7SDag-Erling Smørgrav }
977b5038d7SDag-Erling Smørgrav 
987b5038d7SDag-Erling Smørgrav int
997b5038d7SDag-Erling Smørgrav ldns_get_bit_r(uint8_t bits[], size_t index)
1007b5038d7SDag-Erling Smørgrav {
1017b5038d7SDag-Erling Smørgrav 	/*
1027b5038d7SDag-Erling Smørgrav 	 * The bits are counted from right to left, so bit #0 is the
1037b5038d7SDag-Erling Smørgrav 	 * right most bit.
1047b5038d7SDag-Erling Smørgrav 	 */
1057b5038d7SDag-Erling Smørgrav 	return (int) bits[index / 8] & (1 << (index % 8));
1067b5038d7SDag-Erling Smørgrav }
1077b5038d7SDag-Erling Smørgrav 
1087b5038d7SDag-Erling Smørgrav void
1097b5038d7SDag-Erling Smørgrav ldns_set_bit(uint8_t *byte, int bit_nr, bool value)
1107b5038d7SDag-Erling Smørgrav {
1117b5038d7SDag-Erling Smørgrav 	/*
1127b5038d7SDag-Erling Smørgrav 	 * The bits are counted from right to left, so bit #0 is the
1137b5038d7SDag-Erling Smørgrav 	 * right most bit.
1147b5038d7SDag-Erling Smørgrav 	 */
1157b5038d7SDag-Erling Smørgrav 	if (bit_nr >= 0 && bit_nr < 8) {
1167b5038d7SDag-Erling Smørgrav 		if (value) {
1177b5038d7SDag-Erling Smørgrav 			*byte = *byte | (0x01 << bit_nr);
1187b5038d7SDag-Erling Smørgrav 		} else {
1197b5038d7SDag-Erling Smørgrav 			*byte = *byte & ~(0x01 << bit_nr);
1207b5038d7SDag-Erling Smørgrav 		}
1217b5038d7SDag-Erling Smørgrav 	}
1227b5038d7SDag-Erling Smørgrav }
1237b5038d7SDag-Erling Smørgrav 
1247b5038d7SDag-Erling Smørgrav int
1257b5038d7SDag-Erling Smørgrav ldns_hexdigit_to_int(char ch)
1267b5038d7SDag-Erling Smørgrav {
1277b5038d7SDag-Erling Smørgrav 	switch (ch) {
1287b5038d7SDag-Erling Smørgrav 	case '0': return 0;
1297b5038d7SDag-Erling Smørgrav 	case '1': return 1;
1307b5038d7SDag-Erling Smørgrav 	case '2': return 2;
1317b5038d7SDag-Erling Smørgrav 	case '3': return 3;
1327b5038d7SDag-Erling Smørgrav 	case '4': return 4;
1337b5038d7SDag-Erling Smørgrav 	case '5': return 5;
1347b5038d7SDag-Erling Smørgrav 	case '6': return 6;
1357b5038d7SDag-Erling Smørgrav 	case '7': return 7;
1367b5038d7SDag-Erling Smørgrav 	case '8': return 8;
1377b5038d7SDag-Erling Smørgrav 	case '9': return 9;
1387b5038d7SDag-Erling Smørgrav 	case 'a': case 'A': return 10;
1397b5038d7SDag-Erling Smørgrav 	case 'b': case 'B': return 11;
1407b5038d7SDag-Erling Smørgrav 	case 'c': case 'C': return 12;
1417b5038d7SDag-Erling Smørgrav 	case 'd': case 'D': return 13;
1427b5038d7SDag-Erling Smørgrav 	case 'e': case 'E': return 14;
1437b5038d7SDag-Erling Smørgrav 	case 'f': case 'F': return 15;
1447b5038d7SDag-Erling Smørgrav 	default:
1457b5038d7SDag-Erling Smørgrav 		return -1;
1467b5038d7SDag-Erling Smørgrav 	}
1477b5038d7SDag-Erling Smørgrav }
1487b5038d7SDag-Erling Smørgrav 
1497b5038d7SDag-Erling Smørgrav char
1507b5038d7SDag-Erling Smørgrav ldns_int_to_hexdigit(int i)
1517b5038d7SDag-Erling Smørgrav {
1527b5038d7SDag-Erling Smørgrav 	switch (i) {
1537b5038d7SDag-Erling Smørgrav 	case 0: return '0';
1547b5038d7SDag-Erling Smørgrav 	case 1: return '1';
1557b5038d7SDag-Erling Smørgrav 	case 2: return '2';
1567b5038d7SDag-Erling Smørgrav 	case 3: return '3';
1577b5038d7SDag-Erling Smørgrav 	case 4: return '4';
1587b5038d7SDag-Erling Smørgrav 	case 5: return '5';
1597b5038d7SDag-Erling Smørgrav 	case 6: return '6';
1607b5038d7SDag-Erling Smørgrav 	case 7: return '7';
1617b5038d7SDag-Erling Smørgrav 	case 8: return '8';
1627b5038d7SDag-Erling Smørgrav 	case 9: return '9';
1637b5038d7SDag-Erling Smørgrav 	case 10: return 'a';
1647b5038d7SDag-Erling Smørgrav 	case 11: return 'b';
1657b5038d7SDag-Erling Smørgrav 	case 12: return 'c';
1667b5038d7SDag-Erling Smørgrav 	case 13: return 'd';
1677b5038d7SDag-Erling Smørgrav 	case 14: return 'e';
1687b5038d7SDag-Erling Smørgrav 	case 15: return 'f';
1697b5038d7SDag-Erling Smørgrav 	default:
1707b5038d7SDag-Erling Smørgrav 		abort();
1717b5038d7SDag-Erling Smørgrav 	}
1727b5038d7SDag-Erling Smørgrav }
1737b5038d7SDag-Erling Smørgrav 
1747b5038d7SDag-Erling Smørgrav int
1757b5038d7SDag-Erling Smørgrav ldns_hexstring_to_data(uint8_t *data, const char *str)
1767b5038d7SDag-Erling Smørgrav {
1777b5038d7SDag-Erling Smørgrav 	size_t i;
1787b5038d7SDag-Erling Smørgrav 
1797b5038d7SDag-Erling Smørgrav 	if (!str || !data) {
1807b5038d7SDag-Erling Smørgrav 		return -1;
1817b5038d7SDag-Erling Smørgrav 	}
1827b5038d7SDag-Erling Smørgrav 
1837b5038d7SDag-Erling Smørgrav 	if (strlen(str) % 2 != 0) {
1847b5038d7SDag-Erling Smørgrav 		return -2;
1857b5038d7SDag-Erling Smørgrav 	}
1867b5038d7SDag-Erling Smørgrav 
1877b5038d7SDag-Erling Smørgrav 	for (i = 0; i < strlen(str) / 2; i++) {
1887b5038d7SDag-Erling Smørgrav 		data[i] =
1897b5038d7SDag-Erling Smørgrav 			16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) +
1907b5038d7SDag-Erling Smørgrav 			(uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]);
1917b5038d7SDag-Erling Smørgrav 	}
1927b5038d7SDag-Erling Smørgrav 
1937b5038d7SDag-Erling Smørgrav 	return (int) i;
1947b5038d7SDag-Erling Smørgrav }
1957b5038d7SDag-Erling Smørgrav 
1967b5038d7SDag-Erling Smørgrav const char *
1977b5038d7SDag-Erling Smørgrav ldns_version(void)
1987b5038d7SDag-Erling Smørgrav {
1997b5038d7SDag-Erling Smørgrav 	return (char*)LDNS_VERSION;
2007b5038d7SDag-Erling Smørgrav }
2017b5038d7SDag-Erling Smørgrav 
2027b5038d7SDag-Erling Smørgrav /* Number of days per month (except for February in leap years). */
2037b5038d7SDag-Erling Smørgrav static const int mdays[] = {
2047b5038d7SDag-Erling Smørgrav 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2057b5038d7SDag-Erling Smørgrav };
2067b5038d7SDag-Erling Smørgrav 
2077b5038d7SDag-Erling Smørgrav #define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y)))
2087b5038d7SDag-Erling Smørgrav #define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) -  1 ) : ((x) / (y)))
2097b5038d7SDag-Erling Smørgrav 
2107b5038d7SDag-Erling Smørgrav static int
2117b5038d7SDag-Erling Smørgrav is_leap_year(int year)
2127b5038d7SDag-Erling Smørgrav {
2137b5038d7SDag-Erling Smørgrav 	return LDNS_MOD(year,   4) == 0 && (LDNS_MOD(year, 100) != 0
2147b5038d7SDag-Erling Smørgrav 	    || LDNS_MOD(year, 400) == 0);
2157b5038d7SDag-Erling Smørgrav }
2167b5038d7SDag-Erling Smørgrav 
2177b5038d7SDag-Erling Smørgrav static int
2187b5038d7SDag-Erling Smørgrav leap_days(int y1, int y2)
2197b5038d7SDag-Erling Smørgrav {
2207b5038d7SDag-Erling Smørgrav 	--y1;
2217b5038d7SDag-Erling Smørgrav 	--y2;
2227b5038d7SDag-Erling Smørgrav 	return (LDNS_DIV(y2,   4) - LDNS_DIV(y1,   4)) -
2237b5038d7SDag-Erling Smørgrav 	       (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) +
2247b5038d7SDag-Erling Smørgrav 	       (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400));
2257b5038d7SDag-Erling Smørgrav }
2267b5038d7SDag-Erling Smørgrav 
2277b5038d7SDag-Erling Smørgrav /*
2287b5038d7SDag-Erling Smørgrav  * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
2297b5038d7SDag-Erling Smørgrav  */
2307b5038d7SDag-Erling Smørgrav time_t
231*2787e39aSDag-Erling Smørgrav ldns_mktime_from_utc(const struct tm *tm)
2327b5038d7SDag-Erling Smørgrav {
2337b5038d7SDag-Erling Smørgrav 	int year = 1900 + tm->tm_year;
2347b5038d7SDag-Erling Smørgrav 	time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year);
2357b5038d7SDag-Erling Smørgrav 	time_t hours;
2367b5038d7SDag-Erling Smørgrav 	time_t minutes;
2377b5038d7SDag-Erling Smørgrav 	time_t seconds;
2387b5038d7SDag-Erling Smørgrav 	int i;
2397b5038d7SDag-Erling Smørgrav 
2407b5038d7SDag-Erling Smørgrav 	for (i = 0; i < tm->tm_mon; ++i) {
2417b5038d7SDag-Erling Smørgrav 		days += mdays[i];
2427b5038d7SDag-Erling Smørgrav 	}
2437b5038d7SDag-Erling Smørgrav 	if (tm->tm_mon > 1 && is_leap_year(year)) {
2447b5038d7SDag-Erling Smørgrav 		++days;
2457b5038d7SDag-Erling Smørgrav 	}
2467b5038d7SDag-Erling Smørgrav 	days += tm->tm_mday - 1;
2477b5038d7SDag-Erling Smørgrav 
2487b5038d7SDag-Erling Smørgrav 	hours = days * 24 + tm->tm_hour;
2497b5038d7SDag-Erling Smørgrav 	minutes = hours * 60 + tm->tm_min;
2507b5038d7SDag-Erling Smørgrav 	seconds = minutes * 60 + tm->tm_sec;
2517b5038d7SDag-Erling Smørgrav 
2527b5038d7SDag-Erling Smørgrav 	return seconds;
2537b5038d7SDag-Erling Smørgrav }
2547b5038d7SDag-Erling Smørgrav 
255*2787e39aSDag-Erling Smørgrav time_t
256*2787e39aSDag-Erling Smørgrav mktime_from_utc(const struct tm *tm)
257*2787e39aSDag-Erling Smørgrav {
258*2787e39aSDag-Erling Smørgrav 	return ldns_mktime_from_utc(tm);
259*2787e39aSDag-Erling Smørgrav }
260*2787e39aSDag-Erling Smørgrav 
2617b5038d7SDag-Erling Smørgrav #if SIZEOF_TIME_T <= 4
2627b5038d7SDag-Erling Smørgrav 
2637b5038d7SDag-Erling Smørgrav static void
2647b5038d7SDag-Erling Smørgrav ldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result)
2657b5038d7SDag-Erling Smørgrav {
2667b5038d7SDag-Erling Smørgrav 	int year = 1970;
2677b5038d7SDag-Erling Smørgrav 	int new_year;
2687b5038d7SDag-Erling Smørgrav 
2697b5038d7SDag-Erling Smørgrav 	while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) {
2707b5038d7SDag-Erling Smørgrav 		new_year = year + (int) LDNS_DIV(days, 365);
2717b5038d7SDag-Erling Smørgrav 		days -= (new_year - year) * 365;
2727b5038d7SDag-Erling Smørgrav 		days -= leap_days(year, new_year);
2737b5038d7SDag-Erling Smørgrav 		year  = new_year;
2747b5038d7SDag-Erling Smørgrav 	}
2757b5038d7SDag-Erling Smørgrav 	result->tm_year = year;
2767b5038d7SDag-Erling Smørgrav 	result->tm_yday = (int) days;
2777b5038d7SDag-Erling Smørgrav }
2787b5038d7SDag-Erling Smørgrav 
2797b5038d7SDag-Erling Smørgrav /* Number of days per month in a leap year. */
2807b5038d7SDag-Erling Smørgrav static const int leap_year_mdays[] = {
2817b5038d7SDag-Erling Smørgrav 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2827b5038d7SDag-Erling Smørgrav };
2837b5038d7SDag-Erling Smørgrav 
2847b5038d7SDag-Erling Smørgrav static void
2857b5038d7SDag-Erling Smørgrav ldns_mon_and_mday_from_year_and_yday(struct tm *result)
2867b5038d7SDag-Erling Smørgrav {
2877b5038d7SDag-Erling Smørgrav 	int idays = result->tm_yday;
2887b5038d7SDag-Erling Smørgrav 	const int *mon_lengths = is_leap_year(result->tm_year) ?
2897b5038d7SDag-Erling Smørgrav 					leap_year_mdays : mdays;
2907b5038d7SDag-Erling Smørgrav 
2917b5038d7SDag-Erling Smørgrav 	result->tm_mon = 0;
2927b5038d7SDag-Erling Smørgrav 	while  (idays >= mon_lengths[result->tm_mon]) {
2937b5038d7SDag-Erling Smørgrav 		idays -= mon_lengths[result->tm_mon++];
2947b5038d7SDag-Erling Smørgrav 	}
2957b5038d7SDag-Erling Smørgrav 	result->tm_mday = idays + 1;
2967b5038d7SDag-Erling Smørgrav }
2977b5038d7SDag-Erling Smørgrav 
2987b5038d7SDag-Erling Smørgrav static void
2997b5038d7SDag-Erling Smørgrav ldns_wday_from_year_and_yday(struct tm *result)
3007b5038d7SDag-Erling Smørgrav {
3017b5038d7SDag-Erling Smørgrav 	result->tm_wday = 4 /* 1-1-1970 was a thursday */
3027b5038d7SDag-Erling Smørgrav 			+ LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7)
3037b5038d7SDag-Erling Smørgrav 			+ leap_days(1970, result->tm_year)
3047b5038d7SDag-Erling Smørgrav 			+ result->tm_yday;
3057b5038d7SDag-Erling Smørgrav 	result->tm_wday = LDNS_MOD(result->tm_wday, 7);
3067b5038d7SDag-Erling Smørgrav 	if (result->tm_wday < 0) {
3077b5038d7SDag-Erling Smørgrav 		result->tm_wday += 7;
3087b5038d7SDag-Erling Smørgrav 	}
3097b5038d7SDag-Erling Smørgrav }
3107b5038d7SDag-Erling Smørgrav 
3117b5038d7SDag-Erling Smørgrav static struct tm *
3127b5038d7SDag-Erling Smørgrav ldns_gmtime64_r(int64_t clock, struct tm *result)
3137b5038d7SDag-Erling Smørgrav {
3147b5038d7SDag-Erling Smørgrav 	result->tm_isdst = 0;
3157b5038d7SDag-Erling Smørgrav 	result->tm_sec   = (int) LDNS_MOD(clock, 60);
3167b5038d7SDag-Erling Smørgrav 	clock            =       LDNS_DIV(clock, 60);
3177b5038d7SDag-Erling Smørgrav 	result->tm_min   = (int) LDNS_MOD(clock, 60);
3187b5038d7SDag-Erling Smørgrav 	clock            =       LDNS_DIV(clock, 60);
3197b5038d7SDag-Erling Smørgrav 	result->tm_hour  = (int) LDNS_MOD(clock, 24);
3207b5038d7SDag-Erling Smørgrav 	clock            =       LDNS_DIV(clock, 24);
3217b5038d7SDag-Erling Smørgrav 
3227b5038d7SDag-Erling Smørgrav 	ldns_year_and_yday_from_days_since_epoch(clock, result);
3237b5038d7SDag-Erling Smørgrav 	ldns_mon_and_mday_from_year_and_yday(result);
3247b5038d7SDag-Erling Smørgrav 	ldns_wday_from_year_and_yday(result);
3257b5038d7SDag-Erling Smørgrav 	result->tm_year -= 1900;
3267b5038d7SDag-Erling Smørgrav 
3277b5038d7SDag-Erling Smørgrav 	return result;
3287b5038d7SDag-Erling Smørgrav }
3297b5038d7SDag-Erling Smørgrav 
3307b5038d7SDag-Erling Smørgrav #endif /* SIZEOF_TIME_T <= 4 */
3317b5038d7SDag-Erling Smørgrav 
3327b5038d7SDag-Erling Smørgrav static int64_t
3337b5038d7SDag-Erling Smørgrav ldns_serial_arithmitics_time(int32_t time, time_t now)
3347b5038d7SDag-Erling Smørgrav {
3357b5038d7SDag-Erling Smørgrav 	int32_t offset = time - (int32_t) now;
3367b5038d7SDag-Erling Smørgrav 	return (int64_t) now + offset;
3377b5038d7SDag-Erling Smørgrav }
3387b5038d7SDag-Erling Smørgrav 
3397b5038d7SDag-Erling Smørgrav 
3407b5038d7SDag-Erling Smørgrav struct tm *
3417b5038d7SDag-Erling Smørgrav ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
3427b5038d7SDag-Erling Smørgrav {
3437b5038d7SDag-Erling Smørgrav #if SIZEOF_TIME_T <= 4
3447b5038d7SDag-Erling Smørgrav 	int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now);
3457b5038d7SDag-Erling Smørgrav 	return  ldns_gmtime64_r(secs_since_epoch, result);
3467b5038d7SDag-Erling Smørgrav #else
3477b5038d7SDag-Erling Smørgrav 	time_t  secs_since_epoch = ldns_serial_arithmitics_time(time, now);
3487b5038d7SDag-Erling Smørgrav 	return  gmtime_r(&secs_since_epoch, result);
3497b5038d7SDag-Erling Smørgrav #endif
3507b5038d7SDag-Erling Smørgrav }
3517b5038d7SDag-Erling Smørgrav 
3527b5038d7SDag-Erling Smørgrav /**
3537b5038d7SDag-Erling Smørgrav  * Init the random source
3547b5038d7SDag-Erling Smørgrav  * applications should call this if they need entropy data within ldns
3557b5038d7SDag-Erling Smørgrav  * If openSSL is available, it is automatically seeded from /dev/urandom
3567b5038d7SDag-Erling Smørgrav  * or /dev/random
3577b5038d7SDag-Erling Smørgrav  *
3587b5038d7SDag-Erling Smørgrav  * If you need more entropy, or have no openssl available, this function
3597b5038d7SDag-Erling Smørgrav  * MUST be called at the start of the program
3607b5038d7SDag-Erling Smørgrav  *
3617b5038d7SDag-Erling Smørgrav  * If openssl *is* available, this function just adds more entropy
3627b5038d7SDag-Erling Smørgrav  **/
3637b5038d7SDag-Erling Smørgrav int
3647b5038d7SDag-Erling Smørgrav ldns_init_random(FILE *fd, unsigned int size)
3657b5038d7SDag-Erling Smørgrav {
3667b5038d7SDag-Erling Smørgrav 	/* if fp is given, seed srandom with data from file
3677b5038d7SDag-Erling Smørgrav 	   otherwise use /dev/urandom */
3687b5038d7SDag-Erling Smørgrav 	FILE *rand_f;
3697b5038d7SDag-Erling Smørgrav 	uint8_t *seed;
3707b5038d7SDag-Erling Smørgrav 	size_t read = 0;
3717b5038d7SDag-Erling Smørgrav 	unsigned int seed_i;
3727b5038d7SDag-Erling Smørgrav 	struct timeval tv;
3737b5038d7SDag-Erling Smørgrav 
3747b5038d7SDag-Erling Smørgrav 	/* we'll need at least sizeof(unsigned int) bytes for the
3757b5038d7SDag-Erling Smørgrav 	   standard prng seed */
3767b5038d7SDag-Erling Smørgrav 	if (size < (unsigned int) sizeof(seed_i)){
3777b5038d7SDag-Erling Smørgrav 		size = (unsigned int) sizeof(seed_i);
3787b5038d7SDag-Erling Smørgrav 	}
3797b5038d7SDag-Erling Smørgrav 
3807b5038d7SDag-Erling Smørgrav 	seed = LDNS_XMALLOC(uint8_t, size);
3817b5038d7SDag-Erling Smørgrav         if(!seed) {
3827b5038d7SDag-Erling Smørgrav 		return 1;
3837b5038d7SDag-Erling Smørgrav         }
3847b5038d7SDag-Erling Smørgrav 
3857b5038d7SDag-Erling Smørgrav 	if (!fd) {
3867b5038d7SDag-Erling Smørgrav 		if ((rand_f = fopen("/dev/urandom", "r")) == NULL) {
3877b5038d7SDag-Erling Smørgrav 			/* no readable /dev/urandom, try /dev/random */
3887b5038d7SDag-Erling Smørgrav 			if ((rand_f = fopen("/dev/random", "r")) == NULL) {
3897b5038d7SDag-Erling Smørgrav 				/* no readable /dev/random either, and no entropy
3907b5038d7SDag-Erling Smørgrav 				   source given. we'll have to improvise */
3917b5038d7SDag-Erling Smørgrav 				for (read = 0; read < size; read++) {
3927b5038d7SDag-Erling Smørgrav 					gettimeofday(&tv, NULL);
3937b5038d7SDag-Erling Smørgrav 					seed[read] = (uint8_t) (tv.tv_usec % 256);
3947b5038d7SDag-Erling Smørgrav 				}
3957b5038d7SDag-Erling Smørgrav 			} else {
3967b5038d7SDag-Erling Smørgrav 				read = fread(seed, 1, size, rand_f);
3977b5038d7SDag-Erling Smørgrav 			}
3987b5038d7SDag-Erling Smørgrav 		} else {
3997b5038d7SDag-Erling Smørgrav 			read = fread(seed, 1, size, rand_f);
4007b5038d7SDag-Erling Smørgrav 		}
4017b5038d7SDag-Erling Smørgrav 	} else {
4027b5038d7SDag-Erling Smørgrav 		rand_f = fd;
4037b5038d7SDag-Erling Smørgrav 		read = fread(seed, 1, size, rand_f);
4047b5038d7SDag-Erling Smørgrav 	}
4057b5038d7SDag-Erling Smørgrav 
4067b5038d7SDag-Erling Smørgrav 	if (read < size) {
4077b5038d7SDag-Erling Smørgrav 		LDNS_FREE(seed);
408*2787e39aSDag-Erling Smørgrav 		if (!fd) fclose(rand_f);
4097b5038d7SDag-Erling Smørgrav 		return 1;
4107b5038d7SDag-Erling Smørgrav 	} else {
4117b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
4127b5038d7SDag-Erling Smørgrav 		/* Seed the OpenSSL prng (most systems have it seeded
4137b5038d7SDag-Erling Smørgrav 		   automatically, in that case this call just adds entropy */
4147b5038d7SDag-Erling Smørgrav 		RAND_seed(seed, (int) size);
4157b5038d7SDag-Erling Smørgrav #else
4167b5038d7SDag-Erling Smørgrav 		/* Seed the standard prng, only uses the first
4177b5038d7SDag-Erling Smørgrav 		 * unsigned sizeof(unsiged int) bytes found in the entropy pool
4187b5038d7SDag-Erling Smørgrav 		 */
4197b5038d7SDag-Erling Smørgrav 		memcpy(&seed_i, seed, sizeof(seed_i));
4207b5038d7SDag-Erling Smørgrav 		srandom(seed_i);
4217b5038d7SDag-Erling Smørgrav #endif
4227b5038d7SDag-Erling Smørgrav 		LDNS_FREE(seed);
4237b5038d7SDag-Erling Smørgrav 	}
4247b5038d7SDag-Erling Smørgrav 
4257b5038d7SDag-Erling Smørgrav 	if (!fd) {
4267b5038d7SDag-Erling Smørgrav                 if (rand_f) fclose(rand_f);
4277b5038d7SDag-Erling Smørgrav 	}
4287b5038d7SDag-Erling Smørgrav 
4297b5038d7SDag-Erling Smørgrav 	return 0;
4307b5038d7SDag-Erling Smørgrav }
4317b5038d7SDag-Erling Smørgrav 
4327b5038d7SDag-Erling Smørgrav /**
4337b5038d7SDag-Erling Smørgrav  * Get random number.
4347b5038d7SDag-Erling Smørgrav  *
4357b5038d7SDag-Erling Smørgrav  */
4367b5038d7SDag-Erling Smørgrav uint16_t
4377b5038d7SDag-Erling Smørgrav ldns_get_random(void)
4387b5038d7SDag-Erling Smørgrav {
4397b5038d7SDag-Erling Smørgrav         uint16_t rid = 0;
4407b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
4417b5038d7SDag-Erling Smørgrav         if (RAND_bytes((unsigned char*)&rid, 2) != 1) {
4427b5038d7SDag-Erling Smørgrav                 rid = (uint16_t) random();
4437b5038d7SDag-Erling Smørgrav         }
4447b5038d7SDag-Erling Smørgrav #else
4457b5038d7SDag-Erling Smørgrav         rid = (uint16_t) random();
4467b5038d7SDag-Erling Smørgrav #endif
4477b5038d7SDag-Erling Smørgrav 	return rid;
4487b5038d7SDag-Erling Smørgrav }
4497b5038d7SDag-Erling Smørgrav 
4507b5038d7SDag-Erling Smørgrav /*
4517b5038d7SDag-Erling Smørgrav  * BubbleBabble code taken from OpenSSH
4527b5038d7SDag-Erling Smørgrav  * Copyright (c) 2001 Carsten Raskgaard.  All rights reserved.
4537b5038d7SDag-Erling Smørgrav  */
4547b5038d7SDag-Erling Smørgrav char *
4557b5038d7SDag-Erling Smørgrav ldns_bubblebabble(uint8_t *data, size_t len)
4567b5038d7SDag-Erling Smørgrav {
4577b5038d7SDag-Erling Smørgrav 	char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
4587b5038d7SDag-Erling Smørgrav 	char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
4597b5038d7SDag-Erling Smørgrav 	    'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
4607b5038d7SDag-Erling Smørgrav 	size_t i, j = 0, rounds, seed = 1;
4617b5038d7SDag-Erling Smørgrav 	char *retval;
4627b5038d7SDag-Erling Smørgrav 
4637b5038d7SDag-Erling Smørgrav 	rounds = (len / 2) + 1;
4647b5038d7SDag-Erling Smørgrav 	retval = LDNS_XMALLOC(char, rounds * 6);
4657b5038d7SDag-Erling Smørgrav 	if(!retval) return NULL;
4667b5038d7SDag-Erling Smørgrav 	retval[j++] = 'x';
4677b5038d7SDag-Erling Smørgrav 	for (i = 0; i < rounds; i++) {
4687b5038d7SDag-Erling Smørgrav 		size_t idx0, idx1, idx2, idx3, idx4;
4697b5038d7SDag-Erling Smørgrav 		if ((i + 1 < rounds) || (len % 2 != 0)) {
4707b5038d7SDag-Erling Smørgrav 			idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) +
4717b5038d7SDag-Erling Smørgrav 			    seed) % 6;
4727b5038d7SDag-Erling Smørgrav 			idx1 = (((size_t)(data[2 * i])) >> 2) & 15;
4737b5038d7SDag-Erling Smørgrav 			idx2 = ((((size_t)(data[2 * i])) & 3) +
4747b5038d7SDag-Erling Smørgrav 			    (seed / 6)) % 6;
4757b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
4767b5038d7SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
4777b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
4787b5038d7SDag-Erling Smørgrav 			if ((i + 1) < rounds) {
4797b5038d7SDag-Erling Smørgrav 				idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15;
4807b5038d7SDag-Erling Smørgrav 				idx4 = (((size_t)(data[(2 * i) + 1]))) & 15;
4817b5038d7SDag-Erling Smørgrav 				retval[j++] = consonants[idx3];
4827b5038d7SDag-Erling Smørgrav 				retval[j++] = '-';
4837b5038d7SDag-Erling Smørgrav 				retval[j++] = consonants[idx4];
4847b5038d7SDag-Erling Smørgrav 				seed = ((seed * 5) +
4857b5038d7SDag-Erling Smørgrav 				    ((((size_t)(data[2 * i])) * 7) +
4867b5038d7SDag-Erling Smørgrav 				    ((size_t)(data[(2 * i) + 1])))) % 36;
4877b5038d7SDag-Erling Smørgrav 			}
4887b5038d7SDag-Erling Smørgrav 		} else {
4897b5038d7SDag-Erling Smørgrav 			idx0 = seed % 6;
4907b5038d7SDag-Erling Smørgrav 			idx1 = 16;
4917b5038d7SDag-Erling Smørgrav 			idx2 = seed / 6;
4927b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
4937b5038d7SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
4947b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
4957b5038d7SDag-Erling Smørgrav 		}
4967b5038d7SDag-Erling Smørgrav 	}
4977b5038d7SDag-Erling Smørgrav 	retval[j++] = 'x';
4987b5038d7SDag-Erling Smørgrav 	retval[j++] = '\0';
4997b5038d7SDag-Erling Smørgrav 	return retval;
5007b5038d7SDag-Erling Smørgrav }
501