Commit e32d354f authored by Evan Hunt's avatar Evan Hunt
Browse files

[master] allow arbitrary-size rndc output

4005.	[func]		The buffer used for returning text from rndc
			commands is now dynamically resizable, allowing
			arbitrarily large amounts of text to be sent back
			to the client. (Prior to this change, it was
			possible for the output of "rndc tsig-list" to be
			truncated.) [RT #37731]
parent c4abb197
4005. [func] The buffer used for returning text from rndc
commands is now dynamically resizable, allowing
arbitrarily large amounts of text to be sent back
to the client. (Prior to this change, it was
possible for the output of "rndc tsig-list" to be
truncated.) [RT #37731]
4004. [bug] When delegations had AAAA glue but not A, a
reference could be leaked causing an assertion
failure on shutdown. [RT #37796]
......
......@@ -59,7 +59,7 @@ command_compare(const char *text, const char *command) {
* when a control channel message is received.
*/
isc_result_t
ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t **text) {
isccc_sexpr_t *data;
char *command = NULL;
isc_result_t result;
......@@ -132,7 +132,7 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
#endif
/* Do not flush master files */
ns_server_flushonshutdown(ns_g_server, ISC_FALSE);
ns_os_shutdownmsg(command, text);
ns_os_shutdownmsg(command, *text);
isc_app_shutdown();
result = ISC_R_SUCCESS;
} else if (command_compare(command, NS_COMMAND_STOP)) {
......@@ -149,7 +149,7 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
ns_smf_want_disable = 1;
#endif
ns_server_flushonshutdown(ns_g_server, ISC_TRUE);
ns_os_shutdownmsg(command, text);
ns_os_shutdownmsg(command, *text);
isc_app_shutdown();
result = ISC_R_SUCCESS;
} else if (command_compare(command, NS_COMMAND_DUMPSTATS)) {
......@@ -215,6 +215,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
result = ns_server_zonestatus(ns_g_server, command, text);
} else if (command_compare(command, NS_COMMAND_NTA)) {
result = ns_server_nta(ns_g_server, command, text);
} else if (command_compare(command, NS_COMMAND_TESTGEN)) {
result = ns_server_testgen(command, text);
} else {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
......
......@@ -83,7 +83,7 @@ struct controlconnection {
isc_boolean_t ccmsg_valid;
isc_boolean_t sending;
isc_timer_t * timer;
unsigned char buffer[2048];
isc_buffer_t * buffer;
controllistener_t * listener;
isc_uint32_t nonce;
ISC_LINK(controlconnection_t) link;
......@@ -166,6 +166,9 @@ static void
maybe_free_connection(controlconnection_t *conn) {
controllistener_t *listener = conn->listener;
if (conn->buffer != NULL)
isc_buffer_free(&conn->buffer);
if (conn->timer != NULL)
isc_timer_detach(&conn->timer);
......@@ -326,15 +329,12 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
controlkey_t *key;
isccc_sexpr_t *request = NULL;
isccc_sexpr_t *response = NULL;
isccc_region_t ccregion;
isc_uint32_t algorithm;
isccc_region_t secret;
isc_stdtime_t now;
isc_buffer_t b;
isc_region_t r;
isc_uint32_t len;
isc_buffer_t text;
char textarray[2*1024];
isc_buffer_t *text;
isc_result_t result;
isc_result_t eresult;
isccc_sexpr_t *_ctrl;
......@@ -348,6 +348,7 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
listener = conn->listener;
algorithm = DST_ALG_UNKNOWN;
secret.rstart = NULL;
text = NULL;
/* Is the server shutting down? */
if (listener->controls->shuttingdown)
......@@ -366,6 +367,8 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
key != NULL;
key = ISC_LIST_NEXT(key, link))
{
isccc_region_t ccregion;
ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer);
ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer);
secret.rstart = isc_mem_get(listener->mctx, key->secret.length);
......@@ -445,7 +448,9 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
goto cleanup_request;
}
isc_buffer_init(&text, textarray, sizeof(textarray));
result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048);
if (result != ISC_R_SUCCESS)
goto cleanup_request;
/*
* Establish nonce.
......@@ -471,12 +476,12 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
}
}
if (isc_buffer_usedlength(&text) > 0) {
if (isc_buffer_usedlength(text) > 0) {
isccc_sexpr_t *data;
data = isccc_alist_lookup(response, "_data");
if (data != NULL) {
char *str = (char *)isc_buffer_base(&text);
char *str = (char *)isc_buffer_base(text);
if (isccc_cc_definestring(data, "text", str) == NULL)
goto cleanup_response;
}
......@@ -487,16 +492,26 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
goto cleanup_response;
ccregion.rstart = conn->buffer + 4;
ccregion.rend = conn->buffer + sizeof(conn->buffer);
result = isccc_cc_towire(response, &ccregion, algorithm, &secret);
if (conn->buffer == NULL) {
result = isc_buffer_allocate(listener->mctx,
&conn->buffer, 2 * 2048);
if (result != ISC_R_SUCCESS)
goto cleanup_response;
}
isc_buffer_clear(conn->buffer);
/* Skip the length field (4 bytes) */
isc_buffer_add(conn->buffer, 4);
result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret);
if (result != ISC_R_SUCCESS)
goto cleanup_response;
isc_buffer_init(&b, conn->buffer, 4);
len = sizeof(conn->buffer) - REGION_SIZE(ccregion);
isc_buffer_putuint32(&b, len - 4);
r.base = conn->buffer;
r.length = len;
isc_buffer_init(&b, conn->buffer->base, 4);
isc_buffer_putuint32(&b, conn->buffer->used - 4);
r.base = conn->buffer->base;
r.length = conn->buffer->used;
result = isc_socket_send(conn->sock, &r, task, control_senddone, conn);
if (result != ISC_R_SUCCESS)
......@@ -506,6 +521,7 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
isccc_sexpr_free(&request);
isccc_sexpr_free(&response);
isc_buffer_free(&text);
return;
cleanup_response:
......@@ -514,6 +530,8 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
cleanup_request:
isccc_sexpr_free(&request);
isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret));
if (text != NULL)
isc_buffer_free(&text);
cleanup:
isc_socket_detach(&conn->sock);
......@@ -549,6 +567,7 @@ newconnection(controllistener_t *listener, isc_socket_t *sock) {
isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg);
conn->ccmsg_valid = ISC_TRUE;
conn->sending = ISC_FALSE;
conn->buffer = NULL;
conn->timer = NULL;
isc_interval_set(&interval, 60, 0);
result = isc_timer_create(ns_g_timermgr, isc_timertype_once,
......@@ -565,12 +584,13 @@ newconnection(controllistener_t *listener, isc_socket_t *sock) {
control_recvmessage, conn);
if (result != ISC_R_SUCCESS)
goto cleanup;
isccc_ccmsg_setmaxsize(&conn->ccmsg, 2048);
ISC_LIST_APPEND(listener->connections, conn, link);
return (ISC_R_SUCCESS);
cleanup:
if (conn->buffer != NULL)
isc_buffer_free(&conn->buffer);
isccc_ccmsg_invalidate(&conn->ccmsg);
if (conn->timer != NULL)
isc_timer_detach(&conn->timer);
......
......@@ -68,6 +68,7 @@
#define NS_COMMAND_SIGNING "signing"
#define NS_COMMAND_ZONESTATUS "zonestatus"
#define NS_COMMAND_NTA "nta"
#define NS_COMMAND_TESTGEN "testgen"
isc_result_t
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
......@@ -101,6 +102,6 @@ ns_controls_shutdown(ns_controls_t *controls);
*/
isc_result_t
ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text);
ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t **text);
#endif /* NAMED_CONTROL_H */
......@@ -235,7 +235,7 @@ ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush);
*/
isc_result_t
ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t **text);
/*%<
* Act on a "reload" command from the command channel.
*/
......@@ -247,20 +247,20 @@ ns_server_reconfigcommand(ns_server_t *server, char *args);
*/
isc_result_t
ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t **text);
/*%<
* Act on a "notify" command from the command channel.
*/
isc_result_t
ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t **text);
/*%<
* Act on a "refresh" command from the command channel.
*/
isc_result_t
ns_server_retransfercommand(ns_server_t *server, char *args,
isc_buffer_t *text);
isc_buffer_t **text);
/*%<
* Act on a "retransfer" command from the command channel.
*/
......@@ -314,32 +314,32 @@ ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree);
* Report the server's status.
*/
isc_result_t
ns_server_status(ns_server_t *server, isc_buffer_t *text);
ns_server_status(ns_server_t *server, isc_buffer_t **text);
/*%
* Report a list of dynamic and static tsig keys, per view.
*/
isc_result_t
ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text);
ns_server_tsiglist(ns_server_t *server, isc_buffer_t **text);
/*%
* Delete a specific key (with optional view).
*/
isc_result_t
ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text);
ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t **text);
/*%
* Enable or disable updates for a zone.
*/
isc_result_t
ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
isc_buffer_t *text);
isc_buffer_t **text);
/*%
* Dump zone updates to disk, optionally removing the journal file
*/
isc_result_t
ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_sync(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Update a zone's DNSKEY set from the key repository. If
......@@ -349,7 +349,7 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text);
* take place incrementally.
*/
isc_result_t
ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Dump the current recursive queries.
......@@ -367,37 +367,44 @@ ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr);
* Enable or disable dnssec validation.
*/
isc_result_t
ns_server_validation(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_validation(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Add a zone to a running process
*/
isc_result_t
ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Deletes a zone from a running process
*/
isc_result_t
ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Lists the status of the signing records for a given zone.
*/
isc_result_t
ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_signing(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Lists status information for a given zone (e.g., name, type, files,
* load time, expiry, etc).
*/
isc_result_t
ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Adds a Negative Trust Anchor (NTA) for a specified name and
* duration, in a particular view if specified, or in all views.
*/
isc_result_t
ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text);
ns_server_nta(ns_server_t *server, char *args, isc_buffer_t **text);
/*%
* Generates a test sequence that is only for use in system tests. The
* argument is the size of required output in bytes.
*/
isc_result_t
ns_server_testgen(char *args, isc_buffer_t **text);
#endif /* NAMED_SERVER_H */
This diff is collapsed.
......@@ -73,7 +73,7 @@ static int nserveraddrs;
static int currentaddr = 0;
static unsigned int remoteport = 0;
static isc_socketmgr_t *socketmgr = NULL;
static unsigned char databuf[2048];
static isc_buffer_t *databuf;
static isccc_ccmsg_t ccmsg;
static isc_uint32_t algorithm;
static isccc_region_t secret;
......@@ -306,8 +306,6 @@ rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
isccc_time_t now;
isc_region_t r;
isccc_sexpr_t *data;
isccc_region_t message;
isc_uint32_t len;
isc_buffer_t b;
recvs--;
......@@ -354,15 +352,19 @@ rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
fatal("out of memory");
}
message.rstart = databuf + 4;
message.rend = databuf + sizeof(databuf);
isc_buffer_clear(databuf);
/* Skip the length field (4 bytes) */
isc_buffer_add(databuf, 4);
DO("render message",
isccc_cc_towire(request, &message, algorithm, &secret));
len = sizeof(databuf) - REGION_SIZE(message);
isc_buffer_init(&b, databuf, 4);
isc_buffer_putuint32(&b, len - 4);
r.length = len;
r.base = databuf;
isccc_cc_towire(request, &databuf, algorithm, &secret));
isc_buffer_init(&b, databuf->base, 4);
isc_buffer_putuint32(&b, databuf->used - 4);
r.base = databuf->base;
r.length = databuf->used;
isccc_ccmsg_cancelread(&ccmsg);
DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
......@@ -384,9 +386,7 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
isccc_sexpr_t *request = NULL;
isccc_sexpr_t *data;
isccc_time_t now;
isccc_region_t message;
isc_region_t r;
isc_uint32_t len;
isc_buffer_t b;
isc_result_t result;
......@@ -417,15 +417,19 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
fatal("_data section missing");
if (isccc_cc_definestring(data, "type", "null") == NULL)
fatal("out of memory");
message.rstart = databuf + 4;
message.rend = databuf + sizeof(databuf);
isc_buffer_clear(databuf);
/* Skip the length field (4 bytes) */
isc_buffer_add(databuf, 4);
DO("render message",
isccc_cc_towire(request, &message, algorithm, &secret));
len = sizeof(databuf) - REGION_SIZE(message);
isc_buffer_init(&b, databuf, 4);
isc_buffer_putuint32(&b, len - 4);
r.length = len;
r.base = databuf;
isccc_cc_towire(request, &databuf, algorithm, &secret));
isc_buffer_init(&b, databuf->base, 4);
isc_buffer_putuint32(&b, databuf->used - 4);
r.base = databuf->base;
r.length = databuf->used;
isccc_ccmsg_init(mctx, sock, &ccmsg);
isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
......@@ -875,6 +879,9 @@ main(int argc, char **argv) {
command = *argv;
DO("allocate data buffer",
isc_buffer_allocate(mctx, &databuf, 2048));
/*
* Convert argc/argv into a space-delimited command string
* similar to what the user might enter in interactive mode
......@@ -931,6 +938,8 @@ main(int argc, char **argv) {
dns_name_destroy();
isc_buffer_free(&databuf);
if (show_final_mem)
isc_mem_stats(mctx, stderr);
......
......@@ -21,7 +21,7 @@ top_srcdir = @top_srcdir@
@BIND9_MAKE_INCLUDES@
SUBDIRS = builtin dlzexternal filter-aaaa geoip lwresd resolver rpz \
SUBDIRS = builtin dlzexternal filter-aaaa geoip lwresd resolver rndc rpz \
rsabigexponent tkey tsiggss
TARGETS =
......
# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id$
srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
@BIND9_VERSION@
@BIND9_MAKE_INCLUDES@
CINCLUDES =
CDEFINES =
CWARNINGS =
DNSLIBS =
ISCLIBS = .
DNSDEPLIBS =
ISCDEPLIBS =
DEPLIBS =
LIBS = @LIBS@
TARGETS = gencheck@EXEEXT@
GENCHECKOBJS = gencheck.@O@
SRCS = gencheck.c
@BIND9_MAKE_RULES@
all: gencheck@EXEEXT@
gencheck@EXEEXT@: ${GENCHECKOBJS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${GENCHECKOBJS} ${LIBS}
clean distclean::
rm -f ${TARGETS}
......@@ -22,3 +22,4 @@ rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns4/*.conf
rm -f rndc.status
rm -f rndc.output
/*
* Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define USAGE "usage: gencheck <filename>\n"
static int
check(const char *buf, ssize_t count, size_t *start) {
const char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
ssize_t i;
for (i = 0; i < count; i++, *start = (*start + 1) % (sizeof(chars) - 1)) {
/* Just ignore the trailing newline */
if (buf[i] == '\n')
continue;
if (buf[i] != chars[*start])
return 0;
}
return 1;
}
int
main(int argc, char **argv)
{
int ret;
int fd;
ssize_t count;
char buf[1024];
size_t start;
size_t length;
ret = EXIT_FAILURE;
fd = -1;
length = 0;
if (argc != 2) {
fputs(USAGE, stderr);
goto out;
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
goto out;
start = 0;
while ((count = read(fd, buf, sizeof(buf))) != 0) {
if (count < 0)
goto out;
if (!check(buf, count, &start))
goto out;
length += count;
}
ret = EXIT_SUCCESS;
out:
printf("%zu\n", length);
if (fd != -1)
close(fd);
return (ret);
}
......@@ -384,5 +384,24 @@ $RNDC -s 10.53.0.4 -p 9956 -c ns4/key6.conf nta -l 2h nta1.example 2>&1 | grep "
$RNDC -s 10.53.0.4 -p 9956 -c ns4/key6.conf nta -l 1d nta2.example 2>&1 | grep "Negative trust anchor added" > /dev/null || ret=1
$RNDC -s 10.53.0.4 -p 9956 -c ns4/key6.conf nta -l 1w nta3.example 2>&1 | grep "Negative trust anchor added" > /dev/null || ret=1
$RNDC -s 10.53.0.4 -p 9956 -c ns4/key6.conf nta -l 8d nta4.example 2>&1 | grep "NTA lifetime cannot exceed one week" > /dev/null || ret=1
echo "I:exit status: $status"
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
for i in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288
do
echo "I:testing rndc buffer size limits (size=${i})"
ret=0
$RNDC -s 10.53.0.4 -p 9956 -c ns4/key6.conf testgen ${i} 2>&1 > rndc.output || ret=1
actual_size=`./gencheck rndc.output`
if [ "$?"