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)296*5afab0e5SDag-Erling Smørgrav ldns_serial_arithmetics_time(int32_t time, time_t now)
2977b5038d7SDag-Erling Smørgrav {
298*5afab0e5SDag-Erling Smørgrav /* Casting due to https://github.com/NLnetLabs/ldns/issues/71 */
299*5afab0e5SDag-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
303*5afab0e5SDag-Erling Smørgrav struct tm *
ldns_serial_arithmetics_gmtime_r(int32_t time,time_t now,struct tm * result)304*5afab0e5SDag-Erling Smørgrav ldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result)
305*5afab0e5SDag-Erling Smørgrav {
306*5afab0e5SDag-Erling Smørgrav #if SIZEOF_TIME_T <= 4
307*5afab0e5SDag-Erling Smørgrav int64_t secs_since_epoch = ldns_serial_arithmetics_time(time, now);
308*5afab0e5SDag-Erling Smørgrav return ldns_gmtime64_r(secs_since_epoch, result);
309*5afab0e5SDag-Erling Smørgrav #else
310*5afab0e5SDag-Erling Smørgrav time_t secs_since_epoch = ldns_serial_arithmetics_time(time, now);
311*5afab0e5SDag-Erling Smørgrav return gmtime_r(&secs_since_epoch, result);
312*5afab0e5SDag-Erling Smørgrav #endif
313*5afab0e5SDag-Erling Smørgrav }
3147b5038d7SDag-Erling Smørgrav
315*5afab0e5SDag-Erling Smørgrav #ifdef ldns_serial_arithmitics_gmtime_r
316*5afab0e5SDag-Erling Smørgrav #undef ldns_serial_arithmitics_gmtime_r
317*5afab0e5SDag-Erling Smørgrav #endif
318*5afab0e5SDag-Erling Smørgrav /* alias function because of previously used wrong spelling */
319*5afab0e5SDag-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 {
323*5afab0e5SDag-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
391*5afab0e5SDag-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 ;
562*5afab0e5SDag-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 ;
567*5afab0e5SDag-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 ;
575*5afab0e5SDag-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] = '=';
586*5afab0e5SDag-Erling Smørgrav /* fallthrough */
58717d15b25SDag-Erling Smørgrav case 2: dst[4] = '=';
588*5afab0e5SDag-Erling Smørgrav /* fallthrough */
58917d15b25SDag-Erling Smørgrav case 3: dst[5] = '=';
59017d15b25SDag-Erling Smørgrav dst[6] = '=';
591*5afab0e5SDag-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;
716*5afab0e5SDag-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;
721*5afab0e5SDag-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;
727*5afab0e5SDag-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