From 727fe27b06a8b9c1c21cbf27ba674b69f393d737 Mon Sep 17 00:00:00 2001 From: Netch Date: Mon, 19 Jul 2021 10:50:14 +0800 Subject: [PATCH] Update Redirector --- Redirector/API.cpp | 1 + Redirector/API.h | 5 + Redirector/DNS.cpp | 230 +++++++++++++ Redirector/DNS.h | 14 + Redirector/Data.cpp | 34 +- Redirector/Data.h | 31 +- Redirector/EventHandler.cpp | 102 ++++++ Redirector/EventHandler.h | 23 ++ Redirector/IPEventHandler.cpp | 58 +++- Redirector/IPEventHandler.h | 6 + Redirector/PROTOCOL.txt | 39 +++ Redirector/Redirector.cpp | 123 ++++--- Redirector/Redirector.vcxproj | 11 +- Redirector/Redirector.vcxproj.filters | 19 +- Redirector/Utils.cpp | 44 ++- Redirector/Utils.h | 2 + Redirector/include/nfapi.h | 415 ++++++++++++++++++++++++ Redirector/include/nfdriver.h | 449 ++++++++++++++++++++++++++ Redirector/include/nfevents.h | 270 ++++++++++++++++ Redirector/lib/nfapi.lib | Bin 0 -> 11044 bytes 20 files changed, 1812 insertions(+), 64 deletions(-) create mode 100644 Redirector/API.cpp create mode 100644 Redirector/API.h create mode 100644 Redirector/DNS.cpp create mode 100644 Redirector/DNS.h create mode 100644 Redirector/PROTOCOL.txt create mode 100644 Redirector/include/nfapi.h create mode 100644 Redirector/include/nfdriver.h create mode 100644 Redirector/include/nfevents.h create mode 100644 Redirector/lib/nfapi.lib diff --git a/Redirector/API.cpp b/Redirector/API.cpp new file mode 100644 index 00000000..b5131617 --- /dev/null +++ b/Redirector/API.cpp @@ -0,0 +1 @@ +#include "API.h" diff --git a/Redirector/API.h b/Redirector/API.h new file mode 100644 index 00000000..5fbb7432 --- /dev/null +++ b/Redirector/API.h @@ -0,0 +1,5 @@ +#pragma once +#ifndef API_H +#define API_H + +#endif diff --git a/Redirector/DNS.cpp b/Redirector/DNS.cpp new file mode 100644 index 00000000..39f11edb --- /dev/null +++ b/Redirector/DNS.cpp @@ -0,0 +1,230 @@ +#include "DNS.h" + +#include "API.h" +#include "Data.h" +#include "Utils.h" + +#include + +#include +#include + +using namespace std; + +extern string dnsHost; +extern USHORT dnsPort; +extern USHORT dnsLisn; + +typedef struct _DNSPKT { + ENDPOINT_ID ID; + PBYTE Target; + ULONG TargetLength; + PCHAR Buffer; + ULONG BufferLength; + PNF_UDP_OPTIONS Option; +} DNSPKT, * PDNSPKT; + +BOOL dnsInit = FALSE; +HANDLE dnsLock = NULL; +list dnsList; + +SOCKET CreateSocket() +{ + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + + auto client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (INVALID_SOCKET == client) + { + printf("[Redirector][DNS][CreateSocket] Unable to create socket: %d\n", WSAGetLastError()); + return NULL; + } + + if (SOCKET_ERROR == bind(client, (PSOCKADDR)&addr, sizeof(sockaddr_in))) + { + printf("[Redirector][DNS][CreateSocket] Unable to bind socket: %d\n", WSAGetLastError()); + return NULL; + } + + return client; +} + +void DnsFreePacket(PDNSPKT i) +{ + if (i) + { + if (i->Target) + { + free(i->Target); + } + + if (i->Buffer) + { + free(i->Buffer); + } + + if (i->Option) + { + free(i->Option); + } + + free(i); + } + + i = NULL; +} + +void dns_init() +{ + dnsInit = TRUE; + + if (!dnsLock) + { + dnsLock = CreateMutex(NULL, FALSE, NULL); + } + + dnsDelete(); +} + +void dns_free() +{ + dnsInit = FALSE; + Sleep(10); + + if (dnsLock) + { + dnsDelete(); + + CloseHandle(dnsLock); + dnsLock = NULL; + } +} + +void dnsWorker() +{ + sockaddr_in addr; + memset(&addr, 0, sizeof(sockaddr_in)); + addr.sin_addr.S_un.S_addr = inet_addr(dnsHost.c_str()); + addr.sin_port = htons(dnsPort); + + while (dnsInit) + { + auto client = CreateSocket(); + if (NULL == client) + { + Sleep(100); + continue; + } + + WaitForSingleObject(dnsLock, INFINITE); + if (!dnsList.size()) + { + closesocket(client); + ReleaseMutex(dnsLock); + + Sleep(1); + continue; + } + + auto data = dnsList.front(); + dnsList.remove(data); + ReleaseMutex(dnsLock); + + if (data->BufferLength != (ULONG)sendto(client, (PCHAR)data->Buffer, data->BufferLength, NULL, (PSOCKADDR)&addr, sizeof(sockaddr_in))) + { + closesocket(client); + DnsFreePacket(data); + + printf("[Redirector][DNS][dnsWorker] Unable to send packet: %d\n", WSAGetLastError()); + continue; + } + + char buffer[1500]; + auto length = recvfrom(client, buffer, sizeof(buffer), NULL, NULL, NULL); + if (!length) + { + closesocket(client); + DnsFreePacket(data); + + printf("[Redirector][DNS][dnsWorker] Unable to receive packet: %d\n", WSAGetLastError()); + continue; + } + + nf_udpPostReceive(data->ID, data->Target, buffer, length, data->Option); + closesocket(client); + DnsFreePacket(data); + } +} + +void dnsCreate(ENDPOINT_ID id, PBYTE target, ULONG targetLength, PCHAR buffer, ULONG bufferLength, PNF_UDP_OPTIONS option) +{ + if (!dnsInit) + { + return; + } + + auto data = (PDNSPKT)malloc(sizeof(DNSPKT)); + if (!data) + { + puts("[Redirector][DNS][dnsCreate] Unable to allocate memory"); + return; + } + + memset(data, 0, sizeof(DNSPKT)); + data->ID = id; + + data->Target = (PBYTE)malloc(targetLength); + data->TargetLength = targetLength; + if (!data->Target) + { + free(data); + + puts("[Redirector][DNS][dnsCreate] Unable to allocate memory"); + return; + } + + data->Buffer = (PCHAR)malloc(bufferLength); + data->BufferLength = bufferLength; + if (!data->Buffer) + { + free(data->Target); + free(data); + + puts("[Redirector][DNS][dnsCreate] Unable to allocate memory"); + return; + } + + data->Option = (PNF_UDP_OPTIONS)malloc(sizeof(NF_UDP_OPTIONS)); + if (!data->Option) + { + free(data->Target); + free(data->Buffer); + free(data); + + puts("[Redirector][DNS][dnsCreate] Unable to allocate memory"); + return; + } + + memcpy(data->Target, target, targetLength); + memcpy(data->Buffer, buffer, bufferLength); + memcpy(data->Option, option, sizeof(NF_UDP_OPTIONS)); + + WaitForSingleObject(dnsLock, INFINITE); + dnsList.emplace_back(data); + ReleaseMutex(dnsLock); +} + +void dnsDelete() +{ + WaitForSingleObject(dnsLock, INFINITE); + + for (auto i : dnsList) + { + DnsFreePacket(i); + } + dnsList.clear(); + + ReleaseMutex(dnsLock); +} diff --git a/Redirector/DNS.h b/Redirector/DNS.h new file mode 100644 index 00000000..b5777b2b --- /dev/null +++ b/Redirector/DNS.h @@ -0,0 +1,14 @@ +#pragma once +#ifndef DNS_H +#define DNS_H +#include + +#include + +void dns_init(); +void dns_free(); +void dnsWorker(); +void dnsCreate(ENDPOINT_ID id, PBYTE target, ULONG targetLength, PCHAR buffer, ULONG bufferLength, PNF_UDP_OPTIONS options); +void dnsDelete(); + +#endif diff --git a/Redirector/Data.cpp b/Redirector/Data.cpp index a3baeb6e..964d9ed3 100644 --- a/Redirector/Data.cpp +++ b/Redirector/Data.cpp @@ -1,8 +1,30 @@ #include "Data.h" -BOOL filterLoopback = FALSE; -BOOL filterICMP = TRUE; -BOOL filterTCP = TRUE; -BOOL filterUDP = TRUE; -USHORT tcpLisn = 0; -USHORT udpLisn = 0; +#include +#include +#include +#include + +using namespace std; + +BOOL Started = FALSE; +BOOL filterLoop = FALSE; +BOOL filterICMP = TRUE; +BOOL filterTCP = TRUE; +BOOL filterUDP = TRUE; +BOOL dnsHook = FALSE; +string dnsHost = ""; +USHORT dnsPort = 0; +USHORT apiLisn = 0; +USHORT tcpLisn = 0; +USHORT udpLisn = 0; +vector handleList; +vector bypassList; + +atomic_ulong UP{ 0 }; +atomic_ulong DL{ 0 }; + +HANDLE TCPLock = NULL; +HANDLE UDPLock = NULL; +map TCPContext; +map UDPContext; diff --git a/Redirector/Data.h b/Redirector/Data.h index e51d8eb2..fa2b2bfc 100644 --- a/Redirector/Data.h +++ b/Redirector/Data.h @@ -1,16 +1,35 @@ #pragma once #ifndef DATA_H #define DATA_H -#include #include -enum { - AIO_FILTERLOOPBACK, +#include + +typedef enum _AIO_TYPE { + AIO_FILTERLOOP, AIO_FILTERICMP, AIO_FILTERTCP, AIO_FILTERUDP, - AIO_TCPLISN, - AIO_UDPLISN -}; + + AIO_CLRNAME, + AIO_ADDNAME, + AIO_BYPNAME, + + AIO_DNSHOOK, + AIO_DNSHOST, + AIO_DNSPORT, + + AIO_APIPORT, + AIO_TCPPORT, + AIO_UDPPORT +} AIO_TYPE; + +typedef struct _TCPINFO { + BYTE Target[NF_MAX_ADDRESS_LENGTH]; +} TCPINFO, * PTCPINFO; + +typedef struct _UDPINFO { + SOCKET Socket; +} UDPINFO, * PUDPINFO; #endif diff --git a/Redirector/EventHandler.cpp b/Redirector/EventHandler.cpp index 60f64699..1b93bcab 100644 --- a/Redirector/EventHandler.cpp +++ b/Redirector/EventHandler.cpp @@ -1,3 +1,105 @@ #include "EventHandler.h" #include "Data.h" + +#include + +BOOL checkBypassName(DWORD id) +{ + return FALSE; +} + +BOOL checkHandleName(DWORD id) +{ + return FALSE; +} + +BOOL eh_init() +{ + return TRUE; +} + +void eh_free() +{ + +} + +void threadStart() +{ + +} + +void threadEnd() +{ + +} + +void tcpConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO info) +{ + nf_tcpDisableFiltering(id); +} + +void tcpConnected(ENDPOINT_ID id, PNF_TCP_CONN_INFO info) +{ + +} + +void tcpCanSend(ENDPOINT_ID id) +{ + +} + +void tcpSend(ENDPOINT_ID id, const char* buffer, int length) +{ + nf_tcpPostSend(id, buffer, length); +} + +void tcpCanReceive(ENDPOINT_ID id) +{ + +} + +void tcpReceive(ENDPOINT_ID id, const char* buffer, int length) +{ + nf_tcpPostReceive(id, buffer, length); +} + +void tcpClosed(ENDPOINT_ID id, PNF_TCP_CONN_INFO info) +{ + +} + +void udpCreated(ENDPOINT_ID id, PNF_UDP_CONN_INFO info) +{ + nf_udpDisableFiltering(id); +} + +void udpConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST info) +{ + +} + +void udpCanSend(ENDPOINT_ID id) +{ + +} + +void udpSend(ENDPOINT_ID id, const unsigned char* target, const char* buffer, int length, PNF_UDP_OPTIONS options) +{ + nf_udpPostSend(id, target, buffer, length, options); +} + +void udpCanReceive(ENDPOINT_ID id) +{ + +} + +void udpReceive(ENDPOINT_ID id, const unsigned char* target, const char* buffer, int length, PNF_UDP_OPTIONS options) +{ + nf_udpPostReceive(id, target, buffer, length, options); +} + +void udpClosed(ENDPOINT_ID id, PNF_UDP_CONN_INFO info) +{ + +} diff --git a/Redirector/EventHandler.h b/Redirector/EventHandler.h index b26d2c91..5cf7f771 100644 --- a/Redirector/EventHandler.h +++ b/Redirector/EventHandler.h @@ -1,5 +1,28 @@ #pragma once #ifndef EVENTHANDLER_H #define EVENTHANDLER_H +#include + +#include + +BOOL eh_init(); +void eh_free(); + +void threadStart(); +void threadEnd(); +void tcpConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO info); +void tcpConnected(ENDPOINT_ID id, PNF_TCP_CONN_INFO info); +void tcpCanSend(ENDPOINT_ID id); +void tcpSend(ENDPOINT_ID id, const char* buffer, int length); +void tcpCanReceive(ENDPOINT_ID id); +void tcpReceive(ENDPOINT_ID id, const char* buffer, int length); +void tcpClosed(ENDPOINT_ID id, PNF_TCP_CONN_INFO info); +void udpCreated(ENDPOINT_ID id, PNF_UDP_CONN_INFO info); +void udpConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST info); +void udpCanSend(ENDPOINT_ID id); +void udpSend(ENDPOINT_ID id, const unsigned char* target, const char* buffer, int length, PNF_UDP_OPTIONS options); +void udpCanReceive(ENDPOINT_ID id); +void udpReceive(ENDPOINT_ID id, const unsigned char* target, const char* buffer, int length, PNF_UDP_OPTIONS options); +void udpClosed(ENDPOINT_ID id, PNF_UDP_CONN_INFO info); #endif diff --git a/Redirector/IPEventHandler.cpp b/Redirector/IPEventHandler.cpp index 8b58e17e..8e14b358 100644 --- a/Redirector/IPEventHandler.cpp +++ b/Redirector/IPEventHandler.cpp @@ -1,5 +1,61 @@ #include "IPEventHandler.h" -#include "Data.h" #include "Utils.h" +#include + +void ipSend(const char* buffer, int length, PNF_IP_PACKET_OPTIONS options) +{ + if (options->ip_family != AF_INET || + options->ipHeaderSize != 20 || + length < 28 || + buffer[options->ipHeaderSize] != 0x08) + { + UNREFERENCED_PARAMETER(nf_ipPostSend(buffer, length, options)); + return; + } + + auto data = (PBYTE)malloc(length); + if (!data) + { + puts("[Redirector][IPEventHandler][ipSend] Unable to allocate memory"); + + UNREFERENCED_PARAMETER(nf_ipPostSend(buffer, length, options)); + return; + } + memcpy(data, buffer, length); + + { + BYTE src[4]; + BYTE dst[4]; + memcpy(src, data + 12, 4); + memcpy(dst, data + 16, 4); + memcpy(data + 12, dst, 4); + memcpy(data + 16, src, 4); + } + + data[10] = 0x00; + data[11] = 0x00; + auto ipv4sum = IPv4Checksum(data, options->ipHeaderSize); + data[10] = (ipv4sum >> 8); + data[11] = ipv4sum & 0xff; + + data[options->ipHeaderSize] = 0x00; + data[options->ipHeaderSize + 2] = 0x00; + data[options->ipHeaderSize + 3] = 0x00; + auto icmpsum = ICMPChecksum(data + options->ipHeaderSize, (ULONG64)length - options->ipHeaderSize); + data[options->ipHeaderSize + 2] = icmpsum & 0xff; + data[options->ipHeaderSize + 3] = (icmpsum >> 8); + + if (NF_STATUS_SUCCESS == nf_ipPostReceive((PCHAR)data, length, options)) + { + printf("[Redirector][ipSend] Fake ICMP response for %d.%d.%d.%d\n", data[12], data[13], data[14], data[15]); + } + + free(data); +} + +void ipReceive(const char* buffer, int length, PNF_IP_PACKET_OPTIONS options) +{ + UNREFERENCED_PARAMETER(nf_ipPostReceive(buffer, length, options)); +} diff --git a/Redirector/IPEventHandler.h b/Redirector/IPEventHandler.h index 299c67ab..8d7d8f86 100644 --- a/Redirector/IPEventHandler.h +++ b/Redirector/IPEventHandler.h @@ -1,5 +1,11 @@ #pragma once #ifndef IPEVENTHANDLER_H #define IPEVENTHANDLER_H +#include + +#include + +void ipSend(const char* buffer, int length, PNF_IP_PACKET_OPTIONS options); +void ipReceive(const char* buffer, int length, PNF_IP_PACKET_OPTIONS options); #endif diff --git a/Redirector/PROTOCOL.txt b/Redirector/PROTOCOL.txt new file mode 100644 index 00000000..2aa87d4f --- /dev/null +++ b/Redirector/PROTOCOL.txt @@ -0,0 +1,39 @@ +All address use SOCKS5 format + +/* DNS */ +Only UDP DNS ++------+ +| Data | ++------+ +| ???? | ++------+ + +/* API */ +Based UDP ++-----+----------+-------------+ +| PID | Protocol | Client Port | ++-----+----------+-------------+ +| 4 | 1 | 2 | ++-----+----------+-------------+ + +/* TCP */ ++------+ +| Data | ++------+ +| ???? | ++------+ + +/* UDP */ +Send ++--------+------+ +| Target | Data | ++--------+------+ +| ?????? | ???? | ++--------+------+ + +Receive ++--------+------+ +| Source | Data | ++--------+------+ +| ?????? | ???? | ++--------+------+ diff --git a/Redirector/Redirector.cpp b/Redirector/Redirector.cpp index ced67afe..ad3f92fd 100644 --- a/Redirector/Redirector.cpp +++ b/Redirector/Redirector.cpp @@ -1,14 +1,51 @@ #include "Data.h" #include "Utils.h" #include "EventHandler.h" +#include "IPEventHandler.h" -extern BOOL filterLoopback; +#include + +#include + +#include + +using namespace std; + +extern BOOL filterLoop; extern BOOL filterICMP; extern BOOL filterTCP; extern BOOL filterUDP; +extern BOOL dnsHook; +extern string dnsHost; +extern USHORT dnsPort; +extern USHORT apiLisn; extern USHORT tcpLisn; extern USHORT udpLisn; +NF_EventHandler EventHandler = { + threadStart, + threadEnd, + tcpConnectRequest, + tcpConnected, + tcpClosed, + tcpReceive, + tcpSend, + tcpCanReceive, + tcpCanSend, + udpCreated, + udpConnectRequest, + udpClosed, + udpReceive, + udpSend, + udpCanReceive, + udpCanSend +}; + +NF_IPEventHandler IPEventHandler = { + ipReceive, + ipSend +}; + BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { UNREFERENCED_PARAMETER(hModule); @@ -21,50 +58,58 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv #ifdef __cplusplus extern "C" { #endif - -__declspec(dllexport) BOOL __cdecl aio_dial(INT name, LPWSTR value) -{ - UNREFERENCED_PARAMETER(name); - UNREFERENCED_PARAMETER(value); - - switch (name) + __declspec(dllexport) BOOL __cdecl aio_dial(INT name, LPWSTR value) { - case AIO_FILTERLOOPBACK: - break; - case AIO_FILTERICMP: - break; - case AIO_FILTERTCP: - break; - case AIO_FILTERUDP: - break; - case AIO_TCPLISN: - break; - case AIO_UDPLISN: - break; - default: + UNREFERENCED_PARAMETER(name); + UNREFERENCED_PARAMETER(value); + + switch (name) + { + case AIO_FILTERLOOP: + break; + case AIO_FILTERICMP: + break; + case AIO_FILTERTCP: + break; + case AIO_FILTERUDP: + break; + case AIO_DNSHOOK: + break; + case AIO_DNSHOST: + break; + case AIO_DNSPORT: + break; + case AIO_APIPORT: + break; + case AIO_TCPPORT: + break; + case AIO_UDPPORT: + break; + default: + return FALSE; + } + + return TRUE; + } + + __declspec(dllexport) BOOL __cdecl aio_init() + { + nf_adjustProcessPriviledges(); + + { + WSADATA data; + UNREFERENCED_PARAMETER(WSAStartup(MAKEWORD(2, 2), &data)); + } + return FALSE; } - return TRUE; -} - -__declspec(dllexport) BOOL __cdecl aio_init() -{ + __declspec(dllexport) void __cdecl aio_free() { - WSADATA data; - UNREFERENCED_PARAMETER(WSAStartup(MAKEWORD(2, 2), &data)); + UNREFERENCED_PARAMETER(WSACleanup()); + + return; } - - return FALSE; -} - -__declspec(dllexport) VOID __cdecl aio_free() -{ - UNREFERENCED_PARAMETER(WSACleanup()); - - return; -} - #ifdef __cplusplus } #endif diff --git a/Redirector/Redirector.vcxproj b/Redirector/Redirector.vcxproj index ea8d8f6f..c46ad408 100644 --- a/Redirector/Redirector.vcxproj +++ b/Redirector/Redirector.vcxproj @@ -72,7 +72,7 @@ Console true - ws2_32.lib;%(AdditionalDependencies) + nfapi.lib;ws2_32.lib;%(AdditionalDependencies) @@ -92,25 +92,32 @@ true true true - ws2_32.lib;%(AdditionalDependencies) + nfapi.lib;ws2_32.lib;%(AdditionalDependencies) COPY /Y $(ProjectDir)static\*.dll $(TargetDir) > NUL + + + + + + + diff --git a/Redirector/Redirector.vcxproj.filters b/Redirector/Redirector.vcxproj.filters index 9a8b7803..832dbe21 100644 --- a/Redirector/Redirector.vcxproj.filters +++ b/Redirector/Redirector.vcxproj.filters @@ -9,10 +9,6 @@ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - @@ -30,6 +26,12 @@ Source + + Source + + + Source + @@ -44,5 +46,14 @@ Header + + Header + + + Header + + + + \ No newline at end of file diff --git a/Redirector/Utils.cpp b/Redirector/Utils.cpp index 918ede0f..2c58ad03 100644 --- a/Redirector/Utils.cpp +++ b/Redirector/Utils.cpp @@ -2,18 +2,50 @@ #include "Data.h" +DWORD GetCPUCount() +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + + return info.dwNumberOfProcessors; +} + USHORT IPv4Checksum(PBYTE buffer, ULONG64 size) { - UNREFERENCED_PARAMETER(buffer); - UNREFERENCED_PARAMETER(size); + UINT32 sum = 0; + for (int i = 0; i < size; i += 2) + { + sum += (buffer[i] << 8) + buffer[i + 1]; + } - return 0; + if ((size % 2) == 1) + { + sum += buffer[size - 1] << 8; + } + + while (sum > 0xffff) + { + sum = (sum >> 16) + (sum & 0xffff); + } + + return ~sum & 0xffff; } USHORT ICMPChecksum(PBYTE buffer, ULONG64 size) { - UNREFERENCED_PARAMETER(buffer); - UNREFERENCED_PARAMETER(size); + UINT32 sum = 0; + for (int i = 0; i < size; i += 2) + { + sum += buffer[i] + (buffer[i + 1] << 8); + } - return 0; + if ((size % 2) == 1) + { + sum += buffer[size - 1]; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + return ~sum & 0xffff; } diff --git a/Redirector/Utils.h b/Redirector/Utils.h index 0fc2768e..51151698 100644 --- a/Redirector/Utils.h +++ b/Redirector/Utils.h @@ -1,7 +1,9 @@ #pragma once #ifndef UTILS_H #define UTILS_H +#include +DWORD GetCPUCount(); USHORT IPv4Checksum(PBYTE buffer, ULONG64 size); USHORT ICMPChecksum(PBYTE buffer, ULONG64 size); diff --git a/Redirector/include/nfapi.h b/Redirector/include/nfapi.h new file mode 100644 index 00000000..72628dd5 --- /dev/null +++ b/Redirector/include/nfapi.h @@ -0,0 +1,415 @@ +// +// NetFilterSDK +// Copyright (C) Vitaly Sidorov +// All rights reserved. +// +// This file is a part of the NetFilter SDK. +// The code and information is provided "as-is" without +// warranty of any kind, either expressed or implied. +// + + +#ifndef _NFAPI_H +#define _NFAPI_H +#include + +#define _NFAPI_STATIC_LIB +#ifdef _NFAPI_STATIC_LIB + #define NFAPI_API +#else + #ifdef NFAPI_EXPORTS + #define NFAPI_API __declspec(dllexport) + #else + #define NFAPI_API __declspec(dllimport) + #endif +#endif + +// Flags for NF_UDP_OPTIONS.flags + +#define TDI_RECEIVE_BROADCAST 0x00000004 // received TSDU was broadcast. +#define TDI_RECEIVE_MULTICAST 0x00000008 // received TSDU was multicast. +#define TDI_RECEIVE_PARTIAL 0x00000010 // received TSDU is not fully presented. +#define TDI_RECEIVE_NORMAL 0x00000020 // received TSDU is normal data +#define TDI_RECEIVE_EXPEDITED 0x00000040 // received TSDU is expedited data +#define TDI_RECEIVE_PEEK 0x00000080 // received TSDU is not released +#define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100 // HINT: no back-traffic expected +#define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 // for kernel-mode indications +#define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 // opposite of RECEIVE_PARTIAL + // (for kernel-mode indications) +#define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800 // receive indication called + // at dispatch level +#define TDI_RECEIVE_CONTROL_INFO 0x00001000 // Control info is being passed up. +#define TDI_RECEIVE_FORCE_INDICATION 0x00002000 // reindicate rejected data. +#define TDI_RECEIVE_NO_PUSH 0x00004000 // complete only when full. + +typedef enum _NF_FLAGS +{ + NFF_NONE = 0, + NFF_DONT_DISABLE_TEREDO = 1, + NFF_DONT_DISABLE_TCP_OFFLOADING = 2, + NFF_DISABLE_AUTO_REGISTER = 4, + NFF_DISABLE_AUTO_START = 8, +} NF_FLAGS; + +#ifndef _C_API + namespace nfapi + { + #define NFAPI_NS nfapi:: + #define NFAPI_CC +#else // _C_API + #define NFAPI_CC __cdecl + #define NFAPI_NS + #ifdef __cplusplus + extern "C" + { + #endif +#endif // _C_API + +/** +* Initializes the internal data structures and starts the filtering thread. +* @param driverName The name of hooking driver, without ".sys" extension. +* @param pHandler Pointer to event handling object +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_init(const char * driverName, NF_EventHandler * pHandler); + +/** +* Stops the filtering thread, breaks all filtered connections and closes +* a connection with the hooking driver. +**/ +NFAPI_API void NFAPI_CC +nf_free(); + +/** +* Registers and starts a driver with specified name (without ".sys" extension) +* @param driverName +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_registerDriver(const char * driverName); + +/** +* Registers and starts a driver with specified name (without ".sys" extension) and path to driver folder +* @param driverName +* @param driverPath +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_registerDriverEx(const char * driverName, const char * driverPath); + +/** +* Unregisters a driver with specified name (without ".sys" extension) +* @param driverName +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_unRegisterDriver(const char * driverName); + + +// +// TCP control routines +// + +/** +* Suspends or resumes indicating of sends and receives for specified connection. +* @param id Connection identifier +* @param suspended TRUE(1) for suspend, FALSE(0) for resume +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_tcpSetConnectionState(ENDPOINT_ID id, int suspended); + +/** +* Sends the buffer to remote server via specified connection. +* @param id Connection identifier +* @param buf Pointer to data buffer +* @param len Buffer length +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_tcpPostSend(ENDPOINT_ID id, const char * buf, int len); + +/** +* Indicates the buffer to local process via specified connection. +* @param id Unique connection identifier +* @param buf Pointer to data buffer +* @param len Buffer length +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_tcpPostReceive(ENDPOINT_ID id, const char * buf, int len); + +/** +* Breaks the connection with given id. +* @param id Connection identifier +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_tcpClose(ENDPOINT_ID id); + +/** + * Sets the timeout for TCP connections and returns old timeout. + * @param timeout Timeout value in milliseconds. Specify zero value to disable timeouts. + */ +NFAPI_API unsigned long NFAPI_CC +nf_setTCPTimeout(unsigned long timeout); + +/** + * Disables indicating TCP packets to user mode for the specified endpoint + * @param id Socket identifier + */ +NFAPI_API NF_STATUS NFAPI_CC +nf_tcpDisableFiltering(ENDPOINT_ID id); + + +// +// UDP control routines +// + +/** +* Suspends or resumes indicating of sends and receives for specified socket. +* @param id Socket identifier +* @param suspended TRUE(1) for suspend, FALSE(0) for resume +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_udpSetConnectionState(ENDPOINT_ID id, int suspended); + +/** +* Sends the buffer to remote server via specified socket. +* @param id Socket identifier +* @param options UDP options +* @param remoteAddress Destination address +* @param buf Pointer to data buffer +* @param len Buffer length +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_udpPostSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); + +/** +* Indicates the buffer to local process via specified socket. +* @param id Unique connection identifier +* @param options UDP options +* @param remoteAddress Source address +* @param buf Pointer to data buffer +* @param len Buffer length +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_udpPostReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); + +/** + * Disables indicating UDP packets to user mode for the specified endpoint + * @param id Socket identifier + */ +NFAPI_API NF_STATUS NFAPI_CC +nf_udpDisableFiltering(ENDPOINT_ID id); + + +/** +* Sends a packet to remote IP +* @param buf Pointer to IP packet +* @param len Buffer length +* @param options IP options +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_ipPostSend(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); + +/** +* Indicates a packet to TCP/IP stack +* @param buf Pointer to IP packet +* @param len Buffer length +* @param options IP options +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_ipPostReceive(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); + +// +// Filtering rules +// + +/** +* Add a rule to the head of rules list in driver. +* @param pRule See NF_RULE +* @param toHead TRUE (1) - add rule to list head, FALSE (0) - add rule to tail +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_addRule(PNF_RULE pRule, int toHead); + +/** +* Removes all rules from driver. +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_deleteRules(); + +/** +* Replace the rules in driver with the specified array. +* @param pRules Array of NF_RULE structures +* @param count Number of items in array +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_setRules(PNF_RULE pRules, int count); + +/** +* Add a rule to the head of rules list in driver. +* @param pRule See NF_RULE_EX +* @param toHead TRUE (1) - add rule to list head, FALSE (0) - add rule to tail +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_addRuleEx(PNF_RULE_EX pRule, int toHead); + +/** +* Replace the rules in driver with the specified array. +* @param pRules Array of NF_RULE_EX structures +* @param count Number of items in array +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_setRulesEx(PNF_RULE_EX pRules, int count); + +// +// Debug routine +// + +NFAPI_API unsigned long NFAPI_CC +nf_getConnCount(); + +NFAPI_API NF_STATUS NFAPI_CC +nf_tcpSetSockOpt(ENDPOINT_ID id, int optname, const char* optval, int optlen); + +/** +* Returns the process name for given process id +* @param processId Process identifier +* @param buf Buffer +* @param len Buffer length +**/ +NFAPI_API BOOL NFAPI_CC +nf_getProcessNameA(DWORD processId, char * buf, DWORD len); + +NFAPI_API BOOL NFAPI_CC +nf_getProcessNameW(DWORD processId, wchar_t * buf, DWORD len); + +#ifdef UNICODE +#define nf_getProcessName nf_getProcessNameW +#else +#define nf_getProcessName nf_getProcessNameA +#endif + +NFAPI_API BOOL NFAPI_CC +nf_getProcessNameFromKernel(DWORD processId, wchar_t * buf, DWORD len); + +/** +* Allows the current process to see the names of all processes in system +**/ +NFAPI_API void NFAPI_CC +nf_adjustProcessPriviledges(); + +/** +* Returns TRUE if the specified process acts as a local proxy, accepting the redirected TCP connections. +**/ +NFAPI_API BOOL NFAPI_CC +nf_tcpIsProxy(DWORD processId); + +/** +* Set the number of worker threads and initialization flags. +* The function should be called before nf_init. +* By default nThreads = 1 and flags = 0 +* @param nThreads Number of worker threads for NF_EventHandler events +* @param flags A combination of flags from NF_FLAGS +**/ +NFAPI_API void NFAPI_CC +nf_setOptions(DWORD nThreads, DWORD flags); + +/** +* Complete TCP connect request pended using flag NF_PEND_CONNECT_REQUEST. +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_completeTCPConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); + +/** +* Complete UDP connect request pended using flag NF_PEND_CONNECT_REQUEST. +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_completeUDPConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnInfo); + +/** +* Returns in pConnInfo the properties of TCP connection with specified id. +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_getTCPConnInfo(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); + +/** +* Returns in pConnInfo the properties of UDP socket with specified id. +**/ +NFAPI_API NF_STATUS NFAPI_CC +nf_getUDPConnInfo(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); + +/** +* Set the event handler for IP filtering events +*/ +NFAPI_API void NFAPI_CC +nf_setIPEventHandler(NF_IPEventHandler * pHandler); + +/** +* Add flow control context +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_addFlowCtl(PNF_FLOWCTL_DATA pData, unsigned int * pFcHandle); + +/** +* Delete flow control context +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_deleteFlowCtl(unsigned int fcHandle); + +/** +* Associate flow control context with TCP connection +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_setTCPFlowCtl(ENDPOINT_ID id, unsigned int fcHandle); + +/** +* Associate flow control context with UDP socket +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_setUDPFlowCtl(ENDPOINT_ID id, unsigned int fcHandle); + +/** +* Modify flow control context limits +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_modifyFlowCtl(unsigned int fcHandle, PNF_FLOWCTL_DATA pData); + +/** +* Get flow control context statistics as the numbers of in/out bytes +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_getFlowCtlStat(unsigned int fcHandle, PNF_FLOWCTL_STAT pStat); + +/** +* Get TCP connection statistics as the numbers of in/out bytes. +* The function can be called only from tcpClosed handler! +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_getTCPStat(ENDPOINT_ID id, PNF_FLOWCTL_STAT pStat); + +/** +* Get UDP socket statistics as the numbers of in/out bytes. +* The function can be called only from udpClosed handler! +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_getUDPStat(ENDPOINT_ID id, PNF_FLOWCTL_STAT pStat); + +/** +* Add binding rule to driver +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_addBindingRule(PNF_BINDING_RULE pRule, int toHead); + +/** +* Delete all binding rules from driver +*/ +NFAPI_API NF_STATUS NFAPI_CC +nf_deleteBindingRules(); + +/** +* Returns the type of attached driver (DT_WFP, DT_TDI or DT_UNKNOWN) +*/ +NFAPI_API unsigned long NFAPI_CC +nf_getDriverType(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/Redirector/include/nfdriver.h b/Redirector/include/nfdriver.h new file mode 100644 index 00000000..7f3e3f33 --- /dev/null +++ b/Redirector/include/nfdriver.h @@ -0,0 +1,449 @@ +// +// NetFilterSDK +// Copyright (C) Vitaly Sidorov +// All rights reserved. +// +// This file is a part of the NetFilter SDK. +// The code and information is provided "as-is" without +// warranty of any kind, either expressed or implied. +// + + +#ifndef _NFDRIVER_H +#define _NFDRIVER_H + +#define NF_TCP_PACKET_BUF_SIZE 8192 +#define NF_UDP_PACKET_BUF_SIZE 2 * 65536 + +/** +* IO data codes +**/ +typedef enum _NF_DATA_CODE +{ + NF_TCP_CONNECTED, // TCP connection established + NF_TCP_CLOSED, // TCP connection closed + NF_TCP_RECEIVE, // TCP data packet received + NF_TCP_SEND, // TCP data packet sent + NF_TCP_CAN_RECEIVE, // The buffer for TCP receives is empty + NF_TCP_CAN_SEND, // The buffer for TCP sends is empty + NF_TCP_REQ_SUSPEND, // Requests suspending TCP connection + NF_TCP_REQ_RESUME, // Requests resuming TCP connection + + NF_UDP_CREATED, // UDP socket created + NF_UDP_CLOSED, // UDP socket closed + NF_UDP_RECEIVE, // UDP data packet received + NF_UDP_SEND, // UDP data packet sent + NF_UDP_CAN_RECEIVE, // The buffer for UDP receives is empty + NF_UDP_CAN_SEND, // The buffer for UDP sends is empty + NF_UDP_REQ_SUSPEND, // Requests suspending UDP address + NF_UDP_REQ_RESUME, // Requests resuming UDP address + + NF_REQ_ADD_HEAD_RULE, // Add a rule to list head + NF_REQ_ADD_TAIL_RULE, // Add a rule to list tail + NF_REQ_DELETE_RULES, // Remove all rules + + NF_TCP_CONNECT_REQUEST, // Outgoing TCP connect request + NF_UDP_CONNECT_REQUEST, // Outgoing UDP connect request + + NF_TCP_DISABLE_USER_MODE_FILTERING, // Disable indicating TCP packets to user mode for a connection + NF_UDP_DISABLE_USER_MODE_FILTERING, // Disable indicating UDP packets to user mode for a socket + + NF_REQ_SET_TCP_OPT, // Set TCP socket options + NF_REQ_IS_PROXY, // Check if process with specified id is local proxy + + NF_TCP_REINJECT, // Reinject pended packets + NF_TCP_REMOVE_CLOSED, // Delete TCP context for the closed connection + NF_TCP_DEFERRED_DISCONNECT, // Delete TCP context for the closed connection + + NF_IP_RECEIVE, // IP data packet received + NF_IP_SEND, // IP data packet sent + NF_TCP_RECEIVE_PUSH, // Push all TCP data packets +} NF_DATA_CODE; + +typedef enum _NF_DIRECTION +{ + NF_D_IN = 1, // Incoming TCP connection or UDP packet + NF_D_OUT = 2, // Outgoing TCP connection or UDP packet + NF_D_BOTH = 3 // Any direction +} NF_DIRECTION; + +typedef enum _NF_FILTERING_FLAG +{ + NF_ALLOW = 0, // Allow the activity without filtering transmitted packets + NF_BLOCK = 1, // Block the activity + NF_FILTER = 2, // Filter the transmitted packets + NF_SUSPENDED = 4, // Suspend receives from server and sends from client + NF_OFFLINE = 8, // Emulate establishing a TCP connection with remote server + NF_INDICATE_CONNECT_REQUESTS = 16, // Indicate outgoing connect requests to API + NF_DISABLE_REDIRECT_PROTECTION = 32, // Disable blocking indicating connect requests for outgoing connections of local proxies + NF_PEND_CONNECT_REQUEST = 64, // Pend outgoing connect request to complete it later using nf_complete(TCP|UDP)ConnectRequest + NF_FILTER_AS_IP_PACKETS = 128, // Indicate the traffic as IP packets via ipSend/ipReceive + NF_READONLY = 256, // Don't block the IP packets and indicate them to ipSend/ipReceive only for monitoring + NF_CONTROL_FLOW = 512, // Use the flow limit rules even without NF_FILTER flag + NF_REDIRECT = 1024, // Redirect the outgoing TCP connections to address specified in redirectTo +} NF_FILTERING_FLAG; + +#pragma pack(push, 1) + +#define NF_MAX_ADDRESS_LENGTH 28 +#define NF_MAX_IP_ADDRESS_LENGTH 16 + +#ifndef AF_INET +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#endif + +#ifndef AF_INET6 +#define AF_INET6 23 /* Internetwork Version 6 */ +#endif + +// Protocols + +#ifndef IPPROTO_TCP +#define IPPROTO_TCP 6 +#endif + +#ifndef IPPROTO_UDP +#define IPPROTO_UDP 17 +#endif + +#define TCP_SOCKET_NODELAY 1 +#define TCP_SOCKET_KEEPALIVE 2 +#define TCP_SOCKET_OOBINLINE 3 +#define TCP_SOCKET_BSDURGENT 4 +#define TCP_SOCKET_ATMARK 5 +#define TCP_SOCKET_WINDOW 6 + +/** +* Filtering rule +**/ +typedef UNALIGNED struct _NF_RULE +{ + int protocol; // IPPROTO_TCP or IPPROTO_UDP + unsigned long processId; // Process identifier + unsigned char direction; // See NF_DIRECTION + unsigned short localPort; // Local port + unsigned short remotePort; // Remote port + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + + // Local IP (or network if localIpAddressMask is not zero) + unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; + + // Local IP mask + unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; + + // Remote IP (or network if remoteIpAddressMask is not zero) + unsigned char remoteIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; + + // Remote IP mask + unsigned char remoteIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; + + unsigned long filteringFlag; // See NF_FILTERING_FLAG +} NF_RULE, *PNF_RULE; + + +typedef struct _NF_PORT_RANGE +{ + unsigned short valueLow; + unsigned short valueHigh; +} NF_PORT_RANGE, *PNF_PORT_RANGE; + + +/** +* Filtering rule with additional fields +**/ +typedef UNALIGNED struct _NF_RULE_EX +{ + int protocol; // IPPROTO_TCP or IPPROTO_UDP + unsigned long processId; // Process identifier + unsigned char direction; // See NF_DIRECTION + unsigned short localPort; // Local port + unsigned short remotePort; // Remote port + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + + // Local IP (or network if localIpAddressMask is not zero) + unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; + + // Local IP mask + unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; + + // Remote IP (or network if remoteIpAddressMask is not zero) + unsigned char remoteIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; + + // Remote IP mask + unsigned char remoteIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; + + unsigned long filteringFlag; // See NF_FILTERING_FLAG + + // Process name tail mask (supports * as 0 or more symbols) + wchar_t processName[MAX_PATH]; + + NF_PORT_RANGE localPortRange; // Local port(s) + NF_PORT_RANGE remotePortRange; // Remote port(s) + + // Remote address for redirection as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 + unsigned char redirectTo[NF_MAX_ADDRESS_LENGTH]; + // Process identifier of a local proxy + unsigned long localProxyProcessId; + +} NF_RULE_EX, *PNF_RULE_EX; + +typedef unsigned __int64 ENDPOINT_ID; + + +/** +* TCP connection properties +**/ +typedef UNALIGNED struct _NF_TCP_CONN_INFO +{ + unsigned long filteringFlag; // See NF_FILTERING_FLAG + unsigned long processId; // Process identifier + unsigned char direction; // See NF_DIRECTION + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + + // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 + unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; + + // Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 + unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; + +} NF_TCP_CONN_INFO, *PNF_TCP_CONN_INFO; + +/** +* UDP endpoint properties +**/ +typedef UNALIGNED struct _NF_UDP_CONN_INFO +{ + unsigned long processId; // Process identifier + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + + // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 + unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; + +} NF_UDP_CONN_INFO, *PNF_UDP_CONN_INFO; + +/** +* UDP TDI_CONNECT request properties +**/ +typedef UNALIGNED struct _NF_UDP_CONN_REQUEST +{ + unsigned long filteringFlag; // See NF_FILTERING_FLAG + unsigned long processId; // Process identifier + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + + // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 + unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; + + // Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 + unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; + +} NF_UDP_CONN_REQUEST, *PNF_UDP_CONN_REQUEST; + +/** +* UDP options +**/ +typedef UNALIGNED struct _NF_UDP_OPTIONS +{ + unsigned long flags; // Datagram flags + long optionsLength; // Length of options buffer + unsigned char options[1]; // Options of variable size +} NF_UDP_OPTIONS, *PNF_UDP_OPTIONS; + +typedef enum _NF_IP_FLAG +{ + NFIF_NONE = 0, // No flags + NFIF_READONLY = 1, // The packet was not blocked and indicated only for monitoring in read-only mode + // (see NF_READ_ONLY flags from NF_FILTERING_FLAG). +} NF_IP_FLAG; + +/** +* IP options +**/ +typedef struct _NF_IP_PACKET_OPTIONS +{ + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + unsigned int ipHeaderSize; // Size in bytes of IP header + unsigned long compartmentId; // Network routing compartment identifier (can be zero) + unsigned long interfaceIndex; // Index of the interface on which the original packet data was received (irrelevant to outgoing packets) + unsigned long subInterfaceIndex; // Index of the subinterface on which the original packet data was received (irrelevant to outgoing packets) + unsigned long flags; // Can be a combination of flags from NF_IP_FLAG enumeration +} NF_IP_PACKET_OPTIONS, *PNF_IP_PACKET_OPTIONS; + +/** +* Internal IO structure +**/ +typedef UNALIGNED struct _NF_DATA +{ + int code; + ENDPOINT_ID id; + unsigned long bufferSize; + char buffer[1]; +} NF_DATA, *PNF_DATA; + +typedef UNALIGNED struct _NF_BUFFERS +{ + unsigned __int64 inBuf; + unsigned __int64 inBufLen; + unsigned __int64 outBuf; + unsigned __int64 outBufLen; +} NF_BUFFERS, *PNF_BUFFERS; + +typedef UNALIGNED struct _NF_READ_RESULT +{ + unsigned __int64 length; +} NF_READ_RESULT, *PNF_READ_RESULT; + +typedef UNALIGNED struct _NF_FLOWCTL_DATA +{ + unsigned __int64 inLimit; + unsigned __int64 outLimit; +} NF_FLOWCTL_DATA, *PNF_FLOWCTL_DATA; + +typedef UNALIGNED struct _NF_FLOWCTL_MODIFY_DATA +{ + unsigned int fcHandle; + NF_FLOWCTL_DATA data; +} NF_FLOWCTL_MODIFY_DATA, *PNF_FLOWCTL_MODIFY_DATA; + +typedef UNALIGNED struct _NF_FLOWCTL_STAT +{ + unsigned __int64 inBytes; + unsigned __int64 outBytes; +} NF_FLOWCTL_STAT, *PNF_FLOWCTL_STAT; + +typedef UNALIGNED struct _NF_FLOWCTL_SET_DATA +{ + unsigned __int64 endpointId; + unsigned int fcHandle; +} NF_FLOWCTL_SET_DATA, *PNF_FLOWCTL_SET_DATA; + + +/** +* Binding rule +**/ +typedef UNALIGNED struct _NF_BINDING_RULE +{ + int protocol; // IPPROTO_TCP or IPPROTO_UDP + + unsigned long processId; // Process identifier + + // Process name tail mask (supports * as 0 or more symbols) + wchar_t processName[MAX_PATH]; + + unsigned short localPort; // Local port + + unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 + + // Local IP (or network if localIpAddressMask is not zero) + unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; + + // Local IP mask + unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; + + // Redirect bind request to this IP + unsigned char newLocalIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; + + // Redirect bind request to this port, if it is not zero + unsigned short newLocalPort; + + unsigned long filteringFlag; // See NF_FILTERING_FLAG, NF_ALLOW or NF_FILTER + +} NF_BINDING_RULE, *PNF_BINDING_RULE; + + +#pragma pack(pop) + +#ifdef WIN32 + +typedef enum _NF_DRIVER_TYPE +{ + DT_UNKNOWN = 0, + DT_TDI = 1, + DT_WFP = 2 +} NF_DRIVER_TYPE; + +#ifdef _NF_INTERNALS + +#define NF_REQ_GET_ADDR_INFO \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 101, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_GET_PROCESS_NAME \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 102, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_GET_DRIVER_TYPE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 103, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_TCP_ABORT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 104, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_FLOW_CTL \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 105, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_DELETE_FLOW_CTL \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 106, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_SET_TCP_FLOW_CTL \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 107, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_SET_UDP_FLOW_CTL \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 108, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_MODIFY_FLOW_CTL \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 109, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_GET_FLOW_CTL_STAT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 110, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_CLEAR_TEMP_RULES \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 111, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_TEMP_RULE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 112, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_SET_TEMP_RULES \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 113, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_HEAD_BINDING_RULE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 114, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_TAIL_BINDING_RULE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 115, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_DELETE_BINDING_RULES \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 116, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_HEAD_RULE_EX \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 117, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_TAIL_RULE_EX \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 118, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_ADD_TEMP_RULE_EX \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 119, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define NF_REQ_GET_UDP_ADDR_INFO \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 120, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK + +#define _TCP_CTL_CODE(function, method, access) \ + CTL_CODE(FSCTL_TCP_BASE, function, method, access) + +#define IOCTL_TCP_QUERY_INFORMATION_EX \ + _TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_TCP_SET_INFORMATION_EX \ + _TCP_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +#endif + +#define FSCTL_DEVCTRL_BASE FILE_DEVICE_NETWORK + +#define _DEVCTRL_CTL_CODE(_Function, _Method, _Access) \ + CTL_CODE(FSCTL_DEVCTRL_BASE, _Function, _Method, _Access) + +#define IOCTL_DEVCTRL_OPEN \ + _DEVCTRL_CTL_CODE(0x200, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#endif + +#endif // _NFDRIVER_H \ No newline at end of file diff --git a/Redirector/include/nfevents.h b/Redirector/include/nfevents.h new file mode 100644 index 00000000..07151a57 --- /dev/null +++ b/Redirector/include/nfevents.h @@ -0,0 +1,270 @@ +// +// NetFilterSDK +// Copyright (C) Vitaly Sidorov +// All rights reserved. +// +// This file is a part of the NetFilter SDK. +// The code and information is provided "as-is" without +// warranty of any kind, either expressed or implied. +// + + +#ifndef _NFEVENTS_H +#define _NFEVENTS_H +#pragma warning(disable: 26812) + +/** +* Return status codes +**/ +typedef enum _NF_STATUS +{ + NF_STATUS_SUCCESS = 0, + NF_STATUS_FAIL = -1, + NF_STATUS_INVALID_ENDPOINT_ID = -2, + NF_STATUS_NOT_INITIALIZED = -3, + NF_STATUS_IO_ERROR = -4, + NF_STATUS_REBOOT_REQUIRED = -5 +} NF_STATUS; + +#define _C_API +#ifndef _C_API + + #define NFAPI_NS nfapi:: + #define NFAPI_CC + + ///////////////////////////////////////////////////////////////////////////////////// + // C++ API + ///////////////////////////////////////////////////////////////////////////////////// + + namespace nfapi + { + #include + + /** + * Filtering events + **/ + class NF_EventHandler + { + public: + + /** + * Called immediately after starting the filtering thread. + * Use this event for thread-specific initialization, e.g. calling + * CoInitialize() etc. + **/ + virtual void threadStart() = 0; + + /** + * Called before stopping the thread. + **/ + virtual void threadEnd() = 0; + + // + // TCP events + // + + /** + * Called before establishing an outgoing TCP connection, + * when NF_INDICATE_CONNECT_REQUESTS flag is specified in an appropriate rule. + * It is possible to change pConnInfo->filteringFlag and pConnInfo->remoteAddress + * in this handler. The changes will be applied to connection. + * @param id Unique connection identifier + * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO + **/ + virtual void tcpConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; + + /** + * Called after successful establishing the incoming or outgoing TCP connection. + * @param id Unique connection identifier + * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO + **/ + virtual void tcpConnected(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; + + /** + * Called after closing the connection identified by id. + * @param id Unique connection identifier + * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO + **/ + virtual void tcpClosed(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; + + /** + * Indicates the buffer received from server. + * @param id Unique connection identifier + * @param buf Pointer to data buffer + * @param len Buffer length + **/ + virtual void tcpReceive(ENDPOINT_ID id, const char * buf, int len) = 0; + + /** + * Indicates the buffer sent from the local socket. + * @param id Unique connection identifier + * @param buf Pointer to data buffer + * @param len Buffer length + **/ + virtual void tcpSend(ENDPOINT_ID id, const char * buf, int len) = 0; + + /** + * Informs that the internal buffer for receives is empty and + * it is possible to call nf_tcpPostReceive for pushing receives + * via specified connection. + * @param id Unique connection identifier + **/ + virtual void tcpCanReceive(ENDPOINT_ID id) = 0; + + /** + * Informs that the internal buffer for sends is empty and + * it is possible to call nf_tcpPostSend for pushing sends + * via specified connection. + * @param id Unique connection identifier + **/ + virtual void tcpCanSend(ENDPOINT_ID id) = 0; + + + // + // UDP events + // + + /** + * Called after creating UDP socket. + * @param id Unique socket identifier + * @param pConnInfo Socket parameters, see NF_UDP_CONN_INFO + **/ + virtual void udpCreated(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) = 0; + + /** + * Called before establishing an outgoing UDP connection, + * when NF_INDICATE_CONNECT_REQUESTS flag is specified in an appropriate rule. + * It is possible to change pConnReq->filteringFlag and pConnReq->remoteAddress + * in this handler. The changes will be applied to connection. + * @param id Unique connection identifier + * @param pConnInfo Connection parameters, see NF_UDP_CONN_REQUEST + **/ + virtual void udpConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq) = 0; + + /** + * Called after closing UDP socket identified by id. + * @param id Unique socket identifier + * @param pConnInfo Socket parameters, see NF_UDP_CONN_INFO + **/ + virtual void udpClosed(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) = 0; + + /** + * Indicates the buffer received from server. + * @param id Unique socket identifier + * @param options UDP options + * @param remoteAddress Source address + * @param buf Pointer to data buffer + * @param len Buffer length + **/ + virtual void udpReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) = 0; + + /** + * Indicates the buffer sent from the local socket. + * @param id Unique socket identifier + * @param options UDP options + * @param remoteAddress Destination address + * @param buf Pointer to data buffer + * @param len Buffer length + **/ + virtual void udpSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) = 0; + + /** + * Informs that the internal buffer for receives is empty and + * it is possible to call nf_udpPostReceive for pushing receives + * via specified socket. + * @param id Unique socket identifier + **/ + virtual void udpCanReceive(ENDPOINT_ID id) = 0; + + /** + * Informs that the internal buffer for sends is empty and + * it is possible to call nf_udpPostSend for pushing sends + * via specified socket. + * @param id Unique socket identifier + **/ + virtual void udpCanSend(ENDPOINT_ID id) = 0; + }; + + /** + * IP level filtering events + **/ + class NF_IPEventHandler + { + public: + /** + * Indicates a packet received from server. + * @param buf Pointer to data buffer + * @param len Buffer length + * @param options IP options + **/ + virtual void ipReceive(const char * buf, int len, PNF_IP_PACKET_OPTIONS options) = 0; + + /** + * Indicates a packet sent to server. + * @param buf Pointer to data buffer + * @param len Buffer length + * @param options IP options + **/ + virtual void ipSend(const char * buf, int len, PNF_IP_PACKET_OPTIONS options) = 0; + }; + +#else + +#ifdef WIN32 + #define NFAPI_CC __cdecl +#else + #define NFAPI_CC +#endif + #define NFAPI_NS + + ///////////////////////////////////////////////////////////////////////////////////// + // C API + ///////////////////////////////////////////////////////////////////////////////////// + + #ifdef __cplusplus + extern "C" + { + #endif + + #include + + #pragma pack(push, 1) + + // C analogue of the class NF_EventHandler (see the definition above) + typedef struct _NF_EventHandler + { + void (NFAPI_CC *threadStart)(); + void (NFAPI_CC *threadEnd)(); + void (NFAPI_CC *tcpConnectRequest)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); + void (NFAPI_CC *tcpConnected)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); + void (NFAPI_CC *tcpClosed)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); + void (NFAPI_CC *tcpReceive)(ENDPOINT_ID id, const char * buf, int len); + void (NFAPI_CC *tcpSend)(ENDPOINT_ID id, const char * buf, int len); + void (NFAPI_CC *tcpCanReceive)(ENDPOINT_ID id); + void (NFAPI_CC *tcpCanSend)(ENDPOINT_ID id); + void (NFAPI_CC *udpCreated)(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); + void (NFAPI_CC *udpConnectRequest)(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq); + void (NFAPI_CC *udpClosed)(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); + void (NFAPI_CC *udpReceive)(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); + void (NFAPI_CC *udpSend)(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); + void (NFAPI_CC *udpCanReceive)(ENDPOINT_ID id); + void (NFAPI_CC *udpCanSend)(ENDPOINT_ID id); + } NF_EventHandler, *PNF_EventHandler; + + // C analogue of the class NF_IPEventHandler (see the definition above) + typedef struct _NF_IPEventHandler + { + void (NFAPI_CC *ipReceive)(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); + void (NFAPI_CC *ipSend)(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); + } NF_IPEventHandler, *PNF_IPEventHandler; + + #pragma pack(pop) + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/Redirector/lib/nfapi.lib b/Redirector/lib/nfapi.lib new file mode 100644 index 0000000000000000000000000000000000000000..6d34a036caa003760d5502c92bf6af1f93e04753 GIT binary patch literal 11044 zcmcIqOK)677Cs~)0Z#y9=ix_Ux8t`bgv9A~9BDMuv7HDj!LjU)V1d+WyRS`W+TEV+ zc808G7a=raiCD3iVaWoqU?en)tOJXYh6U0f@dpqK7A%ku^VO|7r>pJ@-;UGL@x68G ztNQ9x)u}pF*CT%@H8$V=W7n%0_jhS-cJ}I(+{LR|SAWqYXD`pq>DRkmL{uc|JxX+P zis;l^M46AYoI#e7sR1pMpAz}9gePR;h?ep5L`o*^X_;9dQZoIGkt&{$sh_os;N2J0 zJp$=_sAcd2A|<0gYU%qPddS$DTFz{sJ&>vQwVeH!NXgKDe2ex#M&HxY z{}_760NSQx=qD}1&?y;(ol5$Kv<%LmJ&>_STE;(wosf~QwVa&?KV%qfQj(d|a{4nO zB?Dh*IrA0T4LO%L@(G@hna`CJi_5RC-d-ydm#(ibt}U+?Zm$(;GwgC=Fzg3fl0ghx+lH~mMuwWG z;UTq@sk9jZwNe2DlL?3wf-9BFYkO6{^Z8Zs%3jrLc`Cc9`qEAc2E!o$d6!&M<@I+| z`F29`xr7E-DM4)O3A$L{tNFw4qy?oX?0S9k&$oAdn5z&RO0PERn_jcIQrhvZsa6G5 zG1xc4*f-i<=T>r~QQx`gHELcpT*%53rc(LdUXvTP+Nj*GRK4=H?)2C^DGgJXo3QGg z2a3%~2?G6!Zh?dQ!)T=hv02~QRbvfTGt0r6_m@4d>Gx%PW~ls~rG)a~Oev54Gt|qq zt-9$oTVo?lJr>f|2oiQKuU^0J)mpEWYUQfeP}PQ&g2(i{QLX=VvE`4Nl@f$@01MgV^XX!LuplRx-K^j0~XXqULo{rGV)J;?LDqW;e8ln?) ziYBOwCh2+l9i64;=olTPK6;5>q!;KoU3#i@AI6xcj=^M_1YE$@v$xth-%o-Hd)oc> zV*f;Iu~0`iWFRlpd|gCu^@4T7N%*MRJoHvAm>AE6I&Nihc4)gED_B6(=y1KOyt1-iHcLpa_Bcs+cUkyh$#4iH6+&^^9QCaw>S zXk5IX#2?x`uvG;X76#=6C(R!D{mJjM|%lov#@;fLn#qD!+XkKfGdsMLfOXrJc>14#5 zmJIeLD5CsGs{;(S?`S|YL&#rZ?mhh5kPGE%)dXX|b^Dc_&*{sr%-yc?!^3p{AOF64 z>={DTp???3-p1bc*t$v5pYZZ`PMBw&x)&}~%B5CmY?iZ5;N?rmcSdm-&pcgxWN^40 z(!VY|et|GfY4enMbO_IGL_q5Iycjh}z1_#4`H!zB#79J1KlHp_*=*FC^{rNBYHd1m zYkB3S$#)*dky6c2f?(2r>&D+_{WsyDyjm8}&aEH5q+frv@c<&UQ^Mxv5g{tg+pO^o z(<}y)RTx0pm|R<<^oTm;r|KfQB5B37f>Z}VS- zQ8T1$8K7RR8FHDk)C~D2C(KjL5LNF1kNkc{6tO*eIp&fvb)U`8T79Oy>VF_e>azr| z%9-x*y;6CV{mWCHy(-Ik<-Pyqgn2650r%~G`W0uWxI5aky($wCYZdvfS$?S2D;&Y_ zJEB8@z!@BO$7(f1o_X8ntk25V0+$QNLY(iIs~rb)%yY?1lz>e*24l7`j|qF2B()D` zFGsWB5R2u|X7P91j(KvtR0OQSK^rWFCpK7P+O%VpyBcjBt_-la`>Y)4neYhL`|bNY zrcK?eNxVm0-lzz(b6#Ft0==Apy~i|fWbn#_Y5O;OCAxo=Yd>f6h20@_pJq863D|}! z8bkyBSh^868ra?D)CM>E{M_)I34XNuJQW^T7K0b6iwgviBb2pkhSW=a^L8ftm1-R;c-vC9djkb1t)B-C$uSPbvmhe z%xS%2OA^+MQ-&dM55QFEXI(wE=>eD>I%L}GTZ&Sjo>(^YNdl4o} zYgdl{StYQOsH5XR6qggmrDltXNr%BUsM(_Ka@e@^J((~&&In)onuv+g+LeuooA9{_ z-&y?q*t&q~m?goQA(!QeMky&O8x|ht(u_??KSBw9m9e?_He7~=4wP#|xSXrL&h1K= z5$80Qb&JR}V%$FW!CcJg3!fD6#m}F2V2QY&WWw})m@o&>2|~$wX-_ONu7Og~z?} z?3gRzWH8}y1vZh?y_bt&8pU``3RC1gEgP4bGs&B$Y|i#2bH`js^Kn{pMc-d{%$PJ! kW`yzS&lB~vy?qV;H0Q~AVLI4(k`xKNVmQP9tHA^Je_4^+k^lez literal 0 HcmV?d00001