diff --git a/CHANGES b/CHANGES index 60559a6cd5..0e18b48abe 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +4518. [func] The "print-time" option in the logging configuration + can now take arguments "local", "iso8601" or + "iso8601-utc" to indicate the format in which the + date and time should be logged. For backward + compatibility, "yes" is a synonym for "local". + [RT #42585] + 4517. [placeholder] 4516. [bug] isc_socketmgr_renderjson was missing from the diff --git a/bin/named/logconf.c b/bin/named/logconf.c index a96a35b537..02d4dec39f 100644 --- a/bin/named/logconf.c +++ b/bin/named/logconf.c @@ -87,8 +87,7 @@ category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) { * in 'cchan' and add it to 'logconfig'. */ static isc_result_t -channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) -{ +channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) { isc_result_t result; isc_logdestination_t dest; unsigned int type; @@ -202,12 +201,21 @@ channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) if (printcat != NULL && cfg_obj_asboolean(printcat)) flags |= ISC_LOG_PRINTCATEGORY; - if (printtime != NULL && cfg_obj_asboolean(printtime)) - flags |= ISC_LOG_PRINTTIME; if (printsev != NULL && cfg_obj_asboolean(printsev)) flags |= ISC_LOG_PRINTLEVEL; if (buffered != NULL && cfg_obj_asboolean(buffered)) flags |= ISC_LOG_BUFFERED; + if (printtime != NULL && cfg_obj_isboolean(printtime)) { + if (cfg_obj_asboolean(printtime)) + flags |= ISC_LOG_PRINTTIME; + } else if (printtime != NULL) { /* local/iso8601/iso8601-utc */ + const char *s = cfg_obj_asstring(printtime); + flags |= ISC_LOG_PRINTTIME; + if (strcasecmp(s, "iso8601") == 0) + flags |= ISC_LOG_ISO8601; + else if (strcasecmp(s, "iso8601-utc") == 0) + flags |= ISC_LOG_ISO8601 | ISC_LOG_UTC; + } } level = ISC_LOG_INFO; diff --git a/bin/tests/system/checkconf/bad-printtime.conf b/bin/tests/system/checkconf/bad-printtime.conf new file mode 100644 index 0000000000..3ae0b4c46a --- /dev/null +++ b/bin/tests/system/checkconf/bad-printtime.conf @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +logging { + channel one { + file "one.out"; + print-time bogus; + }; +}; diff --git a/bin/tests/system/checkconf/good-printtime.conf b/bin/tests/system/checkconf/good-printtime.conf new file mode 100644 index 0000000000..700e349452 --- /dev/null +++ b/bin/tests/system/checkconf/good-printtime.conf @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +logging { + channel one { + file "one.out"; + print-time no; + }; + channel two { + file "two.out"; + print-time yes; + }; + channel three { + file "three.out"; + print-time local; + }; + channel four { + file "four.out"; + print-time iso8601; + }; + channel five { + file "five.out"; + print-time iso8601-utc; + }; +}; diff --git a/bin/tests/system/logfileconfig/clean.sh b/bin/tests/system/logfileconfig/clean.sh index 002d0ac255..14b4ab3078 100644 --- a/bin/tests/system/logfileconfig/clean.sh +++ b/bin/tests/system/logfileconfig/clean.sh @@ -6,8 +6,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -# $Id: clean.sh,v 1.4 2011/03/22 16:51:50 smann Exp $ - # # Clean up after log file tests # @@ -19,4 +17,6 @@ rm -rf ns1/named_dir rm -f ns1/named_deflog rm -f ns*/named.lock rm -f ns1/query_log +rm -f ns1/named_iso8601 +rm -f ns1/named_iso8601_utc rm -f ns1/rndc.out.test* diff --git a/bin/tests/system/logfileconfig/ns1/named.iso8601 b/bin/tests/system/logfileconfig/ns1/named.iso8601 new file mode 100644 index 0000000000..3040855a81 --- /dev/null +++ b/bin/tests/system/logfileconfig/ns1/named.iso8601 @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on port 5300 { + 10.53.0.1; + }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +logging { + channel default_log { + file "named_iso8601"; + print-time iso8601; + severity debug 9; + }; + category default { default_log; default_debug; }; +}; + +controls { + inet 127.0.0.1 port 9593 + allow { 127.0.0.1/32; ::1/128; } + keys { "rndc-key"; }; +}; + +key "rndc-key" { + algorithm hmac-sha256; + secret "Am9vCg=="; +}; + +zone "." { + type master; + file "root.db"; +}; diff --git a/bin/tests/system/logfileconfig/ns1/named.iso8601-utc b/bin/tests/system/logfileconfig/ns1/named.iso8601-utc new file mode 100644 index 0000000000..14241c7135 --- /dev/null +++ b/bin/tests/system/logfileconfig/ns1/named.iso8601-utc @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on port 5300 { + 10.53.0.1; + }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +logging { + channel default_log { + file "named_iso8601_utc"; + print-time iso8601-utc; + severity debug 9; + }; + category default { default_log; default_debug; }; +}; + +controls { + inet 127.0.0.1 port 9593 + allow { 127.0.0.1/32; ::1/128; } + keys { "rndc-key"; }; +}; + +key "rndc-key" { + algorithm hmac-sha256; + secret "Am9vCg=="; +}; + +zone "." { + type master; + file "root.db"; +}; diff --git a/bin/tests/system/logfileconfig/tests.sh b/bin/tests/system/logfileconfig/tests.sh index b2acd3652e..44ef045143 100644 --- a/bin/tests/system/logfileconfig/tests.sh +++ b/bin/tests/system/logfileconfig/tests.sh @@ -12,16 +12,19 @@ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh THISDIR=`pwd` CONFDIR="ns1" -PLAINCONF="${THISDIR}/${CONFDIR}/named.plain" DIRCONF="${THISDIR}/${CONFDIR}/named.dirconf" PIPECONF="${THISDIR}/${CONFDIR}/named.pipeconf" SYMCONF="${THISDIR}/${CONFDIR}/named.symconf" PLAINCONF="${THISDIR}/${CONFDIR}/named.plainconf" +ISOCONF="${THISDIR}/${CONFDIR}/named.iso8601" +ISOCONFUTC="${THISDIR}/${CONFDIR}/named.iso8601-utc" PLAINFILE="named_log" DIRFILE="named_dir" PIPEFILE="named_pipe" SYMFILE="named_sym" DLFILE="named_deflog" +ISOFILE="named_iso8601" +ISOUTCFILE="named_iso8601_utc" PIDFILE="${THISDIR}/${CONFDIR}/named.pid" myRNDC="$RNDC -c ${THISDIR}/${CONFDIR}/rndc.conf" myNAMED="$NAMED -c ${THISDIR}/${CONFDIR}/named.conf -m record,size,mctx -T clienttest -T nosyslog -d 99 -X named.lock -U 4" @@ -238,10 +241,8 @@ else echo "I: skipping symlink test (unable to create symlink)" fi -status=0 - n=`expr $n + 1` -echo "I:testing default logfile using named -L file ($n)" +echo "I: testing default logfile using named -L file ($n)" # Now stop the server again and test the -L option rm -f $DLFILE $PERL ../../stop.pl .. ns1 @@ -270,5 +271,29 @@ else exit 1 fi +echo "I:testing logging functionality" + +n=`expr $n + 1` +echo "I: testing iso8601 timestamp ($n)" +cp $ISOCONF named.conf +$myRNDC reconfig > rndc.out.test$n 2>&1 +if grep '^....-..-..T..:..:..\.... ' $ISOFILE > /dev/null; then + echo "I: testing iso8601 timestamp succeeded" +else + echo "I: testing iso8601 timestamp failed" + status=`expr $status + 1` +fi + +n=`expr $n + 1` +echo "I: testing iso8601-utc timestamp ($n)" +cp $ISOCONFUTC named.conf +$myRNDC reconfig > rndc.out.test$n 2>&1 +if grep '^....-..-..T..:..:..\....Z' $ISOUTCFILE > /dev/null; then + echo "I: testing iso8601-utc timestamp succeeded" +else + echo "I: testing iso8601-utc timestamp failed" + status=`expr $status + 1` +fi + echo "I:exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 17d8272a47..9681c9cbcf 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -3644,7 +3644,7 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. | [ level ] | ); ] [ print-category or ; ] [ print-severity or ; ] - [ print-time or ; ] + [ print-time ( | | | | ) ; [ buffered or ; ] }; ] [ category category_name { @@ -3877,14 +3877,30 @@ notrace. All debugging messages in the server have a debug server's global debug level to determine what messages to print. - If print-time has been turned on, - then - the date and time will be logged. print-time may + print-time can be set to + yes, no, + or a time format specifier, which may be one of + , or + . If set to + no, then the date and time will + not be logged. If set to yes + or , the date and time are logged + in a human readable format, using the local time zone. + If set to the local time is + logged in ISO8601 format. If set to + , then the date and time + are logged in ISO8601 format, with time zone set to + UTC. The default is . + + + print-time may be specified for a syslog channel, - but is usually + but it is usually pointless since syslog also logs - the date and - time. If print-category is + the date and time. + + + If print-category is requested, then the category of the message will be logged as well. Finally, if print-severity is on, then the severity level of the message will be logged. The print- options may diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index af94d3089d..17220730d7 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -39,9 +39,10 @@ Added the ability to specify the maximum number of records - permitted in a zone (max-records #;). This provides a mechanism - to block overly large zone transfers, which is a potential risk - with slave zones from other parties, as described in CVE-2016-6170. + permitted in a zone (). + This provides a mechanism to block overly large zone + transfers, which is a potential risk with slave zones from + other parties, as described in CVE-2016-6170. [RT #42143] @@ -52,7 +53,13 @@ - None. + The option in the + configuration can now take arguments + local, iso8601 or + iso8601-utc to indicate the format in + which the date and time should be logged. For backward + compatibility, yes is a synonym for + local. [RT #42585] diff --git a/lib/isc/include/isc/log.h b/lib/isc/include/isc/log.h index 7780abf3da..e77bafd0ef 100644 --- a/lib/isc/include/isc/log.h +++ b/lib/isc/include/isc/log.h @@ -54,16 +54,18 @@ /*% * Channel flags. */ -#define ISC_LOG_PRINTTIME 0x0001 -#define ISC_LOG_PRINTLEVEL 0x0002 -#define ISC_LOG_PRINTCATEGORY 0x0004 -#define ISC_LOG_PRINTMODULE 0x0008 -#define ISC_LOG_PRINTTAG 0x0010 /* tag and ":" */ -#define ISC_LOG_PRINTPREFIX 0x0020 /* tag only, no colon */ -#define ISC_LOG_PRINTALL 0x003F -#define ISC_LOG_BUFFERED 0x0040 -#define ISC_LOG_DEBUGONLY 0x1000 -#define ISC_LOG_OPENERR 0x8000 /* internal */ +#define ISC_LOG_PRINTTIME 0x00001 +#define ISC_LOG_PRINTLEVEL 0x00002 +#define ISC_LOG_PRINTCATEGORY 0x00004 +#define ISC_LOG_PRINTMODULE 0x00008 +#define ISC_LOG_PRINTTAG 0x00010 /* tag and ":" */ +#define ISC_LOG_PRINTPREFIX 0x00020 /* tag only, no colon */ +#define ISC_LOG_PRINTALL 0x0003F +#define ISC_LOG_BUFFERED 0x00040 +#define ISC_LOG_DEBUGONLY 0x01000 +#define ISC_LOG_OPENERR 0x08000 /* internal */ +#define ISC_LOG_ISO8601 0x10000 /* if PRINTTIME, use ISO8601 */ +#define ISC_LOG_UTC 0x20000 /* if PRINTTIME, use UTC */ /*@}*/ /*@{*/ diff --git a/lib/isc/log.c b/lib/isc/log.c index 337a0d90d5..f5b1a1feac 100644 --- a/lib/isc/log.c +++ b/lib/isc/log.c @@ -697,7 +697,8 @@ isc_log_createchannel(isc_logconfig_t *lcfg, const char *name, isc_logchannel_t *channel; isc_mem_t *mctx; unsigned int permitted = ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY | - ISC_LOG_BUFFERED; + ISC_LOG_BUFFERED | ISC_LOG_ISO8601 | + ISC_LOG_UTC; REQUIRE(VALID_CONFIG(lcfg)); REQUIRE(name != NULL); @@ -1396,12 +1397,15 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, const char *format, va_list args) { int syslog_level; - char time_string[64]; + const char *time_string; + char local_time[64]; + char iso8601z_string[64]; + char iso8601l_string[64]; char level_string[24]; const char *iformat; struct stat statbuf; isc_boolean_t matched = ISC_FALSE; - isc_boolean_t printtime, printtag, printcolon; + isc_boolean_t printtime, iso8601, utc, printtag, printcolon; isc_boolean_t printcategory, printmodule, printlevel, buffered; isc_logconfig_t *lcfg; isc_logchannel_t *channel; @@ -1433,7 +1437,9 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, else iformat = format; - time_string[0] = '\0'; + local_time[0] = '\0'; + iso8601l_string[0] = '\0'; + iso8601z_string[0] = '\0'; level_string[0] = '\0'; LOCK(&lctx->lock); @@ -1496,12 +1502,21 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, continue; if ((channel->flags & ISC_LOG_PRINTTIME) != 0 && - time_string[0] == '\0') { + local_time[0] == '\0') + { isc_time_t isctime; TIME_NOW(&isctime); - isc_time_formattimestamp(&isctime, time_string, - sizeof(time_string)); + + isc_time_formattimestamp(&isctime, + local_time, + sizeof(local_time)); + isc_time_formatISO8601ms(&isctime, + iso8601z_string, + sizeof(iso8601z_string)); + isc_time_formatISO8601Lms(&isctime, + iso8601l_string, + sizeof(iso8601l_string)); } if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 && @@ -1628,6 +1643,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, } } + utc = ISC_TF((channel->flags & ISC_LOG_UTC) != 0); + iso8601 = ISC_TF((channel->flags & ISC_LOG_ISO8601) != 0); printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME) != 0); printtag = ISC_TF((channel->flags & @@ -1644,6 +1661,19 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, buffered = ISC_TF((channel->flags & ISC_LOG_BUFFERED) != 0); + if (printtime) { + if (iso8601) { + if (utc) { + time_string = iso8601z_string; + } else { + time_string = iso8601l_string; + } + } else { + time_string = local_time; + } + } else + time_string = ""; + switch (channel->type) { case ISC_LOG_TOFILE: if (FILE_MAXREACHED(channel)) { @@ -1691,7 +1721,7 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, case ISC_LOG_TOFILEDESC: fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n", - printtime ? time_string : "", + printtime ? time_string : "", printtime ? " " : "", printtag ? lcfg->tag : "", printcolon ? ": " : "", diff --git a/lib/isc/tests/time_test.c b/lib/isc/tests/time_test.c index 810c77c6e7..46109dc3c8 100644 --- a/lib/isc/tests/time_test.c +++ b/lib/isc/tests/time_test.c @@ -8,6 +8,7 @@ #include #include +#include #include @@ -33,11 +34,118 @@ ATF_TC_BODY(isc_time_parsehttptimestamp, tc) { ATF_REQUIRE_EQ(isc_time_seconds(&t), isc_time_seconds(&x)); } +ATF_TC(isc_time_formatISO8601); +ATF_TC_HEAD(isc_time_formatISO8601, tc) { + atf_tc_set_md_var(tc, "descr", "print UTC in ISO8601"); +} +ATF_TC_BODY(isc_time_formatISO8601, tc) { + isc_result_t result; + isc_time_t t; + char buf[64]; + + setenv("TZ", "PST8PDT", 1); + result = isc_time_now(&t); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* yyyy-mm-ddThh:mm:ssZ */ + memset(buf, 'X', sizeof(buf)); + isc_time_formatISO8601(&t, buf, sizeof(buf)); + ATF_CHECK_EQ(strlen(buf), 20); + ATF_CHECK_EQ(buf[4], '-'); + ATF_CHECK_EQ(buf[7], '-'); + ATF_CHECK_EQ(buf[10], 'T'); + ATF_CHECK_EQ(buf[13], ':'); + ATF_CHECK_EQ(buf[16], ':'); + ATF_CHECK_EQ(buf[19], 'Z'); +} + +ATF_TC(isc_time_formatISO8601ms); +ATF_TC_HEAD(isc_time_formatISO8601ms, tc) { + atf_tc_set_md_var(tc, "descr", + "print UTC in ISO8601 with milliseconds"); +} +ATF_TC_BODY(isc_time_formatISO8601ms, tc) { + isc_result_t result; + isc_time_t t; + char buf[64]; + + setenv("TZ", "PST8PDT", 1); + result = isc_time_now(&t); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* yyyy-mm-ddThh:mm:ss.sssZ */ + memset(buf, 'X', sizeof(buf)); + isc_time_formatISO8601ms(&t, buf, sizeof(buf)); + ATF_CHECK_EQ(strlen(buf), 24); + ATF_CHECK_EQ(buf[4], '-'); + ATF_CHECK_EQ(buf[7], '-'); + ATF_CHECK_EQ(buf[10], 'T'); + ATF_CHECK_EQ(buf[13], ':'); + ATF_CHECK_EQ(buf[16], ':'); + ATF_CHECK_EQ(buf[19], '.'); + ATF_CHECK_EQ(buf[23], 'Z'); +} + +ATF_TC(isc_time_formatISO8601L); +ATF_TC_HEAD(isc_time_formatISO8601L, tc) { + atf_tc_set_md_var(tc, "descr", + "print local time in ISO8601"); +} +ATF_TC_BODY(isc_time_formatISO8601L, tc) { + isc_result_t result; + isc_time_t t; + char buf[64]; + + setenv("TZ", "PST8PDT", 1); + result = isc_time_now(&t); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* yyyy-mm-ddThh:mm:ss */ + memset(buf, 'X', sizeof(buf)); + isc_time_formatISO8601L(&t, buf, sizeof(buf)); + ATF_CHECK_EQ(strlen(buf), 19); + ATF_CHECK_EQ(buf[4], '-'); + ATF_CHECK_EQ(buf[7], '-'); + ATF_CHECK_EQ(buf[10], 'T'); + ATF_CHECK_EQ(buf[13], ':'); + ATF_CHECK_EQ(buf[16], ':'); +} + +ATF_TC(isc_time_formatISO8601Lms); +ATF_TC_HEAD(isc_time_formatISO8601Lms, tc) { + atf_tc_set_md_var(tc, "descr", + "print local time in ISO8601 with milliseconds"); +} +ATF_TC_BODY(isc_time_formatISO8601Lms, tc) { + isc_result_t result; + isc_time_t t; + char buf[64]; + + setenv("TZ", "PST8PDT", 1); + result = isc_time_now(&t); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* yyyy-mm-ddThh:mm:ss.sss */ + memset(buf, 'X', sizeof(buf)); + isc_time_formatISO8601Lms(&t, buf, sizeof(buf)); + ATF_CHECK_EQ(strlen(buf), 23); + ATF_CHECK_EQ(buf[4], '-'); + ATF_CHECK_EQ(buf[7], '-'); + ATF_CHECK_EQ(buf[10], 'T'); + ATF_CHECK_EQ(buf[13], ':'); + ATF_CHECK_EQ(buf[16], ':'); + ATF_CHECK_EQ(buf[19], '.'); +} + /* * Main */ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, isc_time_parsehttptimestamp); + ATF_TP_ADD_TC(tp, isc_time_formatISO8601); + ATF_TP_ADD_TC(tp, isc_time_formatISO8601ms); + ATF_TP_ADD_TC(tp, isc_time_formatISO8601L); + ATF_TP_ADD_TC(tp, isc_time_formatISO8601Lms); return (atf_no_error()); } diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h index 939db5d761..47ccd53098 100644 --- a/lib/isc/unix/include/isc/time.h +++ b/lib/isc/unix/include/isc/time.h @@ -323,6 +323,34 @@ isc_time_parsehttptimestamp(char *input, isc_time_t *t); *\li 'buf' and 't' are not NULL. */ +void +isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + +void +isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + void isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len); /*%< diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c index 59008466de..f7d40306f0 100644 --- a/lib/isc/unix/time.c +++ b/lib/isc/unix/time.c @@ -424,6 +424,34 @@ isc_time_parsehttptimestamp(char *buf, isc_time_t *t) { return (ISC_R_SUCCESS); } +void +isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) { + time_t now; + unsigned int flen; + + REQUIRE(len > 0); + + now = (time_t)t->seconds; + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime(&now)); + INSIST(flen < len); +} + +void +isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) { + time_t now; + unsigned int flen; + + REQUIRE(len > 0); + + now = (time_t)t->seconds; + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime(&now)); + INSIST(flen < len); + if (flen > 0U && len - flen >= 6) { + snprintf(buf + flen, len - flen, ".%03u", + t->nanoseconds / NS_PER_MS); + } +} + void isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { time_t now; @@ -446,8 +474,8 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) { now = (time_t)t->seconds; flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); INSIST(flen < len); - if (flen == len - 5) { - flen -= 1; /* rewind one character */ + if (flen > 0U && len - flen >= 5) { + flen -= 1; /* rewind one character (Z) */ snprintf(buf + flen, len - flen, ".%03uZ", t->nanoseconds / NS_PER_MS); } diff --git a/lib/isc/win32/include/isc/time.h b/lib/isc/win32/include/isc/time.h index 4e10a3837e..4b244dba95 100644 --- a/lib/isc/win32/include/isc/time.h +++ b/lib/isc/win32/include/isc/time.h @@ -287,6 +287,34 @@ isc_time_parsehttptimestamp(char *input, isc_time_t *t); *\li 'buf' and 't' are not NULL. */ +void +isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + +void +isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + void isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len); /*%< diff --git a/lib/isc/win32/time.c b/lib/isc/win32/time.c index eaeb69d80f..43e9a84ec1 100644 --- a/lib/isc/win32/time.c +++ b/lib/isc/win32/time.c @@ -328,6 +328,49 @@ isc_time_parsehttptimestamp(char *buf, isc_time_t *t) { return (ISC_R_SUCCESS); } +void +isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) { + SYSTEMTIME st; + char DateBuf[50]; + char TimeBuf[50]; + + /* strtime() format: "%Y-%m-%dT%H:%M:%S" */ + + REQUIRE(len > 0); + if (FileTimeToSystemTime(&t->absolute, &st)) { + GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd", + DateBuf, 50); + GetTimeFormat(LOCALE_USER_DEFAULT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &st, "hh':'mm':'ss", TimeBuf, 50); + snprintf(buf, len, "%sT%s", DateBuf, TimeBuf); + } else { + buf[0] = 0; + } +} + +void +isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) { + SYSTEMTIME st; + char DateBuf[50]; + char TimeBuf[50]; + + /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSS" */ + + REQUIRE(len > 0); + if (FileTimeToSystemTime(&t->absolute, &st)) { + GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd", + DateBuf, 50); + GetTimeFormat(LOCALE_USER_DEFAULT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &st, "hh':'mm':'ss", TimeBuf, 50); + snprintf(buf, len, "%sT%s.%03u", DateBuf, TimeBuf, + st.wMilliseconds); + } else { + buf[0] = 0; + } +} + void isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { SYSTEMTIME st; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 66c4ae2c7c..ee38ffc780 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -123,6 +123,7 @@ static cfg_type_t cfg_type_optional_port; static cfg_type_t cfg_type_optional_uint32; static cfg_type_t cfg_type_options; static cfg_type_t cfg_type_portiplist; +static cfg_type_t cfg_type_printtime; static cfg_type_t cfg_type_querysource4; static cfg_type_t cfg_type_querysource6; static cfg_type_t cfg_type_querysource; @@ -2070,7 +2071,6 @@ static cfg_type_t cfg_type_server = { server_clausesets }; - /*% * Clauses that can be found in a 'channel' clause in the * 'logging' statement. @@ -2078,8 +2078,24 @@ static cfg_type_t cfg_type_server = { * These have some additional constraints that need to be * checked after parsing: * - There must exactly one of file/syslog/null/stderr - * */ + +static const char *printtime_enums[] = { + "local", "iso8601", "iso8601-utc", NULL +}; +static isc_result_t +parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); +} +static void +doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) { + doc_enum_or_other(pctx, type, &cfg_type_boolean); +} +static cfg_type_t cfg_type_printtime = { + "printtime", parse_printtime, cfg_print_ustring, doc_printtime, + &cfg_rep_string, printtime_enums +}; + static cfg_clausedef_t channel_clauses[] = { /* Destinations. We no longer require these to be first. */ @@ -2089,7 +2105,7 @@ channel_clauses[] = { { "stderr", &cfg_type_void, 0 }, /* Options. We now accept these for the null channel, too. */ { "severity", &cfg_type_logseverity, 0 }, - { "print-time", &cfg_type_boolean, 0 }, + { "print-time", &cfg_type_printtime, 0 }, { "print-severity", &cfg_type_boolean, 0 }, { "print-category", &cfg_type_boolean, 0 }, { "buffered", &cfg_type_boolean, 0 },