diff --git a/src/knot/server/zone-load.c b/src/knot/server/zone-load.c index e2bed82b7027518be448a3599ff8a8ff37562193..d7f68e2431df2f1ac95afdf77224a03659ee2114 100644 --- a/src/knot/server/zone-load.c +++ b/src/knot/server/zone-load.c @@ -619,6 +619,26 @@ static int update_zone(knot_zone_t **dst, conf_zone_t *conf, knot_nameserver_t * zones_schedule_ixfr_sync(new_zone, conf->dbsync_timeout); + knot_zone_contents_t *new_contents = new_zone->contents; + if (new_contents) { + /* Check NSEC3PARAM state if present. */ + result = knot_zone_contents_load_nsec3param(new_contents); + if (result != KNOT_EOK) { + log_zone_error("NSEC3 signed zone has invalid or no " + "NSEC3PARAM record.\n"); + goto fail; + } + /* Check minimum EDNS0 payload if signed. (RFC4035/sec. 3) */ + if (knot_zone_contents_is_signed(new_contents)) { + unsigned edns_dnssec_min = EDNS_MIN_DNSSEC_PAYLOAD; + if (knot_edns_get_payload(ns->opt_rr) < edns_dnssec_min) { + log_zone_warning("EDNS payload lower than %uB for " + "DNSSEC-enabled zone '%s'.\n", + edns_dnssec_min, conf->name); + } + } + } + fail: assert(new_zone); diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index a041597b6e30fa813c8b73c725a5ac549f4e58aa..1a06ff230e45c34d88b70e1d8444355bec9a0869 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -1944,12 +1944,6 @@ int zones_ns_conf_hook(const struct conf_t *conf, void *data) knot_nameserver_t *ns = (knot_nameserver_t *)data; dbg_zones_verb("zones: reconfiguring name server.\n"); - knot_zonedb_t *old_db = NULL; - int ret = zones_update_db_from_config(conf, ns, &old_db); - if (ret != KNOT_EOK) { - return ret; - } - /* Server identification, RFC 4892. */ ns->identity = conf->identity; ns->version = conf->version; @@ -1971,6 +1965,12 @@ int zones_ns_conf_hook(const struct conf_t *conf, void *data) knot_opt_rr_t *opt_rr_old = ns->opt_rr; ns->opt_rr = opt_rr; + knot_zonedb_t *old_db = NULL; + int ret = zones_update_db_from_config(conf, ns, &old_db); + if (ret != KNOT_EOK) { + return ret; + } + synchronize_rcu(); knot_edns_free(&opt_rr_old); diff --git a/src/libknot/edns.h b/src/libknot/edns.h index c5e48a32c8ca3428b80cdf17edd0827e320d82f3..947628730c9633a34603b1986153bd10c37c6750 100644 --- a/src/libknot/edns.h +++ b/src/libknot/edns.h @@ -75,6 +75,7 @@ typedef struct knot_opt_rr knot_opt_rr_t; /*! \brief Constants for EDNS. */ enum knot_edns_const { EDNS_MIN_UDP_PAYLOAD = 512, /*!< Minimal UDP payload with EDNS enabled. */ + EDNS_MIN_DNSSEC_PAYLOAD = 1220, /*!< Minimal payload when using DNSSEC (RFC4035/sec.3) */ EDNS_MAX_UDP_PAYLOAD = 4096, /*!< Maximal UDP payload with EDNS enabled. */ EDNS_VERSION = 0, /*!< Supported EDNS version. */ EDNS_NOT_SUPPORTED = 255, /*!< EDNS not supported. */ diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index f8f1a8d8b885c319cc92d892f8c0320bc3d6b2aa..71c6819b56fd5b2861f09ddf3c8c58c81ed19597 100644 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -2045,10 +2045,21 @@ int knot_zone_contents_integrity_check(const knot_zone_contents_t *contents) return data.errors; } -unsigned knot_zone_serial(const knot_zone_contents_t *zone) +uint32_t knot_zone_serial(const knot_zone_contents_t *zone) { if (!zone) return 0; const knot_rrset_t *soa = NULL; soa = knot_node_rrset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); return knot_rdata_soa_serial(soa); } + +bool knot_zone_contents_is_signed(const knot_zone_contents_t *zone) +{ + const knot_rrset_t *soa = NULL; + if (zone->apex) { + /* Returns true if SOA has a RRSIG (basic check). */ + soa = knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA); + return soa && soa->rrsigs; + } + return false; +} diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h index d2438d542ad0bfbf866f7eb97a31e90aa7f238b6..94ec1e902f3d8ac20bd239f5e339ed9dd81af8b8 100644 --- a/src/libknot/zone/zone-contents.h +++ b/src/libknot/zone/zone-contents.h @@ -503,7 +503,12 @@ int knot_zone_contents_integrity_check(const knot_zone_contents_t *contents); * * \return serial or 0 */ -unsigned knot_zone_serial(const knot_zone_contents_t *zone); +uint32_t knot_zone_serial(const knot_zone_contents_t *zone); + +/*! + * \brief Return true if zone is signed. + */ +bool knot_zone_contents_is_signed(const knot_zone_contents_t *zone); #endif diff --git a/src/libknot/zone/zonedb.c b/src/libknot/zone/zonedb.c index 40ed8575d962258bf46d497355f87592eed5c1cd..3cdbecbda8990366489ac65e115bcde042858a57 100644 --- a/src/libknot/zone/zonedb.c +++ b/src/libknot/zone/zonedb.c @@ -134,18 +134,6 @@ int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone) return KNOT_EINVAL; } - /*! \todo Why is this check here? */ - int ret = KNOT_EOK; - if (knot_zone_contents(zone)) { - ret = knot_zone_contents_load_nsec3param( - knot_zone_get_contents(zone)); - if (ret != KNOT_EOK) { - log_zone_error("NSEC3 signed zone has invalid or no " - "NSEC3PARAM record.\n"); - return ret; - } - } - /* Invalidate search index. */ db->stack_height = 0; @@ -153,7 +141,7 @@ int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone) assert(db->count < db->reserved); /* Should be already checked. */ db->array[db->count++] = zone; - return ret; + return KNOT_EOK; } /*----------------------------------------------------------------------------*/