Merge pull request #2573 from pobregat0/tunnels-conf-partial-read

read tunnels.conf section by section if the whole file can't be parsed
This commit is contained in:
orignal
2026-09-23 22:22:13 -04:00
committed by GitHub
2 changed files with 52 additions and 1 deletions
+49 -1
View File
@@ -8,6 +8,7 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include "Config.h"
@@ -631,6 +632,50 @@ namespace client
LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created");
}
void ClientContext::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
int ClientContext::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<std::string, std::shared_ptr<ClientDestination> > destinations; // keys -> destination
+3
View File
@@ -17,6 +17,7 @@
#include <memory>
#include <string_view>
#include <boost/asio.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#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