mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-02-03 18:49:28 -05:00
kzonecheck: consider zone file name with origin auto-detection
Partially revert 38f65806dd
This commit is contained in:
parent
1cec5a5fb0
commit
1464b18288
12 changed files with 133 additions and 218 deletions
|
|
@ -29,8 +29,9 @@ Options
|
|||
.......
|
||||
|
||||
**-o**, **--origin** *origin*
|
||||
Zone origin. If not specified, the origin is determined from the SOA record
|
||||
in the zone file.
|
||||
Zone origin. If not specified, the SOA record owner in the zone file is used
|
||||
and the zone file name (without possible **.zone** suffix) is considered as
|
||||
the initial zone origin in case the owner isn't FQDN.
|
||||
|
||||
**-d**, **--dnssec** **on**\|\ **off**
|
||||
Also check DNSSEC-related records. The default is to decide based on the
|
||||
|
|
|
|||
|
|
@ -120,49 +120,89 @@ static void process_data(zs_scanner_t *scanner)
|
|||
knot_rrset_clear(&rr, NULL);
|
||||
}
|
||||
|
||||
static void check_origin(zs_scanner_t *s)
|
||||
{
|
||||
if (s->r_type == KNOT_RRTYPE_SOA) {
|
||||
uint8_t *origin_buf = s->process.data;
|
||||
assert(s->r_owner_length <= KNOT_DNAME_MAXLEN);
|
||||
origin_buf[0] = s->r_owner_length;
|
||||
memcpy(origin_buf + 1, s->r_owner, s->r_owner_length);
|
||||
s->state = ZS_STATE_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
static void error_origin(zs_scanner_t *s)
|
||||
{
|
||||
log_error("failed to detect zone origin, file '%s', line %"PRIu64" (%s)",
|
||||
s->file.name, s->line_counter, zs_strerror(s->error.code));
|
||||
}
|
||||
|
||||
int zonefile_open(zloader_t *loader, const char *source, const knot_dname_t *origin,
|
||||
uint32_t dflt_ttl, semcheck_optional_t semantic_checks, time_t time)
|
||||
{
|
||||
if (!loader) {
|
||||
if (loader == NULL || source == NULL) {
|
||||
return KNOT_EINVAL;
|
||||
}
|
||||
|
||||
memset(loader, 0, sizeof(zloader_t));
|
||||
|
||||
/* Check zone file. */
|
||||
if (access(source, F_OK | R_OK) != 0) {
|
||||
return knot_map_errno();
|
||||
}
|
||||
|
||||
/* Create context. */
|
||||
zcreator_t *zc = malloc(sizeof(zcreator_t));
|
||||
if (zc == NULL) {
|
||||
return KNOT_ENOMEM;
|
||||
}
|
||||
memset(zc, 0, sizeof(zcreator_t));
|
||||
|
||||
/* Prepare textual owner for zone scanner (NULL for autodetection). */
|
||||
char *origin_str = NULL;
|
||||
if (origin != NULL) {
|
||||
origin_str = knot_dname_to_str_alloc(origin);
|
||||
if (origin_str == NULL) {
|
||||
free(zc);
|
||||
return KNOT_ENOMEM;
|
||||
uint8_t origin_buf[1 + KNOT_DNAME_MAXLEN];
|
||||
if (origin == NULL) { // Origin autodetection based on SOA owner and source.
|
||||
const char *ext = ".zone";
|
||||
char *origin_str = basename(source);
|
||||
if (strcmp(origin_str + strlen(origin_str) - strlen(ext), ext) == 0) {
|
||||
origin_str = strndup(origin_str, strlen(origin_str) - strlen(ext));
|
||||
} else {
|
||||
origin_str = strdup(origin_str);
|
||||
}
|
||||
|
||||
origin_buf[0] = 0;
|
||||
|
||||
zs_scanner_t s;
|
||||
if (zs_init(&s, origin_str, KNOT_CLASS_IN, 0) != 0 ||
|
||||
zs_set_input_file(&s, source) != 0 ||
|
||||
zs_set_processing(&s, check_origin, error_origin, &origin_buf) != 0) {
|
||||
free(origin_str);
|
||||
zs_deinit(&s);
|
||||
return KNOT_EFILE;
|
||||
}
|
||||
free(origin_str);
|
||||
if (zs_parse_all(&s) != 0 && s.error.fatal) {
|
||||
zs_deinit(&s);
|
||||
return KNOT_EPARSEFAIL;
|
||||
}
|
||||
zs_deinit(&s);
|
||||
|
||||
if (origin_buf[0] == 0) {
|
||||
return KNOT_ESOAINVAL;
|
||||
}
|
||||
origin = origin_buf + 1;
|
||||
}
|
||||
|
||||
knot_dname_txt_storage_t origin_str;
|
||||
if (knot_dname_to_str(origin_str, origin, sizeof(origin_str)) == NULL) {
|
||||
return KNOT_EINVAL;
|
||||
}
|
||||
|
||||
if (zs_init(&loader->scanner, origin_str, KNOT_CLASS_IN, dflt_ttl) != 0 ||
|
||||
zs_set_input_file(&loader->scanner, source) != 0 ||
|
||||
zs_set_processing(&loader->scanner, process_data, process_error, zc) != 0) {
|
||||
bool missing_origin = loader->scanner.error.code == ZS_NO_SOA;
|
||||
zs_deinit(&loader->scanner);
|
||||
free(origin_str);
|
||||
free(zc);
|
||||
return missing_origin ? KNOT_ESOAINVAL : KNOT_EFILE;
|
||||
return KNOT_EFILE;
|
||||
}
|
||||
free(origin_str);
|
||||
|
||||
zc->z = zone_contents_new(loader->scanner.zone_origin, true);
|
||||
zc->z = zone_contents_new(origin, true);
|
||||
if (zc->z == NULL) {
|
||||
zs_deinit(&loader->scanner);
|
||||
free(zc);
|
||||
|
|
|
|||
|
|
@ -159,8 +159,6 @@ static const err_table_t err_msgs[] = {
|
|||
"permission denied" ),
|
||||
ERR_ITEM( ZS_BAD_ALPN_BACKSLASH,
|
||||
"unscaped backslash character" ),
|
||||
ERR_ITEM( ZS_NO_SOA,
|
||||
"missing SOA record" ),
|
||||
|
||||
ERR_ITEM( 0, NULL ) // Terminator
|
||||
};
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ enum err_codes {
|
|||
ZS_EMPTY_LIST_ITEM,
|
||||
ZS_FILE_ACCESS,
|
||||
ZS_BAD_ALPN_BACKSLASH,
|
||||
ZS_NO_SOA,
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -104,32 +104,31 @@ int zs_init(
|
|||
// Reset the file descriptor.
|
||||
s->file.descriptor = -1;
|
||||
|
||||
// Use non-empty origin if specified.
|
||||
if (origin != NULL && strlen(origin) > 0) {
|
||||
size_t origin_len = strlen(origin);
|
||||
// Use the root zone as origin if not specified.
|
||||
if (origin == NULL || strlen(origin) == 0) {
|
||||
origin = ".";
|
||||
}
|
||||
size_t origin_len = strlen(origin);
|
||||
|
||||
// Prepare a zone settings header.
|
||||
const char *format;
|
||||
if (origin[origin_len - 1] != '.') {
|
||||
format = "$ORIGIN %s.\n";
|
||||
} else {
|
||||
format = "$ORIGIN %s\n";
|
||||
}
|
||||
|
||||
char settings[1024];
|
||||
int ret = snprintf(settings, sizeof(settings), format, origin);
|
||||
if (ret <= 0 || ret >= sizeof(settings)) {
|
||||
ERR(ZS_ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the settings to set up the scanner origin.
|
||||
if (zs_set_input_string(s, settings, ret) != 0 ||
|
||||
zs_parse_all(s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
// Prepare a zone settings header.
|
||||
const char *format;
|
||||
if (origin[origin_len - 1] != '.') {
|
||||
format = "$ORIGIN %s.\n";
|
||||
} else {
|
||||
s->zone_origin_length = ZS_NO_ORIGIN_LEN;
|
||||
format = "$ORIGIN %s\n";
|
||||
}
|
||||
|
||||
char settings[1024];
|
||||
int ret = snprintf(settings, sizeof(settings), format, origin);
|
||||
if (ret <= 0 || ret >= sizeof(settings)) {
|
||||
ERR(ZS_ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the settings to set up the scanner origin.
|
||||
if (zs_set_input_string(s, settings, ret) != 0 ||
|
||||
zs_parse_all(s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set scanner defaults.
|
||||
|
|
@ -251,46 +250,12 @@ static char *read_file_to_buf(
|
|||
return buf;
|
||||
}
|
||||
|
||||
static void check_origin(zs_scanner_t *ss)
|
||||
{
|
||||
if (ss->r_type == KNOT_RRTYPE_SOA) {
|
||||
zs_scanner_t *s = ss->process.data;
|
||||
memcpy(s->zone_origin, ss->r_owner, ss->r_owner_length);
|
||||
s->zone_origin_length = ss->r_owner_length;
|
||||
ss->state = ZS_STATE_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_origin(zs_scanner_t *s)
|
||||
{
|
||||
if (s->zone_origin_length != ZS_NO_ORIGIN_LEN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zs_scanner_t ss;
|
||||
if (zs_init(&ss, ".", KNOT_CLASS_IN, 0) != 0 ||
|
||||
zs_set_input_string(&ss, s->input.start, s->input.end - s->input.start) != 0 ||
|
||||
zs_set_processing(&ss, check_origin, NULL, s) != 0 ||
|
||||
zs_parse_all(&ss) != 0) {
|
||||
zs_deinit(&ss);
|
||||
return -1;
|
||||
}
|
||||
zs_deinit(&ss);
|
||||
|
||||
return s->zone_origin_length != ZS_NO_ORIGIN_LEN ? 0 : -1;
|
||||
}
|
||||
|
||||
_public_
|
||||
int zs_set_input_string(
|
||||
zs_scanner_t *s,
|
||||
const char *input,
|
||||
size_t size)
|
||||
{
|
||||
if (parse_origin(s) != 0) {
|
||||
ERR(ZS_NO_SOA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->state = ZS_STATE_NONE;
|
||||
|
||||
return set_input_string(s, input, size, false);
|
||||
|
|
@ -390,12 +355,6 @@ int zs_set_input_file(
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (parse_origin(s) != 0) {
|
||||
ERR(ZS_NO_SOA);
|
||||
input_deinit(s, false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->state = ZS_STATE_NONE;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -6499,32 +6499,31 @@ int zs_init(
|
|||
// Reset the file descriptor.
|
||||
s->file.descriptor = -1;
|
||||
|
||||
// Use non-empty origin if specified.
|
||||
if (origin != NULL && strlen(origin) > 0) {
|
||||
size_t origin_len = strlen(origin);
|
||||
// Use the root zone as origin if not specified.
|
||||
if (origin == NULL || strlen(origin) == 0) {
|
||||
origin = ".";
|
||||
}
|
||||
size_t origin_len = strlen(origin);
|
||||
|
||||
// Prepare a zone settings header.
|
||||
const char *format;
|
||||
if (origin[origin_len - 1] != '.') {
|
||||
format = "$ORIGIN %s.\n";
|
||||
} else {
|
||||
format = "$ORIGIN %s\n";
|
||||
}
|
||||
|
||||
char settings[1024];
|
||||
int ret = snprintf(settings, sizeof(settings), format, origin);
|
||||
if (ret <= 0 || ret >= sizeof(settings)) {
|
||||
ERR(ZS_ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the settings to set up the scanner origin.
|
||||
if (zs_set_input_string(s, settings, ret) != 0 ||
|
||||
zs_parse_all(s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
// Prepare a zone settings header.
|
||||
const char *format;
|
||||
if (origin[origin_len - 1] != '.') {
|
||||
format = "$ORIGIN %s.\n";
|
||||
} else {
|
||||
s->zone_origin_length = ZS_NO_ORIGIN_LEN;
|
||||
format = "$ORIGIN %s\n";
|
||||
}
|
||||
|
||||
char settings[1024];
|
||||
int ret = snprintf(settings, sizeof(settings), format, origin);
|
||||
if (ret <= 0 || ret >= sizeof(settings)) {
|
||||
ERR(ZS_ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the settings to set up the scanner origin.
|
||||
if (zs_set_input_string(s, settings, ret) != 0 ||
|
||||
zs_parse_all(s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set scanner defaults.
|
||||
|
|
@ -6646,46 +6645,12 @@ static char *read_file_to_buf(
|
|||
return buf;
|
||||
}
|
||||
|
||||
static void check_origin(zs_scanner_t *ss)
|
||||
{
|
||||
if (ss->r_type == KNOT_RRTYPE_SOA) {
|
||||
zs_scanner_t *s = ss->process.data;
|
||||
memcpy(s->zone_origin, ss->r_owner, ss->r_owner_length);
|
||||
s->zone_origin_length = ss->r_owner_length;
|
||||
ss->state = ZS_STATE_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_origin(zs_scanner_t *s)
|
||||
{
|
||||
if (s->zone_origin_length != ZS_NO_ORIGIN_LEN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zs_scanner_t ss;
|
||||
if (zs_init(&ss, ".", KNOT_CLASS_IN, 0) != 0 ||
|
||||
zs_set_input_string(&ss, s->input.start, s->input.end - s->input.start) != 0 ||
|
||||
zs_set_processing(&ss, check_origin, NULL, s) != 0 ||
|
||||
zs_parse_all(&ss) != 0) {
|
||||
zs_deinit(&ss);
|
||||
return -1;
|
||||
}
|
||||
zs_deinit(&ss);
|
||||
|
||||
return s->zone_origin_length != ZS_NO_ORIGIN_LEN ? 0 : -1;
|
||||
}
|
||||
|
||||
_public_
|
||||
int zs_set_input_string(
|
||||
zs_scanner_t *s,
|
||||
const char *input,
|
||||
size_t size)
|
||||
{
|
||||
if (parse_origin(s) != 0) {
|
||||
ERR(ZS_NO_SOA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->state = ZS_STATE_NONE;
|
||||
|
||||
return set_input_string(s, input, size, false);
|
||||
|
|
@ -6785,12 +6750,6 @@ int zs_set_input_file(
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (parse_origin(s) != 0) {
|
||||
ERR(ZS_NO_SOA);
|
||||
input_deinit(s, false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->state = ZS_STATE_NONE;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -38,9 +38,6 @@
|
|||
/*! \brief Ragel call stack size (see Ragel internals). */
|
||||
#define ZS_RAGEL_STACK_SIZE 16
|
||||
|
||||
/*! \brief Indication of automatic origin detection. */
|
||||
#define ZS_NO_ORIGIN_LEN UINT32_MAX
|
||||
|
||||
/*! \brief Auxiliary structure for storing bitmap window items (see RFC4034). */
|
||||
typedef struct {
|
||||
uint8_t bitmap[32];
|
||||
|
|
@ -268,7 +265,7 @@ struct zs_scanner {
|
|||
* \note Error code is stored in the scanner context.
|
||||
*
|
||||
* \param scanner Scanner context.
|
||||
* \param origin Initial zone origin. Autodetected if empty.
|
||||
* \param origin Initial zone origin ("." is used if empty).
|
||||
* \param rclass Zone class value.
|
||||
* \param ttl Initial ttl value.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -105,32 +105,31 @@ int zs_init(
|
|||
// Reset the file descriptor.
|
||||
s->file.descriptor = -1;
|
||||
|
||||
// Use non-empty origin if specified.
|
||||
if (origin != NULL && strlen(origin) > 0) {
|
||||
size_t origin_len = strlen(origin);
|
||||
// Use the root zone as origin if not specified.
|
||||
if (origin == NULL || strlen(origin) == 0) {
|
||||
origin = ".";
|
||||
}
|
||||
size_t origin_len = strlen(origin);
|
||||
|
||||
// Prepare a zone settings header.
|
||||
const char *format;
|
||||
if (origin[origin_len - 1] != '.') {
|
||||
format = "$ORIGIN %s.\n";
|
||||
} else {
|
||||
format = "$ORIGIN %s\n";
|
||||
}
|
||||
|
||||
char settings[1024];
|
||||
int ret = snprintf(settings, sizeof(settings), format, origin);
|
||||
if (ret <= 0 || ret >= sizeof(settings)) {
|
||||
ERR(ZS_ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the settings to set up the scanner origin.
|
||||
if (zs_set_input_string(s, settings, ret) != 0 ||
|
||||
zs_parse_all(s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
// Prepare a zone settings header.
|
||||
const char *format;
|
||||
if (origin[origin_len - 1] != '.') {
|
||||
format = "$ORIGIN %s.\n";
|
||||
} else {
|
||||
s->zone_origin_length = ZS_NO_ORIGIN_LEN;
|
||||
format = "$ORIGIN %s\n";
|
||||
}
|
||||
|
||||
char settings[1024];
|
||||
int ret = snprintf(settings, sizeof(settings), format, origin);
|
||||
if (ret <= 0 || ret >= sizeof(settings)) {
|
||||
ERR(ZS_ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the settings to set up the scanner origin.
|
||||
if (zs_set_input_string(s, settings, ret) != 0 ||
|
||||
zs_parse_all(s) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set scanner defaults.
|
||||
|
|
@ -252,46 +251,12 @@ static char *read_file_to_buf(
|
|||
return buf;
|
||||
}
|
||||
|
||||
static void check_origin(zs_scanner_t *ss)
|
||||
{
|
||||
if (ss->r_type == KNOT_RRTYPE_SOA) {
|
||||
zs_scanner_t *s = ss->process.data;
|
||||
memcpy(s->zone_origin, ss->r_owner, ss->r_owner_length);
|
||||
s->zone_origin_length = ss->r_owner_length;
|
||||
ss->state = ZS_STATE_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_origin(zs_scanner_t *s)
|
||||
{
|
||||
if (s->zone_origin_length != ZS_NO_ORIGIN_LEN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zs_scanner_t ss;
|
||||
if (zs_init(&ss, ".", KNOT_CLASS_IN, 0) != 0 ||
|
||||
zs_set_input_string(&ss, s->input.start, s->input.end - s->input.start) != 0 ||
|
||||
zs_set_processing(&ss, check_origin, NULL, s) != 0 ||
|
||||
zs_parse_all(&ss) != 0) {
|
||||
zs_deinit(&ss);
|
||||
return -1;
|
||||
}
|
||||
zs_deinit(&ss);
|
||||
|
||||
return s->zone_origin_length != ZS_NO_ORIGIN_LEN ? 0 : -1;
|
||||
}
|
||||
|
||||
_public_
|
||||
int zs_set_input_string(
|
||||
zs_scanner_t *s,
|
||||
const char *input,
|
||||
size_t size)
|
||||
{
|
||||
if (parse_origin(s) != 0) {
|
||||
ERR(ZS_NO_SOA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->state = ZS_STATE_NONE;
|
||||
|
||||
return set_input_string(s, input, size, false);
|
||||
|
|
@ -391,12 +356,6 @@ int zs_set_input_file(
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (parse_origin(s) != 0) {
|
||||
ERR(ZS_NO_SOA);
|
||||
input_deinit(s, false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->state = ZS_STATE_NONE;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ static void print_help(void)
|
|||
"\n"
|
||||
"Options:\n"
|
||||
" -o, --origin <zone_origin> Zone name.\n"
|
||||
" (default filename without .zone)\n"
|
||||
" (default SOA owner)\n"
|
||||
" -d, --dnssec <on|off> Enforce check of DNSSEC records.\n"
|
||||
" (default autodetection)\n"
|
||||
" -j, --jobs <num> Number of threads.\n"
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ int zone_check(const char *zone_file, const knot_dname_t *zone_name, bool zonemd
|
|||
|
||||
if (zone_name == NULL) {
|
||||
knot_dname_txt_storage_t origin;
|
||||
if (knot_dname_to_str(origin,zl.scanner.zone_origin , sizeof(origin)) != NULL) {
|
||||
if (knot_dname_to_str(origin, zl.scanner.zone_origin, sizeof(origin)) != NULL) {
|
||||
log_debug("detected zone origin %s", origin);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
tests/knot/semantic_check_data/soa.relative
Normal file
2
tests/knot/semantic_check_data/soa.relative
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
soa.relative. NS example.net.
|
||||
@ SOA dns1 hostmaster 1 1000 360 10000 7200
|
||||
|
|
@ -103,6 +103,7 @@ plan_lazy
|
|||
expect_error "soa.missing" 0 0 "" "AUTO"
|
||||
test_correct "soa.duplicate" "AUTO"
|
||||
test_correct "soa.nonfirst" "AUTO"
|
||||
test_correct "soa.relative" "AUTO"
|
||||
|
||||
expect_error "soa.missing" 1 1 "$SOA_MISSING"
|
||||
expect_error "soa.multiple" 1 1 "$SOA_MULTIPLE"
|
||||
|
|
|
|||
Loading…
Reference in a new issue