parent
63ed5c16ed
commit
0708a0d897
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# build the shit on mac
|
||||
# t. jeff
|
||||
#
|
||||
|
||||
set -e
|
||||
set +x
|
||||
mkdir -p build-mac
|
||||
cd build-mac
|
||||
cmake \
|
||||
-G Ninja \
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_PACKAGE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DSTATIC_LINK=ON \
|
||||
-DWITH_SYSTEMD=OFF \
|
||||
-DFORCE_OXENMQ_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=OFF \
|
||||
-DWITH_LTO=OFF \
|
||||
-DCMAKE_INSTALL_PREFIX=$(pwd) \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
$@ ..
|
||||
ninja install && ninja sign
|
@ -0,0 +1,24 @@
|
||||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>MacOS/lokinet</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.lokinet.Daemon</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>lokinet</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1</string>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,31 @@
|
||||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>lokinet-extension</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.lokinet.NetworkExtension</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Lokinet</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.networkextension.packet-tunnel</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>Lokinet.LLARPPacketTunnel</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,10 @@
|
||||
<?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.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
for file in "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do
|
||||
codesign -vvvv --force -s "${CODESIGN_KEY}" --entitlements "${SIGN_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file"
|
||||
done
|
||||
|
||||
codesign --verify "${SIGN_TARGET}"
|
@ -0,0 +1,4 @@
|
||||
|
||||
module LokinetExtension {
|
||||
header "@CMAKE_SOURCE_DIR@/include/lokinet-extension.hpp"
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <NetworkExtension/NetworkExtension.h>
|
||||
|
||||
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
// AppDelegateExtension.swift
|
||||
|
||||
import Foundation
|
||||
import LokinetExtension
|
||||
import NetworkExtension
|
||||
|
||||
class LokinetMain: NSObject {
|
||||
var vpnManager = NETunnelProviderManager()
|
||||
|
||||
let lokinetComponent = "org.lokinet.NetworkExtension"
|
||||
var lokinetAdminTimer: DispatchSourceTimer?
|
||||
|
||||
func runMain() {
|
||||
print("Starting up lokinet")
|
||||
NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
|
||||
if let savedManagers = savedManagers {
|
||||
for manager in savedManagers {
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent {
|
||||
print("Found saved VPN Manager")
|
||||
self.vpnManager = manager
|
||||
}
|
||||
}
|
||||
}
|
||||
let providerProtocol = NETunnelProviderProtocol()
|
||||
providerProtocol.serverAddress = "lokinet"
|
||||
providerProtocol.providerBundleIdentifier = self.lokinetComponent
|
||||
self.vpnManager.protocolConfiguration = providerProtocol
|
||||
self.vpnManager.isEnabled = true
|
||||
self.vpnManager.saveToPreferences(completionHandler: { error -> Void in
|
||||
if error != nil {
|
||||
print("Error saving to preferences")
|
||||
} else {
|
||||
print("saved...")
|
||||
self.vpnManager.loadFromPreferences(completionHandler: { error in
|
||||
if error != nil {
|
||||
print("Error loading from preferences")
|
||||
} else {
|
||||
do {
|
||||
print("Trying to start")
|
||||
self.initializeConnectionObserver()
|
||||
try self.vpnManager.connection.startVPNTunnel()
|
||||
} catch let error as NSError {
|
||||
print(error)
|
||||
} catch {
|
||||
print("There was a fatal error")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func initializeConnectionObserver() {
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in
|
||||
|
||||
if self.vpnManager.connection.status == .invalid {
|
||||
print("VPN configuration is invalid")
|
||||
} else if self.vpnManager.connection.status == .disconnected {
|
||||
print("VPN is disconnected.")
|
||||
} else if self.vpnManager.connection.status == .connecting {
|
||||
print("VPN is connecting...")
|
||||
} else if self.vpnManager.connection.status == .reasserting {
|
||||
print("VPN is reasserting...")
|
||||
} else if self.vpnManager.connection.status == .disconnecting {
|
||||
print("VPN is disconnecting...")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let lokinet = LokinetMain()
|
||||
lokinet.runMain()
|
@ -0,0 +1,4 @@
|
||||
|
||||
module Lokinet {
|
||||
header "lokinet-extension.hpp"
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
// AppDelegateExtension.swift
|
||||
// lifed from yggdrasil network ios port
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Lokinet
|
||||
import NetworkExtension
|
||||
|
||||
class LokinetMain: PlatformAppDelegate {
|
||||
var vpnManager = NETunnelProviderManager()
|
||||
var app = NSApplication.shared()
|
||||
let lokinetComponent = "org.lokinet.NetworkExtension"
|
||||
var lokinetAdminTimer: DispatchSourceTimer?
|
||||
|
||||
func runMain() {
|
||||
print("Starting up lokinet")
|
||||
NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
|
||||
if let savedManagers = savedManagers {
|
||||
for manager in savedManagers {
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent {
|
||||
print("Found saved VPN Manager")
|
||||
self.vpnManager = manager
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
self.vpnManager.localizedDescription = "Lokinet"
|
||||
self.vpnManager.isEnabled = true
|
||||
})
|
||||
}
|
||||
app.finishLaunching()
|
||||
app.run()
|
||||
print("end")
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <NetworkExtension/NetworkExtension.h>
|
||||
|
||||
struct ContextWrapper;
|
||||
|
||||
@interface LLARPPacketTunnel : NEPacketTunnelProvider
|
||||
{
|
||||
@private
|
||||
struct ContextWrapper* m_Context;
|
||||
}
|
||||
- (void)startTunnelWithOptions:(NSDictionary<NSString*, NSObject*>*)options
|
||||
completionHandler:(void (^)(NSError* error))completionHandler;
|
||||
|
||||
- (void)stopTunnelWithReason:(NEProviderStopReason)reason
|
||||
completionHandler:(void (^)(void))completionHandler;
|
||||
|
||||
@end
|
@ -0,0 +1,202 @@
|
||||
#include <lokinet-extension.hpp>
|
||||
#include <llarp.hpp>
|
||||
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/ev/vpn.hpp>
|
||||
#include <llarp/util/thread/queue.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace llarp::apple
|
||||
{
|
||||
struct FrameworkContext : public llarp::Context
|
||||
{
|
||||
|
||||
explicit FrameworkContext(NEPacketTunnelProvider * tunnel);
|
||||
|
||||
~FrameworkContext() {}
|
||||
|
||||
std::shared_ptr<vpn::Platform>
|
||||
makeVPNPlatform() override;
|
||||
|
||||
void
|
||||
Start();
|
||||
|
||||
private:
|
||||
NEPacketTunnelProvider * m_Tunnel;
|
||||
std::unique_ptr<std::thread> m_Runner;
|
||||
};
|
||||
|
||||
class VPNInterface final : public vpn::NetworkInterface
|
||||
{
|
||||
NEPacketTunnelProvider * m_Tunnel;
|
||||
|
||||
static inline constexpr auto PacketQueueSize = 1024;
|
||||
|
||||
thread::Queue<net::IPPacket> m_ReadQueue;
|
||||
|
||||
void
|
||||
OfferReadPacket(NSData * data)
|
||||
{
|
||||
llarp::net::IPPacket pkt;
|
||||
const llarp_buffer_t buf{static_cast<const uint8_t *>(data.bytes), data.length};
|
||||
if(pkt.Load(buf))
|
||||
m_ReadQueue.tryPushBack(std::move(pkt));
|
||||
}
|
||||
|
||||
public:
|
||||
explicit VPNInterface(NEPacketTunnelProvider * tunnel)
|
||||
: m_Tunnel{tunnel},
|
||||
m_ReadQueue{PacketQueueSize}
|
||||
{
|
||||
auto handler =
|
||||
[this](NSArray<NSData*> * packets, NSArray<NSNumber*> *)
|
||||
{
|
||||
NSUInteger num = [packets count];
|
||||
for(NSUInteger idx = 0; idx < num ; ++idx)
|
||||
{
|
||||
NSData * pkt = [packets objectAtIndex:idx];
|
||||
OfferReadPacket(pkt);
|
||||
}
|
||||
};
|
||||
[m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler];
|
||||
}
|
||||
|
||||
int
|
||||
PollFD() const override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string
|
||||
IfName() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
net::IPPacket
|
||||
ReadNextPacket() override
|
||||
{
|
||||
net::IPPacket pkt{};
|
||||
if(not m_ReadQueue.empty())
|
||||
pkt = m_ReadQueue.popFront();
|
||||
return pkt;
|
||||
}
|
||||
|
||||
bool
|
||||
WritePacket(net::IPPacket pkt) override
|
||||
{
|
||||
const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET;
|
||||
const uint8_t * pktbuf = pkt.buf;
|
||||
const size_t pktsz = pkt.sz;
|
||||
NSData * datapkt = [NSData dataWithBytes:pktbuf length:pktsz];
|
||||
NEPacket * npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam];
|
||||
NSArray * pkts = @[npkt];
|
||||
return [m_Tunnel.packetFlow writePacketObjects:pkts];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class VPNPlatform final : public vpn::Platform
|
||||
{
|
||||
NEPacketTunnelProvider * m_Tunnel;
|
||||
public:
|
||||
explicit VPNPlatform(NEPacketTunnelProvider * tunnel)
|
||||
: m_Tunnel{tunnel}
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<vpn::NetworkInterface>
|
||||
ObtainInterface(vpn::InterfaceInfo) override
|
||||
{
|
||||
return std::make_shared<VPNInterface>(m_Tunnel);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FrameworkContext::FrameworkContext(NEPacketTunnelProvider * tunnel) :
|
||||
llarp::Context{},
|
||||
m_Tunnel{tunnel}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FrameworkContext::Start()
|
||||
{
|
||||
std::promise<void> result;
|
||||
|
||||
m_Runner = std::make_unique<std::thread>(
|
||||
[&result, this]()
|
||||
{
|
||||
const RuntimeOptions opts{};
|
||||
try
|
||||
{
|
||||
Setup(opts);
|
||||
Configure(llarp::Config::NetworkExtensionConfig());
|
||||
}
|
||||
catch(std::exception & )
|
||||
{
|
||||
result.set_exception(std::current_exception());
|
||||
return;
|
||||
}
|
||||
result.set_value();
|
||||
Run(opts);
|
||||
});
|
||||
|
||||
auto ftr = result.get_future();
|
||||
ftr.get();
|
||||
}
|
||||
|
||||
std::shared_ptr<vpn::Platform>
|
||||
FrameworkContext::makeVPNPlatform()
|
||||
{
|
||||
return std::make_shared<VPNPlatform>(m_Tunnel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ContextWrapper
|
||||
{
|
||||
std::shared_ptr<llarp::apple::FrameworkContext> m_Context;
|
||||
public:
|
||||
explicit ContextWrapper(NEPacketTunnelProvider * tunnel) :
|
||||
m_Context{std::make_shared<llarp::apple::FrameworkContext>(tunnel)}
|
||||
{}
|
||||
|
||||
void
|
||||
Start()
|
||||
{
|
||||
m_Context->Start();
|
||||
}
|
||||
|
||||
void
|
||||
Stop()
|
||||
{
|
||||
m_Context->CloseAsync();
|
||||
m_Context->Wait();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@implementation LLARPPacketTunnel
|
||||
|
||||
- (void)startTunnelWithOptions:(NSDictionary<NSString *,NSObject *> *)options completionHandler:(void (^)(NSError *error))completionHandler {
|
||||
m_Context = new ContextWrapper{self};
|
||||
m_Context->Start();
|
||||
completionHandler(nullptr);
|
||||
}
|
||||
|
||||
- (void)stopTunnelWithReason:(NEProviderStopReason)reason
|
||||
completionHandler:(void (^)(void))completionHandler {
|
||||
if(m_Context)
|
||||
{
|
||||
m_Context->Stop();
|
||||
delete m_Context;
|
||||
m_Context = nullptr;
|
||||
}
|
||||
completionHandler();
|
||||
}
|
||||
|
||||
|
||||
@end
|
@ -1,173 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/ev/vpn.hpp>
|
||||
#include "common.hpp"
|
||||
|
||||
#include <sys/kern_control.h>
|
||||
#include <sys/sys_domain.h>
|
||||
#include <sys/kern_event.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
class AppleInterface : public NetworkInterface
|
||||
{
|
||||
const int m_FD;
|
||||
const InterfaceInfo m_Info;
|
||||
std::string m_IfName;
|
||||
|
||||
static void
|
||||
Exec(std::string cmd)
|
||||
{
|
||||
LogDebug(cmd);
|
||||
system(cmd.c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
AppleInterface(InterfaceInfo info)
|
||||
: m_FD{::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL)}, m_Info{std::move(info)}
|
||||
{
|
||||
if (m_FD == -1)
|
||||
throw std::invalid_argument{"cannot open control socket: " + std::string{strerror(errno)}};
|
||||
|
||||
ctl_info cinfo{};
|
||||
const std::string apple_utun = "com.apple.net.utun_control";
|
||||
std::copy_n(apple_utun.c_str(), apple_utun.size(), cinfo.ctl_name);
|
||||
if (::ioctl(m_FD, CTLIOCGINFO, &cinfo) < 0)
|
||||
{
|
||||
::close(m_FD);
|
||||
throw std::runtime_error{"ioctl CTLIOCGINFO call failed: " + std::string{strerror(errno)}};
|
||||
}
|
||||
sockaddr_ctl addr{};
|
||||
addr.sc_id = cinfo.ctl_id;
|
||||
|
||||
addr.sc_len = sizeof(addr);
|
||||
addr.sc_family = AF_SYSTEM;
|
||||
addr.ss_sysaddr = AF_SYS_CONTROL;
|
||||
addr.sc_unit = 0;
|
||||
|
||||
if (connect(m_FD, (sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
::close(m_FD);
|
||||
throw std::runtime_error{
|
||||
"cannot connect to control socket address: " + std::string{strerror(errno)}};
|
||||
}
|
||||
uint32_t namesz = IFNAMSIZ;
|
||||
char name[IFNAMSIZ + 1]{};
|
||||
if (getsockopt(m_FD, SYSPROTO_CONTROL, 2, name, &namesz) < 0)
|
||||
{
|
||||
::close(m_FD);
|
||||
throw std::runtime_error{
|
||||
"cannot query for interface name: " + std::string{strerror(errno)}};
|
||||
}
|
||||
m_IfName = name;
|
||||
for (const auto& ifaddr : m_Info.addrs)
|
||||
{
|
||||
if (ifaddr.fam == AF_INET)
|
||||
{
|
||||
const huint32_t addr = net::TruncateV6(ifaddr.range.addr);
|
||||
const huint32_t netmask = net::TruncateV6(ifaddr.range.netmask_bits);
|
||||
const huint32_t daddr = addr & netmask;
|
||||
Exec(
|
||||
"/sbin/ifconfig " + m_IfName + " " + addr.ToString() + " " + daddr.ToString()
|
||||
+ " mtu 1500 netmask 255.255.255.255 up");
|
||||
Exec(
|
||||
"/sbin/route add " + daddr.ToString() + " -netmask " + netmask.ToString()
|
||||
+ " -interface " + m_IfName);
|
||||
Exec("/sbin/route add " + addr.ToString() + " -interface lo0");
|
||||
}
|
||||
else if (ifaddr.fam == AF_INET6)
|
||||
{
|
||||
Exec("/sbin/ifconfig " + m_IfName + " inet6 " + ifaddr.range.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~AppleInterface()
|
||||
{
|
||||
::close(m_FD);
|
||||
}
|
||||
|
||||
std::string
|
||||
IfName() const override
|
||||
{
|
||||
return m_IfName;
|
||||
}
|
||||
|
||||
int
|
||||
PollFD() const override
|
||||
{
|
||||
return m_FD;
|
||||
}
|
||||
|
||||
net::IPPacket
|
||||
ReadNextPacket() override
|
||||
{
|
||||
constexpr int uintsize = sizeof(unsigned int);
|
||||
net::IPPacket pkt{};
|
||||
unsigned int pktinfo = 0;
|
||||
const struct iovec vecs[2] = {
|
||||
{.iov_base = &pktinfo, .iov_len = uintsize},
|
||||
{.iov_base = pkt.buf, .iov_len = sizeof(pkt.buf)}};
|
||||
int sz = readv(m_FD, vecs, 2);
|
||||
if (sz >= uintsize)
|
||||
pkt.sz = sz - uintsize;
|
||||
else if (sz >= 0 || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
pkt.sz = 0;
|
||||
else
|
||||
throw std::error_code{errno, std::system_category()};
|
||||
return pkt;
|
||||
}
|
||||
|
||||
bool
|
||||
WritePacket(net::IPPacket pkt) override
|
||||
{
|
||||
static unsigned int af4 = htonl(AF_INET);
|
||||
static unsigned int af6 = htonl(AF_INET6);
|
||||
|
||||
const struct iovec vecs[2] = {
|
||||
{.iov_base = pkt.IsV6() ? &af6 : &af4, .iov_len = sizeof(unsigned int)},
|
||||
{.iov_base = pkt.buf, .iov_len = pkt.sz}};
|
||||
|
||||
ssize_t n = writev(m_FD, vecs, 2);
|
||||
if (n >= (int)sizeof(unsigned int))
|
||||
{
|
||||
n -= sizeof(unsigned int);
|
||||
return static_cast<size_t>(n) == pkt.sz;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class ApplePlatform : public Platform
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<NetworkInterface>
|
||||
ObtainInterface(InterfaceInfo info) override
|
||||
{
|
||||
return std::make_shared<AppleInterface>(std::move(info));
|
||||
}
|
||||
};
|
||||
} // namespace llarp::vpn
|
Loading…
Reference in new issue