From dd16158081777c0402412912d7da71cad202982b Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 9 Sep 2022 23:44:21 -0300 Subject: [PATCH] DNS: default to 127.3.2.1 & high port on Linux Lots of tools struggle with non-default DNS port, so keep a listener on 127.3.2.1:53 (by default). This required various changes to the config handling to hold a vector (instead of an optional) of defaults and values, and now allows passing in an array of defaults instead of just a single default. --- llarp/config/config.cpp | 19 +++-- llarp/config/definition.cpp | 30 +++---- llarp/config/definition.hpp | 159 +++++++++++++++++++----------------- 3 files changed, 110 insertions(+), 98 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 195b96f4d..9826e98f6 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -776,17 +776,18 @@ namespace llarp // Most non-linux platforms have loopback as 127.0.0.1/32, but linux uses 127.0.0.1/8 so that we // can bind to other 127.* IPs to avoid conflicting with something else that may be listening on // 127.0.0.1:53. + constexpr std::array DefaultDNSBind{ #ifdef __linux__ #ifdef WITH_SYSTEMD - // when we have systemd support add a random high port on loopback - // see https://github.com/oxen-io/lokinet/issues/1887#issuecomment-1091897282 - constexpr Default DefaultDNSBind{"127.0.0.1:0"}; -#else - constexpr Default DefaultDNSBind{"127.3.2.1:53"}; + // when we have systemd support add a random high port on loopback as well + // see https://github.com/oxen-io/lokinet/issues/1887#issuecomment-1091897282 + Default{"127.0.0.1:0"}, #endif + Default{"127.3.2.1:53"}, #else - constexpr Default DefaultDNSBind{"127.0.0.1:53"}; + Default{"127.0.0.1:53"}, #endif + }; // Default, but if we get any upstream (including upstream=, i.e. empty string) we clear it constexpr Default DefaultUpstreamDNS{"9.9.9.10:53"}; @@ -829,9 +830,10 @@ namespace llarp "query-bind", #ifdef __APPLE__ Default{"127.0.0.1:1253"}, -#endif -#ifdef _WIN32 +#elif defined(_WIN32) Default{"0.0.0.0:0"}, +#else + Hidden, #endif Comment{ "Address to bind to for sending upstream DNS requests.", @@ -842,6 +844,7 @@ namespace llarp "dns", "bind", DefaultDNSBind, + MultiValue, Comment{ "Address to bind to for handling DNS requests.", }, diff --git a/llarp/config/definition.cpp b/llarp/config/definition.cpp index ccf885c15..aa199ebea 100644 --- a/llarp/config/definition.cpp +++ b/llarp/config/definition.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -176,12 +175,14 @@ namespace llarp std::string ConfigDefinition::generateINIConfig(bool useValues) { - std::ostringstream oss; + std::string ini; + auto ini_append = std::back_inserter(ini); int sectionsVisited = 0; visitSections([&](const std::string& section, const DefinitionMap&) { - std::ostringstream sect_out; + std::string sect_str; + auto sect_append = std::back_inserter(sect_str); visitDefinitions(section, [&](const std::string& name, const OptionDefinition_ptr& def) { bool has_comment = false; @@ -190,44 +191,43 @@ namespace llarp // (i.e. those handled by UndeclaredValueHandler's) for (const std::string& comment : m_definitionComments[section][name]) { - sect_out << "\n# " << comment; + fmt::format_to(sect_append, "\n# {}", comment); has_comment = true; } if (useValues and def->getNumberFound() > 0) { - sect_out << "\n" << name << "=" << def->valueAsString(false) << "\n"; + for (const auto& val : def->valuesAsString()) + fmt::format_to(sect_append, "\n{}={}\n", name, val); } else if (not(def->hidden and not has_comment)) { - sect_out << "\n"; - if (not def->required) - sect_out << "#"; - sect_out << name << "=" << def->defaultValueAsString() << "\n"; + for (const auto& val : def->defaultValuesAsString()) + fmt::format_to(sect_append, "\n{}{}={}\n", def->required ? "" : "#", name, val); } }); - auto sect_str = sect_out.str(); if (sect_str.empty()) return; // Skip sections with no options if (sectionsVisited > 0) - oss << "\n\n"; + ini += "\n\n"; - oss << "[" << section << "]\n"; + fmt::format_to(ini_append, "[{}]\n", section); // TODO: this will create empty objects as a side effect of map's operator[] // TODO: this also won't handle sections which have no definition for (const std::string& comment : m_sectionComments[section]) { - oss << "# " << comment << "\n"; + fmt::format_to(ini_append, "# {}\n", comment); } - oss << "\n" << sect_str; + ini += "\n"; + ini += sect_str; sectionsVisited++; }); - return oss.str(); + return ini; } const OptionDefinition_ptr& diff --git a/llarp/config/definition.hpp b/llarp/config/definition.hpp index b3f9cd0ab..8f9225c28 100644 --- a/llarp/config/definition.hpp +++ b/llarp/config/definition.hpp @@ -97,12 +97,19 @@ namespace llarp template constexpr bool is_default = is_default>; + template + constexpr bool is_default_array = false; + template + constexpr bool is_default_array, N>> = true; + template + constexpr bool is_default_array = is_default_array>; + template constexpr bool is_option = std::is_base_of_v< option_flag, remove_cvref_t< - Option>> or std::is_same_v or is_default