diff --git a/LICENSE b/LICENSE index 17889aaec..e0dd48d4c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ Copyright (c) 2018 Jeff Becker -Win32 port and portions copyright 2018 Rick V. +Windows NT port and portions copyright 2018 Rick V. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/crypto/libntrup/src/avx/mult.c b/crypto/libntrup/src/avx/mult.c index e01e1cd33..cb2ef059a 100644 --- a/crypto/libntrup/src/avx/mult.c +++ b/crypto/libntrup/src/avx/mult.c @@ -5,17 +5,48 @@ #include "rq.h" #include "r3.h" +// 32-bit hosts: use compiler builtins and let compiler +// perform register allocation and/or spilling to core +// +// Confirmed working 3/10/18 -despair +// Less than 5% performance hit, +// all in register loads/stores to/from core +#ifndef __amd64__ #define MULSTEP_gcc(j,h0,h1,h2,h3,h4) \ gj = g[j]; \ h0 += f0 * gj; \ - _mm256_storeu_ps(&h[i + j],h0); \ + _mm256_storeu_ps((float*)&h[i + j],h0); \ h1 += f1 * gj; \ h2 += f2 * gj; \ h3 += f3 * gj; \ h4 += f4 * gj; \ - h0 = _mm256_loadu_ps(&h[i + j + 5]); \ + h0 = _mm256_loadu_ps((float*)&h[i + j + 5]); \ h0 += f5 * gj; +#define MULSTEP MULSTEP_gcc + +#define MULSTEP_noload(j,h0,h1,h2,h3,h4) \ + gj = g[j]; \ + h0 += gj*f0; \ + _mm256_storeu_ps((float*)&h[i+j], h0); \ + h1 += gj*f1; \ + h2 += gj*f2; \ + h3 += gj*f3; \ + h4 += gj*f4; \ + h0 = gj* f5; + +#define MULSTEP_fromzero(j,h0,h1,h2,h3,h4) \ + gj = g[j]; \ + h0 = gj*f0; \ + _mm256_storeu_ps((float*)&h[i+j], h0); \ + h1 = gj*f1; \ + h2 = gj*f2; \ + h3 = gj*f3; \ + h4 = gj*f4; \ + h0 = gj*f5; +#else +// 64-bit hosts: use inline asm as before +#define MULSTEP MULSTEP_asm #define MULSTEP_asm(j,h0,h1,h2,h3,h4) \ gj = g[j]; \ __asm__( \ @@ -30,8 +61,6 @@ : "+x"(h0),"+x"(h1),"+x"(h2),"+x"(h3),"+x"(h4) \ : "x"(gj),"x"(f0),"x"(f1),"x"(f2),"x"(f3),"x"(f4),"x"(f5),"m"(h[i+j]),"m"(h[i+j+5])); -#define MULSTEP MULSTEP_asm - #define MULSTEP_noload(j,h0,h1,h2,h3,h4) \ gj = g[j]; \ __asm__( \ @@ -57,6 +86,7 @@ "vmulps %5,%11,%0 \n\t" \ : "=&x"(h0),"=&x"(h1),"=&x"(h2),"=&x"(h3),"=&x"(h4) \ : "x"(gj),"x"(f0),"x"(f1),"x"(f2),"x"(f3),"x"(f4),"x"(f5),"m"(h[i+j])); +#endif static inline __m128i _mm_load_cvtepi8_epi16(const long long *x) { diff --git a/crypto/libntrup/src/avx/rq.c b/crypto/libntrup/src/avx/rq.c index b6dc8ab6c..9b3d4f365 100644 --- a/crypto/libntrup/src/avx/rq.c +++ b/crypto/libntrup/src/avx/rq.c @@ -21,6 +21,12 @@ #define broadcast(r) _mm256_set1_pd(r) #define floor(x) _mm256_floor_pd(x) +// 32-bit hosts only +#ifndef __amd64__ +#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)(X); \ + __a[N];})) +#endif + void rq_encode(unsigned char *c,const modq *f) { crypto_int32 f0, f1, f2, f3, f4; diff --git a/crypto/libntrup/src/avx/rq_mod3.c b/crypto/libntrup/src/avx/rq_mod3.c index c2b7059b5..6f631d938 100644 --- a/crypto/libntrup/src/avx/rq_mod3.c +++ b/crypto/libntrup/src/avx/rq_mod3.c @@ -1,5 +1,6 @@ #if __AVX2__ #include +#include #include "mod3.h" #include "rq.h" @@ -9,6 +10,12 @@ #define v4591_16 _mm256_set1_epi16(4591) #define v10923_16 _mm256_set1_epi16(10923) +// 32-bit hosts only +#ifndef __amd64__ +#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)(X); \ + __a[N];})) +#endif + static inline __m256i squeeze(__m256i x) { __m256i q = _mm256_mulhrs_epi16(x,v7); diff --git a/daemon/main.cpp b/daemon/main.cpp index 47f0c8b4f..ba62731a0 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -100,7 +100,8 @@ main(int argc, char *argv[]) conffname = fname.string(); if(basedir.string().empty()) { - if(!llarp_ensure_config(fname.string().c_str(), nullptr, overWrite, asRouter)) + if(!llarp_ensure_config(fname.string().c_str(), nullptr, overWrite, + asRouter)) return 1; } else diff --git a/include/llarp/pathset.hpp b/include/llarp/pathset.hpp index 68439337f..0a293cf3b 100644 --- a/include/llarp/pathset.hpp +++ b/include/llarp/pathset.hpp @@ -137,18 +137,18 @@ namespace llarp size_t m_NumPaths; private: - typedef std::pair< RouterID, PathID_t > PathInfo_t; struct PathInfoHash { - size_t operator()(const PathInfo_t & i) const + size_t + operator()(const PathInfo_t& i) const { return *i.first.data_l() ^ *i.second.data_l(); } }; - typedef std::unordered_map< PathInfo_t, Path* , PathInfoHash> PathMap_t; + typedef std::unordered_map< PathInfo_t, Path*, PathInfoHash > PathMap_t; PathMap_t m_Paths; }; diff --git a/include/tuntap.h b/include/tuntap.h index 2f0447309..28da2e51b 100644 --- a/include/tuntap.h +++ b/include/tuntap.h @@ -143,6 +143,9 @@ extern "C" char if_name[IF_NAMESIZE]; #if defined(FreeBSD) int mode; +#endif +#if defined(Windows) + OVERLAPPED ovl; #endif }; diff --git a/llarp/dnsd.cpp b/llarp/dnsd.cpp index 1e476b673..acc3dca29 100644 --- a/llarp/dnsd.cpp +++ b/llarp/dnsd.cpp @@ -82,7 +82,7 @@ writecname_dnss_response(std::string cname, const struct sockaddr *from, dnsd_question_request *request) { const size_t BUFFER_SIZE = 1024 + (request->question.name.size() * 2); - char buf[BUFFER_SIZE]; + char buf[BUFFER_SIZE]; // heh, another UNIX compiler extension: VLAs in C++ memset(buf, 0, BUFFER_SIZE); char *write_buffer = buf; char *bufferBegin = buf; diff --git a/llarp/ev.cpp b/llarp/ev.cpp index a5e5f4c88..07bf7d55b 100644 --- a/llarp/ev.cpp +++ b/llarp/ev.cpp @@ -96,7 +96,7 @@ llarp_ev_udp_sendto(struct llarp_udp_io *udp, const sockaddr *to, const void *buf, size_t sz) { auto ret = static_cast< llarp::ev_io * >(udp->impl)->sendto(to, buf, sz); - if(ret == -1) + if(ret == -1 && errno) { llarp::LogWarn("sendto failed ", strerror(errno)); errno = 0; diff --git a/llarp/ev.hpp b/llarp/ev.hpp index f60853113..d91fe37e2 100644 --- a/llarp/ev.hpp +++ b/llarp/ev.hpp @@ -5,14 +5,16 @@ #ifndef _WIN32 #include #endif - -#ifndef _MSC_VER #include -#endif #include #include #include #include + +#ifdef _WIN32 +#include +#endif + #ifndef MAX_WRITE_QUEUE_SIZE #define MAX_WRITE_QUEUE_SIZE 1024 #endif @@ -29,13 +31,18 @@ namespace llarp int fd; ev_io(int f) : fd(f), m_writeq("writequeue"){}; #else - SOCKET fd; + // on windows, udp event loops are socket fds + // and TUN device is a plain old fd + std::variant< SOCKET, HANDLE > fd; // the unique completion key that helps us to // identify the object instance for which we receive data - // Here, we'll use the address of the udp_listener instance, converted to - // its literal int/int64 representation. + // Here, we'll use the address of the udp_listener instance, converted + // to its literal int/int64 representation. ULONG_PTR listener_id = 0; ev_io(SOCKET f) : fd(f), m_writeq("writequeue"){}; + ev_io(HANDLE t) + : fd(t), m_writeq("writequeue"){}; // overload for TUN device, which + // _is_ a regular file descriptor #endif virtual int read(void* buf, size_t sz) = 0; @@ -50,7 +57,8 @@ namespace llarp #ifndef _WIN32 return write(fd, data, sz) != -1; #else - return WriteFile((void*)fd, data, sz, nullptr, nullptr); + DWORD w; + return WriteFile(std::get< HANDLE >(fd), data, sz, &w, nullptr); #endif } @@ -129,7 +137,7 @@ namespace llarp #ifndef _WIN32 ::close(fd); #else - closesocket(fd); + closesocket(std::get< SOCKET >(fd)); #endif }; }; @@ -156,7 +164,11 @@ struct llarp_ev_loop auto ev = create_udp(l, src); if(ev) { +#ifdef _WIN32 + l->fd = std::get< SOCKET >(ev->fd); +#else l->fd = ev->fd; +#endif } return ev && add_ev(ev, false); } diff --git a/llarp/ev_kqueue.hpp b/llarp/ev_kqueue.hpp index 469986253..43dd1390c 100644 --- a/llarp/ev_kqueue.hpp +++ b/llarp/ev_kqueue.hpp @@ -206,13 +206,13 @@ struct llarp_kqueue_loop : public llarp_ev_loop while(idx < result) { llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].udata); - if (ev) + if(ev) { ev->read(readbuf, sizeof(readbuf)); } else { - llarp::LogWarn("event[", idx,"] udata is not an ev_io"); + llarp::LogWarn("event[", idx, "] udata is not an ev_io"); } ++idx; } @@ -313,7 +313,6 @@ struct llarp_kqueue_loop : public llarp_ev_loop close(fd); return -1; } - return fd; } diff --git a/llarp/ev_win32.hpp b/llarp/ev_win32.hpp index a7fb93bd2..442ff49db 100644 --- a/llarp/ev_win32.hpp +++ b/llarp/ev_win32.hpp @@ -17,11 +17,13 @@ namespace llarp // we receive queued data in the OVERLAPPED data field, // much like the pipefds in the UNIX kqueue and loonix // epoll handles - // 0 is the read port, 1 is the write port - WSAOVERLAPPED portfds[2] = {0}; + WSAOVERLAPPED portfd; size_t iosz; - udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u){}; + udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u) + { + memset((void*)&portfd, 0, sizeof(WSAOVERLAPPED)); + }; ~udp_listener() { @@ -43,8 +45,9 @@ namespace llarp unsigned long flags = 0; WSABUF wbuf = {sz, static_cast< char* >(buf)}; // WSARecvFrom - int ret = ::WSARecvFrom(fd, &wbuf, 1, nullptr, &flags, addr, &slen, - &portfds[0], nullptr); + llarp::LogDebug("read ", sz, " bytes into socket"); + int ret = ::WSARecvFrom(std::get< SOCKET >(fd), &wbuf, 1, nullptr, &flags, + addr, &slen, &portfd, nullptr); // 997 is the error code for queued ops int s_errno = ::WSAGetLastError(); if(ret && s_errno != 997) @@ -74,9 +77,10 @@ namespace llarp return -1; } // WSASendTo - ssize_t sent = - ::WSASendTo(fd, &wbuf, 1, nullptr, 0, to, slen, &portfds[1], nullptr); - int s_errno = ::WSAGetLastError(); + llarp::LogDebug("write ", sz, " bytes into socket"); + ssize_t sent = ::WSASendTo(std::get< SOCKET >(fd), &wbuf, 1, nullptr, 0, + to, slen, &portfd, nullptr); + int s_errno = ::WSAGetLastError(); if(sent && s_errno != 997) { llarp::LogWarn("send socket error ", s_errno); @@ -90,8 +94,9 @@ namespace llarp { llarp_tun_io* t; device* tunif; + OVERLAPPED* tun_async; tun(llarp_tun_io* tio) - : ev_io(-1) + : ev_io(INVALID_HANDLE_VALUE) , t(tio) , tunif(tuntap_init()) @@ -115,6 +120,12 @@ namespace llarp ev_io::flush_write(); } + bool + do_write(void* data, size_t sz) + { + return WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, tun_async); + } + int read(void* buf, size_t sz) { @@ -136,23 +147,24 @@ namespace llarp llarp::LogWarn("failed to start interface"); return false; } - if(tuntap_up(tunif) == -1) + if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1) { - llarp::LogWarn("failed to put interface up: ", strerror(errno)); + llarp::LogWarn("failed to set ip"); return false; } - if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1) + if(tuntap_up(tunif) == -1) { - llarp::LogWarn("failed to set ip"); + llarp::LogWarn("failed to put interface up: ", strerror(errno)); return false; } - fd = (SOCKET)tunif->tun_fd; - if(fd == -1) + + fd = tunif->tun_fd; + tun_async = &tunif->ovl; + if(std::get< HANDLE >(fd) == INVALID_HANDLE_VALUE) return false; - // set non blocking - int on = 1; - return ioctlsocket(fd, FIONBIO, (u_long*)&on) != -1; + // we're already non-blocking + return true; } ~tun() @@ -199,35 +211,29 @@ struct llarp_win32_loop : public llarp_ev_loop // as an arch-specific pointer value ULONG_PTR ev_id = 0; WSAOVERLAPPED* qdata = nullptr; - int result = 0; int idx = 0; + BOOL result = + ::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, ms); - do + if(result && qdata) { - if(ev_id && qdata && iolen) + llarp::udp_listener* ev = reinterpret_cast< llarp::udp_listener* >(ev_id); + if(ev && !ev->fd.valueless_by_exception()) { - llarp::udp_listener* ev = - reinterpret_cast< llarp::udp_listener* >(ev_id); - if(ev && ev->fd) - { - ev->getData(readbuf, sizeof(readbuf), iolen); - } + llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id, + "\tqdata: ", qdata); + ev->getData(readbuf, sizeof(readbuf), iolen); } ++idx; - } while(::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, ms)); - - // tick_listeners inlined since win32 does not - // implement ev_tun - for(auto& l : udp_listeners) - { - if(l->tick) - l->tick(l); } if(!idx) return -1; else + { + tick_listeners(); result = idx; + } return result; } @@ -244,35 +250,30 @@ struct llarp_win32_loop : public llarp_ev_loop // as an arch-specific pointer value ULONG_PTR ev_id = 0; WSAOVERLAPPED* qdata = nullptr; - int result = 0; int idx = 0; + int result = + ::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, 10); // unlike epoll and kqueue, we only need to run so long as the // system call returns TRUE - do + if(result) { - if(ev_id && qdata && iolen) + llarp::udp_listener* ev = reinterpret_cast< llarp::udp_listener* >(ev_id); + if(ev && !ev->fd.valueless_by_exception()) { - llarp::udp_listener* ev = - reinterpret_cast< llarp::udp_listener* >(ev_id); - if(ev && ev->fd) - { - ev->getData(readbuf, sizeof(readbuf), iolen); - } + llarp::LogInfo("size: ", iolen, "\tev_id: ", ev_id, "\tqdata: ", qdata); + ev->getData(readbuf, sizeof(readbuf), iolen); } ++idx; - } while(::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, 10)); - - for(auto& l : udp_listeners) - { - if(l->tick) - l->tick(l); } if(!idx) return -1; else + { + tick_listeners(); result = idx; + } return result; } @@ -292,8 +293,8 @@ struct llarp_win32_loop : public llarp_ev_loop default: return INVALID_SOCKET; } - SOCKET fd = ::WSASocket(addr->sa_family, SOCK_DGRAM, 0, nullptr, 0, - WSA_FLAG_OVERLAPPED); + DWORD on = 1; + SOCKET fd = ::socket(addr->sa_family, SOCK_DGRAM, 0); if(fd == INVALID_SOCKET) { perror("WSASocket()"); @@ -322,7 +323,8 @@ struct llarp_win32_loop : public llarp_ev_loop closesocket(fd); return INVALID_SOCKET; } - llarp::LogInfo("socket fd is ", fd); + llarp::LogDebug("socket fd is ", fd); + ioctlsocket(fd, FIONBIO, &on); return fd; } @@ -331,8 +333,9 @@ struct llarp_win32_loop : public llarp_ev_loop { // On Windows, just close the socket to decrease the iocp refcount // and stop any pending I/O - BOOL stopped = ::CancelIo(reinterpret_cast< HANDLE >(ev->fd)); - return closesocket(ev->fd) == 0 && stopped == TRUE; + BOOL stopped = + ::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd))); + return closesocket(std::get< SOCKET >(ev->fd)) == 0 && stopped == TRUE; } llarp::ev_io* @@ -361,12 +364,37 @@ struct llarp_win32_loop : public llarp_ev_loop bool add_ev(llarp::ev_io* ev, bool write) { - ev->listener_id = reinterpret_cast< ULONG_PTR >(ev); - if(!::CreateIoCompletionPort(reinterpret_cast< HANDLE >(ev->fd), iocpfd, - ev->listener_id, 0)) + uint8_t buf[1024]; + llarp::udp_listener* udp = nullptr; + llarp::tun* t = nullptr; + ev->listener_id = reinterpret_cast< ULONG_PTR >(ev); + memset(&buf, 0, 1024); + + switch(ev->fd.index()) { - delete ev; - return false; + case 0: + udp = dynamic_cast< llarp::udp_listener* >(ev); + if(!::CreateIoCompletionPort((HANDLE)std::get< 0 >(ev->fd), iocpfd, + ev->listener_id, 0)) + { + delete ev; + return false; + } + ::ReadFile((HANDLE)std::get< 0 >(ev->fd), &buf, 1024, nullptr, + &udp->portfd); + break; + case 1: + t = dynamic_cast< llarp::tun* >(ev); + if(!::CreateIoCompletionPort(std::get< 1 >(ev->fd), iocpfd, + ev->listener_id, 0)) + { + delete ev; + return false; + } + ::ReadFile(std::get< 1 >(ev->fd), &buf, 1024, nullptr, t->tun_async); + break; + default: + return false; } return true; } diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 90efd5adb..089a20fd8 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -110,7 +110,8 @@ namespace llarp llarp::Addr tunIp(source_addr); // related to dns_iptracker_setup_dotLokiLookup(&this->dll, tunIp); - dns_iptracker_setup(this->dll.ip_tracker, tunIp); // claim GW IP to make sure it's not inuse + dns_iptracker_setup(this->dll.ip_tracker, + tunIp); // claim GW IP to make sure it's not inuse return true; } return Endpoint::SetOption(k, v); @@ -150,7 +151,8 @@ namespace llarp llarp::Addr tunIp(tunif.ifaddr); dns_iptracker_setup_dotLokiLookup( &this->dll, tunIp); // just set ups dll to use global iptracker - dns_iptracker_setup(this->dll.ip_tracker, tunIp); // claim GW IP to make sure it's not inuse + dns_iptracker_setup(this->dll.ip_tracker, + tunIp); // claim GW IP to make sure it's not inuse // set up networking in currrent thread if we are not isolated if(!SetupNetworking()) @@ -162,8 +164,9 @@ namespace llarp llarp::Addr tunIp(tunif.ifaddr); this->dll.ip_tracker = new dns_iptracker; dns_iptracker_setup_dotLokiLookup( - &this->dll, tunIp); // just set ups dll to use global iptracker - dns_iptracker_setup(this->dll.ip_tracker, tunIp); // claim GW IP to make sure it's not inuse + &this->dll, tunIp); // just set ups dll to use global iptracker + dns_iptracker_setup(this->dll.ip_tracker, + tunIp); // claim GW IP to make sure it's not inuse } // wait for result for network setup llarp::LogInfo("waiting for tun interface..."); @@ -254,9 +257,8 @@ namespace llarp { llarp::LogInfo("Set Up networking for ", Name()); bool result = SetupTun(); -#ifndef _WIN32 - m_TunSetupResult.set_value(result); -#endif + m_TunSetupResult.set_value( + result); // now that NT has tun, we don't need the CPP guard if(!NetworkIsIsolated()) { // need to check to see if we have more than one hidden service diff --git a/llarp/link/utp.cpp b/llarp/link/utp.cpp index a1cc7124c..67ec4d119 100644 --- a/llarp/link/utp.cpp +++ b/llarp/link/utp.cpp @@ -350,7 +350,8 @@ namespace llarp " bytes"); if(::sendto(l->m_udp.fd, (char*)arg->buf, arg->len, arg->flags, arg->address, arg->address_len) - == -1) + == -1 + && errno) { llarp::LogError("sendto failed: ", strerror(errno)); } diff --git a/llarp/time.cpp b/llarp/time.cpp index 6ec997cec..bef56e580 100644 --- a/llarp/time.cpp +++ b/llarp/time.cpp @@ -15,6 +15,9 @@ namespace llarp } // namespace llarp // use std::chrono because otherwise the network breaks with Daylight Savings +// this time, it doesn't get truncated -despair +// that concern is what drove me back to the POSIX C time functions +// in the first place llarp_time_t llarp_time_now_ms() { diff --git a/readme.md b/readme.md index f730d9b19..fc76bf82b 100644 --- a/readme.md +++ b/readme.md @@ -49,10 +49,4 @@ for a development environment: ## Usage -### Windows - -Windows only supports client mode so you run `lokinet.exe` and that's it. - -### Linux - see the [lokinet-builder](https://github.com/loki-project/lokinet-builder) diff --git a/vendor/libtuntap-master/tuntap-windows.c b/vendor/libtuntap-master/tuntap-windows.c index 625a065fc..83b7e880a 100644 --- a/vendor/libtuntap-master/tuntap-windows.c +++ b/vendor/libtuntap-master/tuntap-windows.c @@ -63,7 +63,7 @@ formated_error(LPWSTR pMessage, DWORD m, ...) LPWSTR pBuffer = NULL; va_list args = NULL; - va_start(args, pMessage); + va_start(args, m); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, pMessage, m, 0, (LPSTR)&pBuffer, 0, &args); @@ -189,8 +189,11 @@ tuntap_start(struct device *dev, int mode, int tun) if(mode == TUNTAP_MODE_TUNNEL) { - tuntap_log(TUNTAP_LOG_NOTICE, "Layer 3 tunneling is not implemented"); - return -1; + deviceid = reg_query(NETWORK_ADAPTERS); + snprintf(buf, sizeof buf, "\\\\.\\Global\\%s.tap", deviceid); + tun_fd = CreateFile(buf, GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); } else if(mode != TUNTAP_MODE_ETHERNET) { @@ -198,14 +201,9 @@ tuntap_start(struct device *dev, int mode, int tun) return -1; } - deviceid = reg_query(NETWORK_ADAPTERS); - snprintf(buf, sizeof buf, "\\\\.\\Global\\%s.tap", deviceid); - tun_fd = CreateFile(buf, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); if(tun_fd == TUNFD_INVALID_VALUE) { int errcode = GetLastError(); - tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode)); return -1; } @@ -241,8 +239,8 @@ tuntap_get_hwaddr(struct device *dev) char buf[128]; (void)_snprintf(buf, sizeof buf, - "MAC address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", hwaddr[0], - hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + "MAC address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", hwaddr[0], + hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); tuntap_log(TUNTAP_LOG_DEBUG, buf); } return (char *)hwaddr; @@ -274,8 +272,7 @@ tuntap_sys_set_updown(struct device *dev, ULONG flag) { char buf[32]; - (void)_snprintf(buf, sizeof buf, "Status: %s", - flag ? "Up" : "Down"); + (void)_snprintf(buf, sizeof buf, "Status: %s", flag ? "Up" : "Down"); tuntap_log(TUNTAP_LOG_DEBUG, buf); return 0; } @@ -330,26 +327,54 @@ tuntap_set_mtu(struct device *dev, int mtu) int tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask) { - IPADDR psock[4]; - DWORD len; - - /* Address + Netmask */ - psock[0] = s->S_un.S_addr; - psock[1] = mask; - /* DHCP server address (We don't want it) */ - psock[2] = 0; - /* DHCP lease time */ - psock[3] = 0; - - if(DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_MASQ, &psock, - sizeof(psock), &psock, sizeof(psock), &len, NULL) - == 0) + IPADDR sock[3]; + DWORD len, ret; + IPADDR ep[4]; +#pragma pack(push) +#pragma pack(1) + struct + { + uint8_t dhcp_opt; + uint8_t length; + uint32_t value[2]; + } dns; +#pragma pack(pop) + + sock[0] = s->S_un.S_addr; + sock[2] = mask; + sock[1] = sock[0] & sock[2]; + ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_TUN, &sock, sizeof(sock), + &sock, sizeof(sock), &len, NULL); + ep[0] = s->S_un.S_addr; + ep[1] = mask; + ep[2] = (s->S_un.S_addr | ~mask) + - (mask + 1); /* For the 10.x.0.y subnet (in a class C config), _should_ + be 10.x.0.254 i think */ + ep[3] = 3153600; /* one year */ + + ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof(ep), + ep, sizeof(ep), &len, NULL); + + /* set DNS address to 127.0.0.1 as lokinet-client runs its own DNS resolver + * inline */ + dns.dhcp_opt = 6; + dns.length = 4; + dns.value[0] = + htonl(0x7F000001); /* apparently this doesn't show in network properties, + but it works 🤷🏻‍♂️ */ + dns.value[1] = 0; + + ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_SET_OPT, &dns, + sizeof(dns), &dns, sizeof(dns), &len, NULL); + + if(!ret) { int errcode = GetLastError(); tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode)); return -1; } + return 0; } @@ -369,12 +394,17 @@ tuntap_read(struct device *dev, void *buf, size_t size) { DWORD len; - if(ReadFile(dev->tun_fd, buf, (DWORD)size, &len, NULL) == 0) + if(ReadFile(dev->tun_fd, buf, (DWORD)size, &len, &dev->ovl) == 0) { int errcode = GetLastError(); - tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode)); - return -1; + if (errcode != 997) + { + tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode)); + return -1; + } + else + return 0; } return 0; @@ -385,12 +415,17 @@ tuntap_write(struct device *dev, void *buf, size_t size) { DWORD len; - if(WriteFile(dev->tun_fd, buf, (DWORD)size, &len, NULL) == 0) + if(WriteFile(dev->tun_fd, buf, (DWORD)size, &len, &dev->ovl) == 0) { - int errcode = GetLastError(); - - tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode)); - return -1; + int errcode = GetLastError(); + + if (errcode != 997) + { + tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode)); + return -1; + } + else + return 0; } return 0; @@ -411,7 +446,7 @@ tuntap_set_nonblocking(struct device *dev, int set) (void)dev; (void)set; tuntap_log(TUNTAP_LOG_NOTICE, - "Your system does not support tuntap_set_nonblocking()"); + "TUN/TAP devices on Windows are non-blocking by default using either overlapped I/O or IOCPs"); return -1; } @@ -438,7 +473,6 @@ tuntap_set_descr(struct device *dev, const char *descr) int tuntap_set_ifname(struct device *dev, const char *name) { - /* TODO: Check Windows API to know how to rename an interface */ (void)dev; (void)name; tuntap_log(TUNTAP_LOG_NOTICE, diff --git a/vendor/libtuntap-master/tuntap.cpp b/vendor/libtuntap-master/tuntap.cpp index e821714a1..630107b23 100644 --- a/vendor/libtuntap-master/tuntap.cpp +++ b/vendor/libtuntap-master/tuntap.cpp @@ -68,6 +68,9 @@ extern "C" dev->tun_fd = TUNFD_INVALID_VALUE; dev->ctrl_sock = -1; dev->flags = 0; + #if defined(Windows) + memset(&dev->ovl, 0, sizeof(OVERLAPPED)); + #endif __tuntap_log = &tuntap_log_default; return dev;