[feature] optionally keep inbound convos mapped to same IP on restart (#1672)

* add option to persist address mappings between restarts using [network]:persist-addrmap-file

* make it work

* only persist address map for inbound convos

* turn persisting address map on by default

* dont load addrmap file if it has been modified last over a minute ago to prevent foot cannons fired from loading a really old version of it
pull/1661/head
Jeff 3 years ago committed by GitHub
parent afe55f0932
commit c9b4ca85b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -674,6 +674,22 @@ namespace llarp
m_PathAlignmentTimeout = std::chrono::seconds{val};
});
conf.defineOption<fs::path>(
"network",
"persist-addrmap-file",
ClientOnly,
Default{fs::path{params.defaultDataDir / "addrmap.dat"}},
Comment{
"persist mapped ephemeral addresses to a file",
"on restart the mappings will be loaded so that ip addresses will not be mapped to a "
"different address",
},
[this](fs::path arg) {
if (arg.empty())
throw std::invalid_argument("persist-addrmap-file cannot be empty");
m_AddrMapPersistFile = arg;
});
// Deprecated options:
conf.defineOption<std::string>("network", "enabled", Deprecated);
}

@ -127,10 +127,7 @@ namespace llarp
std::optional<llarp_time_t> m_PathAlignmentTimeout;
// TODO:
// on-up
// on-down
// on-ready
std::optional<fs::path> m_AddrMapPersistFile;
void
defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params);

@ -208,6 +208,110 @@ namespace llarp
m_OurIP = m_OurRange.addr;
m_UseV6 = false;
m_PersistAddrMapFile = conf.m_AddrMapPersistFile;
if (m_PersistAddrMapFile)
{
const auto& file = *m_PersistAddrMapFile;
if (fs::exists(file))
{
bool shouldLoadFile = true;
{
constexpr auto LastModifiedWindow = 1min;
const auto lastmodified = fs::last_write_time(file);
const auto now = decltype(lastmodified)::clock::now();
if (now < lastmodified or now - lastmodified > LastModifiedWindow)
{
shouldLoadFile = false;
}
}
std::vector<char> data;
if (auto maybe = util::OpenFileStream<fs::ifstream>(file, std::ios_base::binary);
maybe and shouldLoadFile)
{
LogInfo(Name(), " loading address map file from ", file);
maybe->seekg(0, std::ios_base::end);
const size_t len = maybe->tellg();
maybe->seekg(0, std::ios_base::beg);
data.resize(len);
LogInfo(Name(), " reading ", len, " bytes");
maybe->read(data.data(), data.size());
}
else
{
if (shouldLoadFile)
{
LogInfo(Name(), " address map file ", file, " does not exist, so we won't load it");
}
else
LogInfo(Name(), " address map file ", file, " not loaded because it's stale");
}
if (not data.empty())
{
std::string_view bdata{data.data(), data.size()};
LogInfo(Name(), " parsing address map data: ", bdata);
const auto parsed = oxenmq::bt_deserialize<oxenmq::bt_dict>(bdata);
for (const auto& [key, value] : parsed)
{
huint128_t ip{};
if (not ip.FromString(key))
{
LogWarn(Name(), " malformed IP in addr map data: ", key);
continue;
}
if (m_OurIP == ip)
continue;
if (not m_OurRange.Contains(ip))
{
LogWarn(Name(), " out of range IP in addr map data: ", ip);
continue;
}
EndpointBase::AddressVariant_t addr;
if (const auto* str = std::get_if<std::string>(&value))
{
if (auto maybe = service::ParseAddress(*str))
{
addr = *maybe;
}
else
{
LogWarn(Name(), " invalid address in addr map: ", *str);
continue;
}
}
else
{
LogWarn(Name(), " invalid first entry in addr map, not a string");
continue;
}
if (const auto* loki = std::get_if<service::Address>(&addr))
{
m_IPToAddr.emplace(ip, loki->data());
m_AddrToIP.emplace(loki->data(), ip);
m_SNodes[*loki] = false;
LogInfo(Name(), " remapped ", ip, " to ", *loki);
}
if (const auto* snode = std::get_if<RouterID>(&addr))
{
m_IPToAddr.emplace(ip, snode->data());
m_AddrToIP.emplace(snode->data(), ip);
m_SNodes[*snode] = true;
LogInfo(Name(), " remapped ", ip, " to ", *snode);
}
if (m_NextIP < ip)
m_NextIP = ip;
// make sure we dont unmap this guy
MarkIPActive(ip);
}
}
}
else
{
LogInfo(
Name(), " skipping loading addr map at ", file, " as it does not currently exist");
}
}
if (auto* quic = GetQUICTunnel())
{
quic->listen([this](std::string_view, uint16_t port) {
@ -858,6 +962,27 @@ namespace llarp
bool
TunEndpoint::Stop()
{
// save address map if applicable
if (m_PersistAddrMapFile)
{
const auto& file = *m_PersistAddrMapFile;
LogInfo(Name(), " saving address map to ", file);
if (auto maybe = util::OpenFileStream<fs::ofstream>(file, std::ios_base::binary))
{
std::map<std::string, std::string> addrmap;
for (const auto& [ip, addr] : m_IPToAddr)
{
if (not m_SNodes.at(addr))
{
const service::Address a{addr.as_array()};
if (HasInboundConvo(a))
addrmap[ip.ToString()] = a.ToString();
}
}
const auto data = oxenmq::bt_serialize(addrmap);
maybe->write(data.data(), data.size());
}
}
if (m_Resolver)
m_Resolver->Stop();
return llarp::service::Endpoint::Stop();

@ -290,6 +290,9 @@ namespace llarp
/// idempotent wakeup for writing messages to network
std::shared_ptr<EventLoopWakeup> m_MessageSendWaker;
/// a file to load / store the ephemeral address map to
std::optional<fs::path> m_PersistAddrMapFile;
};
} // namespace handlers

Loading…
Cancel
Save