From: Chris Hofstaedtler Date: Thu, 29 Oct 2020 12:48:46 +0000 (+0100) Subject: auth,rec: add ignore-unknown-settings setting X-Git-Tag: dnsdist-1.6.0-rc1~31^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d6e970b5e9dcbf252a78f5e817f5f8197d5b3d8;p=thirdparty%2Fpdns.git auth,rec: add ignore-unknown-settings setting --- diff --git a/docs/settings.rst b/docs/settings.rst index f45208dae9..8fa837b60d 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -681,6 +681,21 @@ or slave settings. Run within a guardian process. See :ref:`running-guardian`. +.. _setting-ignore-unknown-settings: + +``ignore-unknown-settings`` +--------------------------- + +.. versionadded:: 4.5.0 + +- Setting names, separated by commas +- Default: empty + +Names of settings to be ignored while parsing configuration files, if the setting +name is unknown to PowerDNS. + +Useful during upgrade testing. + .. _setting-include-dir: ``include-dir`` diff --git a/pdns/arguments.cc b/pdns/arguments.cc index aa21f6ded6..73684cff67 100644 --- a/pdns/arguments.cc +++ b/pdns/arguments.cc @@ -37,17 +37,17 @@ const ArgvMap::param_t::const_iterator ArgvMap::begin() { - return params.begin(); + return d_params.begin(); } const ArgvMap::param_t::const_iterator ArgvMap::end() { - return params.end(); + return d_params.end(); } string & ArgvMap::set(const string &var) { - return params[var]; + return d_params[var]; } void ArgvMap::setDefault(const string &var, const string &value) @@ -58,9 +58,9 @@ void ArgvMap::setDefault(const string &var, const string &value) void ArgvMap::setDefaults() { - for(map::const_iterator i=params.begin();i!=params.end();++i) - if(! defaultmap.count(i->first)) - defaultmap.insert(*i); + for (const auto& i: d_params) + if(! defaultmap.count(i.first)) + defaultmap.insert(i); } bool ArgvMap::mustDo(const string &var) @@ -71,8 +71,8 @@ bool ArgvMap::mustDo(const string &var) vectorArgvMap::list() { vector ret; - for(map::const_iterator i=params.begin();i!=params.end();++i) - ret.push_back(i->first); + for (const auto& i: d_params) + ret.push_back(i.first); return ret; } @@ -105,13 +105,13 @@ string & ArgvMap::setSwitch(const string &var, const string &help) bool ArgvMap::contains(const string &var, const string &val) { - params_t::const_iterator param = params.find(var); - if(param == params.end() || param->second.empty()) { + const auto& param = d_params.find(var); + if(param == d_params.end() || param->second.empty()) { return false; } vector parts; - stringtok( parts, param->second, ", \t" ); + stringtok(parts, param->second, ", \t"); for (const auto& part: parts) { if (part == val) { return true; @@ -154,6 +154,40 @@ string ArgvMap::helpstring(string prefix) return help; } +const string ArgvMap::formatOne(bool running, bool full, const string &var, const string &help, const string& theDefault, const string& current) +{ + string out; + + if (!running || full) { + out += "#################################\n"; + out += "# "; + out += var; + out += "\t"; + out += help; + out += "\n#\n"; + } else { + if (theDefault == current) { + return ""; + } + } + + if (! running || theDefault == current) { + out += "# "; + } + + if (running) { + out += var + "=" + current + "\n"; + if (full) { + out += "\n"; + } + } else { + out += var + "=" + theDefault + "\n\n"; + } + + return out; +} + +// If running and full, only changed settings are returned. string ArgvMap::configstring(bool running, bool full) { string help; @@ -163,40 +197,28 @@ string ArgvMap::configstring(bool running, bool full) else help="# Autogenerated configuration file template\n\n"; + // Affects parsing, should come first. + help += formatOne(running, full, "ignore-unknown-settings", helpmap["ignore-unknown-settings"], defaultmap["ignore-unknown-settings"], d_params["ignore-unknown-settings"]); + for(const auto& i: helpmap) { - if(d_typeMap[i.first]=="Command") + if (d_typeMap[i.first] == "Command") + continue; + if (i.first == "ignore-unknown-settings") continue; - if (! defaultmap.count(i.first)) { - throw ArgException(string("Default for parameter '")+i.first+"' not set"); + if (!defaultmap.count(i.first)) { + throw ArgException(string("Default for setting '")+i.first+"' not set"); } - if (!running || full) { - help+="#################################\n"; - help+="# "; - help+=i.first; - help+="\t"; - help+=i.second; - help+="\n#\n"; - } else { - if (defaultmap[i.first] == params[i.first]) { - continue; - } - } - - if (! running || defaultmap[i.first] == params[i.first]) { - help+="# "; - } + help += formatOne(running, full, i.first, i.second, defaultmap[i.first], d_params[i.first]); + } - if (running) { - help+=i.first+"="+params[i.first]+"\n"; - if (full) { - help+="\n"; - } - } else { - help+=i.first+"="+defaultmap[i.first]+"\n\n"; + if (running) { + for(const auto& i: d_unknownParams) { + help += formatOne(running, full, i.first, "unknown setting", "", i.second); } } + return help; } @@ -205,7 +227,7 @@ const string & ArgvMap::operator[](const string &arg) if(!parmIsset(arg)) throw ArgException(string("Undefined but needed argument: '")+arg+"'"); - return params[arg]; + return d_params[arg]; } mode_t ArgvMap::asMode(const string &arg) @@ -217,7 +239,7 @@ mode_t ArgvMap::asMode(const string &arg) if(!parmIsset(arg)) throw ArgException(string("Undefined but needed argument: '")+arg+"'"); - cptr_orig = params[arg].c_str(); + cptr_orig = d_params[arg].c_str(); mode = static_cast(strtol(cptr_orig, &cptr_ret, 8)); if (mode == 0 && cptr_ret == cptr_orig) throw ArgException("'" + arg + string("' contains invalid octal mode")); @@ -233,11 +255,11 @@ gid_t ArgvMap::asGid(const string &arg) if(!parmIsset(arg)) throw ArgException(string("Undefined but needed argument: '")+arg+"'"); - cptr_orig = params[arg].c_str(); + cptr_orig = d_params[arg].c_str(); gid = static_cast(strtol(cptr_orig, &cptr_ret, 0)); if (gid == 0 && cptr_ret == cptr_orig) { // try to resolve - struct group *group = getgrnam(params[arg].c_str()); + struct group *group = getgrnam(d_params[arg].c_str()); if (group == nullptr) throw ArgException("'" + arg + string("' contains invalid group")); gid = group->gr_gid; @@ -254,11 +276,11 @@ uid_t ArgvMap::asUid(const string &arg) if(!parmIsset(arg)) throw ArgException(string("Undefined but needed argument: '")+arg+"'"); - cptr_orig = params[arg].c_str(); + cptr_orig = d_params[arg].c_str(); uid = static_cast(strtol(cptr_orig, &cptr_ret, 0)); if (uid == 0 && cptr_ret == cptr_orig) { // try to resolve - struct passwd *pwent = getpwnam(params[arg].c_str()); + struct passwd *pwent = getpwnam(d_params[arg].c_str()); if (pwent == nullptr) throw ArgException("'" + arg + string("' contains invalid group")); uid = pwent->pw_uid; @@ -276,10 +298,10 @@ int ArgvMap::asNum(const string &arg, int def) throw ArgException(string("Undefined but needed argument: '")+arg+"'"); // use default for empty values - if (params[arg].empty()) + if (d_params[arg].empty()) return def; - cptr_orig = params[arg].c_str(); + cptr_orig = d_params[arg].c_str(); retval = static_cast(strtol(cptr_orig, &cptr_ret, 0)); if (!retval && cptr_ret == cptr_orig) throw ArgException("'"+arg+"' value '"+string(cptr_orig) + string( "' is not a valid number")); @@ -291,7 +313,7 @@ bool ArgvMap::isEmpty(const string &arg) { if(!parmIsset(arg)) return true; - return params[arg].empty(); + return d_params[arg].empty(); } double ArgvMap::asDouble(const string &arg) @@ -303,10 +325,10 @@ double ArgvMap::asDouble(const string &arg) if(!parmIsset(arg)) throw ArgException(string("Undefined but needed argument: '")+arg+"'"); - if (params[arg].empty()) + if (d_params[arg].empty()) return 0.0; - cptr_orig = params[arg].c_str(); + cptr_orig = d_params[arg].c_str(); retval = strtod(cptr_orig, &cptr_ret); if (retval == 0 && cptr_ret == cptr_orig) @@ -317,12 +339,12 @@ double ArgvMap::asDouble(const string &arg) ArgvMap::ArgvMap() { - + set("ignore-unknown-settings","Configuration settings to ignore if they are unknown")=""; } bool ArgvMap::parmIsset(const string &var) { - return (params.find(var)!=params.end()); + return d_params.find(var) != d_params.end(); } void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax) @@ -365,23 +387,36 @@ void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax) { if(incremental) { - if(params[var].empty()) + if(d_params[var].empty()) { if(!d_cleared.count(var)) - throw ArgException("Incremental parameter '"+var+"' without a parent"); - params[var]=val; + throw ArgException("Incremental setting '"+var+"' without a parent"); + d_params[var] = val; } else - params[var]+=", " + val; + d_params[var] += ", " + val; } else { - params[var]=val; + d_params[var] = val; d_cleared.insert(var); } } - else if(!lax) - throw ArgException("Trying to set unknown parameter '"+var+"'"); + else + { + // unknown setting encountered. see if its on the ignore list before throwing. + std::set parts; + stringtok(parts, d_params["ignore-unknown-settings"], " ,\t\n\r"); + if (parts.find(var) != parts.end()) { + d_unknownParams[var] = val; + g_log< extraConfigs; gatherIncludes(extraConfigs); for(const std::string& fn : extraConfigs) { @@ -491,13 +526,13 @@ bool ArgvMap::file(const char *fname, bool lax, bool included) void ArgvMap::gatherIncludes(std::vector &extraConfigs) { extraConfigs.clear(); - if (params["include-dir"].empty()) + if (d_params["include-dir"].empty()) return; // nothing to do DIR *dir; - if (!(dir = opendir(params["include-dir"].c_str()))) { + if (!(dir = opendir(d_params["include-dir"].c_str()))) { int err = errno; - string msg = params["include-dir"] + " is not accessible: " + strerror(err); + string msg = d_params["include-dir"] + " is not accessible: " + strerror(err); g_log << Logger::Error << msg << std::endl; throw ArgException(msg); } @@ -508,7 +543,7 @@ void ArgvMap::gatherIncludes(std::vector &extraConfigs) { continue; // skip any dots if (boost::ends_with(ent->d_name, ".conf")) { // build name - string name = params["include-dir"] + "/" + ent->d_name; // FIXME: Use some path separator + string name = d_params["include-dir"] + "/" + ent->d_name; // FIXME: Use some path separator // ensure it's readable file struct stat st; if (stat(name.c_str(), &st) || !S_ISREG(st.st_mode)) { diff --git a/pdns/arguments.hh b/pdns/arguments.hh index 1772241638..696f3ffa92 100644 --- a/pdns/arguments.hh +++ b/pdns/arguments.hh @@ -120,8 +120,9 @@ public: void gatherIncludes(std::vector &extraConfigs); private: void parseOne(const string &unparsed, const string &parseOnly="", bool lax=false); - typedef map params_t; - params_t params; + const string formatOne(bool running, bool full, const string &var, const string &help, const string& theDefault, const string& value); + map d_params; + map d_unknownParams; map helpmap; map defaultmap; map d_typeMap; diff --git a/pdns/misc.hh b/pdns/misc.hh index 193750446c..b283992cf3 100644 --- a/pdns/misc.hh +++ b/pdns/misc.hh @@ -80,10 +80,16 @@ struct ServiceTuple }; void parseService(const string &descr, ServiceTuple &st); -template +template void stringtok (Container &container, string const &in, - const char * const delimiters = " \t\n") + const char * const delimiters = " \t\n"); + +template::value>::type = true> +void +stringtok (Container &container, string const &in, + const char * const delimiters) { const string::size_type len = in.length(); string::size_type i = 0; @@ -109,6 +115,36 @@ stringtok (Container &container, string const &in, } } +template::value>::type = true> +void +stringtok (Container &container, string const &in, + const char * const delimiters) +{ + const string::size_type len = in.length(); + string::size_type i = 0; + + while (i bool rfc1982LessThan(T a, T b) { static_assert(std::is_unsigned::value, "rfc1982LessThan only works for unsigned types"); diff --git a/pdns/recursordist/docs/settings.rst b/pdns/recursordist/docs/settings.rst index f4d796bd3d..5914ce1b95 100644 --- a/pdns/recursordist/docs/settings.rst +++ b/pdns/recursordist/docs/settings.rst @@ -794,6 +794,21 @@ If set, EDNS options in incoming queries are extracted and passed to the :func:` If set, the root-hints are read from this file. If unset, default root hints are used. +.. _setting-ignore-unknown-settings: + +``ignore-unknown-settings`` +--------------------------- + +.. versionadded:: 4.6.0 + +- Setting names, separated by commas +- Default: empty + +Names of settings to be ignored while parsing configuration files, if the setting +name is unknown to PowerDNS. + +Useful during upgrade testing. + .. _setting-include-dir: ``include-dir``