Commit fedd6b0b authored by Daniel Salzman's avatar Daniel Salzman

kdig: allow optional SOA serial with NOTIFY query

parent 31e5b70f
......@@ -98,9 +98,10 @@ port is 53.
Set query name. An explicit variant of \fIname\fP specification.
.TP
\fB\-t\fP \fItype\fP
Set query type (e.g. NS, IXFR=12345, TYPE65535). An explicit variant of
\fItype\fP specification. The default type is A. It is also possible to use
NOTIFY parameter to send a notify message.
Set query type (e.g. NS, IXFR=12345, TYPE65535, NOTIFY). An explicit variant of
\fItype\fP specification. The default type is A. IXFR type requires SOA serial
parameter. NOTIFY type without SOA serial parameter causes pure NOTIFY message
without any SOA hint.
.TP
\fB\-v\fP, \fB\-\-version\fP
Print program version.
......
......@@ -75,9 +75,10 @@ Options
Set query name. An explicit variant of *name* specification.
**-t** *type*
Set query type (e.g. NS, IXFR=12345, TYPE65535). An explicit variant of
*type* specification. The default type is A. It is also possible to use
NOTIFY parameter to send a notify message.
Set query type (e.g. NS, IXFR=12345, TYPE65535, NOTIFY). An explicit variant of
*type* specification. The default type is A. IXFR type requires SOA serial
parameter. NOTIFY type without SOA serial parameter causes pure NOTIFY message
without any SOA hint.
**-v**, **--version**
Print program version.
......
......@@ -242,10 +242,10 @@ int params_parse_class(const char *value, uint16_t *rclass)
}
}
int params_parse_type(const char *value, uint16_t *rtype, uint32_t *xfr_serial,
int params_parse_type(const char *value, uint16_t *rtype, int64_t *serial,
bool *notify)
{
if (value == NULL || rtype == NULL || xfr_serial == NULL) {
if (value == NULL || rtype == NULL || serial == NULL) {
DBG_NULL;
return KNOT_EINVAL;
}
......@@ -274,24 +274,26 @@ int params_parse_type(const char *value, uint16_t *rtype, uint32_t *xfr_serial,
if (*rtype == KNOT_RRTYPE_IXFR) {
DBG("SOA serial is required for IXFR query\n");
return KNOT_EINVAL;
} else {
*serial = -1;
}
} else {
// Additional parameter is accepted for IXFR only.
if (*rtype == KNOT_RRTYPE_IXFR) {
// Additional parameter is accepted for IXFR or NOTIFY.
if (*rtype == KNOT_RRTYPE_IXFR || *notify) {
const char *param_str = value + 1 + param_pos;
char *end;
// Convert string to serial.
unsigned long long serial = strtoull(param_str, &end, 10);
unsigned long long num = strtoull(param_str, &end, 10);
// Check for bad serial string.
if (end == param_str || *end != '\0' ||
serial > UINT32_MAX) {
num > UINT32_MAX) {
DBG("bad SOA serial %s\n", param_str);
return KNOT_EINVAL;
}
*xfr_serial = serial;
*serial = num;
} else {
DBG("unsupported parameter in query type '%s'\n", value);
return KNOT_EINVAL;
......
......@@ -155,7 +155,7 @@ char* get_fqd_name(const char *name);
int params_parse_class(const char *value, uint16_t *rclass);
int params_parse_type(const char *value, uint16_t *rtype, uint32_t *xfr_serial,
int params_parse_type(const char *value, uint16_t *rtype, int64_t *serial,
bool *notify);
int params_parse_server(const char *value, list_t *servers, const char *def_port);
......
......@@ -335,11 +335,14 @@ static knot_pkt_t* create_query_packet(const query_t *query)
return NULL;
}
// Begin authority section
knot_pkt_begin(packet, KNOT_AUTHORITY);
// For IXFR query or NOTIFY query with SOA serial, add a proper section.
if (query->serial >= 0) {
if (query->notify) {
knot_pkt_begin(packet, KNOT_ANSWER);
} else {
knot_pkt_begin(packet, KNOT_AUTHORITY);
}
// For IXFR query add authority section.
if (query->type_num == KNOT_RRTYPE_IXFR) {
// SOA rdata in wireformat.
uint8_t wire[22] = { 0x0 };
......@@ -364,7 +367,7 @@ static knot_pkt_t* create_query_packet(const query_t *query)
}
// Set SOA serial.
knot_soa_serial_set(&soa->rrs, query->xfr_serial);
knot_soa_serial_set(&soa->rrs, query->serial);
ret = knot_pkt_put(packet, 0, soa, KNOT_PF_FREE);
if (ret != KNOT_EOK) {
......
......@@ -866,13 +866,14 @@ query_t* query_create(const char *owner, const query_t *conf)
query->servfail_stop = true;
query->class_num = -1;
query->type_num = -1;
query->xfr_serial = 0;
query->serial = -1;
query->notify = false;
query->flags = DEFAULT_FLAGS_DIG;
query->style = DEFAULT_STYLE_DIG;
query->idn = true;
query->nsid = false;
query->edns = -1;
//query->tsig_key
query->subnet = NULL;
#if USE_DNSTAP
query->dt_reader = NULL;
......@@ -901,13 +902,22 @@ query_t* query_create(const char *owner, const query_t *conf)
query->servfail_stop = conf->servfail_stop;
query->class_num = conf->class_num;
query->type_num = conf->type_num;
query->xfr_serial = conf->xfr_serial;
query->serial = conf->serial;
query->notify = conf->notify;
query->flags = conf->flags;
query->style = conf->style;
query->idn = conf->idn;
query->nsid = conf->nsid;
query->edns = conf->edns;
if (conf->tsig_key.name != NULL) {
int ret = knot_tsig_key_copy(&query->tsig_key,
&conf->tsig_key);
if (ret != KNOT_EOK) {
query_free(query);
return NULL;
}
}
if (conf->subnet != NULL) {
query->subnet = malloc(sizeof(subnet_t));
if (query->subnet == NULL) {
......@@ -922,16 +932,6 @@ query_t* query_create(const char *owner, const query_t *conf)
query->dt_reader = conf->dt_reader;
query->dt_writer = conf->dt_writer;
#endif // USE_DNSTAP
if (conf->tsig_key.name) {
int ret = knot_tsig_key_copy(&query->tsig_key,
&conf->tsig_key);
if (ret != KNOT_EOK) {
query_free(query);
return NULL;
}
}
}
// Check dynamic allocation.
......@@ -1184,7 +1184,7 @@ static int parse_tsig(const char *value, query_t *query)
static int parse_type(const char *value, query_t *query)
{
uint16_t rtype;
uint32_t serial;
int64_t serial;
bool notify;
if (params_parse_type(value, &rtype, &serial, &notify) != KNOT_EOK) {
......@@ -1192,7 +1192,7 @@ static int parse_type(const char *value, query_t *query)
}
query->type_num = rtype;
query->xfr_serial = serial;
query->serial = serial;
query->notify = notify;
// If NOTIFY, reset default RD flag.
......@@ -1328,7 +1328,7 @@ void complete_queries(list_t *queries, const query_t *conf)
if (q->type_num < 0) {
if (conf->type_num >= 0) {
q->type_num = conf->type_num;
q->xfr_serial = conf->xfr_serial;
q->serial = conf->serial;
} else {
q->type_num = KNOT_RRTYPE_A;
}
......
......@@ -120,8 +120,8 @@ struct query {
int32_t class_num;
/*!< Type number (16unsigned + -1 uninitialized). */
int32_t type_num;
/*!< SOA serial for XFR. */
uint32_t xfr_serial;
/*!< SOA serial for IXFR and NOTIFY (32unsigned + -1 uninitialized). */
int64_t serial;
/*!< NOTIFY query. */
bool notify;
/*!< Header flags. */
......
......@@ -236,7 +236,7 @@ int khost_parse(kdig_params_t *params, int argc, char *argv[])
query_t *conf = params->config;
uint16_t rclass, rtype;
uint32_t serial;
int64_t serial;
bool notify;
// Long options.
......@@ -307,7 +307,7 @@ int khost_parse(kdig_params_t *params, int argc, char *argv[])
return KNOT_EINVAL;
}
conf->type_num = rtype;
conf->xfr_serial = serial;
conf->serial = serial;
conf->notify = notify;
// If NOTIFY, reset default RD flag.
......
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