diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2022-08-31 01:17:10 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2022-08-31 01:17:10 +0200 |
commit | 7b42d7f3415149005b05b7b5ea14fca6cb01a261 (patch) | |
tree | 0e3ffae3c4bdbe731c199ebff31c3482ace7f722 |
initial commit
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | Makefile | 48 | ||||
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | berkeley.c | 580 | ||||
-rw-r--r-- | berkeley.h | 38 | ||||
-rw-r--r-- | driver.bat | 27 | ||||
-rw-r--r-- | driver.cpp | 116 | ||||
-rw-r--r-- | ksocket.c | 700 | ||||
-rw-r--r-- | ksocket.h | 165 | ||||
-rw-r--r-- | userspace_client.cpp | 78 | ||||
-rw-r--r-- | wsk.h | 456 |
10 files changed, 2222 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08126f7 --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +ifndef DPP_ROOT +$(error DPP_ROOT is undefined) +endif + +include $(DPP_ROOT)/Makefile.inc + +DRIVER_NAME = driver +DRIVER_OBJECTS = $(DRIVER_NAME).o ksocket.o berkeley.o +DRIVER_TARGET = $(DRIVER_NAME).sys +DRIVER_CFLAGS = -I. -Wl,--exclude-all-symbols + +USERSPACE_NAME = userspace_client +USERSPACE_OBJECTS = $(USERSPACE_NAME).o +USERSPACE_TARGET = $(USERSPACE_NAME).exe + +# mingw-w64-ddk-template related +CFLAGS += $(DRIVER_CFLAGS) +DRIVER_LIBS += -lnetio +USER_LIBS += -lws2_32 + +all: $(DRIVER_TARGET) $(USERSPACE_TARGET) + +%.o: %.cpp + $(call BUILD_CPP_OBJECT,$<,$@) + +%.o: %.c + $(call BUILD_C_OBJECT,$<,$@) + +$(DRIVER_TARGET): $(DRIVER_OBJECTS) + $(call LINK_CPP_KERNEL_TARGET,$(DRIVER_OBJECTS),$@) + +$(USERSPACE_TARGET): $(USERSPACE_OBJECTS) + $(call LINK_CPP_USER_TARGET,$(USERSPACE_OBJECTS),$@) + +install: $(DRIVER_TARGET) $(USERSPACE_TARGET) + $(call INSTALL_EXEC_SIGN,$(DRIVER_TARGET)) + $(call INSTALL_EXEC,$(USERSPACE_TARGET)) + $(INSTALL) '$(DRIVER_NAME).bat' '$(DESTDIR)/' + +clean: + rm -f $(DRIVER_OBJECTS) + rm -f $(DRIVER_TARGET) $(DRIVER_TARGET).map + rm -f $(USERSPACE_OBJECTS) + rm -f $(USERSPACE_TARGET) + +.NOTPARALLEL: clean +.PHONY: all install clean +.DEFAULT_GOAL := all diff --git a/README.md b/README.md new file mode 100644 index 0000000..26f2bbd --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Mingw64 C++ Kernel Sockets + +Requires [mingw-w64-dpp](https://github.com/utoni/mingw-w64-dpp). + +Did you ever ask yourself the question: how-the-hell can I open a socket in kernel mode with a Mingw-w64 compiled driver? +Well, this is the solution. `mingw-w64-ksocket` simplifies the use of stream/datagram client/server sockets. +The API is similiar to the BSD socket API. +Greetings to [KSOCKET](https://github.com/wbenny/KSOCKET) for this sweet approach. + +# HowTo + +```shell +make -C . DPP_ROOT="[path-to-mingw-w64-ddk-template-dir]" clean all +``` diff --git a/berkeley.c b/berkeley.c new file mode 100644 index 0000000..e72f92e --- /dev/null +++ b/berkeley.c @@ -0,0 +1,580 @@ +#include "berkeley.h" +#include "ksocket.h" + +////////////////////////////////////////////////////////////////////////// +// Definitions. +////////////////////////////////////////////////////////////////////////// + +#define MEMORY_TAG ((ULONG)0x2e2e4242) +#define SOCKETFD_MAX 128 +#define TO_SOCKETFD(index) ((index % SOCKETFD_MAX) + 0) +#define FROM_SOCKETFD(sockfd) ((sockfd)-0) + +////////////////////////////////////////////////////////////////////////// +// Function prototypes. +////////////////////////////////////////////////////////////////////////// + +NTSTATUS +NTAPI +KspUtilAddrInfoToAddrInfoEx(_In_ PADDRINFOA AddrInfo, + _Out_ PADDRINFOEXW *AddrInfoEx); + +NTSTATUS +NTAPI +KspUtilAddrInfoExToAddrInfo(_In_ PADDRINFOEXW AddrInfoEx, + _Out_ PADDRINFOA *AddrInfo); + +VOID NTAPI KspUtilFreeAddrInfo(_In_ PADDRINFOA AddrInfo); + +VOID NTAPI KspUtilFreeAddrInfoEx(_In_ PADDRINFOEXW AddrInfo); + +////////////////////////////////////////////////////////////////////////// +// Variables. +////////////////////////////////////////////////////////////////////////// + +// +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// +// This is complete bollocks and ideally it should be replaced with +// something like RTL_AVL_TABLE. +// +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// + +PKSOCKET KsArray[SOCKETFD_MAX] = {0}; +ULONG KsIndex = 0; + +////////////////////////////////////////////////////////////////////////// +// Private functions. +////////////////////////////////////////////////////////////////////////// + +NTSTATUS +NTAPI +KspUtilAddrInfoToAddrInfoEx(_In_ PADDRINFOA AddrInfo, + _Out_ PADDRINFOEXW *AddrInfoEx) { + NTSTATUS Status; + + // + // Convert NULL input into NULL output. + // + + if (AddrInfo == NULL) { + *AddrInfoEx = NULL; + return STATUS_SUCCESS; + } + + // + // Allocate memory for the output structure. + // + + PADDRINFOEXW Result = + ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOEXW), MEMORY_TAG); + + if (Result == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Error1; + } + + // + // Copy numeric values. + // + + RtlZeroMemory(Result, sizeof(ADDRINFOEXW)); + Result->ai_flags = AddrInfo->ai_flags; + Result->ai_family = AddrInfo->ai_family; + Result->ai_socktype = AddrInfo->ai_socktype; + Result->ai_protocol = AddrInfo->ai_protocol; + Result->ai_addrlen = AddrInfo->ai_addrlen; + + // + // Copy canonical name. + // + + ANSI_STRING CanonicalNameAnsi; + UNICODE_STRING CanonicalNameUnicode; + + if (AddrInfo->ai_canonname) { + RtlInitAnsiString(&CanonicalNameAnsi, AddrInfo->ai_canonname); + + Status = RtlAnsiStringToUnicodeString(&CanonicalNameUnicode, + &CanonicalNameAnsi, TRUE); + + if (!NT_SUCCESS(Status)) { + goto Error2; + } + + Result->ai_canonname = CanonicalNameUnicode.Buffer; + } + + // + // Copy address. + // + + Result->ai_addr = AddrInfo->ai_addr; + + // + // Copy the next structure (recursively). + // + + PADDRINFOEXW NextAddrInfo; + Status = KspUtilAddrInfoToAddrInfoEx(AddrInfo->ai_next, &NextAddrInfo); + + if (!NT_SUCCESS(Status)) { + goto Error3; + } + + Result->ai_next = NextAddrInfo; + + // + // All done! + // + + *AddrInfoEx = Result; + + return Status; + +Error3: + RtlFreeAnsiString(&CanonicalNameAnsi); + +Error2: + ExFreePoolWithTag(Result, MEMORY_TAG); + +Error1: + return Status; +} + +NTSTATUS +NTAPI +KspUtilAddrInfoExToAddrInfo(_In_ PADDRINFOEXW AddrInfoEx, + _Out_ PADDRINFOA *AddrInfo) { + NTSTATUS Status; + + // + // Convert NULL input into NULL output. + // + + if (AddrInfoEx == NULL) { + *AddrInfo = NULL; + return STATUS_SUCCESS; + } + + // + // Allocate memory for the output structure. + // + + PADDRINFOA Result = + ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOA), MEMORY_TAG); + + if (Result == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Error1; + } + + // + // Copy numeric values. + // + + RtlZeroMemory(Result, sizeof(ADDRINFOA)); + Result->ai_flags = AddrInfoEx->ai_flags; + Result->ai_family = AddrInfoEx->ai_family; + Result->ai_socktype = AddrInfoEx->ai_socktype; + Result->ai_protocol = AddrInfoEx->ai_protocol; + Result->ai_addrlen = AddrInfoEx->ai_addrlen; + + // + // Copy canonical name. + // + + UNICODE_STRING CanonicalNameUnicode; + ANSI_STRING CanonicalNameAnsi; + + if (AddrInfoEx->ai_canonname) { + RtlInitUnicodeString(&CanonicalNameUnicode, AddrInfoEx->ai_canonname); + Status = RtlUnicodeStringToAnsiString(&CanonicalNameAnsi, + &CanonicalNameUnicode, TRUE); + + if (!NT_SUCCESS(Status)) { + goto Error2; + } + + Result->ai_canonname = CanonicalNameAnsi.Buffer; + } + + // + // Copy address. + // + + Result->ai_addr = AddrInfoEx->ai_addr; + + // + // Copy the next structure (recursively). + // + + PADDRINFOA NextAddrInfo; + Status = KspUtilAddrInfoExToAddrInfo(AddrInfoEx->ai_next, &NextAddrInfo); + + if (!NT_SUCCESS(Status)) { + goto Error3; + } + + Result->ai_next = NextAddrInfo; + + // + // All done! + // + + *AddrInfo = Result; + + return Status; + +Error3: + RtlFreeAnsiString(&CanonicalNameAnsi); + +Error2: + ExFreePoolWithTag(Result, MEMORY_TAG); + +Error1: + return Status; +} + +VOID NTAPI KspUtilFreeAddrInfo(_In_ PADDRINFOA AddrInfo) { + // + // Free all structures recursively. + // + + if (AddrInfo->ai_next) { + KspUtilFreeAddrInfo(AddrInfo->ai_next); + } + + // + // Free the canonical name buffer. + // + + if (AddrInfo->ai_canonname) { + ANSI_STRING CanonicalName; + RtlInitAnsiString(&CanonicalName, AddrInfo->ai_canonname); + RtlFreeAnsiString(&CanonicalName); + } + + // + // Finally, free the structure itself. + // + + ExFreePoolWithTag(AddrInfo, MEMORY_TAG); +} + +VOID NTAPI KspUtilFreeAddrInfoEx(_In_ PADDRINFOEXW AddrInfo) { + // + // Free all structures recursively. + // + + if (AddrInfo->ai_next) { + KspUtilFreeAddrInfoEx(AddrInfo->ai_next); + } + + // + // Free the canonical name buffer. + // + + if (AddrInfo->ai_canonname) { + UNICODE_STRING CanonicalName; + RtlInitUnicodeString(&CanonicalName, AddrInfo->ai_canonname); + RtlFreeUnicodeString(&CanonicalName); + } + + // + // Finally, free the structure itself. + // + + ExFreePoolWithTag(AddrInfo, MEMORY_TAG); +} + +////////////////////////////////////////////////////////////////////////// +// Public functions. +////////////////////////////////////////////////////////////////////////// + +uint32_t htonl(uint32_t hostlong) { return __builtin_bswap32(hostlong); } + +uint16_t htons(uint16_t hostshort) { return __builtin_bswap16(hostshort); } + +uint32_t ntohl(uint32_t netlong) { return __builtin_bswap32(netlong); } + +uint16_t ntohs(uint16_t netshort) { return __builtin_bswap16(netshort); } + +int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res) { + NTSTATUS Status; + + // + // Convert node name to the UNICODE_STRING (if present). + // + + ANSI_STRING NodeNameAnsi; + UNICODE_STRING NodeNameUnicode; + PUNICODE_STRING NodeName = NULL; + + if (node) { + RtlInitAnsiString(&NodeNameAnsi, node); + Status = + RtlAnsiStringToUnicodeString(&NodeNameUnicode, &NodeNameAnsi, TRUE); + + if (!NT_SUCCESS(Status)) { + goto Error1; + } + + NodeName = &NodeNameUnicode; + } + + // + // Convert service name to the UNICODE_STRING (if present). + // + + ANSI_STRING ServiceNameAnsi; + UNICODE_STRING ServiceNameUnicode; + PUNICODE_STRING ServiceName = NULL; + + if (service) { + RtlInitAnsiString(&ServiceNameAnsi, service); + Status = RtlAnsiStringToUnicodeString(&ServiceNameUnicode, &ServiceNameAnsi, + TRUE); + + if (!NT_SUCCESS(Status)) { + goto Error2; + } + + ServiceName = &ServiceNameUnicode; + } + + // + // Convert "struct addrinfo" to the "ADDRINFOEXW". + // + + PADDRINFOEXW Hints; + Status = KspUtilAddrInfoToAddrInfoEx((PADDRINFOA)hints, &Hints); + + if (!NT_SUCCESS(Status)) { + goto Error3; + } + + // + // All data is prepared, call the underlying API. + // + + PADDRINFOEXW Result; + Status = KsGetAddrInfo(NodeName, ServiceName, Hints, &Result); + + // + // Free the memory of the converted "Hints". + // + + KspUtilFreeAddrInfoEx(Hints); + + if (!NT_SUCCESS(Status)) { + goto Error3; + } + + // + // Convert the result "ADDRINFOEXW" to the "struct addrinfo". + // + + Status = KspUtilAddrInfoExToAddrInfo(Result, res); + + // + // Free the original result. + // + + KsFreeAddrInfo(Result); + + if (!NT_SUCCESS(Status)) { + goto Error3; + } + + return STATUS_SUCCESS; + +Error3: + RtlFreeUnicodeString(&ServiceNameUnicode); + +Error2: + RtlFreeUnicodeString(&NodeNameUnicode); + +Error1: + return Status; +} + +void freeaddrinfo(struct addrinfo *res) { + // + // Call our implementation. + // + + KspUtilFreeAddrInfo(res); +} + +int socket_connection(int domain, int type, int protocol) { + NTSTATUS Status; + PKSOCKET Socket; + + Status = KsCreateConnectionSocket(&Socket, (ADDRESS_FAMILY)domain, + (USHORT)type, (ULONG)protocol); + + if (NT_SUCCESS(Status)) { + int sockfd = TO_SOCKETFD(KsIndex++); + + KsArray[FROM_SOCKETFD(sockfd)] = Socket; + + return sockfd; + } + + return -1; +} + +int socket_listen(int domain, int type, int protocol) { + NTSTATUS Status; + PKSOCKET Socket; + + // + // WskSocket() returns STATUS_PROTOCOL_UNREACHABLE (0xC000023E) + // when Protocol == 0, so coerce this value to IPPROTO_TCP here. + // + + Status = KsCreateListenSocket(&Socket, (ADDRESS_FAMILY)domain, (USHORT)type, + protocol ? (ULONG)protocol : IPPROTO_TCP); + + if (NT_SUCCESS(Status)) { + int sockfd = TO_SOCKETFD(KsIndex++); + + KsArray[FROM_SOCKETFD(sockfd)] = Socket; + + return sockfd; + } + + return -1; +} + +int socket_datagram(int domain, int type, int protocol) { + NTSTATUS Status; + PKSOCKET Socket; + + Status = KsCreateDatagramSocket(&Socket, (ADDRESS_FAMILY)domain, (USHORT)type, + (ULONG)protocol); + + if (NT_SUCCESS(Status)) { + int sockfd = TO_SOCKETFD(KsIndex++); + + KsArray[FROM_SOCKETFD(sockfd)] = Socket; + + return sockfd; + } + + return -1; +} + +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + UNREFERENCED_PARAMETER(addrlen); + + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + Status = KsConnect(Socket, (PSOCKADDR)addr); + + return NT_SUCCESS(Status) ? 0 : -1; +} + +int listen(int sockfd, int backlog) { + UNREFERENCED_PARAMETER(sockfd); + UNREFERENCED_PARAMETER(backlog); + return 0; +} + +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + UNREFERENCED_PARAMETER(addrlen); + + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + Status = KsBind(Socket, (PSOCKADDR)addr); + + return NT_SUCCESS(Status) ? 0 : -1; +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + PKSOCKET NewSocket; + Status = KsAccept(Socket, &NewSocket, NULL, (PSOCKADDR)addr); + *addrlen = sizeof(SOCKADDR); + + if (NT_SUCCESS(Status)) { + int newsockfd = TO_SOCKETFD(KsIndex++); + + KsArray[FROM_SOCKETFD(newsockfd)] = NewSocket; + + return newsockfd; + } + + return -1; +} + +int send(int sockfd, const void *buf, size_t len, int flags) { + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + ULONG Length = (ULONG)len; + Status = KsSend(Socket, (PVOID)buf, &Length, (ULONG)flags); + + return NT_SUCCESS(Status) ? (int)Length : -1; +} + +int sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) { + UNREFERENCED_PARAMETER(addrlen); + + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + ULONG Length = (ULONG)len; + Status = + KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)dest_addr); + + return NT_SUCCESS(Status) ? (int)Length : -1; +} + +int recv(int sockfd, void *buf, size_t len, int flags) { + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + ULONG Length = (ULONG)len; + Status = KsRecv(Socket, (PVOID)buf, &Length, (ULONG)flags); + + return NT_SUCCESS(Status) ? (int)Length : -1; +} + +int recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) { + UNREFERENCED_PARAMETER(addrlen); + + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + ULONG Length = (ULONG)len; + Status = + KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)src_addr); + *addrlen = sizeof(SOCKADDR); + + return NT_SUCCESS(Status) ? (int)Length : -1; +} + +int closesocket(int sockfd) { + NTSTATUS Status; + PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; + + Status = KsCloseSocket(Socket); + + KsArray[FROM_SOCKETFD(sockfd)] = NULL; + + return NT_SUCCESS(Status) ? 0 : -1; +} diff --git a/berkeley.h b/berkeley.h new file mode 100644 index 0000000..75cdb0f --- /dev/null +++ b/berkeley.h @@ -0,0 +1,38 @@ +#pragma once +#include <ntddk.h> +#include <wsk.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int socklen_t; +typedef intptr_t ssize_t; + +uint32_t htonl(uint32_t hostlong); +uint16_t htons(uint16_t hostshort); +uint32_t ntohl(uint32_t netlong); +uint16_t ntohs(uint16_t netshort); + +int getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res); +void freeaddrinfo(struct addrinfo *res); + +int socket_connection(int domain, int type, int protocol); +int socket_listen(int domain, int type, int protocol); +int socket_datagram(int domain, int type, int protocol); +int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen); +int listen(int sockfd, int backlog); +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int send(int sockfd, const void* buf, size_t len, int flags); +int sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +int recv(int sockfd, void* buf, size_t len, int flags); +int recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +int closesocket(int sockfd); + +#define socket socket_connection + +#ifdef __cplusplus +} +#endif diff --git a/driver.bat b/driver.bat new file mode 100644 index 0000000..519d9e8 --- /dev/null +++ b/driver.bat @@ -0,0 +1,27 @@ +@echo off +set SERVICE_NAME=ksocket +set DRIVER="%~dp0\driver.sys" + +net session >nul 2>&1 +if NOT %ERRORLEVEL% EQU 0 ( + echo ERROR: This script requires Administrator privileges! + pause + exit /b 1 +) + +echo --------------------------------------- +echo -- Service Name: %SERVICE_NAME% +echo -- Driver......: %DRIVER% +echo --------------------------------------- + +sc create %SERVICE_NAME% binPath= %DRIVER% type= kernel +echo --------------------------------------- +sc start %SERVICE_NAME% +echo --------------------------------------- +sc query %SERVICE_NAME% +echo [PRESS A KEY TO STOP THE DRIVER] +pause +sc stop %SERVICE_NAME% +sc delete %SERVICE_NAME% +echo Done. +timeout /t 3 diff --git a/driver.cpp b/driver.cpp new file mode 100644 index 0000000..005468d --- /dev/null +++ b/driver.cpp @@ -0,0 +1,116 @@ + +extern "C" { +#include "berkeley.h" +#include "ksocket.h" +#include "wsk.h" + +DRIVER_INITIALIZE DriverEntry; +DRIVER_UNLOAD DriverUnload; + +#define DebuggerPrint(...) \ + DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__); + +NTSTATUS +NTAPI +DriverEntry(_In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath) { + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(RegistryPath); + + NTSTATUS Status; + + // + // Initialize KSOCKET. + // + + Status = KsInitialize(); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Client. + // Perform HTTP request to http://httpbin.org/uuid + // + + { + int result; + UNREFERENCED_PARAMETER(result); + + char send_buffer[] = "GET /uuid HTTP/1.1\r\n" + "Host: httpbin.org\r\n" + "Connection: close\r\n" + "\r\n"; + + char recv_buffer[1024] = {}; + + struct addrinfo hints = {}; + hints.ai_flags |= AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + struct addrinfo *res; + result = getaddrinfo("httpbin.org", "80", &hints, &res); + + int sockfd; + sockfd = socket_connection(AF_INET, SOCK_STREAM, IPPROTO_TCP); + result = connect(sockfd, res->ai_addr, (int)res->ai_addrlen); + result = send(sockfd, send_buffer, sizeof(send_buffer), 0); + result = recv(sockfd, recv_buffer, sizeof(recv_buffer), 0); + recv_buffer[sizeof(recv_buffer) - 1] = '\0'; + + DebuggerPrint("TCP client:\n%s\n", recv_buffer); + + closesocket(sockfd); + } + + // + // TCP server. + // Listen on port 9095, wait for some message, + // then send our buffer and close connection. + // + + { + int result; + UNREFERENCED_PARAMETER(result); + + char send_buffer[] = "Hello from WSK!"; + char recv_buffer[1024] = {0}; + + int server_sockfd = socket_listen(AF_INET, SOCK_STREAM, 0); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(9095); + + result = bind(server_sockfd, (struct sockaddr *)&addr, sizeof(addr)); + result = listen(server_sockfd, 1); + + socklen_t addrlen = sizeof(addr); + int client_sockfd = + accept(server_sockfd, (struct sockaddr *)&addr, &addrlen); + + result = recv(client_sockfd, recv_buffer, sizeof(recv_buffer) - 1, 0); + recv_buffer[sizeof(recv_buffer) - 1] = '\0'; + + DebuggerPrint("TCP server:\n%s\n", recv_buffer); + + result = send(client_sockfd, send_buffer, sizeof(send_buffer), 0); + + closesocket(client_sockfd); + closesocket(server_sockfd); + } + + KsDestroy(); + + return STATUS_SUCCESS; +} + +VOID DriverUnload(_In_ struct _DRIVER_OBJECT *DriverObject) { + UNREFERENCED_PARAMETER(DriverObject); + + DebuggerPrint("Bye."); +} +} diff --git a/ksocket.c b/ksocket.c new file mode 100644 index 0000000..5262333 --- /dev/null +++ b/ksocket.c @@ -0,0 +1,700 @@ +#include "ksocket.h" + +////////////////////////////////////////////////////////////////////////// +// Definitions. +////////////////////////////////////////////////////////////////////////// + +#define MEMORY_TAG ((ULONG)0x2e2e4142) + +////////////////////////////////////////////////////////////////////////// +// Structures. +////////////////////////////////////////////////////////////////////////// + +typedef struct _KSOCKET_ASYNC_CONTEXT { + KEVENT CompletionEvent; + PIRP Irp; +} KSOCKET_ASYNC_CONTEXT, *PKSOCKET_ASYNC_CONTEXT; + +typedef struct _KSOCKET { + PWSK_SOCKET WskSocket; + + union { + PVOID WskDispatch; + + PWSK_PROVIDER_CONNECTION_DISPATCH WskConnectionDispatch; + PWSK_PROVIDER_LISTEN_DISPATCH WskListenDispatch; + PWSK_PROVIDER_DATAGRAM_DISPATCH WskDatagramDispatch; +#if (NTDDI_VERSION >= NTDDI_WIN10_RS2) + PWSK_PROVIDER_STREAM_DISPATCH WskStreamDispatch; +#endif + }; + + KSOCKET_ASYNC_CONTEXT AsyncContext; +} KSOCKET, *PKSOCKET; + +////////////////////////////////////////////////////////////////////////// +// Variables. +////////////////////////////////////////////////////////////////////////// + +WSK_REGISTRATION WskRegistration; +WSK_PROVIDER_NPI WskProvider; +WSK_CLIENT_DISPATCH WskDispatch = {MAKE_WSK_VERSION(1, 0), 0, NULL}; + +////////////////////////////////////////////////////////////////////////// +// Function prototypes. +////////////////////////////////////////////////////////////////////////// + +NTSTATUS +NTAPI +KspAsyncContextAllocate(_Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext); + +VOID NTAPI KspAsyncContextFree(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext); + +VOID NTAPI KspAsyncContextReset(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext); + +static NTSTATUS +KspAsyncContextCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, _In_ PVOID CompletionEvent); + +NTSTATUS +NTAPI +KspAsyncContextWaitForCompletion(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext, + _Inout_ PNTSTATUS Status); + +////////////////////////////////////////////////////////////////////////// +// Private functions. +////////////////////////////////////////////////////////////////////////// + +NTSTATUS +NTAPI +KspAsyncContextAllocate(_Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext) { + // + // Initialize the completion event. + // + + KeInitializeEvent(&AsyncContext->CompletionEvent, SynchronizationEvent, + FALSE); + + // + // Initialize the IRP. + // + + AsyncContext->Irp = IoAllocateIrp(1, FALSE); + + if (AsyncContext->Irp == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // KspAsyncContextCompletionRoutine will set + // the CompletionEvent. + // + + IoSetCompletionRoutine(AsyncContext->Irp, &KspAsyncContextCompletionRoutine, + &AsyncContext->CompletionEvent, TRUE, TRUE, TRUE); + + return STATUS_SUCCESS; +} + +VOID NTAPI KspAsyncContextFree(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext) { + // + // Free the IRP. + // + + IoFreeIrp(AsyncContext->Irp); +} + +VOID NTAPI KspAsyncContextReset(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext) { + // + // If the WSK application allocated the IRP, or is reusing an IRP + // that it previously allocated, then it must set an IoCompletion + // routine for the IRP before calling a WSK function. In this + // situation, the WSK application must specify TRUE for the + // InvokeOnSuccess, InvokeOnError, and InvokeOnCancel parameters that + // are passed to the IoSetCompletionRoutine function to ensure that + // the IoCompletion routine is always called. Furthermore, the IoCompletion + // routine that is set for the IRP must always return + // STATUS_MORE_PROCESSING_REQUIRED to terminate the completion processing + // of the IRP. If the WSK application is done using the IRP after the + // IoCompletion routine has been called, then it should call the IoFreeIrp + // function to free the IRP before returning from the IoCompletion routine. + // If the WSK application does not free the IRP then it can reuse the IRP + // for a call to another WSK function. + // + // (ref: + // https://docs.microsoft.com/en-us/windows-hardware/drivers/network/using-irps-with-winsock-kernel-functions) + // + + // + // Reset the completion event. + // + + KeResetEvent(&AsyncContext->CompletionEvent); + + // + // Reuse the IRP. + // + + IoReuseIrp(AsyncContext->Irp, STATUS_UNSUCCESSFUL); + + IoSetCompletionRoutine(AsyncContext->Irp, &KspAsyncContextCompletionRoutine, + &AsyncContext->CompletionEvent, TRUE, TRUE, TRUE); +} + +static NTSTATUS +KspAsyncContextCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, _In_ PVOID CompletionEvent) { + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + + KeSetEvent((PKEVENT)CompletionEvent, IO_NO_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +KspAsyncContextWaitForCompletion(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext, + _Inout_ PNTSTATUS Status) { + if (*Status == STATUS_PENDING) { + KeWaitForSingleObject(&AsyncContext->CompletionEvent, Executive, KernelMode, + FALSE, NULL); + + *Status = AsyncContext->Irp->IoStatus.Status; + } + + return *Status; +} + +////////////////////////////////////////////////////////////////////////// +// Public functions. +////////////////////////////////////////////////////////////////////////// + +NTSTATUS +NTAPI +KsInitialize(VOID) { + NTSTATUS Status; + + // + // Register as a WSK client. + // + + WSK_CLIENT_NPI WskClient; + WskClient.ClientContext = NULL; + WskClient.Dispatch = &WskDispatch; + + Status = WskRegister(&WskClient, &WskRegistration); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Capture the provider NPI. + // + + return WskCaptureProviderNPI(&WskRegistration, WSK_INFINITE_WAIT, + &WskProvider); +} + +VOID NTAPI KsDestroy(VOID) { + // + // Release the provider NPI instance. + // + + WskReleaseProviderNPI(&WskRegistration); + + // + // Deregister as a WSK client. + // + + WskDeregister(&WskRegistration); +} + +NTSTATUS +NTAPI +KsGetAddrInfo(_In_ PUNICODE_STRING NodeName, _In_ PUNICODE_STRING ServiceName, + _In_ PADDRINFOEXW Hints, _Out_ PADDRINFOEXW *Result) { + NTSTATUS Status; + + // + // Allocate async context. + // + + KSOCKET_ASYNC_CONTEXT AsyncContext; + Status = KspAsyncContextAllocate(&AsyncContext); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Call the WSK API. + // + + Status = WskProvider.Dispatch->WskGetAddressInfo(WskProvider.Client, // Client + NodeName, // NodeName + ServiceName, // ServiceName + 0, // NameSpace + NULL, // Provider + Hints, // Hints + Result, // Result + NULL, // OwningProcess + NULL, // OwningThread + AsyncContext.Irp // Irp + ); + + KspAsyncContextWaitForCompletion(&AsyncContext, &Status); + + // + // Free the async context. + // + + KspAsyncContextFree(&AsyncContext); + + return Status; +} + +VOID NTAPI KsFreeAddrInfo(_In_ PADDRINFOEXW AddrInfo) { + WskProvider.Dispatch->WskFreeAddressInfo(WskProvider.Client, // Client + AddrInfo // AddrInfo + ); +} + +NTSTATUS +NTAPI +KsCreateSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags) { + NTSTATUS Status; + + // + // Allocate memory for the socket structure. + // + + PKSOCKET NewSocket = + (PKSOCKET)ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG); + + if (!NewSocket) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Allocate async context for the socket. + // + + Status = KspAsyncContextAllocate(&NewSocket->AsyncContext); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Create the WSK socket. + // + + Status = WskProvider.Dispatch->WskSocket(WskProvider.Client, // Client + AddressFamily, // AddressFamily + SocketType, // SocketType + Protocol, // Protocol + Flags, // Flags + NULL, // SocketContext + NULL, // Dispatch + NULL, // OwningProcess + NULL, // OwningThread + NULL, // SecurityDescriptor + NewSocket->AsyncContext.Irp // Irp + ); + + KspAsyncContextWaitForCompletion(&NewSocket->AsyncContext, &Status); + + // + // Save the socket instance and the socket dispatch table. + // + + if (NT_SUCCESS(Status)) { + NewSocket->WskSocket = + (PWSK_SOCKET)NewSocket->AsyncContext.Irp->IoStatus.Information; + NewSocket->WskDispatch = (PVOID)NewSocket->WskSocket->Dispatch; + + *Socket = NewSocket; + } + + return Status; +} + +NTSTATUS +NTAPI +KsCreateConnectionSocket(_Out_ PKSOCKET *Socket, + _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, _In_ ULONG Protocol) { + return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol, + WSK_FLAG_CONNECTION_SOCKET); +} + +NTSTATUS +NTAPI +KsCreateListenSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, _In_ ULONG Protocol) { + return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol, + WSK_FLAG_LISTEN_SOCKET); +} + +NTSTATUS +NTAPI +KsCreateDatagramSocket(_Out_ PKSOCKET *Socket, + _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, _In_ ULONG Protocol) { + return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol, + WSK_FLAG_DATAGRAM_SOCKET); +} + +NTSTATUS +NTAPI +KsCloseSocket(_In_ PKSOCKET Socket) { + NTSTATUS Status; + + // + // Reset the async context. + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Close the WSK socket. + // + + Status = Socket->WskConnectionDispatch->WskCloseSocket( + Socket->WskSocket, Socket->AsyncContext.Irp); + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + // + // Free the async context. + // + + KspAsyncContextFree(&Socket->AsyncContext); + + // + // Free memory for the socket structure. + // + + ExFreePoolWithTag(Socket, MEMORY_TAG); + + return Status; +} + +NTSTATUS +NTAPI +KsBind(_In_ PKSOCKET Socket, _In_ PSOCKADDR LocalAddress) { + NTSTATUS Status; + + // + // Reset the async context. + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Bind the socket. + // + + Status = Socket->WskListenDispatch->WskBind(Socket->WskSocket, // Socket + LocalAddress, // LocalAddress + 0, // Flags (reserved) + Socket->AsyncContext.Irp // Irp + ); + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + return Status; +} + +NTSTATUS +NTAPI +KsAccept(_In_ PKSOCKET Socket, _Out_ PKSOCKET *NewSocket, + _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress) { + NTSTATUS Status; + + // + // Reset the async context. + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Accept the connection. + // + + Status = + Socket->WskListenDispatch->WskAccept(Socket->WskSocket, // ListenSocket + 0, // Flags + NULL, // AcceptSocketContext + NULL, // AcceptSocketDispatch + LocalAddress, // LocalAddress + RemoteAddress, // RemoteAddress + Socket->AsyncContext.Irp // Irp + ); + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + // + // Save the socket instance and the socket dispatch table. + // + + if (NT_SUCCESS(Status)) { + PKSOCKET KNewSocket = + ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG); + + if (!KNewSocket) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + KNewSocket->WskSocket = + (PWSK_SOCKET)Socket->AsyncContext.Irp->IoStatus.Information; + KNewSocket->WskDispatch = (PVOID)KNewSocket->WskSocket->Dispatch; + KspAsyncContextAllocate(&KNewSocket->AsyncContext); + + *NewSocket = KNewSocket; + } + + return Status; +} + +NTSTATUS +NTAPI +KsConnect(_In_ PKSOCKET Socket, _In_ PSOCKADDR RemoteAddress) { + NTSTATUS Status; + + // + // Reset the async context. + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Bind the socket to the local address. + // + + SOCKADDR_IN LocalAddress; + LocalAddress.sin_family = AF_INET; + LocalAddress.sin_addr.s_addr = INADDR_ANY; + LocalAddress.sin_port = 0; + + Status = Socket->WskConnectionDispatch->WskBind( + Socket->WskSocket, // Socket + (PSOCKADDR)&LocalAddress, // LocalAddress + 0, // Flags (reserved) + Socket->AsyncContext.Irp // Irp + ); + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Reset the async context (again). + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Connect to the remote host. + // + // N.B.: Instead of calling WskSocket(), WskBind() and WskConnect(), + // it is possible to just call WskSocketConnect(). + // + + Status = + Socket->WskConnectionDispatch->WskConnect(Socket->WskSocket, // Socket + RemoteAddress, // RemoteAddress + 0, // Flags (reserved) + Socket->AsyncContext.Irp // Irp + ); + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + return Status; +} + +NTSTATUS +NTAPI +KsSendRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length, + _In_ ULONG Flags, _In_ BOOLEAN Send) { + NTSTATUS Status; + + // + // Wrap the buffer into the "WSK buffer". + // + + WSK_BUF WskBuffer; + WskBuffer.Offset = 0; + WskBuffer.Length = *Length; + WskBuffer.Mdl = + IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL); + + //__try + { MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); } +#if 0 + __except (EXCEPTION_EXECUTE_HANDLER) + { + Status = STATUS_ACCESS_VIOLATION; + goto Error; + } +#endif + + // + // Reset the async context. + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Send / receive the data. + // + + if (Send) { + Status = + Socket->WskConnectionDispatch->WskSend(Socket->WskSocket, // Socket + &WskBuffer, // Buffer + Flags, // Flags + Socket->AsyncContext.Irp // Irp + ); + } else { + Status = Socket->WskConnectionDispatch->WskReceive( + Socket->WskSocket, // Socket + &WskBuffer, // Buffer + Flags, // Flags + Socket->AsyncContext.Irp // Irp + ); + } + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + // + // Set the number of bytes sent / received. + // + + if (NT_SUCCESS(Status)) { + *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information; + } + + // + // Free the MDL. + // + + MmUnlockPages(WskBuffer.Mdl); + + // Error: + IoFreeMdl(WskBuffer.Mdl); + return Status; +} + +NTSTATUS +NTAPI +KsSendRecvUdp(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length, + _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress, + _In_ BOOLEAN Send) { + NTSTATUS Status; + + // + // Wrap the buffer into the "WSK buffer". + // + + WSK_BUF WskBuffer; + WskBuffer.Offset = 0; + WskBuffer.Length = *Length; + WskBuffer.Mdl = + IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL); + + //__try + { MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); } +#if 0 + __except (EXCEPTION_EXECUTE_HANDLER) + { + Status = STATUS_ACCESS_VIOLATION; + goto Error; + } +#endif + + // + // Reset the async context. + // + + KspAsyncContextReset(&Socket->AsyncContext); + + // + // Send / receive the data. + // + + if (Send) { + Status = + Socket->WskDatagramDispatch->WskSendTo(Socket->WskSocket, // Socket + &WskBuffer, // Buffer + Flags, // Flags (reserved) + RemoteAddress, // RemoteAddress + 0, // ControlInfoLength + NULL, // ControlInfo + Socket->AsyncContext.Irp // Irp + ); + } else { + Status = Socket->WskDatagramDispatch->WskReceiveFrom( + Socket->WskSocket, // Socket + &WskBuffer, // Buffer + Flags, // Flags (reserved) + RemoteAddress, // RemoteAddress + NULL, // ControlInfoLength + NULL, // ControlInfo + NULL, // ControlFlags + Socket->AsyncContext.Irp // Irp + ); + } + + KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); + + // + // Set the number of bytes sent / received. + // + + if (NT_SUCCESS(Status)) { + *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information; + } + + // + // Free the MDL. + // + + MmUnlockPages(WskBuffer.Mdl); + + // Error: + IoFreeMdl(WskBuffer.Mdl); + return Status; +} + +NTSTATUS +NTAPI +KsSend(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length, + _In_ ULONG Flags) { + return KsSendRecv(Socket, Buffer, Length, Flags, TRUE); +} + +NTSTATUS +NTAPI +KsRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length, + _In_ ULONG Flags) { + return KsSendRecv(Socket, Buffer, Length, Flags, FALSE); +} + +NTSTATUS +NTAPI +KsSendTo(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length, + _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress) { + return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, TRUE); +} + +NTSTATUS +NTAPI +KsRecvFrom(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length, + _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress) { + return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, FALSE); +} diff --git a/ksocket.h b/ksocket.h new file mode 100644 index 0000000..a4bd0f7 --- /dev/null +++ b/ksocket.h @@ -0,0 +1,165 @@ +#pragma once +#include <ntddk.h> +#include "wsk.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _KSOCKET KSOCKET, *PKSOCKET; + +NTSTATUS +NTAPI +KsInitialize( + VOID + ); + +VOID +NTAPI +KsDestroy( + VOID + ); + +NTSTATUS +NTAPI +KsGetAddrInfo( + _In_ PUNICODE_STRING NodeName, + _In_ PUNICODE_STRING ServiceName, + _In_ PADDRINFOEXW Hints, + _Out_ PADDRINFOEXW* Result + ); + +VOID +NTAPI +KsFreeAddrInfo( + _In_ PADDRINFOEXW AddrInfo + ); + +NTSTATUS +NTAPI +KsCreateSocket( + _Out_ PKSOCKET* Socket, + _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, + _In_ ULONG Protocol, + _In_ ULONG Flags + ); + +NTSTATUS +NTAPI +KsCreateConnectionSocket( + _Out_ PKSOCKET* Socket, + _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, + _In_ ULONG Protocol + ); + +NTSTATUS +NTAPI +KsCreateListenSocket( + _Out_ PKSOCKET* Socket, + _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, + _In_ ULONG Protocol + ); + +NTSTATUS +NTAPI +KsCreateDatagramSocket( + _Out_ PKSOCKET* Socket, + _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, + _In_ ULONG Protocol + ); + +NTSTATUS +NTAPI +KsCloseSocket( + _In_ PKSOCKET Socket + ); + +NTSTATUS +NTAPI +KsBind( + _In_ PKSOCKET Socket, + _In_ PSOCKADDR LocalAddress + ); + +NTSTATUS +NTAPI +KsAccept( + _In_ PKSOCKET Socket, + _Out_ PKSOCKET* NewSocket, + _Out_opt_ PSOCKADDR LocalAddress, + _Out_opt_ PSOCKADDR RemoteAddress + ); + +NTSTATUS +NTAPI +KsConnect( + _In_ PKSOCKET Socket, + _In_ PSOCKADDR RemoteAddress + ); + +NTSTATUS +NTAPI +KsSendRecv( + _In_ PKSOCKET Socket, + _In_ PVOID Buffer, + _Inout_ PULONG Length, + _In_ ULONG Flags, + _In_ BOOLEAN Send + ); + +NTSTATUS +NTAPI +KsSendRecvUdp( + _In_ PKSOCKET Socket, + _In_ PVOID Buffer, + _Inout_ PULONG Length, + _In_ ULONG Flags, + _In_ PSOCKADDR RemoteAddress, + _In_ BOOLEAN Send + ); + +NTSTATUS +NTAPI +KsSend( + _In_ PKSOCKET Socket, + _In_ PVOID Buffer, + _Inout_ PULONG Length, + _In_ ULONG Flags + ); + +NTSTATUS +NTAPI +KsRecv( + _In_ PKSOCKET Socket, + _In_ PVOID Buffer, + _Inout_ PULONG Length, + _In_ ULONG Flags + ); + +NTSTATUS +NTAPI +KsSendTo( + _In_ PKSOCKET Socket, + _In_ PVOID Buffer, + _Inout_ PULONG Length, + _In_ ULONG Flags, + _In_ PSOCKADDR RemoteAddress + ); + +NTSTATUS +NTAPI +KsRecvFrom( + _In_ PKSOCKET Socket, + _In_ PVOID Buffer, + _Inout_ PULONG Length, + _In_ ULONG Flags, + _In_ PSOCKADDR RemoteAddress + ); + +#ifdef __cplusplus +} +#endif diff --git a/userspace_client.cpp b/userspace_client.cpp new file mode 100644 index 0000000..efcd782 --- /dev/null +++ b/userspace_client.cpp @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <stdlib.h> // Needed for _wtoi +#include <winsock2.h> +#include <ws2tcpip.h> + +int main(int argc, char **argv) { + WSADATA wsaData = {}; + int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + if (iResult != 0) { + wprintf(L"WSAStartup failed: %d\n", iResult); + return 1; + } + + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sock == INVALID_SOCKET) { + wprintf(L"socket function failed with error = %d\n", WSAGetLastError()); + } else { + wprintf(L"socket function succeeded\n"); + } + + sockaddr_in clientService; + clientService.sin_family = AF_INET; + clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); + clientService.sin_port = htons(9095); + + do { + iResult = connect(sock, (SOCKADDR *)&clientService, sizeof(clientService)); + if (iResult == SOCKET_ERROR) { + wprintf(L"connect function failed with error: %ld\n", WSAGetLastError()); + Sleep(1000); + } + } while (iResult == SOCKET_ERROR); + + wprintf(L"Connected to server.\n"); + + char sendbuf[] = "Hello Driver, greetings from userspace."; + iResult = send(sock, sendbuf, (int)strlen(sendbuf), 0); + if (iResult == SOCKET_ERROR) { + wprintf(L"send failed with error: %d\n", WSAGetLastError()); + closesocket(sock); + WSACleanup(); + return 1; + } + + do { + char recvbuf[1024]; + + iResult = recv(sock, recvbuf, 1024, 0); + if (iResult > 0) { + wprintf(L"Bytes received: %d\n", iResult); + wprintf(L"Data received: %.*s\n", iResult, recvbuf); + } else if (iResult == 0) { + wprintf(L"Connection closed\n"); + } else if (WSAGetLastError() != WSAECONNRESET) { + wprintf(L"recv failed: %d\n", WSAGetLastError()); + } + } while (iResult > 0); + wprintf(L"connection closed by remote\n"); + + iResult = closesocket(sock); + if (iResult == SOCKET_ERROR) { + wprintf(L"closesocket function failed with error: %ld\n", + WSAGetLastError()); + WSACleanup(); + return 1; + } + + WSACleanup(); + + system("pause"); + + return 0; +} @@ -0,0 +1,456 @@ +#ifndef WSK_H +#define WSK_H 1 + +#if !defined(__MINGW64__) +#error "This was designed to work **only** with Mingw-w64! For MSVC, please check https://github.com/wbenny/KSOCKET out" +#endif + +#if (NTDDI_VERSION < NTDDI_WIN10) +#error \ + "Your mingw-w64 toolchain is too old. Please use the one provided by https://github.com/utoni/mingw-w64-ddk-template" +#endif + +#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +#error "This project requires a little endian system. Does Windows support any other?" +#endif + +// --------------------------------------------------------------- +// defines +// --------------------------------------------------------------- + +#define WSKAPI NTAPI +#define MAKE_WSK_VERSION(Mj, Mn) ((USHORT)((Mj) << 8) | (USHORT)((Mn)&0xff)) +#define WSK_NO_WAIT 0 +#define WSK_INFINITE_WAIT 0xffffffff + +#define WSK_FLAG_BASIC_SOCKET 0x00000000 +#define WSK_FLAG_LISTEN_SOCKET 0x00000001 +#define WSK_FLAG_CONNECTION_SOCKET 0x00000002 +#define WSK_FLAG_DATAGRAM_SOCKET 0x00000004 +#define WSK_FLAG_STREAM_SOCKET 0x00000008 + +#define INADDR_ANY ((ULONG)0x00000000) + +// --------------------------------------------------------------- +// forward decls / opaque structs +// --------------------------------------------------------------- + +struct _WSK_CLIENT_CONNECTION_DISPATCH; +typedef struct _WSK_CLIENT_CONNECTION_DISPATCH WSK_CLIENT_CONNECTION_DISPATCH; +typedef WSK_CLIENT_CONNECTION_DISPATCH *PWSK_CLIENT_CONNECTION_DISPATCH; +struct _WSK_CLIENT_NPI; +typedef struct _WSK_CLIENT_NPI WSK_CLIENT_NPI; +typedef struct _WSK_CLIENT_NPI *PWSK_CLIENT_NPI; +struct _WSK_PROVIDER_NPI; +typedef struct _WSK_PROVIDER_NPI WSK_PROVIDER_NPI; +typedef struct _WSK_PROVIDER_NPI *PWSK_PROVIDER_NPI; + +typedef PVOID PWSK_CLIENT; + +// --------------------------------------------------------------- +// enums +// --------------------------------------------------------------- + +typedef enum { + WskSetOption, // set socket option + WskGetOption, // get socket option + WskIoctl, // socket IOCTL + WskControlMax +} WSK_CONTROL_SOCKET_TYPE, + *PWSK_CONTROL_SOCKET_TYPE; + +enum { + AI_PASSIVE = 0x01, + AI_CANONNAME = 0x02, + AI_NUMERICHOST = 0x04, + AI_ALL = 0x0100, + AI_ADDRCONFIG = 0x0400, + AI_V4MAPPED = 0x0800, + AI_NON_AUTHORITATIVE = 0x4000, + AI_SECURE = 0x08000, + AI_RETURN_PREFERRED_NAMES = 0x10000, + AI_FQDN = 0x00020000, + AI_FILESERVER = 0x00040000 +}; + +typedef enum ADDRESS_FAMILY { + AF_UNSPEC = 0, + AF_INET = 2, + AF_INET6 = 23 +} ADDRESS_FAMILY; + +enum { + IPPROTO_ICMP = 1, + IPPROTO_IGMP = 2, + BTHPROTO_RFCOMM = 3, + IPPROTO_TCP = 6, + IPPROTO_UDP = 17, + IPPROTO_ICMPV6 = 58, + IPPROTO_RM = 113 +}; + +enum { + SOCK_STREAM = 1, + SOCK_DGRAM = 2, + SOCK_RAW = 3, + SOCK_RDM = 4, + SOCK_SEQPACKET = 5, +}; + +typedef enum { + WskInspectReject, // reject the connection request + WskInspectAccept, // proceed with accept + WskInspectPend, // delay the decision (use WskInspectComplete later) + WskInspectMax +} WSK_INSPECT_ACTION, + *PWSK_INSPECT_ACTION; + +// --------------------------------------------------------------- +// general structs +// --------------------------------------------------------------- + +typedef struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +} ADDRINFOA, *PADDRINFOA; + +typedef struct addrinfoexA { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + void *ai_blob; + size_t ai_bloblen; + LPGUID ai_provider; + struct addrinfoexA *ai_next; +} ADDRINFOEXA, *PADDRINFOEXA, *LPADDRINFOEXA; + +typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + PWSTR ai_canonname; + struct sockaddr *ai_addr; + struct addrinfoW *ai_next; +} ADDRINFOW, *PADDRINFOW; + +typedef struct addrinfoexW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + PWSTR ai_canonname; + struct sockaddr *ai_addr; + void *ai_blob; + size_t ai_bloblen; + LPGUID ai_provider; + struct addrinfoexW *ai_next; +} ADDRINFOEXW, *PADDRINFOEXW, *LPADDRINFOEXW; + +typedef struct sockaddr { + ADDRESS_FAMILY sa_family; + CHAR sa_data[14]; +} SOCKADDR, *PSOCKADDR, *LPSOCKADDR; + +struct in_addr { + union { + struct { + UCHAR s_b1; + UCHAR s_b2; + UCHAR s_b3; + UCHAR s_b4; + } s_un_b; + struct { + USHORT s_w1; + USHORT s_w2; + } s_un_w; + ULONG s_addr; + }; +}; + +typedef struct sockaddr_in { + short sin_family; + USHORT sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +} SOCKADDR_IN, *PSOCKADDR_IN, *LPSOCKADDR_IN; + +typedef struct _WSK_SOCKET { + const VOID *Dispatch; +} WSK_SOCKET, *PWSK_SOCKET; + +typedef struct _WSK_BUF { + PMDL Mdl; // Locked MDL chain + ULONG Offset; // Offset into the "first" Mdl in the chain + SIZE_T Length; // Length of data starting from Offset +} WSK_BUF, *PWSK_BUF; + +typedef struct _WSK_BUF_LIST { + struct _WSK_BUF_LIST *Next; + WSK_BUF Buffer; +} WSK_BUF_LIST, *PWSK_BUF_LIST; + +typedef struct _WSK_DATA_INDICATION { + struct _WSK_DATA_INDICATION *Next; + WSK_BUF Buffer; +} WSK_DATA_INDICATION, *PWSK_DATA_INDICATION; + +typedef struct _WSK_INSPECT_ID { + ULONG_PTR Key; + ULONG SerialNumber; +} WSK_INSPECT_ID, *PWSK_INSPECT_ID; + +typedef struct _WSACMSGHDR { + SIZE_T cmsg_len; + INT cmsg_level; + INT cmsg_type; +} WSACMSGHDR, *PWSACMSGHDR, *LPWSACMSGHDR, CMSGHDR, *PCMSGHDR; + +typedef struct _WSK_DATAGRAM_INDICATION { + struct _WSK_DATAGRAM_INDICATION *Next; + WSK_BUF Buffer; + _Field_size_bytes_(ControlInfoLength) PCMSGHDR ControlInfo; + ULONG ControlInfoLength; + PSOCKADDR RemoteAddress; +} WSK_DATAGRAM_INDICATION, *PWSK_DATAGRAM_INDICATION; + +typedef struct _WSK_REGISTRATION { + ULONGLONG ReservedRegistrationState; + PVOID ReservedRegistrationContext; + KSPIN_LOCK ReservedRegistrationLock; +} WSK_REGISTRATION, *PWSK_REGISTRATION; + +// --------------------------------------------------------------- +// callback functions +// --------------------------------------------------------------- + +typedef NTSTATUS(WSKAPI *PFN_WSK_CONTROL_SOCKET)( + _In_ PWSK_SOCKET Socket, _In_ WSK_CONTROL_SOCKET_TYPE RequestType, + _In_ ULONG ControlCode, _In_ ULONG Level, _In_ SIZE_T InputSize, + _In_opt_ PVOID InputBuffer, _In_ SIZE_T OutputSize, + _Out_opt_ PVOID OutputBuffer, _Out_opt_ SIZE_T *OutputSizeReturned, + _In_ _Out_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_CLOSE_SOCKET)(_In_ PWSK_SOCKET Socket, + _Inout_ PIRP Irp); + +typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT)(_In_ PWSK_SOCKET Socket, + _In_ PSOCKADDR RemoteAddress, + ULONG Flags, _In_ _Out_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_BIND)(_In_ PWSK_SOCKET Socket, + _In_ PSOCKADDR LocalAddress, + _Reserved_ ULONG Flags, + _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_GET_LOCAL_ADDRESS)( + _In_ PWSK_SOCKET Socket, _Out_ PSOCKADDR LocalAddress, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_GET_REMOTE_ADDRESS)( + _In_ PWSK_SOCKET Socket, _Out_ PSOCKADDR RemoteAddress, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_SEND)(_In_ PWSK_SOCKET Socket, + _In_ PWSK_BUF Buffer, _In_ ULONG Flags, + _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_RECEIVE)(_In_ PWSK_SOCKET Socket, + _In_ PWSK_BUF Buffer, + _In_ ULONG Flags, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_DISCONNECT)(_In_ PWSK_SOCKET Socket, + _In_opt_ PWSK_BUF Buffer, + _In_ ULONG Flags, + _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_RELEASE_DATA_INDICATION_LIST)( + _In_ PWSK_SOCKET Socket, _In_ PWSK_DATA_INDICATION DataIndication); +typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT_EX)(_In_ PWSK_SOCKET Socket, + _In_ PSOCKADDR RemoteAddress, + _In_opt_ PWSK_BUF Buffer, + _Reserved_ ULONG Flags, + _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT_EX)(_In_ PWSK_SOCKET Socket, + _In_ PSOCKADDR RemoteAddress, + _In_opt_ PWSK_BUF Buffer, + _Reserved_ ULONG Flags, + _Inout_ PIRP Irp); +typedef void *PFN_WSK_SEND_EX; // reserved for system use +typedef void *PFN_WSK_RECEIVE_EX; // reserved for system use +typedef _At_(Irp->IoStatus.Information, __drv_allocatesMem(Mem)) + NTSTATUS(WSKAPI *PFN_WSK_ACCEPT)( + _In_ PWSK_SOCKET ListenSocket, _Reserved_ ULONG Flags, + _In_opt_ PVOID AcceptSocketContext, + _In_opt_ CONST WSK_CLIENT_CONNECTION_DISPATCH *AcceptSocketDispatch, + _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress, + _Inout_ PIRP Irp); +typedef _Must_inspect_result_ NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_EVENT)( + _In_opt_ PVOID SocketContext, _In_ ULONG Flags, + _In_opt_ PWSK_DATA_INDICATION DataIndication, _In_ SIZE_T BytesIndicated, + _Inout_ SIZE_T *BytesAccepted); +typedef NTSTATUS(WSKAPI *PFN_WSK_DISCONNECT_EVENT)(_In_opt_ PVOID SocketContext, + _In_ ULONG Flags); +typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_BACKLOG_EVENT)( + _In_opt_ PVOID SocketContext, _In_ SIZE_T IdealBacklogSize); +typedef NTSTATUS(WSKAPI *PFN_WSK_INSPECT_COMPLETE)( + _In_ PWSK_SOCKET ListenSocket, _In_ PWSK_INSPECT_ID InspectID, + _In_ WSK_INSPECT_ACTION Action, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_TO)( + _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF Buffer, _Reserved_ ULONG Flags, + _In_opt_ PSOCKADDR RemoteAddress, _In_ ULONG ControlInfoLength, + _In_reads_bytes_opt_(ControlInfoLength) PCMSGHDR ControlInfo, + _Inout_ PIRP Irp); +typedef _Must_inspect_result_ NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_FROM_EVENT)( + _In_opt_ PVOID SocketContext, _In_ ULONG Flags, + _In_opt_ PWSK_DATAGRAM_INDICATION DataIndication); +typedef NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_FROM)( + _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF Buffer, _Reserved_ ULONG Flags, + _Out_opt_ PSOCKADDR RemoteAddress, _Inout_ PULONG ControlLength, + _Out_writes_bytes_opt_(*ControlLength) PCMSGHDR ControlInfo, + _Out_opt_ PULONG ControlFlags, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_RELEASE_DATAGRAM_INDICATION_LIST)( + _In_ PWSK_SOCKET Socket, _In_ PWSK_DATAGRAM_INDICATION DatagramIndication); +typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_MESSAGES)( + _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF_LIST BufferList, + _Reserved_ ULONG Flags, _In_opt_ PSOCKADDR RemoteAddress, + _In_ ULONG ControlInfoLength, + _In_reads_bytes_opt_(ControlInfoLength) PCMSGHDR ControlInfo, + _Inout_ PIRP Irp); +typedef _At_((void *)Irp->IoStatus.Information, __drv_allocatesMem(Mem)) + NTSTATUS(WSKAPI *PFN_WSK_SOCKET)( + _In_ PWSK_CLIENT Client, _In_ ADDRESS_FAMILY AddressFamily, + _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags, + _In_opt_ PVOID SocketContext, _In_opt_ CONST VOID *Dispatch, + _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, + _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, _Inout_ PIRP Irp); +typedef _At_(Irp->IoStatus.Information, __drv_allocatesMem(Mem)) + NTSTATUS(WSKAPI *PFN_WSK_SOCKET_CONNECT)( + _In_ PWSK_CLIENT Client, _In_ USHORT SocketType, _In_ ULONG Protocol, + _In_ PSOCKADDR LocalAddress, _In_ PSOCKADDR RemoteAddress, + _Reserved_ ULONG Flags, _In_opt_ PVOID SocketContext, + _In_opt_ CONST WSK_CLIENT_CONNECTION_DISPATCH *Dispatch, + _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, + _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_CONTROL_CLIENT)( + _In_ PWSK_CLIENT Client, _In_ ULONG ControlCode, _In_ SIZE_T InputSize, + _In_reads_bytes_opt_(InputSize) PVOID InputBuffer, _In_ SIZE_T OutputSize, + _Out_writes_bytes_opt_(OutputSize) PVOID OutputBuffer, + _Out_opt_ SIZE_T *OutputSizeReturned, _Inout_opt_ PIRP Irp); +typedef _At_(*Result, __drv_allocatesMem(Mem)) + NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO)( + _In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, + _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, + _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, + _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, + _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp); +typedef _At_(AddrInfo, __drv_freesMem(Mem)) + VOID(WSKAPI *PFN_WSK_FREE_ADDRESS_INFO)(_In_ PWSK_CLIENT Client, + _In_ PADDRINFOEXW AddrInfo); +typedef NTSTATUS(WSKAPI *PFN_WSK_GET_NAME_INFO)( + _In_ PWSK_CLIENT Client, _In_ PSOCKADDR SockAddr, _In_ ULONG SockAddrLength, + _Out_opt_ PUNICODE_STRING NodeName, _Out_opt_ PUNICODE_STRING ServiceName, + _In_ ULONG Flags, _In_opt_ PEPROCESS OwningProcess, + _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp); +typedef NTSTATUS(WSKAPI *PFN_WSK_CLIENT_EVENT)( + _In_opt_ PVOID ClientContext, _In_ ULONG EventType, + _In_reads_bytes_opt_(InformationLength) PVOID Information, + _In_ SIZE_T InformationLength); +_Must_inspect_result_ NTSTATUS WskRegister( + _In_ PWSK_CLIENT_NPI WskClientNpi, _Out_ PWSK_REGISTRATION WskRegistration); +_Must_inspect_result_ NTSTATUS WskCaptureProviderNPI( + _In_ PWSK_REGISTRATION WskRegistration, _In_ ULONG WaitTimeout, + _Out_ PWSK_PROVIDER_NPI WskProviderNpi); +VOID WskReleaseProviderNPI(_In_ PWSK_REGISTRATION WskRegistration); +VOID WskDeregister(_In_ PWSK_REGISTRATION WskRegistration); + +// --------------------------------------------------------------- +// function pointer structs +// --------------------------------------------------------------- + +typedef struct _WSK_CLIENT_CONNECTION_DISPATCH { + PFN_WSK_RECEIVE_EVENT WskReceiveEvent; + PFN_WSK_DISCONNECT_EVENT WskDisconnectEvent; + PFN_WSK_SEND_BACKLOG_EVENT WskSendBacklogEvent; +} WSK_CLIENT_CONNECTION_DISPATCH, *PWSK_CLIENT_CONNECTION_DISPATCH; + +typedef struct _WSK_PROVIDER_BASIC_DISPATCH { + PFN_WSK_CONTROL_SOCKET WskControlSocket; + PFN_WSK_CLOSE_SOCKET WskCloseSocket; +} WSK_PROVIDER_BASIC_DISPATCH, *PWSK_PROVIDER_BASIC_DISPATCH; + +typedef struct _WSK_PROVIDER_CONNECTION_DISPATCH { +#ifdef __cplusplus + WSK_PROVIDER_BASIC_DISPATCH Basic; +#else + WSK_PROVIDER_BASIC_DISPATCH; +#endif + PFN_WSK_BIND WskBind; + PFN_WSK_CONNECT WskConnect; + PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress; + PFN_WSK_GET_REMOTE_ADDRESS WskGetRemoteAddress; + PFN_WSK_SEND WskSend; + PFN_WSK_RECEIVE WskReceive; + PFN_WSK_DISCONNECT WskDisconnect; + PFN_WSK_RELEASE_DATA_INDICATION_LIST WskRelease; + PFN_WSK_CONNECT_EX WskConnectEx; + PFN_WSK_SEND_EX WskSendEx; + PFN_WSK_RECEIVE_EX WskReceiveEx; +} WSK_PROVIDER_CONNECTION_DISPATCH, *PWSK_PROVIDER_CONNECTION_DISPATCH; + +typedef struct _WSK_PROVIDER_LISTEN_DISPATCH { +#ifdef __cplusplus + WSK_PROVIDER_BASIC_DISPATCH Basic; +#else + WSK_PROVIDER_BASIC_DISPATCH; +#endif + PFN_WSK_BIND WskBind; + PFN_WSK_ACCEPT WskAccept; + PFN_WSK_INSPECT_COMPLETE WskInspectComplete; + PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress; +} WSK_PROVIDER_LISTEN_DISPATCH, *PWSK_PROVIDER_LISTEN_DISPATCH; + +typedef struct _WSK_PROVIDER_DATAGRAM_DISPATCH { +#ifdef __cplusplus + WSK_PROVIDER_BASIC_DISPATCH Basic; +#else + WSK_PROVIDER_BASIC_DISPATCH; +#endif + PFN_WSK_BIND WskBind; + PFN_WSK_SEND_TO WskSendTo; + PFN_WSK_RECEIVE_FROM WskReceiveFrom; + PFN_WSK_RELEASE_DATAGRAM_INDICATION_LIST WskRelease; + PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress; + PFN_WSK_SEND_MESSAGES WskSendMessages; +} WSK_PROVIDER_DATAGRAM_DISPATCH, *PWSK_PROVIDER_DATAGRAM_DISPATCH; + +typedef struct _WSK_PROVIDER_DISPATCH { + USHORT Version; + USHORT Reserved; + PFN_WSK_SOCKET WskSocket; + PFN_WSK_SOCKET_CONNECT WskSocketConnect; + PFN_WSK_CONTROL_CLIENT WskControlClient; + PFN_WSK_GET_ADDRESS_INFO WskGetAddressInfo; + PFN_WSK_FREE_ADDRESS_INFO WskFreeAddressInfo; + PFN_WSK_GET_NAME_INFO WskGetNameInfo; +} WSK_PROVIDER_DISPATCH, *PWSK_PROVIDER_DISPATCH; + +typedef struct _WSK_CLIENT_DISPATCH { + USHORT Version; + USHORT Reserved; + PFN_WSK_CLIENT_EVENT WskClientEvent; +} WSK_CLIENT_DISPATCH, *PWSK_CLIENT_DISPATCH; + +typedef struct _WSK_CLIENT_NPI { + PVOID ClientContext; + CONST WSK_CLIENT_DISPATCH *Dispatch; +} WSK_CLIENT_NPI, *PWSK_CLIENT_NPI; + +typedef struct _WSK_PROVIDER_NPI { + PWSK_CLIENT Client; + CONST WSK_PROVIDER_DISPATCH *Dispatch; +} WSK_PROVIDER_NPI, *PWSK_PROVIDER_NPI; + +#endif |