1238104Sdes/* 2238104Sdes * util.c 3238104Sdes * 4238104Sdes * some general memory functions 5238104Sdes * 6238104Sdes * a Net::DNS like library for C 7238104Sdes * 8238104Sdes * (c) NLnet Labs, 2004-2006 9238104Sdes * 10238104Sdes * See the file LICENSE for the license 11238104Sdes */ 12238104Sdes 13238104Sdes#include <ldns/config.h> 14238104Sdes 15238104Sdes#include <ldns/rdata.h> 16238104Sdes#include <ldns/rr.h> 17238104Sdes#include <ldns/util.h> 18238104Sdes#include <strings.h> 19238104Sdes#include <stdlib.h> 20238104Sdes#include <stdio.h> 21238104Sdes#include <sys/time.h> 22238104Sdes#include <time.h> 23266114Sdes#include <ctype.h> 24238104Sdes 25238104Sdes#ifdef HAVE_SSL 26238104Sdes#include <openssl/rand.h> 27238104Sdes#endif 28238104Sdes 29238104Sdesldns_lookup_table * 30238104Sdesldns_lookup_by_name(ldns_lookup_table *table, const char *name) 31238104Sdes{ 32238104Sdes while (table->name != NULL) { 33238104Sdes if (strcasecmp(name, table->name) == 0) 34238104Sdes return table; 35238104Sdes table++; 36238104Sdes } 37238104Sdes return NULL; 38238104Sdes} 39238104Sdes 40238104Sdesldns_lookup_table * 41238104Sdesldns_lookup_by_id(ldns_lookup_table *table, int id) 42238104Sdes{ 43238104Sdes while (table->name != NULL) { 44238104Sdes if (table->id == id) 45238104Sdes return table; 46238104Sdes table++; 47238104Sdes } 48238104Sdes return NULL; 49238104Sdes} 50238104Sdes 51238104Sdesint 52238104Sdesldns_get_bit(uint8_t bits[], size_t index) 53238104Sdes{ 54238104Sdes /* 55238104Sdes * The bits are counted from left to right, so bit #0 is the 56238104Sdes * left most bit. 57238104Sdes */ 58238104Sdes return (int) (bits[index / 8] & (1 << (7 - index % 8))); 59238104Sdes} 60238104Sdes 61238104Sdesint 62238104Sdesldns_get_bit_r(uint8_t bits[], size_t index) 63238104Sdes{ 64238104Sdes /* 65238104Sdes * The bits are counted from right to left, so bit #0 is the 66238104Sdes * right most bit. 67238104Sdes */ 68238104Sdes return (int) bits[index / 8] & (1 << (index % 8)); 69238104Sdes} 70238104Sdes 71238104Sdesvoid 72238104Sdesldns_set_bit(uint8_t *byte, int bit_nr, bool value) 73238104Sdes{ 74238104Sdes /* 75238104Sdes * The bits are counted from right to left, so bit #0 is the 76238104Sdes * right most bit. 77238104Sdes */ 78238104Sdes if (bit_nr >= 0 && bit_nr < 8) { 79238104Sdes if (value) { 80238104Sdes *byte = *byte | (0x01 << bit_nr); 81238104Sdes } else { 82238104Sdes *byte = *byte & ~(0x01 << bit_nr); 83238104Sdes } 84238104Sdes } 85238104Sdes} 86238104Sdes 87238104Sdesint 88238104Sdesldns_hexdigit_to_int(char ch) 89238104Sdes{ 90238104Sdes switch (ch) { 91238104Sdes case '0': return 0; 92238104Sdes case '1': return 1; 93238104Sdes case '2': return 2; 94238104Sdes case '3': return 3; 95238104Sdes case '4': return 4; 96238104Sdes case '5': return 5; 97238104Sdes case '6': return 6; 98238104Sdes case '7': return 7; 99238104Sdes case '8': return 8; 100238104Sdes case '9': return 9; 101238104Sdes case 'a': case 'A': return 10; 102238104Sdes case 'b': case 'B': return 11; 103238104Sdes case 'c': case 'C': return 12; 104238104Sdes case 'd': case 'D': return 13; 105238104Sdes case 'e': case 'E': return 14; 106238104Sdes case 'f': case 'F': return 15; 107238104Sdes default: 108238104Sdes return -1; 109238104Sdes } 110238104Sdes} 111238104Sdes 112238104Sdeschar 113238104Sdesldns_int_to_hexdigit(int i) 114238104Sdes{ 115238104Sdes switch (i) { 116238104Sdes case 0: return '0'; 117238104Sdes case 1: return '1'; 118238104Sdes case 2: return '2'; 119238104Sdes case 3: return '3'; 120238104Sdes case 4: return '4'; 121238104Sdes case 5: return '5'; 122238104Sdes case 6: return '6'; 123238104Sdes case 7: return '7'; 124238104Sdes case 8: return '8'; 125238104Sdes case 9: return '9'; 126238104Sdes case 10: return 'a'; 127238104Sdes case 11: return 'b'; 128238104Sdes case 12: return 'c'; 129238104Sdes case 13: return 'd'; 130238104Sdes case 14: return 'e'; 131238104Sdes case 15: return 'f'; 132238104Sdes default: 133238104Sdes abort(); 134238104Sdes } 135238104Sdes} 136238104Sdes 137238104Sdesint 138238104Sdesldns_hexstring_to_data(uint8_t *data, const char *str) 139238104Sdes{ 140238104Sdes size_t i; 141238104Sdes 142238104Sdes if (!str || !data) { 143238104Sdes return -1; 144238104Sdes } 145238104Sdes 146238104Sdes if (strlen(str) % 2 != 0) { 147238104Sdes return -2; 148238104Sdes } 149238104Sdes 150238104Sdes for (i = 0; i < strlen(str) / 2; i++) { 151238104Sdes data[i] = 152238104Sdes 16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) + 153238104Sdes (uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]); 154238104Sdes } 155238104Sdes 156238104Sdes return (int) i; 157238104Sdes} 158238104Sdes 159238104Sdesconst char * 160238104Sdesldns_version(void) 161238104Sdes{ 162238104Sdes return (char*)LDNS_VERSION; 163238104Sdes} 164238104Sdes 165238104Sdes/* Number of days per month (except for February in leap years). */ 166238104Sdesstatic const int mdays[] = { 167238104Sdes 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 168238104Sdes}; 169238104Sdes 170238104Sdes#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y))) 171238104Sdes#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y))) 172238104Sdes 173238104Sdesstatic int 174238104Sdesis_leap_year(int year) 175238104Sdes{ 176238104Sdes return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0 177238104Sdes || LDNS_MOD(year, 400) == 0); 178238104Sdes} 179238104Sdes 180238104Sdesstatic int 181238104Sdesleap_days(int y1, int y2) 182238104Sdes{ 183238104Sdes --y1; 184238104Sdes --y2; 185238104Sdes return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) - 186238104Sdes (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) + 187238104Sdes (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400)); 188238104Sdes} 189238104Sdes 190238104Sdes/* 191238104Sdes * Code adapted from Python 2.4.1 sources (Lib/calendar.py). 192238104Sdes */ 193238104Sdestime_t 194246854Sdesldns_mktime_from_utc(const struct tm *tm) 195238104Sdes{ 196238104Sdes int year = 1900 + tm->tm_year; 197238104Sdes time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year); 198238104Sdes time_t hours; 199238104Sdes time_t minutes; 200238104Sdes time_t seconds; 201238104Sdes int i; 202238104Sdes 203238104Sdes for (i = 0; i < tm->tm_mon; ++i) { 204238104Sdes days += mdays[i]; 205238104Sdes } 206238104Sdes if (tm->tm_mon > 1 && is_leap_year(year)) { 207238104Sdes ++days; 208238104Sdes } 209238104Sdes days += tm->tm_mday - 1; 210238104Sdes 211238104Sdes hours = days * 24 + tm->tm_hour; 212238104Sdes minutes = hours * 60 + tm->tm_min; 213238104Sdes seconds = minutes * 60 + tm->tm_sec; 214238104Sdes 215238104Sdes return seconds; 216238104Sdes} 217238104Sdes 218246854Sdestime_t 219246854Sdesmktime_from_utc(const struct tm *tm) 220246854Sdes{ 221246854Sdes return ldns_mktime_from_utc(tm); 222246854Sdes} 223246854Sdes 224238104Sdes#if SIZEOF_TIME_T <= 4 225238104Sdes 226238104Sdesstatic void 227238104Sdesldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result) 228238104Sdes{ 229238104Sdes int year = 1970; 230238104Sdes int new_year; 231238104Sdes 232238104Sdes while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) { 233238104Sdes new_year = year + (int) LDNS_DIV(days, 365); 234238104Sdes days -= (new_year - year) * 365; 235238104Sdes days -= leap_days(year, new_year); 236238104Sdes year = new_year; 237238104Sdes } 238238104Sdes result->tm_year = year; 239238104Sdes result->tm_yday = (int) days; 240238104Sdes} 241238104Sdes 242238104Sdes/* Number of days per month in a leap year. */ 243238104Sdesstatic const int leap_year_mdays[] = { 244238104Sdes 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 245238104Sdes}; 246238104Sdes 247238104Sdesstatic void 248238104Sdesldns_mon_and_mday_from_year_and_yday(struct tm *result) 249238104Sdes{ 250238104Sdes int idays = result->tm_yday; 251238104Sdes const int *mon_lengths = is_leap_year(result->tm_year) ? 252238104Sdes leap_year_mdays : mdays; 253238104Sdes 254238104Sdes result->tm_mon = 0; 255238104Sdes while (idays >= mon_lengths[result->tm_mon]) { 256238104Sdes idays -= mon_lengths[result->tm_mon++]; 257238104Sdes } 258238104Sdes result->tm_mday = idays + 1; 259238104Sdes} 260238104Sdes 261238104Sdesstatic void 262238104Sdesldns_wday_from_year_and_yday(struct tm *result) 263238104Sdes{ 264238104Sdes result->tm_wday = 4 /* 1-1-1970 was a thursday */ 265238104Sdes + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7) 266238104Sdes + leap_days(1970, result->tm_year) 267238104Sdes + result->tm_yday; 268238104Sdes result->tm_wday = LDNS_MOD(result->tm_wday, 7); 269238104Sdes if (result->tm_wday < 0) { 270238104Sdes result->tm_wday += 7; 271238104Sdes } 272238104Sdes} 273238104Sdes 274238104Sdesstatic struct tm * 275238104Sdesldns_gmtime64_r(int64_t clock, struct tm *result) 276238104Sdes{ 277238104Sdes result->tm_isdst = 0; 278238104Sdes result->tm_sec = (int) LDNS_MOD(clock, 60); 279238104Sdes clock = LDNS_DIV(clock, 60); 280238104Sdes result->tm_min = (int) LDNS_MOD(clock, 60); 281238104Sdes clock = LDNS_DIV(clock, 60); 282238104Sdes result->tm_hour = (int) LDNS_MOD(clock, 24); 283238104Sdes clock = LDNS_DIV(clock, 24); 284238104Sdes 285238104Sdes ldns_year_and_yday_from_days_since_epoch(clock, result); 286238104Sdes ldns_mon_and_mday_from_year_and_yday(result); 287238104Sdes ldns_wday_from_year_and_yday(result); 288238104Sdes result->tm_year -= 1900; 289238104Sdes 290238104Sdes return result; 291238104Sdes} 292238104Sdes 293238104Sdes#endif /* SIZEOF_TIME_T <= 4 */ 294238104Sdes 295238104Sdesstatic int64_t 296238104Sdesldns_serial_arithmitics_time(int32_t time, time_t now) 297238104Sdes{ 298238104Sdes int32_t offset = time - (int32_t) now; 299238104Sdes return (int64_t) now + offset; 300238104Sdes} 301238104Sdes 302238104Sdes 303238104Sdesstruct tm * 304238104Sdesldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result) 305238104Sdes{ 306238104Sdes#if SIZEOF_TIME_T <= 4 307238104Sdes int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); 308238104Sdes return ldns_gmtime64_r(secs_since_epoch, result); 309238104Sdes#else 310238104Sdes time_t secs_since_epoch = ldns_serial_arithmitics_time(time, now); 311238104Sdes return gmtime_r(&secs_since_epoch, result); 312238104Sdes#endif 313238104Sdes} 314238104Sdes 315238104Sdes/** 316238104Sdes * Init the random source 317238104Sdes * applications should call this if they need entropy data within ldns 318238104Sdes * If openSSL is available, it is automatically seeded from /dev/urandom 319238104Sdes * or /dev/random 320238104Sdes * 321238104Sdes * If you need more entropy, or have no openssl available, this function 322238104Sdes * MUST be called at the start of the program 323238104Sdes * 324238104Sdes * If openssl *is* available, this function just adds more entropy 325238104Sdes **/ 326238104Sdesint 327238104Sdesldns_init_random(FILE *fd, unsigned int size) 328238104Sdes{ 329238104Sdes /* if fp is given, seed srandom with data from file 330238104Sdes otherwise use /dev/urandom */ 331238104Sdes FILE *rand_f; 332238104Sdes uint8_t *seed; 333238104Sdes size_t read = 0; 334238104Sdes unsigned int seed_i; 335238104Sdes struct timeval tv; 336238104Sdes 337238104Sdes /* we'll need at least sizeof(unsigned int) bytes for the 338238104Sdes standard prng seed */ 339238104Sdes if (size < (unsigned int) sizeof(seed_i)){ 340238104Sdes size = (unsigned int) sizeof(seed_i); 341238104Sdes } 342238104Sdes 343238104Sdes seed = LDNS_XMALLOC(uint8_t, size); 344238104Sdes if(!seed) { 345238104Sdes return 1; 346238104Sdes } 347238104Sdes 348238104Sdes if (!fd) { 349238104Sdes if ((rand_f = fopen("/dev/urandom", "r")) == NULL) { 350238104Sdes /* no readable /dev/urandom, try /dev/random */ 351238104Sdes if ((rand_f = fopen("/dev/random", "r")) == NULL) { 352238104Sdes /* no readable /dev/random either, and no entropy 353238104Sdes source given. we'll have to improvise */ 354238104Sdes for (read = 0; read < size; read++) { 355238104Sdes gettimeofday(&tv, NULL); 356238104Sdes seed[read] = (uint8_t) (tv.tv_usec % 256); 357238104Sdes } 358238104Sdes } else { 359238104Sdes read = fread(seed, 1, size, rand_f); 360238104Sdes } 361238104Sdes } else { 362238104Sdes read = fread(seed, 1, size, rand_f); 363238104Sdes } 364238104Sdes } else { 365238104Sdes rand_f = fd; 366238104Sdes read = fread(seed, 1, size, rand_f); 367238104Sdes } 368238104Sdes 369238104Sdes if (read < size) { 370238104Sdes LDNS_FREE(seed); 371246854Sdes if (!fd) fclose(rand_f); 372238104Sdes return 1; 373238104Sdes } else { 374238104Sdes#ifdef HAVE_SSL 375238104Sdes /* Seed the OpenSSL prng (most systems have it seeded 376238104Sdes automatically, in that case this call just adds entropy */ 377238104Sdes RAND_seed(seed, (int) size); 378238104Sdes#else 379238104Sdes /* Seed the standard prng, only uses the first 380238104Sdes * unsigned sizeof(unsiged int) bytes found in the entropy pool 381238104Sdes */ 382238104Sdes memcpy(&seed_i, seed, sizeof(seed_i)); 383238104Sdes srandom(seed_i); 384238104Sdes#endif 385238104Sdes LDNS_FREE(seed); 386238104Sdes } 387238104Sdes 388238104Sdes if (!fd) { 389238104Sdes if (rand_f) fclose(rand_f); 390238104Sdes } 391238104Sdes 392238104Sdes return 0; 393238104Sdes} 394238104Sdes 395238104Sdes/** 396238104Sdes * Get random number. 397238104Sdes * 398238104Sdes */ 399238104Sdesuint16_t 400238104Sdesldns_get_random(void) 401238104Sdes{ 402238104Sdes uint16_t rid = 0; 403238104Sdes#ifdef HAVE_SSL 404238104Sdes if (RAND_bytes((unsigned char*)&rid, 2) != 1) { 405238104Sdes rid = (uint16_t) random(); 406238104Sdes } 407238104Sdes#else 408238104Sdes rid = (uint16_t) random(); 409238104Sdes#endif 410238104Sdes return rid; 411238104Sdes} 412238104Sdes 413238104Sdes/* 414238104Sdes * BubbleBabble code taken from OpenSSH 415238104Sdes * Copyright (c) 2001 Carsten Raskgaard. All rights reserved. 416238104Sdes */ 417238104Sdeschar * 418238104Sdesldns_bubblebabble(uint8_t *data, size_t len) 419238104Sdes{ 420238104Sdes char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; 421238104Sdes char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 422238104Sdes 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; 423238104Sdes size_t i, j = 0, rounds, seed = 1; 424238104Sdes char *retval; 425238104Sdes 426238104Sdes rounds = (len / 2) + 1; 427238104Sdes retval = LDNS_XMALLOC(char, rounds * 6); 428238104Sdes if(!retval) return NULL; 429238104Sdes retval[j++] = 'x'; 430238104Sdes for (i = 0; i < rounds; i++) { 431238104Sdes size_t idx0, idx1, idx2, idx3, idx4; 432238104Sdes if ((i + 1 < rounds) || (len % 2 != 0)) { 433238104Sdes idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) + 434238104Sdes seed) % 6; 435238104Sdes idx1 = (((size_t)(data[2 * i])) >> 2) & 15; 436238104Sdes idx2 = ((((size_t)(data[2 * i])) & 3) + 437238104Sdes (seed / 6)) % 6; 438238104Sdes retval[j++] = vowels[idx0]; 439238104Sdes retval[j++] = consonants[idx1]; 440238104Sdes retval[j++] = vowels[idx2]; 441238104Sdes if ((i + 1) < rounds) { 442238104Sdes idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15; 443238104Sdes idx4 = (((size_t)(data[(2 * i) + 1]))) & 15; 444238104Sdes retval[j++] = consonants[idx3]; 445238104Sdes retval[j++] = '-'; 446238104Sdes retval[j++] = consonants[idx4]; 447238104Sdes seed = ((seed * 5) + 448238104Sdes ((((size_t)(data[2 * i])) * 7) + 449238104Sdes ((size_t)(data[(2 * i) + 1])))) % 36; 450238104Sdes } 451238104Sdes } else { 452238104Sdes idx0 = seed % 6; 453238104Sdes idx1 = 16; 454238104Sdes idx2 = seed / 6; 455238104Sdes retval[j++] = vowels[idx0]; 456238104Sdes retval[j++] = consonants[idx1]; 457238104Sdes retval[j++] = vowels[idx2]; 458238104Sdes } 459238104Sdes } 460238104Sdes retval[j++] = 'x'; 461238104Sdes retval[j++] = '\0'; 462238104Sdes return retval; 463238104Sdes} 464266114Sdes 465266114Sdes/* 466266114Sdes * For backwards compatibility, because we have always exported this symbol. 467266114Sdes */ 468266114Sdes#ifdef HAVE_B64_NTOP 469266114Sdesint ldns_b64_ntop(const uint8_t* src, size_t srclength, 470266114Sdes char *target, size_t targsize); 471266114Sdes{ 472266114Sdes return b64_ntop(src, srclength, target, targsize); 473266114Sdes} 474266114Sdes#endif 475266114Sdes 476266114Sdes/* 477266114Sdes * For backwards compatibility, because we have always exported this symbol. 478266114Sdes */ 479266114Sdes#ifdef HAVE_B64_PTON 480266114Sdesint ldns_b64_pton(const char* src, uint8_t *target, size_t targsize) 481266114Sdes{ 482266114Sdes return b64_pton(src, target, targsize); 483266114Sdes} 484266114Sdes#endif 485266114Sdes 486266114Sdes 487266114Sdesstatic int 488266114Sdesldns_b32_ntop_base(const uint8_t* src, size_t src_sz, 489266114Sdes char* dst, size_t dst_sz, 490266114Sdes bool extended_hex, bool add_padding) 491266114Sdes{ 492266114Sdes size_t ret_sz; 493266114Sdes const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv" 494266114Sdes : "abcdefghijklmnopqrstuvwxyz234567"; 495266114Sdes 496266114Sdes size_t c = 0; /* c is used to carry partial base32 character over 497266114Sdes * byte boundaries for sizes with a remainder. 498266114Sdes * (i.e. src_sz % 5 != 0) 499266114Sdes */ 500266114Sdes 501266114Sdes ret_sz = add_padding ? ldns_b32_ntop_calculate_size(src_sz) 502266114Sdes : ldns_b32_ntop_calculate_size_no_padding(src_sz); 503266114Sdes 504266114Sdes /* Do we have enough space? */ 505266114Sdes if (dst_sz < ret_sz + 1) 506266114Sdes return -1; 507266114Sdes 508266114Sdes /* We know the size; terminate the string */ 509266114Sdes dst[ret_sz] = '\0'; 510266114Sdes 511266114Sdes /* First process all chunks of five */ 512266114Sdes while (src_sz >= 5) { 513266114Sdes /* 00000... ........ ........ ........ ........ */ 514266114Sdes dst[0] = b32[(src[0] ) >> 3]; 515266114Sdes 516266114Sdes /* .....111 11...... ........ ........ ........ */ 517266114Sdes dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6]; 518266114Sdes 519266114Sdes /* ........ ..22222. ........ ........ ........ */ 520266114Sdes dst[2] = b32[(src[1] & 0x3e) >> 1]; 521266114Sdes 522266114Sdes /* ........ .......3 3333.... ........ ........ */ 523266114Sdes dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4]; 524266114Sdes 525266114Sdes /* ........ ........ ....4444 4....... ........ */ 526266114Sdes dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7]; 527266114Sdes 528266114Sdes /* ........ ........ ........ .55555.. ........ */ 529266114Sdes dst[5] = b32[(src[3] & 0x7c) >> 2]; 530266114Sdes 531266114Sdes /* ........ ........ ........ ......66 666..... */ 532266114Sdes dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5]; 533266114Sdes 534266114Sdes /* ........ ........ ........ ........ ...77777 */ 535266114Sdes dst[7] = b32[(src[4] & 0x1f) ]; 536266114Sdes 537266114Sdes src_sz -= 5; 538266114Sdes src += 5; 539266114Sdes dst += 8; 540266114Sdes } 541266114Sdes /* Process what remains */ 542266114Sdes switch (src_sz) { 543266114Sdes case 4: /* ........ ........ ........ ......66 666..... */ 544266114Sdes dst[6] = b32[(src[3] & 0x03) << 3]; 545266114Sdes 546266114Sdes /* ........ ........ ........ .55555.. ........ */ 547266114Sdes dst[5] = b32[(src[3] & 0x7c) >> 2]; 548266114Sdes 549266114Sdes /* ........ ........ ....4444 4....... ........ */ 550266114Sdes c = src[3] >> 7 ; 551266114Sdes case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; 552266114Sdes 553266114Sdes /* ........ .......3 3333.... ........ ........ */ 554266114Sdes c = src[2] >> 4 ; 555266114Sdes case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; 556266114Sdes 557266114Sdes /* ........ ..22222. ........ ........ ........ */ 558266114Sdes dst[2] = b32[(src[1] & 0x3e) >> 1]; 559266114Sdes 560266114Sdes /* .....111 11...... ........ ........ ........ */ 561266114Sdes c = src[1] >> 6 ; 562266114Sdes case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; 563266114Sdes 564266114Sdes /* 00000... ........ ........ ........ ........ */ 565266114Sdes dst[0] = b32[ src[0] >> 3]; 566266114Sdes } 567266114Sdes /* Add padding */ 568266114Sdes if (add_padding) { 569266114Sdes switch (src_sz) { 570266114Sdes case 1: dst[2] = '='; 571266114Sdes dst[3] = '='; 572266114Sdes case 2: dst[4] = '='; 573266114Sdes case 3: dst[5] = '='; 574266114Sdes dst[6] = '='; 575266114Sdes case 4: dst[7] = '='; 576266114Sdes } 577266114Sdes } 578266114Sdes return (int)ret_sz; 579266114Sdes} 580266114Sdes 581266114Sdesint 582266114Sdesldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 583266114Sdes{ 584266114Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); 585266114Sdes} 586266114Sdes 587266114Sdesint 588266114Sdesldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 589266114Sdes char* dst, size_t dst_sz) 590266114Sdes{ 591266114Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); 592266114Sdes} 593266114Sdes 594266114Sdes#ifndef HAVE_B32_NTOP 595266114Sdes 596266114Sdesint 597266114Sdesb32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 598266114Sdes{ 599266114Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); 600266114Sdes} 601266114Sdes 602266114Sdesint 603266114Sdesb32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 604266114Sdes char* dst, size_t dst_sz) 605266114Sdes{ 606266114Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); 607266114Sdes} 608266114Sdes 609266114Sdes#endif /* ! HAVE_B32_NTOP */ 610266114Sdes 611266114Sdesstatic int 612266114Sdesldns_b32_pton_base(const char* src, size_t src_sz, 613266114Sdes uint8_t* dst, size_t dst_sz, 614266114Sdes bool extended_hex, bool check_padding) 615266114Sdes{ 616266114Sdes size_t i = 0; 617266114Sdes char ch = '\0'; 618266114Sdes uint8_t buf[8]; 619266114Sdes uint8_t* start = dst; 620266114Sdes 621266114Sdes while (src_sz) { 622266114Sdes /* Collect 8 characters in buf (if possible) */ 623266114Sdes for (i = 0; i < 8; i++) { 624266114Sdes 625266114Sdes do { 626266114Sdes ch = *src++; 627266114Sdes --src_sz; 628266114Sdes 629266114Sdes } while (isspace(ch) && src_sz > 0); 630266114Sdes 631266114Sdes if (ch == '=' || ch == '\0') 632266114Sdes break; 633266114Sdes 634266114Sdes else if (extended_hex) 635266114Sdes 636266114Sdes if (ch >= '0' && ch <= '9') 637266114Sdes buf[i] = (uint8_t)ch - '0'; 638266114Sdes else if (ch >= 'a' && ch <= 'v') 639266114Sdes buf[i] = (uint8_t)ch - 'a' + 10; 640266114Sdes else if (ch >= 'A' && ch <= 'V') 641266114Sdes buf[i] = (uint8_t)ch - 'A' + 10; 642266114Sdes else 643266114Sdes return -1; 644266114Sdes 645266114Sdes else if (ch >= 'a' && ch <= 'z') 646266114Sdes buf[i] = (uint8_t)ch - 'a'; 647266114Sdes else if (ch >= 'A' && ch <= 'Z') 648266114Sdes buf[i] = (uint8_t)ch - 'A'; 649266114Sdes else if (ch >= '2' && ch <= '7') 650266114Sdes buf[i] = (uint8_t)ch - '2' + 26; 651266114Sdes else 652266114Sdes return -1; 653266114Sdes } 654266114Sdes /* Less that 8 characters. We're done. */ 655266114Sdes if (i < 8) 656266114Sdes break; 657266114Sdes 658266114Sdes /* Enough space available at the destination? */ 659266114Sdes if (dst_sz < 5) 660266114Sdes return -1; 661266114Sdes 662266114Sdes /* 00000... ........ ........ ........ ........ */ 663266114Sdes /* .....111 11...... ........ ........ ........ */ 664266114Sdes dst[0] = buf[0] << 3 | buf[1] >> 2; 665266114Sdes 666266114Sdes /* .....111 11...... ........ ........ ........ */ 667266114Sdes /* ........ ..22222. ........ ........ ........ */ 668266114Sdes /* ........ .......3 3333.... ........ ........ */ 669266114Sdes dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 670266114Sdes 671266114Sdes /* ........ .......3 3333.... ........ ........ */ 672266114Sdes /* ........ ........ ....4444 4....... ........ */ 673266114Sdes dst[2] = buf[3] << 4 | buf[4] >> 1; 674266114Sdes 675266114Sdes /* ........ ........ ....4444 4....... ........ */ 676266114Sdes /* ........ ........ ........ .55555.. ........ */ 677266114Sdes /* ........ ........ ........ ......66 666..... */ 678266114Sdes dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 679266114Sdes 680266114Sdes /* ........ ........ ........ ......66 666..... */ 681266114Sdes /* ........ ........ ........ ........ ...77777 */ 682266114Sdes dst[4] = buf[6] << 5 | buf[7]; 683266114Sdes 684266114Sdes dst += 5; 685266114Sdes dst_sz -= 5; 686266114Sdes } 687266114Sdes /* Not ending on a eight byte boundary? */ 688266114Sdes if (i > 0 && i < 8) { 689266114Sdes 690266114Sdes /* Enough space available at the destination? */ 691266114Sdes if (dst_sz < (i + 1) / 2) 692266114Sdes return -1; 693266114Sdes 694266114Sdes switch (i) { 695266114Sdes case 7: /* ........ ........ ........ ......66 666..... */ 696266114Sdes /* ........ ........ ........ .55555.. ........ */ 697266114Sdes /* ........ ........ ....4444 4....... ........ */ 698266114Sdes dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 699266114Sdes 700266114Sdes case 5: /* ........ ........ ....4444 4....... ........ */ 701266114Sdes /* ........ .......3 3333.... ........ ........ */ 702266114Sdes dst[2] = buf[3] << 4 | buf[4] >> 1; 703266114Sdes 704266114Sdes case 4: /* ........ .......3 3333.... ........ ........ */ 705266114Sdes /* ........ ..22222. ........ ........ ........ */ 706266114Sdes /* .....111 11...... ........ ........ ........ */ 707266114Sdes dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 708266114Sdes 709266114Sdes case 2: /* .....111 11...... ........ ........ ........ */ 710266114Sdes /* 00000... ........ ........ ........ ........ */ 711266114Sdes dst[0] = buf[0] << 3 | buf[1] >> 2; 712266114Sdes 713266114Sdes break; 714266114Sdes 715266114Sdes default: 716266114Sdes return -1; 717266114Sdes } 718266114Sdes dst += (i + 1) / 2; 719266114Sdes 720266114Sdes if (check_padding) { 721266114Sdes /* Check remaining padding characters */ 722266114Sdes if (ch != '=') 723266114Sdes return -1; 724266114Sdes 725266114Sdes /* One down, 8 - i - 1 more to come... */ 726266114Sdes for (i = 8 - i - 1; i > 0; i--) { 727266114Sdes 728266114Sdes do { 729266114Sdes if (src_sz == 0) 730266114Sdes return -1; 731266114Sdes ch = *src++; 732266114Sdes src_sz--; 733266114Sdes 734266114Sdes } while (isspace(ch)); 735266114Sdes 736266114Sdes if (ch != '=') 737266114Sdes return -1; 738266114Sdes } 739266114Sdes } 740266114Sdes } 741266114Sdes return dst - start; 742266114Sdes} 743266114Sdes 744266114Sdesint 745266114Sdesldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 746266114Sdes{ 747266114Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); 748266114Sdes} 749266114Sdes 750266114Sdesint 751266114Sdesldns_b32_pton_extended_hex(const char* src, size_t src_sz, 752266114Sdes uint8_t* dst, size_t dst_sz) 753266114Sdes{ 754266114Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); 755266114Sdes} 756266114Sdes 757266114Sdes#ifndef HAVE_B32_PTON 758266114Sdes 759266114Sdesint 760266114Sdesb32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 761266114Sdes{ 762266114Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); 763266114Sdes} 764266114Sdes 765266114Sdesint 766266114Sdesb32_pton_extended_hex(const char* src, size_t src_sz, 767266114Sdes uint8_t* dst, size_t dst_sz) 768266114Sdes{ 769266114Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); 770266114Sdes} 771266114Sdes 772266114Sdes#endif /* ! HAVE_B32_PTON */ 773266114Sdes 774