From 82e4110e090a8f6806ff72765d33170abfafb220 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 11 Feb 2008 15:46:40 +0000 Subject: [PATCH] moved from trunk. git-svn-id: file:///svn/unbound/tags/release-0.9@947 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/stats.c | 6 +- daemon/worker.c | 4 +- doc/Changelog | 5 + doc/libunbound.3 | 202 +++++++++++++++++++++---------------- libunbound/context.c | 30 +++--- libunbound/context.h | 28 ++--- libunbound/libunbound.c | 174 +++++++++++++++++++++++++------- libunbound/libworker.c | 16 +-- libunbound/libworker.h | 12 +-- libunbound/ubsyms.def | 41 ++++---- libunbound/unbound.h | 128 +++++++++++++++-------- services/mesh.c | 17 ++-- smallapp/unbound-host.c | 30 +++--- testcode/asynclook.c | 101 ++++++++++--------- testdata/05-asynclook.tpkg | Bin 1873 -> 2138 bytes util/config_file.c | 162 +++++++++++++++++++++++++++++ util/config_file.h | 11 ++ util/log.c | 8 +- util/log.h | 7 ++ util/timehist.c | 4 +- util/timehist.h | 3 +- 21 files changed, 689 insertions(+), 300 deletions(-) diff --git a/daemon/stats.c b/daemon/stats.c index d16627c38..8c2b917b4 100644 --- a/daemon/stats.c +++ b/daemon/stats.c @@ -59,10 +59,12 @@ void server_stats_querymiss(struct server_stats* stats, struct worker* worker) void server_stats_log(struct server_stats* stats, int threadnum) { - log_info("server stats for thread %d: %u queries, %u from cache", + log_info("server stats for thread %d: %u queries, " + "%u answers from cache, %u recursions", threadnum, (unsigned)stats->num_queries, (unsigned)(stats->num_queries - - stats->num_queries_missed_cache)); + stats->num_queries_missed_cache), + (unsigned)stats->num_queries_missed_cache); log_info("server stats for thread %d: requestlist max %u avg %g " "exceeded %u", threadnum, (unsigned)stats->max_query_list_size, stats->num_queries_missed_cache? diff --git a/daemon/worker.c b/daemon/worker.c index cededdf6c..0893ac13f 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -874,8 +874,8 @@ worker_restart_timer(struct worker* worker) void worker_stat_timer_cb(void* arg) { struct worker* worker = (struct worker*)arg; - mesh_stats(worker->env.mesh, "mesh has"); server_stats_log(&worker->stats, worker->thread_num); + mesh_stats(worker->env.mesh, "mesh has"); worker_mem_report(worker, NULL); server_stats_init(&worker->stats); mesh_stats_clear(worker->env.mesh); @@ -1046,8 +1046,8 @@ worker_delete(struct worker* worker) if(!worker) return; if(worker->env.mesh && verbosity >= VERB_OPS) { - mesh_stats(worker->env.mesh, "mesh has"); server_stats_log(&worker->stats, worker->thread_num); + mesh_stats(worker->env.mesh, "mesh has"); worker_mem_report(worker, NULL); } mesh_delete(worker->env.mesh); diff --git a/doc/Changelog b/doc/Changelog index f7b29e396..c4f4317d4 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,8 @@ +11 February 2008: Wouter + - nicer statistic output (from trunk). + - ub_val to ub_ for library API (from trunk). + - (from trunk) set_option, set_debugout, etc/hosts handling. + 8 February 2008: Wouter - test program for multiple queries over a TCP channel. - tpkg test for stream tcp queries. diff --git a/doc/libunbound.3 b/doc/libunbound.3 index ead195dbb..81e8de1ca 100644 --- a/doc/libunbound.3 +++ b/doc/libunbound.3 @@ -11,101 +11,109 @@ .LP .B libunbound, .B unbound.h, -.B ub_val_ctx, -.B ub_val_result, -.B ub_val_callback_t, -.B ub_val_ctx_create, -.B ub_val_ctx_delete, -.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_file, -.B ub_val_ctx_trustedkeys, -.B ub_val_ctx_debuglevel, -.B ub_val_ctx_async, -.B ub_val_poll, -.B ub_val_wait, -.B ub_val_fd, -.B ub_val_process, -.B ub_val_resolve, -.B ub_val_resolve_async, -.B ub_val_cancel, -.B ub_val_resolve_free, -.B ub_val_strerror +.B ub_ctx, +.B ub_result, +.B ub_callback_t, +.B ub_ctx_create, +.B ub_ctx_delete, +.B ub_ctx_set_option, +.B ub_ctx_config, +.B ub_ctx_set_fwd, +.B ub_ctx_resolvconf, +.B ub_ctx_hosts, +.B ub_ctx_add_ta, +.B ub_ctx_add_ta_file, +.B ub_ctx_trustedkeys, +.B ub_ctx_debugout, +.B ub_ctx_debuglevel, +.B ub_ctx_async, +.B ub_poll, +.B ub_wait, +.B ub_fd, +.B ub_process, +.B ub_resolve, +.B ub_resolve_async, +.B ub_cancel, +.B ub_resolve_free, +.B ub_strerror \- Unbound DNS validating resolver @version@ functions. .SH "SYNOPSIS" .LP .B #include .LP -\fIstruct ub_val_ctx *\fR -\fBub_val_ctx_create\fR(\fIvoid\fR); +\fIstruct ub_ctx *\fR +\fBub_ctx_create\fR(\fIvoid\fR); .LP \fIvoid\fR -\fBub_val_ctx_delete\fR(\fIstruct ub_val_ctx*\fR ctx); +\fBub_ctx_delete\fR(\fIstruct ub_ctx*\fR ctx); .LP \fIint\fR -\fBub_val_ctx_config\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname); +\fBub_ctx_set_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar*\fR val); .LP \fIint\fR -\fBub_val_ctx_set_fwd\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR addr); +\fBub_ctx_config\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR -\fBub_val_ctx_resolvconf\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname); +\fBub_ctx_set_fwd\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR addr); .LP \fIint\fR -\fBub_val_ctx_add_ta\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR ta); +\fBub_ctx_resolvconf\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR -\fBub_val_ctx_add_ta_file\fR(\fIstruct ub_val_ctx*\fR ctx, -.br - \fIchar*\fR fname); +\fBub_ctx_hosts\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR -\fBub_val_ctx_trustedkeys\fR(\fIstruct ub_val_ctx*\fR ctx, -.br - \fIchar*\fR fname); +\fBub_ctx_add_ta\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR ta); .LP \fIint\fR -\fBub_val_ctx_debuglevel\fR(\fIstruct ub_val_ctx*\fR ctx, \fIint\fR d); +\fBub_ctx_add_ta_file\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR -\fBub_val_ctx_async\fR(\fIstruct ub_val_ctx*\fR ctx, \fIint\fR dothread); +\fBub_ctx_trustedkeys\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR -\fBub_val_poll\fR(\fIstruct ub_val_ctx*\fR ctx); +\fBub_ctx_debugout\fR(\fIstruct ub_ctx*\fR ctx, \fIFILE*\fR out); .LP \fIint\fR -\fBub_val_wait\fR(\fIstruct ub_val_ctx*\fR ctx); +\fBub_ctx_debuglevel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR d); .LP \fIint\fR -\fBub_val_fd\fR(\fIstruct ub_val_ctx*\fR ctx); +\fBub_ctx_async\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR dothread); .LP \fIint\fR -\fBub_val_process\fR(\fIstruct ub_val_ctx*\fR ctx); +\fBub_poll\fR(\fIstruct ub_ctx*\fR ctx); .LP \fIint\fR -\fBub_val_resolve\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR name, +\fBub_wait\fR(\fIstruct ub_ctx*\fR ctx); +.LP +\fIint\fR +\fBub_fd\fR(\fIstruct ub_ctx*\fR ctx); +.LP +\fIint\fR +\fBub_process\fR(\fIstruct ub_ctx*\fR ctx); +.LP +\fIint\fR +\fBub_resolve\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name, .br \fIint\fR rrtype, \fIint\fR rrclass, \fIint*\fR secure, .br - \fIint*\fR data, \fIstruct ub_val_result**\fR result); + \fIint*\fR data, \fIstruct ub_result**\fR result); .LP \fIint\fR -\fBub_val_resolve_async\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR name, +\fBub_resolve_async\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name, .br \fIint\fR rrtype, \fIint\fR rrclass, \fIvoid*\fR mydata, .br - \fIub_val_callback_t\fR callback, \fIint*\fR async_id); + \fIub_callback_t\fR callback, \fIint*\fR async_id); .LP \fIint\fR -\fBub_val_cancel\fR(\fIstruct ub_val_ctx*\fR ctx, \fIint\fR async_id); +\fBub_cancel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR async_id); .LP \fIvoid\fR -\fBub_val_resolve_free\fR(\fIstruct ub_val_result*\fR result); +\fBub_resolve_free\fR(\fIstruct ub_result*\fR result); .LP \fIconst char *\fR -\fBub_val_strerror\fR(\fIint\fR err); +\fBub_strerror\fR(\fIint\fR err); .SH "DESCRIPTION" .LP .B Unbound @@ -116,11 +124,11 @@ The library can be used to convert hostnames to ip addresses, and back, and obtain other information from the DNS. The library performs public\-key validation of results with DNSSEC. .P -The library uses a variable of type \fIstruct ub_val_ctx\fR to keep context +The library uses a variable of type \fIstruct ub_ctx\fR to keep context between calls. The user must maintain it, creating it with -.B ub_val_ctx_create +.B ub_ctx_create and deleting it with -.B ub_val_ctx_delete\fR. +.B ub_ctx_delete\fR. It can be created and deleted at any time. Creating it anew removes any previous configuration (such as trusted keys) and clears any cached results. .P @@ -133,20 +141,32 @@ can go on, while the results become available later. The functions are discussed in turn below. .SH "FUNCTIONS" .TP -.B ub_val_ctx_create +.B ub_ctx_create Create a new context, initialised with defaults. +The information from /etc/resolv.conf and /etc/hosts is not utilised +by default. Use +.B ub_ctx_resolvconf +and +.B ub_ctx_hosts +to read them. .TP -.B ub_val_ctx_delete +.B ub_ctx_delete Delete validation context and free associated resources. Outstanding async queries are killed and callbacks are not called for them. .TP -.B ub_val_ctx_config +.B ub_ctx_set_option +A power\-user interface that lets you specify one of the options from the +config file format, see \fIunbound.conf\fR(5). Not all options are +relevant. For some specific options, such as adding trust anchors, special +routines exist. Pass the option name with the trailing ':'. +.TP +.B ub_ctx_config A power\-user interface that lets you specify an unbound config file, see \fIunbound.conf\fR(5), which is read for configuration. Not all options are relevant. For some specific options, such as adding trust anchors, special routines exist. .TP -.B ub_val_ctx_set_fwd +.B ub_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 @@ -155,7 +175,7 @@ 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 +.B ub_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. @@ -165,67 +185,79 @@ 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 ub_ctx_hosts +Read list of hosts from the filename given. +Usually "/etc/hosts". When queried for, these addresses are not marked +DNSSEC secure. If fname NULL is passed, "/etc/hosts" is used. +At this time it is only possible to set configuration before the +first resolve is done. +.TP .B -ub_val_ctx_add_ta +ub_ctx_add_ta Add a trust anchor to the given context. At this time it is only possible to add trusted keys before the first resolve is done. The format is a string, similar to the zone-file format, [domainname] [type] [rdata contents]. Both DS and DNSKEY records are accepted. .TP -.B ub_val_ctx_add_ta_file +.B ub_ctx_add_ta_file Add trust anchors to the given context. Pass name of a file with DS and DNSKEY records in zone file format. At this time it is only possible to add trusted keys before the first resolve is done. .TP -.B ub_val_ctx_trustedkeys +.B ub_ctx_trustedkeys Add trust anchors to the given context. Pass the name of a bind-style config file with trusted-keys{}. At this time it is only possible to add trusted keys before the first resolve is done. .TP -.B ub_val_ctx_debuglevel +.B ub_ctx_debugout +Set debug and error log output to the given stream. Pass NULL to disable +output. Default is stderr. File-names or using syslog can be enabled +using config options, this routine is for using your own stream. +.TP +.B ub_ctx_debuglevel Set debug verbosity for the context. Output is directed to stderr. Higher debug level gives more output. .TP -.B ub_val_ctx_async +.B ub_ctx_async Set a context behaviour for asynchronous action. if set to true, enables threading and a call to -.B ub_val_resolve_async +.B ub_resolve_async creates a thread to handle work in the background. If false, a process is forked to handle work in the background. Changes to this setting after -.B ub_val_resolve_async +.B ub_resolve_async calls have been made have no effect (delete and re\-create the context to change). .TP -.B ub_val_poll +.B ub_poll 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, and then check, or wait using the wait routine. Returns 0 if nothing to read, or nonzero if a result is available. If nonzero, call -.B ub_val_process +.B ub_process to do callbacks. .TP -.B ub_val_wait +.B ub_wait Wait for a context to finish with results. Calls -.B ub_val_process +.B ub_process after the wait for you. After the wait, there are no more outstanding asynchronous queries. .TP -.B ub_val_fd +.B ub_fd Get file descriptor. Wait for it to become readable, at this point answers are returned from the asynchronous validating resolver. -Then call the \fBub_val_process\fR to continue processing. +Then call the \fBub_process\fR to continue processing. .TP -.B ub_val_process +.B ub_process Call this routine to continue processing results from the validating resolver (when the fd becomes readable). Will perform necessary callbacks. .TP -.B ub_val_resolve +.B ub_resolve Perform resolution and validation of the target name. The name is a domain name in a zero terminated text string. The rrtype and rrclass are DNS type and class codes. @@ -233,9 +265,9 @@ The value secure returns true if the answer validated securely. The value data returns true if there was data. The result structure is newly allocated with the resulting data. .TP -.B ub_val_resolve_async +.B ub_resolve_async Perform asynchronous resolution and validation of the target name. -Arguments mean the same as for \fBub_val_resolve\fR except no +Arguments mean the same as for \fBub_resolve\fR except no data is returned immediately, instead a callback is called later. The callback receives a copy of the mydata pointer, that you can use to pass information to the callback. The callback type is a function pointer to @@ -243,27 +275,27 @@ a function declared as .IP void my_callback_function(void* my_arg, int err, .br - struct ub_val_result* result); + struct ub_result* result); .IP The async_id is returned so you can (at your option) decide to track it and cancel the request if needed. .TP -.B ub_val_cancel +.B ub_cancel Cancel an async query in progress. .TP -.B ub_val_resolve_free -Free struct ub_val_result contents after use. +.B ub_resolve_free +Free struct ub_result contents after use. .TP -.B ub_val_strerror +.B ub_strerror Convert error value from one of the unbound library functions to a human readable string. .SH "RESULT DATA STRUCTURE" .LP The result of the DNS resolution and validation is returned as -\fIstruct ub_val_result\fR. The result structure contains the following entries. +\fIstruct ub_result\fR. The result structure contains the following entries. .P .nf - struct ub_val_result { + struct ub_result { char* qname; /* text string, original question */ int qtype; /* type code asked for */ int qclass; /* class code asked for */ @@ -283,15 +315,15 @@ domain of the query. .SH "RETURN VALUES" Many routines return an error code. The value 0 (zero) denotes no error happened. Other values can be passed to -.B ub_val_strerror +.B ub_strerror to obtain a readable error string. -.B ub_val_strerror +.B ub_strerror returns a zero terminated string. -.B ub_val_ctx_create +.B ub_ctx_create returns NULL on an error (a malloc failure). -.B ub_val_poll +.B ub_poll returns true if some information may be available, false otherwise. -.B ub_val_fd +.B ub_fd returns a file descriptor or -1 on error. .SH "SEE ALSO" \fIunbound.conf\fR(5), diff --git a/libunbound/context.c b/libunbound/context.c index e95ca7953..dc6137920 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -51,11 +51,13 @@ #include "util/storage/slabhash.h" int -context_finalize(struct ub_val_ctx* ctx) +context_finalize(struct ub_ctx* ctx) { struct config_file* cfg = ctx->env->cfg; verbosity = cfg->verbosity; - log_init(cfg->logfile, cfg->use_syslog, NULL); + if(ctx->logfile_override) + log_file(ctx->log_out); + else log_init(cfg->logfile, cfg->use_syslog, NULL); config_apply(cfg); if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) return UB_INITFAIL; @@ -99,7 +101,7 @@ void context_query_delete(struct ctx_query* q) { if(!q) return; - ub_val_resolve_free(q->res); + ub_resolve_free(q->res); free(q->msg); free(q); } @@ -108,7 +110,7 @@ context_query_delete(struct ctx_query* q) #define NUM_ID_TRIES 100000 /** find next useful id number of 0 on error */ static int -find_id(struct ub_val_ctx* ctx, int* id) +find_id(struct ub_ctx* ctx, int* id) { size_t tries = 0; ctx->next_querynum++; @@ -122,8 +124,8 @@ find_id(struct ub_val_ctx* ctx, int* id) } struct ctx_query* -context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, - ub_val_callback_t cb, void* cbarg) +context_new(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, + ub_callback_t cb, void* cbarg) { struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); if(!q) return NULL; @@ -138,7 +140,7 @@ context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, q->async = (cb != NULL); q->cb = cb; q->cb_arg = cbarg; - q->res = (struct ub_val_result*)calloc(1, sizeof(*q->res)); + q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); if(!q->res) { free(q); return NULL; @@ -162,7 +164,7 @@ context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, } struct alloc_cache* -context_obtain_alloc(struct ub_val_ctx* ctx, int locking) +context_obtain_alloc(struct ub_ctx* ctx, int locking) { struct alloc_cache* a; int tnum = 0; @@ -188,7 +190,7 @@ context_obtain_alloc(struct ub_val_ctx* ctx, int locking) } void -context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc, +context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, int locking) { if(!ctx || !alloc) @@ -227,7 +229,7 @@ context_serialize_new_query(struct ctx_query* q, uint32_t* len) } struct ctx_query* -context_deserialize_new_query(struct ub_val_ctx* ctx, uint8_t* p, uint32_t len) +context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) { struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); if(!q) return NULL; @@ -239,7 +241,7 @@ context_deserialize_new_query(struct ub_val_ctx* ctx, uint8_t* p, uint32_t len) q->querynum = (int)ldns_read_uint32(p+sizeof(uint32_t)); q->node.key = &q->querynum; q->async = 1; - q->res = (struct ub_val_result*)calloc(1, sizeof(*q->res)); + q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); if(!q->res) { free(q); return NULL; @@ -260,7 +262,7 @@ context_deserialize_new_query(struct ub_val_ctx* ctx, uint8_t* p, uint32_t len) } struct ctx_query* -context_lookup_new_query(struct ub_val_ctx* ctx, uint8_t* p, uint32_t len) +context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) { struct ctx_query* q; int querynum; @@ -304,7 +306,7 @@ context_serialize_answer(struct ctx_query* q, int err, ldns_buffer* pkt, } struct ctx_query* -context_deserialize_answer(struct ub_val_ctx* ctx, +context_deserialize_answer(struct ub_ctx* ctx, uint8_t* p, uint32_t len, int* err) { struct ctx_query* q = NULL ; @@ -343,7 +345,7 @@ context_serialize_cancel(struct ctx_query* q, uint32_t* len) return p; } -struct ctx_query* context_deserialize_cancel(struct ub_val_ctx* ctx, +struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, uint8_t* p, uint32_t len) { struct ctx_query* q; diff --git a/libunbound/context.h b/libunbound/context.h index b44917001..13a6c4f36 100644 --- a/libunbound/context.h +++ b/libunbound/context.h @@ -55,7 +55,7 @@ struct libworker; * qq : write queries to the async service pid/tid. * rr : read results from the async service pid/tid. */ -struct ub_val_ctx { +struct ub_ctx { /* --- pipes --- */ /** mutex on query write pipe */ lock_basic_t qqpipe_lock; @@ -87,6 +87,10 @@ struct ub_val_ctx { int dothread; /** next thread number for new threads */ int thr_next_num; + /** if logfile is overriden */ + int logfile_override; + /** what logfile to use instead */ + FILE* log_out; /** * List of alloc-cache-id points per threadnum for notinuse threads. * Simply the entire struct alloc_cache with the 'super' member used @@ -137,7 +141,7 @@ struct ctx_query { int cancelled; /** for async query, the callback function */ - ub_val_callback_t cb; + ub_callback_t cb; /** for async query, the callback user arg */ void* cb_arg; @@ -152,7 +156,7 @@ struct ctx_query { /** result structure, also contains original query, type, class. * malloced ptr ready to hand to the client. */ - struct ub_val_result* res; + struct ub_result* res; }; /** @@ -206,7 +210,7 @@ enum ub_ctx_cmd { * @param ctx: context to finalize. creates shared data. * @return 0 if OK, or errcode. */ -int context_finalize(struct ub_val_ctx* ctx); +int context_finalize(struct ub_ctx* ctx); /** compare two ctx_query elements */ int context_query_cmp(const void* a, const void* b); @@ -227,8 +231,8 @@ void context_query_delete(struct ctx_query* q); * @param cbarg: user arg for async queries. * @return new ctx_query or NULL for malloc failure. */ -struct ctx_query* context_new(struct ub_val_ctx* ctx, char* name, int rrtype, - int rrclass, ub_val_callback_t cb, void* cbarg); +struct ctx_query* context_new(struct ub_ctx* ctx, char* name, int rrtype, + int rrclass, ub_callback_t cb, void* cbarg); /** * Get a new alloc. Creates a new one or uses a cached one. @@ -236,7 +240,7 @@ struct ctx_query* context_new(struct ub_val_ctx* ctx, char* name, int rrtype, * @param locking: if true, cfglock is locked while getting alloc. * @return an alloc, or NULL on mem error. */ -struct alloc_cache* context_obtain_alloc(struct ub_val_ctx* ctx, int locking); +struct alloc_cache* context_obtain_alloc(struct ub_ctx* ctx, int locking); /** * Release an alloc. Puts it into the cache. @@ -244,7 +248,7 @@ struct alloc_cache* context_obtain_alloc(struct ub_val_ctx* ctx, int locking); * @param locking: if true, cfglock is locked while releasing alloc. * @param alloc: alloc to relinquish. */ -void context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc, +void context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, int locking); /** @@ -301,7 +305,7 @@ enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len); * @param len: length of buffer. * @return looked up ctx_query or NULL for malloc failure. */ -struct ctx_query* context_lookup_new_query(struct ub_val_ctx* ctx, +struct ctx_query* context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len); /** @@ -311,7 +315,7 @@ struct ctx_query* context_lookup_new_query(struct ub_val_ctx* ctx, * @param len: length of buffer. * @return new ctx_query or NULL for malloc failure. */ -struct ctx_query* context_deserialize_new_query(struct ub_val_ctx* ctx, +struct ctx_query* context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len); /** @@ -322,7 +326,7 @@ struct ctx_query* context_deserialize_new_query(struct ub_val_ctx* ctx, * @param err: error code to be returned to client is passed. * @return ctx_query with answer added or NULL for malloc failure. */ -struct ctx_query* context_deserialize_answer(struct ub_val_ctx* ctx, +struct ctx_query* context_deserialize_answer(struct ub_ctx* ctx, uint8_t* p, uint32_t len, int* err); /** @@ -332,7 +336,7 @@ struct ctx_query* context_deserialize_answer(struct ub_val_ctx* ctx, * @param len: length of buffer. * @return ctx_query to cancel or NULL for failure. */ -struct ctx_query* context_deserialize_cancel(struct ub_val_ctx* ctx, +struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, uint8_t* p, uint32_t len); #endif /* LIBUNBOUND_CONTEXT_H */ diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index f1c025f7b..2b694dac1 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -59,16 +59,16 @@ #include "services/cache/infra.h" #include "services/cache/rrset.h" -struct ub_val_ctx* -ub_val_ctx_create() +struct ub_ctx* +ub_ctx_create() { - struct ub_val_ctx* ctx; + struct ub_ctx* ctx; unsigned int seed; log_init(NULL, 0, NULL); /* logs to stderr */ log_ident_set("libunbound"); verbosity = 0; /* errors only */ checklock_start(); - ctx = (struct ub_val_ctx*)calloc(1, sizeof(*ctx)); + ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx)); if(!ctx) { errno = ENOMEM; return NULL; @@ -154,7 +154,7 @@ delq(rbnode_t* n, void* ATTR_UNUSED(arg)) } void -ub_val_ctx_delete(struct ub_val_ctx* ctx) +ub_ctx_delete(struct ub_ctx* ctx) { struct alloc_cache* a, *na; if(!ctx) return; @@ -234,7 +234,23 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx) } int -ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname) +ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val) +{ + lock_basic_lock(&ctx->cfglock); + if(ctx->finalized) { + lock_basic_unlock(&ctx->cfglock); + return UB_AFTERFINAL; + } + if(!config_set_option(ctx->env->cfg, opt, val)) { + lock_basic_unlock(&ctx->cfglock); + return UB_SYNTAX; + } + lock_basic_unlock(&ctx->cfglock); + return UB_NOERROR; +} + +int +ub_ctx_config(struct ub_ctx* ctx, char* fname) { lock_basic_lock(&ctx->cfglock); if(ctx->finalized) { @@ -250,7 +266,7 @@ ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname) } int -ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta) +ub_ctx_add_ta(struct ub_ctx* ctx, char* ta) { char* dup = strdup(ta); if(!dup) return UB_NOMEM; @@ -269,7 +285,7 @@ ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta) } int -ub_val_ctx_add_ta_file(struct ub_val_ctx* ctx, char* fname) +ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname) { char* dup = strdup(fname); if(!dup) return UB_NOMEM; @@ -288,7 +304,7 @@ ub_val_ctx_add_ta_file(struct ub_val_ctx* ctx, char* fname) } int -ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname) +ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname) { char* dup = strdup(fname); if(!dup) return UB_NOMEM; @@ -307,7 +323,7 @@ ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname) } int -ub_val_ctx_debuglevel(struct ub_val_ctx* ctx, int d) +ub_ctx_debuglevel(struct ub_ctx* ctx, int d) { lock_basic_lock(&ctx->cfglock); verbosity = d; @@ -316,8 +332,18 @@ ub_val_ctx_debuglevel(struct ub_val_ctx* ctx, int d) return UB_NOERROR; } +int ub_ctx_debugout(struct ub_ctx* ctx, void* out) +{ + lock_basic_lock(&ctx->cfglock); + log_file((FILE*)out); + ctx->logfile_override = 1; + ctx->log_out = out; + lock_basic_unlock(&ctx->cfglock); + return UB_NOERROR; +} + int -ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread) +ub_ctx_async(struct ub_ctx* ctx, int dothread) { #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) if(dothread) /* cannot do threading */ @@ -335,7 +361,7 @@ ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread) /** perform a select() on the result read pipe */ static int -pollit(struct ub_val_ctx* ctx, struct timeval* t) +pollit(struct ub_ctx* ctx, struct timeval* t) { fd_set r; #ifndef S_SPLINT_S @@ -350,7 +376,7 @@ pollit(struct ub_val_ctx* ctx, struct timeval* t) } int -ub_val_poll(struct ub_val_ctx* ctx) +ub_poll(struct ub_ctx* ctx) { struct timeval t; memset(&t, 0, sizeof(t)); @@ -359,16 +385,16 @@ ub_val_poll(struct ub_val_ctx* ctx) } int -ub_val_fd(struct ub_val_ctx* ctx) +ub_fd(struct ub_ctx* ctx) { return ctx->rrpipe[0]; } /** process answer from bg worker */ static int -process_answer_detail(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len, - ub_val_callback_t* cb, void** cbarg, int* err, - struct ub_val_result** res) +process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, + ub_callback_t* cb, void** cbarg, int* err, + struct ub_result** res) { struct ctx_query* q; if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { @@ -397,7 +423,7 @@ process_answer_detail(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len, } if(*err) { *res = NULL; - ub_val_resolve_free(q->res); + ub_resolve_free(q->res); } else { /* parse the message, extract rcode, fill result */ ldns_buffer* buf = ldns_buffer_new(q->msg_len); @@ -427,12 +453,12 @@ process_answer_detail(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len, /** process answer from bg worker */ static int -process_answer(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len) +process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len) { int err; - ub_val_callback_t cb; + ub_callback_t cb; void* cbarg; - struct ub_val_result* res; + struct ub_result* res; int r; r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res); @@ -446,7 +472,7 @@ process_answer(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len) } int -ub_val_process(struct ub_val_ctx* ctx) +ub_process(struct ub_ctx* ctx) { int r; uint8_t* msg; @@ -470,12 +496,12 @@ ub_val_process(struct ub_val_ctx* ctx) } int -ub_val_wait(struct ub_val_ctx* ctx) +ub_wait(struct ub_ctx* ctx) { int err; - ub_val_callback_t cb; + ub_callback_t cb; void* cbarg; - struct ub_val_result* res; + struct ub_result* res; int r; uint8_t* msg; uint32_t len; @@ -523,8 +549,8 @@ ub_val_wait(struct ub_val_ctx* ctx) } int -ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, - int rrclass, struct ub_val_result** result) +ub_resolve(struct ub_ctx* ctx, char* name, int rrtype, + int rrclass, struct ub_result** result) { struct ctx_query* q; int r; @@ -564,8 +590,8 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, } int -ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype, - int rrclass, void* mydata, ub_val_callback_t callback, int* async_id) +ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, + int rrclass, void* mydata, ub_callback_t callback, int* async_id) { struct ctx_query* q; uint8_t* msg = NULL; @@ -627,7 +653,7 @@ ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype, } int -ub_val_cancel(struct ub_val_ctx* ctx, int async_id) +ub_cancel(struct ub_ctx* ctx, int async_id) { struct ctx_query* q; uint8_t* msg = NULL; @@ -668,7 +694,7 @@ ub_val_cancel(struct ub_val_ctx* ctx, int async_id) } void -ub_val_resolve_free(struct ub_val_result* result) +ub_resolve_free(struct ub_result* result) { char** p; if(!result) return; @@ -684,7 +710,7 @@ ub_val_resolve_free(struct ub_val_result* result) } const char* -ub_val_strerror(int err) +ub_strerror(int err) { switch(err) { case UB_NOERROR: return "no error"; @@ -702,7 +728,7 @@ ub_val_strerror(int err) } int -ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr) +ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr) { struct sockaddr_storage storage; socklen_t stlen; @@ -774,7 +800,7 @@ ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr) } int -ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname) +ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname) { FILE* in; int numserv = 0; @@ -806,7 +832,7 @@ ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname) /* terminate after the address, remove newline */ *parse = 0; - if((r = ub_val_ctx_set_fwd(ctx, addr)) != UB_NOERROR) { + if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) { fclose(in); return r; } @@ -815,7 +841,83 @@ ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname) fclose(in); if(numserv == 0) { /* from resolv.conf(5) if none given, use localhost */ - return ub_val_ctx_set_fwd(ctx, "127.0.0.1"); + return ub_ctx_set_fwd(ctx, "127.0.0.1"); } return UB_NOERROR; } + +int +ub_ctx_hosts(struct ub_ctx* ctx, char* fname) +{ + FILE* in; + char buf[1024], ldata[1024]; + char* parse, *addr, *name, *ins; + lock_basic_lock(&ctx->cfglock); + if(ctx->finalized) { + lock_basic_unlock(&ctx->cfglock); + errno=EINVAL; + return UB_AFTERFINAL; + } + lock_basic_unlock(&ctx->cfglock); + if(fname == NULL) + fname = "/etc/hosts"; + 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(*parse == '#') + continue; /* skip comment */ + /* format: spaces spaces ... */ + addr = parse; + /* skip addr */ + while(isxdigit(*parse) || *parse == '.' || *parse == ':') + parse++; + if(*parse != ' ' && *parse != '\t') { + /* must have whitespace after address */ + fclose(in); + errno=EINVAL; + return UB_SYNTAX; + } + *parse++ = 0; /* end delimiter for addr ... */ + /* go to names and add them */ + while(*parse) { + while(*parse == ' ' || *parse == '\t' || *parse=='\n') + parse++; + if(*parse == 0 || *parse == '#') + break; + /* skip name, allows (too) many printable characters */ + name = parse; + while('!' <= *parse && *parse <= '~') + parse++; + if(*parse) + *parse++ = 0; /* end delimiter for name */ + snprintf(ldata, sizeof(ldata), "%s %s %s", + name, str_is_ip6(addr)?"AAAA":"A", addr); + ins = strdup(ldata); + if(!ins) { + /* out of memory */ + fclose(in); + errno=ENOMEM; + return UB_NOMEM; + } + lock_basic_lock(&ctx->cfglock); + if(!cfg_strlist_insert(&ctx->env->cfg->local_data, + ins)) { + lock_basic_unlock(&ctx->cfglock); + fclose(in); + free(ins); + errno=ENOMEM; + return UB_NOMEM; + } + lock_basic_unlock(&ctx->cfglock); + } + } + fclose(in); + return UB_NOERROR; +} diff --git a/libunbound/libworker.c b/libunbound/libworker.c index d17a61d28..fa029584b 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -88,7 +88,7 @@ libworker_delete(struct libworker* w) /** setup fresh libworker struct */ static struct libworker* -libworker_setup(struct ub_val_ctx* ctx, int is_bg) +libworker_setup(struct ub_ctx* ctx, int is_bg) { unsigned int seed; struct libworker* w = (struct libworker*)calloc(1, sizeof(*w)); @@ -354,7 +354,7 @@ libworker_dobg(void* arg) uint32_t m; int fd; struct libworker* w = (struct libworker*)arg; - struct ub_val_ctx* ctx = w->ctx; + struct ub_ctx* ctx = w->ctx; log_thread_set(&w->thread_num); #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) /* we are forked */ @@ -399,7 +399,7 @@ libworker_dobg(void* arg) return NULL; } -int libworker_bg(struct ub_val_ctx* ctx) +int libworker_bg(struct ub_ctx* ctx) { struct libworker* w; /* fork or threadcreate */ @@ -457,7 +457,7 @@ parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi) /** insert canonname */ static int -fill_canon(struct ub_val_result* res, uint8_t* s) +fill_canon(struct ub_result* res, uint8_t* s) { char buf[255+2]; dname_str(s, buf); @@ -467,7 +467,7 @@ fill_canon(struct ub_val_result* res, uint8_t* s) /** fill data into result */ static int -fill_res(struct ub_val_result* res, struct ub_packed_rrset_key* answer, +fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, uint8_t* finalcname, struct query_info* rq) { size_t i; @@ -504,7 +504,7 @@ fill_res(struct ub_val_result* res, struct ub_packed_rrset_key* answer, /** fill result from parsed message, on error fills servfail */ void -libworker_enter_result(struct ub_val_result* res, ldns_buffer* buf, +libworker_enter_result(struct ub_result* res, ldns_buffer* buf, struct regional* temp, enum sec_status msg_security) { struct query_info rq; @@ -591,7 +591,7 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q, return 1; } -int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q) +int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) { struct libworker* w = libworker_setup(ctx, 0); uint16_t qflags, qid; @@ -690,7 +690,7 @@ libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s) if(q->cancelled) { if(q->w->is_bg_thread) { /* delete it now */ - struct ub_val_ctx* ctx = q->w->ctx; + struct ub_ctx* ctx = q->w->ctx; lock_basic_lock(&ctx->cfglock); (void)rbtree_delete(&ctx->queries, q->node.key); ctx->num_async--; diff --git a/libunbound/libworker.h b/libunbound/libworker.h index d32b60709..6b2543717 100644 --- a/libunbound/libworker.h +++ b/libunbound/libworker.h @@ -44,8 +44,8 @@ #ifndef LIBUNBOUND_WORKER_H #define LIBUNBOUND_WORKER_H #include "util/data/packed_rrset.h" -struct ub_val_ctx; -struct ub_val_result; +struct ub_ctx; +struct ub_result; struct module_env; struct comm_base; struct outside_network; @@ -66,7 +66,7 @@ struct libworker { /** every worker has a unique thread_num. (first in struct) */ int thread_num; /** context we are operating under */ - struct ub_val_ctx* ctx; + struct ub_ctx* ctx; /** is this the bg worker? */ int is_bg; @@ -122,7 +122,7 @@ struct libworker_res_list { * @return 0 if OK, else error. * Further communication is done via the pipes in ctx. */ -int libworker_bg(struct ub_val_ctx* ctx); +int libworker_bg(struct ub_ctx* ctx); /** * Create a foreground worker. @@ -133,7 +133,7 @@ int libworker_bg(struct ub_val_ctx* ctx); * @param q: query (result is stored in here). * @return 0 if finished OK, else error. */ -int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q); +int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q); /** cleanup the cache to remove all rrset IDs from it, arg is libworker */ void libworker_alloc_cleanup(void* arg); @@ -230,7 +230,7 @@ int libworker_read_msg(int fd, uint8_t** buf, uint32_t* len, int nonblock); * On error, the res may contain a different status * (out of memory is not secure, not bogus). */ -void libworker_enter_result(struct ub_val_result* res, ldns_buffer* buf, +void libworker_enter_result(struct ub_result* res, ldns_buffer* buf, struct regional* temp, enum sec_status msg_security); #endif /* LIBUNBOUND_WORKER_H */ diff --git a/libunbound/ubsyms.def b/libunbound/ubsyms.def index 94776a02e..7a8c5852f 100644 --- a/libunbound/ubsyms.def +++ b/libunbound/ubsyms.def @@ -1,19 +1,22 @@ -ub_val_ctx_create -ub_val_ctx_delete -ub_val_ctx_config -ub_val_ctx_set_fwd -ub_val_ctx_resolvconf -ub_val_ctx_add_ta -ub_val_ctx_add_ta_file -ub_val_ctx_trustedkeys -ub_val_ctx_debuglevel -ub_val_ctx_async -ub_val_poll -ub_val_wait -ub_val_fd -ub_val_process -ub_val_resolve -ub_val_resolve_async -ub_val_cancel -ub_val_resolve_free -ub_val_strerror +ub_ctx_create +ub_ctx_delete +ub_ctx_set_option +ub_ctx_config +ub_ctx_set_fwd +ub_ctx_resolvconf +ub_ctx_hosts +ub_ctx_add_ta +ub_ctx_add_ta_file +ub_ctx_trustedkeys +ub_ctx_debugout +ub_ctx_debuglevel +ub_ctx_async +ub_poll +ub_wait +ub_fd +ub_process +ub_resolve +ub_resolve_async +ub_cancel +ub_resolve_free +ub_strerror diff --git a/libunbound/unbound.h b/libunbound/unbound.h index 62436f070..9ee32b9c0 100644 --- a/libunbound/unbound.h +++ b/libunbound/unbound.h @@ -43,29 +43,29 @@ * to perform (validated) DNS lookups. * * All start with - * ctx = ub_val_ctx_create(); - * err = ub_val_ctx_add_ta(ctx, "..."); - * err = ub_val_ctx_add_ta(ctx, "..."); + * ctx = ub_ctx_create(); + * err = ub_ctx_add_ta(ctx, "..."); + * err = ub_ctx_add_ta(ctx, "..."); * ... some lookups - * ... call ub_val_ctx_delete(ctx); when you want to stop. + * ... call ub_ctx_delete(ctx); when you want to stop. * * Application not threaded. Blocking. - * int err = ub_val_resolve(ctx, "www.example.com", ... - * if(err) fprintf(stderr, "lookup error: %s\n", ub_val_strerror(err)); + * int err = ub_resolve(ctx, "www.example.com", ... + * if(err) fprintf(stderr, "lookup error: %s\n", ub_strerror(err)); * ... use the answer * * Application not threaded. Non-blocking ('asynchronous'). - * err = ub_val_resolve_async(ctx, "www.example.com", ... my_callback); + * err = ub_resolve_async(ctx, "www.example.com", ... my_callback); * ... application resumes processing ... - * ... and when either ub_val_poll(ctx) is true - * ... or when the file descriptor ub_val_fd(ctx) is readable, + * ... and when either ub_poll(ctx) is true + * ... or when the file descriptor ub_fd(ctx) is readable, * ... or whenever, the app calls ... - * ub_val_process(ctx); + * ub_process(ctx); * ... if no result is ready, the app resumes processing above, * ... or process() calls my_callback() with results. * * ... if the application has nothing more to do, wait for answer - * ub_val_wait(ctx); + * ub_wait(ctx); * * Application threaded. Blocking. * Blocking, same as above. The current thread does the work. @@ -74,7 +74,7 @@ * * Application threaded. Non-blocking ('asynchronous'). * ... setup threaded-asynchronous config option - * err = ub_val_ctx_async(ctx, 1); + * err = ub_ctx_async(ctx, 1); * ... same as async for non-threaded * ... the callbacks are called in the thread that calls process(ctx) * @@ -84,7 +84,7 @@ * Otherwise, for asynchronous with threading, a worker thread is created. * * The blocking calls use shared ctx-cache when threaded. Thus - * ub_val_resolve() and ub_val_resolve_async() && ub_val_wait() are + * ub_resolve() and ub_resolve_async() && ub_wait() are * 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). * The second calls another worker thread (or process) to perform the work. @@ -100,14 +100,14 @@ * * Its contents are internally defined. */ -struct ub_val_ctx; +struct ub_ctx; /** * The validation and resolution results. * Allocated by the resolver, and need to be freed by the application - * with ub_val_resolve_free(). + * with ub_resolve_free(). */ -struct ub_val_result { +struct ub_result { /** The original question, name text string. */ char* qname; /** the type asked for */ @@ -179,7 +179,7 @@ struct ub_val_result { /** * Callback for results of async queries. * The readable function definition looks like: - * void my_callback(void* my_arg, int err, struct ub_val_result* result); + * void my_callback(void* my_arg, int err, struct ub_result* result); * It is called with * void* my_arg: your pointer to a (struct of) data of your choice, * or NULL. @@ -187,23 +187,40 @@ struct ub_val_result { * are forthcoming. * struct result: pointer to more detailed result structure. * This structure is allocated on the heap and needs to be - * freed with ub_val_resolve_free(result); + * freed with ub_resolve_free(result); */ -typedef void (*ub_val_callback_t)(void*, int, struct ub_val_result*); +typedef void (*ub_callback_t)(void*, int, struct ub_result*); /** * Create a resolving and validation context. + * The information from /etc/resolv.conf and /etc/hosts is not utilised by + * default. Use ub_ctx_resolvconf and ub_ctx_hosts to read them. * @return a new context. default initialisation. * returns NULL on error. */ -struct ub_val_ctx* ub_val_ctx_create(void); +struct ub_ctx* ub_ctx_create(void); /** * Destroy a validation context and free all its resources. * Outstanding async queries are killed and callbacks are not called for them. * @param ctx: context to delete. */ -void ub_val_ctx_delete(struct ub_val_ctx* ctx); +void ub_ctx_delete(struct ub_ctx* ctx); + +/** + * Set an option for the context. + * @param ctx: context. + * @param opt: option name from the unbound.conf config file format. + * (not all settings applicable). The name includes the trailing ':' + * for example ub_ctx_set_option("logfile:", "mylog.txt"); + * This is a power-users interface that lets you specify all sorts + * of options. + * For some specific options, such as adding trust anchors, special + * routines exist. + * @param val: value of the option. + * @return: 0 if OK, else error. + */ +int ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val); /** * setup configuration for the given context. @@ -215,7 +232,7 @@ void ub_val_ctx_delete(struct ub_val_ctx* ctx); * routines exist. * @return: 0 if OK, else error. */ -int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname); +int ub_ctx_config(struct ub_ctx* ctx, char* fname); /** * Set machine to forward DNS queries to, the caching resolver to use. @@ -225,7 +242,7 @@ int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname); * 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. + * use the call ub_ctx_resolvconf. * * @param ctx: context. * At this time it is only possible to set configuration before the @@ -234,7 +251,7 @@ int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname); * 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); +int ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr); /** * Read list of nameservers to use from the filename given. @@ -250,7 +267,20 @@ int ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr); * @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); +int ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname); + +/** + * Read list of hosts from the filename given. + * Usually "/etc/hosts". + * These addresses are not flagged as DNSSEC secure when queried for. + * + * @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/hosts" is used. + * @return 0 if OK, else error. + */ +int ub_ctx_hosts(struct ub_ctx* ctx, char* fname); /** * Add a trust anchor to the given context. @@ -263,7 +293,7 @@ int ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname); * [domainname] [TTL optional] [type] [class optional] [rdata contents] * @return 0 if OK, else error. */ -int ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta); +int ub_ctx_add_ta(struct ub_ctx* ctx, char* ta); /** * Add trust anchors to the given context. @@ -274,7 +304,7 @@ int ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta); * @param fname: filename of file with keyfile with trust anchors. * @return 0 if OK, else error. */ -int ub_val_ctx_add_ta_file(struct ub_val_ctx* ctx, char* fname); +int ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname); /** * Add trust anchors to the given context. @@ -286,7 +316,17 @@ int ub_val_ctx_add_ta_file(struct ub_val_ctx* ctx, char* fname); * anchors. * @return 0 if OK, else error. */ -int ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname); +int ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname); + +/** + * Set debug output (and error output) to the specified stream. + * Pass NULL to disable. Default is stderr. + * @param ctx: context. + * @param out: FILE* out file stream to log to. + * Type void* to avoid stdio dependency of this header file. + * @return 0 if OK, else error. + */ +int ub_ctx_debugout(struct ub_ctx* ctx, void* out); /** * Set debug verbosity for the context @@ -296,7 +336,7 @@ int ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname); * and 3 is lots. * @return 0 if OK, else error. */ -int ub_val_ctx_debuglevel(struct ub_val_ctx* ctx, int d); +int ub_ctx_debuglevel(struct ub_ctx* ctx, int d); /** * Set a context behaviour for asynchronous action. @@ -308,7 +348,7 @@ int ub_val_ctx_debuglevel(struct ub_val_ctx* ctx, int d); * no effect (delete and re-create the context to change). * @return 0 if OK, else error. */ -int ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread); +int ub_ctx_async(struct ub_ctx* ctx, int dothread); /** * Poll a context to see if it has any new results @@ -318,27 +358,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. * If nonzero, call ctx_process() to do callbacks. */ -int ub_val_poll(struct ub_val_ctx* ctx); +int ub_poll(struct ub_ctx* ctx); /** - * Wait for a context to finish with results. Calls ub_val_process() after + * Wait for a context to finish with results. Calls ub_process() after * the wait for you. After the wait, there are no more outstanding * asynchronous queries. * @param ctx: context. * @return: 0 if OK, else error. */ -int ub_val_wait(struct ub_val_ctx* ctx); +int ub_wait(struct ub_ctx* ctx); /** * Get file descriptor. Wait for it to become readable, at this point * answers are returned from the asynchronous validating resolver. - * Then call the ub_val_process to continue processing. + * Then call the ub_process to continue processing. * This routine works immediately after context creation, the fd * does not change. * @param ctx: context. * @return: -1 on error, or file descriptor to use select(2) with. */ -int ub_val_fd(struct ub_val_ctx* ctx); +int ub_fd(struct ub_ctx* ctx); /** * Call this routine to continue processing results from the validating @@ -347,7 +387,7 @@ int ub_val_fd(struct ub_val_ctx* ctx); * @param ctx: context * @return: 0 if OK, else error. */ -int ub_val_process(struct ub_val_ctx* ctx); +int ub_process(struct ub_ctx* ctx); /** * Perform resolution and validation of the target name. @@ -361,8 +401,8 @@ int ub_val_process(struct ub_val_ctx* ctx); * in that case (out of memory). * @return 0 if OK, else error. */ -int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, - int rrclass, struct ub_val_result** result); +int ub_resolve(struct ub_ctx* ctx, char* name, int rrtype, + int rrclass, struct ub_result** result); /** * Perform resolution and validation of the target name. @@ -379,7 +419,7 @@ int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, * and is passed on to the callback function. * @param callback: this is called on completion of the resolution. * It is called as: - * void callback(void* mydata, int err, struct ub_val_result* result) + * void callback(void* mydata, int err, struct ub_result* result) * with mydata: the same as passed here, you may pass NULL, * with err: is 0 when a result has been found. * with result: a newly allocated result structure. @@ -392,8 +432,8 @@ int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, * cancel the query. * @return 0 if OK, else error. */ -int ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype, - int rrclass, void* mydata, ub_val_callback_t callback, int* async_id); +int ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, + int rrclass, void* mydata, ub_callback_t callback, int* async_id); /** * Cancel an async query in progress. @@ -403,19 +443,19 @@ int ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype, * @param async_id: which query to cancel. * @return 0 if OK, else error. */ -int ub_val_cancel(struct ub_val_ctx* ctx, int async_id); +int ub_cancel(struct ub_ctx* ctx, int async_id); /** * Free storage associated with a result structure. * @param result: to free */ -void ub_val_resolve_free(struct ub_val_result* result); +void ub_resolve_free(struct ub_result* result); /** * Convert error value to a human readable string. * @param err: error code from one of the ub_val* functions. * @return pointer to constant text string, zero terminated. */ -const char* ub_val_strerror(int err); +const char* ub_strerror(int err); #endif /* _UB_UNBOUND_H */ diff --git a/services/mesh.c b/services/mesh.c index 57646a128..16552b04e 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -768,20 +768,21 @@ mesh_log_list(struct mesh_area* mesh) void mesh_stats(struct mesh_area* mesh, const char* str) { - log_info("%s %u states (%u with reply, %u detached), " - "%u waiting replies", str, (unsigned)mesh->all.count, + verbose(VERB_DETAIL, "%s %u recursion states (%u with reply, " + "%u detached), %u waiting replies, %u recursion replies " + "sent", str, (unsigned)mesh->all.count, (unsigned)mesh->num_reply_states, (unsigned)mesh->num_detached_states, - (unsigned)mesh->num_reply_addrs); + (unsigned)mesh->num_reply_addrs, + (unsigned)mesh->replies_sent); if(mesh->replies_sent > 0) { struct timeval avg; timeval_divide(&avg, &mesh->replies_sum_wait, mesh->replies_sent); - log_info("sent %u replies, with average wait " - "of %d.%6.6d sec", (unsigned)mesh->replies_sent, - (int)avg.tv_sec, (int)avg.tv_usec); - log_info("histogram of reply wait times"); - timehist_log(mesh->histogram); + log_info("average recursion processing time " + "%d.%6.6d sec", (int)avg.tv_sec, (int)avg.tv_usec); + log_info("histogram of recursion processing times"); + timehist_log(mesh->histogram, "recursions"); } } diff --git a/smallapp/unbound-host.c b/smallapp/unbound-host.c index 15c494deb..b3f0404ae 100644 --- a/smallapp/unbound-host.c +++ b/smallapp/unbound-host.c @@ -176,7 +176,7 @@ massage_class(const char* c) /** nice security status string */ static const char* -secure_str(struct ub_val_result* result) +secure_str(struct ub_result* result) { if(result->secure) return "(secure)"; if(result->bogus) return "(BOGUS (security failure))"; @@ -274,7 +274,7 @@ pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec, /** pretty line of output for results */ static void -pretty_output(char* q, int t, int c, struct ub_val_result* result, int docname) +pretty_output(char* q, int t, int c, struct ub_result* result, int docname) { int i; const char *secstatus = secure_str(result); @@ -337,25 +337,25 @@ pretty_output(char* q, int t, int c, struct ub_val_result* result, int docname) /** perform a lookup and printout return if domain existed */ static int -dnslook(struct ub_val_ctx* ctx, char* q, int t, int c, int docname) +dnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname) { int ret; - struct ub_val_result* result; + struct ub_result* result; - ret = ub_val_resolve(ctx, q, t, c, &result); + ret = ub_resolve(ctx, q, t, c, &result); if(ret != 0) { - fprintf(stderr, "resolve error: %s\n", ub_val_strerror(ret)); + fprintf(stderr, "resolve error: %s\n", ub_strerror(ret)); exit(1); } pretty_output(q, t, c, result, docname); ret = result->nxdomain; - ub_val_resolve_free(result); + ub_resolve_free(result); return ret; } /** perform host lookup */ static void -lookup(struct ub_val_ctx* ctx, const char* nm, const char* qt, const char* qc) +lookup(struct ub_ctx* ctx, const char* nm, const char* qt, const char* qc) { /* massage input into a query name, type and class */ int multi = 0; /* no type, so do A, AAAA, MX */ @@ -374,7 +374,7 @@ lookup(struct ub_val_ctx* ctx, const char* nm, const char* qt, const char* qc) } else { (void)dnslook(ctx, realq, t, c, 1); } - ub_val_ctx_delete(ctx); + ub_ctx_delete(ctx); free(realq); } @@ -389,10 +389,10 @@ int main(int argc, char* argv[]) int c; char* qclass = NULL; char* qtype = NULL; - struct ub_val_ctx* ctx = NULL; + struct ub_ctx* ctx = NULL; int debuglevel = 0; - ctx = ub_val_ctx_create(); + ctx = ub_ctx_create(); if(!ctx) { fprintf(stderr, "error: out of memory\n"); exit(1); @@ -408,7 +408,7 @@ int main(int argc, char* argv[]) debuglevel++; if(debuglevel < 2) debuglevel = 2; /* at least VERB_DETAIL */ - ub_val_ctx_debuglevel(ctx, debuglevel); + ub_ctx_debuglevel(ctx, debuglevel); break; case 't': qtype = optarg; @@ -417,13 +417,13 @@ int main(int argc, char* argv[]) verb++; break; case 'y': - ub_val_ctx_add_ta(ctx, optarg); + ub_ctx_add_ta(ctx, optarg); break; case 'f': - ub_val_ctx_add_ta_file(ctx, optarg); + ub_ctx_add_ta_file(ctx, optarg); break; case 'F': - ub_val_ctx_trustedkeys(ctx, optarg); + ub_ctx_trustedkeys(ctx, optarg); break; case '?': case 'h': diff --git a/testcode/asynclook.c b/testcode/asynclook.c index 2f284fc4d..d119192df 100644 --- a/testcode/asynclook.c +++ b/testcode/asynclook.c @@ -56,7 +56,7 @@ struct lookinfo { /** error code from libunbound */ int err; /** result from lookup */ - struct ub_val_result* result; + struct ub_result* result; }; /** global variable to see how many queries we have left */ @@ -72,6 +72,7 @@ void usage(char* argv[]) printf(" -d : enable debug output\n"); printf(" -f addr : use addr, forward to that server\n"); printf(" -h : this help message\n"); + printf(" -H fname : read hosts from fname\n"); printf(" -r fname : read resolv.conf from fname\n"); printf(" -t : use a resolver thread instead of forking a process\n"); printf(" -x : perform extended threaded test\n"); @@ -85,7 +86,7 @@ print_result(struct lookinfo* info) char buf[100]; if(info->err) /* error (from libunbound) */ printf("%s: error %s\n", info->name, - ub_val_strerror(info->err)); + ub_strerror(info->err)); else if(!info->result) printf("%s: cancelled\n", info->name); else if(info->result->havedata) @@ -105,9 +106,9 @@ print_result(struct lookinfo* info) } } -/** this is a function of type ub_val_callback_t */ +/** this is a function of type ub_callback_t */ static void -lookup_is_done(void* mydata, int err, struct ub_val_result* result) +lookup_is_done(void* mydata, int err, struct ub_result* result) { /* cast mydata back to the correct type */ struct lookinfo* info = (struct lookinfo*)mydata; @@ -123,7 +124,7 @@ static void checkerr(const char* desc, int err) { if(err != 0) { - printf("%s error: %s\n", desc, ub_val_strerror(err)); + printf("%s error: %s\n", desc, ub_strerror(err)); exit(1); } } @@ -143,7 +144,7 @@ struct ext_thr_info { /** thread id */ ub_thread_t tid; /** context */ - struct ub_val_ctx* ctx; + struct ub_ctx* ctx; /** size of array to query */ int argc; /** array of names to query */ @@ -157,7 +158,7 @@ static int q_is_localhost = 0; /** check result structure for the 'correct' answer */ static void -ext_check_result(const char* desc, int err, struct ub_val_result* result) +ext_check_result(const char* desc, int err, struct ub_result* result) { checkerr(desc, err); if(result == NULL) { @@ -218,9 +219,9 @@ ext_check_result(const char* desc, int err, struct ub_val_result* result) } } -/** extended bg result callback, this function is ub_val_callback_t */ +/** extended bg result callback, this function is ub_callback_t */ static void -ext_callback(void* mydata, int err, struct ub_val_result* result) +ext_callback(void* mydata, int err, struct ub_result* result) { int* my_id = (int*)mydata; int doprint = 0; @@ -243,7 +244,7 @@ ext_callback(void* mydata, int err, struct ub_val_result* result) pi.err = 0; print_result(&pi); } - ub_val_resolve_free(result); + ub_resolve_free(result); } /** extended thread worker */ @@ -252,7 +253,7 @@ ext_thread(void* arg) { struct ext_thr_info* inf = (struct ext_thr_info*)arg; int i, r; - struct ub_val_result* result; + struct ub_result* result; int* async_ids = NULL; log_thread_set(&inf->thread_num); if(inf->thread_num > NUMTHR*2/3) { @@ -264,32 +265,32 @@ ext_thread(void* arg) } for(i=0; inumq; i++) { if(async_ids) { - r = ub_val_resolve_async(inf->ctx, + r = ub_resolve_async(inf->ctx, inf->argv[i%inf->argc], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &async_ids[i], ext_callback, &async_ids[i]); - checkerr("ub_val_resolve_async", r); + checkerr("ub_resolve_async", r); if(i > 100) { - r = ub_val_cancel(inf->ctx, async_ids[i-100]); - checkerr("ub_val_cancel", r); + r = ub_cancel(inf->ctx, async_ids[i-100]); + checkerr("ub_cancel", r); async_ids[i-100]=0; } } else if(inf->thread_num > NUMTHR/2) { /* async */ - r = ub_val_resolve_async(inf->ctx, + r = ub_resolve_async(inf->ctx, inf->argv[i%inf->argc], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, NULL, ext_callback, NULL); - checkerr("ub_val_resolve_async", r); + checkerr("ub_resolve_async", r); } else { /* blocking */ - r = ub_val_resolve(inf->ctx, inf->argv[i%inf->argc], + r = ub_resolve(inf->ctx, inf->argv[i%inf->argc], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &result); - ext_check_result("ub_val_resolve", r, result); + ext_check_result("ub_resolve", r, result); } } if(inf->thread_num > NUMTHR/2) { - r = ub_val_wait(inf->ctx); - checkerr("ub_val_ctx_wait", r); + r = ub_wait(inf->ctx); + checkerr("ub_ctx_wait", r); } free(async_ids); @@ -298,7 +299,7 @@ ext_thread(void* arg) /** perform extended threaded test */ static int -ext_test(struct ub_val_ctx* ctx, int argc, char** argv) +ext_test(struct ub_ctx* ctx, int argc, char** argv) { struct ext_thr_info inf[NUMTHR]; int i; @@ -319,7 +320,7 @@ ext_test(struct ub_val_ctx* ctx, int argc, char** argv) ub_thread_join(inf[i].tid); } printf("extended test end\n"); - ub_val_ctx_delete(ctx); + ub_ctx_delete(ctx); checklock_stop(); return 0; } @@ -333,7 +334,7 @@ extern char* optarg; int main(int argc, char** argv) { int c; - struct ub_val_ctx* ctx; + struct ub_ctx* ctx; struct lookinfo* lookups; int i, r, cancel=0, blocking=0, ext=0; @@ -341,7 +342,7 @@ int main(int argc, char** argv) checklock_start(); /* create context */ - ctx = ub_val_ctx_create(); + ctx = ub_ctx_create(); if(!ctx) { printf("could not create context, %s\n", strerror(errno)); return 1; @@ -351,15 +352,15 @@ int main(int argc, char** argv) if(argc == 1) { usage(argv); } - while( (c=getopt(argc, argv, "bcdf:hr:tx")) != -1) { + while( (c=getopt(argc, argv, "bcdf:hH:r:tx")) != -1) { switch(c) { case 'd': - r = ub_val_ctx_debuglevel(ctx, 3); - checkerr("ub_val_ctx_debuglevel", r); + r = ub_ctx_debuglevel(ctx, 3); + checkerr("ub_ctx_debuglevel", r); break; case 't': - r = ub_val_ctx_async(ctx, 1); - checkerr("ub_val_ctx_async", r); + r = ub_ctx_async(ctx, 1); + checkerr("ub_ctx_async", r); break; case 'c': cancel = 1; @@ -368,18 +369,28 @@ int main(int argc, char** argv) blocking = 1; break; case 'r': - r = ub_val_ctx_resolvconf(ctx, optarg); + r = ub_ctx_resolvconf(ctx, optarg); if(r != 0) { - printf("ub_val_ctx_resolvconf " + printf("ub_ctx_resolvconf " "error: %s : %s\n", - ub_val_strerror(r), + ub_strerror(r), + strerror(errno)); + return 1; + } + break; + case 'H': + r = ub_ctx_hosts(ctx, optarg); + if(r != 0) { + printf("ub_ctx_hosts " + "error: %s : %s\n", + ub_strerror(r), strerror(errno)); return 1; } break; case 'f': - r = ub_val_ctx_set_fwd(ctx, optarg); - checkerr("ub_val_ctx_set_fwd", r); + r = ub_ctx_set_fwd(ctx, optarg); + checkerr("ub_ctx_set_fwd", r); break; case 'x': ext = 1; @@ -410,15 +421,15 @@ int main(int argc, char** argv) lookups[i].name = argv[i]; if(blocking) { fprintf(stderr, "lookup %s\n", argv[i]); - r = ub_val_resolve(ctx, argv[i], LDNS_RR_TYPE_A, + r = ub_resolve(ctx, argv[i], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &lookups[i].result); - checkerr("ub_val_resolve", r); + checkerr("ub_resolve", r); } else { fprintf(stderr, "start async lookup %s\n", argv[i]); - r = ub_val_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A, + r = ub_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done, &lookups[i].async_id); - checkerr("ub_val_resolve_async", r); + checkerr("ub_resolve_async", r); } } if(blocking) @@ -426,8 +437,8 @@ int main(int argc, char** argv) else if(cancel) { for(i=0; icSXpt6R!+&~;gQ~+#@cpNctH{E^xUnz`5 z`_DB5f~`UZqPk%BjQuUMY)Sj?Rm+xHH7vA$b+2k{fUyGE_u`q`e-k!KC0I0iskBKp zA>^^J8AJmHLmJ}h;WMhL=XwlA1LlJpZH2N|F!FCG^+4Bm^(eUN>qw@jBmM&~Urrd^ z(vMQ&5PPQ05ep;eaRIIm>KPkd+C`B84MW%Or=sQu%t@K+BBb3qzC1r`ck0FMZ78-I zt>d%z@CqvB${y_OkhdRa-Ngwl_M6zp>;VUDMlpHP;PCK<9Ml)?BsKXF6%MWq$(!xE z=lEeslK3HUd�+$Teucj0UbffTE)NMLUqX^hqHZwmaZMwwvs_-LC8JX8H77l8k~< z0MlvBn=v7U!`{fzJ>CcF@TCball7h+*NZQ*%aaZ1!>x<6X>`kiN7PM>6*BP|jU935 zbBKe#D`UZH6f1X&PlxOfUWbuD`$?h^jqJf8>BYVsx!hNLE)yP?aj?Au|0RX@jelK! zIKS+)f3BOBK?)xmr=82rNxOMbFXLA!73~>`aovCe`3bM6H62diHaQVGr)ODDMkFF$*!(o^y&bg&=@n` zvKvb5Q+6tg>@E^*;SNWsj_ZKWqeO8p6lbaIqN(VwQNiXNLi!AfGp)>ogdW3Hndu-o zck=b~r&@)4IDa1m|EsiG})GH)oDY%T4^5RH&OI z2<|!mc^Iug#`5#us91Z`^ItyW`CqM8^7H>GaNGIMWsH2n8$d?NVi3kSZaF1U;oA7BBHwcVPwo(p zmT`~&@9$^)-<1BpZ&}sc|DOT}Aa7@r`#W&spS4Nj_=gV{9lVJI<4e~e7tN#2=~)YY`p~?P59CeZv{h(bOgkE_i;vCr zq`6>P`?`Vu%yb6L)-hS%WJaTrl-pRG&7{3x8oFiZWkcUHo@zqYT{E&4r(|WPB<+8{ z|37|@E%$%ZM6b`(e^mZo-OJDaC&4Y}f085pg(?8&?Pgt*qIFH4{E8k^DRuaR8_Mh_ zNz4v08|%ZHX+W9JuF;?LOgx1DAty`=<4Ed5Bfop7tO_KFXeM-Mlio>Qm&`CTXN@o~ zWJG0)X(BdHC9_INmS&N%Xds4Dp{NKOGuVj1)bbdYer(p|ZAVTiDNgj&)rTC`o1lb~Li2Gg}?GRz$ng&Ur1^)R&9v#;)hg7$k!O!TW*^ z=azj#sK@QA5}tT&Z@i;4F<|zU+UBw+)Mup$`Cal&iW1WbLOQ<;A1G0|E#s~lA*juC zW15rSAkLEgEt}bY3nia{u~;(5j%7k{q0PzzX`+w+f17Ua0p8(5K>IrKeBQ>u&g_Vx zvLd-6>H&?T0eV=Er&X@4!v&2)>0~}EBrHF>B8sV}FMcLmRgGzGb8nHgu$}qL(vdZ| z-=)reoOn|5y@fkVwq^FuWD_j-kJ7YS3CN|yK{&7J4Y^wWOAMK=mO1M;(~&}{yS~iU9%xq z%m0~0(IpPJZo92q#4|Hp>V)h%V!ng-bNLMuy-Cu#sP5||Pma)D< z!KuZj$}k~K?HtZRmA8+$Nb=EW#AQlrvoORij&vj8MoCE~q(i2PF?z}-DRQkCz2jB@__uP4DK zoXFR`$26i{iViKSzMX*^CPm(Gz+=w=oBI)!wamw9{yBR3i-2}!ej9|F9m-rlNru=c?9 zWuzmunhCdI8oFjr`cw*;Rc60r)Fzw`Y2Wp!7=zCu8J2Zo8j6#(z-c&^bDj-O8z$uC z8{|FV;#o8|AZa3*1GrFFTH$(Z%v|pOPH3-SkKO10d)4an{cpLtpZxx_ocsS%;5&5R z7Vgs8Tve9*lZnvfKHkoBgB-Ka7H$x!hR$Nq6Jq&N20XVL`&}O6?md$46_6N%3i5p` zT=;?dU{%2QrdBa(YYab1MOP>d)hV=&#&mOxH>#d@^%`rt-;p%~?q`~rmm=z39)f~%p9WO_Q|S9tn#%IJ=9 zloE$HGV6|L7{P#XaD9+%>~yV56d71y==#G{)Z&B%DGNh{^t#6vXQ#b>GrzwN`Chww zeEJ5SK^0>R92}6B@8-k#DJ_ndaE#g`2HKor+R~uax+Mqgg*!3-7=g)M!OOQsb^Y)p&Et}9-;elg2u;F4q(6atv3 zwdlr#6k3CcqkC)!X6tDQo+j%(Id0~kWS1v8(#D;Ov#sck1y3wDaaKtA2XuDCV8|d2 zzL3s>=O|X}7T+4v7Ca9lj{Xxw6DzVuEi#CGJ93#X`CKGCF5+PS0RAAkH|?J;-kx3b zdp|czra^M=+9&;s{;OW+yjjMtLMr+*;x|nL4#g)tZ$f@PE9rdp41J7Ehml-vYJIeQ zz9e?cV903zTHe$|N2}=24@E!rys0O0xx_>c^C_U7LP{QgX=3P-Q|sywTj-2AZ!ru7 z`aY}5GQ0D{TDZees^dD~vnVm#6UkW^J71FY*J$9<3L!%Z`MFi*LPC$?s!Hi3p*#6& z!CSK(Dtuw%HbcpB`%3@py>{_r`l5+T4j7O2gsSLEoh&*Erdvz9HAN%j-;QhwAA@`D ze-=g?kg@*$H>zf3cK?eu-v6~)Ro(v&fxGU1CSv3Rz5p^(rdR$t86SQ1ixoHwZg3D8 zW5i<HAGSzVYOd{Ausx+mkNPYik^MRL56>PV)W!Ybe(Y zgOEe{kO;Ut7MK3}nDQIa>Ec`G;+qc6BX8RMqgTKJn>iHTM>hff7J^8xbN2dY_@M{w zHgr!rz20e$w2!}gd)~*FNN{uEI^?`_)IT}x!Vhmd=b}Mg-93NT=}o(H zC9|#@_^*^|(CHqN?I|;vOoZI_vNqHHT*=T)LoXY8#ds)%%vBnh%PN^!m4yHAKmVV; z$JU?!l2NIYXZ4?2)sXjpUFH7|f;;a2BuDxWRRGRzcUvB|WB6^702a6xmOb zn6)q)8^ViOKv~SL@jU67cnE(YCrk_DNZ3Oo|Myf;6-W}%Oz6<2qtm=D(J-U4MyMB3 zBD2Lb5nH4ZS*0LLvq(`i;NzK4G=z;AY(!z^d5lZncbek0BUDO?6GQp41n0Ds{$y~sJM%D~wt0UKvs5l#3w1REp61<$>e~uA-Bd0 z%f2PlWA;@6Z#;K!b094-qV|>C=3*q&=cNhpUGPnc60-_Is$Yf=6fChV<4ZY%TQ=2= zSx$b7I7{}wY-ay86nqNCa>*b&mvYXyHZKpPi9Y`PHQV0OC?Kp72O;cZV5fFO(O3~A zZ@RR&wbxoQv@A@`cJT{s^&Xb>q=k*VM>fZ6ekhh`8*u+AIsJak;ppPd5d@k2F?I67 z`S?`(i0gN22Kxx+4{E`zEOV7G^WSh+v}KQNmj5GjS{kh|p4-&(ED>>6I?~>a+_b2Fdh)jIvyF>*L~cvZo_vUiBz}y^=t^H+ZrPEW<^RZ{=$Zq#ZNF_? z#3OTEdI;%tM12R}=i(ctAJbH7+1%G6AF;d<3nT58FEWE9lTS3~*~GHqD|OwKc@Lxs zhr?(nv&jkLNtP5%m`Jp28iqK;kZ!`=C@B<#)|ko?fu6ESlJHeaitbrew9$p#)<-xm z{eS9EBNzgb3%I)GVZDWS8BCc{l8qRCx8D_R`tJ!z&BP%yLe(73pGIU zBjq7J#xV}+205mo&D|i99sT9<0>q*y2cCNw`C9dab^1==dD-N3mW8%FD*y>NfSB4@Uh%2B8pg0<8}p)^7C@3f>C@3f>C@3f>C@3f>C@3f>C@3f>C@3f>C@3f>C@3f>d= 0 */ +#define IS_NUMBER_OR_ZERO \ + if(atoi(val) == 0 && strcmp(val, "0") != 0) return 0 +/** check that the value passed is > 0 */ +#define IS_NONZERO_NUMBER \ + if(atoi(val) == 0) return 0 +/** check that the value passed is not 0 and a power of 2 */ +#define IS_POW2_NUMBER \ + if(atoi(val) == 0 || !is_pow2((size_t)atoi(val))) return 0 +/** check that the value passed is yes or no */ +#define IS_YES_OR_NO \ + if(strcmp(val, "yes") != 0 && strcmp(val, "no") != 0) return 0 + +int config_set_option(struct config_file* cfg, const char* opt, + const char* val) +{ + if(strcmp(opt, "verbosity:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->verbosity = atoi(val); + } else if(strcmp(opt, "statistics-interval:") == 0) { + if(strcmp(val, "0") == 0 || strcmp(val, "") == 0) + cfg->stat_interval = 0; + else if(atoi(val) == 0) + return 0; + else cfg->stat_interval = atoi(val); + } else if(strcmp(opt, "num_threads:") == 0) { + /* not supported, library must have 1 thread in bgworker */ + return 0; + } else if(strcmp(opt, "do-ip4:") == 0) { + IS_YES_OR_NO; + cfg->do_ip4 = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "do-ip6:") == 0) { + IS_YES_OR_NO; + cfg->do_ip6 = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "do-udp:") == 0) { + IS_YES_OR_NO; + cfg->do_udp = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "do-tcp:") == 0) { + IS_YES_OR_NO; + cfg->do_tcp = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "outgoing-port:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->outgoing_base_port = atoi(val); + } else if(strcmp(opt, "outgoing-range:") == 0) { + IS_NONZERO_NUMBER; + cfg->outgoing_num_ports = atoi(val); + } else if(strcmp(opt, "outgoing-num-tcp:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->outgoing_num_tcp = (size_t)atoi(val); + } else if(strcmp(opt, "incoming-num-tcp:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->incoming_num_tcp = (size_t)atoi(val); + } else if(strcmp(opt, "msg-buffer-size:") == 0) { + IS_NONZERO_NUMBER; + cfg->msg_buffer_size = (size_t)atoi(val); + } else if(strcmp(opt, "msg-cache-size:") == 0) { + return cfg_parse_memsize(val, &cfg->msg_cache_size); + } else if(strcmp(opt, "msg-cache-slabs:") == 0) { + IS_POW2_NUMBER; + cfg->msg_cache_slabs = (size_t)atoi(val); + } else if(strcmp(opt, "num-queries-per-thread:") == 0) { + IS_NONZERO_NUMBER; + cfg->num_queries_per_thread = (size_t)atoi(val); + } else if(strcmp(opt, "rrset-cache-size:") == 0) { + return cfg_parse_memsize(val, &cfg->rrset_cache_size); + } else if(strcmp(opt, "rrset-cache-slabs:") == 0) { + IS_POW2_NUMBER; + cfg->rrset_cache_slabs = (size_t)atoi(val); + } else if(strcmp(opt, "cache-max-ttl:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->max_ttl = atoi(val); + } else if(strcmp(opt, "infra-host-ttl:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->host_ttl = atoi(val); + } else if(strcmp(opt, "infra-lame-ttl:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->lame_ttl = atoi(val); + } else if(strcmp(opt, "infra-cache-slabs:") == 0) { + IS_POW2_NUMBER; + cfg->infra_cache_slabs = (size_t)atoi(val); + } else if(strcmp(opt, "infra-cache-numhosts:") == 0) { + IS_NONZERO_NUMBER; + cfg->infra_cache_numhosts = (size_t)atoi(val); + } else if(strcmp(opt, "infra-cache-lame-size:") == 0) { + return cfg_parse_memsize(val, &cfg->infra_cache_lame_size); + } else if(strcmp(opt, "logfile:") == 0) { + cfg->use_syslog = 0; + free(cfg->logfile); + return (cfg->logfile = strdup(val)) != NULL; + } else if(strcmp(opt, "use-syslog:") == 0) { + IS_YES_OR_NO; + cfg->use_syslog = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "root-hints:") == 0) { + return cfg_strlist_insert(&cfg->root_hints, strdup(val)); + } else if(strcmp(opt, "target-fetch-policy:") == 0) { + free(cfg->target_fetch_policy); + return (cfg->target_fetch_policy = strdup(val)) != NULL; + } else if(strcmp(opt, "harden-glue:") == 0) { + IS_YES_OR_NO; + cfg->harden_glue = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "harden-short-bufsize:") == 0) { + IS_YES_OR_NO; + cfg->harden_short_bufsize = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "harden-large-queries:") == 0) { + IS_YES_OR_NO; + cfg->harden_large_queries = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "harden-dnssec-stripped:") == 0) { + IS_YES_OR_NO; + cfg->harden_dnssec_stripped = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "do-not-query-localhost:") == 0) { + IS_YES_OR_NO; + cfg->donotquery_localhost = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "do-not-query-address:") == 0) { + return cfg_strlist_insert(&cfg->donotqueryaddrs, strdup(val)); + } else if(strcmp(opt, "trust-anchor-file:") == 0) { + return cfg_strlist_insert(&cfg->trust_anchor_file_list, + strdup(val)); + } else if(strcmp(opt, "trust-anchor:") == 0) { + return cfg_strlist_insert(&cfg->trust_anchor_list, + strdup(val)); + } else if(strcmp(opt, "trusted-keys-file:") == 0) { + return cfg_strlist_insert(&cfg->trusted_keys_file_list, + strdup(val)); + } else if(strcmp(opt, "val-override-date:") == 0) { + if(strcmp(val, "") == 0 || strcmp(val, "0") == 0) { + cfg->val_date_override = 0; + } else if(strlen(val) == 14) { + cfg->val_date_override = cfg_convert_timeval(val); + return cfg->val_date_override != 0; + } else { + if(atoi(val) == 0) return 0; + cfg->val_date_override = (uint32_t)atoi(val); + } + } else if(strcmp(opt, "val-bogus-ttl:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->bogus_ttl = atoi(val); + } else if(strcmp(opt, "val-clean-additional:") == 0) { + IS_YES_OR_NO; + cfg->val_clean_additional = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "val-permissive-mode:") == 0) { + IS_YES_OR_NO; + cfg->val_permissive_mode = (strcmp(val, "yes") == 0); + } else if(strcmp(opt, "val-nsec3-keysize-iterations:") == 0) { + free(cfg->val_nsec3_key_iterations); + return (cfg->val_nsec3_key_iterations = strdup(val)) != NULL; + } else if(strcmp(opt, "key-cache-size:") == 0) { + return cfg_parse_memsize(val, &cfg->key_cache_size); + } else if(strcmp(opt, "key-cache-slabs:") == 0) { + IS_POW2_NUMBER; + cfg->key_cache_slabs = (size_t)atoi(val); + } else if(strcmp(opt, "local-data:") == 0) { + return cfg_strlist_insert(&cfg->local_data, strdup(val)); + } else if(strcmp(opt, "module-config:") == 0) { + free(cfg->module_conf); + return (cfg->module_conf = strdup(val)) != NULL; + } else { + /* unknown or unsupported (from the library interface) */ + return 0; + } + return 1; +} + /** initialize the global cfg_parser object */ static void create_cfg_parser(struct config_file* cfg, char* filename) diff --git a/util/config_file.h b/util/config_file.h index ffb6b3bba..c52cc1665 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -271,6 +271,17 @@ void config_delete(struct config_file* config); */ void config_apply(struct config_file* config); +/** + * Set the given keyword to the given value. + * @param config: where to store config + * @param option: option name, including the ':' character. + * @param value: value, this string is copied if needed, or parsed. + * The caller owns the value string. + * @return 0 on error (malloc or syntax error). + */ +int config_set_option(struct config_file* config, const char* option, + const char* value); + /** * Insert string into strlist. * @param head: pointer to strlist head variable. diff --git a/util/log.c b/util/log.c index c1db604cc..998b4c291 100644 --- a/util/log.c +++ b/util/log.c @@ -104,7 +104,7 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) } /* open the file for logging */ if(chrootdir && chrootdir[0] && strncmp(filename, chrootdir, - strlen(chrootdir)) == 0) + strlen(chrootdir)) == 0) filename += strlen(chrootdir); f = fopen(filename, "a"); if(!f) { @@ -115,6 +115,11 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) logfile = f; } +void log_file(FILE *f) +{ + logfile = f; +} + void log_thread_set(int* num) { ub_thread_key_set(logkey, num); @@ -140,6 +145,7 @@ log_vmsg(int pri, const char* type, return; } #endif /* HAVE_SYSLOG_H */ + if(!logfile) return; fprintf(logfile, "[%d] %s[%d:%x] %s: %s\n", (int)time(NULL), ident, (int)getpid(), tid?*tid:0, type, message); fflush(logfile); diff --git a/util/log.h b/util/log.h index f6983181e..394a20111 100644 --- a/util/log.h +++ b/util/log.h @@ -84,6 +84,13 @@ void verbose(enum verbosity_value level, */ void log_init(const char* filename, int use_syslog, const char* chrootdir); +/** + * Set logging to go to the specified file *. + * This setting does not affect the use_syslog setting. + * @param f: to that file, or pass NULL to disable logging. + */ +void log_file(FILE *f); + /** * Init a thread (will print this number for the thread log entries). * Must be called from the thread itself. If not called 0 is printed. diff --git a/util/timehist.c b/util/timehist.c index 48f3a0d4e..047f72e02 100644 --- a/util/timehist.c +++ b/util/timehist.c @@ -156,7 +156,7 @@ void timehist_print(struct timehist* hist) #endif } -void timehist_log(struct timehist* hist) +void timehist_log(struct timehist* hist, const char* name) { #ifndef S_SPLINT_S size_t i; @@ -165,7 +165,7 @@ void timehist_log(struct timehist* hist) timehist_quartile(hist, 0.50), timehist_quartile(hist, 0.75)); /* 0000.000000 0000.000000 0 */ - log_info("lower(secs) upper(secs) replycount"); + log_info("lower(secs) upper(secs) %s", name); for(i=0; inum; i++) { if(hist->buckets[i].count != 0) { log_info("%4d.%6.6d %4d.%6.6d %u", diff --git a/util/timehist.h b/util/timehist.h index 96e744f4d..aabda19c6 100644 --- a/util/timehist.h +++ b/util/timehist.h @@ -108,7 +108,8 @@ void timehist_print(struct timehist* hist); /** * Log histogram, print it to the logfile. * @param hist: histogram + * @param name: the name of the value column */ -void timehist_log(struct timehist* hist); +void timehist_log(struct timehist* hist, const char* name); #endif /* UTIL_TIMEHIST_H */