mirror of https://github.com/oxen-io/lokinet
macos sort of works now
parent
81d27c35c1
commit
7db2459469
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>lokinet-dnsproxy</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.loki-project.lokinet.dns-proxy</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>lokinet</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@LOKINET_VERSION@</string>
|
||||
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11.0</string>
|
||||
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.networkextension.dns-proxy</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>DNSProvider</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.application-identifier</key>
|
||||
<string>SUQ8J2PCT7.com.loki-project.lokinet.dns-proxy</string>
|
||||
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>dns-proxy</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>SUQ8J2PCT7</string>
|
||||
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <NetworkExtension/NetworkExtension.h>
|
||||
|
||||
struct DNSImpl;
|
||||
|
||||
@interface DNSProvider : NEDNSProxyProvider
|
||||
{
|
||||
struct DNSImpl* m_Impl;
|
||||
}
|
||||
- (void)startProxyWithOptions:(NSDictionary<NSString*, id>*)options
|
||||
completionHandler:(void (^)(NSError* error))completionHandler;
|
||||
|
||||
- (void)stopProxyWithReason:(NEProviderStopReason)reason
|
||||
completionHandler:(void (^)(void))completionHandler;
|
||||
|
||||
- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow;
|
||||
|
||||
@end
|
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
static std::string_view
|
||||
DataAsStringView(NSData* data)
|
||||
{
|
||||
return std::string_view{reinterpret_cast<const char*>(data.bytes), data.length};
|
||||
}
|
||||
|
||||
static NSData*
|
||||
StringViewToData(std::string_view data)
|
||||
{
|
||||
const char* ptr = data.data();
|
||||
const size_t sz = data.size();
|
||||
return [NSData dataWithBytes:ptr length:sz];
|
||||
}
|
||||
|
||||
static NSString*
|
||||
StringToNSString(std::string data)
|
||||
{
|
||||
NSData* ptr = StringViewToData(std::string_view{data});
|
||||
return [[NSString alloc] initWithData:ptr encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
static std::string
|
||||
NSStringToString(NSString* str)
|
||||
{
|
||||
return std::string{[str UTF8String]};
|
||||
}
|
||||
|
||||
static std::string
|
||||
NSObjectToString(NSObject* obj)
|
||||
{
|
||||
return NSStringToString([NSString stringWithFormat:@"%@", obj]);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,154 @@
|
||||
#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
|
Loading…
Reference in New Issue