Skip to content

Commit 5fd6dad

Browse files
committed
Add $INCLUDE callback for dependency tracking
Fixes NLnetLabs#229.
1 parent 3b80948 commit 5fd6dad

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

include/zone.h

+16
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,18 @@ typedef int32_t(*zone_accept_t)(
379379
const uint8_t *, // rdata
380380
void *); // user data
381381

382+
/**
383+
* @brief Signature of callback function invoked on $INCLUDE.
384+
*
385+
* Signal file name in $INCLUDE directive to application. Useful for
386+
* dependency tracking, etc.
387+
*/
388+
typedef int32_t(*zone_include_t)(
389+
zone_parser_t *,
390+
const char *, // name in $INCLUDE entry
391+
const char *, // fully qualified path
392+
void *); // user data
393+
382394
/**
383395
* @brief Available configuration options.
384396
*/
@@ -411,6 +423,10 @@ typedef struct {
411423
/** Callback invoked for each RR. */
412424
zone_accept_t callback;
413425
} accept;
426+
struct {
427+
/** Callback invoked for each $INCLUDE entry. */
428+
zone_include_t callback;
429+
} include;
414430
} zone_options_t;
415431

416432
/**

src/generic/format.h

+10
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,16 @@ static really_inline int32_t parse_dollar_include(
299299
}
300300
}
301301

302+
// signal $INCLUDE to application
303+
if (parser->options.include.callback) {
304+
code = parser->options.include.callback(
305+
parser, file->name, file->path, parser->user_data);
306+
if (code) {
307+
zone_close_file(parser, file);
308+
return code;
309+
}
310+
}
311+
302312
adjust_line_count(parser->file);
303313
parser->file = file;
304314
return 0;

tests/include.c

+107
Original file line numberDiff line numberDiff line change
@@ -609,3 +609,110 @@ diagnostic_pop()
609609
(void)rmdir(dir2);
610610
#endif
611611
}
612+
613+
614+
struct file_list {
615+
size_t index;
616+
size_t count;
617+
char **paths;
618+
};
619+
620+
static int32_t track_include_cb(
621+
zone_parser_t *parser,
622+
const char *name,
623+
const char *path,
624+
void *user_data)
625+
{
626+
struct file_list *list = (struct file_list *)user_data;
627+
628+
(void)parser;
629+
(void)path;
630+
631+
fprintf(stderr, "INCLUDED: %s (%s)\n", name, path);
632+
633+
if (list->index >= list->count)
634+
return ZONE_SYNTAX_ERROR;
635+
if (strcmp(name, list->paths[list->index++]) != 0)
636+
return ZONE_SYNTAX_ERROR;
637+
return 0;
638+
}
639+
640+
static int32_t track_accept_cb(
641+
zone_parser_t *parser,
642+
const zone_name_t *owner,
643+
uint16_t type,
644+
uint16_t class,
645+
uint32_t ttl,
646+
uint16_t rdlength,
647+
const uint8_t *rdata,
648+
void *user_data)
649+
{
650+
(void)parser;
651+
(void)owner;
652+
(void)type;
653+
(void)class;
654+
(void)ttl;
655+
(void)rdlength;
656+
(void)rdata;
657+
(void)user_data;
658+
return 0;
659+
}
660+
661+
/*!cmocka */
662+
void track_includes(void **state)
663+
{
664+
char *paths[2] = { NULL, NULL };
665+
FILE *handles[2] = { NULL, NULL };
666+
struct file_list list = { 0, 2, paths };
667+
(void)state;
668+
669+
static const char fmt[] =
670+
"$INCLUDE \"%s\"\n"
671+
"example A 192.0.2.1\n";
672+
673+
paths[0] = get_tempnam(NULL, "zone");
674+
assert_non_null(paths[0]);
675+
handles[0] = fopen(paths[0], "wb");
676+
assert_non_null(handles[0]);
677+
paths[1] = get_tempnam(NULL, "zone");
678+
assert_non_null(paths[1]);
679+
handles[1] = fopen(paths[1], "wb");
680+
assert_non_null(handles[1]);
681+
682+
fprintf(handles[0], fmt, paths[1]);
683+
(void)fflush(handles[0]);
684+
(void)fclose(handles[0]);
685+
fputs("example A 192.0.2.1\n", handles[1]);
686+
(void)fflush(handles[1]);
687+
(void)fclose(handles[1]);
688+
689+
char buf[128];
690+
int len = snprintf(buf, sizeof(buf), fmt, paths[0]);
691+
assert_true(len > 0);
692+
693+
char *str = malloc((size_t)len + ZONE_BLOCK_SIZE + 1);
694+
assert_non_null(str);
695+
(void)snprintf(str, (size_t)len+1, fmt, paths[0]);
696+
697+
zone_parser_t parser;
698+
zone_options_t options;
699+
zone_name_buffer_t name;
700+
zone_rdata_buffer_t rdata;
701+
zone_buffers_t buffers = { 1, &name, &rdata };
702+
703+
memset(&options, 0, sizeof(options));
704+
options.include.callback = &track_include_cb;
705+
options.accept.callback = &track_accept_cb;
706+
options.origin.octets = origin;
707+
options.origin.length = sizeof(origin);
708+
options.default_ttl = 3600;
709+
options.default_class = 1;
710+
711+
int32_t code = zone_parse_string(&parser, &options, &buffers, str, (size_t)len, &list);
712+
assert_int_equal(code, ZONE_SUCCESS);
713+
assert_int_equal(list.index, 2);
714+
715+
free(str);
716+
free(paths[0]);
717+
free(paths[1]);
718+
}

0 commit comments

Comments
 (0)