forwarder mode options for library.

git-svn-id: file:///svn/unbound/trunk@895 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-01-24 14:58:51 +00:00
parent 452b7cc069
commit 2e28288b1d
9 changed files with 263 additions and 42 deletions

View file

@ -5,6 +5,8 @@
- make pipe nonblocking at start. - make pipe nonblocking at start.
- update plane for retry mode with caution to limit bandwidth. - update plane for retry mode with caution to limit bandwidth.
- fix Makefile for concurrent make of unbound-host. - fix Makefile for concurrent make of unbound-host.
- renamed ub_val_ctx_wait/poll/process/fd to ub_val*.
- new calls to set forwarding added to header and docs.
23 January 2008: Wouter 23 January 2008: Wouter
- removed debug prints from if-auto, verb-algo enables some. - removed debug prints from if-auto, verb-algo enables some.

View file

@ -17,15 +17,17 @@
.B ub_val_ctx_create, .B ub_val_ctx_create,
.B ub_val_ctx_delete, .B ub_val_ctx_delete,
.B ub_val_ctx_config, .B ub_val_ctx_config,
.B ub_val_ctx_set_fwd,
.B ub_val_ctx_resolvconf,
.B ub_val_ctx_add_ta, .B ub_val_ctx_add_ta,
.B ub_val_ctx_add_ta_file, .B ub_val_ctx_add_ta_file,
.B ub_val_ctx_trustedkeys, .B ub_val_ctx_trustedkeys,
.B ub_val_ctx_debuglevel, .B ub_val_ctx_debuglevel,
.B ub_val_ctx_async, .B ub_val_ctx_async,
.B ub_val_ctx_poll, .B ub_val_poll,
.B ub_val_ctx_wait, .B ub_val_wait,
.B ub_val_ctx_fd, .B ub_val_fd,
.B ub_val_ctx_process, .B ub_val_process,
.B ub_val_resolve, .B ub_val_resolve,
.B ub_val_resolve_async, .B ub_val_resolve_async,
.B ub_val_cancel, .B ub_val_cancel,
@ -46,6 +48,12 @@
\fBub_val_ctx_config\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname); \fBub_val_ctx_config\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname);
.LP .LP
\fIint\fR \fIint\fR
\fBub_val_ctx_set_fwd\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR addr);
.LP
\fIint\fR
\fBub_val_ctx_resolvconf\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname);
.LP
\fIint\fR
\fBub_val_ctx_add_ta\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR ta); \fBub_val_ctx_add_ta\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR ta);
.LP .LP
\fIint\fR \fIint\fR
@ -65,16 +73,16 @@
\fBub_val_ctx_async\fR(\fIstruct ub_val_ctx*\fR ctx, \fIint\fR dothread); \fBub_val_ctx_async\fR(\fIstruct ub_val_ctx*\fR ctx, \fIint\fR dothread);
.LP .LP
\fIint\fR \fIint\fR
\fBub_val_ctx_poll\fR(\fIstruct ub_val_ctx*\fR ctx); \fBub_val_poll\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP .LP
\fIint\fR \fIint\fR
\fBub_val_ctx_wait\fR(\fIstruct ub_val_ctx*\fR ctx); \fBub_val_wait\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP .LP
\fIint\fR \fIint\fR
\fBub_val_ctx_fd\fR(\fIstruct ub_val_ctx*\fR ctx); \fBub_val_fd\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP .LP
\fIint\fR \fIint\fR
\fBub_val_ctx_process\fR(\fIstruct ub_val_ctx*\fR ctx); \fBub_val_process\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP .LP
\fIint\fR \fIint\fR
\fBub_val_resolve\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR name, \fBub_val_resolve\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR name,
@ -138,6 +146,25 @@ A power\-user interface that lets you specify an unbound config file, see
relevant. For some specific options, such as adding trust anchors, special relevant. For some specific options, such as adding trust anchors, special
routines exist. routines exist.
.TP .TP
.B ub_val_ctx_set_fwd
Set machine to forward DNS queries to, the caching resolver to use.
IP4 or IP6 address. Forwards all DNS requests to that machine, which
is expected to run a recursive resolver. If the proxy is not
DNSSEC capable, validation may fail. Can be called several times, in
that case the addresses are used as backup servers.
At this time it is only possible to set configuration before the
first resolve is done.
.TP
.B ub_val_ctx_resolvconf
Read list of nameservers to use from the filename given.
Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
If they do not support DNSSEC, validation may fail.
Only nameservers are picked up, the searchdomain, ndots and other
settings from \fIresolv.conf\fR(5) are ignored.
If fname NULL is passed, "/etc/resolv.conf" is used.
At this time it is only possible to set configuration before the
first resolve is done.
.TP
.B .B
ub_val_ctx_add_ta ub_val_ctx_add_ta
Add a trust anchor to the given context. Add a trust anchor to the given context.
@ -173,27 +200,27 @@ Changes to this setting after
calls have been made have no effect (delete and re\-create the context calls have been made have no effect (delete and re\-create the context
to change). to change).
.TP .TP
.B ub_val_ctx_poll .B ub_val_poll
Poll a context to see if it has any new results. Poll a context to see if it has any new results.
Do not poll in a loop, instead extract the fd below to poll for readiness, Do not poll in a loop, instead extract the fd below to poll for readiness,
and then check, or wait using the wait routine. and then check, or wait using the wait routine.
Returns 0 if nothing to read, or nonzero if a result is available. Returns 0 if nothing to read, or nonzero if a result is available.
If nonzero, call If nonzero, call
.B ub_val_ctx_process .B ub_val_process
to do callbacks. to do callbacks.
.TP .TP
.B ub_val_ctx_wait .B ub_val_wait
Wait for a context to finish with results. Calls Wait for a context to finish with results. Calls
.B ub_val_ctx_process .B ub_val_process
after the wait for you. After the wait, there are no more outstanding after the wait for you. After the wait, there are no more outstanding
asynchronous queries. asynchronous queries.
.TP .TP
.B ub_val_ctx_fd .B ub_val_fd
Get file descriptor. Wait for it to become readable, at this point Get file descriptor. Wait for it to become readable, at this point
answers are returned from the asynchronous validating resolver. answers are returned from the asynchronous validating resolver.
Then call the \fBub_val_ctx_process\fR to continue processing. Then call the \fBub_val_process\fR to continue processing.
.TP .TP
.B ub_val_ctx_process .B ub_val_process
Call this routine to continue processing results from the validating Call this routine to continue processing results from the validating
resolver (when the fd becomes readable). resolver (when the fd becomes readable).
Will perform necessary callbacks. Will perform necessary callbacks.
@ -264,9 +291,9 @@ to obtain a readable error string.
returns a zero terminated string. returns a zero terminated string.
.B ub_val_ctx_create .B ub_val_ctx_create
returns NULL on an error (a malloc failure). returns NULL on an error (a malloc failure).
.B ub_val_ctx_poll .B ub_val_poll
returns true if some information may be available, false otherwise. returns true if some information may be available, false otherwise.
.B ub_val_ctx_fd .B ub_val_fd
returns a file descriptor or -1 on error. returns a file descriptor or -1 on error.
.SH "SEE ALSO" .SH "SEE ALSO"
\fIunbound.conf\fR(5), \fIunbound.conf\fR(5),

View file

@ -175,7 +175,9 @@ enum ub_ctx_err {
/** initialization failed (bad settings) */ /** initialization failed (bad settings) */
UB_INITFAIL = -7, UB_INITFAIL = -7,
/** error in pipe communication with async bg worker */ /** error in pipe communication with async bg worker */
UB_PIPE = -8 UB_PIPE = -8,
/** error reading from file (resolv.conf) */
UB_READFILE = -9
}; };
/** /**

View file

@ -1,15 +1,17 @@
ub_val_ctx_create ub_val_ctx_create
ub_val_ctx_delete ub_val_ctx_delete
ub_val_ctx_config ub_val_ctx_config
ub_val_ctx_set_fwd
ub_val_ctx_resolvconf
ub_val_ctx_add_ta ub_val_ctx_add_ta
ub_val_ctx_add_ta_file ub_val_ctx_add_ta_file
ub_val_ctx_trustedkeys ub_val_ctx_trustedkeys
ub_val_ctx_debuglevel ub_val_ctx_debuglevel
ub_val_ctx_async ub_val_ctx_async
ub_val_ctx_poll ub_val_poll
ub_val_ctx_wait ub_val_wait
ub_val_ctx_fd ub_val_fd
ub_val_ctx_process ub_val_process
ub_val_resolve ub_val_resolve
ub_val_resolve_async ub_val_resolve_async
ub_val_cancel ub_val_cancel

View file

@ -319,7 +319,7 @@ pollit(struct ub_val_ctx* ctx, struct timeval* t)
} }
int int
ub_val_ctx_poll(struct ub_val_ctx* ctx) ub_val_poll(struct ub_val_ctx* ctx)
{ {
struct timeval t; struct timeval t;
int r; int r;
@ -331,7 +331,7 @@ ub_val_ctx_poll(struct ub_val_ctx* ctx)
} }
int int
ub_val_ctx_wait(struct ub_val_ctx* ctx) ub_val_wait(struct ub_val_ctx* ctx)
{ {
int r; int r;
lock_basic_lock(&ctx->cfglock); lock_basic_lock(&ctx->cfglock);
@ -341,7 +341,7 @@ ub_val_ctx_wait(struct ub_val_ctx* ctx)
r = pollit(ctx, NULL); r = pollit(ctx, NULL);
lock_basic_unlock(&ctx->rrpipe_lock); lock_basic_unlock(&ctx->rrpipe_lock);
if(r) if(r)
ub_val_ctx_process(ctx); ub_val_process(ctx);
lock_basic_lock(&ctx->cfglock); lock_basic_lock(&ctx->cfglock);
} }
lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->cfglock);
@ -349,7 +349,7 @@ ub_val_ctx_wait(struct ub_val_ctx* ctx)
} }
int int
ub_val_ctx_fd(struct ub_val_ctx* ctx) ub_val_fd(struct ub_val_ctx* ctx)
{ {
int fd; int fd;
lock_basic_lock(&ctx->rrpipe_lock); lock_basic_lock(&ctx->rrpipe_lock);
@ -418,7 +418,7 @@ process_answer(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len)
} }
int int
ub_val_ctx_process(struct ub_val_ctx* ctx) ub_val_process(struct ub_val_ctx* ctx)
{ {
int r; int r;
uint8_t* msg = NULL; uint8_t* msg = NULL;
@ -601,6 +601,127 @@ ub_val_strerror(int err)
case UB_INITFAIL: return "initialization failure"; case UB_INITFAIL: return "initialization failure";
case UB_AFTERFINAL: return "setting change after finalize"; case UB_AFTERFINAL: return "setting change after finalize";
case UB_PIPE: return "error in pipe communication with async"; case UB_PIPE: return "error in pipe communication with async";
case UB_READFILE: return "error reading file";
default: return "unknown error"; default: return "unknown error";
} }
} }
int
ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr)
{
struct sockaddr_storage storage;
socklen_t stlen;
struct config_stub* s;
char* dupl;
lock_basic_lock(&ctx->cfglock);
if(ctx->finalized) {
lock_basic_unlock(&ctx->cfglock);
errno=EINVAL;
return UB_AFTERFINAL;
}
if(!addr) {
/* disable fwd mode - the root stub should be first. */
if(ctx->env->cfg->forwards &&
strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
s = ctx->env->cfg->forwards;
ctx->env->cfg->forwards = s->next;
s->next = NULL;
config_delstubs(s);
}
lock_basic_unlock(&ctx->cfglock);
return UB_NOERROR;
}
lock_basic_unlock(&ctx->cfglock);
/* check syntax for addr */
if(!extstrtoaddr(addr, &storage, &stlen)) {
errno=EINVAL;
return UB_SYNTAX;
}
/* it parses, add root stub in front of list */
lock_basic_lock(&ctx->cfglock);
if(!ctx->env->cfg->forwards ||
strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
s = calloc(1, sizeof(*s));
if(!s) {
lock_basic_unlock(&ctx->cfglock);
errno=ENOMEM;
return UB_NOMEM;
}
s->name = strdup(".");
if(!s->name) {
free(s);
lock_basic_unlock(&ctx->cfglock);
errno=ENOMEM;
return UB_NOMEM;
}
s->next = ctx->env->cfg->forwards;
ctx->env->cfg->forwards = s;
} else {
log_assert(ctx->env->cfg->forwards);
s = ctx->env->cfg->forwards;
}
dupl = strdup(addr);
if(!dupl) {
lock_basic_unlock(&ctx->cfglock);
errno=ENOMEM;
return UB_NOMEM;
}
if(!cfg_strlist_insert(&s->addrs, dupl)) {
free(dupl);
lock_basic_unlock(&ctx->cfglock);
errno=ENOMEM;
return UB_NOMEM;
}
lock_basic_unlock(&ctx->cfglock);
return UB_NOERROR;
}
int
ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname)
{
FILE* in;
int numserv = 0;
char buf[1024];
char* parse, *addr;
int r;
if(fname == NULL)
fname = "/etc/resolv.conf";
in = fopen(fname, "r");
if(!in) {
/* error in errno! perror(fname) */
return UB_READFILE;
}
while(fgets(buf, (int)sizeof(buf), in)) {
buf[sizeof(buf)-1] = 0;
parse=buf;
while(*parse == ' ' || *parse == '\t')
parse++;
if(strncmp(parse, "nameserver", 10) == 0) {
numserv++;
parse += 10; /* skip 'nameserver' */
/* skip whitespace */
while(*parse == ' ' || *parse == '\t')
parse++;
addr = parse;
/* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
while(isxdigit(*parse) || *parse=='.' || *parse==':')
parse++;
/* terminate after the address, remove newline */
*parse = 0;
if((r = ub_val_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
fclose(in);
return r;
}
}
}
fclose(in);
if(numserv == 0) {
/* from resolv.conf(5) if none given, use localhost */
log_info("resconf: no nameservers, using localhost");
return ub_val_ctx_set_fwd(ctx, "127.0.0.1");
}
return UB_NOERROR;
}

View file

@ -57,15 +57,15 @@
* Application not threaded. Non-blocking ('asynchronous'). * Application not threaded. Non-blocking ('asynchronous').
* err = ub_val_resolve_async(ctx, "www.example.com", ... my_callback); * err = ub_val_resolve_async(ctx, "www.example.com", ... my_callback);
* ... application resumes processing ... * ... application resumes processing ...
* ... and when either ub_val_ctx_poll(ctx) is true * ... and when either ub_val_poll(ctx) is true
* ... or when the file descriptor ub_val_ctx_fd(ctx) is readable, * ... or when the file descriptor ub_val_fd(ctx) is readable,
* ... or whenever, the app calls ... * ... or whenever, the app calls ...
* ub_val_ctx_process(ctx); * ub_val_process(ctx);
* ... if no result is ready, the app resumes processing above, * ... if no result is ready, the app resumes processing above,
* ... or process() calls my_callback() with results. * ... or process() calls my_callback() with results.
* *
* ... if the application has nothing more to do, wait for answer * ... if the application has nothing more to do, wait for answer
* ub_val_ctx_wait(ctx); * ub_val_wait(ctx);
* *
* Application threaded. Blocking. * Application threaded. Blocking.
* Blocking, same as above. The current thread does the work. * Blocking, same as above. The current thread does the work.
@ -84,7 +84,7 @@
* Otherwise, for asynchronous with threading, a worker thread is created. * Otherwise, for asynchronous with threading, a worker thread is created.
* *
* The blocking calls use shared ctx-cache when threaded. Thus * The blocking calls use shared ctx-cache when threaded. Thus
* ub_val_resolve() and ub_val_resolve_async() && ub_val_ctx_wait() are * ub_val_resolve() and ub_val_resolve_async() && ub_val_wait() are
* not the same. The first makes the current thread do the work, setting * not the same. The first makes the current thread do the work, setting
* up buffers, etc, to perform the work (but using shared cache data). * up buffers, etc, to perform the work (but using shared cache data).
* The second calls another worker thread (or process) to perform the work. * The second calls another worker thread (or process) to perform the work.
@ -217,6 +217,41 @@ void ub_val_ctx_delete(struct ub_val_ctx* ctx);
*/ */
int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname); int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname);
/**
* Set machine to forward DNS queries to, the caching resolver to use.
* IP4 or IP6 address. Forwards all DNS requests to that machine, which
* is expected to run a recursive resolver. If the proxy is not
* DNSSEC-capable, validation may fail. Can be called several times, in
* that case the addresses are used as backup servers.
*
* To read the list of nameservers from /etc/resolv.conf (from DHCP or so),
* use the call ub_val_ctx_resolvconf.
*
* @param ctx: context.
* At this time it is only possible to set configuration before the
* first resolve is done.
* @param addr: address, IP4 or IP6 in string format.
* If the addr is NULL, forwarding is disabled.
* @return 0 if OK, else error.
*/
int ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr);
/**
* Read list of nameservers to use from the filename given.
* Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
* If they do not support DNSSEC, validation may fail.
*
* Only nameservers are picked up, the searchdomain, ndots and other
* settings from resolv.conf(5) are ignored.
*
* @param ctx: context.
* At this time it is only possible to set configuration before the
* first resolve is done.
* @param fname: file name string. If NULL "/etc/resolv.conf" is used.
* @return 0 if OK, else error.
*/
int ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname);
/** /**
* Add a trust anchor to the given context. * Add a trust anchor to the given context.
* The trust anchor is a string, on one line, that holds a valid DNSKEY or * The trust anchor is a string, on one line, that holds a valid DNSKEY or
@ -283,27 +318,27 @@ int ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread);
* @return: 0 if nothing to read, or nonzero if a result is available. * @return: 0 if nothing to read, or nonzero if a result is available.
* If nonzero, call ctx_process() to do callbacks. * If nonzero, call ctx_process() to do callbacks.
*/ */
int ub_val_ctx_poll(struct ub_val_ctx* ctx); int ub_val_poll(struct ub_val_ctx* ctx);
/** /**
* Wait for a context to finish with results. Calls ctx_process() after * Wait for a context to finish with results. Calls ub_val_process() after
* the wait for you. After the wait, there are no more outstanding * the wait for you. After the wait, there are no more outstanding
* asynchronous queries. * asynchronous queries.
* @param ctx: context. * @param ctx: context.
* @return: 0 if OK, else error. * @return: 0 if OK, else error.
*/ */
int ub_val_ctx_wait(struct ub_val_ctx* ctx); int ub_val_wait(struct ub_val_ctx* ctx);
/** /**
* Get file descriptor. Wait for it to become readable, at this point * Get file descriptor. Wait for it to become readable, at this point
* answers are returned from the asynchronous validating resolver. * answers are returned from the asynchronous validating resolver.
* Then call the ub_val_ctx_process to continue processing. * Then call the ub_val_process to continue processing.
* This routine works immediately after context creation, the fd * This routine works immediately after context creation, the fd
* does not change. * does not change.
* @param ctx: context. * @param ctx: context.
* @return: -1 on error, or file descriptor to use select(2) with. * @return: -1 on error, or file descriptor to use select(2) with.
*/ */
int ub_val_ctx_fd(struct ub_val_ctx* ctx); int ub_val_fd(struct ub_val_ctx* ctx);
/** /**
* Call this routine to continue processing results from the validating * Call this routine to continue processing results from the validating
@ -312,7 +347,7 @@ int ub_val_ctx_fd(struct ub_val_ctx* ctx);
* @param ctx: context * @param ctx: context
* @return: 0 if OK, else error. * @return: 0 if OK, else error.
*/ */
int ub_val_ctx_process(struct ub_val_ctx* ctx); int ub_val_process(struct ub_val_ctx* ctx);
/** /**
* Perform resolution and validation of the target name. * Perform resolution and validation of the target name.

View file

@ -69,6 +69,8 @@ void usage(char* argv[])
printf("-d : enable debug output\n"); printf("-d : enable debug output\n");
printf("-t : use a resolver thread instead of forking a process\n"); printf("-t : use a resolver thread instead of forking a process\n");
printf("-c : cancel the requests\n"); printf("-c : cancel the requests\n");
printf("-r fname : read resolv.conf from fname\n");
printf("-f addr : use addr, forward to that server\n");
exit(1); exit(1);
} }
@ -119,6 +121,26 @@ int main(int argc, char** argv)
argc--; argc--;
argv++; argv++;
} }
if(argc > 1 && strcmp(argv[0], "-r") == 0) {
r = ub_val_ctx_resolvconf(ctx, argv[1]);
if(r != 0) {
printf("ub_val_ctx_resolvconf error: %s : %s\n",
ub_val_strerror(r), strerror(errno));
return 1;
}
argc-=2;
argv+=2;
}
if(argc > 1 && strcmp(argv[0], "-f") == 0) {
r = ub_val_ctx_set_fwd(ctx, argv[1]);
if(r != 0) {
printf("ub_val_ctx_set_fwd error: %s\n",
ub_val_strerror(r));
return 1;
}
argc-=2;
argv+=2;
}
/* allocate array for results. */ /* allocate array for results. */
lookups = (struct lookinfo*)calloc((size_t)argc, lookups = (struct lookinfo*)calloc((size_t)argc,
@ -136,6 +158,11 @@ int main(int argc, char** argv)
r = ub_val_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A, r = ub_val_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A,
LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done, LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done,
&lookups[i].async_id); &lookups[i].async_id);
if(r != 0) {
printf("ub_val_resolve_async error: %s\n",
ub_val_strerror(r));
return 1;
}
} }
if(cancel) { if(cancel) {
for(i=0; i<argc; i++) { for(i=0; i<argc; i++) {
@ -149,9 +176,9 @@ int main(int argc, char** argv)
for(i=0; i<1000; i++) { for(i=0; i<1000; i++) {
usleep(100000); usleep(100000);
fprintf(stderr, "%g seconds passed\n", 0.1*(double)i); fprintf(stderr, "%g seconds passed\n", 0.1*(double)i);
r = ub_val_ctx_process(ctx); r = ub_val_process(ctx);
if(r != 0) { if(r != 0) {
printf("ub_val_ctx_process error: %s\n", printf("ub_val_process error: %s\n",
ub_val_strerror(r)); ub_val_strerror(r));
return 1; return 1;
} }

View file

@ -220,8 +220,7 @@ config_deldblstrlist(struct config_str2list* p)
} }
} }
/** delete config stublist */ void
static void
config_delstubs(struct config_stub* p) config_delstubs(struct config_stub* p)
{ {
struct config_stub* np; struct config_stub* np;

View file

@ -298,6 +298,12 @@ void config_delstrlist(struct config_strlist* list);
*/ */
void config_deldblstrlist(struct config_str2list* list); void config_deldblstrlist(struct config_str2list* list);
/**
* Delete items in config stub list.
* @param list: list.
*/
void config_delstubs(struct config_stub* list);
/** /**
* Convert 14digit to time value * Convert 14digit to time value
* @param str: string of 14 digits * @param str: string of 14 digits