mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
Allow for key lifetime unlimited
The keyword 'unlimited' can be used instead of PT0S which means the same but is more comprehensible for users. Also fix some redundant "none" parameters in the kasp test.
This commit is contained in:
committed by
Evan Hunt
parent
9dc630016e
commit
2733edb2a6
@@ -115,7 +115,7 @@ dlz <replaceable>string</replaceable> {
|
||||
<literallayout class="normal">
|
||||
dnssec-policy <replaceable>string</replaceable> {
|
||||
dnskey-ttl <replaceable>duration</replaceable>;
|
||||
keys { ( csk | ksk | zsk ) ( key-directory ) lifetime <replaceable>duration</replaceable>
|
||||
keys { ( csk | ksk | zsk ) ( key-directory ) lifetime ( <replaceable>duration</replaceable> | unlimited )
|
||||
algorithm <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ]; ... };
|
||||
max-zone-ttl <replaceable>duration</replaceable>;
|
||||
parent-ds-ttl <replaceable>duration</replaceable>;
|
||||
|
@@ -19,7 +19,7 @@ dnssec-policy "test" {
|
||||
keys {
|
||||
ksk key-directory lifetime P1Y algorithm 13 256;
|
||||
zsk key-directory lifetime P30D algorithm 13;
|
||||
csk key-directory lifetime P30D algorithm 8 2048;
|
||||
csk key-directory lifetime unlimited algorithm 8 2048;
|
||||
};
|
||||
max-zone-ttl 86400;
|
||||
parent-ds-ttl 7200;
|
||||
|
@@ -45,6 +45,13 @@ zone "default.kasp" {
|
||||
dnssec-policy "default";
|
||||
};
|
||||
|
||||
/* Key lifetime unlimited. */
|
||||
zone "unlimited.kasp" {
|
||||
type master;
|
||||
file "unlimited.kasp.db";
|
||||
dnssec-policy "unlimited";
|
||||
};
|
||||
|
||||
/* A master zone with dnssec-policy, no keys created. */
|
||||
zone "rsasha1.kasp" {
|
||||
type master;
|
||||
|
@@ -9,6 +9,14 @@
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
dnssec-policy "unlimited" {
|
||||
dnskey-ttl 1234;
|
||||
|
||||
keys {
|
||||
csk key-directory lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "rsasha1" {
|
||||
dnskey-ttl 1234;
|
||||
|
||||
|
@@ -43,7 +43,8 @@ U="UNRETENTIVE"
|
||||
# Set up zones that will be initially signed.
|
||||
#
|
||||
for zn in default rsasha1 dnssec-keygen some-keys legacy-keys pregenerated \
|
||||
rumoured rsasha1-nsec3 rsasha256 rsasha512 ecdsa256 ecdsa384 inherit
|
||||
rumoured rsasha1-nsec3 rsasha256 rsasha512 ecdsa256 ecdsa384 \
|
||||
inherit unlimited
|
||||
do
|
||||
setup "${zn}.kasp"
|
||||
cp template.db.in "$zonefile"
|
||||
|
@@ -1026,6 +1026,22 @@ check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
|
||||
#
|
||||
# Zone: unlimited.kasp.
|
||||
#
|
||||
zone_properties "ns3" "unlimited.kasp" "unlimited" "1234" "1" "10.53.0.3"
|
||||
key_properties "KEY1" "csk" "0" "13" "ECDSAP256SHA256" "256" "yes" "yes"
|
||||
key_clear "KEY2"
|
||||
key_clear "KEY3"
|
||||
# The first key is immediately published and activated.
|
||||
key_timings "KEY1" "published" "active" "none" "none" "none"
|
||||
# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
|
||||
key_states "KEY1" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden"
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
#
|
||||
# Zone: inherit.kasp.
|
||||
#
|
||||
@@ -1451,7 +1467,7 @@ check_subdomain
|
||||
# ns5/override.inherit.signed
|
||||
# ns5/inherit.override.signed
|
||||
key_properties "KEY1" "csk" "0" "13" "ECDSAP256SHA256" "256" "yes" "yes"
|
||||
key_timings "KEY1" "published" "active" "none" "none" "none" "none"
|
||||
key_timings "KEY1" "published" "active" "none" "none" "none"
|
||||
key_states "KEY1" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden"
|
||||
|
||||
zone_properties "ns2" "signed.tld" "default" "3600" "1" "10.53.0.2"
|
||||
@@ -1496,7 +1512,7 @@ dnssec_verify
|
||||
# ns5/override.override.unsigned
|
||||
# ns5/override.none.unsigned
|
||||
key_properties "KEY1" "csk" "0" "14" "ECDSAP384SHA384" "384" "yes" "yes"
|
||||
key_timings "KEY1" "published" "active" "none" "none" "none" "none"
|
||||
key_timings "KEY1" "published" "active" "none" "none" "none"
|
||||
key_states "KEY1" "omnipresent" "rumoured" "rumoured" "rumoured" "hidden"
|
||||
|
||||
zone_properties "ns4" "inherit.inherit.signed" "test" "3600" "1" "10.53.0.4"
|
||||
|
@@ -11113,7 +11113,7 @@ example.com CNAME rpz-tcp-only.
|
||||
</para>
|
||||
|
||||
<programlisting>keys {
|
||||
ksk key-directory lifetime P5Y algorithm 8 2048;
|
||||
ksk key-directory lifetime unlimited algorithm 8 2048;
|
||||
zsk key-directory lifetime P30D algorithm 8;
|
||||
csk key-directory lifetime P6MT12H3M15S algorithm 13;
|
||||
};
|
||||
@@ -11133,16 +11133,27 @@ example.com CNAME rpz-tcp-only.
|
||||
<command>key-directory</command>.
|
||||
</para>
|
||||
<para>
|
||||
The third token tells how long the key may be used. In the
|
||||
example the first key has a lifetime of 5 years, the second
|
||||
key may be used for 30 days and the third key has a rather
|
||||
peculiar lifetime of 6 months, 12 hours, 3 minutes and 15
|
||||
seconds.
|
||||
The <command>lifetime</command> parameter specifies how
|
||||
long a key may be used before rolling over. In the
|
||||
example above, the first key will have an unlimited
|
||||
lifetime, the second key may be used for 30 days, and the
|
||||
third key has a rather peculiar lifetime of 6 months,
|
||||
12 hours, 3 minutes and 15 seconds. A lifetime of 0
|
||||
seconds is the same as <command>unlimited</command>.
|
||||
</para>
|
||||
<para>
|
||||
The last token(s) are the key's algorithm and algorithm
|
||||
length. The length may be omitted as shown in the
|
||||
example for the second and third key.
|
||||
Note that the lifetime of a key may be extended if
|
||||
retiring it too soon would cause validation failures:
|
||||
for example, if the key were configured to roll more
|
||||
frequently than its TTL, its lifetime would
|
||||
automatically be extended to account for this.
|
||||
</para>
|
||||
<para>
|
||||
The <command>algorithm</command> parameter(s) are the key's
|
||||
algorithm, expressed numerically, and its size in bits. The
|
||||
size may be omitted, as shown in the example for the
|
||||
second and third keys; in this case an appropriate
|
||||
default size will be used.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@@ -14,7 +14,7 @@
|
||||
<programlisting>
|
||||
<command>dnssec-policy</command> <replaceable>string</replaceable> {
|
||||
<command>dnskey-ttl</command> <replaceable>duration</replaceable>;
|
||||
<command>keys</command> { ( csk | ksk | zsk ) key-directory lifetime <replaceable>duration</replaceable> algorithm <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ] ; ... };
|
||||
<command>keys</command> { ( csk | ksk | zsk ) key-directory lifetime ( <replaceable>duration</replaceable> | unlimited ) algorithm <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ] ; ... };
|
||||
<command>max-zone-ttl</command> <replaceable>duration</replaceable>;
|
||||
<command>parent-ds-ttl</command> <replaceable>duration</replaceable>;
|
||||
<command>parent-propagation-delay</command> <replaceable>duration</replaceable>;
|
||||
|
@@ -199,9 +199,9 @@ is referred to as a CSK. Below is an example configuration for the three types
|
||||
of keys:
|
||||
```
|
||||
keys {
|
||||
ksk key-directory lifetime P5Y algorithm ECDSAP256SHA256;
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime P30D algorithm ECDSAP256SHA256;
|
||||
csk key-directory lifetime PT0S algorithm 8 2048;
|
||||
csk key-directory lifetime P5Y algorithm 8 2048;
|
||||
};
|
||||
```
|
||||
|
||||
|
@@ -2,7 +2,7 @@ dnssec-policy "default" {
|
||||
|
||||
// Keys
|
||||
keys {
|
||||
csk key-directory lifetime 0 algorithm 13;
|
||||
csk key-directory lifetime unlimited algorithm 13;
|
||||
};
|
||||
|
||||
// Key timings
|
||||
|
@@ -23,7 +23,7 @@ dlz <string> {
|
||||
|
||||
dnssec-policy <string> {
|
||||
dnskey-ttl <duration>;
|
||||
keys { ( csk | ksk | zsk ) ( key-directory ) lifetime <duration>
|
||||
keys { ( csk | ksk | zsk ) ( key-directory ) lifetime ( <duration> | unlimited )
|
||||
algorithm <integer> [ <integer> ]; ... };
|
||||
max-zone-ttl <duration>;
|
||||
parent-ds-ttl <duration>;
|
||||
|
@@ -23,7 +23,7 @@ dlz <string> {
|
||||
|
||||
dnssec-policy <string> {
|
||||
dnskey-ttl <duration>;
|
||||
keys { ( csk | ksk | zsk ) ( key-directory ) lifetime <duration>
|
||||
keys { ( csk | ksk | zsk ) ( key-directory ) lifetime ( <duration> | unlimited )
|
||||
algorithm <integer> [ <integer> ]; ... };
|
||||
max-zone-ttl <duration>;
|
||||
parent-ds-ttl <duration>;
|
||||
|
@@ -173,6 +173,7 @@ struct cfg_duration {
|
||||
*/
|
||||
uint32_t parts[7];
|
||||
bool iso8601;
|
||||
bool unlimited;
|
||||
};
|
||||
|
||||
/*%
|
||||
@@ -344,6 +345,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_unsupported;
|
||||
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_fixedpoint;
|
||||
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_percentage;
|
||||
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_duration;
|
||||
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_duration_or_unlimited;
|
||||
/*@}*/
|
||||
|
||||
isc_result_t
|
||||
@@ -535,6 +537,13 @@ cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
|
||||
void
|
||||
cfg_print_duration(cfg_printer_t *pctx, const cfg_obj_t *obj);
|
||||
|
||||
isc_result_t
|
||||
cfg_parse_duration_or_unlimited(cfg_parser_t *pctx, const cfg_type_t *type,
|
||||
cfg_obj_t **ret);
|
||||
|
||||
void
|
||||
cfg_print_duration_or_unlimited(cfg_printer_t *pctx, const cfg_obj_t *obj);
|
||||
|
||||
isc_result_t
|
||||
cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
|
||||
|
||||
|
@@ -78,7 +78,7 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t* kasp)
|
||||
if (config == NULL) {
|
||||
/* We are creating a key reference for the default kasp. */
|
||||
key->role |= DNS_KASP_KEY_ROLE_KSK | DNS_KASP_KEY_ROLE_ZSK;
|
||||
key->lifetime = 0;
|
||||
key->lifetime = 0; /* unlimited */
|
||||
key->algorithm = DNS_KEYALG_ECDSA256;
|
||||
key->length = -1;
|
||||
} else {
|
||||
@@ -94,10 +94,16 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t* kasp)
|
||||
key->role |= DNS_KASP_KEY_ROLE_KSK;
|
||||
key->role |= DNS_KASP_KEY_ROLE_ZSK;
|
||||
}
|
||||
key->lifetime = cfg_obj_asduration(
|
||||
cfg_tuple_get(config, "lifetime"));
|
||||
key->algorithm = cfg_obj_asuint32(
|
||||
cfg_tuple_get(config, "algorithm"));
|
||||
|
||||
key->lifetime = 0; /* unlimited */
|
||||
obj = cfg_tuple_get(config, "lifetime");
|
||||
if (cfg_obj_isduration(obj)) {
|
||||
key->lifetime = cfg_obj_asduration(obj);
|
||||
}
|
||||
|
||||
obj = cfg_tuple_get(config, "algorithm");
|
||||
key->algorithm = cfg_obj_asuint32(obj);
|
||||
|
||||
obj = cfg_tuple_get(config, "length");
|
||||
if (cfg_obj_isuint32(obj)) {
|
||||
key->length = cfg_obj_asuint32(obj);
|
||||
|
@@ -96,7 +96,7 @@ static cfg_type_t cfg_type_logseverity;
|
||||
static cfg_type_t cfg_type_logsuffix;
|
||||
static cfg_type_t cfg_type_logversions;
|
||||
static cfg_type_t cfg_type_masterselement;
|
||||
static cfg_type_t cfg_type_maxttl;
|
||||
static cfg_type_t cfg_type_maxduration;
|
||||
static cfg_type_t cfg_type_minimal;
|
||||
static cfg_type_t cfg_type_nameportiplist;
|
||||
static cfg_type_t cfg_type_notifytype;
|
||||
@@ -439,6 +439,24 @@ static cfg_type_t cfg_type_category = {
|
||||
&cfg_rep_tuple, category_fields
|
||||
};
|
||||
|
||||
static isc_result_t
|
||||
parse_maxduration(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
||||
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_duration, ret));
|
||||
}
|
||||
|
||||
static void
|
||||
doc_maxduration(cfg_printer_t *pctx, const cfg_type_t *type) {
|
||||
cfg_doc_enum_or_other(pctx, type, &cfg_type_duration);
|
||||
}
|
||||
|
||||
/*%
|
||||
* A duration or "unlimited", but not "default".
|
||||
*/
|
||||
static const char *maxduration_enums[] = { "unlimited", NULL };
|
||||
static cfg_type_t cfg_type_maxduration = {
|
||||
"maxduration_no_default", parse_maxduration, cfg_print_ustring,
|
||||
doc_maxduration, &cfg_rep_duration, maxduration_enums
|
||||
};
|
||||
|
||||
/*%
|
||||
* A dnssec key, as used in the "trusted-keys" statement.
|
||||
@@ -509,7 +527,8 @@ static cfg_type_t cfg_type_algorithm = {
|
||||
doc_keyvalue, &cfg_rep_uint32, &algorithm_kw
|
||||
};
|
||||
|
||||
static keyword_type_t lifetime_kw = { "lifetime", &cfg_type_duration };
|
||||
static keyword_type_t lifetime_kw = { "lifetime",
|
||||
&cfg_type_duration_or_unlimited };
|
||||
static cfg_type_t cfg_type_lifetime = {
|
||||
"lifetime", parse_keyvalue, print_keyvalue,
|
||||
doc_keyvalue, &cfg_rep_duration, &lifetime_kw
|
||||
@@ -2227,7 +2246,7 @@ zone_clauses[] = {
|
||||
{ "max-transfer-time-out", &cfg_type_uint32,
|
||||
CFG_ZONE_MASTER | CFG_ZONE_MIRROR | CFG_ZONE_SLAVE
|
||||
},
|
||||
{ "max-zone-ttl", &cfg_type_maxttl,
|
||||
{ "max-zone-ttl", &cfg_type_maxduration,
|
||||
CFG_ZONE_MASTER | CFG_ZONE_REDIRECT
|
||||
},
|
||||
{ "min-refresh-time", &cfg_type_uint32,
|
||||
@@ -3867,25 +3886,6 @@ static cfg_type_t cfg_type_masterselement = {
|
||||
doc_masterselement, NULL, NULL
|
||||
};
|
||||
|
||||
static isc_result_t
|
||||
parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
||||
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_duration, ret));
|
||||
}
|
||||
|
||||
static void
|
||||
doc_maxttl(cfg_printer_t *pctx, const cfg_type_t *type) {
|
||||
cfg_doc_enum_or_other(pctx, type, &cfg_type_duration);
|
||||
}
|
||||
|
||||
/*%
|
||||
* A size or "unlimited", but not "default".
|
||||
*/
|
||||
static const char *maxttl_enums[] = { "unlimited", NULL };
|
||||
static cfg_type_t cfg_type_maxttl = {
|
||||
"maxttl_no_default", parse_maxttl, cfg_print_ustring, doc_maxttl,
|
||||
&cfg_rep_string, maxttl_enums
|
||||
};
|
||||
|
||||
static int cmp_clause(const void *ap, const void *bp) {
|
||||
const cfg_clausedef_t *a = (const cfg_clausedef_t *)ap;
|
||||
const cfg_clausedef_t *b = (const cfg_clausedef_t *)bp;
|
||||
|
@@ -1088,6 +1088,22 @@ cfg_print_duration(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
||||
cfg_print_chars(pctx, buf, strlen(buf));
|
||||
}
|
||||
|
||||
void
|
||||
cfg_print_duration_or_unlimited(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
||||
cfg_duration_t duration;
|
||||
|
||||
REQUIRE(pctx != NULL);
|
||||
REQUIRE(obj != NULL);
|
||||
|
||||
duration = obj->value.duration;
|
||||
|
||||
if (duration.unlimited) {
|
||||
cfg_print_cstr(pctx, "unlimited");
|
||||
} else {
|
||||
cfg_print_duration(pctx, obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
cfg_obj_isduration(const cfg_obj_t *obj) {
|
||||
REQUIRE(obj != NULL);
|
||||
@@ -1250,21 +1266,14 @@ duration_fromtext(isc_textregion_t *source, cfg_duration_t *duration) {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
|
||||
cfg_obj_t **ret)
|
||||
static isc_result_t
|
||||
cfg__parse_duration(cfg_parser_t *pctx, cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
cfg_obj_t *obj = NULL;
|
||||
cfg_duration_t duration;
|
||||
|
||||
UNUSED(type);
|
||||
|
||||
CHECK(cfg_gettoken(pctx, 0));
|
||||
if (pctx->token.type != isc_tokentype_string) {
|
||||
result = ISC_R_UNEXPECTEDTOKEN;
|
||||
goto cleanup;
|
||||
}
|
||||
duration.unlimited = false;
|
||||
|
||||
if (TOKEN_STRING(pctx)[0] == 'P') {
|
||||
result = duration_fromtext(&pctx->token.value.as_textregion,
|
||||
@@ -1278,12 +1287,9 @@ cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
|
||||
* With dns_ttl_fromtext() the information on optional units.
|
||||
* is lost, and is treated as seconds from now on.
|
||||
*/
|
||||
duration.parts[0] = 0;
|
||||
duration.parts[1] = 0;
|
||||
duration.parts[2] = 0;
|
||||
duration.parts[3] = 0;
|
||||
duration.parts[4] = 0;
|
||||
duration.parts[5] = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
duration.parts[i] = 0;
|
||||
}
|
||||
duration.parts[6] = ttl;
|
||||
duration.iso8601 = false;
|
||||
}
|
||||
@@ -1305,6 +1311,66 @@ cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
|
||||
cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(type);
|
||||
|
||||
CHECK(cfg_gettoken(pctx, 0));
|
||||
if (pctx->token.type != isc_tokentype_string) {
|
||||
result = ISC_R_UNEXPECTEDTOKEN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return cfg__parse_duration(pctx, ret);
|
||||
|
||||
cleanup:
|
||||
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
||||
"expected ISO 8601 duration or TTL value");
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_parse_duration_or_unlimited(cfg_parser_t *pctx, const cfg_type_t *type,
|
||||
cfg_obj_t **ret)
|
||||
{
|
||||
isc_result_t result;
|
||||
cfg_obj_t *obj = NULL;
|
||||
cfg_duration_t duration;
|
||||
|
||||
UNUSED(type);
|
||||
|
||||
CHECK(cfg_gettoken(pctx, 0));
|
||||
if (pctx->token.type != isc_tokentype_string) {
|
||||
result = ISC_R_UNEXPECTEDTOKEN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (strcmp(TOKEN_STRING(pctx), "unlimited") == 0) {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
duration.parts[i] = 0;
|
||||
}
|
||||
duration.iso8601 = false;
|
||||
duration.unlimited = true;
|
||||
|
||||
CHECK(cfg_create_obj(pctx, &cfg_type_duration, &obj));
|
||||
obj->value.duration = duration;
|
||||
*ret = obj;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
return cfg__parse_duration(pctx, ret);
|
||||
|
||||
cleanup:
|
||||
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
||||
"expected ISO 8601 duration, TTL value, or unlimited");
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
/*%
|
||||
* A duration as defined by ISO 8601 (P[n]Y[n]M[n]DT[n]H[n]M[n]S).
|
||||
* - P is the duration indicator ("period") placed at the start.
|
||||
@@ -1324,6 +1390,11 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_duration = {
|
||||
"duration", cfg_parse_duration, cfg_print_duration, cfg_doc_terminal,
|
||||
&cfg_rep_duration, NULL
|
||||
};
|
||||
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_duration_or_unlimited = {
|
||||
"duration_or_unlimited", cfg_parse_duration_or_unlimited,
|
||||
cfg_print_duration_or_unlimited, cfg_doc_terminal,
|
||||
&cfg_rep_duration, NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* qstring (quoted string), ustring (unquoted string), astring
|
||||
|
@@ -72,6 +72,7 @@ cfg_parse_bracketed_list
|
||||
cfg_parse_buffer
|
||||
cfg_parse_dscp
|
||||
cfg_parse_duration
|
||||
cfg_parse_duration_or_unlimited
|
||||
cfg_parse_enum
|
||||
cfg_parse_enum_or_other
|
||||
cfg_parse_file
|
||||
@@ -112,6 +113,7 @@ cfg_print_chars
|
||||
cfg_print_clauseflags
|
||||
cfg_print_cstr
|
||||
cfg_print_duration
|
||||
cfg_print_duration_or_unlimited
|
||||
cfg_print_fixedpoint
|
||||
cfg_print_grammar
|
||||
cfg_print_indent
|
||||
|
Reference in New Issue
Block a user