xref: /freebsd/contrib/ldns/util.c (revision 986ba33c7a3bc8f5ba13c7a9d6512602f6e32c61)
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>
2317d15b25SDag-Erling Smørgrav #include <ctype.h>
247b5038d7SDag-Erling Smørgrav 
257b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
267b5038d7SDag-Erling Smørgrav #include <openssl/rand.h>
277b5038d7SDag-Erling Smørgrav #endif
287b5038d7SDag-Erling Smørgrav 
297b5038d7SDag-Erling Smørgrav ldns_lookup_table *
307b5038d7SDag-Erling Smørgrav ldns_lookup_by_name(ldns_lookup_table *table, const char *name)
317b5038d7SDag-Erling Smørgrav {
327b5038d7SDag-Erling Smørgrav 	while (table->name != NULL) {
337b5038d7SDag-Erling Smørgrav 		if (strcasecmp(name, table->name) == 0)
347b5038d7SDag-Erling Smørgrav 			return table;
357b5038d7SDag-Erling Smørgrav 		table++;
367b5038d7SDag-Erling Smørgrav 	}
377b5038d7SDag-Erling Smørgrav 	return NULL;
387b5038d7SDag-Erling Smørgrav }
397b5038d7SDag-Erling Smørgrav 
407b5038d7SDag-Erling Smørgrav ldns_lookup_table *
417b5038d7SDag-Erling Smørgrav ldns_lookup_by_id(ldns_lookup_table *table, int id)
427b5038d7SDag-Erling Smørgrav {
437b5038d7SDag-Erling Smørgrav 	while (table->name != NULL) {
447b5038d7SDag-Erling Smørgrav 		if (table->id == id)
457b5038d7SDag-Erling Smørgrav 			return table;
467b5038d7SDag-Erling Smørgrav 		table++;
477b5038d7SDag-Erling Smørgrav 	}
487b5038d7SDag-Erling Smørgrav 	return NULL;
497b5038d7SDag-Erling Smørgrav }
507b5038d7SDag-Erling Smørgrav 
517b5038d7SDag-Erling Smørgrav int
527b5038d7SDag-Erling Smørgrav ldns_get_bit(uint8_t bits[], size_t index)
537b5038d7SDag-Erling Smørgrav {
547b5038d7SDag-Erling Smørgrav 	/*
557b5038d7SDag-Erling Smørgrav 	 * The bits are counted from left to right, so bit #0 is the
567b5038d7SDag-Erling Smørgrav 	 * left most bit.
577b5038d7SDag-Erling Smørgrav 	 */
587b5038d7SDag-Erling Smørgrav 	return (int) (bits[index / 8] & (1 << (7 - index % 8)));
597b5038d7SDag-Erling Smørgrav }
607b5038d7SDag-Erling Smørgrav 
617b5038d7SDag-Erling Smørgrav int
627b5038d7SDag-Erling Smørgrav ldns_get_bit_r(uint8_t bits[], size_t index)
637b5038d7SDag-Erling Smørgrav {
647b5038d7SDag-Erling Smørgrav 	/*
657b5038d7SDag-Erling Smørgrav 	 * The bits are counted from right to left, so bit #0 is the
667b5038d7SDag-Erling Smørgrav 	 * right most bit.
677b5038d7SDag-Erling Smørgrav 	 */
687b5038d7SDag-Erling Smørgrav 	return (int) bits[index / 8] & (1 << (index % 8));
697b5038d7SDag-Erling Smørgrav }
707b5038d7SDag-Erling Smørgrav 
717b5038d7SDag-Erling Smørgrav void
727b5038d7SDag-Erling Smørgrav ldns_set_bit(uint8_t *byte, int bit_nr, bool value)
737b5038d7SDag-Erling Smørgrav {
747b5038d7SDag-Erling Smørgrav 	/*
757b5038d7SDag-Erling Smørgrav 	 * The bits are counted from right to left, so bit #0 is the
767b5038d7SDag-Erling Smørgrav 	 * right most bit.
777b5038d7SDag-Erling Smørgrav 	 */
787b5038d7SDag-Erling Smørgrav 	if (bit_nr >= 0 && bit_nr < 8) {
797b5038d7SDag-Erling Smørgrav 		if (value) {
807b5038d7SDag-Erling Smørgrav 			*byte = *byte | (0x01 << bit_nr);
817b5038d7SDag-Erling Smørgrav 		} else {
827b5038d7SDag-Erling Smørgrav 			*byte = *byte & ~(0x01 << bit_nr);
837b5038d7SDag-Erling Smørgrav 		}
847b5038d7SDag-Erling Smørgrav 	}
857b5038d7SDag-Erling Smørgrav }
867b5038d7SDag-Erling Smørgrav 
877b5038d7SDag-Erling Smørgrav int
887b5038d7SDag-Erling Smørgrav ldns_hexdigit_to_int(char ch)
897b5038d7SDag-Erling Smørgrav {
907b5038d7SDag-Erling Smørgrav 	switch (ch) {
917b5038d7SDag-Erling Smørgrav 	case '0': return 0;
927b5038d7SDag-Erling Smørgrav 	case '1': return 1;
937b5038d7SDag-Erling Smørgrav 	case '2': return 2;
947b5038d7SDag-Erling Smørgrav 	case '3': return 3;
957b5038d7SDag-Erling Smørgrav 	case '4': return 4;
967b5038d7SDag-Erling Smørgrav 	case '5': return 5;
977b5038d7SDag-Erling Smørgrav 	case '6': return 6;
987b5038d7SDag-Erling Smørgrav 	case '7': return 7;
997b5038d7SDag-Erling Smørgrav 	case '8': return 8;
1007b5038d7SDag-Erling Smørgrav 	case '9': return 9;
1017b5038d7SDag-Erling Smørgrav 	case 'a': case 'A': return 10;
1027b5038d7SDag-Erling Smørgrav 	case 'b': case 'B': return 11;
1037b5038d7SDag-Erling Smørgrav 	case 'c': case 'C': return 12;
1047b5038d7SDag-Erling Smørgrav 	case 'd': case 'D': return 13;
1057b5038d7SDag-Erling Smørgrav 	case 'e': case 'E': return 14;
1067b5038d7SDag-Erling Smørgrav 	case 'f': case 'F': return 15;
1077b5038d7SDag-Erling Smørgrav 	default:
1087b5038d7SDag-Erling Smørgrav 		return -1;
1097b5038d7SDag-Erling Smørgrav 	}
1107b5038d7SDag-Erling Smørgrav }
1117b5038d7SDag-Erling Smørgrav 
1127b5038d7SDag-Erling Smørgrav char
1137b5038d7SDag-Erling Smørgrav ldns_int_to_hexdigit(int i)
1147b5038d7SDag-Erling Smørgrav {
1157b5038d7SDag-Erling Smørgrav 	switch (i) {
1167b5038d7SDag-Erling Smørgrav 	case 0: return '0';
1177b5038d7SDag-Erling Smørgrav 	case 1: return '1';
1187b5038d7SDag-Erling Smørgrav 	case 2: return '2';
1197b5038d7SDag-Erling Smørgrav 	case 3: return '3';
1207b5038d7SDag-Erling Smørgrav 	case 4: return '4';
1217b5038d7SDag-Erling Smørgrav 	case 5: return '5';
1227b5038d7SDag-Erling Smørgrav 	case 6: return '6';
1237b5038d7SDag-Erling Smørgrav 	case 7: return '7';
1247b5038d7SDag-Erling Smørgrav 	case 8: return '8';
1257b5038d7SDag-Erling Smørgrav 	case 9: return '9';
1267b5038d7SDag-Erling Smørgrav 	case 10: return 'a';
1277b5038d7SDag-Erling Smørgrav 	case 11: return 'b';
1287b5038d7SDag-Erling Smørgrav 	case 12: return 'c';
1297b5038d7SDag-Erling Smørgrav 	case 13: return 'd';
1307b5038d7SDag-Erling Smørgrav 	case 14: return 'e';
1317b5038d7SDag-Erling Smørgrav 	case 15: return 'f';
1327b5038d7SDag-Erling Smørgrav 	default:
1337b5038d7SDag-Erling Smørgrav 		abort();
1347b5038d7SDag-Erling Smørgrav 	}
1357b5038d7SDag-Erling Smørgrav }
1367b5038d7SDag-Erling Smørgrav 
1377b5038d7SDag-Erling Smørgrav int
1387b5038d7SDag-Erling Smørgrav ldns_hexstring_to_data(uint8_t *data, const char *str)
1397b5038d7SDag-Erling Smørgrav {
1407b5038d7SDag-Erling Smørgrav 	size_t i;
1417b5038d7SDag-Erling Smørgrav 
1427b5038d7SDag-Erling Smørgrav 	if (!str || !data) {
1437b5038d7SDag-Erling Smørgrav 		return -1;
1447b5038d7SDag-Erling Smørgrav 	}
1457b5038d7SDag-Erling Smørgrav 
1467b5038d7SDag-Erling Smørgrav 	if (strlen(str) % 2 != 0) {
1477b5038d7SDag-Erling Smørgrav 		return -2;
1487b5038d7SDag-Erling Smørgrav 	}
1497b5038d7SDag-Erling Smørgrav 
1507b5038d7SDag-Erling Smørgrav 	for (i = 0; i < strlen(str) / 2; i++) {
1517b5038d7SDag-Erling Smørgrav 		data[i] =
1527b5038d7SDag-Erling Smørgrav 			16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) +
1537b5038d7SDag-Erling Smørgrav 			(uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]);
1547b5038d7SDag-Erling Smørgrav 	}
1557b5038d7SDag-Erling Smørgrav 
1567b5038d7SDag-Erling Smørgrav 	return (int) i;
1577b5038d7SDag-Erling Smørgrav }
1587b5038d7SDag-Erling Smørgrav 
1597b5038d7SDag-Erling Smørgrav const char *
1607b5038d7SDag-Erling Smørgrav ldns_version(void)
1617b5038d7SDag-Erling Smørgrav {
1627b5038d7SDag-Erling Smørgrav 	return (char*)LDNS_VERSION;
1637b5038d7SDag-Erling Smørgrav }
1647b5038d7SDag-Erling Smørgrav 
1657b5038d7SDag-Erling Smørgrav /* Number of days per month (except for February in leap years). */
1667b5038d7SDag-Erling Smørgrav static const int mdays[] = {
1677b5038d7SDag-Erling Smørgrav 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1687b5038d7SDag-Erling Smørgrav };
1697b5038d7SDag-Erling Smørgrav 
1707b5038d7SDag-Erling Smørgrav #define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y)))
1717b5038d7SDag-Erling Smørgrav #define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) -  1 ) : ((x) / (y)))
1727b5038d7SDag-Erling Smørgrav 
1737b5038d7SDag-Erling Smørgrav static int
1747b5038d7SDag-Erling Smørgrav is_leap_year(int year)
1757b5038d7SDag-Erling Smørgrav {
1767b5038d7SDag-Erling Smørgrav 	return LDNS_MOD(year,   4) == 0 && (LDNS_MOD(year, 100) != 0
1777b5038d7SDag-Erling Smørgrav 	    || LDNS_MOD(year, 400) == 0);
1787b5038d7SDag-Erling Smørgrav }
1797b5038d7SDag-Erling Smørgrav 
1807b5038d7SDag-Erling Smørgrav static int
1817b5038d7SDag-Erling Smørgrav leap_days(int y1, int y2)
1827b5038d7SDag-Erling Smørgrav {
1837b5038d7SDag-Erling Smørgrav 	--y1;
1847b5038d7SDag-Erling Smørgrav 	--y2;
1857b5038d7SDag-Erling Smørgrav 	return (LDNS_DIV(y2,   4) - LDNS_DIV(y1,   4)) -
1867b5038d7SDag-Erling Smørgrav 	       (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) +
1877b5038d7SDag-Erling Smørgrav 	       (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400));
1887b5038d7SDag-Erling Smørgrav }
1897b5038d7SDag-Erling Smørgrav 
1907b5038d7SDag-Erling Smørgrav /*
1917b5038d7SDag-Erling Smørgrav  * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
1927b5038d7SDag-Erling Smørgrav  */
1937b5038d7SDag-Erling Smørgrav time_t
1942787e39aSDag-Erling Smørgrav ldns_mktime_from_utc(const struct tm *tm)
1957b5038d7SDag-Erling Smørgrav {
1967b5038d7SDag-Erling Smørgrav 	int year = 1900 + tm->tm_year;
1977b5038d7SDag-Erling Smørgrav 	time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year);
1987b5038d7SDag-Erling Smørgrav 	time_t hours;
1997b5038d7SDag-Erling Smørgrav 	time_t minutes;
2007b5038d7SDag-Erling Smørgrav 	time_t seconds;
2017b5038d7SDag-Erling Smørgrav 	int i;
2027b5038d7SDag-Erling Smørgrav 
2037b5038d7SDag-Erling Smørgrav 	for (i = 0; i < tm->tm_mon; ++i) {
2047b5038d7SDag-Erling Smørgrav 		days += mdays[i];
2057b5038d7SDag-Erling Smørgrav 	}
2067b5038d7SDag-Erling Smørgrav 	if (tm->tm_mon > 1 && is_leap_year(year)) {
2077b5038d7SDag-Erling Smørgrav 		++days;
2087b5038d7SDag-Erling Smørgrav 	}
2097b5038d7SDag-Erling Smørgrav 	days += tm->tm_mday - 1;
2107b5038d7SDag-Erling Smørgrav 
2117b5038d7SDag-Erling Smørgrav 	hours = days * 24 + tm->tm_hour;
2127b5038d7SDag-Erling Smørgrav 	minutes = hours * 60 + tm->tm_min;
2137b5038d7SDag-Erling Smørgrav 	seconds = minutes * 60 + tm->tm_sec;
2147b5038d7SDag-Erling Smørgrav 
2157b5038d7SDag-Erling Smørgrav 	return seconds;
2167b5038d7SDag-Erling Smørgrav }
2177b5038d7SDag-Erling Smørgrav 
2182787e39aSDag-Erling Smørgrav time_t
2192787e39aSDag-Erling Smørgrav mktime_from_utc(const struct tm *tm)
2202787e39aSDag-Erling Smørgrav {
2212787e39aSDag-Erling Smørgrav 	return ldns_mktime_from_utc(tm);
2222787e39aSDag-Erling Smørgrav }
2232787e39aSDag-Erling Smørgrav 
2247b5038d7SDag-Erling Smørgrav #if SIZEOF_TIME_T <= 4
2257b5038d7SDag-Erling Smørgrav 
2267b5038d7SDag-Erling Smørgrav static void
2277b5038d7SDag-Erling Smørgrav ldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result)
2287b5038d7SDag-Erling Smørgrav {
2297b5038d7SDag-Erling Smørgrav 	int year = 1970;
2307b5038d7SDag-Erling Smørgrav 	int new_year;
2317b5038d7SDag-Erling Smørgrav 
2327b5038d7SDag-Erling Smørgrav 	while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) {
2337b5038d7SDag-Erling Smørgrav 		new_year = year + (int) LDNS_DIV(days, 365);
2347b5038d7SDag-Erling Smørgrav 		days -= (new_year - year) * 365;
2357b5038d7SDag-Erling Smørgrav 		days -= leap_days(year, new_year);
2367b5038d7SDag-Erling Smørgrav 		year  = new_year;
2377b5038d7SDag-Erling Smørgrav 	}
2387b5038d7SDag-Erling Smørgrav 	result->tm_year = year;
2397b5038d7SDag-Erling Smørgrav 	result->tm_yday = (int) days;
2407b5038d7SDag-Erling Smørgrav }
2417b5038d7SDag-Erling Smørgrav 
2427b5038d7SDag-Erling Smørgrav /* Number of days per month in a leap year. */
2437b5038d7SDag-Erling Smørgrav static const int leap_year_mdays[] = {
2447b5038d7SDag-Erling Smørgrav 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2457b5038d7SDag-Erling Smørgrav };
2467b5038d7SDag-Erling Smørgrav 
2477b5038d7SDag-Erling Smørgrav static void
2487b5038d7SDag-Erling Smørgrav ldns_mon_and_mday_from_year_and_yday(struct tm *result)
2497b5038d7SDag-Erling Smørgrav {
2507b5038d7SDag-Erling Smørgrav 	int idays = result->tm_yday;
2517b5038d7SDag-Erling Smørgrav 	const int *mon_lengths = is_leap_year(result->tm_year) ?
2527b5038d7SDag-Erling Smørgrav 					leap_year_mdays : mdays;
2537b5038d7SDag-Erling Smørgrav 
2547b5038d7SDag-Erling Smørgrav 	result->tm_mon = 0;
2557b5038d7SDag-Erling Smørgrav 	while  (idays >= mon_lengths[result->tm_mon]) {
2567b5038d7SDag-Erling Smørgrav 		idays -= mon_lengths[result->tm_mon++];
2577b5038d7SDag-Erling Smørgrav 	}
2587b5038d7SDag-Erling Smørgrav 	result->tm_mday = idays + 1;
2597b5038d7SDag-Erling Smørgrav }
2607b5038d7SDag-Erling Smørgrav 
2617b5038d7SDag-Erling Smørgrav static void
2627b5038d7SDag-Erling Smørgrav ldns_wday_from_year_and_yday(struct tm *result)
2637b5038d7SDag-Erling Smørgrav {
2647b5038d7SDag-Erling Smørgrav 	result->tm_wday = 4 /* 1-1-1970 was a thursday */
2657b5038d7SDag-Erling Smørgrav 			+ LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7)
2667b5038d7SDag-Erling Smørgrav 			+ leap_days(1970, result->tm_year)
2677b5038d7SDag-Erling Smørgrav 			+ result->tm_yday;
2687b5038d7SDag-Erling Smørgrav 	result->tm_wday = LDNS_MOD(result->tm_wday, 7);
2697b5038d7SDag-Erling Smørgrav 	if (result->tm_wday < 0) {
2707b5038d7SDag-Erling Smørgrav 		result->tm_wday += 7;
2717b5038d7SDag-Erling Smørgrav 	}
2727b5038d7SDag-Erling Smørgrav }
2737b5038d7SDag-Erling Smørgrav 
2747b5038d7SDag-Erling Smørgrav static struct tm *
2757b5038d7SDag-Erling Smørgrav ldns_gmtime64_r(int64_t clock, struct tm *result)
2767b5038d7SDag-Erling Smørgrav {
2777b5038d7SDag-Erling Smørgrav 	result->tm_isdst = 0;
2787b5038d7SDag-Erling Smørgrav 	result->tm_sec   = (int) LDNS_MOD(clock, 60);
2797b5038d7SDag-Erling Smørgrav 	clock            =       LDNS_DIV(clock, 60);
2807b5038d7SDag-Erling Smørgrav 	result->tm_min   = (int) LDNS_MOD(clock, 60);
2817b5038d7SDag-Erling Smørgrav 	clock            =       LDNS_DIV(clock, 60);
2827b5038d7SDag-Erling Smørgrav 	result->tm_hour  = (int) LDNS_MOD(clock, 24);
2837b5038d7SDag-Erling Smørgrav 	clock            =       LDNS_DIV(clock, 24);
2847b5038d7SDag-Erling Smørgrav 
2857b5038d7SDag-Erling Smørgrav 	ldns_year_and_yday_from_days_since_epoch(clock, result);
2867b5038d7SDag-Erling Smørgrav 	ldns_mon_and_mday_from_year_and_yday(result);
2877b5038d7SDag-Erling Smørgrav 	ldns_wday_from_year_and_yday(result);
2887b5038d7SDag-Erling Smørgrav 	result->tm_year -= 1900;
2897b5038d7SDag-Erling Smørgrav 
2907b5038d7SDag-Erling Smørgrav 	return result;
2917b5038d7SDag-Erling Smørgrav }
2927b5038d7SDag-Erling Smørgrav 
2937b5038d7SDag-Erling Smørgrav #endif /* SIZEOF_TIME_T <= 4 */
2947b5038d7SDag-Erling Smørgrav 
2957b5038d7SDag-Erling Smørgrav static int64_t
2967b5038d7SDag-Erling Smørgrav ldns_serial_arithmitics_time(int32_t time, time_t now)
2977b5038d7SDag-Erling Smørgrav {
2987b5038d7SDag-Erling Smørgrav 	int32_t offset = time - (int32_t) now;
2997b5038d7SDag-Erling Smørgrav 	return (int64_t) now + offset;
3007b5038d7SDag-Erling Smørgrav }
3017b5038d7SDag-Erling Smørgrav 
3027b5038d7SDag-Erling Smørgrav 
3037b5038d7SDag-Erling Smørgrav struct tm *
3047b5038d7SDag-Erling Smørgrav ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
3057b5038d7SDag-Erling Smørgrav {
3067b5038d7SDag-Erling Smørgrav #if SIZEOF_TIME_T <= 4
3077b5038d7SDag-Erling Smørgrav 	int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now);
3087b5038d7SDag-Erling Smørgrav 	return  ldns_gmtime64_r(secs_since_epoch, result);
3097b5038d7SDag-Erling Smørgrav #else
3107b5038d7SDag-Erling Smørgrav 	time_t  secs_since_epoch = ldns_serial_arithmitics_time(time, now);
3117b5038d7SDag-Erling Smørgrav 	return  gmtime_r(&secs_since_epoch, result);
3127b5038d7SDag-Erling Smørgrav #endif
3137b5038d7SDag-Erling Smørgrav }
3147b5038d7SDag-Erling Smørgrav 
3157b5038d7SDag-Erling Smørgrav /**
3167b5038d7SDag-Erling Smørgrav  * Init the random source
3177b5038d7SDag-Erling Smørgrav  * applications should call this if they need entropy data within ldns
3187b5038d7SDag-Erling Smørgrav  * If openSSL is available, it is automatically seeded from /dev/urandom
3197b5038d7SDag-Erling Smørgrav  * or /dev/random
3207b5038d7SDag-Erling Smørgrav  *
3217b5038d7SDag-Erling Smørgrav  * If you need more entropy, or have no openssl available, this function
3227b5038d7SDag-Erling Smørgrav  * MUST be called at the start of the program
3237b5038d7SDag-Erling Smørgrav  *
3247b5038d7SDag-Erling Smørgrav  * If openssl *is* available, this function just adds more entropy
3257b5038d7SDag-Erling Smørgrav  **/
3267b5038d7SDag-Erling Smørgrav int
3277b5038d7SDag-Erling Smørgrav ldns_init_random(FILE *fd, unsigned int size)
3287b5038d7SDag-Erling Smørgrav {
3297b5038d7SDag-Erling Smørgrav 	/* if fp is given, seed srandom with data from file
3307b5038d7SDag-Erling Smørgrav 	   otherwise use /dev/urandom */
3317b5038d7SDag-Erling Smørgrav 	FILE *rand_f;
3327b5038d7SDag-Erling Smørgrav 	uint8_t *seed;
3337b5038d7SDag-Erling Smørgrav 	size_t read = 0;
3347b5038d7SDag-Erling Smørgrav 	unsigned int seed_i;
3357b5038d7SDag-Erling Smørgrav 	struct timeval tv;
3367b5038d7SDag-Erling Smørgrav 
3377b5038d7SDag-Erling Smørgrav 	/* we'll need at least sizeof(unsigned int) bytes for the
3387b5038d7SDag-Erling Smørgrav 	   standard prng seed */
3397b5038d7SDag-Erling Smørgrav 	if (size < (unsigned int) sizeof(seed_i)){
3407b5038d7SDag-Erling Smørgrav 		size = (unsigned int) sizeof(seed_i);
3417b5038d7SDag-Erling Smørgrav 	}
3427b5038d7SDag-Erling Smørgrav 
3437b5038d7SDag-Erling Smørgrav 	seed = LDNS_XMALLOC(uint8_t, size);
3447b5038d7SDag-Erling Smørgrav         if(!seed) {
3457b5038d7SDag-Erling Smørgrav 		return 1;
3467b5038d7SDag-Erling Smørgrav         }
3477b5038d7SDag-Erling Smørgrav 
3487b5038d7SDag-Erling Smørgrav 	if (!fd) {
3497b5038d7SDag-Erling Smørgrav 		if ((rand_f = fopen("/dev/urandom", "r")) == NULL) {
3507b5038d7SDag-Erling Smørgrav 			/* no readable /dev/urandom, try /dev/random */
3517b5038d7SDag-Erling Smørgrav 			if ((rand_f = fopen("/dev/random", "r")) == NULL) {
3527b5038d7SDag-Erling Smørgrav 				/* no readable /dev/random either, and no entropy
3537b5038d7SDag-Erling Smørgrav 				   source given. we'll have to improvise */
3547b5038d7SDag-Erling Smørgrav 				for (read = 0; read < size; read++) {
3557b5038d7SDag-Erling Smørgrav 					gettimeofday(&tv, NULL);
3567b5038d7SDag-Erling Smørgrav 					seed[read] = (uint8_t) (tv.tv_usec % 256);
3577b5038d7SDag-Erling Smørgrav 				}
3587b5038d7SDag-Erling Smørgrav 			} else {
3597b5038d7SDag-Erling Smørgrav 				read = fread(seed, 1, size, rand_f);
3607b5038d7SDag-Erling Smørgrav 			}
3617b5038d7SDag-Erling Smørgrav 		} else {
3627b5038d7SDag-Erling Smørgrav 			read = fread(seed, 1, size, rand_f);
3637b5038d7SDag-Erling Smørgrav 		}
3647b5038d7SDag-Erling Smørgrav 	} else {
3657b5038d7SDag-Erling Smørgrav 		rand_f = fd;
3667b5038d7SDag-Erling Smørgrav 		read = fread(seed, 1, size, rand_f);
3677b5038d7SDag-Erling Smørgrav 	}
3687b5038d7SDag-Erling Smørgrav 
3697b5038d7SDag-Erling Smørgrav 	if (read < size) {
3707b5038d7SDag-Erling Smørgrav 		LDNS_FREE(seed);
3712787e39aSDag-Erling Smørgrav 		if (!fd) fclose(rand_f);
3727b5038d7SDag-Erling Smørgrav 		return 1;
3737b5038d7SDag-Erling Smørgrav 	} else {
3747b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
3757b5038d7SDag-Erling Smørgrav 		/* Seed the OpenSSL prng (most systems have it seeded
3767b5038d7SDag-Erling Smørgrav 		   automatically, in that case this call just adds entropy */
3777b5038d7SDag-Erling Smørgrav 		RAND_seed(seed, (int) size);
3787b5038d7SDag-Erling Smørgrav #else
3797b5038d7SDag-Erling Smørgrav 		/* Seed the standard prng, only uses the first
3807b5038d7SDag-Erling Smørgrav 		 * unsigned sizeof(unsiged int) bytes found in the entropy pool
3817b5038d7SDag-Erling Smørgrav 		 */
3827b5038d7SDag-Erling Smørgrav 		memcpy(&seed_i, seed, sizeof(seed_i));
3837b5038d7SDag-Erling Smørgrav 		srandom(seed_i);
3847b5038d7SDag-Erling Smørgrav #endif
3857b5038d7SDag-Erling Smørgrav 		LDNS_FREE(seed);
3867b5038d7SDag-Erling Smørgrav 	}
3877b5038d7SDag-Erling Smørgrav 
3887b5038d7SDag-Erling Smørgrav 	if (!fd) {
3897b5038d7SDag-Erling Smørgrav                 if (rand_f) fclose(rand_f);
3907b5038d7SDag-Erling Smørgrav 	}
3917b5038d7SDag-Erling Smørgrav 
3927b5038d7SDag-Erling Smørgrav 	return 0;
3937b5038d7SDag-Erling Smørgrav }
3947b5038d7SDag-Erling Smørgrav 
3957b5038d7SDag-Erling Smørgrav /**
3967b5038d7SDag-Erling Smørgrav  * Get random number.
3977b5038d7SDag-Erling Smørgrav  *
3987b5038d7SDag-Erling Smørgrav  */
3997b5038d7SDag-Erling Smørgrav uint16_t
4007b5038d7SDag-Erling Smørgrav ldns_get_random(void)
4017b5038d7SDag-Erling Smørgrav {
4027b5038d7SDag-Erling Smørgrav         uint16_t rid = 0;
4037b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
4047b5038d7SDag-Erling Smørgrav         if (RAND_bytes((unsigned char*)&rid, 2) != 1) {
4057b5038d7SDag-Erling Smørgrav                 rid = (uint16_t) random();
4067b5038d7SDag-Erling Smørgrav         }
4077b5038d7SDag-Erling Smørgrav #else
4087b5038d7SDag-Erling Smørgrav         rid = (uint16_t) random();
4097b5038d7SDag-Erling Smørgrav #endif
4107b5038d7SDag-Erling Smørgrav 	return rid;
4117b5038d7SDag-Erling Smørgrav }
4127b5038d7SDag-Erling Smørgrav 
4137b5038d7SDag-Erling Smørgrav /*
4147b5038d7SDag-Erling Smørgrav  * BubbleBabble code taken from OpenSSH
4157b5038d7SDag-Erling Smørgrav  * Copyright (c) 2001 Carsten Raskgaard.  All rights reserved.
4167b5038d7SDag-Erling Smørgrav  */
4177b5038d7SDag-Erling Smørgrav char *
4187b5038d7SDag-Erling Smørgrav ldns_bubblebabble(uint8_t *data, size_t len)
4197b5038d7SDag-Erling Smørgrav {
4207b5038d7SDag-Erling Smørgrav 	char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
4217b5038d7SDag-Erling Smørgrav 	char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
4227b5038d7SDag-Erling Smørgrav 	    'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
4237b5038d7SDag-Erling Smørgrav 	size_t i, j = 0, rounds, seed = 1;
4247b5038d7SDag-Erling Smørgrav 	char *retval;
4257b5038d7SDag-Erling Smørgrav 
4267b5038d7SDag-Erling Smørgrav 	rounds = (len / 2) + 1;
4277b5038d7SDag-Erling Smørgrav 	retval = LDNS_XMALLOC(char, rounds * 6);
4287b5038d7SDag-Erling Smørgrav 	if(!retval) return NULL;
4297b5038d7SDag-Erling Smørgrav 	retval[j++] = 'x';
4307b5038d7SDag-Erling Smørgrav 	for (i = 0; i < rounds; i++) {
4317b5038d7SDag-Erling Smørgrav 		size_t idx0, idx1, idx2, idx3, idx4;
4327b5038d7SDag-Erling Smørgrav 		if ((i + 1 < rounds) || (len % 2 != 0)) {
4337b5038d7SDag-Erling Smørgrav 			idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) +
4347b5038d7SDag-Erling Smørgrav 			    seed) % 6;
4357b5038d7SDag-Erling Smørgrav 			idx1 = (((size_t)(data[2 * i])) >> 2) & 15;
4367b5038d7SDag-Erling Smørgrav 			idx2 = ((((size_t)(data[2 * i])) & 3) +
4377b5038d7SDag-Erling Smørgrav 			    (seed / 6)) % 6;
4387b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
4397b5038d7SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
4407b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
4417b5038d7SDag-Erling Smørgrav 			if ((i + 1) < rounds) {
4427b5038d7SDag-Erling Smørgrav 				idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15;
4437b5038d7SDag-Erling Smørgrav 				idx4 = (((size_t)(data[(2 * i) + 1]))) & 15;
4447b5038d7SDag-Erling Smørgrav 				retval[j++] = consonants[idx3];
4457b5038d7SDag-Erling Smørgrav 				retval[j++] = '-';
4467b5038d7SDag-Erling Smørgrav 				retval[j++] = consonants[idx4];
4477b5038d7SDag-Erling Smørgrav 				seed = ((seed * 5) +
4487b5038d7SDag-Erling Smørgrav 				    ((((size_t)(data[2 * i])) * 7) +
4497b5038d7SDag-Erling Smørgrav 				    ((size_t)(data[(2 * i) + 1])))) % 36;
4507b5038d7SDag-Erling Smørgrav 			}
4517b5038d7SDag-Erling Smørgrav 		} else {
4527b5038d7SDag-Erling Smørgrav 			idx0 = seed % 6;
4537b5038d7SDag-Erling Smørgrav 			idx1 = 16;
4547b5038d7SDag-Erling Smørgrav 			idx2 = seed / 6;
4557b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
4567b5038d7SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
4577b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
4587b5038d7SDag-Erling Smørgrav 		}
4597b5038d7SDag-Erling Smørgrav 	}
4607b5038d7SDag-Erling Smørgrav 	retval[j++] = 'x';
4617b5038d7SDag-Erling Smørgrav 	retval[j++] = '\0';
4627b5038d7SDag-Erling Smørgrav 	return retval;
4637b5038d7SDag-Erling Smørgrav }
46417d15b25SDag-Erling Smørgrav 
46517d15b25SDag-Erling Smørgrav /*
46617d15b25SDag-Erling Smørgrav  * For backwards compatibility, because we have always exported this symbol.
46717d15b25SDag-Erling Smørgrav  */
46817d15b25SDag-Erling Smørgrav #ifdef HAVE_B64_NTOP
46917d15b25SDag-Erling Smørgrav int ldns_b64_ntop(const uint8_t* src, size_t srclength,
47017d15b25SDag-Erling Smørgrav 		char *target, size_t targsize);
47117d15b25SDag-Erling Smørgrav {
47217d15b25SDag-Erling Smørgrav 	return b64_ntop(src, srclength, target, targsize);
47317d15b25SDag-Erling Smørgrav }
47417d15b25SDag-Erling Smørgrav #endif
47517d15b25SDag-Erling Smørgrav 
47617d15b25SDag-Erling Smørgrav /*
47717d15b25SDag-Erling Smørgrav  * For backwards compatibility, because we have always exported this symbol.
47817d15b25SDag-Erling Smørgrav  */
47917d15b25SDag-Erling Smørgrav #ifdef HAVE_B64_PTON
48017d15b25SDag-Erling Smørgrav int ldns_b64_pton(const char* src, uint8_t *target, size_t targsize)
48117d15b25SDag-Erling Smørgrav {
48217d15b25SDag-Erling Smørgrav 	return b64_pton(src, target, targsize);
48317d15b25SDag-Erling Smørgrav }
48417d15b25SDag-Erling Smørgrav #endif
48517d15b25SDag-Erling Smørgrav 
48617d15b25SDag-Erling Smørgrav 
48717d15b25SDag-Erling Smørgrav static int
48817d15b25SDag-Erling Smørgrav ldns_b32_ntop_base(const uint8_t* src, size_t src_sz,
48917d15b25SDag-Erling Smørgrav 		char* dst, size_t dst_sz,
49017d15b25SDag-Erling Smørgrav 		bool extended_hex, bool add_padding)
49117d15b25SDag-Erling Smørgrav {
49217d15b25SDag-Erling Smørgrav 	size_t ret_sz;
49317d15b25SDag-Erling Smørgrav 	const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv"
49417d15b25SDag-Erling Smørgrav 	                               : "abcdefghijklmnopqrstuvwxyz234567";
49517d15b25SDag-Erling Smørgrav 
49617d15b25SDag-Erling Smørgrav 	size_t c = 0; /* c is used to carry partial base32 character over
49717d15b25SDag-Erling Smørgrav 	               * byte boundaries for sizes with a remainder.
49817d15b25SDag-Erling Smørgrav 		       * (i.e. src_sz % 5 != 0)
49917d15b25SDag-Erling Smørgrav 		       */
50017d15b25SDag-Erling Smørgrav 
50117d15b25SDag-Erling Smørgrav 	ret_sz = add_padding ? ldns_b32_ntop_calculate_size(src_sz)
50217d15b25SDag-Erling Smørgrav 	                     : ldns_b32_ntop_calculate_size_no_padding(src_sz);
50317d15b25SDag-Erling Smørgrav 
50417d15b25SDag-Erling Smørgrav 	/* Do we have enough space? */
50517d15b25SDag-Erling Smørgrav 	if (dst_sz < ret_sz + 1)
50617d15b25SDag-Erling Smørgrav 		return -1;
50717d15b25SDag-Erling Smørgrav 
50817d15b25SDag-Erling Smørgrav 	/* We know the size; terminate the string */
50917d15b25SDag-Erling Smørgrav 	dst[ret_sz] = '\0';
51017d15b25SDag-Erling Smørgrav 
51117d15b25SDag-Erling Smørgrav 	/* First process all chunks of five */
51217d15b25SDag-Erling Smørgrav 	while (src_sz >= 5) {
51317d15b25SDag-Erling Smørgrav 		/* 00000... ........ ........ ........ ........ */
51417d15b25SDag-Erling Smørgrav 		dst[0] = b32[(src[0]       ) >> 3];
51517d15b25SDag-Erling Smørgrav 
51617d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
51717d15b25SDag-Erling Smørgrav 		dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6];
51817d15b25SDag-Erling Smørgrav 
51917d15b25SDag-Erling Smørgrav 		/* ........ ..22222. ........ ........ ........ */
52017d15b25SDag-Erling Smørgrav 		dst[2] = b32[(src[1] & 0x3e) >> 1];
52117d15b25SDag-Erling Smørgrav 
52217d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
52317d15b25SDag-Erling Smørgrav 		dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4];
52417d15b25SDag-Erling Smørgrav 
52517d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
52617d15b25SDag-Erling Smørgrav 		dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7];
52717d15b25SDag-Erling Smørgrav 
52817d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ .55555.. ........ */
52917d15b25SDag-Erling Smørgrav 		dst[5] = b32[(src[3] & 0x7c) >> 2];
53017d15b25SDag-Erling Smørgrav 
53117d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ......66 666..... */
53217d15b25SDag-Erling Smørgrav 		dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5];
53317d15b25SDag-Erling Smørgrav 
53417d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ........ ...77777 */
53517d15b25SDag-Erling Smørgrav 		dst[7] = b32[(src[4] & 0x1f)     ];
53617d15b25SDag-Erling Smørgrav 
53717d15b25SDag-Erling Smørgrav 		src_sz -= 5;
53817d15b25SDag-Erling Smørgrav 		src    += 5;
53917d15b25SDag-Erling Smørgrav 		dst    += 8;
54017d15b25SDag-Erling Smørgrav 	}
54117d15b25SDag-Erling Smørgrav 	/* Process what remains */
54217d15b25SDag-Erling Smørgrav 	switch (src_sz) {
54317d15b25SDag-Erling Smørgrav 	case 4: /* ........ ........ ........ ......66 666..... */
54417d15b25SDag-Erling Smørgrav 		dst[6] = b32[(src[3] & 0x03) << 3];
54517d15b25SDag-Erling Smørgrav 
54617d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ .55555.. ........ */
54717d15b25SDag-Erling Smørgrav 		dst[5] = b32[(src[3] & 0x7c) >> 2];
54817d15b25SDag-Erling Smørgrav 
54917d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
55017d15b25SDag-Erling Smørgrav 		         c =  src[3]         >> 7 ;
55117d15b25SDag-Erling Smørgrav 	case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c];
55217d15b25SDag-Erling Smørgrav 
55317d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
55417d15b25SDag-Erling Smørgrav 			 c =  src[2]         >> 4 ;
55517d15b25SDag-Erling Smørgrav 	case 2:	dst[3] = b32[(src[1] & 0x01) << 4 | c];
55617d15b25SDag-Erling Smørgrav 
55717d15b25SDag-Erling Smørgrav 		/* ........ ..22222. ........ ........ ........ */
55817d15b25SDag-Erling Smørgrav 		dst[2] = b32[(src[1] & 0x3e) >> 1];
55917d15b25SDag-Erling Smørgrav 
56017d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
56117d15b25SDag-Erling Smørgrav 	                 c =  src[1]         >> 6 ;
56217d15b25SDag-Erling Smørgrav 	case 1:	dst[1] = b32[(src[0] & 0x07) << 2 | c];
56317d15b25SDag-Erling Smørgrav 
56417d15b25SDag-Erling Smørgrav 		/* 00000... ........ ........ ........ ........ */
56517d15b25SDag-Erling Smørgrav 		dst[0] = b32[ src[0]         >> 3];
56617d15b25SDag-Erling Smørgrav 	}
56717d15b25SDag-Erling Smørgrav 	/* Add padding */
56817d15b25SDag-Erling Smørgrav 	if (add_padding) {
56917d15b25SDag-Erling Smørgrav 		switch (src_sz) {
57017d15b25SDag-Erling Smørgrav 			case 1: dst[2] = '=';
57117d15b25SDag-Erling Smørgrav 				dst[3] = '=';
57217d15b25SDag-Erling Smørgrav 			case 2: dst[4] = '=';
57317d15b25SDag-Erling Smørgrav 			case 3: dst[5] = '=';
57417d15b25SDag-Erling Smørgrav 				dst[6] = '=';
57517d15b25SDag-Erling Smørgrav 			case 4: dst[7] = '=';
57617d15b25SDag-Erling Smørgrav 		}
57717d15b25SDag-Erling Smørgrav 	}
57817d15b25SDag-Erling Smørgrav 	return (int)ret_sz;
57917d15b25SDag-Erling Smørgrav }
58017d15b25SDag-Erling Smørgrav 
58117d15b25SDag-Erling Smørgrav int
58217d15b25SDag-Erling Smørgrav ldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
58317d15b25SDag-Erling Smørgrav {
58417d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true);
58517d15b25SDag-Erling Smørgrav }
58617d15b25SDag-Erling Smørgrav 
58717d15b25SDag-Erling Smørgrav int
58817d15b25SDag-Erling Smørgrav ldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
58917d15b25SDag-Erling Smørgrav 		char* dst, size_t dst_sz)
59017d15b25SDag-Erling Smørgrav {
59117d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true);
59217d15b25SDag-Erling Smørgrav }
59317d15b25SDag-Erling Smørgrav 
59417d15b25SDag-Erling Smørgrav #ifndef HAVE_B32_NTOP
59517d15b25SDag-Erling Smørgrav 
59617d15b25SDag-Erling Smørgrav int
59717d15b25SDag-Erling Smørgrav b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
59817d15b25SDag-Erling Smørgrav {
59917d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true);
60017d15b25SDag-Erling Smørgrav }
60117d15b25SDag-Erling Smørgrav 
60217d15b25SDag-Erling Smørgrav int
60317d15b25SDag-Erling Smørgrav b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
60417d15b25SDag-Erling Smørgrav 		char* dst, size_t dst_sz)
60517d15b25SDag-Erling Smørgrav {
60617d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true);
60717d15b25SDag-Erling Smørgrav }
60817d15b25SDag-Erling Smørgrav 
60917d15b25SDag-Erling Smørgrav #endif /* ! HAVE_B32_NTOP */
61017d15b25SDag-Erling Smørgrav 
61117d15b25SDag-Erling Smørgrav static int
61217d15b25SDag-Erling Smørgrav ldns_b32_pton_base(const char* src, size_t src_sz,
61317d15b25SDag-Erling Smørgrav 		uint8_t* dst, size_t dst_sz,
61417d15b25SDag-Erling Smørgrav 		bool extended_hex, bool check_padding)
61517d15b25SDag-Erling Smørgrav {
61617d15b25SDag-Erling Smørgrav 	size_t i = 0;
61717d15b25SDag-Erling Smørgrav 	char ch = '\0';
61817d15b25SDag-Erling Smørgrav 	uint8_t buf[8];
61917d15b25SDag-Erling Smørgrav 	uint8_t* start = dst;
62017d15b25SDag-Erling Smørgrav 
62117d15b25SDag-Erling Smørgrav 	while (src_sz) {
62217d15b25SDag-Erling Smørgrav 		/* Collect 8 characters in buf (if possible) */
62317d15b25SDag-Erling Smørgrav 		for (i = 0; i < 8; i++) {
62417d15b25SDag-Erling Smørgrav 
62517d15b25SDag-Erling Smørgrav 			do {
62617d15b25SDag-Erling Smørgrav 				ch = *src++;
62717d15b25SDag-Erling Smørgrav 				--src_sz;
62817d15b25SDag-Erling Smørgrav 
629*986ba33cSDag-Erling Smørgrav 			} while (isspace((unsigned char)ch) && src_sz > 0);
63017d15b25SDag-Erling Smørgrav 
63117d15b25SDag-Erling Smørgrav 			if (ch == '=' || ch == '\0')
63217d15b25SDag-Erling Smørgrav 				break;
63317d15b25SDag-Erling Smørgrav 
63417d15b25SDag-Erling Smørgrav 			else if (extended_hex)
63517d15b25SDag-Erling Smørgrav 
63617d15b25SDag-Erling Smørgrav 				if (ch >= '0' && ch <= '9')
63717d15b25SDag-Erling Smørgrav 					buf[i] = (uint8_t)ch - '0';
63817d15b25SDag-Erling Smørgrav 				else if (ch >= 'a' && ch <= 'v')
63917d15b25SDag-Erling Smørgrav 					buf[i] = (uint8_t)ch - 'a' + 10;
64017d15b25SDag-Erling Smørgrav 				else if (ch >= 'A' && ch <= 'V')
64117d15b25SDag-Erling Smørgrav 					buf[i] = (uint8_t)ch - 'A' + 10;
64217d15b25SDag-Erling Smørgrav 				else
64317d15b25SDag-Erling Smørgrav 					return -1;
64417d15b25SDag-Erling Smørgrav 
64517d15b25SDag-Erling Smørgrav 			else if (ch >= 'a' && ch <= 'z')
64617d15b25SDag-Erling Smørgrav 				buf[i] = (uint8_t)ch - 'a';
64717d15b25SDag-Erling Smørgrav 			else if (ch >= 'A' && ch <= 'Z')
64817d15b25SDag-Erling Smørgrav 				buf[i] = (uint8_t)ch - 'A';
64917d15b25SDag-Erling Smørgrav 			else if (ch >= '2' && ch <= '7')
65017d15b25SDag-Erling Smørgrav 				buf[i] = (uint8_t)ch - '2' + 26;
65117d15b25SDag-Erling Smørgrav 			else
65217d15b25SDag-Erling Smørgrav 				return -1;
65317d15b25SDag-Erling Smørgrav 		}
65417d15b25SDag-Erling Smørgrav 		/* Less that 8 characters. We're done. */
65517d15b25SDag-Erling Smørgrav 		if (i < 8)
65617d15b25SDag-Erling Smørgrav 			break;
65717d15b25SDag-Erling Smørgrav 
65817d15b25SDag-Erling Smørgrav 		/* Enough space available at the destination? */
65917d15b25SDag-Erling Smørgrav 		if (dst_sz < 5)
66017d15b25SDag-Erling Smørgrav 			return -1;
66117d15b25SDag-Erling Smørgrav 
66217d15b25SDag-Erling Smørgrav 		/* 00000... ........ ........ ........ ........ */
66317d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
66417d15b25SDag-Erling Smørgrav 		dst[0] = buf[0] << 3 | buf[1] >> 2;
66517d15b25SDag-Erling Smørgrav 
66617d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
66717d15b25SDag-Erling Smørgrav 		/* ........ ..22222. ........ ........ ........ */
66817d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
66917d15b25SDag-Erling Smørgrav 		dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
67017d15b25SDag-Erling Smørgrav 
67117d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
67217d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
67317d15b25SDag-Erling Smørgrav 		dst[2] = buf[3] << 4 | buf[4] >> 1;
67417d15b25SDag-Erling Smørgrav 
67517d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
67617d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ .55555.. ........ */
67717d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ......66 666..... */
67817d15b25SDag-Erling Smørgrav 		dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
67917d15b25SDag-Erling Smørgrav 
68017d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ......66 666..... */
68117d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ........ ...77777 */
68217d15b25SDag-Erling Smørgrav 		dst[4] = buf[6] << 5 | buf[7];
68317d15b25SDag-Erling Smørgrav 
68417d15b25SDag-Erling Smørgrav 		dst += 5;
68517d15b25SDag-Erling Smørgrav 		dst_sz -= 5;
68617d15b25SDag-Erling Smørgrav 	}
68717d15b25SDag-Erling Smørgrav 	/* Not ending on a eight byte boundary? */
68817d15b25SDag-Erling Smørgrav 	if (i > 0 && i < 8) {
68917d15b25SDag-Erling Smørgrav 
69017d15b25SDag-Erling Smørgrav 		/* Enough space available at the destination? */
69117d15b25SDag-Erling Smørgrav 		if (dst_sz < (i + 1) / 2)
69217d15b25SDag-Erling Smørgrav 			return -1;
69317d15b25SDag-Erling Smørgrav 
69417d15b25SDag-Erling Smørgrav 		switch (i) {
69517d15b25SDag-Erling Smørgrav 		case 7: /* ........ ........ ........ ......66 666..... */
69617d15b25SDag-Erling Smørgrav 			/* ........ ........ ........ .55555.. ........ */
69717d15b25SDag-Erling Smørgrav 			/* ........ ........ ....4444 4....... ........ */
69817d15b25SDag-Erling Smørgrav 			dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
69917d15b25SDag-Erling Smørgrav 
70017d15b25SDag-Erling Smørgrav 		case 5: /* ........ ........ ....4444 4....... ........ */
70117d15b25SDag-Erling Smørgrav 			/* ........ .......3 3333.... ........ ........ */
70217d15b25SDag-Erling Smørgrav 			dst[2] = buf[3] << 4 | buf[4] >> 1;
70317d15b25SDag-Erling Smørgrav 
70417d15b25SDag-Erling Smørgrav 		case 4: /* ........ .......3 3333.... ........ ........ */
70517d15b25SDag-Erling Smørgrav 			/* ........ ..22222. ........ ........ ........ */
70617d15b25SDag-Erling Smørgrav 			/* .....111 11...... ........ ........ ........ */
70717d15b25SDag-Erling Smørgrav 			dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
70817d15b25SDag-Erling Smørgrav 
70917d15b25SDag-Erling Smørgrav 		case 2: /* .....111 11...... ........ ........ ........ */
71017d15b25SDag-Erling Smørgrav 			/* 00000... ........ ........ ........ ........ */
71117d15b25SDag-Erling Smørgrav 			dst[0] = buf[0] << 3 | buf[1] >> 2;
71217d15b25SDag-Erling Smørgrav 
71317d15b25SDag-Erling Smørgrav 			break;
71417d15b25SDag-Erling Smørgrav 
71517d15b25SDag-Erling Smørgrav 		default:
71617d15b25SDag-Erling Smørgrav 			return -1;
71717d15b25SDag-Erling Smørgrav 		}
71817d15b25SDag-Erling Smørgrav 		dst += (i + 1) / 2;
71917d15b25SDag-Erling Smørgrav 
72017d15b25SDag-Erling Smørgrav 		if (check_padding) {
72117d15b25SDag-Erling Smørgrav 			/* Check remaining padding characters */
72217d15b25SDag-Erling Smørgrav 			if (ch != '=')
72317d15b25SDag-Erling Smørgrav 				return -1;
72417d15b25SDag-Erling Smørgrav 
72517d15b25SDag-Erling Smørgrav 			/* One down, 8 - i - 1 more to come... */
72617d15b25SDag-Erling Smørgrav 			for (i = 8 - i - 1; i > 0; i--) {
72717d15b25SDag-Erling Smørgrav 
72817d15b25SDag-Erling Smørgrav 				do {
72917d15b25SDag-Erling Smørgrav 					if (src_sz == 0)
73017d15b25SDag-Erling Smørgrav 						return -1;
73117d15b25SDag-Erling Smørgrav 					ch = *src++;
73217d15b25SDag-Erling Smørgrav 					src_sz--;
73317d15b25SDag-Erling Smørgrav 
734*986ba33cSDag-Erling Smørgrav 				} while (isspace((unsigned char)ch));
73517d15b25SDag-Erling Smørgrav 
73617d15b25SDag-Erling Smørgrav 				if (ch != '=')
73717d15b25SDag-Erling Smørgrav 					return -1;
73817d15b25SDag-Erling Smørgrav 			}
73917d15b25SDag-Erling Smørgrav 		}
74017d15b25SDag-Erling Smørgrav 	}
74117d15b25SDag-Erling Smørgrav 	return dst - start;
74217d15b25SDag-Erling Smørgrav }
74317d15b25SDag-Erling Smørgrav 
74417d15b25SDag-Erling Smørgrav int
74517d15b25SDag-Erling Smørgrav ldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
74617d15b25SDag-Erling Smørgrav {
74717d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true);
74817d15b25SDag-Erling Smørgrav }
74917d15b25SDag-Erling Smørgrav 
75017d15b25SDag-Erling Smørgrav int
75117d15b25SDag-Erling Smørgrav ldns_b32_pton_extended_hex(const char* src, size_t src_sz,
75217d15b25SDag-Erling Smørgrav 		uint8_t* dst, size_t dst_sz)
75317d15b25SDag-Erling Smørgrav {
75417d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true);
75517d15b25SDag-Erling Smørgrav }
75617d15b25SDag-Erling Smørgrav 
75717d15b25SDag-Erling Smørgrav #ifndef HAVE_B32_PTON
75817d15b25SDag-Erling Smørgrav 
75917d15b25SDag-Erling Smørgrav int
76017d15b25SDag-Erling Smørgrav b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
76117d15b25SDag-Erling Smørgrav {
76217d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true);
76317d15b25SDag-Erling Smørgrav }
76417d15b25SDag-Erling Smørgrav 
76517d15b25SDag-Erling Smørgrav int
76617d15b25SDag-Erling Smørgrav b32_pton_extended_hex(const char* src, size_t src_sz,
76717d15b25SDag-Erling Smørgrav 		uint8_t* dst, size_t dst_sz)
76817d15b25SDag-Erling Smørgrav {
76917d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true);
77017d15b25SDag-Erling Smørgrav }
77117d15b25SDag-Erling Smørgrav 
77217d15b25SDag-Erling Smørgrav #endif /* ! HAVE_B32_PTON */
77317d15b25SDag-Erling Smørgrav 
774