Commit 6dce7dce authored by Lubos Slovak's avatar Lubos Slovak
Browse files

Serial policy applicable to DDNS and DNSSEC.

refs #158
parent b1d0d81c
......@@ -905,6 +905,40 @@ static int zones_update_forward(int fd, knot_ns_transport_t ttype,
/*----------------------------------------------------------------------------*/
static int zones_serial_policy(const knot_zone_t *zone)
{
if (zone == NULL) {
return KNOT_EINVAL;
}
zonedata_t *data = (zonedata_t *)knot_zone_data(zone);
if (data == NULL) {
return KNOT_ERROR;
}
return data->conf->serial_policy;
}
static uint32_t zones_next_serial(int64_t old_sn, int serial_policy)
{
if (old_sn < 0) {
return KNOT_EINVAL;
}
switch (serial_policy) {
case CONF_SERIAL_INCREMENT:
return (uint32_t)old_sn + 1;
break;
case CONF_SERIAL_UNIXTIME:
return (uint32_t)time(NULL);
break;
default:
assert(0);
}
}
/*----------------------------------------------------------------------------*/
static int replan_zone_sign_after_ddns(knot_zone_t *zone, zonedata_t *zd,
uint32_t used_lifetime,
uint32_t used_refresh)
......@@ -981,10 +1015,14 @@ static int zones_process_update_auth(knot_zone_t *zone,
}
*rcode = KNOT_RCODE_SERVFAIL; /* SERVFAIL unless it applies correctly. */
uint32_t new_serial = zones_next_serial(
knot_zone_serial(knot_zone_contents(zone)),
zones_serial_policy(zone));
knot_zone_contents_t *new_contents = NULL;
ret = knot_ns_process_update(knot_packet_query(resp),
knot_zone_get_contents(zone),
&new_contents, chgsets, rcode);
&new_contents, chgsets, rcode, new_serial);
if (ret != KNOT_EOK) {
if (ret < 0) {
log_zone_error("%s %s\n", msg, knot_strerror(ret));
......@@ -1028,7 +1066,8 @@ static int zones_process_update_auth(knot_zone_t *zone,
ret = knot_dnssec_sign_changeset(new_contents,
knot_changesets_get_last(chgsets),
sec_ch, KNOT_SOA_SERIAL_KEEP,
&used_lifetime, &used_refresh);
&used_lifetime, &used_refresh,
new_serial);
if (ret != KNOT_EOK) {
log_zone_error("%s: Failed to sign incoming update (%s)\n",
msg, knot_strerror(ret));
......@@ -2544,11 +2583,16 @@ static int zones_dnssec_ev(event_t *event, bool force)
log_zone_info("%s Signing zone...\n", msgpref);
}
uint32_t new_serial = zones_next_serial(
knot_zone_serial(knot_zone_contents(zone)),
zones_serial_policy(zone));
if (force) {
ret = knot_dnssec_zone_sign_force(zone, ch, &expires_at);
ret = knot_dnssec_zone_sign_force(zone, ch, &expires_at,
new_serial);
} else {
ret = knot_dnssec_zone_sign(zone, ch, KNOT_SOA_SERIAL_INC,
&expires_at);
&expires_at, new_serial);
}
if (ret != KNOT_EOK) {
goto done;
......@@ -2985,17 +3029,19 @@ int zones_do_diff_and_sign(const conf_zone_t *z, knot_zone_t *zone,
return KNOT_ENOMEM;
}
log_zone_info("DNSSEC: Zone %s - Signing started...\n",
z->name);
uint32_t new_serial = zones_next_serial(
knot_zone_serial(zc),
zones_serial_policy(zone));
/*!
* Increment serial even if diff did that. This way it's always
* possible to flush the changes to zonefile.
*/
knot_update_serial_t soa_up = KNOT_SOA_SERIAL_INC;
log_zone_info("DNSSEC: Zone %s - Signing started...\n",
z->name);
int ret = knot_dnssec_zone_sign(zone, sec_ch, soa_up,
&expires_at);
int ret = knot_dnssec_zone_sign(zone, sec_ch, KNOT_SOA_SERIAL_INC,
&expires_at, new_serial);
if (ret != KNOT_EOK) {
knot_changesets_free(&diff_chs);
knot_changesets_free(&sec_chs);
......
......@@ -89,7 +89,8 @@ static int init_dnssec_structs(const knot_zone_t *zone,
}
static int zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch, bool force,
knot_update_serial_t soa_up, uint32_t *expires_at)
knot_update_serial_t soa_up, uint32_t *expires_at,
uint32_t new_serial)
{
assert(zone);
assert(zone->contents);
......@@ -164,7 +165,7 @@ static int zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch, bool force,
KNOT_RRTYPE_SOA);
assert(soa);
result = knot_zone_sign_update_soa(soa, &zone_keys, &policy,
out_ch);
new_serial, out_ch);
if (result != KNOT_EOK) {
log_zone_error("%s Cannot update SOA record (%s). Not signing"
"the zone!\n", msgpref, knot_strerror(result));
......@@ -182,23 +183,26 @@ static int zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch, bool force,
}
int knot_dnssec_zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch,
knot_update_serial_t soa_up, uint32_t *expires_at)
knot_update_serial_t soa_up, uint32_t *expires_at,
uint32_t new_serial)
{
if (zone == NULL || zone->contents == NULL || out_ch == NULL) {
return KNOT_EINVAL;
}
return zone_sign(zone, out_ch, false, soa_up, expires_at);
return zone_sign(zone, out_ch, false, soa_up, expires_at, new_serial);
}
int knot_dnssec_zone_sign_force(knot_zone_t *zone,
knot_changeset_t *out_ch, uint32_t *expires_at)
knot_changeset_t *out_ch, uint32_t *expires_at,
uint32_t new_serial)
{
if (zone == NULL || zone->contents == NULL || out_ch == NULL) {
return KNOT_EINVAL;
}
return zone_sign(zone, out_ch, true, KNOT_SOA_SERIAL_INC, expires_at);
return zone_sign(zone, out_ch, true, KNOT_SOA_SERIAL_INC, expires_at,
new_serial);
}
int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
......@@ -206,7 +210,8 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
knot_changeset_t *out_ch,
knot_update_serial_t soa_up,
uint32_t *used_lifetime,
uint32_t *used_refresh)
uint32_t *used_refresh,
uint32_t new_serial)
{
if (!used_lifetime || !used_refresh) {
return KNOT_EINVAL;
......@@ -263,7 +268,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
// Update SOA RRSIGs
ret = knot_zone_sign_update_soa(knot_node_rrset(zone->apex,
KNOT_RRTYPE_SOA),
&zone_keys, &policy,
&zone_keys, &policy, new_serial,
out_ch);
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to sign SOA RR (%s)\n", msgpref,
......
......@@ -43,7 +43,8 @@
* \return Error code, KNOT_EOK if successful.
*/
int knot_dnssec_zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch,
knot_update_serial_t soa_up, uint32_t *expires_at);
knot_update_serial_t soa_up, uint32_t *expires_at,
uint32_t new_serial);
/*!
* \brief DNSSEC sign zone, store new records into changeset. Even valid
......@@ -56,7 +57,7 @@ int knot_dnssec_zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch,
* \return Error code, KNOT_EOK if successful.
*/
int knot_dnssec_zone_sign_force(knot_zone_t *zone, knot_changeset_t *out_ch,
uint32_t *expires_at);
uint32_t *expires_at, uint32_t new_serial);
/*!
* \brief Sign changeset created by DDNS or zone-diff.
......@@ -75,7 +76,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
knot_changeset_t *out_ch,
knot_update_serial_t soa_up,
uint32_t *used_lifetime,
uint32_t *used_refresh);
uint32_t *used_refresh, uint32_t new_serial);
#endif // _KNOT_DNSSEC_ZONE_EVENTS_H_
/*! @} */
......@@ -1091,6 +1091,7 @@ bool knot_zone_sign_soa_expired(const knot_zone_contents_t *zone,
int knot_zone_sign_update_soa(const knot_rrset_t *soa,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy,
uint32_t new_serial,
knot_changeset_t *changeset)
{
if (!soa || !zone_keys || !policy || !changeset) {
......@@ -1105,11 +1106,11 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa,
return KNOT_EINVAL;
}
uint32_t new_serial = serial;
if (policy->soa_up == KNOT_SOA_SERIAL_INC) {
new_serial += 1;
assert(new_serial >= 0);
} else {
assert(policy->soa_up == KNOT_SOA_SERIAL_KEEP);
new_serial = serial;
}
int result;
......
......@@ -65,7 +65,7 @@ int knot_zone_sign(const knot_zone_contents_t *zone,
int knot_zone_sign_update_soa(const knot_rrset_t *soa,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy,
knot_changeset_t *changeset);
uint32_t new_serial, knot_changeset_t *changeset);
/*!
* \brief Check if zone SOA signatures are expired.
......
......@@ -4159,9 +4159,10 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver,
* order to get rid of duplicate code.
*/
int knot_ns_process_update(const knot_packet_t *query,
knot_zone_contents_t *old_contents,
knot_zone_contents_t **new_contents,
knot_changesets_t *chgs, knot_rcode_t *rcode)
knot_zone_contents_t *old_contents,
knot_zone_contents_t **new_contents,
knot_changesets_t *chgs, knot_rcode_t *rcode,
uint32_t new_serial)
{
if (query == NULL || old_contents == NULL || chgs == NULL ||
EMPTY_LIST(chgs->sets) || new_contents == NULL || rcode == NULL) {
......@@ -4185,7 +4186,7 @@ int knot_ns_process_update(const knot_packet_t *query,
dbg_ns_verb("Applying the UPDATE and creating changeset...\n");
ret = knot_ddns_process_update(contents_copy, query,
knot_changesets_get_last(chgs),
chgs->changes, rcode);
chgs->changes, rcode, new_serial);
if (ret != KNOT_EOK) {
dbg_ns("Failed to apply UPDATE to the zone copy or no update"
" made: %s\n", (ret < 0) ? knot_strerror(ret)
......
......@@ -358,9 +358,10 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver,
knot_ns_xfr_t *xfr);
int knot_ns_process_update(const knot_packet_t *query,
knot_zone_contents_t *old_contents,
knot_zone_contents_t **new_contents,
knot_changesets_t *chgs, knot_rcode_t *rcode);
knot_zone_contents_t *old_contents,
knot_zone_contents_t **new_contents,
knot_changesets_t *chgs, knot_rcode_t *rcode,
uint32_t new_serial);
int knot_ns_create_forward_query(const knot_packet_t *query,
uint8_t *query_wire, size_t *size);
......
......@@ -1721,7 +1721,7 @@ int knot_ddns_process_update(knot_zone_contents_t *zone,
const knot_packet_t *query,
knot_changeset_t *changeset,
knot_changes_t *changes,
knot_rcode_t *rcode)
knot_rcode_t *rcode, uint32_t new_serial)
{
if (zone == NULL || query == NULL || changeset == NULL || rcode == NULL
|| changes == NULL) {
......@@ -1748,12 +1748,10 @@ int knot_ddns_process_update(knot_zone_contents_t *zone,
int64_t sn = knot_rdata_soa_serial(soa_begin);
int64_t sn_new;
/* Incremented SERIAL
* We must set it now to be able to compare SERIAL from SOAs in the
* UPDATE to it. Although we do not have the new SOA yet.
*/
/* Set the new serial according to policy. */
if (sn > -1) {
sn_new = (uint32_t)sn + 1;
sn_new = new_serial;
assert(sn_new != KNOT_EINVAL);
} else {
*rcode = KNOT_RCODE_SERVFAIL;
return ret;
......@@ -1798,7 +1796,7 @@ int knot_ddns_process_update(knot_zone_contents_t *zone,
&& (knot_rrset_class(rr) == KNOT_CLASS_NONE
|| knot_rrset_class(rr) == KNOT_CLASS_ANY
|| ns_serial_compare(knot_rdata_soa_serial(rr),
sn_new) < 0)) {
sn) <= 0)) {
// This ignores also SOA removals
dbg_ddns_verb("Ignoring SOA...\n");
continue;
......@@ -1822,7 +1820,7 @@ int knot_ddns_process_update(knot_zone_contents_t *zone,
int64_t sn_rr = knot_rdata_soa_serial(rr);
dbg_ddns_verb("Replacing SOA. Old serial: %"PRId64", "
"new serial: %"PRId64"\n", sn_new, sn_rr);
assert(ns_serial_compare(sn_rr, sn_new) >= 0);
assert(ns_serial_compare(sn_rr, sn) > 0);
assert(rr_copy != NULL);
sn_new = sn_rr;
soa_end = rr_copy;
......@@ -1840,7 +1838,6 @@ int knot_ddns_process_update(knot_zone_contents_t *zone,
}
/* If not set, create new SOA. */
assert(sn_new == (uint32_t)sn + 1);
ret = knot_rrset_deep_copy_no_sig(soa, &soa_end);
if (ret != KNOT_EOK) {
dbg_ddns("Failed to copy ending SOA: %s\n",
......
......@@ -70,7 +70,7 @@ int knot_ddns_process_update(knot_zone_contents_t *zone,
const knot_packet_t *query,
knot_changeset_t *changeset,
knot_changes_t *changes,
knot_rcode_t *rcode);
knot_rcode_t *rcode, uint32_t new_serial);
void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment