]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] allow arbitrary-size rndc output
authorEvan Hunt <each@isc.org>
Fri, 14 Nov 2014 23:58:54 +0000 (15:58 -0800)
committerEvan Hunt <each@isc.org>
Fri, 14 Nov 2014 23:58:54 +0000 (15:58 -0800)
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]

24 files changed:
CHANGES
bin/named/control.c
bin/named/controlconf.c
bin/named/include/named/control.h
bin/named/include/named/server.h
bin/named/server.c
bin/rndc/rndc.c
bin/tests/system/Makefile.in
bin/tests/system/rndc/Makefile.in [new file with mode: 0644]
bin/tests/system/rndc/clean.sh
bin/tests/system/rndc/gencheck.c [new file with mode: 0644]
bin/tests/system/rndc/tests.sh
configure
configure.in
doc/arm/notes.xml
lib/dns/include/dns/nta.h
lib/dns/nta.c
lib/isc/buffer.c
lib/isc/include/isc/buffer.h
lib/isc/tests/Makefile.in
lib/isc/tests/buffer_test.c [new file with mode: 0644]
lib/isc/win32/libisc.def.in
lib/isccc/cc.c
lib/isccc/include/isccc/cc.h

diff --git a/CHANGES b/CHANGES
index 1ed92b40a93eb9717d6e30672fbe25a4735c8a9c..8c72283732ec28af8a1b90e670b4e37e3a75de59 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+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]
index 5def85fb5bd5d64232e887206e0d95682ce670d9..41be1f36537d3537b94f259b114f7cecc8088842 100644 (file)
@@ -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,
index 765afdd9662aa351281ff4544f34f0612825a1c5..9492aae8c65a5c9640f14479440d37f762abdd1e 100644 (file)
@@ -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);
index 33a16193d941b5573598c547697500dc963e5bd4..ee1d6969453e0ea3e4fac64d0e7177afd3f4af59 100644 (file)
@@ -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 */
index 0b241b7471b02893089dba05d78c9ae6f765105e..953eae77d3600aa1788dd1de492a600ed03f0c9e 100644 (file)
@@ -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 */
index c650b3d79a5bc356968d2ccde6dcdeec05d96e38..5c45fa8cdb1fd24b3b6c992dae4f8c4c9962f6b2 100644 (file)
 #define TCHECK(op) \
        do { tresult = (op);                                     \
                if (tresult != ISC_R_SUCCESS) {                  \
-                       isc_buffer_clear(text);                  \
+                       isc_buffer_clear(*text);                 \
                        goto cleanup;                            \
                }                                                \
        } while (0)
@@ -418,10 +418,16 @@ static void
 newzone_cfgctx_destroy(void **cfgp);
 
 static isc_result_t
-putstr(isc_buffer_t *b, const char *str);
+putstr(isc_buffer_t **b, const char *str);
 
 static isc_result_t
-putnull(isc_buffer_t *b);
+putmem(isc_buffer_t **b, const char *str, size_t len);
+
+static isc_result_t
+putuint8(isc_buffer_t **b, isc_uint8_t val);
+
+static isc_result_t
+putnull(isc_buffer_t **b);
 
 isc_result_t
 add_comment(FILE *fp, const char *viewname);
@@ -7138,7 +7144,7 @@ next_token(char **stringp, const char *delim) {
 static isc_result_t
 zone_from_args(ns_server_t *server, char *args, const char *zonetxt,
               dns_zone_t **zonep, const char **zonename,
-              isc_buffer_t *text, isc_boolean_t skip)
+              isc_buffer_t **text, isc_boolean_t skip)
 {
        char *input, *ptr;
        char *classtxt;
@@ -7243,7 +7249,7 @@ zone_from_args(ns_server_t *server, char *args, const char *zonetxt,
  */
 isc_result_t
 ns_server_retransfercommand(ns_server_t *server, char *args,
-                           isc_buffer_t *text)
+                           isc_buffer_t **text)
 {
        isc_result_t result;
        dns_zone_t *zone = NULL;
@@ -7275,7 +7281,7 @@ ns_server_retransfercommand(ns_server_t *server, char *args,
  * Act on a "reload" command from the command channel.
  */
 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) {
        isc_result_t result;
        dns_zone_t *zone = NULL;
        dns_zonetype_t type;
@@ -7316,9 +7322,10 @@ ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
                        }
                }
        }
-       if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
-               isc_buffer_putmem(text, (const unsigned char *)msg,
-                                 strlen(msg) + 1);
+       if (msg != NULL) {
+               putstr(text, msg);
+               putnull(text);
+       }
        return (result);
 }
 
@@ -7337,10 +7344,10 @@ ns_server_reconfigcommand(ns_server_t *server, char *args) {
  * Act on a "notify" command from the command channel.
  */
 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) {
        isc_result_t result;
        dns_zone_t *zone = NULL;
-       const unsigned char msg[] = "zone notify queued";
+       const char msg[] = "zone notify queued";
 
        result = zone_from_args(server, args, NULL, &zone, NULL,
                                text, ISC_TRUE);
@@ -7351,8 +7358,8 @@ ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
 
        dns_zone_notify(zone);
        dns_zone_detach(&zone);
-       if (sizeof(msg) <= isc_buffer_availablelength(text))
-               isc_buffer_putmem(text, msg, sizeof(msg));
+       putstr(text, msg);
+       putnull(text);
 
        return (ISC_R_SUCCESS);
 }
@@ -7361,11 +7368,12 @@ ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
  * Act on a "refresh" 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)
+{
        isc_result_t result;
        dns_zone_t *zone = NULL, *raw = NULL;
-       const unsigned char msg1[] = "zone refresh queued";
-       const unsigned char msg2[] = "not a slave or stub zone";
+       const char msg1[] = "zone refresh queued";
+       const char msg2[] = "not a slave or stub zone";
        dns_zonetype_t type;
 
        result = zone_from_args(server, args, NULL, &zone, NULL,
@@ -7386,14 +7394,14 @@ ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
        if (type == dns_zone_slave || type == dns_zone_stub) {
                dns_zone_refresh(zone);
                dns_zone_detach(&zone);
-               if (sizeof(msg1) <= isc_buffer_availablelength(text))
-                       isc_buffer_putmem(text, msg1, sizeof(msg1));
+               putstr(text, msg1);
+               putnull(text);
                return (ISC_R_SUCCESS);
        }
 
        dns_zone_detach(&zone);
-       if (sizeof(msg2) <= isc_buffer_availablelength(text))
-               isc_buffer_putmem(text, msg2, sizeof(msg2));
+       putstr(text, msg2);
+       putnull(text);
        return (ISC_R_FAILURE);
 }
 
@@ -7969,7 +7977,7 @@ ns_server_setdebuglevel(ns_server_t *server, char *args) {
 }
 
 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) {
        char *ptr, *viewname;
        dns_view_t *view;
        isc_boolean_t changed = ISC_FALSE;
@@ -8016,29 +8024,16 @@ ns_server_validation(ns_server_t *server, char *args, isc_buffer_t *text) {
                        view->enablevalidation = enable;
                        changed = ISC_TRUE;
                } else {
-                       unsigned int n;
-                       if (!first) {
-                               n = snprintf((char *)isc_buffer_used(text),
-                                            isc_buffer_availablelength(text),
-                                            "\n");
-                               if (n >= isc_buffer_availablelength(text)) {
-                                       result = ISC_R_NOSPACE;
-                                       goto out;
-                               }
-                               isc_buffer_add(text, n);
-                       }
+                       if (!first)
+                               putstr(text, "\n");
+                       putstr(text, "DNSSEC validation is ");
+                       putstr(text, view->enablevalidation
+                                      ? "enabled" : "disabled");
+                       putstr(text, " (view ");
+                       putstr(text, view->name);
+                       putstr(text, ")");
+                       putnull(text);
                        first = ISC_FALSE;
-                       n = snprintf((char *)isc_buffer_used(text),
-                                    isc_buffer_availablelength(text),
-                                    "DNSSEC validation is %s (view %s)",
-                                    view->enablevalidation ?
-                                      "enabled" : "disabled",
-                                    view->name);
-                       if (n >= isc_buffer_availablelength(text)) {
-                               result = ISC_R_NOSPACE;
-                               goto out;
-                       }
-                       isc_buffer_add(text, n);
                }
        }
 
@@ -8280,12 +8275,12 @@ ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) {
 }
 
 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) {
+       isc_result_t result;
        unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
        unsigned int automatic;
-       unsigned int n;
        const char *ob = "", *cb = "", *alt = "";
-       char boottime[80], configtime[80];
+       char boottime[80], configtime[80], line[1024];
 
        if (ns_g_server->version_set) {
                ob = " (";
@@ -8310,40 +8305,93 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) {
        isc_time_formathttptimestamp(&ns_g_configtime, configtime,
                                     sizeof(configtime));
 
-       n = snprintf((char *)isc_buffer_used(text),
-                    isc_buffer_availablelength(text),
-                    "version: %s%s%s%s <id:%s>\n"
-                    "boot time: %s\n"
-                    "last configured: %s\n"
-#ifdef ISC_PLATFORM_USETHREADS
-                    "CPUs found: %u\n"
-                    "worker threads: %u\n"
-                    "UDP listeners per interface: %u\n"
-#endif
-                    "number of zones: %u (%u automatic)\n"
-                    "debug level: %d\n"
-                    "xfers running: %u\n"
-                    "xfers deferred: %u\n"
-                    "soa queries in progress: %u\n"
-                    "query logging is %s\n"
-                    "recursive clients: %d/%d/%d\n"
-                    "tcp clients: %d/%d\n"
-                    "server is up and running",
-                    ns_g_version, ob, alt, cb, ns_g_srcid,
-                    boottime, configtime,
+       snprintf(line, sizeof(line), "version: %s%s%s%s <id:%s>\n",
+                ns_g_version, ob, alt, cb, ns_g_srcid);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "boot time: %s\n", boottime);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "last configured: %s\n", configtime);
+       CHECK(putstr(text, line));
+
 #ifdef ISC_PLATFORM_USETHREADS
-                    ns_g_cpus_detected, ns_g_cpus, ns_g_udpdisp,
+       snprintf(line, sizeof(line), "CPUs found: %u\n", ns_g_cpus_detected);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "worker threads: %u\n", ns_g_cpus);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
+                ns_g_udpdisp);
+       CHECK(putstr(text, line));
+
 #endif
-                    zonecount, automatic, ns_g_debuglevel, xferrunning,
-                    xferdeferred, soaqueries,
-                    server->log_queries ? "ON" : "OFF",
+       snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
+                    zonecount, automatic);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "debug level: %d\n", ns_g_debuglevel);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "soa queries in progress: %u\n",
+                    soaqueries);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "query logging is %s\n",
+                    server->log_queries ? "ON" : "OFF");
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "recursive clients: %d/%d/%d\n",
                     server->recursionquota.used, server->recursionquota.soft,
-                    server->recursionquota.max,
+                    server->recursionquota.max);
+       CHECK(putstr(text, line));
+
+       snprintf(line, sizeof(line), "tcp clients: %d/%d\n",
                     server->tcpquota.used, server->tcpquota.max);
-       if (n >= isc_buffer_availablelength(text))
-               return (ISC_R_NOSPACE);
-       isc_buffer_add(text, n);
+       CHECK(putstr(text, line));
+
+       CHECK(putstr(text, "server is up and running"));
+       CHECK(putnull(text));
+
        return (ISC_R_SUCCESS);
+ cleanup:
+       return (result);
+}
+
+isc_result_t
+ns_server_testgen(char *args, isc_buffer_t **text) {
+       isc_result_t result;
+       char *ptr;
+       unsigned long count;
+       unsigned long i;
+       const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
+
+       /* Skip the command name. */
+       ptr = next_token(&args, " \t");
+       if (ptr == NULL)
+               return (ISC_R_UNEXPECTEDEND);
+
+       ptr = next_token(&args, " \t");
+       if (ptr == NULL)
+               count = 26;
+       else
+               count = strtoul(ptr, NULL, 10);
+
+       CHECK(isc_buffer_reserve(text, count));
+       for (i = 0; i < count; i++)
+               CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
+
+       CHECK(putnull(text));
+
+ cleanup:
+       return (result);
 }
 
 static isc_result_t
@@ -8410,13 +8458,12 @@ delete_keynames(dns_tsig_keyring_t *ring, char *target,
 }
 
 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) {
        isc_result_t result;
-       unsigned int n;
        dns_view_t *view;
        unsigned int foundkeys = 0;
-       char *target;
-       char *viewname;
+       char *target, *viewname;
+       char fbuf[16];
 
        (void)next_token(&command, " \t");  /* skip command name */
        target = next_token(&command, " \t");
@@ -8443,19 +8490,19 @@ ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
        }
        isc_task_endexclusive(server->task);
 
-       n = snprintf((char *)isc_buffer_used(text),
-                    isc_buffer_availablelength(text),
-                    "%d tsig keys deleted.\n", foundkeys);
-       if (n >= isc_buffer_availablelength(text))
-               return (ISC_R_NOSPACE);
-       isc_buffer_add(text, n);
+       snprintf(fbuf, sizeof(fbuf), "%d", foundkeys);
 
-       return (ISC_R_SUCCESS);
+       CHECK(putstr(text, fbuf));
+       CHECK(putstr(text, " tsig keys deleted."));
+       CHECK(putnull(text));
+
+ cleanup:
+       return (result);
 }
 
 static isc_result_t
-list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
-            unsigned int *foundkeys)
+list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
+             unsigned int *foundkeys)
 {
        char namestr[DNS_NAME_FORMATSIZE];
        char creatorstr[DNS_NAME_FORMATSIZE];
@@ -8466,7 +8513,6 @@ list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
        dns_name_t *origin;
        dns_rbtnode_t *node;
        dns_tsigkey_t *tkey;
-       unsigned int n;
        const char *viewname;
 
        if (view != NULL)
@@ -8495,43 +8541,46 @@ list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
                tkey = node->data;
 
                if (tkey != NULL) {
-                       (*foundkeys)++;
                        dns_name_format(&tkey->name, namestr, sizeof(namestr));
                        if (tkey->generated) {
                                dns_name_format(tkey->creator, creatorstr,
                                                sizeof(creatorstr));
-                               n = snprintf((char *)isc_buffer_used(text),
-                                            isc_buffer_availablelength(text),
-                                            "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n",
-                                            viewname, namestr, creatorstr);
+                               if (*foundkeys != 0)
+                                       putstr(text, "\n");
+                               CHECK(putstr(text, "view \""));
+                               CHECK(putstr(text, viewname));
+                               CHECK(putstr(text,
+                                            "\"; type \"dynamic\"; key \""));
+                               CHECK(putstr(text, namestr));
+                               CHECK(putstr(text, "\"; creator \""));
+                               CHECK(putstr(text, creatorstr));
+                               CHECK(putstr(text, "\";"));
                        } else {
-                               n = snprintf((char *)isc_buffer_used(text),
-                                            isc_buffer_availablelength(text),
-                                            "view \"%s\"; type \"static\"; key \"%s\";\n",
-                                            viewname, namestr);
-                       }
-                       if (n >= isc_buffer_availablelength(text)) {
-                               dns_rbtnodechain_invalidate(&chain);
-                               return (ISC_R_NOSPACE);
+                               if (*foundkeys != 0)
+                                       putstr(text, "\n");
+                               CHECK(putstr(text, "view \""));
+                               CHECK(putstr(text, viewname));
+                               CHECK(putstr(text,
+                                            "\"; type \"static\"; key \""));
+                               CHECK(putstr(text, namestr));
+                               CHECK(putstr(text, "\";"));
                        }
-                       isc_buffer_add(text, n);
+                       (*foundkeys)++;
                }
                result = dns_rbtnodechain_next(&chain, &foundname, origin);
-               if (result == ISC_R_NOMORE)
+               if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN)
                        break;
-               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
-                       dns_rbtnodechain_invalidate(&chain);
-                       return (result);
-               }
        }
 
        return (ISC_R_SUCCESS);
+ cleanup:
+       dns_rbtnodechain_invalidate(&chain);
+       return (result);
 }
 
 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) {
        isc_result_t result;
-       unsigned int n;
        dns_view_t *view;
        unsigned int foundkeys = 0;
 
@@ -8559,14 +8608,11 @@ ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
        }
        isc_task_endexclusive(server->task);
 
-       if (foundkeys == 0) {
-               n = snprintf((char *)isc_buffer_used(text),
-                            isc_buffer_availablelength(text),
-                            "no tsig keys found.\n");
-               if (n >= isc_buffer_availablelength(text))
-                       return (ISC_R_NOSPACE);
-               isc_buffer_add(text, n);
-       }
+       if (foundkeys == 0)
+               putstr(text, "no tsig keys found.");
+
+       if (isc_buffer_usedlength(*text) > 0)
+               putnull(text);
 
        return (ISC_R_SUCCESS);
 }
@@ -8575,7 +8621,7 @@ ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
  * Act on a "sign" or "loadkeys" command from the command channel.
  */
 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) {
        isc_result_t result;
        dns_zone_t *zone = NULL;
        dns_zonetype_t type;
@@ -8641,7 +8687,7 @@ synczone(dns_zone_t *zone, void *uap) {
 }
 
 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) {
        isc_result_t result, tresult;
        dns_view_t *view;
        dns_zone_t *zone = NULL;
@@ -8691,9 +8737,10 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
        result = synczone(zone, &cleanup);
        isc_task_endexclusive(server->task);
 
-       if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
-               isc_buffer_putmem(text, (const unsigned char *)msg,
-                                 strlen(msg) + 1);
+       if (msg != NULL) {
+               putstr(text, msg);
+               putnull(text);
+       }
 
        view = dns_zone_getview(zone);
        if (strcmp(view->name, "_default") == 0 ||
@@ -8724,7 +8771,7 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
  */
 isc_result_t
 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
-                isc_buffer_t *text)
+                isc_buffer_t **text)
 {
        isc_result_t result, tresult;
        dns_zone_t *zone = NULL, *raw = NULL;
@@ -8815,9 +8862,10 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
        }
        isc_task_endexclusive(server->task);
 
-       if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
-               isc_buffer_putmem(text, (const unsigned char *)msg,
-                                 strlen(msg) + 1);
+       if (msg != NULL) {
+               putstr(text, msg);
+               putnull(text);
+       }
 
        view = dns_zone_getview(zone);
        if (strcmp(view->name, "_default") == 0 ||
@@ -8849,16 +8897,8 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
  * is managed by smf and is also running chroot.
  */
 isc_result_t
-ns_smf_add_message(isc_buffer_t *text) {
-       unsigned int n;
-
-       n = snprintf((char *)isc_buffer_used(text),
-               isc_buffer_availablelength(text),
-               "use svcadm(1M) to manage named");
-       if (n >= isc_buffer_availablelength(text))
-               return (ISC_R_NOSPACE);
-       isc_buffer_add(text, n);
-       return (ISC_R_SUCCESS);
+ns_smf_add_message(isc_buffer_t **text) {
+       return (putstr(text, "use svcadm(1M) to manage named"));
 }
 #endif /* HAVE_LIBSCF */
 
@@ -8883,7 +8923,7 @@ add_comment(FILE *fp, const char *viewname) {
  * Act on an "addzone" command from the command channel.
  */
 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) {
        isc_result_t         result, tresult;
        isc_buffer_t         argbuf;
        size_t               arglen;
@@ -9042,7 +9082,7 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
        /* Emit the zone name, quoted and escaped */
        isc_buffer_init(&buf, namebuf, sizeof(namebuf));
        CHECK(dns_name_totext(dnsname, ISC_TRUE, &buf));
-       putnull(&buf);
+       isc_buffer_putuint8(&buf, 0);
        CHECK(isc_stdio_write("zone \"", 6, 1, fp, NULL));
        CHECK(isc_stdio_write(namebuf, strlen(namebuf), 1, fp, NULL));
        CHECK(isc_stdio_write("\" ", 2, 1, fp, NULL));
@@ -9081,7 +9121,7 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
        result = ISC_R_SUCCESS;
 
  cleanup:
-       if (isc_buffer_usedlength(text) > 0)
+       if (isc_buffer_usedlength(*text) > 0)
                putnull(text);
        if (fp != NULL)
                isc_stdio_close(fp);
@@ -9099,18 +9139,16 @@ ns_server_add_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
 }
 
 static isc_boolean_t
-inuse(const char* file, isc_boolean_t first, isc_buffer_t *text) {
+inuse(const char* file, isc_boolean_t first, isc_buffer_t **text) {
 #define INUSEMSG "The following files were in use and may now be removed:\n"
 
-       if (file != NULL && isc_file_exists(file) &&
-           isc_buffer_availablelength(text) >
-           strlen(file) + (first ? sizeof(INUSEMSG) : sizeof("\n")))
-       {
+       if (file != NULL && isc_file_exists(file)) {
                if (first)
                        (void) putstr(text, INUSEMSG);
                else
                        (void) putstr(text, "\n");
                (void) putstr(text, file);
+               putnull(text);
                return (ISC_FALSE);
        }
        return (first);
@@ -9120,7 +9158,7 @@ inuse(const char* file, isc_boolean_t first, isc_buffer_t *text) {
  * Act on a "delzone" command from the command channel.
  */
 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) {
        isc_result_t result;
        dns_zone_t *zone = NULL;
        dns_zone_t *raw = NULL;
@@ -9346,7 +9384,7 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
        result = ISC_R_SUCCESS;
 
  cleanup:
-       if (isc_buffer_usedlength(text) > 0)
+       if (isc_buffer_usedlength(*text) > 0)
                putnull(text);
        if (exclusive)
                isc_task_endexclusive(server->task);
@@ -9429,7 +9467,7 @@ generate_salt(unsigned char *salt, size_t saltlen) {
 }
 
 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) {
        isc_result_t result = ISC_R_SUCCESS;
        dns_zone_t *zone = NULL;
        dns_name_t *origin;
@@ -9576,21 +9614,13 @@ ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) {
 
                        isc_buffer_init(&buf, output, sizeof(output));
                        CHECK(dns_private_totext(&priv, &buf));
-
                        if (!first)
-                               putstr(text, "\n");
+                               CHECK(putstr(text, "\n"));
+                       CHECK(putstr(text, output));
                        first = ISC_FALSE;
-
-                       n = snprintf((char *)isc_buffer_used(text),
-                                    isc_buffer_availablelength(text),
-                                    "%s", output);
-                       if (n >= isc_buffer_availablelength(text))
-                               CHECK(ISC_R_NOSPACE);
-
-                       isc_buffer_add(text, (unsigned int)n);
                }
                if (!first)
-                       putnull(text);
+                       CHECK(putnull(text));
 
                if (result == ISC_R_NOMORE)
                        result = ISC_R_SUCCESS;
@@ -9612,30 +9642,41 @@ ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) {
 }
 
 static isc_result_t
-putstr(isc_buffer_t *b, const char *str) {
-       unsigned int l = strlen(str);
+putmem(isc_buffer_t **b, const char *str, size_t len) {
+       isc_result_t result;
 
-       /*
-        * Use >= to leave space for NUL termination.
-        */
-       if (l >= isc_buffer_availablelength(b))
+       result = isc_buffer_reserve(b, len);
+       if (result != ISC_R_SUCCESS)
                return (ISC_R_NOSPACE);
 
-       isc_buffer_putmem(b, (const unsigned char *)str, l);
+       isc_buffer_putmem(*b, (const unsigned char *)str, len);
        return (ISC_R_SUCCESS);
 }
 
+static inline isc_result_t
+putstr(isc_buffer_t **b, const char *str) {
+       return (putmem(b, str, strlen(str)));
+}
+
 static isc_result_t
-putnull(isc_buffer_t *b) {
-       if (isc_buffer_availablelength(b) == 0)
+putuint8(isc_buffer_t **b, isc_uint8_t val) {
+       isc_result_t result;
+
+       result = isc_buffer_reserve(b, 1);
+       if (result != ISC_R_SUCCESS)
                return (ISC_R_NOSPACE);
 
-       isc_buffer_putuint8(b, 0);
+       isc_buffer_putuint8(*b, val);
        return (ISC_R_SUCCESS);
 }
 
+static inline isc_result_t
+putnull(isc_buffer_t **b) {
+       return (putuint8(b, 0));
+}
+
 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) {
        isc_result_t result = ISC_R_SUCCESS;
        dns_zone_t *zone = NULL, *raw = NULL;
        const char *type, *file, *zonename = NULL;
@@ -9907,7 +9948,7 @@ argcheck(char *cmd, const char *full) {
 }
 
 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) {
        dns_view_t *view;
        dns_ntatable_t *ntatable = NULL;
        isc_result_t result = ISC_R_SUCCESS;
@@ -10083,10 +10124,7 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
                                      nametext, view->name);
                }
 
-               if (isc_buffer_availablelength(text) == 0)
-                       return (ISC_R_NOSPACE);
-
-               isc_buffer_putuint8(text, 0);
+               CHECK(putnull(text));
        }
 
  cleanup:
index 6e8367cee43829eed88797d10aa175003d2814ce..ab2973df57225bf410884585c37770bb3980f2f2 100644 (file)
@@ -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);
 
index a4ce2fd1e9c5f54793baa6bda34ee180d9317439..0bf725ec521e47d733a2f285746a99590774144b 100644 (file)
@@ -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 =
 
diff --git a/bin/tests/system/rndc/Makefile.in b/bin/tests/system/rndc/Makefile.in
new file mode 100644 (file)
index 0000000..787d35a
--- /dev/null
@@ -0,0 +1,55 @@
+# 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}
index a7b321637e3a269961f0ffd647e1e2a312f257ad..ca307a63938f09070cbb0c5ec08e4f6e9b128fd3 100644 (file)
@@ -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
diff --git a/bin/tests/system/rndc/gencheck.c b/bin/tests/system/rndc/gencheck.c
new file mode 100644 (file)
index 0000000..d720787
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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);
+}
index 8cc8992c1490553eb4c662e80728fdf16fb8293b..e0163b81ad40aacfd8ba34b5626fb900599a4b3a 100644 (file)
@@ -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 [ "$?" = "0" ]; then
+           expected_size=`expr $i + 1`
+           if [ $actual_size != $expected_size ]; then ret=1; fi
+       else
+           ret=1
+       fi
+
+       if [ $ret != 0 ]; then echo "I:failed"; fi
+       status=`expr $status + $ret`
+done
+
 exit $status
index e4f4987819f7c769643538063097cad35f29d25d..d8c45204b5dbedd864435115f949802e20b20063 100755 (executable)
--- a/configure
+++ b/configure
@@ -21724,7 +21724,7 @@ ac_config_commands="$ac_config_commands chmod"
 # elsewhere if there's a good reason for doing so.
 #
 
-ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/builtin/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/filter-aaaa/Makefile bin/tests/system/geoip/Makefile bin/tests/system/inline/checkdsa.sh bin/tests/system/lwresd/Makefile bin/tests/system/resolver/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/sit/prereq.sh bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-latex.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/tests/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/Makefile unit/unittest.sh"
+ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/builtin/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/filter-aaaa/Makefile bin/tests/system/geoip/Makefile bin/tests/system/inline/checkdsa.sh bin/tests/system/lwresd/Makefile bin/tests/system/resolver/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/sit/prereq.sh bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-latex.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/tests/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/Makefile unit/unittest.sh"
 
 
 #
@@ -22777,6 +22777,7 @@ do
     "bin/tests/system/inline/checkdsa.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/inline/checkdsa.sh" ;;
     "bin/tests/system/lwresd/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/lwresd/Makefile" ;;
     "bin/tests/system/resolver/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/resolver/Makefile" ;;
+    "bin/tests/system/rndc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rndc/Makefile" ;;
     "bin/tests/system/rpz/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rpz/Makefile" ;;
     "bin/tests/system/rsabigexponent/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rsabigexponent/Makefile" ;;
     "bin/tests/system/sit/prereq.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/sit/prereq.sh" ;;
index 59c78162222f79354a21c2ce4a7d5ec303b89b01..271a3b4db8a25188bae783b9c1f244aa73690a50 100644 (file)
@@ -4535,6 +4535,7 @@ AC_CONFIG_FILES([
        bin/tests/system/inline/checkdsa.sh
        bin/tests/system/lwresd/Makefile
        bin/tests/system/resolver/Makefile
+       bin/tests/system/rndc/Makefile
        bin/tests/system/rpz/Makefile
        bin/tests/system/rsabigexponent/Makefile
        bin/tests/system/sit/prereq.sh
index db721d7f9a98efab1ee7ee7668f781653dbf8029..bb06f1e07e59033ae9346761de307b7ed3aa5100 100644 (file)
          name format is found to exist, it will continue to be used.
        </para>
       </listitem>
+      <listitem>
+       <para>
+         "rndc" can now return text output of arbitrary size to
+         the caller. (Prior to this, certain commands such as
+         "rndc tsig-list" and "rndc zonestatus" could return
+         truncated output.)
+       </para>
+      </listitem>
     </itemizedlist>
   </sect2>
   <sect2 id="relnotes_bugs">
index f6826485a96a20205fb9f8261303c932e672fb96..1e24f4de3269fb75cff4bb13cc4d0cf4e08bd79c 100644 (file)
@@ -199,9 +199,9 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
  */
 
 isc_result_t
-dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf);
+dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t **buf);
 /*%<
- * Dump the NTA table to buffer 'buf'
+ * Dump the NTA table to buffer at 'buf'
  */
 
 isc_result_t
index 414fac1318cb693c40dce669ba1e72f0aad2e3fc..3d78acce2f0303a0ce3a7c969e593c75d4577044 100644 (file)
@@ -501,7 +501,7 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
 }
 
 isc_result_t
-dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf) {
+dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t **buf) {
        isc_result_t result;
        dns_rbtnode_t *node;
        dns_rbtnodechain_t chain;
@@ -539,11 +539,12 @@ dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf) {
                                 n->expiry < now ? "expired" : "expiry",
                                 tbuf);
                        first = ISC_FALSE;
-                       if (strlen(obuf) >= isc_buffer_availablelength(buf)) {
+                       result = isc_buffer_reserve(buf, strlen(obuf));
+                       if (result != ISC_R_SUCCESS) {
                                result = ISC_R_NOSPACE;
                                goto cleanup;
-                       } else
-                               isc_buffer_putstr(buf, obuf);
+                       }
+                       isc_buffer_putstr(*buf, obuf);
                }
                result = dns_rbtnodechain_next(&chain, NULL, NULL);
                if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
@@ -553,8 +554,9 @@ dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf) {
                }
        }
 
-       if (isc_buffer_availablelength(buf) != 0)
-               isc_buffer_putuint8(buf, 0);
+       isc_buffer_reserve(buf, 1);
+       if (isc_buffer_availablelength(*buf) != 0)
+               isc_buffer_putuint8(*buf, 0);
 
    cleanup:
        dns_rbtnodechain_invalidate(&chain);
index 2d15e248575c1b75f8e42db0ebff4ff6fc5429f0..848888ea63156896156545343dd0120a8f957f41 100644 (file)
@@ -15,8 +15,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: buffer.c,v 1.49 2008/09/25 04:02:39 tbox Exp $ */
-
 /*! \file */
 
 #include <config.h>
@@ -467,6 +465,63 @@ isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
        return (ISC_R_SUCCESS);
 }
 
+isc_result_t
+isc_buffer_reallocate(isc_buffer_t **dynbuffer, unsigned int length) {
+       isc_buffer_t *dbuf;
+
+       REQUIRE(dynbuffer != NULL);
+       REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+
+       if ((*dynbuffer)->length > length)
+               return (ISC_R_NOSPACE);
+
+       /*
+        * XXXMUKS: This is far more expensive than plain realloc() as
+        * it doesn't remap pages, but does ordinary copy. So is
+        * isc_mem_reallocate(), which has additional issues.
+        */
+       dbuf = isc_mem_get((*dynbuffer)->mctx, length + sizeof(isc_buffer_t));
+       if (dbuf == NULL)
+               return (ISC_R_NOMEMORY);
+
+       memmove(dbuf, *dynbuffer, (*dynbuffer)->length + sizeof(isc_buffer_t));
+       isc_mem_put(dbuf->mctx, *dynbuffer,
+                   (*dynbuffer)->length + sizeof(isc_buffer_t));
+
+       dbuf->base = ((unsigned char *)dbuf) + sizeof(isc_buffer_t);
+       dbuf->length = length;
+
+       INSIST(ISC_BUFFER_VALID(dbuf));
+
+       *dynbuffer = dbuf;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
+       isc_uint64_t len;
+
+       REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+
+       len = (*dynbuffer)->length;
+       if ((len - (*dynbuffer)->used) > size)
+               return (ISC_R_SUCCESS);
+
+       /* Round to nearest buffer size increment */
+       len += size;
+       len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR));
+
+       /* Cap at UINT_MAX */
+       if (len > UINT_MAX) {
+               len = UINT_MAX;
+               if ((len - (*dynbuffer)->used) < size)
+                       return (ISC_R_NOMEMORY);
+       }
+
+       return (isc_buffer_reallocate(dynbuffer, (unsigned int) len));
+}
+
 void
 isc_buffer_free(isc_buffer_t **dynbuffer) {
        unsigned int real_length;
index f9c0775790e72eba8bf09d6858890e1f6aa613a4..a6193a53c24f864b084292ad0fbd482a8a9a3efc 100644 (file)
@@ -15,8 +15,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: buffer.h,v 1.55 2010/12/20 23:47:21 tbox Exp $ */
-
 #ifndef ISC_BUFFER_H
 #define ISC_BUFFER_H 1
 
@@ -127,6 +125,13 @@ ISC_LANG_BEGINDECLS
 #define ISC_BUFFER_VALID(b)            ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC)
 /*@}*/
 
+/*!
+ * Size granularity for dynamically resizeable buffers; when reserving
+ * space in a buffer, we round the allocated buffer length up to the
+ * nearest * multiple of this value.
+ */
+#define ISC_BUFFER_INCR 2048
+
 /*
  * The following macros MUST be used only on valid buffers.  It is the
  * caller's responsibility to ensure this by using the ISC_BUFFER_VALID
@@ -205,6 +210,50 @@ isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
  *\li  Changing the buffer's length field is not permitted.
  */
 
+isc_result_t
+isc_buffer_reallocate(isc_buffer_t **dynbuffer, unsigned int length);
+/*!<
+ * \brief Reallocate the buffer to be "length" bytes long. The buffer
+ * pointer may move when you call this function.
+ *
+ * Requires:
+ *\li  "dynbuffer" is not NULL.
+ *
+ *\li  "*dynbuffer" is a valid dynamic buffer.
+ *
+ *\li  'length' > current length of buffer.
+ *
+ * Returns:
+ *\li  ISC_R_SUCCESS           - success
+ *\li  ISC_R_NOMEMORY          - no memory available
+ *
+ * Ensures:
+ *\li  "*dynbuffer" will be valid on return and will contain all the
+ *     original data. However, the buffer pointer may be moved during
+ *     reallocation.
+ */
+
+isc_result_t
+isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size);
+/*!<
+ * \brief Make "size" bytes of space available in the buffer. The buffer
+ * pointer may move when you call this function.
+ *
+ * Requires:
+ *\li  "dynbuffer" is not NULL.
+ *
+ *\li  "*dynbuffer" is a valid dynamic buffer.
+ *
+ * Returns:
+ *\li  ISC_R_SUCCESS           - success
+ *\li  ISC_R_NOMEMORY          - no memory available
+ *
+ * Ensures:
+ *\li  "*dynbuffer" will be valid on return and will contain all the
+ *     original data. However, the buffer pointer may be moved during
+ *     reallocation.
+ */
+
 void
 isc_buffer_free(isc_buffer_t **dynbuffer);
 /*!<
index afc672de2fbead71e61761a583624dd5404a358f..8160f8a9a047ca904d9fbabfd68351f39d33680f 100644 (file)
@@ -40,7 +40,7 @@ SRCS =                isctest.c taskpool_test.c socket_test.c hash_test.c \
                sockaddr_test.c symtab_test.c task_test.c queue_test.c \
                parse_test.c pool_test.c print_test.c regex_test.c \
                socket_test.c safe_test.c time_test.c aes_test.c \
-               file_test.c
+               file_test.c buffer_test.c
 
 SUBDIRS =
 TARGETS =      taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
@@ -49,7 +49,7 @@ TARGETS =     taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
                queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \
                print_test@EXEEXT@ regex_test@EXEEXT@ socket_test@EXEEXT@ \
                safe_test@EXEEXT@ time_test@EXEEXT@ aes_test@EXEEXT@ \
-               file_test@EXEEXT@
+               file_test@EXEEXT@ buffer_test@EXEEXT@
 
 @BIND9_MAKE_RULES@
 
@@ -125,6 +125,10 @@ file_test@EXEEXT@: file_test.@O@ ${ISCDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
                        file_test.@O@ ${ISCLIBS} ${LIBS}
 
+buffer_test@EXEEXT@: buffer_test.@O@ ${ISCDEPLIBS}
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+                       buffer_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
 unit::
        sh ${top_srcdir}/unit/unittest.sh
 
diff --git a/lib/isc/tests/buffer_test.c b/lib/isc/tests/buffer_test.c
new file mode 100644 (file)
index 0000000..d1b2783
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+
+#include <atf-c.h>
+
+#include "isctest.h"
+
+#include <isc/buffer.h>
+#include <isc/result.h>
+
+ATF_TC(isc_buffer_reserve);
+ATF_TC_HEAD(isc_buffer_reserve, tc) {
+       atf_tc_set_md_var(tc, "descr", "reserve space in dynamic buffers");
+}
+
+ATF_TC_BODY(isc_buffer_reserve, tc) {
+       isc_result_t result;
+       isc_buffer_t *b;
+
+       result = isc_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       b = NULL;
+       result = isc_buffer_allocate(mctx, &b, 1024);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       ATF_CHECK_EQ(b->length, 1024);
+
+       /*
+        * 1024 bytes should already be available, so this call does
+        * nothing.
+        */
+       result = isc_buffer_reserve(&b, 1024);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 1024);
+
+       /*
+        * This call should grow it to 2048 bytes as only 1024 bytes are
+        * available in the buffer.
+        */
+       result = isc_buffer_reserve(&b, 1025);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 2048);
+
+       /*
+        * 2048 bytes should already be available, so this call does
+        * nothing.
+        */
+       result = isc_buffer_reserve(&b, 2048);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 2048);
+
+       /*
+        * This call should grow it to 4096 bytes as only 2048 bytes are
+        * available in the buffer.
+        */
+       result = isc_buffer_reserve(&b, 2049);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 4096);
+
+       /* Consume some of the buffer so we can run the next test. */
+       isc_buffer_add(b, 4096);
+
+       /*
+        * This call should fail and leave buffer untouched.
+        */
+       result = isc_buffer_reserve(&b, UINT_MAX);
+       ATF_CHECK_EQ(result, ISC_R_NOMEMORY);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 4096);
+
+       isc_buffer_free(&b);
+
+       isc_test_end();
+}
+
+ATF_TC(isc_buffer_reallocate);
+ATF_TC_HEAD(isc_buffer_reallocate, tc) {
+       atf_tc_set_md_var(tc, "descr", "reallocate dynamic buffers");
+}
+
+ATF_TC_BODY(isc_buffer_reallocate, tc) {
+       isc_result_t result;
+       isc_buffer_t *b;
+
+       result = isc_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       b = NULL;
+       result = isc_buffer_allocate(mctx, &b, 1024);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       ATF_CHECK_EQ(b->length, 1024);
+
+       result = isc_buffer_reallocate(&b, 512);
+       ATF_CHECK_EQ(result, ISC_R_NOSPACE);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 1024);
+
+       result = isc_buffer_reallocate(&b, 1536);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+       ATF_CHECK(ISC_BUFFER_VALID(b));
+       ATF_CHECK_EQ(b->length, 1536);
+
+       isc_buffer_free(&b);
+
+       isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+       ATF_TP_ADD_TC(tp, isc_buffer_reserve);
+       ATF_TP_ADD_TC(tp, isc_buffer_reallocate);
+       return (atf_no_error());
+}
index 1164d9e47582fd2a20cd8ce75bf7c084fb0ff473..2dbbfaf026716213247add21c979fd62948029db 100644 (file)
@@ -159,6 +159,8 @@ isc_buffer_getuint16
 isc_buffer_getuint32
 isc_buffer_getuint8
 isc_buffer_reinit
+isc_buffer_reallocate
+isc_buffer_reserve
 isc_bufferlist_availablecount
 isc_bufferlist_usedcount
 isc_commandline_parse
index 43e309436ef5abcddfadbf2a95867bbbab075dc2..36d4dffaee60ac2dcd8c331637fde3f03957ecb6 100644 (file)
@@ -108,84 +108,102 @@ static unsigned char auth_hsha[] = {
 #define HSHA_LENGTH    88
 
 static isc_result_t
-table_towire(isccc_sexpr_t *alist, isccc_region_t *target);
+table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
 
 static isc_result_t
-list_towire(isccc_sexpr_t *alist, isccc_region_t *target);
+list_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
 
 static isc_result_t
-value_towire(isccc_sexpr_t *elt, isccc_region_t *target)
+value_towire(isccc_sexpr_t *elt, isc_buffer_t **buffer)
 {
        unsigned int len;
-       unsigned char *lenp;
        isccc_region_t *vr;
        isc_result_t result;
 
        if (isccc_sexpr_binaryp(elt)) {
                vr = isccc_sexpr_tobinary(elt);
                len = REGION_SIZE(*vr);
-               if (REGION_SIZE(*target) < 1 + 4 + len)
+               result = isc_buffer_reserve(buffer, 1 + 4);
+               if (result != ISC_R_SUCCESS)
                        return (ISC_R_NOSPACE);
-               PUT8(ISCCC_CCMSGTYPE_BINARYDATA, target->rstart);
-               PUT32(len, target->rstart);
-               if (REGION_SIZE(*target) < len)
+               isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_BINARYDATA);
+               isc_buffer_putuint32(*buffer, len);
+
+               result = isc_buffer_reserve(buffer, len);
+               if (result != ISC_R_SUCCESS)
                        return (ISC_R_NOSPACE);
-               PUT_MEM(vr->rstart, len, target->rstart);
+               isc_buffer_putmem(*buffer, vr->rstart, len);
        } else if (isccc_alist_alistp(elt)) {
-               if (REGION_SIZE(*target) < 1 + 4)
+               unsigned int used;
+               isc_buffer_t b;
+
+               result = isc_buffer_reserve(buffer, 1 + 4);
+               if (result != ISC_R_SUCCESS)
                        return (ISC_R_NOSPACE);
-               PUT8(ISCCC_CCMSGTYPE_TABLE, target->rstart);
+               isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_TABLE);
                /*
                 * Emit a placeholder length.
                 */
-               lenp = target->rstart;
-               PUT32(0, target->rstart);
+               used = (*buffer)->used;
+               isc_buffer_putuint32(*buffer, 0);
+
                /*
                 * Emit the table.
                 */
-               result = table_towire(elt, target);
+               result = table_towire(elt, buffer);
                if (result != ISC_R_SUCCESS)
                        return (result);
-               len = (unsigned int)(target->rstart - lenp);
+
+               len = (*buffer)->used - used;
                /*
                 * 'len' is 4 bytes too big, since it counts
-                * the placeholder length too.  Adjust and
+                * the placeholder length too.  Adjust and
                 * emit.
                 */
                INSIST(len >= 4U);
                len -= 4;
-               PUT32(len, lenp);
+
+               isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
+               isc_buffer_putuint32(&b, len);
        } else if (isccc_sexpr_listp(elt)) {
-               if (REGION_SIZE(*target) < 1 + 4)
+               unsigned int used;
+               isc_buffer_t b;
+
+               result = isc_buffer_reserve(buffer, 1 + 4);
+               if (result != ISC_R_SUCCESS)
                        return (ISC_R_NOSPACE);
-               PUT8(ISCCC_CCMSGTYPE_LIST, target->rstart);
+               isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_LIST);
                /*
-                * Emit a placeholder length and count.
+                * Emit a placeholder length.
                 */
-               lenp = target->rstart;
-               PUT32(0, target->rstart);
+               used = (*buffer)->used;
+               isc_buffer_putuint32(*buffer, 0);
+
                /*
                 * Emit the list.
                 */
-               result = list_towire(elt, target);
+               result = list_towire(elt, buffer);
                if (result != ISC_R_SUCCESS)
                        return (result);
-               len = (unsigned int)(target->rstart - lenp);
+
+               len = (*buffer)->used - used;
                /*
                 * 'len' is 4 bytes too big, since it counts
-                * the placeholder length.  Adjust and emit.
+                * the placeholder length too.  Adjust and
+                * emit.
                 */
                INSIST(len >= 4U);
                len -= 4;
-               PUT32(len, lenp);
+
+               isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
+               isc_buffer_putuint32(&b, len);
        }
 
        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
-table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
-{
+table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer) {
        isccc_sexpr_t *kv, *elt, *k, *v;
        char *ks;
        isc_result_t result;
@@ -203,14 +221,15 @@ table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
                /*
                 * Emit the key name.
                 */
-               if (REGION_SIZE(*target) < 1 + len)
+               result = isc_buffer_reserve(buffer, 1 + len);
+               if (result != ISC_R_SUCCESS)
                        return (ISC_R_NOSPACE);
-               PUT8(len, target->rstart);
-               PUT_MEM(ks, len, target->rstart);
+               isc_buffer_putuint8(*buffer, len);
+               isc_buffer_putmem(*buffer, (const unsigned char *) ks, len);
                /*
                 * Emit the value.
                 */
-               result = value_towire(v, target);
+               result = value_towire(v, buffer);
                if (result != ISC_R_SUCCESS)
                        return (result);
        }
@@ -219,12 +238,11 @@ table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
 }
 
 static isc_result_t
-list_towire(isccc_sexpr_t *list, isccc_region_t *target)
-{
+list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) {
        isc_result_t result;
 
        while (list != NULL) {
-               result = value_towire(ISCCC_SEXPR_CAR(list), target);
+               result = value_towire(ISCCC_SEXPR_CAR(list), buffer);
                if (result != ISC_R_SUCCESS)
                        return (result);
                list = ISCCC_SEXPR_CDR(list);
@@ -324,24 +342,24 @@ sign(unsigned char *data, unsigned int length, unsigned char *hmac,
 }
 
 isc_result_t
-isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
+isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
                isc_uint32_t algorithm, isccc_region_t *secret)
 {
-       unsigned char *hmac_rstart, *signed_rstart;
+       unsigned int hmac_size, signed_size;
        isc_result_t result;
 
-       if (algorithm == ISCCC_ALG_HMACMD5) {
-               if (REGION_SIZE(*target) < 4 + sizeof(auth_hmd5))
-                       return (ISC_R_NOSPACE);
-       } else {
-               if (REGION_SIZE(*target) < 4 + sizeof(auth_hsha))
-                       return (ISC_R_NOSPACE);
-       }
+       result = isc_buffer_reserve(buffer,
+                                   4 + ((algorithm == ISCCC_ALG_HMACMD5) ?
+                                        sizeof(auth_hmd5) :
+                                        sizeof(auth_hsha)));
+       if (result != ISC_R_SUCCESS)
+               return (ISC_R_NOSPACE);
 
        /*
         * Emit protocol version.
         */
-       PUT32(1, target->rstart);
+       isc_buffer_putuint32(*buffer, 1);
+
        if (secret != NULL) {
                /*
                 * Emit _auth section with zeroed HMAC signature.
@@ -349,19 +367,21 @@ isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
                 * we know what it is.
                 */
                if (algorithm == ISCCC_ALG_HMACMD5) {
-                       hmac_rstart = target->rstart + HMD5_OFFSET;
-                       PUT_MEM(auth_hmd5, sizeof(auth_hmd5), target->rstart);
+                       hmac_size = (*buffer)->used + HMD5_OFFSET;
+                       isc_buffer_putmem(*buffer,
+                                         auth_hmd5, sizeof(auth_hmd5));
                } else {
                        unsigned char *hmac_alg;
 
-                       hmac_rstart = target->rstart + HSHA_OFFSET;
-                       hmac_alg = hmac_rstart - 1;
-                       PUT_MEM(auth_hsha, sizeof(auth_hsha), target->rstart);
-                       PUT8(algorithm, hmac_alg);
+                       hmac_size = (*buffer)->used + HSHA_OFFSET;
+                       hmac_alg = (unsigned char *) isc_buffer_used(*buffer) + HSHA_OFFSET - 1;
+                       isc_buffer_putmem(*buffer,
+                                         auth_hsha, sizeof(auth_hsha));
+                       *hmac_alg = algorithm;
                }
        } else
-               hmac_rstart = NULL;
-       signed_rstart = target->rstart;
+               hmac_size = 0;
+       signed_size = (*buffer)->used;
        /*
         * Delete any existing _auth section so that we don't try
         * to encode it.
@@ -370,13 +390,15 @@ isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
        /*
         * Emit the message.
         */
-       result = table_towire(alist, target);
+       result = table_towire(alist, buffer);
        if (result != ISC_R_SUCCESS)
                return (result);
        if (secret != NULL)
-               return (sign(signed_rstart,
-                            (unsigned int)(target->rstart - signed_rstart),
-                            hmac_rstart, algorithm, secret));
+               return (sign((unsigned char *) (*buffer)->base + signed_size,
+                            (*buffer)->used - signed_size,
+                            (hmac_size == 0 ? NULL :
+                             (unsigned char *) (*buffer)->base + hmac_size),
+                            algorithm, secret));
        return (ISC_R_SUCCESS);
 }
 
index 55dc7a0a36510ebdc5dbbd61288827cc819f48de..5f7f88e1e532d69081751e09a5a46bb450f48622 100644 (file)
@@ -37,6 +37,7 @@
 /*! \file isccc/cc.h */
 
 #include <isc/lang.h>
+#include <isc/buffer.h>
 #include <isccc/types.h>
 
 ISC_LANG_BEGINDECLS
@@ -65,7 +66,7 @@ ISC_LANG_BEGINDECLS
 
 /*% Send to Wire */
 isc_result_t
-isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
+isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
                isc_uint32_t algorithm, isccc_region_t *secret);
 
 /*% Get From Wire */