diff --git a/CMakeLists.txt b/CMakeLists.txt index 831bb45..adf4c8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,7 +135,6 @@ target_include_directories( target_sources(zone PRIVATE src/zone.c - src/types.c src/log.c src/parser.c src/fallback/parser.c diff --git a/README.md b/README.md index 7227145..2aa9ff3 100644 --- a/README.md +++ b/README.md @@ -25,15 +25,15 @@ similar performance boost for parsing zone data. Running `zone-bench` on my system (Intel Core i7-1065G7) against an older `.com` zone file of 12482791271 bytes under Linux (Fedora 37). -GCC 12.2.1, release mode: +clang version 15.0.7, release mode: ``` $ time ./zone-bench parse ../../zones/com.zone Selected target haswell Parsed 341535548 records -real 0m18.721s -user 0m17.503s -sys 0m1.181s +real 0m16.344s +user 0m15.125s +sys 0m1.165s ``` There are bound to be bugs and quite possibly smarter ways of implementing diff --git a/include/zone.h b/include/zone.h index a14ed99..061fb6a 100644 --- a/include/zone.h +++ b/include/zone.h @@ -183,9 +183,6 @@ extern "C" { #define ZONE_DLV (32769u) /** @} */ -typedef int32_t zone_code_t; -typedef int32_t zone_return_t; - typedef struct zone_string zone_string_t; struct zone_string { size_t length; @@ -194,7 +191,10 @@ struct zone_string { typedef struct zone_symbol zone_symbol_t; struct zone_symbol { - zone_string_t key; + struct { + char data[24]; // zero padded for convenient vectorized comparison + size_t length; + } key; uint32_t value; }; @@ -204,34 +204,6 @@ struct zone_table { const zone_symbol_t *symbols; // sorted for use with bsearch }; -// @private -// -// bsearch is quite slow compared to a hash table, but a hash table is either -// quite big or there is a significant chance or collisions. a minimal perfect -// hash table can be used instead, but there is a good chance of mispredicted -// branches. -// -// the fast table provides a hybrid solution. the current incarnation uses the -// first (upper case) character to make a first selection. the last character -// is permuted and used as key for the smaller table. in practice, it should -// effectively function as a one-level radix trie without branching. -// -// the permutation used is the following. -// 1. use the last character as one always exists, token length is available, -// is very likely alphanumeric and likely does not reoccur too often for -// records starting with the same alphabetic character. this will provide -// a unique key for e.g. MB, MD, MF MG, MR, MX and e.g. NSEC, NSEC3. -// 2. multiply the character by a given number to get a reasonably good -// distribution. -// 3. increment the character by the length of the identifier to ensure -// unique keys for identifiers that begin and end with the same -// characters. e.g. A and AAAA. -typedef struct zone_fast_table zone_fast_table_t; -struct zone_fast_table { - uint8_t keys[16]; - const zone_symbol_t *symbols[16]; -}; - /** * @brief Type of value defined by field * @@ -326,6 +298,7 @@ typedef enum { #define ZONE_CAA_TAG (1u << 12) /** @} */ +// FIXME: drop rdata_info, just use field_info typedef struct zone_rdata_info zone_rdata_info_t; struct zone_rdata_info { zone_string_t name; @@ -351,8 +324,7 @@ typedef struct zone_rdata_info zone_field_info_t; typedef struct zone_type_info zone_type_info_t; struct zone_type_info { - zone_string_t name; - uint16_t code; + zone_symbol_t name; uint32_t options; struct { size_t length; @@ -508,7 +480,7 @@ struct zone_name { // invoked for each record (host order). header (owner, type, class and ttl) // fields are passed individually for convenience. rdata fields can be visited // individually by means of the iterator -typedef zone_return_t(*zone_add_t)( +typedef int32_t(*zone_add_t)( zone_parser_t *, const zone_name_t *, // owner (length + octets) uint16_t, // type @@ -615,7 +587,7 @@ struct zone_parser { /** * @brief Parse zone file */ -ZONE_EXPORT zone_return_t +ZONE_EXPORT int32_t zone_parse( zone_parser_t *parser, const zone_options_t *options, @@ -627,7 +599,7 @@ zone_nonnull((1,2,3,4)); /** * @brief Parse zone from string */ -ZONE_EXPORT zone_return_t +ZONE_EXPORT int32_t zone_parse_string( zone_parser_t *parser, const zone_options_t *options, diff --git a/scripts/hash.c b/scripts/hash.c new file mode 100755 index 0000000..189448c --- /dev/null +++ b/scripts/hash.c @@ -0,0 +1,161 @@ +/* + * hash.c -- Calculate perfect hash for TYPEs and CLASSes + * + * Copyright (c) 2023, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include + +typedef struct tuple tuple_t; +struct tuple { + char name[16]; + uint16_t code; + bool type; +}; + +static const tuple_t types_and_classes[] = { + // classes + { "IN", 1, false }, + { "CS", 2, false }, + { "CH", 3, false }, + { "HS", 4, false }, + // types + { "A", 1, true }, + { "NS", 2, true }, + { "MD", 3, true }, + { "MF", 4, true }, + { "CNAME", 5, true }, + { "SOA", 6, true }, + { "MB", 7, true }, + { "MG", 8, true }, + { "MR", 9, true }, + { "NULL", 10, true }, + { "WKS", 11, true }, + { "PTR", 12, true }, + { "HINFO", 13, true }, + { "MINFO", 14, true }, + { "MX", 15, true }, + { "TXT", 16, true }, + { "RP", 17, true }, + { "AFSDB", 18, true }, + { "X25", 19, true }, + { "ISDN", 20, true }, + { "RT", 21, true }, + { "NSAP", 22, true }, + { "NSAP-PTR", 23, true }, + { "SIG", 24, true }, + { "KEY", 25, true }, + { "PX", 26, true }, + { "GPOS", 27, true }, + { "AAAA", 28, true }, + { "LOC", 29, true }, + { "NXT", 30, true }, + { "SRV", 33, true }, + { "NAPTR", 35, true }, + { "KX", 36, true }, + { "CERT", 37, true }, + { "A6", 38, true }, + { "DNAME", 39, true }, + { "APL", 42, true }, + { "DS", 43, true }, + { "SSHFP", 44, true }, + { "IPSECKEY", 45, true }, + { "RRSIG", 46, true }, + { "NSEC", 47, true }, + { "DNSKEY", 48, true }, + { "DHCID", 49, true }, + { "NSEC3", 50, true }, + { "NSEC3PARAM", 51, true }, + { "TLSA", 52, true }, + { "SMIMEA", 53, true }, + { "HIP", 55, true }, + { "CDS", 59, true }, + { "CDNSKEY", 60, true }, + { "OPENPGPKEY", 61, true }, + { "CSYNC", 62, true }, + { "ZONEMD", 63, true }, + { "SVCB", 64, true }, + { "HTTPS", 65, true }, + { "SPF", 99, true }, + { "NID", 104, true }, + { "L32", 105, true }, + { "L64", 106, true }, + { "LP", 107, true }, + { "EUI48", 108, true }, + { "EUI64", 109, true }, + { "URI", 256, true }, + { "CAA", 257, true }, + { "AVC", 258, true }, + { "DLV", 32769, true } +}; + +const uint64_t original_magic = 3523216699ull; // original hash from hash.cpp + +static uint8_t hash(uint64_t magic, uint64_t value) +{ + uint32_t value32 = ((value >> 32) ^ value); + return (value32 * magic) >> 32; +} + +static void print_table(uint64_t magic) +{ + struct { uint16_t code; bool type; } keys[256]; + memset(keys, 0, sizeof(keys)); + const size_t n = sizeof(types_and_classes)/sizeof(types_and_classes[0]); + for (size_t i=0; i < n; i++) { + uint64_t value; + memcpy(&value, types_and_classes[i].name, 8); + uint8_t key = hash(magic, value); + keys[key].code = types_and_classes[i].code; + keys[key].type = types_and_classes[i].type; + } + + printf("static const symbol_t *hash_to_symbol[256] = {\n"); + for (size_t i=0; i < 256; ) { + for (size_t j=i+8; i < j; i++) { + uint16_t code = keys[i].code; + char macro = !code || keys[i].type ? 'T' : 'C'; + printf("%c(%u), ", macro, code); + } + printf("\n"); + } + printf("};\n"); +} + +int main(int argc, char *argv[]) +{ + const size_t n = sizeof(types_and_classes)/sizeof(types_and_classes[0]); + for (uint64_t magic = original_magic; magic < UINT64_MAX; magic++) { + size_t i; + uint16_t keys[256] = { 0 }; + for (i=0; i < n; i++) { + uint64_t value; + memcpy(&value, types_and_classes[i].name, 8); + + uint8_t key = hash(magic, value); + if (keys[key]) + break; + keys[key] = 1; + } + + if (i == n) { + printf("i: %zu, magic: %" PRIu64 "\n", i, magic); + for (i=0; i < n; i++) { + uint64_t value; + memcpy(&value, types_and_classes[i].name, 8); + uint8_t key = hash(magic, value); + printf("TYPE_%s: %" PRIu8 " (%" PRIu16 ")\n", types_and_classes[i].name, key, types_and_classes[i].code); + } + print_table(magic); + return 0; + } + } + + printf("no magic value\n"); + return 1; +} diff --git a/scripts/keys.py b/scripts/keys.py deleted file mode 100755 index 0171738..0000000 --- a/scripts/keys.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/python -# -# keys.py -- generate key material for fast identifier table -# -# Copyright (c) 2023, NLnet Labs. All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# - -classes = [ 'CH', 'CS', 'HS', 'IN' ] - -types = [ - 'A', 'A6', 'AAAA', 'AFSDB', 'APL', 'AVC', - 'CAA', 'CDS', 'CDNSKEY', 'CERT', 'CNAME', 'CSYNC', - 'DNAME', 'DS', 'DNSKEY', 'DHCID', 'DLV', - 'EUI48', 'EUI64', - 'GPOS', - 'HINFO', 'HIP', 'HTTPS', - 'IPSECKEY', 'ISDN', - 'KEY', 'KX', - 'L32', 'L64', 'LOC', 'LP', - 'MB', 'MD', 'MF', 'MG', 'MINFO', 'MR', 'MX', - 'NAPTR', 'NID', 'NS', 'NSAP', 'NSAP-PTR', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'NULL', 'NXT', - 'OPENPGPKEY', 'OPT', - 'PTR', 'PX', - 'RP', 'RRSIG', 'RT', - 'SIG', 'SMIMEA', 'SOA', 'SPF', 'SRV', 'SSHFP', 'SVCB', - 'TXT', 'TLSA', - 'URI', - 'WKS', - 'X25', - 'ZONEMD', -] - -keys = [[0 for x in range(255)] for y in range(32)] - -for c in classes: - k = ((ord(c[0]) & 0xdf) - 0x41) & 0x1f - h = ((ord(c[-1]) & 0xdf)) - h = (h * 0x07) - h = (h + len(c)) & 0xff - if keys[k][h]: - print(f'class: {c}, key: {k}, hash: {h} (collision)') - else: - print(f'class: {c}, key: {k}, hash: {h}') - keys[k][h] = True - -for c in types: - k = ((ord(c[0]) & 0xdf) - 0x41) & 0x1f - h = ((ord(c[-1]) & 0xdf)) - h = (h * 0x07) - h = (h + len(c)) & 0xff - if keys[k][h]: - print(f'type: {c}, key: {k}, hash: {h} (collision)') - else: - print(f'type: {c}, key: {k}, hash: {h}') - keys[k][h] = True diff --git a/src/fallback/ip4.h b/src/fallback/ip4.h index 2bb1dac..5a658b3 100644 --- a/src/fallback/ip4.h +++ b/src/fallback/ip4.h @@ -34,7 +34,7 @@ static zone_really_inline int32_t parse_ip4( n = n * 10 + (uint8_t)d; } else { if (!(p - ps) || p - ps > 3 || n < m[(p - ps)] || n > 255 || o - os > 3) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); ps = p + 1; *o++ = (uint8_t)n; if (*p != '.') @@ -44,7 +44,7 @@ static zone_really_inline int32_t parse_ip4( } if (is_contiguous((uint8_t)*p) || o - os != 4) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->length += 4; return ZONE_IP4; diff --git a/src/fallback/name.h b/src/fallback/name.h index 0223b62..d422618 100644 --- a/src/fallback/name.h +++ b/src/fallback/name.h @@ -39,20 +39,20 @@ static zone_really_inline int32_t scan_name( d[1] = (uint8_t)s[2] - '0'; d[2] = (uint8_t)s[3] - '0'; if (d[1] > m || d[2] > m) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); b[0] = d[0] * 100 + d[1] * 10 + d[0]; b += 1; s += 4; } } else if (c == '.') { if ((b - 1) - l > 63 || (b - 1) - l == 0) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); l[0] = (uint8_t)((b - 1) - l); l = b; l[0] = 0; b += 1; s += 1; } else if (delimiters[c] != token->code) { if ((b - 1) - l > 63) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); l[0] = (uint8_t)((b - 1) - l); break; } else { @@ -62,7 +62,7 @@ static zone_really_inline int32_t scan_name( } if (delimiters[(uint8_t)*s] == token->code) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); *length = (size_t)(b - octets); return l[0] == 0 ? 0 : ZONE_NAME; @@ -124,7 +124,7 @@ static zone_really_inline int32_t parse_name( relative: if (n > 255 - parser->file->origin.length) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); memcpy(o+n, parser->file->origin.octets, parser->file->origin.length); parser->rdata->length += n + parser->file->origin.length; return ZONE_NAME; diff --git a/src/fallback/parser.c b/src/fallback/parser.c index cde1194..bc552b0 100644 --- a/src/fallback/parser.c +++ b/src/fallback/parser.c @@ -14,9 +14,8 @@ #include "fallback/scanner.h" #include "generic/number.h" #include "generic/ttl.h" -#include "generic/time.h" +#include "fallback/time.h" #include "fallback/name.h" -#include "fallback/type.h" #include "fallback/ip4.h" #include "generic/ip6.h" #include "fallback/text.h" @@ -27,6 +26,8 @@ #include "generic/caa.h" #include "generic/ilnp64.h" #include "visit.h" +#include "types.h" +#include "fallback/type.h" #include "parser.h" diagnostic_push() diff --git a/src/fallback/text.h b/src/fallback/text.h index ba2a4a6..582bf31 100644 --- a/src/fallback/text.h +++ b/src/fallback/text.h @@ -35,7 +35,7 @@ static zone_really_inline int32_t parse_string_internal( x[2] = (uint8_t)t[3] - '0'; const uint32_t o = x[0] * 100 + x[1] * 10 + x[2]; if (o > 255 || x[1] > 9 || x[2] > 9) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); w[0] = (uint8_t)o; w += 1; t += 4; } @@ -48,7 +48,7 @@ static zone_really_inline int32_t parse_string_internal( } if (w == we) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); assert(d[(uint8_t)*t] != token->code); parser->rdata->octets[parser->rdata->length] = (uint8_t)((w - ws) - 1); parser->rdata->length += (size_t)(w - ws); @@ -92,7 +92,7 @@ static zone_really_inline int32_t parse_text_internal( x[2] = (uint8_t)t[3] - '0'; const uint32_t o = x[0] * 100 + x[1] * 10 + x[0]; if (o > 255 || x[1] > 9 || x[2] > 9) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); w[0] = (uint8_t)o; w += 1; t += 4; } @@ -105,7 +105,7 @@ static zone_really_inline int32_t parse_text_internal( } if (w == we) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); assert(d[(uint8_t)*t] != token->code); parser->rdata->length += (size_t)(w - ws); return ZONE_BLOB; diff --git a/src/generic/time.h b/src/fallback/time.h similarity index 83% rename from src/generic/time.h rename to src/fallback/time.h index b5ca149..7106542 100644 --- a/src/generic/time.h +++ b/src/fallback/time.h @@ -45,11 +45,11 @@ static zone_really_inline int32_t parse_time( for (int i = 0; i < 14; i++) { d[i] = (uint8_t)p[i] - '0'; if (d[i] > 9) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } if (contiguous[ (uint8_t)p[14] ] == CONTIGUOUS) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); // code adapted from Python 2.4.1 sources (Lib/calendar.py) const uint64_t year = (d[0] * 1000) + (d[1] * 100) + (d[2] * 10) + d[3]; @@ -60,17 +60,17 @@ static zone_really_inline int32_t parse_time( const uint64_t sec = (d[12] * 10) + d[13]; if (year < 1970 || year > 2106) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); uint64_t leap_year = is_leap_year(year); uint64_t days = 365 * (year - 1970) + leap_days(1970, year); if (!mon || mon > 12) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); if (!mday || mday > days_in_month[mon] + (leap_year & (mon == 2))) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); if (hour > 23 || min > 59 || sec > 59) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); days += days_to_month[mon]; days += (mon > 2) & leap_year; diff --git a/src/fallback/type.h b/src/fallback/type.h index da3730a..19df180 100644 --- a/src/fallback/type.h +++ b/src/fallback/type.h @@ -16,36 +16,311 @@ #include #endif -#include "zone.h" +static const uint8_t type_code_page[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0f + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1f + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27 + // hyphen + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, // 0x28 - 0x2f + // digits + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // 0x30 - 0x37 + 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3f + // letters (upper case) + 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // 0x40 - 0x47 + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, // 0x48 - 0x4f + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // 0x50 - 0x57 + 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5f + // letters (lower case) + 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // 0x60 - 0x67 + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, // 0x68 - 0x6f + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // 0x70 - 0x77 + 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7f + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8f + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9f + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa0 - 0xa7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa8 - 0xaf + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb0 - 0xb7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb8 - 0xbf + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 - 0xc7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc8 - 0xcf + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd0 - 0xd7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd8 - 0xdf + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xe0 - 0xe7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xe8 - 0xef + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf0 - 0xf7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf8 - 0xff +}; -extern const zone_table_t *zone_identifiers; +zone_nonnull_all +static zone_really_inline int32_t maybe_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol, + uint16_t key) +{ + (void)parser; + (void)type; + (void)field; + + const zone_symbol_t *s = &types[key].info.name; + + if (strncasecmp(token->data, s->key.data, s->key.length) != 0 || + contiguous[ (uint8_t)token->data[ s->key.length ] ] == CONTIGUOUS) + return 0; + + *symbol = s; + *code = (uint16_t)s->value; + return ZONE_TYPE; +} zone_nonnull_all -static zone_really_inline int32_t scan_type_or_class( +static zone_really_inline int32_t maybe_class( zone_parser_t *parser, const zone_type_info_t *type, const zone_field_info_t *field, const token_t *token, - uint16_t *code) + uint16_t *code, + const zone_symbol_t **symbol, + uint16_t key) { - int32_t r; - const zone_symbol_t *s = NULL; + (void)parser; + (void)type; + (void)field; - if ((r = have_contiguous(parser, type, field, token)) < 0) - return r; - if ((s = lookup_symbol(zone_identifiers, token))) - return (void)(*code = s->value & 0xffff), s->value >> 16; + const zone_symbol_t *s = &classes[key].name; + if (strncasecmp(token->data, s->key.data, s->key.length) != 0 || + contiguous[ (uint8_t)token->data[ s->key.length ] ] == CONTIGUOUS) + return 0; - if (strncasecmp(token->data, "TYPE", 4) == 0) - r = ZONE_TYPE; - else if (strncasecmp(token->data, "CLASS", 5) == 0) - r = ZONE_CLASS; + *symbol = s; + *code = (uint16_t)s->value; + return ZONE_CLASS; +} + +zone_nonnull_all +static zone_really_inline int32_t find_type_or_class( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + const char *p = token->data; + +#define MAYBE_TYPE(key) \ + return maybe_type(parser, type, field, token, code, symbol, key) +#define MAYBE_CLASS(key) \ + return maybe_class(parser, type, field, token, code, symbol, key) + + switch (type_code_page[ (uint8_t)p[0] ]) { + case 'A': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 0 : MAYBE_TYPE(ZONE_A); + case 'A': MAYBE_TYPE(ZONE_AAAA); + case 'F': MAYBE_TYPE(ZONE_AFSDB); + case 'P': MAYBE_TYPE(ZONE_APL); + case '6': MAYBE_TYPE(ZONE_A6); + case 'V': MAYBE_TYPE(ZONE_AVC); + } + break; + case 'C': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'N': MAYBE_TYPE(ZONE_CNAME); + case 'D': + switch (type_code_page[ (uint8_t)p[2] ]) { + case 'S': MAYBE_TYPE(ZONE_CDS); + case 'N': MAYBE_TYPE(ZONE_CDNSKEY); + } + break; + case 'H': MAYBE_CLASS(ZONE_CH); + case 'A': MAYBE_TYPE(ZONE_CAA); + case 'E': MAYBE_TYPE(ZONE_CERT); + case 'S': + switch (type_code_page[ (uint8_t)p[2] ]) { + case 0 : MAYBE_CLASS(ZONE_CS); + case 'Y': MAYBE_TYPE(ZONE_CSYNC); + } + } + break; + case 'D': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'N': + switch (type_code_page[ (uint8_t)p[2] ]) { + case 'A': MAYBE_TYPE(ZONE_DNAME); + case 'S': MAYBE_TYPE(ZONE_DNSKEY); + } + break; + case 'S': MAYBE_TYPE(ZONE_DS); + case 'H': MAYBE_TYPE(ZONE_DHCID); + case 'L': MAYBE_TYPE(259); + } + break; + case 'E': + switch (type_code_page[ (uint8_t)p[3] ]) { + case '4': MAYBE_TYPE(ZONE_EUI48); + case '6': MAYBE_TYPE(ZONE_EUI64); + } + break; + case 'G': MAYBE_TYPE(ZONE_GPOS); + case 'H': + switch (type_code_page[ (uint8_t)p[2] ]) { + case 'T': MAYBE_TYPE(ZONE_HTTPS); + case 'N': MAYBE_TYPE(ZONE_HINFO); + case 'P': MAYBE_TYPE(ZONE_HIP); + case 0 : MAYBE_CLASS(ZONE_HS); + } + break; + case 'I': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'N': MAYBE_CLASS(ZONE_IN); + case 'P': MAYBE_TYPE(ZONE_IPSECKEY); + case 'S': MAYBE_TYPE(ZONE_ISDN); + } + break; + case 'K': + switch (type_code_page[ (uint8_t)p[1] ] ) { + case 'E': MAYBE_TYPE(ZONE_KEY); + case 'X': MAYBE_TYPE(ZONE_KX); + } + break; + case 'L': + switch (type_code_page[ (uint8_t)p[1] ]) { + case '3': MAYBE_TYPE(ZONE_L32); + case '6': MAYBE_TYPE(ZONE_L64); + case 'O': MAYBE_TYPE(ZONE_LOC); + case 'P': MAYBE_TYPE(ZONE_LP); + } + break; + case 'M': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'X': MAYBE_TYPE(ZONE_MX); + case 'B': MAYBE_TYPE(ZONE_MB); + case 'D': MAYBE_TYPE(ZONE_MD); + case 'F': MAYBE_TYPE(ZONE_MF); + case 'G': MAYBE_TYPE(ZONE_MG); + case 'I': MAYBE_TYPE(ZONE_MINFO); + case 'R': MAYBE_TYPE(ZONE_MR); + } + break; + case 'N': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'S': + switch (type_code_page[ (uint8_t)p[2] ]) { + case 0 : MAYBE_TYPE(ZONE_NS); + case 'E': + switch (type_code_page[ (uint8_t)p[4] ]) { + case 0 : MAYBE_TYPE(ZONE_NSEC); + case '3': + switch (type_code_page[ (uint8_t)p[5] ]) { + case 0 : MAYBE_TYPE(ZONE_NSEC3); + case 'P': MAYBE_TYPE(ZONE_NSEC3PARAM); + } + } + break; + case 'A': + switch (type_code_page[ (uint8_t)p[4] ]) { + case 0 : MAYBE_TYPE(ZONE_NSAP); + case '-': MAYBE_TYPE(ZONE_NSAP_PTR); + } + } + break; + case 'A': MAYBE_TYPE(ZONE_NAPTR); + case 'I': MAYBE_TYPE(ZONE_NID); + case 'X': MAYBE_TYPE(ZONE_NXT); + } + break; + case 'O': MAYBE_TYPE(ZONE_OPENPGPKEY); + case 'P': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'T': MAYBE_TYPE(ZONE_PTR); + case 'X': MAYBE_TYPE(ZONE_PX); + } + break; + case 'R': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'R': MAYBE_TYPE(ZONE_RRSIG); + case 'P': MAYBE_TYPE(ZONE_RP); + case 'T': MAYBE_TYPE(ZONE_RT); + } + break; + case 'S': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'O': MAYBE_TYPE(ZONE_SOA); + case 'R': MAYBE_TYPE(ZONE_SRV); + case 'I': MAYBE_TYPE(ZONE_SIG); + case 'M': MAYBE_TYPE(ZONE_SMIMEA); + case 'P': MAYBE_TYPE(ZONE_SPF); + case 'S': MAYBE_TYPE(ZONE_SSHFP); + case 'V': MAYBE_TYPE(ZONE_SVCB); + } + break; + case 'T': + switch (type_code_page[ (uint8_t)p[1] ]) { + case 'X': MAYBE_TYPE(ZONE_TXT); + case 'L': MAYBE_TYPE(ZONE_TLSA); + } + break; + case 'U': MAYBE_TYPE(ZONE_URI); + case 'W': MAYBE_TYPE(ZONE_WKS); + case 'X': MAYBE_TYPE(ZONE_X25); + case 'Z': MAYBE_TYPE(ZONE_ZONEMD); + } + +#undef MAYBE_TYPE +#undef MAYBE_CLASS + return 0; +} + +zone_nonnull_all +static zone_really_inline int32_t scan_generic_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + const char *ps = token->data + 4, *p = ps; + uint64_t n = 0; + for (;; p++) { + const uint64_t d = (uint8_t)*p - '0'; + if (d > 9) + break; + n = n * 10 + d; + } + + if (!n || n > 65535 || p - ps > 5 || is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + + *code = (uint16_t)n; + if (*code <= 258) + *symbol = &types[*code].info.name; + else if (*code == ZONE_DLV) + *symbol = &types[259].info.name; else - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + *symbol = &types[0].info.name; + return ZONE_TYPE; +} +zone_nonnull_all +static zone_really_inline int32_t scan_generic_class( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + const char *ps = token->data + 5, *p = ps; uint64_t n = 0; - const char *p, *q; - p = q = token->data + 4 + (r == ZONE_CLASS); for (;; p++) { const uint64_t d = (uint8_t)*p - '0'; if (d > 9) @@ -53,11 +328,39 @@ static zone_really_inline int32_t scan_type_or_class( n = n * 10 + d; } - if (!n || n > UINT16_MAX || p - q >= 5 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + if (!n || n > 65535 || p - ps >= 5 || is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); *code = (uint16_t)n; - return r; + if (*code <= 4) + *symbol = &classes[*code].name; + else + *symbol = &classes[0].name; + return ZONE_CLASS; +} + +zone_nonnull_all +static zone_really_inline int32_t scan_type_or_class( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + int32_t r; + + if ((r = have_contiguous(parser, type, field, token)) < 0) + return r; + if ((r = find_type_or_class(parser, type, field, token, code, symbol))) + return r; + + if (strncasecmp(token->data, "TYPE", 4) == 0) + return scan_generic_type(parser, type, field, token, code, symbol); + else if (strncasecmp(token->data, "CLASS", 5) == 0) + return scan_generic_class(parser, type, field, token, code, symbol); + + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } zone_nonnull_all @@ -66,31 +369,20 @@ static zone_really_inline int32_t scan_type( const zone_type_info_t *type, const zone_field_info_t *field, const token_t *token, - uint16_t *code) + uint16_t *code, + const zone_symbol_t **symbol) { int32_t r; - const zone_symbol_t *s; if ((r = have_contiguous(parser, type, field, token)) < 0) return r; - if ((s = lookup_symbol(zone_identifiers, token))) - return (void)(*code = s->value & 0xffff), s->value >> 16; + if ((r = find_type_or_class(parser, type, field, token, code, symbol)) == ZONE_TYPE) + return r; if (strncasecmp(token->data, "TYPE", 4) != 0) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - - uint64_t n = 0; - const char *p, *q; - p = q = token->data + 4; - for (;; p++) { - const uint64_t d = (uint8_t)*p - '0'; - if (d > 9) - break; - n = n * 10 + d; - } + return scan_generic_type(parser, type, field, token, code, symbol); - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - return ZONE_NAME; + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } zone_nonnull_all @@ -98,19 +390,20 @@ static zone_really_inline int32_t parse_type( zone_parser_t *parser, const zone_type_info_t *type, const zone_field_info_t *field, - token_t *token) + const token_t *token) { int32_t r; uint16_t c = 0; + const zone_symbol_t *s; if ((r = have_contiguous(parser, type, field, token)) < 0) return r; - scan_type(parser, type, field, token, &c); + scan_type(parser, type, field, token, &c, &s); c = htons(c); memcpy(&parser->rdata->octets[parser->rdata->length], &c, sizeof(c)); parser->rdata->length += sizeof(c); - return ZONE_NAME; + return ZONE_TYPE; } #endif // TYPE_H diff --git a/src/generic/base16.h b/src/generic/base16.h index 056ab0d..51f8476 100644 --- a/src/generic/base16.h +++ b/src/generic/base16.h @@ -45,12 +45,12 @@ static zone_really_inline int32_t parse_base16( } if (is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), TNAME(type)); lex(parser, token); } while (token->code == CONTIGUOUS); if (state != 0) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); if ((r = have_delimiter(parser, type, token)) < 0) return r; @@ -94,9 +94,9 @@ static zone_really_inline int32_t parse_salt( } if (p == token->data || contiguous[ (uint8_t)*p ] == CONTIGUOUS) - SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), TNAME(type)); if (state != 0) - SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s record", NAME(field), TNAME(type)); parser->rdata->octets[rdlength] = (uint8_t)(parser->rdata->length - rdlength); return ZONE_STRING; diff --git a/src/generic/base32.h b/src/generic/base32.h index 58c3016..f44edd2 100644 --- a/src/generic/base32.h +++ b/src/generic/base32.h @@ -81,7 +81,7 @@ static zone_really_inline int32_t parse_base32( case 1: case 3: case 6: - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); case 2: // require six pad characters state = 13; continue; @@ -96,7 +96,7 @@ static zone_really_inline int32_t parse_base32( break; default: if (state == 8) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); assert(state > 8); state--; break; @@ -104,9 +104,9 @@ static zone_really_inline int32_t parse_base32( } if (contiguous[ (uint8_t)*p ] == CONTIGUOUS) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); if (state != 0 && state != 8) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return ZONE_STRING; } diff --git a/src/generic/base64.h b/src/generic/base64.h index 8f9ed36..587dc78 100644 --- a/src/generic/base64.h +++ b/src/generic/base64.h @@ -58,7 +58,7 @@ static zone_really_inline int32_t parse_base64( state = 0; break; default: - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } } @@ -66,7 +66,7 @@ static zone_really_inline int32_t parse_base64( switch (state) { case 0: // invalid, pad character in first position case 1: // invalid, pad character in second position - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); case 2: // valid, one byte of info state = 4; if (*p++ != '=') @@ -83,14 +83,14 @@ static zone_really_inline int32_t parse_base64( } if (is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); lex(parser, token); } while (token->code == CONTIGUOUS); if ((r = have_delimiter(parser, type, token)) < 0) return r; if (state != 0 && state != 5) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return ZONE_BLOB; } diff --git a/src/generic/caa.h b/src/generic/caa.h index 6be969e..5af9ebe 100644 --- a/src/generic/caa.h +++ b/src/generic/caa.h @@ -62,7 +62,7 @@ static zone_really_inline int32_t parse_caa_tag( } else if (contiguous[c] != CONTIGUOUS) { break; } else { - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } } @@ -70,7 +70,7 @@ static zone_really_inline int32_t parse_caa_tag( // tags registered by IANA. if (w >= we) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->octets[parser->rdata->length] = (uint8_t)(w - ws); parser->rdata->length += (size_t)(w - ws) + 1; return ZONE_STRING; diff --git a/src/generic/ilnp64.h b/src/generic/ilnp64.h index 986dd40..2b7b8e0 100644 --- a/src/generic/ilnp64.h +++ b/src/generic/ilnp64.h @@ -49,7 +49,7 @@ static zone_really_inline int32_t parse_ilnp64( } if (n != 3 || p == g || p - g > 4 || contiguous[(uint8_t)*p] == CONTIGUOUS) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); a[0] = htons(a[0]); a[1] = htons(a[1]); a[2] = htons(a[2]); diff --git a/src/generic/ip6.h b/src/generic/ip6.h index 5eee793..50186a8 100644 --- a/src/generic/ip6.h +++ b/src/generic/ip6.h @@ -183,7 +183,7 @@ static zone_really_inline int32_t parse_ip6( return ZONE_IP6; } - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } #endif // IP6_H diff --git a/src/generic/name.h b/src/generic/name.h index 32ea0a2..c8d214c 100644 --- a/src/generic/name.h +++ b/src/generic/name.h @@ -72,11 +72,11 @@ static zone_really_inline int32_t scan_name( if (digits[0] < 2) { if (digits[1] > 9 || digits[2] > 9) SEMANTIC_ERROR(parser, "Bad escape sequence in %s of %s record", - field->name.data, type->name.data); + NAME(field), TNAME(type)); } else { if (digits[1] > 5 || digits[2] > 5) SEMANTIC_ERROR(parser, "Bad escape sequence in %s of %s record", - field->name.data, type->name.data); + NAME(field), TNAME(type)); } wire[size] = digits[0] * 100 + digits[1] * 10 + digits[0]; @@ -89,7 +89,7 @@ static zone_really_inline int32_t scan_name( if (wire - octets > 255) SEMANTIC_ERROR(parser, "Bad domain name in %s of %s", - field->name.data, type->name.data); + field->name.data, TNAME(type)); if (block.label) { uint64_t count = 0, last = 0; @@ -100,7 +100,7 @@ static zone_really_inline int32_t scan_name( *label += count; if (!*label || *label > 63) SEMANTIC_ERROR(parser, "Bad domain name in %s of %s record", - field->name.data, type->name.data); + NAME(field), TNAME(type)); label += *label + 1; *label = 0; last += count + 1; @@ -111,13 +111,13 @@ static zone_really_inline int32_t scan_name( *label += (uint8_t)size; if (*label > 63) SEMANTIC_ERROR(parser, "Bad domain name in %s of %s record", - field->name.data, type->name.data); + NAME(field), TNAME(type)); } } if (!(wire - octets)) { SEMANTIC_ERROR(parser, "Invalid domain name in %s of %s", - field->name.data, type->name.data); + NAME(field), TNAME(type)); } *length = (size_t)(wire - octets); @@ -184,7 +184,7 @@ static zone_really_inline int32_t parse_name( relative: if (n > 255 - parser->file->origin.length) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); memcpy(o+n, parser->file->origin.octets, parser->file->origin.length); parser->rdata->length += n + parser->file->origin.length; return ZONE_NAME; diff --git a/src/generic/nsec.h b/src/generic/nsec.h index 54965a8..a550525 100644 --- a/src/generic/nsec.h +++ b/src/generic/nsec.h @@ -9,6 +9,15 @@ #ifndef NSEC_H #define NSEC_H +zone_nonnull_all +static zone_really_inline int32_t scan_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol); + typedef uint8_t zone_nsec_t[256 + 2]; zone_nonnull_all @@ -20,6 +29,7 @@ static zone_really_inline int32_t parse_nsec( { uint16_t code; uint16_t highest_bit = 0; + const zone_symbol_t *symbol; uint8_t *data = &parser->rdata->octets[parser->rdata->length]; zone_nsec_t *bitmap = (void *)&parser->rdata->octets[parser->rdata->length]; @@ -30,7 +40,7 @@ static zone_really_inline int32_t parse_nsec( // a name. walk the bits according to the nsec++ draft from jakob. do { - scan_type(parser, type, field, token, &code); + scan_type(parser, type, field, token, &code, &symbol); const uint8_t bit = (uint8_t)((uint16_t)code % 256); const uint8_t window = (uint8_t)((uint16_t)code / 256); diff --git a/src/generic/number.h b/src/generic/number.h index d2eea7f..b436412 100644 --- a/src/generic/number.h +++ b/src/generic/number.h @@ -39,11 +39,11 @@ static zone_really_inline int32_t parse_symbol( if (is_contiguous((uint8_t)*p)) { const zone_symbol_t *s; if (!(s = lookup_symbol(&field->symbols, token))) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); n = (uint8_t)s->value; } else { if (n > UINT8_MAX || p - token->data > 3) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } parser->rdata->octets[parser->rdata->length] = (uint8_t)n; @@ -73,7 +73,7 @@ static zone_really_inline int32_t parse_int8( } if (n > UINT8_MAX || p - token->data > 3 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->octets[parser->rdata->length] = (uint8_t)n; parser->rdata->length += sizeof(uint8_t); @@ -102,7 +102,7 @@ static zone_really_inline int32_t parse_int16( } if (n > UINT16_MAX || p - token->data > 5 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); uint16_t n16 = htons((uint16_t)n); memcpy(&parser->rdata->octets[parser->rdata->length], &n16, sizeof(n16)); @@ -111,7 +111,7 @@ static zone_really_inline int32_t parse_int16( } zone_nonnull_all -static zone_really_inline zone_return_t parse_int32( +static zone_really_inline int32_t parse_int32( zone_parser_t *parser, const zone_type_info_t *type, const zone_field_info_t *field, @@ -132,7 +132,7 @@ static zone_really_inline zone_return_t parse_int32( } if (n > UINT32_MAX || p - token->data > 10 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); const uint32_t n32 = htonl((uint32_t)n); memcpy(&parser->rdata->octets[parser->rdata->length], &n32, sizeof(n32)); diff --git a/src/generic/text.h b/src/generic/text.h index 0809b18..54ce869 100644 --- a/src/generic/text.h +++ b/src/generic/text.h @@ -47,7 +47,7 @@ static zone_really_inline int32_t parse_contiguous_string_internal( const size_t n = trailing_zeroes(b.backslash); const size_t o = unescape(t, w); if (!o) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); w += n + 1; t += n + o; } else { const size_t n = trailing_zeroes(b.delimiter | (1llu << 32)); @@ -58,7 +58,7 @@ static zone_really_inline int32_t parse_contiguous_string_internal( } if (w >= we) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->octets[parser->rdata->length] = (uint8_t)((w - ws) - 1); parser->rdata->length += (size_t)(w - ws); return ZONE_STRING; @@ -83,7 +83,7 @@ static zone_really_inline int32_t parse_quoted_string_internal( const size_t n = trailing_zeroes(b.backslash); const size_t o = unescape(t, w); if (!o) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); w += n + 1; t += n + o; } else { const size_t n = trailing_zeroes(b.delimiter | (1llu << 32)); @@ -94,7 +94,7 @@ static zone_really_inline int32_t parse_quoted_string_internal( } if (w >= we) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->octets[parser->rdata->length] = (uint8_t)((w - ws) - 1); parser->rdata->length += (size_t)(w - ws); return ZONE_STRING; @@ -134,7 +134,7 @@ static zone_really_inline int32_t parse_contiguous_text_internal( const size_t n = trailing_zeroes(b.backslash); const size_t o = unescape(t+n, w+n); if (!o) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); w += n + 1; t += n + o; } else { const size_t n = trailing_zeroes(b.delimiter | (1llu << 32)); @@ -145,7 +145,7 @@ static zone_really_inline int32_t parse_contiguous_text_internal( } if (w >= we) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->length += (size_t)(w - ws); return ZONE_BLOB; @@ -170,7 +170,7 @@ static zone_really_inline int32_t parse_quoted_text_internal( const size_t n = trailing_zeroes(b.backslash); const size_t o = unescape(t+n, w+n); if (!o) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); w += n + 1; t += n + o; } else { const size_t n = trailing_zeroes(b.delimiter | (1llu << 32)); @@ -181,7 +181,7 @@ static zone_really_inline int32_t parse_quoted_text_internal( } if (w >= we) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->length += (size_t)(w - ws); return ZONE_BLOB; diff --git a/src/generic/ttl.h b/src/generic/ttl.h index 0d34f11..7036d40 100644 --- a/src/generic/ttl.h +++ b/src/generic/ttl.h @@ -54,13 +54,13 @@ static zone_really_inline int32_t scan_ttl( if (zone_likely(contiguous[ (uint8_t)*p ] != CONTIGUOUS)) { // FIXME: comment RFC2308 msb if (t > m || !t || p - token->data > 10) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); if (t & (1llu << 31)) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); *seconds = (uint32_t)t; return ZONE_TTL; } else if (p == token->data || !parser->options.pretty_ttls) { - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); } uint64_t n = t, u = 0, f = 0; @@ -77,11 +77,11 @@ static zone_really_inline int32_t scan_ttl( // units must not be repeated e.g. 1m1m } else if (u == f) { SYNTAX_ERROR(parser, "Invalid %s in %s, reuse of unit %c", - NAME(field), NAME(type), *p); + NAME(field), TNAME(type), *p); // greater units must precede smaller units. e.g. 1m1s, not 1s1m } else if (u < f) { SYNTAX_ERROR(parser, "Invalid %s in %s, unit %c follows smaller unit", - NAME(field), NAME(type), *p); + NAME(field), TNAME(type), *p); } else { f = u; n = n * u; @@ -90,35 +90,35 @@ static zone_really_inline int32_t scan_ttl( if (n > m) SYNTAX_ERROR(parser, "Invalid %s in %s", - NAME(field), NAME(type)); + NAME(field), TNAME(type)); } else if (s == UNIT) { // units must be followed by a number. e.g. 1h30m, not 1hh if (d > 9) SYNTAX_ERROR(parser, "Invalid %s in %s, non-digit follows unit", - NAME(field), NAME(type)); + NAME(field), TNAME(type)); // units must not be followed by a number if smallest unit, // i.e. seconds, was previously specified if (f == 1) SYNTAX_ERROR(parser, "Invalid %s in %s, digit follows unit s", - NAME(field), NAME(type)); + NAME(field), TNAME(type)); t = t + n; n = d; s = NUMBER; if (t > m) SYNTAX_ERROR(parser, "Invalid %s in %s", - NAME(field), NAME(type)); + NAME(field), TNAME(type)); } } if (zone_unlikely(contiguous[ (uint8_t)*p ] != CONTIGUOUS)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); t = t + n; if (t > m || !t) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); if (t & (1llu << 31)) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); *seconds = (uint32_t)t; return ZONE_TTL; diff --git a/src/generic/type.h b/src/generic/type.h deleted file mode 100644 index c6f9591..0000000 --- a/src/generic/type.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * type.h -- some useful comment - * - * Copyright (c) 2023, NLnet Labs. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#ifndef TYPE_H -#define TYPE_H - -#include -#if !defined _WIN32 -#include -#endif - -extern const zone_table_t *zone_identifiers; -extern const zone_fast_table_t *zone_fast_identifiers; - -zone_nonnull_all -static zone_really_inline const zone_symbol_t *lookup_type_or_class( - zone_parser_t *parser, const token_t *token) -{ - delimited_t delimited; - - (void)parser; - // FIXME: Not explicitly specified, but RRTYPE names (so far) consist of - // [0-9a-zA-Z-]. A simple range check (as described on #66) may - // outperform scanning for delimiters. - scan_delimited(&delimited, non_contiguous, blank, token->data); - - const size_t length = trailing_zeroes(delimited.delimiter | (1llu << 63)); - uint8_t key = ((uint8_t)(token->data[0] & 0xdf) - 0x41) & 0x1f; - uint8_t hash = token->data[length - 1] & 0xdf; - hash *= 0x07; // better distribution (A + 1 != B) - hash += (uint8_t)length; - - const zone_fast_table_t *table = &zone_fast_identifiers[key]; - - simd_8x16_t keys; - simd_loadu_8x16(&keys, table->keys); - const uint64_t bits = simd_find_8x16(&keys, (char)hash); - const uint64_t index = trailing_zeroes(bits | (1llu << 15)); - - const zone_symbol_t *symbol = table->symbols[index]; - - if (!symbol || strncasecmp(token->data, symbol->key.data, symbol->key.length)) - return NULL; - if (contiguous[ (uint8_t)token->data[symbol->key.length] ] == CONTIGUOUS) - return NULL; - - return symbol; -} - -zone_nonnull_all -static zone_really_inline int32_t scan_type_or_class( - zone_parser_t *parser, - const zone_type_info_t *type, - const zone_field_info_t *field, - const token_t *token, - uint16_t *code) -{ - int32_t r; - const zone_symbol_t *s; - - if ((r = have_contiguous(parser, type, field, token)) < 0) - return r; - - if ((s = lookup_type_or_class(parser, token))) - return (void)(*code = s->value & 0xffffu), s->value >> 16; - - if (strncasecmp(token->data, "TYPE", 4) == 0) - r = ZONE_TYPE; - else if (strncasecmp(token->data, "CLASS", 5) == 0) - r = ZONE_CLASS; - else - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - - uint64_t n = 0; - const char *p = token->data + 4 + (r == ZONE_CLASS); - for (;; p++) { - const uint64_t d = (uint8_t)*p - '0'; - if (d > 9) - break; - n = n * 10 + d; - } - - if (!n || n > UINT16_MAX || p - token->data >= 5 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - - *code = (uint16_t)n; - return r; -} - -zone_nonnull_all -static zone_really_inline int32_t scan_type( - zone_parser_t *parser, - const zone_type_info_t *type, - const zone_field_info_t *field, - const token_t *token, - uint16_t *code) -{ - int32_t r; - const zone_symbol_t *s; - - if ((r = have_contiguous(parser, type, field, token)) < 0) - return r; - - if ((s = lookup_type_or_class(parser, token))) - return (void)(*code = s->value & 0xffffu), s->value >> 16; - - if (strncasecmp(token->data, "TYPE", 4) == 0) - r = ZONE_TYPE; - else - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - - uint64_t n = 0; - const char *p = token->data + 4; - for (;; p++) { - const uint64_t d = (uint8_t)*p - '0'; - if (d > 9) - break; - n = n * 10 + d; - } - - if (!n || n > UINT16_MAX || p - token->data > 5 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); - - *code = (uint16_t)n; - return r; -} - -zone_nonnull_all -static zone_really_inline int32_t parse_type( - zone_parser_t *parser, - const zone_type_info_t *type, - const zone_field_info_t *field, - const token_t *token) -{ - int32_t r; - uint16_t c; - - if ((r = scan_type(parser, type, field, token, &c)) < 0) - return r; - c = htons(c); - memcpy(&parser->rdata->octets[parser->rdata->length], &c, sizeof(c)); - parser->rdata->length += sizeof(c); - return ZONE_TYPE; -} - -#endif // TYPE_H diff --git a/src/haswell/parser.c b/src/haswell/parser.c index 71ddd9e..a59ad3f 100644 --- a/src/haswell/parser.c +++ b/src/haswell/parser.c @@ -20,7 +20,6 @@ #include "generic/ttl.h" #include "westmere/time.h" #include "generic/name.h" -#include "generic/type.h" #include "westmere/ip4.h" #include "generic/ip6.h" #include "generic/text.h" @@ -31,12 +30,14 @@ #include "generic/caa.h" #include "generic/ilnp64.h" #include "visit.h" +#include "types.h" +#include "westmere/type.h" #include "parser.h" diagnostic_push() clang_diagnostic_ignored(missing-prototypes) -zone_return_t zone_haswell_parse(zone_parser_t *parser) +int32_t zone_haswell_parse(zone_parser_t *parser) { return parse(parser); } diff --git a/src/lexer.h b/src/lexer.h index 66ae5de..ff50f05 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -134,9 +134,9 @@ static zone_really_inline int32_t have_contiguous( else if (token->code < 0) return token->code; else if (token->code == QUOTED) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); assert(token->code == END_OF_FILE || token->code == LINE_FEED); - SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), TNAME(type)); } zone_nonnull_all @@ -152,9 +152,9 @@ static zone_really_inline int32_t have_quoted( else if (token->code < 0) return token->code; else if (token->code == CONTIGUOUS) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); assert(token->code == END_OF_FILE || token->code == LINE_FEED); - SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), TNAME(type)); } zone_nonnull_all @@ -170,7 +170,7 @@ static zone_really_inline int32_t have_string( else if (token->code < 0) return token->code; assert(token->code == END_OF_FILE || token->code == LINE_FEED); - SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), TNAME(type)); } zone_nonnull_all @@ -185,7 +185,7 @@ static zone_really_inline int32_t have_delimiter( else if (token->code < 0) return token->code; assert(token->code == CONTIGUOUS || token->code == QUOTED); - SYNTAX_ERROR(parser, "Trailing data in %s", NAME(type)); + SYNTAX_ERROR(parser, "Trailing data in %s", TNAME(type)); } static zone_really_inline bool is_quoted(uint8_t octet) diff --git a/src/log.h b/src/log.h index 10bf0df..e624182 100644 --- a/src/log.h +++ b/src/log.h @@ -16,6 +16,7 @@ #include "zone.h" #define NAME(info) ((info)->name.data) +#define TNAME(info) ((info)->name.key.data) #define RAISE(parser, code, ...) \ do { \ diff --git a/src/parser.c b/src/parser.c index c45b3f7..5becf00 100644 --- a/src/parser.c +++ b/src/parser.c @@ -35,7 +35,7 @@ static zone_really_inline ssize_t check_bytes( { (void)data; if (length < size) - SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), TNAME(type)); return (ssize_t)size; } @@ -62,13 +62,13 @@ static zone_really_inline ssize_t check_ttl( uint32_t number; if (length < sizeof(number)) - SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), TNAME(type)); memcpy(&number, data, sizeof(number)); number = ntohl(number); if (number > INT32_MAX) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return 4; } @@ -84,12 +84,12 @@ static zone_really_inline ssize_t check_type( uint16_t number; if (length < sizeof(number)) - SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME(field), TNAME(type)); memcpy(&number, data, sizeof(number)); if (!number) - SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return 2; } @@ -111,7 +111,7 @@ static zone_really_inline ssize_t check_name( } if (!count || count > length) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return (ssize_t)count; } @@ -127,7 +127,7 @@ static zone_really_inline ssize_t check_string( size_t count; if (!length || (count = 1 + (size_t)data[0]) > length) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return (ssize_t)count; } @@ -148,16 +148,16 @@ static zone_really_inline ssize_t check_nsec( const size_t blocks = 1 + (size_t)data[1]; if (window < last_window || !window != !last_window) SYNTAX_ERROR(parser, "Invalid %s in %s, windows are out-of-order", - NAME(field), NAME(type)); + NAME(field), TNAME(type)); if (blocks > 32) SYNTAX_ERROR(parser, "Invalid %s in %s, blocks are out-of-bounds", - NAME(field), NAME(type)); + NAME(field), TNAME(type)); count += 2 + blocks; last_window = window; } if (count != length) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); return (ssize_t)count; } @@ -189,7 +189,7 @@ int32_t zone_check_a_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -207,7 +207,7 @@ int32_t zone_check_ns_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -231,7 +231,7 @@ int32_t zone_check_soa_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -250,7 +250,7 @@ int32_t zone_check_mb_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -269,7 +269,7 @@ int32_t zone_check_hinfo_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -288,7 +288,7 @@ int32_t zone_check_minfo_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -307,7 +307,7 @@ int32_t zone_check_mx_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -329,7 +329,7 @@ int32_t zone_check_txt_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -348,7 +348,7 @@ int32_t zone_check_rp_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -366,7 +366,7 @@ int32_t zone_check_x25_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -387,7 +387,7 @@ int32_t zone_check_isdn_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -406,7 +406,7 @@ int32_t zone_check_rt_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -448,7 +448,7 @@ int32_t zone_check_aaaa_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s record", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s record", TNAME(type)); return accept_rr(parser); } @@ -469,7 +469,7 @@ int32_t zone_check_srv_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -501,7 +501,7 @@ int32_t zone_check_ds_rdata( // e.g. SHA-1 digest is 20 bytes, see RFC3658 section 2.4 if (c >= n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -522,13 +522,13 @@ int32_t zone_check_sshfp_rdata( // https://www.iana.org/assignments/dns-sshfp-rr-parameters if (c >= n) - SYNTAX_ERROR(parser, "Missing %s in %s", NAME((&f[0])), NAME(type)); + SYNTAX_ERROR(parser, "Missing %s in %s", NAME((&f[0])), TNAME(type)); else if (o[1] == 1 && (n - c) != 20) SEMANTIC_ERROR(parser, "Wrong fingerprint size for type %s in %s", - "SHA1", NAME(type)); + "SHA1", TNAME(type)); else if (o[1] == 2 && (n - c) != 32) SEMANTIC_ERROR(parser, "Wrong fingerprint size for type %s in %s", - "SHA256", NAME(type)); + "SHA256", TNAME(type)); return accept_rr(parser); } @@ -554,7 +554,7 @@ int32_t zone_check_rrsig_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -573,7 +573,7 @@ int32_t zone_check_nsec_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -593,7 +593,7 @@ int32_t zone_check_dnskey_rdata( return r; if (c >= n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -605,7 +605,7 @@ int32_t zone_check_dhcid_rdata( // 2-octet identifier type, 1-octet digest type, followed by one or more // octets representing the actual identifier if (parser->rdata->length < 4) - SEMANTIC_ERROR(parser, "Invalid %s", NAME(type)); + SEMANTIC_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -628,7 +628,7 @@ int32_t zone_check_nsec3_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -649,7 +649,7 @@ int32_t zone_check_nsec3param_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -668,7 +668,7 @@ int32_t zone_check_l32_rdata( return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -686,7 +686,7 @@ int32_t zone_check_l64_rdata( (r = add(&c, check_ilnp64(parser, type, &f[1], o+c, n-c)))) return r; if (c != n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -704,7 +704,7 @@ int32_t zone_check_uri_rdata( (r = add(&c, check_int16(parser, type, &f[1], o+c, n-c)))) return r; if (c >= n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } @@ -722,7 +722,7 @@ int32_t zone_check_caa_rdata( (r = add(&c, check_int8(parser, type, &f[1], o+c, n-c)))) return r; if (c >= n) - SYNTAX_ERROR(parser, "Invalid %s", NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s", TNAME(type)); return accept_rr(parser); } diff --git a/src/parser.h b/src/parser.h index 49b2992..dfff60b 100644 --- a/src/parser.h +++ b/src/parser.h @@ -9,1356 +9,6 @@ #ifndef PARSER_H #define PARSER_H -zone_nonnull_all -extern int32_t zone_check_a_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_a_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_ip4(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_ns_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_ns_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_soa_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_soa_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int32(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ttl(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ttl(parser, type, &type->rdata.fields[4], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ttl(parser, type, &type->rdata.fields[5], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ttl(parser, type, &type->rdata.fields[6], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_hinfo_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_hinfo_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_string(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_minfo_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_minfo_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_mx_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_mx_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_txt_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_txt_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - do { - if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - } while (token->code & (CONTIGUOUS | QUOTED)); - - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_x25_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_x25_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_isdn_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_isdn_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - - // subaddress is optional - if (token->code & (CONTIGUOUS | QUOTED)) { - if ((r = parse_string(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - } - - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_rt_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_rt_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_key_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_key_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return zone_check_key_rdata(parser, type); -} - -zone_nonnull_all -extern int32_t zone_check_aaaa_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_aaaa_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_ip6(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_srv_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_srv_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_naptr_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_naptr_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_string(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_string(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_string(parser, type, &type->rdata.fields[4], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[5], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_ds_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_ds_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_symbol(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_base16(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_sshfp_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_sshfp_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int8(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_base16(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - - return zone_check_sshfp_rdata(parser, type); -} - -zone_nonnull_all -extern int32_t zone_check_rrsig_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_rrsig_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_type(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ttl(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_time(parser, type, &type->rdata.fields[4], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_time(parser, type, &type->rdata.fields[5], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[6], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_name(parser, type, &type->rdata.fields[7], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[8], token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_nsec_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_nsec_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_nsec(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_dnskey_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_dnskey_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_symbol(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_dhcid_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_dhcid_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_base64(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - - return zone_check_dhcid_rdata(parser, type); -} - -zone_nonnull_all -extern int32_t zone_check_nsec3_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_nsec3_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_symbol(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_salt(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_base32(parser, type, &type->rdata.fields[4], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_nsec(parser, type, &type->rdata.fields[5], token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_nsec3param_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_nsec3param_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_symbol(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_salt(parser, type, &type->rdata.fields[3], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_l32_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_l32_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ip4(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_l64_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_l64_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_ilnp64(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_uri_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_uri_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_int16(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_quoted_text(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -zone_nonnull_all -extern int32_t zone_check_caa_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_caa_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - int32_t r; - - if ((r = parse_int8(parser, type, &type->rdata.fields[0], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_caa_tag(parser, type, &type->rdata.fields[1], token)) < 0) - return r; - lex(parser, token); - if ((r = parse_text(parser, type, &type->rdata.fields[2], token)) < 0) - return r; - lex(parser, token); - if ((r = have_delimiter(parser, type, token)) < 0) - return r; - - return accept_rr(parser); -} - -typedef struct zone_type_descriptor zone_type_descriptor_t; -struct zone_type_descriptor { - zone_type_info_t info; - int32_t (*check)(zone_parser_t *, const zone_type_info_t *); - int32_t (*parse)(zone_parser_t *, const zone_type_info_t *, token_t *); -}; - -zone_nonnull_all -extern int32_t zone_check_generic_rdata( - zone_parser_t *parser, const zone_type_info_t *type); - -zone_nonnull_all -static int32_t parse_generic_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - static const zone_field_info_t fields[2] = { - { { 12, "RDATA length" }, ZONE_INT16, 0, { 0, NULL } }, - { { 5, "RDATA" }, ZONE_BLOB, 0, { 0, NULL } } - }; - - int32_t r; - - lex(parser, token); // discard "\\#" - if ((r = have_contiguous(parser, type, &fields[0], token)) < 0) - return r; - - size_t n = 0; - const char *p = token->data; - for (;; p++) { - const size_t d = (uint8_t)*p - '0'; - if (d > 9) - break; - n = n * 10 +d; - } - - if (n > UINT16_MAX || p - token->data > 5 || is_contiguous((uint8_t)*p)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(type)); - - lex(parser, token); - if (n) - r = parse_base16(parser, type, &fields[1], token); - else - r = have_delimiter(parser, type, token); - if (r < 0) - return r; - if (parser->rdata->length != n) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), NAME(type)); - return ((const zone_type_descriptor_t *)type)->check(parser, type); -} - -zone_nonnull_all -static int32_t parse_unknown_rdata( - zone_parser_t *parser, const zone_type_info_t *type, token_t *token) -{ - (void)type; - (void)token; - SYNTAX_ERROR(parser, "Unknown record type"); -} - -#define SYMBOLS(symbols) \ - { (sizeof(symbols)/sizeof(symbols[0])), symbols } - -#define SYMBOL(name, value) \ - { { sizeof(name) - 1, name }, value } - -#define FIELDS(fields) \ - { (sizeof(fields)/sizeof(fields[0])), fields } - -#define FIELD(name, type, /* qualifiers, symbols */ ...) \ - { { sizeof(name) - 1, name }, type, __VA_ARGS__ } - -#define TYPE(name, code, options, fields, check, parse) \ - { { { sizeof(name) - 1, name }, code, options, fields }, check, parse } - -#define UNKNOWN_TYPE(code) \ - { { { 0, "" }, code, 0, { 0, NULL } }, \ - zone_check_generic_rdata, parse_unknown_rdata } - -diagnostic_push() -gcc_diagnostic_ignored(missing-field-initializers) -clang_diagnostic_ignored(missing-field-initializers) - -static const zone_field_info_t a_rdata_fields[] = { - FIELD("address", ZONE_IP4, 0) -}; - -static const zone_field_info_t ns_rdata_fields[] = { - FIELD("host", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t md_rdata_fields[] = { - FIELD("madname", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t mf_rdata_fields[] = { - FIELD("madname", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t cname_rdata_fields[] = { - FIELD("host", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t soa_rdata_fields[] = { - FIELD("primary", ZONE_NAME, ZONE_COMPRESSED), - FIELD("mailbox", ZONE_NAME, ZONE_MAILBOX), - FIELD("serial", ZONE_INT32, 0), - FIELD("refresh", ZONE_INT32, ZONE_TTL), - FIELD("retry", ZONE_INT32, ZONE_TTL), - FIELD("expire", ZONE_INT32, ZONE_TTL), - FIELD("minimum", ZONE_INT32, ZONE_TTL) -}; - -static const zone_field_info_t mb_rdata_fields[] = { - FIELD("madname", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t mg_rdata_fields[] = { - FIELD("mgmname", ZONE_NAME, ZONE_MAILBOX) -}; - -static const zone_field_info_t mr_rdata_fields[] = { - FIELD("newname", ZONE_NAME, ZONE_MAILBOX) -}; - -static const zone_field_info_t ptr_rdata_fields[] = { - FIELD("ptrdname", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t hinfo_rdata_fields[] = { - FIELD("cpu", ZONE_STRING, 0), - FIELD("os", ZONE_STRING, 0) -}; - -static const zone_field_info_t minfo_rdata_fields[] = { - FIELD("rmailbx", ZONE_NAME, ZONE_MAILBOX), - FIELD("emailbx", ZONE_NAME, ZONE_MAILBOX) -}; - -static const zone_field_info_t wks_rdata_fields[] = { - FIELD("address", ZONE_IP4, 0), - FIELD("protocol", ZONE_INT8, 0), - FIELD("bitmap", ZONE_WKS, 0) -}; - -static const zone_field_info_t mx_rdata_fields[] = { - FIELD("priority", ZONE_INT16, 0), - FIELD("hostname", ZONE_NAME, ZONE_COMPRESSED) -}; - -static const zone_field_info_t txt_rdata_fields[] = { - FIELD("text", ZONE_STRING, ZONE_SEQUENCE) -}; - -static const zone_field_info_t rp_rdata_fields[] = { - FIELD("mailbox", ZONE_NAME, ZONE_MAILBOX), - FIELD("text", ZONE_NAME, 0) -}; - -static const zone_field_info_t afsdb_rdata_fields[] = { - FIELD("subtype", ZONE_INT16, 0), - FIELD("hostname", ZONE_NAME, 0) -}; - -static const zone_field_info_t x25_rdata_fields[] = { - FIELD("address", ZONE_STRING, 0) -}; - -static const zone_field_info_t isdn_rdata_fields[] = { - FIELD("address", ZONE_STRING, 0), - FIELD("subaddress", ZONE_STRING, 0) -}; - -static const zone_field_info_t rt_rdata_fields[] = { - FIELD("preference", ZONE_INT16, 0), - FIELD("hostname", ZONE_NAME, 0) -}; - -static const zone_field_info_t key_rdata_fields[] = { - FIELD("flags", ZONE_INT16, 0), - FIELD("protocol", ZONE_INT8, 0), - FIELD("algorithm", ZONE_INT8, 0), - FIELD("publickey", ZONE_BLOB, ZONE_BASE64) -}; - -static const zone_field_info_t aaaa_rdata_fields[] = { - FIELD("address", ZONE_IP6, 0) -}; - -static const zone_field_info_t srv_rdata_fields[] = { - FIELD("priority", ZONE_INT16, 0), - FIELD("weight", ZONE_INT16, 0), - FIELD("port", ZONE_INT16, 0), - FIELD("target", ZONE_NAME, 0) -}; - -static const zone_field_info_t naptr_rdata_fields[] = { - FIELD("order", ZONE_INT16, 0), - FIELD("preference", ZONE_INT16, 0), - FIELD("flags", ZONE_STRING, 0), - FIELD("services", ZONE_STRING, 0), - FIELD("regex", ZONE_STRING, 0), - FIELD("replacement", ZONE_NAME, 0), -}; - -static const zone_field_info_t kx_rdata_fields[] = { - FIELD("preference", ZONE_INT16, 0), - FIELD("exchanger", ZONE_NAME, 0) -}; - -static const zone_field_info_t dname_rdata_fields[] = { - FIELD("source", ZONE_NAME, 0) -}; - -static const zone_symbol_t ds_algorithm_symbols[] = { - SYMBOL("DH", 2), - SYMBOL("DSA", 3), - SYMBOL("DSA-NSEC-SHA1", 6), - SYMBOL("ECC", 4), - SYMBOL("ECC-GOST", 12), - SYMBOL("ECDSAP256SHA256", 13), - SYMBOL("ECDSAP384SHA384", 14), - SYMBOL("INDIRECT", 252), - SYMBOL("PRIVATEDNS", 253), - SYMBOL("PRIVATEOID", 254), - SYMBOL("RSAMD5", 1), - SYMBOL("RSASHA1", 5), - SYMBOL("RSASHA1-NSEC3-SHA1", 7), - SYMBOL("RSASHA256", 8), - SYMBOL("RSASHA512", 10) -}; - -static const zone_symbol_t ds_digest_type_symbols[] = { - SYMBOL("GOST", 3), - SYMBOL("SHA-1", 1), - SYMBOL("SHA-256", 2), - SYMBOL("SHA-384", 4) -}; - -static const zone_field_info_t ds_rdata_fields[] = { - FIELD("keytag", ZONE_INT16, 0), - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(ds_algorithm_symbols)), - FIELD("digtype", ZONE_INT8, 0, SYMBOLS(ds_digest_type_symbols)), - FIELD("digest", ZONE_BLOB, ZONE_BASE16) -}; - -static const zone_field_info_t sshfp_rdata_fields[] = { - FIELD("algorithm", ZONE_INT8, 0), - FIELD("ftype", ZONE_INT8, 0), - FIELD("fingerprint", ZONE_BLOB, ZONE_BASE16) -}; - -static const zone_symbol_t dnssec_algorithm_symbols[] = { - SYMBOL("DH", 2), - SYMBOL("DSA", 3), - SYMBOL("ECC", 4), - SYMBOL("INDIRECT", 252), - SYMBOL("PRIVATEDNS", 253), - SYMBOL("PRIVATEOID", 254), - SYMBOL("RSAMD5", 1), - SYMBOL("RSASHA1", 5) -}; - -static const zone_field_info_t rrsig_rdata_fields[] = { - FIELD("rrtype", ZONE_INT16, ZONE_TYPE), - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), - FIELD("labels", ZONE_INT8, 0), - FIELD("origttl", ZONE_INT32, ZONE_TTL), - FIELD("expire", ZONE_INT32, ZONE_TIME), - FIELD("inception", ZONE_INT32, ZONE_TIME), - FIELD("keytag", ZONE_INT16, 0), - FIELD("signer", ZONE_NAME, 0), - FIELD("signature", ZONE_BLOB, ZONE_BASE64) -}; - -static const zone_field_info_t nsec_rdata_fields[] = { - FIELD("next", ZONE_NAME, 0), - FIELD("types", ZONE_NSEC, 0) -}; - -static const zone_field_info_t dnskey_rdata_fields[] = { - FIELD("flags", ZONE_INT16, 0), - FIELD("protocol", ZONE_INT8, 0), - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), - FIELD("publickey", ZONE_BLOB, ZONE_BASE64) -}; - -static const zone_field_info_t dhcid_rdata_fields[] = { - FIELD("dhcpinfo", ZONE_BLOB, ZONE_BASE64) -}; - -static const zone_symbol_t nsec3_algorithm_symbols[] = { - SYMBOL("SHA-1", 1) -}; - -static const zone_symbol_t nsec3_flags_symbols[] = { - SYMBOL("OPTOUT", 1) -}; - -static const zone_field_info_t nsec3_rdata_fields[] = { - FIELD("algorithm", ZONE_INT8, 0), - FIELD("flags", ZONE_INT8, 0), - FIELD("iterations", ZONE_INT16, 0), - FIELD("salt", ZONE_STRING | ZONE_BASE16), - FIELD("next", ZONE_STRING | ZONE_BASE32), - FIELD("types", ZONE_NSEC, 0) -}; - -static const zone_field_info_t nsec3param_rdata_fields[] = { - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(nsec3_algorithm_symbols)), - FIELD("flags", ZONE_INT8, 0, SYMBOLS(nsec3_flags_symbols)), - FIELD("iterations", ZONE_INT16, 0), - FIELD("salt", ZONE_STRING, ZONE_BASE16) -}; - -static const zone_field_info_t cds_rdata_fields[] = { - FIELD("keytag", ZONE_INT16, 0), - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(ds_algorithm_symbols)), - FIELD("digtype", ZONE_INT8, 0, SYMBOLS(ds_digest_type_symbols)), - FIELD("digest", ZONE_BLOB, ZONE_BASE16) -}; - -static const zone_field_info_t cdnskey_rdata_fields[] = { - FIELD("flags", ZONE_INT16, 0), - FIELD("protocol", ZONE_INT8, 0), - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), - FIELD("publickey", ZONE_BLOB, ZONE_BASE64) -}; - -static const zone_field_info_t spf_rdata_fields[] = { - FIELD("text", ZONE_STRING, ZONE_SEQUENCE) -}; - -// RFC6742 specifies the syntax for the locator is compatible with the syntax -// for IPv4 addresses, but then proceeds to provide an example with leading -// zeroes. The example is corrected in the errata. -static const zone_field_info_t l32_rdata_fields[] = { - FIELD("preference", ZONE_INT16, 0), - FIELD("locator", ZONE_IP4, 0) -}; - -static const zone_field_info_t l64_rdata_fields[] = { - FIELD("preference", ZONE_INT16, 0), - FIELD("locator", ZONE_ILNP64, 0) -}; - -static const zone_field_info_t lp_rdata_fields[] = { - FIELD("preference", ZONE_INT16, 0), - FIELD("pointer", ZONE_NAME, 0) -}; - -static const zone_field_info_t uri_rdata_fields[] = { - FIELD("priority", ZONE_INT16, 0), - FIELD("weight", ZONE_INT16, 0), - FIELD("target", ZONE_BLOB, 0) -}; - -static const zone_field_info_t caa_rdata_fields[] = { - FIELD("flags", ZONE_INT8, 0), - FIELD("tag", ZONE_STRING, ZONE_CAA_TAG), - FIELD("value", ZONE_BLOB, 0) -}; - -// https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template -static const zone_field_info_t avc_rdata_fields[] = { - FIELD("text", ZONE_STRING, ZONE_SEQUENCE) -}; - -static const zone_field_info_t dlv_rdata_fields[] = { - FIELD("key", ZONE_INT16, 0), - FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), - FIELD("type", ZONE_INT8, 0), - FIELD("digest", ZONE_BLOB, ZONE_BASE16) -}; - -static const zone_type_descriptor_t types[] = { - UNKNOWN_TYPE(0), - - TYPE("A", ZONE_A, ZONE_ANY, FIELDS(a_rdata_fields), - zone_check_a_rdata, parse_a_rdata), - TYPE("NS", ZONE_NS, ZONE_ANY, FIELDS(ns_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("MD", ZONE_MD, ZONE_ANY | ZONE_OBSOLETE, FIELDS(md_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("MF", ZONE_MF, ZONE_ANY | ZONE_OBSOLETE, FIELDS(mf_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("CNAME", ZONE_CNAME, ZONE_ANY, FIELDS(cname_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("SOA", ZONE_SOA, ZONE_ANY, FIELDS(soa_rdata_fields), - zone_check_soa_rdata, parse_soa_rdata), - TYPE("MB", ZONE_MB, ZONE_ANY | ZONE_EXPERIMENTAL, FIELDS(mb_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("MG", ZONE_MG, ZONE_ANY | ZONE_EXPERIMENTAL, FIELDS(mg_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("MR", ZONE_MR, ZONE_ANY | ZONE_EXPERIMENTAL, FIELDS(mr_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - - UNKNOWN_TYPE(10), - - TYPE("WKS", ZONE_WKS, ZONE_IN, FIELDS(wks_rdata_fields), 0, 0), - TYPE("PTR", ZONE_PTR, ZONE_ANY, FIELDS(ptr_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - TYPE("HINFO", ZONE_HINFO, ZONE_ANY, FIELDS(hinfo_rdata_fields), - zone_check_hinfo_rdata, parse_hinfo_rdata), - TYPE("MINFO", ZONE_MINFO, ZONE_ANY, FIELDS(minfo_rdata_fields), - zone_check_minfo_rdata, parse_minfo_rdata), - TYPE("MX", ZONE_MX, ZONE_ANY, FIELDS(mx_rdata_fields), - zone_check_mx_rdata, parse_mx_rdata), - TYPE("TXT", ZONE_TXT, ZONE_ANY, FIELDS(txt_rdata_fields), - zone_check_txt_rdata, parse_txt_rdata), - TYPE("RP", ZONE_RP, ZONE_ANY, FIELDS(rp_rdata_fields), - zone_check_minfo_rdata, parse_minfo_rdata), - TYPE("AFSDB", ZONE_AFSDB, ZONE_ANY, FIELDS(afsdb_rdata_fields), - zone_check_mx_rdata, parse_mx_rdata), - TYPE("X25", ZONE_X25, ZONE_ANY, FIELDS(x25_rdata_fields), - zone_check_x25_rdata, parse_x25_rdata), - TYPE("ISDN", ZONE_ISDN, ZONE_ANY, FIELDS(isdn_rdata_fields), - zone_check_isdn_rdata, parse_isdn_rdata), - TYPE("RT", ZONE_RT, ZONE_ANY, FIELDS(rt_rdata_fields), - zone_check_rt_rdata, parse_rt_rdata), - - UNKNOWN_TYPE(22), - UNKNOWN_TYPE(23), - UNKNOWN_TYPE(24), - - TYPE("KEY", ZONE_KEY, ZONE_ANY, FIELDS(key_rdata_fields), - zone_check_key_rdata, parse_key_rdata), - - UNKNOWN_TYPE(26), - UNKNOWN_TYPE(27), - - TYPE("AAAA", ZONE_AAAA, ZONE_IN, FIELDS(aaaa_rdata_fields), - zone_check_aaaa_rdata, parse_aaaa_rdata), - - UNKNOWN_TYPE(29), - UNKNOWN_TYPE(30), - UNKNOWN_TYPE(31), - UNKNOWN_TYPE(32), - - TYPE("SRV", ZONE_SRV, ZONE_IN, FIELDS(srv_rdata_fields), - zone_check_srv_rdata, parse_srv_rdata), - - UNKNOWN_TYPE(34), - - TYPE("NAPTR", ZONE_NAPTR, ZONE_IN, FIELDS(naptr_rdata_fields), - zone_check_naptr_rdata, parse_naptr_rdata), - TYPE("KX", ZONE_KX, ZONE_IN, FIELDS(kx_rdata_fields), - zone_check_mx_rdata, parse_mx_rdata), - - UNKNOWN_TYPE(37), - UNKNOWN_TYPE(38), - - TYPE("DNAME", ZONE_DNAME, ZONE_ANY, FIELDS(dname_rdata_fields), - zone_check_ns_rdata, parse_ns_rdata), - - UNKNOWN_TYPE(40), - UNKNOWN_TYPE(41), - UNKNOWN_TYPE(42), - - TYPE("DS", ZONE_DS, ZONE_ANY, FIELDS(ds_rdata_fields), - zone_check_ds_rdata, parse_ds_rdata), - TYPE("SSHFP", ZONE_SSHFP, ZONE_ANY, FIELDS(sshfp_rdata_fields), - zone_check_sshfp_rdata, parse_sshfp_rdata), - - UNKNOWN_TYPE(45), // IPSECKEY - - TYPE("RRSIG", ZONE_RRSIG, ZONE_ANY, FIELDS(rrsig_rdata_fields), - zone_check_rrsig_rdata, parse_rrsig_rdata), - TYPE("NSEC", ZONE_NSEC, ZONE_ANY, FIELDS(nsec_rdata_fields), - zone_check_nsec_rdata, parse_nsec_rdata), - TYPE("DNSKEY", ZONE_DNSKEY, ZONE_ANY, FIELDS(dnskey_rdata_fields), - zone_check_dnskey_rdata, parse_dnskey_rdata), - TYPE("DHCID", ZONE_DHCID, ZONE_IN, FIELDS(dhcid_rdata_fields), - zone_check_dhcid_rdata, parse_dhcid_rdata), - TYPE("NSEC3", ZONE_NSEC3, ZONE_ANY, FIELDS(nsec3_rdata_fields), - zone_check_nsec3_rdata, parse_nsec3_rdata), - TYPE("NSEC3PARAM", ZONE_NSEC3PARAM, ZONE_ANY, FIELDS(nsec3param_rdata_fields), - zone_check_nsec3param_rdata, parse_nsec3param_rdata), - - UNKNOWN_TYPE(52), // TLSA - UNKNOWN_TYPE(53), // SMIMEA - UNKNOWN_TYPE(54), - UNKNOWN_TYPE(55), // HIP - UNKNOWN_TYPE(56), - UNKNOWN_TYPE(57), - UNKNOWN_TYPE(58), - - TYPE("CDS", ZONE_CDS, ZONE_ANY, FIELDS(cds_rdata_fields), - zone_check_ds_rdata, parse_ds_rdata), - TYPE("CDNSKEY", ZONE_CDNSKEY, ZONE_ANY, FIELDS(cdnskey_rdata_fields), - zone_check_dnskey_rdata, parse_dnskey_rdata), - - UNKNOWN_TYPE(61), - UNKNOWN_TYPE(62), - UNKNOWN_TYPE(63), - UNKNOWN_TYPE(64), - UNKNOWN_TYPE(65), - UNKNOWN_TYPE(66), - UNKNOWN_TYPE(67), - UNKNOWN_TYPE(68), - UNKNOWN_TYPE(69), - UNKNOWN_TYPE(70), - UNKNOWN_TYPE(71), - UNKNOWN_TYPE(72), - UNKNOWN_TYPE(73), - UNKNOWN_TYPE(74), - UNKNOWN_TYPE(75), - UNKNOWN_TYPE(76), - UNKNOWN_TYPE(77), - UNKNOWN_TYPE(78), - UNKNOWN_TYPE(79), - UNKNOWN_TYPE(80), - UNKNOWN_TYPE(81), - UNKNOWN_TYPE(82), - UNKNOWN_TYPE(83), - UNKNOWN_TYPE(84), - UNKNOWN_TYPE(85), - UNKNOWN_TYPE(86), - UNKNOWN_TYPE(87), - UNKNOWN_TYPE(88), - UNKNOWN_TYPE(89), - UNKNOWN_TYPE(90), - UNKNOWN_TYPE(91), - UNKNOWN_TYPE(92), - UNKNOWN_TYPE(93), - UNKNOWN_TYPE(94), - UNKNOWN_TYPE(95), - UNKNOWN_TYPE(96), - UNKNOWN_TYPE(97), - UNKNOWN_TYPE(98), - - TYPE("SPF", ZONE_SPF, ZONE_ANY | ZONE_OBSOLETE, FIELDS(spf_rdata_fields), - zone_check_txt_rdata, parse_txt_rdata), - - UNKNOWN_TYPE(100), - UNKNOWN_TYPE(101), - UNKNOWN_TYPE(102), - UNKNOWN_TYPE(103), - UNKNOWN_TYPE(104), - - TYPE("L32", ZONE_L32, ZONE_ANY, FIELDS(l32_rdata_fields), - zone_check_l32_rdata, parse_l32_rdata), - TYPE("L64", ZONE_L64, ZONE_ANY, FIELDS(l64_rdata_fields), - zone_check_l64_rdata, parse_l64_rdata), - TYPE("LP", ZONE_LP, ZONE_ANY, FIELDS(lp_rdata_fields), - zone_check_mx_rdata, parse_mx_rdata), - - UNKNOWN_TYPE(108), - UNKNOWN_TYPE(109), - UNKNOWN_TYPE(110), - UNKNOWN_TYPE(111), - UNKNOWN_TYPE(112), - UNKNOWN_TYPE(113), - UNKNOWN_TYPE(114), - UNKNOWN_TYPE(115), - UNKNOWN_TYPE(116), - UNKNOWN_TYPE(117), - UNKNOWN_TYPE(118), - UNKNOWN_TYPE(119), - UNKNOWN_TYPE(120), - UNKNOWN_TYPE(121), - UNKNOWN_TYPE(122), - UNKNOWN_TYPE(123), - UNKNOWN_TYPE(124), - UNKNOWN_TYPE(125), - UNKNOWN_TYPE(126), - UNKNOWN_TYPE(127), - UNKNOWN_TYPE(128), - UNKNOWN_TYPE(129), - UNKNOWN_TYPE(130), - UNKNOWN_TYPE(131), - UNKNOWN_TYPE(132), - UNKNOWN_TYPE(133), - UNKNOWN_TYPE(134), - UNKNOWN_TYPE(135), - UNKNOWN_TYPE(136), - UNKNOWN_TYPE(137), - UNKNOWN_TYPE(138), - UNKNOWN_TYPE(139), - UNKNOWN_TYPE(140), - UNKNOWN_TYPE(141), - UNKNOWN_TYPE(142), - UNKNOWN_TYPE(143), - UNKNOWN_TYPE(144), - UNKNOWN_TYPE(145), - UNKNOWN_TYPE(146), - UNKNOWN_TYPE(147), - UNKNOWN_TYPE(148), - UNKNOWN_TYPE(149), - UNKNOWN_TYPE(150), - UNKNOWN_TYPE(151), - UNKNOWN_TYPE(152), - UNKNOWN_TYPE(153), - UNKNOWN_TYPE(154), - UNKNOWN_TYPE(155), - UNKNOWN_TYPE(156), - UNKNOWN_TYPE(157), - UNKNOWN_TYPE(158), - UNKNOWN_TYPE(159), - UNKNOWN_TYPE(160), - UNKNOWN_TYPE(161), - UNKNOWN_TYPE(162), - UNKNOWN_TYPE(163), - UNKNOWN_TYPE(164), - UNKNOWN_TYPE(165), - UNKNOWN_TYPE(166), - UNKNOWN_TYPE(167), - UNKNOWN_TYPE(168), - UNKNOWN_TYPE(169), - UNKNOWN_TYPE(170), - UNKNOWN_TYPE(171), - UNKNOWN_TYPE(172), - UNKNOWN_TYPE(173), - UNKNOWN_TYPE(174), - UNKNOWN_TYPE(175), - UNKNOWN_TYPE(176), - UNKNOWN_TYPE(177), - UNKNOWN_TYPE(178), - UNKNOWN_TYPE(179), - UNKNOWN_TYPE(180), - UNKNOWN_TYPE(181), - UNKNOWN_TYPE(182), - UNKNOWN_TYPE(183), - UNKNOWN_TYPE(184), - UNKNOWN_TYPE(185), - UNKNOWN_TYPE(186), - UNKNOWN_TYPE(187), - UNKNOWN_TYPE(188), - UNKNOWN_TYPE(189), - UNKNOWN_TYPE(190), - UNKNOWN_TYPE(191), - UNKNOWN_TYPE(192), - UNKNOWN_TYPE(193), - UNKNOWN_TYPE(194), - UNKNOWN_TYPE(195), - UNKNOWN_TYPE(196), - UNKNOWN_TYPE(197), - UNKNOWN_TYPE(198), - UNKNOWN_TYPE(199), - UNKNOWN_TYPE(200), - UNKNOWN_TYPE(201), - UNKNOWN_TYPE(202), - UNKNOWN_TYPE(203), - UNKNOWN_TYPE(204), - UNKNOWN_TYPE(205), - UNKNOWN_TYPE(206), - UNKNOWN_TYPE(207), - UNKNOWN_TYPE(208), - UNKNOWN_TYPE(209), - UNKNOWN_TYPE(210), - UNKNOWN_TYPE(211), - UNKNOWN_TYPE(212), - UNKNOWN_TYPE(213), - UNKNOWN_TYPE(214), - UNKNOWN_TYPE(215), - UNKNOWN_TYPE(216), - UNKNOWN_TYPE(217), - UNKNOWN_TYPE(218), - UNKNOWN_TYPE(219), - UNKNOWN_TYPE(220), - UNKNOWN_TYPE(221), - UNKNOWN_TYPE(222), - UNKNOWN_TYPE(223), - UNKNOWN_TYPE(224), - UNKNOWN_TYPE(225), - UNKNOWN_TYPE(226), - UNKNOWN_TYPE(227), - UNKNOWN_TYPE(228), - UNKNOWN_TYPE(229), - UNKNOWN_TYPE(230), - UNKNOWN_TYPE(231), - UNKNOWN_TYPE(232), - UNKNOWN_TYPE(233), - UNKNOWN_TYPE(234), - UNKNOWN_TYPE(235), - UNKNOWN_TYPE(236), - UNKNOWN_TYPE(237), - UNKNOWN_TYPE(238), - UNKNOWN_TYPE(239), - UNKNOWN_TYPE(240), - UNKNOWN_TYPE(241), - UNKNOWN_TYPE(242), - UNKNOWN_TYPE(243), - UNKNOWN_TYPE(244), - UNKNOWN_TYPE(245), - UNKNOWN_TYPE(246), - UNKNOWN_TYPE(247), - UNKNOWN_TYPE(248), - UNKNOWN_TYPE(249), - UNKNOWN_TYPE(250), - UNKNOWN_TYPE(251), - UNKNOWN_TYPE(252), - UNKNOWN_TYPE(253), - UNKNOWN_TYPE(254), - UNKNOWN_TYPE(255), - - TYPE("URI", ZONE_URI, ZONE_ANY, FIELDS(uri_rdata_fields), - zone_check_uri_rdata, parse_uri_rdata), - TYPE("CAA", ZONE_CAA, ZONE_ANY, FIELDS(caa_rdata_fields), - zone_check_caa_rdata, parse_caa_rdata), - TYPE("AVC", ZONE_AVC, ZONE_ANY, FIELDS(avc_rdata_fields), - zone_check_txt_rdata, parse_txt_rdata), - TYPE("DLV", ZONE_DLV, ZONE_ANY | ZONE_OBSOLETE, FIELDS(dlv_rdata_fields), - zone_check_ds_rdata, parse_ds_rdata) -}; - -#undef UNKNOWN_TYPE -#undef TYPE - -diagnostic_pop() - zone_nonnull_all static zone_really_inline int32_t parse_owner( zone_parser_t *parser, @@ -1391,7 +41,7 @@ static zone_really_inline int32_t parse_owner( relative: if (n > 255 - parser->file->origin.length) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); memcpy(o+n, parser->file->origin.octets, parser->file->origin.length); parser->owner->length = n + parser->file->origin.length; return ZONE_NAME; @@ -1402,7 +52,7 @@ static zone_really_inline int32_t parse_rr( zone_parser_t *parser, token_t *token) { static const zone_type_info_t unknown = - { { 6, "record" }, 0, 0, { 0, NULL } }; + { { { "record", 6 }, 0 }, 0, { 0, NULL } }; static const zone_field_info_t owner = { { 5, "owner" }, ZONE_NAME, 0, { 0 } }; static const zone_field_info_t ttl = @@ -1412,9 +62,10 @@ static zone_really_inline int32_t parse_rr( static const zone_string_t backslash_hash = { 2, "\\#" }; int32_t r; - const zone_type_descriptor_t *descriptor; + const type_descriptor_t *descriptor; uint16_t code; uint32_t epoch; + const zone_symbol_t *symbol; if (parser->file->start_of_line) { parse_owner(parser, &unknown, &owner, token); @@ -1426,7 +77,7 @@ static zone_really_inline int32_t parse_rr( return r; goto class_or_type; } else { - r = scan_type_or_class(parser, &unknown, &type, token, &code); + r = scan_type_or_class(parser, &unknown, &type, token, &code, &symbol); if (zone_likely(r == ZONE_TYPE)) { parser->file->last_type = code; goto rdata; @@ -1441,12 +92,12 @@ static zone_really_inline int32_t parse_rr( ttl_or_type: lex(parser, token); - if ((uint8_t)token->data[0] - '0' <= 9) { // << this is illegal before checking the code + if ((uint8_t)token->data[0] - '0' <= 9) { if ((r = scan_ttl(parser, &unknown, &ttl, token, &epoch)) < 0) return r; goto type; } else { - if ((r = scan_type(parser, &unknown, &type, token, &code)) < 0) + if ((r = scan_type(parser, &unknown, &type, token, &code, &symbol)) < 0) return r; parser->file->last_type = code; goto rdata; @@ -1454,7 +105,7 @@ static zone_really_inline int32_t parse_rr( class_or_type: lex(parser, token); - r = scan_type_or_class(parser, &unknown, &type, token, &code); + r = scan_type_or_class(parser, &unknown, &type, token, &code, &symbol); if (zone_likely(r == ZONE_TYPE)) { parser->file->last_type = code; goto rdata; @@ -1468,17 +119,12 @@ static zone_really_inline int32_t parse_rr( type: lex(parser, token); - if ((r = scan_type(parser, &unknown, &type, token, &code)) < 0) + if ((r = scan_type(parser, &unknown, &type, token, &code, &symbol)) < 0) return r; parser->file->last_type = code; rdata: - if (zone_likely(code <= 258)) - descriptor = &types[code]; - else if (code == ZONE_DLV) - descriptor = &types[259]; - else - descriptor = &types[0]; // unknown type + descriptor = (type_descriptor_t *)symbol; parser->rdata->length = 0; @@ -1504,7 +150,7 @@ static zone_really_inline int32_t parse_dollar_include( { { 11, "domain-name" }, ZONE_NAME, 0, { 0 } } }; static const zone_type_info_t type = - { { 8, "$INCLUDE" }, 0, 0, { 1, fields } }; + { { { "$INCLUDE", 8 }, 0 }, 0, { 1, fields } }; int32_t r; zone_file_t *includer, *file; @@ -1578,7 +224,7 @@ static zone_really_inline int32_t parse_dollar_include( return 0; relative_name: zone_close_file(parser, file); - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&type), NAME(&fields[1])); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[1]), TNAME(&type)); invalid_name: zone_close_file(parser, file); return r; @@ -1593,7 +239,7 @@ static inline int32_t parse_dollar_origin( static const zone_field_info_t field = { { 4, "name" }, ZONE_NAME, 0, { 0 } }; static const zone_type_info_t type = - { { 7, "$ORIGIN" }, 0, 0, { 1, &field } }; + { { { "$ORIGIN", 7 }, 0 }, 0, { 1, &field } }; int32_t r; @@ -1612,7 +258,7 @@ static inline int32_t parse_dollar_origin( if (r < 0) return r; if (r > 0) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&field), NAME(&type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&field), TNAME(&type)); lex(parser, token); return have_delimiter(parser, &type, token); @@ -1627,7 +273,7 @@ static inline int32_t parse_dollar_ttl( static const zone_field_info_t field = { { 3, "ttl" }, ZONE_INT32, 0, { 0 } }; static const zone_type_info_t type = - { { 4, "$TTL" }, 0, 0, { 1, &field } }; + { { { "$TTL", 4 }, 0 }, 0, { 1, &field } }; int32_t r; diff --git a/src/types.c b/src/types.c deleted file mode 100644 index df71d89..0000000 --- a/src/types.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * types.h -- some useful description - * - * Copyright (c) 2023, NLnet Labs. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#include "zone.h" - -#define TYPE(name, code) { { sizeof(name) - 1, name }, (ZONE_TYPE << 16) | code } -#define CLASS(name, code) { { sizeof(name) - 1, name }, (ZONE_CLASS << 16) | code } - -static const zone_symbol_t x[] = { - /* 0 */ TYPE("A", ZONE_A), - /* 1 */ TYPE("A6", ZONE_A6), - /* 2 */ TYPE("AAAA", ZONE_AAAA), - /* 3 */ TYPE("AFSDB", ZONE_AFSDB), - /* 4 */ TYPE("APL", ZONE_APL), - /* 5 */ TYPE("AVC", ZONE_AVC), - - /* 6 */ TYPE("CAA", ZONE_CAA), - /* 7 */ TYPE("CDNSKEY", ZONE_CDNSKEY), - /* 8 */ TYPE("CDS", ZONE_CDS), - /* 9 */ TYPE("CERT", ZONE_CERT), - /* 0 */ CLASS("CH", ZONE_CH), - /* 11 */ TYPE("CNAME", ZONE_CNAME), - /* 12 */ CLASS("CS", ZONE_CS), - /* 13 */ TYPE("CSYNC", ZONE_CSYNC), - - /* 14 */ TYPE("DHCID", ZONE_DHCID), - /* 15 */ TYPE("DLV", ZONE_DLV), - /* 16 */ TYPE("DNAME", ZONE_DNAME), - /* 17 */ TYPE("DNSKEY", ZONE_DNSKEY), - /* 18 */ TYPE("DS", ZONE_DS), - - /* 19 */ TYPE("EUI48", ZONE_EUI48), - /* 20 */ TYPE("EUI64", ZONE_EUI64), - - /* 21 */ TYPE("GPOS", ZONE_GPOS), - - /* 22 */ TYPE("HINFO", ZONE_HINFO), - /* 23 */ TYPE("HIP", ZONE_HIP), - /* 24 */ CLASS("HS", ZONE_HS), - /* 25 */ TYPE("HTTPS", ZONE_HTTPS), - - /* 26 */ CLASS("IN", ZONE_IN), - /* 27 */ TYPE("IPSECKEY", ZONE_IPSECKEY), - /* 28 */ TYPE("ISDN", ZONE_ISDN), - - /* 29 */ TYPE("KEY", ZONE_KEY), - /* 30 */ TYPE("KX", ZONE_KX), - - /* 31 */ TYPE("L32", ZONE_L32), - /* 32 */ TYPE("L64", ZONE_L64), - /* 33 */ TYPE("LOC", ZONE_LOC), - /* 34 */ TYPE("LP", ZONE_LP), - - /* 35 */ TYPE("MB", ZONE_MB), - /* 36 */ TYPE("MD", ZONE_MD), - /* 37 */ TYPE("MF", ZONE_MF), - /* 38 */ TYPE("MG", ZONE_MG), - /* 39 */ TYPE("MINFO", ZONE_MINFO), - /* 40 */ TYPE("MR", ZONE_MR), - /* 41 */ TYPE("MX", ZONE_MX), - - /* 42 */ TYPE("NAPTR", ZONE_NAPTR), - /* 43 */ TYPE("NID", ZONE_NID), - /* 44 */ TYPE("NS", ZONE_NS), - /* 45 */ TYPE("NSAP", ZONE_NSAP), - /* 46 */ TYPE("NSAP-PTR", ZONE_NSAP_PTR), - /* 47 */ TYPE("NSEC", ZONE_NSEC), - /* 48 */ TYPE("NSEC3", ZONE_NSEC3), - /* 49 */ TYPE("NSEC3PARAM", ZONE_NSEC3PARAM), - /* 50 */ TYPE("NULL", ZONE_NULL), - /* 51 */ TYPE("NXT", ZONE_NXT), - - /* 52 */ TYPE("OPENPGPKEY", ZONE_OPENPGPKEY), - - /* 53 */ TYPE("PTR", ZONE_PTR), - /* 54 */ TYPE("PX", ZONE_PX), - - /* 55 */ TYPE("RP", ZONE_RP), - /* 56 */ TYPE("RRSIG", ZONE_RRSIG), - /* 57 */ TYPE("RT", ZONE_RT), - - /* 58 */ TYPE("SIG", ZONE_SIG), - /* 59 */ TYPE("SMIMEA", ZONE_SMIMEA), - /* 60 */ TYPE("SOA", ZONE_SOA), - /* 61 */ TYPE("SPF", ZONE_SPF), - /* 62 */ TYPE("SRV", ZONE_SRV), - /* 63 */ TYPE("SSHFP", ZONE_SSHFP), - /* 64 */ TYPE("SVCB", ZONE_SVCB), - - /* 65 */ TYPE("TLSA", ZONE_TLSA), - /* 66 */ TYPE("TXT", ZONE_TXT), - - /* 67 */ TYPE("URI", ZONE_URI), - - /* 68 */ TYPE("WKS", ZONE_WKS), - - /* 69 */ TYPE("X25", ZONE_X25), - - /* 70 */ TYPE("ZONEMD", ZONE_MD) -}; - -#undef CLASS -#undef TYPE - -static const zone_table_t identifiers = { sizeof(x)/sizeof(x[0]), x }; - -// type: AVC, key: 0, hash: 216 -static const zone_fast_table_t fast_identifiers[32] = { - // A[A,A6,AAAA,AFSDB,APL] - { { 200, 156, 203, 211, 23, 216 }, - { &x[0], &x[1], &x[2], &x[3], &x[4], &x[5] } }, - // B - { { 0 }, { NULL } }, - // C[CAA,CDS,CDNSKEY,CERT,CH,CNAME,CS,CSYNC] - { { 202, 118, 72, 80, 250, 232, 71, 218 }, - { &x[6], &x[7], &x[8], &x[9], &x[10], &x[11], &x[12], &x[13] } }, - // D[DHCID, DLV, DNAME, DNSKEY, DS] - { { 225, 93, 232, 117, 71 }, - { &x[14], &x[15], &x[16], &x[17], &x[18] } }, - // E[EUI48=108,EUI64=109] - { { 173, 145 }, - { &x[19], &x[20] } }, - // F - { { 0 }, { NULL } }, - // G[GPOS=27] - { { 73 }, - { &x[21] } }, - // H[HINFO,HIP,HS,HTTPS] - { { 46,51,71,74 }, - { &x[22], &x[23], &x[24], &x[25] } }, - // I[IN,IPSECKEY,ISDN] - { { 36, 119, 38 }, - { &x[26], &x[27], &x[28] } }, - // J - { { 0 }, { NULL } }, - // K[KEY,KX] - { { 114, 106 }, - { &x[29], &x[30] } }, - // L[L32,L64,LOC,LP] - { { 129, 143, 216, 50 }, - { &x[31], &x[32], &x[33], &x[34] } }, - // M[MB,MD,MF,MG,MINFO,MR,MX] - { { 208, 222, 236, 243, 46, 64, 106 }, - { &x[35], &x[36], &x[37], &x[38], &x[39], &x[40], &x[41] } }, - // N[NAPTR,NID,NS,NSAP,NSAP-PTR,NSEC,NSEC3,NSEC3PARAM,NULL,NXT] - { { 67, 223, 71, 52, 70, 217, 138, 37, 24, 79}, - { &x[42], &x[43], &x[44], &x[45], &x[46], &x[47], &x[48], &x[49], &x[50], - &x[51] } }, - // O[OPENPGPKEY,OPT] - { { 121 }, - { &x[52] } }, - // P[PTR=12,PX=26] - { { 65, 106 }, - { &x[53], &x[54] } }, - // Q - { { 0 }, { NULL } }, - // R[RP,RRSIG,RT] - { { 50, 246, 78 }, - { &x[55], &x[56], &x[57] } }, - // S[SIG,SMIMEA,SOA,SPF,SRV,SSHFP,SVCB] - { { 244, 205, 202, 237, 93, 53, 210 }, - { &x[58], &x[59], &x[60], &x[61], &x[62], &x[63], &x[64] } }, - // T[TLSA,TXT] - { { 203, 79 }, - { &x[65], &x[66] } }, - // U[URI] - { { 2 }, - { &x[67] } }, - // V - { { 0 }, { NULL } }, - // W[WKS] - { { 66 }, - { &x[68] } }, - // X[X25] - { { 150 }, - { &x[69] } }, - // Y - { { 0 }, { NULL } }, - // Z[ZONEMD] - { { 226 }, - { &x[70] } }, - { { 0 }, { NULL } }, - { { 0 }, { NULL } }, - { { 0 }, { NULL } }, - { { 0 }, { NULL } }, - { { 0 }, { NULL } }, - { { 0 }, { NULL } }, -}; - -const zone_table_t *zone_identifiers = &identifiers; -const zone_fast_table_t *zone_fast_identifiers = fast_identifiers; diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..cecc7a7 --- /dev/null +++ b/src/types.h @@ -0,0 +1,1408 @@ +/* + * types.h -- some useful comment + * + * Copyright (c) 2023, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef TYPES_H +#define TYPES_H + +zone_nonnull_all +static zone_really_inline int32_t scan_type_or_class( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol); + +zone_nonnull_all +static zone_really_inline int32_t scan_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol); + +zone_nonnull_all +static zone_really_inline int32_t parse_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token); + +zone_nonnull_all +extern int32_t zone_check_a_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_a_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_ip4(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_ns_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_ns_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_soa_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_soa_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int32(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ttl(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ttl(parser, type, &type->rdata.fields[4], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ttl(parser, type, &type->rdata.fields[5], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ttl(parser, type, &type->rdata.fields[6], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_hinfo_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_hinfo_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_string(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_minfo_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_minfo_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_mx_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_mx_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_txt_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_txt_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + do { + if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + } while (token->code & (CONTIGUOUS | QUOTED)); + + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_x25_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_x25_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_isdn_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_isdn_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_string(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + + // subaddress is optional + if (token->code & (CONTIGUOUS | QUOTED)) { + if ((r = parse_string(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + } + + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_rt_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_rt_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_key_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_key_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return zone_check_key_rdata(parser, type); +} + +zone_nonnull_all +extern int32_t zone_check_aaaa_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_aaaa_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_ip6(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_srv_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_srv_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_naptr_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_naptr_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_string(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_string(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_string(parser, type, &type->rdata.fields[4], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[5], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_ds_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_ds_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_symbol(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_base16(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_sshfp_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_sshfp_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int8(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_base16(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + + return zone_check_sshfp_rdata(parser, type); +} + +zone_nonnull_all +extern int32_t zone_check_rrsig_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_rrsig_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_type(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int8(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ttl(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_time(parser, type, &type->rdata.fields[4], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_time(parser, type, &type->rdata.fields[5], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[6], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_name(parser, type, &type->rdata.fields[7], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_base64(parser, type, &type->rdata.fields[8], token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_nsec_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_nsec_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_name(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_nsec(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_dnskey_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_dnskey_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int8(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_symbol(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_base64(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_dhcid_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_dhcid_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_base64(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + + return zone_check_dhcid_rdata(parser, type); +} + +zone_nonnull_all +extern int32_t zone_check_nsec3_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_nsec3_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_symbol(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_salt(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_base32(parser, type, &type->rdata.fields[4], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_nsec(parser, type, &type->rdata.fields[5], token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_nsec3param_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_nsec3param_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_symbol(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_symbol(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_salt(parser, type, &type->rdata.fields[3], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_l32_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_l32_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ip4(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_l64_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_l64_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_ilnp64(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_uri_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_uri_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int16(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_int16(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_quoted_text(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +zone_nonnull_all +extern int32_t zone_check_caa_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_caa_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + int32_t r; + + if ((r = parse_int8(parser, type, &type->rdata.fields[0], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_caa_tag(parser, type, &type->rdata.fields[1], token)) < 0) + return r; + lex(parser, token); + if ((r = parse_text(parser, type, &type->rdata.fields[2], token)) < 0) + return r; + lex(parser, token); + if ((r = have_delimiter(parser, type, token)) < 0) + return r; + + return accept_rr(parser); +} + +typedef struct type_descriptor type_descriptor_t; +struct type_descriptor { + zone_type_info_t info; + int32_t (*check)(zone_parser_t *, const zone_type_info_t *); + int32_t (*parse)(zone_parser_t *, const zone_type_info_t *, token_t *); +}; + +zone_nonnull_all +extern int32_t zone_check_generic_rdata( + zone_parser_t *parser, const zone_type_info_t *type); + +zone_nonnull_all +static int32_t parse_generic_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + static const zone_field_info_t fields[2] = { + { { 12, "RDATA length" }, ZONE_INT16, 0, { 0, NULL } }, + { { 5, "RDATA" }, ZONE_BLOB, 0, { 0, NULL } } + }; + + int32_t r; + + lex(parser, token); // discard "\\#" + if ((r = have_contiguous(parser, type, &fields[0], token)) < 0) + return r; + + size_t n = 0; + const char *p = token->data; + for (;; p++) { + const size_t d = (uint8_t)*p - '0'; + if (d > 9) + break; + n = n * 10 +d; + } + + if (n > UINT16_MAX || p - token->data > 5 || is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), TNAME(type)); + + lex(parser, token); + if (n) + r = parse_base16(parser, type, &fields[1], token); + else + r = have_delimiter(parser, type, token); + if (r < 0) + return r; + if (parser->rdata->length != n) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(&fields[0]), TNAME(type)); + return ((const type_descriptor_t *)type)->check(parser, type); +} + +zone_nonnull_all +static int32_t parse_unknown_rdata( + zone_parser_t *parser, const zone_type_info_t *type, token_t *token) +{ + (void)type; + (void)token; + SYNTAX_ERROR(parser, "Unknown record type"); +} + +#define SYMBOLS(symbols) \ + { (sizeof(symbols)/sizeof(symbols[0])), symbols } + +#define SYMBOL(name, value) \ + { { name, sizeof(name) - 1 }, value } + +#define FIELDS(fields) \ + { (sizeof(fields)/sizeof(fields[0])), fields } + +#define FIELD(name, type, /* qualifiers, symbols */ ...) \ + { { sizeof(name) - 1, name }, type, __VA_ARGS__ } + +#define CLASS(name, code) \ + { { { name, sizeof(name) - 1 }, code } } + +#define UNKNOWN_CLASS(code) \ + { { { "", 0 }, code } } + +#define TYPE(name, code, options, fields, check, parse) \ + { { { { name, sizeof(name) - 1 }, code }, options, fields }, check, parse } + +#define UNKNOWN_TYPE(code) \ + { { { { "", 0 }, code }, 0, { 0, NULL } }, \ + zone_check_generic_rdata, parse_unknown_rdata } + +diagnostic_push() +gcc_diagnostic_ignored(missing-field-initializers) +clang_diagnostic_ignored(missing-field-initializers) + +typedef struct class_descriptor class_descriptor_t; +struct class_descriptor { + zone_symbol_t name; +}; + +static const class_descriptor_t classes[] = { + UNKNOWN_CLASS(0), + CLASS("IN", 1), + CLASS("CS", 2), + CLASS("CH", 3), + CLASS("HS", 4) +}; + +static const zone_field_info_t a_rdata_fields[] = { + FIELD("address", ZONE_IP4, 0) +}; + +static const zone_field_info_t ns_rdata_fields[] = { + FIELD("host", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t md_rdata_fields[] = { + FIELD("madname", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t mf_rdata_fields[] = { + FIELD("madname", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t cname_rdata_fields[] = { + FIELD("host", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t soa_rdata_fields[] = { + FIELD("primary", ZONE_NAME, ZONE_COMPRESSED), + FIELD("mailbox", ZONE_NAME, ZONE_MAILBOX), + FIELD("serial", ZONE_INT32, 0), + FIELD("refresh", ZONE_INT32, ZONE_TTL), + FIELD("retry", ZONE_INT32, ZONE_TTL), + FIELD("expire", ZONE_INT32, ZONE_TTL), + FIELD("minimum", ZONE_INT32, ZONE_TTL) +}; + +static const zone_field_info_t mb_rdata_fields[] = { + FIELD("madname", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t mg_rdata_fields[] = { + FIELD("mgmname", ZONE_NAME, ZONE_MAILBOX) +}; + +static const zone_field_info_t mr_rdata_fields[] = { + FIELD("newname", ZONE_NAME, ZONE_MAILBOX) +}; + +static const zone_field_info_t ptr_rdata_fields[] = { + FIELD("ptrdname", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t hinfo_rdata_fields[] = { + FIELD("cpu", ZONE_STRING, 0), + FIELD("os", ZONE_STRING, 0) +}; + +static const zone_field_info_t minfo_rdata_fields[] = { + FIELD("rmailbx", ZONE_NAME, ZONE_MAILBOX), + FIELD("emailbx", ZONE_NAME, ZONE_MAILBOX) +}; + +static const zone_field_info_t wks_rdata_fields[] = { + FIELD("address", ZONE_IP4, 0), + FIELD("protocol", ZONE_INT8, 0), + FIELD("bitmap", ZONE_WKS, 0) +}; + +static const zone_field_info_t mx_rdata_fields[] = { + FIELD("priority", ZONE_INT16, 0), + FIELD("hostname", ZONE_NAME, ZONE_COMPRESSED) +}; + +static const zone_field_info_t txt_rdata_fields[] = { + FIELD("text", ZONE_STRING, ZONE_SEQUENCE) +}; + +static const zone_field_info_t rp_rdata_fields[] = { + FIELD("mailbox", ZONE_NAME, ZONE_MAILBOX), + FIELD("text", ZONE_NAME, 0) +}; + +static const zone_field_info_t afsdb_rdata_fields[] = { + FIELD("subtype", ZONE_INT16, 0), + FIELD("hostname", ZONE_NAME, 0) +}; + +static const zone_field_info_t x25_rdata_fields[] = { + FIELD("address", ZONE_STRING, 0) +}; + +static const zone_field_info_t isdn_rdata_fields[] = { + FIELD("address", ZONE_STRING, 0), + FIELD("subaddress", ZONE_STRING, 0) +}; + +static const zone_field_info_t rt_rdata_fields[] = { + FIELD("preference", ZONE_INT16, 0), + FIELD("hostname", ZONE_NAME, 0) +}; + +static const zone_field_info_t key_rdata_fields[] = { + FIELD("flags", ZONE_INT16, 0), + FIELD("protocol", ZONE_INT8, 0), + FIELD("algorithm", ZONE_INT8, 0), + FIELD("publickey", ZONE_BLOB, ZONE_BASE64) +}; + +static const zone_field_info_t aaaa_rdata_fields[] = { + FIELD("address", ZONE_IP6, 0) +}; + +static const zone_field_info_t srv_rdata_fields[] = { + FIELD("priority", ZONE_INT16, 0), + FIELD("weight", ZONE_INT16, 0), + FIELD("port", ZONE_INT16, 0), + FIELD("target", ZONE_NAME, 0) +}; + +static const zone_field_info_t naptr_rdata_fields[] = { + FIELD("order", ZONE_INT16, 0), + FIELD("preference", ZONE_INT16, 0), + FIELD("flags", ZONE_STRING, 0), + FIELD("services", ZONE_STRING, 0), + FIELD("regex", ZONE_STRING, 0), + FIELD("replacement", ZONE_NAME, 0), +}; + +static const zone_field_info_t kx_rdata_fields[] = { + FIELD("preference", ZONE_INT16, 0), + FIELD("exchanger", ZONE_NAME, 0) +}; + +static const zone_field_info_t dname_rdata_fields[] = { + FIELD("source", ZONE_NAME, 0) +}; + +static const zone_symbol_t ds_algorithm_symbols[] = { + SYMBOL("DH", 2), + SYMBOL("DSA", 3), + SYMBOL("DSA-NSEC-SHA1", 6), + SYMBOL("ECC", 4), + SYMBOL("ECC-GOST", 12), + SYMBOL("ECDSAP256SHA256", 13), + SYMBOL("ECDSAP384SHA384", 14), + SYMBOL("INDIRECT", 252), + SYMBOL("PRIVATEDNS", 253), + SYMBOL("PRIVATEOID", 254), + SYMBOL("RSAMD5", 1), + SYMBOL("RSASHA1", 5), + SYMBOL("RSASHA1-NSEC3-SHA1", 7), + SYMBOL("RSASHA256", 8), + SYMBOL("RSASHA512", 10) +}; + +static const zone_symbol_t ds_digest_type_symbols[] = { + SYMBOL("GOST", 3), + SYMBOL("SHA-1", 1), + SYMBOL("SHA-256", 2), + SYMBOL("SHA-384", 4) +}; + +static const zone_field_info_t ds_rdata_fields[] = { + FIELD("keytag", ZONE_INT16, 0), + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(ds_algorithm_symbols)), + FIELD("digtype", ZONE_INT8, 0, SYMBOLS(ds_digest_type_symbols)), + FIELD("digest", ZONE_BLOB, ZONE_BASE16) +}; + +static const zone_field_info_t sshfp_rdata_fields[] = { + FIELD("algorithm", ZONE_INT8, 0), + FIELD("ftype", ZONE_INT8, 0), + FIELD("fingerprint", ZONE_BLOB, ZONE_BASE16) +}; + +static const zone_symbol_t dnssec_algorithm_symbols[] = { + SYMBOL("DH", 2), + SYMBOL("DSA", 3), + SYMBOL("ECC", 4), + SYMBOL("INDIRECT", 252), + SYMBOL("PRIVATEDNS", 253), + SYMBOL("PRIVATEOID", 254), + SYMBOL("RSAMD5", 1), + SYMBOL("RSASHA1", 5) +}; + +static const zone_field_info_t rrsig_rdata_fields[] = { + FIELD("rrtype", ZONE_INT16, ZONE_TYPE), + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), + FIELD("labels", ZONE_INT8, 0), + FIELD("origttl", ZONE_INT32, ZONE_TTL), + FIELD("expire", ZONE_INT32, ZONE_TIME), + FIELD("inception", ZONE_INT32, ZONE_TIME), + FIELD("keytag", ZONE_INT16, 0), + FIELD("signer", ZONE_NAME, 0), + FIELD("signature", ZONE_BLOB, ZONE_BASE64) +}; + +static const zone_field_info_t nsec_rdata_fields[] = { + FIELD("next", ZONE_NAME, 0), + FIELD("types", ZONE_NSEC, 0) +}; + +static const zone_field_info_t dnskey_rdata_fields[] = { + FIELD("flags", ZONE_INT16, 0), + FIELD("protocol", ZONE_INT8, 0), + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), + FIELD("publickey", ZONE_BLOB, ZONE_BASE64) +}; + +static const zone_field_info_t dhcid_rdata_fields[] = { + FIELD("dhcpinfo", ZONE_BLOB, ZONE_BASE64) +}; + +static const zone_symbol_t nsec3_algorithm_symbols[] = { + SYMBOL("SHA-1", 1) +}; + +static const zone_symbol_t nsec3_flags_symbols[] = { + SYMBOL("OPTOUT", 1) +}; + +static const zone_field_info_t nsec3_rdata_fields[] = { + FIELD("algorithm", ZONE_INT8, 0), + FIELD("flags", ZONE_INT8, 0), + FIELD("iterations", ZONE_INT16, 0), + FIELD("salt", ZONE_STRING | ZONE_BASE16), + FIELD("next", ZONE_STRING | ZONE_BASE32), + FIELD("types", ZONE_NSEC, 0) +}; + +static const zone_field_info_t nsec3param_rdata_fields[] = { + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(nsec3_algorithm_symbols)), + FIELD("flags", ZONE_INT8, 0, SYMBOLS(nsec3_flags_symbols)), + FIELD("iterations", ZONE_INT16, 0), + FIELD("salt", ZONE_STRING, ZONE_BASE16) +}; + +static const zone_field_info_t cds_rdata_fields[] = { + FIELD("keytag", ZONE_INT16, 0), + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(ds_algorithm_symbols)), + FIELD("digtype", ZONE_INT8, 0, SYMBOLS(ds_digest_type_symbols)), + FIELD("digest", ZONE_BLOB, ZONE_BASE16) +}; + +static const zone_field_info_t cdnskey_rdata_fields[] = { + FIELD("flags", ZONE_INT16, 0), + FIELD("protocol", ZONE_INT8, 0), + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), + FIELD("publickey", ZONE_BLOB, ZONE_BASE64) +}; + +static const zone_field_info_t spf_rdata_fields[] = { + FIELD("text", ZONE_STRING, ZONE_SEQUENCE) +}; + +// RFC6742 specifies the syntax for the locator is compatible with the syntax +// for IPv4 addresses, but then proceeds to provide an example with leading +// zeroes. The example is corrected in the errata. +static const zone_field_info_t l32_rdata_fields[] = { + FIELD("preference", ZONE_INT16, 0), + FIELD("locator", ZONE_IP4, 0) +}; + +static const zone_field_info_t l64_rdata_fields[] = { + FIELD("preference", ZONE_INT16, 0), + FIELD("locator", ZONE_ILNP64, 0) +}; + +static const zone_field_info_t lp_rdata_fields[] = { + FIELD("preference", ZONE_INT16, 0), + FIELD("pointer", ZONE_NAME, 0) +}; + +static const zone_field_info_t uri_rdata_fields[] = { + FIELD("priority", ZONE_INT16, 0), + FIELD("weight", ZONE_INT16, 0), + FIELD("target", ZONE_BLOB, 0) +}; + +static const zone_field_info_t caa_rdata_fields[] = { + FIELD("flags", ZONE_INT8, 0), + FIELD("tag", ZONE_STRING, ZONE_CAA_TAG), + FIELD("value", ZONE_BLOB, 0) +}; + +// https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template +static const zone_field_info_t avc_rdata_fields[] = { + FIELD("text", ZONE_STRING, ZONE_SEQUENCE) +}; + +static const zone_field_info_t dlv_rdata_fields[] = { + FIELD("key", ZONE_INT16, 0), + FIELD("algorithm", ZONE_INT8, 0, SYMBOLS(dnssec_algorithm_symbols)), + FIELD("type", ZONE_INT8, 0), + FIELD("digest", ZONE_BLOB, ZONE_BASE16) +}; + +static const type_descriptor_t types[] = { + UNKNOWN_TYPE(0), + + TYPE("A", ZONE_A, ZONE_ANY, FIELDS(a_rdata_fields), + zone_check_a_rdata, parse_a_rdata), + TYPE("NS", ZONE_NS, ZONE_ANY, FIELDS(ns_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("MD", ZONE_MD, ZONE_ANY | ZONE_OBSOLETE, FIELDS(md_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("MF", ZONE_MF, ZONE_ANY | ZONE_OBSOLETE, FIELDS(mf_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("CNAME", ZONE_CNAME, ZONE_ANY, FIELDS(cname_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("SOA", ZONE_SOA, ZONE_ANY, FIELDS(soa_rdata_fields), + zone_check_soa_rdata, parse_soa_rdata), + TYPE("MB", ZONE_MB, ZONE_ANY | ZONE_EXPERIMENTAL, FIELDS(mb_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("MG", ZONE_MG, ZONE_ANY | ZONE_EXPERIMENTAL, FIELDS(mg_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("MR", ZONE_MR, ZONE_ANY | ZONE_EXPERIMENTAL, FIELDS(mr_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + + UNKNOWN_TYPE(10), + + TYPE("WKS", ZONE_WKS, ZONE_IN, FIELDS(wks_rdata_fields), 0, 0), + TYPE("PTR", ZONE_PTR, ZONE_ANY, FIELDS(ptr_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + TYPE("HINFO", ZONE_HINFO, ZONE_ANY, FIELDS(hinfo_rdata_fields), + zone_check_hinfo_rdata, parse_hinfo_rdata), + TYPE("MINFO", ZONE_MINFO, ZONE_ANY, FIELDS(minfo_rdata_fields), + zone_check_minfo_rdata, parse_minfo_rdata), + TYPE("MX", ZONE_MX, ZONE_ANY, FIELDS(mx_rdata_fields), + zone_check_mx_rdata, parse_mx_rdata), + TYPE("TXT", ZONE_TXT, ZONE_ANY, FIELDS(txt_rdata_fields), + zone_check_txt_rdata, parse_txt_rdata), + TYPE("RP", ZONE_RP, ZONE_ANY, FIELDS(rp_rdata_fields), + zone_check_minfo_rdata, parse_minfo_rdata), + TYPE("AFSDB", ZONE_AFSDB, ZONE_ANY, FIELDS(afsdb_rdata_fields), + zone_check_mx_rdata, parse_mx_rdata), + TYPE("X25", ZONE_X25, ZONE_ANY, FIELDS(x25_rdata_fields), + zone_check_x25_rdata, parse_x25_rdata), + TYPE("ISDN", ZONE_ISDN, ZONE_ANY, FIELDS(isdn_rdata_fields), + zone_check_isdn_rdata, parse_isdn_rdata), + TYPE("RT", ZONE_RT, ZONE_ANY, FIELDS(rt_rdata_fields), + zone_check_rt_rdata, parse_rt_rdata), + + UNKNOWN_TYPE(22), + UNKNOWN_TYPE(23), + UNKNOWN_TYPE(24), + + TYPE("KEY", ZONE_KEY, ZONE_ANY, FIELDS(key_rdata_fields), + zone_check_key_rdata, parse_key_rdata), + + UNKNOWN_TYPE(26), + UNKNOWN_TYPE(27), + + TYPE("AAAA", ZONE_AAAA, ZONE_IN, FIELDS(aaaa_rdata_fields), + zone_check_aaaa_rdata, parse_aaaa_rdata), + + UNKNOWN_TYPE(29), + UNKNOWN_TYPE(30), + UNKNOWN_TYPE(31), + UNKNOWN_TYPE(32), + + TYPE("SRV", ZONE_SRV, ZONE_IN, FIELDS(srv_rdata_fields), + zone_check_srv_rdata, parse_srv_rdata), + + UNKNOWN_TYPE(34), + + TYPE("NAPTR", ZONE_NAPTR, ZONE_IN, FIELDS(naptr_rdata_fields), + zone_check_naptr_rdata, parse_naptr_rdata), + TYPE("KX", ZONE_KX, ZONE_IN, FIELDS(kx_rdata_fields), + zone_check_mx_rdata, parse_mx_rdata), + + UNKNOWN_TYPE(37), + UNKNOWN_TYPE(38), + + TYPE("DNAME", ZONE_DNAME, ZONE_ANY, FIELDS(dname_rdata_fields), + zone_check_ns_rdata, parse_ns_rdata), + + UNKNOWN_TYPE(40), + UNKNOWN_TYPE(41), + UNKNOWN_TYPE(42), + + TYPE("DS", ZONE_DS, ZONE_ANY, FIELDS(ds_rdata_fields), + zone_check_ds_rdata, parse_ds_rdata), + TYPE("SSHFP", ZONE_SSHFP, ZONE_ANY, FIELDS(sshfp_rdata_fields), + zone_check_sshfp_rdata, parse_sshfp_rdata), + + UNKNOWN_TYPE(45), // IPSECKEY + + TYPE("RRSIG", ZONE_RRSIG, ZONE_ANY, FIELDS(rrsig_rdata_fields), + zone_check_rrsig_rdata, parse_rrsig_rdata), + TYPE("NSEC", ZONE_NSEC, ZONE_ANY, FIELDS(nsec_rdata_fields), + zone_check_nsec_rdata, parse_nsec_rdata), + TYPE("DNSKEY", ZONE_DNSKEY, ZONE_ANY, FIELDS(dnskey_rdata_fields), + zone_check_dnskey_rdata, parse_dnskey_rdata), + TYPE("DHCID", ZONE_DHCID, ZONE_IN, FIELDS(dhcid_rdata_fields), + zone_check_dhcid_rdata, parse_dhcid_rdata), + TYPE("NSEC3", ZONE_NSEC3, ZONE_ANY, FIELDS(nsec3_rdata_fields), + zone_check_nsec3_rdata, parse_nsec3_rdata), + TYPE("NSEC3PARAM", ZONE_NSEC3PARAM, ZONE_ANY, FIELDS(nsec3param_rdata_fields), + zone_check_nsec3param_rdata, parse_nsec3param_rdata), + + UNKNOWN_TYPE(52), // TLSA + UNKNOWN_TYPE(53), // SMIMEA + UNKNOWN_TYPE(54), + UNKNOWN_TYPE(55), // HIP + UNKNOWN_TYPE(56), + UNKNOWN_TYPE(57), + UNKNOWN_TYPE(58), + + TYPE("CDS", ZONE_CDS, ZONE_ANY, FIELDS(cds_rdata_fields), + zone_check_ds_rdata, parse_ds_rdata), + TYPE("CDNSKEY", ZONE_CDNSKEY, ZONE_ANY, FIELDS(cdnskey_rdata_fields), + zone_check_dnskey_rdata, parse_dnskey_rdata), + + UNKNOWN_TYPE(61), + UNKNOWN_TYPE(62), + UNKNOWN_TYPE(63), + UNKNOWN_TYPE(64), + UNKNOWN_TYPE(65), + UNKNOWN_TYPE(66), + UNKNOWN_TYPE(67), + UNKNOWN_TYPE(68), + UNKNOWN_TYPE(69), + UNKNOWN_TYPE(70), + UNKNOWN_TYPE(71), + UNKNOWN_TYPE(72), + UNKNOWN_TYPE(73), + UNKNOWN_TYPE(74), + UNKNOWN_TYPE(75), + UNKNOWN_TYPE(76), + UNKNOWN_TYPE(77), + UNKNOWN_TYPE(78), + UNKNOWN_TYPE(79), + UNKNOWN_TYPE(80), + UNKNOWN_TYPE(81), + UNKNOWN_TYPE(82), + UNKNOWN_TYPE(83), + UNKNOWN_TYPE(84), + UNKNOWN_TYPE(85), + UNKNOWN_TYPE(86), + UNKNOWN_TYPE(87), + UNKNOWN_TYPE(88), + UNKNOWN_TYPE(89), + UNKNOWN_TYPE(90), + UNKNOWN_TYPE(91), + UNKNOWN_TYPE(92), + UNKNOWN_TYPE(93), + UNKNOWN_TYPE(94), + UNKNOWN_TYPE(95), + UNKNOWN_TYPE(96), + UNKNOWN_TYPE(97), + UNKNOWN_TYPE(98), + + TYPE("SPF", ZONE_SPF, ZONE_ANY | ZONE_OBSOLETE, FIELDS(spf_rdata_fields), + zone_check_txt_rdata, parse_txt_rdata), + + UNKNOWN_TYPE(100), + UNKNOWN_TYPE(101), + UNKNOWN_TYPE(102), + UNKNOWN_TYPE(103), + UNKNOWN_TYPE(104), + + TYPE("L32", ZONE_L32, ZONE_ANY, FIELDS(l32_rdata_fields), + zone_check_l32_rdata, parse_l32_rdata), + TYPE("L64", ZONE_L64, ZONE_ANY, FIELDS(l64_rdata_fields), + zone_check_l64_rdata, parse_l64_rdata), + TYPE("LP", ZONE_LP, ZONE_ANY, FIELDS(lp_rdata_fields), + zone_check_mx_rdata, parse_mx_rdata), + + UNKNOWN_TYPE(108), + UNKNOWN_TYPE(109), + UNKNOWN_TYPE(110), + UNKNOWN_TYPE(111), + UNKNOWN_TYPE(112), + UNKNOWN_TYPE(113), + UNKNOWN_TYPE(114), + UNKNOWN_TYPE(115), + UNKNOWN_TYPE(116), + UNKNOWN_TYPE(117), + UNKNOWN_TYPE(118), + UNKNOWN_TYPE(119), + UNKNOWN_TYPE(120), + UNKNOWN_TYPE(121), + UNKNOWN_TYPE(122), + UNKNOWN_TYPE(123), + UNKNOWN_TYPE(124), + UNKNOWN_TYPE(125), + UNKNOWN_TYPE(126), + UNKNOWN_TYPE(127), + UNKNOWN_TYPE(128), + UNKNOWN_TYPE(129), + UNKNOWN_TYPE(130), + UNKNOWN_TYPE(131), + UNKNOWN_TYPE(132), + UNKNOWN_TYPE(133), + UNKNOWN_TYPE(134), + UNKNOWN_TYPE(135), + UNKNOWN_TYPE(136), + UNKNOWN_TYPE(137), + UNKNOWN_TYPE(138), + UNKNOWN_TYPE(139), + UNKNOWN_TYPE(140), + UNKNOWN_TYPE(141), + UNKNOWN_TYPE(142), + UNKNOWN_TYPE(143), + UNKNOWN_TYPE(144), + UNKNOWN_TYPE(145), + UNKNOWN_TYPE(146), + UNKNOWN_TYPE(147), + UNKNOWN_TYPE(148), + UNKNOWN_TYPE(149), + UNKNOWN_TYPE(150), + UNKNOWN_TYPE(151), + UNKNOWN_TYPE(152), + UNKNOWN_TYPE(153), + UNKNOWN_TYPE(154), + UNKNOWN_TYPE(155), + UNKNOWN_TYPE(156), + UNKNOWN_TYPE(157), + UNKNOWN_TYPE(158), + UNKNOWN_TYPE(159), + UNKNOWN_TYPE(160), + UNKNOWN_TYPE(161), + UNKNOWN_TYPE(162), + UNKNOWN_TYPE(163), + UNKNOWN_TYPE(164), + UNKNOWN_TYPE(165), + UNKNOWN_TYPE(166), + UNKNOWN_TYPE(167), + UNKNOWN_TYPE(168), + UNKNOWN_TYPE(169), + UNKNOWN_TYPE(170), + UNKNOWN_TYPE(171), + UNKNOWN_TYPE(172), + UNKNOWN_TYPE(173), + UNKNOWN_TYPE(174), + UNKNOWN_TYPE(175), + UNKNOWN_TYPE(176), + UNKNOWN_TYPE(177), + UNKNOWN_TYPE(178), + UNKNOWN_TYPE(179), + UNKNOWN_TYPE(180), + UNKNOWN_TYPE(181), + UNKNOWN_TYPE(182), + UNKNOWN_TYPE(183), + UNKNOWN_TYPE(184), + UNKNOWN_TYPE(185), + UNKNOWN_TYPE(186), + UNKNOWN_TYPE(187), + UNKNOWN_TYPE(188), + UNKNOWN_TYPE(189), + UNKNOWN_TYPE(190), + UNKNOWN_TYPE(191), + UNKNOWN_TYPE(192), + UNKNOWN_TYPE(193), + UNKNOWN_TYPE(194), + UNKNOWN_TYPE(195), + UNKNOWN_TYPE(196), + UNKNOWN_TYPE(197), + UNKNOWN_TYPE(198), + UNKNOWN_TYPE(199), + UNKNOWN_TYPE(200), + UNKNOWN_TYPE(201), + UNKNOWN_TYPE(202), + UNKNOWN_TYPE(203), + UNKNOWN_TYPE(204), + UNKNOWN_TYPE(205), + UNKNOWN_TYPE(206), + UNKNOWN_TYPE(207), + UNKNOWN_TYPE(208), + UNKNOWN_TYPE(209), + UNKNOWN_TYPE(210), + UNKNOWN_TYPE(211), + UNKNOWN_TYPE(212), + UNKNOWN_TYPE(213), + UNKNOWN_TYPE(214), + UNKNOWN_TYPE(215), + UNKNOWN_TYPE(216), + UNKNOWN_TYPE(217), + UNKNOWN_TYPE(218), + UNKNOWN_TYPE(219), + UNKNOWN_TYPE(220), + UNKNOWN_TYPE(221), + UNKNOWN_TYPE(222), + UNKNOWN_TYPE(223), + UNKNOWN_TYPE(224), + UNKNOWN_TYPE(225), + UNKNOWN_TYPE(226), + UNKNOWN_TYPE(227), + UNKNOWN_TYPE(228), + UNKNOWN_TYPE(229), + UNKNOWN_TYPE(230), + UNKNOWN_TYPE(231), + UNKNOWN_TYPE(232), + UNKNOWN_TYPE(233), + UNKNOWN_TYPE(234), + UNKNOWN_TYPE(235), + UNKNOWN_TYPE(236), + UNKNOWN_TYPE(237), + UNKNOWN_TYPE(238), + UNKNOWN_TYPE(239), + UNKNOWN_TYPE(240), + UNKNOWN_TYPE(241), + UNKNOWN_TYPE(242), + UNKNOWN_TYPE(243), + UNKNOWN_TYPE(244), + UNKNOWN_TYPE(245), + UNKNOWN_TYPE(246), + UNKNOWN_TYPE(247), + UNKNOWN_TYPE(248), + UNKNOWN_TYPE(249), + UNKNOWN_TYPE(250), + UNKNOWN_TYPE(251), + UNKNOWN_TYPE(252), + UNKNOWN_TYPE(253), + UNKNOWN_TYPE(254), + UNKNOWN_TYPE(255), + + TYPE("URI", ZONE_URI, ZONE_ANY, FIELDS(uri_rdata_fields), + zone_check_uri_rdata, parse_uri_rdata), + TYPE("CAA", ZONE_CAA, ZONE_ANY, FIELDS(caa_rdata_fields), + zone_check_caa_rdata, parse_caa_rdata), + TYPE("AVC", ZONE_AVC, ZONE_ANY, FIELDS(avc_rdata_fields), + zone_check_txt_rdata, parse_txt_rdata), + TYPE("DLV", ZONE_DLV, ZONE_ANY | ZONE_OBSOLETE, FIELDS(dlv_rdata_fields), + zone_check_ds_rdata, parse_ds_rdata) +}; + +#undef UNKNOWN_CLASS +#undef CLASS +#undef UNKNOWN_TYPE +#undef TYPE + +diagnostic_pop() + +#endif // TYPES_H diff --git a/src/visit.h b/src/visit.h index cbd4c8a..69ce1df 100644 --- a/src/visit.h +++ b/src/visit.h @@ -11,7 +11,7 @@ static zone_really_inline int32_t accept_rr(zone_parser_t *parser) { - zone_return_t result; + int32_t result; assert(parser->owner->length <= UINT8_MAX); assert(parser->rdata->length <= UINT16_MAX); diff --git a/src/westmere/ip4.h b/src/westmere/ip4.h index 96b868d..c0f213d 100644 --- a/src/westmere/ip4.h +++ b/src/westmere/ip4.h @@ -11,24 +11,24 @@ #define IP4_H static const uint8_t patterns_id[256] = { - 38, 65, 255, 56, 73, 255, 255, 255, 255, 255, 255, 3, 255, 255, 6, - 255, 255, 9, 255, 27, 255, 12, 30, 255, 255, 255, 255, 15, 255, 33, - 255, 255, 255, 255, 18, 36, 255, 255, 255, 54, 21, 255, 39, 255, 255, - 57, 255, 255, 255, 255, 255, 255, 255, 255, 24, 42, 255, 255, 255, 60, - 255, 255, 255, 255, 255, 255, 255, 255, 45, 255, 255, 63, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 48, 53, 255, 255, 66, 71, 255, 255, 16, - 255, 34, 255, 255, 255, 255, 255, 255, 255, 52, 255, 255, 22, 70, 40, - 255, 255, 58, 51, 255, 255, 69, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 5, 255, 255, 255, 255, 255, 255, 11, 29, 46, 255, 255, 64, 255, - 255, 72, 0, 77, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 76, 255, 255, 255, 255, 255, 255, 255, 75, 255, - 80, 255, 255, 255, 26, 255, 44, 255, 7, 62, 255, 255, 25, 255, 43, - 13, 31, 61, 255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 19, 37, - 255, 255, 50, 55, 79, 68, 255, 255, 255, 255, 49, 255, 255, 67, 255, - 255, 255, 255, 17, 255, 35, 78, 255, 4, 255, 255, 255, 255, 255, 255, - 10, 23, 28, 41, 255, 255, 59, 255, 255, 255, 8, 255, 255, 255, 255, - 255, 1, 14, 32, 255, 255, 255, 255, 255, 255, 255, 255, 74, 255, 47, - 20, + 38, 65, 255, 56, 73, 255, 255, 255, 255, 255, 255, 3, 255, 255, 6, + 255, 255, 9, 255, 27, 255, 12, 30, 255, 255, 255, 255, 15, 255, 33, + 255, 255, 255, 255, 18, 36, 255, 255, 255, 54, 21, 255, 39, 255, 255, + 57, 255, 255, 255, 255, 255, 255, 255, 255, 24, 42, 255, 255, 255, 60, + 255, 255, 255, 255, 255, 255, 255, 255, 45, 255, 255, 63, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 48, 53, 255, 255, 66, 71, 255, 255, 16, + 255, 34, 255, 255, 255, 255, 255, 255, 255, 52, 255, 255, 22, 70, 40, + 255, 255, 58, 51, 255, 255, 69, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 5, 255, 255, 255, 255, 255, 255, 11, 29, 46, 255, 255, 64, 255, + 255, 72, 0, 77, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 76, 255, 255, 255, 255, 255, 255, 255, 75, 255, + 80, 255, 255, 255, 26, 255, 44, 255, 7, 62, 255, 255, 25, 255, 43, + 13, 31, 61, 255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 19, 37, + 255, 255, 50, 55, 79, 68, 255, 255, 255, 255, 49, 255, 255, 67, 255, + 255, 255, 255, 17, 255, 35, 78, 255, 4, 255, 255, 255, 255, 255, 255, + 10, 23, 28, 41, 255, 255, 59, 255, 255, 255, 8, 255, 255, 255, 255, + 255, 1, 14, 32, 255, 255, 255, 255, 255, 255, 255, 255, 74, 255, 47, + 20, }; static const uint8_t patterns[81][16] = { @@ -197,7 +197,7 @@ static zone_really_inline int32_t parse_ip4( // Note that this assumes that reading up to token->data + 16 is safe (i.e., we do not cross a page). if (sse_inet_aton(token->data, o, &n) != 1 || is_contiguous((uint8_t)token->data[n])) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); parser->rdata->length += sizeof(struct in_addr); return ZONE_IP4; } diff --git a/src/westmere/name.h b/src/westmere/name.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/westmere/parser.c b/src/westmere/parser.c index 02a4209..218e7c0 100644 --- a/src/westmere/parser.c +++ b/src/westmere/parser.c @@ -20,7 +20,6 @@ #include "generic/ttl.h" #include "westmere/time.h" #include "generic/name.h" -#include "generic/type.h" #include "westmere/ip4.h" #include "generic/ip6.h" #include "generic/text.h" @@ -31,6 +30,8 @@ #include "generic/caa.h" #include "generic/ilnp64.h" #include "visit.h" +#include "types.h" +#include "westmere/type.h" #include "parser.h" diagnostic_push() diff --git a/src/westmere/string.h b/src/westmere/string.h index 7b3ac6a..2001113 100644 --- a/src/westmere/string.h +++ b/src/westmere/string.h @@ -31,6 +31,7 @@ static zone_really_inline void copy_contiguous_string_block( _mm_storeu_si128((__m128i *)(wire), i0); _mm_storeu_si128((__m128i *)(wire+16), i1); + // FIXME: this is and error! const __m128i ds00 = _mm_shuffle_epi8(d0, _mm_srli_epi16(i0, 4)); const __m128i ds01 = _mm_shuffle_epi8(d1, i0); const __m128i ds0 = _mm_and_si128(ds00, ds01); diff --git a/src/westmere/time.h b/src/westmere/time.h index 2618efa..89d9058 100644 --- a/src/westmere/time.h +++ b/src/westmere/time.h @@ -130,11 +130,11 @@ static zone_really_inline int32_t parse_time( const char *p = token->data; uint32_t sse_result; if (!sse_parse_time(p, &sse_result)) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); // FIXME: once support for specifying as an unsigned number of seconds is // implemented, update this check too if (contiguous[(uint8_t)token->data[14]] == CONTIGUOUS) - SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); uint32_t time = htonl(sse_result); memcpy(&parser->rdata->octets[parser->rdata->length], &time, sizeof(time)); diff --git a/src/westmere/type.h b/src/westmere/type.h new file mode 100644 index 0000000..d65cf6f --- /dev/null +++ b/src/westmere/type.h @@ -0,0 +1,268 @@ +/* + * type.h -- SSE4.1 RRTYPE parser + * + * Copyright (c) 2023, NLnet Labs. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef TYPE_H +#define TYPE_H + +#define T(code) { &(types[code].info.name), ZONE_TYPE } +#define C(code) { &(classes[code].name), ZONE_CLASS } + +// map hash to type or class descriptor (generated using hash.c) +static const struct { + const zone_symbol_t *symbol; + int32_t type; +} types_and_classes[256] = { + T(0), T(0), T(0), T(0), T(0), T(44), T(0), T(3), + T(0), T(0), T(0), T(0), T(11), T(0), T(42), T(0), + T(0), T(0), T(0), T(0), T(0), T(62), T(0), T(0), + T(0), T(99), T(25), T(0), T(53), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(50), T(0), T(0), T(0), + T(0), T(39), T(0), T(21), T(0), T(5), T(0), T(0), + T(0), T(0), T(0), T(0), T(0), T(1), T(0), T(0), + C(1), T(0), T(105), T(49), T(0), T(59), T(0), T(29), + T(0), T(20), T(0), T(6), T(0), T(0), T(0), C(3), + T(0), T(63), T(0), T(0), T(0), C(2), T(43), T(37), + T(0), C(4), T(0), T(0), T(45), T(104), T(2), T(0), + T(23), T(55), T(0), T(24), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(7), T(0), T(0), T(0), T(12), + T(0), T(0), T(60), T(0), T(0), T(36), T(10), T(15), + T(0), T(26), T(0), T(0), T(19), T(0), T(0), T(0), + T(0), T(0), T(0), T(65), T(0), T(8), T(0), T(108), + T(0), T(38), T(0), T(9), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(46), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(0), T(0), T(27), T(48), + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), + T(0), T(0), T(28), T(4), T(51), T(0), T(0), T(30), + T(0), T(106), T(0), T(0), T(16), T(64), T(0), T(0), + T(0), T(0), T(257), T(0), T(0), T(0), T(0), T(0), + T(256), T(0), T(0), T(0), T(0), T(22), T(0), T(0), + T(0), T(33), T(0), T(61), T(0), T(52), T(0), T(0), + T(259), T(0), T(0), T(0), T(14), T(0), T(0), T(0), + T(13), T(0), T(0), T(0), T(0), T(0), T(107), T(0), + T(0), T(18), T(0), T(17), T(0), T(0), T(35), T(0), + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(258), T(0), T(0), T(109), + T(0), T(0), T(0), T(0), T(0), T(0), T(47), T(0) +}; + +#undef T +#undef C + +static int8_t zero_masks[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static zone_really_inline uint8_t hash(uint64_t prefix) +{ + uint32_t value = (uint32_t)((prefix >> 32) ^ prefix); + // magic value is generated using hash.c, rerun when adding types + return (uint8_t)((value * 3523264710ull) >> 32); +} + +zone_nonnull_all +static zone_really_inline int32_t find_type_or_class( + zone_parser_t *parser, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + (void)parser; + + __m128i input = _mm_loadu_si128((const __m128i *)token->data); + + // RRTYPEs consist of [0-9a-zA-Z-] (unofficially, no other values are in use) + // 0x2d : hyphen : 0b0010_1101 + // 0x30 - 0x39 : 0 - 9 : 0b0011_0000 - 0b0011_1001 + // 0x41 - 0x4f : A - O : 0b0100_0001 - 0b0100_1111 + // 0x50 - 0x5a : P - Z : 0b0101_0000 - 0b0101_1010 + // 0x61 - 0x6f : a - o : 0b0110_0001 - 0b0110_1111 + // 0x70 - 0x7a : p - z : 0b0111_0000 - 0b0111_1010 + // + // delimiters for strings consisting of a contiguous set of characters + // 0x00 : end-of-file : 0b0000_0000 + // 0x20 : space : 0b0010_0000 + // 0x22 : quote : 0b0010_0010 + // 0x28 : left parenthesis : 0b0010_1000 + // 0x29 : right parenthesis : 0b0010_1001 + // 0x09 : tab : 0b0000_1001 + // 0x0a : line feed : 0b0000_1010 + // 0x3b : semicolon : 0b0011_1011 + // 0x0d : carriage return : 0b0000_1101 + // + // deltas do not catch ('.' (0x2e) or '/' (0x2f)), but neither is a delimiter + const __m128i deltas = _mm_setr_epi8( + -16, -32, -45, 70, -65, 37, -97, 5, 0, 0, 0, 0, 0, 0, 0, 0); + const __m128i nibbles = _mm_and_si128(_mm_srli_epi32(input, 4), _mm_set1_epi8(0x0f)); + const __m128i check = _mm_add_epi8(_mm_shuffle_epi8(deltas, nibbles), input); + + int mask = (uint16_t)_mm_movemask_epi8(check); + uint16_t length = (uint16_t)__builtin_ctz((unsigned int)mask); + + const __m128i upper = _mm_setr_epi8( + -1, -1, -1, -1, -1, -1, -33, -33, -1, -1, -1, -1, -1, -1, -1, -1); + + const __m128i zero_mask = _mm_loadu_si128((const __m128i *)(zero_masks + 16 - length)); + input = _mm_and_si128(input, _mm_shuffle_epi8(upper, nibbles)); + input = _mm_andnot_si128(zero_mask, input); + + // input is now sanitized and upper case + + const uint8_t index = hash((uint64_t)_mm_cvtsi128_si64(input)); + *symbol = types_and_classes[index].symbol; + + const __m128i compar = _mm_loadu_si128((const __m128i *)(*symbol)->key.data); + const __m128i xorthem = _mm_xor_si128(compar, input); + + *code = (uint16_t)(*symbol)->value; + + const uint8_t delimiter = (uint8_t)token->data[length]; + if (_mm_test_all_zeros(xorthem, xorthem) & (contiguous[delimiter] != CONTIGUOUS)) + return types_and_classes[index].type; + return 0; +} + +zone_nonnull_all +static zone_really_inline int32_t scan_generic_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + const char *ps = token->data + 4, *p = ps; + uint64_t n = 0; + for (;; p++) { + const uint64_t d = (uint8_t)*p - '0'; + if (d > 9) + break; + n = n * 10 + d; + } + + if (!n || n > 65535 || p - ps > 5 || is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + + *code = (uint16_t)n; + if (*code <= 258) + *symbol = &types[*code].info.name; + else if (*code == ZONE_DLV) + *symbol = &types[259].info.name; + else + *symbol = &types[0].info.name; + return ZONE_TYPE; +} + +zone_nonnull_all +static zone_really_inline int32_t scan_generic_class( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + const char *ps = token->data + 5, *p = ps; + uint64_t n = 0; + for (;; p++) { + const uint64_t d = (uint8_t)*p - '0'; + if (d > 9) + break; + n = n * 10 + d; + } + + if (!n || n > 65535 || p - ps >= 5 || is_contiguous((uint8_t)*p)) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + + *code = (uint16_t)n; + if (*code <= 4) + *symbol = &classes[*code].name; + else + *symbol = &classes[0].name; + return ZONE_CLASS; +} + +#define TYPE (0x5459504500000000llu) +#define CLASS (0x434c415353000000llu) + +zone_nonnull_all +static zone_really_inline int32_t scan_type_or_class( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + int32_t r; + + if ((r = have_contiguous(parser, type, field, token)) < 0) + return r; + if ((r = find_type_or_class(parser, token, code, symbol))) + return r; + + uint64_t k; + memcpy(&k, token->data, 8); + if ((k & 0xdfdfdfdf00000000llu) == TYPE) + return scan_generic_type(parser, type, field, token, code, symbol); + else if ((k & 0xdfdfdfdfdf000000llu) == CLASS) + return scan_generic_class(parser, type, field, token, code, symbol); + + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); +} + +zone_nonnull_all +static zone_really_inline int32_t scan_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token, + uint16_t *code, + const zone_symbol_t **symbol) +{ + int32_t r; + + if ((r = have_contiguous(parser, type, field, token)) < 0) + return r; + if ((r = find_type_or_class(parser, token, code, symbol)) == ZONE_TYPE) + return r; + + uint64_t k; + memcpy(&k, token->data, 8); + if ((k & 0xdfdfdfdf00000000) == TYPE) + return scan_generic_type(parser, type, field, token, code, symbol); + + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); +} + +#undef TYPE +#undef CLASS + +zone_nonnull_all +static zone_really_inline int32_t parse_type( + zone_parser_t *parser, + const zone_type_info_t *type, + const zone_field_info_t *field, + const token_t *token) +{ + int32_t r; + uint16_t c; + const zone_symbol_t *s; + + if ((r = scan_type(parser, type, field, token, &c, &s)) != ZONE_TYPE) + SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), TNAME(type)); + c = htons(c); + memcpy(&parser->rdata->octets[parser->rdata->length], &c, sizeof(c)); + parser->rdata->length += sizeof(c); + return ZONE_TYPE; +} + +#endif // TYPE_H diff --git a/src/zone.c b/src/zone.c index a03a800..2613109 100644 --- a/src/zone.c +++ b/src/zone.c @@ -106,7 +106,7 @@ extern int32_t zone_haswell_parse(zone_parser_t *, void *); extern int32_t zone_westmere_parse(zone_parser_t *, void *); #endif -extern zone_return_t zone_fallback_parse(zone_parser_t *, void *); +extern int32_t zone_fallback_parse(zone_parser_t *, void *); typedef struct target target_t; struct target { diff --git a/tests/include.c b/tests/include.c index 9249c22..809d303 100644 --- a/tests/include.c +++ b/tests/include.c @@ -125,7 +125,7 @@ int setup(void **state) diagnostic_pop() -static zone_return_t add_rr( +static int32_t add_rr( zone_parser_t *parser, const zone_name_t *owner, uint16_t type, @@ -159,7 +159,7 @@ void include_from_string(void **state) zone_rdata_block_t rdata; zone_cache_t cache = { 1, &name, &rdata }; zone_options_t options = { 0 }; - zone_return_t result; + int32_t result; options.accept.add = &add_rr; options.origin = "example.com."; diff --git a/tests/ip4.c b/tests/ip4.c index 92352e3..efd29df 100644 --- a/tests/ip4.c +++ b/tests/ip4.c @@ -13,7 +13,7 @@ #include "zone.h" -static zone_return_t add_rr( +static int32_t add_rr( zone_parser_t *parser, const zone_name_t *owner, uint16_t type, diff --git a/tests/types.c b/tests/types.c index 6553803..3ad45db 100644 --- a/tests/types.c +++ b/tests/types.c @@ -506,7 +506,7 @@ static const test_t tests[] = { { ZONE_DLV, dlv_generic_text, &cds_rdata } }; -static zone_return_t add_rr( +static int32_t add_rr( zone_parser_t *parser, const zone_name_t *owner, uint16_t type, @@ -541,7 +541,7 @@ void supported_types(void **state) zone_rdata_block_t rdata; zone_cache_t cache = { 1, &name, &rdata }; zone_options_t options = { 0 }; - zone_return_t result; + int32_t result; options.accept.add = add_rr; options.origin = "example.com.";