mirror of https://github.com/oxen-io/lokinet
SRV Record handling for introsets (#1331)
* update loki-mq submodule for tuple support * srv record reply implementation still need to encode srv records into intro sets / router contacts as well as decode from them and match against queried service.proto * inverted condition fix in config code * SRV record struct (de-)serialization for intro sets * parsing and using srv records from config (for/in introsets) * adopt str utils from core and use for srv parsing * changes to repeat requests no longer drop repeat requests on the floor, but do not make an *actual* request for them if one is in progress. do not call reply hook for each reply for a request, as each userland request is actually made into several lokinet requests and this would result in duplicate replies. * fetch SRVs from introsets for .loki * make format * dns and srv fixes, srv appears to be workingpull/1332/head
parent
521765b5a8
commit
b1c14af938
@ -1 +1 @@
|
||||
Subproject commit 07b31bd8a1b39a7de7913b91aab7b8e1e12e928b
|
||||
Subproject commit 30faadf01a561be8bda1b9fd78cd606bb209576a
|
@ -0,0 +1,102 @@
|
||||
#include <dns/srv_data.hpp>
|
||||
#include <util/str.hpp>
|
||||
#include <util/logging/logger.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
bool
|
||||
SRVData::IsValid() const
|
||||
{
|
||||
// if target is of first two forms outlined above
|
||||
if (target == "." or target.size() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check target size is not absurd
|
||||
if (target.size() > TARGET_MAX_SIZE)
|
||||
{
|
||||
LogWarn("SRVData target larger than max size (", TARGET_MAX_SIZE, ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
// does target end in .loki?
|
||||
size_t pos = target.find(".loki");
|
||||
if (pos != std::string::npos && pos == (target.size() - 5))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// does target end in .snode?
|
||||
pos = target.find(".snode");
|
||||
if (pos != std::string::npos && pos == (target.size() - 6))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// if we're here, target is invalid
|
||||
LogWarn("SRVData invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
SRVTuple
|
||||
SRVData::toTuple() const
|
||||
{
|
||||
return std::make_tuple(service_proto, priority, weight, port, target);
|
||||
}
|
||||
|
||||
SRVData
|
||||
SRVData::fromTuple(SRVTuple tuple)
|
||||
{
|
||||
SRVData s;
|
||||
|
||||
std::tie(s.service_proto, s.priority, s.weight, s.port, s.target) = std::move(tuple);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool
|
||||
SRVData::fromString(std::string_view srvString)
|
||||
{
|
||||
LogDebug("SRVData::fromString(\"", srvString, "\")");
|
||||
|
||||
// split on spaces, discard trailing empty strings
|
||||
auto splits = split(srvString, " ", false);
|
||||
|
||||
if (splits.size() != 5 && splits.size() != 4)
|
||||
{
|
||||
LogWarn("SRV record should have either 4 or 5 space-separated parts");
|
||||
return false;
|
||||
}
|
||||
|
||||
service_proto = splits[0];
|
||||
|
||||
if (not parse_int(splits[1], priority))
|
||||
{
|
||||
LogWarn("SRV record failed to parse \"", splits[1], "\" as uint16_t (priority)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (not parse_int(splits[2], weight))
|
||||
{
|
||||
LogWarn("SRV record failed to parse \"", splits[2], "\" as uint16_t (weight)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (not parse_int(splits[3], port))
|
||||
{
|
||||
LogWarn("SRV record failed to parse \"", splits[3], "\" as uint16_t (port)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (splits.size() == 5)
|
||||
target = splits[4];
|
||||
else
|
||||
target = "";
|
||||
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
} // namespace llarp::dns
|
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <dns/name.hpp>
|
||||
#include <dns/serialize.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <string_view>
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
typedef std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string> SRVTuple;
|
||||
|
||||
struct SRVData
|
||||
{
|
||||
static constexpr size_t TARGET_MAX_SIZE = 200;
|
||||
|
||||
std::string service_proto; // service and protocol may as well be together
|
||||
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
|
||||
// target string for the SRV record to point to
|
||||
// options:
|
||||
// empty - refer to query name
|
||||
// dot - authoritative "no such service available"
|
||||
// any other .loki or .snode - target is that .loki or .snode
|
||||
std::string target;
|
||||
|
||||
// do some basic validation on the target string
|
||||
// note: this is not a conclusive, regex solution,
|
||||
// but rather some sanity/safety checks
|
||||
bool
|
||||
IsValid() const;
|
||||
|
||||
SRVTuple
|
||||
toTuple() const;
|
||||
|
||||
static SRVData
|
||||
fromTuple(SRVTuple tuple);
|
||||
|
||||
/* bind-like formatted string for SRV records in config file
|
||||
*
|
||||
* format:
|
||||
* srv=service.proto priority weight port target
|
||||
*
|
||||
* exactly one space character between parts.
|
||||
*
|
||||
* target can be empty, in which case the space after port should
|
||||
* be omitted. if this is the case, the target is
|
||||
* interpreted as the .loki or .snode of the current context.
|
||||
*
|
||||
* if target is not empty, it must be either
|
||||
* - simply a full stop (dot/period) OR
|
||||
* - a name within the .loki or .snode subdomains. a target
|
||||
* specified in this manner must not end with a full stop.
|
||||
*/
|
||||
bool
|
||||
fromString(std::string_view srvString);
|
||||
};
|
||||
|
||||
} // namespace llarp::dns
|
Loading…
Reference in New Issue