tun code refactor (#1495)

* partial tun code refactor

* take out the trash

* move vpn platform code into llarp/vpn/platform.cpp

* fix hive build

* fix win32

* fix memory leak on win32

* reduce cpu use

* make macos compile

* win32 patches:

* use wepoll for zmq
* use all cores on windows iocp read loop

* fix zmq patch for windows

* clean up cmake for win32

* add uninstall before reinstall option to win32 installer

* more ipv6 stuff

* make it compile

* fix up route poker

* remove an unneeded code block in macos wtf

* always use call to system

* fix route poker behavior on macos

* disable ipv6 on windows for now

* cpu perf improvement:

* colease calls to Router::PumpLL to 1 per event loop wakeup

* set up THEN add addresses

* emulate proactor event loop on win32

* remove excessively verbose error message

* fix issue #1499

* exclude uv_poll from win32 so that it can start up

* update logtag to include directory

* create minidump on windows if there was a crash

* make windows happy

* use dmp suffix on minidump files

* typo fix

* address feedback from jason
* use PROJECT_SOURCE_DIR instead of CMAKE_SOURCE_DIR
* quote $@ in apply-patches in case path has spaces in it

* address feedback from tom

* remove llarp/ev/pipe
* add comments for clairification
* make event loop queue size constant named
This commit is contained in:
Jeff 2021-01-11 18:13:22 -05:00 committed by GitHub
parent 029b6db364
commit 49b9ad7197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 1416 additions and 8657 deletions

View File

@ -23,7 +23,7 @@ set(RELEASE_MOTTO "Proof of soon" CACHE STRING "Release motto")
add_definitions(-DLLARP_VERSION_MAJOR=${lokinet_VERSION_MAJOR})
add_definitions(-DLLARP_VERSION_MINOR=${lokinet_VERSION_MINOR})
add_definitions(-DLLARP_VERSION_PATCH=${lokinet_VERSION_PATCH})
if(RELEASE_MOTTO)
if(RELEASE_MOTTO AND CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]")
add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}")
endif()
@ -329,8 +329,6 @@ add_subdirectory(external/date EXCLUDE_FROM_ALL)
include_directories(SYSTEM external/sqlite_orm/include)
add_subdirectory(vendor)
if(ANDROID)
target_link_libraries(base_libs INTERFACE log)
target_compile_definitions(base_libs INTERFACE ANDROID)

View File

@ -259,9 +259,16 @@ build_external(sqlite3)
add_static_target(sqlite3 sqlite3_external libsqlite3.a)
if(ZMQ_VERSION VERSION_LESS 4.3.4 AND CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
if(ARCH_TRIPLET MATCHES mingw)
set(zmq_extra --with-poller=wepoll)
endif()
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
set(zmq_patch
PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-closesocket.patch)
PATCH_COMMAND ${PROJECT_SOURCE_DIR}/contrib/apply-patches.sh ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-wepoll.patch)
if(ZMQ_VERSION VERSION_LESS 4.3.4)
set(zmq_patch ${zmq_patch} ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-closesocket.patch)
endif()
endif()
build_external(zmq
@ -269,7 +276,7 @@ build_external(zmq
${zmq_patch}
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared
--disable-curve-keygen --enable-curve --disable-drafts --disable-libunwind --with-libsodium
--without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror
--without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror ${zmq_extra}
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=${deps_CFLAGS} -fstack-protector" "CXXFLAGS=${deps_CXXFLAGS} -fstack-protector"
"sodium_CFLAGS=-I${DEPS_DESTDIR}/include" "sodium_LIBS=-L${DEPS_DESTDIR}/lib -lsodium"
)

View File

@ -1,6 +1,8 @@
function(add_log_tag target)
get_target_property(TARGET_SRCS ${target} SOURCES)
foreach(F ${TARGET_SRCS})
set_property(SOURCE ${F} APPEND PROPERTY COMPILE_DEFINITIONS LOG_TAG=\"${F}\")
get_filename_component(fpath "${F}" ABSOLUTE)
string(REPLACE "${PROJECT_SOURCE_DIR}/" "" logtag "${fpath}")
set_property(SOURCE ${F} APPEND PROPERTY COMPILE_DEFINITIONS LOG_TAG=\"${logtag}\")
endforeach()
endfunction()

View File

@ -1,5 +1,8 @@
set(GUI_ZIP_URL "https://oxen.rocks/loki-project/loki-network-control-panel/master/lokinet-gui-windows-32bit-v0.3.5.zip")
set(GUI_ZIP_HASH SHA256=fcb1d78f7d6eecb440d05a034dd7e60ae506275af5b0f600b416bb1a896f32aa)
if(NOT GUI_ZIP_URL)
set(GUI_ZIP_URL "https://oxen.rocks/loki-project/loki-network-control-panel/master/lokinet-gui-windows-32bit-v0.3.5.zip")
set(GUI_ZIP_HASH_OPTS EXPECTED_HASH SHA256=fcb1d78f7d6eecb440d05a034dd7e60ae506275af5b0f600b416bb1a896f32aa)
endif()
set(TUNTAP_URL "https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe")
set(TUNTAP_EXE "${CMAKE_BINARY_DIR}/tuntap-install.exe")
set(BOOTSTRAP_URL "https://seed.lokinet.org/lokinet.signed")
@ -16,7 +19,7 @@ file(DOWNLOAD
file(DOWNLOAD
${GUI_ZIP_URL}
${CMAKE_BINARY_DIR}/lokinet-gui.zip
EXPECTED_HASH ${GUI_ZIP_HASH})
${GUI_ZIP_HASH_OPTS})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_BINARY_DIR}/lokinet-gui.zip
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
@ -28,6 +31,7 @@ install(FILES ${BOOTSTRAP_FILE} DESTINATION share)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Lokinet")
set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/win32-setup/lokinet.ico")
set(CPACK_NSIS_DEFINES "RequestExecutionLevel admin")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '$INSTDIR\\\\bin\\\\tuntap-install.exe /S'\\nExecWait '$INSTDIR\\\\bin\\\\lokinet.exe --install'\\nExecWait '$INSTDIR\\\\bin\\\\lokinet.exe -g C:\\\\ProgramData\\\\lokinet\\\\lokinet.ini'\\nCopyFiles '$INSTDIR\\\\share\\\\bootstrap.signed' C:\\\\ProgramData\\\\lokinet\\\\bootstrap.signed")
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "ExecWait 'net stop lokinet'\\nExecWait 'taskkill /f /t /im lokinet-gui.exe'\\nExecWait '$INSTDIR\\\\bin\\\\lokinet.exe --remove'\\nRMDir /r /REBOOTOK C:\\\\ProgramData\\\\lokinet")
set(CPACK_NSIS_CREATE_ICONS_EXTRA

4
contrib/apply-patches.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
for f in "$@" ; do
patch -p1 -i "$f"
done

View File

@ -0,0 +1,16 @@
diff --git a/external/wepoll/wepoll.c b/external/wepoll/wepoll.c
--- a/external/wepoll/wepoll.c
+++ b/external/wepoll/wepoll.c
@@ -140,9 +140,9 @@
#pragma warning(push, 1)
#endif
-#include <WS2tcpip.h>
-#include <WinSock2.h>
-#include <Windows.h>
+#include <ws2tcpip.h>
+#include <winsock2.h>
+#include <windows.h>
#ifndef __GNUC__
#pragma warning(pop)

View File

@ -1,5 +1,5 @@
#!/bin/bash
mkdir -p build-windows
cd build-windows
cmake -G Ninja -DCMAKE_CROSSCOMPILE=ON -DCMAKE_EXE_LINKER_FLAGS=-fstack-protector -DLIBUV_ROOT=$PWD/../external/libuv -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw64.cmake -DBUILD_STATIC_DEPS=ON -DBUILD_PACKAGE=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DWITH_TESTS=OFF -DNATIVE_BUILD=OFF -DSTATIC_LINK=ON -DWITH_SYSTEMD=OFF -DFORCE_LOKIMQ_SUBMODULE=ON -DSUBMODULE_CHECK=OFF -DWITH_LTO=OFF ..
cmake -G Ninja -DCMAKE_CROSSCOMPILE=ON -DCMAKE_EXE_LINKER_FLAGS=-fstack-protector -DLIBUV_ROOT=$PWD/../external/libuv -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw64.cmake -DBUILD_STATIC_DEPS=ON -DBUILD_PACKAGE=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DWITH_TESTS=OFF -DNATIVE_BUILD=OFF -DSTATIC_LINK=ON -DWITH_SYSTEMD=OFF -DFORCE_LOKIMQ_SUBMODULE=ON -DSUBMODULE_CHECK=OFF -DWITH_LTO=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_CROSSCOMPLING=ON ..
ninja package

View File

@ -8,6 +8,10 @@
#include <util/str.hpp>
#include <util/thread/logic.hpp>
#ifdef _WIN32
#include <dbghelp.h>
#endif
#include <csignal>
#include <cxxopts.hpp>
@ -329,6 +333,45 @@ class WindowsServiceStopped
TellWindowsServiceStopped();
}
};
/// minidump generation for windows jizz
/// will make a coredump when there is an unhandled exception
LONG
GenerateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
std::stringstream ss;
ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp";
const std::string fname = ss.str();
HANDLE hDumpFile;
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
MINIDUMP_EXCEPTION_INFORMATION ExpParam;
hDumpFile = CreateFile(
fname.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
CREATE_ALWAYS,
0,
0);
ExpParam.ThreadId = GetCurrentThreadId();
ExpParam.ExceptionPointers = pExceptionPointers;
ExpParam.ClientPointers = TRUE;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hDumpFile,
MiniDumpWithDataSegs,
&ExpParam,
NULL,
NULL);
return 1;
}
#endif
int
@ -521,6 +564,10 @@ lokinet_main(int argc, char* argv[])
return 0;
}
#ifdef _WIN32
SetUnhandledExceptionFilter(&GenerateDump);
#endif
std::thread main_thread{std::bind(&run_main_context, configFile, opts)};
auto ftr = exit_code.get_future();

View File

@ -4,6 +4,7 @@
#include <util/fs.hpp>
#include <util/types.hpp>
#include <ev/ev.hpp>
#include <ev/vpn.hpp>
#include <nodedb.hpp>
#include <crypto/crypto.hpp>
#include <router/abstractrouter.hpp>
@ -95,6 +96,10 @@ namespace llarp
virtual std::unique_ptr<AbstractRouter>
makeRouter(llarp_ev_loop_ptr __netloop, std::shared_ptr<Logic> logic);
/// create the vpn platform for use in creating network interfaces
virtual std::unique_ptr<llarp::vpn::Platform>
makeVPNPlatform();
protected:
std::shared_ptr<Config> config = nullptr;

View File

@ -1,267 +0,0 @@
/*
* Copyright (c) 2012 Tristan Le Guern <leguern AT medu DOT se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#if defined Windows
#else /* Unix */
#include <sys/socket.h>
#endif
#if !defined Windows /* Unix :) */
#if !defined Linux
#include <netinet/in.h>
#endif
#if defined(Linux)
// Once we drop xenial support we can just include net/if.h on linux
#include <linux/if.h>
#else
#include <net/if.h>
#endif
#if defined Linux
#include <netinet/in.h>
#elif defined(iOS)
#include <net/ethernet.h>
#else
#include <netinet/if_ether.h>
#endif
#endif
#include <stdint.h>
#ifndef LIBTUNTAP_H_
#define LIBTUNTAP_H_
#if defined IFNAMSIZ && !defined IF_NAMESIZE
#define IF_NAMESIZE IFNAMSIZ /* Historical BSD name */
#elif !defined IF_NAMESIZE
#define IF_NAMESIZE 16
#endif
#define IF_DESCRSIZE 50 /* XXX: Tests needed on NetBSD and OpenBSD */
#if defined TUNSETDEBUG
#define TUNSDEBUG TUNSETDEBUG
#endif
#if defined Windows
#define TUNFD_INVALID_VALUE INVALID_HANDLE_VALUE
#else /* Unix */
#define TUNFD_INVALID_VALUE -1
#endif
/*
* Uniformize types
* - t_tun: tun device file descriptor
* - t_tun_in_addr: struct in_addr/IN_ADDR
* - t_tun_in6_addr: struct in6_addr/IN6_ADDR
*/
#if defined Windows
#include <windows.h>
#include <in6addr.h>
#include <winsock2.h>
typedef HANDLE t_tun;
typedef IN_ADDR t_tun_in_addr;
typedef IN6_ADDR t_tun_in6_addr;
#else /* Unix */
typedef int t_tun;
typedef struct in_addr t_tun_in_addr;
typedef struct in6_addr t_tun_in6_addr;
#endif
/*
* Windows helpers
*/
#if defined Windows
//#define strncat(x, y, z) strncat_s((x), _countof(x), (y), (z));
#define strdup(x) _strdup(x)
#endif
#define TUNTAP_ID_MAX 256
#define TUNTAP_ID_ANY 257
#define TUNTAP_MODE_ETHERNET 0x0001
#define TUNTAP_MODE_TUNNEL 0x0002
#define TUNTAP_MODE_PERSIST 0x0004
#define TUNTAP_LOG_NONE 0x0000
#define TUNTAP_LOG_DEBUG 0x0001
#define TUNTAP_LOG_INFO 0x0002
#define TUNTAP_LOG_NOTICE 0x0004
#define TUNTAP_LOG_WARN 0x0008
#define TUNTAP_LOG_ERR 0x0016
/* Versioning: 0xMMmm, with 'M' for major and 'm' for minor */
#define TUNTAP_VERSION_MAJOR 0
#define TUNTAP_VERSION_MINOR 3
#define TUNTAP_VERSION ((TUNTAP_VERSION_MAJOR << 8) | TUNTAP_VERSION_MINOR)
#define TUNTAP_GET_FD(x) (x)->tun_fd
/* Handle Windows symbols export */
#if defined Windows
#if defined(tuntap_EXPORTS) && defined(_USRDLL) /* CMake generated goo */
#define TUNTAP_EXPORT __declspec(dllexport)
#elif defined(tuntap_EXPORTS)
#define TUNTAP_EXPORT __declspec(dllimport)
#else
#define TUNTAP_EXPORT extern
#endif
#else /* Unix */
#define TUNTAP_EXPORT extern
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct device
{
/** set me on ios and android to block on a promise for the fd */
int (*obtain_fd)(struct device*);
/** user data */
void* user;
t_tun tun_fd;
int ctrl_sock;
int flags; /* ifr.ifr_flags on Unix */
char if_name[IF_NAMESIZE];
#if defined(Windows)
int idx; /* needed to set ipv6 address */
DWORD bindaddr; /* set DNS client address */
#endif
#if defined(FreeBSD)
int mode;
#endif
#if defined(__sun)
int ip_fd;
int reserved;
char internal_name[IF_NAMESIZE];
#endif
};
/* User definable log callback */
typedef void (*t_tuntap_log)(int, int, const char*, const char*);
TUNTAP_EXPORT t_tuntap_log __tuntap_log;
#ifndef LOG_TAG
#define LOG_TAG "tuntap"
#endif
#define tuntap_log(lvl, msg) __tuntap_log(lvl, __LINE__, LOG_TAG, msg)
/* Portable "public" functions */
TUNTAP_EXPORT struct device*
tuntap_init(void);
TUNTAP_EXPORT int
tuntap_version(void);
TUNTAP_EXPORT void
tuntap_destroy(struct device*);
TUNTAP_EXPORT void
tuntap_release(struct device*);
TUNTAP_EXPORT int
tuntap_start(struct device*, int, int);
TUNTAP_EXPORT char*
tuntap_get_ifname(struct device*);
TUNTAP_EXPORT int
tuntap_set_ifname(struct device*, const char*);
TUNTAP_EXPORT int
tuntap_set_descr(struct device*, const char*);
TUNTAP_EXPORT int
tuntap_up(struct device*);
TUNTAP_EXPORT int
tuntap_down(struct device*);
TUNTAP_EXPORT int
tuntap_get_mtu(struct device*);
TUNTAP_EXPORT int
tuntap_set_mtu(struct device*, int);
/** set ip address and netmask
*/
TUNTAP_EXPORT int
tuntap_set_ip(struct device*, const char* srcaddr, const char* dstaddr, int netmask);
// TUNTAP_EXPORT int tuntap_set_ip_old(struct device *, const char
// *, int);
/*TUNTAP_EXPORT int tuntap_set_ip_old(struct device *, const char
* *, int);*/
TUNTAP_EXPORT int
tuntap_read(struct device*, void*, size_t);
TUNTAP_EXPORT int
tuntap_write(struct device*, void*, size_t);
TUNTAP_EXPORT int
tuntap_get_readable(struct device*);
TUNTAP_EXPORT int
tuntap_set_nonblocking(struct device* dev, int);
TUNTAP_EXPORT int
tuntap_set_debug(struct device* dev, int);
/* Logging functions */
TUNTAP_EXPORT void
tuntap_log_set_cb(t_tuntap_log cb);
void
tuntap_log_default(int, int, const char*, const char*);
void
tuntap_log_hexdump(void*, size_t);
void
tuntap_log_chksum(void*, int);
/* OS specific functions */
int
tuntap_sys_start(struct device*, int, int);
void
tuntap_sys_destroy(struct device*);
int
tuntap_sys_set_ipv4(struct device*, t_tun_in_addr*, uint32_t);
#if defined(Windows)
int
tuntap_sys_set_dns(struct device* dev, t_tun_in_addr* s, uint32_t mask);
#endif
#if defined(FreeBSD)
int
tuntap_sys_set_ipv4_tap(struct device*, t_tun_in_addr*, uint32_t);
int
tuntap_sys_set_ipv4_tun(
struct device* dev, t_tun_in_addr* s4, t_tun_in_addr* s4dest, uint32_t bits, int netmask);
#endif
int
tuntap_sys_set_ipv6(struct device*, t_tun_in6_addr*, uint32_t);
int
tuntap_sys_set_ifname(struct device*, const char*, size_t);
int
tuntap_sys_set_descr(struct device*, const char*, size_t);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -52,7 +52,6 @@ add_library(lokinet-platform
ev/ev.cpp
ev/pipe.cpp
ev/ev_libuv.cpp
net/ip.cpp
net/ip_address.cpp
net/ip_packet.cpp
@ -61,7 +60,7 @@ add_library(lokinet-platform
net/net_int.cpp
net/route.cpp
net/sock_addr.cpp
$<TARGET_OBJECTS:tuntap>
vpn/platform.cpp
)
target_link_libraries(lokinet-platform PUBLIC lokinet-cryptography lokinet-util Threads::Threads base_libs libuv)
@ -83,7 +82,6 @@ endif()
if (WIN32)
target_sources(lokinet-platform PRIVATE
ev/ev_libuv.cpp
ev/ev_win32.cpp
win32/win32_inet.c
win32/win32_intrnl.c)

View File

@ -98,7 +98,16 @@ namespace llarp
std::unique_ptr<AbstractRouter>
Context::makeRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<Logic> logic)
{
return std::make_unique<Router>(netloop, logic);
return std::make_unique<Router>(netloop, logic, makeVPNPlatform());
}
std::unique_ptr<vpn::Platform>
Context::makeVPNPlatform()
{
auto plat = vpn::MakeNativePlatform(this);
if (plat == nullptr)
throw std::runtime_error("vpn platform not supported");
return plat;
}
int
@ -123,9 +132,9 @@ namespace llarp
llarp_ev_loop_run_single_process(mainloop, logic);
if (closeWaiter)
{
// inform promise if called by CloseAsync
closeWaiter->set_value();
}
Close();
return 0;
}
@ -177,13 +186,6 @@ namespace llarp
/// async stop router on sigint
router->Stop();
}
else
{
if (logic)
logic->stop();
llarp_ev_loop_stop(mainloop);
Close();
}
}
void

View File

@ -47,14 +47,7 @@ namespace llarp
return false;
}
}
const IpAddress any("0.0.0.0", 0);
auto self = shared_from_this();
LogicCall(m_ClientLogic, [=]() {
llarp_ev_add_udp(self->m_ClientLoop.get(), &self->m_Client, any.createSockAddr());
});
return (
llarp_ev_add_udp(self->m_ServerLoop.get(), &self->m_Server, addr.createSockAddr()) == 0);
return (llarp_ev_add_udp(m_ServerLoop, &m_Server, addr.createSockAddr()) == 0);
}
static Proxy::Buffer_t

View File

@ -9,10 +9,6 @@
// We libuv now
#include <ev/ev_libuv.hpp>
#if defined(_WIN32) || defined(_WIN64) || defined(__NT__)
#define SHUT_RDWR SD_BOTH
#include <ev/ev_win32.hpp>
#endif
llarp_ev_loop_ptr
llarp_make_ev_loop(size_t queueLength)
@ -34,14 +30,14 @@ llarp_ev_loop_run_single_process(llarp_ev_loop_ptr ev, std::shared_ptr<llarp::Lo
}
int
llarp_ev_add_udp(struct llarp_ev_loop* ev, struct llarp_udp_io* udp, const llarp::SockAddr& src)
llarp_ev_add_udp(const llarp_ev_loop_ptr& ev, struct llarp_udp_io* udp, const llarp::SockAddr& src)
{
if (ev == nullptr or udp == nullptr)
{
llarp::LogError("Attempting llarp_ev_add_udp() with null event loop or udp io struct.");
return -1;
}
udp->parent = ev;
udp->parent = ev.get();
if (ev->udp_listen(udp, src))
return 0;
llarp::LogError("llarp_ev_add_udp() call to udp_listen failed.");
@ -75,129 +71,3 @@ llarp_ev_udp_sendto(struct llarp_udp_io* udp, const llarp::SockAddr& to, const l
{
return udp->sendto(udp, to, buf.base, buf.sz);
}
bool
llarp_ev_add_tun(struct llarp_ev_loop* loop, struct llarp_tun_io* tun)
{
if (tun->ifaddr[0] == 0 || strcmp(tun->ifaddr, "auto") == 0)
{
LogError("invalid ifaddr on tun: ", tun->ifaddr);
return false;
}
if (tun->ifname[0] == 0 || strcmp(tun->ifname, "auto") == 0)
{
LogError("invalid ifname on tun: ", tun->ifname);
return false;
}
#if !defined(_WIN32)
return loop->tun_listen(tun);
#else
UNREFERENCED_PARAMETER(loop);
auto dev = new win32_tun_io(tun);
tun->impl = dev;
// We're not even going to add this to the socket event loop
if (dev)
{
dev->setup();
return dev->add_ev(loop); // start up tun and add to event queue
}
llarp::LogWarn("Loop could not create tun");
return false;
#endif
}
bool
llarp_ev_tun_async_write(struct llarp_tun_io* tun, const llarp_buffer_t& buf)
{
if (buf.sz > EV_WRITE_BUF_SZ)
{
llarp::LogWarn("packet too big, ", buf.sz, " > ", EV_WRITE_BUF_SZ);
return false;
}
#ifndef _WIN32
return tun->writepkt(tun, buf.base, buf.sz);
#else
return static_cast<win32_tun_io*>(tun->impl)->queue_write(buf.base, buf.sz);
#endif
}
bool
llarp_tcp_conn_async_write(struct llarp_tcp_conn* conn, const llarp_buffer_t& b)
{
ManagedBuffer buf{b};
size_t sz = buf.underlying.sz;
buf.underlying.cur = buf.underlying.base;
while (sz > EV_WRITE_BUF_SZ)
{
ssize_t amount = conn->write(conn, buf.underlying.cur, EV_WRITE_BUF_SZ);
if (amount <= 0)
{
llarp::LogError("write underrun");
llarp_tcp_conn_close(conn);
return false;
}
buf.underlying.cur += amount;
sz -= amount;
}
return conn->write(conn, buf.underlying.cur, sz) > 0;
}
void
llarp_tcp_async_try_connect(struct llarp_ev_loop* loop, struct llarp_tcp_connecter* tcp)
{
tcp->loop = loop;
llarp::IpAddress address(tcp->remote);
if (not address.getPort())
throw std::runtime_error(llarp::stringify("Address with no port: ", address));
llarp::SockAddr addr = address.createSockAddr();
if (!loop->tcp_connect(tcp, addr))
{
llarp::LogError("async connect failed");
if (tcp->error)
tcp->error(tcp);
}
}
bool
llarp_tcp_serve(
struct llarp_ev_loop* loop, struct llarp_tcp_acceptor* tcp, const llarp::SockAddr& bindaddr)
{
tcp->loop = loop;
return loop->tcp_listen(tcp, bindaddr);
}
void
llarp_tcp_acceptor_close(struct llarp_tcp_acceptor* tcp)
{
tcp->close(tcp);
}
void
llarp_tcp_conn_close(struct llarp_tcp_conn* conn)
{
conn->close(conn);
}
namespace llarp
{
bool
tcp_conn::tick()
{
if (_shouldClose)
{
if (tcp.closed)
tcp.closed(&tcp);
::shutdown(fd, SHUT_RDWR);
return false;
}
if (tcp.tick)
tcp.tick(&tcp);
return true;
}
} // namespace llarp

View File

@ -4,7 +4,6 @@
#include <net/ip_address.hpp>
#include <util/buffer.hpp>
#include <util/time.hpp>
#include <tuntap.h>
#ifdef _WIN32
#include <winsock2.h>
@ -31,17 +30,13 @@
#define EV_TICK_INTERVAL 10
// forward declare
struct llarp_threadpool;
struct llarp_ev_loop;
namespace llarp
{
class Logic;
}
struct EventLoop;
} // namespace llarp
using llarp_ev_loop_ptr = std::shared_ptr<llarp_ev_loop>;
using llarp_ev_loop_ptr = std::shared_ptr<llarp::EventLoop>;
/// make an event loop using our baked in event loop on Windows
/// make an event loop using libuv otherwise.
@ -68,7 +63,7 @@ struct llarp_udp_io
int fd;
void* user;
void* impl;
struct llarp_ev_loop* parent;
llarp::EventLoop* parent;
/// called every event loop tick after reads
void (*tick)(struct llarp_udp_io*);
@ -80,7 +75,7 @@ struct llarp_udp_io
/// add UDP handler
int
llarp_ev_add_udp(struct llarp_ev_loop* ev, struct llarp_udp_io* udp, const llarp::SockAddr& src);
llarp_ev_add_udp(const llarp_ev_loop_ptr& ev, struct llarp_udp_io* udp, const llarp::SockAddr& src);
/// send a UDP packet
int
@ -90,139 +85,4 @@ llarp_ev_udp_sendto(struct llarp_udp_io* udp, const llarp::SockAddr& to, const l
int
llarp_ev_close_udp(struct llarp_udp_io* udp);
// forward declare
struct llarp_tcp_acceptor;
/// a single tcp connection
struct llarp_tcp_conn
{
/// user data
void* user;
/// private implementation
void* impl;
/// parent loop (dont set me)
struct llarp_ev_loop* loop;
/// handle read event
void (*read)(struct llarp_tcp_conn*, const llarp_buffer_t&);
//// set by parent
ssize_t (*write)(struct llarp_tcp_conn*, const byte_t*, size_t sz);
/// set by parent
bool (*is_open)(struct llarp_tcp_conn*);
/// handle close event (free-ing is handled by event loop)
void (*closed)(struct llarp_tcp_conn*);
/// explict close by user (set by parent)
void (*close)(struct llarp_tcp_conn*);
/// handle event loop tick
void (*tick)(struct llarp_tcp_conn*);
};
/// queue async write a buffer in full
/// return if we queued it or not
bool
llarp_tcp_conn_async_write(struct llarp_tcp_conn*, const llarp_buffer_t&);
/// close a tcp connection
void
llarp_tcp_conn_close(struct llarp_tcp_conn*);
/// handles outbound connections to 1 endpoint
struct llarp_tcp_connecter
{
/// remote address family
int af;
/// remote address string
llarp::IpAddress remote;
/// userdata pointer
void* user;
/// private implementation (dont set me)
void* impl;
/// parent event loop (dont set me)
struct llarp_ev_loop* loop;
/// handle outbound connection made
void (*connected)(struct llarp_tcp_connecter*, struct llarp_tcp_conn*);
/// handle outbound connection error
void (*error)(struct llarp_tcp_connecter*);
};
/// async try connecting to a remote connection 1 time
void
llarp_tcp_async_try_connect(struct llarp_ev_loop* l, struct llarp_tcp_connecter* tcp);
/// handles inbound connections
struct llarp_tcp_acceptor
{
/// userdata pointer
void* user;
/// internal implementation
void* impl;
/// parent event loop (dont set me)
struct llarp_ev_loop* loop;
/// handle event loop tick
void (*tick)(struct llarp_tcp_acceptor*);
/// handle inbound connection
void (*accepted)(struct llarp_tcp_acceptor*, struct llarp_tcp_conn*);
/// handle after server socket closed (free-ing is handled by event loop)
void (*closed)(struct llarp_tcp_acceptor*);
/// set by impl
void (*close)(struct llarp_tcp_acceptor*);
};
/// bind to an address and start serving async
/// return false if failed to bind
/// return true on success
bool
llarp_tcp_serve(
struct llarp_ev_loop* loop, struct llarp_tcp_acceptor* t, const llarp::SockAddr& bindaddr);
/// close and stop accepting connections
void
llarp_tcp_acceptor_close(struct llarp_tcp_acceptor*);
#ifdef _WIN32
#define IFNAMSIZ (16)
#endif
struct llarp_fd_promise;
/// wait until the fd promise is set
int
llarp_fd_promise_wait_for_value(struct llarp_fd_promise* promise);
struct llarp_tun_io
{
// TODO: more info?
char ifaddr[128];
// windows only
uint32_t dnsaddr;
int netmask;
char ifname[IFNAMSIZ + 1];
void* user;
void* impl;
/// functor for getting a promise that returns the vpn fd
/// dont set me if you don't know how to use this
struct llarp_fd_promise* (*get_fd_promise)(struct llarp_tun_io*);
struct llarp_ev_loop* parent;
/// called when we are able to write right before we write
/// this happens after reading packets
void (*before_write)(struct llarp_tun_io*);
/// called every event loop tick after reads
void (*tick)(struct llarp_tun_io*);
void (*recvpkt)(struct llarp_tun_io*, const llarp_buffer_t&);
/// set by parent
bool (*writepkt)(struct llarp_tun_io*, const byte_t*, size_t);
};
/// create tun interface with network interface name ifname
/// returns true on success otherwise returns false
bool
llarp_ev_add_tun(struct llarp_ev_loop* ev, struct llarp_tun_io* tun);
/// async write a packet on tun interface
/// returns true if queued, returns false on drop
bool
llarp_ev_tun_async_write(struct llarp_tun_io* tun, const llarp_buffer_t&);
#endif

View File

@ -2,6 +2,7 @@
#define LLARP_EV_HPP
#include <net/ip_address.hpp>
#include <net/ip_packet.hpp>
#include <ev/ev.h>
#include <util/buffer.hpp>
#include <util/codel.hpp>
@ -51,759 +52,81 @@ struct llarp_ev_pkt_pipe;
#define EV_WRITE_BUF_SZ (4 * 1024UL)
#endif
/// do io and reset errno after
static ssize_t
IO(std::function<ssize_t(void)> iofunc)
{
ssize_t ret = iofunc();
#ifndef _WIN32
errno = 0;
#else
WSASetLastError(0);
#endif
return ret;
}
namespace llarp
{
#ifdef _WIN32
struct win32_ev_io
namespace vpn
{
struct WriteBuffer
{
llarp_time_t timestamp = 0s;
size_t bufsz;
byte_t buf[EV_WRITE_BUF_SZ] = {0};
class NetworkInterface;
}
WriteBuffer() = default;
// this (nearly!) abstract base class
// is overriden for each platform
struct EventLoop
{
byte_t readbuf[EV_READ_BUF_SZ] = {0};
WriteBuffer(const byte_t* ptr, size_t sz)
{
if (sz <= sizeof(buf))
{
bufsz = sz;
memcpy(buf, ptr, bufsz);
}
else
bufsz = 0;
}
struct GetTime
{
llarp_time_t
operator()(const WriteBuffer& buf) const
{
return buf.timestamp;
}
};
struct GetNow
{
llarp_ev_loop_ptr loop;
GetNow(llarp_ev_loop_ptr l) : loop(l)
{}
llarp_time_t
operator()() const
{
return llarp_ev_loop_time_now_ms(loop);
}
};
struct PutTime
{
llarp_ev_loop_ptr loop;
PutTime(llarp_ev_loop_ptr l) : loop(l)
{}
void
operator()(WriteBuffer& buf)
{
buf.timestamp = llarp_ev_loop_time_now_ms(loop);
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
using LosslessWriteQueue_t = std::deque<WriteBuffer>;
intptr_t fd; // Sockets only, fuck UNIX-style reactive IO with a rusty knife
int flags = 0;
win32_ev_io(intptr_t f) : fd(f){};
/// for tcp
win32_ev_io(intptr_t f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{}
virtual void
error()
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL, ebuf, 1024, nullptr);
llarp::LogError(ebuf);
}
virtual int
read(byte_t* buf, size_t sz) = 0;
virtual int
sendto(const SockAddr& dst, const void* data, size_t sz)
{
UNREFERENCED_PARAMETER(dst);
UNREFERENCED_PARAMETER(data);
UNREFERENCED_PARAMETER(sz);
return -1;
};
/// return false if we want to deregister and remove ourselves
virtual bool
tick()
{
return true;
};
/// used for tun interface and tcp conn
virtual ssize_t
do_write(void* data, size_t sz)
{
return send(fd, (char*)data, sz, 0);
}
bool
queue_write(const byte_t* buf, size_t sz)
{
if (m_BlockingWriteQueue)
{
m_BlockingWriteQueue->emplace_back(buf, sz);
return true;
}
else
return false;
}
virtual void
flush_write()
{
flush_write_buffers(0);
}
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual void
flush_write_buffers(size_t amount)
{
if (m_BlockingWriteQueue)
{
if (amount)
{
while (amount && m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, std::min(amount, itr.bufsz));
if (result == -1)
return;
ssize_t dlt = itr.bufsz - result;
if (dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
amount -= result;
}
}
else
{
// write buffers
while (m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, itr.bufsz);
if (result == -1)
return;
ssize_t dlt = itr.bufsz - result;
if (dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
int wsaerr = WSAGetLastError();
if (wsaerr == WSA_IO_PENDING || wsaerr == WSAEWOULDBLOCK)
{
WSASetLastError(0);
return;
}
}
}
}
/// reset errno
WSASetLastError(0);
}
std::unique_ptr<LosslessWriteQueue_t> m_BlockingWriteQueue;
virtual ~win32_ev_io()
{
closesocket(fd);
};
};
#else
struct posix_ev_io
{
struct WriteBuffer
{
llarp_time_t timestamp = 0s;
size_t bufsz;
byte_t buf[EV_WRITE_BUF_SZ];
WriteBuffer() = default;
WriteBuffer(const byte_t* ptr, size_t sz)
{
if (sz <= sizeof(buf))
{
bufsz = sz;
memcpy(buf, ptr, bufsz);
}
else
bufsz = 0;
}
struct GetTime
{
llarp_time_t
operator()(const WriteBuffer& writebuf) const
{
return writebuf.timestamp;
}
};
struct GetNow
{
llarp_ev_loop_ptr loop;
GetNow(llarp_ev_loop_ptr l) : loop(std::move(l))
{}
llarp_time_t
operator()() const
{
return llarp_ev_loop_time_now_ms(loop);
}
};
struct PutTime
{
llarp_ev_loop_ptr loop;
PutTime(llarp_ev_loop_ptr l) : loop(std::move(l))
{}
void
operator()(WriteBuffer& writebuf)
{
writebuf.timestamp = llarp_ev_loop_time_now_ms(loop);
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
using LossyWriteQueue_t = llarp::util::CoDelQueue<
WriteBuffer,
WriteBuffer::GetTime,
WriteBuffer::PutTime,
WriteBuffer::Compare,
WriteBuffer::GetNow,
llarp::util::NullMutex,
llarp::util::NullLock>;
using LosslessWriteQueue_t = std::deque<WriteBuffer>;
int fd;
int flags = 0;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || (__APPLE__ && __MACH__)
struct kevent change;
#endif
posix_ev_io(int f) : fd(f)
{}
/// for tun
posix_ev_io(int f, LossyWriteQueue_t* q) : fd(f), m_LossyWriteQueue(q)
{}
/// for tcp
posix_ev_io(int f, LosslessWriteQueue_t* q) : fd(f), m_BlockingWriteQueue(q)
{}
virtual void
error()
{
llarp::LogError(strerror(errno));
}
init() = 0;
virtual int
read(byte_t* buf, size_t sz) = 0;
run() = 0;
virtual int
sendto(
__attribute__((unused)) const SockAddr& dst,
__attribute__((unused)) const void* data,
__attribute__((unused)) size_t sz)
{
return -1;
}
/// return false if we want to deregister and remove ourselves
virtual bool
tick()
{
return true;
}
/// used for tun interface and tcp conn
virtual ssize_t
do_write(void* data, size_t sz)
{
return write(fd, data, sz);
}
bool
queue_write(const byte_t* buf, size_t sz)
{
if (m_LossyWriteQueue)
{
m_LossyWriteQueue->Emplace(buf, sz);
return true;
}
if (m_BlockingWriteQueue)
{
m_BlockingWriteQueue->emplace_back(buf, sz);
return true;
}
return false;
}
running() const = 0;
virtual void
flush_write()
{
flush_write_buffers(0);
}
virtual void
before_flush_write()
update_time()
{}
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual llarp_time_t
time_now() const
{
return llarp::time_now_ms();
}
virtual void
flush_write_buffers(size_t amount)
{
before_flush_write();
if (m_LossyWriteQueue)
{
m_LossyWriteQueue->Process([&](WriteBuffer& buffer) {
do_write(buffer.buf, buffer.bufsz);
// if we would block we save the entries for later
// discard entry
});
}
else if (m_BlockingWriteQueue)
{
if (amount)
{
while (amount && m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, std::min(amount, itr.bufsz));
if (result <= 0)
return;
ssize_t dlt = itr.bufsz - result;
if (dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
amount -= result;
}
}
else
{
// write buffers
while (m_BlockingWriteQueue->size())
{
auto& itr = m_BlockingWriteQueue->front();
ssize_t result = do_write(itr.buf, itr.bufsz);
if (result <= 0)
{
errno = 0;
return;
}
ssize_t dlt = itr.bufsz - result;
if (dlt > 0)
{
// queue remaining to front of queue
WriteBuffer buff(itr.buf + dlt, itr.bufsz - dlt);
m_BlockingWriteQueue->pop_front();
m_BlockingWriteQueue->push_front(buff);
// TODO: errno?
return;
}
m_BlockingWriteQueue->pop_front();
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
errno = 0;
return;
}
}
}
}
/// reset errno
errno = 0;
}
stopped(){};
std::unique_ptr<LossyWriteQueue_t> m_LossyWriteQueue;
std::unique_ptr<LosslessWriteQueue_t> m_BlockingWriteQueue;
virtual uint32_t
call_after_delay(llarp_time_t delay_ms, std::function<void(void)> callback) = 0;
virtual ~posix_ev_io()
{
close(fd);
}
virtual void
cancel_delayed_call(uint32_t call_id) = 0;
virtual bool
add_network_interface(
std::shared_ptr<vpn::NetworkInterface> netif,
std::function<void(net::IPPacket)> packetHandler) = 0;
virtual bool
add_ticker(std::function<void(void)> ticker) = 0;
virtual void
stop() = 0;
virtual bool
udp_listen(llarp_udp_io* l, const llarp::SockAddr& src) = 0;
virtual bool
udp_close(llarp_udp_io* l) = 0;
/// give this event loop a logic thread for calling
virtual void set_logic(std::shared_ptr<llarp::Logic>) = 0;
virtual ~EventLoop() = default;
virtual void
call_soon(std::function<void(void)> f) = 0;
/// set the function that is called once per cycle the flush all the queues
virtual void
set_pump_function(std::function<void(void)> pumpll) = 0;
virtual void
register_poll_fd_readable(int fd, std::function<void(void)> callback) = 0;
virtual void
deregister_poll_fd_readable(int fd) = 0;
};
#endif
// finally create aliases by platform
#ifdef _WIN32
using ev_io = win32_ev_io;
#else
using ev_io = posix_ev_io;
#endif
// wew, managed to get away with using
// 'int fd' across all platforms
// since we're operating entirely
// on sockets
struct tcp_conn : public ev_io
{
bool _shouldClose = false;
bool _calledConnected = false;
llarp_tcp_conn tcp;
// null if inbound otherwise outbound
llarp_tcp_connecter* _conn;
static void
DoClose(llarp_tcp_conn* conn)
{
static_cast<tcp_conn*>(conn->impl)->_shouldClose = true;
}
/// inbound
tcp_conn(llarp_ev_loop* loop, int _fd) : ev_io(_fd, new LosslessWriteQueue_t{}), _conn(nullptr)
{
tcp.impl = this;
tcp.loop = loop;
tcp.closed = nullptr;
tcp.user = nullptr;
tcp.read = nullptr;
tcp.tick = nullptr;
tcp.close = &DoClose;
}
/// outbound
tcp_conn(llarp_ev_loop* loop, int _fd, const SockAddr& addr, llarp_tcp_connecter* conn)
: ev_io(_fd, new LosslessWriteQueue_t{}), _conn(conn)
{
(void)addr;
tcp.impl = this;
tcp.loop = loop;
tcp.closed = nullptr;
tcp.user = nullptr;
tcp.read = nullptr;
tcp.tick = nullptr;
tcp.close = &DoClose;
}
~tcp_conn() override = default;
/// start connecting
void
connect();
/// calls connected hooks
void
connected()
{
sockaddr_storage st;
socklen_t sl;
if (getpeername(fd, (sockaddr*)&st, &sl) == 0)
{
// we are connected yeh boi
if (_conn)
{
if (_conn->connected && !_calledConnected)
_conn->connected(_conn, &tcp);
}
_calledConnected = true;
}
else
{
error();
}
}
void
flush_write() override;
void
flush_write_buffers(size_t a) override
{
connected();
ev_io::flush_write_buffers(a);
}
void
error() override
{
_shouldClose = true;
if (_conn)
{
#ifndef _WIN32
llarp::LogError("tcp_conn error: ", strerror(errno));
#else
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL, ebuf, 1024, nullptr);
llarp::LogError("tcp_conn error: ", ebuf);
#endif
if (_conn->error)
_conn->error(_conn);
}
errno = 0;
}
ssize_t
do_write(void* buf, size_t sz) override;
int
read(byte_t* buf, size_t sz) override;
bool
tick() override;
};
struct tcp_serv : public ev_io
{
llarp_ev_loop* loop;
llarp_tcp_acceptor* tcp;
tcp_serv(llarp_ev_loop* l, int _fd, llarp_tcp_acceptor* t) : ev_io(_fd), loop(l), tcp(t)
{
tcp->impl = this;
}
bool
tick() override
{
if (tcp->tick)
tcp->tick(tcp);
return true;
}
/// actually does accept() :^)
int
read(byte_t*, size_t) override;
};
} // namespace llarp
#ifdef _WIN32
struct llarp_fd_promise
{
void Set(std::pair<int, int>)
{}
int
Get()
{
return -1;
}
};
#else
struct llarp_fd_promise
{
using promise_val_t = std::pair<int, int>;
llarp_fd_promise(std::promise<promise_val_t>* p) : _impl(p)
{}
std::promise<promise_val_t>* _impl;
void
Set(promise_val_t fds)
{
_impl->set_value(fds);
}
promise_val_t
Get()
{
auto future = _impl->get_future();
future.wait();
return future.get();
}
};
#endif
// this (nearly!) abstract base class
// is overriden for each platform
struct llarp_ev_loop
{
byte_t readbuf[EV_READ_BUF_SZ] = {0};
virtual bool
init() = 0;
virtual int
run() = 0;
virtual bool
running() const = 0;
virtual void
update_time()
{}
virtual llarp_time_t
time_now() const
{
return llarp::time_now_ms();
}
virtual void
stopped(){};
/// return false on socket error (non blocking)
virtual bool
tcp_connect(llarp_tcp_connecter* tcp, const llarp::SockAddr& addr) = 0;
virtual int
tick(int ms) = 0;
virtual uint32_t
call_after_delay(llarp_time_t delay_ms, std::function<void(void)> callback) = 0;
virtual void
cancel_delayed_call(uint32_t call_id) = 0;
virtual bool
add_ticker(std::function<void(void)> ticker) = 0;
virtual void
stop() = 0;
virtual bool
udp_listen(llarp_udp_io* l, const llarp::SockAddr& src) = 0;
virtual bool
udp_close(llarp_udp_io* l) = 0;
/// deregister event listener
virtual bool
close_ev(llarp::ev_io* ev) = 0;
virtual bool
tun_listen(llarp_tun_io* tun)
{
auto dev = create_tun(tun);
tun->impl = dev;
if (dev)
{
return add_ev(dev, false);
}
return false;
}
virtual llarp::ev_io*
create_tun(llarp_tun_io* tun) = 0;
virtual llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const llarp::SockAddr& addr) = 0;
virtual bool
add_pipe(llarp_ev_pkt_pipe*)
{
return false;
}
/// give this event loop a logic thread for calling
virtual void set_logic(std::shared_ptr<llarp::Logic>) = 0;
/// register event listener
virtual bool
add_ev(llarp::ev_io* ev, bool write) = 0;
virtual bool
tcp_listen(llarp_tcp_acceptor* tcp, const llarp::SockAddr& addr)
{
auto conn = bind_tcp(tcp, addr);
return conn && add_ev(conn, true);
}
virtual ~llarp_ev_loop() = default;
std::list<std::unique_ptr<llarp::ev_io>> handlers;
virtual void
tick_listeners()
{
auto itr = handlers.begin();
while (itr != handlers.end())
{
if ((*itr)->tick())
++itr;
else
{
close_ev(itr->get());
itr = handlers.erase(itr);
}
}
}
virtual void
call_soon(std::function<void(void)> f) = 0;
virtual void
register_poll_fd_readable(int fd, std::function<void(void)> callback) = 0;
virtual void
deregister_poll_fd_readable(int fd) = 0;
};
#endif

View File

@ -1,4 +1,5 @@
#include <ev/ev_libuv.hpp>
#include <ev/vpn.hpp>
#include <util/thread/logic.hpp>
#include <util/thread/queue.hpp>
@ -19,347 +20,6 @@ namespace libuv
Close() = 0;
};
/// tcp connection glue between llarp and libuv
struct conn_glue : public glue
{
using WriteBuffer_t = std::vector<char>;
struct WriteEvent
{
WriteBuffer_t data;
uv_write_t request;
WriteEvent() = default;
explicit WriteEvent(size_t sz, char* ptr)
{
request.data = this;
data.resize(sz);
std::copy_n(ptr, sz, data.begin());
}
uv_buf_t
Buffer()
{
return uv_buf_init(data.data(), data.size());
}
uv_write_t*
Request()
{
return &request;
}
};
uv_tcp_t m_Handle;
uv_connect_t m_Connect;
uv_check_t m_Ticker;
llarp_tcp_connecter* const m_TCP;
llarp_tcp_acceptor* const m_Accept;
llarp_tcp_conn m_Conn;
llarp::SockAddr m_Addr;
conn_glue(uv_loop_t* loop, llarp_tcp_connecter* tcp, const llarp::SockAddr& addr)
: m_TCP(tcp), m_Accept(nullptr), m_Addr(addr)
{
m_Connect.data = this;
m_Handle.data = this;
m_TCP->impl = this;
uv_tcp_init(loop, &m_Handle);
m_Ticker.data = this;
uv_check_init(loop, &m_Ticker);
m_Conn.close = &ExplicitClose;
m_Conn.write = &ExplicitWrite;
}
conn_glue(uv_loop_t* loop, llarp_tcp_acceptor* tcp, const llarp::SockAddr& addr)
: m_TCP(nullptr), m_Accept(tcp), m_Addr(addr)
{
m_Connect.data = nullptr;
m_Handle.data = this;
uv_tcp_init(loop, &m_Handle);
m_Ticker.data = this;
uv_check_init(loop, &m_Ticker);
m_Accept->close = &ExplicitCloseAccept;
m_Conn.write = nullptr;
m_Conn.closed = nullptr;
m_Conn.tick = nullptr;
}
conn_glue(conn_glue* parent) : m_TCP(nullptr), m_Accept(nullptr)
{
m_Connect.data = nullptr;
m_Conn.close = &ExplicitClose;
m_Conn.write = &ExplicitWrite;
m_Handle.data = this;
uv_tcp_init(parent->m_Handle.loop, &m_Handle);
m_Ticker.data = this;
uv_check_init(parent->m_Handle.loop, &m_Ticker);
}
static void
OnOutboundConnect(uv_connect_t* c, int status)
{
conn_glue* self = static_cast<conn_glue*>(c->data);
self->HandleConnectResult(status);
c->data = nullptr;
}
bool
ConnectAsync()
{
return uv_tcp_connect(&m_Connect, &m_Handle, m_Addr, &OnOutboundConnect) != -1;
}
static void
ExplicitClose(llarp_tcp_conn* conn)
{
static_cast<conn_glue*>(conn->impl)->Close();
}
static void
ExplicitCloseAccept(llarp_tcp_acceptor* tcp)
{
static_cast<conn_glue*>(tcp->impl)->Close();
}
static ssize_t
ExplicitWrite(llarp_tcp_conn* conn, const byte_t* ptr, size_t sz)
{
return static_cast<conn_glue*>(conn->impl)->WriteAsync((char*)ptr, sz);
}
static void
OnRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
{
if (nread >= 0)
{
auto* conn = static_cast<conn_glue*>(stream->data);
conn->Read(buf->base, nread);
}
else if (nread < 0)
{
static_cast<conn_glue*>(stream->data)->Close();
}
delete[] buf->base;
}
static void
Alloc(uv_handle_t*, size_t suggested_size, uv_buf_t* buf)
{
buf->base = new char[suggested_size];
buf->len = suggested_size;
}
void
Read(const char* ptr, ssize_t sz)
{
if (m_Conn.read)
{
llarp::LogDebug("tcp read ", sz, " bytes");
const llarp_buffer_t buf(ptr, sz);
m_Conn.read(&m_Conn, buf);
}
}
void
HandleConnectResult(int status)
{
if (m_TCP && m_TCP->connected)
{
if (status == 0)
{
m_Conn.impl = this;
m_Conn.loop = m_TCP->loop;
m_Conn.close = &ExplicitClose;
m_Conn.write = &ExplicitWrite;
m_TCP->connected(m_TCP, &m_Conn);
Start();
}
else if (m_TCP->error)
{
llarp::LogError("failed to connect tcp ", uv_strerror(status));
m_TCP->error(m_TCP);
}
}
}
void
WriteFail()
{
if (m_Conn.close)
m_Conn.close(&m_Conn);
}
uv_stream_t*
Stream()
{
return (uv_stream_t*)&m_Handle;
}
static void
OnWritten(uv_write_t* req, int status)
{
WriteEvent* ev = static_cast<WriteEvent*>(req->data);
if (status == 0)
{
llarp::LogDebug("wrote ", ev->data.size());
}
else
{
llarp::LogDebug("write fail");
}
delete ev;
}
int
WriteAsync(char* data, size_t sz)
{
if (uv_is_closing((const uv_handle_t*)&m_Handle))
return -1;
WriteEvent* ev = new WriteEvent(sz, data);
auto buf = ev->Buffer();
if (uv_write(ev->Request(), Stream(), &buf, 1, &OnWritten) == 0)
return sz;
delete ev;
return -1;
}
static void
OnClosed(uv_handle_t* h)
{
conn_glue* conn = static_cast<conn_glue*>(h->data);
conn->HandleClosed();
}
static void
FullClose(uv_handle_t* h)
{
auto* self = static_cast<conn_glue*>(h->data);
h->data = nullptr;
delete self;
llarp::LogDebug("deleted");
}
void
HandleClosed()
{
m_Handle.data = nullptr;
if (m_Accept)
{
if (m_Accept->closed)
m_Accept->closed(m_Accept);
m_Accept->impl = nullptr;
}
if (m_Conn.closed)
{
m_Conn.closed(&m_Conn);
}
m_Conn.impl = nullptr;
llarp::LogDebug("closed");
uv_close((uv_handle_t*)&m_Ticker, &FullClose);
}
static void
OnShutdown(uv_shutdown_t* shut, int code)
{
llarp::LogDebug("shut down ", code);
auto* self = static_cast<conn_glue*>(shut->data);
uv_close((uv_handle_t*)&self->m_Handle, &OnClosed);
delete shut;
}
void
Close() override
{
if (uv_is_closing((uv_handle_t*)Stream()))
return;
llarp::LogDebug("close tcp connection");
uv_check_stop(&m_Ticker);
uv_read_stop(Stream());
auto* shut = new uv_shutdown_t();
shut->data = this;
uv_shutdown(shut, Stream(), &OnShutdown);
}
static void
OnAccept(uv_stream_t* stream, int status)
{
if (status == 0)
{
conn_glue* conn = static_cast<conn_glue*>(stream->data);
conn->Accept();
}
else
{
llarp::LogError("tcp accept failed: ", uv_strerror(status));
}
}
static void
OnTick(uv_check_t* t)
{
llarp::LogTrace("conn_glue::OnTick() start");
conn_glue* conn = static_cast<conn_glue*>(t->data);
conn->Tick();
llarp::LogTrace("conn_glue::OnTick() end");
}
void
Tick()
{
if (m_Accept && m_Accept->tick)
{
m_Accept->tick(m_Accept);
}
if (m_Conn.tick)
{
m_Conn.tick(&m_Conn);
}
}
void
Start()
{
auto result = uv_check_start(&m_Ticker, &OnTick);
if (result)
llarp::LogError("failed to start timer ", uv_strerror(result));
result = uv_read_start(Stream(), &Alloc, &OnRead);
if (result)
llarp::LogError("failed to start reader ", uv_strerror(result));
}
void
Accept()
{
if (m_Accept && m_Accept->accepted)
{
auto* child = new conn_glue(this);
llarp::LogDebug("accepted new connection");
child->m_Conn.impl = child;
child->m_Conn.loop = m_Accept->loop;
child->m_Conn.close = &ExplicitClose;
child->m_Conn.write = &ExplicitWrite;
auto res = uv_accept(Stream(), child->Stream());
if (res)
{
llarp::LogError("failed to accept tcp connection ", uv_strerror(res));
child->Close();
return;
}
m_Accept->accepted(m_Accept, &child->m_Conn);
child->Start();
}
}
bool
Server()
{
uv_check_start(&m_Ticker, &OnTick);
m_Accept->close = &ExplicitCloseAccept;
return uv_tcp_bind(&m_Handle, m_Addr, 0) == 0 && uv_listen(Stream(), 5, &OnAccept) == 0;
}
};
struct ticker_glue : public glue
{
std::function<void(void)> func;
@ -376,8 +36,8 @@ namespace libuv
llarp::LogTrace("ticker_glue::OnTick() start");
ticker_glue* ticker = static_cast<ticker_glue*>(t->data);
ticker->func();
Loop* loop = static_cast<Loop*>(t->loop->data);
loop->FlushLogic();
// Loop* loop = static_cast<Loop*>(t->loop->data);
// loop->FlushLogic();
llarp::LogTrace("ticker_glue::OnTick() end");
}
@ -473,14 +133,9 @@ namespace libuv
auto* self = static_cast<udp_glue*>(udp->impl);
if (self == nullptr)
return -1;
auto buf = uv_buf_init((char*)ptr, sz);
auto ret = uv_udp_try_send(
const auto buf = uv_buf_init((char*)ptr, sz);
return uv_udp_try_send(
&self->m_Handle, &buf, 1, (const sockaddr*)static_cast<const sockaddr_in*>(to));
if (ret < 0)
{
llarp::LogError("udp sendto failed: ", uv_strerror(ret));
}
return ret;
}
bool
@ -533,109 +188,28 @@ namespace libuv
}
};
struct pipe_glue : public glue
struct tun_glue : public glue
{
byte_t m_Buffer[1024 * 8];
llarp_ev_pkt_pipe* const m_Pipe;
pipe_glue(uv_loop_t* loop, llarp_ev_pkt_pipe* pipe) : m_Pipe(pipe)
uv_poll_t m_Handle;
uv_check_t m_Ticker;
std::shared_ptr<llarp::vpn::NetworkInterface> m_NetIf;
std::function<void(llarp::net::IPPacket)> m_Handler;
tun_glue(
std::shared_ptr<llarp::vpn::NetworkInterface> netif,
std::function<void(llarp::net::IPPacket)> handler)
: m_NetIf{std::move(netif)}, m_Handler{std::move(handler)}
{
m_Handle.data = this;
m_Ticker.data = this;
uv_poll_init(loop, &m_Handle, m_Pipe->fd);
uv_check_init(loop, &m_Ticker);
}
void
Tick()
{
LoopCall(&m_Handle, std::bind(&llarp_ev_pkt_pipe::tick, m_Pipe));
}
static void
OnRead(uv_poll_t* handle, int status, int)
{
if (status)
{
return;
}
pipe_glue* glue = static_cast<pipe_glue*>(handle->data);
int r = glue->m_Pipe->read(glue->m_Buffer, sizeof(glue->m_Buffer));
if (r <= 0)
return;
const llarp_buffer_t buf{glue->m_Buffer, static_cast<size_t>(r)};
glue->m_Pipe->OnRead(buf);
}
static void
OnClosed(uv_handle_t* h)
{
auto* self = static_cast<pipe_glue*>(h->data);
if (self)
{
h->data = nullptr;
delete self;
}
}
void
Close() override
{
uv_check_stop(&m_Ticker);
uv_close((uv_handle_t*)&m_Handle, &OnClosed);
}
static void
OnTick(uv_check_t* h)
{
llarp::LogTrace("pipe_glue::OnTick() start");
pipe_glue* pipe = static_cast<pipe_glue*>(h->data);
LoopCall(h, std::bind(&pipe_glue::Tick, pipe));
llarp::LogTrace("pipe_glue::OnTick() end");
}
bool
Start()
{
if (uv_poll_start(&m_Handle, UV_READABLE, &OnRead))
return false;
if (uv_check_start(&m_Ticker, &OnTick))
return false;
return true;
}
uv_poll_t m_Handle;
uv_check_t m_Ticker;
};
#if defined(_WIN32) || defined(_WIN64)
#else
struct tun_glue : public glue
{
uv_poll_t m_Handle;
uv_check_t m_Ticker;
llarp_tun_io* const m_Tun;
device* const m_Device;
byte_t m_Buffer[1500];
bool readpkt;
tun_glue(llarp_tun_io* tun) : m_Tun(tun), m_Device(tuntap_init())
{
m_Handle.data = this;
m_Ticker.data = this;
readpkt = false;
}
~tun_glue() override
{
tuntap_destroy(m_Device);
}
static void
OnTick(uv_check_t* timer)
{
llarp::LogTrace("tun_glue::OnTick() start");
tun_glue* tun = static_cast<tun_glue*>(timer->data);
tun->Tick();
llarp::LogTrace("tun_glue::OnTick() end");
auto self = static_cast<tun_glue*>(h->data);
while (self->m_NetIf->HasNextPacket())
self->Read();
}
static void
@ -650,23 +224,10 @@ namespace libuv
void
Read()
{
auto sz = tuntap_read(m_Device, m_Buffer, sizeof(m_Buffer));
if (sz > 0)
{
llarp::LogDebug("tun read ", sz);
const llarp_buffer_t pkt(m_Buffer, sz);
if (m_Tun && m_Tun->recvpkt)
m_Tun->recvpkt(m_Tun, pkt);
}
}
void
Tick()
{
if (m_Tun->before_write)
m_Tun->before_write(m_Tun);
if (m_Tun->tick)
m_Tun->tick(m_Tun);
auto pkt = m_NetIf->ReadNextPacket();
LogDebug("got packet ", pkt.sz);
if (m_Handler)
m_Handler(std::move(pkt));
}
static void
@ -683,80 +244,38 @@ namespace libuv
void
Close() override
{
if (m_Tun->impl == nullptr)
return;
m_Tun->impl = nullptr;
uv_check_stop(&m_Ticker);
uv_close((uv_handle_t*)&m_Ticker, [](uv_handle_t* h) {
tun_glue* glue = static_cast<tun_glue*>(h->data);
uv_close((uv_handle_t*)&glue->m_Handle, &OnClosed);
});
}
bool
Write(const byte_t* pkt, size_t sz)
{
return tuntap_write(m_Device, (void*)pkt, sz) != -1;
}
static bool
WritePkt(llarp_tun_io* tun, const byte_t* pkt, size_t sz)
{
tun_glue* glue = static_cast<tun_glue*>(tun->impl);
return glue && glue->Write(pkt, sz);
#ifndef _WIN32
uv_close((uv_handle_t*)&m_Handle, &OnClosed);
#endif
}
bool
Init(uv_loop_t* loop)
{
memcpy(m_Device->if_name, m_Tun->ifname, sizeof(m_Device->if_name));
if (tuntap_start(m_Device, TUNTAP_MODE_TUNNEL, 0) == -1)
if (uv_check_init(loop, &m_Ticker) == -1)
{
llarp::LogError("failed to start up ", m_Tun->ifname);
return false;
}
// copy back
memcpy(m_Tun->ifname, m_Device->if_name, sizeof(m_Tun->ifname));
if (tuntap_set_ip(m_Device, m_Tun->ifaddr, m_Tun->ifaddr, m_Tun->netmask) == -1)
if (uv_check_start(&m_Ticker, &OnTick) == -1)
{
llarp::LogError("failed to set address on ", m_Tun->ifname);
return false;
}
if (tuntap_up(m_Device) == -1)
#ifndef _WIN32
if (uv_poll_init(loop, &m_Handle, m_NetIf->PollFD()) == -1)
{
llarp::LogError("failed to put up ", m_Tun->ifname);
return false;
}
if (m_Device->tun_fd == -1)
{
llarp::LogError("tun interface ", m_Tun->ifname, " has invalid fd: ", m_Device->tun_fd);
return false;
}
tuntap_set_nonblocking(m_Device, 1);
if (uv_poll_init(loop, &m_Handle, m_Device->tun_fd) == -1)
{
llarp::LogError("failed to start polling on ", m_Tun->ifname);
llarp::LogError("failed to initialize polling on ", m_NetIf->IfName());
return false;
}
if (uv_poll_start(&m_Handle, UV_READABLE, &OnPoll))
{
llarp::LogError("failed to start polling on ", m_Tun->ifname);
llarp::LogError("failed to start polling on ", m_NetIf->IfName());
return false;
}
if (uv_check_init(loop, &m_Ticker) != 0 || uv_check_start(&m_Ticker, &OnTick) != 0)
{
llarp::LogError("failed to set up tun interface timer for ", m_Tun->ifname);
return false;
}
m_Tun->writepkt = &WritePkt;
m_Tun->impl = this;
#endif
return true;
}
};
#endif
void
Loop::FlushLogic()
@ -779,13 +298,20 @@ namespace libuv
loop->process_timer_queue();
loop->process_cancel_queue();
loop->FlushLogic();
loop->PumpLL();
auto& log = llarp::LogContext::Instance();
if (log.logStream)
log.logStream->Tick(loop->time_now());
}
constexpr size_t TimeQueueSize = 20;
Loop::Loop(size_t queue_size)
: llarp_ev_loop(), m_LogicCalls(queue_size), m_timerQueue(20), m_timerCancelQueue(20)
: llarp::EventLoop{}
, PumpLL{[]() {}}
, m_LogicCalls{queue_size}
, m_timerQueue{TimerQueueSize}
, m_timerCancelQueue{TimerQueueSize}
{}
bool
@ -818,7 +344,7 @@ namespace libuv
void
Loop::update_time()
{
llarp_ev_loop::update_time();
llarp::EventLoop::update_time();
uv_update_time(&m_Impl);
}
@ -828,18 +354,6 @@ namespace libuv
return m_Run.load();
}
bool
Loop::tcp_connect(llarp_tcp_connecter* tcp, const llarp::SockAddr& addr)
{
auto* impl = new conn_glue(&m_Impl, tcp, addr);
tcp->impl = impl;
if (impl->ConnectAsync())
return true;
delete impl;
tcp->impl = nullptr;
return false;
}
static void
OnTickTimeout(uv_timer_t* timer)
{
@ -854,18 +368,10 @@ namespace libuv
return uv_run(&m_Impl, UV_RUN_DEFAULT);
}
int
Loop::tick(int ms)
void
Loop::set_pump_function(std::function<void(void)> pump)
{
if (m_Run)
{
#ifdef TESTNET_SPEED
ms *= TESTNET_SPEED;
#endif
uv_timer_start(m_TickTimer, &OnTickTimeout, ms, 0);
uv_run(&m_Impl, UV_RUN_ONCE);
}
return 0;
PumpLL = std::move(pump);
}
struct TimerData
@ -1025,6 +531,19 @@ namespace libuv
return false;
}
bool
Loop::add_network_interface(
std::shared_ptr<llarp::vpn::NetworkInterface> netif,
std::function<void(llarp::net::IPPacket)> handler)
{
auto* glue = new tun_glue(netif, handler);
// call to Init gives ownership of glue to event loop
if (glue->Init(&m_Impl))
return true;
delete glue;
return false;
}
bool
Loop::udp_close(llarp_udp_io* udp)
{
@ -1037,46 +556,6 @@ namespace libuv
return true;
}
bool
Loop::tun_listen(llarp_tun_io* tun)
{
#if defined(_WIN32) || defined(_WIN64)
(void)tun;
return false;
#else
auto* glue = new tun_glue(tun);
tun->impl = glue;
if (glue->Init(&m_Impl))
{
return true;
}
delete glue;
return false;
#endif
}
bool
Loop::tcp_listen(llarp_tcp_acceptor* tcp, const llarp::SockAddr& addr)
{
auto* glue = new conn_glue(&m_Impl, tcp, addr);
tcp->impl = glue;
if (glue->Server())
return true;
tcp->impl = nullptr;
delete glue;
return false;
}
bool
Loop::add_pipe(llarp_ev_pkt_pipe* p)
{
auto* glue = new pipe_glue(&m_Impl, p);
if (glue->Start())
return true;
delete glue;
return false;
}
void
Loop::call_soon(std::function<void(void)> f)
{

View File

@ -1,7 +1,6 @@
#ifndef LLARP_EV_LIBUV_HPP
#define LLARP_EV_LIBUV_HPP
#include <ev/ev.hpp>
#include <ev/pipe.hpp>
#include <uv.h>
#include <vector>
#include <functional>
@ -13,7 +12,7 @@
namespace libuv
{
struct Loop final : public llarp_ev_loop
struct Loop final : public llarp::EventLoop
{
typedef std::function<void(void)> Callback;
@ -38,13 +37,6 @@ namespace libuv
void
update_time() override;
/// return false on socket error (non blocking)
bool
tcp_connect(llarp_tcp_connecter* tcp, const llarp::SockAddr& addr) override;
int
tick(int ms) override;
uint32_t
call_after_delay(llarp_time_t delay_ms, std::function<void(void)> callback) override;
@ -75,43 +67,13 @@ namespace libuv
bool
udp_close(llarp_udp_io* l) override;
/// deregister event listener
bool
close_ev(llarp::ev_io*) override
{
return true;
}
bool
tun_listen(llarp_tun_io* tun) override;
llarp::ev_io*
create_tun(llarp_tun_io*) override
{
return nullptr;
}
bool
tcp_listen(llarp_tcp_acceptor* tcp, const llarp::SockAddr& addr) override;
bool
add_pipe(llarp_ev_pkt_pipe* p) override;
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor*, const llarp::SockAddr&) override
{
return nullptr;
}
bool
add_ticker(std::function<void(void)> ticker) override;
/// register event listener
bool
add_ev(llarp::ev_io*, bool) override
{
return false;
}
add_network_interface(
std::shared_ptr<llarp::vpn::NetworkInterface> netif,
std::function<void(llarp::net::IPPacket)> handler) override;
void
set_logic(std::shared_ptr<llarp::Logic> l) override
@ -131,9 +93,14 @@ namespace libuv
void
deregister_poll_fd_readable(int fd) override;
void
set_pump_function(std::function<void(void)> pumpll) override;
void
FlushLogic();
std::function<void(void)> PumpLL;
private:
uv_loop_t m_Impl;
uv_timer_t* m_TickTimer;

View File

@ -1,226 +0,0 @@
#include <ev/ev_win32.hpp>
#ifdef _WIN32
#include <util/logging/logger.hpp>
#include <atomic>
// a single event queue for the TUN interface
static HANDLE tun_event_queue = INVALID_HANDLE_VALUE;
// we hand the kernel our thread handles to process completion events
static HANDLE* kThreadPool;
static int poolSize;
// list of TUN listeners (useful for exits or other nodes with multiple TUNs)
std::list<win32_tun_io*> tun_listeners;
void
begin_tun_loop(int nThreads, llarp_ev_loop* loop)
{
kThreadPool = new HANDLE[nThreads];
for (int i = 0; i < nThreads; ++i)
{
kThreadPool[i] = CreateThread(nullptr, 0, &tun_ev_loop, loop, 0, nullptr);
}
llarp::LogInfo("created ", nThreads, " threads for TUN event queue");
poolSize = nThreads;
}
// this one is called from the TUN handler
bool
win32_tun_io::queue_write(const byte_t* buf, size_t sz)
{
return do_write((void*)buf, sz);
}
bool
win32_tun_io::setup()
{
if (tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
return false;
}
if (tuntap_up(tunif) == -1)
{
char ebuf[1024];
int err = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL, ebuf, 1024, nullptr);
llarp::LogWarn("failed to put interface up: ", ebuf);
return false;
}
tunif->bindaddr = t->dnsaddr;
if (tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
{
llarp::LogWarn("failed to set ip");
return false;
}
if (tunif->tun_fd == INVALID_HANDLE_VALUE)
return false;
return true;
}
// first TUN device gets to set up the event port
bool
win32_tun_io::add_ev(llarp_ev_loop* loop)
{
if (tun_event_queue == INVALID_HANDLE_VALUE)
{
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
unsigned long numCPU = sys_info.dwNumberOfProcessors;
// let the system handle 2x the number of CPUs or hardware
// threads
tun_event_queue = CreateIoCompletionPort(tunif->tun_fd, nullptr, (ULONG_PTR)this, numCPU * 2);
begin_tun_loop(numCPU * 2, loop);
}
else
CreateIoCompletionPort(tunif->tun_fd, tun_event_queue, (ULONG_PTR)this, 0);
// we're already non-blocking
// add to list
tun_listeners.push_back(this);
byte_t* readbuf = (byte_t*)malloc(1500);
read(readbuf, 1500);
return true;
}
// places data in event queue for kernel to process
bool
win32_tun_io::do_write(void* data, size_t sz)
{
DWORD code;
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->buf = data;
pkt->sz = sz;
pkt->write = true;
memset(&pkt->pkt, '\0', sizeof(pkt->pkt));
WriteFile(tunif->tun_fd, data, sz, nullptr, &pkt->pkt);
code = GetLastError();
// llarp::LogInfo("wrote data, error ", code);
return (code == 0 || code == 997);
}
// while this one is called from the event loop
// eventually comes back and calls queue_write()
void
win32_tun_io::flush_write()
{
if (t->before_write)
t->before_write(t);
}
void
win32_tun_io::read(byte_t* buf, size_t sz)
{
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->buf = buf;
memset(&pkt->pkt, '\0', sizeof(OVERLAPPED));
pkt->sz = sz;
pkt->write = false;
ReadFile(tunif->tun_fd, buf, sz, nullptr, &pkt->pkt);
}
// and now the event loop itself
extern "C" DWORD FAR PASCAL
tun_ev_loop(void* u)
{
llarp_ev_loop* logic = static_cast<llarp_ev_loop*>(u);
DWORD size = 0;
OVERLAPPED* ovl = nullptr;
ULONG_PTR listener = 0;
asio_evt_pkt* pkt = nullptr;
BOOL alert;
std::atomic_flag tick_queued;
while (true)
{
alert = GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, EV_TICK_INTERVAL);
if (!alert)
{
// tick listeners on io timeout, this is required to be done every tick
// cycle regardless of any io being done, this manages the internal state
// of the tun logic
if (tick_queued.test_and_set())
continue; // if tick queued, don't queue another
logic->call_soon([&]() {
for (const auto& tun : tun_listeners)
{
tun->flush_write();
if (tun->t->tick)
tun->t->tick(tun->t);
}
tick_queued.clear();
});
continue;
}
if (listener == (ULONG_PTR)~0)
break;
// if we're here, then we got something interesting :>
pkt = (asio_evt_pkt*)ovl;
win32_tun_io* ev = reinterpret_cast<win32_tun_io*>(listener);
if (!pkt->write)
{
// llarp::LogInfo("read tun ", size, " bytes, pass to handler");
logic->call_soon([pkt, size, ev]() {
if (ev->t->recvpkt)
ev->t->recvpkt(ev->t, llarp_buffer_t(pkt->buf, size));
free(pkt->buf);
delete pkt;
});
byte_t* readbuf = (byte_t*)malloc(1500);
ev->read(readbuf, 1500);
}
logic->call_soon([ev]() {
ev->flush_write();
if (ev->t->tick)
ev->t->tick(ev->t);
});
}
llarp::LogDebug("exit TUN event loop thread from system managed thread pool");
return 0;
}
void
exit_tun_loop()
{
if (kThreadPool)
{
// kill the kernel's thread pool
// int i = (&kThreadPool)[1] - kThreadPool; // get the size of our thread
// pool
llarp::LogInfo("closing ", poolSize, " threads");
// if we get all-ones in the queue, thread exits, and we clean up
for (int j = 0; j < poolSize; ++j)
PostQueuedCompletionStatus(tun_event_queue, 0, ~0, nullptr);
WaitForMultipleObjects(poolSize, kThreadPool, TRUE, INFINITE);
for (int j = 0; j < poolSize; ++j)
CloseHandle(kThreadPool[j]);
delete[] kThreadPool;
kThreadPool = nullptr;
// the IOCP refcount is decreased each time an associated fd
// is closed
// the fds are closed in their destructors
// once we get to zero, we can safely close the event port
auto itr = tun_listeners.begin();
while (itr != tun_listeners.end())
{
delete (*itr);
itr = tun_listeners.erase(itr);
}
CloseHandle(tun_event_queue);
}
}
#endif

View File

@ -1,97 +0,0 @@
#ifndef EV_WIN32_H
#define EV_WIN32_H
#ifdef _WIN32
#include <ev/ev.hpp>
#include <net/net.h>
#include <net/net.hpp>
#include <util/buffer.hpp>
#include <util/thread/logic.hpp>
#include <windows.h>
#include <process.h>
#include <cstdio>
// io packet for TUN read/write
struct asio_evt_pkt
{
OVERLAPPED pkt = {0, 0, 0, 0, nullptr}; // must be first, since this is part of the IO call
bool write = false; // true, or false if read pkt
size_t sz; // should match the queued data size, if not try again?
void* buf; // must remain valid until we get notification; this is _supposed_
// to be zero-copy
};
extern "C" DWORD FAR PASCAL
tun_ev_loop(void* unused);
void
exit_tun_loop();
void
begin_tun_loop(int nThreads);
namespace llarp
{
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
udp_listener(int fd, llarp_udp_io* u) : ev_io(fd), udp(u){};
~udp_listener()
{}
bool
tick();
int
read(byte_t* buf, size_t sz);
int
sendto(const sockaddr* to, const void* data, size_t sz);
};
} // namespace llarp
// A different kind of event loop,
// more suited for the native Windows NT
// event model
struct win32_tun_io
{
llarp_tun_io* t;
device* tunif;
win32_tun_io(llarp_tun_io* tio) : t(tio), tunif(tuntap_init()){};
bool
queue_write(const byte_t* buf, size_t sz);
bool
setup();
// first TUN device gets to set up the event port
bool
add_ev(llarp_ev_loop* l);
// places data in event queue for kernel to process
bool
do_write(void* data, size_t sz);
// we call this one when we get a packet in the event port
// which then kicks off another write
void
flush_write();
void
read(byte_t* buf, size_t sz);
~win32_tun_io()
{
CancelIo(tunif->tun_fd);
if (tunif->tun_fd)
tuntap_destroy(tunif);
}
};
#endif
#endif

View File

@ -1,66 +0,0 @@
#include <ev/pipe.hpp>
#include <utility>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <fcntl.h>
llarp_ev_pkt_pipe::llarp_ev_pkt_pipe(llarp_ev_loop_ptr loop)
: llarp::ev_io(-1, new LosslessWriteQueue_t()), m_Loop(std::move(loop))
{}
bool
llarp_ev_pkt_pipe::StartPipe()
{
#if defined(_WIN32)
llarp::LogError("llarp_ev_pkt_pipe not supported on win32");
return false;
#else
int _fds[2];
if (pipe(_fds) == -1 && fcntl(_fds[0], F_SETFL, fcntl(_fds[0], F_GETFL) | O_NONBLOCK))
{
return false;
}
fd = _fds[0];
writefd = _fds[1];
return m_Loop->add_pipe(this);
#endif
}
int
llarp_ev_pkt_pipe::read(byte_t* pkt, size_t sz)
{
auto res = ::read(fd, pkt, sz);
if (res <= 0)
return res;
llarp::LogDebug("read ", res, " on pipe");
llarp_buffer_t buf(pkt, res);
OnRead(buf);
return res;
}
ssize_t
llarp_ev_pkt_pipe::do_write(void* buf, size_t sz)
{
return ::write(writefd, buf, sz);
}
bool
llarp_ev_pkt_pipe::Write(const llarp_buffer_t& pkt)
{
const ssize_t sz = pkt.sz;
if (do_write(pkt.base, pkt.sz) != sz)
{
llarp::LogDebug("queue write ", pkt.sz);
return queue_write(pkt.base, pkt.sz);
}
return true;
}
bool
llarp_ev_pkt_pipe::tick()
{
llarp::ev_io::flush_write();
return true;
}

View File

@ -1,39 +0,0 @@
#ifndef LLARP_EV_PIPE_HPP
#define LLARP_EV_PIPE_HPP
#include <ev/ev.hpp>
/// a unidirectional packet pipe
struct llarp_ev_pkt_pipe : public llarp::ev_io
{
llarp_ev_pkt_pipe(llarp_ev_loop_ptr loop);
/// start the pipe, initialize fds
bool
StartPipe();
/// write to the pipe from outside the event loop
/// returns true on success
/// returns false on failure
bool
Write(const llarp_buffer_t& buf);
/// override me to handle a packet from the other side in the owned event loop
virtual void
OnRead(const llarp_buffer_t& buf) = 0;
ssize_t
do_write(void* buf, size_t sz) override;
bool
tick() override;
int
read(byte_t* buf, size_t sz) override;
private:
llarp_ev_loop_ptr m_Loop;
int writefd;
};
#endif

87
llarp/ev/vpn.hpp Normal file
View File

@ -0,0 +1,87 @@
#pragma once
#include <net/ip_range.hpp>
#include <net/ip_packet.hpp>
#include <set>
namespace llarp
{
struct Context;
}
namespace llarp::vpn
{
struct InterfaceAddress
{
constexpr InterfaceAddress(IPRange r, int f = AF_INET) : range{std::move(r)}, fam{f}
{}
IPRange range;
int fam;
bool
operator<(const InterfaceAddress& other) const
{
return range < other.range or fam < other.fam;
}
};
struct InterfaceInfo
{
std::string ifname;
huint32_t dnsaddr;
std::set<InterfaceAddress> addrs;
};
/// a vpn network interface
class NetworkInterface
{
public:
NetworkInterface() = default;
NetworkInterface(const NetworkInterface&) = delete;
NetworkInterface(NetworkInterface&&) = delete;
virtual ~NetworkInterface() = default;
/// get pollable fd for reading
virtual int
PollFD() const = 0;
/// the interface's name
virtual std::string
IfName() const = 0;
/// read next ip packet
/// blocks until ready
virtual net::IPPacket
ReadNextPacket() = 0;
/// return true if we have another packet to read
virtual bool
HasNextPacket() = 0;
/// write a packet to the interface
/// returns false if we dropped it
virtual bool
WritePacket(net::IPPacket pkt) = 0;
};
/// a vpn platform
/// responsible for obtaining vpn interfaces
class Platform
{
public:
Platform() = default;
Platform(const Platform&) = delete;
Platform(Platform&&) = delete;
virtual ~Platform() = default;
/// get a new network interface fully configured given the interface info
/// blocks until ready, throws on error
virtual std::shared_ptr<NetworkInterface>
ObtainInterface(InterfaceInfo info) = 0;
};
/// create native vpn platform
std::unique_ptr<Platform>
MakeNativePlatform(llarp::Context* ctx);
} // namespace llarp::vpn

View File

@ -188,7 +188,7 @@ namespace llarp
// flush upstream queue
while (m_UpstreamQueue.size())
{
m_Parent->QueueOutboundTraffic(m_UpstreamQueue.top().pkt.ConstBuffer());
m_Parent->QueueOutboundTraffic(m_UpstreamQueue.top().pkt);
m_UpstreamQueue.pop();
}
// flush downstream queue

View File

@ -13,49 +13,15 @@ namespace llarp
{
namespace handlers
{
static void
ExitHandlerRecvPkt(llarp_tun_io* tun, const llarp_buffer_t& buf)
{
std::vector<byte_t> pkt;
pkt.resize(buf.sz);
std::copy_n(buf.base, buf.sz, pkt.data());
auto self = static_cast<ExitEndpoint*>(tun->user);
LogicCall(self->GetRouter()->logic(), [self, pktbuf = std::move(pkt)]() {
self->OnInetPacket(std::move(pktbuf));
});
}
static void
ExitHandlerFlush(llarp_tun_io* tun)
{
auto* ep = static_cast<ExitEndpoint*>(tun->user);
ep->Flush();
}
ExitEndpoint::ExitEndpoint(const std::string& name, AbstractRouter* r)
: m_Router(r)
, m_Resolver(std::make_shared<dns::Proxy>(
r->netloop(), r->logic(), r->netloop(), r->logic(), this))
, m_Name(name)
, m_Tun{{0},
0,
0,
{0},
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr}
, m_LocalResolverAddr("127.0.0.1", 53)
, m_InetToNetwork(name + "_exit_rx", r->netloop(), r->netloop())
{
m_Tun.user = this;
m_Tun.recvpkt = &ExitHandlerRecvPkt;
m_Tun.tick = &ExitHandlerFlush;
m_ShouldInitTun = true;
}
@ -337,12 +303,26 @@ namespace llarp
m_SNodeKeys.insert(us);
if (m_ShouldInitTun)
{
vpn::InterfaceInfo info;
info.ifname = m_ifname;
info.addrs.emplace(m_OurRange);
m_NetIf = GetRouter()->GetVPNPlatform()->ObtainInterface(std::move(info));
if (not m_NetIf)
{
llarp::LogError("Could not create interface");
return false;
}
auto loop = GetRouter()->netloop();
if (!llarp_ev_add_tun(loop.get(), &m_Tun))
if (not loop->add_network_interface(
m_NetIf, [&](net::IPPacket pkt) { OnInetPacket(std::move(pkt)); }))
{
llarp::LogWarn("Could not create tunnel for exit endpoint");
return false;
}
loop->add_ticker([&]() { Flush(); });
llarp::LogInfo("Trying to start resolver ", m_LocalResolverAddr.toString());
return m_Resolver->Start(m_LocalResolverAddr, m_UpstreamResolvers);
}
@ -444,9 +424,9 @@ namespace llarp
}
bool
ExitEndpoint::QueueOutboundTraffic(const llarp_buffer_t& buf)
ExitEndpoint::QueueOutboundTraffic(net::IPPacket pkt)
{
return llarp_ev_tun_async_write(&m_Tun, buf);
return m_NetIf && m_NetIf->WritePacket(std::move(pkt));
}
void
@ -469,11 +449,9 @@ namespace llarp
}
void
ExitEndpoint::OnInetPacket(std::vector<byte_t> buf)
ExitEndpoint::OnInetPacket(net::IPPacket pkt)
{
const llarp_buffer_t buffer(buf);
m_InetToNetwork.EmplaceIf(
[b = ManagedBuffer(buffer)](Pkt_t& pkt) -> bool { return pkt.Load(b); });
m_InetToNetwork.Emplace(std::move(pkt));
}
bool
@ -487,7 +465,7 @@ namespace llarp
pkt.UpdateIPv6Address(from, m_IfAddr);
else
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(from)), xhtonl(net::TruncateV6(m_IfAddr)));
return llarp_ev_tun_async_write(&m_Tun, pkt.Buffer());
return m_NetIf and m_NetIf->WritePacket(std::move(pkt));
}
exit::Endpoint*
@ -560,37 +538,20 @@ namespace llarp
}
const auto host_str = m_OurRange.BaseAddressString();
// string, or just a plain char array?
strncpy(m_Tun.ifaddr, host_str.c_str(), sizeof(m_Tun.ifaddr) - 1);
m_Tun.netmask = m_OurRange.HostmaskBits();
m_IfAddr = m_OurRange.addr;
m_NextAddr = m_IfAddr;
m_HigestAddr = m_OurRange.HighestAddr();
LogInfo(
Name(),
" set ifaddr range to ",
m_Tun.ifaddr,
"/",
m_Tun.netmask,
" lo=",
m_IfAddr,
" hi=",
m_HigestAddr);
m_UseV6 = not m_OurRange.IsV4();
std::string ifname = networkConfig.m_ifname;
if (ifname.empty())
m_ifname = networkConfig.m_ifname;
if (m_ifname.empty())
{
const auto maybe = llarp::FindFreeTun();
if (not maybe.has_value())
throw std::runtime_error("cannot find free interface name");
ifname = *maybe;
m_ifname = *maybe;
}
if (ifname.length() >= sizeof(m_Tun.ifname))
{
throw std::invalid_argument(stringify(Name() + " ifname '", ifname, "' is too long"));
}
strncpy(m_Tun.ifname, ifname.c_str(), sizeof(m_Tun.ifname) - 1);
LogInfo(Name(), " set ifname to ", m_Tun.ifname);
LogInfo(Name(), " set ifname to ", m_ifname);
// TODO: "exit-whitelist" and "exit-blacklist"
// (which weren't originally implemented)

View File

@ -54,7 +54,7 @@ namespace llarp
/// handle ip packet from outside
void
OnInetPacket(std::vector<byte_t> buf);
OnInetPacket(net::IPPacket buf);
AbstractRouter*
GetRouter();
@ -84,7 +84,7 @@ namespace llarp
RemoveExit(const exit::Endpoint* ep);
bool
QueueOutboundTraffic(const llarp_buffer_t& buf);
QueueOutboundTraffic(net::IPPacket pkt);
/// sets up networking and starts traffic
bool
@ -161,10 +161,11 @@ namespace llarp
huint128_t m_NextAddr;
IPRange m_OurRange;
std::string m_ifname;
std::unordered_map<huint128_t, llarp_time_t> m_IPActivity;
llarp_tun_io m_Tun;
std::shared_ptr<vpn::NetworkInterface> m_NetIf;
IpAddress m_LocalResolverAddr;
std::vector<IpAddress> m_UpstreamResolvers;

View File

@ -30,17 +30,6 @@ namespace llarp
{
namespace handlers
{
void
TunEndpoint::FlushToUser(std::function<bool(const net::IPPacket&)> send)
{
// flush network to user
while (not m_NetworkToUserPktQueue.empty())
{
send(m_NetworkToUserPktQueue.top().pkt);
m_NetworkToUserPktQueue.pop();
}
}
bool
TunEndpoint::ShouldFlushNow(llarp_time_t now) const
{
@ -48,44 +37,19 @@ namespace llarp
return now >= m_LastFlushAt + FlushInterval;
}
void
TunEndpoint::tunifTick(llarp_tun_io* tun)
{
llarp::LogTrace("TunEndpoint::tunifTick()");
auto* self = static_cast<TunEndpoint*>(tun->user);
self->Flush();
}
TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent, bool lazyVPN)
TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent)
: service::Endpoint(r, parent)
, m_UserToNetworkPktQueue("endpoint_sendq", r->netloop(), r->netloop())
, m_Resolver(std::make_shared<dns::Proxy>(
r->netloop(), r->logic(), r->netloop(), r->logic(), this))
{
if (not lazyVPN)
{
tunif.reset(new llarp_tun_io());
std::fill(tunif->ifaddr, tunif->ifaddr + sizeof(tunif->ifaddr), 0);
std::fill(tunif->ifname, tunif->ifname + sizeof(tunif->ifname), 0);
tunif->netmask = 0;
tunif->get_fd_promise = nullptr;
tunif->user = this;
// eh this shouldn't do anything on windows anyway
tunif->tick = &tunifTick;
tunif->before_write = &tunifBeforeWrite;
tunif->recvpkt = &tunifRecvPkt;
}
}
{}
util::StatusObject
TunEndpoint::ExtractStatus() const
{
auto obj = service::Endpoint::ExtractStatus();
obj["ifaddr"] = m_OurRange.ToString();
if (tunif)
{
obj["ifname"] = tunif->ifname;
}
obj["ifname"] = m_IfName;
std::vector<std::string> resolvers;
for (const auto& addr : m_UpstreamResolvers)
resolvers.emplace_back(addr.toString());
@ -199,42 +163,27 @@ namespace llarp
return false;
}
std::string ifname = conf.m_ifname;
if (ifname.empty())
m_IfName = conf.m_ifname;
if (m_IfName.empty())
{
const auto maybe = llarp::FindFreeTun();
if (not maybe.has_value())
throw std::runtime_error("cannot find free interface name");
ifname = *maybe;
m_IfName = *maybe;
}
if (tunif)
m_OurRange = conf.m_ifaddr;
if (!m_OurRange.addr.h)
{
if (ifname.length() >= sizeof(tunif->ifname))
const auto maybe = llarp::FindFreeRange();
if (not maybe.has_value())
{
llarp::LogError(Name() + " ifname '", ifname, "' is too long");
return false;
throw std::runtime_error("cannot find free address range");
}
strncpy(tunif->ifname, ifname.c_str(), sizeof(tunif->ifname) - 1);
llarp::LogInfo(Name() + " setting ifname to ", tunif->ifname);
m_OurRange = conf.m_ifaddr;
if (!m_OurRange.addr.h)
{
const auto maybe = llarp::FindFreeRange();
if (not maybe.has_value())
{
throw std::runtime_error("cannot find free address range");
}
m_OurRange = *maybe;
}
m_UseV6 = not m_OurRange.IsV4();
tunif->netmask = m_OurRange.HostmaskBits();
const auto addr = m_OurRange.BaseAddressString();
llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ", tunif->netmask);
strncpy(tunif->ifaddr, addr.c_str(), sizeof(tunif->ifaddr) - 1);
m_OurRange = *maybe;
}
m_OurIP = m_OurRange.addr;
m_UseV6 = not m_OurRange.IsV4();
return Endpoint::Configure(conf, dnsConf);
}
@ -249,6 +198,12 @@ namespace llarp
{
FlushSend();
Pump(Now());
// flush network to user
while (not m_NetworkToUserPktQueue.empty())
{
m_NetIf->WritePacket(m_NetworkToUserPktQueue.top().pkt);
m_NetworkToUserPktQueue.pop();
}
}
static bool
@ -713,8 +668,6 @@ namespace llarp
#ifdef _WIN32
return net::TruncateV6(GetIfAddr()).ToString();
#else
if (tunif)
return tunif->ifname;
return m_IfName;
#endif
}
@ -740,122 +693,9 @@ namespace llarp
bool
TunEndpoint::SetupTun()
{
lazy_vpn vpn;
huint32_t ip;
auto loop = EndpointNetLoop();
if (tunif == nullptr)
{
llarp::LogInfo(Name(), " waiting for vpn to start");
vpn = m_LazyVPNPromise.get_future().get();
vpnif = vpn.io;
if (vpnif == nullptr)
{
llarp::LogError(Name(), " failed to recieve vpn interface");
return false;
}
llarp::LogInfo(Name(), " got vpn interface");
auto self = shared_from_this();
// function to queue a packet to send to vpn interface
auto sendpkt = [self](const net::IPPacket& pkt) -> bool {
// drop if no endpoint
auto impl = self->GetVPNImpl();
// drop if no vpn interface
if (impl == nullptr)
return true;
// drop if queue to vpn not enabled
if (not impl->reader.queue.enabled())
return true;
// drop if queue to vpn full
if (impl->reader.queue.full())
return true;
// queue to reader
impl->reader.queue.pushBack(pkt);
return false;
};
// event loop ticker
auto ticker = [self, sendpkt]() {
llarp::LogTrace("TunEndpoint ticker() start");
TunEndpoint* ep = self.get();
const bool running = not ep->IsStopped();
auto impl = ep->GetVPNImpl();
if (impl)
{
/// get packets from vpn
while (not impl->writer.queue.empty())
{
// queue it to be sent over lokinet
auto pkt = impl->writer.queue.popFront();
if (running)
ep->m_UserToNetworkPktQueue.Emplace(pkt);
}
}
// process packets queued from vpn
if (running)
{
ep->Flush();
ep->FlushToUser(sendpkt);
}
// if impl has a tick function call it
if (impl && impl->parent && impl->parent->tick)
impl->parent->tick(impl->parent);
llarp::LogTrace("TunEndpoint ticker() end");
};
if (not loop->add_ticker(ticker))
{
llarp::LogError(Name(), " failed to add vpn to event loop");
if (vpnif->injected)
vpnif->injected(vpnif, false);
return false;
}
}
else
{
if (!llarp_ev_add_tun(loop.get(), tunif.get()))
{
llarp::LogError(
Name(), " failed to set up tun interface: ", tunif->ifaddr, " on ", tunif->ifname);
return false;
}
}
const char* ifname;
const char* ifaddr;
unsigned char netmask;
if (tunif)
{
ifname = tunif->ifname;
ifaddr = tunif->ifaddr;
netmask = tunif->netmask;
}
else
{
ifname = vpn.info.ifname;
ifaddr = vpn.info.ifaddr;
netmask = vpn.info.netmask;
}
m_IfName = ifname;
if (ip.FromString(ifaddr))
{
m_OurIP = net::ExpandV4(ip);
m_OurRange.netmask_bits = netmask_ipv6_bits(netmask + 96);
}
else if (m_OurIP.FromString(ifaddr))
{
m_OurRange.netmask_bits = netmask_ipv6_bits(netmask);
m_UseV6 = true;
}
else
{
LogError(Name(), " invalid interface address given, ifaddr=", ifaddr);
if (vpnif && vpnif->injected)
vpnif->injected(vpnif, false);
return false;
}
m_NextIP = m_OurIP;
m_OurRange.addr = m_OurIP;
m_MaxIP = m_OurRange.HighestAddr();
llarp::LogInfo(Name(), " set ", ifname, " to have address ", m_OurIP);
llarp::LogInfo(Name(), " set ", m_IfName, " to have address ", m_OurIP);
llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", m_OurRange);
const service::Address ourAddr = m_Identity.pub.Addr();
@ -865,15 +705,43 @@ namespace llarp
return false;
}
vpn::InterfaceInfo info;
info.addrs.emplace(m_OurRange);
info.ifname = m_IfName;
info.dnsaddr.FromString(m_LocalResolverAddr.toHost());
LogInfo(Name(), " setting up network...");
try
{
m_NetIf = Router()->GetVPNPlatform()->ObtainInterface(std::move(info));
}
catch (std::exception& ex)
{
LogError(Name(), " failed to set up network interface: ", ex.what());
}
if (not m_NetIf)
{
LogError(Name(), " failed to obtain network interface");
return false;
}
m_IfName = m_NetIf->IfName();
LogInfo(Name(), " got network interface ", m_IfName);
auto netloop = Router()->netloop();
if (not netloop->add_network_interface(
m_NetIf, [&](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); }))
{
LogError(Name(), " failed to add network interface");
return false;
}
netloop->add_ticker([&]() { Flush(); });
if (m_OnUp)
{
m_OnUp->NotifyAsync(NotifyParams());
}
if (vpnif && vpnif->injected)
{
vpnif->injected(vpnif, true);
}
return HasAddress(ourAddr);
}
@ -883,8 +751,7 @@ namespace llarp
auto env = Endpoint::NotifyParams();
env.emplace("IP_ADDR", m_OurIP.ToString());
env.emplace("IF_ADDR", m_OurRange.ToString());
if (tunif)
env.emplace("IF_NAME", tunif->ifname);
env.emplace("IF_NAME", m_IfName);
std::string strictConnect;
for (const auto& addr : m_StrictConnectAddrs)
strictConnect += addr.toString() + " ";
@ -940,6 +807,26 @@ namespace llarp
dst = pkt.dstv6();
src = pkt.srcv6();
}
// this is for ipv6 slaac on ipv6 exits
/*
constexpr huint128_t ipv6_multicast_all_nodes =
huint128_t{uint128_t{0xff01'0000'0000'0000UL, 1UL}};
constexpr huint128_t ipv6_multicast_all_routers =
huint128_t{uint128_t{0xff01'0000'0000'0000UL, 2UL}};
if (dst == ipv6_multicast_all_nodes and m_state->m_ExitEnabled)
{
// send ipv6 multicast
for (const auto& [ip, addr] : m_IPToAddr)
{
(void)ip;
SendToServiceOrQueue(
service::Address{addr.as_array()}, pkt.ConstBuffer(), service::eProtocolExit);
}
return;
}
*/
auto itr = m_IPToAddr.find(dst);
if (itr == m_IPToAddr.end())
{
@ -956,7 +843,8 @@ namespace llarp
else
{
const auto addr = *exits.begin();
pkt.ZeroSourceAddress();
if (pkt.IsV4())
pkt.ZeroSourceAddress();
MarkAddressOutbound(addr);
EnsurePathToService(
addr,
@ -971,6 +859,7 @@ namespace llarp
}
return;
}
bool rewriteAddrs = true;
if (m_SNodes.at(itr->second))
{
sendFunc = std::bind(
@ -979,8 +868,9 @@ namespace llarp
itr->second.as_array(),
std::placeholders::_1);
}
else if (m_state->m_ExitEnabled)
else if (m_state->m_ExitEnabled and src != m_OurIP)
{
rewriteAddrs = false;
sendFunc = std::bind(
&TunEndpoint::SendToServiceOrQueue,
this,
@ -999,7 +889,7 @@ namespace llarp
}
// prepare packet for insertion into network
// this includes clearing IP addresses, recalculating checksums, etc
if (not m_state->m_ExitEnabled)
if (rewriteAddrs)
{
if (pkt.IsV4())
pkt.UpdateIPv4Address({0}, {0});
@ -1034,23 +924,37 @@ namespace llarp
net::IPPacket pkt;
if (not pkt.Load(buf))
return false;
if (m_state->m_ExitEnabled)
{
// exit side from exit
src = ObtainIPForAddr(addr, snode);
if (pkt.IsV4())
dst = pkt.dst4to6();
else if (pkt.IsV6())
dst = pkt.dstv6();
if (t == service::eProtocolExit)
{
if (pkt.IsV4())
dst = pkt.dst4to6Lan();
else if (pkt.IsV6())
dst = pkt.dstv6();
}
else
{
// non exit traffic on exit
dst = m_OurIP;
}
}
else if (t == service::eProtocolExit)
{
// client side exit traffic from exit
if (pkt.IsV4())
{
dst = m_OurIP;
src = pkt.src4to6();
}
else if (pkt.IsV6())
{
dst = pkt.dstv6();
src = pkt.srcv6();
dst = m_OurIP;
}
// find what exit we think this should be for
const auto mapped = m_ExitMap.FindAll(src);
if (mapped.count(service::Address{addr}) == 0 or IsBogon(src))
@ -1182,32 +1086,9 @@ namespace llarp
}
void
TunEndpoint::TickTun(__attribute__((unused)) llarp_time_t now)
TunEndpoint::HandleGotUserPacket(net::IPPacket pkt)
{
// called in the isolated thread
}
void
TunEndpoint::tunifBeforeWrite(llarp_tun_io* tun)
{
// called in the isolated network thread
auto* self = static_cast<TunEndpoint*>(tun->user);
self->Flush();
self->FlushToUser([self, tun](const net::IPPacket& pkt) -> bool {
if (not llarp_ev_tun_async_write(tun, pkt.ConstBuffer()))
{
llarp::LogWarn(self->Name(), " packet dropped");
}
return false;
});
} // namespace handlers
void
TunEndpoint::tunifRecvPkt(llarp_tun_io* tun, const llarp_buffer_t& b)
{
// called for every packet read from user in isolated network thread
auto* self = static_cast<TunEndpoint*>(tun->user);
self->m_UserToNetworkPktQueue.EmplaceIf([&](net::IPPacket& pkt) { return pkt.Load(b); });
m_UserToNetworkPktQueue.Emplace(std::move(pkt));
}
TunEndpoint::~TunEndpoint() = default;

View File

@ -2,8 +2,8 @@
#define LLARP_HANDLERS_TUN_HPP
#include <dns/server.hpp>
#include <ev/ev.h>
#include <ev/vpnio.hpp>
#include <ev/ev.hpp>
#include <ev/vpn.hpp>
#include <net/ip.hpp>
#include <net/ip_packet.hpp>
#include <net/net.hpp>
@ -22,7 +22,7 @@ namespace llarp
public dns::IQueryHandler,
public std::enable_shared_from_this<TunEndpoint>
{
TunEndpoint(AbstractRouter* r, llarp::service::Context* parent, bool lazyVPN = false);
TunEndpoint(AbstractRouter* r, llarp::service::Context* parent);
~TunEndpoint() override;
path::PathSet_ptr
@ -62,9 +62,6 @@ namespace llarp
void
TickTun(llarp_time_t now);
static void
tunifTick(llarp_tun_io*);
bool
MapAddress(const service::Address& remote, huint128_t ip, bool SNode);
@ -102,6 +99,10 @@ namespace llarp
bool
QueueOutboundTraffic(llarp::net::IPPacket&& pkt);
/// we got a packet from the user
void
HandleGotUserPacket(llarp::net::IPPacket pkt);
/// get the local interface's address
huint128_t
GetIfAddr() const override;
@ -116,35 +117,6 @@ namespace llarp
bool
HasLocalIP(const huint128_t& ip) const;
std::unique_ptr<llarp_tun_io> tunif;
llarp_vpn_io* vpnif = nullptr;
bool
InjectVPN(llarp_vpn_io* io, llarp_vpn_ifaddr_info info) override
{
if (tunif)
return false;
m_LazyVPNPromise.set_value(lazy_vpn{info, io});
return true;
}
/// called before writing to tun interface
static void
tunifBeforeWrite(llarp_tun_io* t);
/// handle user to network send buffer flush
/// called in router logic thread
static void
handleNetSend(void*);
/// called every time we wish to read a packet from the tun interface
static void
tunifRecvPkt(llarp_tun_io* t, const llarp_buffer_t& buf);
/// called in the endpoint logic thread
static void
handleTickTun(void* u);
/// get a key for ip address
template <typename Addr_t>
Addr_t
@ -236,14 +208,6 @@ namespace llarp
std::unordered_map<AlignedBuffer<32>, bool, AlignedBuffer<32>::Hash> m_SNodes;
private:
llarp_vpn_io_impl*
GetVPNImpl()
{
if (vpnif && vpnif->impl)
return static_cast<llarp_vpn_io_impl*>(vpnif->impl);
return nullptr;
}
template <typename Addr_t, typename Endpoint_t>
void
SendDNSReply(
@ -285,19 +249,9 @@ namespace llarp
std::vector<IpAddress> m_StrictConnectAddrs;
/// use v6?
bool m_UseV6;
struct lazy_vpn
{
llarp_vpn_ifaddr_info info;
llarp_vpn_io* io;
};
std::promise<lazy_vpn> m_LazyVPNPromise;
std::string m_IfName;
/// send packets on endpoint to user using send function
/// send function returns true to indicate stop iteration and do codel
/// drop
void
FlushToUser(std::function<bool(const net::IPPacket&)> sendfunc);
std::shared_ptr<vpn::NetworkInterface> m_NetIf;
};
} // namespace handlers

View File

@ -162,7 +162,7 @@ namespace llarp
}
}
m_ourAddr.setPort(port);
return llarp_ev_add_udp(m_Loop.get(), &m_udp, m_ourAddr.createSockAddr()) != -1;
return llarp_ev_add_udp(m_Loop, &m_udp, m_ourAddr.createSockAddr()) != -1;
}
void

View File

@ -16,6 +16,12 @@ namespace llarp::net
return huint128_t{0x0000'ffff'0000'0000UL} | huint128_t{x.h};
}
constexpr huint128_t
ExpandV4Lan(huint32_t x)
{
return huint128_t{uint128_t{0xfe80'0000'0000'0000UL, 0UL}} | huint128_t{x.h};
}
constexpr huint32_t
TruncateV6(huint128_t x)
{

View File

@ -112,6 +112,18 @@ namespace llarp
return ExpandV4(srcv4());
}
huint128_t
IPPacket::dst4to6Lan() const
{
return ExpandV4Lan(dstv4());
}
huint128_t
IPPacket::src4to6Lan() const
{
return ExpandV4Lan(srcv4());
}
static uint16_t
ipchksum(const byte_t* buf, size_t sz, uint32_t sum = 0)
{
@ -462,7 +474,7 @@ namespace llarp
}
else if (IsV6())
{
UpdateIPv6Address({0}, {ntoh128(dstv6().h)}, flowlabel);
UpdateIPv6Address({0}, dstv6(), flowlabel);
}
}

View File

@ -254,6 +254,12 @@ namespace llarp
huint128_t
dst4to6() const;
huint128_t
src4to6Lan() const;
huint128_t
dst4to6Lan() const;
void
UpdateIPv4Address(nuint32_t src, nuint32_t dst);

View File

@ -83,6 +83,12 @@ namespace llarp
|| this->netmask_bits < other.netmask_bits;
}
bool
operator==(const IPRange& other) const
{
return addr == other.addr and netmask_bits == other.netmask_bits;
}
std::string
ToString() const
{
@ -97,3 +103,17 @@ namespace llarp
};
} // namespace llarp
namespace std
{
template <>
struct hash<llarp::IPRange>
{
size_t
operator()(const llarp::IPRange& range) const
{
const auto str = range.ToString();
return std::hash<std::string>{}(str);
}
};
} // namespace std

View File

@ -4,6 +4,13 @@
namespace llarp
{
template <>
nuint32_t
ToNet(huint32_t h)
{
return xhtonl(h);
}
template <>
void
huint32_t::ToV6(V6Container& c)

View File

@ -218,6 +218,15 @@ namespace llarp
{
return huint16_t{ntohs(x.n)};
}
template <typename UInt_t>
huint_t<UInt_t>
ToHost(nuint_t<UInt_t> h);
template <typename UInt_t>
nuint_t<UInt_t>
ToNet(huint_t<UInt_t> h);
} // namespace llarp
namespace std

View File

@ -39,44 +39,8 @@ namespace llarp::net
void
Execute(std::string cmd)
{
LogDebug(cmd);
#ifdef _WIN32
LogInfo(cmd);
system(cmd.c_str());
#else
std::vector<std::string> parts_str;
std::vector<const char*> parts_raw;
std::stringstream in(cmd);
for (std::string part; std::getline(in, part, ' ');)
{
if (part.empty())
continue;
parts_str.push_back(part);
}
for (const auto& part : parts_str)
{
parts_raw.push_back(part.c_str());
}
parts_raw.push_back(nullptr);
const auto pid = fork();
if (pid == -1)
{
throw std::runtime_error("failed to fork");
}
else if (pid == 0)
{
char* const* args = (char* const*)parts_raw.data();
const auto result = execv(parts_raw[0], args);
if (result)
{
std::cout << "failed: " << result << std::endl;
}
exit(result);
}
else
{
waitpid(pid, 0, 0);
}
#endif
}
#endif
@ -472,10 +436,6 @@ namespace llarp::net
return gateways;
#elif __APPLE__
LogDebug("get gateways not on ", ifname);
const auto maybe = GetIFAddr(ifname);
if (not maybe.has_value())
return gateways;
const auto interface = maybe->toString();
// mac os is so godawful man
FILE* p = popen("/usr/sbin/netstat -rn -f inet", "r");
if (p == nullptr)

View File

@ -75,6 +75,11 @@ namespace llarp
class ThreadPool;
}
namespace vpn
{
class Platform;
}
using LMQ_ptr = std::shared_ptr<lokimq::LokiMQ>;
struct AbstractRouter
@ -91,6 +96,9 @@ namespace llarp
virtual LMQ_ptr
lmq() const = 0;
virtual vpn::Platform*
GetVPNPlatform() const = 0;
virtual std::shared_ptr<rpc::LokidRpcClient>
RpcClient() const = 0;

View File

@ -9,25 +9,20 @@ namespace llarp
void
RoutePoker::AddRoute(huint32_t ip)
{
llarp::LogInfo(
"RoutePoker::AddRoute adding route to IP (",
ip.ToString(),
") via current gateway (",
m_CurrentGateway.ToString(),
")");
m_PokedRoutes.emplace(ip, m_CurrentGateway);
if (m_CurrentGateway.h == 0)
{
llarp::LogInfo("RoutePoker::AddRoute no current gateway, cannot enable route.");
llarp::LogDebug("RoutePoker::AddRoute no current gateway, cannot enable route.");
}
else if (m_Enabled or m_Enabling)
{
llarp::LogInfo("RoutePoker::AddRoute enabled, enabling route.");
llarp::LogInfo(
"RoutePoker::AddRoute enabled, enabling route to ", ip, " via ", m_CurrentGateway);
EnableRoute(ip, m_CurrentGateway);
}
else
{
llarp::LogInfo("RoutePoker::AddRoute disabled, not enabling route.");
llarp::LogDebug("RoutePoker::AddRoute disabled, not enabling route.");
}
}
@ -91,7 +86,10 @@ namespace llarp
RoutePoker::~RoutePoker()
{
for (const auto& [ip, gateway] : m_PokedRoutes)
net::DelRoute(ip.ToString(), gateway.ToString());
{
if (gateway.h)
net::DelRoute(ip.ToString(), gateway.ToString());
}
}
std::optional<huint32_t>
@ -102,9 +100,12 @@ namespace llarp
const auto ep = m_Router->hiddenServiceContext().GetDefault();
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
if (gateways.empty())
{
return std::nullopt;
}
huint32_t addr{};
if (not gateways.empty())
addr.FromString(gateways[0]);
addr.FromString(gateways[0]);
return addr;
}

View File

@ -46,11 +46,15 @@ static constexpr std::chrono::milliseconds ROUTER_TICK_INTERVAL = 1s;
namespace llarp
{
Router::Router(llarp_ev_loop_ptr __netloop, std::shared_ptr<Logic> l)
Router::Router(
llarp_ev_loop_ptr __netloop,
std::shared_ptr<Logic> l,
std::unique_ptr<vpn::Platform> vpnPlatform)
: ready(false)
, m_lmq(std::make_shared<lokimq::LokiMQ>())
, _netloop(std::move(__netloop))
, _logic(std::move(l))
, _vpnPlatform(std::move(vpnPlatform))
, paths(this)
, _exitContext(this)
, _dht(llarp_dht_context_new(this))
@ -1119,8 +1123,12 @@ namespace llarp
LogInfo("have ", _nodedb->num_loaded(), " routers");
#ifdef _WIN32
// windows uses proactor event loop so we need to constantly pump
_netloop->add_ticker(std::bind(&Router::PumpLL, this));
#else
_netloop->set_pump_function(std::bind(&Router::PumpLL, this));
#endif
ScheduleTicker(ROUTER_TICK_INTERVAL);
_running.store(true);
_startedAt = Now();

View File

@ -166,6 +166,12 @@ namespace llarp
return _netloop;
}
vpn::Platform*
GetVPNPlatform() const override
{
return _vpnPlatform.get();
}
void
QueueWork(std::function<void(void)> func) override;
@ -176,6 +182,7 @@ namespace llarp
llarp_ev_loop_ptr _netloop;
std::shared_ptr<Logic> _logic;
std::unique_ptr<vpn::Platform> _vpnPlatform;
path::PathContext paths;
exit::Context _exitContext;
SecretKey _identity;
@ -319,7 +326,10 @@ namespace llarp
void
GossipRCIfNeeded(const RouterContact rc) override;
explicit Router(llarp_ev_loop_ptr __netloop, std::shared_ptr<Logic> logic);
explicit Router(
llarp_ev_loop_ptr __netloop,
std::shared_ptr<Logic> logic,
std::unique_ptr<vpn::Platform> vpnPlatform);
virtual ~Router() override;

View File

@ -8,6 +8,7 @@
#include <service/context.hpp>
#include <service/auth.hpp>
#include <service/name.hpp>
#include <router/abstractrouter.hpp>
namespace llarp::rpc
{

View File

@ -20,15 +20,15 @@ namespace llarp
static EndpointConstructors endpointConstructors = {
{"tun",
[](AbstractRouter* r, service::Context* c) {
return std::make_shared<handlers::TunEndpoint>(r, c, false);
return std::make_shared<handlers::TunEndpoint>(r, c);
}},
{"android",
[](AbstractRouter* r, service::Context* c) {
return std::make_shared<handlers::TunEndpoint>(r, c, true);
return std::make_shared<handlers::TunEndpoint>(r, c);
}},
{"ios",
[](AbstractRouter* r, service::Context* c) {
return std::make_shared<handlers::TunEndpoint>(r, c, true);
return std::make_shared<handlers::TunEndpoint>(r, c);
}},
{"null", [](AbstractRouter* r, service::Context* c) {
return std::make_shared<handlers::NullEndpoint>(r, c);

View File

@ -17,8 +17,12 @@
#include <set>
#include <unordered_map>
struct llarp_ev_loop;
using llarp_ev_loop_ptr = std::shared_ptr<llarp_ev_loop>;
namespace llarp
{
struct EventLoop;
}
using llarp_ev_loop_ptr = std::shared_ptr<llarp::EventLoop>;
namespace llarp
{

View File

@ -10,7 +10,7 @@ namespace tooling
std::unique_ptr<llarp::AbstractRouter>
HiveContext::makeRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<llarp::Logic> logic)
{
return std::make_unique<HiveRouter>(netloop, logic, m_hive);
return std::make_unique<HiveRouter>(netloop, logic, makeVPNPlatform(), m_hive);
}
HiveRouter*

View File

@ -5,8 +5,11 @@
namespace tooling
{
HiveRouter::HiveRouter(
llarp_ev_loop_ptr netloop, std::shared_ptr<llarp::Logic> logic, RouterHive* hive)
: Router(netloop, logic), m_hive(hive)
llarp_ev_loop_ptr netloop,
std::shared_ptr<llarp::Logic> logic,
std::unique_ptr<llarp::vpn::Platform> plat,
RouterHive* hive)
: Router(netloop, logic, std::move(plat)), m_hive(hive)
{}
bool

View File

@ -10,7 +10,11 @@ namespace tooling
/// code.
struct HiveRouter : public llarp::Router
{
HiveRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<llarp::Logic> logic, RouterHive* hive);
explicit HiveRouter(
llarp_ev_loop_ptr netloop,
std::shared_ptr<llarp::Logic> logic,
std::unique_ptr<llarp::vpn::Platform> vpnPlatform,
RouterHive* hive);
virtual ~HiveRouter() = default;

View File

@ -56,7 +56,7 @@ namespace llarp
}
void
Logic::set_event_loop(llarp_ev_loop* loop)
Logic::set_event_loop(EventLoop* loop)
{
m_Loop = loop;
SetQueuer([loop](std::function<void(void)> work) { loop->call_soon(work); });

View File

@ -29,13 +29,13 @@ namespace llarp
SetQueuer(std::function<void(std::function<void(void)>)> q);
void
set_event_loop(llarp_ev_loop* loop);
set_event_loop(EventLoop* loop);
void
clear_event_loop();
private:
llarp_ev_loop* m_Loop = nullptr;
EventLoop* m_Loop = nullptr;
std::function<void(std::function<void(void)>)> m_Queue;
};
} // namespace llarp

176
llarp/vpn/apple.hpp Normal file
View File

@ -0,0 +1,176 @@
#pragma once
#include <ev/vpn.hpp>
#include <vpn/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;
}
bool
HasNextPacket() override
{
return false;
}
net::IPPacket
ReadNextPacket() override
{
net::IPPacket pkt{};
unsigned int pktinfo = 0;
const struct iovec vecs[2] = {{.iov_base = &pktinfo, .iov_len = sizeof(unsigned int)},
{.iov_base = pkt.buf, .iov_len = sizeof(pkt.buf)}};
int n = readv(m_FD, vecs, 2);
if (n >= (int)(sizeof(unsigned int)))
{
n -= sizeof(unsigned int);
pkt.sz = n;
}
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

32
llarp/vpn/common.hpp Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
namespace llarp::vpn
{
struct IOCTL
{
const int _fd;
explicit IOCTL(int af) : _fd{::socket(af, SOCK_DGRAM, IPPROTO_IP)}
{
if (_fd == -1)
throw std::invalid_argument{strerror(errno)};
};
~IOCTL()
{
::close(_fd);
}
template <typename Command, typename... Args>
void
ioctl(Command cmd, Args&&... args)
{
if (::ioctl(_fd, cmd, std::forward<Args>(args)...) == -1)
throw std::runtime_error("ioctl failed: " + std::string{strerror(errno)});
}
};
} // namespace llarp::vpn

129
llarp/vpn/linux.hpp Normal file
View File

@ -0,0 +1,129 @@
#pragma once
#include <ev/vpn.hpp>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <vpn/common.hpp>
#include <linux/if_tun.h>
namespace llarp::vpn
{
struct in6_ifreq
{
in6_addr addr;
uint32_t prefixlen;
unsigned int ifindex;
};
class LinuxInterface : public NetworkInterface
{
const int m_fd;
const InterfaceInfo m_Info;
public:
LinuxInterface(InterfaceInfo info)
: NetworkInterface{}, m_fd{::open("/dev/net/tun", O_RDWR)}, m_Info{std::move(info)}
{
if (m_fd == -1)
throw std::runtime_error("cannot open /dev/net/tun " + std::string{strerror(errno)});
ifreq ifr{};
in6_ifreq ifr6{};
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
std::copy_n(
m_Info.ifname.c_str(),
std::min(m_Info.ifname.size(), sizeof(ifr.ifr_name)),
ifr.ifr_name);
if (::ioctl(m_fd, TUNSETIFF, &ifr) == -1)
throw std::runtime_error("cannot set interface name: " + std::string{strerror(errno)});
IOCTL control{AF_INET};
control.ioctl(SIOCGIFFLAGS, &ifr);
const int flags = ifr.ifr_flags;
control.ioctl(SIOCGIFINDEX, &ifr);
const int ifindex = ifr.ifr_ifindex;
IOCTL control6{AF_INET6};
for (const auto& ifaddr : m_Info.addrs)
{
if (ifaddr.fam == AF_INET)
{
ifr.ifr_addr.sa_family = AF_INET;
const nuint32_t addr = ToNet(net::TruncateV6(ifaddr.range.addr));
((sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr = addr.n;
control.ioctl(SIOCSIFADDR, &ifr);
const nuint32_t mask = ToNet(net::TruncateV6(ifaddr.range.netmask_bits));
((sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr = mask.n;
control.ioctl(SIOCSIFNETMASK, &ifr);
}
if (ifaddr.fam == AF_INET6)
{
ifr6.addr = net::HUIntToIn6(ifaddr.range.addr);
ifr6.prefixlen = llarp::bits::count_bits(ifaddr.range.netmask_bits);
ifr6.ifindex = ifindex;
control6.ioctl(SIOCSIFADDR, &ifr6);
}
}
ifr.ifr_flags = flags | IFF_UP | IFF_NO_PI;
control.ioctl(SIOCSIFFLAGS, &ifr);
}
virtual ~LinuxInterface()
{
if (m_fd != -1)
::close(m_fd);
}
int
PollFD() const override
{
return m_fd;
}
net::IPPacket
ReadNextPacket() override
{
net::IPPacket pkt;
const auto sz = read(m_fd, pkt.buf, sizeof(pkt.buf));
if (sz >= 0)
pkt.sz = std::min(sz, ssize_t{sizeof(pkt.buf)});
return pkt;
}
bool
WritePacket(net::IPPacket pkt) override
{
const auto sz = write(m_fd, pkt.buf, pkt.sz);
if (sz <= 0)
return false;
return sz == static_cast<ssize_t>(pkt.sz);
}
bool
HasNextPacket() override
{
return false;
}
std::string
IfName() const override
{
return m_Info.ifname;
}
};
class LinuxPlatform : public Platform
{
public:
std::shared_ptr<NetworkInterface>
ObtainInterface(InterfaceInfo info) override
{
return std::make_shared<LinuxInterface>(std::move(info));
};
};
} // namespace llarp::vpn

38
llarp/vpn/platform.cpp Normal file
View File

@ -0,0 +1,38 @@
#ifdef _WIN32
#include <vpn/win32.hpp>
#endif
#ifdef __linux__
#ifdef ANDROID
#include <vpn/android.hpp>
#else
#include <vpn/linux.hpp>
#endif
#endif
#ifdef __APPLE__
#include <vpn/apple.hpp>
#endif
namespace llarp::vpn
{
std::unique_ptr<Platform>
MakeNativePlatform(llarp::Context* ctx)
{
(void)ctx;
std::unique_ptr<Platform> plat;
#ifdef _WIN32
plat = std::make_unique<vpn::Win32Platform>();
#endif
#ifdef __linux__
#ifdef ANDROID
plat = std::make_unique<vpn::AndroidPlatform>();
#else
plat = std::make_unique<vpn::LinuxPlatform>();
#endif
#endif
#ifdef __APPLE__
plat = std::make_unique<vpn::ApplePlatform>();
#endif
return plat;
}
} // namespace llarp::vpn

446
llarp/vpn/win32.hpp Normal file
View File

@ -0,0 +1,446 @@
#pragma once
#include <windows.h>
#include <iphlpapi.h>
#include <io.h>
#include <fcntl.h>
#include <util/thread/queue.hpp>
#include <ev/vpn.hpp>
// DDK macros
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define FILE_DEVICE_UNKNOWN 0x00000022
#define FILE_ANY_ACCESS 0x00000000
#define METHOD_BUFFERED 0
/* From OpenVPN tap driver, common.h */
#define TAP_CONTROL_CODE(request, method) \
CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE(2, METHOD_BUFFERED)
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE(3, METHOD_BUFFERED)
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE(4, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE(5, METHOD_BUFFERED)
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE(7, METHOD_BUFFERED)
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE(8, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE(9, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, METHOD_BUFFERED)
/* Windows registry crap */
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
#define NETWORK_ADAPTERS \
"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-" \
"08002BE10318}"
typedef unsigned long IPADDR;
namespace llarp::vpn
{
static char*
reg_query(char* key_name)
{
HKEY adapters, adapter;
DWORD i, ret, len;
char* deviceid = nullptr;
DWORD sub_keys = 0;
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key_name), 0, KEY_READ, &adapters);
if (ret != ERROR_SUCCESS)
{
return nullptr;
}
ret = RegQueryInfoKey(
adapters, NULL, NULL, NULL, &sub_keys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS)
{
return nullptr;
}
if (sub_keys <= 0)
{
return nullptr;
}
/* Walk througt all adapters */
for (i = 0; i < sub_keys; i++)
{
char new_key[MAX_KEY_LENGTH];
char data[256];
TCHAR key[MAX_KEY_LENGTH];
DWORD keylen = MAX_KEY_LENGTH;
/* Get the adapter key name */
ret = RegEnumKeyEx(adapters, i, key, &keylen, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS)
{
continue;
}
/* Append it to NETWORK_ADAPTERS and open it */
snprintf(new_key, sizeof new_key, "%s\\%s", key_name, key);
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(new_key), 0, KEY_READ, &adapter);
if (ret != ERROR_SUCCESS)
{
continue;
}
/* Check its values */
len = sizeof data;
ret = RegQueryValueEx(adapter, "ComponentId", NULL, NULL, (LPBYTE)data, &len);
if (ret != ERROR_SUCCESS)
{
/* This value doesn't exist in this adaptater tree */
goto clean;
}
/* If its a tap adapter, its all good */
if (strncmp(data, "tap0901", 7) == 0)
{
DWORD type;
len = sizeof data;
ret = RegQueryValueEx(adapter, "NetCfgInstanceId", NULL, &type, (LPBYTE)data, &len);
if (ret != ERROR_SUCCESS)
{
goto clean;
}
deviceid = strdup(data);
break;
}
clean:
RegCloseKey(adapter);
}
RegCloseKey(adapters);
return deviceid;
}
class Win32Interface : public NetworkInterface
{
std::atomic<bool> m_Run;
HANDLE m_Device, m_IOCP;
std::vector<HANDLE> m_Threads;
thread::Queue<net::IPPacket> m_ReadQueue;
const InterfaceInfo m_Info;
static std::wstring
get_win_sys_path()
{
wchar_t win_sys_path[MAX_PATH] = {0};
const wchar_t* default_sys_path = L"C:\\Windows\\system32";
if (!GetSystemDirectoryW(win_sys_path, _countof(win_sys_path)))
{
wcsncpy(win_sys_path, default_sys_path, _countof(win_sys_path));
win_sys_path[_countof(win_sys_path) - 1] = L'\0';
}
return win_sys_path;
}
static std::string
NetSHCommand()
{
std::wstring wcmd = get_win_sys_path() + L"\\netsh.exe";
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;
return converter.to_bytes(wcmd);
}
static void
NetSH(std::string commands)
{
commands = NetSHCommand() + " " + commands;
::system(commands.c_str());
}
public:
Win32Interface(InterfaceInfo info) : m_ReadQueue{1024}, m_Info{std::move(info)}
{
DWORD len;
const auto device_id = reg_query(NETWORK_ADAPTERS);
if (device_id == nullptr)
{
LogError("cannot query registry");
throw std::invalid_argument{"cannot query registery"};
}
std::stringstream ss;
ss << "\\\\.\\Global\\" << device_id << ".tap";
const auto fname = ss.str();
m_Device = CreateFile(
fname.c_str(),
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0);
if (m_Device == INVALID_HANDLE_VALUE)
{
LogError("failed to open device");
throw std::invalid_argument{"cannot open " + fname};
}
LogInfo("putting interface up...");
ULONG flag = 1;
// put the interface up
if (not DeviceIoControl(
m_Device,
TAP_IOCTL_SET_MEDIA_STATUS,
&flag,
sizeof(flag),
&flag,
sizeof(flag),
&len,
nullptr))
{
LogError("cannot up interface up");
throw std::invalid_argument{"cannot put interface up"};
}
LogInfo("setting addresses");
// set ipv4 addresses
for (const auto& ifaddr : m_Info.addrs)
{
if (ifaddr.fam == AF_INET)
{
IPADDR sock[3]{};
const nuint32_t addr = xhtonl(net::TruncateV6(ifaddr.range.addr));
const nuint32_t mask = xhtonl(net::TruncateV6(ifaddr.range.netmask_bits));
LogInfo("address ", addr, " netmask ", mask);
sock[0] = addr.n;
sock[1] = addr.n & mask.n;
sock[2] = mask.n;
if (not DeviceIoControl(
m_Device,
TAP_IOCTL_CONFIG_TUN,
&sock,
sizeof(sock),
&sock,
sizeof(sock),
&len,
nullptr))
{
LogError("cannot set address");
throw std::invalid_argument{"cannot configure tun interface address"};
}
IPADDR ep[4]{};
ep[0] = addr.n;
ep[1] = mask.n;
ep[2] = (addr.n | ~mask.n) - htonl(1);
ep[3] = 31536000;
if (not DeviceIoControl(
m_Device,
TAP_IOCTL_CONFIG_DHCP_MASQ,
ep,
sizeof(ep),
ep,
sizeof(ep),
&len,
nullptr))
{
LogError("cannot set dhcp masq");
throw std::invalid_argument{"Cannot configure tun interface dhcp"};
}
#pragma pack(push)
#pragma pack(1)
struct opt
{
uint8_t dhcp_opt;
uint8_t length;
uint32_t value;
} dns, gateway;
#pragma pack(pop)
const nuint32_t dnsaddr{xhtonl(m_Info.dnsaddr)};
dns.dhcp_opt = 6;
dns.length = 4;
dns.value = dnsaddr.n;
gateway.dhcp_opt = 3;
gateway.length = 4;
gateway.value = addr.n + htonl(1);
if (not DeviceIoControl(
m_Device,
TAP_IOCTL_CONFIG_DHCP_SET_OPT,
&gateway,
sizeof(gateway),
&gateway,
sizeof(gateway),
&len,
nullptr))
{
LogError("cannot set gateway");
throw std::invalid_argument{"cannot set tun gateway"};
}
if (not DeviceIoControl(
m_Device,
TAP_IOCTL_CONFIG_DHCP_SET_OPT,
&dns,
sizeof(dns),
&dns,
sizeof(dns),
&len,
nullptr))
{
LogError("cannot set dns");
throw std::invalid_argument{"cannot set tun dns"};
}
}
}
// set ipv6 addresses
/*
for (const auto& ifaddr : m_Info.addrs)
{
if (ifaddr.fam == AF_INET6)
{
IPRange range = ifaddr.range;
range.netmask_bits = netmask_ipv6_bits(128);
NetSH(
"interface ipv6 set address " + std::to_string(ifindex) + " " + range.ToString()
+ " store=active");
}
}
*/
}
~Win32Interface()
{
ULONG flag = 0;
DWORD len;
// put the interface down
DeviceIoControl(
m_Device,
TAP_IOCTL_SET_MEDIA_STATUS,
&flag,
sizeof(flag),
&flag,
sizeof(flag),
&len,
nullptr);
m_Run = false;
CloseHandle(m_IOCP);
// close the handle
CloseHandle(m_Device);
// close the reader threads
for (auto& thread : m_Threads)
CloseHandle(thread);
}
int
PollFD() const override
{
return -1;
}
bool
HasNextPacket() override
{
return not m_ReadQueue.empty();
}
std::string
IfName() const override
{
return "";
}
static DWORD FAR PASCAL
Loop(void* u)
{
static_cast<Win32Interface*>(u)->ReadLoop();
return 0;
}
void
Start()
{
m_Run = true;
const auto numThreads = std::thread::hardware_concurrency();
m_IOCP = CreateIoCompletionPort(m_Device, nullptr, (ULONG_PTR)this, 1 + numThreads);
for (size_t idx = 0; idx < numThreads; ++idx)
m_Threads.push_back(CreateThread(nullptr, 0, &Loop, this, 0, nullptr));
}
net::IPPacket
ReadNextPacket()
{
return m_ReadQueue.popFront();
}
struct asio_evt_pkt
{
explicit asio_evt_pkt(bool _read) : read{_read}
{}
OVERLAPPED hdr = {0, 0, 0, 0, nullptr}; // must be first, since this is part of the IO call
bool read;
net::IPPacket pkt;
void
Read(HANDLE dev)
{
ReadFile(dev, pkt.buf, sizeof(pkt.buf), nullptr, &hdr);
}
};
bool
WritePacket(net::IPPacket pkt)
{
LogDebug("write packet ", pkt.sz);
asio_evt_pkt* ev = new asio_evt_pkt{false};
std::copy_n(pkt.buf, pkt.sz, ev->pkt.buf);
ev->pkt.sz = pkt.sz;
WriteFile(m_Device, ev->pkt.buf, ev->pkt.sz, nullptr, &ev->hdr);
return true;
}
void
ReadLoop()
{
std::unique_ptr<asio_evt_pkt> ev = std::make_unique<asio_evt_pkt>(true);
ev->Read(m_Device);
while (m_Run)
{
DWORD size;
ULONG_PTR user;
OVERLAPPED* ovl = nullptr;
if (not GetQueuedCompletionStatus(m_IOCP, &size, &user, &ovl, 1000))
continue;
asio_evt_pkt* pkt = (asio_evt_pkt*)ovl;
LogDebug("got iocp event size=", size, " read=", pkt->read);
if (pkt->read)
{
pkt->pkt.sz = size;
m_ReadQueue.pushBack(pkt->pkt);
pkt->Read(m_Device);
}
else
delete pkt;
}
}
};
class Win32Platform : public Platform
{
public:
std::shared_ptr<NetworkInterface>
ObtainInterface(InterfaceInfo info) override
{
auto netif = std::make_shared<Win32Interface>(std::move(info));
netif->Start();
return netif;
};
};
} // namespace llarp::vpn

28
vendor/CMakeLists.txt vendored
View File

@ -1,28 +0,0 @@
add_library(tuntap OBJECT
libtuntap-master/tuntap.cpp
libtuntap-master/tuntap_log.cpp)
get_target_property(nlohmann_inc nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(tuntap PRIVATE ../llarp ../include ${nlohmann_inc})
if(WIN32)
target_sources(tuntap PRIVATE libtuntap-master/tuntap-windows.c)
else()
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix.c)
if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix-linux.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix-openbsd.c libtuntap-master/tuntap-unix-bsd.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix-netbsd.c libtuntap-master/tuntap-unix-bsd.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD|DragonFly")
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix-freebsd.c libtuntap-master/tuntap-unix-bsd.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS")
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix-darwin.c libtuntap-master/tuntap-unix-bsd.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
target_sources(tuntap PRIVATE libtuntap-master/tuntap-unix-sunos.c)
else()
message(FATAL_ERROR "Your operating system - ${CMAKE_SYSTEM_NAME} is not supported yet for libtuntap")
endif()
endif()

View File

@ -1,137 +0,0 @@
# libtuntap CMakeLists.txt
# ========================
project(libtuntap)
cmake_minimum_required(VERSION 2.8)
# CMake global options
# --------------------
option(ENABLE_REGRESS "Enable the regression tests" OFF)
option(ENABLE_CXX "Enable the C++ wrapper library" OFF)
option(ENABLE_PYTHON "Enable the Python wrapper library" OFF)
if(ENABLE_PYTHON AND NOT ENABLE_CXX)
set(ENABLE_CXX ON)
message(WARNING "ENABLE_CXX also set to ON")
endif()
# CMake Configuration
# -------------------
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_INSTALL_PREFIX "/usr/local/")
set(${CMAKE_SYSTEM_NAME} True)
# Global CPP definitions
# ----------------------
add_definitions(-D${CMAKE_SYSTEM_NAME})
# Portable source files
# ---------------------
set(SOURCES_LIST
tuntap.c
tuntap_log.c
)
# OS families specific things
# ---------------------------
if(UNIX)
# Unix specific include directories
# ---------------------------------
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}"
/usr/include/
/usr/local/include
)
# Unix specific definitions
# -------------------------
add_definitions(-DUnix)
# Unix specific source files
# --------------------------
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix.c )
endif(UNIX)
if(Windows)
# Windows specific definitions
# ----------------------------
add_definitions(-DWindows)
# Windows specific source files
# -----------------------------
set(SOURCES_LIST ${SOURCES_LIST} tuntap-windows.c )
endif(Windows)
# OS specific things
# ------------------
if(UNIX)
if(Linux)
set(CMAKE_INSTALL_PREFIX "/usr/")
add_definitions(-D_GNU_SOURCE)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-linux.c)
elseif (OpenBSD)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-openbsd.c)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-bsd.c)
elseif (NetBSD)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-netbsd.c)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-bsd.c)
elseif (FreeBSD)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-freebsd.c)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-bsd.c)
elseif (Darwin)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-darwin.c)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-bsd.c)
elseif (DragonFly)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-freebsd.c)
set(SOURCES_LIST ${SOURCES_LIST} tuntap-unix-bsd.c)
else()
message(FATAL_ERROR "Your operating system is not supported yet")
endif()
endif(UNIX)
# Library definition
# ------------------
add_library(tuntap SHARED ${SOURCES_LIST} tuntap.h)
set_target_properties(tuntap PROPERTIES VERSION 2.1)
add_library(tuntap-static STATIC ${SOURCES_LIST})
set_target_properties(tuntap-static PROPERTIES OUTPUT_NAME "tuntap")
if(UNIX)
set_target_properties(tuntap-static PROPERTIES PREFIX "lib")
endif(UNIX)
if(Windows)
target_link_libraries(tuntap Ws2_32.lib)
target_link_libraries(tuntap-static Ws2_32.lib)
endif(Windows)
# C++ Binding definition
# ----------------------
if(ENABLE_CXX)
include(bindings/cpp/CMakeLists.txt)
endif(ENABLE_CXX)
# Python Binding definition
# -------------------------
if(ENABLE_PYTHON)
include(bindings/python/CMakeLists.txt)
endif (ENABLE_PYTHON)
# Install rules
# -------------
if(UNIX)
install(TARGETS tuntap DESTINATION lib)
install(TARGETS tuntap-static DESTINATION lib)
install(FILES tuntap.h DESTINATION include)
target_include_directories(tuntap INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
endif(UNIX)
include(CMakeLists.txt.local OPTIONAL)
# Tests rules
# -----------
if (ENABLE_REGRESS)
include(regress/CMakeLists.txt)
endif (ENABLE_REGRESS)

View File

@ -1,377 +0,0 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.9
# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:
#=============================================================================
# Special targets provided by cmake.
# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =
.SUFFIXES: .hpux_make_needs_suffix_list
# Suppress display of executed commands.
$(VERBOSE).SILENT:
# A target that is always out of date.
cmake_force:
.PHONY : cmake_force
#=============================================================================
# Set environment variables for the build.
# The shell in which to execute make rules.
SHELL = /bin/sh
# The CMake executable.
CMAKE_COMMAND = /usr/local/bin/cmake
# The command to remove a file.
RM = /usr/local/bin/cmake -E remove -f
# Escaping for special characters.
EQUALS = =
# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /Users/rtharp/Sites/llarp/vendor/libtuntap-master
# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /Users/rtharp/Sites/llarp/vendor/libtuntap-master
#=============================================================================
# Targets provided globally by CMake.
# Special rule for the target install/local
install/local: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
/usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
.PHONY : install/local
# Special rule for the target install/local
install/local/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
/usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
.PHONY : install/local/fast
# Special rule for the target install/strip
install/strip: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
/usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
.PHONY : install/strip
# Special rule for the target install/strip
install/strip/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
/usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
.PHONY : install/strip/fast
# Special rule for the target install
install: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
/usr/local/bin/cmake -P cmake_install.cmake
.PHONY : install
# Special rule for the target install
install/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
/usr/local/bin/cmake -P cmake_install.cmake
.PHONY : install/fast
# Special rule for the target list_install_components
list_install_components:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
.PHONY : list_install_components
# Special rule for the target list_install_components
list_install_components/fast: list_install_components
.PHONY : list_install_components/fast
# Special rule for the target rebuild_cache
rebuild_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
/usr/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache
# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast
# Special rule for the target edit_cache
edit_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
/usr/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : edit_cache
# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast
# The main all target
all: cmake_check_build_system
$(CMAKE_COMMAND) -E cmake_progress_start /Users/rtharp/Sites/llarp/vendor/libtuntap-master/CMakeFiles /Users/rtharp/Sites/llarp/vendor/libtuntap-master/CMakeFiles/progress.marks
$(MAKE) -f CMakeFiles/Makefile2 all
$(CMAKE_COMMAND) -E cmake_progress_start /Users/rtharp/Sites/llarp/vendor/libtuntap-master/CMakeFiles 0
.PHONY : all
# The main clean target
clean:
$(MAKE) -f CMakeFiles/Makefile2 clean
.PHONY : clean
# The main clean target
clean/fast: clean
.PHONY : clean/fast
# Prepare targets for installation.
preinstall: all
$(MAKE) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall
# Prepare targets for installation.
preinstall/fast:
$(MAKE) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall/fast
# clear depends
depend:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend
#=============================================================================
# Target rules for targets named tuntap-static
# Build rule for target.
tuntap-static: cmake_check_build_system
$(MAKE) -f CMakeFiles/Makefile2 tuntap-static
.PHONY : tuntap-static
# fast build rule for target.
tuntap-static/fast:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/build
.PHONY : tuntap-static/fast
#=============================================================================
# Target rules for targets named tuntap
# Build rule for target.
tuntap: cmake_check_build_system
$(MAKE) -f CMakeFiles/Makefile2 tuntap
.PHONY : tuntap
# fast build rule for target.
tuntap/fast:
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/build
.PHONY : tuntap/fast
tuntap-unix-bsd.o: tuntap-unix-bsd.c.o
.PHONY : tuntap-unix-bsd.o
# target to build an object file
tuntap-unix-bsd.c.o:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix-bsd.c.o
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix-bsd.c.o
.PHONY : tuntap-unix-bsd.c.o
tuntap-unix-bsd.i: tuntap-unix-bsd.c.i
.PHONY : tuntap-unix-bsd.i
# target to preprocess a source file
tuntap-unix-bsd.c.i:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix-bsd.c.i
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix-bsd.c.i
.PHONY : tuntap-unix-bsd.c.i
tuntap-unix-bsd.s: tuntap-unix-bsd.c.s
.PHONY : tuntap-unix-bsd.s
# target to generate assembly for a file
tuntap-unix-bsd.c.s:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix-bsd.c.s
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix-bsd.c.s
.PHONY : tuntap-unix-bsd.c.s
tuntap-unix-darwin.o: tuntap-unix-darwin.c.o
.PHONY : tuntap-unix-darwin.o
# target to build an object file
tuntap-unix-darwin.c.o:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix-darwin.c.o
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix-darwin.c.o
.PHONY : tuntap-unix-darwin.c.o
tuntap-unix-darwin.i: tuntap-unix-darwin.c.i
.PHONY : tuntap-unix-darwin.i
# target to preprocess a source file
tuntap-unix-darwin.c.i:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix-darwin.c.i
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix-darwin.c.i
.PHONY : tuntap-unix-darwin.c.i
tuntap-unix-darwin.s: tuntap-unix-darwin.c.s
.PHONY : tuntap-unix-darwin.s
# target to generate assembly for a file
tuntap-unix-darwin.c.s:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix-darwin.c.s
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix-darwin.c.s
.PHONY : tuntap-unix-darwin.c.s
tuntap-unix.o: tuntap-unix.c.o
.PHONY : tuntap-unix.o
# target to build an object file
tuntap-unix.c.o:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix.c.o
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix.c.o
.PHONY : tuntap-unix.c.o
tuntap-unix.i: tuntap-unix.c.i
.PHONY : tuntap-unix.i
# target to preprocess a source file
tuntap-unix.c.i:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix.c.i
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix.c.i
.PHONY : tuntap-unix.c.i
tuntap-unix.s: tuntap-unix.c.s
.PHONY : tuntap-unix.s
# target to generate assembly for a file
tuntap-unix.c.s:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap-unix.c.s
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap-unix.c.s
.PHONY : tuntap-unix.c.s
tuntap.o: tuntap.c.o
.PHONY : tuntap.o
# target to build an object file
tuntap.c.o:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap.c.o
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap.c.o
.PHONY : tuntap.c.o
tuntap.i: tuntap.c.i
.PHONY : tuntap.i
# target to preprocess a source file
tuntap.c.i:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap.c.i
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap.c.i
.PHONY : tuntap.c.i
tuntap.s: tuntap.c.s
.PHONY : tuntap.s
# target to generate assembly for a file
tuntap.c.s:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap.c.s
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap.c.s
.PHONY : tuntap.c.s
tuntap_log.o: tuntap_log.c.o
.PHONY : tuntap_log.o
# target to build an object file
tuntap_log.c.o:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap_log.c.o
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap_log.c.o
.PHONY : tuntap_log.c.o
tuntap_log.i: tuntap_log.c.i
.PHONY : tuntap_log.i
# target to preprocess a source file
tuntap_log.c.i:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap_log.c.i
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap_log.c.i
.PHONY : tuntap_log.c.i
tuntap_log.s: tuntap_log.c.s
.PHONY : tuntap_log.s
# target to generate assembly for a file
tuntap_log.c.s:
$(MAKE) -f CMakeFiles/tuntap-static.dir/build.make CMakeFiles/tuntap-static.dir/tuntap_log.c.s
$(MAKE) -f CMakeFiles/tuntap.dir/build.make CMakeFiles/tuntap.dir/tuntap_log.c.s
.PHONY : tuntap_log.c.s
# Help Target
help:
@echo "The following are some of the valid targets for this Makefile:"
@echo "... all (the default if no target is provided)"
@echo "... clean"
@echo "... depend"
@echo "... install/local"
@echo "... install/strip"
@echo "... install"
@echo "... list_install_components"
@echo "... tuntap-static"
@echo "... rebuild_cache"
@echo "... edit_cache"
@echo "... tuntap"
@echo "... tuntap-unix-bsd.o"
@echo "... tuntap-unix-bsd.i"
@echo "... tuntap-unix-bsd.s"
@echo "... tuntap-unix-darwin.o"
@echo "... tuntap-unix-darwin.i"
@echo "... tuntap-unix-darwin.s"
@echo "... tuntap-unix.o"
@echo "... tuntap-unix.i"
@echo "... tuntap-unix.s"
@echo "... tuntap.o"
@echo "... tuntap.i"
@echo "... tuntap.s"
@echo "... tuntap_log.o"
@echo "... tuntap_log.i"
@echo "... tuntap_log.s"
.PHONY : help
#=============================================================================
# Special targets to cleanup operation of make.
# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system

View File

@ -1,53 +0,0 @@
libtuntap
=========
Description
-----------
libtuntap is a library for configuring TUN or TAP devices in a portable manner.
TUN and TAP are virtual networking devices which allow userland applications
to receive packets sent to it. The userland applications can also send their
own packets to the devices and they will be forwarded to the kernel.
This is useful for developping tunnels, private networks or virtualisation
systems.
Supported Features
------------------
* Creation of TUN _and_ TAP devices;
* Autodetection of available TUN or TAP devices;
* Setting and getting the MAC address of the device;
* Setting and getting the MTU of the device;
* Setting the status of the device (up/down);
* Setting the IPv4 address and netmask of the device;
* Setting the persistence mode of the device;
* Setting the name of the device (Linux only);
* Setting the description of the device (OpenBSD and FreeBSD only).
Supported Systems
-----------------
* OpenBSD;
* Linux;
* NetBSD;
* Darwin.
Current Porting Efforts
-----------------------
* Windows;
* FreeBSD.
In the future
-------------
* AIX;
* Solaris.
License
-------
All the code is licensed under the ISC License.
It's free, not GPLed !

View File

@ -1,17 +0,0 @@
# TODO
- [ ] Create a system of automatic testing with VMs
- [X] OpenBSD vm
- [X] Debian vm
- [ ] Import some patches from dev branch in master
- [ ] tuntap_get_descr() is not implemented in master
- [X] Test on OpenBSD (not working)
- [ ] Fix tuntap-unix-openbsd.c
- [ ] Test on NetBSD
- [ ] Test on FreeBSD
- [ ] Test on Darwin
- [X] Test on Debian (working)
- [ ] Fix shell scripts based tests test35 and test36
- [ ] Test on FreeBSD
- [ ] Test on Windows
- [ ] Move away from cmake?

View File

@ -1,7 +0,0 @@
libtuntap bindings
==================
libtuntap supports bindings in C++ and Python, thanks to Fabien Pichot
(@drepdash on Github). This is a work in progress.
Support for more languages is planned.

View File

@ -1,24 +0,0 @@
# libtuntap C++ binding CMakeLists.txt
# ====================================
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp
)
add_library(tuntap++ SHARED
${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp/tuntap++.cc
${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp/tuntap++.hh
)
set_target_properties(tuntap++ PROPERTIES VERSION 2.1)
add_library(tuntap++-static STATIC
${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp/tuntap++.cc
${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp/tuntap++.hh
)
set_target_properties(tuntap++-static PROPERTIES OUTPUT_NAME "tuntap++")
target_link_libraries(tuntap++ tuntap)
target_link_libraries(tuntap++-static tuntap)
target_include_directories(tuntap++ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp)

View File

@ -1,176 +0,0 @@
#include "tuntap++.hh"
#include <iostream>
#include <string>
#include <algorithm>
namespace tuntap {
tun::tun()
: _dev{tuntap_init()}
{
tuntap_start(_dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY);
}
tun::~tun()
{
tuntap_destroy(_dev);
}
tun::tun(tun &&t)
: _dev(nullptr)
{
std::swap(t._dev, this->_dev);
}
void
tun::release()
{
tuntap_release(_dev);
}
std::string
tun::name() const
{
return tuntap_get_ifname(_dev);
}
void
tun::name(std::string const &s)
{
tuntap_set_ifname(_dev, s.c_str());
}
t_tun
tun::native_handle() const
{
return TUNTAP_GET_FD(this->_dev);
}
void
tun::up()
{
tuntap_up(_dev);
}
void
tun::down()
{
tuntap_down(_dev);
}
int
tun::mtu() const
{
return tuntap_get_mtu(_dev);
}
void
tun::mtu(int m)
{
tuntap_set_mtu(_dev, m);
}
void
tun::ip(std::string const &s, int netmask)
{
tuntap_set_ip(_dev, s.c_str(), netmask);
}
void
tun::nonblocking(bool b)
{
tuntap_set_nonblocking(_dev, int(b));
}
tap::tap()
: _dev{tuntap_init()}
{
tuntap_start(_dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY);
}
tap::~tap()
{
tuntap_destroy(_dev);
}
tap::tap(tap &&t)
: _dev(nullptr)
{
std::swap(t._dev, this->_dev);
}
void
tap::release()
{
tuntap_release(_dev);
}
std::string
tap::name() const
{
return tuntap_get_ifname(_dev);
}
void
tap::name(std::string const &s)
{
tuntap_set_ifname(_dev, s.c_str());
}
std::string
tap::hwaddr() const
{
return tuntap_get_hwaddr(_dev);
}
void
tap::hwaddr(std::string const &s)
{
tuntap_set_hwaddr(_dev, s.c_str());
}
t_tun
tap::native_handle() const
{
return TUNTAP_GET_FD(this->_dev);
}
void
tap::up()
{
tuntap_up(_dev);
}
void
tap::down()
{
tuntap_down(_dev);
}
int
tap::mtu() const
{
return tuntap_get_mtu(_dev);
}
void
tap::mtu(int m)
{
tuntap_set_mtu(_dev, m);
}
void
tap::ip(std::string const &s, int netmask)
{
tuntap_set_ip(_dev, s.c_str(), netmask);
}
void
tap::nonblocking(bool b)
{
tuntap_set_nonblocking(_dev, int(b));
}
} /* tuntap */

View File

@ -1,72 +0,0 @@
#pragma once
#ifndef LIBTUNTAP_ALY0MA60
#define LIBTUNTAP_ALY0MA60
#include <string>
#include <tuntap.h>
namespace tuntap {
class tun
{
public:
tun();
~tun();
tun(tun const &) = delete;
tun & operator = (tun const &) = delete;
tun(tun &&);
// Properties
std::string name() const;
void name(std::string const &);
int mtu() const ;
void mtu(int);
t_tun native_handle() const;
// Network
void up();
void down();
void ip(std::string const &presentation, int netmask);
// System
void release();
void nonblocking(bool);
private:
struct device* _dev;
};
class tap
{
public:
tap();
~tap();
tap(tap const &) = delete;
tap & operator = (tap const &) = delete;
tap(tap &&);
// Properties
std::string name() const;
void name(std::string const &);
std::string hwaddr() const;
void hwaddr(std::string const &);
int mtu() const;
void mtu(int);
t_tun native_handle() const;
// Network
void up();
void down();
void ip(std::string const &presentation, int netmask);
// System
void release();
void nonblocking(bool);
private:
struct device* _dev;
};
} /* tuntap */
#endif /* end of include guard: LIBTUNTAP_ALY0MA60 */

View File

@ -1,32 +0,0 @@
# libtuntap python binding CMakeLists.txt
# =======================================
find_package(PythonLibs)
find_package(Boost COMPONENTS system thread python)
if(${PYTHONLIBS_FOUND} AND ${Boost_FOUND})
include_directories(${PYTHON_INCLUDE_PATH})
include_directories(${Boost_INCLUDE_PATH})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/bindings/cpp)
add_library(python-tuntap SHARED
${CMAKE_CURRENT_SOURCE_DIR}/bindings/python/pytuntap.cc
)
target_link_libraries(python-tuntap
${PYTHON_LIBRARIES}
${Boost_LIBRARIES}
tuntap++
)
add_custom_command(TARGET python-tuntap POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${PROJECT_SOURCE_DIR}/bindings/python/__init__.py"
"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/bindings/python/pytuntap"
)
set_target_properties(python-tuntap PROPERTIES OUTPUT_NAME "_pytuntap")
set_target_properties(python-tuntap PROPERTIES PREFIX "")
set_target_properties(python-tuntap
PROPERTIES LIBRARY_OUTPUT_DIRECTORY
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/bindings/python/pytuntap
)
endif()

View File

@ -1,24 +0,0 @@
from _pytuntap import *
import io
class TunTapFileIO(io.FileIO):
def __init__(self, tuntap):
super(TunTapFileIO, self).__init__(tuntap.native_handle, 'rb+')
def read(self, size):
return memoryview(bytearray(super(TunTapFileIO, self).read(size)))
def readinto():
raise NotImplementedError
def readall():
raise NotImplementedError
def writelines():
raise NotImplementedError
def _file(self):
return TunTapFileIO(self)
Tap.file = _file
Tun.file = _file

View File

@ -1,44 +0,0 @@
#include "tuntap++.hh"
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(_pytuntap)
{
using namespace tuntap;
using namespace boost::python;
std::string (tap::*tap_get_name)() const = &tap::name;
void (tap::*tap_set_name)(std::string const &) = &tap::name;
std::string (tap::*tap_get_hwaddr)() const = &tap::hwaddr;
void (tap::*tap_set_hwaddr)(std::string const &) = &tap::hwaddr;
int (tap::*tap_get_mtu)() const = &tap::mtu;
void (tap::*tap_set_mtu)(int) = &tap::mtu;
std::string (tun::*tun_get_name)() const = &tun::name;
void (tun::*tun_set_name)(std::string const &) = &tun::name;
int (tun::*tun_get_mtu)() const = &tun::mtu;
void (tun::*tun_set_mtu)(int) = &tun::mtu;
def("tuntap_version", tuntap_version);
class_<tun, boost::noncopyable>("Tun", init<>())
.def("release", &tun::release)
.def("up", &tun::up)
.def("down", &tun::down)
.def("ip", &tun::ip)
.def("nonblocking", &tun::nonblocking)
.add_property("name", tun_get_name, tun_set_name)
.add_property("mtu", tun_get_mtu, tun_set_mtu)
.add_property("native_handle", &tun::native_handle)
;
class_<tap, boost::noncopyable>("Tap", init<>())
.def("release", &tap::release)
.def("up", &tap::up)
.def("down", &tap::down)
.def("ip", &tap::ip)
.def("nonblocking", &tap::nonblocking)
.add_property("name", tap_get_name, tap_set_name)
.add_property("hwaddr", tap_set_hwaddr, tap_set_hwaddr)
.add_property("mtu", tap_set_mtu, tap_set_mtu)
.add_property("native_handle", &tap::native_handle)
;
}

View File

@ -1,327 +0,0 @@
API
===
Types
=====
struct device
-------------
The `struct device` is an opaque structure containing internal parameter, like the device name, device flags, device file descriptor, etc. You should not access them.
The structure size may vary from an operating system to an other, you should not rely on it.
t_tuntap_log
------------
typedef void (*t_tuntap_log)(int level, const char *msg);
This type is a pointer to a log function. It allows to override the default behaviour, which is printing every messages on the error output prefixed with its error level.
Error levels are described later, they are macros in the form `TUNTAP_LOG_*`.
t_tun
-----
The `t_tun` type map the file descriptor type of a given operating system.
Typically it's an `int` on UNIXes and a `HANDLE` on Windows.
Macros
======
There is two type of macros, the libtuntap ones, and the "portable" ones. The laters are here to help portable parts of the code to rely on meaningful names, not hard-coded magic values.
libtuntap macros
----------------
TUNTAP_ID_MAX
-------------
`TUNTAP_ID_MAX` is the maximal device unit giveable as the third parameter of `tuntap_start()`.
TUNTAP_ID_ANY
-------------
`TUNTAP_ID_ANY` is the wild-card device unit giveable as the third parameter of `tuntap_start()`.
TUNTAP_MODE_ETHERNET
--------------------
`TUNTAP_MODE_ETHERNET` is the tap-mode giveable as the second parameter of `tuntap_start()`.
TUNTAP_MODE_TUNNEL
------------------
`TUNTAP_MODE_TUNNEL` is the tun-mode giveable as the second parameter of `tuntap_start()`.
TUNTAP_MODE_PERSIST
-------------------
`TUNTAP_MODE_PERSIST` is the persistence flag giveable OR'ed with the second parameter of `tuntap_start()`.
This flag is optional and should be used with either `TUNTAP_MODE_TUNNEL` or `TUNTAP_MODE_ETHERNET`.
TUNTAP_LOG_ERR
--------------
`TUNTAP_LOG_ERR` describes an error message.
TUNTAP_LOG_WARN
---------------
`TUNTAP_LOG_WARN` describes a warning message.
TUNTAP_LOG_INFO
---------------
`TUNTAP_LOG_INFO` describes an informational message.
TUNTAP_LOG_NOTICE
-----------------
`TUNTAP_LOG_NOTICE` describes a message which is not really an error nor a warning. It is mostly used to warn about unimplemented or unavailable part of the libtuntap.
TUNTAP_LOG_DEBUG
----------------
`TUNTAP_LOG_DEBUG` describes a debug messages. You should see one only if your are using the git HEAD.
TUNTAP_LOG_NONE
---------------
`TUNTAP_LOG_NONE` describes other things. It is only used by `tuntap_log_hexdump()` and `tuntap_log_chksum()`.
Portable macros
---------------
ETHER_ADDR_LEN
--------------
`ETHER_ADDR_LEN` is a value dictated by [[http://www.ieee802.org/3/|IEEE 802.3]] standard.
On Linux systems its value is mapped on `ETH_ALEN` one.
IF_NAMESIZE
-----------
`IF_NAMESIZE` gives the maximal length of an interface name.
On BSD systems its value is mapped on `IFNAMSIZ` one.
IF_DESCRSIZE
------------
`IF_DESCSIZE` gives the maximal length of an interface description.
TUNFD_INVALID_VALUE
-------------------
`TUNFD_INVALID_VALUE` is the invalid value of the t_tun type.
On UNIXes systems its value is `-1`.
On Windows systems its value is `INVALID_HANDLE_VALUE`.
Functions
=========
tuntap_init
-----------
struct device *tuntap_init(void);
This function will allocate and initialise a `struct device`.
tuntap_version
--------------
int tuntap_version(void);
This function returns the version number of libtuntap.
You can extract the major and the minor like this:
int version = tuntap_version();
int major = version >> 8;
int minor = version & major;
Note that this version number is not the same as the shared library version.
tuntap_destroy
--------------
void tuntap_destroy(struct device *dev);
This function will free allocated memory, close file descriptors and destroy the interface.
=== tuntap_release
void tuntap_release(struct device *dev);
This function will free allocated memory and close file descriptors. leaving the interface.
=== tuntap_start
int tuntap_start(struct device dev*, int mode, int unit);
This function will configure the device with the mode `mode` and the optional device unit `unit`.
The `mode` parameter should be either `TUNTAP_MODE_ETHERNET` or `TUNTAP_MODE_TUNNEL` eventually ORed with `TUNTAP_MODE_PERSIST`.
The `unit` parameter should always be less than `TUNTAP_ID_MAX` and greater than 0. If you don't need a particular value, you should use `TUNTAP_ID_ANY`, which is a sort of wild-card device unit. With this parameter, the kernel will pick the next available device.
The term "device unit" is also known as PPA, for Physical Point of Attachment, in Solaris documentation.
Examples:
tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY)
tuntap_start(dev, TUNTAP_MODE_TUNNEL, 2)
tuntap_start(dev, TUNTAP_MODE_TUNNEL | TUNTAP_MODE_PERSIST, TUNTAP_ID_ANY)
tuntap_get_ifname
-----------------
char *tuntap_get_ifname(struct device *dev);
This function fetch and return the name of the interface described by `dev`.
tuntap_set_ifname
-----------------
int tuntap_set_ifname(struct device *dev, const char *ifname);
This function replaces the name of the interface described by `dev` with the given name `ifname`.
It returns -1 on error.
Compatibility: Linux.
tuntap_get_hwaddr
-----------------
char *tuntap_get_hwaddr(struct device *dev);
This function fetch and returns the link-layer address (MAC) of the interface described by `dev`.
The returned string come from a statically allocated buffer, ans thus should be saved if needed for later use.
tuntap_set_hwaddr
-----------------
int tuntap_set_hwaddr(struct device *dev, const char *mac_addr);
This function replaces the link-layer address of the interface described by `dev` with the given address `mac_addr`.
It returns -1 on error.
tuntap_set_descr
----------------
int tuntap_set_descr(struct device *dev, const char *desc);
This function replaces the description of the interface described by `dev` with the given string `desc`.
Compatibility: OpenBSD, FreeBSD.
tuntap_up
---------
int tuntap_up(struct device *dev);
This function set interface to the UP state, just like `ifconfig eth0 up` would do.
tuntap_down
-----------
int tuntap_down(struct device *dev);
This function set interface to the DOWN state, just like `ifconfig eth0 down` would do.
tuntap_get_mtu
--------------
int tuntap_get_mtu(struct device *dev);
This function fetch and returns the Maximum Transfer Unit (MTU) of the interface described by `dev`.
tuntap_set_mtu
--------------
int tuntap_set_mtu(struct device *dev, int mtu);
This function replaces the MTU of the interface described by `dev` with the given value `mtu`.
tuntap_set_ip
-------------
int tuntap_set_ip(struct device *dev, const char *, int ip_addr);
This function replaces the IP address of the interface described by `dev` with the given address `ip_addr`.
tuntap_read
-----------
int tuntap_read(struct device *dev, void *buf, size_t buf_len);
This function will read one packet from the interface descibed by `dev` and will store it in the buffer `buf` of size `buf_len`. This value can be retrieved with a call to `tuntap_get_readable()`.
tuntap_write
------------
int tuntap_write(struct device *dev, void *buf, size_t buf_len);
This function will write the packet stored in the buffer `buf` of size `buf_len` to the interface descibed by `dev`.
tuntap_get_readable
-------------------
int tuntap_get_readable(struct device *dev);
This function will return the size of the next packet waiting in the buffer queue of the interface described by `dev`.
On Linux this function is the same as `tuntap_get_mtu()`, because the ioctl call `FIONREAD` is not supported on caracter devices.
tuntap_set_nonblocking
----------------------
int tuntap_set_nonblocking(struct device *dev, int set);
This function will set the socket of the interface described by `dev` to a non-blocking state.
tuntap_set_debug
----------------
int tuntap_set_debug(struct device *dev, int set);
This function will enable or disable the debug mode of the interface described by `dev`, depending of the value of `set`.
If `set` is 0, it will disable debug, and if it is 1 it will enable it.
The debug mode will add more output regarding the interface on the console.
This functionality depend on your operating system. It is enable by default on FreeBSD and NetBSD, but you might have to recompile your tun and tap drivers on Linux and OpenBSD to enable it.
tuntap_log_set_cb
-----------------
void tuntap_log_set_cb(t_tuntap_log cb);
This function allow to set an external printing function, in order to erase the default behaviour.
tuntap_log_hexdump
------------------
void tuntap_log_hexdump(void *, size_t);
This function is actualy not documented.
tuntap_log_chksum
-----------------
void tuntap_log_chksum(void *, int);
This function is actualy not documented.
TUNTAP_GET_FD
-------------
int TUNTAP_GET_FD(struct device *dev)
This macro will return the socket of the interface described by `dev`.

View File

@ -1,100 +0,0 @@
# libtuntap regression tests CMakeLists.txt
# =========================================
cmake_minimum_required(VERSION 2.8)
enable_testing()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
# C based tests
# -------------
file(GLOB ALL_C_TESTS regress/test*.c)
foreach(SOURCE_FILE ${ALL_C_TESTS})
string(REPLACE ".c" "" PATH_WO_SUFFIX ${SOURCE_FILE})
string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/ ""
TEST_SRC_PATH ${SOURCE_FILE})
string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/regress/ ""
TEST_NAME ${PATH_WO_SUFFIX})
add_executable(${TEST_NAME} ${TEST_SRC_PATH})
target_link_libraries(${TEST_NAME} tuntap)
add_test(${TEST_NAME} ${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME})
endforeach(SOURCE_FILE)
# Shell based tests
# -----------------
file(GLOB ALL_SH_TESTS regress/test*.sh)
foreach(SOURCE_FILE ${ALL_SH_TESTS})
string(REPLACE ".sh" "" PATH_WO_SUFFIX ${SOURCE_FILE})
string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/ ""
TEST_SRC_PATH ${SOURCE_FILE})
string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/regress/ ""
TEST_NAME ${PATH_WO_SUFFIX})
string(REPLACE ".sh" ".c" HELPER_SRC_PATH ${TEST_SRC_PATH})
string(REPLACE "test" "helper" HELPER_SRC_PATH ${HELPER_SRC_PATH})
string(REPLACE "test" "helper" HELPER_NAME ${TEST_NAME})
# XXX: Do it conditionaly
add_executable(${HELPER_NAME} ${HELPER_SRC_PATH})
target_link_libraries(${HELPER_NAME} tuntap)
# XXX: This is cancerous
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME})
file(COPY ${TEST_SRC_PATH}
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE
)
file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.sh
${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME})
add_test(${TEST_NAME} ${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME})
endforeach(SOURCE_FILE)
# "Will fail" tests
# -----------------
# Only NetBSD, FreeBSD and DragonFlyBSD have the debug mode compiled by default
if(NOT NetBSD AND NOT FreeBSD AND NOT DragonFly)
set_tests_properties(test39 PROPERTIES WILL_FAIL true)
set_tests_properties(test40 PROPERTIES WILL_FAIL true)
endif()
# Only Linux has a tuntap_set_ifname() implemented
if(NOT Linux)
set_tests_properties(test41 PROPERTIES WILL_FAIL true)
endif()
# Only FreeBSD and OpenBSD have a tuntap_set_descr() implemented
if(NOT FreeBSD AND NOT OpenBSD)
set_tests_properties(test44 PROPERTIES WILL_FAIL true)
set_tests_properties(test46 PROPERTIES WILL_FAIL true)
endif()
# Windows work-in-progress (tap)
if (Windows)
set_tests_properties(test05 PROPERTIES WILL_FAIL true)
set_tests_properties(test07 PROPERTIES WILL_FAIL true)
set_tests_properties(test09 PROPERTIES WILL_FAIL true)
set_tests_properties(test39 PROPERTIES WILL_FAIL true)
set_tests_properties(test41 PROPERTIES WILL_FAIL true)
set_tests_properties(test44 PROPERTIES WILL_FAIL true)
endif()
# Windows work-in-progress (tun)
if (Windows)
set_tests_properties(test02 PROPERTIES WILL_FAIL true)
set_tests_properties(test04 PROPERTIES WILL_FAIL true)
set_tests_properties(test06 PROPERTIES WILL_FAIL true)
set_tests_properties(test08 PROPERTIES WILL_FAIL true)
set_tests_properties(test10 PROPERTIES WILL_FAIL true)
set_tests_properties(test12 PROPERTIES WILL_FAIL true)
set_tests_properties(test14 PROPERTIES WILL_FAIL true)
set_tests_properties(test18 PROPERTIES WILL_FAIL true)
set_tests_properties(test22 PROPERTIES WILL_FAIL true)
set_tests_properties(test24 PROPERTIES WILL_FAIL true)
set_tests_properties(test26 PROPERTIES WILL_FAIL true)
set_tests_properties(test40 PROPERTIES WILL_FAIL true)
endif()

View File

@ -1,50 +0,0 @@
Regression Testing
==================
test01: Create a tapN device
test02: Create a tunN device
test03: Create a tap0 device
test04: Create a tun0 device
test05: Create a tapN device and set its mtu to 1400
test06: Create a tunN device and set its mtu to 1400
test07: Create a tapN device and set its MAC address to 54:1a:13:ef:b6:b5
test08: Create a tunN device and set its MAC address to 54:1a:13:ef:b6:b5
test09: Create a tapN device and set its MAC address to random
test10: Create a tunN device and set its MAC address to random
test11: Create a tapN device and turn it up
test12: Create a tunN device and turn it up
test13: Create a tapN device, turn it up and set its IPv4 address
test14: Create a tunN device, turn it up and set its IPv4 address
#test15: Create a tapN device, turn it up and set its IPv6 address
#test16: Create a tunN device, turn it up and set its IPv6 address
test17: Create a tapN device, set its IPv4 address and turn it up
test18: Create a tunN device, set its IPv4 address and turn it up
#test19: Create a tapN device, set its IPv6 address and turn it up
#test20: Create a tunN device, set its IPv6 address and turn it up
test21: Create a tapN device and set its IP address to NULL
test22: Create a tunN device and set its IP address to NULL
test23: Create a tapN device and set its netmask to a negative value
test24: Create a tunN device and set its netmask to a negative value
test25: Create a tapN device and set its IP address to a dumb value
test26: Create a tunN device and set its IP address to a dumb value
#test27: Create a tapN device and set its netmask to a dumb value
#test28: Create a tunN device and set its netmask to a dumb value
test29: Double create a tapN device
test30: Create a device with a wrong type
test31: Create a device with a wrong number
test32: Create a tapN device and check its pre-existing MAC address
test33: Create a tap0 persistent device and destroy it
test34: Create a tun0 persistent device and destroy it
test35: Create a tap0 persistent device and release it
test36: Create a tun1 persistent device and release it
test37: Set a log callback and generate an error
test38: Set a log callback and generate all possible error levels
test39: Enable debug for a tap device
test40: Enable debug for a tun device
test41: Set a new name to an interface
test42: Set a NULL name to an interface
test43: Set a name of more than IF_NAMESIZE to an interface
test44: Set a description to an interface
test45: Set a NULL description to an interface
test46: Set a description to an interface and check it

View File

@ -1,26 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET|TUNTAP_MODE_PERSIST
, 0) == -1)
ret = 1;
tuntap_destroy(dev);
return ret;
}

View File

@ -1,26 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL|TUNTAP_MODE_PERSIST, 0)
== -1)
ret = 1;
tuntap_destroy(dev);
return ret;
}

View File

@ -1,26 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET|TUNTAP_MODE_PERSIST
, 0) == -1)
ret = 1;
tuntap_release(dev);
return ret;
}

View File

@ -1,25 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL|TUNTAP_MODE_PERSIST, 1) == -1)
ret = 1;
tuntap_release(dev);
return ret;
}

View File

@ -1,25 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1)
ret = 1;
tuntap_destroy(dev);
return ret;
}

View File

@ -1,25 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1)
ret = 1;
tuntap_destroy(dev);
return ret;
}

View File

@ -1,25 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, 0) == -1)
ret = 1;
tuntap_destroy(dev);
return ret;
}

View File

@ -1,25 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, 0) == -1)
ret = 1;
tuntap_destroy(dev);
return ret;
}

View File

@ -1,39 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
int mtu;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY)
== -1) {
ret = 1;
goto clean;
}
if (tuntap_set_mtu(dev, 1400) == -1) {
ret = 1;
goto clean;
}
mtu = tuntap_get_mtu(dev);
if (mtu != 1400)
ret = 1;
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,39 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
int mtu;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
ret = 1;
goto clean;
}
if (tuntap_set_mtu(dev, 1400) == -1) {
ret = 1;
goto clean;
}
mtu = tuntap_get_mtu(dev);
if (mtu != 1400) {
ret = 1;
}
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,42 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
# define strcasecmp(x, y) _stricmp((x), (y))
#else
# include <strings.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
char *hwaddr;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY)
== -1) {
ret = 1;
goto clean;
}
if (tuntap_set_hwaddr(dev, "54:1a:13:ef:b6:b5") == -1) {
ret = 1;
goto clean;
}
hwaddr = tuntap_get_hwaddr(dev);
if (strcasecmp(hwaddr, "54:1a:13:ef:b6:b5") != 0)
ret = 1;
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,31 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
/* This test SHOULD fail, it's normal */
int
main(void) {
int ret;
struct device *dev;
ret = 1;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1)
goto clean;
if (tuntap_set_hwaddr(dev, "54:1a:13:ef:b6:b5") == -1)
ret = 0;
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,33 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY)
== -1) {
ret = 1;
goto clean;
}
if (tuntap_set_hwaddr(dev, "random") == -1) {
ret = 1;
}
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,33 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
/* This test SHOULD fail, it's normal */
int
main(void) {
int ret;
struct device *dev;
ret = 1;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
goto clean;
}
if (tuntap_set_hwaddr(dev, "random") == -1) {
ret = 0;
}
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,32 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY)
== -1) {
ret = 1;
goto clean;
}
if (tuntap_up(dev) == -1)
ret = 1;
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,31 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
ret = 1;
goto clean;
}
if (tuntap_up(dev) == -1)
ret = 1;
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,43 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
/*
* This test seems to pass on Windows, but it's not true.
* tuntap_up() should be call _after_ tuntap_set_ip(), as in test17.c
*
* Fuck.
*/
int
main(void) {
int ret;
struct device *dev;
ret = 0;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
ret = 1;
goto clean;
}
if (tuntap_up(dev) == -1) {
ret = 1;
goto clean;
}
if (tuntap_set_ip(dev, "1.2.3.4", 24) == -1) {
ret = 1;
}
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,32 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_up(dev) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "1.2.3.4", 24) == -1) {
return 1;
}
tuntap_destroy(dev);
return 0;
}

View File

@ -1,32 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "1.2.3.4", 24) == -1) {
return 1;
}
if (tuntap_up(dev) == -1) {
return 1;
}
tuntap_destroy(dev);
return 0;
}

View File

@ -1,32 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "1.2.3.4", 24) == -1) {
return 1;
}
if (tuntap_up(dev) == -1) {
return 1;
}
tuntap_destroy(dev);
return 0;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, NULL, 24) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, NULL, 24) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "1.2.3.4", -2) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "1.2.3.4", -2) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "Chipot", 24) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_set_ip(dev, "Chipot", 24) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,28 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
return 1;
}
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,24 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, 42, TUNTAP_ID_ANY) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,24 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
struct device *dev;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_TUNNEL, -1) == -1) {
tuntap_destroy(dev);
return 0;
}
return 1;
}

View File

@ -1,37 +0,0 @@
/* Public domain - Tristan Le Guern <tleguern@bouledef.eu> */
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#if defined Windows
# include <windows.h>
#endif
#include "tuntap.h"
int
main(void) {
int ret;
struct device *dev;
char *hwaddr;
ret = 1;
dev = tuntap_init();
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY) == -1) {
goto clean;
}
hwaddr = tuntap_get_hwaddr(dev);
(void)fprintf(stderr, "%s\n", hwaddr);
if (strcmp(hwaddr, "0:0:0:0:0:0") == 0)
goto clean;
if (strcmp(hwaddr, "00:00:00:00:00:00") == 0)
goto clean;
ret = 0;
clean:
tuntap_destroy(dev);
return ret;
}

View File

@ -1,40 +0,0 @@
#!/bin/sh
# test33: Create a tap0 persistent device and destroy it
TEST="`pwd`/helper33"
SYSTEM=`uname`
# There is no tap driver on OpenBSD
if [ "$SYSTEM" = "OpenBSD" ]; then
TARGET='tun0'
TYPE='tap'
else
TARGET='tap0'
TYPE='tap'
fi
if [ "$SYSTEM" = "Linux" ]; then
IFDEL="ip tuntap del $TARGET mode $TYPE"
else
IFDEL="ifconfig $TARGET destroy"
fi
OK=0
$TEST && OK=1
# If the $TEST was a success, check if the interface still exist
if [ $OK -eq 1 ]; then
ifconfig $TARGET > /dev/null && OK=2
else
exit 1
fi
# The $TARGET still exists, clean it and return failure
if [ $OK -eq 2 ]; then
$IFDEL
exit 1
fi
# Everything went fine
exit 0

View File

@ -1,32 +0,0 @@
#!/bin/sh
# test34: Create a tun0 persistent device and destroy it
TEST="`pwd`/helper34"
SYSTEM=`uname`
TARGET='tun0'
TYPE='tun'
if [ "$SYSTEM" = "Linux" ]; then
IFDEL="ip tuntap del $TARGET mode $TYPE"
else
IFDEL="ifconfig $TARGET destroy"
fi
OK=0
$TEST && OK=1
# The $TEST is successful
if [ $OK -eq 1 ]; then
ifconfig $TARGET && OK=2
else
exit 1
fi
# The $TARGET still exists
if [ $OK -eq 2 ]; then
$IFDEL
exit 1
fi
exit 0

Some files were not shown because too many files have changed in this diff Show More