diff --git a/include/config.h b/include/config.h index 633b73140..3695edb6d 100644 --- a/include/config.h +++ b/include/config.h @@ -294,6 +294,12 @@ #define UNREALIRCD_DEFAULT_ECDH_CURVES "secp521r1:secp384r1:prime256v1" #endif +/* These are just defaults, which you can override via set::dns */ +#define DNS_DEFAULT_CLIENT_TIMEOUT 1500 +#define DNS_DEFAULT_CLIENT_RETRIES 2 +#define DNS_DEFAULT_DNSBL_TIMEOUT 3000 +#define DNS_DEFAULT_DNSBL_RETRIES 2 + /* ------------------------- END CONFIGURATION SECTION -------------------- */ #define MOTD MPATH #define RULES RPATH diff --git a/include/dynconf.h b/include/dynconf.h index 2a3c000fd..4d273a682 100644 --- a/include/dynconf.h +++ b/include/dynconf.h @@ -179,6 +179,10 @@ struct Configuration { int server_notice_show_event; LimitSVSCMDS limit_svscmds; int high_connection_rate; + int dns_client_timeout; + int dns_client_retry; + int dns_dnsbl_timeout; + int dns_dnsbl_retry; }; extern MODVAR Configuration iConf; diff --git a/include/h.h b/include/h.h index 4480b2a4d..828f37708 100644 --- a/include/h.h +++ b/include/h.h @@ -1126,6 +1126,7 @@ extern void set_targmax_defaults(void); extern void parse_chanmodes_protoctl(Client *client, const char *str); extern void concat_params(char *buf, int len, int parc, const char *parv[]); extern void charsys_check_for_changes(void); +extern void dns_check_for_changes(void); extern MODVAR int maxclients; extern int fast_badword_match(ConfigItem_badword *badword, const char *line); extern int fast_badword_replace(ConfigItem_badword *badword, const char *line, char *buf, int max); diff --git a/src/conf.c b/src/conf.c index 2248c438e..422a2615f 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1825,6 +1825,10 @@ void config_setdefaultsettings(Configuration *i) i->central_spamfilter_except = safe_alloc(sizeof(SecurityGroup)); i->central_spamfilter_except->reputation_score = 2016; /* 7 days unregged, or 3.5 days identified */ unreal_add_mask_string(&i->central_spamfilter_except->mask, "*.irccloud.com"); + i->dns_client_timeout = DNS_DEFAULT_CLIENT_TIMEOUT; + i->dns_client_retry = DNS_DEFAULT_CLIENT_RETRIES; + i->dns_dnsbl_timeout = DNS_DEFAULT_DNSBL_TIMEOUT; + i->dns_dnsbl_retry = DNS_DEFAULT_DNSBL_RETRIES; } /* Some settings have been moved to here - we (re)set some defaults */ @@ -8311,6 +8315,31 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce) } else if (!strcmp(cep->name, "best-practices")) { /* This is handled in config test already (there is no other way) */ + } else if (!strcmp(cep->name, "dns")) + { + for (cepp = cep->items; cepp; cepp = cepp->next) + { + if (!strcmp(cepp->name, "client")) + { + for (ceppp = cepp->items; ceppp; ceppp = ceppp->next) + { + if (!strcmp(ceppp->name, "timeout")) + tempiConf.dns_client_timeout = atoi(ceppp->value); + else if (!strcmp(ceppp->name, "retry")) + tempiConf.dns_client_retry = atoi(ceppp->value); + } + } else + if (!strcmp(cepp->name, "dnsbl")) + { + for (ceppp = cepp->items; ceppp; ceppp = ceppp->next) + { + if (!strcmp(ceppp->name, "timeout")) + tempiConf.dns_dnsbl_timeout = atoi(ceppp->value); + else if (!strcmp(ceppp->name, "retry")) + tempiConf.dns_dnsbl_retry = atoi(ceppp->value); + } + } + } } else if (config_set_dynamic_set_block_item(conf, &dynamic_set, cep)) { /* Handled by config_set_dynamic_set_block_item - nothing to do here */ @@ -9755,6 +9784,52 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce) continue; } } + } else if (!strcmp(cep->name, "dns")) + { + for (cepp = cep->items; cepp; cepp = cepp->next) + { + if (!strcmp(cepp->name, "client") || !strcmp(cepp->name, "dnsbl")) + { + for (ceppp = cepp->items; ceppp; ceppp = ceppp->next) + { + CheckNull(ceppp); + if (!strcmp(ceppp->name, "timeout")) + { + int v = atoi(ceppp->value); + if ((v < 1000) || (v > 10000)) + { + config_error("%s:%i: the timeout needs to be in milliseconds and in the range 1000-10000.", + ceppp->file->filename, ceppp->line_number); + errors++; + } + } else + if (!strcmp(ceppp->name, "retry")) + { + int v = atoi(ceppp->value); + if ((v < 0) || (v > 5)) + { + config_error("%s:%i: retry value needs to be in range 0-5.", + ceppp->file->filename, ceppp->line_number); + errors++; + } + } else + { + config_error_unknown(ceppp->file->filename, + ceppp->line_number, "set::dns::..::", + ceppp->name); + errors++; + continue; + } + } + } else + { + config_error_unknown(cepp->file->filename, + cepp->line_number, "set::dns", + cepp->name); + errors++; + continue; + } + } } else if ((n = test_dynamic_set_block_item(conf, NULL, cep)) >= 0) { /* Handled by test_dynamic_set_block_item: @@ -9982,6 +10057,7 @@ void config_run(void) if (!loop.booted) add_proc_io_server(); free_all_config_resources(); + dns_check_for_changes(); } int _conf_offchans(ConfigFile *conf, ConfigEntry *ce) diff --git a/src/dns.c b/src/dns.c index b77aa4b98..024532619 100644 --- a/src/dns.c +++ b/src/dns.c @@ -157,14 +157,6 @@ void init_resolver(int firsttime) } memset(&options, 0, sizeof(options)); - options.timeout = 1500; /* 1.5 seconds */ - options.tries = 2; - /* Note that the effective DNS timeout is NOT simply 1500*2=3000. - * This is because c-ares does some incremental timeout stuff itself - * that may add up to twice the timeout in the second round, - * so effective max is 1500ms first and then up to 3000s, so 4500ms in total - * (until they change the algorithm again, that is...). - */ options.flags |= ARES_FLAG_NOALIASES|ARES_FLAG_IGNTC; options.sock_state_cb = unrealdns_sock_state_cb; /* Don't search domains or you'll get lookups for like @@ -181,8 +173,10 @@ void init_resolver(int firsttime) optmask |= ARES_OPT_LOOKUPS; #endif - /* First the client channel */ + /*** First the client channel ***/ options.sock_state_cb_data = RESOLVER_CHANNEL_CLIENT; + options.timeout = iConf.dns_client_timeout ? iConf.dns_client_timeout : DNS_DEFAULT_CLIENT_TIMEOUT; + options.tries = iConf.dns_client_retry ? iConf.dns_client_retry : DNS_DEFAULT_CLIENT_RETRIES; n = ares_init_options(&resolver_channel_client, &options, optmask); if (n != ARES_SUCCESS) { @@ -197,6 +191,8 @@ void init_resolver(int firsttime) /* And then the DNSBL channel */ options.sock_state_cb_data = RESOLVER_CHANNEL_DNSBL; + options.timeout = iConf.dns_dnsbl_timeout ? iConf.dns_dnsbl_timeout : DNS_DEFAULT_DNSBL_TIMEOUT; + options.tries = iConf.dns_dnsbl_retry ? iConf.dns_dnsbl_retry : DNS_DEFAULT_DNSBL_RETRIES; n = ares_init_options(&resolver_channel_dnsbl, &options, optmask); if (n != ARES_SUCCESS) { @@ -667,6 +663,34 @@ void unrealdns_delasyncconnects(void) } +void dns_check_for_changes(void) +{ + struct ares_options inf; + int changed = 0; + int optmask; + + memset(&inf, 0, sizeof(inf)); + ares_save_options(resolver_channel_client, &inf, &optmask); + if ((inf.timeout != iConf.dns_client_timeout) || (inf.tries != iConf.dns_client_retry)) + changed = 1; + ares_destroy_options(&inf); + + memset(&inf, 0, sizeof(inf)); + ares_save_options(resolver_channel_dnsbl, &inf, &optmask); + if ((inf.timeout != iConf.dns_dnsbl_timeout) || (inf.tries != iConf.dns_dnsbl_retry)) + changed = 1; + ares_destroy_options(&inf); + + if (changed) + { + if (loop.booted) + config_status("DNS Configuration changed, reinitializing DNS..."); + ares_destroy(resolver_channel_client); + ares_destroy(resolver_channel_dnsbl); + init_resolver(0); + } +} + CMD_FUNC(cmd_dns) { DNSCache *c; @@ -749,6 +773,7 @@ CMD_FUNC(cmd_dns) sendtxtnumeric(client, " timeout: %d", inf.timeout); if (optmask & ARES_OPT_TRIES) sendtxtnumeric(client, " tries: %d", inf.tries); + ares_destroy_options(&inf); sendtxtnumeric(client, "=== DNSBL resolver channel ==="); i = 0; @@ -768,10 +793,10 @@ CMD_FUNC(cmd_dns) sendtxtnumeric(client, " timeout: %d", inf.timeout); if (optmask & ARES_OPT_TRIES) sendtxtnumeric(client, " tries: %d", inf.tries); + ares_destroy_options(&inf); sendtxtnumeric(client, "****** End of DNS Configuration Info ******"); - ares_destroy_options(&inf); } else /* STATISTICS */ { sendtxtnumeric(client, "DNS CACHE Stats:");