mirror of https://github.com/oxen-io/lokinet
Add RouteManager; make exit on/off work
This commit is contained in:
parent
c74dcba463
commit
e84390748d
|
@ -15,7 +15,7 @@ find_library(COREFOUNDATION CoreFoundation REQUIRED)
|
|||
target_sources(lokinet-util PRIVATE apple_logger.cpp)
|
||||
target_link_libraries(lokinet-util PUBLIC ${FOUNDATION})
|
||||
|
||||
target_sources(lokinet-platform PRIVATE vpn_interface.cpp context_wrapper.cpp)
|
||||
target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp context_wrapper.cpp)
|
||||
|
||||
add_executable(lokinet-extension MACOSX_BUNDLE
|
||||
PacketTunnelProvider.m
|
||||
|
|
|
@ -7,6 +7,8 @@ NSString* error_domain = @"com.loki-project.lokinet";
|
|||
@interface LLARPPacketTunnel : NEPacketTunnelProvider
|
||||
{
|
||||
void* lokinet;
|
||||
@public NEPacketTunnelNetworkSettings* settings;
|
||||
@public NEIPv4Route* tun_route4;
|
||||
}
|
||||
|
||||
- (void)startTunnelWithOptions:(NSDictionary<NSString*, NSObject*>*)options
|
||||
|
@ -20,6 +22,8 @@ NSString* error_domain = @"com.loki-project.lokinet";
|
|||
|
||||
- (void)readPackets;
|
||||
|
||||
- (void)updateNetworkSettings;
|
||||
|
||||
@end
|
||||
|
||||
void nslogger(const char* msg) { NSLog(@"%s", msg); }
|
||||
|
@ -42,6 +46,97 @@ void start_packet_reader(void* ctx) {
|
|||
[t readPackets];
|
||||
}
|
||||
|
||||
void add_ipv4_route(const char* addr, const char* netmask, void* ctx) {
|
||||
NEIPv4Route* route = [[NEIPv4Route alloc]
|
||||
initWithDestinationAddress: [NSString stringWithUTF8String:addr]
|
||||
subnetMask: [NSString stringWithUTF8String:netmask]];
|
||||
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
for (NEIPv4Route* r in t->settings.IPv4Settings.includedRoutes)
|
||||
if ([r.destinationAddress isEqualToString:route.destinationAddress] &&
|
||||
[r.destinationSubnetMask isEqualToString:route.destinationSubnetMask])
|
||||
return; // Already in the settings, nothing to add.
|
||||
|
||||
t->settings.IPv4Settings.includedRoutes =
|
||||
[t->settings.IPv4Settings.includedRoutes arrayByAddingObject:route];
|
||||
|
||||
[t updateNetworkSettings];
|
||||
}
|
||||
|
||||
void del_ipv4_route(const char* addr, const char* netmask, void* ctx) {
|
||||
NEIPv4Route* route = [[NEIPv4Route alloc]
|
||||
initWithDestinationAddress: [NSString stringWithUTF8String:addr]
|
||||
subnetMask: [NSString stringWithUTF8String:netmask]];
|
||||
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
NSMutableArray<NEIPv4Route*>* routes = [NSMutableArray arrayWithArray:t->settings.IPv4Settings.includedRoutes];
|
||||
for (int i = 0; i < routes.count; i++) {
|
||||
if ([routes[i].destinationAddress isEqualToString:route.destinationAddress] &&
|
||||
[routes[i].destinationSubnetMask isEqualToString:route.destinationSubnetMask]) {
|
||||
[routes removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (routes.count != t->settings.IPv4Settings.includedRoutes.count) {
|
||||
t->settings.IPv4Settings.includedRoutes = routes;
|
||||
[t updateNetworkSettings];
|
||||
}
|
||||
}
|
||||
|
||||
void add_ipv6_route(const char* addr, int prefix, void* ctx) {
|
||||
NEIPv6Route* route = [[NEIPv6Route alloc]
|
||||
initWithDestinationAddress: [NSString stringWithUTF8String:addr]
|
||||
networkPrefixLength: [NSNumber numberWithInt:prefix]];
|
||||
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
for (NEIPv6Route* r in t->settings.IPv6Settings.includedRoutes)
|
||||
if ([r.destinationAddress isEqualToString:route.destinationAddress] &&
|
||||
[r.destinationNetworkPrefixLength isEqualToNumber:route.destinationNetworkPrefixLength])
|
||||
return; // Already in the settings, nothing to add.
|
||||
|
||||
t->settings.IPv6Settings.includedRoutes =
|
||||
[t->settings.IPv6Settings.includedRoutes arrayByAddingObject:route];
|
||||
|
||||
[t updateNetworkSettings];
|
||||
}
|
||||
void del_ipv6_route(const char* addr, int prefix, void* ctx) {
|
||||
NEIPv6Route* route = [[NEIPv6Route alloc]
|
||||
initWithDestinationAddress: [NSString stringWithUTF8String:addr]
|
||||
networkPrefixLength: [NSNumber numberWithInt:prefix]];
|
||||
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
NSMutableArray<NEIPv6Route*>* routes = [NSMutableArray arrayWithArray:t->settings.IPv6Settings.includedRoutes];
|
||||
for (int i = 0; i < routes.count; i++) {
|
||||
if ([routes[i].destinationAddress isEqualToString:route.destinationAddress] &&
|
||||
[routes[i].destinationNetworkPrefixLength isEqualToNumber:route.destinationNetworkPrefixLength]) {
|
||||
[routes removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (routes.count != t->settings.IPv6Settings.includedRoutes.count) {
|
||||
t->settings.IPv6Settings.includedRoutes = routes;
|
||||
[t updateNetworkSettings];
|
||||
}
|
||||
}
|
||||
void add_default_route(void* ctx) {
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
|
||||
t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute];
|
||||
t->settings.IPv6Settings.includedRoutes = @[NEIPv6Route.defaultRoute];
|
||||
|
||||
[t updateNetworkSettings];
|
||||
}
|
||||
void del_default_route(void* ctx) {
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
|
||||
t->settings.IPv4Settings.includedRoutes = @[t->tun_route4];
|
||||
t->settings.IPv4Settings.includedRoutes = @[]; // No tun_route6 yet.
|
||||
|
||||
[t updateNetworkSettings];
|
||||
}
|
||||
|
||||
@implementation LLARPPacketTunnel
|
||||
|
||||
- (void)readPackets
|
||||
|
@ -63,21 +158,39 @@ void start_packet_reader(void* ctx) {
|
|||
char mask_buf[16];
|
||||
char dns_buf[16];
|
||||
|
||||
NSString* default_bootstrap = [[NSBundle mainBundle] pathForResource:@"bootstrap" ofType:@"signed"];
|
||||
NSString* default_bootstrap = [NSBundle.mainBundle pathForResource:@"bootstrap" ofType:@"signed"];
|
||||
NSString* home = NSHomeDirectory();
|
||||
|
||||
lokinet = llarp_apple_init(nslogger, NSHomeDirectory().UTF8String, default_bootstrap.UTF8String, ip_buf, mask_buf, dns_buf);
|
||||
llarp_apple_config conf = {
|
||||
.config_dir = home.UTF8String,
|
||||
.default_bootstrap = default_bootstrap.UTF8String,
|
||||
.ns_logger = nslogger,
|
||||
.packet_writer = packet_writer,
|
||||
.start_reading = start_packet_reader,
|
||||
.route_callbacks = {
|
||||
.add_ipv4_route = add_ipv4_route,
|
||||
.del_ipv4_route = del_ipv4_route,
|
||||
.add_ipv6_route = add_ipv6_route,
|
||||
.del_ipv6_route = del_ipv6_route,
|
||||
.add_default_route = add_default_route,
|
||||
.del_default_route = del_default_route
|
||||
},
|
||||
};
|
||||
|
||||
lokinet = llarp_apple_init(&conf);
|
||||
if (!lokinet) {
|
||||
NSError *init_failure = [NSError errorWithDomain:error_domain code:500 userInfo:@{@"Error": @"Failed to initialize lokinet"}];
|
||||
NSLog(@"%@", [init_failure localizedDescription]);
|
||||
return completionHandler(init_failure);
|
||||
}
|
||||
|
||||
NSString* ip = [[NSString alloc] initWithUTF8String:ip_buf];
|
||||
NSString* mask = [[NSString alloc] initWithUTF8String:mask_buf];
|
||||
NSString* dnsaddr = [[NSString alloc] initWithUTF8String:dns_buf];
|
||||
|
||||
NEPacketTunnelNetworkSettings* settings =
|
||||
[[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"];
|
||||
NSString* ip = [NSString stringWithUTF8String:conf.tunnel_ipv4_ip];
|
||||
NSString* mask = [NSString stringWithUTF8String:conf.tunnel_ipv4_netmask];
|
||||
NSString* dnsaddr = [NSString stringWithUTF8String:conf.tunnel_dns];
|
||||
|
||||
// We don't have a fixed address so just stick some bogus value here:
|
||||
settings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.3.2.1"];
|
||||
|
||||
NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]];
|
||||
dns.domainName = @"localhost.loki";
|
||||
// In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems
|
||||
|
@ -96,16 +209,21 @@ void start_packet_reader(void* ctx) {
|
|||
dns.searchDomains = @[];
|
||||
NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip]
|
||||
subnetMasks:@[mask]];
|
||||
ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]];
|
||||
tun_route4 = [[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask];
|
||||
ipv4.includedRoutes = @[tun_route4];
|
||||
settings.IPv4Settings = ipv4;
|
||||
settings.DNSSettings = dns;
|
||||
__weak LLARPPacketTunnel* weakSelf = self;
|
||||
[self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) {
|
||||
if (err) {
|
||||
NSLog(@"Failed to configure lokinet tunnel: %@", err);
|
||||
return completionHandler(err);
|
||||
}
|
||||
|
||||
int start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, (__bridge void*) self);
|
||||
LLARPPacketTunnel* strongSelf = weakSelf;
|
||||
if (!strongSelf)
|
||||
return completionHandler(nil);
|
||||
|
||||
int start_ret = llarp_apple_start(strongSelf->lokinet, (__bridge void*) strongSelf);
|
||||
if (start_ret != 0) {
|
||||
NSError *start_failure = [NSError errorWithDomain:error_domain code:start_ret userInfo:@{@"Error": @"Failed to start lokinet"}];
|
||||
NSLog(@"%@", start_failure);
|
||||
|
@ -132,4 +250,34 @@ void start_packet_reader(void* ctx) {
|
|||
NSData* response = [NSData dataWithBytesNoCopy:"ok" length:3 freeWhenDone:NO];
|
||||
completionHandler(response);
|
||||
}
|
||||
|
||||
- (void)updateNetworkSettings
|
||||
{
|
||||
self.reasserting = YES;
|
||||
__weak LLARPPacketTunnel* weakSelf = self;
|
||||
// Apple documentation says that setting network settings to nil isn't required before setting it
|
||||
// to a new value. Apple lies: both end up with a routing table that looks exactly the same (from
|
||||
// both `netstat -rn` and from everything that happens in `route -n monitor`), but if we don't
|
||||
// call with nil first then everything fails to route to either lokinet *and* clearnet through the
|
||||
// exit, so there is apparently some special magic internal Apple state that actually *does*
|
||||
// require the tunnel settings being reset with nil first.
|
||||
//
|
||||
// Thanks for the accurate documentation, Apple.
|
||||
//
|
||||
[self setTunnelNetworkSettings:nil completionHandler:^(NSError* err) {
|
||||
if (err)
|
||||
NSLog(@"Failed to clear lokinet tunnel settings: %@", err);
|
||||
LLARPPacketTunnel* strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[weakSelf setTunnelNetworkSettings:strongSelf->settings completionHandler:^(NSError* err) {
|
||||
LLARPPacketTunnel* strongSelf = weakSelf;
|
||||
if (strongSelf)
|
||||
strongSelf.reasserting = NO;
|
||||
if (err)
|
||||
NSLog(@"Failed to reconfigure lokinet tunnel settings: %@", err);
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <llarp.hpp>
|
||||
#include "vpn_platform.hpp"
|
||||
#include "route_manager.hpp"
|
||||
|
||||
namespace llarp::apple
|
||||
{
|
||||
|
@ -10,7 +11,7 @@ namespace llarp::apple
|
|||
std::shared_ptr<vpn::Platform>
|
||||
makeVPNPlatform() override
|
||||
{
|
||||
return std::make_shared<VPNPlatform>(*this, m_PacketWriter, m_OnReadable);
|
||||
return std::make_shared<VPNPlatform>(*this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context);
|
||||
}
|
||||
|
||||
// Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main
|
||||
|
@ -18,6 +19,8 @@ namespace llarp::apple
|
|||
// after construction.
|
||||
VPNInterface::packet_write_callback m_PacketWriter;
|
||||
VPNInterface::on_readable_callback m_OnReadable;
|
||||
llarp_route_callbacks route_callbacks{};
|
||||
void* callback_context = nullptr;
|
||||
};
|
||||
|
||||
} // namespace llarp::apple
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace
|
|||
{
|
||||
llarp::apple::Context context;
|
||||
std::thread runner;
|
||||
packet_writer_callback packet_writer;
|
||||
start_reading_callback start_reading;
|
||||
|
||||
std::weak_ptr<llarp::apple::VPNInterface> iface;
|
||||
};
|
||||
|
@ -26,19 +28,13 @@ namespace
|
|||
} // namespace
|
||||
|
||||
void*
|
||||
llarp_apple_init(
|
||||
ns_logger_callback ns_logger,
|
||||
const char* config_dir_,
|
||||
const char* default_bootstrap,
|
||||
char* ip,
|
||||
char* netmask,
|
||||
char* dns)
|
||||
llarp_apple_init(llarp_apple_config* appleconf)
|
||||
{
|
||||
llarp::LogContext::Instance().logStream = std::make_unique<llarp::apple::NSLogStream>(ns_logger);
|
||||
llarp::LogContext::Instance().logStream = std::make_unique<llarp::apple::NSLogStream>(appleconf->ns_logger);
|
||||
|
||||
try
|
||||
{
|
||||
auto config_dir = fs::u8path(config_dir_);
|
||||
auto config_dir = fs::u8path(appleconf->config_dir);
|
||||
auto config = std::make_shared<llarp::Config>(config_dir);
|
||||
fs::path config_path = config_dir / "lokinet.ini";
|
||||
if (!fs::exists(config_path))
|
||||
|
@ -59,10 +55,10 @@ llarp_apple_init(
|
|||
auto mask = llarp::net::TruncateV6(range.netmask_bits).ToString();
|
||||
if (addr.size() > 15 || mask.size() > 15)
|
||||
throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"};
|
||||
std::strcpy(ip, addr.c_str());
|
||||
std::strcpy(netmask, mask.c_str());
|
||||
std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str());
|
||||
std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str());
|
||||
// XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons?
|
||||
std::strcpy(dns, addr.c_str());
|
||||
std::strcpy(appleconf->tunnel_dns, addr.c_str());
|
||||
|
||||
// The default DNS bind setting just isn't something we can use as a non-root network extension
|
||||
// so remap the default value to a high port unless explicitly set to something else.
|
||||
|
@ -71,10 +67,16 @@ llarp_apple_init(
|
|||
|
||||
// If no explicit bootstrap then set the system default one included with the app bundle
|
||||
if (config->bootstrap.files.empty())
|
||||
config->bootstrap.files.push_back(fs::u8path(default_bootstrap));
|
||||
config->bootstrap.files.push_back(fs::u8path(appleconf->default_bootstrap));
|
||||
|
||||
auto inst = std::make_unique<instance_data>();
|
||||
inst->context.Configure(std::move(config));
|
||||
inst->context.route_callbacks = appleconf->route_callbacks;
|
||||
|
||||
inst->packet_writer = appleconf->packet_writer;
|
||||
inst->start_reading = appleconf->start_reading;
|
||||
|
||||
|
||||
return inst.release();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
@ -87,21 +89,22 @@ llarp_apple_init(
|
|||
int
|
||||
llarp_apple_start(
|
||||
void* lokinet,
|
||||
packet_writer_callback packet_writer,
|
||||
start_reading_callback start_reading,
|
||||
void* callback_context)
|
||||
{
|
||||
auto* inst = static_cast<instance_data*>(lokinet);
|
||||
inst->context.m_PacketWriter = [inst, packet_writer, callback_context](
|
||||
int af_family, void* data, size_t size) {
|
||||
packet_writer(af_family, data, size, callback_context);
|
||||
return true;
|
||||
|
||||
inst->context.callback_context = callback_context;
|
||||
|
||||
inst->context.m_PacketWriter = [inst, callback_context](
|
||||
int af_family, void* data, size_t size) {
|
||||
inst->packet_writer(af_family, data, size, callback_context);
|
||||
return true;
|
||||
};
|
||||
|
||||
inst->context.m_OnReadable =
|
||||
[inst, start_reading, callback_context](llarp::apple::VPNInterface& iface) {
|
||||
[inst, callback_context](llarp::apple::VPNInterface& iface) {
|
||||
inst->iface = iface.weak_from_this();
|
||||
start_reading(callback_context);
|
||||
inst->start_reading(callback_context);
|
||||
};
|
||||
|
||||
std::promise<void> result;
|
||||
|
|
|
@ -12,70 +12,112 @@ extern "C"
|
|||
#include <sys/socket.h>
|
||||
|
||||
/// C callback function for us to invoke when we need to write a packet
|
||||
typedef void(packet_writer_callback)(int af, const void* data, size_t size, void* ctx);
|
||||
typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx);
|
||||
|
||||
/// C callback function to invoke once we are ready to start receiving packets
|
||||
typedef void(start_reading_callback)(void* ctx);
|
||||
typedef void(*start_reading_callback)(void* ctx);
|
||||
|
||||
/// C callback that bridges things into NSLog
|
||||
typedef void(ns_logger_callback)(const char* msg);
|
||||
typedef void(*ns_logger_callback)(const char* msg);
|
||||
|
||||
/// C callbacks to add/remove specific and default routes to the tunnel
|
||||
typedef void(*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx);
|
||||
typedef void(*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx);
|
||||
typedef void(*llarp_default_route_callback)(void* ctx);
|
||||
typedef struct llarp_route_callbacks {
|
||||
/// Callback invoked to set up an IPv4 range that should be routed through the tunnel
|
||||
/// interface. Called with the address and netmask.
|
||||
llarp_route_ipv4_callback add_ipv4_route;
|
||||
|
||||
/// Callback invoked to set the tunnel as the default IPv4 route.
|
||||
llarp_default_route_callback add_ipv4_default_route;
|
||||
|
||||
/// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the
|
||||
/// address and netmask.
|
||||
llarp_route_ipv4_callback del_ipv4_route;
|
||||
|
||||
/// Callback invoked to set up an IPv6 range that should be routed through the tunnel
|
||||
/// interface. Called with the address and netmask.
|
||||
llarp_route_ipv6_callback add_ipv6_route;
|
||||
|
||||
/// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the
|
||||
/// address and netmask.
|
||||
llarp_route_ipv6_callback del_ipv6_route;
|
||||
|
||||
/// Callback invoked to set the tunnel as the default IPv4/IPv6 route.
|
||||
llarp_default_route_callback add_default_route;
|
||||
|
||||
/// Callback invoked to remove the tunnel as the default IPv4/IPv6 route.
|
||||
llarp_default_route_callback del_default_route;
|
||||
} llarp_route_callbacks;
|
||||
|
||||
/// Pack of crap to be passed into llarp_apple_init to initialize
|
||||
typedef struct llarp_apple_config
|
||||
{
|
||||
/// lokinet configuration directory, expected to be the application-specific "home" directory,
|
||||
/// which is where state files are stored and the lokinet.ini will be loaded (or created if it
|
||||
/// doesn't exist).
|
||||
const char* config_dir;
|
||||
/// path to the default bootstrap.signed file included in installation, which will be used by
|
||||
/// default when no specific bootstrap is in the config file.
|
||||
const char* default_bootstrap;
|
||||
/// llarp_apple_init writes the IP address for the primary tunnel IP address here,
|
||||
/// null-terminated.
|
||||
char tunnel_ipv4_ip[16];
|
||||
/// llarp_apple_init writes the netmask of the tunnel address here, null-terminated.
|
||||
char tunnel_ipv4_netmask[16];
|
||||
/// The DNS server IPv4 address the OS should use. Null-terminated.
|
||||
char tunnel_dns[16];
|
||||
|
||||
/// \defgroup callbacks Callbacks
|
||||
/// Callbacks we invoke for various operations that require glue into the Apple network
|
||||
/// extension APIs. All of these except for ns_logger are passed the pointer provided to
|
||||
/// llarp_apple_start when invoked.
|
||||
/// @{
|
||||
|
||||
/// simple wrapper around NSLog for lokinet message logging
|
||||
ns_logger_callback ns_logger;
|
||||
|
||||
/// C function callback that will be called when we need to write a packet to the packet
|
||||
/// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of
|
||||
/// the data in bytes.
|
||||
packet_writer_callback packet_writer;
|
||||
|
||||
/// C function callback that will be called when lokinet is setup and ready to start receiving
|
||||
/// packets from the packet tunnel. This should set up the read handler to deliver packets
|
||||
/// via llarp_apple_incoming.
|
||||
start_reading_callback start_reading;
|
||||
|
||||
/// Callbacks invoked to add/remove routes to the tunnel.
|
||||
llarp_route_callbacks route_callbacks;
|
||||
|
||||
/// @}
|
||||
} llarp_apple_config;
|
||||
|
||||
|
||||
/// Initializes a lokinet instance by initializing various objects and loading the configuration
|
||||
/// (if {config_dir}/lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start
|
||||
/// (if <config_dir>/lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start
|
||||
/// for that).
|
||||
///
|
||||
/// Returns NULL if there was a problem initializing/loading the configuration, otherwise returns
|
||||
/// an opaque void pointer that should be passed into the other llarp_apple_* functions.
|
||||
///
|
||||
/// \param logger a logger callback that we pass log messages to to relay them (i.e. via NSLog).
|
||||
///
|
||||
/// \param config_dir the lokinet configuration directory where lokinet.ini can be and the various
|
||||
/// other lokinet state files go.
|
||||
///
|
||||
/// \param default_bootstrap the path to the default bootstrap.signed included in installation,
|
||||
/// which will be used if no explicit bootstrap is set in the config file.
|
||||
///
|
||||
/// \param ip - char buffer where we will write the primary tunnel IP address as a string such as
|
||||
/// "172.16.0.0". Will write up to 16 characters (including the null terminator). This will be
|
||||
/// the tunnel IP from the lokinet.ini, if it exists and specifies a range, otherwise we'll
|
||||
/// configure lokinet to use a currently-unused range and return that.
|
||||
///
|
||||
/// \param netmask the tunnel netmask as a string such as "255.255.0.0". Will write up to 16
|
||||
/// characters (including the null terminator).
|
||||
///
|
||||
/// \param dns the DNS address that should be configured to query lokinet, as a string such as
|
||||
/// "172.16.0.1". Will write up to 16 characters (including the null terminator).
|
||||
/// \param config pointer to a llarp_apple_config where we get the various settings needed
|
||||
/// and return the ip/mask/dns fields needed for the tunnel.
|
||||
void*
|
||||
llarp_apple_init(
|
||||
ns_logger_callback ns_logger,
|
||||
const char* config_dir,
|
||||
const char* default_bootstrap,
|
||||
char* ip,
|
||||
char* netmask,
|
||||
char* dns);
|
||||
llarp_apple_init(llarp_apple_config* config);
|
||||
|
||||
/// Starts the lokinet instance in a new thread.
|
||||
///
|
||||
/// \param packet_writer C function callback that will be called when we need to write a packet to
|
||||
/// the packet tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, the size
|
||||
/// of the data in bytes, and the opaque callback_context pointer.
|
||||
/// \param lokinet the void pointer returned by llarp_apple_init
|
||||
///
|
||||
/// \param start_reading C function callback that will be called when lokinet is setup and ready
|
||||
/// to start receiving packets from the packet tunnel. This should set up the read handler to
|
||||
/// deliver packets via llarp_apple_incoming. This is called with a single argument of the opaque
|
||||
/// callback_context pointer.
|
||||
///
|
||||
/// \param callback_context Opaque pointer that is passed into the packet_writer and start_reading
|
||||
/// callback, intended to allow context to be passed through to the callbacks. This code does
|
||||
/// nothing with this pointer aside from passing it through to callbacks.
|
||||
/// \param callback_context Opaque pointer that is passed into the various callbacks provided to
|
||||
/// llarp_apple_init. This code does nothing with this pointer aside from passing it through to
|
||||
/// callbacks.
|
||||
///
|
||||
/// \returns 0 on succesful startup, -1 on failure.
|
||||
int
|
||||
llarp_apple_start(
|
||||
void* lokinet,
|
||||
packet_writer_callback packet_writer,
|
||||
start_reading_callback start_reading,
|
||||
void* callback_context);
|
||||
llarp_apple_start(void* lokinet, void* callback_context);
|
||||
|
||||
/// Called to deliver an incoming packet from the apple layer into lokinet; returns 0 on success,
|
||||
/// -1 if the packet could not be parsed, -2 if there is no current active VPNInterface associated
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
#include "route_manager.hpp"
|
||||
|
||||
namespace llarp::apple {
|
||||
|
||||
void RouteManager::AddDefaultRouteViaInterface(std::string)
|
||||
{
|
||||
LogWarn("AddDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", adr=", (bool) route_callbacks.add_default_route);
|
||||
if (callback_context and route_callbacks.add_default_route)
|
||||
route_callbacks.add_default_route(callback_context);
|
||||
}
|
||||
|
||||
void RouteManager::DelDefaultRouteViaInterface(std::string)
|
||||
{
|
||||
LogWarn("DelDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", ddr=", (bool) route_callbacks.del_default_route);
|
||||
if (callback_context and route_callbacks.del_default_route)
|
||||
route_callbacks.del_default_route(callback_context);
|
||||
}
|
||||
|
||||
void
|
||||
RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range)
|
||||
{
|
||||
LogWarn("AddRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.add_ipv4_route,
|
||||
"a6r", (bool) route_callbacks.add_ipv6_route);
|
||||
|
||||
if (callback_context)
|
||||
{
|
||||
if (range.IsV4()) {
|
||||
if (route_callbacks.add_ipv4_route)
|
||||
route_callbacks.add_ipv4_route(
|
||||
range.BaseAddressString().c_str(),
|
||||
net::TruncateV6(range.netmask_bits).ToString().c_str(),
|
||||
callback_context);
|
||||
} else {
|
||||
if (route_callbacks.add_ipv6_route)
|
||||
route_callbacks.add_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range)
|
||||
{
|
||||
LogWarn("DelRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.del_ipv4_route,
|
||||
"a6r", (bool) route_callbacks.del_ipv6_route);
|
||||
|
||||
if (callback_context)
|
||||
{
|
||||
if (range.IsV4()) {
|
||||
if (route_callbacks.del_ipv4_route)
|
||||
route_callbacks.del_ipv4_route(
|
||||
range.BaseAddressString().c_str(),
|
||||
net::TruncateV6(range.netmask_bits).ToString().c_str(),
|
||||
callback_context);
|
||||
} else {
|
||||
if (route_callbacks.del_ipv6_route)
|
||||
route_callbacks.del_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/ev/vpn.hpp>
|
||||
#include "context_wrapper.h"
|
||||
|
||||
namespace llarp::apple {
|
||||
|
||||
class RouteManager final : public llarp::vpn::IRouteManager {
|
||||
public:
|
||||
RouteManager(llarp_route_callbacks rcs, void* callback_context)
|
||||
: route_callbacks{std::move(rcs)}, callback_context{callback_context} {}
|
||||
|
||||
/// These are called for poking route holes, but we don't have to do that at all on macos
|
||||
/// because the appex isn't subject to its own rules.
|
||||
void
|
||||
AddRoute(IPVariant_t ip, IPVariant_t gateway) override {}
|
||||
|
||||
void
|
||||
DelRoute(IPVariant_t ip, IPVariant_t gateway) override {}
|
||||
|
||||
void
|
||||
AddDefaultRouteViaInterface(std::string ifname) override;
|
||||
|
||||
void
|
||||
DelDefaultRouteViaInterface(std::string ifname) override;
|
||||
|
||||
void
|
||||
AddRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override;
|
||||
|
||||
void
|
||||
DelRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override;
|
||||
|
||||
virtual std::vector<IPVariant_t>
|
||||
GetGatewaysNotOnInterface(std::string ifname) override {
|
||||
// We can't get this on mac from our sandbox, but we don't actually need it because we
|
||||
// ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP.
|
||||
std::vector<IPVariant_t> ret;
|
||||
ret.push_back(huint32_t{0});
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* callback_context = nullptr;
|
||||
llarp_route_callbacks route_callbacks;
|
||||
};
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <llarp/ev/vpn.hpp>
|
||||
#include "vpn_interface.hpp"
|
||||
#include "route_manager.hpp"
|
||||
|
||||
namespace llarp::apple
|
||||
{
|
||||
|
@ -11,8 +12,11 @@ namespace llarp::apple
|
|||
explicit VPNPlatform(
|
||||
Context& ctx,
|
||||
VPNInterface::packet_write_callback packet_writer,
|
||||
VPNInterface::on_readable_callback on_readable)
|
||||
VPNInterface::on_readable_callback on_readable,
|
||||
llarp_route_callbacks route_callbacks,
|
||||
void* callback_context)
|
||||
: m_Context{ctx}
|
||||
, m_RouteManager{std::move(route_callbacks), callback_context}
|
||||
, m_PacketWriter{std::move(packet_writer)}
|
||||
, m_OnReadable{std::move(on_readable)}
|
||||
{}
|
||||
|
@ -22,8 +26,11 @@ namespace llarp::apple
|
|||
return std::make_shared<VPNInterface>(m_Context, m_PacketWriter, m_OnReadable);
|
||||
}
|
||||
|
||||
vpn::IRouteManager& RouteManager() override { return m_RouteManager; }
|
||||
|
||||
private:
|
||||
Context& m_Context;
|
||||
apple::RouteManager m_RouteManager;
|
||||
VPNInterface::packet_write_callback m_PacketWriter;
|
||||
VPNInterface::on_readable_callback m_OnReadable;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue