Skip to content
Snippets Groups Projects
Commit 97be03b5 authored by Daniel Salzman's avatar Daniel Salzman
Browse files

knsupdate: fix prerequisite support

parent 441881a6
No related branches found
No related tags found
1 merge request!265Knsupdate prereq
......@@ -87,6 +87,20 @@ Specifies TSIG key to authenticate the request. This command has the same
semantics as the program option \fB\-y\fR, except that the MAC algorithm
cannot be set.
.TP
[\fBprereq\fR] \fBnxdomain\fR \fIname\fR
Adds a prerequisite for non-existing record owned by \fIname\fR.
.TP
[\fBprereq\fR] \fByxdomain\fR \fIname\fR
Adds a prerequisite for existing record owned by \fIname\fR.
.TP
[\fBprereq\fR] \fBnxrrset\fR \fIname\fR [\fIclass\fR] \fItype\fR
Adds a prerequisite for non-existing record of the \fItype\fR owned by \fIname\fR.
Internet class is expected.
.TP
[\fBprereq\fR] \fByxrrset\fR \fIname\fR [\fIclass\fR] \fItype\fR [\fIdata\fR]
Adds a prerequisite for existing record of the \fItype\fR owned by \fIname\fR
with optional \fIdata\fR. Internet class is expected.
.TP
[\fBupdate\fR] \fBadd\fR \fIname\fR [\fIttl\fR] [\fIclass\fR] \fItype\fR \fIdata\fR
Adds a request to add a new resource record into the zone. Please note that if the
\fIname\fR is not fully qualified domain name, current \fIorigin\fR name is appended to it.
......@@ -111,7 +125,7 @@ Enable debugging. This command has the same meaning as program option \fB\-d\fR.
.SS Missing features with regard to ISC nsupdate
Options \fB\-D\fR, \fB\-g\fR, \fB\-o\fR, \fB\-l\fR, \fB\-L\fR, \fB\-R\fR, \fB\-u\fR.
.TP
Commands: \fBgsstsig\fR, \fBoldgsstsig\fR, \fBrealm\fR, \fBprereq\fR (\fBnxdomain\fR, \fByxdomain\fR, \fBnxrrset\fR, \fByxrrset\fR).
Commands: \fBgsstsig\fR, \fBoldgsstsig\fR, \fBrealm\fR.
.SS Differences with regard to ISC nsupdate
Zone name/server guessing, if the zone name/server is not specified.
.TP 0
......
......@@ -60,7 +60,6 @@ const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT = {
.empty_ttl = false,
.human_ttl = false,
.human_tmstamp = true,
.empty_rdata = false,
.ascii_to_idn = NULL
};
......@@ -1799,7 +1798,7 @@ int knot_rrset_txt_dump_data(const knot_rrset_t *rrset,
int ret = 0;
if (data_len == 0 && style->empty_rdata) {
if (data_len == 0 && rrset->rclass != KNOT_CLASS_IN) {
return ret;
}
......
......@@ -46,8 +46,6 @@ typedef struct {
bool human_ttl;
/*!< Format timestamp as YYYYMMDDHHmmSS. */
bool human_tmstamp;
/*!< Allow empty rdata for all types (DDNS). */
bool empty_rdata;
/*!< ASCII string to IDN string transformation callback. */
void (*ascii_to_idn)(char **name);
} knot_dump_style_t;
......
......@@ -55,7 +55,6 @@ static const style_t DEFAULT_STYLE_DIG = {
.empty_ttl = false,
.human_ttl = false,
.human_tmstamp = true,
.empty_rdata = false,
.ascii_to_idn = name_to_idn
},
.show_query = false,
......
......@@ -43,7 +43,6 @@ static const style_t DEFAULT_STYLE_HOST = {
.empty_ttl = false,
.human_ttl = false,
.human_tmstamp = true,
.empty_rdata = false,
.ascii_to_idn = name_to_idn
},
.show_query = false,
......
......@@ -46,6 +46,8 @@ int cmd_del(const char* lp, nsupdate_params_t *params);
int cmd_gsstsig(const char* lp, nsupdate_params_t *params);
int cmd_key(const char* lp, nsupdate_params_t *params);
int cmd_local(const char* lp, nsupdate_params_t *params);
int cmd_nxdomain(const char *lp, nsupdate_params_t *params);
int cmd_nxrrset(const char *lp, nsupdate_params_t *params);
int cmd_oldgsstsig(const char* lp, nsupdate_params_t *params);
int cmd_origin(const char* lp, nsupdate_params_t *params);
int cmd_prereq(const char* lp, nsupdate_params_t *params);
......@@ -55,6 +57,8 @@ int cmd_server(const char* lp, nsupdate_params_t *params);
int cmd_show(const char* lp, nsupdate_params_t *params);
int cmd_ttl(const char* lp, nsupdate_params_t *params);
int cmd_update(const char* lp, nsupdate_params_t *params);
int cmd_yxdomain(const char *lp, nsupdate_params_t *params);
int cmd_yxrrset(const char *lp, nsupdate_params_t *params);
int cmd_zone(const char* lp, nsupdate_params_t *params);
/* Sorted list of commands.
......@@ -71,6 +75,8 @@ const char* cmd_array[] = {
"\x7" "gsstsig",
"\x3" "key", /* {name} {secret} */
"\x5" "local", /* {address} [port] */
"\x8" "nxdomain",
"\x7" "nxrrset",
"\xa" "oldgsstsig",
"\x6" "origin", /* {name} */
"\x6" "prereq", /* (nx|yx)(domain|rrset) {domain-name} ... */
......@@ -80,6 +86,8 @@ const char* cmd_array[] = {
"\x4" "show",
"\x3" "ttl", /* {seconds} */
"\x6" "update", /* (add|delete) {domain-name} ... */
"\x8" "yxdomain",
"\x7" "yxrrset",
"\x4" "zone", /* {zonename} */
NULL
};
......@@ -94,6 +102,8 @@ cmd_handle_f cmd_handle[] = {
cmd_gsstsig,
cmd_key,
cmd_local,
cmd_nxdomain,
cmd_nxrrset,
cmd_oldgsstsig,
cmd_origin,
cmd_prereq,
......@@ -103,6 +113,8 @@ cmd_handle_f cmd_handle[] = {
cmd_show,
cmd_ttl,
cmd_update,
cmd_yxdomain,
cmd_yxrrset,
cmd_zone,
};
......@@ -127,17 +139,18 @@ enum {
/* RR parser flags */
enum {
PARSE_NODEFAULT = 1 << 0, /* Do not fill defaults. */
PARSE_NAMEONLY = 1 << 1 /* Parse only name. */
PARSE_NAMEONLY = 1 << 1, /* Parse only name. */
PARSE_NOTTL = 1 << 2 /* Ignore TTL item. */
};
static int dname_isvalid(const char *lp, size_t len)
static bool dname_isvalid(const char *lp)
{
knot_dname_t *dn = knot_dname_from_str(lp);
if (dn == NULL) {
return 0;
return false;
}
knot_dname_free(&dn, NULL);
return 1;
return true;
}
/* This is probably redundant, but should be a bit faster so let's keep it. */
......@@ -206,6 +219,9 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags)
/* Parse only name? */
if (flags & PARSE_NAMEONLY) {
if (*lp != '\0') {
WARN("ignoring input data: '%s'\n", lp);
}
return KNOT_EOK;
}
......@@ -213,8 +229,12 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags)
char *np = NULL;
long ttl = strtol(lp, &np, 10);
if (ttl >= 0 && np && (*np == '\0' || isspace((unsigned char)(*np)))) {
s->r_ttl = ttl;
DBG("%s: parsed ttl=%lu\n", __func__, ttl);
if (flags & PARSE_NOTTL) {
WARN("ignoring TTL value: '%ld'\n", ttl);
} else {
s->r_ttl = ttl;
}
lp = tok_skipspace(np);
}
......@@ -264,7 +284,7 @@ static int parse_partial_rr(zs_scanner_t *s, const char *lp, unsigned flags)
}
/* Need to parse rdata, synthetize input. */
char *rr = sprintf_alloc(" %u %s %s\n", s->r_ttl, type, lp);
char *rr = sprintf_alloc(" %u IN %s %s\n", s->r_ttl, type, lp);
free(cls);
free(type);
if (rr == NULL || zs_scanner_parse(s, rr, rr + strlen(rr), true) < 0) {
......@@ -348,7 +368,8 @@ static int rr_list_to_packet(knot_pkt_t *dst, list_t *list)
int ret = KNOT_EOK;
ptrnode_t *node = NULL;
WALK_LIST(node, *list) {
ret = knot_pkt_put(dst, COMPR_HINT_NONE, (knot_rrset_t *)node->d, 0);
ret = knot_pkt_put(dst, COMPR_HINT_NONE,
(knot_rrset_t *)node->d, 0);
if (ret != KNOT_EOK) {
break;
}
......@@ -368,7 +389,8 @@ static int build_query(nsupdate_params_t *params)
knot_wire_set_id(query->wire, knot_random_uint16_t());
knot_wire_set_opcode(query->wire, KNOT_OPCODE_UPDATE);
knot_dname_t *qname = knot_dname_from_str(params->zone);
int ret = knot_pkt_put_question(query, qname, params->class_num, params->type_num);
int ret = knot_pkt_put_question(query, qname, params->class_num,
params->type_num);
knot_dname_free(&qname, NULL);
if (ret != KNOT_EOK) {
return ret;
......@@ -585,8 +607,7 @@ int cmd_class(const char* lp, nsupdate_params_t *params)
return KNOT_EPARSEFAIL;
} else {
params->class_num = cls;
zs_scanner_t *s = params->parser;
s->default_class = params->class_num;
params->parser->default_class = params->class_num;
}
return KNOT_EOK;
......@@ -614,9 +635,8 @@ int cmd_debug(const char* lp, nsupdate_params_t *params)
return KNOT_EOK;
}
int cmd_prereq_domain(const char *lp, nsupdate_params_t *params, unsigned type)
int cmd_nxdomain(const char *lp, nsupdate_params_t *params)
{
UNUSED(type);
DBG("%s: lp='%s'\n", __func__, lp);
zs_scanner_t *s = params->parser;
......@@ -625,26 +645,74 @@ int cmd_prereq_domain(const char *lp, nsupdate_params_t *params, unsigned type)
return ret;
}
return ret;
s->r_ttl = 0;
s->r_class = KNOT_CLASS_NONE;
return rr_list_append(s, &params->prereq_list, &params->mm);
}
int cmd_prereq_rrset(const char *lp, nsupdate_params_t *params, unsigned type)
int cmd_yxdomain(const char *lp, nsupdate_params_t *params)
{
UNUSED(type);
DBG("%s: lp='%s'\n", __func__, lp);
zs_scanner_t *rrp = params->parser;
if (parse_partial_rr(rrp, lp, 0) != KNOT_EOK) {
zs_scanner_t *s = params->parser;
int ret = parse_partial_rr(s, lp, PARSE_NODEFAULT|PARSE_NAMEONLY);
if (ret != KNOT_EOK) {
return ret;
}
s->r_ttl = 0;
s->r_class = KNOT_CLASS_ANY;
return rr_list_append(s, &params->prereq_list, &params->mm);
}
int cmd_nxrrset(const char *lp, nsupdate_params_t *params)
{
DBG("%s: lp='%s'\n", __func__, lp);
zs_scanner_t *s = params->parser;
int ret = parse_partial_rr(s, lp, PARSE_NOTTL);
if (ret != KNOT_EOK) {
return KNOT_EPARSEFAIL;
}
/* Check owner name. */
if (rrp->r_owner_length == 0) {
if (s->r_owner_length == 0) {
ERR("failed to parse prereq owner name '%s'\n", lp);
return KNOT_EPARSEFAIL;
}
return KNOT_EOK;
s->r_ttl = 0;
s->r_class = KNOT_CLASS_NONE;
return rr_list_append(s, &params->prereq_list, &params->mm);
}
int cmd_yxrrset(const char *lp, nsupdate_params_t *params)
{
DBG("%s: lp='%s'\n", __func__, lp);
zs_scanner_t *s = params->parser;
int ret = parse_partial_rr(s, lp, PARSE_NOTTL);
if (ret != KNOT_EOK) {
return KNOT_EPARSEFAIL;
}
/* Check owner name. */
if (s->r_owner_length == 0) {
ERR("failed to parse prereq owner name '%s'\n", lp);
return KNOT_EPARSEFAIL;
}
s->r_ttl = 0;
if (s->r_data_length > 0) {
s->r_class = KNOT_CLASS_IN;
} else {
s->r_class = KNOT_CLASS_ANY;
}
return rr_list_append(s, &params->prereq_list, &params->mm);
}
int cmd_prereq(const char* lp, nsupdate_params_t *params)
......@@ -659,31 +727,22 @@ int cmd_prereq(const char* lp, nsupdate_params_t *params)
const char *tok = pq_array[prereq_type];
DBG("%s: type %s\n", __func__, TOK_S(tok));
lp = tok_skipspace(lp + TOK_L(tok));
switch(prereq_type) {
case PQ_NXDOMAIN:
ret = cmd_nxdomain(lp, params);
break;
case PQ_YXDOMAIN:
ret = cmd_prereq_domain(lp, params, prereq_type);
ret = cmd_yxdomain(lp, params);
break;
case PQ_NXRRSET:
ret = cmd_nxrrset(lp, params);
break;
case PQ_YXRRSET:
ret = cmd_prereq_rrset(lp, params, prereq_type);
ret = cmd_yxrrset(lp, params);
break;
default:
return KNOT_ERROR;
}
/* Append to packet. */
if (ret == KNOT_EOK) {
zs_scanner_t *s = params->parser;
s->r_ttl = 0; /* Set TTL = 0 for prereq. */
/* YX{RRSET,DOMAIN} - cls ANY */
if (prereq_type == PQ_YXRRSET || prereq_type == PQ_YXDOMAIN) {
s->r_class = KNOT_CLASS_ANY;
} else { /* NX{RRSET,DOMAIN} - cls NONE */
s->r_class = KNOT_CLASS_NONE;
}
ret = rr_list_append(s, &params->prereq_list, &params->mm);
ret = KNOT_ERROR;
}
return ret;
......@@ -767,14 +826,13 @@ int cmd_zone(const char* lp, nsupdate_params_t *params)
DBG("%s: lp='%s'\n", __func__, lp);
/* Check zone name. */
size_t len = strcspn(lp, SEP_CHARS);
if (!dname_isvalid(lp, len)) {
if (!dname_isvalid(lp)) {
ERR("failed to parse zone '%s'\n", lp);
return KNOT_EPARSEFAIL;
}
free(params->zone);
params->zone = strndup(lp, len);
params->zone = strdup(lp);
return KNOT_EOK;
}
......@@ -864,19 +922,12 @@ int cmd_origin(const char* lp, nsupdate_params_t *params)
DBG("%s: lp='%s'\n", __func__, lp);
/* Check zone name. */
size_t len = strcspn(lp, SEP_CHARS);
if (!dname_isvalid(lp, len)) {
if (!dname_isvalid(lp)) {
ERR("failed to parse zone '%s'\n", lp);
return KNOT_EPARSEFAIL;
}
char *name = strndup(lp, len);
int ret = nsupdate_set_origin(params, name);
free(name);
return ret;
return nsupdate_set_origin(params, lp);
}
/*
......
......@@ -42,7 +42,6 @@ static const style_t DEFAULT_STYLE_NSUPDATE = {
.empty_ttl = false,
.human_ttl = false,
.human_tmstamp = true,
.empty_rdata = true,
.ascii_to_idn = NULL
},
.show_query = false,
......
zone example.com
ttl 60
origin example.com
server 127.0.0.1
;
prereq nxdomain nxdomain_test1
nxdomain nxdomain_test2
;
prereq yxdomain yxdomain_test1
yxdomain yxdomain_test2
;
prereq nxrrset nxrrset_test1 A
nxrrset nxrrset_test2 IN A
;
prereq yxrrset yxrrset_test1 A
yxrrset yxrrset_test2 IN A
;
prereq yxrrset yxrrset_test3 A 1.2.3.4
yxrrset yxrrset_test4 IN A 1.2.3.4
;
update add add_test1 120 TXT "test"
add add_test2 TXT "test"
add add_test3 IN TXT "test"
;
update delete del_test1 120
del del_test2
del del_test3 IN
del del_test4 IN AAAA
del del_test5 AAAA
del del_test6 IN AAAA ::1
del del_test7 TXT "test"
;
show
;send
zone example.com.
ttl 60
server 127.0.0.1
;
prereq nxdomain nxdomain_test1.example.com.
nxdomain nxdomain_test2.example.com.
;
prereq yxdomain yxdomain_test1.example.com.
yxdomain yxdomain_test2.example.com.
;
prereq nxrrset nxrrset_test1.example.com. A
nxrrset nxrrset_test2.example.com. IN A
;
prereq yxrrset yxrrset_test1.example.com. A
yxrrset yxrrset_test2.example.com. IN A
;
prereq yxrrset yxrrset_test3.example.com. A 1.2.3.4
yxrrset yxrrset_test4.example.com. IN A 1.2.3.4
;
update add add_test1.example.com. 120 TXT "test"
add add_test2.example.com. TXT "test"
add add_test3.example.com. IN TXT "test"
;
update delete del_test1.example.com. 120
del del_test2.example.com.
del del_test3.example.com. IN
del del_test4.example.com. IN AAAA
del del_test5.example.com. AAAA
del del_test6.example.com. IN AAAA ::1
del del_test7.example.com. TXT "test"
;
show
;send
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment