diff options
Diffstat (limited to 'berkeley.c')
-rw-r--r-- | berkeley.c | 580 |
1 files changed, 580 insertions, 0 deletions
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; +} |