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> 23269257Sdes#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} 464269257Sdes 465269257Sdes/* 466269257Sdes * For backwards compatibility, because we have always exported this symbol. 467269257Sdes */ 468269257Sdes#ifdef HAVE_B64_NTOP 469269257Sdesint ldns_b64_ntop(const uint8_t* src, size_t srclength, 470269257Sdes char *target, size_t targsize); 471269257Sdes{ 472269257Sdes return b64_ntop(src, srclength, target, targsize); 473269257Sdes} 474269257Sdes#endif 475269257Sdes 476269257Sdes/* 477269257Sdes * For backwards compatibility, because we have always exported this symbol. 478269257Sdes */ 479269257Sdes#ifdef HAVE_B64_PTON 480269257Sdesint ldns_b64_pton(const char* src, uint8_t *target, size_t targsize) 481269257Sdes{ 482269257Sdes return b64_pton(src, target, targsize); 483269257Sdes} 484269257Sdes#endif 485269257Sdes 486269257Sdes 487269257Sdesstatic int 488269257Sdesldns_b32_ntop_base(const uint8_t* src, size_t src_sz, 489269257Sdes char* dst, size_t dst_sz, 490269257Sdes bool extended_hex, bool add_padding) 491269257Sdes{ 492269257Sdes size_t ret_sz; 493269257Sdes const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv" 494269257Sdes : "abcdefghijklmnopqrstuvwxyz234567"; 495269257Sdes 496269257Sdes size_t c = 0; /* c is used to carry partial base32 character over 497269257Sdes * byte boundaries for sizes with a remainder. 498269257Sdes * (i.e. src_sz % 5 != 0) 499269257Sdes */ 500269257Sdes 501269257Sdes ret_sz = add_padding ? ldns_b32_ntop_calculate_size(src_sz) 502269257Sdes : ldns_b32_ntop_calculate_size_no_padding(src_sz); 503269257Sdes 504269257Sdes /* Do we have enough space? */ 505269257Sdes if (dst_sz < ret_sz + 1) 506269257Sdes return -1; 507269257Sdes 508269257Sdes /* We know the size; terminate the string */ 509269257Sdes dst[ret_sz] = '\0'; 510269257Sdes 511269257Sdes /* First process all chunks of five */ 512269257Sdes while (src_sz >= 5) { 513269257Sdes /* 00000... ........ ........ ........ ........ */ 514269257Sdes dst[0] = b32[(src[0] ) >> 3]; 515269257Sdes 516269257Sdes /* .....111 11...... ........ ........ ........ */ 517269257Sdes dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6]; 518269257Sdes 519269257Sdes /* ........ ..22222. ........ ........ ........ */ 520269257Sdes dst[2] = b32[(src[1] & 0x3e) >> 1]; 521269257Sdes 522269257Sdes /* ........ .......3 3333.... ........ ........ */ 523269257Sdes dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4]; 524269257Sdes 525269257Sdes /* ........ ........ ....4444 4....... ........ */ 526269257Sdes dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7]; 527269257Sdes 528269257Sdes /* ........ ........ ........ .55555.. ........ */ 529269257Sdes dst[5] = b32[(src[3] & 0x7c) >> 2]; 530269257Sdes 531269257Sdes /* ........ ........ ........ ......66 666..... */ 532269257Sdes dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5]; 533269257Sdes 534269257Sdes /* ........ ........ ........ ........ ...77777 */ 535269257Sdes dst[7] = b32[(src[4] & 0x1f) ]; 536269257Sdes 537269257Sdes src_sz -= 5; 538269257Sdes src += 5; 539269257Sdes dst += 8; 540269257Sdes } 541269257Sdes /* Process what remains */ 542269257Sdes switch (src_sz) { 543269257Sdes case 4: /* ........ ........ ........ ......66 666..... */ 544269257Sdes dst[6] = b32[(src[3] & 0x03) << 3]; 545269257Sdes 546269257Sdes /* ........ ........ ........ .55555.. ........ */ 547269257Sdes dst[5] = b32[(src[3] & 0x7c) >> 2]; 548269257Sdes 549269257Sdes /* ........ ........ ....4444 4....... ........ */ 550269257Sdes c = src[3] >> 7 ; 551269257Sdes case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; 552269257Sdes 553269257Sdes /* ........ .......3 3333.... ........ ........ */ 554269257Sdes c = src[2] >> 4 ; 555269257Sdes case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; 556269257Sdes 557269257Sdes /* ........ ..22222. ........ ........ ........ */ 558269257Sdes dst[2] = b32[(src[1] & 0x3e) >> 1]; 559269257Sdes 560269257Sdes /* .....111 11...... ........ ........ ........ */ 561269257Sdes c = src[1] >> 6 ; 562269257Sdes case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; 563269257Sdes 564269257Sdes /* 00000... ........ ........ ........ ........ */ 565269257Sdes dst[0] = b32[ src[0] >> 3]; 566269257Sdes } 567269257Sdes /* Add padding */ 568269257Sdes if (add_padding) { 569269257Sdes switch (src_sz) { 570269257Sdes case 1: dst[2] = '='; 571269257Sdes dst[3] = '='; 572269257Sdes case 2: dst[4] = '='; 573269257Sdes case 3: dst[5] = '='; 574269257Sdes dst[6] = '='; 575269257Sdes case 4: dst[7] = '='; 576269257Sdes } 577269257Sdes } 578269257Sdes return (int)ret_sz; 579269257Sdes} 580269257Sdes 581269257Sdesint 582269257Sdesldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 583269257Sdes{ 584269257Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); 585269257Sdes} 586269257Sdes 587269257Sdesint 588269257Sdesldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 589269257Sdes char* dst, size_t dst_sz) 590269257Sdes{ 591269257Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); 592269257Sdes} 593269257Sdes 594269257Sdes#ifndef HAVE_B32_NTOP 595269257Sdes 596269257Sdesint 597269257Sdesb32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 598269257Sdes{ 599269257Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); 600269257Sdes} 601269257Sdes 602269257Sdesint 603269257Sdesb32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 604269257Sdes char* dst, size_t dst_sz) 605269257Sdes{ 606269257Sdes return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); 607269257Sdes} 608269257Sdes 609269257Sdes#endif /* ! HAVE_B32_NTOP */ 610269257Sdes 611269257Sdesstatic int 612269257Sdesldns_b32_pton_base(const char* src, size_t src_sz, 613269257Sdes uint8_t* dst, size_t dst_sz, 614269257Sdes bool extended_hex, bool check_padding) 615269257Sdes{ 616269257Sdes size_t i = 0; 617269257Sdes char ch = '\0'; 618269257Sdes uint8_t buf[8]; 619269257Sdes uint8_t* start = dst; 620269257Sdes 621269257Sdes while (src_sz) { 622269257Sdes /* Collect 8 characters in buf (if possible) */ 623269257Sdes for (i = 0; i < 8; i++) { 624269257Sdes 625269257Sdes do { 626269257Sdes ch = *src++; 627269257Sdes --src_sz; 628269257Sdes 629269257Sdes } while (isspace(ch) && src_sz > 0); 630269257Sdes 631269257Sdes if (ch == '=' || ch == '\0') 632269257Sdes break; 633269257Sdes 634269257Sdes else if (extended_hex) 635269257Sdes 636269257Sdes if (ch >= '0' && ch <= '9') 637269257Sdes buf[i] = (uint8_t)ch - '0'; 638269257Sdes else if (ch >= 'a' && ch <= 'v') 639269257Sdes buf[i] = (uint8_t)ch - 'a' + 10; 640269257Sdes else if (ch >= 'A' && ch <= 'V') 641269257Sdes buf[i] = (uint8_t)ch - 'A' + 10; 642269257Sdes else 643269257Sdes return -1; 644269257Sdes 645269257Sdes else if (ch >= 'a' && ch <= 'z') 646269257Sdes buf[i] = (uint8_t)ch - 'a'; 647269257Sdes else if (ch >= 'A' && ch <= 'Z') 648269257Sdes buf[i] = (uint8_t)ch - 'A'; 649269257Sdes else if (ch >= '2' && ch <= '7') 650269257Sdes buf[i] = (uint8_t)ch - '2' + 26; 651269257Sdes else 652269257Sdes return -1; 653269257Sdes } 654269257Sdes /* Less that 8 characters. We're done. */ 655269257Sdes if (i < 8) 656269257Sdes break; 657269257Sdes 658269257Sdes /* Enough space available at the destination? */ 659269257Sdes if (dst_sz < 5) 660269257Sdes return -1; 661269257Sdes 662269257Sdes /* 00000... ........ ........ ........ ........ */ 663269257Sdes /* .....111 11...... ........ ........ ........ */ 664269257Sdes dst[0] = buf[0] << 3 | buf[1] >> 2; 665269257Sdes 666269257Sdes /* .....111 11...... ........ ........ ........ */ 667269257Sdes /* ........ ..22222. ........ ........ ........ */ 668269257Sdes /* ........ .......3 3333.... ........ ........ */ 669269257Sdes dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 670269257Sdes 671269257Sdes /* ........ .......3 3333.... ........ ........ */ 672269257Sdes /* ........ ........ ....4444 4....... ........ */ 673269257Sdes dst[2] = buf[3] << 4 | buf[4] >> 1; 674269257Sdes 675269257Sdes /* ........ ........ ....4444 4....... ........ */ 676269257Sdes /* ........ ........ ........ .55555.. ........ */ 677269257Sdes /* ........ ........ ........ ......66 666..... */ 678269257Sdes dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 679269257Sdes 680269257Sdes /* ........ ........ ........ ......66 666..... */ 681269257Sdes /* ........ ........ ........ ........ ...77777 */ 682269257Sdes dst[4] = buf[6] << 5 | buf[7]; 683269257Sdes 684269257Sdes dst += 5; 685269257Sdes dst_sz -= 5; 686269257Sdes } 687269257Sdes /* Not ending on a eight byte boundary? */ 688269257Sdes if (i > 0 && i < 8) { 689269257Sdes 690269257Sdes /* Enough space available at the destination? */ 691269257Sdes if (dst_sz < (i + 1) / 2) 692269257Sdes return -1; 693269257Sdes 694269257Sdes switch (i) { 695269257Sdes case 7: /* ........ ........ ........ ......66 666..... */ 696269257Sdes /* ........ ........ ........ .55555.. ........ */ 697269257Sdes /* ........ ........ ....4444 4....... ........ */ 698269257Sdes dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 699269257Sdes 700269257Sdes case 5: /* ........ ........ ....4444 4....... ........ */ 701269257Sdes /* ........ .......3 3333.... ........ ........ */ 702269257Sdes dst[2] = buf[3] << 4 | buf[4] >> 1; 703269257Sdes 704269257Sdes case 4: /* ........ .......3 3333.... ........ ........ */ 705269257Sdes /* ........ ..22222. ........ ........ ........ */ 706269257Sdes /* .....111 11...... ........ ........ ........ */ 707269257Sdes dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 708269257Sdes 709269257Sdes case 2: /* .....111 11...... ........ ........ ........ */ 710269257Sdes /* 00000... ........ ........ ........ ........ */ 711269257Sdes dst[0] = buf[0] << 3 | buf[1] >> 2; 712269257Sdes 713269257Sdes break; 714269257Sdes 715269257Sdes default: 716269257Sdes return -1; 717269257Sdes } 718269257Sdes dst += (i + 1) / 2; 719269257Sdes 720269257Sdes if (check_padding) { 721269257Sdes /* Check remaining padding characters */ 722269257Sdes if (ch != '=') 723269257Sdes return -1; 724269257Sdes 725269257Sdes /* One down, 8 - i - 1 more to come... */ 726269257Sdes for (i = 8 - i - 1; i > 0; i--) { 727269257Sdes 728269257Sdes do { 729269257Sdes if (src_sz == 0) 730269257Sdes return -1; 731269257Sdes ch = *src++; 732269257Sdes src_sz--; 733269257Sdes 734269257Sdes } while (isspace(ch)); 735269257Sdes 736269257Sdes if (ch != '=') 737269257Sdes return -1; 738269257Sdes } 739269257Sdes } 740269257Sdes } 741269257Sdes return dst - start; 742269257Sdes} 743269257Sdes 744269257Sdesint 745269257Sdesldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 746269257Sdes{ 747269257Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); 748269257Sdes} 749269257Sdes 750269257Sdesint 751269257Sdesldns_b32_pton_extended_hex(const char* src, size_t src_sz, 752269257Sdes uint8_t* dst, size_t dst_sz) 753269257Sdes{ 754269257Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); 755269257Sdes} 756269257Sdes 757269257Sdes#ifndef HAVE_B32_PTON 758269257Sdes 759269257Sdesint 760269257Sdesb32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 761269257Sdes{ 762269257Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); 763269257Sdes} 764269257Sdes 765269257Sdesint 766269257Sdesb32_pton_extended_hex(const char* src, size_t src_sz, 767269257Sdes uint8_t* dst, size_t dst_sz) 768269257Sdes{ 769269257Sdes return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); 770269257Sdes} 771269257Sdes 772269257Sdes#endif /* ! HAVE_B32_PTON */ 773269257Sdes 774