Skip to content

Commit 241bc3b

Browse files
committed
Simplify parser interface and code
Exposing type and field information makes little sense. Applications are required to interpret wire representation for handling queries. Unknown types can simply be handled generically. Removing the information simplifies the interface and code. Fixes #98.
1 parent 91bb96e commit 241bc3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+7049
-6788
lines changed

.github/workflows/build-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,4 @@ jobs:
8787
set -e -x
8888
cd build
8989
ctest -j 4 --output-on-failure -T test -C ${BUILD_TYPE:-RelWithDebInfo}
90-
ZONE_TARGET=fallback ctest -j 4 --output-on-failure -T test -C ${BUILD_TYPE:-RelWithDebInfo}
90+
ZONE_KERNEL=fallback ctest -j 4 --output-on-failure -T test -C ${BUILD_TYPE:-RelWithDebInfo}

CMakeLists.txt

+3-4
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,7 @@ target_include_directories(
145145
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
146146

147147
target_sources(zone PRIVATE
148-
src/zone.c
149-
src/log.c
150-
src/fallback/parser.c)
148+
src/zone.c src/fallback/parser.c)
151149

152150
add_executable(zone-bench src/bench.c src/fallback/bench.c)
153151
target_include_directories(
@@ -227,7 +225,8 @@ foreach(match ${matches})
227225
endforeach()
228226

229227
file(GENERATE OUTPUT config.h CONTENT "${template}")
230-
configure_file(src/fallback/endian.h.in fallback/endian.h @ONLY)
228+
# FIXME: we'll need to port this over to autoconf as well
229+
configure_file(src/generic/endian.h.in generic/endian.h @ONLY)
231230

232231

233232
if(BUILD_TESTING)

include/zone.h

+30-200
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* zone.h -- (DNS) zone parser
2+
* zone.h -- (DNS) presentation format parser
33
*
44
* Copyright (c) 2022-2023, NLnet Labs. All rights reserved.
55
*
@@ -40,6 +40,8 @@ extern "C" {
4040
#define ZONE_CH (3u)
4141
/** Hesiod @rfc{1035} */
4242
#define ZONE_HS (4u)
43+
/** Any (QCLASS) @rfc{1035} */
44+
#define ZONE_ANY (255u)
4345
/** @} */
4446

4547
/**
@@ -133,11 +135,11 @@ extern "C" {
133135
#define ZONE_NSEC (47u)
134136
/** DNS Public Key @rfc{4034} @rfc{3755} */
135137
#define ZONE_DNSKEY (48u)
136-
/** DHCID [RFC4701] */
138+
/** DHCID @rfc{4701} */
137139
#define ZONE_DHCID (49u)
138-
/** NSEC3 [RFC5155] */
140+
/** NSEC3 @rfc{5155} */
139141
#define ZONE_NSEC3 (50u)
140-
/** NSEC3PARAM [RFC5155] */
142+
/** NSEC3PARAM @rfc{5155} */
141143
#define ZONE_NSEC3PARAM (51u)
142144
/** TLSA @rfc{6698} */
143145
#define ZONE_TLSA (52u)
@@ -183,156 +185,9 @@ extern "C" {
183185
#define ZONE_DLV (32769u)
184186
/** @} */
185187

186-
typedef struct zone_string zone_string_t;
187-
struct zone_string {
188-
size_t length;
189-
const char *data;
190-
};
191-
192-
// FIXME: probably best to rename this to mnemonic to stay with DNS terminology?
193-
typedef struct zone_symbol zone_symbol_t;
194-
struct zone_symbol {
195-
struct {
196-
char data[24]; // zero padded for convenient vectorized comparison
197-
size_t length;
198-
} key;
199-
uint32_t value;
200-
};
201-
202-
typedef struct zone_table zone_table_t;
203-
struct zone_table {
204-
size_t length;
205-
const zone_symbol_t *symbols; // sorted for use with bsearch
206-
};
207-
208-
/**
209-
* @brief Type of value defined by field
210-
*
211-
* Fields are defined by their binary representation, NOT their textual
212-
* representation. e.g. time-to-live and timestamp fields are encoded as
213-
* 32-bit integers on the wire. @ref type_qualifiers are used to complement
214-
* the type information. e.g. @ref ZONE_TTL and @ref ZONE_TIME can be used to
215-
* provide extra information regarding the aforementioned types.
216-
*/
217-
typedef enum {
218-
ZONE_INT8,
219-
ZONE_INT16,
220-
ZONE_INT32,
221-
ZONE_IP4,
222-
ZONE_IP6,
223-
ZONE_NAME,
224-
ZONE_STRING,
225-
// (B)inary (L)arge (Ob)ject. Inspired by relational database terminology.
226-
// Must be last.
227-
ZONE_BLOB,
228-
ZONE_ILNP64,
229-
// hex fields
230-
// ZONE_EUI48 (ZONE_HEX6?)
231-
// ZONE_EUI64 (ZONE_HEX8?)
232-
// miscellaneous fields
233-
ZONE_SVC_PARAM, /**< SVCB service parameter */
234-
ZONE_TYPE_BITMAP, /**< NSEC type bitmap */
235-
ZONE_SERVICE_BITMAP /**< WKS service bitmap */
236-
} zone_type_t;
237-
238-
/**
239-
* @defgroup type_qualifiers Type qualifiers
240-
*
241-
* Type qualifiers provide additional information for RDATA fields. Types
242-
* indicate the binary representation of an RDATA field, qualifier(s) can be
243-
* used to communicate semantics. e.g. a time-to-live is presented on the
244-
* wire as a 32-bit integer, ZONE_TTL can be used to signal the field
245-
* represents a time-to-live value.
246-
*
247-
* @note Some types allow for more than one qualifier to be specified, hence
248-
* each qualifier is assigned a separate bit.
249-
*
250-
* @{
251-
*/
252-
/**
253-
* @brief Type code (#ZONE_INT16)
254-
*
255-
* Type codes may appear in text by name or generic type notation @rfc{3597}.
256-
*/
257-
#define ZONE_TYPE (1u << 0)
258-
/**
259-
* @brief Class code (#ZONE_INT16)
260-
*
261-
* Class codes may appear in text by name or generic class notation @rfc{3597}.
262-
*/
263-
#define ZONE_CLASS (1u << 1)
264-
/**
265-
* @brief Time-to-live (TTL) (#ZONE_INT32)
266-
*
267-
* Time-to-live values may appear in text as numeric value (seconds) or in
268-
* "1h2m3s" notation (@e extension).
269-
*/
270-
#define ZONE_TTL (1u << 2)
271-
/**
272-
* @brief Timestamp (#ZONE_INT32)
273-
*
274-
* Timestamps must be presented in text in "YYYYMMDDHHmmSS" notation.
275-
*/
276-
#define ZONE_TIME (1u << 3)
277-
/** @brief Text representation is base16 (#ZONE_STRING or #ZONE_BLOB) */
278-
#define ZONE_BASE16 (1u << 4)
279-
/** @brief Text representation is base32 (#ZONE_BLOB) */
280-
#define ZONE_BASE32 (1u << 5)
281-
/** @brief Text representation is base64 (#ZONE_BLOB) */
282-
#define ZONE_BASE64 (1u << 6)
283-
/** @brief Name is compressed (#ZONE_NAME) */
284-
#define ZONE_COMPRESSED (1u << 7)
285-
/** @brief Name represents a mailbox (#ZONE_NAME) */
286-
#define ZONE_MAILBOX (1u << 8)
287-
/** @brief Name is converted to lower case for DNSSEC validation (#ZONE_NAME) */
288-
#define ZONE_LOWER_CASE (1u << 9)
289-
/** @brief Optional (#ZONE_NAME) */
290-
#define ZONE_OPTIONAL (1u << 10)
291-
/**
292-
* @brief May occur multiple times (#ZONE_STRING or #ZONE_SVC_PARAM)
293-
*
294-
* Field may occur multiple times. e.g. #ZONE_STRING in #ZONE_TXT or
295-
* #ZONE_SVC_PARAM in #ZONE_SVCB. Sequences must be the last field in the
296-
* record.
297-
*/
298-
#define ZONE_SEQUENCE (1u << 11)
299-
300-
#define ZONE_CAA_TAG (1u << 12)
301-
/** @} */
302-
303-
typedef struct zone_field_info zone_field_info_t;
304-
struct zone_field_info {
305-
zone_string_t name;
306-
uint32_t type;
307-
uint32_t qualifiers;
308-
zone_table_t symbols;
309-
};
310-
311-
/**
312-
* @defgroup options Type options
313-
* @brief Options for record types
314-
*
315-
* @{
316-
*/
317-
#define ZONE_ANY (1<<2)
318-
#define ZONE_EXPERIMENTAL (1<<3)
319-
#define ZONE_OBSOLETE (1<<4)
320-
/** @} */
321-
322-
typedef struct zone_type_info zone_type_info_t;
323-
struct zone_type_info {
324-
zone_symbol_t name;
325-
uint32_t options;
326-
struct {
327-
size_t length;
328-
const zone_field_info_t *fields;
329-
} rdata;
330-
};
331-
332188
#define ZONE_BLOCK_SIZE (64)
333189
#define ZONE_WINDOW_SIZE (256 * ZONE_BLOCK_SIZE) // 16KB
334190

335-
336191
// tape capacity must be large enough to hold every token from a single
337192
// worst-case read (e.g. 64 consecutive line feeds). in practice a single
338193
// block will never contain 64 tokens, therefore, to optimize throughput,
@@ -350,10 +205,10 @@ struct zone_name_buffer {
350205
uint8_t octets[ ZONE_NAME_SIZE + ZONE_PADDING_SIZE ];
351206
};
352207

208+
// FIXME: explain need for NSEC padding
353209
typedef struct zone_rdata_buffer zone_rdata_buffer_t;
354210
struct zone_rdata_buffer {
355-
size_t length; /**< Length of RDATA stored in buffer */
356-
uint8_t octets[ ZONE_RDATA_SIZE + 4096 /* nsec padding */ ];
211+
uint8_t octets[ ZONE_RDATA_SIZE + 4096 /* NSEC padding */ ];
357212
};
358213

359214
// @private
@@ -425,65 +280,42 @@ struct zone_parser;
425280

426281
typedef void(*zone_log_t)(
427282
zone_parser_t *,
428-
const char *, // file
429-
size_t, // line
430-
const char *, // function
431283
uint32_t, // category
432284
const char *, // message
433285
void *); // user data
434286

435287
/**
436288
* @brief Write error message to active log handler.
437289
*
438-
* @note Direct use is discouraged. Use of #ZONE_LOG instead.
290+
* The zone parser operates on a per-record base and therefore cannot detect
291+
* errors that span records. e.g. SOA records being specified more than once.
292+
* The user may print a message using the active log handler, keeping the
293+
* error message format consistent.
439294
*
440295
* @param[in] parser Zone parser
441-
* @param[in] file Name of source file
442-
* @param[in] line Line number in source file
443-
* @param[in] function Name of function
444296
* @param[in] category Log category
445297
* @param[in] format Format string compatible with printf
446298
* @param[in] ... Variadic arguments corresponding to #format
447299
*/
448300
ZONE_EXPORT void zone_log(
449301
zone_parser_t *parser,
450-
const char *file,
451-
size_t line,
452-
const char *function,
453302
uint32_t category,
454303
const char *format,
455304
...)
456-
zone_nonnull((1,2,4,6))
457-
zone_format_printf(6,7);
458-
459-
/**
460-
* @brief Write log message to active log handler.
461-
*
462-
* The zone parser operates on a per-record base and therefore cannot detect
463-
* errors that span records. e.g. SOA records being specified more than once.
464-
* The user may print a message using the active log handler, keeping the
465-
* error message format consistent.
466-
*
467-
* @param[in] parser Zone parser
468-
* @param[in] category Log category
469-
* @param[in] format Format string compatible with printf
470-
* @param[in] ... Variadic arguments corresponding to @ref format
471-
*/
472-
#define ZONE_LOG(parser, category, ...) \
473-
zone_log(parser, __FILE__, __LINE__, __func__, category, __VA_ARGS__)
305+
zone_nonnull((1,3))
306+
zone_format_printf(3,4);
474307

475308
typedef struct zone_name zone_name_t;
476309
struct zone_name {
477310
uint8_t length;
478311
uint8_t *octets;
479312
};
480313

481-
// invoked for each record (host order). header (owner, type, class and ttl)
314+
// invoked for each resource record (host order). header (owner, type, class and ttl)
482315
// fields are passed individually for convenience. rdata fields can be visited
483316
// individually by means of the iterator
484-
typedef int32_t(*zone_add_t)(
317+
typedef int32_t(*zone_accept_t)(
485318
zone_parser_t *,
486-
const zone_type_info_t *, // type information
487319
const zone_name_t *, // owner (length + octets)
488320
uint16_t, // type
489321
uint16_t, // class
@@ -493,16 +325,17 @@ typedef int32_t(*zone_add_t)(
493325
void *); // user data
494326

495327
typedef struct {
496-
/** Lax mode of operation. */
328+
/** Non-strict mode of operation. */
497329
/** Authoritative servers may choose to be more lenient when operating as
498-
as a secondary as data may have been transferred over AXFR/IXFR that
330+
a secondary as data may have been transferred over AXFR/IXFR that
499331
would have triggered an error otherwise. */
500-
bool secondary;
332+
bool non_strict;
501333
/** Disable $INCLUDE directive. */
502334
/** Useful in setups where untrusted input may be offered. */
503335
bool no_includes;
504336
/** Enable 1h2m3s notations for TTLS. */
505337
bool pretty_ttls;
338+
// FIXME: require origin to be in wire format? (#115)
506339
const char *origin;
507340
uint32_t default_ttl;
508341
uint16_t default_class;
@@ -512,13 +345,10 @@ typedef struct {
512345
custom callback was specified. */
513346
uint32_t categories;
514347
/** Callback used to write out log messages. */
515-
zone_log_t write;
348+
zone_log_t callback;
516349
} log;
517350
struct {
518-
zone_add_t add;
519-
// FIXME: more callbacks to be added at a later stage to support efficient
520-
// (de)serialization of AXFR/IXFR in text representation.
521-
//zone_delete_t remove;
351+
zone_accept_t callback;
522352
} accept;
523353
} zone_options_t;
524354

@@ -568,21 +398,21 @@ struct zone_parser {
568398
/** Success */
569399
#define ZONE_SUCCESS (0)
570400
/** Syntax error */
571-
#define ZONE_SYNTAX_ERROR (-1)
401+
#define ZONE_SYNTAX_ERROR (-256) // (-1 << 8)
572402
/** Semantic error */
573-
#define ZONE_SEMANTIC_ERROR (-2)
403+
#define ZONE_SEMANTIC_ERROR (-512) // (-2 << 8)
574404
/** Operation failed due to lack of memory */
575-
#define ZONE_OUT_OF_MEMORY (-3)
405+
#define ZONE_OUT_OF_MEMORY (-768) // (-3 << 8)
576406
/** Bad parameter value */
577-
#define ZONE_BAD_PARAMETER (-4)
407+
#define ZONE_BAD_PARAMETER (-1024) // (-4 << 8)
578408
/** Error reading zone file */
579-
#define ZONE_IO_ERROR (-5)
409+
#define ZONE_READ_ERROR (-1280) // (-5 << 8)
580410
/** Control directive or support for record type is not implemented */
581-
#define ZONE_NOT_IMPLEMENTED (-6)
411+
#define ZONE_NOT_IMPLEMENTED (-1536) // (-6 << 8)
582412
/** Specified file does not exist */
583-
#define ZONE_NOT_A_FILE (-6)
413+
#define ZONE_NOT_A_FILE (-1792) // (-7 << 8)
584414
/** Access to specified file is not allowed */
585-
#define ZONE_NOT_PERMITTED (-7)
415+
#define ZONE_NOT_PERMITTED (-2048) // (-8 << 8)
586416
/** @} */
587417

588418
/**

include/zone/attributes.h

-18
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,9 @@
4343
#define zone_nonnull_all zone_attribute((__nonnull__))
4444

4545
#if _MSC_VER
46-
# define zone_really_inline __forceinline
47-
# define zone_never_inline __declspec(noinline)
48-
# define zone_warn_unused_result
49-
50-
# define zone_likely(params) (params)
51-
# define zone_unlikely(params) (params)
52-
5346
# define zone_format(params)
5447
# define zone_format_printf(string_index, first_to_check)
5548
#else // _MSC_VER
56-
# define zone_really_inline inline zone_attribute((always_inline))
57-
# define zone_never_inline zone_attribute((noinline))
58-
# if zone_has_attribute(warn_unused_result)
59-
# define zone_warn_unused_result zone_attribute((warn_unused_result))
60-
# else
61-
# define zone_warn_unused_result
62-
# endif
63-
64-
# define zone_likely(params) __builtin_expect(!!(params), 1)
65-
# define zone_unlikely(params) __builtin_expect(!!(params), 0)
66-
6749
# if zone_has_attribute(format)
6850
# define zone_format(params) zone_attribute((__format__ params))
6951
# if __MINGW32__

0 commit comments

Comments
 (0)