Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (2)
......@@ -184,6 +184,12 @@ will be held up until the zone is thawed. (#)
\fBzone\-thaw\fP [\fIzone\fP\&...]
Trigger dismissal of zone freeze. (#)
.TP
\fBzone\-xfr\-freeze\fP [\fIzone\fP\&...]
Temporarily disable outgoing AXFR/IXFR for the zone(s). (#)
.TP
\fBzone\-xfr\-thaw\fP [\fIzone\fP\&...]
Dismiss outgoing XFR freeze. (#)
.TP
\fBzone\-read\fP \fIzone\fP [\fIowner\fP [\fItype\fP]]
Get zone data that are currently being presented.
.TP
......
......@@ -161,6 +161,12 @@ Actions
**zone-thaw** [*zone*...]
Trigger dismissal of zone freeze. (#)
**zone-xfr-freeze** [*zone*...]
Temporarily disable outgoing AXFR/IXFR for the zone(s). (#)
**zone-xfr-thaw** [*zone*...]
Dismiss outgoing XFR freeze. (#)
**zone-read** *zone* [*owner* [*type*]]
Get zone data that are currently being presented.
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -635,6 +635,24 @@ static int zone_thaw(zone_t *zone, _unused_ ctl_args_t *args)
return schedule_trigger(zone, args, ZONE_EVENT_UTHAW, false);
}
static int zone_xfr_freeze(zone_t *zone, _unused_ ctl_args_t *args)
{
zone_set_flag(zone, ZONE_XFR_FROZEN);
log_zone_info(zone->name, "outgoing XFR frozen");
return KNOT_EOK;
}
static int zone_xfr_thaw(zone_t *zone, _unused_ ctl_args_t *args)
{
zone_unset_flag(zone, ZONE_XFR_FROZEN);
log_zone_info(zone->name, "outgoing XFR unfrozen");
return KNOT_EOK;
}
static int zone_txn_begin(zone_t *zone, _unused_ ctl_args_t *args)
{
if (zone->control_update != NULL) {
......@@ -1567,6 +1585,10 @@ static int ctl_zone(ctl_args_t *args, ctl_cmd_t cmd)
return zones_apply(args, zone_freeze);
case CTL_ZONE_THAW:
return zones_apply(args, zone_thaw);
case CTL_ZONE_XFR_FREEZE:
return zones_apply(args, zone_xfr_freeze);
case CTL_ZONE_XFR_THAW:
return zones_apply(args, zone_xfr_thaw);
case CTL_ZONE_READ:
return zones_apply(args, zone_read);
case CTL_ZONE_BEGIN:
......@@ -2009,6 +2031,8 @@ static const desc_t cmd_table[] = {
[CTL_ZONE_KSK_SBM] = { "zone-ksk-submitted", ctl_zone },
[CTL_ZONE_FREEZE] = { "zone-freeze", ctl_zone },
[CTL_ZONE_THAW] = { "zone-thaw", ctl_zone },
[CTL_ZONE_XFR_FREEZE] = { "zone-xfr-freeze", ctl_zone },
[CTL_ZONE_XFR_THAW] = { "zone-xfr-thaw", ctl_zone },
[CTL_ZONE_READ] = { "zone-read", ctl_zone },
[CTL_ZONE_BEGIN] = { "zone-begin", ctl_zone },
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -74,6 +74,8 @@ typedef enum {
CTL_ZONE_KSK_SBM,
CTL_ZONE_FREEZE,
CTL_ZONE_THAW,
CTL_ZONE_XFR_FREEZE,
CTL_ZONE_XFR_THAW,
CTL_ZONE_READ,
CTL_ZONE_BEGIN,
......
......@@ -35,7 +35,7 @@
false, fmt)
static void init_qdata_from_request(knotd_qdata_t *qdata,
const zone_t *zone,
zone_t *zone,
knot_request_t *req,
knotd_qdata_params_t *params,
knotd_qdata_extra_t *extra)
......@@ -312,7 +312,7 @@ static void forward_requests(conf_t *conf, zone_t *zone, list_t *requests)
}
}
static void send_update_response(conf_t *conf, const zone_t *zone, knot_request_t *req)
static void send_update_response(conf_t *conf, zone_t *zone, knot_request_t *req)
{
if (req->resp) {
if (!zone_is_slave(conf, zone)) {
......@@ -343,7 +343,7 @@ static void free_request(knot_request_t *req)
free(req);
}
static void send_update_responses(conf_t *conf, const zone_t *zone, list_t *updates)
static void send_update_responses(conf_t *conf, zone_t *zone, list_t *updates)
{
ptrnode_t *node, *nxt;
WALK_LIST_DELSAFE(node, nxt, *updates) {
......
......@@ -129,6 +129,12 @@ static int axfr_query_init(knotd_qdata_t *qdata)
}
}
if (zone_get_flag(qdata->extra->zone, ZONE_XFR_FROZEN, false)) {
qdata->rcode = KNOT_RCODE_REFUSED;
qdata->rcode_ede = KNOT_EDNS_EDE_NOT_READY;
return KNOT_EAGAIN;
}
/* Create transfer processing context. */
knot_mm_t *mm = qdata->mm;
struct axfr_proc *axfr = mm_alloc(mm, sizeof(struct axfr_proc));
......@@ -186,6 +192,9 @@ int axfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
case KNOT_EMALF: /* Malformed query. */
AXFROUT_LOG(LOG_DEBUG, qdata, "malformed query");
return KNOT_STATE_FAIL;
case KNOT_EAGAIN: /* Outgoing AXFR temporarily disabled. */
AXFROUT_LOG(LOG_INFO, qdata, "outgoing AXFR frozen");
return KNOT_STATE_FAIL;
default:
AXFROUT_LOG(LOG_ERR, qdata, "failed to start (%s)",
knot_strerror(ret));
......
......@@ -173,6 +173,12 @@ static int ixfr_answer_init(knotd_qdata_t *qdata, uint32_t *serial_from)
}
}
if (zone_get_flag(qdata->extra->zone, ZONE_XFR_FROZEN, false)) {
qdata->rcode = KNOT_RCODE_REFUSED;
qdata->rcode_ede = KNOT_EDNS_EDE_NOT_READY;
return KNOT_EAGAIN;
}
const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
*serial_from = knot_soa_serial(their_soa->rrs.rdata);
......@@ -278,6 +284,9 @@ int ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
case KNOT_EMALF: /* Malformed query. */
IXFROUT_LOG(LOG_DEBUG, qdata, "malformed query");
return KNOT_STATE_FAIL;
case KNOT_EAGAIN: /* Outgoing IXFR temporarily disabled. */
IXFROUT_LOG(LOG_INFO, qdata, "outgoing IXFR frozen");
return KNOT_STATE_FAIL;
default: /* Server errors. */
IXFROUT_LOG(LOG_ERR, qdata, "failed to start (%s)",
knot_strerror(ret));
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -182,12 +182,12 @@ static int query_chaos(knot_pkt_t *pkt, knot_layer_t *ctx)
}
/*! \brief Find zone for given question. */
static const zone_t *answer_zone_find(const knot_pkt_t *query, knot_zonedb_t *zonedb)
static zone_t *answer_zone_find(const knot_pkt_t *query, knot_zonedb_t *zonedb)
{
uint16_t qtype = knot_pkt_qtype(query);
uint16_t qclass = knot_pkt_qclass(query);
const knot_dname_t *qname = knot_pkt_qname(query);
const zone_t *zone = NULL;
zone_t *zone = NULL;
// search for zone only for IN and ANY classes
if (qclass != KNOT_CLASS_IN && qclass != KNOT_CLASS_ANY) {
......
/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -26,7 +26,7 @@ const knot_layer_api_t *process_query_layer(void);
/*! \brief Query processing intermediate data. */
typedef struct knotd_qdata_extra {
const zone_t *zone; /*!< Zone from which is answered. */
zone_t *zone; /*!< Zone from which is answered. */
const zone_contents_t *contents; /*!< Zone contents from which is answered. */
list_t wildcards; /*!< Visited wildcards. */
list_t rrsigs; /*!< Section RRSIGs. */
......
......@@ -410,14 +410,14 @@ void zone_clear_preferred_master(zone_t *zone)
pthread_mutex_unlock(&zone->preferred_lock);
}
void zone_set_flag(zone_t *zone, zone_flag_t flag)
static void set_flag(zone_t *zone, zone_flag_t flag, bool remove)
{
if (zone == NULL) {
return;
}
pthread_mutex_lock(&zone->preferred_lock); // this mutex seems OK to be reused for this
zone->flags |= flag;
zone->flags = remove ? (zone->flags & ~flag) : (zone->flags | flag);
pthread_mutex_unlock(&zone->preferred_lock);
if (flag & ZONE_IS_CATALOG) {
......@@ -425,6 +425,16 @@ void zone_set_flag(zone_t *zone, zone_flag_t flag)
}
}
void zone_set_flag(zone_t *zone, zone_flag_t flag)
{
return set_flag(zone, flag, false);
}
void zone_unset_flag(zone_t *zone, zone_flag_t flag)
{
return set_flag(zone, flag, true);
}
zone_flag_t zone_get_flag(zone_t *zone, zone_flag_t flag, bool clear)
{
if (zone == NULL) {
......
......@@ -43,6 +43,7 @@ typedef enum {
ZONE_FORCE_ZSK_ROLL = 1 << 4, /*!< Force ZSK rollover. */
ZONE_IS_CATALOG = 1 << 5, /*!< This is a catalog. */
ZONE_IS_CAT_MEMBER = 1 << 6, /*!< This zone exists according to a catalog. */
ZONE_XFR_FROZEN = 1 << 7, /*!< Outgoing AXFR/IXFR temporarily disabled. */
} zone_flag_t;
/*!
......@@ -180,6 +181,9 @@ void zone_clear_preferred_master(zone_t *zone);
/*! \brief Sets a zone flag. */
void zone_set_flag(zone_t *zone, zone_flag_t flag);
/*! \brief Unsets a zone flag. */
void zone_unset_flag(zone_t *zone, zone_flag_t flag);
/*! \brief Returns if a flag is set (and optionally clears it). */
zone_flag_t zone_get_flag(zone_t *zone, zone_flag_t flag, bool clear);
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -54,6 +54,8 @@
#define CMD_ZONE_KSK_SBM "zone-ksk-submitted"
#define CMD_ZONE_FREEZE "zone-freeze"
#define CMD_ZONE_THAW "zone-thaw"
#define CMD_ZONE_XFR_FREEZE "zone-xfr-freeze"
#define CMD_ZONE_XFR_THAW "zone-xfr-thaw"
#define CMD_ZONE_READ "zone-read"
#define CMD_ZONE_BEGIN "zone-begin"
......@@ -380,6 +382,8 @@ static void format_block(ctl_cmd_t cmd, bool failed, bool empty)
case CTL_ZONE_KSK_SBM:
case CTL_ZONE_FREEZE:
case CTL_ZONE_THAW:
case CTL_ZONE_XFR_FREEZE:
case CTL_ZONE_XFR_THAW:
case CTL_ZONE_BEGIN:
case CTL_ZONE_COMMIT:
case CTL_ZONE_ABORT:
......@@ -1186,6 +1190,8 @@ const cmd_desc_t cmd_table[] = {
{ CMD_ZONE_KSK_SBM, cmd_zone_ctl, CTL_ZONE_KSK_SBM, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
{ CMD_ZONE_FREEZE, cmd_zone_ctl, CTL_ZONE_FREEZE, CMD_FOPT_ZONE },
{ CMD_ZONE_THAW, cmd_zone_ctl, CTL_ZONE_THAW, CMD_FOPT_ZONE },
{ CMD_ZONE_XFR_FREEZE, cmd_zone_ctl, CTL_ZONE_XFR_FREEZE, CMD_FOPT_ZONE },
{ CMD_ZONE_XFR_THAW, cmd_zone_ctl, CTL_ZONE_XFR_THAW, CMD_FOPT_ZONE },
{ CMD_ZONE_READ, cmd_zone_node_ctl, CTL_ZONE_READ, CMD_FREQ_ZONE },
{ CMD_ZONE_BEGIN, cmd_zone_ctl, CTL_ZONE_BEGIN, CMD_FREQ_ZONE | CMD_FOPT_ZONE },
......@@ -1236,6 +1242,8 @@ static const cmd_help_t cmd_help_table[] = {
{ CMD_ZONE_KSK_SBM, " <zone>...", "When KSK submission, confirm parent's DS presence. (#)" },
{ CMD_ZONE_FREEZE, "[<zone>...]", "Temporarily postpone automatic zone-changing events. (#)" },
{ CMD_ZONE_THAW, "[<zone>...]", "Dismiss zone freeze. (#)" },
{ CMD_ZONE_XFR_FREEZE, "[<zone>...]", "Temporarily disable outgoing AXFR/IXFR. (#)" },
{ CMD_ZONE_XFR_THAW, "[<zone>...]", "Dismiss outgoing XFR freeze. (#)" },
{ "", "", "" },
{ CMD_ZONE_READ, "<zone> [<owner> [<type>]]", "Get zone data that are currently being presented." },
{ CMD_ZONE_BEGIN, "<zone>...", "Begin a zone transaction." },
......
#!/usr/bin/env python3
'''Test of IXFR freeze.'''
from dnstest.test import Test
t = Test()
master = t.server("knot")
slave = t.server("knot")
zone = t.zone_rnd(1, records=50)
t.link(zone, master, slave)
t.start()
serial_init = master.zone_wait(zone)
slave.zone_wait(zone)
master.ctl("zone-xfr-freeze", wait=True)
master.random_ddns(zone, allow_empty=False)
t.sleep(4)
resp = master.dig(zone[0].name, "AXFR", tries=1)
resp.check_xfr(rcode="REFUSED")
resp = slave.dig(zone[0].name, "SOA")
serial = resp.soa_serial()
if serial != serial_init:
set_err("SOA serial mismatch")
detail_log("SOA serial mismatch %d != %d" % (serial, serial_init))
master.ctl("zone-xfr-thaw", wait=True)
master.ctl("zone-notify")
slave.zone_wait(zone, serial_init)
t.xfr_diff(master, slave, zone)
t.end()
......@@ -287,19 +287,19 @@ class ZoneFile(object):
changes = 0
with open(self.path, 'r') as file:
for fline in file:
line = fline.split(None, 3)
line = fline.split(None, 4)
if len(line) < 3:
continue
if line[0][0] not in [";", "@"]:
dname = line[0]
ttl = 0
if line[1].isnumeric():
ttl = line[1]
rtype = line[2]
rdata = ' '.join(line[3:])
else:
ttl = 0
rtype = line[1]
rdata = ' '.join(line[2:])
del line[1]
if line[1] == "IN":
del line[1]
rtype = line[1]
rdata = ' '.join(line[2:])
if rtype not in ["SOA", "RRSIG", "DNSKEY", "DS", "CDS", "CDNSKEY", "NSEC", "NSEC3", "NSEC3PARAM"]:
try:
if random.randint(1, 20) in [4, 5]:
......