diff --git a/Makefile b/Makefile index 0dd20ca09..6f2e3b591 100644 --- a/Makefile +++ b/Makefile @@ -96,17 +96,15 @@ SCAN_BUILD ?= scan-build UNAME = $(shell which uname) ifeq ($(shell $(UNAME)),SunOS) -CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") +CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") +CONFIG_CMD_WINDOWS = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=ON -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") -CONFIG_CMD_WINDOWS = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=ON -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") +ANALYZE_CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") -ANALYZE_CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") - -COVERAGE_CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DWITH_COVERAGE=yes -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") +COVERAGE_CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DWITH_COVERAGE=yes -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") else -CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") - -CONFIG_CMD_WINDOWS = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=ON -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") +CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") +CONFIG_CMD_WINDOWS = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=ON -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") ANALYZE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DNON_PC_TARGET=$(NON_PC_TARGET) -DWITH_SHARED=$(SHARED_LIB) -DASAN=$(ASAN) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON '$(REPO)'") diff --git a/cmake/unix.cmake b/cmake/unix.cmake index 6d80525a4..6f23640c2 100644 --- a/cmake/unix.cmake +++ b/cmake/unix.cmake @@ -53,6 +53,14 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-darwin.c ${TT_ROOT}/tuntap-unix-bsd.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-sunos.c) + # Apple C++ screws up name decorations in stdc++fs, causing link to fail + # Samsung does not build c++experimental or c++fs in their Apple libc++ pkgsrc build + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + add_subdirectory(vendor) + include_directories("${CMAKE_CURRENT_LIST_DIR}/../vendor/cppbackport-master/lib") + add_definitions(-DLOKINET_USE_CPPBACKPORT) + set(FS_LIB cppbackport) + endif() else() message(FATAL_ERROR "Your operating system is not supported yet") endif() diff --git a/cmake/win32.cmake b/cmake/win32.cmake index 07f02df64..31f826968 100644 --- a/cmake/win32.cmake +++ b/cmake/win32.cmake @@ -18,8 +18,12 @@ if(NOT MSVC_VERSION) # to .r[o]data section one after the other! add_compile_options(-fno-ident -Wa,-mbig-obj) link_libraries( -lshlwapi -ldbghelp ) - add_definitions(-DWINVER=0x0500 -D_WIN32_WINNT=0x0500) - # set(FS_LIB stdc++fs) + add_definitions(-DWINVER=0x0500 -D_WIN32_WINNT=0x0500) + # Wait a minute, if we're not Microsoft C++, nor a Clang paired with Microsoft C++, + # then the only possible option has to be GNU or a GNU-linked Clang! + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(FS_LIB stdc++fs) + endif() endif() get_filename_component(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-windows.c ABSOLUTE) diff --git a/daemon/main.cpp b/daemon/main.cpp index 66e6d0872..7ef10e051 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -16,6 +16,8 @@ #ifdef _WIN32 #define wmin(x, y) (((x) < (y)) ? (x) : (y)) #define MIN wmin +extern "C" LONG FAR PASCAL +win32_signal_handler(EXCEPTION_POINTERS *); #endif struct llarp_main *ctx = 0; @@ -116,6 +118,7 @@ main(int argc, char *argv[]) if(startWinsock()) return -1; SetConsoleCtrlHandler(handle_signal_win32, TRUE); + // SetUnhandledExceptionFilter(win32_signal_handler); #endif #ifdef LOKINET_DEBUG diff --git a/include/tuntap.h b/include/tuntap.h index 09480a1a7..8a56eb28e 100644 --- a/include/tuntap.h +++ b/include/tuntap.h @@ -146,6 +146,9 @@ extern "C" int ctrl_sock; int flags; /* ifr.ifr_flags on Unix */ char if_name[IF_NAMESIZE]; +#if defined(Windows) + int idx; /* needed to set ipv6 address */ +#endif #if defined(FreeBSD) int mode; #endif diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index 224f0a1aa..feb6221c6 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -633,17 +633,16 @@ namespace libuv Loop::CloseAll() { llarp::LogInfo("Closing all handles"); - uv_walk( - m_Impl.get(), - [](uv_handle_t* h, void*) { - if(uv_is_closing(h)) - return; - if(h->data && uv_is_active(h)) - { - static_cast< glue* >(h->data)->Close(); - } - }, - nullptr); + uv_walk(m_Impl.get(), + [](uv_handle_t* h, void*) { + if(uv_is_closing(h)) + return; + if(h->data && uv_is_active(h)) + { + static_cast< glue* >(h->data)->Close(); + } + }, + nullptr); } void diff --git a/llarp/ev/ev_win32.cpp b/llarp/ev/ev_win32.cpp index 1b1567297..1768dc243 100644 --- a/llarp/ev/ev_win32.cpp +++ b/llarp/ev/ev_win32.cpp @@ -368,6 +368,13 @@ namespace llarp return 0; } + static int + UDPSendTo(llarp_udp_io* udp, const sockaddr* to, const byte_t* ptr, size_t sz) + { + llarp::ev_io* io = (llarp::ev_io*)udp->impl; + return io->sendto(to, ptr, sz); + } + int udp_listener::sendto(const sockaddr* to, const void* data, size_t sz) { @@ -634,6 +641,7 @@ llarp_win32_loop::create_udp(llarp_udp_io* l, const sockaddr* src) return nullptr; llarp::ev_io* listener = new llarp::udp_listener(fd, l); l->impl = listener; + l->sendto = &llarp::UDPSendTo; return listener; } diff --git a/llarp/metrics/metrictank_publisher.cpp b/llarp/metrics/metrictank_publisher.cpp index 1f76c770b..ab9a98597 100644 --- a/llarp/metrics/metrictank_publisher.cpp +++ b/llarp/metrics/metrictank_publisher.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #endif diff --git a/llarp/path/path_context.cpp b/llarp/path/path_context.cpp index 84a19f575..b2460f84b 100644 --- a/llarp/path/path_context.cpp +++ b/llarp/path/path_context.cpp @@ -164,15 +164,14 @@ namespace llarp HopHandler_ptr PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id) { - auto own = MapGet( - m_OurPaths, id, - [](const PathSet_ptr) -> bool { - // TODO: is this right? - return true; - }, - [remote, id](PathSet_ptr p) -> HopHandler_ptr { - return p->GetByUpstream(remote, id); - }); + auto own = MapGet(m_OurPaths, id, + [](const PathSet_ptr) -> bool { + // TODO: is this right? + return true; + }, + [remote, id](PathSet_ptr p) -> HopHandler_ptr { + return p->GetByUpstream(remote, id); + }); if(own) return own; diff --git a/llarp/path/pathset.cpp b/llarp/path/pathset.cpp index 122948a4f..5514d51e2 100644 --- a/llarp/path/pathset.cpp +++ b/llarp/path/pathset.cpp @@ -295,10 +295,9 @@ namespace llarp PathSet::HandlePathBuildFailed(Path_ptr p) { LogWarn(Name(), " path build ", p->HopsString(), " failed"); - m_BuildStats.fails ++; + m_BuildStats.fails++; } - void PathSet::PathBuildStarted(Path_ptr p) { diff --git a/llarp/util/threading.cpp b/llarp/util/threading.cpp index 8354ee6be..77d687011 100644 --- a/llarp/util/threading.cpp +++ b/llarp/util/threading.cpp @@ -4,11 +4,17 @@ #ifdef POSIX #include -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include #endif #endif +#ifdef _MSC_VER +#include +extern "C" void +SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); +#endif + namespace llarp { namespace util @@ -17,13 +23,16 @@ namespace llarp SetThreadName(const std::string& name) { #ifdef POSIX -#if defined(__FreeBSD__) - /* on free bsd this function has void return type */ +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + /* on bsd this function has void return type */ pthread_set_name_np(pthread_self(), name.c_str()); #else #if defined(__MACH__) const int rc = pthread_setname_np(name.c_str()); -#elif defined(__linux__) +// API present upstream since v2.11.3 and imported downstream +// in CR 8158 +// We only use the native function on Microsoft C++ builds +#elif defined(__linux__) || defined(__sun) const int rc = pthread_setname_np(pthread_self(), name.c_str()); #else #error "unsupported platform" @@ -34,6 +43,10 @@ namespace llarp " errstr = ", strerror(rc)); } #endif +#elif _MSC_VER + ::SetThreadName(::GetCurrentThreadId(), name.c_str()); +#elif __MINGW32__ + const int rc = pthread_setname_np(pthread_self(), name.c_str()); #else LogInfo("Thread name setting not supported on this platform"); (void)name; diff --git a/llarp/utp/linklayer.cpp b/llarp/utp/linklayer.cpp index 577cf6b0f..332880590 100644 --- a/llarp/utp/linklayer.cpp +++ b/llarp/utp/linklayer.cpp @@ -332,9 +332,7 @@ namespace llarp { LogWarn("dropping inbound utp session from ", remote); // close later - self->m_Logic->call_later(50, [=]() { - session->Close(); - }); + self->m_Logic->call_later(50, [=]() { session->Close(); }); } else { diff --git a/llarp/win32/win32_intrnl.c b/llarp/win32/win32_intrnl.c index 38ced0549..94da90fce 100644 --- a/llarp/win32/win32_intrnl.c +++ b/llarp/win32/win32_intrnl.c @@ -1,572 +1,676 @@ -#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 -#include - -// 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 -#include -#include -#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 - -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 +#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 +#include + +// 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 +#include +#include +#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... +#ifdef _MSC_VER +#include + +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 + +#ifdef _WIN32 +#if 0 +// Generate a core dump if we crash. Finally. +// Unix-style, we just leave a file named "core" in +// the user's working directory. Gets overwritten if +// a new crash occurs. +#include +#ifdef _MSC_VER +#pragma comment(lib, "dbghelp.lib") +#endif + +HRESULT +GenerateCrashDump(MINIDUMP_TYPE flags, EXCEPTION_POINTERS *seh) +{ + HRESULT error = S_OK; + MINIDUMP_USER_STREAM_INFORMATION info = {0}; + MINIDUMP_USER_STREAM stream = {0}; + + // get the time + SYSTEMTIME sysTime = {0}; + GetSystemTime(&sysTime); + + // get the computer name + char compName[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD compNameLen = ARRAYSIZE(compName); + GetComputerNameA(compName, &compNameLen); + + // This information is written to a core dump user stream + char extra_info[1024] = {0}; + snprintf(extra_info, 1024, + "hostname=%s;datetime=%02u-%02u-%02u_%02u-%02u-%02u", compName, + sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, + sysTime.wMinute, sysTime.wSecond); + + // open the file + HANDLE hFile = + CreateFileA("core", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + error = GetLastError(); + error = HRESULT_FROM_WIN32(error); + return error; + } + + // get the process information + HANDLE hProc = GetCurrentProcess(); + DWORD procID = GetCurrentProcessId(); + + // if we have SEH info, package it up + MINIDUMP_EXCEPTION_INFORMATION sehInfo = {0}; + MINIDUMP_EXCEPTION_INFORMATION *sehPtr = NULL; + + // Collect hostname and time + info.UserStreamCount = 1; + info.UserStreamArray = &stream; + stream.Type = CommentStreamA; + stream.BufferSize = strlen(extra_info) + 1; + stream.Buffer = extra_info; + + if(seh) + { + sehInfo.ThreadId = GetCurrentThreadId(); + sehInfo.ExceptionPointers = seh; + sehInfo.ClientPointers = FALSE; + sehPtr = &sehInfo; + } + + // generate the crash dump + BOOL result = + MiniDumpWriteDump(hProc, procID, hFile, flags, sehPtr, &info, NULL); + if(!result) + { + error = (HRESULT)GetLastError(); // already an HRESULT + } + + // close the file + CloseHandle(hFile); + return error; +} + +// ok try a UNIX-style signal handler +LONG FAR PASCAL win32_signal_handler(EXCEPTION_POINTERS *e) +{ + MessageBox(NULL, + "A fatal error has occurred. A core dump was generated and " + "dropped in the daemon's working directory. Please create an " + "issue at https://github.com/loki-network/loki-project, and " + "attach the core dump for further assistance.", + "Fatal Error", MB_ICONHAND); + GenerateCrashDump( + MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo + | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo + | MiniDumpWithUnloadedModules | MiniDumpWithFullAuxiliaryState + | MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation, + e); + exit(127); + return 0; +} +#endif +#endif \ No newline at end of file diff --git a/test/win32/test.rc b/test/win32/test.rc index d6629504f..7469cfc14 100644 --- a/test/win32/test.rc +++ b/test/win32/test.rc @@ -79,8 +79,12 @@ BEGIN VALUE "FileDescription", "LokiNET for Microsoft� Windows� NT�" #ifdef LLARP_RELEASE_MOTTO VALUE "FileVersion", VERSION_STRING(0.4.0, RELEASE_MOTTO, GIT_REV) +#else +#ifdef __GNUC__ + VALUE "FileVersion", VERSION_STRING(0.4.0-dev-, GIT_REV) #else VALUE "FileVersion", "0.4.0-dev" +#endif #endif VALUE "InternalName", "llarpd" VALUE "LegalCopyright", "Copyright �2018-2019 Jeff Becker, Rick V for the Loki Foundation. All rights reserved. This software is provided under the terms of the zlib-libpng licence; see the file LICENSE for details." @@ -88,8 +92,12 @@ BEGIN VALUE "ProductName", "LokiNET for Windows" #ifdef LLARP_RELEASE_MOTTO VALUE "ProductVersion", VERSION_STRING(0.4.0, RELEASE_MOTTO, GIT_REV) +#else +#ifdef __GNUC__ + VALUE "ProductVersion", VERSION_STRING(0.4.0-dev-, GIT_REV) #else VALUE "ProductVersion", "0.4.0-dev" +#endif #endif END END diff --git a/vendor/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc b/vendor/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc index 59e72785e..2a034d65a 100644 --- a/vendor/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc +++ b/vendor/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc @@ -44,7 +44,7 @@ typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( IN ULONG frames_to_skip, IN ULONG frames_to_capture, OUT PVOID *backtrace, - OUT PULONG backtrace_hash); + OUT PULONG backtrace_hash); // Until 2001, this was a required parameter // Load the function we need at static init time, where we don't have // to worry about someone else holding the loader's lock. @@ -56,10 +56,11 @@ template static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, const void *ucp, int *min_dropped_frames) { int n = 0; + ULONG hash; if (!RtlCaptureStackBackTrace_fn) { // can't find a stacktrace with no function to call } else { - n = (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, 0); + n = (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, &hash); } if (IS_STACK_FRAMES) { // No implementation for finding out the stack frame sizes yet. diff --git a/vendor/abseil-cpp/absl/time/time.h b/vendor/abseil-cpp/absl/time/time.h index bdd163987..3afec565e 100644 --- a/vendor/abseil-cpp/absl/time/time.h +++ b/vendor/abseil-cpp/absl/time/time.h @@ -66,7 +66,7 @@ #if !defined(_MSC_VER) #include #else -#include +#include #endif #include // NOLINT(build/c++11) #include diff --git a/vendor/libtuntap-master/tuntap-windows.c b/vendor/libtuntap-master/tuntap-windows.c index 05fb62dfc..080170b1b 100644 --- a/vendor/libtuntap-master/tuntap-windows.c +++ b/vendor/libtuntap-master/tuntap-windows.c @@ -23,7 +23,10 @@ #include /*#include */ #include "tuntap.h" +#include +char * +tuntap_get_hwaddr(struct device *dev); // DDK macros #define CTL_CODE(DeviceType, Function, Method, Access) \ @@ -175,6 +178,10 @@ tuntap_start(struct device *dev, int mode, int tun) HANDLE tun_fd; char *deviceid; char buf[60]; + char msg[256]; + ULONG size; + IP_ADAPTER_INFO* netif_data, *next_if; + char* if_addr; (void)(tun); /* put something in there to avoid problems (uninitialised field access) */ @@ -215,9 +222,32 @@ tuntap_start(struct device *dev, int mode, int tun) free(deviceid); return -1; } - + dev->tun_fd = tun_fd; free(deviceid); + + /* get the size of our adapter list */ + GetAdaptersInfo(NULL, &size); + netif_data = alloca(size); + + /* get our own interface address. If we're down here already, then we're ok */ + if_addr = tuntap_get_hwaddr(dev); + + /* get our interface data */ + GetAdaptersInfo(netif_data, &size); + next_if = netif_data; + while (next_if) + { + if(!memcmp(next_if->Address, if_addr, ETHER_ADDR_LEN)) + { + dev->idx = next_if->Index; + (void)_snprintf(msg, sizeof msg, "Our TAP interface index is %d", dev->idx); + tuntap_log(TUNTAP_LOG_INFO, msg); + break; + } + next_if = next_if->Next; + } + return 0; } @@ -405,8 +435,7 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask) return 0; } -/* To be implemented at a later time? I'm not quite certain TAP-Windows v9.x - * supports inet6 */ + int tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s, uint32_t mask) { diff --git a/win32-setup/dbghelp32.dll b/win32-setup/dbghelp32.dll new file mode 100644 index 000000000..62d850863 Binary files /dev/null and b/win32-setup/dbghelp32.dll differ diff --git a/win32-setup/dbghelp64.dll b/win32-setup/dbghelp64.dll new file mode 100644 index 000000000..f3bd78ff9 Binary files /dev/null and b/win32-setup/dbghelp64.dll differ diff --git a/win32-setup/lokinet-win32.iss b/win32-setup/lokinet-win32.iss index 46722785a..1e3c589cb 100644 --- a/win32-setup/lokinet-win32.iss +++ b/win32-setup/lokinet-win32.iss @@ -68,11 +68,14 @@ Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescrip #ifdef SINGLE_ARCH Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#DevPath}build\liblokinet-shared.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "dbghelp64.dll"; DestName: "dbghelp.dll"; DestDir: "{app}"; Flags: ignoreversion #else Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64 Source: "{#DevPath}build\liblokinet-shared.dll"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64 +Source: "dbghelp32.dll"; DestName: "dbghelp.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not IsWin64 Source: "{#DevPath}build64\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64 Source: "{#DevPath}build64\liblokinet-shared.dll"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64 +Source: "dbghelp64.dll"; DestDir: "{app}"; DestName: "dbghelp.dll"; Flags: ignoreversion; Check: IsWin64 #endif ; UI has landed! #ifndef RELEASE