Skip to content

Commit 6a953e6

Browse files
committed
Add $INCLUDE callback for dependency tracking
Fixes NLnetLabs#229.
1 parent ec24e75 commit 6a953e6

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

include/zone.h

+16
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,18 @@ typedef int32_t(*zone_accept_t)(
384384
const uint8_t *, // rdata
385385
void *); // user data
386386

387+
/**
388+
* @brief Signature of callback function invoked on $INCLUDE.
389+
*
390+
* Signal file name in $INCLUDE directive to application. Useful for
391+
* dependency tracking, etc.
392+
*/
393+
typedef int32_t(*zone_include_t)(
394+
zone_parser_t *,
395+
const char *, // name in $INCLUDE entry
396+
const char *, // fully qualified path
397+
void *); // user data
398+
387399
/**
388400
* @brief Available configuration options.
389401
*/
@@ -416,6 +428,10 @@ typedef struct {
416428
/** Callback invoked for each RR. */
417429
zone_accept_t callback;
418430
} accept;
431+
struct {
432+
/** Callback invoked for each $INCLUDE entry. */
433+
zone_include_t callback;
434+
} include;
419435
} zone_options_t;
420436

421437
/**

src/generic/format.h

+10
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,16 @@ static really_inline int32_t parse_dollar_include(
302302
}
303303
}
304304

305+
// signal $INCLUDE to application
306+
if (parser->options.include.callback) {
307+
code = parser->options.include.callback(
308+
parser, file->name, file->path, parser->user_data);
309+
if (code) {
310+
zone_close_file(parser, file);
311+
return code;
312+
}
313+
}
314+
305315
adjust_line_count(parser->file);
306316
parser->file = file;
307317
return 0;

tests/include.c

+110
Original file line numberDiff line numberDiff line change
@@ -609,3 +609,113 @@ 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+
diagnostic_push()
674+
msvc_diagnostic_ignored(4996)
675+
paths[0] = get_tempnam(NULL, "zone");
676+
assert_non_null(paths[0]);
677+
handles[0] = fopen(paths[0], "wb");
678+
assert_non_null(handles[0]);
679+
paths[1] = get_tempnam(NULL, "zone");
680+
assert_non_null(paths[1]);
681+
handles[1] = fopen(paths[1], "wb");
682+
assert_non_null(handles[1]);
683+
diagnostic_pop()
684+
685+
fprintf(handles[0], fmt, paths[1]);
686+
(void)fflush(handles[0]);
687+
(void)fclose(handles[0]);
688+
fputs("example A 192.0.2.1\n", handles[1]);
689+
(void)fflush(handles[1]);
690+
(void)fclose(handles[1]);
691+
692+
char buf[128];
693+
int len = snprintf(buf, sizeof(buf), fmt, paths[0]);
694+
assert_true(len > 0);
695+
696+
char *str = malloc((size_t)len + ZONE_BLOCK_SIZE + 1);
697+
assert_non_null(str);
698+
(void)snprintf(str, (size_t)len+1, fmt, paths[0]);
699+
700+
zone_parser_t parser;
701+
zone_options_t options;
702+
zone_name_buffer_t name;
703+
zone_rdata_buffer_t rdata;
704+
zone_buffers_t buffers = { 1, &name, &rdata };
705+
706+
memset(&options, 0, sizeof(options));
707+
options.include.callback = &track_include_cb;
708+
options.accept.callback = &track_accept_cb;
709+
options.origin.octets = origin;
710+
options.origin.length = sizeof(origin);
711+
options.default_ttl = 3600;
712+
options.default_class = 1;
713+
714+
int32_t code = zone_parse_string(&parser, &options, &buffers, str, (size_t)len, &list);
715+
assert_int_equal(code, ZONE_SUCCESS);
716+
assert_int_equal(list.index, 2);
717+
718+
free(str);
719+
free(paths[0]);
720+
free(paths[1]);
721+
}

0 commit comments

Comments
 (0)