mirror of
https://github.com/isc-projects/bind9.git
synced 2026-04-24 07:41:10 -04:00
1480. [bug] Provide replay protection for rndc commands. Full
replay protection requires both rndc and named to
be updated. Partial replay protection (limited
exposure after restart) is provided if just named
is updated.
This commit is contained in:
parent
57fe5960b5
commit
edb8af0b14
7 changed files with 185 additions and 13 deletions
6
CHANGES
6
CHANGES
|
|
@ -1,3 +1,9 @@
|
|||
1480. [bug] Provide replay protection for rndc commands. Full
|
||||
replay protection requires both rndc and named to
|
||||
be updated. Partial replay protection (limited
|
||||
exposure after restart) is provided if just named
|
||||
is updated.
|
||||
|
||||
1479. [bug] cfg_create_tuple() failed to handle out of
|
||||
memory cleanup. parse_list() would leak memory
|
||||
on syntax errors.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: control.c,v 1.7 2001/05/31 01:21:06 bwelling Exp $ */
|
||||
/* $Id: control.c,v 1.7.2.1 2003/07/17 06:36:45 marka Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
|
|
@ -110,6 +110,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
|
|||
result = ns_server_flushcache(ns_g_server, command);
|
||||
} else if (command_compare(command, NS_COMMAND_STATUS)) {
|
||||
result = ns_server_status(ns_g_server, text);
|
||||
} else if (command_compare(command, NS_COMMAND_NULL)) {
|
||||
result = ISC_R_SUCCESS;
|
||||
} else {
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: controlconf.c,v 1.28.2.7 2001/11/27 22:38:14 gson Exp $ */
|
||||
/* $Id: controlconf.c,v 1.28.2.8 2003/07/17 06:36:45 marka Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
#include <isccc/events.h>
|
||||
#include <isccc/result.h>
|
||||
#include <isccc/sexpr.h>
|
||||
#include <isccc/symtab.h>
|
||||
#include <isccc/util.h>
|
||||
|
||||
#include <dns/keyvalues.h>
|
||||
|
|
@ -86,6 +87,7 @@ struct controlconnection {
|
|||
isc_timer_t * timer;
|
||||
unsigned char buffer[2048];
|
||||
controllistener_t * listener;
|
||||
isc_uint32_t nonce;
|
||||
ISC_LINK(controlconnection_t) link;
|
||||
};
|
||||
|
||||
|
|
@ -107,11 +109,14 @@ struct ns_controls {
|
|||
ns_server_t *server;
|
||||
controllistenerlist_t listeners;
|
||||
isc_boolean_t shuttingdown;
|
||||
isccc_symtab_t *symtab;
|
||||
};
|
||||
|
||||
static void control_newconn(isc_task_t *task, isc_event_t *event);
|
||||
static void control_recvmessage(isc_task_t *task, isc_event_t *event);
|
||||
|
||||
#define CLOCKSKEW 300
|
||||
|
||||
static void
|
||||
free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
|
||||
if (key->keyname != NULL)
|
||||
|
|
@ -327,6 +332,10 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
|
|||
char textarray[1024];
|
||||
isc_result_t result;
|
||||
isc_result_t eresult;
|
||||
isccc_sexpr_t *_ctrl;
|
||||
isccc_time_t sent;
|
||||
isccc_time_t exp;
|
||||
isc_uint32_t nonce;
|
||||
|
||||
REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG);
|
||||
|
||||
|
|
@ -387,10 +396,64 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
isc_stdtime_get(&now);
|
||||
|
||||
/*
|
||||
* Limit exposure to replay attacks.
|
||||
*/
|
||||
_ctrl = isccc_alist_lookup(request, "_ctrl");
|
||||
if (_ctrl == NULL) {
|
||||
log_invalid(&conn->ccmsg, ISC_R_FAILURE);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) {
|
||||
if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) {
|
||||
log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
log_invalid(&conn->ccmsg, ISC_R_FAILURE);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expire messages that are too old.
|
||||
*/
|
||||
if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
|
||||
now > exp) {
|
||||
log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate suppression (required for UDP).
|
||||
*/
|
||||
isccc_cc_cleansymtab(listener->controls->symtab, now);
|
||||
result = isccc_cc_checkdup(listener->controls->symtab, request, now);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (result == ISC_R_EXISTS)
|
||||
result = ISCCC_R_DUPLICATE;
|
||||
log_invalid(&conn->ccmsg, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (conn->nonce != 0 &&
|
||||
(isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS ||
|
||||
conn->nonce != nonce)) {
|
||||
log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Establish nonce.
|
||||
*/
|
||||
while (conn->nonce == 0)
|
||||
isc_random_get(&conn->nonce);
|
||||
|
||||
isc_buffer_init(&text, textarray, sizeof(textarray));
|
||||
eresult = ns_control_docommand(request, &text);
|
||||
|
||||
isc_stdtime_get(&now);
|
||||
result = isccc_cc_createresponse(request, now, now + 60, &response);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
|
|
@ -416,6 +479,11 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
|
|||
}
|
||||
}
|
||||
|
||||
_ctrl = isccc_alist_lookup(response, "_ctrl");
|
||||
if (_ctrl == NULL ||
|
||||
isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
ccregion.rstart = conn->buffer + 4;
|
||||
ccregion.rend = conn->buffer + sizeof(conn->buffer);
|
||||
result = isccc_cc_towire(response, &ccregion, &secret);
|
||||
|
|
@ -491,6 +559,7 @@ newconnection(controllistener_t *listener, isc_socket_t *sock) {
|
|||
goto cleanup;
|
||||
|
||||
conn->listener = listener;
|
||||
conn->nonce = 0;
|
||||
ISC_LINK_INIT(conn, link);
|
||||
|
||||
result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task,
|
||||
|
|
@ -1230,12 +1299,20 @@ ns_controls_configure(ns_controls_t *cp, cfg_obj_t *config,
|
|||
isc_result_t
|
||||
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
|
||||
isc_mem_t *mctx = server->mctx;
|
||||
isc_result_t result;
|
||||
ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
|
||||
|
||||
if (controls == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
controls->server = server;
|
||||
ISC_LIST_INIT(controls->listeners);
|
||||
controls->shuttingdown = ISC_FALSE;
|
||||
controls->symtab = NULL;
|
||||
result = isccc_cc_createsymtab(&controls->symtab);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_mem_put(server->mctx, controls, sizeof(*controls));
|
||||
return (result);
|
||||
}
|
||||
*ctrlsp = controls;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
|
@ -1246,6 +1323,7 @@ ns_controls_destroy(ns_controls_t **ctrlsp) {
|
|||
|
||||
REQUIRE(ISC_LIST_EMPTY(controls->listeners));
|
||||
|
||||
isccc_symtab_destroy(&controls->symtab);
|
||||
isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
|
||||
*ctrlsp = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: control.h,v 1.6 2001/05/08 04:09:40 bwelling Exp $ */
|
||||
/* $Id: control.h,v 1.6.2.1 2003/07/17 06:36:45 marka Exp $ */
|
||||
|
||||
#ifndef NAMED_CONTROL_H
|
||||
#define NAMED_CONTROL_H 1
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
#define NS_COMMAND_NOTRACE "notrace"
|
||||
#define NS_COMMAND_FLUSH "flush"
|
||||
#define NS_COMMAND_STATUS "status"
|
||||
#define NS_COMMAND_NULL "null"
|
||||
|
||||
isc_result_t
|
||||
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: rndc.c,v 1.77.2.3 2003/05/15 01:17:55 marka Exp $ */
|
||||
/* $Id: rndc.c,v 1.77.2.4 2003/07/17 06:36:46 marka Exp $ */
|
||||
|
||||
/*
|
||||
* Principal Author: DCL
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include <isc/log.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netdb.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/socket.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/string.h>
|
||||
|
|
@ -85,6 +86,7 @@ static char *command;
|
|||
static char *args;
|
||||
static char program[256];
|
||||
static isc_socket_t *sock = NULL;
|
||||
static isc_uint32_t serial;
|
||||
|
||||
static void
|
||||
usage(int status) {
|
||||
|
|
@ -256,6 +258,83 @@ rndc_recvdone(isc_task_t *task, isc_event_t *event) {
|
|||
isc_app_shutdown();
|
||||
}
|
||||
|
||||
static void
|
||||
rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
|
||||
isccc_sexpr_t *response = NULL;
|
||||
isccc_sexpr_t *_ctrl;
|
||||
isccc_region_t source;
|
||||
isc_result_t result;
|
||||
isc_uint32_t nonce;
|
||||
isccc_sexpr_t *request = NULL;
|
||||
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--;
|
||||
|
||||
if (ccmsg.result == ISC_R_EOF)
|
||||
fatal("connection to remote host closed\n"
|
||||
"This may indicate that the remote server is using "
|
||||
"an older version of \n"
|
||||
"the command protocol, this host is not authorized "
|
||||
"to connect,\nor the key is invalid.");
|
||||
|
||||
if (ccmsg.result != ISC_R_SUCCESS)
|
||||
fatal("recv failed: %s", isc_result_totext(ccmsg.result));
|
||||
|
||||
source.rstart = isc_buffer_base(&ccmsg.buffer);
|
||||
source.rend = isc_buffer_used(&ccmsg.buffer);
|
||||
|
||||
DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
|
||||
|
||||
_ctrl = isccc_alist_lookup(response, "_ctrl");
|
||||
if (_ctrl == NULL)
|
||||
fatal("_ctrl section missing");
|
||||
nonce = 0;
|
||||
if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
|
||||
nonce = 0;
|
||||
|
||||
isc_stdtime_get(&now);
|
||||
|
||||
DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
|
||||
now, now + 60, &request));
|
||||
data = isccc_alist_lookup(request, "_data");
|
||||
if (data == NULL)
|
||||
fatal("_data section missing");
|
||||
if (isccc_cc_definestring(data, "type", args) == NULL)
|
||||
fatal("out of memory");
|
||||
if (nonce != 0) {
|
||||
_ctrl = isccc_alist_lookup(request, "_ctrl");
|
||||
if (_ctrl == NULL)
|
||||
fatal("_ctrl section missing");
|
||||
if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
|
||||
fatal("out of memory");
|
||||
}
|
||||
message.rstart = databuf + 4;
|
||||
message.rend = databuf + sizeof(databuf);
|
||||
DO("render message", isccc_cc_towire(request, &message, &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_ccmsg_cancelread(&ccmsg);
|
||||
DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
|
||||
rndc_recvdone, NULL));
|
||||
recvs++;
|
||||
DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
|
||||
NULL));
|
||||
sends++;
|
||||
|
||||
isc_event_free(&event);
|
||||
isccc_sexpr_free(&response);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
rndc_connected(isc_task_t *task, isc_event_t *event) {
|
||||
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
|
||||
|
|
@ -274,13 +353,12 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
|
|||
fatal("connect failed: %s", isc_result_totext(sevent->result));
|
||||
|
||||
isc_stdtime_get(&now);
|
||||
srandom(now + isc_thread_self());
|
||||
DO("create message", isccc_cc_createmessage(1, NULL, NULL, random(),
|
||||
DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
|
||||
now, now + 60, &request));
|
||||
data = isccc_alist_lookup(request, "_data");
|
||||
if (data == NULL)
|
||||
fatal("_data section missing");
|
||||
if (isccc_cc_definestring(data, "type", args) == NULL)
|
||||
if (isccc_cc_definestring(data, "type", "null") == NULL)
|
||||
fatal("out of memory");
|
||||
message.rstart = databuf + 4;
|
||||
message.rend = databuf + sizeof(databuf);
|
||||
|
|
@ -295,13 +373,12 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
|
|||
isccc_ccmsg_setmaxsize(&ccmsg, 1024);
|
||||
|
||||
DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
|
||||
rndc_recvdone, NULL));
|
||||
rndc_recvnonce, NULL));
|
||||
recvs++;
|
||||
DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
|
||||
NULL));
|
||||
sends++;
|
||||
isc_event_free(&event);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -550,6 +627,8 @@ main(int argc, char **argv) {
|
|||
if (argc < 1)
|
||||
usage(1);
|
||||
|
||||
isc_random_get(&serial);
|
||||
|
||||
DO("create memory context", isc_mem_create(0, 0, &mctx));
|
||||
DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr));
|
||||
DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr));
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: result.h,v 1.3 2001/03/28 23:11:41 bwelling Exp $ */
|
||||
/* $Id: result.h,v 1.3.2.1 2003/07/17 06:36:47 marka Exp $ */
|
||||
|
||||
#ifndef ISCCC_RESULT_H
|
||||
#define ISCCC_RESULT_H 1
|
||||
|
|
@ -30,8 +30,11 @@
|
|||
#define ISCCC_R_UNKNOWNVERSION (ISC_RESULTCLASS_ISCCC + 0)
|
||||
#define ISCCC_R_SYNTAX (ISC_RESULTCLASS_ISCCC + 1)
|
||||
#define ISCCC_R_BADAUTH (ISC_RESULTCLASS_ISCCC + 2)
|
||||
#define ISCCC_R_EXPIRED (ISC_RESULTCLASS_ISCCC + 3)
|
||||
#define ISCCC_R_CLOCKSKEW (ISC_RESULTCLASS_ISCCC + 4)
|
||||
#define ISCCC_R_DUPLICATE (ISC_RESULTCLASS_ISCCC + 5)
|
||||
|
||||
#define ISCCC_R_NRESULTS 3 /* Number of results */
|
||||
#define ISCCC_R_NRESULTS 6 /* Number of results */
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: result.c,v 1.3 2001/03/28 23:11:40 bwelling Exp $ */
|
||||
/* $Id: result.c,v 1.3.2.1 2003/07/17 06:36:46 marka Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
|
|
@ -30,6 +30,9 @@ static const char *text[ISCCC_R_NRESULTS] = {
|
|||
"unknown version", /* 1 */
|
||||
"syntax error", /* 2 */
|
||||
"bad auth", /* 3 */
|
||||
"expired", /* 4 */
|
||||
"clock skew", /* 5 */
|
||||
"duplicate" /* 6 */
|
||||
};
|
||||
|
||||
#define ISCCC_RESULT_RESULTSET 2
|
||||
|
|
|
|||
Loading…
Reference in a new issue