I have stare-reviewed the code, then run it back and forth with different
config files. Works as advertised.

Note that this patch contains controversial impersonate_as_system() which we
will remove or #ifdef in the patches to follow.

Acked-By: Simon Rozman <si...@rozman.si>

Best regards,
Simon

> -----Original Message-----
> From: Lev Stipakov <lstipa...@gmail.com>
> Sent: Tuesday, December 17, 2019 1:44 PM
> To: openvpn-devel@lists.sourceforge.net
> Cc: Lev Stipakov <l...@openvpn.net>
> Subject: [Openvpn-devel] [PATCH v8 4/7] wintun: ring buffers based I/O
> 
> From: Lev Stipakov <l...@openvpn.net>
> 
> Implemented according to Wintun documentation and reference client code.
> 
> Wintun uses ring buffers to communicate between kernel driver and user
> process. Client allocates send and receive ring buffers, creates events
> and passes it to kernel driver under LocalSystem privileges.
> 
> When data is available for read, wintun modifies "tail" pointer of send
> ring and signals via event.
> User process reads data from "head" to "tail" and updates "head"
> pointer.
> 
> When user process is ready to write, it writes to receive ring, updates
> "tail" pointer and signals to kernel via event.
> 
> In openvpn code we add send ring's event to event loop.
> Before performing io wait, we compare "head" and "tail"
> pointers of send ring and if they're different, we skip io wait and
> perform read.
> 
> This also adds ring buffers support to tcp and udp server code.
> 
> Signed-off-by: Lev Stipakov <l...@openvpn.net>
> ---
> 
>  v8:
>   - make DeviceIoControl result check more robust
>   - fix struct tun_ring layout
> 
>  v7:
>   - fix comments (no code changes)
> 
>  v6:
>   - added a sanity check to write_wintun() to avoid
>     writing malformed IPv4/6 packet, which causes
>     "ring buffer is out of capacity" error.
> 
>  v5:
>   - fix crash at ring buffer registration on Win7
>     (passing NULL to DeviceIOControl, reported by kitsune1)
> 
>  v4:
>   - added helper function tuntap_ring_empty()
>   - refactored event handling, got rid of separate
>     event_ctl() call for wintun and send/receive_tail_moved
>     members
>   - added wintun_ prefix for ring buffer variables
>   - added a comment explaining the size of wintun-specific buffers
> 
>  v3:
>   - simplified convoluted #ifdefs
>   - replaced "greater than" with "greater or equal than"
> 
>  v2:
>   - rebased on top of master
> 
>  src/openvpn/forward.c |  29 +++++++-
>  src/openvpn/forward.h |  38 +++++++++-
>  src/openvpn/mtcp.c    |  19 ++++-
>  src/openvpn/mudp.c    |   7 +-
>  src/openvpn/options.c |   4 +-
>  src/openvpn/syshead.h |   1 +
>  src/openvpn/tun.c     |  62 +++++++++++++++-
>  src/openvpn/tun.h     | 169 +++++++++++++++++++++++++++++++++++++++++-
>  src/openvpn/win32.c   | 122 ++++++++++++++++++++++++++++++
>  src/openvpn/win32.h   |  50 +++++++++++++
>  10 files changed, 490 insertions(+), 11 deletions(-)
> 
> diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index
> 8451706b..6b823613 100644
> --- a/src/openvpn/forward.c
> +++ b/src/openvpn/forward.c
> @@ -1256,8 +1256,24 @@ read_incoming_tun(struct context *c)
>      perf_push(PERF_READ_IN_TUN);
> 
>      c->c2.buf = c->c2.buffers->read_tun_buf;
> +
>  #ifdef _WIN32
> -    read_tun_buffered(c->c1.tuntap, &c->c2.buf);
> +    if (c->c1.tuntap->wintun)
> +    {
> +        read_wintun(c->c1.tuntap, &c->c2.buf);
> +        if (c->c2.buf.len == -1)
> +        {
> +            register_signal(c, SIGHUP, "tun-abort");
> +            c->persist.restart_sleep_seconds = 1;
> +            msg(M_INFO, "Wintun read error, restarting");
> +            perf_pop();
> +            return;
> +        }
> +    }
> +    else
> +    {
> +        read_tun_buffered(c->c1.tuntap, &c->c2.buf);
> +    }
>  #else
>      ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame)));
>      ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); @@ -
> 2099,6 +2115,17 @@ io_wait_dowork(struct context *c, const unsigned int
> flags)
>          tuntap |= EVENT_READ;
>      }
> 
> +#ifdef _WIN32
> +    if (tuntap_is_wintun(c->c1.tuntap))
> +    {
> +        /*
> +         * With wintun we are only interested in read event. Ring
> buffer is
> +         * always ready for write, so we don't do wait.
> +         */
> +        tuntap = EVENT_READ;
> +    }
> +#endif
> +
>      /*
>       * Configure event wait based on socket, tuntap flags.
>       */
> diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index
> 48202c07..b711ff00 100644
> --- a/src/openvpn/forward.h
> +++ b/src/openvpn/forward.h
> @@ -375,6 +375,12 @@ p2p_iow_flags(const struct context *c)
>      {
>          flags |= IOW_TO_TUN;
>      }
> +#ifdef _WIN32
> +    if (tuntap_ring_empty(c->c1.tuntap))
> +    {
> +        flags &= ~IOW_READ_TUN;
> +    }
> +#endif
>      return flags;
>  }
> 
> @@ -403,8 +409,36 @@ io_wait(struct context *c, const unsigned int
> flags)
>      }
>      else
>      {
> -        /* slow path */
> -        io_wait_dowork(c, flags);
> +#ifdef _WIN32
> +        bool skip_iowait = flags & IOW_TO_TUN;
> +        if (flags & IOW_READ_TUN)
> +        {
> +            /*
> +             * don't read from tun if we have pending write to link,
> +             * since every tun read overwrites to_link buffer filled
> +             * by previous tun read
> +             */
> +            skip_iowait = !(flags & IOW_TO_LINK);
> +        }
> +        if (tuntap_is_wintun(c->c1.tuntap) && skip_iowait)
> +        {
> +            unsigned int ret = 0;
> +            if (flags & IOW_TO_TUN)
> +            {
> +                ret |= TUN_WRITE;
> +            }
> +            if (flags & IOW_READ_TUN)
> +            {
> +                ret |= TUN_READ;
> +            }
> +            c->c2.event_set_status = ret;
> +        }
> +        else
> +#endif
> +        {
> +            /* slow path */
> +            io_wait_dowork(c, flags);
> +        }
>      }
>  }
> 
> diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index
> abe20593..ee28a710 100644
> --- a/src/openvpn/mtcp.c
> +++ b/src/openvpn/mtcp.c
> @@ -269,8 +269,25 @@ multi_tcp_wait(const struct context *c,
>                 struct multi_tcp *mtcp)
>  {
>      int status;
> +    unsigned int *persistent = &mtcp->tun_rwflags;
>      socket_set_listen_persistent(c->c2.link_socket, mtcp->es,
> MTCP_SOCKET);
> -    tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp-
> >tun_rwflags);
> +
> +#ifdef _WIN32
> +    if (tuntap_is_wintun(c->c1.tuntap))
> +    {
> +        if (!tuntap_ring_empty(c->c1.tuntap))
> +        {
> +            /* there is data in wintun ring buffer, read it immediately
> */
> +            mtcp->esr[0].arg = MTCP_TUN;
> +            mtcp->esr[0].rwflags = EVENT_READ;
> +            mtcp->n_esr = 1;
> +            return 1;
> +        }
> +        persistent = NULL;
> +    }
> +#endif
> +    tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, persistent);
> +
>  #ifdef ENABLE_MANAGEMENT
>      if (management)
>      {
> diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index
> b7f061a2..6a29ccc8 100644
> --- a/src/openvpn/mudp.c
> +++ b/src/openvpn/mudp.c
> @@ -278,7 +278,12 @@ p2mp_iow_flags(const struct multi_context *m)
>      {
>          flags |= IOW_READ;
>      }
> -
> +#ifdef _WIN32
> +    if (tuntap_ring_empty(m->top.c1.tuntap))
> +    {
> +        flags &= ~IOW_READ_TUN;
> +    }
> +#endif
>      return flags;
>  }
> 
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c index
> 49affc29..cebcbb07 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -3016,10 +3016,10 @@ options_postprocess_mutate_invariant(struct
> options *options)
>          options->ifconfig_noexec = false;
>      }
> 
> -    /* for wintun kernel doesn't send DHCP requests, so use ipapi to
> set IP address and netmask */
> +    /* for wintun kernel doesn't send DHCP requests, so use netsh to
> + set IP address and netmask */
>      if (options->wintun)
>      {
> -        options->tuntap_options.ip_win32_type = IPW32_SET_IPAPI;
> +        options->tuntap_options.ip_win32_type = IPW32_SET_NETSH;
>      }
> 
>      remap_redirect_gateway_flags(options);
> diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index
> 899aa59e..e9accb52 100644
> --- a/src/openvpn/syshead.h
> +++ b/src/openvpn/syshead.h
> @@ -39,6 +39,7 @@
>  #ifdef _WIN32
>  #include <windows.h>
>  #include <winsock2.h>
> +#include <tlhelp32.h>
>  #define sleep(x) Sleep((x)*1000)
>  #define random rand
>  #define srandom srand
> diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index
> 599fd817..3f66b216 100644
> --- a/src/openvpn/tun.c
> +++ b/src/openvpn/tun.c
> @@ -775,9 +775,27 @@ init_tun_post(struct tuntap *tt,  #ifdef _WIN32
>      overlapped_io_init(&tt->reads, frame, FALSE, true);
>      overlapped_io_init(&tt->writes, frame, TRUE, true);
> -    tt->rw_handle.read = tt->reads.overlapped.hEvent;
> -    tt->rw_handle.write = tt->writes.overlapped.hEvent;
>      tt->adapter_index = TUN_ADAPTER_INDEX_INVALID;
> +
> +    if (tt->wintun)
> +    {
> +        tt->wintun_send_ring = malloc(sizeof(struct tun_ring));
> +        tt->wintun_receive_ring = malloc(sizeof(struct tun_ring));
> +        if ((tt->wintun_send_ring == NULL) || (tt->wintun_receive_ring
> == NULL))
> +        {
> +            msg(M_FATAL, "Cannot allocate memory for ring buffer");
> +        }
> +        ZeroMemory(tt->wintun_send_ring, sizeof(struct tun_ring));
> +        ZeroMemory(tt->wintun_receive_ring, sizeof(struct tun_ring));
> +
> +        tt->rw_handle.read = CreateEvent(NULL, FALSE, FALSE, NULL);
> +        tt->rw_handle.write = CreateEvent(NULL, FALSE, FALSE, NULL);
> +    }
> +    else
> +    {
> +        tt->rw_handle.read = tt->reads.overlapped.hEvent;
> +        tt->rw_handle.write = tt->writes.overlapped.hEvent;
> +    }
>  #endif
>  }
> 
> @@ -6177,6 +6195,34 @@ open_tun(const char *dev, const char *dev_type,
> const char *dev_node, struct tun
>              tt->ipapi_context_defined = true;
>          }
>      }
> +
> +    if (tt->wintun)
> +    {
> +        if (tt->options.msg_channel)
> +        {
> +            /* TODO */
> +        }
> +        else
> +        {
> +            if (!impersonate_as_system())
> +            {
> +                msg(M_FATAL, "ERROR:  Failed to impersonate as SYSTEM,
> make sure process is running under privileged account");
> +            }
> +            if (!register_ring_buffers(tt->hand,
> +                                       tt->wintun_send_ring,
> +                                       tt->wintun_receive_ring,
> +                                       tt->rw_handle.read,
> +                                       tt->rw_handle.write))
> +            {
> +                msg(M_FATAL, "ERROR:  Failed to register ring buffers:
> %lu", GetLastError());
> +            }
> +            if (!RevertToSelf())
> +            {
> +                msg(M_FATAL, "ERROR:  RevertToSelf error: %lu",
> GetLastError());
> +            }
> +        }
> +    }
> +
>      /*netcmd_semaphore_release ();*/
>      gc_free(&gc);
>  }
> @@ -6315,6 +6361,18 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t
> *ctx)
>          free(tt->actual_name);
>      }
> 
> +    if (tt->wintun)
> +    {
> +        CloseHandle(tt->rw_handle.read);
> +        CloseHandle(tt->rw_handle.write);
> +    }
> +
> +    free(tt->wintun_receive_ring);
> +    free(tt->wintun_send_ring);
> +
> +    tt->wintun_receive_ring = NULL;
> +    tt->wintun_send_ring = NULL;
> +
>      clear_tuntap(tt);
>      free(tt);
>      gc_free(&gc);
> diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index
> 66b75d93..10f687c5 100644
> --- a/src/openvpn/tun.h
> +++ b/src/openvpn/tun.h
> @@ -182,6 +182,9 @@ struct tuntap
> 
>      bool wintun; /* true if wintun is used instead of tap-windows6 */
>      int standby_iter;
> +
> +    struct tun_ring *wintun_send_ring;
> +    struct tun_ring *wintun_receive_ring;
>  #else  /* ifdef _WIN32 */
>      int fd; /* file descriptor for TUN/TAP dev */  #endif @@ -211,6
> +214,20 @@ tuntap_defined(const struct tuntap *tt)  #endif  }
> 
> +#ifdef _WIN32
> +inline bool
> +tuntap_is_wintun(struct tuntap *tt)
> +{
> +    return tt && tt->wintun;
> +}
> +
> +inline bool
> +tuntap_ring_empty(struct tuntap *tt)
> +{
> +    return tuntap_is_wintun(tt) && (tt->wintun_send_ring->head ==
> +tt->wintun_send_ring->tail); } #endif
> +
>  /*
>   * Function prototypes
>   */
> @@ -478,10 +495,158 @@ read_tun_buffered(struct tuntap *tt, struct
> buffer *buf)
>      return tun_finalize(tt->hand, &tt->reads, buf);  }
> 
> +static inline ULONG
> +wintun_ring_packet_align(ULONG size)
> +{
> +    return (size + (WINTUN_PACKET_ALIGN - 1)) & ~(WINTUN_PACKET_ALIGN -
> +1); }
> +
> +static inline ULONG
> +wintun_ring_wrap(ULONG value)
> +{
> +    return value & (WINTUN_RING_CAPACITY - 1); }
> +
> +static inline void
> +read_wintun(struct tuntap *tt, struct buffer* buf) {
> +    struct tun_ring *ring = tt->wintun_send_ring;
> +    ULONG head = ring->head;
> +    ULONG tail = ring->tail;
> +    ULONG content_len;
> +    struct TUN_PACKET *packet;
> +    ULONG aligned_packet_size;
> +
> +    *buf = tt->reads.buf_init;
> +    buf->len = 0;
> +
> +    if ((head >= WINTUN_RING_CAPACITY) || (tail >=
> WINTUN_RING_CAPACITY))
> +    {
> +        msg(M_INFO, "Wintun: ring capacity exceeded");
> +        buf->len = -1;
> +        return;
> +    }
> +
> +    if (head == tail)
> +    {
> +        /* nothing to read */
> +        return;
> +    }
> +
> +    content_len = wintun_ring_wrap(tail - head);
> +    if (content_len < sizeof(struct TUN_PACKET_HEADER))
> +    {
> +        msg(M_INFO, "Wintun: incomplete packet header in send ring");
> +        buf->len = -1;
> +        return;
> +    }
> +
> +    packet = (struct TUN_PACKET *) &ring->data[head];
> +    if (packet->size > WINTUN_MAX_PACKET_SIZE)
> +    {
> +        msg(M_INFO, "Wintun: packet too big in send ring");
> +        buf->len = -1;
> +        return;
> +    }
> +
> +    aligned_packet_size = wintun_ring_packet_align(sizeof(struct
> TUN_PACKET_HEADER) + packet->size);
> +    if (aligned_packet_size > content_len)
> +    {
> +        msg(M_INFO, "Wintun: incomplete packet in send ring");
> +        buf->len = -1;
> +        return;
> +    }
> +
> +    buf_write(buf, packet->data, packet->size);
> +
> +    head = wintun_ring_wrap(head + aligned_packet_size);
> +    ring->head = head;
> +}
> +
> +static inline bool
> +is_ip_packet_valid(const struct buffer *buf) {
> +    const struct openvpn_iphdr* ih = (const struct openvpn_iphdr
> +*)BPTR(buf);
> +
> +    if (OPENVPN_IPH_GET_VER(ih->version_len) == 4)
> +    {
> +        if (BLEN(buf) < sizeof(struct openvpn_iphdr))
> +        {
> +            return false;
> +        }
> +    }
> +    else if (OPENVPN_IPH_GET_VER(ih->version_len) == 6)
> +    {
> +        if (BLEN(buf) < sizeof(struct openvpn_ipv6hdr))
> +        {
> +            return false;
> +        }
> +    }
> +    else
> +    {
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +static inline int
> +write_wintun(struct tuntap *tt, struct buffer *buf) {
> +    struct tun_ring *ring = tt->wintun_receive_ring;
> +    ULONG head = ring->head;
> +    ULONG tail = ring->tail;
> +    ULONG aligned_packet_size;
> +    ULONG buf_space;
> +    struct TUN_PACKET *packet;
> +
> +    /* wintun marks ring as corrupted (overcapacity) if it receives
> invalid IP packet */
> +    if (!is_ip_packet_valid(buf))
> +    {
> +        msg(D_LOW, "write_wintun(): drop invalid IP packet");
> +        return 0;
> +    }
> +
> +    if ((head >= WINTUN_RING_CAPACITY) || (tail >=
> WINTUN_RING_CAPACITY))
> +    {
> +        msg(M_INFO, "write_wintun(): head/tail value is over
> capacity");
> +        return -1;
> +    }
> +
> +    aligned_packet_size = wintun_ring_packet_align(sizeof(struct
> TUN_PACKET_HEADER) + BLEN(buf));
> +    buf_space = wintun_ring_wrap(head - tail - WINTUN_PACKET_ALIGN);
> +    if (aligned_packet_size > buf_space)
> +    {
> +        msg(M_INFO, "write_wintun(): ring is full");
> +        return 0;
> +    }
> +
> +    /* copy packet size and data into ring */
> +    packet = (struct TUN_PACKET* )&ring->data[tail];
> +    packet->size = BLEN(buf);
> +    memcpy(packet->data, BPTR(buf), BLEN(buf));
> +
> +    /* move ring tail */
> +    ring->tail = wintun_ring_wrap(tail + aligned_packet_size);
> +    if (ring->alertable != 0)
> +    {
> +        SetEvent(tt->rw_handle.write);
> +    }
> +
> +    return BLEN(buf);
> +}
> +
>  static inline int
>  write_tun_buffered(struct tuntap *tt, struct buffer *buf)  {
> -    return tun_write_win32(tt, buf);
> +    if (tt->wintun)
> +    {
> +        return write_wintun(tt, buf);
> +    }
> +    else
> +    {
> +        return tun_write_win32(tt, buf);
> +    }
>  }
> 
>  #else  /* ifdef _WIN32 */
> @@ -544,7 +709,7 @@ tun_set(struct tuntap *tt,
>              }
>          }
>  #ifdef _WIN32
> -        if (rwflags & EVENT_READ)
> +        if (!tt->wintun && (rwflags & EVENT_READ))
>          {
>              tun_read_queue(tt, 0);
>          }
> diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index
> eb4c0307..24dae7d6 100644
> --- a/src/openvpn/win32.c
> +++ b/src/openvpn/win32.c
> @@ -1493,4 +1493,126 @@ send_msg_iservice(HANDLE pipe, const void *data,
> size_t size,
>      return ret;
>  }
> 
> +bool
> +impersonate_as_system()
> +{
> +    HANDLE thread_token, process_snapshot, winlogon_process,
> winlogon_token, duplicated_token;
> +    PROCESSENTRY32 entry;
> +    BOOL ret;
> +    DWORD pid = 0;
> +    TOKEN_PRIVILEGES privileges;
> +
> +    CLEAR(entry);
> +    CLEAR(privileges);
> +
> +    entry.dwSize = sizeof(PROCESSENTRY32);
> +
> +    privileges.PrivilegeCount = 1;
> +    privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
> +
> +    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME,
> &privileges.Privileges[0].Luid))
> +    {
> +        return false;
> +    }
> +
> +    if (!ImpersonateSelf(SecurityImpersonation))
> +    {
> +        return false;
> +    }
> +
> +    if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES,
> FALSE, &thread_token))
> +    {
> +        RevertToSelf();
> +        return false;
> +    }
> +    if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges,
> sizeof(privileges), NULL, NULL))
> +    {
> +        CloseHandle(thread_token);
> +        RevertToSelf();
> +        return false;
> +    }
> +    CloseHandle(thread_token);
> +
> +    process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
> +    if (process_snapshot == INVALID_HANDLE_VALUE)
> +    {
> +        RevertToSelf();
> +        return false;
> +    }
> +    for (ret = Process32First(process_snapshot, &entry); ret; ret =
> Process32Next(process_snapshot, &entry))
> +    {
> +        if (!_stricmp(entry.szExeFile, "winlogon.exe"))
> +        {
> +            pid = entry.th32ProcessID;
> +            break;
> +        }
> +    }
> +    CloseHandle(process_snapshot);
> +    if (!pid)
> +    {
> +        RevertToSelf();
> +        return false;
> +    }
> +
> +    winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
> pid);
> +    if (!winlogon_process)
> +    {
> +        RevertToSelf();
> +        return false;
> +    }
> +
> +    if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE |
> TOKEN_DUPLICATE, &winlogon_token))
> +    {
> +        CloseHandle(winlogon_process);
> +        RevertToSelf();
> +        return false;
> +    }
> +    CloseHandle(winlogon_process);
> +
> +    if (!DuplicateToken(winlogon_token, SecurityImpersonation,
> &duplicated_token))
> +    {
> +        CloseHandle(winlogon_token);
> +        RevertToSelf();
> +        return false;
> +    }
> +    CloseHandle(winlogon_token);
> +
> +    if (!SetThreadToken(NULL, duplicated_token))
> +    {
> +        CloseHandle(duplicated_token);
> +        RevertToSelf();
> +        return false;
> +    }
> +    CloseHandle(duplicated_token);
> +
> +    return true;
> +}
> +
> +bool
> +register_ring_buffers(HANDLE device,
> +                      struct tun_ring* send_ring,
> +                      struct tun_ring* receive_ring,
> +                      HANDLE send_tail_moved,
> +                      HANDLE receive_tail_moved) {
> +    struct tun_register_rings rr;
> +    BOOL res;
> +    DWORD bytes_returned;
> +
> +    ZeroMemory(&rr, sizeof(rr));
> +
> +    rr.send.ring = send_ring;
> +    rr.send.ring_size = sizeof(struct tun_ring);
> +    rr.send.tail_moved = send_tail_moved;
> +
> +    rr.receive.ring = receive_ring;
> +    rr.receive.ring_size = sizeof(struct tun_ring);
> +    rr.receive.tail_moved = receive_tail_moved;
> +
> +    res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr,
> sizeof(rr),
> +                          NULL, 0, &bytes_returned, NULL);
> +
> +    return res != FALSE;
> +}
> +
>  #endif /* ifdef _WIN32 */
> diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index
> 4814bbc5..5fe95f47 100644
> --- a/src/openvpn/win32.h
> +++ b/src/openvpn/win32.h
> @@ -25,6 +25,8 @@
>  #ifndef OPENVPN_WIN32_H
>  #define OPENVPN_WIN32_H
> 
> +#include <winioctl.h>
> +
>  #include "mtu.h"
>  #include "openvpn-msg.h"
>  #include "argv.h"
> @@ -323,5 +325,53 @@ bool send_msg_iservice(HANDLE pipe, const void
> *data, size_t size,  int  openvpn_execve(const struct argv *a, const
> struct env_set *es, const unsigned int flags);
> 
> +/*
> + * Values below are taken from Wireguard Windows client
> + *
> +https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_w
> +indows.go#L14
> + */
> +#define WINTUN_RING_CAPACITY 0x800000
> +#define WINTUN_RING_TRAILING_BYTES 0x10000 #define
> +WINTUN_MAX_PACKET_SIZE 0xffff #define WINTUN_PACKET_ALIGN 4
> +
> +struct tun_ring
> +{
> +    volatile ULONG head;
> +    volatile ULONG tail;
> +    volatile LONG alertable;
> +    UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; };
> +
> +struct tun_register_rings
> +{
> +    struct
> +    {
> +        ULONG ring_size;
> +        struct tun_ring *ring;
> +        HANDLE tail_moved;
> +    } send, receive;
> +};
> +
> +struct TUN_PACKET_HEADER
> +{
> +    uint32_t size;
> +};
> +
> +struct TUN_PACKET
> +{
> +    uint32_t size;
> +    UCHAR data[WINTUN_MAX_PACKET_SIZE]; };
> +
> +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U,
> +METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
> +
> +bool impersonate_as_system();
> +
> +bool register_ring_buffers(HANDLE device,
> +                           struct tun_ring *send_ring,
> +                           struct tun_ring *receive_ring,
> +                           HANDLE send_tail_moved,
> +                           HANDLE receive_tail_moved);
> +
>  #endif /* ifndef OPENVPN_WIN32_H */
>  #endif /* ifdef _WIN32 */
> --
> 2.17.1
> 
> 
> 
> _______________________________________________
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Attachment: smime.p7s
Description: S/MIME cryptographic signature

_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to