monero/external/unbound/sldns/parseutil.c
Erik de Castro Lopo a85b5759f3 Upgrade unbound library
These files were pulled from the 1.6.3 release tarball.

This new version builds against OpenSSL version 1.1 which will be
the default in the new Debian Stable which is due to be released
RealSoonNow (tm).
2017-06-17 23:04:00 +10:00

727 lines
17 KiB
C

/*
* parseutil.c - parse utilities for string and wire conversion
*
* (c) NLnet Labs, 2004-2006
*
* See the file LICENSE for the license
*/
/**
* \file
*
* Utility functions for parsing, base32(DNS variant) and base64 encoding
* and decoding, Hex, Time units, Escape codes.
*/
#include "config.h"
#include "sldns/parseutil.h"
#include <sys/time.h>
#include <time.h>
#include <ctype.h>
sldns_lookup_table *
sldns_lookup_by_name(sldns_lookup_table *table, const char *name)
{
while (table->name != NULL) {
if (strcasecmp(name, table->name) == 0)
return table;
table++;
}
return NULL;
}
sldns_lookup_table *
sldns_lookup_by_id(sldns_lookup_table *table, int id)
{
while (table->name != NULL) {
if (table->id == id)
return table;
table++;
}
return NULL;
}
/* Number of days per month (except for February in leap years). */
static const int mdays[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y)))
#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y)))
static int
is_leap_year(int year)
{
return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0
|| LDNS_MOD(year, 400) == 0);
}
static int
leap_days(int y1, int y2)
{
--y1;
--y2;
return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) -
(LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) +
(LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400));
}
/*
* Code adapted from Python 2.4.1 sources (Lib/calendar.py).
*/
time_t
sldns_mktime_from_utc(const struct tm *tm)
{
int year = 1900 + tm->tm_year;
time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year);
time_t hours;
time_t minutes;
time_t seconds;
int i;
for (i = 0; i < tm->tm_mon; ++i) {
days += mdays[i];
}
if (tm->tm_mon > 1 && is_leap_year(year)) {
++days;
}
days += tm->tm_mday - 1;
hours = days * 24 + tm->tm_hour;
minutes = hours * 60 + tm->tm_min;
seconds = minutes * 60 + tm->tm_sec;
return seconds;
}
#if SIZEOF_TIME_T <= 4
static void
sldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result)
{
int year = 1970;
int new_year;
while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) {
new_year = year + (int) LDNS_DIV(days, 365);
days -= (new_year - year) * 365;
days -= leap_days(year, new_year);
year = new_year;
}
result->tm_year = year;
result->tm_yday = (int) days;
}
/* Number of days per month in a leap year. */
static const int leap_year_mdays[] = {
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static void
sldns_mon_and_mday_from_year_and_yday(struct tm *result)
{
int idays = result->tm_yday;
const int *mon_lengths = is_leap_year(result->tm_year) ?
leap_year_mdays : mdays;
result->tm_mon = 0;
while (idays >= mon_lengths[result->tm_mon]) {
idays -= mon_lengths[result->tm_mon++];
}
result->tm_mday = idays + 1;
}
static void
sldns_wday_from_year_and_yday(struct tm *result)
{
result->tm_wday = 4 /* 1-1-1970 was a thursday */
+ LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7)
+ leap_days(1970, result->tm_year)
+ result->tm_yday;
result->tm_wday = LDNS_MOD(result->tm_wday, 7);
if (result->tm_wday < 0) {
result->tm_wday += 7;
}
}
static struct tm *
sldns_gmtime64_r(int64_t clock, struct tm *result)
{
result->tm_isdst = 0;
result->tm_sec = (int) LDNS_MOD(clock, 60);
clock = LDNS_DIV(clock, 60);
result->tm_min = (int) LDNS_MOD(clock, 60);
clock = LDNS_DIV(clock, 60);
result->tm_hour = (int) LDNS_MOD(clock, 24);
clock = LDNS_DIV(clock, 24);
sldns_year_and_yday_from_days_since_epoch(clock, result);
sldns_mon_and_mday_from_year_and_yday(result);
sldns_wday_from_year_and_yday(result);
result->tm_year -= 1900;
return result;
}
#endif /* SIZEOF_TIME_T <= 4 */
static int64_t
sldns_serial_arithmitics_time(int32_t time, time_t now)
{
int32_t offset = time - (int32_t) now;
return (int64_t) now + offset;
}
struct tm *
sldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
{
#if SIZEOF_TIME_T <= 4
int64_t secs_since_epoch = sldns_serial_arithmitics_time(time, now);
return sldns_gmtime64_r(secs_since_epoch, result);
#else
time_t secs_since_epoch = sldns_serial_arithmitics_time(time, now);
return gmtime_r(&secs_since_epoch, result);
#endif
}
int
sldns_hexdigit_to_int(char ch)
{
switch (ch) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default:
return -1;
}
}
uint32_t
sldns_str2period(const char *nptr, const char **endptr)
{
int sign = 0;
uint32_t i = 0;
uint32_t seconds = 0;
for(*endptr = nptr; **endptr; (*endptr)++) {
switch (**endptr) {
case ' ':
case '\t':
break;
case '-':
if(sign == 0) {
sign = -1;
} else {
return seconds;
}
break;
case '+':
if(sign == 0) {
sign = 1;
} else {
return seconds;
}
break;
case 's':
case 'S':
seconds += i;
i = 0;
break;
case 'm':
case 'M':
seconds += i * 60;
i = 0;
break;
case 'h':
case 'H':
seconds += i * 60 * 60;
i = 0;
break;
case 'd':
case 'D':
seconds += i * 60 * 60 * 24;
i = 0;
break;
case 'w':
case 'W':
seconds += i * 60 * 60 * 24 * 7;
i = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
i *= 10;
i += (**endptr - '0');
break;
default:
seconds += i;
/* disregard signedness */
return seconds;
}
}
seconds += i;
/* disregard signedness */
return seconds;
}
int
sldns_parse_escape(uint8_t *ch_p, const char** str_p)
{
uint16_t val;
if ((*str_p)[0] && isdigit((unsigned char)(*str_p)[0]) &&
(*str_p)[1] && isdigit((unsigned char)(*str_p)[1]) &&
(*str_p)[2] && isdigit((unsigned char)(*str_p)[2])) {
val = (uint16_t)(((*str_p)[0] - '0') * 100 +
((*str_p)[1] - '0') * 10 +
((*str_p)[2] - '0'));
if (val > 255) {
goto error;
}
*ch_p = (uint8_t)val;
*str_p += 3;
return 1;
} else if ((*str_p)[0] && !isdigit((unsigned char)(*str_p)[0])) {
*ch_p = (uint8_t)*(*str_p)++;
return 1;
}
error:
*str_p = NULL;
return 0; /* LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE */
}
/** parse one character, with escape codes */
int
sldns_parse_char(uint8_t *ch_p, const char** str_p)
{
switch (**str_p) {
case '\0': return 0;
case '\\': *str_p += 1;
return sldns_parse_escape(ch_p, str_p);
default: *ch_p = (uint8_t)*(*str_p)++;
return 1;
}
}
size_t sldns_b32_ntop_calculate_size(size_t src_data_length)
{
return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8;
}
size_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length)
{
return ((src_data_length + 3) * 8 / 5) - 4;
}
static int
sldns_b32_ntop_base(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz,
int extended_hex, int add_padding)
{
size_t ret_sz;
const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv"
: "abcdefghijklmnopqrstuvwxyz234567";
size_t c = 0; /* c is used to carry partial base32 character over
* byte boundaries for sizes with a remainder.
* (i.e. src_sz % 5 != 0)
*/
ret_sz = add_padding ? sldns_b32_ntop_calculate_size(src_sz)
: sldns_b32_ntop_calculate_size_no_padding(src_sz);
/* Do we have enough space? */
if (dst_sz < ret_sz + 1)
return -1;
/* We know the size; terminate the string */
dst[ret_sz] = '\0';
/* First process all chunks of five */
while (src_sz >= 5) {
/* 00000... ........ ........ ........ ........ */
dst[0] = b32[(src[0] ) >> 3];
/* .....111 11...... ........ ........ ........ */
dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6];
/* ........ ..22222. ........ ........ ........ */
dst[2] = b32[(src[1] & 0x3e) >> 1];
/* ........ .......3 3333.... ........ ........ */
dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4];
/* ........ ........ ....4444 4....... ........ */
dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7];
/* ........ ........ ........ .55555.. ........ */
dst[5] = b32[(src[3] & 0x7c) >> 2];
/* ........ ........ ........ ......66 666..... */
dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5];
/* ........ ........ ........ ........ ...77777 */
dst[7] = b32[(src[4] & 0x1f) ];
src_sz -= 5;
src += 5;
dst += 8;
}
/* Process what remains */
switch (src_sz) {
case 4: /* ........ ........ ........ ......66 666..... */
dst[6] = b32[(src[3] & 0x03) << 3];
/* ........ ........ ........ .55555.. ........ */
dst[5] = b32[(src[3] & 0x7c) >> 2];
/* ........ ........ ....4444 4....... ........ */
c = src[3] >> 7 ;
case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c];
/* ........ .......3 3333.... ........ ........ */
c = src[2] >> 4 ;
case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c];
/* ........ ..22222. ........ ........ ........ */
dst[2] = b32[(src[1] & 0x3e) >> 1];
/* .....111 11...... ........ ........ ........ */
c = src[1] >> 6 ;
case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c];
/* 00000... ........ ........ ........ ........ */
dst[0] = b32[ src[0] >> 3];
}
/* Add padding */
if (add_padding) {
switch (src_sz) {
case 1: dst[2] = '=';
dst[3] = '=';
case 2: dst[4] = '=';
case 3: dst[5] = '=';
dst[6] = '=';
case 4: dst[7] = '=';
}
}
return (int)ret_sz;
}
int
sldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
{
return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 0, 1);
}
int
sldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
char* dst, size_t dst_sz)
{
return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 1, 1);
}
size_t sldns_b32_pton_calculate_size(size_t src_text_length)
{
return src_text_length * 5 / 8;
}
static int
sldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz,
int extended_hex, int check_padding)
{
size_t i = 0;
char ch = '\0';
uint8_t buf[8];
uint8_t* start = dst;
while (src_sz) {
/* Collect 8 characters in buf (if possible) */
for (i = 0; i < 8; i++) {
do {
ch = *src++;
--src_sz;
} while (isspace((unsigned char)ch) && src_sz > 0);
if (ch == '=' || ch == '\0')
break;
else if (extended_hex)
if (ch >= '0' && ch <= '9')
buf[i] = (uint8_t)ch - '0';
else if (ch >= 'a' && ch <= 'v')
buf[i] = (uint8_t)ch - 'a' + 10;
else if (ch >= 'A' && ch <= 'V')
buf[i] = (uint8_t)ch - 'A' + 10;
else
return -1;
else if (ch >= 'a' && ch <= 'z')
buf[i] = (uint8_t)ch - 'a';
else if (ch >= 'A' && ch <= 'Z')
buf[i] = (uint8_t)ch - 'A';
else if (ch >= '2' && ch <= '7')
buf[i] = (uint8_t)ch - '2' + 26;
else
return -1;
}
/* Less that 8 characters. We're done. */
if (i < 8)
break;
/* Enough space available at the destination? */
if (dst_sz < 5)
return -1;
/* 00000... ........ ........ ........ ........ */
/* .....111 11...... ........ ........ ........ */
dst[0] = buf[0] << 3 | buf[1] >> 2;
/* .....111 11...... ........ ........ ........ */
/* ........ ..22222. ........ ........ ........ */
/* ........ .......3 3333.... ........ ........ */
dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
/* ........ .......3 3333.... ........ ........ */
/* ........ ........ ....4444 4....... ........ */
dst[2] = buf[3] << 4 | buf[4] >> 1;
/* ........ ........ ....4444 4....... ........ */
/* ........ ........ ........ .55555.. ........ */
/* ........ ........ ........ ......66 666..... */
dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
/* ........ ........ ........ ......66 666..... */
/* ........ ........ ........ ........ ...77777 */
dst[4] = buf[6] << 5 | buf[7];
dst += 5;
dst_sz -= 5;
}
/* Not ending on a eight byte boundary? */
if (i > 0 && i < 8) {
/* Enough space available at the destination? */
if (dst_sz < (i + 1) / 2)
return -1;
switch (i) {
case 7: /* ........ ........ ........ ......66 666..... */
/* ........ ........ ........ .55555.. ........ */
/* ........ ........ ....4444 4....... ........ */
dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
case 5: /* ........ ........ ....4444 4....... ........ */
/* ........ .......3 3333.... ........ ........ */
dst[2] = buf[3] << 4 | buf[4] >> 1;
case 4: /* ........ .......3 3333.... ........ ........ */
/* ........ ..22222. ........ ........ ........ */
/* .....111 11...... ........ ........ ........ */
dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
case 2: /* .....111 11...... ........ ........ ........ */
/* 00000... ........ ........ ........ ........ */
dst[0] = buf[0] << 3 | buf[1] >> 2;
break;
default:
return -1;
}
dst += (i + 1) / 2;
if (check_padding) {
/* Check remaining padding characters */
if (ch != '=')
return -1;
/* One down, 8 - i - 1 more to come... */
for (i = 8 - i - 1; i > 0; i--) {
do {
if (src_sz == 0)
return -1;
ch = *src++;
src_sz--;
} while (isspace((unsigned char)ch));
if (ch != '=')
return -1;
}
}
}
return dst - start;
}
int
sldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
{
return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 0, 1);
}
int
sldns_b32_pton_extended_hex(const char* src, size_t src_sz,
uint8_t* dst, size_t dst_sz)
{
return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 1, 1);
}
size_t sldns_b64_ntop_calculate_size(size_t srcsize)
{
return ((((srcsize + 2) / 3) * 4) + 1);
}
/* RFC 1521, section 5.2.
*
* The encoding process represents 24-bit groups of input bits as output
* strings of 4 encoded characters. Proceeding from left to right, a
* 24-bit input group is formed by concatenating 3 8-bit input groups.
* These 24 bits are then treated as 4 concatenated 6-bit groups, each
* of which is translated into a single digit in the base64 alphabet.
*
* This routine does not insert spaces or linebreaks after 76 characters.
*/
int sldns_b64_ntop(uint8_t const *src, size_t srclength,
char *target, size_t targsize)
{
const char* b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char pad64 = '=';
size_t i = 0, o = 0;
if(targsize < sldns_b64_ntop_calculate_size(srclength))
return -1;
/* whole chunks: xxxxxxyy yyyyzzzz zzwwwwww */
while(i+3 <= srclength) {
if(o+4 > targsize) return -1;
target[o] = b64[src[i] >> 2];
target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ];
target[o+2] = b64[ ((src[i+1]&0x0f)<<2) | (src[i+2]>>6) ];
target[o+3] = b64[ (src[i+2]&0x3f) ];
i += 3;
o += 4;
}
/* remainder */
switch(srclength - i) {
case 2:
/* two at end, converted into A B C = */
target[o] = b64[src[i] >> 2];
target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ];
target[o+2] = b64[ ((src[i+1]&0x0f)<<2) ];
target[o+3] = pad64;
/* i += 2; */
o += 4;
break;
case 1:
/* one at end, converted into A B = = */
target[o] = b64[src[i] >> 2];
target[o+1] = b64[ ((src[i]&0x03)<<4) ];
target[o+2] = pad64;
target[o+3] = pad64;
/* i += 1; */
o += 4;
break;
case 0:
default:
/* nothing */
break;
}
/* assert: i == srclength */
if(o+1 > targsize) return -1;
target[o] = 0;
return (int)o;
}
size_t sldns_b64_pton_calculate_size(size_t srcsize)
{
return (((((srcsize + 3) / 4) * 3)) + 1);
}
int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize)
{
const uint8_t pad64 = 64; /* is 64th in the b64 array */
const char* s = src;
uint8_t in[4];
size_t o = 0, incount = 0;
while(*s) {
/* skip any character that is not base64 */
/* conceptually we do:
const char* b64 = pad'=' is appended to array
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
const char* d = strchr(b64, *s++);
and use d-b64;
*/
char d = *s++;
if(d <= 'Z' && d >= 'A')
d -= 'A';
else if(d <= 'z' && d >= 'a')
d = d - 'a' + 26;
else if(d <= '9' && d >= '0')
d = d - '0' + 52;
else if(d == '+')
d = 62;
else if(d == '/')
d = 63;
else if(d == '=')
d = 64;
else continue;
in[incount++] = (uint8_t)d;
if(incount != 4)
continue;
/* process whole block of 4 characters into 3 output bytes */
if(in[3] == pad64 && in[2] == pad64) { /* A B = = */
if(o+1 > targsize)
return -1;
target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
o += 1;
break; /* we are done */
} else if(in[3] == pad64) { /* A B C = */
if(o+2 > targsize)
return -1;
target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
o += 2;
break; /* we are done */
} else {
if(o+3 > targsize)
return -1;
/* write xxxxxxyy yyyyzzzz zzwwwwww */
target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
target[o+2]= ((in[2]&0x03)<<6) | in[3];
o += 3;
}
incount = 0;
}
return (int)o;
}