From 61ee7d34f5355e78eb1c18a6ba85c021866dc2b3 Mon Sep 17 00:00:00 2001 From: PobreGato <315121269+pobregat0@users.noreply.github.com> Date: Wed, 23 Sep 2026 22:02:25 -0400 Subject: [PATCH 1/2] read tunnels.conf section by section if the whole file can't be parsed --- libi2pd_client/ClientContext.cpp | 50 +++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 6d89c0a3..06b05954 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include "Config.h" @@ -631,6 +632,50 @@ namespace client LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created"); } + static void AddSection (boost::property_tree::ptree& pt, const std::string& name, + const std::string& chunk, int& numSections) + { + if (chunk.empty ()) return; + boost::property_tree::ptree section; + try + { + std::stringstream ss (chunk); + boost::property_tree::read_ini (ss, section); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "Clients: Skipped ", name.empty () ? "tunnels config header" : name, ": ", ex.what ()); + return; + } + for (auto& it: section) + pt.push_back (it); + numSections++; + } + + // Fallback for a file rejected as a whole: a single malformed line makes read_ini throw + // and every tunnel is lost, including sections that are correct. Read section by section + // instead, so that only unreadable ones are skipped + static int ReadTunnelsBySection (const std::string& tunConf, boost::property_tree::ptree& pt) + { + std::ifstream f (tunConf); + if (!f.is_open ()) return 0; + int numSections = 0; + std::string line, chunk, name; + while (std::getline (f, line)) + { + auto start = line.find_first_not_of (" \t"); + if (start != std::string::npos && line[start] == '[') + { + AddSection (pt, name, chunk, numSections); + chunk.clear (); + name = line.substr (start); + } + chunk += line; chunk += "\n"; + } + AddSection (pt, name, chunk, numSections); + return numSections; + } + void ClientContext::ReadTunnels (const std::string& tunConf, int& numClientTunnels, int& numServerTunnels) { boost::property_tree::ptree pt; @@ -638,7 +683,10 @@ namespace client boost::property_tree::read_ini (tunConf, pt); } catch (std::exception& ex) { LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ()); - return; + pt.clear (); + int numSections = ReadTunnelsBySection (tunConf, pt); + if (!numSections) return; + LogPrint (eLogWarning, "Clients: ", tunConf, " read section by section, ", numSections, " section(s) accepted"); } std::map > destinations; // keys -> destination From 3852c7a4854bd7aa6ae55ff9ff43c3b84aad6c0f Mon Sep 17 00:00:00 2001 From: PobreGato <315121269+pobregat0@users.noreply.github.com> Date: Wed, 23 Sep 2026 22:18:00 -0400 Subject: [PATCH 2/2] make tunnels config section readers members of ClientContext --- libi2pd_client/ClientContext.cpp | 4 ++-- libi2pd_client/ClientContext.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 06b05954..315173c3 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -632,7 +632,7 @@ namespace client LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created"); } - static void AddSection (boost::property_tree::ptree& pt, const std::string& name, + void ClientContext::AddSection (boost::property_tree::ptree& pt, const std::string& name, const std::string& chunk, int& numSections) { if (chunk.empty ()) return; @@ -655,7 +655,7 @@ namespace client // Fallback for a file rejected as a whole: a single malformed line makes read_ini throw // and every tunnel is lost, including sections that are correct. Read section by section // instead, so that only unreadable ones are skipped - static int ReadTunnelsBySection (const std::string& tunConf, boost::property_tree::ptree& pt) + int ClientContext::ReadTunnelsBySection (const std::string& tunConf, boost::property_tree::ptree& pt) { std::ifstream f (tunConf); if (!f.is_open ()) return 0; diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 09003cde..a726d29c 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "Destination.h" #include "I2PService.h" #include "I2PTunnel.h" @@ -133,6 +134,8 @@ namespace client void ReadTunnels (); void ReadTunnels (const std::string& tunConf, int& numClientTunnels, int& numServerTunnels); + int ReadTunnelsBySection (const std::string& tunConf, boost::property_tree::ptree& pt); + void AddSection (boost::property_tree::ptree& pt, const std::string& name, const std::string& chunk, int& numSections); void ReadHttpProxy (); void ReadSocksProxy (); // take the proxy out under the lock, so it can be stopped without holding it