Merge branch 'dev' into reeeee-divergence

ok hope this works -rick

# Conflicts:
#	.gitignore
#	.vscode/settings.json
#	include/llarp/service/context.hpp
#	llarp/dns.cpp
#	llarp/dnsc.cpp
#	llarp/ev.cpp
#	llarp/ev.hpp
#	llarp/ev_win32.hpp
#	llarp/net.cpp
#	llarp/router.cpp
#	llarp/router.hpp
#	llarp/service/context.cpp
pull/91/head
despair 6 years ago
commit d26141d433

2
.gitignore vendored

@ -46,3 +46,5 @@ rapidjson/
.gradle/
.idea
.vscode
build64/
build2/

@ -21,23 +21,26 @@ set(CMAKE_CXX_EXTENSIONS OFF)
# turns off those annoying warnings for
# target-specific crypto code paths not
# applicable to the host's FPU -rick
add_compile_options(-Wall -Wextra -Werror -Wno-unknown-pragmas)
add_compile_options(-Wall -Wextra -Werror -Wno-unknown-pragmas -Wno-unknown-warning-option)
# vla are evil
add_compile_options(-Wvla)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
add_compile_options(-Wno-unused-function -Wno-deprecated-declarations -Wno-unknown-pragmas)
# gah, can't recall which -Wno flag is exclusive to clang
# -Wno-cast-function-type is GNU exclusive..i think
if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
# dynamic linking does this all the time
add_compile_options(-Wno-cast-function-type)
if (USING_CLANG)
option(NO_LIBGCC "use compiler-rt instead" OFF)
add_compile_options(-Wno-unused-command-line-argument -Wno-c++11-narrowing)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
# because clang is insane enough to inline whole sections of the C++ library!
# May have been fixed in llvm-7.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition --rtlib=libgcc")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition")
if (NO_LIBGCC)
set(CMAKE_CXX_STANDARD_LIBRARIES "-lgcc_eh ${CMAKE_CXX_STANDARD_LIBRARIES}")
set(CMAKE_C_STANDARD_LIBRARIES "-lgcc_eh ${CMAKE_C_STANDARD_LIBRARIES}")
endif()
else()
# found it. this is GNU only
add_compile_options(-Wno-cast-function-type)
endif(USING_CLANG)
endif()
@ -46,7 +49,7 @@ endif()
if(WIN32)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
add_compile_options(-Wno-cast-function-type)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-cast-function-type>)
set(FS_LIB stdc++fs)
endif(WIN32)
@ -204,7 +207,7 @@ if(UNIX)
endif()
elseif(WIN32)
set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-windows.c)
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32 -DWINVER=0x600 -D_WIN32_WINNT=0x600)
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500)
else()
message(FATAL_ERROR "What operating system _are_ you building on/for?")
endif(UNIX)
@ -283,6 +286,10 @@ set(LIB_PLATFORM_SRC
${LIBTUNTAP_SRC}
# c++17 compat code
${CXX_COMPAT_SRC}
# win32 inline code
llarp/win32_inet.c
llarp/win32_intrnl.c
llarp/win32_upoll.c
)
set(NTRU_AVX_SRC
@ -488,7 +495,6 @@ set(LIB_SRC
llarp/service/protocol.cpp
llarp/service/tag.cpp
llarp/service/info.cpp
)
set(RC_SRC

@ -1,11 +1,15 @@
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
if($ENV{ALT} MATCHES "1")
set(TOOLCHAIN_PREFIX amd64-w64-mingw32)
endif()
add_definitions("-DWINNT_CROSS_COMPILE")
# target environment on the build host system
# second one is for non-root installs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX} /home/$ENV{USER}/mingw32 /home/$ENV{USER}/mingw32/${TOOLCHAIN_PREFIX})
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX} /home/$ENV{USER}/mingw32 /home/$ENV{USER}/mingw64 /home/$ENV{USER}/mingw64/${TOOLCHAIN_PREFIX} /home/$ENV{USER}/mingw32/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

@ -0,0 +1,15 @@
{
"targets": [
{
"target_name": "lokinet",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [ "lokinet.cc" ],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
}
]
}

@ -0,0 +1,62 @@
#include <napi.h>
#include <llarp.hpp>
struct Lokinet : public Napi::ObjectWrap< Lokinet >
{
llarp::Context ctx;
static Napi::Object
Init(Napi::Env env, Napi::Object exports)
{
Napi::HandleScope scope(env);
Napi::Function func =
DefineClass(env, "Lokinet",
{InstanceMethod("configure", &Lokinet::Configure),
InstanceMethod("run", &Lokient::Run),
InstanceMethod("kill", &Lokinet::Kill)});
constructor = Napi::Persistent(func);
constructor.SuppressDestruct();
exports.Set("Lokinet", func);
return exports;
};
Napi::Value
Configure(const Napi::CallbackInfo& info)
{
if(info.Length() != 1 || !info[0].IsString())
{
Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException();
}
bool result = ctx.LoadConfig(info[0].As< std::string >());
if(result)
{
result &= ctx.Setup() == 0;
}
return Napi::Value(info.Env(), result);
}
Napi::Value
Run(const Napi::CallbackInfo& info)
{
bool result = ctx.Run() == 0;
return Napi::Value(info.Env(), result);
}
Napi::Value
Kill(const Napi::CallbackInfo& info)
{
bool result = ctx.Stop();
return Napi::Value(info.Env(), result);
}
};
Napi::Object
InitAll(Napi::Env env, Napi::Object exports)
{
return Lokinet::Init(env, exports);
}
NODE_API_MODULE(addon, InitAll)

@ -0,0 +1,2 @@
var lokinet = require("bindings")("lokinet");
console.log(lokinet);

@ -0,0 +1,12 @@
{
"name": "lokinet",
"version": "0.0.0",
"description": "lokinet god awful node binding",
"main": "lokinet.js",
"private": true,
"gypfile": true,
"dependencies": {
"bindings": "~1.2.1",
"node-addon-api": "^1.0.0"
}
}

@ -35,7 +35,8 @@ sodium_init(void)
{
return -1; /* LCOV_EXCL_LINE */
}
return 1;
/* if we're here, we already started properly */
return initialized ? 0: -1;
}
_sodium_runtime_get_cpu_features();
_crypto_generichash_blake2b_pick_best_implementation();

@ -8,7 +8,7 @@
#include <sodium/private/sse2_64_32.h>
#include <sodium/utils.h>
#if __AVX2__ && __amd64__
#if __AVX2__
#ifdef __GNUC__
#pragma GCC target("sse2")

@ -3,6 +3,7 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#ifndef ssize_t
#define ssize_t long
#endif

@ -35,16 +35,32 @@ namespace llarp
std::string nodeName;
LogLevel minlevel = eLogInfo;
std::ostream& out;
std::function< void(const std::string&) > customLog;
llarp::util::Mutex access;
#ifdef _WIN32
bool isConsoleModern =
true; // qol fix so oldfag clients don't see ugly escapes
HANDLE fd1 = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
short old_attrs;
#endif
Logger() : Logger(std::cout, "unnamed")
{
#ifdef _WIN32
// Attempt to use ANSI escapes directly
// if the modern console is active.
DWORD mode_flags;
HANDLE fd1 = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(fd1, &mode_flags);
// since release SDKs don't have ANSI escape support yet
mode_flags |= 0x0004;
SetConsoleMode(fd1, mode_flags);
// we get all or nothing: if we can't get it, then we wouldn't
// be able to get any of them individually
mode_flags |= 0x0004 | 0x0008;
BOOL t = SetConsoleMode(fd1, mode_flags);
if(!t)
this->isConsoleModern = false; // fall back to setting colours manually
#endif
}
@ -143,27 +159,69 @@ namespace llarp
break;
}
#else
switch(lvl)
#ifdef _WIN32
if(_glog.isConsoleModern)
{
case eLogNone:
break;
case eLogDebug:
ss << (char)27 << "[0m";
ss << "[DBG] ";
break;
case eLogInfo:
ss << (char)27 << "[1m";
ss << "[NFO] ";
break;
case eLogWarn:
ss << (char)27 << "[1;33m";
ss << "[WRN] ";
break;
case eLogError:
ss << (char)27 << "[1;31m";
ss << "[ERR] ";
break;
#endif
switch(lvl)
{
case eLogNone:
break;
case eLogDebug:
ss << (char)27 << "[0m";
ss << "[DBG] ";
break;
case eLogInfo:
ss << (char)27 << "[1m";
ss << "[NFO] ";
break;
case eLogWarn:
ss << (char)27 << "[1;33m";
ss << "[WRN] ";
break;
case eLogError:
ss << (char)27 << "[1;31m";
ss << "[ERR] ";
break;
}
#ifdef _WIN32
}
else // legacy console
{
// these _should_ be low white on black
GetConsoleScreenBufferInfo(_glog.fd1, &_glog.consoleInfo);
_glog.old_attrs = _glog.consoleInfo.wAttributes;
switch(lvl)
{
case eLogNone:
break;
case eLogDebug:
SetConsoleTextAttribute(_glog.fd1,
FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE); // low white on black
ss << "[DBG] ";
break;
case eLogInfo:
SetConsoleTextAttribute(
_glog.fd1,
FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE); // high white on black
ss << "[NFO] ";
break;
case eLogWarn:
SetConsoleTextAttribute(_glog.fd1,
FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_INTENSITY); // bright yellow
ss << "[WRN] ";
break;
case eLogError:
SetConsoleTextAttribute(
_glog.fd1, FOREGROUND_RED | FOREGROUND_INTENSITY); // bright red
ss << "[ERR] ";
break;
}
}
#endif
#endif
std::string tag = fname;
ss << _glog.nodeName << " (" << thread_id_string() << ") "
@ -171,16 +229,27 @@ namespace llarp
ss << "\t";
LogAppend(ss, std::forward< TArgs >(args)...);
#ifndef ANDROID
ss << (char)27 << "[0;0m";
_glog.out << ss.str() << std::endl;
#ifdef _WIN32
if(_glog.isConsoleModern)
{
#endif
ss << (char)27 << "[0;0m";
_glog.out << ss.str() << std::endl;
#ifdef _WIN32
}
else
{
_glog.out << ss.str() << std::endl;
SetConsoleTextAttribute(
_glog.fd1, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
#endif
#else
{
tag = "LOKINET|" + tag;
__android_log_write(loglev, tag.c_str(), ss.str().c_str());
}
#endif
#ifdef SHADOW_TESTNET
_glog.out << "\n" << std::flush;
#endif
}
} // namespace llarp

@ -34,12 +34,16 @@ namespace llarp
{
if(buff.base + idx == buff.cur)
{
#ifndef _WIN32
printf("%c[1;31m", 27);
#endif
}
printf("%.2x", buff.base[idx]);
if(buff.base + idx == buff.cur)
{
#ifndef _WIN32
printf("%c[0;0m", 27);
#endif
}
++idx;
if(idx % align == 0)
@ -59,7 +63,9 @@ namespace llarp
{
if(buff.base + idx == buff.cur)
{
#ifndef _WIN32
printf("%c[1;31m", 27);
#endif
}
if(std::isprint(buff.base[idx]))
{
@ -71,7 +77,9 @@ namespace llarp
}
if(buff.base + idx == buff.cur)
{
#ifndef _WIN32
printf("%c[0;0m", 27);
#endif
}
++idx;
if(idx % align == 0)

@ -3,6 +3,21 @@
#if defined(_WIN32) || defined(__MINGW32__)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
// because this shit is not defined for Windows NT reeeee
#ifdef __cplusplus
extern "C"
{
#endif
#if _WIN32_WINNT < 0x600
const char*
inet_ntop(int af, const void* src, char* dst, size_t size);
int
inet_pton(int af, const char* src, void* dst);
#endif
#ifdef __cplusplus
}
#endif
typedef unsigned short in_port_t;
typedef unsigned int in_addr_t;
#else

@ -19,6 +19,7 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif

@ -147,9 +147,6 @@ extern "C"
char if_name[IF_NAMESIZE];
#if defined(FreeBSD)
int mode;
#endif
#if defined(Windows)
OVERLAPPED ovl[2];
#endif
};

@ -25,8 +25,23 @@
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include "libutp_inet_ntop.h"
// we already have our own definition of these
// -despair
#if _WIN32_WINNT < 0x600
namespace
{
extern "C"
{
const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
int
inet_pton(int af, const char *src, void *dst);
}
} // namespace
#endif
//######################################################################
const char *
libutp::inet_ntop(int af, const void *src, char *dest, size_t length)

@ -250,7 +250,38 @@ ReverseHandlerIter(struct llarp::service::Context::endpoint_iter *endpointCfg)
// well the tunif is just one ip on a network range...
// support "b._dns-sd._udp.0.0.200.10.in-addr.arpa"
size_t searchTokens = tokensSearch.size();
size_t searchTokens = tokensSearch.size();
// if the query has five or fewer levels,
// tack on leading '0.'s to form a minimum six-level
// PTR query -rick
if(searchTokens < 6)
{
switch(searchTokens)
{
case 5:
tokensSearch.clear();
context->lName.insert(0, "0.");
tokensSearch = split(context->lName);
searchTokens = tokensSearch.size();
break;
case 4:
tokensSearch.clear();
context->lName.insert(0, "0.0.");
tokensSearch = split(context->lName);
searchTokens = tokensSearch.size();
break;
case 3:
tokensSearch.clear();
context->lName.insert(0, "0.0.0.");
tokensSearch = split(context->lName);
searchTokens = tokensSearch.size();
break;
default:
llarp::LogError("invalid PTR query: ", context->lName);
break;
}
}
// this expression assumes a six-level name
std::string searchIp = tokensSearch[searchTokens - 3] + "."
+ tokensSearch[searchTokens - 4] + "." + tokensSearch[searchTokens - 5]
+ "." + tokensSearch[searchTokens - 6];

@ -118,11 +118,27 @@ llarp_ev_udp_sendto(struct llarp_udp_io *udp, const sockaddr *to,
{
auto ret =
static_cast< llarp::ev_io * >(udp->impl)->sendto(to, buf.base, buf.sz);
#ifndef _WIN32
if(ret == -1 && errno != 0)
{
#else
if(ret == -1 && WSAGetLastError())
{
#endif
#ifndef _WIN32
llarp::LogWarn("sendto failed ", strerror(errno));
errno = 0;
}
#else
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL, ebuf,
1024, nullptr);
llarp::LogWarn("sendto failed: ", ebuf);
WSASetLastError(0);
}
#endif
return ret;
}
@ -132,9 +148,7 @@ llarp_ev_add_tun(struct llarp_ev_loop *loop, struct llarp_tun_io *tun)
auto dev = loop->create_tun(tun);
tun->impl = dev;
if(dev)
{
return loop->add_ev(dev, false);
}
return false;
}

@ -14,9 +14,15 @@
#include <algorithm>
#ifdef _WIN32
#include <variant>
#else
#include <sys/un.h>
#include <win32_up.h>
#include <win32_upoll.h>
// 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; // if this doesn't match what is in the packet, note the error
};
#endif
#ifndef MAX_WRITE_QUEUE_SIZE
@ -108,31 +114,35 @@ namespace llarp
using LosslessWriteQueue_t = std::deque< WriteBuffer >;
// on windows, tcp/udp event loops are socket fds
// and TUN device is a plain old fd
std::variant< SOCKET, HANDLE > fd;
ULONG_PTR listener_id = 0;
bool isTCP = false;
bool write = false;
WSAOVERLAPPED portfd[2];
union {
intptr_t socket;
HANDLE tun;
} fd;
int flags = 0;
bool is_tun = false;
// constructors
// for udp
win32_ev_io(SOCKET f) : fd(f)
win32_ev_io(intptr_t f)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
};
// for tun
win32_ev_io(HANDLE t, LossyWriteQueue_t* q) : fd(t), m_LossyWriteQueue(q)
fd.socket = f;
}
/// for tun
win32_ev_io(HANDLE f, LossyWriteQueue_t* q) : m_LossyWriteQueue(q)
{
fd.tun = f;
}
/// for tcp
win32_ev_io(intptr_t f, LosslessWriteQueue_t* q) : m_BlockingWriteQueue(q)
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
fd.socket = f;
}
// for tcp
win32_ev_io(SOCKET f, LosslessWriteQueue_t* q)
: fd(f), m_BlockingWriteQueue(q)
virtual void
error()
{
memset((void*)&portfd[0], 0, sizeof(WSAOVERLAPPED) * 2);
isTCP = true;
llarp::LogError(strerror(errno));
}
virtual int
@ -158,13 +168,24 @@ namespace llarp
virtual ssize_t
do_write(void* data, size_t sz)
{
// DWORD w;
if(std::holds_alternative< HANDLE >(fd))
WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, &portfd[1]);
else
WriteFile((HANDLE)std::get< SOCKET >(fd), data, sz, nullptr,
&portfd[1]);
return sz;
if(this->is_tun)
{
DWORD x;
bool r;
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->sz = sz;
pkt->write = true;
int e = 0;
r = WriteFile(fd.tun, data, sz, &x, &pkt->pkt);
if(r) // we returned immediately
return x;
e = GetLastError();
if(e == ERROR_IO_PENDING)
return sz;
else
return -1;
}
return uwrite(fd.socket, (char*)data, sz);
}
bool
@ -246,17 +267,21 @@ namespace llarp
return;
}
m_BlockingWriteQueue->pop_front();
if(errno == EAGAIN || errno == EWOULDBLOCK)
int wsaerr = WSAGetLastError();
int syserr = GetLastError();
if(wsaerr == WSA_IO_PENDING || wsaerr == WSAEWOULDBLOCK
|| syserr == 997 || syserr == 21)
{
errno = 0;
SetLastError(0);
WSASetLastError(0);
return;
}
}
}
}
/// reset errno
errno = 0;
SetLastError(0);
WSASetLastError(0);
}
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
@ -264,7 +289,7 @@ namespace llarp
virtual ~win32_ev_io()
{
closesocket(std::get< SOCKET >(fd));
uclose(fd.socket);
};
};
#endif
@ -584,7 +609,15 @@ namespace llarp
{
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);
}

@ -12,19 +12,16 @@
#undef sizeof
#endif
// TODO: convert all socket errno calls to WSAGetLastError(3),
// don't think winsock sets regular errno to this day
namespace llarp
{
int
tcp_conn::read(byte_t* buf, size_t sz)
{
WSABUF r_buf = {(u_long)sz, (char*)buf};
DWORD amount = 0;
if(_shouldClose)
return -1;
ssize_t amount = uread(fd.socket, (char*)buf, sz);
WSARecv(std::get< SOCKET >(fd), &r_buf, 1, nullptr, 0, &portfd[0], nullptr);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[0], &amount,
TRUE);
if(amount > 0)
{
if(tcp.read)
@ -39,21 +36,6 @@ namespace llarp
return 0;
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
WSABUF s_buf = {(u_long)sz, (char*)buf};
DWORD sent = 0;
if(_shouldClose)
return -1;
WSASend(std::get< SOCKET >(fd), &s_buf, 1, nullptr, 0, &portfd[1], nullptr);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[1], &sent,
TRUE);
return sent;
}
void
tcp_conn::flush_write()
{
@ -61,6 +43,14 @@ namespace llarp
ev_io::flush_write();
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
return uwrite(fd.socket, (char*)buf, sz);
}
void
tcp_conn::connect()
{
@ -69,24 +59,27 @@ namespace llarp
slen = 115;
else if(_addr.ss_family == AF_INET6)
slen = sizeof(sockaddr_in6);
int result =
::connect(std::get< SOCKET >(fd), (const sockaddr*)&_addr, slen);
int result = ::connect(fd.socket, (const sockaddr*)&_addr, slen);
if(result == 0)
{
llarp::LogDebug("connected immedidately");
connected();
}
else if(errno == EINPROGRESS)
else if(WSAGetLastError() == WSAEINPROGRESS)
{
// in progress
llarp::LogDebug("connect in progress");
errno = 0;
WSASetLastError(0);
return;
}
else if(_conn->error)
{
// wtf?
llarp::LogError("error connecting ", strerror(errno));
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogError("error connecting: ", ebuf);
_conn->error(_conn);
}
}
@ -94,11 +87,14 @@ namespace llarp
int
tcp_serv::read(byte_t*, size_t)
{
SOCKET new_fd = ::accept(std::get< SOCKET >(fd), nullptr, nullptr);
if(new_fd == INVALID_SOCKET)
{
llarp::LogError("failed to accept on ", std::get< SOCKET >(fd), ":",
strerror(errno));
int new_fd = ::accept(fd.socket, nullptr, nullptr);
if(new_fd == -1)
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogError("failed to accept on ", fd.socket, ":", ebuf);
return -1;
}
// build handler
@ -115,96 +111,25 @@ namespace llarp
return -1;
}
struct udp_listener : public ev_io
{
llarp_udp_io* udp;
udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u){};
~udp_listener()
{
}
bool
tick()
{
if(udp->tick)
udp->tick(udp);
return true;
}
virtual int
read(byte_t* buf, size_t sz)
{
printf("read\n");
sockaddr_in6 src;
socklen_t slen = sizeof(src);
sockaddr* addr = (sockaddr*)&src;
unsigned long flags = 0;
WSABUF wbuf = {(u_long)sz, (char*)buf};
// WSARecvFrom
llarp::LogDebug("read ", sz, " bytes from socket");
int ret = ::WSARecvFrom(std::get< SOCKET >(fd), &wbuf, 1, nullptr, &flags,
addr, &slen, &portfd[0], nullptr);
// 997 is the error code for queued ops
int s_errno = ::WSAGetLastError();
if(ret && s_errno != 997)
{
llarp::LogWarn("recv socket error ", s_errno);
return -1;
}
udp->recvfrom(udp, addr, llarp::InitBuffer(buf, sz));
return 0;
}
virtual int
sendto(const sockaddr* to, const void* data, size_t sz)
{
printf("sendto\n");
socklen_t slen;
WSABUF wbuf = {(u_long)sz, (char*)data};
switch(to->sa_family)
{
case AF_INET:
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
slen = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
// WSASendTo
llarp::LogDebug("write ", sz, " bytes into socket");
ssize_t sent = ::WSASendTo(std::get< SOCKET >(fd), &wbuf, 1, nullptr, 0,
to, slen, &portfd[1], nullptr);
int s_errno = ::WSAGetLastError();
if(sent && s_errno != 997)
{
llarp::LogWarn("send socket error ", s_errno);
return -1;
}
return 0;
}
};
struct tun : public ev_io
{
llarp_tun_io* t;
device* tunif;
OVERLAPPED* tun_async[2];
tun(llarp_tun_io* tio, llarp_ev_loop* l)
: ev_io(INVALID_HANDLE_VALUE,
new LossyWriteQueue_t("win32_tun_write", l, l))
new LossyWriteQueue_t("win32_tun_write_queue", l, l))
, t(tio)
, tunif(tuntap_init()){};
, tunif(tuntap_init())
{
this->is_tun = true;
};
int
sendto(const sockaddr* to, const void* data, size_t sz)
{
(void)(to);
(void)(data);
(void)(sz);
UNREFERENCED_PARAMETER(to);
UNREFERENCED_PARAMETER(data);
UNREFERENCED_PARAMETER(sz);
return -1;
}
@ -214,8 +139,8 @@ namespace llarp
if(t->before_write)
{
t->before_write(t);
ev_io::flush_write();
}
ev_io::flush_write();
}
bool
@ -227,12 +152,6 @@ namespace llarp
return true;
}
ssize_t
do_write(void* data, size_t sz)
{
return WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, tun_async[1]);
}
int
read(byte_t* buf, size_t sz)
{
@ -247,8 +166,6 @@ namespace llarp
bool
setup()
{
llarp::LogDebug("set ifname to ", t->ifname);
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
@ -261,14 +178,16 @@ namespace llarp
}
if(tuntap_up(tunif) == -1)
{
llarp::LogWarn("failed to put interface up: ", strerror(errno));
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;
}
fd = tunif->tun_fd;
tun_async[0] = &tunif->ovl[0];
tun_async[1] = &tunif->ovl[1];
if(std::get< HANDLE >(fd) == INVALID_HANDLE_VALUE)
fd.tun = tunif->tun_fd;
if(fd.tun == INVALID_HANDLE_VALUE)
return false;
// we're already non-blocking
@ -280,13 +199,79 @@ 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()
{
if(udp->tick)
udp->tick(udp);
return true;
}
int
read(byte_t* buf, size_t sz)
{
llarp_buffer_t b;
b.base = buf;
b.cur = b.base;
sockaddr_in6 src;
socklen_t slen = sizeof(sockaddr_in6);
sockaddr* addr = (sockaddr*)&src;
ssize_t ret = ::recvfrom(fd.socket, (char*)b.base, sz, 0, addr, &slen);
if(ret < 0)
return -1;
if(static_cast< size_t >(ret) > sz)
return -1;
b.sz = ret;
udp->recvfrom(udp, addr, b);
return 0;
}
int
sendto(const sockaddr* to, const void* data, size_t sz)
{
socklen_t slen;
switch(to->sa_family)
{
case AF_INET:
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
slen = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
ssize_t sent = ::sendto(fd.socket, (char*)data, sz, 0, to, slen);
if(sent == -1)
{
char ebuf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
ebuf, 1024, nullptr);
llarp::LogWarn(ebuf);
}
return sent;
}
};
}; // namespace llarp
struct llarp_win32_loop : public llarp_ev_loop
{
HANDLE iocpfd;
upoll_t* upollfd;
HANDLE tun_event_queue;
llarp_win32_loop() : iocpfd(INVALID_HANDLE_VALUE)
llarp_win32_loop() : upollfd(nullptr), tun_event_queue(INVALID_HANDLE_VALUE)
{
}
@ -294,9 +279,8 @@ struct llarp_win32_loop : public llarp_ev_loop
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr)
{
// create socket
SOCKET fd = WSASocket(remoteaddr->sa_family, SOCK_STREAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
int fd = usocket(remoteaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, remoteaddr, tcp);
add_ev(conn, true);
@ -304,19 +288,11 @@ struct llarp_win32_loop : public llarp_ev_loop
return true;
}
~llarp_win32_loop()
{
if(iocpfd != INVALID_HANDLE_VALUE)
::CloseHandle(iocpfd);
iocpfd = INVALID_HANDLE_VALUE;
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
SOCKET fd = WSASocket(bindaddr->sa_family, SOCK_STREAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
int fd = usocket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
@ -331,107 +307,157 @@ struct llarp_win32_loop : public llarp_ev_loop
sz = 110; // current size in 10.0.17763, verify each time the beta PSDK
// is updated
}
if(::bind(fd, bindaddr, sz) == SOCKET_ERROR)
if(::bind(fd, bindaddr, sz) == -1)
{
::closesocket(fd);
uclose(fd);
return nullptr;
}
if(::listen(fd, 5) == SOCKET_ERROR)
if(ulisten(fd, 5) == -1)
{
::closesocket(fd);
uclose(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return new llarp::tcp_serv(this, fd, tcp);
}
return serv;
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = ev->fd.socket;
return ev && add_ev(ev, false);
}
bool
init()
~llarp_win32_loop()
{
if(iocpfd == INVALID_HANDLE_VALUE)
iocpfd = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
if(upollfd)
upoll_destroy(upollfd);
if(tun_event_queue != INVALID_HANDLE_VALUE)
CloseHandle(tun_event_queue);
}
if(iocpfd == INVALID_HANDLE_VALUE)
return false;
bool
running() const
{
return (upollfd != nullptr) && (tun_event_queue != INVALID_HANDLE_VALUE);
}
return true;
bool
init()
{
if(!upollfd)
upollfd = upoll_create(1);
if(tun_event_queue == INVALID_HANDLE_VALUE)
tun_event_queue =
CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1024);
return upollfd && (tun_event_queue != INVALID_HANDLE_VALUE);
}
// it works! -despair86, 3-Aug-18 @0420
int
tick(int ms)
{
OVERLAPPED_ENTRY events[1024];
memset(&events, 0, sizeof(OVERLAPPED_ENTRY) * 1024);
ULONG result = 0;
::GetQueuedCompletionStatusEx(iocpfd, events, 1024, &result, ms, false);
ULONG idx = 0;
while(idx < result)
{
llarp::ev_io* ev =
reinterpret_cast< llarp::ev_io* >(events[idx].lpCompletionKey);
if(ev && events[idx].lpOverlapped)
upoll_event_t events[1024];
int result;
result = upoll_wait(upollfd, events, 1024, ms);
if(result > 0)
{
int idx = 0;
while(idx < result)
{
auto amount =
std::min(EV_READ_BUF_SZ, events[idx].dwNumberOfBytesTransferred);
if(ev->write)
ev->flush_write_buffers(amount);
else
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
memcpy(readbuf, events[idx].lpOverlapped->Pointer, amount);
ev->read(readbuf, amount);
if(events[idx].events & UPOLLERR)
{
ev->error();
}
else
{
if(events[idx].events & UPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & UPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
}
++idx;
}
tick_listeners();
DWORD size = 0;
OVERLAPPED* ovl = nullptr;
ULONG_PTR listener = 0;
asio_evt_pkt* pkt;
while(
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, ms))
{
pkt = (asio_evt_pkt*)ovl;
llarp::ev_io* ev = reinterpret_cast< llarp::ev_io* >(listener);
/*if(size != pkt->sz)
llarp::LogWarn("incomplete async io operation: got ", size,
" bytes, expected ", pkt->sz, " bytes");*/
if(!pkt->write)
ev->read(readbuf, size);
else
{
ev->flush_write_buffers(pkt->sz);
printf("write tun\n");
}
++result;
delete pkt;
}
if(result != -1)
tick_listeners();
return result;
}
// ok apparently this isn't being used yet...
int
run()
{
// The only field we really care about is
// the listener_id, as it contains the address
// of the udp_listener instance.
DWORD iolen = 0;
// ULONG_PTR is guaranteed to be the same size
// as an arch-specific pointer value
ULONG_PTR ev_id = 0;
WSAOVERLAPPED* qdata = nullptr;
int idx = 0;
BOOL result =
::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, 10);
if(result && qdata)
{
llarp::udp_listener* ev = reinterpret_cast< llarp::udp_listener* >(ev_id);
if(ev)
upoll_event_t events[1024];
int result;
do
{
result = upoll_wait(upollfd, events, 1024, EV_TICK_INTERVAL);
if(result > 0)
{
llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id,
"\tqdata: ", qdata);
if(iolen <= sizeof(readbuf))
ev->read(readbuf, iolen);
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(events[idx].events & UPOLLERR)
{
ev->error();
}
else
{
if(events[idx].events & UPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & UPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
}
}
++idx;
}
if(!idx)
return -1;
else
{
result = idx;
tick_listeners();
}
if(result != -1)
tick_listeners();
} while(upollfd);
return result;
}
SOCKET
int
udp_bind(const sockaddr* addr)
{
socklen_t slen;
@ -444,28 +470,26 @@ struct llarp_win32_loop : public llarp_ev_loop
slen = sizeof(struct sockaddr_in6);
break;
default:
return INVALID_SOCKET;
return -1;
}
SOCKET fd = WSASocket(addr->sa_family, SOCK_DGRAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
int fd = usocket(addr->sa_family, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("WSASocket()");
return INVALID_SOCKET;
perror("usocket()");
return -1;
}
if(addr->sa_family == AF_INET6)
{
// enable dual stack explicitly
int dual = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&dual,
sizeof(dual))
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&dual, sizeof(dual))
== -1)
{
// failed
perror("setsockopt()");
closesocket(fd);
return INVALID_SOCKET;
close(fd);
return -1;
}
}
llarp::Addr a(*addr);
@ -473,49 +497,23 @@ struct llarp_win32_loop : public llarp_ev_loop
if(bind(fd, addr, slen) == -1)
{
perror("bind()");
closesocket(fd);
return INVALID_SOCKET;
close(fd);
return -1;
}
llarp::LogDebug("socket fd is ", fd);
return fd;
}
bool
close_ev(llarp::ev_io* ev)
{
// On Windows, just close the descriptor to decrease the iocp refcount
// and stop any pending I/O
BOOL stopped;
int close_fd;
if(std::holds_alternative< SOCKET >(ev->fd))
{
stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
close_fd = closesocket(std::get< SOCKET >(ev->fd));
}
else
if(ev->is_tun)
{
stopped = ::CancelIo(std::get< HANDLE >(ev->fd));
close_fd = CloseHandle(std::get< HANDLE >(ev->fd));
if(close_fd)
close_fd = 0; // must be zero
else
close_fd = 1;
CancelIo(ev->fd.tun);
CloseHandle(ev->fd.tun);
return true;
}
return close_fd == 0 && stopped == TRUE;
}
llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src)
{
SOCKET fd = udp_bind(src);
llarp::LogDebug("new socket fd is ", fd);
if(fd == INVALID_SOCKET)
return nullptr;
llarp::udp_listener* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
return upoll_ctl(upollfd, UPOLL_CTL_DEL, ev->fd.socket, nullptr) != -1;
}
llarp::ev_io*
@ -523,60 +521,49 @@ struct llarp_win32_loop : public llarp_ev_loop
{
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
{
return t;
}
delete t;
return nullptr;
}
bool
add_ev(llarp::ev_io* ev, bool write)
llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src)
{
ev->listener_id = reinterpret_cast< ULONG_PTR >(ev);
// if the write flag was set earlier,
// clear it on demand
if(ev->write && !write)
ev->write = false;
int fd = udp_bind(src);
if(fd == -1)
return nullptr;
llarp::ev_io* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
}
bool
add_ev(llarp::ev_io* e, bool write)
{
if(e->is_tun)
{
asio_evt_pkt* pkt = new asio_evt_pkt;
pkt->write = false;
pkt->sz = sizeof(readbuf);
CreateIoCompletionPort(e->fd.tun, tun_event_queue, (ULONG_PTR)e, 1024);
// queue an initial read
ReadFile(e->fd.tun, readbuf, sizeof(readbuf), nullptr, &pkt->pkt);
goto add;
}
upoll_event_t ev;
ev.data.ptr = e;
ev.events = UPOLLIN | UPOLLERR;
if(write)
ev->write = true;
// now write a blank packet containing nothing but the address of
// the event listener
if(ev->isTCP)
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
else
goto start_loop;
}
if(std::holds_alternative< SOCKET >(ev->fd))
ev.events |= UPOLLOUT;
if(upoll_ctl(upollfd, UPOLL_CTL_ADD, e->fd.socket, &ev) == -1)
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
}
else
{
if(!::CreateIoCompletionPort(std::get< HANDLE >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
delete e;
return false;
}
start_loop:
PostQueuedCompletionStatus(iocpfd, 0, ev->listener_id, nullptr);
handlers.emplace_back(ev);
add:
handlers.emplace_back(e);
return true;
}
@ -604,31 +591,24 @@ struct llarp_win32_loop : public llarp_ev_loop
return ret;
}
bool
running() const
{
return iocpfd != INVALID_HANDLE_VALUE;
}
bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = std::get< SOCKET >(ev->fd);
return ev && add_ev(ev, false);
}
void
stop()
{
// Are we leaking any file descriptors?
// This was part of the reason I had this
// in the destructor.
/*if(iocpfd != INVALID_HANDLE_VALUE)
::CloseHandle(iocpfd);
iocpfd = INVALID_HANDLE_VALUE;*/
if(upollfd)
upoll_destroy(upollfd);
upollfd = nullptr;
if(tun_event_queue != INVALID_HANDLE_VALUE)
{
CloseHandle(tun_event_queue);
tun_event_queue = INVALID_HANDLE_VALUE;
}
}
};
extern "C" asio_evt_pkt*
getTunEventPkt()
{
return new asio_evt_pkt;
}
#endif

@ -280,7 +280,8 @@ namespace llarp
}
std::string nmask_str = v.substr(1 + pos);
std::string host_str = v.substr(0, pos);
strncpy(m_Tun.ifaddr, host_str.c_str(), sizeof(m_Tun.ifaddr));
// string, or just a plain char array?
strncpy(m_Tun.ifaddr, host_str.c_str(), sizeof(m_Tun.ifaddr) - 1);
m_Tun.netmask = std::atoi(nmask_str.c_str());
llarp::Addr ifaddr(host_str);
@ -292,7 +293,7 @@ namespace llarp
}
if(k == "ifname")
{
strncpy(m_Tun.ifname, v.c_str(), sizeof(m_Tun.ifname));
strncpy(m_Tun.ifname, v.c_str(), sizeof(m_Tun.ifname) - 1);
llarp::LogInfo(Name(), " set ifname to ", m_Tun.ifname);
}
if(k == "exit-whitelist")

@ -267,7 +267,7 @@ namespace llarp
struct addrinfo hint, *res = NULL;
int ret;
memset(&hint, '\0', sizeof hint);
memset(&hint, 0, sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;

@ -17,6 +17,11 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#endif
#ifndef IP_DONTFRAGMENT
#define IP_DONTFRAGMENT IP_DONTFRAG
#endif
namespace llarp
@ -329,12 +334,77 @@ namespace llarp
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
llarp::LogDebug("utp_sendto ", Addr(*arg->address), " ", arg->len,
" bytes");
// For whatever reason, the UTP_UDP_DONTFRAG flag is set
// on the socket itself....which isn't correct and causes
// winsock (at minimum) to reeee
// here, we check its value, then set fragmentation the _right_
// way. Naturally, Linux has its own special procedure.
// Of course, the flag itself is cleared. -rick
#ifndef _WIN32
// No practical method of doing this on NetBSD or Darwin
// without resorting to raw sockets
#if !(__NetBSD__ || __OpenBSD__ || (__APPLE__ && __MACH__))
#ifndef __linux__
if(arg->flags == 2)
{
int val = 1;
setsockopt(l->m_udp.fd, IPPROTO_IP, IP_DONTFRAGMENT, &val,
sizeof(val));
}
else
{
int val = 0;
setsockopt(l->m_udp.fd, IPPROTO_IP, IP_DONTFRAGMENT, &val,
sizeof(val));
}
#else
if(arg->flags == 2)
{
int val = IP_PMTUDISC_DO;
setsockopt(l->m_udp.fd, IPPROTO_IP, IP_MTU_DISCOVER, &val,
sizeof(val));
}
else
{
int val = IP_PMTUDISC_DONT;
setsockopt(l->m_udp.fd, IPPROTO_IP, IP_MTU_DISCOVER, &val,
sizeof(val));
}
#endif
#endif
arg->flags = 0;
if(::sendto(l->m_udp.fd, (char*)arg->buf, arg->len, arg->flags,
arg->address, arg->address_len)
== -1
&& errno)
#else
if(arg->flags == 2)
{
char val = 1;
setsockopt(l->m_udp.fd, IPPROTO_IP, IP_DONTFRAGMENT, &val,
sizeof(val));
}
else
{
char val = 0;
setsockopt(l->m_udp.fd, IPPROTO_IP, IP_DONTFRAGMENT, &val,
sizeof(val));
}
arg->flags = 0;
if(::sendto(l->m_udp.fd, (char*)arg->buf, arg->len, arg->flags,
arg->address, arg->address_len)
== -1)
#endif
{
#ifdef _WIN32
char buf[1024];
int err = WSAGetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_NEUTRAL,
buf, 1024, nullptr);
llarp::LogError("sendto failed: ", buf);
#else
llarp::LogError("sendto failed: ", strerror(errno));
#endif
}
return 0;
}
@ -369,7 +439,7 @@ namespace llarp
LinkLayer(llarp_router* r) : ILinkLayer()
{
router = r;
router = r;
_utp_ctx = utp_init(2);
utp_context_set_userdata(_utp_ctx, this);
utp_set_callback(_utp_ctx, UTP_SENDTO, &LinkLayer::SendTo);
@ -421,12 +491,12 @@ namespace llarp
memset(&msg, 0, sizeof(msg));
msg.msg_name = &remote;
msg.msg_namelen = sizeof(remote);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_control = ancillary_buf;
msg.msg_name = &remote;
msg.msg_namelen = sizeof(remote);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_control = ancillary_buf;
msg.msg_controllen = sizeof(ancillary_buf);
len = recvmsg(m_udp.fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
@ -457,7 +527,7 @@ namespace llarp
continue;
}
icmp_addr = (struct sockaddr*)SO_EE_OFFENDER(e);
icmp_sin = (struct sockaddr_in*)icmp_addr;
icmp_sin = (struct sockaddr_in*)icmp_addr;
if(icmp_sin->sin_port != 0)
{
continue;
@ -568,22 +638,22 @@ namespace llarp
{
DiscardMessage msg;
byte_t tmp[128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
if(!this->QueueWriteBuffers(buf))
return false;
}
return true;
};
gotLIM = false;
gotLIM = false;
recvBufOffset = 0;
TimedOut = [&](llarp_time_t now) -> bool {
TimedOut = [&](llarp_time_t now) -> bool {
return this->IsTimedOut(now) || this->state == eClose;
};
GetPubKey = std::bind(&BaseSession::RemotePubKey, this);
GetPubKey = std::bind(&BaseSession::RemotePubKey, this);
lastActive = parent->now();
// Pump = []() {};
Pump = std::bind(&BaseSession::PumpWrite, this);
@ -595,7 +665,7 @@ namespace llarp
return this->state == eSessionReady || this->state == eLinkEstablished;
};
SendClose = std::bind(&BaseSession::Close, this);
SendClose = std::bind(&BaseSession::Close, this);
GetRemoteEndpoint = std::bind(&BaseSession::RemoteEndpoint, this);
}
@ -605,12 +675,12 @@ namespace llarp
{
remoteRC.Clear();
remoteTransportPubKey = addr.pubkey;
remoteRC = rc;
sock = s;
remoteRC = rc;
sock = s;
assert(utp_set_userdata(sock, this) == this);
assert(s == sock);
remoteAddr = addr;
Start = std::bind(&BaseSession::Connect, this);
Start = std::bind(&BaseSession::Connect, this);
GotLIM =
std::bind(&BaseSession::OutboundLIM, this, std::placeholders::_1);
}
@ -625,7 +695,7 @@ namespace llarp
assert(s == sock);
assert(utp_set_userdata(sock, this) == this);
remoteAddr = addr;
Start = []() {};
Start = []() {};
GotLIM = std::bind(&BaseSession::InboundLIM, this, std::placeholders::_1);
}
@ -637,7 +707,7 @@ namespace llarp
return false;
}
remoteRC = msg->rc;
gotLIM = true;
gotLIM = true;
if(!DoKeyExchange(Router()->crypto.transport_dh_server, msg->N,
remoteRC.enckey, parent->TransportSecretKey()))
return false;
@ -651,8 +721,8 @@ namespace llarp
if(sendq.size() >= MaxSendQueueSize)
return false;
llarp::LogDebug("write ", buf.sz, " bytes to ", remoteAddr);
lastActive = parent->now();
size_t sz = buf.sz;
lastActive = parent->now();
size_t sz = buf.sz;
byte_t* ptr = buf.base;
while(sz)
{
@ -672,7 +742,7 @@ namespace llarp
return false;
}
remoteRC = msg->rc;
gotLIM = true;
gotLIM = true;
// TODO: update address info pubkey
return DoKeyExchange(Router()->crypto.transport_dh_client, msg->N,
remoteTransportPubKey, Router()->encryption);
@ -712,7 +782,7 @@ namespace llarp
return;
}
// rewind
buf.sz = buf.cur - buf.base;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// send
if(!SendMessageBuffer(buf))
@ -835,14 +905,14 @@ namespace llarp
sendq.emplace_back();
auto& buf = sendq.back();
vecq.emplace_back();
auto& vec = vecq.back();
auto& vec = vecq.back();
vec.iov_base = buf.data();
vec.iov_len = FragmentBufferSize;
vec.iov_len = FragmentBufferSize;
llarp::LogDebug("encrypt then hash ", sz, " bytes last=", isLastFragment);
buf.Randomize();
byte_t* nonce = buf.data() + FragmentHashSize;
byte_t* body = nonce + FragmentNonceSize;
byte_t* base = body;
byte_t* body = nonce + FragmentNonceSize;
byte_t* base = body;
if(isLastFragment)
htobe32buf(body, 0);
else
@ -859,8 +929,8 @@ namespace llarp
Router()->crypto.xchacha20(payload, sessionKey, nonce);
payload.base = nonce;
payload.cur = payload.base;
payload.sz = FragmentBufferSize - FragmentHashSize;
payload.cur = payload.base;
payload.sz = FragmentBufferSize - FragmentHashSize;
// key'd hash
Router()->crypto.hmac(buf.data(), payload, sessionKey);
}

@ -68,8 +68,25 @@ operator==(const sockaddr_in6& a, const sockaddr_in6& b)
#include <iphlpapi.h>
#include <strsafe.h>
// current strategy: mingw 32-bit builds call an inlined version of the function
// microsoft c++ and mingw 64-bit builds call the normal function
#define DEFAULT_BUFFER_SIZE 15000
// the inline monkey patch for downlevel platforms
#ifndef _MSC_VER
extern "C" DWORD FAR PASCAL
_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen);
#endif
// in any case, we still need to implement some form of
// getifaddrs(3) with compatible semantics on NT...
// daemon.ini section [bind] will have something like
// [bind]
// Ethernet=1090
// inside, since that's what we use in windows to refer to
// network interfaces
struct llarp_nt_ifaddrs_t
{
struct llarp_nt_ifaddrs_t* ifa_next; /* Pointer to the next structure. */
@ -123,6 +140,148 @@ llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
return 0;
}
/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes
* 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced
* with -D_USE_32BIT_TIME_T with side effects to everything else.
*
* Only supports IPv4 addressing similar to SIOCGIFCONF socket option.
*
* Interfaces that are not "operationally up" will return the address 0.0.0.0,
* this includes adapters with static IP addresses but with disconnected cable.
* This is documented under the GetIpAddrTable API. Interface status can only
* be determined by the address, a separate flag is introduced with the
* GetAdapterAddresses API.
*
* The IPv4 loopback interface is not included.
*
* Available in Windows 2000 and Wine 1.0.
*/
static bool
_llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
{
DWORD dwRet;
ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE;
PIP_ADAPTER_INFO pAdapterInfo = nullptr;
PIP_ADAPTER_INFO pAdapter = nullptr;
/* loop to handle interfaces coming online causing a buffer overflow
* between first call to list buffer length and second call to enumerate.
*/
for(unsigned i = 3; i; i--)
{
#ifdef DEBUG
fprintf(stderr, "IP_ADAPTER_INFO buffer length %lu bytes.\n", ulOutBufLen);
#endif
pAdapterInfo = (IP_ADAPTER_INFO*)_llarp_nt_heap_alloc(ulOutBufLen);
dwRet = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if(ERROR_BUFFER_OVERFLOW == dwRet)
{
_llarp_nt_heap_free(pAdapterInfo);
pAdapterInfo = nullptr;
}
else
{
break;
}
}
switch(dwRet)
{
case ERROR_SUCCESS: /* NO_ERROR */
break;
case ERROR_BUFFER_OVERFLOW:
errno = ENOBUFS;
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
return false;
default:
errno = dwRet;
#ifdef DEBUG
fprintf(stderr, "system call failed: %lu\n", GetLastError());
#endif
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
return false;
}
/* count valid adapters */
int n = 0, k = 0;
for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
{
for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr;
pIPAddr = pIPAddr->Next)
{
/* skip null adapters */
if(strlen(pIPAddr->IpAddress.String) == 0)
continue;
++n;
}
}
#ifdef DEBUG
fprintf(stderr, "GetAdaptersInfo() discovered %d interfaces.\n", n);
#endif
/* contiguous block for adapter list */
struct _llarp_nt_ifaddrs_t* ifa =
llarp_nt_new0(struct _llarp_nt_ifaddrs_t, n);
struct _llarp_nt_ifaddrs_t* ift = ifa;
/* now populate list */
for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
{
for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr;
pIPAddr = pIPAddr->Next)
{
/* skip null adapters */
if(strlen(pIPAddr->IpAddress.String) == 0)
continue;
/* address */
ift->_ifa.ifa_addr = (struct sockaddr*)&ift->_addr;
assert(1
== llarp_nt_sockaddr_pton(pIPAddr->IpAddress.String,
ift->_ifa.ifa_addr));
/* name */
#ifdef DEBUG
fprintf(stderr, "name:%s IPv4 index:%lu\n", pAdapter->AdapterName,
pAdapter->Index);
#endif
ift->_ifa.ifa_name = ift->_name;
StringCchCopyN(ift->_ifa.ifa_name, 128, pAdapter->AdapterName, 128);
/* flags: assume up, broadcast and multicast */
ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST;
if(pAdapter->Type == MIB_IF_TYPE_LOOPBACK)
ift->_ifa.ifa_flags |= IFF_LOOPBACK;
/* netmask */
ift->_ifa.ifa_netmask = (sockaddr*)&ift->_netmask;
assert(1
== llarp_nt_sockaddr_pton(pIPAddr->IpMask.String,
ift->_ifa.ifa_netmask));
/* next */
if(k++ < (n - 1))
{
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
}
else
{
ift->_ifa.ifa_next = nullptr;
}
}
}
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
return true;
}
#if 0
/* Supports both IPv4 and IPv6 addressing. The size of IP_ADAPTER_ADDRESSES
* changes between Windows XP, XP SP1, and Vista with additional members.
*
@ -136,6 +295,9 @@ llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
* and lower layer down.
*
* Available in Windows XP and Wine 1.3.
*
* NOTE(despair): an inline implementation is provided, much like
* getaddrinfo(3) for old hosts. See "win32_intrnl.*"
*/
static bool
_llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
@ -152,12 +314,12 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "IP_ADAPTER_ADDRESSES buffer length %lu bytes.\n", dwSize);
#endif
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_MULTICAST,
nullptr, pAdapterAddresses, &dwSize);
dwRet = _GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_MULTICAST,
nullptr, pAdapterAddresses, &dwSize);
if(ERROR_BUFFER_OVERFLOW == dwRet)
{
_llarp_nt_heap_free(pAdapterAddresses);
@ -459,13 +621,18 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
return TRUE;
}
#endif
// an implementation of if_nametoindex(3) based on GetAdapterIndex(2)
// with a fallback to GetAdaptersAddresses(2) commented out for now
// unless it becomes evident that the first codepath fails in certain
// edge cases?
static unsigned
_llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
{
ULONG ifIndex;
DWORD dwSize = 4096, dwRet;
IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter;
DWORD /* dwSize = 4096,*/ dwRet;
// IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter;
char szAdapterName[256];
if(!ifname)
@ -479,6 +646,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
else
return 0;
#if 0
/* fallback to finding index via iterating adapter list */
/* loop to handle interfaces coming online causing a buffer overflow
@ -487,7 +655,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
for(unsigned i = 3; i; i--)
{
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
dwRet = GetAdaptersAddresses(
dwRet = _GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST,
@ -534,6 +702,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
if(pAdapterAddresses)
_llarp_nt_heap_free(pAdapterAddresses);
return 0;
#endif
}
// the emulated getifaddrs(3) itself.
@ -545,7 +714,7 @@ llarp_nt_getifaddrs(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "llarp_nt_getifaddrs (ifap:%p error:%p)\n", (void*)ifap,
(void*)errno);
#endif
return _llarp_nt_getadaptersaddresses(ifap);
return _llarp_nt_getadaptersinfo(ifap);
}
static void

@ -11,6 +11,7 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif

@ -0,0 +1,315 @@
#if defined(__MINGW32__) && !defined(_WIN64)
/*
* Contains routines missing from WS2_32.DLL until 2006, if yer using
* Microsoft C/C++, then this code is irrelevant, as the official
* Platform SDK already links against these routines in the correct
* libraries.
*
* -despair86 30/07/18
*/
// these need to be in a specific order
#include <assert.h>
#include <llarp/net.h>
#include <windows.h>
#include <iphlpapi.h>
#if WINNT_CROSS_COMPILE && !NTSTATUS
typedef LONG NTSTATUS;
#endif
#include "win32_intrnl.h"
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
int address_length;
DWORD string_length = size;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
memset(&sa, 0, sizeof(sa));
switch(af)
{
case AF_INET:
address_length = sizeof(struct sockaddr_in);
sin->sin_family = af;
memcpy(&sin->sin_addr, src, sizeof(struct in_addr));
break;
case AF_INET6:
address_length = sizeof(struct sockaddr_in6);
sin6->sin6_family = af;
memcpy(&sin6->sin6_addr, src, sizeof(struct in6_addr));
break;
default:
return NULL;
}
if(WSAAddressToString((LPSOCKADDR)&sa, address_length, NULL, dst,
&string_length)
== 0)
{
return dst;
}
return NULL;
}
int
inet_pton(int af, const char *src, void *dst)
{
int address_length;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
switch(af)
{
case AF_INET:
address_length = sizeof(struct sockaddr_in);
break;
case AF_INET6:
address_length = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
if(WSAStringToAddress((LPTSTR)src, af, NULL, (LPSOCKADDR)&sa, &address_length)
== 0)
{
switch(af)
{
case AF_INET:
memcpy(dst, &sin->sin_addr, sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(dst, &sin6->sin6_addr, sizeof(struct in6_addr));
break;
}
return 1;
}
return 0;
}
typedef struct _InterfaceIndexTable
{
DWORD numIndexes;
IF_INDEX indexes[1];
} InterfaceIndexTable;
// windows 2000
// todo(despair86): implement IPv6 detection using
// the ipv6 preview stack/adv net pack from 1999/2001
DWORD FAR PASCAL
_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen)
{
InterfaceIndexTable *indexTable;
IFInfo ifInfo;
int i;
ULONG ret, requiredSize = 0;
PIP_ADAPTER_ADDRESSES currentAddress;
PUCHAR currentLocation;
HANDLE tcpFile;
(void)(Family);
if(!pOutBufLen)
return ERROR_INVALID_PARAMETER;
if(Reserved)
return ERROR_INVALID_PARAMETER;
indexTable = getInterfaceIndexTable();
if(!indexTable)
return ERROR_NOT_ENOUGH_MEMORY;
ret = openTcpFile(&tcpFile, FILE_READ_DATA);
if(!NT_SUCCESS(ret))
return ERROR_NO_DATA;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
/* The whole struct */
requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
/* Friendly name */
if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
requiredSize +=
strlen((char *)ifInfo.if_info.ent.if_descr) + 1; // FIXME
/* Adapter name */
requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
requiredSize += 2 * sizeof(WCHAR);
/* We're only going to implement what's required for XP SP0 */
}
}
#ifdef DEBUG
fprintf(stderr, "size: %ld, requiredSize: %ld\n", *pOutBufLen, requiredSize);
#endif
if(!pAdapterAddresses || *pOutBufLen < requiredSize)
{
*pOutBufLen = requiredSize;
closeTcpFile(tcpFile);
free(indexTable);
return ERROR_BUFFER_OVERFLOW;
}
RtlZeroMemory(pAdapterAddresses, requiredSize);
/* Let's set up the pointers */
currentAddress = pAdapterAddresses;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
currentLocation =
(PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
/* FIXME: Friendly name */
if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
{
currentAddress->FriendlyName = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
}
/* Adapter name */
currentAddress->AdapterName = (PVOID)currentLocation;
currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Address.lpSockaddr =
(PVOID)currentLocation;
currentLocation += sizeof(struct sockaddr);
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
currentAddress->DnsSuffix = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Description = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Next = (PVOID)currentLocation;
/* Terminate the last address correctly */
if(i == 0)
currentAddress->Next = NULL;
/* We're only going to implement what's required for XP SP0 */
currentAddress = currentAddress->Next;
}
}
/* Now again, for real this time */
currentAddress = pAdapterAddresses;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
/* Make sure we're not looping more than we hoped for */
assert(currentAddress);
/* Alignment information */
currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
currentAddress->IfIndex = indexTable->indexes[i];
/* Adapter name */
strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress->Length =
sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Flags = 0; // FIXME
currentAddress->FirstUnicastAddress->Next =
NULL; // FIXME: Support more than one address per adapter
currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family =
AF_INET;
memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
&ifInfo.ip_addr.iae_addr, sizeof(ifInfo.ip_addr.iae_addr));
currentAddress->FirstUnicastAddress->Address.iSockaddrLength =
sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
currentAddress->FirstUnicastAddress->PrefixOrigin =
IpPrefixOriginOther; // FIXME
currentAddress->FirstUnicastAddress->SuffixOrigin =
IpSuffixOriginOther; // FIXME
currentAddress->FirstUnicastAddress->DadState =
IpDadStatePreferred; // FIXME
currentAddress->FirstUnicastAddress->ValidLifetime =
0xFFFFFFFF; // FIXME
currentAddress->FirstUnicastAddress->PreferredLifetime =
0xFFFFFFFF; // FIXME
currentAddress->FirstUnicastAddress->LeaseLifetime =
0xFFFFFFFF; // FIXME
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
currentAddress->FirstAnycastAddress = NULL;
currentAddress->FirstMulticastAddress = NULL;
currentAddress->FirstDnsServerAddress = NULL;
/* FIXME: Implement dns suffix, description, and friendly name */
currentAddress->DnsSuffix[0] = UNICODE_NULL;
currentAddress->Description[0] = UNICODE_NULL;
currentAddress->FriendlyName[0] = UNICODE_NULL;
/* Physical Address */
memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr,
ifInfo.if_info.ent.if_physaddrlen);
currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
/* Flags */
currentAddress->Flags = 0; // FIXME
/* MTU */
currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
/* Interface type */
currentAddress->IfType = ifInfo.if_info.ent.if_type;
/* Operational status */
if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
currentAddress->OperStatus = IfOperStatusUp;
else
currentAddress->OperStatus = IfOperStatusDown;
/* We're only going to implement what's required for XP SP0 */
/* Move to the next address */
currentAddress = currentAddress->Next;
}
}
closeTcpFile(tcpFile);
free(indexTable);
return NO_ERROR;
}
#endif

@ -0,0 +1,572 @@
#if defined(__MINGW32__) && !defined(_WIN64)
/*
* All the user-mode scaffolding necessary to backport GetAdaptersAddresses(2))
* to the NT 5.x series. See further comments for any limitations.
* NOTE: this is dead code, i haven't had time to debug it yet due to illness.
* For now, downlevel platforms use GetAdaptersInfo(2) which is inet4 only.
* -despair86 20/08/18
*/
#include <assert.h>
#include <stdio.h>
// apparently mingw-w64 loses its shit over this
// but only for 32-bit builds, naturally
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
// these need to be in a specific order
#include <windows.h>
#include <winternl.h>
#include <tdi.h>
#include "win32_intrnl.h"
const PWCHAR TcpFileName = L"\\Device\\Tcp";
// from ntdll.dll
typedef void(FAR PASCAL *pRtlInitUString)(UNICODE_STRING *, const WCHAR *);
typedef NTSTATUS(FAR PASCAL *pNTOpenFile)(HANDLE *, ACCESS_MASK,
OBJECT_ATTRIBUTES *,
IO_STATUS_BLOCK *, ULONG, ULONG);
typedef NTSTATUS(FAR PASCAL *pNTClose)(HANDLE);
#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK
#define _TCP_CTL_CODE(Function, Method, Access) \
CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access)
#define IOCTL_TCP_QUERY_INFORMATION_EX \
_TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef struct _InterfaceIndexTable
{
DWORD numIndexes;
DWORD numAllocated;
DWORD indexes[1];
} InterfaceIndexTable;
NTSTATUS
tdiGetMibForIfEntity(HANDLE tcpFile, TDIEntityID *ent,
IFEntrySafelySized *entry)
{
TCP_REQUEST_QUERY_INFORMATION_EX req;
NTSTATUS status = 0;
DWORD returnSize;
#ifdef DEBUG
fprintf(stderr, "TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n",
(int)tcpFile, (int)ent->tei_instance);
#endif
memset(&req, 0, sizeof(req));
req.ID.toi_class = INFO_CLASS_PROTOCOL;
req.ID.toi_type = INFO_TYPE_PROVIDER;
req.ID.toi_id = 1;
req.ID.toi_entity = *ent;
status =
DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), entry, sizeof(*entry), &returnSize, NULL);
if(!status)
{
perror("IOCTL Failed\n");
return 0xc0000001;
}
fprintf(stderr,
"TdiGetMibForIfEntity() => {\n"
" if_index ....................... %lx\n"
" if_type ........................ %lx\n"
" if_mtu ......................... %ld\n"
" if_speed ....................... %lx\n"
" if_physaddrlen ................. %ld\n",
entry->ent.if_index, entry->ent.if_type, entry->ent.if_mtu,
entry->ent.if_speed, entry->ent.if_physaddrlen);
fprintf(stderr,
" if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n"
" if_descr ....................... %s\n",
entry->ent.if_physaddr[0] & 0xff, entry->ent.if_physaddr[1] & 0xff,
entry->ent.if_physaddr[2] & 0xff, entry->ent.if_physaddr[3] & 0xff,
entry->ent.if_physaddr[4] & 0xff, entry->ent.if_physaddr[5] & 0xff,
entry->ent.if_descr);
fprintf(stderr, "} status %08lx\n", status);
return 0;
}
static NTSTATUS
tdiGetSetOfThings(HANDLE tcpFile, DWORD toiClass, DWORD toiType, DWORD toiId,
DWORD teiEntity, DWORD teiInstance, DWORD fixedPart,
DWORD entrySize, PVOID *tdiEntitySet, PDWORD numEntries)
{
TCP_REQUEST_QUERY_INFORMATION_EX req;
PVOID entitySet = 0;
NTSTATUS status = 0;
DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES,
arraySize = entrySize * MAX_TDI_ENTITIES;
memset(&req, 0, sizeof(req));
req.ID.toi_class = toiClass;
req.ID.toi_type = toiType;
req.ID.toi_id = toiId;
req.ID.toi_entity.tei_entity = teiEntity;
req.ID.toi_entity.tei_instance = teiInstance;
/* There's a subtle problem here...
* If an interface is added at this exact instant, (as if by a PCMCIA
* card insertion), the array will still not have enough entries after
* have allocated it after the first DeviceIoControl call.
*
* We'll get around this by repeating until the number of interfaces
* stabilizes.
*/
do
{
status =
DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), 0, 0, &allocationSizeForEntityArray, NULL);
if(!status)
return 0xc0000001;
arraySize = allocationSizeForEntityArray;
entitySet = HeapAlloc(GetProcessHeap(), 0, arraySize);
if(!entitySet)
{
status = ((NTSTATUS)0xC000009A);
return status;
}
status = DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), entitySet, arraySize,
&allocationSizeForEntityArray, NULL);
/* This is why we have the loop -- we might have added an adapter */
if(arraySize == allocationSizeForEntityArray)
break;
HeapFree(GetProcessHeap(), 0, entitySet);
entitySet = 0;
if(!status)
return 0xc0000001;
} while(TRUE); /* We break if the array we received was the size we
* expected. Therefore, we got here because it wasn't */
*numEntries = (arraySize - fixedPart) / entrySize;
*tdiEntitySet = entitySet;
return 0;
}
static NTSTATUS
tdiGetEntityIDSet(HANDLE tcpFile, TDIEntityID **entitySet, PDWORD numEntities)
{
NTSTATUS status =
tdiGetSetOfThings(tcpFile, INFO_CLASS_GENERIC, INFO_TYPE_PROVIDER,
ENTITY_LIST_ID, GENERIC_ENTITY, 0, 0,
sizeof(TDIEntityID), (PVOID *)entitySet, numEntities);
return status;
}
NTSTATUS
tdiGetIpAddrsForIpEntity(HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs,
PDWORD numAddrs)
{
NTSTATUS status;
#ifdef DEBUG
fprintf(stderr, "TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%lx)\n",
tcpFile, ent->tei_instance);
#endif
status = tdiGetSetOfThings(tcpFile, INFO_CLASS_PROTOCOL, INFO_TYPE_PROVIDER,
0x102, CL_NL_ENTITY, ent->tei_instance, 0,
sizeof(IPAddrEntry), (PVOID *)addrs, numAddrs);
return status;
}
static VOID
tdiFreeThingSet(PVOID things)
{
HeapFree(GetProcessHeap(), 0, things);
}
NTSTATUS
openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess)
{
UNICODE_STRING fileName;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
pRtlInitUString _RtlInitUnicodeString;
pNTOpenFile _NTOpenFile;
HANDLE ntdll;
ntdll = GetModuleHandle("ntdll.dll");
_RtlInitUnicodeString =
(pRtlInitUString)GetProcAddress(ntdll, "RtlInitUnicodeString");
_NTOpenFile = (pNTOpenFile)GetProcAddress(ntdll, "NtOpenFile");
_RtlInitUnicodeString(&fileName, TcpFileName);
InitializeObjectAttributes(&objectAttributes, &fileName, OBJ_CASE_INSENSITIVE,
NULL, NULL);
status = _NTOpenFile(tcpFile, DesiredAccess | SYNCHRONIZE, &objectAttributes,
&ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
/* String does not need to be freed: it points to the constant
* string we provided */
if(!NT_SUCCESS(status))
*tcpFile = INVALID_HANDLE_VALUE;
return status;
}
VOID
closeTcpFile(HANDLE h)
{
pNTClose _NTClose;
HANDLE ntdll = GetModuleHandle("ntdll.dll");
_NTClose = (pNTClose)GetProcAddress(ntdll, "NtClose");
assert(h != INVALID_HANDLE_VALUE);
_NTClose(h);
}
BOOL
isLoopback(HANDLE tcpFile, TDIEntityID *loop_maybe)
{
IFEntrySafelySized entryInfo;
NTSTATUS status;
status = tdiGetMibForIfEntity(tcpFile, loop_maybe, &entryInfo);
return NT_SUCCESS(status)
&& (entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
}
BOOL
isIpEntity(HANDLE tcpFile, TDIEntityID *ent)
{
UNREFERENCED_PARAMETER(tcpFile);
return (ent->tei_entity == CL_NL_ENTITY || ent->tei_entity == CO_NL_ENTITY);
}
NTSTATUS
getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID *ent)
{
DWORD numEntities = 0;
DWORD numRoutes = 0;
TDIEntityID *entitySet = 0;
NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
unsigned i;
if(!NT_SUCCESS(status))
return status;
for(i = 0; i < numEntities; i++)
{
if(isIpEntity(tcpFile, &entitySet[i]))
{
fprintf(stderr, "Entity %d is an IP Entity\n", i);
if(numRoutes == index)
break;
else
numRoutes++;
}
}
if(numRoutes == index && i < numEntities)
{
fprintf(stderr, "Index %lu is entity #%d - %04lx:%08lx\n", index, i,
entitySet[i].tei_entity, entitySet[i].tei_instance);
memcpy(ent, &entitySet[i], sizeof(*ent));
tdiFreeThingSet(entitySet);
return 0;
}
else
{
tdiFreeThingSet(entitySet);
return 0xc000001;
}
}
BOOL
isInterface(TDIEntityID *if_maybe)
{
return if_maybe->tei_entity == IF_ENTITY;
}
NTSTATUS
getInterfaceInfoSet(HANDLE tcpFile, IFInfo **infoSet, PDWORD numInterfaces)
{
DWORD numEntities;
TDIEntityID *entIDSet = NULL;
NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entIDSet, &numEntities);
IFInfo *infoSetInt = 0;
int curInterf = 0;
unsigned i;
if(!NT_SUCCESS(status))
{
fprintf(stderr, "getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n",
status);
return status;
}
infoSetInt = HeapAlloc(GetProcessHeap(), 0, sizeof(IFInfo) * numEntities);
if(infoSetInt)
{
for(i = 0; i < numEntities; i++)
{
if(isInterface(&entIDSet[i]))
{
infoSetInt[curInterf].entity_id = entIDSet[i];
status = tdiGetMibForIfEntity(tcpFile, &entIDSet[i],
&infoSetInt[curInterf].if_info);
fprintf(stderr, "tdiGetMibForIfEntity: %08lx\n", status);
if(NT_SUCCESS(status))
{
DWORD numAddrs;
IPAddrEntry *addrs;
TDIEntityID ip_ent;
unsigned j;
status = getNthIpEntity(tcpFile, curInterf, &ip_ent);
if(NT_SUCCESS(status))
status =
tdiGetIpAddrsForIpEntity(tcpFile, &ip_ent, &addrs, &numAddrs);
for(j = 0; NT_SUCCESS(status) && j < numAddrs; j++)
{
fprintf(stderr, "ADDR %d: index %ld (target %ld)\n", j,
addrs[j].iae_index,
infoSetInt[curInterf].if_info.ent.if_index);
if(addrs[j].iae_index == infoSetInt[curInterf].if_info.ent.if_index)
{
memcpy(&infoSetInt[curInterf].ip_addr, &addrs[j],
sizeof(addrs[j]));
curInterf++;
break;
}
}
if(NT_SUCCESS(status))
tdiFreeThingSet(addrs);
}
}
}
tdiFreeThingSet(entIDSet);
if(NT_SUCCESS(status))
{
*infoSet = infoSetInt;
*numInterfaces = curInterf;
}
else
{
HeapFree(GetProcessHeap(), 0, infoSetInt);
}
return status;
}
else
{
tdiFreeThingSet(entIDSet);
return ((NTSTATUS)0xC000009A);
}
}
NTSTATUS
getInterfaceInfoByName(HANDLE tcpFile, char *name, IFInfo *info)
{
IFInfo *ifInfo;
DWORD numInterfaces;
unsigned i;
NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
if(NT_SUCCESS(status))
{
for(i = 0; i < numInterfaces; i++)
{
if(!strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name))
{
memcpy(info, &ifInfo[i], sizeof(*info));
break;
}
}
HeapFree(GetProcessHeap(), 0, ifInfo);
return i < numInterfaces ? 0 : 0xc0000001;
}
return status;
}
NTSTATUS
getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo *info)
{
IFInfo *ifInfo;
DWORD numInterfaces;
NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
unsigned i;
if(NT_SUCCESS(status))
{
for(i = 0; i < numInterfaces; i++)
{
if(ifInfo[i].if_info.ent.if_index == index)
{
memcpy(info, &ifInfo[i], sizeof(*info));
break;
}
}
HeapFree(GetProcessHeap(), 0, ifInfo);
return i < numInterfaces ? 0 : 0xc0000001;
}
return status;
}
NTSTATUS
getIPAddrEntryForIf(HANDLE tcpFile, char *name, DWORD index, IFInfo *ifInfo)
{
NTSTATUS status = name ? getInterfaceInfoByName(tcpFile, name, ifInfo)
: getInterfaceInfoByIndex(tcpFile, index, ifInfo);
if(!NT_SUCCESS(status))
{
fprintf(stderr, "getIPAddrEntryForIf returning %lx\n", status);
}
return status;
}
InterfaceIndexTable *
getInterfaceIndexTableInt(BOOL nonLoopbackOnly)
{
DWORD numInterfaces, curInterface = 0;
unsigned i;
IFInfo *ifInfo;
InterfaceIndexTable *ret = 0;
HANDLE tcpFile;
NTSTATUS status = openTcpFile(&tcpFile, FILE_READ_DATA);
ifInfo = NULL;
if(NT_SUCCESS(status))
{
status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
fprintf(stderr, "InterfaceInfoSet: %08lx, %04lx:%08lx\n", status,
ifInfo->entity_id.tei_entity, ifInfo->entity_id.tei_instance);
if(NT_SUCCESS(status))
{
ret = (InterfaceIndexTable *)calloc(
1, sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
if(ret)
{
ret->numAllocated = numInterfaces;
fprintf(stderr, "NumInterfaces = %ld\n", numInterfaces);
for(i = 0; i < numInterfaces; i++)
{
fprintf(stderr, "Examining interface %d\n", i);
if(!nonLoopbackOnly || !isLoopback(tcpFile, &ifInfo[i].entity_id))
{
fprintf(stderr, "Interface %d matches (%ld)\n", i, curInterface);
ret->indexes[curInterface++] = ifInfo[i].if_info.ent.if_index;
}
}
ret->numIndexes = curInterface;
}
tdiFreeThingSet(ifInfo);
}
closeTcpFile(tcpFile);
}
return ret;
}
InterfaceIndexTable *
getInterfaceIndexTable(void)
{
return getInterfaceIndexTableInt(FALSE);
}
#endif
// there's probably an use case for a _newer_ implementation
// of pthread_setname_np(3), in fact, I may just merge _this_
// upstream...
#if 0
#include <windows.h>
typedef HRESULT(FAR PASCAL *p_SetThreadDescription)(void *, const wchar_t *);
#define EXCEPTION_SET_THREAD_NAME ((DWORD)0x406D1388)
typedef struct _THREADNAME_INFO
{
DWORD dwType; /* must be 0x1000 */
LPCSTR szName; /* pointer to name (in user addr space) */
DWORD dwThreadID; /* thread ID (-1=caller thread) */
DWORD dwFlags; /* reserved for future use, must be zero */
} THREADNAME_INFO;
void
SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
{
THREADNAME_INFO info;
DWORD infosize;
HANDLE hThread;
/* because loonix is SHIT and limits thread names to 16 bytes */
wchar_t thr_name_w[16];
p_SetThreadDescription _SetThreadDescription;
/* current win10 flights now have a new named-thread API, let's try to use
* that first! */
/* first, dlsym(2) the new call from system library */
hThread = NULL;
_SetThreadDescription = (p_SetThreadDescription)GetProcAddress(
GetModuleHandle("kernel32"), "SetThreadDescription");
if(_SetThreadDescription)
{
/* grab another reference to the thread */
hThread = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, dwThreadID);
/* windows takes unicode, our input is utf-8 or plain ascii */
MultiByteToWideChar(CP_ACP, 0, szThreadName, -1, thr_name_w, 16);
if(hThread)
_SetThreadDescription(hThread, thr_name_w);
else
goto old; /* for whatever reason, we couldn't get a handle to the thread.
Just use the old method. */
}
else
{
old:
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
infosize = sizeof(info) / sizeof(DWORD);
__try
{
RaiseException(EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *)&info);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
/* clean up */
if(hThread)
CloseHandle(hThread);
}
#endif

@ -0,0 +1,110 @@
#ifndef WIN32_INTRNL_H
#define WIN32_INTRNL_H
#if defined(__MINGW32__) && !defined(_WIN64)
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
#include <tdiinfo.h>
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned int uint;
/* forward declare, each module has their own idea of what this is */
typedef struct _InterfaceIndexTable InterfaceIndexTable;
typedef struct IFEntry
{
ulong if_index;
ulong if_type;
ulong if_mtu;
ulong if_speed;
ulong if_physaddrlen;
uchar if_physaddr[8];
ulong if_adminstatus;
ulong if_operstatus;
ulong if_lastchange;
ulong if_inoctets;
ulong if_inucastpkts;
ulong if_innucastpkts;
ulong if_indiscards;
ulong if_inerrors;
ulong if_inunknownprotos;
ulong if_outoctets;
ulong if_outucastpkts;
ulong if_outnucastpkts;
ulong if_outdiscards;
ulong if_outerrors;
ulong if_outqlen;
ulong if_descrlen;
uchar if_descr[1];
} IFEntry;
typedef struct IPAddrEntry
{
ulong iae_addr;
ulong iae_index;
ulong iae_mask;
ulong iae_bcastaddr;
ulong iae_reasmsize;
ushort iae_context;
ushort iae_pad;
} IPAddrEntry;
typedef union _IFEntrySafelySized {
CHAR MaxSize[sizeof(DWORD) + sizeof(IFEntry) + 128 + 1];
IFEntry ent;
} IFEntrySafelySized;
#ifndef IFENT_SOFTWARE_LOOPBACK
#define IFENT_SOFTWARE_LOOPBACK 24 /* This is an SNMP constant from rfc1213 */
#endif /*IFENT_SOFTWARE_LOOPBACK*/
/* Encapsulates information about an interface */
typedef struct _IFInfo
{
TDIEntityID entity_id;
IFEntrySafelySized if_info;
IPAddrEntry ip_addr;
} IFInfo;
/* functions */
NTSTATUS
openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess);
VOID
closeTcpFile(HANDLE h);
BOOL
isLoopback(HANDLE tcpFile, TDIEntityID* loop_maybe);
BOOL
isIpEntity(HANDLE tcpFile, TDIEntityID* ent);
NTSTATUS
getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID* ent);
BOOL
isInterface(TDIEntityID* if_maybe);
NTSTATUS
getInterfaceInfoSet(HANDLE tcpFile, IFInfo** infoSet, PDWORD numInterfaces);
NTSTATUS
getInterfaceInfoByName(HANDLE tcpFile, char* name, IFInfo* info);
NTSTATUS
getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo* info);
NTSTATUS
getIPAddrEntryForIf(HANDLE tcpFile, char* name, DWORD index, IFInfo* ifInfo);
InterfaceIndexTable*
getInterfaceIndexTableInt(BOOL nonLoopbackOnly);
InterfaceIndexTable*
getInterfaceIndexTable(void);
#endif
#endif

@ -0,0 +1,69 @@
#ifndef _UP_H_
#define _UP_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#define UPOLL_CTL_ADD 1
#define UPOLL_CTL_DEL 2
#define UPOLL_CTL_MOD 3
#define UPOLLIN 0x01
#define UPOLLOUT 0x02
#define UPOLLERR 0x04
#define UPOLLET 0x08
typedef struct upoll upoll_t;
typedef union upoll_data {
void* ptr;
intptr_t fd;
uint32_t u32;
uint64_t u64;
} upoll_data_t;
typedef struct upoll_event
{
uint32_t events;
upoll_data_t data;
} upoll_event_t;
upoll_t*
upoll_create(uint32_t size);
int
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event);
int
upoll_wait(upoll_t* upq, upoll_event_t* events, int maxevents, int timeout);
void
upoll_destroy(upoll_t* upq);
intptr_t
usocket(int domain, int type, int proto);
intptr_t
uaccept(intptr_t sock);
int
ubind(intptr_t sock, const char* name, const char* serv);
int
ulisten(intptr_t sock, int backlog);
int
uconnect(intptr_t sock, const char* name, const char* serv);
int
uclose(intptr_t sock);
/* TCP sockets */
int
uread(intptr_t fd, char* buf, size_t len);
int
uwrite(intptr_t fd, const char* buf, size_t len);
int
usocketpair(intptr_t socks[2], int async);
#ifdef __cplusplus
}
#endif
#endif /* _UP_H_ */

@ -0,0 +1,673 @@
#ifdef _WIN32
/* wake me up inside */
#pragma GCC diagnostic ignored "-Wvla"
/* emulated epoll, because the native async event system does not do
* particularly well with notification
*/
#include "win32_upoll.h"
#define uhash_slot(K, S) (((K) ^ (K >> 8)) & (S - 1))
static uhash_t*
uhash_create(uint32_t size)
{
unsigned int i;
size--;
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
size++;
uhash_t* hash = (uhash_t*)calloc(1, sizeof(uhash_t) + size * sizeof(ulist_t));
hash->count = 0;
hash->size = size;
hash->items = (ulist_t*)(((char*)hash) + sizeof(uhash_t));
for(i = 0; i < size; i++)
{
ulist_init(&hash->items[i]);
}
return hash;
}
static void*
uhash_lookup(uhash_t* hash, intptr_t key)
{
uint32_t slot = uhash_slot(key, hash->size);
ulist_t* q;
ulist_scan(q, &hash->items[slot])
{
uitem_t* i = ulist_data(q, uitem_t, list);
if(i->key == key)
return i->val;
}
return NULL;
}
static void
uhash_insert(uhash_t* hash, intptr_t key, void* val)
{
uint32_t slot = uhash_slot(key, hash->size);
uitem_t* item = (uitem_t*)calloc(1, sizeof(uitem_t));
ulist_init(&item->list);
item->key = key;
item->val = val;
ulist_append(&hash->items[slot], &item->list);
}
static int
uhash_delete(uhash_t* hash, intptr_t key)
{
uint32_t slot = uhash_slot(key, hash->size);
ulist_t* q;
ulist_scan(q, &hash->items[slot])
{
uitem_t* i = ulist_data(q, uitem_t, list);
if(i->key == key)
{
ulist_remove(q);
free(q);
return 1;
}
}
return 0;
}
static int
uhash_destroy(uhash_t* hash)
{
int i;
for(i = 0; i < hash->size; i++)
{
while(!ulist_empty(&hash->items[i]))
{
ulist_t* q = ulist_next(&hash->items[i]);
uitem_t* n = ulist_data(q, uitem_t, list);
ulist_remove(q);
free(n);
}
}
return 0;
}
upoll_t*
upoll_create(uint32_t size)
{
assert(size > 0);
upoll_t* upq = (upoll_t*)calloc(1, sizeof(upoll_t));
ulist_init(&upq->alive);
upq->table = uhash_create(size);
return upq;
}
void
upoll_destroy(upoll_t* upq)
{
assert(upq != NULL);
uhash_destroy(upq->table);
ulist_t* q = NULL;
unote_t* n = NULL;
while(!ulist_empty(&upq->alive))
{
q = ulist_next(&upq->alive);
n = ulist_data(n, unote_t, queue);
ulist_remove(q);
free(n);
}
free(upq);
}
int
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event)
{
if(fd < 0)
return -EBADF;
unote_t* note = NULL;
switch(op)
{
case UPOLL_CTL_ADD:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
{
note = (unote_t*)calloc(1, sizeof(unote_t));
note->upoll = upq;
ulist_init(&note->queue);
note->event = *event;
note->fd = fd;
ulist_append(&upq->alive, &note->queue);
uhash_insert(upq->table, fd, (void*)note);
}
break;
}
case UPOLL_CTL_DEL:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
return -ENOENT;
event = &note->event;
ulist_remove(&note->queue);
uhash_delete(upq->table, fd);
free(note);
break;
}
case UPOLL_CTL_MOD:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
return -ENOENT;
note->event = *event;
break;
}
default:
{
return -EINVAL;
}
}
return 0;
}
#if defined(HAVE_POLL)
int
upoll_wait_poll(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
/* FD_SETSIZE should be smaller than OPEN_MAX, but OPEN_MAX isn't portable */
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;
unote_t* nvec[nev];
int r, i, nfds = 0;
uint32_t hint;
struct pollfd pfds[nev];
unote_t* n = NULL;
ulist_t* s = ulist_mark(&upq->alive);
ulist_t* q = ulist_next(&upq->alive);
while(q != s && nfds < nev)
{
n = ulist_data(q, unote_t, queue);
q = ulist_next(q);
ulist_remove(&n->queue);
ulist_insert(&upq->alive, &n->queue);
nvec[nfds] = n;
pfds[nfds].events = 0;
pfds[nfds].fd = n->fd;
if(n->event.events & UPOLLIN)
{
pfds[nfds].events |= POLLIN;
}
if(n->event.events & UPOLLOUT)
{
pfds[nfds].events |= POLLOUT;
}
nfds++;
}
r = poll(pfds, nfds, timeout);
if(r < 0)
return -errno;
int e = 0;
for(i = 0; i < nfds && e < nev; i++)
{
hint = 0;
if(pfds[i].revents)
{
n = nvec[i];
if(pfds[i].revents & POLLIN)
hint |= UPOLLIN;
if(pfds[i].revents & POLLOUT)
hint |= UPOLLOUT;
if(pfds[i].revents & (POLLERR | POLLNVAL | POLLHUP))
hint |= (UPOLLERR | UPOLLIN);
if(hint & UPOLLERR)
hint &= ~UPOLLOUT;
evs[e].data = n->event.data;
evs[e].events = hint;
++e;
}
}
return e;
}
#else
int
upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
/* ok we need to test each file descriptor to see whether it is a real file
* or a socket. select any file handles (they are always ready)
*/
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;
unote_t* nvec[nev];
int i, maxfd = 0, e = 0, nfds = 0;
fd_set pollin, pollout, pollerr;
FD_ZERO(&pollin);
FD_ZERO(&pollout);
FD_ZERO(&pollerr);
struct timeval tv;
struct timeval* tvp = &tv;
tv.tv_usec = 0;
if(timeout < 0)
{
tvp = NULL;
}
else if(timeout == 0)
tv.tv_sec = 0;
else
{
tv.tv_sec = (timeout / 1000);
tv.tv_usec = (timeout % 1000) * 1000;
}
unote_t* n = NULL;
ulist_t* s = ulist_mark(&upq->alive);
ulist_t* q = ulist_next(&upq->alive);
while(q != s && nfds < nev)
{
n = ulist_data(q, unote_t, queue);
q = ulist_next(q);
ulist_remove(&n->queue);
ulist_insert(&upq->alive, &n->queue);
nvec[nfds] = n;
if(n->event.events & UPOLLIN)
{
FD_SET((SOCKET)n->fd, &pollin);
}
if(n->event.events & UPOLLOUT)
{
FD_SET((SOCKET)n->fd, &pollout);
}
FD_SET((SOCKET)n->fd, &pollerr);
if(maxfd < n->fd)
maxfd = n->fd;
nfds++;
}
#if defined(__WINDOWS__)
int rc = select(0, &pollin, &pollout, &pollerr, tvp);
if(rc == SOCKET_ERROR)
{
assert(WSAGetLastError() == WSAENOTSOCK);
return -WSAGetLastError();
}
#else
int rc = select(maxfd + 1, &pollin, &pollout, &pollerr, tvp);
if(rc == -1)
{
assert(errno == EINTR || errno == EBADF);
return -errno;
}
#endif
e = 0;
for(i = 0; i < nfds && e < nev; i++)
{
uint32_t hint = 0;
unote_t* n = nvec[i];
if(FD_ISSET(n->fd, &pollin))
{
hint |= UPOLLIN;
}
if(FD_ISSET(n->fd, &pollerr))
{
hint |= (UPOLLERR | UPOLLIN);
}
else if(FD_ISSET(n->fd, &pollout))
{
hint |= UPOLLOUT;
}
if(hint)
{
evs[e].data = n->event.data;
evs[e].events = hint;
++e;
}
}
return e;
}
#endif
int
upoll_wait(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
int r = 0;
#if defined(HAVE_POLL)
r = upoll_wait_poll(upq, evs, nev, timeout);
#else
r = upoll_wait_select(upq, evs, nev, timeout);
#endif
return r;
}
intptr_t
usocket(int domain, int type, int proto)
{
intptr_t fd = (intptr_t)socket(domain, type, proto);
#if defined(__WINDOWS__)
if(fd < 0)
return -WSAGetLastError();
unsigned long flags = 1;
int rc = ioctlsocket((SOCKET)fd, FIONBIO, &flags);
if(rc < 0)
return -WSAGetLastError();
#else
if(fd < 0)
return -errno;
int rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
if(rc < 0)
return -errno;
#endif
return fd;
}
int
ubind(intptr_t fd, const char* host, const char* serv)
{
struct addrinfo* info;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
int optval = 0;
unsigned int optlen = sizeof(optval);
#if defined(__WINDOWS__)
int rc = getsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, (char*)&optval,
(int*)&optlen);
#else
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
#endif
hint.ai_family = AF_INET;
hint.ai_socktype = optval;
rc = getaddrinfo(host, serv, &hint, &info);
optval = 1;
if(!rc)
{
#if defined(__WINDOWS__)
rc = setsockopt((SOCKET)fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval,
sizeof(optval));
#else
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
#endif
if(!rc)
rc = bind(fd, info->ai_addr, info->ai_addrlen);
}
freeaddrinfo(info);
if(rc)
{
#if defined(__WINDOWS__)
return WSAGetLastError();
#else
return errno;
#endif
}
return 0;
}
int
uconnect(intptr_t fd, const char* host, const char* serv)
{
struct addrinfo* info;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
int optval = 0;
unsigned int optlen;
#if defined(__WINDOWS__)
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*)&optval, (int*)&optlen);
#else
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
#endif
hint.ai_family = AF_INET;
hint.ai_socktype = optval;
rc = getaddrinfo(host, serv, &hint, &info);
if(!rc)
{
#if defined(__WINDOWS__)
rc = connect((SOCKET)fd, info->ai_addr, info->ai_addrlen);
#else
rc = connect(fd, info->ai_addr, info->ai_addrlen);
#endif
}
freeaddrinfo(info);
if(rc)
{
#if defined(__WINDOWS__)
if(WSAGetLastError() != WSAEWOULDBLOCK)
return WSAGetLastError();
#else
if(errno != EINPROGRESS)
return errno;
#endif
}
return 0;
}
int
ulisten(intptr_t sock, int backlog)
{
return listen(sock, backlog);
}
intptr_t
uaccept(intptr_t sock)
{
struct sockaddr addr;
addr.sa_family = AF_INET;
socklen_t addr_len;
#if defined(__WINDOWS__)
intptr_t fd = (intptr_t)accept((SOCKET)sock, &addr, &addr_len);
if(fd == -1)
return WSAGetLastError();
#else
intptr_t fd = accept(sock, &addr, &addr_len);
if(fd < 0)
return errno;
#endif
return fd;
}
int
uclose(intptr_t sock)
{
#if defined(__WINDOWS__)
return closesocket((SOCKET)sock);
#else
return close(sock);
#endif
}
int
uread(intptr_t fd, char* buf, size_t len)
{
return recv(fd, buf, len, 0);
}
int
uwrite(intptr_t fd, const char* buf, size_t len)
{
return send(fd, buf, len, 0);
}
/* adapted from (renamed make_overlapped to async for allergy reasons): */
/* socketpair.c
Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
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 name of the author must not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Changes:
* 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements
* git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54
* github.com/GerHobbelt/selectable-socketpair
* always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64
* and UNIX/other platforms
* 2013-07-18: Change to BSD 3-clause license
* 2010-03-31:
* set addr to 127.0.0.1 because win32 getsockname does not always set it.
* 2010-02-25:
* set SO_REUSEADDR option to avoid leaking some windows resource.
* Windows System Error 10049, "Event ID 4226 TCP/IP has reached
* the security limit imposed on the number of concurrent TCP connect
* attempts." Bleah.
* 2007-04-25:
* preserve value of WSAGetLastError() on all error returns.
* 2007-04-22: (Thanks to Matthew Gregan <kinetik@flim.org>)
* s/EINVAL/WSAEINVAL/ fix trivial compile failure
* s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout
* of a child process.
* add argument make_overlapped
*/
#if defined(__WINDOWS__)
int
usocketpair(intptr_t socks[2], int async)
{
union {
struct sockaddr_in inaddr;
struct sockaddr addr;
} a;
SOCKET listener;
int e;
socklen_t addrlen = sizeof(a.inaddr);
DWORD flags = (async ? WSA_FLAG_OVERLAPPED : 0);
int reuse = 1;
if(socks == 0)
{
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
socks[0] = socks[1] = -1;
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listener == INVALID_SOCKET)
return SOCKET_ERROR;
memset(&a, 0, sizeof(a));
a.inaddr.sin_family = AF_INET;
a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
a.inaddr.sin_port = 0;
for(;;)
{
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse,
(socklen_t)sizeof(reuse))
== -1)
break;
if(bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
break;
memset(&a, 0, sizeof(a));
if(getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
break;
// win32 getsockname may only set the port number, p=0.0005.
// ( http://msdn.microsoft.com/library/ms738543.aspx ):
a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
a.inaddr.sin_family = AF_INET;
if(listen(listener, 1) == SOCKET_ERROR)
break;
socks[0] = (intptr_t)WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
if(socks[0] == -1)
break;
if(connect((SOCKET)socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
break;
socks[1] = (intptr_t)accept(listener, NULL, NULL);
if(socks[1] == -1)
break;
closesocket(listener);
return 0;
}
e = WSAGetLastError();
closesocket(listener);
closesocket((SOCKET)socks[0]);
closesocket((SOCKET)socks[1]);
WSASetLastError(e);
socks[0] = socks[1] = -1;
return SOCKET_ERROR;
}
#else
int
usocketpair(intptr_t socks[2], int dummy)
{
int sovec[2];
if(socks == 0)
{
errno = EINVAL;
return -1;
}
dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, sovec);
if(dummy)
{
socks[0] = socks[1] = -1;
}
else
{
socks[0] = sovec[0];
socks[1] = sovec[1];
}
return dummy;
}
#endif
#endif

@ -0,0 +1,144 @@
#ifndef _UPOLL_H_
#define _UPOLL_H_
#include "win32_up.h"
#if(defined(__64BIT__) || defined(__x86_64__))
#define __IS_64BIT__
#else
#define __IS_32BIT__
#endif
#if(defined WIN32 || defined _WIN32)
#undef __WINDOWS__
#define __WINDOWS__
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#if defined(__WINDOWS__)
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#else
#include <unistd.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#endif
#if defined(__linux__)
#undef HAVE_EPOLL
#define HAVE_EPOLL 1
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#undef HAVE_POLL
#define HAVE_POLL 1
#else
#undef HAVE_SELECT
#define HAVE_SELECT 1
#endif
#if defined(HAVE_EPOLL)
#include <sys/epoll.h>
#elif defined(HAVE_POLL)
#include <poll.h>
#endif
typedef struct unote unote_t;
typedef struct ulist ulist_t;
typedef struct uitem uitem_t;
typedef struct uhash uhash_t;
struct ulist
{
ulist_t* next;
ulist_t* prev;
};
struct uitem
{
ulist_t list;
intptr_t key;
void* val;
};
struct uhash
{
uint16_t count;
uint16_t size;
ulist_t* items;
};
struct upoll
{
int fd; /* backend fd (epoll, kqueue) */
ulist_t alive; /* all notes this queue knows about */
uhash_t* table;
};
struct unote
{
upoll_event_t event;
intptr_t fd;
ulist_t queue; /* handle for the queue's notes */
upoll_t* upoll;
};
#define container_of(ptr, type, member) \
((type*)((char*)(ptr)-offsetof(type, member)))
#define ulist_init(q) \
(q)->prev = q; \
(q)->next = q
#define ulist_head(h) (h)->next
#define ulist_next(q) (q)->next
#define ulist_tail(h) (h)->prev
#define ulist_prev(q) (q)->prev
#define ulist_empty(h) (h == (h)->prev)
#define ulist_append(h, x) \
(x)->prev = (h)->prev; \
(x)->prev->next = x; \
(x)->next = h; \
(h)->prev = x
#define ulist_insert(h, x) \
(x)->next = (h)->next; \
(x)->next->prev = x; \
(x)->prev = h; \
(h)->next = x
#define ulist_remove(x) \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next; \
(x)->prev = x; \
(x)->next = x
#define ulist_mark(h) (h)
#define ulist_scan(q, h) \
for((q) = ulist_head(h); (q) != ulist_mark(h); (q) = ulist_next(q))
#define ulist_data(q, type, link) container_of(q, type, link)
#endif /* _UPOLL_H_ */

@ -64,7 +64,7 @@ if cross-compiling, install mingw-w64 from your distro's package manager, or [bu
$ export COMPILER=clang # if using clang for windows
$ cmake .. -DCMAKE_BUILD_TYPE=[Debug|Release] -DSTATIC_LINK=ON -DCMAKE_CROSSCOMPILING=ON -DDNS_PORT=53 -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw[32].cmake
this will create a static binary that can be installed anywhere, with no other dependency other than libc (7.0)
this will create a static binary that can be installed anywhere, with no other dependency other than libc (minimum v6.1)
## Running on Linux/UNIX/BSD

@ -7,6 +7,8 @@ struct ExitTest : public ::testing::Test
ExitTest()
{
llarp_crypto_init(&r.crypto);
r.netloop = nullptr; // only windows uses defined sentinel values in
// uninitialised blocks
}
llarp_router r;
};

@ -1,8 +1,33 @@
#include <gtest/gtest.h>
#ifdef _WIN32
#include <winsock2.h>
int
startWinsock()
{
WSADATA wsockd;
int err;
err = ::WSAStartup(MAKEWORD(2, 2), &wsockd);
if(err)
{
perror("Failed to start Windows Sockets");
return err;
}
return 0;
}
#endif
int
main(int argc, char** argv)
{
#ifdef _WIN32
if(startWinsock())
return -1;
#endif
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
int r = RUN_ALL_TESTS();
#ifdef _WIN32
WSACleanup();
#endif
return r;
}

338
ui-win32/.gitignore vendored

@ -0,0 +1,338 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
**/wwwroot/lib/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="false">
<!-- for modern PCs without .NET 2.0 -->
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
</configuration>

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace lokivpn
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new UI_Main_Frame());
}
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LokiNET for Windows")]
[assembly: AssemblyDescription("LokiNET Client UI for Windows NT (standalone)")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Loki Project")]
[assembly: AssemblyProduct("lokinet-win32")]
[assembly: AssemblyCopyright("Copyright ©2018 Rick V for the Loki Project. All rights reserved. See LICENSE for more details.")]
[assembly: AssemblyTrademark("Loki, Loki Project, LokiNET are ™ & © 2018 Loki Foundation")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1cdee73c-29c5-4781-bd74-1eeac6f75a14")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace lokivpn.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("lokivpn.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace lokivpn.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

@ -0,0 +1,163 @@
namespace lokivpn
{
partial class UI_Main_Frame
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UI_Main_Frame));
this.StatusLabel = new System.Windows.Forms.Label();
this.lokinetd_fd1 = new System.Windows.Forms.TextBox();
this.NotificationTrayIcon = new System.Windows.Forms.NotifyIcon(this.components);
this.btnHide = new System.Windows.Forms.Button();
this.UIVersionLabel = new System.Windows.Forms.Label();
this.btnConnect = new System.Windows.Forms.Button();
this.btnDrop = new System.Windows.Forms.Button();
this.btnConfigProfile = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// StatusLabel
//
this.StatusLabel.AutoSize = true;
this.StatusLabel.Location = new System.Drawing.Point(13, 13);
this.StatusLabel.Name = "StatusLabel";
this.StatusLabel.Size = new System.Drawing.Size(97, 13);
this.StatusLabel.TabIndex = 0;
this.StatusLabel.Text = "[connection status]";
//
// lokinetd_fd1
//
this.lokinetd_fd1.AcceptsReturn = true;
this.lokinetd_fd1.AcceptsTab = true;
this.lokinetd_fd1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.lokinetd_fd1.BackColor = System.Drawing.SystemColors.InfoText;
this.lokinetd_fd1.Font = new System.Drawing.Font("Iosevka Term Light", 9.749999F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lokinetd_fd1.ForeColor = System.Drawing.Color.Lime;
this.lokinetd_fd1.Location = new System.Drawing.Point(12, 39);
this.lokinetd_fd1.MaxLength = 0;
this.lokinetd_fd1.Multiline = true;
this.lokinetd_fd1.Name = "lokinetd_fd1";
this.lokinetd_fd1.ReadOnly = true;
this.lokinetd_fd1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.lokinetd_fd1.Size = new System.Drawing.Size(776, 330);
this.lokinetd_fd1.TabIndex = 1;
this.lokinetd_fd1.Text = "[pipe lokinetd fd 1 here]";
//
// NotificationTrayIcon
//
this.NotificationTrayIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("NotificationTrayIcon.Icon")));
this.NotificationTrayIcon.Text = "LokiNET for Windows - [status]";
this.NotificationTrayIcon.Visible = true;
//
// btnHide
//
this.btnHide.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnHide.Location = new System.Drawing.Point(713, 415);
this.btnHide.Name = "btnHide";
this.btnHide.Size = new System.Drawing.Size(75, 23);
this.btnHide.TabIndex = 2;
this.btnHide.Text = "Hide";
this.btnHide.UseVisualStyleBackColor = true;
//
// UIVersionLabel
//
this.UIVersionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.UIVersionLabel.AutoSize = true;
this.UIVersionLabel.Location = new System.Drawing.Point(529, 388);
this.UIVersionLabel.Name = "UIVersionLabel";
this.UIVersionLabel.Size = new System.Drawing.Size(259, 13);
this.UIVersionLabel.TabIndex = 3;
this.UIVersionLabel.Text = "LokiNET for Windows UI [version]/LokiNET [vcs-rev]";
//
// btnConnect
//
this.btnConnect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnConnect.Location = new System.Drawing.Point(13, 415);
this.btnConnect.Name = "btnConnect";
this.btnConnect.Size = new System.Drawing.Size(75, 23);
this.btnConnect.TabIndex = 4;
this.btnConnect.Text = "Connect";
this.btnConnect.UseVisualStyleBackColor = true;
//
// btnDrop
//
this.btnDrop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnDrop.Location = new System.Drawing.Point(95, 414);
this.btnDrop.Name = "btnDrop";
this.btnDrop.Size = new System.Drawing.Size(75, 23);
this.btnDrop.TabIndex = 5;
this.btnDrop.Text = "Disconnect";
this.btnDrop.UseVisualStyleBackColor = true;
//
// btnConfigProfile
//
this.btnConfigProfile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnConfigProfile.Location = new System.Drawing.Point(177, 413);
this.btnConfigProfile.Name = "btnConfigProfile";
this.btnConfigProfile.Size = new System.Drawing.Size(75, 23);
this.btnConfigProfile.TabIndex = 6;
this.btnConfigProfile.Text = "Settings...";
this.btnConfigProfile.UseVisualStyleBackColor = true;
this.btnConfigProfile.Click += new System.EventHandler(this.btnConfigProfile_Click);
//
// UI_Main_Frame
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.btnConfigProfile);
this.Controls.Add(this.btnDrop);
this.Controls.Add(this.btnConnect);
this.Controls.Add(this.UIVersionLabel);
this.Controls.Add(this.btnHide);
this.Controls.Add(this.lokinetd_fd1);
this.Controls.Add(this.StatusLabel);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "UI_Main_Frame";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "LokiNET for Windows";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label StatusLabel;
private System.Windows.Forms.TextBox lokinetd_fd1;
private System.Windows.Forms.NotifyIcon NotificationTrayIcon;
private System.Windows.Forms.Button btnHide;
private System.Windows.Forms.Label UIVersionLabel;
private System.Windows.Forms.Button btnConnect;
private System.Windows.Forms.Button btnDrop;
private System.Windows.Forms.Button btnConfigProfile;
}
}

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace lokivpn
{
public partial class UI_Main_Frame : Form
{
public UI_Main_Frame()
{
InitializeComponent();
}
private void btnConfigProfile_Click(object sender, EventArgs e)
{
MessageBox.Show("not implemented yet", "error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1CDEE73C-29C5-4781-BD74-1EEAC6F75A14}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>lokivpn</RootNamespace>
<AssemblyName>lokivpn</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>lokinet.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="UIMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UIMain.Designer.cs">
<DependentUpon>UIMain.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="UIMain.resx">
<DependentUpon>UIMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="App.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<Content Include="lokinet.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -24,6 +24,20 @@
/*#include <strsafe.h>*/
#include "tuntap.h"
// io packet for TUN read/write
// this _should_ be the same size as
// the corresponding C++ struct
struct asio_evt_pkt
{
OVERLAPPED pkt; // must be first, since this is part of the IO call
_Bool write; // true, or false if read pkt
size_t sz; // if this doesn't match what is in the packet, note the error
};
// function from c++
struct asio_evt_pkt *
getTunEventPkt();
// DDK macros
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
@ -385,7 +399,7 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
dns.length = 4;
dns.value[0] =
htonl(0x7F000001); /* apparently this doesn't show in network properties,
but it works 🤷🏻 */
but it works */
dns.value[1] = 0;
ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_SET_OPT, &dns,
@ -415,38 +429,49 @@ tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s, uint32_t mask)
int
tuntap_read(struct device *dev, void *buf, size_t size)
{
DWORD x;
BOOL r;
int e = 0;
struct asio_evt_pkt *pkt = getTunEventPkt();
pkt->write = FALSE;
pkt->sz = size;
if(size)
{
ReadFile(dev->tun_fd, buf, (DWORD)size, NULL, &dev->ovl[0]);
int errcode = GetLastError();
if(errcode != 997)
r = ReadFile(dev->tun_fd, buf, (DWORD)size, &x, &pkt->pkt);
if(r)
return x;
e = GetLastError();
if(e && e != 997)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
(const char *)formated_error(L"%1%0", _doserrno));
return -1;
}
}
return 0;
else
return -1; // unreachable
return size;
}
int
tuntap_write(struct device *dev, void *buf, size_t size)
{
DWORD x;
if(size)
{
WriteFile(dev->tun_fd, buf, (DWORD)size, NULL, &dev->ovl[1]);
WriteFile(dev->tun_fd, buf, (DWORD)size, &x, NULL);
int errcode = GetLastError();
if(errcode != 997)
if(errcode)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
return -1;
}
}
return 0;
else
return -1;
return x;
}
int
@ -497,4 +522,4 @@ tuntap_set_ifname(struct device *dev, const char *name)
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_ifname()");
return -1;
}
}

@ -30,6 +30,13 @@
#if defined Windows
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#if _WIN32_WINNT < 0x0600
extern "C" int
inet_pton(int af, const char *src, void *dst);
extern "C" const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#else
#include <arpa/inet.h>
#include <netinet/in.h>
@ -62,11 +69,8 @@ extern "C"
dev->tun_fd = TUNFD_INVALID_VALUE;
dev->ctrl_sock = -1;
dev->flags = 0;
#if defined(Windows)
memset(&dev->ovl[0], 0, sizeof(OVERLAPPED) * 2);
#endif
__tuntap_log = &tuntap_log_default;
__tuntap_log = &tuntap_log_default;
return dev;
}

@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "loki-network"
#define MyAppVersion "0.3.0"
#define MyAppVersion "0.3.1"
#define MyAppPublisher "Loki Project"
#define MyAppURL "https://loki.network"
#define MyAppExeName "lokinet.exe"
@ -32,16 +32,15 @@ OutputDir={#DevPath}win32-setup
OutputBaseFilename=lokinet-win32
Compression=lzma
SolidCompression=yes
VersionInfoVersion=0.3.0
VersionInfoVersion=0.3.1
VersionInfoCompany=Loki Project
VersionInfoDescription=lokinet for windows
VersionInfoTextVersion=0.3.0-dev
VersionInfoTextVersion=0.3.1-dev
VersionInfoProductName=loki-network
VersionInfoProductVersion=0.3.0
VersionInfoProductTextVersion=0.3.0-dev
VersionInfoProductVersion=0.3.1
VersionInfoProductTextVersion=0.3.1-dev
InternalCompressLevel=ultra64
; rip D:
MinVersion=0,6.0
MinVersion=0,5.0
ArchitecturesInstallIn64BitMode=x64
VersionInfoCopyright=Copyright ©2018 Loki Project
AlwaysRestart=yes
@ -54,11 +53,11 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Files]
; we're grabbing the builds from jenkins-ci now, which are fully linked
; only one of these is installed
Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64
Source: "{#DevPath}build\lokinet64.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64
Source: "{#DevPath}build64\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64
; eh, might as well ship the 32-bit port of everything else
; do we _need_ to ship these?
Source: "{#DevPath}build\dns.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#DevPath}build\llarpc.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#DevPath}build\rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion
@ -66,22 +65,66 @@ Source: "{#DevPath}build\rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion
; and download an initial RC
Source: "{#DevPath}lokinet-bootstrap.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{#DevPath}win32-setup\7z.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
; if nonexistent, then inet6 was already installed
Source: "{tmp}\inet6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall skipifsourcedoesntexist; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
; Copy the correct tuntap driver for the selected platform
Source: "{tmp}\tuntapv9.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; OnlyBelowVersion: 0, 6.0
Source: "{tmp}\tuntapv9_n6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,6.0
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[UninstallDelete]
Type: filesandordirs; Name: "{app}\tap-windows*"
Type: filesandordirs; Name: "{app}\inet6_driver"; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
Type: filesandordirs; Name: "{userappdata}\.lokinet"
[UninstallRun]
Filename: "{app}\tap-windows-9.21.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.21.2"; MinVersion: 0,6.0; Flags: runascurrentuser
Filename: "{app}\tap-windows-9.9.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.9.2"; OnlyBelowVersion: 0,6.0; Flags: runascurrentuser
[Dirs]
Name: "{userappdata}\.lokinet"
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
Version: TWindowsVersion;
begin
if CurStep = ssPostInstall then
begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and (Version.Major = 5) and (Version.Minor = 0) and (FileExists(ExpandConstant('{tmp}\inet6.7z')) = true) then
// I need a better message...
MsgBox('Set up IPv6 in Network Connections after reboot.', mbInformation, MB_OK);
end;
end;
procedure InitializeWizard();
var
Version: TWindowsVersion;
S: String;
begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and
(Version.Major < 6) then
begin
// Windows 2000, XP, .NET Svr 2003
// these have a horribly crippled WinInet that issues Triple-DES as its most secure
// cipher suite
idpAddFile('http://www.rvx86.net/files/tuntapv9.7z', ExpandConstant('{tmp}\tuntapv9.7z'));
// Windows 2000 only, we need to install inet6 separately
if (FileExists(ExpandConstant('{sys}\drivers\tcpip6.sys')) = false) and (Version.Major = 5) and (Version.Minor = 0) then
begin
idpAddFile('http://www.rvx86.net/files/inet6.7z', ExpandConstant('{tmp}\inet6.7z'));
end;
end
else
begin
// current versions of windows :-)
// (Arguably, one could pull this from any of the forks.)
idpAddFile('https://github.com/despair86/loki-network/raw/master/contrib/tuntapv9-ndis/tap-windows-9.21.2.7z', ExpandConstant('{tmp}\tuntapv9_n6.7z'));
end;
idpDownloadAfter(wpReady);
end;
@ -96,7 +139,14 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBa
[Run]
Filename: "{app}\{#MyAppExeName}"; Flags: nowait postinstall skipifsilent; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"
; wait until either one or two of these terminates
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9_n6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; MinVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x inet6.7z"; WorkingDir: "{app}"; Flags: skipifdoesntexist runascurrentuser waituntilterminated; Description: "extract inet6 driver"; StatusMsg: "Extracting IPv6 driver..."; MinVersion: 0, 5.0; OnlyBelowVersion: 0, 5.1
Filename: "{tmp}\lokinet-bootstrap.exe"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "bootstrap dht"; StatusMsg: "Downloading initial RC..."
; then ask to install drivers
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
Filename: "{app}\tap-windows-9.9.2\install.bat"; WorkingDir: "{app}\tap-windows-9.9.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
; install inet6 if not present. (I'd assume netsh displays something helpful if inet6 is already set up and configured.)
; if it doesn't exist, then the inet6 driver appears to be installed
Filename: "{app}\inet6_driver\setup\hotfix.exe"; Parameters: "/m /z"; WorkingDir: "{app}\inet6_driver\setup\"; Flags: runascurrentuser waituntilterminated skipifdoesntexist; Description: "Install IPv6 driver"; StatusMsg: "Installing IPv6..."; OnlyBelowVersion: 0, 5.1
Filename: "{sys}\netsh.exe"; Parameters: "int ipv6 install"; Flags: runascurrentuser waituntilterminated; Description: "install ipv6 on whistler"; StatusMsg: "Installing IPv6..."; MinVersion: 0,5.1; OnlyBelowVersion: 0,6.0
Loading…
Cancel
Save