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

[master] rndc dnstap -roll

4411.	[func]		"rndc dnstap -roll" automatically rolls the
			dnstap output file; the previous version is
			saved with ".0" suffix, and earlier versions
			with ".1" and so on. An optional numeric argument
			indicates how many prior files to save. [RT #42830]
parent a2101037
4411. [func] "rndc dnstap -roll" automatically rolls the
dnstap output file; the previous version is
saved with ".0" suffix, and earlier versions
with ".1" and so on. An optional numeric argument
indicates how many prior files to save. [RT #42830]
4410. [bug] Address use after free and memory leak with dnstap.
[RT #42746]
......
......@@ -272,8 +272,9 @@ ns_control_docommand(isccc_sexpr_t *message, isc_boolean_t readonly,
result = ns_server_testgen(lex, text);
} else if (command_compare(command, NS_COMMAND_MKEYS)) {
result = ns_server_mkeys(ns_g_server, lex, text);
} else if (command_compare(command, NS_COMMAND_DNSTAPREOPEN)) {
result = ns_server_dnstap_reopen(ns_g_server);
} else if (command_compare(command, NS_COMMAND_DNSTAP) ||
command_compare(command, NS_COMMAND_DNSTAPREOPEN)) {
result = ns_server_dnstap(ns_g_server, lex, text);
} else {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
......
......@@ -64,6 +64,7 @@
#define NS_COMMAND_TESTGEN "testgen"
#define NS_COMMAND_MKEYS "managed-keys"
#define NS_COMMAND_DNSTAPREOPEN "dnstap-reopen"
#define NS_COMMAND_DNSTAP "dnstap"
isc_result_t
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
......
......@@ -740,6 +740,6 @@ ns_server_mkeys(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text);
* Close and reopen DNSTAP output file.
*/
isc_result_t
ns_server_dnstap_reopen(ns_server_t *server);
ns_server_dnstap(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text);
#endif /* NAMED_SERVER_H */
......@@ -12211,14 +12211,45 @@ ns_server_mkeys(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
}
isc_result_t
ns_server_dnstap_reopen(ns_server_t *server) {
ns_server_dnstap(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
#if HAVE_DNSTAP
if (server->dtenv != NULL)
return(dns_dt_reopen(server->dtenv));
return (ISC_R_NOTFOUND);
char *ptr;
if (server->dtenv == NULL)
return (ISC_R_NOTFOUND);
/* Check the command name. */
ptr = next_token(lex, text);
if (ptr == NULL)
return (ISC_R_UNEXPECTEDEND);
/* "dnstap-reopen" was used in 9.11.0b1 */
if (strcasecmp(ptr, "dnstap-reopen") == 0)
return (dns_dt_reopen(server->dtenv, ISC_FALSE));
/* Find out what we are to do. */
ptr = next_token(lex, text);
if (ptr == NULL)
return (ISC_R_UNEXPECTEDEND);
if (strcasecmp(ptr, "-reopen") == 0)
return (dns_dt_reopen(server->dtenv, -1));
else if ((strcasecmp(ptr, "-roll") == 0)) {
int backups = 0;
unsigned int n;
ptr = next_token(lex, text);
if (ptr != NULL) {
n = sscanf(ptr, "%u", &backups);
if (n != 1U)
return (ISC_R_BADNUMBER);
}
return (dns_dt_reopen(server->dtenv, backups));
} else
return (DNS_R_SYNTAX);
#else
UNUSED(server);
UNUSED(lex);
UNUSED(text);
return (ISC_R_NOTIMPLEMENTED);
#endif
}
......@@ -306,11 +306,18 @@
</varlistentry>
<varlistentry>
<term><userinput>dnstap-reopen</userinput></term>
<term><userinput>dnstap ( -reopen | -roll <optional><replaceable>number</replaceable></optional> )</userinput></term>
<listitem>
<para>
Close and re-open DNSTAP output files. This allows the files
to be renamed externally then to be re-opened.
Close and re-open DNSTAP output files.
<command>rndc dnstap -reopen</command> allows the output
file to be renamed externally, then re-opened.
<command>rndc dnstap -roll</command> causes the output file
to be rolled automatically, similar to log files; the most
recent output file has ".0" appended to its name; the
previous most recent output file is moved to ".1", and so on.
If <replaceable>number</replaceable> is specified, then the
number of backup log files is limited to that number.
</para>
</listitem>
</varlistentry>
......@@ -605,17 +612,17 @@
</varlistentry>
<varlistentry>
<term><userinput>recursing</userinput></term>
<listitem>
<para>
Dump the list of queries <command>named</command> is currently
recursing on, and the list of domains to which iterative
queries are currently being sent. (The second list includes
the number of fetches currently active for the given domain,
and how many have been passed or dropped because of the
<option>fetches-per-zone</option> option.)
</para>
</listitem>
<term><userinput>recursing</userinput></term>
<listitem>
<para>
Dump the list of queries <command>named</command> is currently
recursing on, and the list of domains to which iterative
queries are currently being sent. (The second list includes
the number of fetches currently active for the given domain,
and how many have been passed or dropped because of the
<option>fetches-per-zone</option> option.)
</para>
</listitem>
</varlistentry>
<varlistentry>
......
......@@ -15,15 +15,16 @@ status=0
$DIG +short @10.53.0.3 -p 5300 a.example > dig.out
# check three different dnstap reopen/roll methods:
# ns1: dnstap-reopen; ns2: dnstap -reopen; ns3: dnstap -roll
mv ns1/dnstap.out ns1/dnstap.out.save
mv ns2/dnstap.out ns2/dnstap.out.save
mv ns3/dnstap.out ns3/dnstap.out.save
sleep 2
$RNDCCMD -s 10.53.0.1 dnstap-reopen | sed 's/^/I:ns1 /'
$RNDCCMD -s 10.53.0.2 dnstap-reopen | sed 's/^/I:ns2 /'
$RNDCCMD -s 10.53.0.3 dnstap-reopen | sed 's/^/I:ns3 /'
$RNDCCMD -s 10.53.0.2 dnstap -reopen | sed 's/^/I:ns2 /'
$RNDCCMD -s 10.53.0.3 dnstap -roll | sed 's/^/I:ns3 /'
$DIG +short @10.53.0.3 -p 5300 a.example > dig.out
sleep 1
......@@ -56,6 +57,7 @@ cr2=`$DNSTAPREAD ns2/dnstap.out.save | grep "CR " | wc -l`
rq2=`$DNSTAPREAD ns2/dnstap.out.save | grep "RQ " | wc -l`
rr2=`$DNSTAPREAD ns2/dnstap.out.save | grep "RR " | wc -l`
mv ns3/dnstap.out.0 ns3/dnstap.out.save
udp3=`$DNSTAPREAD ns3/dnstap.out.save | grep "UDP " | wc -l`
tcp3=`$DNSTAPREAD ns3/dnstap.out.save | grep "TCP " | wc -l`
aq3=`$DNSTAPREAD ns3/dnstap.out.save | grep "AQ " | wc -l`
......
......@@ -196,8 +196,19 @@
a human-readable format.
</para>
<para>
<command>rndc dnstap-reopen</command> can be used reopen
dnstap output files after renaming them.
<command>rndc dnstap -roll</command> causes <command>dnstap</command>
output files to be rolled like log files -- the most recent output
file is renamed with a <filename>.0</filename> suffix, the next
most recent with <filename>.1</filename>, etc. (Note that this
only works when <command>dnstap</command> output is being written
to a file, not to a UNIX domain socket.) An optional numerical
argument specifies how many backup log files to retain; if not
specified or set to 0, there is no limit.
</para>
<para>
<command>rndc dnstap -reopen</command> simply closes and reopens
the <command>dnstap</command> output channel without renaming
the output file.
</para>
<para>
For more information on <command>dnstap</command>, see
......
......@@ -96,6 +96,7 @@ struct dns_dtenv {
isc_region_t identity;
isc_region_t version;
char *path;
dns_dtmode_t mode;
};
#define CHECK(x) do { \
......@@ -232,6 +233,7 @@ dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
fstrm_writer_destroy(&fw);
CHECK(ISC_R_FAILURE);
}
env->mode = mode;
isc_mem_attach(mctx, &env->mctx);
......@@ -265,25 +267,46 @@ dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
}
isc_result_t
dns_dt_reopen(dns_dtenv_t *env) {
isc_result_t result = ISC_R_SUCCESS;
dns_dt_reopen(dns_dtenv_t *env, int roll) {
isc_result_t result;
isc_logfile_t file;
fstrm_res res;
REQUIRE(VALID_DTENV(env));
if (env->fw == NULL)
return (ISC_R_FAILURE);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSTAP,
DNS_LOGMODULE_DNSTAP, ISC_LOG_INFO,
"reopening dnstap destination '%s'",
"%s dnstap destination '%s'",
(roll < 0) ? "reopening" : "rolling",
env->path);
if (env->fw != NULL) {
res = fstrm_writer_close(env->fw);
if (res == fstrm_res_success)
fstrm_writer_open(env->fw);
return (ISC_R_SUCCESS);
res = fstrm_writer_close(env->fw);
if (res != fstrm_res_success)
return (ISC_R_FAILURE);
if (roll >= 0) {
/*
* Create a temporary isc_logfile_t structure so we can
* take advantage of the logfile rolling facility.
*/
char *filename = isc_mem_strdup(env->mctx, env->path);
file.name = filename;
file.stream = NULL;
file.versions = roll != 0 ? roll : ISC_LOG_ROLLINFINITE;
file.maximum_size = 0;
file.maximum_reached = ISC_FALSE;
result = isc_logfile_roll(&file);
isc_mem_free(env->mctx, filename);
if (result != ISC_R_SUCCESS)
return (result);
}
return (result);
fstrm_writer_open(env->fw);
return (ISC_R_SUCCESS);
}
static isc_result_t
......
......@@ -150,10 +150,16 @@ dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
*/
isc_result_t
dns_dt_reopen(dns_dtenv_t *env);
dns_dt_reopen(dns_dtenv_t *env, int roll);
/*%<
* Reopens files established by dns_dt_create().
*
* If 'roll' is non-negative and 'env->mode' is dns_dtmode_file,
* then the file is automatically rolled over before reopening.
* The value of 'roll' indicates the number of backup log files to
* keep. If 'roll' is negative, or if 'env->mode' is dns_dtmode_unix,
* then the channel is simply reopened.
*
* Requires:
*\li 'env' is a valid dnstap environment.
*/
......
......@@ -139,11 +139,11 @@ ATF_TC_BODY(dispatchset_get, tc) {
static void
senddone(isc_task_t *task, isc_event_t *event) {
isc_socket_t *socket = event->ev_arg;
isc_socket_t *sock = event->ev_arg;
UNUSED(task);
isc_socket_detach(&socket);
isc_socket_detach(&sock);
isc_event_free(&event);
}
......@@ -152,7 +152,7 @@ nameserver(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
isc_region_t region;
isc_socket_t *dummy;
isc_socket_t *socket = event->ev_arg;
isc_socket_t *sock = event->ev_arg;
isc_socketevent_t *ev = (isc_socketevent_t *)event;
static unsigned char buf1[16];
static unsigned char buf2[16];
......@@ -171,8 +171,8 @@ nameserver(isc_task_t *task, isc_event_t *event) {
region.base = buf1;
region.length = sizeof(buf1);
dummy = NULL;
isc_socket_attach(socket, &dummy);
result = isc_socket_sendto(socket, &region, task, senddone, socket,
isc_socket_attach(sock, &dummy);
result = isc_socket_sendto(sock, &region, task, senddone, sock,
&ev->address, NULL);
if (result != ISC_R_SUCCESS)
isc_socket_detach(&dummy);
......@@ -183,8 +183,8 @@ nameserver(isc_task_t *task, isc_event_t *event) {
region.base = buf2;
region.length = sizeof(buf2);
dummy = NULL;
isc_socket_attach(socket, &dummy);
result = isc_socket_sendto(socket, &region, task, senddone, socket,
isc_socket_attach(sock, &dummy);
result = isc_socket_sendto(sock, &region, task, senddone, sock,
&ev->address, NULL);
if (result != ISC_R_SUCCESS)
isc_socket_detach(&dummy);
......@@ -222,8 +222,8 @@ ATF_TC_BODY(dispatch_getnext, tc) {
isc_region_t region;
isc_result_t result;
isc_sockaddr_t local;
isc_socket_t *dsocket = NULL;
isc_socket_t *socket = NULL;
isc_socket_t *dsock = NULL;
isc_socket_t *sock = NULL;
isc_task_t *task = NULL;
isc_uint16_t id;
struct in_addr ina;
......@@ -254,21 +254,21 @@ ATF_TC_BODY(dispatch_getnext, tc) {
* Create a local udp nameserver on the loopback.
*/
result = isc_socket_create(socketmgr, AF_INET, isc_sockettype_udp,
&socket);
&sock);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ina.s_addr = htonl(INADDR_LOOPBACK);
isc_sockaddr_fromin(&local, &ina, 0);
result = isc_socket_bind(socket, &local, 0);
result = isc_socket_bind(sock, &local, 0);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = isc_socket_getsockname(socket, &local);
result = isc_socket_getsockname(sock, &local);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
first = ISC_TRUE;
region.base = rbuf;
region.length = sizeof(rbuf);
result = isc_socket_recv(socket, &region, 1, task, nameserver, socket);
result = isc_socket_recv(sock, &region, 1, task, nameserver, sock);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_dispatch_addresponse(dispatch, &local, task, response,
......@@ -279,10 +279,10 @@ ATF_TC_BODY(dispatch_getnext, tc) {
message[0] = (id >> 8) & 0xff;
message[1] = id & 0xff;
isc_socket_attach(dns_dispatch_getsocket(dispatch), &dsocket);
isc_socket_attach(dns_dispatch_getsocket(dispatch), &dsock);
region.base = message;
region.length = sizeof(message);
result = isc_socket_sendto(dsocket, &region, task, senddone, dsocket,
result = isc_socket_sendto(dsock, &region, task, senddone, dsock,
&local, NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
......@@ -294,8 +294,8 @@ ATF_TC_BODY(dispatch_getnext, tc) {
/*
* Shutdown nameserver.
*/
isc_socket_cancel(socket, task, ISC_SOCKCANCEL_RECV);
isc_socket_detach(&socket);
isc_socket_cancel(sock, task, ISC_SOCKCANCEL_RECV);
isc_socket_detach(&sock);
isc_task_detach(&task);
/*
......
......@@ -903,6 +903,15 @@ isc_log_setcontext(isc_log_t *lctx);
*\li lctx be a valid context.
*/
isc_result_t
isc_logfile_roll(isc_logfile_t *file);
/*%<
* Roll a logfile.
*
* Requires:
*\li file is not NULL.
*/
ISC_LANG_ENDDECLS
#endif /* ISC_LOG_H */
......@@ -223,10 +223,7 @@ static isc_result_t
sync_channellist(isc_logconfig_t *lcfg);
static isc_result_t
greatest_version(isc_logchannel_t *channel, int *greatest);
static isc_result_t
roll_log(isc_logchannel_t *channel);
greatest_version(isc_logfile_t *file, int *greatest);
static void
isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
......@@ -1134,8 +1131,7 @@ sync_channellist(isc_logconfig_t *lcfg) {
}
static isc_result_t
greatest_version(isc_logchannel_t *channel, int *greatestp) {
/* XXXDCL HIGHLY NT */
greatest_version(isc_logfile_t *file, int *greatestp) {
char *bname, *digit_end;
const char *dirname;
int version, greatest = -1;
......@@ -1147,15 +1143,13 @@ greatest_version(isc_logchannel_t *channel, int *greatestp) {
char *bname2;
#endif
REQUIRE(channel->type == ISC_LOG_TOFILE);
/*
* It is safe to DE_CONST the file.name because it was copied
* with isc_mem_strdup in isc_log_createchannel.
* with isc_mem_strdup().
*/
bname = strrchr(FILE_NAME(channel), sep);
bname = strrchr(file->name, sep);
#ifdef _WIN32
bname2 = strrchr(FILE_NAME(channel), '\\');
bname2 = strrchr(file->name, '\\');
if ((bname != NULL && bname2 != NULL && bname2 > bname) ||
(bname == NULL && bname2 != NULL)) {
bname = bname2;
......@@ -1164,9 +1158,9 @@ greatest_version(isc_logchannel_t *channel, int *greatestp) {
#endif
if (bname != NULL) {
*bname++ = '\0';
dirname = FILE_NAME(channel);
dirname = file->name;
} else {
DE_CONST(FILE_NAME(channel), bname);
DE_CONST(file->name, bname);
dirname = ".";
}
bnamelen = strlen(bname);
......@@ -1177,7 +1171,7 @@ greatest_version(isc_logchannel_t *channel, int *greatestp) {
/*
* Replace the file separator if it was taken out.
*/
if (bname != FILE_NAME(channel))
if (bname != file->name)
*(bname - 1) = sep;
/*
......@@ -1189,8 +1183,8 @@ greatest_version(isc_logchannel_t *channel, int *greatestp) {
while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
if (dir.entry.length > bnamelen &&
strncmp(dir.entry.name, bname, bnamelen) == 0 &&
dir.entry.name[bnamelen] == '.') {
dir.entry.name[bnamelen] == '.')
{
version = strtol(&dir.entry.name[bnamelen + 1],
&digit_end, 10);
if (*digit_end == '\0' && version > greatest)
......@@ -1204,23 +1198,25 @@ greatest_version(isc_logchannel_t *channel, int *greatestp) {
return (ISC_R_SUCCESS);
}
static isc_result_t
roll_log(isc_logchannel_t *channel) {
isc_result_t
isc_logfile_roll(isc_logfile_t *file) {
int i, n, greatest;
char current[PATH_MAX + 1];
char new[PATH_MAX + 1];
const char *path;
isc_result_t result;
REQUIRE(file != NULL);
/*
* Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
* is specified. Apparently complete external control over the log
* files is desired.
*/
if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
if (file->versions == ISC_LOG_ROLLNEVER)
return (ISC_R_SUCCESS);
path = FILE_NAME(channel);
path = file->name;
/*
* Set greatest_version to the greatest existing version
......@@ -1228,30 +1224,29 @@ roll_log(isc_logchannel_t *channel) {
* though the file names are 0 based, so an oldest log of log.1
* is a greatest_version of 2.
*/
result = greatest_version(channel, &greatest);
result = greatest_version(file, &greatest);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Now greatest should be set to the highest version number desired.
* Since the highest number is one less than FILE_VERSIONS(channel)
* Since the highest number is one less than file->versions.
* when not doing infinite log rolling, greatest will need to be
* decremented when it is equal to -- or greater than --
* FILE_VERSIONS(channel). When greatest is less than
* FILE_VERSIONS(channel), it is already suitable for use as
* file->versions. When greatest is less than
* file->versions, it is already suitable for use as
* the maximum version number.
*/
if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE ||
FILE_VERSIONS(channel) > greatest)
if (file->versions == ISC_LOG_ROLLINFINITE || file->versions > greatest)
; /* Do nothing. */
else
/*
* When greatest is >= FILE_VERSIONS(channel), it needs to
* be reduced until it is FILE_VERSIONS(channel) - 1.
* When greatest is >= file->versions, it needs to
* be reduced until it is file->versions - 1.
* Remove any excess logs on the way to that value.
*/
while (--greatest >= FILE_VERSIONS(channel)) {
while (--greatest >= file->versions) {
n = snprintf(current, sizeof(current), "%s.%d",
path, greatest);
if (n >= (int)sizeof(current) || n < 0)
......@@ -1286,7 +1281,7 @@ roll_log(isc_logchannel_t *channel) {
isc_result_totext(result));
}
if (FILE_VERSIONS(channel) != 0) {
if (file->versions != 0) {
n = snprintf(new, sizeof(new), "%s.0", path);
if (n >= (int)sizeof(new) || n < 0)
result = ISC_R_NOSPACE;
......@@ -1348,11 +1343,11 @@ isc_log_open(isc_logchannel_t *channel) {
if (result == ISC_R_SUCCESS && roll) {
if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER)
return (ISC_R_MAXSIZE);
result = roll_log(channel);
result = isc_logfile_roll(&channel->destination.file);
if (result != ISC_R_SUCCESS) {
if ((channel->flags & ISC_LOG_OPENERR) == 0) {
syslog(LOG_ERR,
"isc_log_open: roll_log '%s' "
"isc_log_open: isc_logfile_roll '%s' "
"failed: %s",
FILE_NAME(channel),
isc_result_totext(result));
......
......@@ -399,6 +399,7 @@ isc_logconfig_create
isc_logconfig_destroy
isc_logconfig_get
isc_logconfig_use
isc_logfile_roll
isc_md5_final
isc_md5_init
isc_md5_invalidate
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment