xref: /freebsd/contrib/ldns/util.c (revision 5afab0e5)
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 *
ldns_lookup_by_name(ldns_lookup_table * table,const char * name)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 *
ldns_lookup_by_id(ldns_lookup_table * table,int id)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
ldns_get_bit(uint8_t bits[],size_t index)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
ldns_get_bit_r(uint8_t bits[],size_t index)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
ldns_set_bit(uint8_t * byte,int bit_nr,bool value)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
ldns_hexdigit_to_int(char ch)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
ldns_int_to_hexdigit(int i)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
ldns_hexstring_to_data(uint8_t * data,const char * str)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 *
ldns_version(void)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
is_leap_year(int year)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
leap_days(int y1,int y2)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
ldns_mktime_from_utc(const struct tm * tm)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
mktime_from_utc(const struct tm * tm)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
ldns_year_and_yday_from_days_since_epoch(int64_t days,struct tm * result)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
ldns_mon_and_mday_from_year_and_yday(struct tm * result)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
ldns_wday_from_year_and_yday(struct tm * result)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 *
ldns_gmtime64_r(int64_t clock,struct tm * result)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
ldns_serial_arithmetics_time(int32_t time,time_t now)2965afab0e5SDag-Erling Smørgrav ldns_serial_arithmetics_time(int32_t time, time_t now)
2977b5038d7SDag-Erling Smørgrav {
2985afab0e5SDag-Erling Smørgrav 	/* Casting due to https://github.com/NLnetLabs/ldns/issues/71 */
2995afab0e5SDag-Erling Smørgrav 	int32_t offset = (int32_t) ((uint32_t) time - (uint32_t) now);
3007b5038d7SDag-Erling Smørgrav 	return (int64_t) now + offset;
3017b5038d7SDag-Erling Smørgrav }
3027b5038d7SDag-Erling Smørgrav 
3035afab0e5SDag-Erling Smørgrav struct tm *
ldns_serial_arithmetics_gmtime_r(int32_t time,time_t now,struct tm * result)3045afab0e5SDag-Erling Smørgrav ldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result)
3055afab0e5SDag-Erling Smørgrav {
3065afab0e5SDag-Erling Smørgrav #if SIZEOF_TIME_T <= 4
3075afab0e5SDag-Erling Smørgrav 	int64_t secs_since_epoch = ldns_serial_arithmetics_time(time, now);
3085afab0e5SDag-Erling Smørgrav 	return  ldns_gmtime64_r(secs_since_epoch, result);
3095afab0e5SDag-Erling Smørgrav #else
3105afab0e5SDag-Erling Smørgrav 	time_t  secs_since_epoch = ldns_serial_arithmetics_time(time, now);
3115afab0e5SDag-Erling Smørgrav 	return  gmtime_r(&secs_since_epoch, result);
3125afab0e5SDag-Erling Smørgrav #endif
3135afab0e5SDag-Erling Smørgrav }
3147b5038d7SDag-Erling Smørgrav 
3155afab0e5SDag-Erling Smørgrav #ifdef ldns_serial_arithmitics_gmtime_r
3165afab0e5SDag-Erling Smørgrav #undef ldns_serial_arithmitics_gmtime_r
3175afab0e5SDag-Erling Smørgrav #endif
3185afab0e5SDag-Erling Smørgrav /* alias function because of previously used wrong spelling */
3195afab0e5SDag-Erling Smørgrav struct tm *ldns_serial_arithmitics_gmtime_r(int32_t, time_t, struct tm *);
3207b5038d7SDag-Erling Smørgrav struct tm *
ldns_serial_arithmitics_gmtime_r(int32_t time,time_t now,struct tm * result)3217b5038d7SDag-Erling Smørgrav ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
3227b5038d7SDag-Erling Smørgrav {
3235afab0e5SDag-Erling Smørgrav 	return ldns_serial_arithmetics_gmtime_r(time, now, result);
3247b5038d7SDag-Erling Smørgrav }
3257b5038d7SDag-Erling Smørgrav 
3267b5038d7SDag-Erling Smørgrav /**
3277b5038d7SDag-Erling Smørgrav  * Init the random source
3287b5038d7SDag-Erling Smørgrav  * applications should call this if they need entropy data within ldns
3297b5038d7SDag-Erling Smørgrav  * If openSSL is available, it is automatically seeded from /dev/urandom
3307b5038d7SDag-Erling Smørgrav  * or /dev/random
3317b5038d7SDag-Erling Smørgrav  *
3327b5038d7SDag-Erling Smørgrav  * If you need more entropy, or have no openssl available, this function
3337b5038d7SDag-Erling Smørgrav  * MUST be called at the start of the program
3347b5038d7SDag-Erling Smørgrav  *
3357b5038d7SDag-Erling Smørgrav  * If openssl *is* available, this function just adds more entropy
3367b5038d7SDag-Erling Smørgrav  **/
3377b5038d7SDag-Erling Smørgrav int
ldns_init_random(FILE * fd,unsigned int size)3387b5038d7SDag-Erling Smørgrav ldns_init_random(FILE *fd, unsigned int size)
3397b5038d7SDag-Erling Smørgrav {
3407b5038d7SDag-Erling Smørgrav 	/* if fp is given, seed srandom with data from file
3417b5038d7SDag-Erling Smørgrav 	   otherwise use /dev/urandom */
3427b5038d7SDag-Erling Smørgrav 	FILE *rand_f;
3437b5038d7SDag-Erling Smørgrav 	uint8_t *seed;
3447b5038d7SDag-Erling Smørgrav 	size_t read = 0;
3457b5038d7SDag-Erling Smørgrav 	unsigned int seed_i;
3467b5038d7SDag-Erling Smørgrav 	struct timeval tv;
3477b5038d7SDag-Erling Smørgrav 
3487b5038d7SDag-Erling Smørgrav 	/* we'll need at least sizeof(unsigned int) bytes for the
3497b5038d7SDag-Erling Smørgrav 	   standard prng seed */
3507b5038d7SDag-Erling Smørgrav 	if (size < (unsigned int) sizeof(seed_i)){
3517b5038d7SDag-Erling Smørgrav 		size = (unsigned int) sizeof(seed_i);
3527b5038d7SDag-Erling Smørgrav 	}
3537b5038d7SDag-Erling Smørgrav 
3547b5038d7SDag-Erling Smørgrav 	seed = LDNS_XMALLOC(uint8_t, size);
3557b5038d7SDag-Erling Smørgrav         if(!seed) {
3567b5038d7SDag-Erling Smørgrav 		return 1;
3577b5038d7SDag-Erling Smørgrav         }
3587b5038d7SDag-Erling Smørgrav 
3597b5038d7SDag-Erling Smørgrav 	if (!fd) {
3607b5038d7SDag-Erling Smørgrav 		if ((rand_f = fopen("/dev/urandom", "r")) == NULL) {
3617b5038d7SDag-Erling Smørgrav 			/* no readable /dev/urandom, try /dev/random */
3627b5038d7SDag-Erling Smørgrav 			if ((rand_f = fopen("/dev/random", "r")) == NULL) {
3637b5038d7SDag-Erling Smørgrav 				/* no readable /dev/random either, and no entropy
3647b5038d7SDag-Erling Smørgrav 				   source given. we'll have to improvise */
3657b5038d7SDag-Erling Smørgrav 				for (read = 0; read < size; read++) {
3667b5038d7SDag-Erling Smørgrav 					gettimeofday(&tv, NULL);
3677b5038d7SDag-Erling Smørgrav 					seed[read] = (uint8_t) (tv.tv_usec % 256);
3687b5038d7SDag-Erling Smørgrav 				}
3697b5038d7SDag-Erling Smørgrav 			} else {
3707b5038d7SDag-Erling Smørgrav 				read = fread(seed, 1, size, rand_f);
3717b5038d7SDag-Erling Smørgrav 			}
3727b5038d7SDag-Erling Smørgrav 		} else {
3737b5038d7SDag-Erling Smørgrav 			read = fread(seed, 1, size, rand_f);
3747b5038d7SDag-Erling Smørgrav 		}
3757b5038d7SDag-Erling Smørgrav 	} else {
3767b5038d7SDag-Erling Smørgrav 		rand_f = fd;
3777b5038d7SDag-Erling Smørgrav 		read = fread(seed, 1, size, rand_f);
3787b5038d7SDag-Erling Smørgrav 	}
3797b5038d7SDag-Erling Smørgrav 
3807b5038d7SDag-Erling Smørgrav 	if (read < size) {
3817b5038d7SDag-Erling Smørgrav 		LDNS_FREE(seed);
3822787e39aSDag-Erling Smørgrav 		if (!fd) fclose(rand_f);
3837b5038d7SDag-Erling Smørgrav 		return 1;
3847b5038d7SDag-Erling Smørgrav 	} else {
3857b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
3867b5038d7SDag-Erling Smørgrav 		/* Seed the OpenSSL prng (most systems have it seeded
3877b5038d7SDag-Erling Smørgrav 		   automatically, in that case this call just adds entropy */
3887b5038d7SDag-Erling Smørgrav 		RAND_seed(seed, (int) size);
3897b5038d7SDag-Erling Smørgrav #else
3907b5038d7SDag-Erling Smørgrav 		/* Seed the standard prng, only uses the first
3915afab0e5SDag-Erling Smørgrav 		 * unsigned sizeof(unsigned int) bytes found in the entropy pool
3927b5038d7SDag-Erling Smørgrav 		 */
3937b5038d7SDag-Erling Smørgrav 		memcpy(&seed_i, seed, sizeof(seed_i));
3947b5038d7SDag-Erling Smørgrav 		srandom(seed_i);
3957b5038d7SDag-Erling Smørgrav #endif
3967b5038d7SDag-Erling Smørgrav 		LDNS_FREE(seed);
3977b5038d7SDag-Erling Smørgrav 	}
3987b5038d7SDag-Erling Smørgrav 
3997b5038d7SDag-Erling Smørgrav 	if (!fd) {
4007b5038d7SDag-Erling Smørgrav                 if (rand_f) fclose(rand_f);
4017b5038d7SDag-Erling Smørgrav 	}
4027b5038d7SDag-Erling Smørgrav 
4037b5038d7SDag-Erling Smørgrav 	return 0;
4047b5038d7SDag-Erling Smørgrav }
4057b5038d7SDag-Erling Smørgrav 
4067b5038d7SDag-Erling Smørgrav /**
4077b5038d7SDag-Erling Smørgrav  * Get random number.
4087b5038d7SDag-Erling Smørgrav  *
4097b5038d7SDag-Erling Smørgrav  */
4107b5038d7SDag-Erling Smørgrav uint16_t
ldns_get_random(void)4117b5038d7SDag-Erling Smørgrav ldns_get_random(void)
4127b5038d7SDag-Erling Smørgrav {
4137b5038d7SDag-Erling Smørgrav         uint16_t rid = 0;
4147b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
4157b5038d7SDag-Erling Smørgrav         if (RAND_bytes((unsigned char*)&rid, 2) != 1) {
4167b5038d7SDag-Erling Smørgrav                 rid = (uint16_t) random();
4177b5038d7SDag-Erling Smørgrav         }
4187b5038d7SDag-Erling Smørgrav #else
4197b5038d7SDag-Erling Smørgrav         rid = (uint16_t) random();
4207b5038d7SDag-Erling Smørgrav #endif
4217b5038d7SDag-Erling Smørgrav 	return rid;
4227b5038d7SDag-Erling Smørgrav }
4237b5038d7SDag-Erling Smørgrav 
4247b5038d7SDag-Erling Smørgrav /*
4257b5038d7SDag-Erling Smørgrav  * BubbleBabble code taken from OpenSSH
4267b5038d7SDag-Erling Smørgrav  * Copyright (c) 2001 Carsten Raskgaard.  All rights reserved.
4277b5038d7SDag-Erling Smørgrav  */
4287b5038d7SDag-Erling Smørgrav char *
ldns_bubblebabble(uint8_t * data,size_t len)4297b5038d7SDag-Erling Smørgrav ldns_bubblebabble(uint8_t *data, size_t len)
4307b5038d7SDag-Erling Smørgrav {
4317b5038d7SDag-Erling Smørgrav 	char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
4327b5038d7SDag-Erling Smørgrav 	char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
4337b5038d7SDag-Erling Smørgrav 	    'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
4347b5038d7SDag-Erling Smørgrav 	size_t i, j = 0, rounds, seed = 1;
4357b5038d7SDag-Erling Smørgrav 	char *retval;
4367b5038d7SDag-Erling Smørgrav 
4377b5038d7SDag-Erling Smørgrav 	rounds = (len / 2) + 1;
4387b5038d7SDag-Erling Smørgrav 	retval = LDNS_XMALLOC(char, rounds * 6);
4397b5038d7SDag-Erling Smørgrav 	if(!retval) return NULL;
4407b5038d7SDag-Erling Smørgrav 	retval[j++] = 'x';
4417b5038d7SDag-Erling Smørgrav 	for (i = 0; i < rounds; i++) {
4427b5038d7SDag-Erling Smørgrav 		size_t idx0, idx1, idx2, idx3, idx4;
4437b5038d7SDag-Erling Smørgrav 		if ((i + 1 < rounds) || (len % 2 != 0)) {
4447b5038d7SDag-Erling Smørgrav 			idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) +
4457b5038d7SDag-Erling Smørgrav 			    seed) % 6;
4467b5038d7SDag-Erling Smørgrav 			idx1 = (((size_t)(data[2 * i])) >> 2) & 15;
4477b5038d7SDag-Erling Smørgrav 			idx2 = ((((size_t)(data[2 * i])) & 3) +
4487b5038d7SDag-Erling Smørgrav 			    (seed / 6)) % 6;
4497b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
4507b5038d7SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
4517b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
4527b5038d7SDag-Erling Smørgrav 			if ((i + 1) < rounds) {
4537b5038d7SDag-Erling Smørgrav 				idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15;
4547b5038d7SDag-Erling Smørgrav 				idx4 = (((size_t)(data[(2 * i) + 1]))) & 15;
4557b5038d7SDag-Erling Smørgrav 				retval[j++] = consonants[idx3];
4567b5038d7SDag-Erling Smørgrav 				retval[j++] = '-';
4577b5038d7SDag-Erling Smørgrav 				retval[j++] = consonants[idx4];
4587b5038d7SDag-Erling Smørgrav 				seed = ((seed * 5) +
4597b5038d7SDag-Erling Smørgrav 				    ((((size_t)(data[2 * i])) * 7) +
4607b5038d7SDag-Erling Smørgrav 				    ((size_t)(data[(2 * i) + 1])))) % 36;
4617b5038d7SDag-Erling Smørgrav 			}
4627b5038d7SDag-Erling Smørgrav 		} else {
4637b5038d7SDag-Erling Smørgrav 			idx0 = seed % 6;
4647b5038d7SDag-Erling Smørgrav 			idx1 = 16;
4657b5038d7SDag-Erling Smørgrav 			idx2 = seed / 6;
4667b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
4677b5038d7SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
4687b5038d7SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
4697b5038d7SDag-Erling Smørgrav 		}
4707b5038d7SDag-Erling Smørgrav 	}
4717b5038d7SDag-Erling Smørgrav 	retval[j++] = 'x';
4727b5038d7SDag-Erling Smørgrav 	retval[j++] = '\0';
4737b5038d7SDag-Erling Smørgrav 	return retval;
4747b5038d7SDag-Erling Smørgrav }
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_NTOP
48017d15b25SDag-Erling Smørgrav int ldns_b64_ntop(const uint8_t* src, size_t srclength,
48117d15b25SDag-Erling Smørgrav 		char *target, size_t targsize);
48217d15b25SDag-Erling Smørgrav {
48317d15b25SDag-Erling Smørgrav 	return b64_ntop(src, srclength, target, targsize);
48417d15b25SDag-Erling Smørgrav }
48517d15b25SDag-Erling Smørgrav #endif
48617d15b25SDag-Erling Smørgrav 
48717d15b25SDag-Erling Smørgrav /*
48817d15b25SDag-Erling Smørgrav  * For backwards compatibility, because we have always exported this symbol.
48917d15b25SDag-Erling Smørgrav  */
49017d15b25SDag-Erling Smørgrav #ifdef HAVE_B64_PTON
ldns_b64_pton(const char * src,uint8_t * target,size_t targsize)49117d15b25SDag-Erling Smørgrav int ldns_b64_pton(const char* src, uint8_t *target, size_t targsize)
49217d15b25SDag-Erling Smørgrav {
49317d15b25SDag-Erling Smørgrav 	return b64_pton(src, target, targsize);
49417d15b25SDag-Erling Smørgrav }
49517d15b25SDag-Erling Smørgrav #endif
49617d15b25SDag-Erling Smørgrav 
49717d15b25SDag-Erling Smørgrav 
49817d15b25SDag-Erling Smørgrav static int
ldns_b32_ntop_base(const uint8_t * src,size_t src_sz,char * dst,size_t dst_sz,bool extended_hex,bool add_padding)49917d15b25SDag-Erling Smørgrav ldns_b32_ntop_base(const uint8_t* src, size_t src_sz,
50017d15b25SDag-Erling Smørgrav 		char* dst, size_t dst_sz,
50117d15b25SDag-Erling Smørgrav 		bool extended_hex, bool add_padding)
50217d15b25SDag-Erling Smørgrav {
50317d15b25SDag-Erling Smørgrav 	size_t ret_sz;
50417d15b25SDag-Erling Smørgrav 	const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv"
50517d15b25SDag-Erling Smørgrav 	                               : "abcdefghijklmnopqrstuvwxyz234567";
50617d15b25SDag-Erling Smørgrav 
50717d15b25SDag-Erling Smørgrav 	size_t c = 0; /* c is used to carry partial base32 character over
50817d15b25SDag-Erling Smørgrav 	               * byte boundaries for sizes with a remainder.
50917d15b25SDag-Erling Smørgrav 		       * (i.e. src_sz % 5 != 0)
51017d15b25SDag-Erling Smørgrav 		       */
51117d15b25SDag-Erling Smørgrav 
51217d15b25SDag-Erling Smørgrav 	ret_sz = add_padding ? ldns_b32_ntop_calculate_size(src_sz)
51317d15b25SDag-Erling Smørgrav 	                     : ldns_b32_ntop_calculate_size_no_padding(src_sz);
51417d15b25SDag-Erling Smørgrav 
51517d15b25SDag-Erling Smørgrav 	/* Do we have enough space? */
51617d15b25SDag-Erling Smørgrav 	if (dst_sz < ret_sz + 1)
51717d15b25SDag-Erling Smørgrav 		return -1;
51817d15b25SDag-Erling Smørgrav 
51917d15b25SDag-Erling Smørgrav 	/* We know the size; terminate the string */
52017d15b25SDag-Erling Smørgrav 	dst[ret_sz] = '\0';
52117d15b25SDag-Erling Smørgrav 
52217d15b25SDag-Erling Smørgrav 	/* First process all chunks of five */
52317d15b25SDag-Erling Smørgrav 	while (src_sz >= 5) {
52417d15b25SDag-Erling Smørgrav 		/* 00000... ........ ........ ........ ........ */
52517d15b25SDag-Erling Smørgrav 		dst[0] = b32[(src[0]       ) >> 3];
52617d15b25SDag-Erling Smørgrav 
52717d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
52817d15b25SDag-Erling Smørgrav 		dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6];
52917d15b25SDag-Erling Smørgrav 
53017d15b25SDag-Erling Smørgrav 		/* ........ ..22222. ........ ........ ........ */
53117d15b25SDag-Erling Smørgrav 		dst[2] = b32[(src[1] & 0x3e) >> 1];
53217d15b25SDag-Erling Smørgrav 
53317d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
53417d15b25SDag-Erling Smørgrav 		dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4];
53517d15b25SDag-Erling Smørgrav 
53617d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
53717d15b25SDag-Erling Smørgrav 		dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7];
53817d15b25SDag-Erling Smørgrav 
53917d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ .55555.. ........ */
54017d15b25SDag-Erling Smørgrav 		dst[5] = b32[(src[3] & 0x7c) >> 2];
54117d15b25SDag-Erling Smørgrav 
54217d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ......66 666..... */
54317d15b25SDag-Erling Smørgrav 		dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5];
54417d15b25SDag-Erling Smørgrav 
54517d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ........ ...77777 */
54617d15b25SDag-Erling Smørgrav 		dst[7] = b32[(src[4] & 0x1f)     ];
54717d15b25SDag-Erling Smørgrav 
54817d15b25SDag-Erling Smørgrav 		src_sz -= 5;
54917d15b25SDag-Erling Smørgrav 		src    += 5;
55017d15b25SDag-Erling Smørgrav 		dst    += 8;
55117d15b25SDag-Erling Smørgrav 	}
55217d15b25SDag-Erling Smørgrav 	/* Process what remains */
55317d15b25SDag-Erling Smørgrav 	switch (src_sz) {
55417d15b25SDag-Erling Smørgrav 	case 4: /* ........ ........ ........ ......66 666..... */
55517d15b25SDag-Erling Smørgrav 		dst[6] = b32[(src[3] & 0x03) << 3];
55617d15b25SDag-Erling Smørgrav 
55717d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ .55555.. ........ */
55817d15b25SDag-Erling Smørgrav 		dst[5] = b32[(src[3] & 0x7c) >> 2];
55917d15b25SDag-Erling Smørgrav 
56017d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
56117d15b25SDag-Erling Smørgrav 		         c =  src[3]         >> 7 ;
5625afab0e5SDag-Erling Smørgrav 		/* fallthrough */
56317d15b25SDag-Erling Smørgrav 	case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c];
56417d15b25SDag-Erling Smørgrav 
56517d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
56617d15b25SDag-Erling Smørgrav 			 c =  src[2]         >> 4 ;
5675afab0e5SDag-Erling Smørgrav 		/* fallthrough */
56817d15b25SDag-Erling Smørgrav 	case 2:	dst[3] = b32[(src[1] & 0x01) << 4 | c];
56917d15b25SDag-Erling Smørgrav 
57017d15b25SDag-Erling Smørgrav 		/* ........ ..22222. ........ ........ ........ */
57117d15b25SDag-Erling Smørgrav 		dst[2] = b32[(src[1] & 0x3e) >> 1];
57217d15b25SDag-Erling Smørgrav 
57317d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
57417d15b25SDag-Erling Smørgrav 	                 c =  src[1]         >> 6 ;
5755afab0e5SDag-Erling Smørgrav 		/* fallthrough */
57617d15b25SDag-Erling Smørgrav 	case 1:	dst[1] = b32[(src[0] & 0x07) << 2 | c];
57717d15b25SDag-Erling Smørgrav 
57817d15b25SDag-Erling Smørgrav 		/* 00000... ........ ........ ........ ........ */
57917d15b25SDag-Erling Smørgrav 		dst[0] = b32[ src[0]         >> 3];
58017d15b25SDag-Erling Smørgrav 	}
58117d15b25SDag-Erling Smørgrav 	/* Add padding */
58217d15b25SDag-Erling Smørgrav 	if (add_padding) {
58317d15b25SDag-Erling Smørgrav 		switch (src_sz) {
58417d15b25SDag-Erling Smørgrav 			case 1: dst[2] = '=';
58517d15b25SDag-Erling Smørgrav 				dst[3] = '=';
5865afab0e5SDag-Erling Smørgrav 				/* fallthrough */
58717d15b25SDag-Erling Smørgrav 			case 2: dst[4] = '=';
5885afab0e5SDag-Erling Smørgrav 				/* fallthrough */
58917d15b25SDag-Erling Smørgrav 			case 3: dst[5] = '=';
59017d15b25SDag-Erling Smørgrav 				dst[6] = '=';
5915afab0e5SDag-Erling Smørgrav 				/* fallthrough */
59217d15b25SDag-Erling Smørgrav 			case 4: dst[7] = '=';
59317d15b25SDag-Erling Smørgrav 		}
59417d15b25SDag-Erling Smørgrav 	}
59517d15b25SDag-Erling Smørgrav 	return (int)ret_sz;
59617d15b25SDag-Erling Smørgrav }
59717d15b25SDag-Erling Smørgrav 
59817d15b25SDag-Erling Smørgrav int
ldns_b32_ntop(const uint8_t * src,size_t src_sz,char * dst,size_t dst_sz)59917d15b25SDag-Erling Smørgrav ldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
60017d15b25SDag-Erling Smørgrav {
60117d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true);
60217d15b25SDag-Erling Smørgrav }
60317d15b25SDag-Erling Smørgrav 
60417d15b25SDag-Erling Smørgrav int
ldns_b32_ntop_extended_hex(const uint8_t * src,size_t src_sz,char * dst,size_t dst_sz)60517d15b25SDag-Erling Smørgrav ldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
60617d15b25SDag-Erling Smørgrav 		char* dst, size_t dst_sz)
60717d15b25SDag-Erling Smørgrav {
60817d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true);
60917d15b25SDag-Erling Smørgrav }
61017d15b25SDag-Erling Smørgrav 
61117d15b25SDag-Erling Smørgrav #ifndef HAVE_B32_NTOP
61217d15b25SDag-Erling Smørgrav 
61317d15b25SDag-Erling Smørgrav int
b32_ntop(const uint8_t * src,size_t src_sz,char * dst,size_t dst_sz)61417d15b25SDag-Erling Smørgrav b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
61517d15b25SDag-Erling Smørgrav {
61617d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true);
61717d15b25SDag-Erling Smørgrav }
61817d15b25SDag-Erling Smørgrav 
61917d15b25SDag-Erling Smørgrav int
b32_ntop_extended_hex(const uint8_t * src,size_t src_sz,char * dst,size_t dst_sz)62017d15b25SDag-Erling Smørgrav b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
62117d15b25SDag-Erling Smørgrav 		char* dst, size_t dst_sz)
62217d15b25SDag-Erling Smørgrav {
62317d15b25SDag-Erling Smørgrav 	return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true);
62417d15b25SDag-Erling Smørgrav }
62517d15b25SDag-Erling Smørgrav 
62617d15b25SDag-Erling Smørgrav #endif /* ! HAVE_B32_NTOP */
62717d15b25SDag-Erling Smørgrav 
62817d15b25SDag-Erling Smørgrav static int
ldns_b32_pton_base(const char * src,size_t src_sz,uint8_t * dst,size_t dst_sz,bool extended_hex,bool check_padding)62917d15b25SDag-Erling Smørgrav ldns_b32_pton_base(const char* src, size_t src_sz,
63017d15b25SDag-Erling Smørgrav 		uint8_t* dst, size_t dst_sz,
63117d15b25SDag-Erling Smørgrav 		bool extended_hex, bool check_padding)
63217d15b25SDag-Erling Smørgrav {
63317d15b25SDag-Erling Smørgrav 	size_t i = 0;
63417d15b25SDag-Erling Smørgrav 	char ch = '\0';
63517d15b25SDag-Erling Smørgrav 	uint8_t buf[8];
63617d15b25SDag-Erling Smørgrav 	uint8_t* start = dst;
63717d15b25SDag-Erling Smørgrav 
63817d15b25SDag-Erling Smørgrav 	while (src_sz) {
63917d15b25SDag-Erling Smørgrav 		/* Collect 8 characters in buf (if possible) */
64017d15b25SDag-Erling Smørgrav 		for (i = 0; i < 8; i++) {
64117d15b25SDag-Erling Smørgrav 
64217d15b25SDag-Erling Smørgrav 			do {
64317d15b25SDag-Erling Smørgrav 				ch = *src++;
64417d15b25SDag-Erling Smørgrav 				--src_sz;
64517d15b25SDag-Erling Smørgrav 
646986ba33cSDag-Erling Smørgrav 			} while (isspace((unsigned char)ch) && src_sz > 0);
64717d15b25SDag-Erling Smørgrav 
64817d15b25SDag-Erling Smørgrav 			if (ch == '=' || ch == '\0')
64917d15b25SDag-Erling Smørgrav 				break;
65017d15b25SDag-Erling Smørgrav 
65117d15b25SDag-Erling Smørgrav 			else if (extended_hex)
65217d15b25SDag-Erling Smørgrav 
65317d15b25SDag-Erling Smørgrav 				if (ch >= '0' && ch <= '9')
65417d15b25SDag-Erling Smørgrav 					buf[i] = (uint8_t)ch - '0';
65517d15b25SDag-Erling Smørgrav 				else if (ch >= 'a' && ch <= 'v')
65617d15b25SDag-Erling Smørgrav 					buf[i] = (uint8_t)ch - 'a' + 10;
65717d15b25SDag-Erling Smørgrav 				else if (ch >= 'A' && ch <= 'V')
65817d15b25SDag-Erling Smørgrav 					buf[i] = (uint8_t)ch - 'A' + 10;
65917d15b25SDag-Erling Smørgrav 				else
66017d15b25SDag-Erling Smørgrav 					return -1;
66117d15b25SDag-Erling Smørgrav 
66217d15b25SDag-Erling Smørgrav 			else if (ch >= 'a' && ch <= 'z')
66317d15b25SDag-Erling Smørgrav 				buf[i] = (uint8_t)ch - 'a';
66417d15b25SDag-Erling Smørgrav 			else if (ch >= 'A' && ch <= 'Z')
66517d15b25SDag-Erling Smørgrav 				buf[i] = (uint8_t)ch - 'A';
66617d15b25SDag-Erling Smørgrav 			else if (ch >= '2' && ch <= '7')
66717d15b25SDag-Erling Smørgrav 				buf[i] = (uint8_t)ch - '2' + 26;
66817d15b25SDag-Erling Smørgrav 			else
66917d15b25SDag-Erling Smørgrav 				return -1;
67017d15b25SDag-Erling Smørgrav 		}
67117d15b25SDag-Erling Smørgrav 		/* Less that 8 characters. We're done. */
67217d15b25SDag-Erling Smørgrav 		if (i < 8)
67317d15b25SDag-Erling Smørgrav 			break;
67417d15b25SDag-Erling Smørgrav 
67517d15b25SDag-Erling Smørgrav 		/* Enough space available at the destination? */
67617d15b25SDag-Erling Smørgrav 		if (dst_sz < 5)
67717d15b25SDag-Erling Smørgrav 			return -1;
67817d15b25SDag-Erling Smørgrav 
67917d15b25SDag-Erling Smørgrav 		/* 00000... ........ ........ ........ ........ */
68017d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
68117d15b25SDag-Erling Smørgrav 		dst[0] = buf[0] << 3 | buf[1] >> 2;
68217d15b25SDag-Erling Smørgrav 
68317d15b25SDag-Erling Smørgrav 		/* .....111 11...... ........ ........ ........ */
68417d15b25SDag-Erling Smørgrav 		/* ........ ..22222. ........ ........ ........ */
68517d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
68617d15b25SDag-Erling Smørgrav 		dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
68717d15b25SDag-Erling Smørgrav 
68817d15b25SDag-Erling Smørgrav 		/* ........ .......3 3333.... ........ ........ */
68917d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
69017d15b25SDag-Erling Smørgrav 		dst[2] = buf[3] << 4 | buf[4] >> 1;
69117d15b25SDag-Erling Smørgrav 
69217d15b25SDag-Erling Smørgrav 		/* ........ ........ ....4444 4....... ........ */
69317d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ .55555.. ........ */
69417d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ......66 666..... */
69517d15b25SDag-Erling Smørgrav 		dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
69617d15b25SDag-Erling Smørgrav 
69717d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ......66 666..... */
69817d15b25SDag-Erling Smørgrav 		/* ........ ........ ........ ........ ...77777 */
69917d15b25SDag-Erling Smørgrav 		dst[4] = buf[6] << 5 | buf[7];
70017d15b25SDag-Erling Smørgrav 
70117d15b25SDag-Erling Smørgrav 		dst += 5;
70217d15b25SDag-Erling Smørgrav 		dst_sz -= 5;
70317d15b25SDag-Erling Smørgrav 	}
70417d15b25SDag-Erling Smørgrav 	/* Not ending on a eight byte boundary? */
70517d15b25SDag-Erling Smørgrav 	if (i > 0 && i < 8) {
70617d15b25SDag-Erling Smørgrav 
70717d15b25SDag-Erling Smørgrav 		/* Enough space available at the destination? */
70817d15b25SDag-Erling Smørgrav 		if (dst_sz < (i + 1) / 2)
70917d15b25SDag-Erling Smørgrav 			return -1;
71017d15b25SDag-Erling Smørgrav 
71117d15b25SDag-Erling Smørgrav 		switch (i) {
71217d15b25SDag-Erling Smørgrav 		case 7: /* ........ ........ ........ ......66 666..... */
71317d15b25SDag-Erling Smørgrav 			/* ........ ........ ........ .55555.. ........ */
71417d15b25SDag-Erling Smørgrav 			/* ........ ........ ....4444 4....... ........ */
71517d15b25SDag-Erling Smørgrav 			dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
7165afab0e5SDag-Erling Smørgrav 			/* fallthrough */
71717d15b25SDag-Erling Smørgrav 
71817d15b25SDag-Erling Smørgrav 		case 5: /* ........ ........ ....4444 4....... ........ */
71917d15b25SDag-Erling Smørgrav 			/* ........ .......3 3333.... ........ ........ */
72017d15b25SDag-Erling Smørgrav 			dst[2] = buf[3] << 4 | buf[4] >> 1;
7215afab0e5SDag-Erling Smørgrav 			/* fallthrough */
72217d15b25SDag-Erling Smørgrav 
72317d15b25SDag-Erling Smørgrav 		case 4: /* ........ .......3 3333.... ........ ........ */
72417d15b25SDag-Erling Smørgrav 			/* ........ ..22222. ........ ........ ........ */
72517d15b25SDag-Erling Smørgrav 			/* .....111 11...... ........ ........ ........ */
72617d15b25SDag-Erling Smørgrav 			dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
7275afab0e5SDag-Erling Smørgrav 			/* fallthrough */
72817d15b25SDag-Erling Smørgrav 
72917d15b25SDag-Erling Smørgrav 		case 2: /* .....111 11...... ........ ........ ........ */
73017d15b25SDag-Erling Smørgrav 			/* 00000... ........ ........ ........ ........ */
73117d15b25SDag-Erling Smørgrav 			dst[0] = buf[0] << 3 | buf[1] >> 2;
73217d15b25SDag-Erling Smørgrav 
73317d15b25SDag-Erling Smørgrav 			break;
73417d15b25SDag-Erling Smørgrav 
73517d15b25SDag-Erling Smørgrav 		default:
73617d15b25SDag-Erling Smørgrav 			return -1;
73717d15b25SDag-Erling Smørgrav 		}
73817d15b25SDag-Erling Smørgrav 		dst += (i + 1) / 2;
73917d15b25SDag-Erling Smørgrav 
74017d15b25SDag-Erling Smørgrav 		if (check_padding) {
74117d15b25SDag-Erling Smørgrav 			/* Check remaining padding characters */
74217d15b25SDag-Erling Smørgrav 			if (ch != '=')
74317d15b25SDag-Erling Smørgrav 				return -1;
74417d15b25SDag-Erling Smørgrav 
74517d15b25SDag-Erling Smørgrav 			/* One down, 8 - i - 1 more to come... */
74617d15b25SDag-Erling Smørgrav 			for (i = 8 - i - 1; i > 0; i--) {
74717d15b25SDag-Erling Smørgrav 
74817d15b25SDag-Erling Smørgrav 				do {
74917d15b25SDag-Erling Smørgrav 					if (src_sz == 0)
75017d15b25SDag-Erling Smørgrav 						return -1;
75117d15b25SDag-Erling Smørgrav 					ch = *src++;
75217d15b25SDag-Erling Smørgrav 					src_sz--;
75317d15b25SDag-Erling Smørgrav 
754986ba33cSDag-Erling Smørgrav 				} while (isspace((unsigned char)ch));
75517d15b25SDag-Erling Smørgrav 
75617d15b25SDag-Erling Smørgrav 				if (ch != '=')
75717d15b25SDag-Erling Smørgrav 					return -1;
75817d15b25SDag-Erling Smørgrav 			}
75917d15b25SDag-Erling Smørgrav 		}
76017d15b25SDag-Erling Smørgrav 	}
76117d15b25SDag-Erling Smørgrav 	return dst - start;
76217d15b25SDag-Erling Smørgrav }
76317d15b25SDag-Erling Smørgrav 
76417d15b25SDag-Erling Smørgrav int
ldns_b32_pton(const char * src,size_t src_sz,uint8_t * dst,size_t dst_sz)76517d15b25SDag-Erling Smørgrav ldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
76617d15b25SDag-Erling Smørgrav {
76717d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true);
76817d15b25SDag-Erling Smørgrav }
76917d15b25SDag-Erling Smørgrav 
77017d15b25SDag-Erling Smørgrav int
ldns_b32_pton_extended_hex(const char * src,size_t src_sz,uint8_t * dst,size_t dst_sz)77117d15b25SDag-Erling Smørgrav ldns_b32_pton_extended_hex(const char* src, size_t src_sz,
77217d15b25SDag-Erling Smørgrav 		uint8_t* dst, size_t dst_sz)
77317d15b25SDag-Erling Smørgrav {
77417d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true);
77517d15b25SDag-Erling Smørgrav }
77617d15b25SDag-Erling Smørgrav 
77717d15b25SDag-Erling Smørgrav #ifndef HAVE_B32_PTON
77817d15b25SDag-Erling Smørgrav 
77917d15b25SDag-Erling Smørgrav int
b32_pton(const char * src,size_t src_sz,uint8_t * dst,size_t dst_sz)78017d15b25SDag-Erling Smørgrav b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
78117d15b25SDag-Erling Smørgrav {
78217d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true);
78317d15b25SDag-Erling Smørgrav }
78417d15b25SDag-Erling Smørgrav 
78517d15b25SDag-Erling Smørgrav int
b32_pton_extended_hex(const char * src,size_t src_sz,uint8_t * dst,size_t dst_sz)78617d15b25SDag-Erling Smørgrav b32_pton_extended_hex(const char* src, size_t src_sz,
78717d15b25SDag-Erling Smørgrav 		uint8_t* dst, size_t dst_sz)
78817d15b25SDag-Erling Smørgrav {
78917d15b25SDag-Erling Smørgrav 	return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true);
79017d15b25SDag-Erling Smørgrav }
79117d15b25SDag-Erling Smørgrav 
79217d15b25SDag-Erling Smørgrav #endif /* ! HAVE_B32_PTON */
79317d15b25SDag-Erling Smørgrav 
794