zonemd, zonemd-reject-absence config for an auth-zone rejects the zone if

no ZONEMD is present.
This commit is contained in:
W.C.A. Wijngaards 2020-10-26 15:37:43 +01:00
parent 8e53f0b14f
commit 94ac072f9b
10 changed files with 3411 additions and 3338 deletions

View file

@ -998,6 +998,7 @@ remote-control:
# name: "example.org"
# for-downstream: yes
# for-upstream: yes
# zonemd-reject-absence: no
# zonefile: "example.org.zone"
# Views

View file

@ -1829,6 +1829,19 @@ to the authority servers for this zone, it'll fetch the data directly from
the zone data. Turn it on when you want unbound to provide recursion for
downstream clients, and use the zone data as a local copy to speed up lookups.
.TP
.B zonemd\-reject\-absence: \fI<yes or no>
Enable this option to reject the absence of the ZONEMD record. Without it,
when zonemd is not there it is not checked. It is useful to enable for a
nonDNSSEC signed zone where the operator wants to require the verification
of a ZONEMD, hence a missing ZONEMD is a failure. The action upon
failure is controlled by the \fBzonemd\-permissive\-mode\fR option, for
log only or also block the zone. The default is no.
.IP
Without the option absence of a ZONEMD is only a failure when the zone is
DNSSEC signed, and we have a trust anchor, and the DNSSEC verification of
the absence of the ZONEMD fails. With the option enabled, the absence of
a ZONEMD is always a failure, also for nonDNSSEC signed zones.
.TP
.B zonefile: \fI<filename>
The filename where the zone is stored. If not given then no zonefile is used.
If the file does not exist or is empty, unbound will attempt to fetch zone

View file

@ -2047,6 +2047,7 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c)
z->for_downstream = c->for_downstream;
z->for_upstream = c->for_upstream;
z->fallback_enabled = c->fallback_enabled;
z->zonemd_reject_absence = c->zonemd_reject_absence;
if(c->isrpz && !z->rpz){
if(!(z->rpz = rpz_create(c))){
fatal_exit("Could not setup RPZ zones");
@ -7887,7 +7888,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
}
}
if(zonemd_absent && 0) {
if(zonemd_absent && z->zonemd_reject_absence) {
auth_zone_zonemd_fail(z, env, "ZONEMD absent and that is not allowed by config", NULL, result);
return;
}

View file

@ -132,6 +132,8 @@ struct auth_zone {
/** for upstream: this zone answers queries that unbound intends to
* send upstream. */
int for_upstream;
/** reject absence of ZONEMD records */
int zonemd_reject_absence;
/** RPZ zones */
struct rpz* rpz;
/** store the env (worker thread specific) for the zonemd callbacks

View file

@ -710,6 +710,8 @@ struct config_auth {
/** Always reply with this CNAME target if the cname override action is
* used */
char* rpz_cname;
/** Reject absence of ZONEMD records, zone must have one */
int zonemd_reject_absence;
};
/**

File diff suppressed because it is too large Load diff

View file

@ -400,6 +400,7 @@ neg-cache-size{COLON} { YDVAR(1, VAR_NEG_CACHE_SIZE) }
val-nsec3-keysize-iterations{COLON} {
YDVAR(1, VAR_VAL_NSEC3_KEYSIZE_ITERATIONS) }
zonemd-permissive-mode{COLON} { YDVAR(1, VAR_ZONEMD_PERMISSIVE_MODE) }
zonemd-reject-absence{COLON} { YDVAR(1, VAR_ZONEMD_REJECT_ABSENCE) }
add-holddown{COLON} { YDVAR(1, VAR_ADD_HOLDDOWN) }
del-holddown{COLON} { YDVAR(1, VAR_DEL_HOLDDOWN) }
keep-missing{COLON} { YDVAR(1, VAR_KEEP_MISSING) }

File diff suppressed because it is too large Load diff

View file

@ -348,7 +348,8 @@ extern int yydebug;
VAR_DYNLIB_FILE = 554,
VAR_EDNS_CLIENT_TAG = 555,
VAR_EDNS_CLIENT_TAG_OPCODE = 556,
VAR_ZONEMD_PERMISSIVE_MODE = 557
VAR_ZONEMD_PERMISSIVE_MODE = 557,
VAR_ZONEMD_REJECT_ABSENCE = 558
};
#endif
/* Tokens. */
@ -652,6 +653,7 @@ extern int yydebug;
#define VAR_EDNS_CLIENT_TAG 555
#define VAR_EDNS_CLIENT_TAG_OPCODE 556
#define VAR_ZONEMD_PERMISSIVE_MODE 557
#define VAR_ZONEMD_REJECT_ABSENCE 558
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@ -661,7 +663,7 @@ union YYSTYPE
char* str;
#line 665 "util/configparser.h"
#line 667 "util/configparser.h"
};
typedef union YYSTYPE YYSTYPE;

View file

@ -179,7 +179,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME
%token VAR_DYNLIB VAR_DYNLIB_FILE VAR_EDNS_CLIENT_TAG VAR_EDNS_CLIENT_TAG_OPCODE
%token VAR_ZONEMD_PERMISSIVE_MODE
%token VAR_ZONEMD_PERMISSIVE_MODE VAR_ZONEMD_REJECT_ABSENCE
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -360,6 +360,7 @@ authstart: VAR_AUTH_ZONE
s->for_downstream = 1;
s->for_upstream = 1;
s->fallback_enabled = 0;
s->zonemd_reject_absence = 0;
s->isrpz = 0;
} else
yyerror("out of memory");
@ -369,7 +370,7 @@ contents_auth: contents_auth content_auth
| ;
content_auth: auth_name | auth_zonefile | auth_master | auth_url |
auth_for_downstream | auth_for_upstream | auth_fallback_enabled |
auth_allow_notify
auth_allow_notify | auth_zonemd_reject_absence
;
rpz_tag: VAR_TAGS STRING_ARG
@ -2673,6 +2674,16 @@ auth_allow_notify: VAR_ALLOW_NOTIFY STRING_ARG
yyerror("out of memory");
}
;
auth_zonemd_reject_absence: VAR_ZONEMD_REJECT_ABSENCE STRING_ARG
{
OUTYY(("P(zonemd-reject-absence:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->auths->zonemd_reject_absence =
(strcmp($2, "yes")==0);
free($2);
}
;
auth_for_downstream: VAR_FOR_DOWNSTREAM STRING_ARG
{
OUTYY(("P(for-downstream:%s)\n", $2));