#ifndef TTL_H
#define TTL_H
static const uint32_t ttl_units[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
0, 0, 0, 1, 0, 0, 0, 604800, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 86400, 0, 0, 0, 3600, 0, 0, 0, 0, 60, 0, 0,
0, 0, 0, 1, 0, 0, 0, 604800, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
nonnull_all
static really_inline int32_t scan_ttl(
const char *data, size_t length, bool allow_units, uint32_t *ttl)
{
if (scan_int32(data, length, ttl))
return 1;
if (!allow_units)
return 0;
uint64_t sum = 0, number = (uint8_t)data[0] - '0';
if (number > 9)
return 0;
uint64_t unit = 0, last_unit = 0;
enum { NUMBER, UNIT } state = NUMBER;
for (size_t count = 1; count < length; count++) {
const uint64_t digit = (uint8_t)data[count] - '0';
if (state == NUMBER) {
if (digit < 10) {
number = number * 10 + digit;
if (number > UINT32_MAX)
return 0;
} else if (!(unit = ttl_units[ (uint8_t)data[count] ])) {
return 0;
} else if (unit == last_unit) {
return 0;
} else if (unit < last_unit) {
return 0;
} else {
if (UINT32_MAX / unit < number)
return 0;
number *= unit;
if (UINT32_MAX - sum < number)
return 0;
last_unit = unit;
sum += number;
number = 0;
state = UNIT;
}
} else if (state == UNIT) {
if (digit > 9)
return 0;
if (last_unit == 1)
return 0;
number = digit;
state = NUMBER;
}
}
if (UINT32_MAX - sum < number)
return 0;
sum += number;
*ttl = (uint32_t)sum;
return 1;
}
nonnull_all
static really_inline int32_t parse_ttl(
parser_t *parser,
const type_info_t *type,
const rdata_info_t *field,
rdata_t *rdata,
const token_t *token)
{
uint32_t ttl;
if (!scan_ttl(token->data, token->length, parser->options.pretty_ttls, &ttl))
SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
if (ttl & (1u << 31))
SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type));
ttl = htobe32(ttl);
memcpy(rdata->octets, &ttl, sizeof(ttl));
rdata->octets += 4;
return 0;
}
#endif