mirror of https://github.com/oxen-io/lokinet
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
4.3 KiB
Plaintext
155 lines
4.3 KiB
Plaintext
#include <lokinet-dnsproxy.hpp>
|
|
#include <llarp/apple.hpp>
|
|
#include <oxenmq/oxenmq.h>
|
|
#include <llarp/util/logging/logger.hpp>
|
|
#include <thread>
|
|
#include <memory>
|
|
|
|
#include <llarp/util/buffer.hpp>
|
|
#include <llarp/dns/message.hpp>
|
|
|
|
struct DNSImpl
|
|
{
|
|
oxenmq::OxenMQ m_MQ;
|
|
std::optional<oxenmq::ConnectionID> m_Conn;
|
|
|
|
explicit DNSImpl(oxenmq::address rpc)
|
|
{
|
|
m_MQ.start();
|
|
m_MQ.connect_remote(
|
|
rpc, [this](auto conn) { m_Conn = conn; }, nullptr);
|
|
}
|
|
|
|
bool
|
|
ShouldHookFlow(NEAppProxyFlow* flow) const
|
|
{
|
|
LogInfo(NSObjectToString(flow));
|
|
return true;
|
|
}
|
|
|
|
void
|
|
RelayDNSData(NEAppProxyUDPFlow* flow, NWEndpoint* remote, NSData* data)
|
|
{
|
|
if (not m_Conn)
|
|
return;
|
|
auto view = DataAsStringView(data);
|
|
|
|
llarp_buffer_t buf{view};
|
|
llarp::dns::MessageHeader hdr{};
|
|
if (not hdr.Decode(&buf))
|
|
return;
|
|
llarp::dns::Message msg{hdr};
|
|
if (not msg.Decode(&buf))
|
|
return;
|
|
llarp::util::StatusObject request{
|
|
{"qname", msg.questions[0].qname}, {"qtype", msg.questions[0].qtype}};
|
|
m_MQ.request(
|
|
*m_Conn,
|
|
"llarp.dns_query",
|
|
[flow, remote, msg = std::make_shared<llarp::dns::Message>(std::move(msg))](
|
|
bool good, std::vector<std::string> parts) {
|
|
auto closeHandler = [flow](NSError* err) {
|
|
[flow closeWriteWithError:err];
|
|
[flow closeReadWithError:err];
|
|
};
|
|
if (good and parts.size() == 1)
|
|
{
|
|
try
|
|
{
|
|
const auto obj = nlohmann::json::parse(parts[0]);
|
|
const auto result = obj["result"];
|
|
if (const auto itr = result.find("answers"); itr != result.end())
|
|
{
|
|
for (const auto& result : (*itr))
|
|
{
|
|
llarp::dns::RR_RData_t rdata;
|
|
if (const auto data_itr = result.find("rdata"); data_itr != result.end())
|
|
{
|
|
const auto data = data_itr->get<std::string>();
|
|
rdata.resize(data.size());
|
|
std::copy_n(data.begin(), data.size(), rdata.begin());
|
|
}
|
|
else
|
|
continue;
|
|
|
|
msg->answers.emplace_back(
|
|
result["name"].get<std::string>(),
|
|
result["type"].get<llarp::dns::RRType_t>(),
|
|
rdata);
|
|
}
|
|
}
|
|
}
|
|
catch (std::exception& ex)
|
|
{
|
|
LogError("dns query failed: ", ex.what());
|
|
return;
|
|
}
|
|
const auto buf = msg->ToBuffer();
|
|
NSData* data = StringViewToData(
|
|
std::string_view{reinterpret_cast<const char*>(buf.buf.get()), buf.sz});
|
|
[flow writeDatagrams:@[data] sentByEndpoints:@[remote] completionHandler:closeHandler];
|
|
}
|
|
else
|
|
closeHandler(nullptr);
|
|
},
|
|
request.dump());
|
|
}
|
|
|
|
void
|
|
HandleUDPFlow(NEAppProxyUDPFlow* flow)
|
|
{
|
|
auto handler =
|
|
[this, flow](
|
|
NSArray<NSData*>* datagrams, NSArray<NWEndpoint*>* remoteEndpoints, NSError* error) {
|
|
if (error)
|
|
return;
|
|
NSInteger num = [datagrams count];
|
|
for (NSInteger idx = 0; idx < num; ++idx)
|
|
{
|
|
RelayDNSData(flow, [remoteEndpoints objectAtIndex:idx], [datagrams objectAtIndex:idx]);
|
|
}
|
|
};
|
|
[flow readDatagramsWithCompletionHandler:handler];
|
|
}
|
|
};
|
|
|
|
@implementation DNSProvider
|
|
|
|
- (void)startProxyWithOptions:(NSDictionary<NSString*, id>*)options
|
|
completionHandler:(void (^)(NSError* error))completionHandler
|
|
{
|
|
m_Impl = new DNSImpl{oxenmq::address{"tcp://127.0.0.1:1190"}};
|
|
completionHandler(nil);
|
|
}
|
|
|
|
- (void)stopProxyWithReason:(NEProviderStopReason)reason
|
|
completionHandler:(void (^)(void))completionHandler
|
|
{
|
|
if (m_Impl)
|
|
{
|
|
delete m_Impl;
|
|
m_Impl = nullptr;
|
|
}
|
|
completionHandler();
|
|
}
|
|
|
|
- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow
|
|
{
|
|
if (not [flow isKindOfClass:[NEAppProxyUDPFlow class]])
|
|
return NO;
|
|
if (m_Impl->ShouldHookFlow(flow))
|
|
{
|
|
NEAppProxyUDPFlow* udp = (NEAppProxyUDPFlow*)flow;
|
|
auto handler = [impl = m_Impl, udp](NSError* err) {
|
|
if (err)
|
|
return;
|
|
impl->HandleUDPFlow(udp);
|
|
};
|
|
[flow openWithLocalEndpoint:nil completionHandler:handler];
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
@end
|