From d7f47f4de61461959114aa3c275d8bb2f83d1fe5 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 11 Feb 2008 15:22:57 +0000 Subject: [PATCH] nice option interface. Nice debug output stream option. git-svn-id: file:///svn/unbound/trunk@945 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 2 + doc/TODO | 1 + doc/libunbound.3 | 19 +++++ libunbound/context.c | 4 +- libunbound/context.h | 4 + libunbound/libunbound.c | 26 +++++++ libunbound/ubsyms.def | 2 + libunbound/unbound.h | 25 +++++++ util/config_file.c | 158 ++++++++++++++++++++++++++++++++++++++++ util/config_file.h | 11 +++ util/log.c | 8 +- util/log.h | 7 ++ 12 files changed, 265 insertions(+), 2 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index b30787697..5404c1351 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,8 @@ - changed library to use ub_ instead of ub_val_ as prefix. - statistics output text nice. - etc/hosts handling. + - library function to put logging to a stream. + - set any option interface. 8 February 2008: Wouter - test program for multiple queries over a TCP channel. diff --git a/doc/TODO b/doc/TODO index c60f8f638..9876ed40d 100644 --- a/doc/TODO +++ b/doc/TODO @@ -55,3 +55,4 @@ o support multiple dns messages in a TCP query stream for the unbound server. o SIG(0) and TSIG. o support OPT record placement on recv anywhere in the additional section. o add local-file: config with authority features. +o option to make local-data answers be secure for libunbound (default=no) diff --git a/doc/libunbound.3 b/doc/libunbound.3 index dd9f97cac..81e8de1ca 100644 --- a/doc/libunbound.3 +++ b/doc/libunbound.3 @@ -16,6 +16,7 @@ .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, @@ -23,6 +24,7 @@ .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, @@ -46,6 +48,9 @@ \fBub_ctx_delete\fR(\fIstruct ub_ctx*\fR ctx); .LP \fIint\fR +\fBub_ctx_set_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar*\fR val); +.LP +\fIint\fR \fBub_ctx_config\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR @@ -67,6 +72,9 @@ \fBub_ctx_trustedkeys\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname); .LP \fIint\fR +\fBub_ctx_debugout\fR(\fIstruct ub_ctx*\fR ctx, \fIFILE*\fR out); +.LP +\fIint\fR \fBub_ctx_debuglevel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR d); .LP \fIint\fR @@ -146,6 +154,12 @@ to read them. Delete validation context and free associated resources. Outstanding async queries are killed and callbacks are not called for them. .TP +.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 @@ -198,6 +212,11 @@ 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_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. diff --git a/libunbound/context.c b/libunbound/context.c index 188157cf4..dc6137920 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -55,7 +55,9 @@ 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; diff --git a/libunbound/context.h b/libunbound/context.h index ef193ef23..13a6c4f36 100644 --- a/libunbound/context.h +++ b/libunbound/context.h @@ -87,6 +87,10 @@ struct ub_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 diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index 0533fca5b..2b694dac1 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -233,6 +233,22 @@ ub_ctx_delete(struct ub_ctx* ctx) free(ctx); } +int +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) { @@ -316,6 +332,16 @@ ub_ctx_debuglevel(struct ub_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_ctx_async(struct ub_ctx* ctx, int dothread) { diff --git a/libunbound/ubsyms.def b/libunbound/ubsyms.def index 2b7b174fc..7a8c5852f 100644 --- a/libunbound/ubsyms.def +++ b/libunbound/ubsyms.def @@ -1,5 +1,6 @@ ub_ctx_create ub_ctx_delete +ub_ctx_set_option ub_ctx_config ub_ctx_set_fwd ub_ctx_resolvconf @@ -7,6 +8,7 @@ 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 diff --git a/libunbound/unbound.h b/libunbound/unbound.h index f5f8248ff..9ee32b9c0 100644 --- a/libunbound/unbound.h +++ b/libunbound/unbound.h @@ -207,6 +207,21 @@ struct ub_ctx* ub_ctx_create(void); */ 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. * @param ctx: context. @@ -303,6 +318,16 @@ int ub_ctx_add_ta_file(struct ub_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 * Output is directed to stderr. diff --git a/util/config_file.c b/util/config_file.c index 42728b6f9..e7266c079 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -164,6 +164,164 @@ struct config_file* config_create_forlib() return cfg; } +int config_set_option(struct config_file* cfg, const char* opt, + const char* val) +{ +#define IS_NUMBER_OR_ZERO \ + if(atoi(val) == 0 && strcmp(val, "0") != 0) return 0 +#define IS_NONZERO_NUMBER \ + if(atoi(val) == 0) return 0 +#define IS_POW2_NUMBER \ + if(atoi(val) == 0 || !is_pow2(atoi(val))) return 0 +#define IS_YES_OR_NO \ + if(strcmp(val, "yes") != 0 && strcmp(val, "no") != 0) return 0 + + 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 = atoi(val); + } else if(strcmp(opt, "incoming-num-tcp:") == 0) { + IS_NUMBER_OR_ZERO; + cfg->incoming_num_tcp = atoi(val); + } else if(strcmp(opt, "msg-buffer-size:") == 0) { + IS_NONZERO_NUMBER; + cfg->msg_buffer_size = 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 = atoi(val); + } else if(strcmp(opt, "num-queries-per-thread:") == 0) { + IS_NONZERO_NUMBER; + cfg->num_queries_per_thread = 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 = 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 = atoi(val); + } else if(strcmp(opt, "infra-cache-numhosts:") == 0) { + IS_NONZERO_NUMBER; + cfg->infra_cache_numhosts = 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 = 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 = 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. -- 2.47.2